Merge branch '138-toggle-free-look-with-hotkey' into main/gingo-test
[ryzomcore.git] / ryzom / client / src / net_manager.cpp
blob5edefdf38012fbd59cffe2801ab64547ce954fc3
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 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) 2014-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/>.
24 /////////////
25 // INCLUDE //
26 /////////////
27 #include "stdpch.h"
28 // Game Share
29 #include "game_share/generic_xml_msg_mngr.h"
30 #include "game_share/msg_client_server.h"
31 #include "game_share/bot_chat_types.h"
32 #include "game_share/mode_and_behaviour.h"
33 #include "game_share/chat_group.h"
34 #include "game_share/character_summary.h"
35 #include "game_share/sphrase_com.h"
36 #include "game_share/outpost.h"
37 #include "game_share/msg_client_server.h"
38 #include "game_share/ryzom_database_banks.h"
39 #include "game_share/msg_encyclopedia.h"
40 #include "game_share/prerequisit_infos.h"
41 #include "game_share/permanent_ban_magic_number.h"
42 #include "game_share/item_special_effect.h"
43 #include "game_share/combat_flying_text.h"
44 #include "game_share/shard_names.h"
45 // Client.
46 #include "nel/gui/group_list.h"
47 #include "interface_v3/interface_manager.h"
48 #include "net_manager.h"
49 #include "client_cfg.h"
50 #include "entities.h"
51 #include "client_chat_manager.h"
52 #include "world_database_manager.h"
53 #include "continent_manager.h"
54 #include "motion/user_controls.h"
55 #include "interface_v3/bot_chat_manager.h"
56 #include "interface_v3/bot_chat_page_all.h"
57 #include "interface_v3/bot_chat_page_trade.h"
58 #include "interface_v3/bot_chat_page_create_guild.h"
59 #include "interface_v3/obs_huge_list.h"
60 #include "string_manager_client.h"
61 #include "interface_v3/people_interraction.h"
62 #include "interface_v3/bot_chat_manager.h"
63 #include "interface_v3/bot_chat_page_all.h"
64 #include "nel/gui/view_text_id.h"
65 #include "nel/gui/ctrl_text_button.h"
66 #include "interface_v3/input_handler_manager.h"
67 #include "interface_v3/guild_manager.h"
68 #include "interface_v3/skill_manager.h"
69 #include "misc.h"
70 #include "interface_v3/inventory_manager.h"
71 #include "interface_v3/sphrase_manager.h"
72 #include "outpost_manager.h"
73 #include "interface_v3/encyclopedia_manager.h"
74 #include "user_entity.h"
75 #include "init_main_loop.h"
76 #include "interface_v3/group_map.h"
77 #include "sound_manager.h"
78 #include "interface_v3/group_compas.h"
79 #include "interface_v3/group_html_webig.h"
80 #include "interface_v3/bar_manager.h"
81 #include "permanent_ban.h"
82 #include "global.h"
83 #include "connection.h"
84 #include "faction_war_manager.h"
85 #include "far_tp.h"
86 #include "input.h"
87 #include "r2/editor.h"
88 #include "game_share/r2_share_itf.h"
89 #include "game_share/r2_types.h"
90 #include "npc_icon.h"
91 #include "interface_v3/action_handler_base.h"
93 // Std.
94 #include <vector>
96 #ifdef DEBUG_NEW
97 #define new DEBUG_NEW
98 #endif
100 #define OLD_STRING_SYSTEM
101 #define BAR_STEP_TP 2
103 ///////////
104 // USING //
105 ///////////
106 using namespace NLMISC;
107 using namespace NL3D;
108 using namespace std;
111 extern bool FirstFrame;
112 extern void selectTipsOfTheDay (uint tips);
115 ////////////
116 // GLOBAL //
117 ////////////
118 CGenericXmlMsgHeaderManager GenericMsgHeaderMngr; // Manage messages
119 #ifdef CLIENT_MULTI
120 CNetManagerMulti NetMngr; // Manage the connection.
121 #else
122 CNetManager NetMngr; // Manage the connection.
123 #endif
125 bool UseFemaleTitles = false;
127 bool serverReceivedReady = false;
129 static const std::string PLAYER_EXCHANGE_INVITATION_DIALOG = "ui:interface:accept_trade_invitation";
131 // Hierarchical timer
132 H_AUTO_DECL ( RZ_Client_Net_Mngr_Update )
134 ////////////
135 // EXTERN //
136 ////////////
137 extern bool noUserChar; // \todo GUIGUI : do this better.
138 extern bool userChar; // \todo GUIGUI : do this better.
139 extern std::vector<CCharacterSummary> CharacterSummaries;
140 extern uint8 ServerPeopleActive;
141 extern uint8 ServerCareerActive;
142 extern vector<CMainlandSummary> Mainlands;
143 extern bool UserCharPosReceived;
144 extern CGenericXmlMsgHeaderManager GenericMsgHeaderMngr;
145 extern CClientChatManager ChatMngr;
147 extern bool CharNameValidArrived;
148 extern bool CharNameValid;
149 bool IsInRingSession = false;
150 TSessionId HighestMainlandSessionId; // highest in the position stack
151 std::string lastUniversMessage;
153 extern const char *CDBBankNames[INVALID_CDB_BANK+1];
155 void cbImpulsionGatewayOpen(NLMISC::CBitMemStream &bms);
156 void cbImpulsionGatewayMessage(NLMISC::CBitMemStream &bms);
157 void cbImpulsionGatewayClose(NLMISC::CBitMemStream &bms);
161 ///////////////
162 // FUNCTIONS //
163 ///////////////
165 void impulseDatabaseInitPlayer(NLMISC::CBitMemStream &impulse)
169 sint32 p = impulse.getPos();
171 // get the egs tick of this change
172 TGameCycle serverTick;
173 impulse.serial(serverTick);
175 // read delta
176 IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer );
177 IngameDbMngr.setInitPacketReceived();
178 nlinfo( "DB_INIT:PLR done (%u bytes)", impulse.getPos()-p );
180 catch (const Exception &e)
182 BOMB( NLMISC::toString( "Problem while decoding a DB_INIT:PLR msg, skipped: %s", e.what() ), return );
186 void impulseDatabaseUpdatePlayer(NLMISC::CBitMemStream &impulse)
190 // get the egs tick of this change
191 TGameCycle serverTick;
192 impulse.serial(serverTick);
194 // read delta
195 IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer ); // unlike on the server, here there is only one unified CCDBSynchronized object
197 catch (const Exception &e)
200 BOMB( NLMISC::toString( "Problem while decoding a DB_UPDATE_PLR msg, skipped: %s", e.what() ), return );
204 template <class CInventoryCategoryTemplate>
205 void updateInventoryFromStream(NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges);
207 void impulseDatabaseUpdateBank(NLMISC::CBitMemStream &impulse)
209 uint32 bank = INVALID_CDB_BANK;
212 // get the egs tick of this change
213 TGameCycle serverTick;
214 impulse.serial(serverTick);
216 // decode bank
217 uint nbits;
218 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
219 impulse.serial( bank, nbits );
221 // read delta
222 IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
224 // read guild inventory update
225 if ( bank == CDBGuild )
227 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
230 catch (const Exception &e)
232 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:UPDATE_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
236 void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse)
238 uint32 bank = INVALID_CDB_BANK;
241 // get the egs tick of this change
242 TGameCycle serverTick;
243 impulse.serial(serverTick);
245 // decode bank
246 uint nbits;
247 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
248 impulse.serial( bank, nbits );
250 // read delta
251 IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
252 nldebug( "CDB: DB_GROUP:INIT_BANK %s", CDBBankNames[bank] );
254 // read guild inventory update
255 if ( bank == CDBGuild )
257 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
260 catch (const Exception &e)
262 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:INIT_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
266 void impulseDatabaseResetBank(NLMISC::CBitMemStream &impulse)
268 uint32 bank = INVALID_CDB_BANK;
271 // get the egs tick of this change
272 TGameCycle serverTick;
273 impulse.serial(serverTick);
275 // read the bank to reset
276 uint nbits;
277 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
278 impulse.serial( bank, nbits );
280 // reset the bank
281 IngameDbMngr.resetBank( serverTick, bank );
282 nldebug( "CDB: DB_GROUP:RESET_BANK %s", CDBBankNames[bank] );
284 catch (const Exception &e)
286 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:RESET_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
290 static void readPrivileges(NLMISC::CBitMemStream &impulse)
292 nlassert(impulse.isReading());
293 // nico : temporarily uses a try block here to avoid prb with people having updated client and not the server
296 impulse.serial(UserPrivileges);
298 catch(const EStreamOverflow &)
300 nlwarning("User privileges not serialised, assuming none");
301 UserPrivileges.clear();
305 void impulseNoUserChar(NLMISC::CBitMemStream &impulse)
307 // received NO_USER_CHAR
308 //nlinfo("impulseCallBack : Received CONNECTION:NO_USER_CHAR");
310 impulse.serial(ServerPeopleActive);
311 impulse.serial(ServerCareerActive);
312 readPrivileges(impulse);
313 impulse.serialCont(Mainlands);
314 CharacterSummaries.clear();
315 noUserChar = true;
317 LoginSM.pushEvent(CLoginStateMachine::ev_no_user_char);
319 updatePatcherPriorityBasedOnCharacters();
322 void impulseFarTP(NLMISC::CBitMemStream &impulse)
324 // received FAR_TP
325 TSessionId sessionId;
326 impulse.serial(sessionId);
327 //nlinfo("impulseCallback : Received CONNECTION:FAR_TP %u", sessionId.asInt());
328 bool bailOutIfSessionVanished;
329 impulse.serial(bailOutIfSessionVanished);
330 FarTP.requestFarTPToSession(sessionId, PlayerSelectedSlot, CFarTP::JoinSession, bailOutIfSessionVanished);
334 static std::string lookupSrcKeyFile(const std::string &src)
336 if (CFile::isExists("save/" + src)) return "save/" + src;
337 return CPath::lookup(src, false);
340 void copyKeySet(const std::string &srcPath, const std::string &destPath)
342 // can't use CFile copyFile here, because src may be in a bnp file
343 std::string srcStr;
344 srcStr.resize(CFile::getFileSize(srcPath));
345 if (srcStr.empty())
347 nlwarning("Can't copy keys from %s : file not found or empty");
348 return;
352 CIFile ifile(srcPath);
353 ifile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
354 COFile ofile(destPath);
355 ofile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
357 catch(const EStream &)
359 nlwarning("Couldn't copy %s to %s to create new character keyset", srcPath.c_str(), destPath.c_str());
363 void impulseUserChars(NLMISC::CBitMemStream &impulse)
365 // received USER_CHARS
366 //nlinfo("impulseCallBack : Received CONNECTION:USER_CHARS");
368 impulse.serial(ServerPeopleActive);
369 impulse.serial(ServerCareerActive);
370 // read characters summary
371 CharacterSummaries.clear();
372 impulse.serialCont (CharacterSummaries);
373 // read shard name summaries
374 std::vector<string> shardNames;
375 impulse.serialCont (shardNames);
376 CShardNames::getInstance().loadShardNames(shardNames);
377 // read privileges
378 readPrivileges(impulse);
379 impulse.serial(FreeTrial);
380 FreeTrial = false;
381 impulse.serialCont(Mainlands);
382 userChar = true;
384 LoginSM.pushEvent(CLoginStateMachine::ev_chars_received);
386 // Create the message for the server to select the first character.
387 /* CBitMemStream out;
388 if(GenericMsgHeaderMngr.pushNameToStream("CONNECTION:SELECT_CHAR", out))
390 CSelectCharMsg SelectCharMsg;
391 SelectCharMsg.c = 0; //TODO set here the character choosen by player
392 out.serial( SelectCharMsg );
393 NetMngr.push(out);
394 NetMngr.send(NetMngr.getCurrentServerTick());
395 // send CONNECTION:USER_CHARS
396 nldebug("impulseCallBack : CONNECTION:SELECT_CHAR sent");
398 else
399 nlwarning("impulseCallBack : unknown message name : 'CONNECTION:SELECT_CHAR'.");
401 noUserChar = true;
404 if (!NewKeysCharNameValidated.empty())
406 // if there's a new char for which a key set was wanted, create it now
407 for (uint k = 0; k < CharacterSummaries.size(); ++k)
409 if (toLower(CharacterSummaries[k].Name.toUtf8()) == toLower(NewKeysCharNameValidated))
411 // first, stripes server name
412 copyKeySet(lookupSrcKeyFile(GameKeySet), "save/keys_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
413 copyKeySet(lookupSrcKeyFile(RingEditorKeySet), "save/keys_r2ed_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
414 break;
418 updatePatcherPriorityBasedOnCharacters();
421 void impulseUserChar(NLMISC::CBitMemStream &impulse)
423 // received USER_CHAR
424 //nlinfo("impulseCallBack : Received CONNECTION:USER_CHAR");
426 // Serialize the message
427 COfflineEntityState posState;
428 extern uint8 ServerSeasonValue;
429 extern bool ServerSeasonReceived;
430 uint32 userRole;
431 CUserCharMsg::read( impulse, posState, ServerSeasonValue, userRole, IsInRingSession, HighestMainlandSessionId, CharFirstConnectedTime, CharPlayedTime );
432 ServerSeasonReceived = true; // set the season that will be used when selecting the continent from the position
434 if (UserEntity)
436 UserEntity->pos(CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f));
437 UserEntity->front(CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f));
438 UserEntity->dir(UserEntity->front());
439 UserEntity->setHeadPitch(0);
440 UserControls.resetCameraDeltaYaw();
441 //nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntity->pos().x,UserEntity->pos().y,UserEntity->pos().z,posState.Heading);
443 // Update the position for the vision.
444 NetMngr.setReferencePosition(UserEntity->pos());
446 else
448 UserEntityInitPos = CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f);
449 UserEntityInitFront = CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f);
450 //nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntityInitPos.x,UserEntityInitPos.y,UserEntityInitPos.z,posState.Heading);
452 // Update the position for the vision.
453 NetMngr.setReferencePosition(UserEntityInitPos);
456 UserCharPosReceived = true;
458 // Configure the ring editor
459 extern R2::TUserRole UserRoleInSession;
460 UserRoleInSession = R2::TUserRole::TValues(userRole);
461 ClientCfg.R2EDEnabled = IsInRingSession /*&& (UserRoleInSession.getValue() != R2::TUserRole::ur_player)*/;
462 // !!!Do NOT uncomment the following line do the ClientCfg.R2EDEnabled = IsInRingSession && (UserRoleInSession != R2::TUserRole::ur_player);
463 // even with UserRoleInSession R2::TUserRole::ur_player the ring features must be activated
464 // because if the ring is not activated the dss do not know the existence of the player
465 // So we can not kick him, tp to him, tp in to next act ....
466 nldebug( "EnableR2Ed = %u, IsInRingSession = %u, UserRoleInSession = %u", (uint)ClientCfg.R2EDEnabled, (uint)IsInRingSession, userRole );
468 updatePatcherPriorityBasedOnCharacters();
471 void impulseCharNameValid(NLMISC::CBitMemStream &impulse)
473 //nlinfo("impulseCallBack : Received CONNECTION:VALID_NAME");
474 uint8 nTmp;
475 impulse.serial(nTmp);
476 CharNameValid = ((nTmp != 0) ? true : false);
477 CharNameValidArrived = true;
478 if (CharNameValid) NewKeysCharNameValidated = NewKeysCharNameWanted;
482 void checkHandshake( NLMISC::CBitMemStream &impulse )
484 // Decode handshake to check versions
485 uint16 handshakeVersion;
486 uint16 itemSlotVersion;
487 impulse.serial( handshakeVersion );
488 if ( handshakeVersion > 0 )
489 nlerror( "Server handshake version is more recent than client one" );
490 impulse.serial( itemSlotVersion );
491 if ( itemSlotVersion != INVENTORIES::CItemSlot::getVersion() )
492 nlerror( "Handshake: itemSlotVersion mismatch (S:%hu C:%hu)", itemSlotVersion, INVENTORIES::CItemSlot::getVersion() );
496 void impulseServerReady(NLMISC::CBitMemStream &impulse)
498 // received CONNECTION:READY
499 //nlinfo("impulseCallBack : Received CONNECTION:READY");
501 serverReceivedReady = true;
503 checkHandshake( impulse );
505 LoginSM.pushEvent(CLoginStateMachine::ev_ready_received);
508 void impulseShardId(NLMISC::CBitMemStream &impulse)
510 // received SHARD_ID
512 uint32 shardId;
513 impulse.serial(shardId);
514 ShardId = shardId;
516 string webHost;
517 impulse.serial(webHost);
518 if (!webHost.empty())
520 WebServer = webHost;
523 nlinfo("WEB: Received SHARD_ID %d, web hosted at '%s', using '%s'", shardId, webHost.c_str(), WebServer.c_str());
526 void impulseServerQuitOk(NLMISC::CBitMemStream &impulse)
528 // receive CONNECTION:SERVER_QUIT_OK
529 if (FarTP.isFarTPInProgress())
531 FarTP.onServerQuitOk();
533 else
535 // ensure first a quit request is really asked
536 if(game_exit_request)
538 // quit!
539 game_exit= true;
540 ryzom_exit= true;
545 void impulseServerQuitAbort(NLMISC::CBitMemStream &impulse)
547 // receive CONNECTION:SERVER_QUIT_ABORT
548 if (FarTP.isFarTPInProgress())
550 FarTP.onServerQuitAbort();
552 else
554 // abort any quit request
555 game_exit_request= false;
556 ryzom_exit_request= false;
560 void impulseMailNotification(NLMISC::CBitMemStream &impulse)
562 if (PermanentlyBanned) return;
563 // receive CONNECTION:MAIL_AVAILABLE
564 CInterfaceManager::getInstance()->notifyMailAvailable();
567 void impulseForumNotification(NLMISC::CBitMemStream &impulse)
569 if (PermanentlyBanned) return;
570 // receive CONNECTION:GUILD_MESSAGE_AVAILABLE
571 CInterfaceManager::getInstance()->notifyForumUpdated();
575 void impulsePermanentBan(NLMISC::CBitMemStream &impulse)
577 uint64 magicNumber;
578 impulse.serial(magicNumber);
579 if (magicNumber != PermanentBanMSGMagicNumber) return; // bad msg
580 setPermanentBanMarkers(true);
581 applyPermanentBanPunishment();
582 PermanentlyBanned = true;
585 void impulsePermanentUnban(NLMISC::CBitMemStream &impulse)
587 uint64 magicNumber;
588 impulse.serial(magicNumber);
589 if (magicNumber != PermanentUnbanMSGMagicNumber) return; // bad msg
590 setPermanentBanMarkers(false);
591 PermanentlyBanned = false;
592 if (UserEntity)
594 // allows to walk / run again
595 UserEntity->walkVelocity(ClientCfg.Walk);
596 UserEntity->runVelocity(ClientCfg.Run);
601 // ***************************************************************************
602 class CInterfaceChatDisplayer : public CClientChatManager::IChatDisplayer
604 public:
605 virtual void displayChat(TDataSetIndex compressedSenderIndex, const std::string &ucstr, const std::string &rawMessage, CChatGroup::TGroupType mode, NLMISC::CEntityId dynChatId, std::string &senderName, uint bubbleTimer=0);
606 virtual void displayTell(/*TDataSetIndex senderIndex, */const std::string &ucstr, const std::string &senderName);
607 virtual void clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex);
609 private:
610 // Add colorization tag for sender name
611 void colorizeSender(string &text, const string &senderName, CRGBA baseColor);
614 static CInterfaceChatDisplayer InterfaceChatDisplayer;
616 void CInterfaceChatDisplayer::colorizeSender(string &text, const string &senderName, CRGBA baseColor)
618 // find the sender/text separator to put color tags
619 string::size_type pos = senderName.length() - 1;
620 if (pos != string::npos)
622 string str;
624 CInterfaceProperty prop;
625 prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
627 CChatWindow::encodeColorTag(prop.getRGBA(), str, false);
629 str += text.substr(0, pos+1);
631 CChatWindow::encodeColorTag(baseColor, str, true);
633 str += text.substr(pos+1);
635 text = str;
639 // display a chat from network to interface
640 void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, const std::string &ucstr, const std::string &rawMessage, CChatGroup::TGroupType mode, NLMISC::CEntityId dynChatId, std::string &senderName, uint bubbleTimer)
642 CInterfaceManager *pIM = CInterfaceManager::getInstance();
643 string finalString;
644 string stringCategory = getStringCategory(ucstr, finalString);
646 bool bubbleWanted = true;
648 // Subtract rawMessage from ucstr so that the 'sender' part remains.
649 string senderPart = ucstr.substr(0, ucstr.length() - rawMessage.length());
651 // search a "{no_bubble}" tag
653 string::size_type index = finalString.find("{no_bubble}");
654 const size_t tokenSize= 11; // length of "{no_bubble}"
655 if (index != string::npos)
657 bubbleWanted = false;
658 finalString = finalString.substr(0, index) + finalString.substr(index+tokenSize,finalString.size());
663 // **** get color
664 CRGBA col;
665 if (mode != CChatGroup::system)
667 // Remove all {break}
668 for(;;)
670 string::size_type index = finalString.find("{break}");
671 if (index == string::npos) break;
672 finalString = finalString.substr(0, index) + finalString.substr(index+7,finalString.size());
675 // select DB
676 sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
677 clamp(dbIndex, (sint32)0 , (sint32)CChatGroup::MaxDynChanPerPlayer);
678 string entry="UI:SAVE:CHAT:COLORS:";
679 switch(mode)
681 case CChatGroup::dyn_chat: entry+="DYN:" + NLMISC::toString(dbIndex); break;
682 case CChatGroup::say: entry+="SAY"; break;
683 case CChatGroup::shout: entry+="SHOUT"; break;
684 case CChatGroup::team: entry+="GROUP"; break;
685 case CChatGroup::guild: entry+="CLADE"; break;
686 case CChatGroup::civilization: entry+="CIVILIZATION"; break;
687 case CChatGroup::territory: entry+="TERRITORY"; break;
688 case CChatGroup::universe: entry+="UNIVERSE_NEW"; break;
689 case CChatGroup::region: entry+="REGION"; break;
690 case CChatGroup::tell: entry+="TELL"; break;
691 default: nlwarning("unknown group type"); return;
694 // read DB
695 CInterfaceProperty prop;
696 prop.readRGBA(entry.c_str()," ");
697 col = prop.getRGBA();
699 // Override color if the string contains the color
700 if (!stringCategory.empty() && stringCategory != "SYS")
702 map<string, CClientConfig::SSysInfoParam>::const_iterator it;
703 it = ClientCfg.SystemInfoParams.find(toLowerAscii(stringCategory));
704 if (it != ClientCfg.SystemInfoParams.end())
706 col = it->second.Color;
711 if (stringCategory == "emt")
713 bubbleWanted = false;
716 if (mode != CChatGroup::system)
718 // find the sender/text separator to put color tags
719 if (senderPart.empty() && stringCategory == "emt")
721 size_t pos = finalString.find(": ", 0);
722 if (pos != string::npos)
724 senderPart = finalString.substr(0, pos + 2);
727 colorizeSender(finalString, senderPart, col);
730 // play associated fx if any
731 if( !stringCategory.empty() )
733 map<string, CClientConfig::SSysInfoParam>::const_iterator it;
734 it = ClientCfg.SystemInfoParams.find( toLowerAscii(stringCategory) );
735 if( it != ClientCfg.SystemInfoParams.end() )
737 if( !(*it).second.SysInfoFxName.empty() )
739 NL3D::UParticleSystemInstance sysInfoFx = FXMngr.instantFX((*it).second.SysInfoFxName);
740 if( !sysInfoFx.empty() )
742 sysInfoFx.setClusterSystem( UserEntity->getClusterSystem() );
743 sysInfoFx.setPos( UserEntity->pos() );
745 else
747 nlwarning("<CInterfaceChatDisplayer::displayChat> Can't set chat fx %s",(*it).second.SysInfoFxName.c_str());
753 // **** redirect to the correct interface output
754 if( stringCategory != "bbl" )
756 bool windowVisible;
757 if (mode == CChatGroup::system)
759 pIM->displaySystemInfo(finalString, stringCategory);
761 else if (mode == CChatGroup::guild)
763 PeopleInterraction.ChatInput.Guild.displayMessage(finalString, col, 2, &windowVisible);
765 else if (mode == CChatGroup::team)
767 PeopleInterraction.ChatInput.Team.displayMessage(finalString, col, 2, &windowVisible);
769 else if (mode == CChatGroup::region)
771 PeopleInterraction.ChatInput.Region.displayMessage(finalString, col, 2, &windowVisible);
773 else if (mode == CChatGroup::universe)
775 if (lastUniversMessage != finalString)
777 PeopleInterraction.ChatInput.Universe.displayMessage(finalString, col, 2, &windowVisible);
778 lastUniversMessage = finalString;
781 else if (mode == CChatGroup::dyn_chat)
783 // retrieve the DBIndex from the dynamic chat id
784 sint32 dbIndex= ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
785 // if found, display, else discarded
786 if(dbIndex >= 0 && dbIndex < CChatGroup::MaxDynChanPerPlayer)
788 PeopleInterraction.ChatInput.DynamicChat[dbIndex].displayMessage(finalString, col, 2, &windowVisible);
790 // Add dynchannel info before text so that the chat log will show the correct string.
791 CCDBNodeLeaf* node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_DYN_CHANNEL_NAME_IN_CHAT_CB", false);
792 if (pIM->getLogState())
794 // Add dyn chan number before string
795 string prefix = "[" + NLMISC::toString(dbIndex) + "]";
796 // Find position to put the new string
797 // After timestamp?
798 size_t pos = finalString.find("]");
799 size_t colonpos = finalString.find(": @{");
800 // If no ] found or if found but after the colon (so part of the user chat)
801 if (pos == string::npos || (colonpos < pos))
803 // No timestamp, so put it right after the color and add a space
804 pos = finalString.find("}");;
805 prefix += " ";
807 finalString = finalString.substr(0, pos + 1) + prefix + finalString.substr(pos + 1);
809 if (node && node->getValueBool())
811 uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(dbIndex);
812 string title;
813 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
814 prefix = (title.empty() ? "" : " ") + title;
815 pos = finalString.find("] ");
816 finalString = finalString.substr(0, pos) + prefix + finalString.substr(pos);
820 else
822 nlwarning("Dynamic chat %s not found for message: %s", dynChatId.toString().c_str(), finalString.c_str());
825 else
827 string::size_type index = finalString.find("<BPFX>");
828 if (index != string::npos)
830 bubbleWanted = false;
831 finalString = finalString.substr(index+6,finalString.size());
832 string::size_type index2 = finalString.find(string(" "));
833 string playerName;
834 if (index2 < (finalString.size()-3))
836 playerName = finalString.substr(0,index2);
837 finalString = finalString.substr(index2+1,finalString.size());
839 if (!senderName.empty())
841 CEntityCL *senderEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(senderName), true, true);
842 if (senderEntity)
844 if (senderEntity->Type != CEntityCL::Player)
846 if (playerName.empty())
848 senderEntity->removeStateFx();
849 senderEntity->setStateFx(finalString);
850 nlinfo("empty");
852 else
854 CEntityCL *destEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(playerName), false, true);
855 if (destEntity)
857 destEntity->removeStateFx();
858 destEntity->setStateFx(finalString);
859 nlinfo("no empty");
865 finalString.clear();
867 else
869 PeopleInterraction.ChatInput.AroundMe.displayMessage(finalString, col, 2, &windowVisible);
872 // if tell, bkup sendername
873 if (mode == CChatGroup::tell && windowVisible && !senderName.empty())
875 PeopleInterraction.LastSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
879 // received CHAT
880 //nldebug("<impulseChat> Received CHAT : %s with category %s",finalString.toString().c_str(),stringCategory.c_str());
883 // **** Process chat entry for the bubbles
884 // todo hulud : registering a chat callback would be better than calling this hardcoded action handler
885 string finalRawMessage;
886 // remove color qualifier from raw string
887 getStringCategory(rawMessage, finalRawMessage);
888 if (bubbleWanted)
890 InSceneBubbleManager.chatOpen(compressedSenderIndex, finalRawMessage, bubbleTimer);
893 // Log
895 string channel;
896 if (mode == CChatGroup::dyn_chat)
898 sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
899 clamp(dbIndex, (sint32)0 , (sint32)CChatGroup::MaxDynChanPerPlayer);
901 channel = "dyn" + toString(dbIndex);
903 else
905 channel = CChatGroup::groupTypeToString(mode);
906 if (channel.empty())
908 channel = "#" + toString((uint32)mode);
911 if (!stringCategory.empty() && NLMISC::compareCaseInsensitive(stringCategory.c_str(), "SYS")) // Not empty and not 'SYS'
913 channel = channel + "/" + stringCategory;
915 pIM->log (finalString, channel);
920 // display a tell from network to interface
921 void CInterfaceChatDisplayer::displayTell(/*TDataSetIndex senderIndex, */const std::string &ucstr, const std::string &senderName)
924 string finalString = ucstr;
926 // for now, '&' are removed by server so use another format until a special msg is made
927 if (strFindReplace(finalString, "<R2_INVITE>", string()))
929 CLuaManager::getInstance().executeLuaScript("RingAccessPoint:forceRefresh()");
933 CInterfaceProperty prop;
934 prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
935 bool windowVisible;
937 string goodSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
939 // The sender part is up to and including the first ":" after the goodSenderName
940 string::size_type pos = finalString.find(goodSenderName);
941 pos = finalString.find(':', pos);
942 pos = finalString.find(' ', pos);
943 string senderPart = finalString.substr(0, pos+1);
944 colorizeSender(finalString, senderPart, prop.getRGBA());
946 PeopleInterraction.ChatInput.Tell.displayTellMessage(/*senderIndex, */finalString, goodSenderName, prop.getRGBA(), 2, &windowVisible);
947 CInterfaceManager::getInstance()->log(finalString, CChatGroup::groupTypeToString(CChatGroup::tell));
949 // Open the free teller window
950 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
951 if (pCGW != NULL)
952 pCGW->setActiveFreeTeller(goodSenderName);
954 if (windowVisible && !goodSenderName.empty())
955 PeopleInterraction.LastSenderName = goodSenderName;
958 // clear a channel
959 void CInterfaceChatDisplayer::clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex)
961 if (mode == CChatGroup::guild) PeopleInterraction.ChatInput.Guild.clearMessages();
962 else if (mode == CChatGroup::team) PeopleInterraction.ChatInput.Team.clearMessages();
963 else if (mode == CChatGroup::region) PeopleInterraction.ChatInput.Region.clearMessages();
964 else if (mode == CChatGroup::arround) PeopleInterraction.ChatInput.AroundMe.clearMessages();
965 else if (mode == CChatGroup::universe) PeopleInterraction.ChatInput.Universe.clearMessages();
966 else if (mode == CChatGroup::dyn_chat)
968 // if correct dbIndex, clear
969 if(dynChatDbIndex<CChatGroup::MaxDynChanPerPlayer)
970 PeopleInterraction.ChatInput.DynamicChat[dynChatDbIndex].clearMessages();
971 else
972 nlwarning("Dynamic chat %d not found for clearing", dynChatDbIndex);
975 // don't support other for now (NB: actually used only for dyn_chat)
979 // ***************************************************************************
980 void impulseChat(NLMISC::CBitMemStream &impulse)
982 ChatMngr.processChatString(impulse, InterfaceChatDisplayer);
985 void impulseChat2(NLMISC::CBitMemStream &impulse)
987 ChatMngr.processChatString2(impulse, InterfaceChatDisplayer);
990 void impulseTell(NLMISC::CBitMemStream &impulse)
992 ChatMngr.processTellString(impulse, InterfaceChatDisplayer);
995 void impulseFarTell(NLMISC::CBitMemStream &impulse)
997 ChatMngr.processFarTellString(impulse, InterfaceChatDisplayer);
1000 void impulseTell2(NLMISC::CBitMemStream &impulse)
1002 ChatMngr.processTellString2(impulse, InterfaceChatDisplayer);
1005 void impulseDynString(NLMISC::CBitMemStream &impulse)
1007 ChatMngr.processChatStringWithNoSender(impulse, CChatGroup::system, InterfaceChatDisplayer);
1010 void inpulseDynStringInChatGroup(NLMISC::CBitMemStream &impulse)
1012 CChatGroup::TGroupType type = CChatGroup::say;
1013 impulse.serialEnum(type);
1014 ChatMngr.processChatStringWithNoSender(impulse, type, InterfaceChatDisplayer);
1017 // ***************************************************************************
1018 //void impulseAddDynStr(NLMISC::CBitMemStream &impulse)
1020 // bool huff = false;
1021 // impulse.serialBit(huff);
1023 // uint32 index;
1024 // ucstring ucstr; // OLD
1026 // impulse.serial( index );
1027 // impulse.serial( ucstr );
1029 // vector<bool> code;
1030 // if( huff )
1031 // {
1032 // impulse.serialCont( code );
1033 // }
1034 // if (PermanentlyBanned) return;
1035 // #ifdef OLD_STRING_SYSTEM
1036 // ChatMngr.getDynamicDB().add( index, ucstr, code );
1037 // #else
1038 // nlwarning( "// TRAP // WE MUST NEVER CALL THIS IMPULE ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!" );
1039 // #endif
1041 // // received ADD_DYN_STR
1042 // nlinfo("impulseCallBack : Received ADD_DYN_STR : adding %s at index %d",ucstr.toString().c_str(),index);
1045 string getInterfaceNameFromId (sint botType, sint interfaceId)
1047 string interfaceName = "ui:interface:bot_chat_";
1049 switch (botType)
1051 case 0: interfaceName += "figurant_"; break;
1052 case 1: interfaceName += "figurant_presse_"; break;
1053 case 2: interfaceName += "chef_village_"; break;
1054 default: interfaceName += "figurant_"; break;
1057 switch (interfaceId)
1059 case BOTCHATTYPE::Intro: interfaceName += "intro"; break;
1060 case BOTCHATTYPE::FriendlyMainPage: interfaceName += "friendly_main"; break;
1061 case BOTCHATTYPE::NeutralMainPage: interfaceName += "neutral_main"; break;
1062 case BOTCHATTYPE::NastyMainPage: interfaceName += "nasty_main"; break;
1063 case BOTCHATTYPE::MoreNewsPage: interfaceName += "more_news"; break;
1064 case BOTCHATTYPE::Done: nlinfo ("end of bot chat"); interfaceName.clear(); break;
1066 return interfaceName;
1069 static char *shortNews[] = {
1070 "The wind is sour and brings only bad tidings...", "Kitins have been sighted near the village!", "",
1071 "The tribe of the Black Circle has recently", "increased its activities in our region.", "",
1072 "The Black Circle has made an incursion", "into our territory!", "",
1073 "The Black Circle has been sighted near one", "of our forward posts, deep in dangerous territory.", "",
1074 "The tide has washed up evil news, friend.", "The Black Circle is active in our region.", "",
1075 "Our people suffer from a debilitating shortage.", "We are in sore need of KamiBast.", "",
1076 "The economy is slow and our reserve of", "Live Seed low.", "",
1077 "We are in sore need of Live Seed", "If there is a Goo epidemic, we shall all perish!", "",
1078 "Our master mages have gotten wind of", "the growing Kami discontentment", "",
1081 static char *longNews[] = {
1082 "These powerful predators haven't come this near", "to the village since their devastating attack", "over 15 seasons ago!",
1083 "They are after more KamiBast", "for their occult practices.", "",
1084 "They have captured", "2 of our fortifications in the bush!", "",
1085 "They have taken over one of our richest sources", "of KamiBast, and are exploiting it", "for their own occult purposes.",
1086 "They now hold an important source", "of Live Seed hostage,", "close to one of our forward posts.",
1087 "We use the magical properties of KamiBast and", "its unusually rich fibers for all our crafts.", "",
1088 "If we don't harvest new Seed soon,", "we will have no way of purchasing goods", "and resources, beyond what we produce ourselves",
1089 "We use the rich Sap of Live Seed to produce", "an antidote that counters the disastrous", "effects of the Goo on all Atysian life forms.",
1090 "The Kamis are shaken by the Black Circle's", "presence. If the Circle continues it's occult", "practices, we will all suffer the Kamic anger.",
1094 void setFakeNews ()
1096 char *table[] = { "figurant", "chef_village", "garde", "commercant" };
1098 sint rnd = rand ()%(sizeof(shortNews)/sizeof(shortNews[0])/3);
1099 rnd;
1101 for (uint i = 0; i < sizeof(table)/sizeof(table[0]); i++)
1103 { // set test for the friendly main
1104 string iname;
1105 iname = "ui:interface:bot_chat_";
1106 iname += table[i];
1107 iname += "_friendly_main";
1109 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1110 if (inter == NULL)
1112 nlwarning ("cant find interface 's%'", iname.c_str());
1113 continue;
1116 CViewText *inter2 = (CViewText *)inter->getView("title0");
1117 nlassert (inter2 != NULL);
1118 inter2->setText(ucstring(shortNews[rnd*3])); // OLD
1120 CViewText *inter3 = (CViewText *)inter->getView("title1");
1121 nlassert (inter3 != NULL);
1122 inter3->setText(ucstring(shortNews[rnd*3+1])); // OLD
1124 CViewText *inter4 = (CViewText *)inter->getView("title2");
1125 nlassert (inter4 != NULL);
1126 inter4->setText(ucstring(shortNews[rnd*3+2])); // OLD
1128 { // set test for the neutral main
1129 string iname;
1130 iname = "ui:interface:bot_chat_";
1131 iname += table[i];
1132 iname += "_neutral_main";
1134 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1135 if (inter == NULL)
1137 nlwarning ("cant find interface 's%'", iname.c_str());
1138 continue;
1141 CViewText *inter2 = (CViewText *)inter->getView("title0");
1142 nlassert (inter2 != NULL);
1143 inter2->setText(ucstring(shortNews[rnd*3])); // OLD
1145 CViewText *inter3 = (CViewText *)inter->getView("title1");
1146 nlassert (inter3 != NULL);
1147 inter3->setText(ucstring(shortNews[rnd*3+1])); // OLD
1149 { // set test for the more news
1150 string iname;
1151 iname = "ui:interface:bot_chat_";
1152 iname += table[i];
1153 iname += "_more_news";
1155 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1156 if (inter == NULL)
1158 nlwarning ("cant find interface 's%'", iname.c_str());
1159 continue;
1162 CViewText *inter2 = (CViewText *)inter->getView("title0");
1163 nlassert (inter2 != NULL);
1164 inter2->setText(ucstring(longNews[rnd*3])); // OLD
1166 CViewText *inter3 = (CViewText *)inter->getView("title1");
1167 nlassert (inter3 != NULL);
1168 inter3->setText(ucstring(longNews[rnd*3+1])); // OLD
1170 CViewText *inter4 = (CViewText *)inter->getView("title2");
1171 nlassert (inter4 != NULL);
1172 inter4->setText(ucstring(longNews[rnd*3+2])); // OLD
1182 //=========================================
1183 /** Temp setup for choice list
1186 static void setupBotChatChoiceList(CInterfaceGroup *botChatGroup)
1188 // Temp for test. Should then be read from server msg
1189 std::vector<string> choices;
1190 for(uint k = 0; k < 90; ++k)
1192 choices.push_back("Choice " + toString(k));
1194 CBotChat::setChoiceList(botChatGroup, choices, false);
1198 //=========================================
1199 /** Temp setup for description list
1202 static void setupBotChatDescription(CInterfaceGroup *botChatGroup)
1204 string desc;
1205 for(uint k = 0; k < 90; ++k)
1207 desc += "This is a multi line description. ";
1209 CBotChat::setDescription(botChatGroup, desc);
1213 //=========================================
1214 /** Temp setup for bot chat gift
1217 static void setupBotChatBotGift(CInterfaceGroup *botChatGroup)
1219 // create dummy item in the db
1220 CInterfaceManager *im = CInterfaceManager::getInstance();
1221 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:0:SHEET")->setValue32(CSheetId("ai_flesh_poisson.item").asInt());
1222 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:0:QUALITY")->setValue32(0);
1223 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:1:SHEET")->setValue32(CSheetId("fyros_sword_lvl_01_05.item").asInt());
1224 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:1:QUALITY")->setValue32(2);
1225 CBotChat::setBotGift(botChatGroup, "Thanks to have succeeded the mission", "Here's your reward", "The bot has taken the object quest from your inventory");
1229 //-----------------------------------------------
1230 // impulseBotChatSetInterface :
1231 //-----------------------------------------------
1232 #if 0
1233 void impulseBotChatSetInterface(NLMISC::CBitMemStream &impulse)
1235 // received ADD_DYN_STR
1237 CEntityId user;
1238 uint32 happyness;
1239 BOTCHATTYPE::TBotChatInterfaceId interfaceId;
1240 bool hasNews;
1242 impulse.serial (user);
1243 impulse.serial (happyness);
1245 // impulse.serialEnum (interfaceId);
1246 uint16 interfId;
1247 impulse.serial(interfId);
1248 interfaceId = (BOTCHATTYPE::TBotChatInterfaceId)(interfId&0xff);
1249 uint8 botType = (interfId>>8) & 0xff;
1251 impulse.serial (hasNews);
1253 nldebug("impulseCallBack : Received BOT_CHAT:SET_INTERFACE interface %d, have news %s, happy %d, bottype %hu", interfaceId, hasNews?"yes":"no", happyness,(uint16)botType);
1255 string stringId;
1256 vector<uint64> args;
1257 if (hasNews)
1260 /* impulse.serial (stringId);
1261 impulse.serialCont (args);
1262 nlinfo ("receive the news '%s' with %d args", stringId.c_str(), args.size());
1264 // TEMP FOR THE DEMO, DON'T USE THE NETWORK NEW BUT SELECT A NEWS HERE
1266 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId("ui:interface:bot_chat_intro");
1267 nlassert (inter != NULL);
1268 inter->setActive(true);
1270 CViewText *inter2 = (CViewText *)inter->getView("hi");
1271 nlassert (inter2 != NULL);
1272 inter2->NetworkTextId.setString("IOS_NEWS_FOOTBALL_SHORT_EEII", &ChatMngr);
1273 inter2->NetworkTextId.Args.push_back(10);
1274 inter2->NetworkTextId.Args.push_back(20);
1275 inter2->NetworkTextId.Args.push_back(1);
1276 inter2->NetworkTextId.Args.push_back(2);
1277 */ }
1279 // FOR THE DEMO, find and set a fake news:
1280 // setFakeNews ();
1282 string interfaceName = getInterfaceNameFromId (botType, interfaceId);
1284 if(interfaceName.empty())
1286 nlwarning ("Received an unknown bot chat interface %d", interfaceId);
1288 else
1290 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(interfaceName);
1291 if (inter == NULL)
1293 nlwarning ("Can't find interface name '%s' %d", interfaceName.c_str(), interfaceId);
1295 else
1297 CInterfaceManager::getInstance()->setBotChatWin(inter);
1298 if (inter->getActive())
1300 nlwarning ("Interface %s is already active, not normal!", interfaceName.c_str());
1302 else
1304 nlinfo ("server want to me display the bot chat interface %s %d", interfaceName.c_str(), interfaceId);
1305 inter->setActive(true);
1310 #endif
1314 //-----------------------------------------------
1315 // impulseBeginTrade :
1316 //-----------------------------------------------
1317 void impulseBeginTrade(NLMISC::CBitMemStream &impulse)
1319 if (PermanentlyBanned) return;
1320 //open trade window
1321 CInterfaceGroup* win = CWidgetManager::getInstance()->getWindowFromId("ui:interface:trade");
1322 if (!win)
1324 nlwarning("invalid interface ui:interface:trade");
1325 return;
1327 win->setActive(true);
1330 //-----------------------------------------------
1331 // impulseBuyPrice :
1332 //-----------------------------------------------
1333 void impulseBuyPrice(NLMISC::CBitMemStream &impulse)
1335 uint16 botChatSession;
1336 uint32 sheetID;
1337 uint16 quality;
1338 uint64 price;
1339 impulse.serial(botChatSession);
1340 impulse.serial(price);
1341 impulse.serial(sheetID);
1342 impulse.serial(quality);
1343 // no more used
1346 //-----------------------------------------------
1347 // impulseDynChatOpen
1348 //-----------------------------------------------
1349 void impulseDynChatOpen(NLMISC::CBitMemStream &impulse)
1351 uint32 BotUID; // Compressed Index
1352 uint32 BotName; // Server string
1353 vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
1354 impulse.serial(BotUID);
1355 impulse.serial(BotName);
1356 impulse.serialCont(DynStrs);
1358 if (PermanentlyBanned) return;
1360 /* string sTmp = "impulseCallback : Received BOTCHAT:DYNCHAT_OPEN BotUID:";
1361 sTmp += toString(BotUID) + " BotName:";
1362 sTmp += toString(BotName) + " DynStrs:";
1363 for (uint32 i = 0; i < DynStrs.size(); ++i)
1365 sTmp += toString(DynStrs[i]);
1366 if (i != DynStrs.size()-1) sTmp += ",";
1368 nlinfo(sTmp.c_str());*/
1370 InSceneBubbleManager.dynChatOpen(BotUID, BotName, DynStrs);
1373 //-----------------------------------------------
1374 // impulseDynChatClose
1375 //-----------------------------------------------
1376 void impulseDynChatClose(NLMISC::CBitMemStream &impulse)
1378 uint32 BotUID; // Compressed Index
1379 impulse.serial(BotUID);
1380 if (PermanentlyBanned) return;
1381 //nlinfo("impulseCallback : Received BOTCHAT:DYNCHAT_CLOSE BotUID:"+toString(BotUID));
1382 InSceneBubbleManager.dynChatClose(BotUID);
1385 //-----------------------------------------------
1386 // impulseBeginCast:
1387 //-----------------------------------------------
1388 void impulseBeginCast(NLMISC::CBitMemStream &impulse)
1390 //open cast window
1391 uint32 begin,end;
1392 impulse.serial(begin);
1393 impulse.serial(end);
1394 if (PermanentlyBanned) return;
1395 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
1396 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:SPELL_CAST")->setValue32(1);
1397 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CAST_BEGIN")->setValue32(begin);
1398 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CAST_END")->setValue32(end);
1403 //-----------------------------------------------
1404 // impulseCorrectPos :
1405 // Message from the server to correct the user position because he is not at the same position on the server..
1406 //-----------------------------------------------
1407 void impulseCorrectPos(NLMISC::CBitMemStream &impulse)
1409 // TP:CORRECT
1410 //nlinfo("impulseCallback : Received TP:CORRECT");
1411 sint32 x, y, z;
1412 impulse.serial(x);
1413 impulse.serial(y);
1414 impulse.serial(z);
1415 nlinfo("impulseCorrectPos: new user position %d %d %d", x, y, z);
1417 if(UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
1419 if (x == 0) // Get SpeedAdjustement
1421 UserEntity->setSpeedServerAdjust(-0.2f);
1423 else
1425 // Compute the destination.
1426 CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
1427 // Update the position for the vision.
1428 NetMngr.setReferencePosition(dest);
1429 // Change the user poisition.
1430 UserEntity->correctPos(dest);
1433 }// impulseCorrectPos //
1435 class CDummyProgress : public IProgressCallback
1437 void progress (float /* value */) {}
1440 //-----------------------------------------------
1441 // impulseTP :
1442 // Message from the server to teleport the user.
1443 // \warning This function remove the current target. Do no use to correct a position.
1444 //-----------------------------------------------
1445 void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason);
1446 void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason);
1448 void impulseTP(NLMISC::CBitMemStream &impulse)
1450 impulseTPCommon(impulse, false);
1453 void impulseTPWithSeason(NLMISC::CBitMemStream &impulse)
1455 impulseTPCommon(impulse, true);
1458 struct SQueuedTP
1460 NLMISC::CBitMemStream Impulse;
1461 bool HasSeason;
1463 SQueuedTP(const NLMISC::CBitMemStream &impulse, bool hasSeason)
1464 :Impulse(impulse), HasSeason(hasSeason)
1469 // note - this method added by Sadge and Hamster to deal with unexplained recursive calls to impulseTPCommon
1470 // these calls are provoked by the net manager update which is called during loading
1471 void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason)
1473 CNiceInputAuto niceInputs;
1474 static std::list<SQueuedTP> queuedTPs;
1475 SQueuedTP thisTP(impulse,hasSeason);
1476 queuedTPs.push_back(thisTP);
1478 BOMB_IF(queuedTPs.size()!=1,NLMISC::toString("Queueing recursive TPs depth=%u",queuedTPs.size()),return);
1480 while(!queuedTPs.empty())
1482 impulseTPCommon2(queuedTPs.front().Impulse,queuedTPs.front().HasSeason);
1483 queuedTPs.pop_front();
1489 void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason)
1491 // choose a default screen if not setuped
1492 if (LoadingBackground != ResurectKamiBackground && LoadingBackground != ResurectKaravanBackground
1493 && LoadingBackground != TeleportKamiBackground && LoadingBackground != TeleportKaravanBackground)
1494 LoadingBackground = ElevatorBackground;
1495 // if resurect but user not dead, choose default. NB: this is a bug, the tp impulse should tell
1496 // which background to choose. \todo yoyo: this is a temp fix
1497 if (UserEntity && !UserEntity->isDead() && (LoadingBackground == ResurectKamiBackground || LoadingBackground == ResurectKaravanBackground))
1498 LoadingBackground = ElevatorBackground;
1500 // Play music according to the background
1501 if (SoundMngr)
1503 LoadingMusic.clear();
1504 switch (LoadingBackground)
1506 case TeleportKamiBackground:
1507 LoadingMusic = ClientCfg.KamiTeleportMusic;
1508 break;
1509 case TeleportKaravanBackground:
1510 LoadingMusic = ClientCfg.KaravanTeleportMusic;
1511 break;
1512 case ResurectKamiBackground:
1513 case ResurectKaravanBackground:
1514 // TODO: Resurrect music
1515 break;
1516 default:
1517 LoadingMusic = ClientCfg.TeleportLoadingMusic;
1518 break;
1521 // start to play
1522 SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true);
1525 // Create the loading texture.
1526 beginLoading (LoadingBackground);
1528 // No ESCAPE key
1529 UseEscapeDuringLoading = false;
1531 // Change the tips
1532 selectTipsOfTheDay (rand());
1534 // start progress bar and display background
1535 ProgressBar.reset (BAR_STEP_TP);
1536 string nmsg("Loading...");
1537 ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) );
1540 // received ADD_DYN_STR
1541 nlinfo("impulseTP: received a request for a TP.");
1542 sint32 x, y, z;
1543 impulse.serial(x);
1544 impulse.serial(y);
1545 impulse.serial(z);
1546 bool useHeading;
1547 impulse.serialBit( useHeading );
1548 // Is there an orientation too ?
1549 if( useHeading )
1551 float angle;
1552 impulse.serial(angle);
1553 nlinfo("impulseTP: to %d %d %d %f", x, y, z, angle);
1554 CVector ori = CVector((float)cos(angle), (float)sin(angle), 0.0f);
1555 ori.normalize();
1556 UserEntity->dir(ori, false, false);
1557 UserEntity->front(ori, false, false);
1558 UserEntity->setHeadPitch(0);
1559 UserControls.resetCameraDeltaYaw();
1561 else
1562 nlinfo("impulseTP: to %d %d %d", x, y, z);
1564 if (hasSeason)
1566 extern uint8 ServerSeasonValue;
1567 extern bool ServerSeasonReceived;
1568 impulse.serial(ServerSeasonValue);
1569 ServerSeasonReceived = true;
1572 if (ClientCfg.R2EDEnabled)
1574 R2::getEditor().tpReceived();
1577 // Compute the destination.
1578 CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
1579 // Update the position for the vision.
1580 NetMngr.setReferencePosition(dest);
1581 // Change the position of the entity and in Pacs.
1582 UserEntity->pos(dest);
1584 // Fade out the Game Sound
1585 if(SoundMngr)
1586 SoundMngr->fadeOutGameSound(ClientCfg.SoundTPFade);
1589 R2::TTeleportContext tpContext = R2::TPContext_Unknown;
1591 string tpReason;
1592 string tpCancelText;
1596 R2::TR2TpInfos tpInfos;
1597 impulse.serial(tpInfos);
1600 if ( tpInfos.UseTpMessage)
1602 tpReason = CI18N::get(tpInfos.TpReasonId);
1604 uint32 size = (uint32)tpInfos.TpReasonParams.size();
1605 uint32 first = 0;
1606 CSString str(tpReason);
1607 for (;first != size ; ++first)
1609 std::string value = tpInfos.TpReasonParams[first];
1610 std::string key = NLMISC::toString("%%%u", first +1);
1611 str = str.replace( key.c_str(), value.c_str());
1613 tpReason = string(str);
1614 tpCancelText = CI18N::get(tpInfos.TpCancelTextId);
1615 tpContext = tpInfos.TpContext;
1619 catch (const EStream &)
1621 tpReason = "TP Reason";
1622 tpCancelText = "Cancel TP"; // for test
1623 // try to deduce tp context from current editor mode
1624 switch (R2::getEditor().getMode())
1626 case R2::CEditor::EditionMode:
1627 case R2::CEditor::NotInitialized:
1628 tpContext = R2::TPContext_Unknown;
1629 tpReason = string();
1630 tpCancelText = string();
1631 break;
1632 case R2::CEditor::GoingToDMMode:
1633 case R2::CEditor::TestMode:
1634 case R2::CEditor::DMMode:
1635 tpContext = R2::TPContext_Edit;
1636 break;
1637 case R2::CEditor::AnimationModeLoading:
1638 case R2::CEditor::AnimationModeWaitingForLoading:
1639 case R2::CEditor::AnimationModeDm:
1640 case R2::CEditor::AnimationModeGoingToDm:
1641 tpContext = R2::TPContext_IslandOwner;
1642 break;
1643 case R2::CEditor::AnimationModePlay:
1644 case R2::CEditor::AnimationModeGoingToPlay:
1645 default:
1646 tpContext = R2::TPContext_Mainland;
1647 break;
1653 if (!tpReason.empty())
1655 std::string tpIcon;
1656 switch(tpContext)
1658 case R2::TPContext_Mainland: tpIcon = "cancel_tp_main_land.tga"; break;
1659 case R2::TPContext_Edit: tpIcon = "cancel_tp_edit.tga"; break;
1660 case R2::TPContext_IslandOwner: tpIcon = "cancel_tp_island_owner.tga"; break;
1661 default: break;
1663 ProgressBar.setTPMessages(tpReason, tpCancelText, tpIcon);
1666 ProgressBar.progress(0);
1667 // enable hardware mouse to allow to click the buttons
1668 //bool oldHardwareCursor = IsMouseCursorHardware();
1669 //InitMouseWithCursor(true);
1670 // Select the closest continent from the new position.
1671 ContinentMngr.select(dest, ProgressBar);
1673 //InitMouseWithCursor(oldHardwareCursor);
1675 // reset 'cancel' button
1676 ProgressBar.setTPMessages(string(), string(), "");
1679 // ProgressBar.enableQuitButton(false); // TMP TMP
1680 ProgressBar.progress(1.f); // do a last display without the buttons because first frame may take a while to draw, and the buttons have no more effect at this point.
1681 ProgressBar.finish();
1682 // ProgressBar.enableQuitButton(true); // TMP TMP
1684 // Teleport the User.
1685 UserEntity->tp(dest);
1687 // Msg Received, send an acknowledge after the landscape has been loaded.
1688 CBitMemStream out;
1689 if(GenericMsgHeaderMngr.pushNameToStream("TP:ACK", out))
1691 NetMngr.push(out);
1692 nlinfo("impulseTP: teleport acknowledge 'TP:ACK' sent.");
1694 else
1695 nlwarning("impulseTP: unknown message name : 'TP:ACK'.");
1698 // First frame
1699 FirstFrame = true;
1702 // if tp canceling was asked, act accordingly
1703 if (ProgressBar.getTPCancelFlag(true))
1705 switch(tpContext)
1707 case R2::TPContext_Mainland:
1708 CAHManager::getInstance()->runActionHandler("return_to_mainland", NULL);
1709 break;
1710 case R2::TPContext_Edit:
1711 CAHManager::getInstance()->runActionHandler("r2ed_stop_test", NULL);
1712 break;
1713 case R2::TPContext_IslandOwner:
1714 CAHManager::getInstance()->runActionHandler("r2_stop_live", NULL);
1715 break;
1716 default:
1717 break;
1721 initHardwareCursor(true);
1722 }// impulseTP //
1724 //-----------------------------------------------
1725 // impulseCombatEngageFailed :
1726 //-----------------------------------------------
1727 void impulseCombatEngageFailed(NLMISC::CBitMemStream &impulse)
1729 if (PermanentlyBanned) return;
1730 nlinfo("impulseCombatEngageFailed: Combat Engage Failed.");
1732 // Unlock the motion.
1733 UserControls.locked(false);
1734 }// impulseCombatEngageFailed //
1736 //-----------------------------------------------
1737 // impulseTeamInvitation :
1738 //-----------------------------------------------
1739 void impulseTeamInvitation(NLMISC::CBitMemStream &impulse)
1741 nlinfo("impulseTeamInvitation: received an invitation");
1743 uint32 textID;
1744 impulse.serial(textID);
1745 if (PermanentlyBanned) return;
1747 CLuaManager::getInstance().executeLuaScript("game:onTeamInvation("+toString(textID)+")", 0);
1748 }// impulseTeamInvitation //
1750 //-----------------------------------------------
1751 // impulseTeamShareOpen
1752 // The server request that the client opens the team sharing system
1753 //-----------------------------------------------
1754 void impulseTeamShareOpen(NLMISC::CBitMemStream &impulse)
1756 if (PermanentlyBanned) return;
1757 CInterfaceManager *im = CInterfaceManager::getInstance();
1758 CGroupContainer *gc = dynamic_cast<CGroupContainer*>( CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share"));
1759 if (!gc) return;
1760 gc->setActive(true);
1761 CWidgetManager::getInstance()->setTopWindow(gc);
1762 gc->updateCoords();
1763 gc->center();
1764 }// impulseTeamShareOpen //
1766 //-----------------------------------------------
1767 // impulseTeamShareInvalid
1768 // invalidate the player validation. If someone has choosen an item/phrase after the player has validated
1769 // the player receive this message to let him know that the chance percentage to obtain a specific item has
1770 // changed and so the player can update its own settings to fit better to what he wants.
1771 // On the client side we have just to show the valid button. All the resets are done on the server side.
1772 //-----------------------------------------------
1773 void impulseTeamShareInvalid(NLMISC::CBitMemStream &impulse)
1775 if (PermanentlyBanned) return;
1776 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1777 CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share:content:ok"));
1778 if (pTB != NULL)
1779 pTB->setActive(true);
1780 }// impulseTeamShareInvalid //
1782 //-----------------------------------------------
1783 // impulseTeamShareClose
1784 // The server wants to close the team sharing interface (if the sharing has been validated or other reasons)
1785 //-----------------------------------------------
1786 void impulseTeamShareClose(NLMISC::CBitMemStream &impulse)
1788 if (PermanentlyBanned) return;
1789 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1790 CGroupContainer
1791 *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share"));
1792 if (pGC != NULL)
1793 pGC->setActive(false);
1794 CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share:content:ok"));
1795 if (pTB != NULL)
1796 pTB->setActive(true);
1797 }// impulseTeamShareClose //
1799 //-----------------------------------------------
1800 // impulseTeamContactInit
1801 // initialize friend list and ignore list from the contact list
1802 //-----------------------------------------------
1803 void impulseTeamContactInit(NLMISC::CBitMemStream &impulse)
1805 vector<uint32> vFriendListName;
1806 vector<TCharConnectionState> vFriendListOnline;
1807 vector<ucstring> vIgnoreListName; // TODO: UTF-8 (serial)
1809 impulse.serialCont(vFriendListName);
1810 uint32 nbState;
1811 impulse.serial(nbState);
1812 vFriendListOnline.resize(nbState);
1813 for (uint i=0; i<nbState; ++i)
1815 impulse.serialShortEnum(vFriendListOnline[i]);
1817 // impulse.serialCont(vFriendListOnline);
1818 impulse.serialCont(vIgnoreListName);
1820 if (PermanentlyBanned) return;
1822 //nlinfo("impulseCallback : Received TEAM:CONTACT_INIT nbfriend:%d nbignore:%d", vFriendListName.size(), vIgnoreListName.size());
1824 PeopleInterraction.initContactLists(vFriendListName, vFriendListOnline, vIgnoreListName);
1825 }// impulseTeamContactInit //
1827 //-----------------------------------------------
1828 // impulseTeamContactCreate
1829 // create one character from the friend or ignore list
1830 //-----------------------------------------------
1831 void impulseTeamContactCreate(NLMISC::CBitMemStream &impulse)
1833 uint32 contactId;
1834 uint32 nameId;
1835 TCharConnectionState online = ccs_offline;
1836 uint8 nList;
1838 impulse.serial(contactId);
1839 impulse.serial(nameId);
1840 impulse.serialShortEnum(online);
1841 impulse.serial(nList);
1843 // client patch to resolve bad server response when requesting ignore list contact creation
1844 if (nList == 1) // ignore list
1846 // prevent adding an empty player to ignore list
1847 if (nameId == 0) return;
1850 if (PermanentlyBanned) return;
1852 //nlinfo("impulseCallback : Received TEAM:CONTACT_CREATE %d %d %s %d", contactId, nameId, online?"true":"false", nList);
1854 PeopleInterraction.addContactInList(contactId, nameId, online, nList);
1856 }// impulseTeamContactStatus //
1858 //-----------------------------------------------
1859 // impulseTeamContactStatus
1860 // update one of the character from the friend list
1861 //-----------------------------------------------
1862 void impulseTeamContactStatus(NLMISC::CBitMemStream &impulse)
1864 uint32 contactId;
1865 TCharConnectionState online = ccs_offline;
1867 impulse.serial(contactId);
1868 impulse.serialShortEnum(online);
1870 if (PermanentlyBanned) return;
1872 //nlinfo("impulseCallback : Received TEAM:CONTACT_STATUS %d %s", contactId, online == ccs_online ?"online": online==ccs_offline?"offline" : "foreign_online");
1874 // 0<=FriendList (actually ignore list does not show online state)
1875 PeopleInterraction.updateContactInList(contactId, online, 0);
1877 // Resort the contact list if needed
1878 CInterfaceManager* pIM= CInterfaceManager::getInstance();
1879 CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
1881 if (order == CPeopleList::sort_online)
1883 PeopleInterraction.FriendList.sortEx(order);
1885 }// impulseTeamContactStatus //
1888 //-----------------------------------------------
1889 // impulseTeamContactRemove
1890 // Remove a contact by the server
1891 //-----------------------------------------------
1892 void impulseTeamContactRemove(NLMISC::CBitMemStream &impulse)
1894 uint32 contactId;
1895 uint8 nList;
1897 impulse.serial(contactId);
1898 impulse.serial(nList);
1900 if (PermanentlyBanned) return;
1902 //nlinfo("impulseCallback : Received TEAM:CONTACT_REMOVE %d %d", contactId, nList);
1904 PeopleInterraction.removeContactFromList(contactId, nList);
1906 }// impulseTeamContactRemove //
1909 //-----------------------------------------------
1910 // servers sets information of a guild member:
1911 // u16 ( member index ) u32 (player name ), u8 ( player grade + last bit set if player online ).
1912 //-----------------------------------------------
1913 /*void impulseGuildSetMemberInfo(NLMISC::CBitMemStream &impulse)
1915 uint16 index;
1916 impulse.serial(index);
1917 uint32 guildMemberName;
1918 impulse.serial(guildMemberName);
1919 uint8 grade;
1920 impulse.serial(grade);
1921 bool online = ((grade&0x80) != 0);
1922 grade = (grade & 0x7F);
1923 CGuildManager::getInstance()->set(index, guildMemberName, grade, online);
1926 //-----------------------------------------------
1927 // vector of pair( u32 (player name ), u8 ( player grade + last bit set if player online ) )
1928 //-----------------------------------------------
1929 /*void impulseGuildInitMemberInfo(NLMISC::CBitMemStream &impulse)
1931 vector < pair < uint32, uint8 > > AllMembers;
1932 uint16 nbEntries;
1933 impulse.serial(nbEntries);
1934 AllMembers.resize(nbEntries);
1935 for (uint32 i = 0; i < nbEntries; ++i)
1937 uint32 name;
1938 impulse.serial(name);
1939 uint8 gradeNonline;
1940 impulse.serial(gradeNonline);
1941 AllMembers[i].first = name;
1942 AllMembers[i].second = gradeNonline;
1945 CGuildManager::getInstance()->init(AllMembers);
1949 //-----------------------------------------------
1950 // impulseGuildInvitation
1951 //-----------------------------------------------
1952 /*void impulseGuildInvitation(NLMISC::CBitMemStream &impulse)
1954 nlinfo("impulseGuildInvitation");
1958 //-----------------------------------------------
1959 // impulseGuildJoinProposal
1960 // server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
1961 //-----------------------------------------------
1962 void impulseGuildJoinProposal(NLMISC::CBitMemStream &impulse)
1965 uint32 phraseID;
1966 impulse.serial(phraseID);
1968 if (PermanentlyBanned) return;
1970 //nlinfo("impulseCallback : Received GUILD:JOIN_PROPOSAL %d", phraseID);
1972 CGuildManager::getInstance()->launchJoinProposal(phraseID);
1973 /*//activate the pop up window
1974 CInterfaceManager *im = CInterfaceManager::getInstance();
1975 CGroupContainer *gc = dynamic_cast<CGroupContainer *>( CWidgetManager::getInstance()->getElementFromId("ui:interface:join_guild_proposal"));
1976 if (!gc) return;
1977 CViewText *vt = dynamic_cast<CViewText*>(gc->getView("invitor_name"));
1978 if (vt == NULL) return;
1979 vt->setText(invitor);
1980 gc->setActive(true);
1981 CWidgetManager::getInstance()->setTopWindow(gc);
1982 gc->updateCoords();
1983 gc->center();
1984 gc->enableBlink(2);*/
1985 }// impulseGuildJoinProposal //
1988 //-----------------------------------------------
1989 // impulseCloseTempInv
1990 //-----------------------------------------------
1991 void impulseCloseTempInv(NLMISC::CBitMemStream &impulse)
1993 CTempInvManager::getInstance()->close();
1996 //-----------------------------------------------
1997 // impulseAscencorTeleport
1998 //-----------------------------------------------
1999 void impulseAscencorTeleport(NLMISC::CBitMemStream &impulse)
2002 } // impulseAscencorTeleport //
2004 //-----------------------------------------------
2005 // impulseEnterCrZoneProposal
2006 // server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
2007 //-----------------------------------------------
2008 void impulseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
2010 uint32 phraseID;
2011 impulse.serial(phraseID);
2012 if (PermanentlyBanned) return;
2014 //nlinfo("impulseCallback : Received MISSION:ASK_ENTER_CRITICAL %d", phraseID);
2016 //activate the pop up window
2017 CInterfaceManager *im = CInterfaceManager::getInstance();
2018 CGroupContainer *gc = dynamic_cast<CGroupContainer *>( CWidgetManager::getInstance()->getElementFromId("ui:interface:enter_crzone_proposal"));
2019 if (!gc) return;
2020 CViewTextID *vti = dynamic_cast<CViewTextID *>(gc->getView("phrase"));
2021 if (!vti) return;
2022 vti->setTextId(phraseID);
2023 gc->setActive(true);
2024 CWidgetManager::getInstance()->setTopWindow(gc);
2025 gc->updateCoords();
2026 gc->center();
2027 gc->enableBlink(2);
2028 }// impulseEnterCrZoneProposal //
2030 //-----------------------------------------------
2031 // impulseCloseEnterCrZoneProposal
2032 // server close proposal interface
2033 //-----------------------------------------------
2034 void impulseCloseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
2036 // hide interface
2037 CInterfaceManager* pIM = CInterfaceManager::getInstance();
2038 CInterfaceGroup *pIG = (CInterfaceGroup*)CWidgetManager::getInstance()->getElementFromId ("ui:interface:enter_crzone_proposal");
2039 if(pIG)
2040 pIG->setActive(false);
2041 }// impulseCloseEnterCrZoneProposal //
2044 //-----------------------------------------------
2045 // impulseExchangeInvitation :
2046 //-----------------------------------------------
2047 void impulseExchangeInvitation(NLMISC::CBitMemStream &impulse)
2049 uint32 textID;
2050 impulse.serial(textID);
2051 if (PermanentlyBanned) return;
2052 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
2054 // show the modal window that allow the player to accept / decline the invitation
2055 CGroupContainer *wnd = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
2056 if (wnd)
2058 wnd->setActive(true);
2059 wnd->updateCoords();
2060 wnd->center();
2061 wnd->enableBlink(2);
2062 CWidgetManager::getInstance()->setTopWindow(wnd);
2065 CViewTextID *vti = dynamic_cast<CViewTextID *>(wnd->getView("invite_phrase"));
2066 if (vti)
2068 vti->setTextId(textID);
2071 }// impulseExchangeInvitation //
2073 //-----------------------------------------------
2074 // impulseExchangeCloseInvitation :
2075 //-----------------------------------------------
2076 void impulseExchangeCloseInvitation(NLMISC::CBitMemStream &impulse)
2078 if (PermanentlyBanned) return;
2079 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
2080 // hide the modal window that allow the player to accept / decline the invitation
2081 CInterfaceGroup *wnd = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
2082 if (wnd) wnd->setActive(false);
2085 //-----------------------------------------------
2086 // impulseMountAbort :
2087 //-----------------------------------------------
2088 void impulseMountAbort(NLMISC::CBitMemStream &impulse)
2090 nlwarning("impulseMountAbort: Received ANIMALS:MOUNT_ABORT => no more used");
2091 }// impulseMountAbort //
2093 //-----------------------------------------------
2094 // impulseRyzomTime :
2095 // Synchronize the ryzom time with the server.
2096 //-----------------------------------------------
2098 void impulseRyzomTime(NLMISC::CBitMemStream &impulse)
2100 nlinfo("impulseRyzomTime: Ryzom Time Received");
2101 uint32 serverTick;
2102 float ryzomTime;
2103 uint32 ryzomDay;
2104 impulse.serial(serverTick);
2105 impulse.serial(ryzomTime);
2106 impulse.serial(ryzomDay);
2107 nlinfo("impulseRyzomTime: Day '%d' Time '%f'.", ryzomDay, ryzomTime);
2109 // Initialize
2110 RT.setOrigin( serverTick, ryzomDay, ryzomTime );
2111 }// impulseRyzomTime //
2113 //-----------------------------------------------
2114 // impulseWhere :
2115 // Display server position
2116 //-----------------------------------------------
2117 void impulseWhere(NLMISC::CBitMemStream &impulse)
2119 //nlinfo("impulseCallback : Received DEBUG:REPLY_WHERE");
2121 sint32 x,y,z;
2122 impulse.serial(x);
2123 impulse.serial(y);
2124 impulse.serial(z);
2125 if (PermanentlyBanned) return;
2126 char buf[128];
2128 double xf = ((double)x)/1000.0f;
2129 double yf = ((double)y)/1000.0f;
2130 double zf = ((double)z)/1000.0f;
2132 sprintf(buf,"Your server position is : X= %g Y= %g Z= %g",xf,yf,zf);
2133 nlinfo(buf);
2134 CInterfaceManager::getInstance()->displaySystemInfo(buf);
2135 }// impulseWhere //
2137 //-----------------------------------------------
2138 // impulseWho :
2139 // Display server position
2140 //-----------------------------------------------
2142 void impulseWho(NLMISC::CBitMemStream &impulse)
2144 nlinfo("impulseWho Received");
2145 CInterfaceManager::getInstance()->displaySystemInfo("Players currently in the game :");
2147 ucstring name; // OLD
2148 uint32 loginId;
2149 uint16 dist;
2150 uint8 dirshort;
2151 string str;
2152 while( impulse.getPos() < (sint32)impulse.length() )
2154 impulse.serial(name);
2155 impulse.serial(loginId);
2156 impulse.serial(dist);
2157 impulse.serial(dirshort);
2159 double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
2160 angle -= NLMISC::Pi;
2161 nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
2162 sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
2163 direction = ((direction%16)+16)%16;
2164 static const string txts[]=
2166 "uiW",
2167 "uiWSW",
2168 "uiSW",
2169 "uiSSW",
2170 "uiS",
2171 "uiSSE",
2172 "uiSE",
2173 "uiESE",
2174 "uiE",
2175 "uiENE",
2176 "uiNE",
2177 "uiNNE",
2178 "uiN",
2179 "uiNNW",
2180 "uiNW",
2181 "uiWNW",
2184 str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
2185 CInterfaceManager::getInstance()->displaySystemInfo(name + str + CI18N::get(txts[direction]));
2187 }// impulseWho //
2191 void impulseWhoGM(NLMISC::CBitMemStream &impulse)
2193 nlinfo("impulseWhoGM Received");
2194 CInterfaceManager::getInstance()->displaySystemInfo("Players currently in the game :");
2196 ucstring name; // OLD
2197 uint32 loginId;
2198 uint16 dist;
2199 uint8 dirshort;
2200 string str;
2201 while( impulse.getPos() < (sint32)impulse.length() )
2203 impulse.serial(name);
2204 impulse.serial(loginId);
2205 impulse.serial(dist);
2206 impulse.serial(dirshort);
2208 double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
2209 angle -= NLMISC::Pi;
2210 nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
2211 sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
2212 direction = ((direction%16)+16)%16;
2213 static const string txts[]=
2215 "uiW",
2216 "uiWSW",
2217 "uiSW",
2218 "uiSSW",
2219 "uiS",
2220 "uiSSE",
2221 "uiSE",
2222 "uiESE",
2223 "uiE",
2224 "uiENE",
2225 "uiNE",
2226 "uiNNE",
2227 "uiN",
2228 "uiNNW",
2229 "uiNW",
2230 "uiWNW",
2233 str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
2234 CInterfaceManager::getInstance()->displaySystemInfo(name + str + CI18N::get(txts[direction]));
2236 }// impulseWho //
2238 //-----------------------------------------------
2239 // impulseCounter :
2240 // check UDP validity
2241 //-----------------------------------------------
2242 void impulseCounter(NLMISC::CBitMemStream &impulse)
2244 //nlinfo("impulseCallBack : Received DEBUG:COUNTER");
2247 uint32 counter;
2248 impulse.serial(counter);
2250 static uint queueTop = 0;
2251 static deque<bool> queue;
2253 if (counter > queueTop)
2255 queue.resize(queue.size()+counter-queueTop, false);
2256 queueTop = counter;
2259 if (queueTop-counter+1 > queue.size())
2261 nlinfo("COUNTER: counter %d arrived too late...", counter);
2263 else
2265 if (queue[queue.size()-1-(queueTop-counter)])
2267 nlwarning("COUNTER: Received counter %d more than once !", counter);
2269 else
2271 nldebug("COUNTER: set counter %d", counter);
2272 queue[queue.size()-1-(queueTop-counter)] = true;
2275 while (queue.size() > 128)
2277 if (!queue.front())
2279 nlwarning("COUNTER: counter %d not received !", queueTop-queue.size()-1);
2282 queue.pop_front();
2286 catch (const Exception &e)
2288 nlwarning ("Problem while decoding a COUTNER msg, skipped: %s", e.what());
2292 //-----------------------------------------------
2293 // impulsePhraseSend :
2294 // A dyn string (or phrase) is send (so, we receive it)
2295 //-----------------------------------------------
2296 void impulsePhraseSend(NLMISC::CBitMemStream &impulse)
2298 STRING_MANAGER::CStringManagerClient::instance()->receiveDynString(impulse);
2301 //-----------------------------------------------
2302 // impulseStringResp :
2303 // Update the local string set
2304 //-----------------------------------------------
2305 void impulseStringResp(NLMISC::CBitMemStream &impulse)
2307 uint32 stringId;
2308 string str;
2309 impulse.serial(stringId);
2310 impulse.serial(str);
2312 if (PermanentlyBanned) return;
2314 STRING_MANAGER::CStringManagerClient::instance()->receiveString(stringId, str);
2317 //-----------------------------------------------
2318 // impulseReloadCache :
2319 // reload the string cache
2320 //-----------------------------------------------
2321 void impulseReloadCache(NLMISC::CBitMemStream &impulse)
2323 uint32 timestamp;;
2324 impulse.serial(timestamp);
2325 if (PermanentlyBanned) return;
2326 STRING_MANAGER::CStringManagerClient::instance()->loadCache(timestamp);
2329 //-----------------------------------------------
2330 // impulseBotChatEnd
2331 // ForceThe end of the bot chat
2332 //-----------------------------------------------
2333 void impulseBotChatForceEnd(NLMISC::CBitMemStream &impulse)
2335 if (PermanentlyBanned) return;
2336 CBotChatManager::getInstance()->setCurrPage(NULL);
2340 //-----------------------------------------------
2341 // MISSION COMPLETED JOURNAL
2342 //-----------------------------------------------
2344 #define MC_M_CONTAINER "ui:interface:info_player_journal"
2345 #define MC_S_CONTAINER "ui:interface:ipj_com_missions"
2346 #define MC_TEMPLATE "tipj_mission_complete"
2347 //-----------------------------------------------
2348 CGroupContainer *getMissionCompletedContainer()
2350 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2351 CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(MC_M_CONTAINER);
2352 CGroupContainer *pGCM = dynamic_cast<CGroupContainer*>(pIE);
2353 if (pGCM == NULL) return NULL;
2355 CGroupList *pList = pGCM->getList();
2356 CGroupContainer *pGCS = dynamic_cast<CGroupContainer*>(pList->getGroup(MC_S_CONTAINER));
2357 return pGCS;
2360 //-----------------------------------------------
2361 void clearMissions()
2363 CGroupContainer *pGCMC = getMissionCompletedContainer();
2364 CInterfaceGroup *pContent = pGCMC->getGroup("content");
2365 pContent->clearGroups();
2367 //-----------------------------------------------
2368 void addMission(uint32 titleID)
2370 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2371 CGroupContainer *pGCMC = getMissionCompletedContainer();
2372 if (pGCMC == NULL)
2374 nlwarning("cannot get container for missions completed");
2375 return;
2377 CInterfaceGroup *pContent = pGCMC->getGroup("content");
2379 uint32 nNbMission = pContent->getGroups().size();
2380 vector<pair<string, string> > vArgs;
2382 vArgs.push_back(pair<string,string>("id", "mc"+NLMISC::toString(nNbMission)));
2383 vArgs.push_back(pair<string,string>("mcid", NLMISC::toString(titleID)));
2385 if (nNbMission == 0)
2387 vArgs.push_back(pair<string,string>("posref", "TL TL"));
2388 vArgs.push_back(pair<string,string>("posparent", "parent"));
2389 vArgs.push_back(pair<string,string>("y", "0"));
2391 else
2393 vArgs.push_back(pair<string,string>("posref", "BL TL"));
2396 CInterfaceGroup *pIG = pIM->createGroupInstance(MC_TEMPLATE, pContent->getId(), vArgs);
2397 if (pIG == NULL)
2399 nlwarning("cannot create a mission completed");
2400 return;
2402 pIG->setParent(pContent);
2403 if (nNbMission == 0)
2404 pIG->setParentPos(pContent);
2405 else
2406 pIG->setParentPos(pContent->getGroups()[nNbMission-1]);
2407 pContent->addGroup(pIG);
2410 //-----------------------------------------------
2411 // impulseJournalInitCompletedMissions :
2412 // initialize the player journal missions for completed missions
2413 //-----------------------------------------------
2414 void impulseJournalInitCompletedMissions (NLMISC::CBitMemStream &impulse)
2417 vector<uint32> vMissionCompleted;
2418 impulse.serialCont(vMissionCompleted);
2420 clearMissions();
2422 for (uint32 i = 0; i < vMissionCompleted.size(); ++i)
2423 addMission (vMissionCompleted[i]);
2427 //-----------------------------------------------
2428 // impulseJournalInitCompletedMissions :
2429 // initialize the player journal missions for completed missions
2430 //-----------------------------------------------
2431 void impulseJournalUpdateCompletedMissions (NLMISC::CBitMemStream &impulse)
2434 uint32 nNewCompletedMission;
2435 impulse.serial(nNewCompletedMission);
2437 addMission (nNewCompletedMission);
2442 //-----------------------------------------------
2443 // impulseJournalCantAbandon :
2444 // server refuses mission abandon
2445 //-----------------------------------------------
2446 void impulseJournalCantAbandon (NLMISC::CBitMemStream &impulse)
2448 if (PermanentlyBanned) return;
2449 /// reactivate abandon button
2450 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:MISSION_ABANDON_BUTTON",false);
2451 if (pNL != NULL)
2452 pNL->setValue64(1);
2457 //-----------------------------------------------
2458 // server add a compass target
2459 //-----------------------------------------------
2460 void impulseJournalAddCompass(NLMISC::CBitMemStream &impulse)
2462 sint32 x;
2463 sint32 y;
2464 uint32 text;
2465 impulse.serial(x);
2466 impulse.serial(y);
2467 impulse.serial(text);
2468 if (PermanentlyBanned) return;
2469 //nlinfo("impulseCallback : Received JOURNAL:ADD_COMPASS %d %d %d", x, y, text);
2470 CCompassDialogsManager::getInstance().addEntry( x,y,text );
2473 //-----------------------------------------------
2474 // server removes a compass target
2475 //-----------------------------------------------
2476 void impulseJournalRemoveCompass(NLMISC::CBitMemStream &impulse)
2478 uint32 text;
2479 impulse.serial(text);
2480 if (PermanentlyBanned) return;
2481 //nlinfo("impulseCallback : Received JOURNAL:REMOVE_COMPASS %d", text);
2482 CCompassDialogsManager::getInstance().removeEntry( text );
2488 // the server ask me to execute a command
2490 void impulseRemoteAdmin (NLMISC::CBitMemStream &impulse)
2492 CLog logDisplayVars;
2493 CLightMemDisplayer mdDisplayVars;
2494 logDisplayVars.addDisplayer (&mdDisplayVars);
2495 mdDisplayVars.setParam (10);
2497 uint32 rid;
2498 impulse.serial (rid);
2499 string cmd;
2500 impulse.serial (cmd);
2502 // remove the 2 first rc character if exists, only there to say to the EGS that is a remote command
2503 if (cmd.size()>2 && tolower(cmd[0])=='r' && tolower(cmd[1])=='c') // FIXME: toLowerAscii
2504 cmd = cmd.substr(2);
2506 mdDisplayVars.clear ();
2507 ICommand::execute(cmd, logDisplayVars, !ICommand::isCommand(cmd));
2508 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
2510 string str;
2511 if (ICommand::isCommand(cmd))
2513 for (uint k = 0; k < strs.size(); k++)
2515 str += strs[k];
2518 else
2520 if (!strs.empty())
2522 str = strs[0].substr(0,strs[0].size()-1);
2523 // replace all spaces into underscore because space is a reserved char
2524 for (uint i = 0; i < str.size(); i++) if (str[i] == ' ') str[i] = '_';
2526 else
2528 str = "???";
2531 mdDisplayVars.unlockStrings();
2533 //nlinfo("impulseCallback : Received COMMAND:REMOTE_ADMIN : Server asked me to execute '%s', result is '%s'", cmd.c_str(), str.c_str());
2535 CBitMemStream out;
2536 if(GenericMsgHeaderMngr.pushNameToStream("COMMAND:REMOTE_ADMIN_ANSWER", out))
2538 out.serial (rid);
2539 out.serial (cmd);
2540 out.serial (str);
2541 NetMngr.push (out);
2542 //nlinfo("impulseCallback : COMMAND:REMOTE_ADMIN_ANSWER %d %s %s sent", rid, cmd.c_str(), str.c_str());
2547 //-----------------------------------------------
2548 // impulseGuildAscensor :
2549 // server request that the client launch the ascensor interface
2550 //-----------------------------------------------
2552 void impulseGuildAscensor (NLMISC::CBitMemStream &impulse)
2554 if (PermanentlyBanned) return;
2555 //nlinfo("impulseCallback : Received GUILD:ASCENSOR");
2556 CGuildManager::getInstance()->launchAscensor();
2559 //-----------------------------------------------
2560 //impulseGuildLeaveAscensor
2561 //-----------------------------------------------
2562 void impulseGuildLeaveAscensor (NLMISC::CBitMemStream &impulse)
2564 if (PermanentlyBanned) return;
2565 //nlinfo("impulseCallback : Received GUILD:LEAVE_ASCENSOR");
2566 CGuildManager::getInstance()->quitAscensor();
2569 //-----------------------------------------------
2570 //impulseGuildAbortCreation
2571 //-----------------------------------------------
2572 void impulseGuildAbortCreation (NLMISC::CBitMemStream &impulse)
2574 CBotChatPage *pPage = CBotChatManager::getInstance()->getCurrPage();
2575 CBotChatPageCreateGuild *pPageCG = dynamic_cast<CBotChatPageCreateGuild*>(pPage);
2576 if (pPageCG == BotChatPageAll->CreateGuild)
2577 CBotChatManager::getInstance()->setCurrPage(NULL);
2580 void impulseGuildOpenGuildWindow(NLMISC::CBitMemStream &impulse)
2582 CGuildManager::getInstance()->openGuildWindow();
2586 //-----------------------------------------------
2587 // impulseGuildOpenInventory
2588 //-----------------------------------------------
2589 void impulseGuildOpenInventory (NLMISC::CBitMemStream &impulse)
2591 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2592 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(1);
2595 //-----------------------------------------------
2596 // impulseGuildCloseInventory
2597 //-----------------------------------------------
2598 void impulseGuildCloseInventory (NLMISC::CBitMemStream &impulse)
2600 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2601 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(0);
2604 //-----------------------------------------------
2605 // impulseGuildUpdatePlayerTitle
2606 // server block/unblock some reserved titles
2607 //-----------------------------------------------
2608 void impulseGuildUpdatePlayerTitle(NLMISC::CBitMemStream &impulse)
2610 CSkillManager *pSM = CSkillManager::getInstance();
2611 bool bUnblock;
2612 impulse.serial(bUnblock);
2613 vector<uint16> vTitles;
2614 impulse.serialCont(vTitles);
2615 if (PermanentlyBanned) return;
2616 if (bUnblock)
2618 for (uint32 i = 0; i < vTitles.size(); ++i)
2619 pSM->unblockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
2621 else
2623 for (uint32 i = 0; i < vTitles.size(); ++i)
2624 pSM->blockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
2628 //-----------------------------------------------
2629 // impulseGuildUseFemaleTitles
2630 // server activates/deactivates use of female titles
2631 //-----------------------------------------------
2632 void impulseGuildUseFemaleTitles(NLMISC::CBitMemStream &impulse)
2634 impulse.serial( UseFemaleTitles );
2637 //-----------------------------------------------
2638 // impulsePhraseDownLoad
2639 // server upload the phrases.
2640 //-----------------------------------------------
2641 void impulsePhraseDownLoad (NLMISC::CBitMemStream &impulse)
2643 std::vector<CSPhraseSlot> phrases;
2645 // Read Known Phrases
2646 impulse.serialCont(phrases);
2647 CSPhraseManager *pPM= CSPhraseManager::getInstance();
2648 for(uint i=0;i<phrases.size();i++)
2650 if(phrases[i].PhraseSheetId != CSheetId::Unknown)
2652 CSPhraseCom phraseCom;
2653 pPM->buildPhraseFromSheet(phraseCom, phrases[i].PhraseSheetId.asInt());
2654 pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phraseCom);
2656 else
2658 pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phrases[i].Phrase);
2661 // must update the DB (NB: if initInGameDone) after all phrase set.
2662 pPM->updateBookDB();
2664 // Then Read Memorized Phrases
2665 std::vector<CSPhraseMemorySlot> memorizedPhrases;
2666 impulse.serialCont(memorizedPhrases);
2667 if (PermanentlyBanned) return;
2668 for(uint i=0;i<memorizedPhrases.size();i++)
2670 pPM->memorizePhrase(
2671 memorizedPhrases[i].MemoryLineId,
2672 memorizedPhrases[i].MemorySlotId,
2673 memorizedPhrases[i].PhraseId);
2676 // OK.
2677 extern bool SabrinaPhraseBookLoaded;
2678 SabrinaPhraseBookLoaded= true;
2680 // update gray state, if game inited.
2681 pPM->updateMemoryBar();
2684 //-----------------------------------------------
2685 // impulsePhraseConfirmBuy
2686 // server confirm/infirm the buy of botchat phrase.
2687 //-----------------------------------------------
2688 void impulsePhraseConfirmBuy (NLMISC::CBitMemStream &impulse)
2690 uint16 phraseId;
2691 bool confirm;
2693 impulse.serial(phraseId);
2694 impulse.serial(confirm);
2696 if (PermanentlyBanned) return;
2698 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2699 pSM->receiveBotChatConfirmBuy(phraseId, confirm);
2703 //-----------------------------------------------
2704 // impulsePhraseAckExecuteCyclic
2705 // server confirm/infirm the cyclic execution of a phrase
2706 //-----------------------------------------------
2707 void impulsePhraseAckExecuteCyclic (NLMISC::CBitMemStream &impulse)
2709 uint8 counter;
2710 bool ok;
2712 impulse.serial(ok);
2713 impulse.serial(counter);
2715 if (PermanentlyBanned) return;
2718 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2719 pSM->receiveAckExecuteFromServer(true, counter, ok);
2723 //-----------------------------------------------
2724 // impulsePhraseAckExecuteCyclic
2725 // server confirm/infirm the execution of a phrase
2726 //-----------------------------------------------
2727 void impulsePhraseAckExecuteNext (NLMISC::CBitMemStream &impulse)
2729 uint8 counter;
2730 bool ok;
2732 impulse.serial(ok);
2733 impulse.serial(counter);
2735 if (PermanentlyBanned) return;
2737 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2738 pSM->receiveAckExecuteFromServer(false, counter, ok);
2741 // Same params as in BOMB_IF
2742 #ifdef FINAL_VERSION
2743 #define SKIP_IF(condition,msg,skipAction) if (!(condition)); else skipAction;
2744 #else
2745 #define SKIP_IF(condition,msg,skipAction) if (!(condition)) WARN(msg); else skipAction;
2746 #endif
2748 template <class CInventoryCategoryTemplate>
2749 void updateInventoryFromStream (NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges)
2753 // get the egs tick of this change
2754 TGameCycle serverTick;
2755 impulse.serial(serverTick);
2757 // For All inventories
2758 for ( uint invId=0; invId!=CInventoryCategoryTemplate::NbInventoryIds; ++invId )
2760 // Presence bit
2761 bool hasContent;
2762 impulse.serialBit( hasContent );
2763 if ( ! hasContent )
2764 continue;
2766 // Number field
2767 uint32 nbChanges;
2768 impulse.serial( nbChanges, INVENTORIES::LowNumberBits );
2769 if ( nbChanges == INVENTORIES::LowNumberBound )
2770 impulse.serial( nbChanges, 32 );
2772 const string invBranchStr = CInventoryCategoryTemplate::getDbStr( (typename CInventoryCategoryTemplate::TInventoryId)invId );
2773 ICDBNode::CTextId textId( invBranchStr );
2774 ICDBNode *inventoryNode = IngameDbMngr.getNodePtr()->getNode( textId, false );
2775 BOMB_IF(!inventoryNode, "Inventory missing in database", return);
2777 // List of updates
2778 for ( uint c=0; c!=nbChanges; ++c )
2780 // Unpack (the bitmemstream is written from high-order to low-order)
2781 uint32 iuInfoVersion;
2782 impulse.serial( iuInfoVersion, 1 );
2783 if ( iuInfoVersion == 1 )
2785 uint32 slotIndex;
2786 impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
2788 // Access the database leaf
2789 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
2790 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( INVENTORIES::InfoVersionStr ));
2791 BOMB_IF( !leafNode, "Inventory slot property missing in database", continue );
2793 // Apply or increment Info Version in database
2794 if ( CInventoryCategoryTemplate::needPlainInfoVersionTransfer() )
2796 uint32 infoVersion;
2797 impulse.serial( infoVersion, INVENTORIES::InfoVersionBitSize );
2798 leafNode->setPropCheckGC( serverTick, infoVersion );
2800 else
2802 // NB: don't need to check GC on a info version upgrade, since this is always a delta of +1
2803 // the order of received of this impulse is not important
2804 leafNode->setValue64( leafNode->getValue64() + 1 );
2808 else
2810 uint32 iuAll;
2811 impulse.serial( iuAll, 1 );
2812 if ( iuAll == 1 )
2814 INVENTORIES::CItemSlot itemSlot;
2815 itemSlot.serialAll( impulse, templ );
2816 //nldebug( "Inv %s Update %u", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex() );
2818 // Apply all properties to database
2819 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
2820 for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
2822 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
2823 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2824 leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getItemProp( ( INVENTORIES::TItemPropId)i ) );
2827 else
2829 uint32 iuOneProp;
2830 impulse.serial( iuOneProp, 1 );
2831 if ( iuOneProp == 1 )
2833 INVENTORIES::CItemSlot itemSlot;
2834 itemSlot.serialOneProp( impulse, templ );
2835 //nldebug( "Inv %s Prop %u %s", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex(), INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId] );
2837 // Apply property to database
2838 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
2839 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId]) ));
2840 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2841 leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getOneProp().ItemPropValue );
2844 else // iuReset
2846 uint32 slotIndex;
2847 impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
2848 //nldebug( "Inv %s Reset %u", CInventoryCategoryTemplate::InventoryStr[invId], slotIndex );
2850 // Reset all properties in database
2851 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
2852 for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
2854 // Instead of clearing all leaves (by index), we must find and clear only the
2855 // properties in TItemPropId, because the actual database leaves may have
2856 // less properties, and because we must not clear the leaf INFO_VERSION.
2857 // NOTE: For example, only player BAG inventory has WORNED leaf.
2858 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
2859 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2860 leafNode->setPropCheckGC( serverTick, 0 );
2868 CInventoryManager::getInstance()->sortBag();
2870 catch (const Exception &e)
2872 nlwarning ("Problem while decoding a DB_UPD_INV msg, skipped: %s", e.what());
2876 //-----------------------------------------------
2877 // impulseUpdateInventory:
2878 //-----------------------------------------------
2879 void impulseUpdateInventory (NLMISC::CBitMemStream &impulse)
2881 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForCharacter*)NULL, true );
2884 //-----------------------------------------------
2885 // impulseInitInventory:
2886 //-----------------------------------------------
2887 void impulseInitInventory (NLMISC::CBitMemStream &impulse)
2889 sint32 p = impulse.getPos();
2890 impulseUpdateInventory( impulse );
2891 IngameDbMngr.setInitPacketReceived();
2892 nlinfo( "DB_INIT:INV done (%u bytes)", impulse.getPos()-p );
2894 getInventory().onUpdateEquipHands();
2897 //-----------------------------------------------
2898 // impulseItemInfoSet:
2899 //-----------------------------------------------
2900 void impulseItemInfoSet (NLMISC::CBitMemStream &impulse)
2902 CItemInfos itemInfos;
2903 impulse.serial(itemInfos);
2905 getInventory().onReceiveItemInfo(itemInfos);
2908 //-----------------------------------------------
2909 // impulseItemInfoRefreshVersion:
2910 //-----------------------------------------------
2911 void impulseItemInfoRefreshVersion (NLMISC::CBitMemStream &impulse)
2913 uint16 slotId;
2914 uint8 infoVersion;
2915 impulse.serial(slotId);
2916 impulse.serial(infoVersion);
2918 getInventory().onRefreshItemInfoVersion(slotId, infoVersion);
2921 //-----------------------------------------------
2922 // impulsePrereqInfoSet:
2923 //-----------------------------------------------
2924 void impulsePrereqInfoSet (NLMISC::CBitMemStream &impulse)
2926 CPrerequisitInfos prereqInfos;
2927 uint8 index;
2928 impulse.serial(prereqInfos);
2929 impulse.serial(index);
2931 //write infos in interface
2932 CBotChatManager::getInstance()->onReceiveMissionInfo(index, prereqInfos);
2935 //-----------------------------------------------
2936 //-----------------------------------------------
2937 void impulseDeathRespawnPoint (NLMISC::CBitMemStream &impulse)
2939 CRespawnPointsMsg msg;
2940 impulse.serial(msg);
2941 if (PermanentlyBanned) return;
2942 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2943 CGroupMap *pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:respawn_map:content:map_content:actual_map"));
2944 if (pMap == NULL)
2946 nlwarning("problem cannot find ui:interface:respawn_map:content:map_content:actual_map");
2947 return;
2949 pMap->addRespawnPoints(msg);
2952 pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
2953 if (pMap == NULL)
2955 nlwarning("problem cannot find ui:interface:map:content:map_content:actual_map");
2956 return;
2958 pMap->addRespawnPoints(msg);
2961 //-----------------------------------------------
2962 //-----------------------------------------------
2963 void impulseDeathRespawn (NLMISC::CBitMemStream &impulse)
2965 // TODO : Bring me to life !!!
2968 //-----------------------------------------------
2969 // impulseDuelInvitation :
2970 //-----------------------------------------------
2971 void impulseDuelInvitation(NLMISC::CBitMemStream &impulse)
2973 uint32 textID;
2974 impulse.serial(textID);
2976 //nlinfo("impulseCallback : Received DUEL:INVITATION %d", textID);
2978 if (PermanentlyBanned) return;
2980 //activate the pop up window
2981 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2982 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_duel_proposal"));
2983 if (pGC == NULL) return;
2984 CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
2985 if (pVTID == NULL) return;
2986 pVTID->setTextId(textID);
2987 pGC->setActive(true);
2988 CWidgetManager::getInstance()->setTopWindow(pGC);
2989 pGC->updateCoords();
2990 pGC->center();
2991 pGC->enableBlink(2);
2993 }// impulseDuelInvitation //
2995 //-----------------------------------------------
2996 // impulseDuelCancelInvitation:
2997 //-----------------------------------------------
2998 void impulseDuelCancelInvitation(NLMISC::CBitMemStream &impulse)
3000 if (PermanentlyBanned) return;
3001 //nlinfo("impulseCallback : Received DUEL:CANCEL_INVITATION");
3003 //activate the pop up window
3004 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3005 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_duel_proposal"));
3006 if (pGC == NULL) return;
3007 pGC->setActive(false);
3009 }// impulseDuelCancelInvitation //
3011 //-----------------------------------------------
3012 // impulsePVPChallengeInvitation :
3013 //-----------------------------------------------
3014 void impulsePVPChallengeInvitation(NLMISC::CBitMemStream &impulse)
3016 uint32 textID;
3017 impulse.serial(textID);
3019 if (PermanentlyBanned) return;
3021 //nlinfo("impulseCallback : Received PVP_CHALLENGE:INVITATION %d", textID);
3023 //activate the pop up window
3024 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3025 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
3026 if (pGC == NULL) return;
3027 CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
3028 if (pVTID == NULL) return;
3029 pVTID->setTextId(textID);
3030 pGC->setActive(true);
3031 CWidgetManager::getInstance()->setTopWindow(pGC);
3032 pGC->updateCoords();
3033 pGC->center();
3034 pGC->enableBlink(2);
3036 }// impulsePVPChallengeInvitation //
3038 //-----------------------------------------------
3039 // impulsePVPChallengeCancelInvitation:
3040 //-----------------------------------------------
3041 void impulsePVPChallengeCancelInvitation(NLMISC::CBitMemStream &impulse)
3043 //nlinfo("impulseCallback : Received PVP_CHALLENGE:CANCEL_INVITATION");
3045 //activate the pop up window
3046 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3047 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
3048 if (pGC == NULL) return;
3049 pGC->setActive(false);
3051 }// impulsePVPChallengeCancelInvitation //
3055 //-----------------------------------------------
3056 // impulsePVPFactionPushFactionWar:
3057 //-----------------------------------------------
3058 void impulsePVPFactionPushFactionWar(NLMISC::CBitMemStream &impulse)
3060 //nlinfo("impulseCallback : Received PVP_FACTION:PUSH_FACTION_WAR");
3062 PVP_CLAN::CFactionWar factionWar;
3063 impulse.serialEnum(factionWar.Clan1);
3064 impulse.serialEnum(factionWar.Clan2);
3066 CFactionWarManager::getInstance()->addFactionWar(factionWar);
3070 //-----------------------------------------------
3071 // impulsePVPFactionPopFactionWar:
3072 //-----------------------------------------------
3073 void impulsePVPFactionPopFactionWar(NLMISC::CBitMemStream &impulse)
3075 //nlinfo("impulseCallback : Received PVP_FACTION:POP_FACTION_WAR");
3077 PVP_CLAN::CFactionWar factionWar;
3078 impulse.serialEnum(factionWar.Clan1);
3079 impulse.serialEnum(factionWar.Clan2);
3081 CFactionWarManager::getInstance()->stopFactionWar(factionWar);
3085 //-----------------------------------------------
3086 // impulsePVPFactionFactionWars:
3087 //-----------------------------------------------
3088 void impulsePVPFactionFactionWars(NLMISC::CBitMemStream &impulse)
3090 //nlinfo("impulseCallback : Received PVP_FACTION:FACTION_WARS");
3092 CFactionWarsMsg factionWars;
3093 impulse.serial(factionWars);
3095 for( uint i=0; i<factionWars.FactionWarOccurs.size(); ++i )
3097 CFactionWarManager::getInstance()->addFactionWar(factionWars.FactionWarOccurs[i]);
3103 //-----------------------------------------------
3104 // impulsePVPChooseClan
3105 //-----------------------------------------------
3107 void impulsePVPChooseClan(NLMISC::CBitMemStream &impulse)
3109 nlinfo("impulsePVPChooseClan : Received PVP_CLAN:CHOOSE_CLAN");
3111 EGSPD::CPeople::TPeople clan1= EGSPD::CPeople::Unknown, clan2= EGSPD::CPeople::Unknown;
3112 impulse.serialEnum( clan1 );
3113 impulse.serialEnum( clan2 );
3115 if (PermanentlyBanned) return;
3117 //activate the pop up window
3118 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3119 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal"));
3120 if (pGC == NULL) return;
3121 pGC->setActive(true);
3123 CCtrlTextButton * butClan1 = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan1"));
3124 if( butClan1 == NULL )
3125 return;
3126 butClan1->setText( EGSPD::CPeople::toString( clan1 ) );
3128 CCtrlTextButton * butClan2 = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan2"));
3129 if( butClan2 == NULL )
3130 return;
3131 butClan2->setText( EGSPD::CPeople::toString( clan2 ) );
3135 //-----------------------------------------------
3136 // impulseEncyclopediaUpdate
3137 //-----------------------------------------------
3138 void impulseEncyclopediaUpdate(NLMISC::CBitMemStream &impulse)
3140 //nlinfo("impulseCallback : Received ENCYCLOPEDIA:UPDATE");
3142 CEncyclopediaUpdateMsg msg;
3143 impulse.serial(msg);
3144 if (PermanentlyBanned) return;
3145 CEncyclopediaManager::getInstance()->update(msg);
3146 }// impulseEncyclopediaUpdate //
3148 //-----------------------------------------------
3149 // impulseEncyclopediaInit
3150 //-----------------------------------------------
3151 void impulseEncyclopediaInit(NLMISC::CBitMemStream &impulse)
3153 //nlinfo("impulseCallback : Received ENCYCLOPEDIA:INIT");
3155 CEncyclopediaUpdateMsg msg;
3156 impulse.serial(msg);
3157 if (PermanentlyBanned) return;
3158 CEncyclopediaManager::getInstance()->update(msg);
3159 }// impulseEncyclopediaInit //
3161 //-----------------------------------------------
3162 //-----------------------------------------------
3163 void impulseItemOpenRoomInventory(NLMISC::CBitMemStream &impulse)
3165 if (PermanentlyBanned) return;
3166 // This is a message because we may do other things there
3167 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3168 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(1);
3171 //-----------------------------------------------
3172 //-----------------------------------------------
3173 void impulseItemCloseRoomInventory(NLMISC::CBitMemStream &impulse)
3175 if (PermanentlyBanned) return;
3176 // This is a message because we may do other things there
3177 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3178 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(0);
3180 // deactivate the pop up window
3181 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:inv_room"));
3182 if (pGC == NULL) return;
3183 pGC->setActive(false);
3186 //-----------------------------------------------
3187 //-----------------------------------------------
3188 void impulseUserBars(NLMISC::CBitMemStream &impulse)
3190 uint8 msgNumber;
3191 sint32 hp, sap, sta, focus;
3192 impulse.serial(msgNumber);
3193 impulse.serial(hp);
3194 impulse.serial(sap);
3195 impulse.serial(sta);
3196 impulse.serial(focus);
3198 if (PermanentlyBanned) return;
3200 // Setup the user Bars
3201 CBarManager::CBarInfo bi;
3202 CBarManager::getInstance()->setupUserBarInfo(msgNumber, hp, sap, sta, focus);
3205 //-----------------------------------------------
3206 //-----------------------------------------------
3207 void impulseOutpostChooseSide(NLMISC::CBitMemStream &impulse)
3209 // read message
3210 uint8 type;
3211 bool outpostInFire;
3212 bool playerGuildInConflict;
3213 bool playerGuildIsAttacker;
3214 impulse.serial(type);
3215 impulse.serial(outpostInFire);
3216 impulse.serial(playerGuildInConflict);
3217 impulse.serial(playerGuildIsAttacker);
3218 uint32 ownerGuildNameId;
3219 impulse.serial( ownerGuildNameId );
3220 uint32 attackerGuildNameId;
3221 impulse.serial( attackerGuildNameId );
3222 uint32 declTimer;
3223 impulse.serial( declTimer );
3225 // start
3226 OutpostManager.startPvpJoinProposal((OUTPOSTENUMS::TPVPType)type, outpostInFire, playerGuildInConflict, playerGuildIsAttacker,
3227 ownerGuildNameId, attackerGuildNameId, declTimer);
3230 //-----------------------------------------------
3231 //-----------------------------------------------
3232 void impulseOutpostDeclareWarAck(NLMISC::CBitMemStream &impulse)
3234 bool canValidate;
3235 uint32 docTextId;
3236 uint32 timeStartAttack;
3238 impulse.serial(canValidate);
3239 impulse.serial(docTextId);
3240 impulse.serial(timeStartAttack);
3242 // write result in Local DB.
3243 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3245 // ack reception
3246 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_RECEIVED");
3247 if(node)
3248 node->setValueBool(true);
3249 // set result of ACK
3250 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_OK");
3251 if(node)
3252 node->setValueBool(canValidate);
3253 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TEXTID");
3254 if(node)
3255 node->setValue32(docTextId);
3256 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TIME_RANGE_ATT");
3257 if(node)
3258 node->setValue32(timeStartAttack);
3261 extern void addWebIGParams(string &url, bool trustedDomain);
3263 //-----------------------------------------------
3264 //-----------------------------------------------
3265 class CServerMessageBoxOnReceiveTextId : public STRING_MANAGER::IStringWaitCallback
3267 private:
3268 enum TTextType {TitleType= 0, ContentType, NumTextType};
3269 uint32 _TextId[NumTextType];
3270 bool _TextReceived[NumTextType];
3271 bool _AlreadyDisplayed;
3273 // show the window
3274 void activateMsgBoxWindow()
3276 STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
3278 // get the content string (should have been received!)
3279 string contentStr;
3280 string titleStr;
3281 if(!pSMC->getDynString(_TextId[ContentType], contentStr))
3282 return;
3284 if(!pSMC->getDynString(_TextId[TitleType], titleStr))
3285 return;
3287 // if the string start with a @{Wxxxx} code, remove it and get the wanted window size
3288 sint w = 256; // default size to 256 !!
3289 bool is_webig = false;
3291 if(contentStr.size()>=6 && contentStr[0]=='W' && contentStr[1]=='E' && contentStr[2]=='B'
3292 && contentStr[3]==' ' && contentStr[4]==':' && contentStr[5]==' ' )
3294 uint i;
3295 const uint digitStart= 6;
3296 const uint digitMaxEnd= (uint)contentStr.size();
3298 is_webig = true;
3300 for(i = digitStart; i < digitMaxEnd; i++)
3302 if(contentStr[i] == ' ')
3303 break;
3305 if(i != digitMaxEnd)
3307 string web_app = contentStr.substr(digitStart, i-digitStart);
3308 contentStr = string(ClientCfg.WebIgMainDomain + "/") + web_app + string("/index.php?") + contentStr.substr((size_t)i + 1);
3310 else
3312 contentStr.clear();
3313 i = digitStart;
3316 else if(contentStr.size()>=5 && contentStr[0]=='@' && contentStr[1]=='{' && contentStr[2]=='W')
3318 uint i;
3319 const uint digitStart= 3;
3320 const uint digitMaxEnd= 8;
3321 for(i=digitStart;i<contentStr.size() && i<digitMaxEnd;i++)
3323 if(contentStr[i]=='}')
3324 break;
3326 if(i!=digitMaxEnd)
3328 // get the width
3329 string digitStr= contentStr.substr(digitStart, i-digitStart);
3330 fromString(digitStr, w);
3331 // remove the first tag
3332 contentStr= contentStr.substr(i+1);
3336 // open the message box window or web ig
3337 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3339 if (is_webig)
3341 CGroupHTML *groupHtml;
3342 string group = titleStr;
3343 // <missing:XXX>
3344 group = group.substr(9, group.size()-10);
3345 groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:"+group+":content:html"));
3346 if (!groupHtml)
3348 groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:webig:content:html"));
3349 group = "webig";
3352 if (groupHtml)
3354 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:"+group));
3355 if (pGC)
3357 if (contentStr.empty())
3359 pGC->setActive(false);
3361 else
3363 if (group == "webig")
3364 pGC->setActive(true);
3365 string url = contentStr;
3366 addWebIGParams(url, true);
3367 groupHtml->browse(url.c_str());
3368 CWidgetManager::getInstance()->setTopWindow(pGC);
3373 else
3375 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:server_message_box"));
3376 if (pGC)
3378 // show the window with correct width
3379 pGC->setW(w);
3380 pGC->setActive(true);
3382 // must set the text by hand
3383 CViewText *vt= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(CWidgetManager::getInstance()->getParser()->getDefine("server_message_box_content_view_text")));
3384 if(vt)
3385 vt->setTextFormatTaged(contentStr);
3387 // open
3388 CWidgetManager::getInstance()->setTopWindow(pGC);
3389 pGC->invalidateCoords();
3390 // Yoyo: because of buggued group container, I found that 6 times is a good number....
3391 for(uint i=0;i<6;i++)
3392 pGC->updateCoords();
3393 pGC->center();
3394 pGC->enableBlink(2);
3399 public:
3400 // called when the string is available
3401 virtual void onDynStringAvailable(uint stringId, const std::string &value)
3403 // don't care if already displayed
3404 if(_AlreadyDisplayed)
3405 return;
3407 // check if one of waited text
3408 for(uint i=0;i<NumTextType;i++)
3410 if(stringId==_TextId[i])
3412 _TextReceived[i]= true;
3416 // all received?
3417 for(uint i=0;i<NumTextType;i++)
3419 if(!_TextReceived[i])
3420 return;
3422 // Yes => display window
3423 _AlreadyDisplayed= true;
3424 activateMsgBoxWindow();
3427 // start the waiter
3428 void startWaitTexts(uint32 titleTextId, uint32 docTextId)
3430 // reset
3431 _TextId[TitleType]= titleTextId;
3432 _TextId[ContentType]= docTextId;
3433 _TextReceived[TitleType]= false;
3434 _TextReceived[ContentType]= false;
3435 _AlreadyDisplayed= false;
3437 // start to wait receive of those string (NB: they may be already here, but waitDynStrings calls directly the callback in this case)
3438 STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
3439 pSMC->waitDynString(titleTextId, this);
3440 pSMC->waitDynString(docTextId, this);
3443 CServerMessageBoxOnReceiveTextId ServerMessageBoxOnReceiveTextId;
3446 void impulseUserPopup(NLMISC::CBitMemStream &impulse)
3448 uint32 titleTextId;
3449 uint32 docTextId;
3450 impulse.serial(titleTextId);
3451 impulse.serial(docTextId);
3453 // setup TEMP DB for title
3454 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3455 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:SERVER_POPUP:TITLE");
3456 if(node) node->setValue32(titleTextId);
3458 // Open the Popup only when the 2 dyn strings are available
3459 ServerMessageBoxOnReceiveTextId.startWaitTexts(titleTextId, docTextId);
3462 //-----------------------------------------------
3463 //-----------------------------------------------
3464 //extern void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse);
3465 void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse)
3467 uint32 entityID;
3468 uint32 rgba;
3469 sint16 hpDelta;
3470 impulse.serial(entityID);
3471 impulse.serial(rgba);
3472 impulse.serial(hpDelta);
3473 CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
3474 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3475 if (entity)
3476 entity->addHPOutput(toString("%d", hpDelta), color);
3479 void impulseCombatFlyingTextItemSpecialEffectProc(NLMISC::CBitMemStream &impulse)
3481 uint32 entityID;
3482 uint32 rgba;
3483 uint8 effect;
3484 sint32 param;
3485 impulse.serial(entityID);
3486 impulse.serial(rgba);
3487 impulse.serial(effect);
3488 impulse.serial(param);
3489 CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
3490 string text = CI18N::get(toString("uiItemSpecialEffectFlyingText%s", ITEM_SPECIAL_EFFECT::toString((ITEM_SPECIAL_EFFECT::TItemSpecialEffect)effect).c_str()));
3491 strFindReplace(text, "%param", toString("%d", param));
3492 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3493 if (entity)
3494 entity->addHPOutput(text, color);
3497 void impulseCombatFlyingText(NLMISC::CBitMemStream &impulse)
3499 uint32 entityID;
3500 uint8 tmp;
3501 impulse.serial(entityID);
3502 impulse.serial(tmp);
3503 COMBAT_FLYING_TEXT::TCombatFlyingText type = (COMBAT_FLYING_TEXT::TCombatFlyingText)tmp;
3505 CRGBA color(255, 255, 255);
3506 string text("");
3507 float dt = 0.0f;
3509 switch (type)
3511 case COMBAT_FLYING_TEXT::TargetDodge: // The target dodged
3512 color = CRGBA(255, 128, 64);
3513 text = CI18N::get("uiDodge");
3514 break;
3516 case COMBAT_FLYING_TEXT::TargetParry: // The target parried
3517 color = CRGBA(255, 128, 64);
3518 text = CI18N::get("uiParry");
3519 break;
3521 case COMBAT_FLYING_TEXT::TargetEvade: // Actually the user miss his hit
3522 color = CRGBA(255, 128, 64);
3523 text = CI18N::get("uiEvade");
3524 break;
3526 case COMBAT_FLYING_TEXT::SelfEvade: // Actually the target miss his hit
3527 color = CRGBA(255, 255, 0);
3528 text = CI18N::get("uiEvade");
3529 break;
3531 case COMBAT_FLYING_TEXT::TargetResist: // The target resisted magic
3532 color = CRGBA(255, 128, 64);
3533 text = CI18N::get("uiResist");
3534 break;
3536 case COMBAT_FLYING_TEXT::SelfResist: // The user resisted magic
3537 color = CRGBA(255, 255, 0);
3538 text = CI18N::get("uiResist");
3539 break;
3541 case COMBAT_FLYING_TEXT::SelfInterrupt: // the user cast was interupted
3542 color = CRGBA(200, 0, 0);
3543 text = CI18N::get("uiInterrupt");
3544 dt = 0.4f;
3545 break;
3547 case COMBAT_FLYING_TEXT::SelfFailure: // The user failed to cast
3548 color = CRGBA(200, 0, 0);
3549 text = CI18N::get("uiFailure");
3550 break;
3552 default: // bad type
3553 nlwarning("Bad type for COMBAT_FLYING_TEXT:TCombatFlyingText enum");
3554 break;
3557 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3558 if (entity)
3559 entity->addHPOutput(text, color, dt);
3562 void impulseSetSeason(NLMISC::CBitMemStream &impulse)
3564 extern uint8 ServerSeasonValue;
3565 extern bool ServerSeasonReceived;
3566 impulse.serial(ServerSeasonValue);
3567 ServerSeasonReceived = true;
3570 void impulseDssDown(NLMISC::CBitMemStream &impulse)
3572 FarTP.onDssDown();
3575 void impulseSetNpcIconDesc(NLMISC::CBitMemStream &impulse)
3577 uint8 nb8;
3578 impulse.serial(nb8);
3579 bool hasChanged = false;
3580 for (uint i=0; i!=(uint)nb8; ++i)
3582 TNPCIconCacheKey npcIconCacheKey;
3583 impulse.serial(npcIconCacheKey);
3584 uint32 state;
3585 impulse.serial(state);
3586 hasChanged = CNPCIconCache::getInstance().onReceiveMissionAvailabilityForThisChar(npcIconCacheKey, (NPC_ICON::TNPCMissionGiverState)state) || hasChanged; // mind the order to avoid partial evaluation
3588 if (hasChanged)
3589 CNPCIconCache::getInstance().refreshIconsOfScene();
3592 void impulseServerEventForMissionAvailability(NLMISC::CBitMemStream &impulse)
3594 CNPCIconCache::getInstance().onEventForMissionAvailabilityForThisChar();
3597 void impulseSetNpcIconTimer(NLMISC::CBitMemStream &impulse)
3599 NLMISC::TGameCycle delay;
3600 impulse.serial(delay);
3601 CNPCIconCache::getInstance().setMissionGiverTimer(delay);
3604 //-----------------------------------------------
3605 // initializeNetwork :
3606 //-----------------------------------------------
3607 void initializeNetwork()
3609 GenericMsgHeaderMngr.setCallback("DB_UPD_PLR", impulseDatabaseUpdatePlayer);
3610 GenericMsgHeaderMngr.setCallback("DB_INIT:PLR", impulseDatabaseInitPlayer);
3611 GenericMsgHeaderMngr.setCallback("DB_UPD_INV", impulseUpdateInventory);
3612 GenericMsgHeaderMngr.setCallback("DB_INIT:INV", impulseInitInventory);
3613 GenericMsgHeaderMngr.setCallback("DB_GROUP:UPDATE_BANK", impulseDatabaseUpdateBank);
3614 GenericMsgHeaderMngr.setCallback("DB_GROUP:INIT_BANK", impulseDatabaseInitBank);
3615 GenericMsgHeaderMngr.setCallback("DB_GROUP:RESET_BANK", impulseDatabaseResetBank);
3616 GenericMsgHeaderMngr.setCallback("CONNECTION:NO_USER_CHAR", impulseNoUserChar);
3617 GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHARS", impulseUserChars);
3618 GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHAR", impulseUserChar);
3619 GenericMsgHeaderMngr.setCallback("CONNECTION:FAR_TP", impulseFarTP);
3620 GenericMsgHeaderMngr.setCallback("CONNECTION:READY", impulseServerReady);
3621 GenericMsgHeaderMngr.setCallback("CONNECTION:VALID_NAME", impulseCharNameValid);
3622 GenericMsgHeaderMngr.setCallback("CONNECTION:SHARD_ID", impulseShardId);
3623 GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_OK", impulseServerQuitOk);
3624 GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_ABORT", impulseServerQuitAbort);
3625 GenericMsgHeaderMngr.setCallback("CONNECTION:MAIL_AVAILABLE", impulseMailNotification);
3626 GenericMsgHeaderMngr.setCallback("CONNECTION:GUILD_MESSAGE_AVAILABLE", impulseForumNotification);
3627 GenericMsgHeaderMngr.setCallback("CONNECTION:PERMANENT_BAN", impulsePermanentBan);
3628 GenericMsgHeaderMngr.setCallback("CONNECTION:UNBAN", impulsePermanentUnban);
3630 GenericMsgHeaderMngr.setCallback("STRING:CHAT", impulseChat);
3631 GenericMsgHeaderMngr.setCallback("STRING:TELL", impulseTell);
3632 GenericMsgHeaderMngr.setCallback("STRING:FAR_TELL", impulseFarTell);
3633 GenericMsgHeaderMngr.setCallback("STRING:CHAT2", impulseChat2);
3634 GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING", impulseDynString);
3635 GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING_GROUP", inpulseDynStringInChatGroup);
3636 GenericMsgHeaderMngr.setCallback("STRING:TELL2", impulseTell2);
3637 // GenericMsgHeaderMngr.setCallback("STRING:ADD_DYN_STR", impulseAddDynStr);
3638 GenericMsgHeaderMngr.setCallback("TP:DEST", impulseTP);
3639 GenericMsgHeaderMngr.setCallback("TP:DEST_WITH_SEASON", impulseTPWithSeason);
3640 GenericMsgHeaderMngr.setCallback("TP:CORRECT", impulseCorrectPos);
3641 GenericMsgHeaderMngr.setCallback("COMBAT:ENGAGE_FAILED", impulseCombatEngageFailed);
3642 GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_OPEN", impulseDynChatOpen);
3643 GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_CLOSE", impulseDynChatClose);
3645 GenericMsgHeaderMngr.setCallback("CASTING:BEGIN", impulseBeginCast);
3646 GenericMsgHeaderMngr.setCallback("TEAM:INVITATION", impulseTeamInvitation);
3647 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_OPEN", impulseTeamShareOpen);
3648 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_INVALID", impulseTeamShareInvalid);
3649 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_CLOSE", impulseTeamShareClose);
3650 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_INIT", impulseTeamContactInit);
3651 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_CREATE", impulseTeamContactCreate);
3652 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_STATUS", impulseTeamContactStatus);
3653 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_REMOVE", impulseTeamContactRemove);
3655 GenericMsgHeaderMngr.setCallback("EXCHANGE:INVITATION", impulseExchangeInvitation);
3656 GenericMsgHeaderMngr.setCallback("EXCHANGE:CLOSE_INVITATION", impulseExchangeCloseInvitation);
3657 GenericMsgHeaderMngr.setCallback("ANIMALS:MOUNT_ABORT", impulseMountAbort);
3659 GenericMsgHeaderMngr.setCallback("DEBUG:REPLY_WHERE", impulseWhere);
3660 GenericMsgHeaderMngr.setCallback("DEBUG:COUNTER", impulseCounter);
3663 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:PHRASE_SEND", impulsePhraseSend);
3664 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:STRING_RESP", impulseStringResp);
3665 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:RELOAD_CACHE", impulseReloadCache);
3667 GenericMsgHeaderMngr.setCallback("BOTCHAT:FORCE_END", impulseBotChatForceEnd);
3669 GenericMsgHeaderMngr.setCallback("JOURNAL:INIT_COMPLETED_MISSIONS", impulseJournalInitCompletedMissions);
3670 GenericMsgHeaderMngr.setCallback("JOURNAL:UPDATE_COMPLETED_MISSIONS", impulseJournalUpdateCompletedMissions);
3671 // GenericMsgHeaderMngr.setCallback("JOURNAL:CANT_ABANDON", impulseJournalCantAbandon);
3673 GenericMsgHeaderMngr.setCallback("JOURNAL:ADD_COMPASS", impulseJournalAddCompass);
3674 GenericMsgHeaderMngr.setCallback("JOURNAL:REMOVE_COMPASS", impulseJournalRemoveCompass);
3677 //GenericMsgHeaderMngr.setCallback("GUILD:SET_MEMBER_INFO", impulseGuildSetMemberInfo);
3678 //GenericMsgHeaderMngr.setCallback("GUILD:INIT_MEMBER_INFO", impulseGuildInitMemberInfo);
3680 GenericMsgHeaderMngr.setCallback("GUILD:JOIN_PROPOSAL", impulseGuildJoinProposal);
3682 GenericMsgHeaderMngr.setCallback("GUILD:ASCENSOR", impulseGuildAscensor);
3683 GenericMsgHeaderMngr.setCallback("GUILD:LEAVE_ASCENSOR", impulseGuildLeaveAscensor);
3684 GenericMsgHeaderMngr.setCallback("GUILD:ABORT_CREATION", impulseGuildAbortCreation);
3685 GenericMsgHeaderMngr.setCallback("GUILD:OPEN_GUILD_WINDOW", impulseGuildOpenGuildWindow);
3687 GenericMsgHeaderMngr.setCallback("GUILD:OPEN_INVENTORY", impulseGuildOpenInventory);
3688 GenericMsgHeaderMngr.setCallback("GUILD:CLOSE_INVENTORY", impulseGuildCloseInventory);
3690 GenericMsgHeaderMngr.setCallback("GUILD:UPDATE_PLAYER_TITLE", impulseGuildUpdatePlayerTitle);
3691 GenericMsgHeaderMngr.setCallback("GUILD:USE_FEMALE_TITLES", impulseGuildUseFemaleTitles);
3692 //GenericMsgHeaderMngr.setCallback("GUILD:INVITATION", impulseGuildInvitation);
3694 GenericMsgHeaderMngr.setCallback("HARVEST:CLOSE_TEMP_INVENTORY", impulseCloseTempInv);
3696 GenericMsgHeaderMngr.setCallback("COMMAND:REMOTE_ADMIN", impulseRemoteAdmin);
3698 GenericMsgHeaderMngr.setCallback("PHRASE:DOWNLOAD", impulsePhraseDownLoad);
3699 GenericMsgHeaderMngr.setCallback("PHRASE:CONFIRM_BUY", impulsePhraseConfirmBuy);
3700 GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_CYCLIC_ACK", impulsePhraseAckExecuteCyclic);
3701 GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_NEXT_ACK", impulsePhraseAckExecuteNext);
3703 GenericMsgHeaderMngr.setCallback("ITEM_INFO:SET", impulseItemInfoSet);
3704 GenericMsgHeaderMngr.setCallback("ITEM_INFO:REFRESH_VERSION", impulseItemInfoRefreshVersion);
3705 GenericMsgHeaderMngr.setCallback("MISSION_PREREQ:SET", impulsePrereqInfoSet);
3706 GenericMsgHeaderMngr.setCallback("ITEM:OPEN_ROOM_INVENTORY", impulseItemOpenRoomInventory);
3707 GenericMsgHeaderMngr.setCallback("ITEM:CLOSE_ROOM_INVENTORY", impulseItemCloseRoomInventory);
3709 GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN_POINT", impulseDeathRespawnPoint);
3710 GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN", impulseDeathRespawn);
3712 GenericMsgHeaderMngr.setCallback("DUEL:INVITATION", impulseDuelInvitation);
3713 GenericMsgHeaderMngr.setCallback("DUEL:CANCEL_INVITATION", impulseDuelCancelInvitation);
3715 GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:INVITATION", impulsePVPChallengeInvitation);
3716 GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:CANCEL_INVITATION", impulsePVPChallengeCancelInvitation);
3718 GenericMsgHeaderMngr.setCallback("PVP_FACTION:PUSH_FACTION_WAR", impulsePVPFactionPushFactionWar);
3719 GenericMsgHeaderMngr.setCallback("PVP_FACTION:POP_FACTION_WAR", impulsePVPFactionPopFactionWar);
3720 GenericMsgHeaderMngr.setCallback("PVP_FACTION:FACTION_WARS", impulsePVPFactionFactionWars);
3723 // GenericMsgHeaderMngr.setCallback("PVP_VERSUS:CHOOSE_CLAN", impulsePVPChooseClan);
3725 GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:UPDATE", impulseEncyclopediaUpdate);
3726 GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:INIT", impulseEncyclopediaInit);
3728 GenericMsgHeaderMngr.setCallback("USER:BARS", impulseUserBars);
3729 GenericMsgHeaderMngr.setCallback("USER:POPUP", impulseUserPopup);
3732 GenericMsgHeaderMngr.setCallback("MISSION:ASK_ENTER_CRITICAL", impulseEnterCrZoneProposal);
3733 GenericMsgHeaderMngr.setCallback("MISSION:CLOSE_ENTER_CRITICAL", impulseCloseEnterCrZoneProposal);
3735 // Module gateway message
3736 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FEOPEN", cbImpulsionGatewayOpen);
3737 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:GATEWAY_MSG", cbImpulsionGatewayMessage );
3738 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FECLOSE", cbImpulsionGatewayClose );
3740 GenericMsgHeaderMngr.setCallback( "OUTPOST:CHOOSE_SIDE", impulseOutpostChooseSide );
3741 GenericMsgHeaderMngr.setCallback( "OUTPOST:DECLARE_WAR_ACK", impulseOutpostDeclareWarAck );
3743 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_HP_DELTA", impulseCombatFlyingHpDelta );
3744 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT_ISE", impulseCombatFlyingTextItemSpecialEffectProc );
3745 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT", impulseCombatFlyingText );
3747 GenericMsgHeaderMngr.setCallback( "SEASON:SET", impulseSetSeason );
3748 GenericMsgHeaderMngr.setCallback( "RING_MISSION:DSS_DOWN", impulseDssDown );
3750 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_DESC", impulseSetNpcIconDesc );
3751 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SVR_EVENT_MIS_AVL", impulseServerEventForMissionAvailability );
3752 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_TIMER", impulseSetNpcIconTimer );
3756 //-----------------------------------------------
3757 // impulseCallBack :
3758 // The impulse callback to receive all msg from the frontend.
3759 //-----------------------------------------------
3760 void impulseCallBack(NLMISC::CBitMemStream &impulse, sint32 packet, void *arg)
3762 GenericMsgHeaderMngr.execute(impulse);
3766 ////////////
3767 // METHOD //
3768 ////////////
3769 //-----------------------------------------------
3770 // CNetManager :
3771 // Constructor.
3772 //-----------------------------------------------
3773 CNetManager::CNetManager() : CNetworkConnection()
3775 #ifdef ENABLE_INCOMING_MSG_RECORDER
3776 _IsReplayStarting = false;
3777 #endif
3778 }// CNetManager //
3780 //-----------------------------------------------
3781 // update :
3782 // Updates the whole connection with the frontend.
3783 // Call this method evently.
3784 // \return bool : 'true' if data were sent/received.
3785 //-----------------------------------------------
3786 bool CNetManager::update()
3788 H_AUTO_USE ( RZ_Client_Net_Mngr_Update )
3790 #ifdef ENABLE_INCOMING_MSG_RECORDER
3791 if(_IsReplayStarting)
3792 return;
3793 #endif
3795 // If the client is in Local Mode -> no network.
3796 if(ClientCfg.Local)
3798 // Init
3799 if(_CurrentServerTick == 0)
3801 if(T1 >= _LCT)
3803 _MachineTimeAtTick = T1;
3804 _CurrentClientTime = _MachineTimeAtTick - _LCT;
3805 _CurrentClientTick = 0;
3806 _CurrentServerTick = 10;
3809 return false;
3812 if((T1 - _MachineTimeAtTick) >= _MsPerTick)
3814 NLMISC::TGameCycle nbTick = (NLMISC::TGameCycle)((T1 - _MachineTimeAtTick)/_MsPerTick);
3815 _CurrentClientTick += nbTick;
3816 _CurrentServerTick += nbTick;
3817 _MachineTimeAtTick += nbTick*_MsPerTick;
3820 // update the smooth server tick for debug
3821 CNetworkConnection::updateSmoothServerTick();
3823 // emulation done
3824 #ifdef ENABLE_INCOMING_MSG_RECORDER
3825 return false;
3826 #endif
3829 // Update the base class.
3830 bool result = CNetworkConnection::update();
3831 // Get changes with the update.
3832 const vector<CChange> &changes = NetMngr.getChanges();
3834 // Manage changes
3835 vector<CChange>::const_iterator it;
3836 for(it = changes.begin(); it < changes.end(); ++it)
3838 const CChange &change = *it;
3839 // Update a property.
3840 if(change.Property < AddNewEntity)
3842 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3844 // Update the visual property for the slot.
3845 EntitiesMngr.updateVisualProperty(change.GameCycle, change.ShortId, change.Property, change.PositionInfo.PredictedInterval);
3847 else
3849 nlwarning("CNetManager::update : Skipping EntitiesMngr.updateVisualProperty() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3852 // Add New Entity (and remove the old one in the slot).
3853 else if(change.Property == AddNewEntity)
3855 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3857 // Remove the old entity.
3858 EntitiesMngr.remove(change.ShortId, false);
3859 // Create the new entity.
3860 if(EntitiesMngr.create(change.ShortId, get(change.ShortId), change.NewEntityInfo) == 0)
3861 nlwarning("CNetManager::update : entity in the slot '%u' has not been created.", change.ShortId);
3863 else
3865 nlwarning("CNetManager::update : Skipping EntitiesMngr.create() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3868 // Delete an entity
3869 else if(change.Property == RemoveOldEntity)
3871 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3873 // Remove the old entity.
3874 EntitiesMngr.remove(change.ShortId, true);
3876 else
3878 nlwarning("CNetManager::update : Skipping EntitiesMngr.remove() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3881 // Lag detected.
3882 else if(change.Property == LagDetected)
3884 nldebug("CNetManager::update : Lag detected.");
3886 // Probe received.
3887 else if(change.Property == ProbeReceived)
3889 nldebug("CNetManager::update : Probe Received.");
3891 // Connection ready.
3892 else if(change.Property == ConnectionReady)
3894 nldebug("CNetManager::update : Connection Ready.");
3896 // Property unknown.
3897 else
3898 nlwarning("CNetManager::update : The property '%d' is unknown.", change.Property);
3900 ChatMngr.flushBuffer(InterfaceChatDisplayer);
3901 // Clear all changes.
3902 clearChanges();
3904 // Update data base server state
3905 if (IngameDbMngr.getNodePtr())
3907 CInterfaceManager *im = CInterfaceManager::getInstance();
3908 if (im)
3910 CCDBNodeLeaf *node = NULL;
3912 if (!m_PingLeaf)
3913 m_PingLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:PING", false);
3915 if (m_PingLeaf)
3917 node = &*m_PingLeaf;
3918 if (node)
3919 node->setValue32(getPing());
3922 if (!m_UploadLeaf)
3923 m_UploadLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:UPLOAD", false);
3925 if (m_UploadLeaf)
3927 node = &*m_UploadLeaf;
3928 if (node)
3929 node->setValue32((sint32)(getMeanUpload()*1024.f/8.f));
3932 if (!m_DownloadLeaf)
3933 m_DownloadLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:DOWNLOAD", false);
3935 if (m_DownloadLeaf)
3937 node = &*m_DownloadLeaf;
3938 if (node)
3939 node->setValue32((sint32)(getMeanDownload()*1024.f/8.f));
3942 if (!m_PacketLostLeaf)
3943 m_PacketLostLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:PACKETLOST", false);
3945 if (m_PacketLostLeaf)
3947 node = &*m_PacketLostLeaf;
3948 if (node)
3949 node->setValue32((sint32)getMeanPacketLoss());
3952 if (!m_ServerStateLeaf)
3953 m_ServerStateLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:SERVERSTATE", false);
3955 if (m_ServerStateLeaf)
3957 node = &*m_ServerStateLeaf;
3958 if (node)
3959 node->setValue32((sint32)getConnectionState());
3962 if (!m_ConnectionQualityLeaf)
3963 m_ConnectionQualityLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CONNECTION_QUALITY", false);
3965 if (m_ConnectionQualityLeaf)
3967 node = &*m_ConnectionQualityLeaf;
3968 if (node)
3969 node->setValue32((sint32)getConnectionQuality());
3974 // Return 'true' if data were sent/received.
3975 return result;
3978 }// update //
3980 //-----------------------------------------------
3981 // getConnectionQuality :
3982 //-----------------------------------------------
3983 bool CNetManager::getConnectionQuality()
3985 // If the client is in Local Mode -> no network.
3986 if(ClientCfg.Local)
3987 return true;
3989 return CNetworkConnection::getConnectionQuality();
3990 }// getConnectionQuality //
3994 * Buffers a bitmemstream, that will be converted into a generic action, to be sent later to the server (at next update).
3996 void CNetManager::push(NLMISC::CBitMemStream &msg)
3998 // If the client is in Local Mode -> no network.
3999 if(ClientCfg.Local)
4000 return;
4002 if (PermanentlyBanned) return;
4004 CNetworkConnection::push(msg);
4008 * Buffers a target action
4010 void CNetManager::pushTarget(CLFECOMMON::TCLEntityId slot)
4012 // If the client is in Local Mode -> no network.
4013 if(ClientCfg.Local)
4015 if(UserEntity->mode() != MBEHAV::COMBAT
4016 && UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
4018 UserEntity->targetSlot(slot);
4020 return;
4023 CNetworkConnection::pushTarget(slot, LHSTATE::NONE);
4028 * Buffers a pick-up action
4030 void CNetManager::pushPickup(CLFECOMMON::TCLEntityId slot, LHSTATE::TLHState lootOrHarvest)
4032 // If the client is in Local Mode -> no network.
4033 if(ClientCfg.Local)
4035 return;
4038 CNetworkConnection::pushTarget(slot, lootOrHarvest);
4043 * Send
4045 void CNetManager::send(NLMISC::TGameCycle gameCycle)
4047 // If the client is in Local Mode -> no network.
4048 if(ClientCfg.Local)
4049 return;
4051 // wait till next server is received
4052 if (_LastSentCycle >= gameCycle)
4054 //nlinfo ("Try to CNetManager::send(%d) _LastSentCycle=%d more than one time with the same game cycle, so we wait new game cycle to send", gameCycle, _LastSentCycle);
4055 while (_LastSentCycle >= gameCycle)
4057 // Update network.
4058 update();
4059 // Send dummy info
4060 send();
4061 // Do not take all the CPU.
4062 nlSleep(100);
4064 gameCycle = getCurrentServerTick();
4068 CNetworkConnection::send(gameCycle);
4072 * Send
4074 void CNetManager::send()
4076 // If the client is in Local Mode -> no network.
4077 if(ClientCfg.Local)
4078 return;
4080 CNetworkConnection::send();
4084 * Disconnects the current connection
4086 void CNetManager::disconnect()
4088 // If the client is in Local Mode -> no need to disconnect.
4089 if(ClientCfg.Local)
4090 return;
4092 CNetworkConnection::disconnect();
4093 }// disconnect //
4097 * Reset data and init the socket
4099 void CNetManager::reinit()
4101 if(ClientCfg.Local)
4102 return;
4104 IngameDbMngr.resetInitState();
4105 CNetworkConnection::reinit();
4108 void CNetManager::waitForServer()
4110 sint LastGameCycle = getCurrentServerTick();
4112 for(;;)
4114 // Event server get events
4115 CInputHandlerManager::getInstance()->pumpEventsNoIM();
4116 // Update Network.
4117 update();
4119 if (LastGameCycle != (sint) getCurrentServerTick())
4120 break;
4122 nlSleep(100);
4123 send();
4126 }// waitForServer //
4129 #ifdef ENABLE_INCOMING_MSG_RECORDER
4130 //-----------------------------------------------
4131 // setReplayingMode :
4132 //-----------------------------------------------
4133 void CNetManager::setReplayingMode( bool onOff, const std::string& filename )
4135 CNetworkConnection::setReplayingMode(onOff, filename);
4136 _IsReplayStarting = onOff;
4137 }// setReplayingMode //
4139 //-----------------------------------------------
4140 // startReplay :
4141 //-----------------------------------------------
4142 void CNetManager::startReplay()
4144 // Init Replay
4145 _MachineTimeAtTick = T1;
4146 if(_MachineTimeAtTick >= _LCT)
4147 _CurrentClientTime = _MachineTimeAtTick - _LCT;
4148 else
4149 _CurrentClientTime = 0;
4150 // Replay now in progress.
4151 _IsReplayStarting = false;
4152 }// startReplay //
4153 #endif
4157 * Create the net managers in CLIENT_MULTI mode
4159 void CNetManagerMulti::init( const std::string& cookie, const std::string& addr )
4161 uint nb, baseCookie;
4162 NLMISC::CConfigFile::CVar *var = ClientCfg.ConfigFile.getVarPtr( "NbConnections" );
4163 if ( var )
4164 nb = var->asInt();
4165 else
4166 nb = 1;
4167 var = ClientCfg.ConfigFile.getVarPtr( "UserId" );
4168 if ( var )
4169 baseCookie = var->asInt();
4170 else
4171 baseCookie = 0;
4172 std::vector<std::string> fsAddrs;
4173 fsAddrs.push_back( addr );
4174 string portString = addr.substr( addr.find( ':' ) );
4175 var = ClientCfg.ConfigFile.getVarPtr( "AdditionalFSList" );
4176 if ( var )
4178 for ( uint i=0; i!=var->size(); ++i )
4179 fsAddrs.push_back( var->asString( i ) + portString );
4181 nlinfo( "CNetManagerMulti: Creating %u connections to %u front-ends, baseCookie=%u...", nb, fsAddrs.size(), baseCookie );
4183 for ( uint i=0; i!=nb; ++i )
4185 CNetManager *nm = new CNetManager();
4186 string multicook = NLMISC::toString( "%8x|%8x|%8x", 0, 0, baseCookie + i );
4187 nm->init( multicook, fsAddrs[i % fsAddrs.size()] );
4188 _NetManagers.push_back( nm );
4193 uint32 ShardId = 0;
4194 std::string WebServer;
4199 /////////////////////////////////////////////////////////////////////////////
4200 /////////////////////////////////////////////////////////////////////////////
4201 /////////////////////////////////////////////////////////////////////////////
4202 /////////////////////////////////////////////////////////////////////////////
4203 /////////// COMMANDS after should NOT appear IN the FINAL VERSION ///////////
4204 /////////////////////////////////////////////////////////////////////////////
4205 /////////////////////////////////////////////////////////////////////////////
4206 /////////////////////////////////////////////////////////////////////////////
4207 /////////////////////////////////////////////////////////////////////////////
4208 /////////////////////////////////////////////////////////////////////////////
4211 #if !FINAL_VERSION
4213 // temp : simulate a team msg in local mode
4214 NLMISC_COMMAND(localTellTeam, "Temp : simulate a tell in local mode", "<people_name> <msg>")
4216 if (args.empty()) return false;
4217 string player = args[0];
4218 std::string msg;
4219 if (args.size() >= 2)
4221 msg = args[1];
4222 for(uint k = 2; k < args.size(); ++k)
4224 msg += " " + args[k];
4227 TDataSetIndex dsi = INVALID_DATASET_INDEX;
4228 InterfaceChatDisplayer.displayChat(dsi, msg, msg, CChatGroup::team, NLMISC::CEntityId::Unknown, player);
4229 return true;
4232 // temp : simulate a tell in local mode
4233 NLMISC_COMMAND(localTell, "Temp : simulate a tell in local mode", "<people_name> <msg>")
4235 if (args.empty()) return false;
4236 string player = args[0];
4237 std::string msg;
4238 if (args.size() >= 2)
4240 msg = args[1];
4241 for(uint k = 2; k < args.size(); ++k)
4243 msg += " " + args[k];
4246 // TDataSetIndex dsi = INVALID_DATASET_ROW;
4247 InterfaceChatDisplayer.displayTell(/*dsi, */msg, player);
4248 return true;
4251 NLMISC_COMMAND(testDynChatOpen, "", "")
4253 NLMISC::CBitMemStream bm;
4254 if (bm.isReading()) bm.invert();
4255 uint32 BotUID = 22; // Compressed Index
4256 uint32 BotName = 654; // Server string
4257 vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
4258 DynStrs.push_back(16540);
4259 DynStrs.push_back(11465);
4260 DynStrs.push_back(12654);
4261 bm.serial(BotUID);
4262 bm.serial(BotName);
4263 bm.serialCont(DynStrs);
4264 bm.invert();
4265 bm.seek(0, NLMISC::IStream::begin);
4266 impulseDynChatOpen(bm);
4267 return true;
4270 NLMISC_COMMAND(testDynChatClose, "", "")
4272 NLMISC::CBitMemStream bm;
4273 if (bm.isReading()) bm.invert();
4274 uint32 BotUID = 22; // Compressed Index
4275 bm.serial(BotUID);
4276 bm.invert();
4277 bm.seek(0, NLMISC::IStream::begin);
4278 impulseDynChatClose(bm);
4279 return true;
4283 NLMISC_COMMAND(testCloseTempInv, "","")
4285 NLMISC::CBitMemStream bm;
4286 impulseCloseTempInv(bm);
4287 return true;
4290 NLMISC_COMMAND(testTeamInvite, "","")
4292 NLMISC::CBitMemStream bm;
4293 if (bm.isReading()) bm.invert();
4294 uint32 index = 10;
4295 bm.serial(index);
4296 bm.invert();
4297 bm.seek(0, NLMISC::IStream::begin);
4298 impulseTeamInvitation(bm);
4299 return true;
4301 NLMISC_COMMAND(testGuildInvite, "","")
4303 NLMISC::CBitMemStream bm;
4304 if (bm.isReading()) bm.invert();
4305 uint32 index = 10;
4306 bm.serial(index);
4307 bm.serial(index);
4308 bm.invert();
4309 bm.seek(0, NLMISC::IStream::begin);
4310 impulseGuildJoinProposal(bm);
4311 return true;
4314 NLMISC_COMMAND( testExchangeInvitation, "Test the modal window for invitation exchange", "" )
4316 CBitMemStream impulse;
4317 uint32 nameIndex = 0;
4318 impulse.serial(nameIndex);
4319 impulse.invert();
4320 impulseExchangeInvitation(impulse);
4321 return true;
4325 NLMISC_COMMAND(testAscensor, "Temp : Simulate a GUILD:ASCENSOR message coming from server","")
4327 NLMISC::CBitMemStream bm;
4328 if (bm.isReading()) bm.invert();
4329 uint32 index = 10;
4330 bm.serial(index);
4331 bm.invert();
4332 bm.seek(0, NLMISC::IStream::begin);
4333 impulseGuildAscensor(bm);
4334 return true;
4337 NLMISC_COMMAND(testDuelInvite, "","")
4339 NLMISC::CBitMemStream bm;
4340 if (bm.isReading()) bm.invert();
4341 uint32 index = 10;
4342 bm.serial(index);
4343 bm.invert();
4344 bm.seek(0, NLMISC::IStream::begin);
4345 impulseDuelInvitation(bm);
4346 return true;
4349 //NLMISC_COMMAND(receiveId, "","<num> <name>")
4351 // uint32 index;
4352 // fromString(args[0], index);
4353 // ucstring ucstr = args[1]; // OLD
4355 // vector<bool> code;
4357 //#ifdef OLD_STRING_SYSTEM
4358 // ChatMngr.getDynamicDB().add( index, ucstr, code );
4359 //#else
4360 // // TRAP // WE MUST NEVER CALL THIS COMMAND ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!
4361 // nlstop;
4362 //#endif
4364 // return true;
4367 NLMISC_COMMAND(testOutpostChooseSide, "","b b u32 u32")
4369 if(args.size()<4)
4370 return false;
4371 NLMISC::CBitMemStream bm;
4372 if (bm.isReading()) bm.invert();
4373 bool playerGuildInConflict;
4374 fromString(args[0], playerGuildInConflict);
4375 bool playerGuildIsAttacker;
4376 fromString(args[1], playerGuildIsAttacker);
4377 bm.serial(playerGuildInConflict);
4378 bm.serial(playerGuildIsAttacker);
4379 uint32 ownerGuildNameId;
4380 fromString(args[2], ownerGuildNameId);
4381 bm.serial( ownerGuildNameId );
4382 uint32 attackerGuildNameId;
4383 fromString(args[3], attackerGuildNameId);
4384 bm.serial( attackerGuildNameId );
4385 uint32 declTimer= 100;
4386 bm.serial( declTimer );
4388 bm.invert();
4389 bm.seek(0, NLMISC::IStream::begin);
4390 impulseOutpostChooseSide(bm);
4391 return true;
4394 NLMISC_COMMAND(testUserPopup, "","u32 u32")
4396 if(args.size()<2)
4397 return false;
4398 NLMISC::CBitMemStream bm;
4399 if (bm.isReading()) bm.invert();
4400 uint32 titleId;
4401 fromString(args[0], titleId);
4402 bm.serial( titleId );
4403 uint32 textId;
4404 fromString(args[1], textId);
4405 bm.serial( textId );
4407 bm.invert();
4408 bm.seek(0, NLMISC::IStream::begin);
4409 impulseUserPopup(bm);
4410 return true;
4414 #endif