Add custom formatter for regen text
[ryzomcore.git] / ryzom / client / src / net_manager.cpp
blobaa6a99051bfaae83aa536bc041dab284a94905f3
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 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/msg_client_server.h"
37 #include "game_share/ryzom_database_banks.h"
38 #include "game_share/msg_encyclopedia.h"
39 #include "game_share/prerequisit_infos.h"
40 #include "game_share/permanent_ban_magic_number.h"
41 #include "game_share/item_special_effect.h"
42 #include "game_share/combat_flying_text.h"
43 #include "game_share/shard_names.h"
44 // Client.
45 #include "nel/gui/group_list.h"
46 #include "interface_v3/interface_manager.h"
47 #include "net_manager.h"
48 #include "client_cfg.h"
49 #include "entities.h"
50 #include "client_chat_manager.h"
51 #include "world_database_manager.h"
52 #include "continent_manager.h"
53 #include "motion/user_controls.h"
54 #include "interface_v3/bot_chat_manager.h"
55 #include "interface_v3/bot_chat_page_all.h"
56 #include "interface_v3/bot_chat_page_trade.h"
57 #include "interface_v3/bot_chat_page_create_guild.h"
58 #include "interface_v3/obs_huge_list.h"
59 #include "string_manager_client.h"
60 #include "interface_v3/people_interraction.h"
61 #include "interface_v3/bot_chat_manager.h"
62 #include "interface_v3/bot_chat_page_all.h"
63 #include "nel/gui/view_text_id.h"
64 #include "nel/gui/ctrl_text_button.h"
65 #include "interface_v3/input_handler_manager.h"
66 #include "interface_v3/guild_manager.h"
67 #include "interface_v3/skill_manager.h"
68 #include "misc.h"
69 #include "interface_v3/inventory_manager.h"
70 #include "interface_v3/sphrase_manager.h"
71 #include "outpost_manager.h"
72 #include "interface_v3/encyclopedia_manager.h"
73 #include "user_entity.h"
74 #include "init_main_loop.h"
75 #include "interface_v3/group_map.h"
76 #include "sound_manager.h"
77 #include "interface_v3/group_compas.h"
78 #include "interface_v3/group_html_webig.h"
79 #include "interface_v3/bar_manager.h"
80 #include "permanent_ban.h"
81 #include "global.h"
82 #include "connection.h"
83 #include "faction_war_manager.h"
84 #include "far_tp.h"
85 #include "input.h"
86 #include "r2/editor.h"
87 #include "game_share/r2_share_itf.h"
88 #include "game_share/r2_types.h"
89 #include "npc_icon.h"
90 #include "interface_v3/action_handler_base.h"
92 // Std.
93 #include <vector>
95 #ifdef DEBUG_NEW
96 #define new DEBUG_NEW
97 #endif
99 #define OLD_STRING_SYSTEM
100 #define BAR_STEP_TP 2
102 ///////////
103 // USING //
104 ///////////
105 using namespace NLMISC;
106 using namespace NL3D;
107 using namespace std;
110 extern bool FirstFrame;
111 extern void selectTipsOfTheDay (uint tips);
114 ////////////
115 // GLOBAL //
116 ////////////
117 CGenericXmlMsgHeaderManager GenericMsgHeaderMngr; // Manage messages
118 #ifdef CLIENT_MULTI
119 CNetManagerMulti NetMngr; // Manage the connection.
120 #else
121 CNetManager NetMngr; // Manage the connection.
122 #endif
124 bool UseFemaleTitles = false;
126 bool serverReceivedReady = false;
128 static const std::string PLAYER_EXCHANGE_INVITATION_DIALOG = "ui:interface:accept_trade_invitation";
130 // Hierarchical timer
131 H_AUTO_DECL ( RZ_Client_Net_Mngr_Update )
133 ////////////
134 // EXTERN //
135 ////////////
136 extern bool noUserChar; // \todo GUIGUI : do this better.
137 extern bool userChar; // \todo GUIGUI : do this better.
138 extern std::vector<CCharacterSummary> CharacterSummaries;
139 extern uint8 ServerPeopleActive;
140 extern uint8 ServerCareerActive;
141 extern vector<CMainlandSummary> Mainlands;
142 extern bool UserCharPosReceived;
143 extern CGenericXmlMsgHeaderManager GenericMsgHeaderMngr;
144 extern CClientChatManager ChatMngr;
146 extern bool CharNameValidArrived;
147 extern bool CharNameValid;
148 bool IsInRingSession = false;
149 TSessionId HighestMainlandSessionId; // highest in the position stack
151 extern const char *CDBBankNames[INVALID_CDB_BANK+1];
153 void cbImpulsionGatewayOpen(NLMISC::CBitMemStream &bms);
154 void cbImpulsionGatewayMessage(NLMISC::CBitMemStream &bms);
155 void cbImpulsionGatewayClose(NLMISC::CBitMemStream &bms);
159 ///////////////
160 // FUNCTIONS //
161 ///////////////
163 void impulseDatabaseInitPlayer(NLMISC::CBitMemStream &impulse)
167 sint32 p = impulse.getPos();
169 // get the egs tick of this change
170 TGameCycle serverTick;
171 impulse.serial(serverTick);
173 // read delta
174 IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer );
175 IngameDbMngr.setInitPacketReceived();
176 nlinfo( "DB_INIT:PLR done (%u bytes)", impulse.getPos()-p );
178 catch (const Exception &e)
180 BOMB( NLMISC::toString( "Problem while decoding a DB_INIT:PLR msg, skipped: %s", e.what() ), return );
184 void impulseDatabaseUpdatePlayer(NLMISC::CBitMemStream &impulse)
188 // get the egs tick of this change
189 TGameCycle serverTick;
190 impulse.serial(serverTick);
192 // read delta
193 IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer ); // unlike on the server, here there is only one unified CCDBSynchronized object
195 catch (const Exception &e)
198 BOMB( NLMISC::toString( "Problem while decoding a DB_UPDATE_PLR msg, skipped: %s", e.what() ), return );
202 template <class CInventoryCategoryTemplate>
203 void updateInventoryFromStream(NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges);
205 void impulseDatabaseUpdateBank(NLMISC::CBitMemStream &impulse)
207 uint32 bank = INVALID_CDB_BANK;
210 // get the egs tick of this change
211 TGameCycle serverTick;
212 impulse.serial(serverTick);
214 // decode bank
215 uint nbits;
216 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
217 impulse.serial( bank, nbits );
219 // read delta
220 IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
222 // read guild inventory update
223 if ( bank == CDBGuild )
225 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
228 catch (const Exception &e)
230 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:UPDATE_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
234 void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse)
236 uint32 bank = INVALID_CDB_BANK;
239 // get the egs tick of this change
240 TGameCycle serverTick;
241 impulse.serial(serverTick);
243 // decode bank
244 uint nbits;
245 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
246 impulse.serial( bank, nbits );
248 // read delta
249 IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
250 nldebug( "CDB: DB_GROUP:INIT_BANK %s", CDBBankNames[bank] );
252 // read guild inventory update
253 if ( bank == CDBGuild )
255 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
258 catch (const Exception &e)
260 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:INIT_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
264 void impulseDatabaseResetBank(NLMISC::CBitMemStream &impulse)
266 uint32 bank = INVALID_CDB_BANK;
269 // get the egs tick of this change
270 TGameCycle serverTick;
271 impulse.serial(serverTick);
273 // read the bank to reset
274 uint nbits;
275 FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
276 impulse.serial( bank, nbits );
278 // reset the bank
279 IngameDbMngr.resetBank( serverTick, bank );
280 nldebug( "CDB: DB_GROUP:RESET_BANK %s", CDBBankNames[bank] );
282 catch (const Exception &e)
284 BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:RESET_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
288 static void readPrivileges(NLMISC::CBitMemStream &impulse)
290 nlassert(impulse.isReading());
291 // nico : temporarily uses a try block here to avoid prb with people having updated client and not the server
294 impulse.serial(UserPrivileges);
296 catch(const EStreamOverflow &)
298 nlwarning("User privileges not serialised, assuming none");
299 UserPrivileges.clear();
303 void impulseNoUserChar(NLMISC::CBitMemStream &impulse)
305 // received NO_USER_CHAR
306 //nlinfo("impulseCallBack : Received CONNECTION:NO_USER_CHAR");
308 impulse.serial(ServerPeopleActive);
309 impulse.serial(ServerCareerActive);
310 readPrivileges(impulse);
311 impulse.serialCont(Mainlands);
312 CharacterSummaries.clear();
313 noUserChar = true;
315 LoginSM.pushEvent(CLoginStateMachine::ev_no_user_char);
317 updatePatcherPriorityBasedOnCharacters();
320 void impulseFarTP(NLMISC::CBitMemStream &impulse)
322 // received FAR_TP
323 TSessionId sessionId;
324 impulse.serial(sessionId);
325 //nlinfo("impulseCallback : Received CONNECTION:FAR_TP %u", sessionId.asInt());
326 bool bailOutIfSessionVanished;
327 impulse.serial(bailOutIfSessionVanished);
328 FarTP.requestFarTPToSession(sessionId, PlayerSelectedSlot, CFarTP::JoinSession, bailOutIfSessionVanished);
332 static std::string lookupSrcKeyFile(const std::string &src)
334 if (CFile::isExists("save/" + src)) return "save/" + src;
335 return CPath::lookup(src, false);
338 void copyKeySet(const std::string &srcPath, const std::string &destPath)
340 // can't use CFile copyFile here, because src may be in a bnp file
341 std::string srcStr;
342 srcStr.resize(CFile::getFileSize(srcPath));
343 if (srcStr.empty())
345 nlwarning("Can't copy keys from %s : file not found or empty");
346 return;
350 CIFile ifile(srcPath);
351 ifile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
352 COFile ofile(destPath);
353 ofile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
355 catch(const EStream &)
357 nlwarning("Couldn't copy %s to %s to create new character keyset", srcPath.c_str(), destPath.c_str());
361 void impulseUserChars(NLMISC::CBitMemStream &impulse)
363 // received USER_CHARS
364 //nlinfo("impulseCallBack : Received CONNECTION:USER_CHARS");
366 impulse.serial(ServerPeopleActive);
367 impulse.serial(ServerCareerActive);
368 // read characters summary
369 CharacterSummaries.clear();
370 impulse.serialCont (CharacterSummaries);
371 // read shard name summaries
372 std::vector<string> shardNames;
373 impulse.serialCont (shardNames);
374 CShardNames::getInstance().loadShardNames(shardNames);
375 // read privileges
376 readPrivileges(impulse);
377 impulse.serial(FreeTrial);
378 FreeTrial = false;
379 impulse.serialCont(Mainlands);
380 userChar = true;
382 LoginSM.pushEvent(CLoginStateMachine::ev_chars_received);
384 // Create the message for the server to select the first character.
385 /* CBitMemStream out;
386 if(GenericMsgHeaderMngr.pushNameToStream("CONNECTION:SELECT_CHAR", out))
388 CSelectCharMsg SelectCharMsg;
389 SelectCharMsg.c = 0; //TODO set here the character choosen by player
390 out.serial( SelectCharMsg );
391 NetMngr.push(out);
392 NetMngr.send(NetMngr.getCurrentServerTick());
393 // send CONNECTION:USER_CHARS
394 nldebug("impulseCallBack : CONNECTION:SELECT_CHAR sent");
396 else
397 nlwarning("impulseCallBack : unknown message name : 'CONNECTION:SELECT_CHAR'.");
399 noUserChar = true;
402 if (!NewKeysCharNameValidated.empty())
404 // if there's a new char for which a key set was wanted, create it now
405 for (uint k = 0; k < CharacterSummaries.size(); ++k)
407 if (toLower(CharacterSummaries[k].Name.toUtf8()) == toLower(NewKeysCharNameValidated))
409 // first, stripes server name
410 copyKeySet(lookupSrcKeyFile(GameKeySet), "save/keys_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
411 copyKeySet(lookupSrcKeyFile(RingEditorKeySet), "save/keys_r2ed_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
412 break;
416 updatePatcherPriorityBasedOnCharacters();
419 void impulseUserChar(NLMISC::CBitMemStream &impulse)
421 // received USER_CHAR
422 //nlinfo("impulseCallBack : Received CONNECTION:USER_CHAR");
424 // Serialize the message
425 COfflineEntityState posState;
426 extern uint8 ServerSeasonValue;
427 extern bool ServerSeasonReceived;
428 uint32 userRole;
429 CUserCharMsg::read( impulse, posState, ServerSeasonValue, userRole, IsInRingSession, HighestMainlandSessionId, CharFirstConnectedTime, CharPlayedTime );
430 ServerSeasonReceived = true; // set the season that will be used when selecting the continent from the position
432 if (UserEntity)
434 UserEntity->pos(CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f));
435 UserEntity->front(CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f));
436 UserEntity->dir(UserEntity->front());
437 UserEntity->setHeadPitch(0);
438 UserControls.resetCameraDeltaYaw();
439 //nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntity->pos().x,UserEntity->pos().y,UserEntity->pos().z,posState.Heading);
441 // Update the position for the vision.
442 NetMngr.setReferencePosition(UserEntity->pos());
444 else
446 UserEntityInitPos = CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f);
447 UserEntityInitFront = CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f);
448 //nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntityInitPos.x,UserEntityInitPos.y,UserEntityInitPos.z,posState.Heading);
450 // Update the position for the vision.
451 NetMngr.setReferencePosition(UserEntityInitPos);
454 UserCharPosReceived = true;
456 // Configure the ring editor
457 extern R2::TUserRole UserRoleInSession;
458 UserRoleInSession = R2::TUserRole::TValues(userRole);
459 ClientCfg.R2EDEnabled = IsInRingSession /*&& (UserRoleInSession.getValue() != R2::TUserRole::ur_player)*/;
460 // !!!Do NOT uncomment the following line do the ClientCfg.R2EDEnabled = IsInRingSession && (UserRoleInSession != R2::TUserRole::ur_player);
461 // even with UserRoleInSession R2::TUserRole::ur_player the ring features must be activated
462 // because if the ring is not activated the dss do not know the existence of the player
463 // So we can not kick him, tp to him, tp in to next act ....
464 nldebug( "EnableR2Ed = %u, IsInRingSession = %u, UserRoleInSession = %u", (uint)ClientCfg.R2EDEnabled, (uint)IsInRingSession, userRole );
466 updatePatcherPriorityBasedOnCharacters();
469 void impulseCharNameValid(NLMISC::CBitMemStream &impulse)
471 //nlinfo("impulseCallBack : Received CONNECTION:VALID_NAME");
472 uint8 nTmp;
473 impulse.serial(nTmp);
474 CharNameValid = ((nTmp != 0) ? true : false);
475 CharNameValidArrived = true;
476 if (CharNameValid) NewKeysCharNameValidated = NewKeysCharNameWanted;
480 void checkHandshake( NLMISC::CBitMemStream &impulse )
482 // Decode handshake to check versions
483 uint16 handshakeVersion;
484 uint16 itemSlotVersion;
485 impulse.serial( handshakeVersion );
486 if ( handshakeVersion > 0 )
487 nlerror( "Server handshake version is more recent than client one" );
488 impulse.serial( itemSlotVersion );
489 if ( itemSlotVersion != INVENTORIES::CItemSlot::getVersion() )
490 nlerror( "Handshake: itemSlotVersion mismatch (S:%hu C:%hu)", itemSlotVersion, INVENTORIES::CItemSlot::getVersion() );
494 void impulseServerReady(NLMISC::CBitMemStream &impulse)
496 // received CONNECTION:READY
497 //nlinfo("impulseCallBack : Received CONNECTION:READY");
499 serverReceivedReady = true;
501 checkHandshake( impulse );
503 LoginSM.pushEvent(CLoginStateMachine::ev_ready_received);
506 void impulseShardId(NLMISC::CBitMemStream &impulse)
508 // received SHARD_ID
510 uint32 shardId;
511 impulse.serial(shardId);
512 ShardId = shardId;
514 string webHost;
515 impulse.serial(webHost);
516 if (!webHost.empty())
518 WebServer = webHost;
521 nlinfo("WEB: Received SHARD_ID %d, web hosted at '%s', using '%s'", shardId, webHost.c_str(), WebServer.c_str());
524 void impulseServerQuitOk(NLMISC::CBitMemStream &impulse)
526 // receive CONNECTION:SERVER_QUIT_OK
527 if (FarTP.isFarTPInProgress())
529 FarTP.onServerQuitOk();
531 else
533 // ensure first a quit request is really asked
534 if(game_exit_request)
536 // quit!
537 game_exit= true;
538 ryzom_exit= true;
543 void impulseServerQuitAbort(NLMISC::CBitMemStream &impulse)
545 // receive CONNECTION:SERVER_QUIT_ABORT
546 if (FarTP.isFarTPInProgress())
548 FarTP.onServerQuitAbort();
550 else
552 // abort any quit request
553 game_exit_request= false;
554 ryzom_exit_request= false;
558 void impulseMailNotification(NLMISC::CBitMemStream &impulse)
560 if (PermanentlyBanned) return;
561 // receive CONNECTION:MAIL_AVAILABLE
562 CInterfaceManager::getInstance()->notifyMailAvailable();
565 void impulseForumNotification(NLMISC::CBitMemStream &impulse)
567 if (PermanentlyBanned) return;
568 // receive CONNECTION:GUILD_MESSAGE_AVAILABLE
569 CInterfaceManager::getInstance()->notifyForumUpdated();
573 void impulsePermanentBan(NLMISC::CBitMemStream &impulse)
575 uint64 magicNumber;
576 impulse.serial(magicNumber);
577 if (magicNumber != PermanentBanMSGMagicNumber) return; // bad msg
578 setPermanentBanMarkers(true);
579 applyPermanentBanPunishment();
580 PermanentlyBanned = true;
583 void impulsePermanentUnban(NLMISC::CBitMemStream &impulse)
585 uint64 magicNumber;
586 impulse.serial(magicNumber);
587 if (magicNumber != PermanentUnbanMSGMagicNumber) return; // bad msg
588 setPermanentBanMarkers(false);
589 PermanentlyBanned = false;
590 if (UserEntity)
592 // allows to walk / run again
593 UserEntity->walkVelocity(ClientCfg.Walk);
594 UserEntity->runVelocity(ClientCfg.Run);
599 // ***************************************************************************
600 class CInterfaceChatDisplayer : public CClientChatManager::IChatDisplayer
602 public:
603 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);
604 virtual void displayTell(/*TDataSetIndex senderIndex, */const std::string &ucstr, const std::string &senderName);
605 virtual void clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex);
607 private:
608 // Add colorization tag for sender name
609 void colorizeSender(string &text, const string &senderName, CRGBA baseColor);
612 static CInterfaceChatDisplayer InterfaceChatDisplayer;
614 void CInterfaceChatDisplayer::colorizeSender(string &text, const string &senderName, CRGBA baseColor)
616 // find the sender/text separator to put color tags
617 string::size_type pos = senderName.length() - 1;
618 if (pos != string::npos)
620 string str;
622 CInterfaceProperty prop;
623 prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
625 CChatWindow::encodeColorTag(prop.getRGBA(), str, false);
627 str += text.substr(0, pos+1);
629 CChatWindow::encodeColorTag(baseColor, str, true);
631 str += text.substr(pos+1);
633 text = str;
637 // display a chat from network to interface
638 void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, const std::string &ucstr, const std::string &rawMessage, CChatGroup::TGroupType mode, NLMISC::CEntityId dynChatId, std::string &senderName, uint bubbleTimer)
640 CInterfaceManager *pIM = CInterfaceManager::getInstance();
641 string finalString;
642 string stringCategory = getStringCategory(ucstr, finalString);
644 bool bubbleWanted = true;
646 // Subtract rawMessage from ucstr so that the 'sender' part remains.
647 string senderPart = ucstr.substr(0, ucstr.length() - rawMessage.length());
649 // search a "{no_bubble}" tag
651 string::size_type index = finalString.find("{no_bubble}");
652 const size_t tokenSize= 11; // length of "{no_bubble}"
653 if (index != string::npos)
655 bubbleWanted = false;
656 finalString = finalString.substr(0, index) + finalString.substr(index+tokenSize,finalString.size());
661 // **** get color
662 CRGBA col;
663 if (mode != CChatGroup::system)
665 // Remove all {break}
666 for(;;)
668 string::size_type index = finalString.find("{break}");
669 if (index == string::npos) break;
670 finalString = finalString.substr(0, index) + finalString.substr(index+7,finalString.size());
673 // select DB
674 sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
675 clamp(dbIndex, (sint32)0 , (sint32)CChatGroup::MaxDynChanPerPlayer);
676 string entry="UI:SAVE:CHAT:COLORS:";
677 switch(mode)
679 case CChatGroup::dyn_chat: entry+="DYN:" + NLMISC::toString(dbIndex); break;
680 case CChatGroup::say: entry+="SAY"; break;
681 case CChatGroup::shout: entry+="SHOUT"; break;
682 case CChatGroup::team: entry+="GROUP"; break;
683 case CChatGroup::guild: entry+="CLADE"; break;
684 case CChatGroup::civilization: entry+="CIVILIZATION"; break;
685 case CChatGroup::territory: entry+="TERRITORY"; break;
686 case CChatGroup::universe: entry+="UNIVERSE_NEW"; break;
687 case CChatGroup::region: entry+="REGION"; break;
688 case CChatGroup::tell: entry+="TELL"; break;
689 default: nlwarning("unknown group type"); return;
692 // read DB
693 CInterfaceProperty prop;
694 prop.readRGBA(entry.c_str()," ");
695 col = prop.getRGBA();
697 // Override color if the string contains the color
698 if (!stringCategory.empty() && stringCategory != "SYS")
700 map<string, CClientConfig::SSysInfoParam>::const_iterator it;
701 it = ClientCfg.SystemInfoParams.find(toLowerAscii(stringCategory));
702 if (it != ClientCfg.SystemInfoParams.end())
704 col = it->second.Color;
709 if (stringCategory == "emt")
711 bubbleWanted = false;
714 if (mode != CChatGroup::system)
716 // find the sender/text separator to put color tags
717 if (senderPart.empty() && stringCategory == "emt")
719 size_t pos = finalString.find(": ", 0);
720 if (pos != string::npos)
722 senderPart = finalString.substr(0, pos + 2);
725 colorizeSender(finalString, senderPart, col);
728 // play associated fx if any
729 if( !stringCategory.empty() )
731 map<string, CClientConfig::SSysInfoParam>::const_iterator it;
732 it = ClientCfg.SystemInfoParams.find( toLowerAscii(stringCategory) );
733 if( it != ClientCfg.SystemInfoParams.end() )
735 if( !(*it).second.SysInfoFxName.empty() )
737 NL3D::UParticleSystemInstance sysInfoFx = FXMngr.instantFX((*it).second.SysInfoFxName);
738 if( !sysInfoFx.empty() )
740 sysInfoFx.setClusterSystem( UserEntity->getClusterSystem() );
741 sysInfoFx.setPos( UserEntity->pos() );
743 else
745 nlwarning("<CInterfaceChatDisplayer::displayChat> Can't set chat fx %s",(*it).second.SysInfoFxName.c_str());
751 // **** redirect to the correct interface output
752 if( stringCategory != "bbl" )
754 bool windowVisible;
755 if (mode == CChatGroup::system)
757 pIM->displaySystemInfo(finalString, stringCategory);
759 else if (mode == CChatGroup::guild)
761 PeopleInterraction.ChatInput.Guild.displayMessage(finalString, col, 2, &windowVisible);
763 else if (mode == CChatGroup::team)
765 PeopleInterraction.ChatInput.Team.displayMessage(finalString, col, 2, &windowVisible);
767 else if (mode == CChatGroup::region)
769 PeopleInterraction.ChatInput.Region.displayMessage(finalString, col, 2, &windowVisible);
771 else if (mode == CChatGroup::universe)
773 PeopleInterraction.ChatInput.Universe.displayMessage(finalString, col, 2, &windowVisible);
775 else if (mode == CChatGroup::dyn_chat)
777 // retrieve the DBIndex from the dynamic chat id
778 sint32 dbIndex= ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
779 // if found, display, else discarded
780 if(dbIndex >= 0 && dbIndex < CChatGroup::MaxDynChanPerPlayer)
782 PeopleInterraction.ChatInput.DynamicChat[dbIndex].displayMessage(finalString, col, 2, &windowVisible);
784 // Add dynchannel info before text so that the chat log will show the correct string.
785 CCDBNodeLeaf* node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_DYN_CHANNEL_NAME_IN_CHAT_CB", false);
786 if (pIM->getLogState())
788 // Add dyn chan number before string
789 string prefix = "[" + NLMISC::toString(dbIndex) + "]";
790 // Find position to put the new string
791 // After timestamp?
792 size_t pos = finalString.find("]");
793 size_t colonpos = finalString.find(": @{");
794 // If no ] found or if found but after the colon (so part of the user chat)
795 if (pos == string::npos || (colonpos < pos))
797 // No timestamp, so put it right after the color and add a space
798 pos = finalString.find("}");;
799 prefix += " ";
801 finalString = finalString.substr(0, pos + 1) + prefix + finalString.substr(pos + 1);
803 if (node && node->getValueBool())
805 uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(dbIndex);
806 string title;
807 STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
808 prefix = (title.empty() ? "" : " ") + title;
809 pos = finalString.find("] ");
810 finalString = finalString.substr(0, pos) + prefix + finalString.substr(pos);
814 else
816 nlwarning("Dynamic chat %s not found for message: %s", dynChatId.toString().c_str(), finalString.c_str());
819 else
821 string::size_type index = finalString.find("<BPFX>");
822 if (index != string::npos)
824 bubbleWanted = false;
825 finalString = finalString.substr(index+6,finalString.size());
826 string::size_type index2 = finalString.find(string(" "));
827 string playerName;
828 if (index2 < (finalString.size()-3))
830 playerName = finalString.substr(0,index2);
831 finalString = finalString.substr(index2+1,finalString.size());
833 if (!senderName.empty())
835 CEntityCL *senderEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(senderName), true, true);
836 if (senderEntity)
838 if (senderEntity->Type != CEntityCL::Player)
840 if (playerName.empty())
842 senderEntity->removeStateFx();
843 senderEntity->setStateFx(finalString);
844 nlinfo("empty");
846 else
848 CEntityCL *destEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(playerName), false, true);
849 if (destEntity)
851 destEntity->removeStateFx();
852 destEntity->setStateFx(finalString);
853 nlinfo("no empty");
859 finalString.clear();
861 else
863 PeopleInterraction.ChatInput.AroundMe.displayMessage(finalString, col, 2, &windowVisible);
866 // if tell, bkup sendername
867 if (mode == CChatGroup::tell && windowVisible && !senderName.empty())
869 PeopleInterraction.LastSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
873 // received CHAT
874 //nldebug("<impulseChat> Received CHAT : %s with category %s",finalString.toString().c_str(),stringCategory.c_str());
877 // **** Process chat entry for the bubbles
878 // todo hulud : registering a chat callback would be better than calling this hardcoded action handler
879 string finalRawMessage;
880 // remove color qualifier from raw string
881 getStringCategory(rawMessage, finalRawMessage);
882 if (bubbleWanted)
884 InSceneBubbleManager.chatOpen(compressedSenderIndex, finalRawMessage, bubbleTimer);
887 // Log
889 string channel;
890 if (mode == CChatGroup::dyn_chat)
892 sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
893 clamp(dbIndex, (sint32)0 , (sint32)CChatGroup::MaxDynChanPerPlayer);
895 channel = "dyn" + toString(dbIndex);
897 else
899 channel = CChatGroup::groupTypeToString(mode);
900 if (channel.empty())
902 channel = "#" + toString((uint32)mode);
905 if (!stringCategory.empty() && NLMISC::compareCaseInsensitive(stringCategory.c_str(), "SYS")) // Not empty and not 'SYS'
907 channel = channel + "/" + stringCategory;
909 pIM->log (finalString, channel);
914 // display a tell from network to interface
915 void CInterfaceChatDisplayer::displayTell(/*TDataSetIndex senderIndex, */const std::string &ucstr, const std::string &senderName)
918 string finalString = ucstr;
920 // for now, '&' are removed by server so use another format until a special msg is made
921 if (strFindReplace(finalString, "<R2_INVITE>", string()))
923 CLuaManager::getInstance().executeLuaScript("RingAccessPoint:forceRefresh()");
927 CInterfaceProperty prop;
928 prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
929 bool windowVisible;
931 string goodSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
933 // The sender part is up to and including the first ":" after the goodSenderName
934 string::size_type pos = finalString.find(goodSenderName);
935 pos = finalString.find(':', pos);
936 pos = finalString.find(' ', pos);
937 string senderPart = finalString.substr(0, pos+1);
938 colorizeSender(finalString, senderPart, prop.getRGBA());
940 PeopleInterraction.ChatInput.Tell.displayTellMessage(/*senderIndex, */finalString, goodSenderName, prop.getRGBA(), 2, &windowVisible);
941 CInterfaceManager::getInstance()->log(finalString, CChatGroup::groupTypeToString(CChatGroup::tell));
943 // Open the free teller window
944 CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
945 if (pCGW != NULL)
946 pCGW->setActiveFreeTeller(goodSenderName);
948 if (windowVisible && !goodSenderName.empty())
949 PeopleInterraction.LastSenderName = goodSenderName;
952 // clear a channel
953 void CInterfaceChatDisplayer::clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex)
955 if (mode == CChatGroup::guild) PeopleInterraction.ChatInput.Guild.clearMessages();
956 else if (mode == CChatGroup::team) PeopleInterraction.ChatInput.Team.clearMessages();
957 else if (mode == CChatGroup::region) PeopleInterraction.ChatInput.Region.clearMessages();
958 else if (mode == CChatGroup::arround) PeopleInterraction.ChatInput.AroundMe.clearMessages();
959 else if (mode == CChatGroup::universe) PeopleInterraction.ChatInput.Universe.clearMessages();
960 else if (mode == CChatGroup::dyn_chat)
962 // if correct dbIndex, clear
963 if(dynChatDbIndex<CChatGroup::MaxDynChanPerPlayer)
964 PeopleInterraction.ChatInput.DynamicChat[dynChatDbIndex].clearMessages();
965 else
966 nlwarning("Dynamic chat %d not found for clearing", dynChatDbIndex);
969 // don't support other for now (NB: actually used only for dyn_chat)
973 // ***************************************************************************
974 void impulseChat(NLMISC::CBitMemStream &impulse)
976 ChatMngr.processChatString(impulse, InterfaceChatDisplayer);
979 void impulseChat2(NLMISC::CBitMemStream &impulse)
981 ChatMngr.processChatString2(impulse, InterfaceChatDisplayer);
984 void impulseTell(NLMISC::CBitMemStream &impulse)
986 ChatMngr.processTellString(impulse, InterfaceChatDisplayer);
989 void impulseFarTell(NLMISC::CBitMemStream &impulse)
991 ChatMngr.processFarTellString(impulse, InterfaceChatDisplayer);
994 void impulseTell2(NLMISC::CBitMemStream &impulse)
996 ChatMngr.processTellString2(impulse, InterfaceChatDisplayer);
999 void impulseDynString(NLMISC::CBitMemStream &impulse)
1001 ChatMngr.processChatStringWithNoSender(impulse, CChatGroup::system, InterfaceChatDisplayer);
1004 void inpulseDynStringInChatGroup(NLMISC::CBitMemStream &impulse)
1006 CChatGroup::TGroupType type = CChatGroup::say;
1007 impulse.serialEnum(type);
1008 ChatMngr.processChatStringWithNoSender(impulse, type, InterfaceChatDisplayer);
1011 // ***************************************************************************
1012 //void impulseAddDynStr(NLMISC::CBitMemStream &impulse)
1014 // bool huff = false;
1015 // impulse.serialBit(huff);
1017 // uint32 index;
1018 // ucstring ucstr; // OLD
1020 // impulse.serial( index );
1021 // impulse.serial( ucstr );
1023 // vector<bool> code;
1024 // if( huff )
1025 // {
1026 // impulse.serialCont( code );
1027 // }
1028 // if (PermanentlyBanned) return;
1029 // #ifdef OLD_STRING_SYSTEM
1030 // ChatMngr.getDynamicDB().add( index, ucstr, code );
1031 // #else
1032 // nlwarning( "// TRAP // WE MUST NEVER CALL THIS IMPULE ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!" );
1033 // #endif
1035 // // received ADD_DYN_STR
1036 // nlinfo("impulseCallBack : Received ADD_DYN_STR : adding %s at index %d",ucstr.toString().c_str(),index);
1039 string getInterfaceNameFromId (sint botType, sint interfaceId)
1041 string interfaceName = "ui:interface:bot_chat_";
1043 switch (botType)
1045 case 0: interfaceName += "figurant_"; break;
1046 case 1: interfaceName += "figurant_presse_"; break;
1047 case 2: interfaceName += "chef_village_"; break;
1048 default: interfaceName += "figurant_"; break;
1051 switch (interfaceId)
1053 case BOTCHATTYPE::Intro: interfaceName += "intro"; break;
1054 case BOTCHATTYPE::FriendlyMainPage: interfaceName += "friendly_main"; break;
1055 case BOTCHATTYPE::NeutralMainPage: interfaceName += "neutral_main"; break;
1056 case BOTCHATTYPE::NastyMainPage: interfaceName += "nasty_main"; break;
1057 case BOTCHATTYPE::MoreNewsPage: interfaceName += "more_news"; break;
1058 case BOTCHATTYPE::Done: nlinfo ("end of bot chat"); interfaceName.clear(); break;
1060 return interfaceName;
1063 static char *shortNews[] = {
1064 "The wind is sour and brings only bad tidings...", "Kitins have been sighted near the village!", "",
1065 "The tribe of the Black Circle has recently", "increased its activities in our region.", "",
1066 "The Black Circle has made an incursion", "into our territory!", "",
1067 "The Black Circle has been sighted near one", "of our forward posts, deep in dangerous territory.", "",
1068 "The tide has washed up evil news, friend.", "The Black Circle is active in our region.", "",
1069 "Our people suffer from a debilitating shortage.", "We are in sore need of KamiBast.", "",
1070 "The economy is slow and our reserve of", "Live Seed low.", "",
1071 "We are in sore need of Live Seed", "If there is a Goo epidemic, we shall all perish!", "",
1072 "Our master mages have gotten wind of", "the growing Kami discontentment", "",
1075 static char *longNews[] = {
1076 "These powerful predators haven't come this near", "to the village since their devastating attack", "over 15 seasons ago!",
1077 "They are after more KamiBast", "for their occult practices.", "",
1078 "They have captured", "2 of our fortifications in the bush!", "",
1079 "They have taken over one of our richest sources", "of KamiBast, and are exploiting it", "for their own occult purposes.",
1080 "They now hold an important source", "of Live Seed hostage,", "close to one of our forward posts.",
1081 "We use the magical properties of KamiBast and", "its unusually rich fibers for all our crafts.", "",
1082 "If we don't harvest new Seed soon,", "we will have no way of purchasing goods", "and resources, beyond what we produce ourselves",
1083 "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.",
1084 "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.",
1088 void setFakeNews ()
1090 char *table[] = { "figurant", "chef_village", "garde", "commercant" };
1092 sint rnd = rand ()%(sizeof(shortNews)/sizeof(shortNews[0])/3);
1093 rnd;
1095 for (uint i = 0; i < sizeof(table)/sizeof(table[0]); i++)
1097 { // set test for the friendly main
1098 string iname;
1099 iname = "ui:interface:bot_chat_";
1100 iname += table[i];
1101 iname += "_friendly_main";
1103 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1104 if (inter == NULL)
1106 nlwarning ("cant find interface 's%'", iname.c_str());
1107 continue;
1110 CViewText *inter2 = (CViewText *)inter->getView("title0");
1111 nlassert (inter2 != NULL);
1112 inter2->setText(ucstring(shortNews[rnd*3])); // OLD
1114 CViewText *inter3 = (CViewText *)inter->getView("title1");
1115 nlassert (inter3 != NULL);
1116 inter3->setText(ucstring(shortNews[rnd*3+1])); // OLD
1118 CViewText *inter4 = (CViewText *)inter->getView("title2");
1119 nlassert (inter4 != NULL);
1120 inter4->setText(ucstring(shortNews[rnd*3+2])); // OLD
1122 { // set test for the neutral main
1123 string iname;
1124 iname = "ui:interface:bot_chat_";
1125 iname += table[i];
1126 iname += "_neutral_main";
1128 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1129 if (inter == NULL)
1131 nlwarning ("cant find interface 's%'", iname.c_str());
1132 continue;
1135 CViewText *inter2 = (CViewText *)inter->getView("title0");
1136 nlassert (inter2 != NULL);
1137 inter2->setText(ucstring(shortNews[rnd*3])); // OLD
1139 CViewText *inter3 = (CViewText *)inter->getView("title1");
1140 nlassert (inter3 != NULL);
1141 inter3->setText(ucstring(shortNews[rnd*3+1])); // OLD
1143 { // set test for the more news
1144 string iname;
1145 iname = "ui:interface:bot_chat_";
1146 iname += table[i];
1147 iname += "_more_news";
1149 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(iname);
1150 if (inter == NULL)
1152 nlwarning ("cant find interface 's%'", iname.c_str());
1153 continue;
1156 CViewText *inter2 = (CViewText *)inter->getView("title0");
1157 nlassert (inter2 != NULL);
1158 inter2->setText(ucstring(longNews[rnd*3])); // OLD
1160 CViewText *inter3 = (CViewText *)inter->getView("title1");
1161 nlassert (inter3 != NULL);
1162 inter3->setText(ucstring(longNews[rnd*3+1])); // OLD
1164 CViewText *inter4 = (CViewText *)inter->getView("title2");
1165 nlassert (inter4 != NULL);
1166 inter4->setText(ucstring(longNews[rnd*3+2])); // OLD
1176 //=========================================
1177 /** Temp setup for choice list
1180 static void setupBotChatChoiceList(CInterfaceGroup *botChatGroup)
1182 // Temp for test. Should then be read from server msg
1183 std::vector<string> choices;
1184 for(uint k = 0; k < 90; ++k)
1186 choices.push_back("Choice " + toString(k));
1188 CBotChat::setChoiceList(botChatGroup, choices, false);
1192 //=========================================
1193 /** Temp setup for description list
1196 static void setupBotChatDescription(CInterfaceGroup *botChatGroup)
1198 string desc;
1199 for(uint k = 0; k < 90; ++k)
1201 desc += "This is a multi line description. ";
1203 CBotChat::setDescription(botChatGroup, desc);
1207 //=========================================
1208 /** Temp setup for bot chat gift
1211 static void setupBotChatBotGift(CInterfaceGroup *botChatGroup)
1213 // create dummy item in the db
1214 CInterfaceManager *im = CInterfaceManager::getInstance();
1215 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:0:SHEET")->setValue32(CSheetId("ai_flesh_poisson.item").asInt());
1216 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:0:QUALITY")->setValue32(0);
1217 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:1:SHEET")->setValue32(CSheetId("fyros_sword_lvl_01_05.item").asInt());
1218 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:INVENTORY:20:1:QUALITY")->setValue32(2);
1219 CBotChat::setBotGift(botChatGroup, "Thanks to have succeeded the mission", "Here's your reward", "The bot has taken the object quest from your inventory");
1223 //-----------------------------------------------
1224 // impulseBotChatSetInterface :
1225 //-----------------------------------------------
1226 #if 0
1227 void impulseBotChatSetInterface(NLMISC::CBitMemStream &impulse)
1229 // received ADD_DYN_STR
1231 CEntityId user;
1232 uint32 happyness;
1233 BOTCHATTYPE::TBotChatInterfaceId interfaceId;
1234 bool hasNews;
1236 impulse.serial (user);
1237 impulse.serial (happyness);
1239 // impulse.serialEnum (interfaceId);
1240 uint16 interfId;
1241 impulse.serial(interfId);
1242 interfaceId = (BOTCHATTYPE::TBotChatInterfaceId)(interfId&0xff);
1243 uint8 botType = (interfId>>8) & 0xff;
1245 impulse.serial (hasNews);
1247 nldebug("impulseCallBack : Received BOT_CHAT:SET_INTERFACE interface %d, have news %s, happy %d, bottype %hu", interfaceId, hasNews?"yes":"no", happyness,(uint16)botType);
1249 string stringId;
1250 vector<uint64> args;
1251 if (hasNews)
1254 /* impulse.serial (stringId);
1255 impulse.serialCont (args);
1256 nlinfo ("receive the news '%s' with %d args", stringId.c_str(), args.size());
1258 // TEMP FOR THE DEMO, DON'T USE THE NETWORK NEW BUT SELECT A NEWS HERE
1260 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId("ui:interface:bot_chat_intro");
1261 nlassert (inter != NULL);
1262 inter->setActive(true);
1264 CViewText *inter2 = (CViewText *)inter->getView("hi");
1265 nlassert (inter2 != NULL);
1266 inter2->NetworkTextId.setString("IOS_NEWS_FOOTBALL_SHORT_EEII", &ChatMngr);
1267 inter2->NetworkTextId.Args.push_back(10);
1268 inter2->NetworkTextId.Args.push_back(20);
1269 inter2->NetworkTextId.Args.push_back(1);
1270 inter2->NetworkTextId.Args.push_back(2);
1271 */ }
1273 // FOR THE DEMO, find and set a fake news:
1274 // setFakeNews ();
1276 string interfaceName = getInterfaceNameFromId (botType, interfaceId);
1278 if(interfaceName.empty())
1280 nlwarning ("Received an unknown bot chat interface %d", interfaceId);
1282 else
1284 CInterfaceGroup *inter = CWidgetManager::getInstance()->getWindowFromId(interfaceName);
1285 if (inter == NULL)
1287 nlwarning ("Can't find interface name '%s' %d", interfaceName.c_str(), interfaceId);
1289 else
1291 CInterfaceManager::getInstance()->setBotChatWin(inter);
1292 if (inter->getActive())
1294 nlwarning ("Interface %s is already active, not normal!", interfaceName.c_str());
1296 else
1298 nlinfo ("server want to me display the bot chat interface %s %d", interfaceName.c_str(), interfaceId);
1299 inter->setActive(true);
1304 #endif
1308 //-----------------------------------------------
1309 // impulseBeginTrade :
1310 //-----------------------------------------------
1311 void impulseBeginTrade(NLMISC::CBitMemStream &impulse)
1313 if (PermanentlyBanned) return;
1314 //open trade window
1315 CInterfaceGroup* win = CWidgetManager::getInstance()->getWindowFromId("ui:interface:trade");
1316 if (!win)
1318 nlwarning("invalid interface ui:interface:trade");
1319 return;
1321 win->setActive(true);
1324 //-----------------------------------------------
1325 // impulseBuyPrice :
1326 //-----------------------------------------------
1327 void impulseBuyPrice(NLMISC::CBitMemStream &impulse)
1329 uint16 botChatSession;
1330 uint32 sheetID;
1331 uint16 quality;
1332 uint64 price;
1333 impulse.serial(botChatSession);
1334 impulse.serial(price);
1335 impulse.serial(sheetID);
1336 impulse.serial(quality);
1337 // no more used
1340 //-----------------------------------------------
1341 // impulseDynChatOpen
1342 //-----------------------------------------------
1343 void impulseDynChatOpen(NLMISC::CBitMemStream &impulse)
1345 uint32 BotUID; // Compressed Index
1346 uint32 BotName; // Server string
1347 vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
1348 impulse.serial(BotUID);
1349 impulse.serial(BotName);
1350 impulse.serialCont(DynStrs);
1352 if (PermanentlyBanned) return;
1354 /* string sTmp = "impulseCallback : Received BOTCHAT:DYNCHAT_OPEN BotUID:";
1355 sTmp += toString(BotUID) + " BotName:";
1356 sTmp += toString(BotName) + " DynStrs:";
1357 for (uint32 i = 0; i < DynStrs.size(); ++i)
1359 sTmp += toString(DynStrs[i]);
1360 if (i != DynStrs.size()-1) sTmp += ",";
1362 nlinfo(sTmp.c_str());*/
1364 InSceneBubbleManager.dynChatOpen(BotUID, BotName, DynStrs);
1367 //-----------------------------------------------
1368 // impulseDynChatClose
1369 //-----------------------------------------------
1370 void impulseDynChatClose(NLMISC::CBitMemStream &impulse)
1372 uint32 BotUID; // Compressed Index
1373 impulse.serial(BotUID);
1374 if (PermanentlyBanned) return;
1375 //nlinfo("impulseCallback : Received BOTCHAT:DYNCHAT_CLOSE BotUID:"+toString(BotUID));
1376 InSceneBubbleManager.dynChatClose(BotUID);
1379 //-----------------------------------------------
1380 // impulseBeginCast:
1381 //-----------------------------------------------
1382 void impulseBeginCast(NLMISC::CBitMemStream &impulse)
1384 //open cast window
1385 uint32 begin,end;
1386 impulse.serial(begin);
1387 impulse.serial(end);
1388 if (PermanentlyBanned) return;
1389 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
1390 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:SPELL_CAST")->setValue32(1);
1391 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CAST_BEGIN")->setValue32(begin);
1392 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CAST_END")->setValue32(end);
1397 //-----------------------------------------------
1398 // impulseCorrectPos :
1399 // Message from the server to correct the user position because he is not at the same position on the server..
1400 //-----------------------------------------------
1401 void impulseCorrectPos(NLMISC::CBitMemStream &impulse)
1403 // TP:CORRECT
1404 //nlinfo("impulseCallback : Received TP:CORRECT");
1405 sint32 x, y, z;
1406 impulse.serial(x);
1407 impulse.serial(y);
1408 impulse.serial(z);
1409 nlinfo("impulseCorrectPos: new user position %d %d %d", x, y, z);
1411 if(UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
1413 if (x == 0) // Get SpeedAdjustement
1415 UserEntity->setSpeedServerAdjust(-0.2f);
1417 else
1419 // Compute the destination.
1420 CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
1421 // Update the position for the vision.
1422 NetMngr.setReferencePosition(dest);
1423 // Change the user poisition.
1424 UserEntity->correctPos(dest);
1427 }// impulseCorrectPos //
1429 class CDummyProgress : public IProgressCallback
1431 void progress (float /* value */) {}
1434 //-----------------------------------------------
1435 // impulseTP :
1436 // Message from the server to teleport the user.
1437 // \warning This function remove the current target. Do no use to correct a position.
1438 //-----------------------------------------------
1439 void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason);
1440 void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason);
1442 void impulseTP(NLMISC::CBitMemStream &impulse)
1444 impulseTPCommon(impulse, false);
1447 void impulseTPWithSeason(NLMISC::CBitMemStream &impulse)
1449 impulseTPCommon(impulse, true);
1452 struct SQueuedTP
1454 NLMISC::CBitMemStream Impulse;
1455 bool HasSeason;
1457 SQueuedTP(const NLMISC::CBitMemStream &impulse, bool hasSeason)
1458 :Impulse(impulse), HasSeason(hasSeason)
1463 // note - this method added by Sadge and Hamster to deal with unexplained recursive calls to impulseTPCommon
1464 // these calls are provoked by the net manager update which is called during loading
1465 void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason)
1467 CNiceInputAuto niceInputs;
1468 static std::list<SQueuedTP> queuedTPs;
1469 SQueuedTP thisTP(impulse,hasSeason);
1470 queuedTPs.push_back(thisTP);
1472 BOMB_IF(queuedTPs.size()!=1,NLMISC::toString("Queueing recursive TPs depth=%u",queuedTPs.size()),return);
1474 while(!queuedTPs.empty())
1476 impulseTPCommon2(queuedTPs.front().Impulse,queuedTPs.front().HasSeason);
1477 queuedTPs.pop_front();
1483 void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason)
1485 // choose a default screen if not setuped
1486 if (LoadingBackground != ResurectKamiBackground && LoadingBackground != ResurectKaravanBackground
1487 && LoadingBackground != TeleportKamiBackground && LoadingBackground != TeleportKaravanBackground)
1488 LoadingBackground = ElevatorBackground;
1489 // if resurect but user not dead, choose default. NB: this is a bug, the tp impulse should tell
1490 // which background to choose. \todo yoyo: this is a temp fix
1491 if (UserEntity && !UserEntity->isDead() && (LoadingBackground == ResurectKamiBackground || LoadingBackground == ResurectKaravanBackground))
1492 LoadingBackground = ElevatorBackground;
1494 // Play music according to the background
1495 if (SoundMngr)
1497 LoadingMusic.clear();
1498 switch (LoadingBackground)
1500 case TeleportKamiBackground:
1501 LoadingMusic = ClientCfg.KamiTeleportMusic;
1502 break;
1503 case TeleportKaravanBackground:
1504 LoadingMusic = ClientCfg.KaravanTeleportMusic;
1505 break;
1506 case ResurectKamiBackground:
1507 case ResurectKaravanBackground:
1508 // TODO: Resurrect music
1509 break;
1510 default:
1511 LoadingMusic = ClientCfg.TeleportLoadingMusic;
1512 break;
1515 // start to play
1516 SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true);
1519 // Create the loading texture.
1520 beginLoading (LoadingBackground);
1522 // No ESCAPE key
1523 UseEscapeDuringLoading = false;
1525 // Change the tips
1526 selectTipsOfTheDay (rand());
1528 // start progress bar and display background
1529 ProgressBar.reset (BAR_STEP_TP);
1530 string nmsg("Loading...");
1531 ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) );
1534 // received ADD_DYN_STR
1535 nlinfo("impulseTP: received a request for a TP.");
1536 sint32 x, y, z;
1537 impulse.serial(x);
1538 impulse.serial(y);
1539 impulse.serial(z);
1540 bool useHeading;
1541 impulse.serialBit( useHeading );
1542 // Is there an orientation too ?
1543 if( useHeading )
1545 float angle;
1546 impulse.serial(angle);
1547 nlinfo("impulseTP: to %d %d %d %f", x, y, z, angle);
1548 CVector ori = CVector((float)cos(angle), (float)sin(angle), 0.0f);
1549 ori.normalize();
1550 UserEntity->dir(ori, false, false);
1551 UserEntity->front(ori, false, false);
1552 UserEntity->setHeadPitch(0);
1553 UserControls.resetCameraDeltaYaw();
1555 else
1556 nlinfo("impulseTP: to %d %d %d", x, y, z);
1558 if (hasSeason)
1560 extern uint8 ServerSeasonValue;
1561 extern bool ServerSeasonReceived;
1562 impulse.serial(ServerSeasonValue);
1563 ServerSeasonReceived = true;
1566 if (ClientCfg.R2EDEnabled)
1568 R2::getEditor().tpReceived();
1571 // Compute the destination.
1572 CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
1573 // Update the position for the vision.
1574 NetMngr.setReferencePosition(dest);
1575 // Change the position of the entity and in Pacs.
1576 UserEntity->pos(dest);
1578 // Fade out the Game Sound
1579 if(SoundMngr)
1580 SoundMngr->fadeOutGameSound(ClientCfg.SoundTPFade);
1583 R2::TTeleportContext tpContext = R2::TPContext_Unknown;
1585 string tpReason;
1586 string tpCancelText;
1590 R2::TR2TpInfos tpInfos;
1591 impulse.serial(tpInfos);
1594 if ( tpInfos.UseTpMessage)
1596 tpReason = CI18N::get(tpInfos.TpReasonId);
1598 uint32 size = (uint32)tpInfos.TpReasonParams.size();
1599 uint32 first = 0;
1600 CSString str(tpReason);
1601 for (;first != size ; ++first)
1603 std::string value = tpInfos.TpReasonParams[first];
1604 std::string key = NLMISC::toString("%%%u", first +1);
1605 str = str.replace( key.c_str(), value.c_str());
1607 tpReason = string(str);
1608 tpCancelText = CI18N::get(tpInfos.TpCancelTextId);
1609 tpContext = tpInfos.TpContext;
1613 catch (const EStream &)
1615 tpReason = "TP Reason";
1616 tpCancelText = "Cancel TP"; // for test
1617 // try to deduce tp context from current editor mode
1618 switch (R2::getEditor().getMode())
1620 case R2::CEditor::EditionMode:
1621 case R2::CEditor::NotInitialized:
1622 tpContext = R2::TPContext_Unknown;
1623 tpReason = string();
1624 tpCancelText = string();
1625 break;
1626 case R2::CEditor::GoingToDMMode:
1627 case R2::CEditor::TestMode:
1628 case R2::CEditor::DMMode:
1629 tpContext = R2::TPContext_Edit;
1630 break;
1631 case R2::CEditor::AnimationModeLoading:
1632 case R2::CEditor::AnimationModeWaitingForLoading:
1633 case R2::CEditor::AnimationModeDm:
1634 case R2::CEditor::AnimationModeGoingToDm:
1635 tpContext = R2::TPContext_IslandOwner;
1636 break;
1637 case R2::CEditor::AnimationModePlay:
1638 case R2::CEditor::AnimationModeGoingToPlay:
1639 default:
1640 tpContext = R2::TPContext_Mainland;
1641 break;
1647 if (!tpReason.empty())
1649 std::string tpIcon;
1650 switch(tpContext)
1652 case R2::TPContext_Mainland: tpIcon = "cancel_tp_main_land.tga"; break;
1653 case R2::TPContext_Edit: tpIcon = "cancel_tp_edit.tga"; break;
1654 case R2::TPContext_IslandOwner: tpIcon = "cancel_tp_island_owner.tga"; break;
1655 default: break;
1657 ProgressBar.setTPMessages(tpReason, tpCancelText, tpIcon);
1660 ProgressBar.progress(0);
1661 // enable hardware mouse to allow to click the buttons
1662 //bool oldHardwareCursor = IsMouseCursorHardware();
1663 //InitMouseWithCursor(true);
1664 // Select the closest continent from the new position.
1665 ContinentMngr.select(dest, ProgressBar);
1667 //InitMouseWithCursor(oldHardwareCursor);
1669 // reset 'cancel' button
1670 ProgressBar.setTPMessages(string(), string(), "");
1673 // ProgressBar.enableQuitButton(false); // TMP TMP
1674 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.
1675 ProgressBar.finish();
1676 // ProgressBar.enableQuitButton(true); // TMP TMP
1678 // Teleport the User.
1679 UserEntity->tp(dest);
1681 // Msg Received, send an acknowledge after the landscape has been loaded.
1682 CBitMemStream out;
1683 if(GenericMsgHeaderMngr.pushNameToStream("TP:ACK", out))
1685 NetMngr.push(out);
1686 nlinfo("impulseTP: teleport acknowledge 'TP:ACK' sent.");
1688 else
1689 nlwarning("impulseTP: unknown message name : 'TP:ACK'.");
1692 // First frame
1693 FirstFrame = true;
1696 // if tp canceling was asked, act accordingly
1697 if (ProgressBar.getTPCancelFlag(true))
1699 switch(tpContext)
1701 case R2::TPContext_Mainland:
1702 CAHManager::getInstance()->runActionHandler("return_to_mainland", NULL);
1703 break;
1704 case R2::TPContext_Edit:
1705 CAHManager::getInstance()->runActionHandler("r2ed_stop_test", NULL);
1706 break;
1707 case R2::TPContext_IslandOwner:
1708 CAHManager::getInstance()->runActionHandler("r2_stop_live", NULL);
1709 break;
1710 default:
1711 break;
1715 initHardwareCursor(true);
1716 }// impulseTP //
1718 //-----------------------------------------------
1719 // impulseCombatEngageFailed :
1720 //-----------------------------------------------
1721 void impulseCombatEngageFailed(NLMISC::CBitMemStream &impulse)
1723 if (PermanentlyBanned) return;
1724 nlinfo("impulseCombatEngageFailed: Combat Engage Failed.");
1726 // Unlock the motion.
1727 UserControls.locked(false);
1728 }// impulseCombatEngageFailed //
1730 //-----------------------------------------------
1731 // impulseTeamInvitation :
1732 //-----------------------------------------------
1733 void impulseTeamInvitation(NLMISC::CBitMemStream &impulse)
1735 nlinfo("impulseTeamInvitation: received an invitation");
1737 uint32 textID;
1738 impulse.serial(textID);
1739 if (PermanentlyBanned) return;
1741 CLuaManager::getInstance().executeLuaScript("game:onTeamInvation("+toString(textID)+")", 0);
1742 }// impulseTeamInvitation //
1744 //-----------------------------------------------
1745 // impulseTeamShareOpen
1746 // The server request that the client opens the team sharing system
1747 //-----------------------------------------------
1748 void impulseTeamShareOpen(NLMISC::CBitMemStream &impulse)
1750 if (PermanentlyBanned) return;
1751 CInterfaceManager *im = CInterfaceManager::getInstance();
1752 CGroupContainer *gc = dynamic_cast<CGroupContainer*>( CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share"));
1753 if (!gc) return;
1754 gc->setActive(true);
1755 CWidgetManager::getInstance()->setTopWindow(gc);
1756 gc->updateCoords();
1757 gc->center();
1758 }// impulseTeamShareOpen //
1760 //-----------------------------------------------
1761 // impulseTeamShareInvalid
1762 // invalidate the player validation. If someone has choosen an item/phrase after the player has validated
1763 // the player receive this message to let him know that the chance percentage to obtain a specific item has
1764 // changed and so the player can update its own settings to fit better to what he wants.
1765 // On the client side we have just to show the valid button. All the resets are done on the server side.
1766 //-----------------------------------------------
1767 void impulseTeamShareInvalid(NLMISC::CBitMemStream &impulse)
1769 if (PermanentlyBanned) return;
1770 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1771 CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share:content:ok"));
1772 if (pTB != NULL)
1773 pTB->setActive(true);
1774 }// impulseTeamShareInvalid //
1776 //-----------------------------------------------
1777 // impulseTeamShareClose
1778 // The server wants to close the team sharing interface (if the sharing has been validated or other reasons)
1779 //-----------------------------------------------
1780 void impulseTeamShareClose(NLMISC::CBitMemStream &impulse)
1782 if (PermanentlyBanned) return;
1783 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1784 CGroupContainer
1785 *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share"));
1786 if (pGC != NULL)
1787 pGC->setActive(false);
1788 CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:team_share:content:ok"));
1789 if (pTB != NULL)
1790 pTB->setActive(true);
1791 }// impulseTeamShareClose //
1793 //-----------------------------------------------
1794 // impulseTeamContactInit
1795 // initialize friend list and ignore list from the contact list
1796 //-----------------------------------------------
1797 void impulseTeamContactInit(NLMISC::CBitMemStream &impulse)
1799 vector<uint32> vFriendListName;
1800 vector<TCharConnectionState> vFriendListOnline;
1801 vector<ucstring> vIgnoreListName; // TODO: UTF-8 (serial)
1803 impulse.serialCont(vFriendListName);
1804 uint32 nbState;
1805 impulse.serial(nbState);
1806 vFriendListOnline.resize(nbState);
1807 for (uint i=0; i<nbState; ++i)
1809 impulse.serialShortEnum(vFriendListOnline[i]);
1811 // impulse.serialCont(vFriendListOnline);
1812 impulse.serialCont(vIgnoreListName);
1814 if (PermanentlyBanned) return;
1816 //nlinfo("impulseCallback : Received TEAM:CONTACT_INIT nbfriend:%d nbignore:%d", vFriendListName.size(), vIgnoreListName.size());
1818 PeopleInterraction.initContactLists(vFriendListName, vFriendListOnline, vIgnoreListName);
1819 }// impulseTeamContactInit //
1821 //-----------------------------------------------
1822 // impulseTeamContactCreate
1823 // create one character from the friend or ignore list
1824 //-----------------------------------------------
1825 void impulseTeamContactCreate(NLMISC::CBitMemStream &impulse)
1827 uint32 contactId;
1828 uint32 nameId;
1829 TCharConnectionState online = ccs_offline;
1830 uint8 nList;
1832 impulse.serial(contactId);
1833 impulse.serial(nameId);
1834 impulse.serialShortEnum(online);
1835 impulse.serial(nList);
1837 // client patch to resolve bad server response when requesting ignore list contact creation
1838 if (nList == 1) // ignore list
1840 // prevent adding an empty player to ignore list
1841 if (nameId == 0) return;
1844 if (PermanentlyBanned) return;
1846 //nlinfo("impulseCallback : Received TEAM:CONTACT_CREATE %d %d %s %d", contactId, nameId, online?"true":"false", nList);
1848 PeopleInterraction.addContactInList(contactId, nameId, online, nList);
1850 }// impulseTeamContactStatus //
1852 //-----------------------------------------------
1853 // impulseTeamContactStatus
1854 // update one of the character from the friend list
1855 //-----------------------------------------------
1856 void impulseTeamContactStatus(NLMISC::CBitMemStream &impulse)
1858 uint32 contactId;
1859 TCharConnectionState online = ccs_offline;
1861 impulse.serial(contactId);
1862 impulse.serialShortEnum(online);
1864 if (PermanentlyBanned) return;
1866 //nlinfo("impulseCallback : Received TEAM:CONTACT_STATUS %d %s", contactId, online == ccs_online ?"online": online==ccs_offline?"offline" : "foreign_online");
1868 // 0<=FriendList (actually ignore list does not show online state)
1869 PeopleInterraction.updateContactInList(contactId, online, 0);
1871 // Resort the contact list if needed
1872 CInterfaceManager* pIM= CInterfaceManager::getInstance();
1873 CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
1875 if (order == CPeopleList::sort_online)
1877 PeopleInterraction.FriendList.sortEx(order);
1879 }// impulseTeamContactStatus //
1882 //-----------------------------------------------
1883 // impulseTeamContactRemove
1884 // Remove a contact by the server
1885 //-----------------------------------------------
1886 void impulseTeamContactRemove(NLMISC::CBitMemStream &impulse)
1888 uint32 contactId;
1889 uint8 nList;
1891 impulse.serial(contactId);
1892 impulse.serial(nList);
1894 if (PermanentlyBanned) return;
1896 //nlinfo("impulseCallback : Received TEAM:CONTACT_REMOVE %d %d", contactId, nList);
1898 PeopleInterraction.removeContactFromList(contactId, nList);
1900 }// impulseTeamContactRemove //
1903 //-----------------------------------------------
1904 // servers sets information of a guild member:
1905 // u16 ( member index ) u32 (player name ), u8 ( player grade + last bit set if player online ).
1906 //-----------------------------------------------
1907 /*void impulseGuildSetMemberInfo(NLMISC::CBitMemStream &impulse)
1909 uint16 index;
1910 impulse.serial(index);
1911 uint32 guildMemberName;
1912 impulse.serial(guildMemberName);
1913 uint8 grade;
1914 impulse.serial(grade);
1915 bool online = ((grade&0x80) != 0);
1916 grade = (grade & 0x7F);
1917 CGuildManager::getInstance()->set(index, guildMemberName, grade, online);
1920 //-----------------------------------------------
1921 // vector of pair( u32 (player name ), u8 ( player grade + last bit set if player online ) )
1922 //-----------------------------------------------
1923 /*void impulseGuildInitMemberInfo(NLMISC::CBitMemStream &impulse)
1925 vector < pair < uint32, uint8 > > AllMembers;
1926 uint16 nbEntries;
1927 impulse.serial(nbEntries);
1928 AllMembers.resize(nbEntries);
1929 for (uint32 i = 0; i < nbEntries; ++i)
1931 uint32 name;
1932 impulse.serial(name);
1933 uint8 gradeNonline;
1934 impulse.serial(gradeNonline);
1935 AllMembers[i].first = name;
1936 AllMembers[i].second = gradeNonline;
1939 CGuildManager::getInstance()->init(AllMembers);
1943 //-----------------------------------------------
1944 // impulseGuildInvitation
1945 //-----------------------------------------------
1946 /*void impulseGuildInvitation(NLMISC::CBitMemStream &impulse)
1948 nlinfo("impulseGuildInvitation");
1952 //-----------------------------------------------
1953 // impulseGuildJoinProposal
1954 // server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
1955 //-----------------------------------------------
1956 void impulseGuildJoinProposal(NLMISC::CBitMemStream &impulse)
1959 uint32 phraseID;
1960 impulse.serial(phraseID);
1962 if (PermanentlyBanned) return;
1964 //nlinfo("impulseCallback : Received GUILD:JOIN_PROPOSAL %d", phraseID);
1966 CGuildManager::getInstance()->launchJoinProposal(phraseID);
1967 /*//activate the pop up window
1968 CInterfaceManager *im = CInterfaceManager::getInstance();
1969 CGroupContainer *gc = dynamic_cast<CGroupContainer *>( CWidgetManager::getInstance()->getElementFromId("ui:interface:join_guild_proposal"));
1970 if (!gc) return;
1971 CViewText *vt = dynamic_cast<CViewText*>(gc->getView("invitor_name"));
1972 if (vt == NULL) return;
1973 vt->setText(invitor);
1974 gc->setActive(true);
1975 CWidgetManager::getInstance()->setTopWindow(gc);
1976 gc->updateCoords();
1977 gc->center();
1978 gc->enableBlink(2);*/
1979 }// impulseGuildJoinProposal //
1982 //-----------------------------------------------
1983 // impulseCloseTempInv
1984 //-----------------------------------------------
1985 void impulseCloseTempInv(NLMISC::CBitMemStream &impulse)
1987 CTempInvManager::getInstance()->close();
1990 //-----------------------------------------------
1991 // impulseAscencorTeleport
1992 //-----------------------------------------------
1993 void impulseAscencorTeleport(NLMISC::CBitMemStream &impulse)
1996 } // impulseAscencorTeleport //
1998 //-----------------------------------------------
1999 // impulseEnterCrZoneProposal
2000 // server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
2001 //-----------------------------------------------
2002 void impulseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
2004 uint32 phraseID;
2005 impulse.serial(phraseID);
2006 if (PermanentlyBanned) return;
2008 //nlinfo("impulseCallback : Received MISSION:ASK_ENTER_CRITICAL %d", phraseID);
2010 //activate the pop up window
2011 CInterfaceManager *im = CInterfaceManager::getInstance();
2012 CGroupContainer *gc = dynamic_cast<CGroupContainer *>( CWidgetManager::getInstance()->getElementFromId("ui:interface:enter_crzone_proposal"));
2013 if (!gc) return;
2014 CViewTextID *vti = dynamic_cast<CViewTextID *>(gc->getView("phrase"));
2015 if (!vti) return;
2016 vti->setTextId(phraseID);
2017 gc->setActive(true);
2018 CWidgetManager::getInstance()->setTopWindow(gc);
2019 gc->updateCoords();
2020 gc->center();
2021 gc->enableBlink(2);
2022 }// impulseEnterCrZoneProposal //
2024 //-----------------------------------------------
2025 // impulseCloseEnterCrZoneProposal
2026 // server close proposal interface
2027 //-----------------------------------------------
2028 void impulseCloseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
2030 // hide interface
2031 CInterfaceManager* pIM = CInterfaceManager::getInstance();
2032 CInterfaceGroup *pIG = (CInterfaceGroup*)CWidgetManager::getInstance()->getElementFromId ("ui:interface:enter_crzone_proposal");
2033 if(pIG)
2034 pIG->setActive(false);
2035 }// impulseCloseEnterCrZoneProposal //
2038 //-----------------------------------------------
2039 // impulseExchangeInvitation :
2040 //-----------------------------------------------
2041 void impulseExchangeInvitation(NLMISC::CBitMemStream &impulse)
2043 uint32 textID;
2044 impulse.serial(textID);
2045 if (PermanentlyBanned) return;
2046 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
2048 // show the modal window that allow the player to accept / decline the invitation
2049 CGroupContainer *wnd = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
2050 if (wnd)
2052 wnd->setActive(true);
2053 wnd->updateCoords();
2054 wnd->center();
2055 wnd->enableBlink(2);
2056 CWidgetManager::getInstance()->setTopWindow(wnd);
2059 CViewTextID *vti = dynamic_cast<CViewTextID *>(wnd->getView("invite_phrase"));
2060 if (vti)
2062 vti->setTextId(textID);
2065 }// impulseExchangeInvitation //
2067 //-----------------------------------------------
2068 // impulseExchangeCloseInvitation :
2069 //-----------------------------------------------
2070 void impulseExchangeCloseInvitation(NLMISC::CBitMemStream &impulse)
2072 if (PermanentlyBanned) return;
2073 CInterfaceManager* iMngr = CInterfaceManager::getInstance();
2074 // hide the modal window that allow the player to accept / decline the invitation
2075 CInterfaceGroup *wnd = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
2076 if (wnd) wnd->setActive(false);
2079 //-----------------------------------------------
2080 // impulseMountAbort :
2081 //-----------------------------------------------
2082 void impulseMountAbort(NLMISC::CBitMemStream &impulse)
2084 nlwarning("impulseMountAbort: Received ANIMALS:MOUNT_ABORT => no more used");
2085 }// impulseMountAbort //
2087 //-----------------------------------------------
2088 // impulseRyzomTime :
2089 // Synchronize the ryzom time with the server.
2090 //-----------------------------------------------
2092 void impulseRyzomTime(NLMISC::CBitMemStream &impulse)
2094 nlinfo("impulseRyzomTime: Ryzom Time Received");
2095 uint32 serverTick;
2096 float ryzomTime;
2097 uint32 ryzomDay;
2098 impulse.serial(serverTick);
2099 impulse.serial(ryzomTime);
2100 impulse.serial(ryzomDay);
2101 nlinfo("impulseRyzomTime: Day '%d' Time '%f'.", ryzomDay, ryzomTime);
2103 // Initialize
2104 RT.setOrigin( serverTick, ryzomDay, ryzomTime );
2105 }// impulseRyzomTime //
2107 //-----------------------------------------------
2108 // impulseWhere :
2109 // Display server position
2110 //-----------------------------------------------
2111 void impulseWhere(NLMISC::CBitMemStream &impulse)
2113 //nlinfo("impulseCallback : Received DEBUG:REPLY_WHERE");
2115 sint32 x,y,z;
2116 impulse.serial(x);
2117 impulse.serial(y);
2118 impulse.serial(z);
2119 if (PermanentlyBanned) return;
2120 char buf[128];
2122 double xf = ((double)x)/1000.0f;
2123 double yf = ((double)y)/1000.0f;
2124 double zf = ((double)z)/1000.0f;
2126 sprintf(buf,"Your server position is : X= %g Y= %g Z= %g",xf,yf,zf);
2127 nlinfo(buf);
2128 CInterfaceManager::getInstance()->displaySystemInfo(buf);
2129 }// impulseWhere //
2131 //-----------------------------------------------
2132 // impulseWho :
2133 // Display server position
2134 //-----------------------------------------------
2136 void impulseWho(NLMISC::CBitMemStream &impulse)
2138 nlinfo("impulseWho Received");
2139 CInterfaceManager::getInstance()->displaySystemInfo("Players currently in the game :");
2141 ucstring name; // OLD
2142 uint32 loginId;
2143 uint16 dist;
2144 uint8 dirshort;
2145 string str;
2146 while( impulse.getPos() < (sint32)impulse.length() )
2148 impulse.serial(name);
2149 impulse.serial(loginId);
2150 impulse.serial(dist);
2151 impulse.serial(dirshort);
2153 double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
2154 angle -= NLMISC::Pi;
2155 nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
2156 sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
2157 direction = ((direction%16)+16)%16;
2158 static const string txts[]=
2160 "uiW",
2161 "uiWSW",
2162 "uiSW",
2163 "uiSSW",
2164 "uiS",
2165 "uiSSE",
2166 "uiSE",
2167 "uiESE",
2168 "uiE",
2169 "uiENE",
2170 "uiNE",
2171 "uiNNE",
2172 "uiN",
2173 "uiNNW",
2174 "uiNW",
2175 "uiWNW",
2178 str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
2179 CInterfaceManager::getInstance()->displaySystemInfo(name + str + CI18N::get(txts[direction]));
2181 }// impulseWho //
2185 void impulseWhoGM(NLMISC::CBitMemStream &impulse)
2187 nlinfo("impulseWhoGM Received");
2188 CInterfaceManager::getInstance()->displaySystemInfo("Players currently in the game :");
2190 ucstring name; // OLD
2191 uint32 loginId;
2192 uint16 dist;
2193 uint8 dirshort;
2194 string str;
2195 while( impulse.getPos() < (sint32)impulse.length() )
2197 impulse.serial(name);
2198 impulse.serial(loginId);
2199 impulse.serial(dist);
2200 impulse.serial(dirshort);
2202 double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
2203 angle -= NLMISC::Pi;
2204 nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
2205 sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
2206 direction = ((direction%16)+16)%16;
2207 static const string txts[]=
2209 "uiW",
2210 "uiWSW",
2211 "uiSW",
2212 "uiSSW",
2213 "uiS",
2214 "uiSSE",
2215 "uiSE",
2216 "uiESE",
2217 "uiE",
2218 "uiENE",
2219 "uiNE",
2220 "uiNNE",
2221 "uiN",
2222 "uiNNW",
2223 "uiNW",
2224 "uiWNW",
2227 str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
2228 CInterfaceManager::getInstance()->displaySystemInfo(name + str + CI18N::get(txts[direction]));
2230 }// impulseWho //
2232 //-----------------------------------------------
2233 // impulseCounter :
2234 // check UDP validity
2235 //-----------------------------------------------
2236 void impulseCounter(NLMISC::CBitMemStream &impulse)
2238 //nlinfo("impulseCallBack : Received DEBUG:COUNTER");
2241 uint32 counter;
2242 impulse.serial(counter);
2244 static uint queueTop = 0;
2245 static deque<bool> queue;
2247 if (counter > queueTop)
2249 queue.resize(queue.size()+counter-queueTop, false);
2250 queueTop = counter;
2253 if (queueTop-counter+1 > queue.size())
2255 nlinfo("COUNTER: counter %d arrived too late...", counter);
2257 else
2259 if (queue[queue.size()-1-(queueTop-counter)])
2261 nlwarning("COUNTER: Received counter %d more than once !", counter);
2263 else
2265 nldebug("COUNTER: set counter %d", counter);
2266 queue[queue.size()-1-(queueTop-counter)] = true;
2269 while (queue.size() > 128)
2271 if (!queue.front())
2273 nlwarning("COUNTER: counter %d not received !", queueTop-queue.size()-1);
2276 queue.pop_front();
2280 catch (const Exception &e)
2282 nlwarning ("Problem while decoding a COUTNER msg, skipped: %s", e.what());
2286 //-----------------------------------------------
2287 // impulsePhraseSend :
2288 // A dyn string (or phrase) is send (so, we receive it)
2289 //-----------------------------------------------
2290 void impulsePhraseSend(NLMISC::CBitMemStream &impulse)
2292 STRING_MANAGER::CStringManagerClient::instance()->receiveDynString(impulse);
2295 //-----------------------------------------------
2296 // impulseStringResp :
2297 // Update the local string set
2298 //-----------------------------------------------
2299 void impulseStringResp(NLMISC::CBitMemStream &impulse)
2301 uint32 stringId;
2302 string str;
2303 impulse.serial(stringId);
2304 impulse.serial(str);
2306 if (PermanentlyBanned) return;
2308 STRING_MANAGER::CStringManagerClient::instance()->receiveString(stringId, str);
2311 //-----------------------------------------------
2312 // impulseReloadCache :
2313 // reload the string cache
2314 //-----------------------------------------------
2315 void impulseReloadCache(NLMISC::CBitMemStream &impulse)
2317 uint32 timestamp;;
2318 impulse.serial(timestamp);
2319 if (PermanentlyBanned) return;
2320 STRING_MANAGER::CStringManagerClient::instance()->loadCache(timestamp);
2323 //-----------------------------------------------
2324 // impulseBotChatEnd
2325 // ForceThe end of the bot chat
2326 //-----------------------------------------------
2327 void impulseBotChatForceEnd(NLMISC::CBitMemStream &impulse)
2329 if (PermanentlyBanned) return;
2330 CBotChatManager::getInstance()->setCurrPage(NULL);
2334 //-----------------------------------------------
2335 // MISSION COMPLETED JOURNAL
2336 //-----------------------------------------------
2338 #define MC_M_CONTAINER "ui:interface:info_player_journal"
2339 #define MC_S_CONTAINER "ui:interface:ipj_com_missions"
2340 #define MC_TEMPLATE "tipj_mission_complete"
2341 //-----------------------------------------------
2342 CGroupContainer *getMissionCompletedContainer()
2344 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2345 CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(MC_M_CONTAINER);
2346 CGroupContainer *pGCM = dynamic_cast<CGroupContainer*>(pIE);
2347 if (pGCM == NULL) return NULL;
2349 CGroupList *pList = pGCM->getList();
2350 CGroupContainer *pGCS = dynamic_cast<CGroupContainer*>(pList->getGroup(MC_S_CONTAINER));
2351 return pGCS;
2354 //-----------------------------------------------
2355 void clearMissions()
2357 CGroupContainer *pGCMC = getMissionCompletedContainer();
2358 CInterfaceGroup *pContent = pGCMC->getGroup("content");
2359 pContent->clearGroups();
2361 //-----------------------------------------------
2362 void addMission(uint32 titleID)
2364 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2365 CGroupContainer *pGCMC = getMissionCompletedContainer();
2366 if (pGCMC == NULL)
2368 nlwarning("cannot get container for missions completed");
2369 return;
2371 CInterfaceGroup *pContent = pGCMC->getGroup("content");
2373 uint32 nNbMission = pContent->getGroups().size();
2374 vector<pair<string, string> > vArgs;
2376 vArgs.push_back(pair<string,string>("id", "mc"+NLMISC::toString(nNbMission)));
2377 vArgs.push_back(pair<string,string>("mcid", NLMISC::toString(titleID)));
2379 if (nNbMission == 0)
2381 vArgs.push_back(pair<string,string>("posref", "TL TL"));
2382 vArgs.push_back(pair<string,string>("posparent", "parent"));
2383 vArgs.push_back(pair<string,string>("y", "0"));
2385 else
2387 vArgs.push_back(pair<string,string>("posref", "BL TL"));
2390 CInterfaceGroup *pIG = pIM->createGroupInstance(MC_TEMPLATE, pContent->getId(), vArgs);
2391 if (pIG == NULL)
2393 nlwarning("cannot create a mission completed");
2394 return;
2396 pIG->setParent(pContent);
2397 if (nNbMission == 0)
2398 pIG->setParentPos(pContent);
2399 else
2400 pIG->setParentPos(pContent->getGroups()[nNbMission-1]);
2401 pContent->addGroup(pIG);
2404 //-----------------------------------------------
2405 // impulseJournalInitCompletedMissions :
2406 // initialize the player journal missions for completed missions
2407 //-----------------------------------------------
2408 void impulseJournalInitCompletedMissions (NLMISC::CBitMemStream &impulse)
2411 vector<uint32> vMissionCompleted;
2412 impulse.serialCont(vMissionCompleted);
2414 clearMissions();
2416 for (uint32 i = 0; i < vMissionCompleted.size(); ++i)
2417 addMission (vMissionCompleted[i]);
2421 //-----------------------------------------------
2422 // impulseJournalInitCompletedMissions :
2423 // initialize the player journal missions for completed missions
2424 //-----------------------------------------------
2425 void impulseJournalUpdateCompletedMissions (NLMISC::CBitMemStream &impulse)
2428 uint32 nNewCompletedMission;
2429 impulse.serial(nNewCompletedMission);
2431 addMission (nNewCompletedMission);
2436 //-----------------------------------------------
2437 // impulseJournalCantAbandon :
2438 // server refuses mission abandon
2439 //-----------------------------------------------
2440 void impulseJournalCantAbandon (NLMISC::CBitMemStream &impulse)
2442 if (PermanentlyBanned) return;
2443 /// reactivate abandon button
2444 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:MISSION_ABANDON_BUTTON",false);
2445 if (pNL != NULL)
2446 pNL->setValue64(1);
2451 //-----------------------------------------------
2452 // server add a compass target
2453 //-----------------------------------------------
2454 void impulseJournalAddCompass(NLMISC::CBitMemStream &impulse)
2456 sint32 x;
2457 sint32 y;
2458 uint32 text;
2459 impulse.serial(x);
2460 impulse.serial(y);
2461 impulse.serial(text);
2462 if (PermanentlyBanned) return;
2463 //nlinfo("impulseCallback : Received JOURNAL:ADD_COMPASS %d %d %d", x, y, text);
2464 CCompassDialogsManager::getInstance().addEntry( x,y,text );
2467 //-----------------------------------------------
2468 // server removes a compass target
2469 //-----------------------------------------------
2470 void impulseJournalRemoveCompass(NLMISC::CBitMemStream &impulse)
2472 uint32 text;
2473 impulse.serial(text);
2474 if (PermanentlyBanned) return;
2475 //nlinfo("impulseCallback : Received JOURNAL:REMOVE_COMPASS %d", text);
2476 CCompassDialogsManager::getInstance().removeEntry( text );
2482 // the server ask me to execute a command
2484 void impulseRemoteAdmin (NLMISC::CBitMemStream &impulse)
2486 CLog logDisplayVars;
2487 CLightMemDisplayer mdDisplayVars;
2488 logDisplayVars.addDisplayer (&mdDisplayVars);
2489 mdDisplayVars.setParam (10);
2491 uint32 rid;
2492 impulse.serial (rid);
2493 string cmd;
2494 impulse.serial (cmd);
2496 // remove the 2 first rc character if exists, only there to say to the EGS that is a remote command
2497 if (cmd.size()>2 && tolower(cmd[0])=='r' && tolower(cmd[1])=='c') // FIXME: toLowerAscii
2498 cmd = cmd.substr(2);
2500 mdDisplayVars.clear ();
2501 ICommand::execute(cmd, logDisplayVars, !ICommand::isCommand(cmd));
2502 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
2504 string str;
2505 if (ICommand::isCommand(cmd))
2507 for (uint k = 0; k < strs.size(); k++)
2509 str += strs[k];
2512 else
2514 if (!strs.empty())
2516 str = strs[0].substr(0,strs[0].size()-1);
2517 // replace all spaces into underscore because space is a reserved char
2518 for (uint i = 0; i < str.size(); i++) if (str[i] == ' ') str[i] = '_';
2520 else
2522 str = "???";
2525 mdDisplayVars.unlockStrings();
2527 //nlinfo("impulseCallback : Received COMMAND:REMOTE_ADMIN : Server asked me to execute '%s', result is '%s'", cmd.c_str(), str.c_str());
2529 CBitMemStream out;
2530 if(GenericMsgHeaderMngr.pushNameToStream("COMMAND:REMOTE_ADMIN_ANSWER", out))
2532 out.serial (rid);
2533 out.serial (cmd);
2534 out.serial (str);
2535 NetMngr.push (out);
2536 //nlinfo("impulseCallback : COMMAND:REMOTE_ADMIN_ANSWER %d %s %s sent", rid, cmd.c_str(), str.c_str());
2541 //-----------------------------------------------
2542 // impulseGuildAscensor :
2543 // server request that the client launch the ascensor interface
2544 //-----------------------------------------------
2546 void impulseGuildAscensor (NLMISC::CBitMemStream &impulse)
2548 if (PermanentlyBanned) return;
2549 //nlinfo("impulseCallback : Received GUILD:ASCENSOR");
2550 CGuildManager::getInstance()->launchAscensor();
2553 //-----------------------------------------------
2554 //impulseGuildLeaveAscensor
2555 //-----------------------------------------------
2556 void impulseGuildLeaveAscensor (NLMISC::CBitMemStream &impulse)
2558 if (PermanentlyBanned) return;
2559 //nlinfo("impulseCallback : Received GUILD:LEAVE_ASCENSOR");
2560 CGuildManager::getInstance()->quitAscensor();
2563 //-----------------------------------------------
2564 //impulseGuildAbortCreation
2565 //-----------------------------------------------
2566 void impulseGuildAbortCreation (NLMISC::CBitMemStream &impulse)
2568 CBotChatPage *pPage = CBotChatManager::getInstance()->getCurrPage();
2569 CBotChatPageCreateGuild *pPageCG = dynamic_cast<CBotChatPageCreateGuild*>(pPage);
2570 if (pPageCG == BotChatPageAll->CreateGuild)
2571 CBotChatManager::getInstance()->setCurrPage(NULL);
2574 void impulseGuildOpenGuildWindow(NLMISC::CBitMemStream &impulse)
2576 CGuildManager::getInstance()->openGuildWindow();
2580 //-----------------------------------------------
2581 // impulseGuildOpenInventory
2582 //-----------------------------------------------
2583 void impulseGuildOpenInventory (NLMISC::CBitMemStream &impulse)
2585 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2586 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(1);
2589 //-----------------------------------------------
2590 // impulseGuildCloseInventory
2591 //-----------------------------------------------
2592 void impulseGuildCloseInventory (NLMISC::CBitMemStream &impulse)
2594 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2595 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(0);
2598 //-----------------------------------------------
2599 // impulseGuildUpdatePlayerTitle
2600 // server block/unblock some reserved titles
2601 //-----------------------------------------------
2602 void impulseGuildUpdatePlayerTitle(NLMISC::CBitMemStream &impulse)
2604 CSkillManager *pSM = CSkillManager::getInstance();
2605 bool bUnblock;
2606 impulse.serial(bUnblock);
2607 vector<uint16> vTitles;
2608 impulse.serialCont(vTitles);
2609 if (PermanentlyBanned) return;
2610 if (bUnblock)
2612 for (uint32 i = 0; i < vTitles.size(); ++i)
2613 pSM->unblockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
2615 else
2617 for (uint32 i = 0; i < vTitles.size(); ++i)
2618 pSM->blockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
2622 //-----------------------------------------------
2623 // impulseGuildUseFemaleTitles
2624 // server activates/deactivates use of female titles
2625 //-----------------------------------------------
2626 void impulseGuildUseFemaleTitles(NLMISC::CBitMemStream &impulse)
2628 impulse.serial( UseFemaleTitles );
2631 //-----------------------------------------------
2632 // impulsePhraseDownLoad
2633 // server upload the phrases.
2634 //-----------------------------------------------
2635 void impulsePhraseDownLoad (NLMISC::CBitMemStream &impulse)
2637 std::vector<CSPhraseSlot> phrases;
2639 // Read Known Phrases
2640 impulse.serialCont(phrases);
2641 CSPhraseManager *pPM= CSPhraseManager::getInstance();
2642 for(uint i=0;i<phrases.size();i++)
2644 if(phrases[i].PhraseSheetId != CSheetId::Unknown)
2646 CSPhraseCom phraseCom;
2647 pPM->buildPhraseFromSheet(phraseCom, phrases[i].PhraseSheetId.asInt());
2648 pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phraseCom);
2650 else
2652 pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phrases[i].Phrase);
2655 // must update the DB (NB: if initInGameDone) after all phrase set.
2656 pPM->updateBookDB();
2658 // Then Read Memorized Phrases
2659 std::vector<CSPhraseMemorySlot> memorizedPhrases;
2660 impulse.serialCont(memorizedPhrases);
2661 if (PermanentlyBanned) return;
2662 for(uint i=0;i<memorizedPhrases.size();i++)
2664 pPM->memorizePhrase(
2665 memorizedPhrases[i].MemoryLineId,
2666 memorizedPhrases[i].MemorySlotId,
2667 memorizedPhrases[i].PhraseId);
2670 // OK.
2671 extern bool SabrinaPhraseBookLoaded;
2672 SabrinaPhraseBookLoaded= true;
2674 // update gray state, if game inited.
2675 pPM->updateMemoryBar();
2678 //-----------------------------------------------
2679 // impulsePhraseConfirmBuy
2680 // server confirm/infirm the buy of botchat phrase.
2681 //-----------------------------------------------
2682 void impulsePhraseConfirmBuy (NLMISC::CBitMemStream &impulse)
2684 uint16 phraseId;
2685 bool confirm;
2687 impulse.serial(phraseId);
2688 impulse.serial(confirm);
2690 if (PermanentlyBanned) return;
2692 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2693 pSM->receiveBotChatConfirmBuy(phraseId, confirm);
2697 //-----------------------------------------------
2698 // impulsePhraseAckExecuteCyclic
2699 // server confirm/infirm the cyclic execution of a phrase
2700 //-----------------------------------------------
2701 void impulsePhraseAckExecuteCyclic (NLMISC::CBitMemStream &impulse)
2703 uint8 counter;
2704 bool ok;
2706 impulse.serial(ok);
2707 impulse.serial(counter);
2709 if (PermanentlyBanned) return;
2712 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2713 pSM->receiveAckExecuteFromServer(true, counter, ok);
2717 //-----------------------------------------------
2718 // impulsePhraseAckExecuteCyclic
2719 // server confirm/infirm the execution of a phrase
2720 //-----------------------------------------------
2721 void impulsePhraseAckExecuteNext (NLMISC::CBitMemStream &impulse)
2723 uint8 counter;
2724 bool ok;
2726 impulse.serial(ok);
2727 impulse.serial(counter);
2729 if (PermanentlyBanned) return;
2731 CSPhraseManager *pSM= CSPhraseManager::getInstance();
2732 pSM->receiveAckExecuteFromServer(false, counter, ok);
2735 // Same params as in BOMB_IF
2736 #ifdef FINAL_VERSION
2737 #define SKIP_IF(condition,msg,skipAction) if (!(condition)); else skipAction;
2738 #else
2739 #define SKIP_IF(condition,msg,skipAction) if (!(condition)) WARN(msg); else skipAction;
2740 #endif
2742 template <class CInventoryCategoryTemplate>
2743 void updateInventoryFromStream (NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges)
2747 // get the egs tick of this change
2748 TGameCycle serverTick;
2749 impulse.serial(serverTick);
2751 // For All inventories
2752 for ( uint invId=0; invId!=CInventoryCategoryTemplate::NbInventoryIds; ++invId )
2754 // Presence bit
2755 bool hasContent;
2756 impulse.serialBit( hasContent );
2757 if ( ! hasContent )
2758 continue;
2760 // Number field
2761 uint32 nbChanges;
2762 impulse.serial( nbChanges, INVENTORIES::LowNumberBits );
2763 if ( nbChanges == INVENTORIES::LowNumberBound )
2764 impulse.serial( nbChanges, 32 );
2766 const string invBranchStr = CInventoryCategoryTemplate::getDbStr( (typename CInventoryCategoryTemplate::TInventoryId)invId );
2767 ICDBNode::CTextId textId( invBranchStr );
2768 ICDBNode *inventoryNode = IngameDbMngr.getNodePtr()->getNode( textId, false );
2769 BOMB_IF(!inventoryNode, "Inventory missing in database", return);
2771 // List of updates
2772 for ( uint c=0; c!=nbChanges; ++c )
2774 // Unpack (the bitmemstream is written from high-order to low-order)
2775 uint32 iuInfoVersion;
2776 impulse.serial( iuInfoVersion, 1 );
2777 if ( iuInfoVersion == 1 )
2779 uint32 slotIndex;
2780 impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
2782 // Access the database leaf
2783 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
2784 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( INVENTORIES::InfoVersionStr ));
2785 BOMB_IF( !leafNode, "Inventory slot property missing in database", continue );
2787 // Apply or increment Info Version in database
2788 if ( CInventoryCategoryTemplate::needPlainInfoVersionTransfer() )
2790 uint32 infoVersion;
2791 impulse.serial( infoVersion, INVENTORIES::InfoVersionBitSize );
2792 leafNode->setPropCheckGC( serverTick, infoVersion );
2794 else
2796 // NB: don't need to check GC on a info version upgrade, since this is always a delta of +1
2797 // the order of received of this impulse is not important
2798 leafNode->setValue64( leafNode->getValue64() + 1 );
2802 else
2804 uint32 iuAll;
2805 impulse.serial( iuAll, 1 );
2806 if ( iuAll == 1 )
2808 INVENTORIES::CItemSlot itemSlot;
2809 itemSlot.serialAll( impulse, templ );
2810 //nldebug( "Inv %s Update %u", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex() );
2812 // Apply all properties to database
2813 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
2814 for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
2816 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
2817 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2818 leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getItemProp( ( INVENTORIES::TItemPropId)i ) );
2821 else
2823 uint32 iuOneProp;
2824 impulse.serial( iuOneProp, 1 );
2825 if ( iuOneProp == 1 )
2827 INVENTORIES::CItemSlot itemSlot;
2828 itemSlot.serialOneProp( impulse, templ );
2829 //nldebug( "Inv %s Prop %u %s", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex(), INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId] );
2831 // Apply property to database
2832 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
2833 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId]) ));
2834 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2835 leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getOneProp().ItemPropValue );
2838 else // iuReset
2840 uint32 slotIndex;
2841 impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
2842 //nldebug( "Inv %s Reset %u", CInventoryCategoryTemplate::InventoryStr[invId], slotIndex );
2844 // Reset all properties in database
2845 CCDBNodeBranch *slotNode = safe_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
2846 for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
2848 // Instead of clearing all leaves (by index), we must find and clear only the
2849 // properties in TItemPropId, because the actual database leaves may have
2850 // less properties, and because we must not clear the leaf INFO_VERSION.
2851 // NOTE: For example, only player BAG inventory has WORNED leaf.
2852 CCDBNodeLeaf *leafNode = type_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
2853 SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
2854 leafNode->setPropCheckGC( serverTick, 0 );
2862 CInventoryManager::getInstance()->sortBag();
2864 catch (const Exception &e)
2866 nlwarning ("Problem while decoding a DB_UPD_INV msg, skipped: %s", e.what());
2870 //-----------------------------------------------
2871 // impulseUpdateInventory:
2872 //-----------------------------------------------
2873 void impulseUpdateInventory (NLMISC::CBitMemStream &impulse)
2875 updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForCharacter*)NULL, true );
2878 //-----------------------------------------------
2879 // impulseInitInventory:
2880 //-----------------------------------------------
2881 void impulseInitInventory (NLMISC::CBitMemStream &impulse)
2883 sint32 p = impulse.getPos();
2884 impulseUpdateInventory( impulse );
2885 IngameDbMngr.setInitPacketReceived();
2886 nlinfo( "DB_INIT:INV done (%u bytes)", impulse.getPos()-p );
2889 //-----------------------------------------------
2890 // impulseItemInfoSet:
2891 //-----------------------------------------------
2892 void impulseItemInfoSet (NLMISC::CBitMemStream &impulse)
2894 CItemInfos itemInfos;
2895 impulse.serial(itemInfos);
2897 getInventory().onReceiveItemInfo(itemInfos);
2900 //-----------------------------------------------
2901 // impulseItemInfoRefreshVersion:
2902 //-----------------------------------------------
2903 void impulseItemInfoRefreshVersion (NLMISC::CBitMemStream &impulse)
2905 uint16 slotId;
2906 uint8 infoVersion;
2907 impulse.serial(slotId);
2908 impulse.serial(infoVersion);
2910 getInventory().onRefreshItemInfoVersion(slotId, infoVersion);
2913 //-----------------------------------------------
2914 // impulsePrereqInfoSet:
2915 //-----------------------------------------------
2916 void impulsePrereqInfoSet (NLMISC::CBitMemStream &impulse)
2918 CPrerequisitInfos prereqInfos;
2919 uint8 index;
2920 impulse.serial(prereqInfos);
2921 impulse.serial(index);
2923 //write infos in interface
2924 CBotChatManager::getInstance()->onReceiveMissionInfo(index, prereqInfos);
2927 //-----------------------------------------------
2928 //-----------------------------------------------
2929 void impulseDeathRespawnPoint (NLMISC::CBitMemStream &impulse)
2931 CRespawnPointsMsg msg;
2932 impulse.serial(msg);
2933 if (PermanentlyBanned) return;
2934 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2935 CGroupMap *pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:respawn_map:content:map_content:actual_map"));
2936 if (pMap == NULL)
2938 nlwarning("problem cannot find ui:interface:respawn_map:content:map_content:actual_map");
2939 return;
2941 pMap->addRespawnPoints(msg);
2944 pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
2945 if (pMap == NULL)
2947 nlwarning("problem cannot find ui:interface:map:content:map_content:actual_map");
2948 return;
2950 pMap->addRespawnPoints(msg);
2953 //-----------------------------------------------
2954 //-----------------------------------------------
2955 void impulseDeathRespawn (NLMISC::CBitMemStream &impulse)
2957 // TODO : Bring me to life !!!
2960 //-----------------------------------------------
2961 // impulseDuelInvitation :
2962 //-----------------------------------------------
2963 void impulseDuelInvitation(NLMISC::CBitMemStream &impulse)
2965 uint32 textID;
2966 impulse.serial(textID);
2968 //nlinfo("impulseCallback : Received DUEL:INVITATION %d", textID);
2970 if (PermanentlyBanned) return;
2972 //activate the pop up window
2973 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2974 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_duel_proposal"));
2975 if (pGC == NULL) return;
2976 CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
2977 if (pVTID == NULL) return;
2978 pVTID->setTextId(textID);
2979 pGC->setActive(true);
2980 CWidgetManager::getInstance()->setTopWindow(pGC);
2981 pGC->updateCoords();
2982 pGC->center();
2983 pGC->enableBlink(2);
2985 }// impulseDuelInvitation //
2987 //-----------------------------------------------
2988 // impulseDuelCancelInvitation:
2989 //-----------------------------------------------
2990 void impulseDuelCancelInvitation(NLMISC::CBitMemStream &impulse)
2992 if (PermanentlyBanned) return;
2993 //nlinfo("impulseCallback : Received DUEL:CANCEL_INVITATION");
2995 //activate the pop up window
2996 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2997 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_duel_proposal"));
2998 if (pGC == NULL) return;
2999 pGC->setActive(false);
3001 }// impulseDuelCancelInvitation //
3003 //-----------------------------------------------
3004 // impulsePVPChallengeInvitation :
3005 //-----------------------------------------------
3006 void impulsePVPChallengeInvitation(NLMISC::CBitMemStream &impulse)
3008 uint32 textID;
3009 impulse.serial(textID);
3011 if (PermanentlyBanned) return;
3013 //nlinfo("impulseCallback : Received PVP_CHALLENGE:INVITATION %d", textID);
3015 //activate the pop up window
3016 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3017 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
3018 if (pGC == NULL) return;
3019 CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
3020 if (pVTID == NULL) return;
3021 pVTID->setTextId(textID);
3022 pGC->setActive(true);
3023 CWidgetManager::getInstance()->setTopWindow(pGC);
3024 pGC->updateCoords();
3025 pGC->center();
3026 pGC->enableBlink(2);
3028 }// impulsePVPChallengeInvitation //
3030 //-----------------------------------------------
3031 // impulsePVPChallengeCancelInvitation:
3032 //-----------------------------------------------
3033 void impulsePVPChallengeCancelInvitation(NLMISC::CBitMemStream &impulse)
3035 //nlinfo("impulseCallback : Received PVP_CHALLENGE:CANCEL_INVITATION");
3037 //activate the pop up window
3038 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3039 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
3040 if (pGC == NULL) return;
3041 pGC->setActive(false);
3043 }// impulsePVPChallengeCancelInvitation //
3047 //-----------------------------------------------
3048 // impulsePVPFactionPushFactionWar:
3049 //-----------------------------------------------
3050 void impulsePVPFactionPushFactionWar(NLMISC::CBitMemStream &impulse)
3052 //nlinfo("impulseCallback : Received PVP_FACTION:PUSH_FACTION_WAR");
3054 PVP_CLAN::CFactionWar factionWar;
3055 impulse.serialEnum(factionWar.Clan1);
3056 impulse.serialEnum(factionWar.Clan2);
3058 CFactionWarManager::getInstance()->addFactionWar(factionWar);
3062 //-----------------------------------------------
3063 // impulsePVPFactionPopFactionWar:
3064 //-----------------------------------------------
3065 void impulsePVPFactionPopFactionWar(NLMISC::CBitMemStream &impulse)
3067 //nlinfo("impulseCallback : Received PVP_FACTION:POP_FACTION_WAR");
3069 PVP_CLAN::CFactionWar factionWar;
3070 impulse.serialEnum(factionWar.Clan1);
3071 impulse.serialEnum(factionWar.Clan2);
3073 CFactionWarManager::getInstance()->stopFactionWar(factionWar);
3077 //-----------------------------------------------
3078 // impulsePVPFactionFactionWars:
3079 //-----------------------------------------------
3080 void impulsePVPFactionFactionWars(NLMISC::CBitMemStream &impulse)
3082 //nlinfo("impulseCallback : Received PVP_FACTION:FACTION_WARS");
3084 CFactionWarsMsg factionWars;
3085 impulse.serial(factionWars);
3087 for( uint i=0; i<factionWars.FactionWarOccurs.size(); ++i )
3089 CFactionWarManager::getInstance()->addFactionWar(factionWars.FactionWarOccurs[i]);
3095 //-----------------------------------------------
3096 // impulsePVPChooseClan
3097 //-----------------------------------------------
3099 void impulsePVPChooseClan(NLMISC::CBitMemStream &impulse)
3101 nlinfo("impulsePVPChooseClan : Received PVP_CLAN:CHOOSE_CLAN");
3103 EGSPD::CPeople::TPeople clan1= EGSPD::CPeople::Unknown, clan2= EGSPD::CPeople::Unknown;
3104 impulse.serialEnum( clan1 );
3105 impulse.serialEnum( clan2 );
3107 if (PermanentlyBanned) return;
3109 //activate the pop up window
3110 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3111 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal"));
3112 if (pGC == NULL) return;
3113 pGC->setActive(true);
3115 CCtrlTextButton * butClan1 = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan1"));
3116 if( butClan1 == NULL )
3117 return;
3118 butClan1->setText( EGSPD::CPeople::toString( clan1 ) );
3120 CCtrlTextButton * butClan2 = dynamic_cast<CCtrlTextButton*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan2"));
3121 if( butClan2 == NULL )
3122 return;
3123 butClan2->setText( EGSPD::CPeople::toString( clan2 ) );
3127 //-----------------------------------------------
3128 // impulseEncyclopediaUpdate
3129 //-----------------------------------------------
3130 void impulseEncyclopediaUpdate(NLMISC::CBitMemStream &impulse)
3132 //nlinfo("impulseCallback : Received ENCYCLOPEDIA:UPDATE");
3134 CEncyclopediaUpdateMsg msg;
3135 impulse.serial(msg);
3136 if (PermanentlyBanned) return;
3137 CEncyclopediaManager::getInstance()->update(msg);
3138 }// impulseEncyclopediaUpdate //
3140 //-----------------------------------------------
3141 // impulseEncyclopediaInit
3142 //-----------------------------------------------
3143 void impulseEncyclopediaInit(NLMISC::CBitMemStream &impulse)
3145 //nlinfo("impulseCallback : Received ENCYCLOPEDIA:INIT");
3147 CEncyclopediaUpdateMsg msg;
3148 impulse.serial(msg);
3149 if (PermanentlyBanned) return;
3150 CEncyclopediaManager::getInstance()->update(msg);
3151 }// impulseEncyclopediaInit //
3153 //-----------------------------------------------
3154 //-----------------------------------------------
3155 void impulseItemOpenRoomInventory(NLMISC::CBitMemStream &impulse)
3157 if (PermanentlyBanned) return;
3158 // This is a message because we may do other things there
3159 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3160 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(1);
3163 //-----------------------------------------------
3164 //-----------------------------------------------
3165 void impulseItemCloseRoomInventory(NLMISC::CBitMemStream &impulse)
3167 if (PermanentlyBanned) return;
3168 // This is a message because we may do other things there
3169 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3170 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(0);
3172 // deactivate the pop up window
3173 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:inv_room"));
3174 if (pGC == NULL) return;
3175 pGC->setActive(false);
3178 //-----------------------------------------------
3179 //-----------------------------------------------
3180 void impulseUserBars(NLMISC::CBitMemStream &impulse)
3182 uint8 msgNumber;
3183 sint32 hp, sap, sta, focus;
3184 impulse.serial(msgNumber);
3185 impulse.serial(hp);
3186 impulse.serial(sap);
3187 impulse.serial(sta);
3188 impulse.serial(focus);
3190 if (PermanentlyBanned) return;
3192 // Setup the user Bars
3193 CBarManager::CBarInfo bi;
3194 CBarManager::getInstance()->setupUserBarInfo(msgNumber, hp, sap, sta, focus);
3197 //-----------------------------------------------
3198 //-----------------------------------------------
3199 void impulseOutpostChooseSide(NLMISC::CBitMemStream &impulse)
3201 // read message
3202 bool outpostInFire;
3203 bool playerGuildInConflict;
3204 bool playerGuildIsAttacker;
3205 impulse.serial(outpostInFire);
3206 impulse.serial(playerGuildInConflict);
3207 impulse.serial(playerGuildIsAttacker);
3208 uint32 ownerGuildNameId;
3209 impulse.serial( ownerGuildNameId );
3210 uint32 attackerGuildNameId;
3211 impulse.serial( attackerGuildNameId );
3212 uint32 declTimer;
3213 impulse.serial( declTimer );
3215 // start
3216 OutpostManager.startPvpJoinProposal(outpostInFire, playerGuildInConflict, playerGuildIsAttacker,
3217 ownerGuildNameId, attackerGuildNameId, declTimer);
3220 //-----------------------------------------------
3221 //-----------------------------------------------
3222 void impulseOutpostDeclareWarAck(NLMISC::CBitMemStream &impulse)
3224 bool canValidate;
3225 uint32 docTextId;
3226 uint32 timeStartAttack;
3228 impulse.serial(canValidate);
3229 impulse.serial(docTextId);
3230 impulse.serial(timeStartAttack);
3232 // write result in Local DB.
3233 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3235 // ack reception
3236 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_RECEIVED");
3237 if(node)
3238 node->setValueBool(true);
3239 // set result of ACK
3240 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_OK");
3241 if(node)
3242 node->setValueBool(canValidate);
3243 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TEXTID");
3244 if(node)
3245 node->setValue32(docTextId);
3246 node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TIME_RANGE_ATT");
3247 if(node)
3248 node->setValue32(timeStartAttack);
3251 extern void addWebIGParams(string &url, bool trustedDomain);
3253 //-----------------------------------------------
3254 //-----------------------------------------------
3255 class CServerMessageBoxOnReceiveTextId : public STRING_MANAGER::IStringWaitCallback
3257 private:
3258 enum TTextType {TitleType= 0, ContentType, NumTextType};
3259 uint32 _TextId[NumTextType];
3260 bool _TextReceived[NumTextType];
3261 bool _AlreadyDisplayed;
3263 // show the window
3264 void activateMsgBoxWindow()
3266 STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
3268 // get the content string (should have been received!)
3269 string contentStr;
3270 string titleStr;
3271 if(!pSMC->getDynString(_TextId[ContentType], contentStr))
3272 return;
3274 if(!pSMC->getDynString(_TextId[TitleType], titleStr))
3275 return;
3277 // if the string start with a @{Wxxxx} code, remove it and get the wanted window size
3278 sint w = 256; // default size to 256 !!
3279 bool is_webig = false;
3281 if(contentStr.size()>=6 && contentStr[0]=='W' && contentStr[1]=='E' && contentStr[2]=='B'
3282 && contentStr[3]==' ' && contentStr[4]==':' && contentStr[5]==' ' )
3284 uint i;
3285 const uint digitStart= 6;
3286 const uint digitMaxEnd= (uint)contentStr.size();
3288 is_webig = true;
3290 for(i = digitStart; i < digitMaxEnd; i++)
3292 if(contentStr[i] == ' ')
3293 break;
3295 if(i != digitMaxEnd)
3297 string web_app = contentStr.substr(digitStart, i-digitStart);
3298 contentStr = string(ClientCfg.WebIgMainDomain + "/") + web_app + string("/index.php?") + contentStr.substr((size_t)i + 1);
3300 else
3302 contentStr.clear();
3303 i = digitStart;
3306 else if(contentStr.size()>=5 && contentStr[0]=='@' && contentStr[1]=='{' && contentStr[2]=='W')
3308 uint i;
3309 const uint digitStart= 3;
3310 const uint digitMaxEnd= 8;
3311 for(i=digitStart;i<contentStr.size() && i<digitMaxEnd;i++)
3313 if(contentStr[i]=='}')
3314 break;
3316 if(i!=digitMaxEnd)
3318 // get the width
3319 string digitStr= contentStr.substr(digitStart, i-digitStart);
3320 fromString(digitStr, w);
3321 // remove the first tag
3322 contentStr= contentStr.substr(i+1);
3326 // open the message box window or web ig
3327 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3329 if (is_webig)
3331 CGroupHTML *groupHtml;
3332 string group = titleStr;
3333 // <missing:XXX>
3334 group = group.substr(9, group.size()-10);
3335 groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:"+group+":content:html"));
3336 if (!groupHtml)
3338 groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:webig:content:html"));
3339 group = "webig";
3342 if (groupHtml)
3344 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:"+group));
3345 if (pGC)
3347 if (contentStr.empty())
3349 pGC->setActive(false);
3351 else
3353 if (group == "webig")
3354 pGC->setActive(true);
3355 string url = contentStr;
3356 addWebIGParams(url, true);
3357 groupHtml->browse(url.c_str());
3358 CWidgetManager::getInstance()->setTopWindow(pGC);
3363 else
3365 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:server_message_box"));
3366 if (pGC)
3368 // show the window with correct width
3369 pGC->setW(w);
3370 pGC->setActive(true);
3372 // must set the text by hand
3373 CViewText *vt= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(CWidgetManager::getInstance()->getParser()->getDefine("server_message_box_content_view_text")));
3374 if(vt)
3375 vt->setTextFormatTaged(contentStr);
3377 // open
3378 CWidgetManager::getInstance()->setTopWindow(pGC);
3379 pGC->invalidateCoords();
3380 // Yoyo: because of buggued group container, I found that 6 times is a good number....
3381 for(uint i=0;i<6;i++)
3382 pGC->updateCoords();
3383 pGC->center();
3384 pGC->enableBlink(2);
3389 public:
3390 // called when the string is available
3391 virtual void onDynStringAvailable(uint stringId, const std::string &value)
3393 // don't care if already displayed
3394 if(_AlreadyDisplayed)
3395 return;
3397 // check if one of waited text
3398 for(uint i=0;i<NumTextType;i++)
3400 if(stringId==_TextId[i])
3402 _TextReceived[i]= true;
3406 // all received?
3407 for(uint i=0;i<NumTextType;i++)
3409 if(!_TextReceived[i])
3410 return;
3412 // Yes => display window
3413 _AlreadyDisplayed= true;
3414 activateMsgBoxWindow();
3417 // start the waiter
3418 void startWaitTexts(uint32 titleTextId, uint32 docTextId)
3420 // reset
3421 _TextId[TitleType]= titleTextId;
3422 _TextId[ContentType]= docTextId;
3423 _TextReceived[TitleType]= false;
3424 _TextReceived[ContentType]= false;
3425 _AlreadyDisplayed= false;
3427 // start to wait receive of those string (NB: they may be already here, but waitDynStrings calls directly the callback in this case)
3428 STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
3429 pSMC->waitDynString(titleTextId, this);
3430 pSMC->waitDynString(docTextId, this);
3433 CServerMessageBoxOnReceiveTextId ServerMessageBoxOnReceiveTextId;
3436 void impulseUserPopup(NLMISC::CBitMemStream &impulse)
3438 uint32 titleTextId;
3439 uint32 docTextId;
3440 impulse.serial(titleTextId);
3441 impulse.serial(docTextId);
3443 // setup TEMP DB for title
3444 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3445 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:SERVER_POPUP:TITLE");
3446 if(node) node->setValue32(titleTextId);
3448 // Open the Popup only when the 2 dyn strings are available
3449 ServerMessageBoxOnReceiveTextId.startWaitTexts(titleTextId, docTextId);
3452 //-----------------------------------------------
3453 //-----------------------------------------------
3454 //extern void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse);
3455 void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse)
3457 uint32 entityID;
3458 uint32 rgba;
3459 sint16 hpDelta;
3460 impulse.serial(entityID);
3461 impulse.serial(rgba);
3462 impulse.serial(hpDelta);
3463 CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
3464 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3465 if (entity)
3466 entity->addHPOutput(toString("%d", hpDelta), color);
3469 void impulseCombatFlyingTextItemSpecialEffectProc(NLMISC::CBitMemStream &impulse)
3471 uint32 entityID;
3472 uint32 rgba;
3473 uint8 effect;
3474 sint32 param;
3475 impulse.serial(entityID);
3476 impulse.serial(rgba);
3477 impulse.serial(effect);
3478 impulse.serial(param);
3479 CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
3480 string text = CI18N::get(toString("uiItemSpecialEffectFlyingText%s", ITEM_SPECIAL_EFFECT::toString((ITEM_SPECIAL_EFFECT::TItemSpecialEffect)effect).c_str()));
3481 strFindReplace(text, "%param", toString("%d", param));
3482 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3483 if (entity)
3484 entity->addHPOutput(text, color);
3487 void impulseCombatFlyingText(NLMISC::CBitMemStream &impulse)
3489 uint32 entityID;
3490 uint8 tmp;
3491 impulse.serial(entityID);
3492 impulse.serial(tmp);
3493 COMBAT_FLYING_TEXT::TCombatFlyingText type = (COMBAT_FLYING_TEXT::TCombatFlyingText)tmp;
3495 CRGBA color(255, 255, 255);
3496 string text("");
3497 float dt = 0.0f;
3499 switch (type)
3501 case COMBAT_FLYING_TEXT::TargetDodge: // The target dodged
3502 color = CRGBA(255, 128, 64);
3503 text = CI18N::get("uiDodge");
3504 break;
3506 case COMBAT_FLYING_TEXT::TargetParry: // The target parried
3507 color = CRGBA(255, 128, 64);
3508 text = CI18N::get("uiParry");
3509 break;
3511 case COMBAT_FLYING_TEXT::TargetEvade: // Actually the user miss his hit
3512 color = CRGBA(255, 128, 64);
3513 text = CI18N::get("uiEvade");
3514 break;
3516 case COMBAT_FLYING_TEXT::SelfEvade: // Actually the target miss his hit
3517 color = CRGBA(255, 255, 0);
3518 text = CI18N::get("uiEvade");
3519 break;
3521 case COMBAT_FLYING_TEXT::TargetResist: // The target resisted magic
3522 color = CRGBA(255, 128, 64);
3523 text = CI18N::get("uiResist");
3524 break;
3526 case COMBAT_FLYING_TEXT::SelfResist: // The user resisted magic
3527 color = CRGBA(255, 255, 0);
3528 text = CI18N::get("uiResist");
3529 break;
3531 case COMBAT_FLYING_TEXT::SelfInterrupt: // the user cast was interupted
3532 color = CRGBA(200, 0, 0);
3533 text = CI18N::get("uiInterrupt");
3534 dt = 0.4f;
3535 break;
3537 case COMBAT_FLYING_TEXT::SelfFailure: // The user failed to cast
3538 color = CRGBA(200, 0, 0);
3539 text = CI18N::get("uiFailure");
3540 break;
3542 default: // bad type
3543 nlwarning("Bad type for COMBAT_FLYING_TEXT:TCombatFlyingText enum");
3544 break;
3547 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
3548 if (entity)
3549 entity->addHPOutput(text, color, dt);
3552 void impulseSetSeason(NLMISC::CBitMemStream &impulse)
3554 extern uint8 ServerSeasonValue;
3555 extern bool ServerSeasonReceived;
3556 impulse.serial(ServerSeasonValue);
3557 ServerSeasonReceived = true;
3560 void impulseDssDown(NLMISC::CBitMemStream &impulse)
3562 FarTP.onDssDown();
3565 void impulseSetNpcIconDesc(NLMISC::CBitMemStream &impulse)
3567 uint8 nb8;
3568 impulse.serial(nb8);
3569 bool hasChanged = false;
3570 for (uint i=0; i!=(uint)nb8; ++i)
3572 TNPCIconCacheKey npcIconCacheKey;
3573 impulse.serial(npcIconCacheKey);
3574 uint32 state;
3575 impulse.serial(state);
3576 hasChanged = CNPCIconCache::getInstance().onReceiveMissionAvailabilityForThisChar(npcIconCacheKey, (NPC_ICON::TNPCMissionGiverState)state) || hasChanged; // mind the order to avoid partial evaluation
3578 if (hasChanged)
3579 CNPCIconCache::getInstance().refreshIconsOfScene();
3582 void impulseServerEventForMissionAvailability(NLMISC::CBitMemStream &impulse)
3584 CNPCIconCache::getInstance().onEventForMissionAvailabilityForThisChar();
3587 void impulseSetNpcIconTimer(NLMISC::CBitMemStream &impulse)
3589 NLMISC::TGameCycle delay;
3590 impulse.serial(delay);
3591 CNPCIconCache::getInstance().setMissionGiverTimer(delay);
3594 //-----------------------------------------------
3595 // initializeNetwork :
3596 //-----------------------------------------------
3597 void initializeNetwork()
3599 GenericMsgHeaderMngr.setCallback("DB_UPD_PLR", impulseDatabaseUpdatePlayer);
3600 GenericMsgHeaderMngr.setCallback("DB_INIT:PLR", impulseDatabaseInitPlayer);
3601 GenericMsgHeaderMngr.setCallback("DB_UPD_INV", impulseUpdateInventory);
3602 GenericMsgHeaderMngr.setCallback("DB_INIT:INV", impulseInitInventory);
3603 GenericMsgHeaderMngr.setCallback("DB_GROUP:UPDATE_BANK", impulseDatabaseUpdateBank);
3604 GenericMsgHeaderMngr.setCallback("DB_GROUP:INIT_BANK", impulseDatabaseInitBank);
3605 GenericMsgHeaderMngr.setCallback("DB_GROUP:RESET_BANK", impulseDatabaseResetBank);
3606 GenericMsgHeaderMngr.setCallback("CONNECTION:NO_USER_CHAR", impulseNoUserChar);
3607 GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHARS", impulseUserChars);
3608 GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHAR", impulseUserChar);
3609 GenericMsgHeaderMngr.setCallback("CONNECTION:FAR_TP", impulseFarTP);
3610 GenericMsgHeaderMngr.setCallback("CONNECTION:READY", impulseServerReady);
3611 GenericMsgHeaderMngr.setCallback("CONNECTION:VALID_NAME", impulseCharNameValid);
3612 GenericMsgHeaderMngr.setCallback("CONNECTION:SHARD_ID", impulseShardId);
3613 GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_OK", impulseServerQuitOk);
3614 GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_ABORT", impulseServerQuitAbort);
3615 GenericMsgHeaderMngr.setCallback("CONNECTION:MAIL_AVAILABLE", impulseMailNotification);
3616 GenericMsgHeaderMngr.setCallback("CONNECTION:GUILD_MESSAGE_AVAILABLE", impulseForumNotification);
3617 GenericMsgHeaderMngr.setCallback("CONNECTION:PERMANENT_BAN", impulsePermanentBan);
3618 GenericMsgHeaderMngr.setCallback("CONNECTION:UNBAN", impulsePermanentUnban);
3620 GenericMsgHeaderMngr.setCallback("STRING:CHAT", impulseChat);
3621 GenericMsgHeaderMngr.setCallback("STRING:TELL", impulseTell);
3622 GenericMsgHeaderMngr.setCallback("STRING:FAR_TELL", impulseFarTell);
3623 GenericMsgHeaderMngr.setCallback("STRING:CHAT2", impulseChat2);
3624 GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING", impulseDynString);
3625 GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING_GROUP", inpulseDynStringInChatGroup);
3626 GenericMsgHeaderMngr.setCallback("STRING:TELL2", impulseTell2);
3627 // GenericMsgHeaderMngr.setCallback("STRING:ADD_DYN_STR", impulseAddDynStr);
3628 GenericMsgHeaderMngr.setCallback("TP:DEST", impulseTP);
3629 GenericMsgHeaderMngr.setCallback("TP:DEST_WITH_SEASON", impulseTPWithSeason);
3630 GenericMsgHeaderMngr.setCallback("TP:CORRECT", impulseCorrectPos);
3631 GenericMsgHeaderMngr.setCallback("COMBAT:ENGAGE_FAILED", impulseCombatEngageFailed);
3632 GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_OPEN", impulseDynChatOpen);
3633 GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_CLOSE", impulseDynChatClose);
3635 GenericMsgHeaderMngr.setCallback("CASTING:BEGIN", impulseBeginCast);
3636 GenericMsgHeaderMngr.setCallback("TEAM:INVITATION", impulseTeamInvitation);
3637 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_OPEN", impulseTeamShareOpen);
3638 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_INVALID", impulseTeamShareInvalid);
3639 GenericMsgHeaderMngr.setCallback("TEAM:SHARE_CLOSE", impulseTeamShareClose);
3640 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_INIT", impulseTeamContactInit);
3641 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_CREATE", impulseTeamContactCreate);
3642 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_STATUS", impulseTeamContactStatus);
3643 GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_REMOVE", impulseTeamContactRemove);
3645 GenericMsgHeaderMngr.setCallback("EXCHANGE:INVITATION", impulseExchangeInvitation);
3646 GenericMsgHeaderMngr.setCallback("EXCHANGE:CLOSE_INVITATION", impulseExchangeCloseInvitation);
3647 GenericMsgHeaderMngr.setCallback("ANIMALS:MOUNT_ABORT", impulseMountAbort);
3649 GenericMsgHeaderMngr.setCallback("DEBUG:REPLY_WHERE", impulseWhere);
3650 GenericMsgHeaderMngr.setCallback("DEBUG:COUNTER", impulseCounter);
3653 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:PHRASE_SEND", impulsePhraseSend);
3654 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:STRING_RESP", impulseStringResp);
3655 GenericMsgHeaderMngr.setCallback("STRING_MANAGER:RELOAD_CACHE", impulseReloadCache);
3657 GenericMsgHeaderMngr.setCallback("BOTCHAT:FORCE_END", impulseBotChatForceEnd);
3659 GenericMsgHeaderMngr.setCallback("JOURNAL:INIT_COMPLETED_MISSIONS", impulseJournalInitCompletedMissions);
3660 GenericMsgHeaderMngr.setCallback("JOURNAL:UPDATE_COMPLETED_MISSIONS", impulseJournalUpdateCompletedMissions);
3661 // GenericMsgHeaderMngr.setCallback("JOURNAL:CANT_ABANDON", impulseJournalCantAbandon);
3663 GenericMsgHeaderMngr.setCallback("JOURNAL:ADD_COMPASS", impulseJournalAddCompass);
3664 GenericMsgHeaderMngr.setCallback("JOURNAL:REMOVE_COMPASS", impulseJournalRemoveCompass);
3667 //GenericMsgHeaderMngr.setCallback("GUILD:SET_MEMBER_INFO", impulseGuildSetMemberInfo);
3668 //GenericMsgHeaderMngr.setCallback("GUILD:INIT_MEMBER_INFO", impulseGuildInitMemberInfo);
3670 GenericMsgHeaderMngr.setCallback("GUILD:JOIN_PROPOSAL", impulseGuildJoinProposal);
3672 GenericMsgHeaderMngr.setCallback("GUILD:ASCENSOR", impulseGuildAscensor);
3673 GenericMsgHeaderMngr.setCallback("GUILD:LEAVE_ASCENSOR", impulseGuildLeaveAscensor);
3674 GenericMsgHeaderMngr.setCallback("GUILD:ABORT_CREATION", impulseGuildAbortCreation);
3675 GenericMsgHeaderMngr.setCallback("GUILD:OPEN_GUILD_WINDOW", impulseGuildOpenGuildWindow);
3677 GenericMsgHeaderMngr.setCallback("GUILD:OPEN_INVENTORY", impulseGuildOpenInventory);
3678 GenericMsgHeaderMngr.setCallback("GUILD:CLOSE_INVENTORY", impulseGuildCloseInventory);
3680 GenericMsgHeaderMngr.setCallback("GUILD:UPDATE_PLAYER_TITLE", impulseGuildUpdatePlayerTitle);
3681 GenericMsgHeaderMngr.setCallback("GUILD:USE_FEMALE_TITLES", impulseGuildUseFemaleTitles);
3682 //GenericMsgHeaderMngr.setCallback("GUILD:INVITATION", impulseGuildInvitation);
3684 GenericMsgHeaderMngr.setCallback("HARVEST:CLOSE_TEMP_INVENTORY", impulseCloseTempInv);
3686 GenericMsgHeaderMngr.setCallback("COMMAND:REMOTE_ADMIN", impulseRemoteAdmin);
3688 GenericMsgHeaderMngr.setCallback("PHRASE:DOWNLOAD", impulsePhraseDownLoad);
3689 GenericMsgHeaderMngr.setCallback("PHRASE:CONFIRM_BUY", impulsePhraseConfirmBuy);
3690 GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_CYCLIC_ACK", impulsePhraseAckExecuteCyclic);
3691 GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_NEXT_ACK", impulsePhraseAckExecuteNext);
3693 GenericMsgHeaderMngr.setCallback("ITEM_INFO:SET", impulseItemInfoSet);
3694 GenericMsgHeaderMngr.setCallback("ITEM_INFO:REFRESH_VERSION", impulseItemInfoRefreshVersion);
3695 GenericMsgHeaderMngr.setCallback("MISSION_PREREQ:SET", impulsePrereqInfoSet);
3696 GenericMsgHeaderMngr.setCallback("ITEM:OPEN_ROOM_INVENTORY", impulseItemOpenRoomInventory);
3697 GenericMsgHeaderMngr.setCallback("ITEM:CLOSE_ROOM_INVENTORY", impulseItemCloseRoomInventory);
3699 GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN_POINT", impulseDeathRespawnPoint);
3700 GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN", impulseDeathRespawn);
3702 GenericMsgHeaderMngr.setCallback("DUEL:INVITATION", impulseDuelInvitation);
3703 GenericMsgHeaderMngr.setCallback("DUEL:CANCEL_INVITATION", impulseDuelCancelInvitation);
3705 GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:INVITATION", impulsePVPChallengeInvitation);
3706 GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:CANCEL_INVITATION", impulsePVPChallengeCancelInvitation);
3708 GenericMsgHeaderMngr.setCallback("PVP_FACTION:PUSH_FACTION_WAR", impulsePVPFactionPushFactionWar);
3709 GenericMsgHeaderMngr.setCallback("PVP_FACTION:POP_FACTION_WAR", impulsePVPFactionPopFactionWar);
3710 GenericMsgHeaderMngr.setCallback("PVP_FACTION:FACTION_WARS", impulsePVPFactionFactionWars);
3713 // GenericMsgHeaderMngr.setCallback("PVP_VERSUS:CHOOSE_CLAN", impulsePVPChooseClan);
3715 GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:UPDATE", impulseEncyclopediaUpdate);
3716 GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:INIT", impulseEncyclopediaInit);
3718 GenericMsgHeaderMngr.setCallback("USER:BARS", impulseUserBars);
3719 GenericMsgHeaderMngr.setCallback("USER:POPUP", impulseUserPopup);
3722 GenericMsgHeaderMngr.setCallback("MISSION:ASK_ENTER_CRITICAL", impulseEnterCrZoneProposal);
3723 GenericMsgHeaderMngr.setCallback("MISSION:CLOSE_ENTER_CRITICAL", impulseCloseEnterCrZoneProposal);
3725 // Module gateway message
3726 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FEOPEN", cbImpulsionGatewayOpen);
3727 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:GATEWAY_MSG", cbImpulsionGatewayMessage );
3728 GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FECLOSE", cbImpulsionGatewayClose );
3730 GenericMsgHeaderMngr.setCallback( "OUTPOST:CHOOSE_SIDE", impulseOutpostChooseSide );
3731 GenericMsgHeaderMngr.setCallback( "OUTPOST:DECLARE_WAR_ACK", impulseOutpostDeclareWarAck );
3733 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_HP_DELTA", impulseCombatFlyingHpDelta );
3734 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT_ISE", impulseCombatFlyingTextItemSpecialEffectProc );
3735 GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT", impulseCombatFlyingText );
3737 GenericMsgHeaderMngr.setCallback( "SEASON:SET", impulseSetSeason );
3738 GenericMsgHeaderMngr.setCallback( "RING_MISSION:DSS_DOWN", impulseDssDown );
3740 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_DESC", impulseSetNpcIconDesc );
3741 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SVR_EVENT_MIS_AVL", impulseServerEventForMissionAvailability );
3742 GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_TIMER", impulseSetNpcIconTimer );
3746 //-----------------------------------------------
3747 // impulseCallBack :
3748 // The impulse callback to receive all msg from the frontend.
3749 //-----------------------------------------------
3750 void impulseCallBack(NLMISC::CBitMemStream &impulse, sint32 packet, void *arg)
3752 GenericMsgHeaderMngr.execute(impulse);
3756 ////////////
3757 // METHOD //
3758 ////////////
3759 //-----------------------------------------------
3760 // CNetManager :
3761 // Constructor.
3762 //-----------------------------------------------
3763 CNetManager::CNetManager() : CNetworkConnection()
3765 #ifdef ENABLE_INCOMING_MSG_RECORDER
3766 _IsReplayStarting = false;
3767 #endif
3768 }// CNetManager //
3770 //-----------------------------------------------
3771 // update :
3772 // Updates the whole connection with the frontend.
3773 // Call this method evently.
3774 // \return bool : 'true' if data were sent/received.
3775 //-----------------------------------------------
3776 bool CNetManager::update()
3778 H_AUTO_USE ( RZ_Client_Net_Mngr_Update )
3780 #ifdef ENABLE_INCOMING_MSG_RECORDER
3781 if(_IsReplayStarting)
3782 return;
3783 #endif
3785 // If the client is in Local Mode -> no network.
3786 if(ClientCfg.Local)
3788 // Init
3789 if(_CurrentServerTick == 0)
3791 if(T1 >= _LCT)
3793 _MachineTimeAtTick = T1;
3794 _CurrentClientTime = _MachineTimeAtTick - _LCT;
3795 _CurrentClientTick = 0;
3796 _CurrentServerTick = 10;
3799 return false;
3802 if((T1 - _MachineTimeAtTick) >= _MsPerTick)
3804 NLMISC::TGameCycle nbTick = (NLMISC::TGameCycle)((T1 - _MachineTimeAtTick)/_MsPerTick);
3805 _CurrentClientTick += nbTick;
3806 _CurrentServerTick += nbTick;
3807 _MachineTimeAtTick += nbTick*_MsPerTick;
3810 // update the smooth server tick for debug
3811 CNetworkConnection::updateSmoothServerTick();
3813 // emulation done
3814 #ifdef ENABLE_INCOMING_MSG_RECORDER
3815 return false;
3816 #endif
3819 // Update the base class.
3820 bool result = CNetworkConnection::update();
3821 // Get changes with the update.
3822 const vector<CChange> &changes = NetMngr.getChanges();
3824 // Manage changes
3825 vector<CChange>::const_iterator it;
3826 for(it = changes.begin(); it < changes.end(); ++it)
3828 const CChange &change = *it;
3829 // Update a property.
3830 if(change.Property < AddNewEntity)
3832 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3834 // Update the visual property for the slot.
3835 EntitiesMngr.updateVisualProperty(change.GameCycle, change.ShortId, change.Property, change.PositionInfo.PredictedInterval);
3837 else
3839 nlwarning("CNetManager::update : Skipping EntitiesMngr.updateVisualProperty() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3842 // Add New Entity (and remove the old one in the slot).
3843 else if(change.Property == AddNewEntity)
3845 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3847 // Remove the old entity.
3848 EntitiesMngr.remove(change.ShortId, false);
3849 // Create the new entity.
3850 if(EntitiesMngr.create(change.ShortId, get(change.ShortId), change.NewEntityInfo) == 0)
3851 nlwarning("CNetManager::update : entity in the slot '%u' has not been created.", change.ShortId);
3853 else
3855 nlwarning("CNetManager::update : Skipping EntitiesMngr.create() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3858 // Delete an entity
3859 else if(change.Property == RemoveOldEntity)
3861 if (!IgnoreEntityDbUpdates || change.ShortId == 0)
3863 // Remove the old entity.
3864 EntitiesMngr.remove(change.ShortId, true);
3866 else
3868 nlwarning("CNetManager::update : Skipping EntitiesMngr.remove() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
3871 // Lag detected.
3872 else if(change.Property == LagDetected)
3874 nldebug("CNetManager::update : Lag detected.");
3876 // Probe received.
3877 else if(change.Property == ProbeReceived)
3879 nldebug("CNetManager::update : Probe Received.");
3881 // Connection ready.
3882 else if(change.Property == ConnectionReady)
3884 nldebug("CNetManager::update : Connection Ready.");
3886 // Property unknown.
3887 else
3888 nlwarning("CNetManager::update : The property '%d' is unknown.", change.Property);
3890 ChatMngr.flushBuffer(InterfaceChatDisplayer);
3891 // Clear all changes.
3892 clearChanges();
3894 // Update data base server state
3895 if (IngameDbMngr.getNodePtr())
3897 CInterfaceManager *im = CInterfaceManager::getInstance();
3898 if (im)
3900 CCDBNodeLeaf *node = NULL;
3902 if (!m_PingLeaf)
3903 m_PingLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:PING", false);
3905 if (m_PingLeaf)
3907 node = &*m_PingLeaf;
3908 if (node)
3909 node->setValue32(getPing());
3912 if (!m_UploadLeaf)
3913 m_UploadLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:UPLOAD", false);
3915 if (m_UploadLeaf)
3917 node = &*m_UploadLeaf;
3918 if (node)
3919 node->setValue32((sint32)(getMeanUpload()*1024.f/8.f));
3922 if (!m_DownloadLeaf)
3923 m_DownloadLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:DOWNLOAD", false);
3925 if (m_DownloadLeaf)
3927 node = &*m_DownloadLeaf;
3928 if (node)
3929 node->setValue32((sint32)(getMeanDownload()*1024.f/8.f));
3932 if (!m_PacketLostLeaf)
3933 m_PacketLostLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:PACKETLOST", false);
3935 if (m_PacketLostLeaf)
3937 node = &*m_PacketLostLeaf;
3938 if (node)
3939 node->setValue32((sint32)getMeanPacketLoss());
3942 if (!m_ServerStateLeaf)
3943 m_ServerStateLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:SERVERSTATE", false);
3945 if (m_ServerStateLeaf)
3947 node = &*m_ServerStateLeaf;
3948 if (node)
3949 node->setValue32((sint32)getConnectionState());
3952 if (!m_ConnectionQualityLeaf)
3953 m_ConnectionQualityLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CONNECTION_QUALITY", false);
3955 if (m_ConnectionQualityLeaf)
3957 node = &*m_ConnectionQualityLeaf;
3958 if (node)
3959 node->setValue32((sint32)getConnectionQuality());
3964 // Return 'true' if data were sent/received.
3965 return result;
3968 }// update //
3970 //-----------------------------------------------
3971 // getConnectionQuality :
3972 //-----------------------------------------------
3973 bool CNetManager::getConnectionQuality()
3975 // If the client is in Local Mode -> no network.
3976 if(ClientCfg.Local)
3977 return true;
3979 return CNetworkConnection::getConnectionQuality();
3980 }// getConnectionQuality //
3984 * Buffers a bitmemstream, that will be converted into a generic action, to be sent later to the server (at next update).
3986 void CNetManager::push(NLMISC::CBitMemStream &msg)
3988 // If the client is in Local Mode -> no network.
3989 if(ClientCfg.Local)
3990 return;
3992 if (PermanentlyBanned) return;
3994 CNetworkConnection::push(msg);
3998 * Buffers a target action
4000 void CNetManager::pushTarget(CLFECOMMON::TCLEntityId slot)
4002 // If the client is in Local Mode -> no network.
4003 if(ClientCfg.Local)
4005 if(UserEntity->mode() != MBEHAV::COMBAT
4006 && UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
4008 UserEntity->targetSlot(slot);
4010 return;
4013 CNetworkConnection::pushTarget(slot, LHSTATE::NONE);
4018 * Buffers a pick-up action
4020 void CNetManager::pushPickup(CLFECOMMON::TCLEntityId slot, LHSTATE::TLHState lootOrHarvest)
4022 // If the client is in Local Mode -> no network.
4023 if(ClientCfg.Local)
4025 return;
4028 CNetworkConnection::pushTarget(slot, lootOrHarvest);
4033 * Send
4035 void CNetManager::send(NLMISC::TGameCycle gameCycle)
4037 // If the client is in Local Mode -> no network.
4038 if(ClientCfg.Local)
4039 return;
4041 // wait till next server is received
4042 if (_LastSentCycle >= gameCycle)
4044 //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);
4045 while (_LastSentCycle >= gameCycle)
4047 // Update network.
4048 update();
4049 // Send dummy info
4050 send();
4051 // Do not take all the CPU.
4052 nlSleep(100);
4054 gameCycle = getCurrentServerTick();
4058 CNetworkConnection::send(gameCycle);
4062 * Send
4064 void CNetManager::send()
4066 // If the client is in Local Mode -> no network.
4067 if(ClientCfg.Local)
4068 return;
4070 CNetworkConnection::send();
4074 * Disconnects the current connection
4076 void CNetManager::disconnect()
4078 // If the client is in Local Mode -> no need to disconnect.
4079 if(ClientCfg.Local)
4080 return;
4082 CNetworkConnection::disconnect();
4083 }// disconnect //
4087 * Reset data and init the socket
4089 void CNetManager::reinit()
4091 if(ClientCfg.Local)
4092 return;
4094 IngameDbMngr.resetInitState();
4095 CNetworkConnection::reinit();
4098 void CNetManager::waitForServer()
4100 sint LastGameCycle = getCurrentServerTick();
4102 for(;;)
4104 // Event server get events
4105 CInputHandlerManager::getInstance()->pumpEventsNoIM();
4106 // Update Network.
4107 update();
4109 if (LastGameCycle != (sint) getCurrentServerTick())
4110 break;
4112 nlSleep(100);
4113 send();
4116 }// waitForServer //
4119 #ifdef ENABLE_INCOMING_MSG_RECORDER
4120 //-----------------------------------------------
4121 // setReplayingMode :
4122 //-----------------------------------------------
4123 void CNetManager::setReplayingMode( bool onOff, const std::string& filename )
4125 CNetworkConnection::setReplayingMode(onOff, filename);
4126 _IsReplayStarting = onOff;
4127 }// setReplayingMode //
4129 //-----------------------------------------------
4130 // startReplay :
4131 //-----------------------------------------------
4132 void CNetManager::startReplay()
4134 // Init Replay
4135 _MachineTimeAtTick = T1;
4136 if(_MachineTimeAtTick >= _LCT)
4137 _CurrentClientTime = _MachineTimeAtTick - _LCT;
4138 else
4139 _CurrentClientTime = 0;
4140 // Replay now in progress.
4141 _IsReplayStarting = false;
4142 }// startReplay //
4143 #endif
4147 * Create the net managers in CLIENT_MULTI mode
4149 void CNetManagerMulti::init( const std::string& cookie, const std::string& addr )
4151 uint nb, baseCookie;
4152 NLMISC::CConfigFile::CVar *var = ClientCfg.ConfigFile.getVarPtr( "NbConnections" );
4153 if ( var )
4154 nb = var->asInt();
4155 else
4156 nb = 1;
4157 var = ClientCfg.ConfigFile.getVarPtr( "UserId" );
4158 if ( var )
4159 baseCookie = var->asInt();
4160 else
4161 baseCookie = 0;
4162 std::vector<std::string> fsAddrs;
4163 fsAddrs.push_back( addr );
4164 string portString = addr.substr( addr.find( ':' ) );
4165 var = ClientCfg.ConfigFile.getVarPtr( "AdditionalFSList" );
4166 if ( var )
4168 for ( uint i=0; i!=var->size(); ++i )
4169 fsAddrs.push_back( var->asString( i ) + portString );
4171 nlinfo( "CNetManagerMulti: Creating %u connections to %u front-ends, baseCookie=%u...", nb, fsAddrs.size(), baseCookie );
4173 for ( uint i=0; i!=nb; ++i )
4175 CNetManager *nm = new CNetManager();
4176 string multicook = NLMISC::toString( "%8x|%8x|%8x", 0, 0, baseCookie + i );
4177 nm->init( multicook, fsAddrs[i % fsAddrs.size()] );
4178 _NetManagers.push_back( nm );
4183 uint32 ShardId = 0;
4184 std::string WebServer;
4189 /////////////////////////////////////////////////////////////////////////////
4190 /////////////////////////////////////////////////////////////////////////////
4191 /////////////////////////////////////////////////////////////////////////////
4192 /////////////////////////////////////////////////////////////////////////////
4193 /////////// COMMANDS after should NOT appear IN the FINAL VERSION ///////////
4194 /////////////////////////////////////////////////////////////////////////////
4195 /////////////////////////////////////////////////////////////////////////////
4196 /////////////////////////////////////////////////////////////////////////////
4197 /////////////////////////////////////////////////////////////////////////////
4198 /////////////////////////////////////////////////////////////////////////////
4201 #if !FINAL_VERSION
4203 // temp : simulate a team msg in local mode
4204 NLMISC_COMMAND(localTellTeam, "Temp : simulate a tell in local mode", "<people_name> <msg>")
4206 if (args.empty()) return false;
4207 string player = args[0];
4208 std::string msg;
4209 if (args.size() >= 2)
4211 msg = args[1];
4212 for(uint k = 2; k < args.size(); ++k)
4214 msg += " " + args[k];
4217 TDataSetIndex dsi = INVALID_DATASET_INDEX;
4218 InterfaceChatDisplayer.displayChat(dsi, msg, msg, CChatGroup::team, NLMISC::CEntityId::Unknown, player);
4219 return true;
4222 // temp : simulate a tell in local mode
4223 NLMISC_COMMAND(localTell, "Temp : simulate a tell in local mode", "<people_name> <msg>")
4225 if (args.empty()) return false;
4226 string player = args[0];
4227 std::string msg;
4228 if (args.size() >= 2)
4230 msg = args[1];
4231 for(uint k = 2; k < args.size(); ++k)
4233 msg += " " + args[k];
4236 // TDataSetIndex dsi = INVALID_DATASET_ROW;
4237 InterfaceChatDisplayer.displayTell(/*dsi, */msg, player);
4238 return true;
4241 NLMISC_COMMAND(testDynChatOpen, "", "")
4243 NLMISC::CBitMemStream bm;
4244 if (bm.isReading()) bm.invert();
4245 uint32 BotUID = 22; // Compressed Index
4246 uint32 BotName = 654; // Server string
4247 vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
4248 DynStrs.push_back(16540);
4249 DynStrs.push_back(11465);
4250 DynStrs.push_back(12654);
4251 bm.serial(BotUID);
4252 bm.serial(BotName);
4253 bm.serialCont(DynStrs);
4254 bm.invert();
4255 bm.seek(0, NLMISC::IStream::begin);
4256 impulseDynChatOpen(bm);
4257 return true;
4260 NLMISC_COMMAND(testDynChatClose, "", "")
4262 NLMISC::CBitMemStream bm;
4263 if (bm.isReading()) bm.invert();
4264 uint32 BotUID = 22; // Compressed Index
4265 bm.serial(BotUID);
4266 bm.invert();
4267 bm.seek(0, NLMISC::IStream::begin);
4268 impulseDynChatClose(bm);
4269 return true;
4273 NLMISC_COMMAND(testCloseTempInv, "","")
4275 NLMISC::CBitMemStream bm;
4276 impulseCloseTempInv(bm);
4277 return true;
4280 NLMISC_COMMAND(testTeamInvite, "","")
4282 NLMISC::CBitMemStream bm;
4283 if (bm.isReading()) bm.invert();
4284 uint32 index = 10;
4285 bm.serial(index);
4286 bm.invert();
4287 bm.seek(0, NLMISC::IStream::begin);
4288 impulseTeamInvitation(bm);
4289 return true;
4291 NLMISC_COMMAND(testGuildInvite, "","")
4293 NLMISC::CBitMemStream bm;
4294 if (bm.isReading()) bm.invert();
4295 uint32 index = 10;
4296 bm.serial(index);
4297 bm.serial(index);
4298 bm.invert();
4299 bm.seek(0, NLMISC::IStream::begin);
4300 impulseGuildJoinProposal(bm);
4301 return true;
4304 NLMISC_COMMAND( testExchangeInvitation, "Test the modal window for invitation exchange", "" )
4306 CBitMemStream impulse;
4307 uint32 nameIndex = 0;
4308 impulse.serial(nameIndex);
4309 impulse.invert();
4310 impulseExchangeInvitation(impulse);
4311 return true;
4315 NLMISC_COMMAND(testAscensor, "Temp : Simulate a GUILD:ASCENSOR message coming from server","")
4317 NLMISC::CBitMemStream bm;
4318 if (bm.isReading()) bm.invert();
4319 uint32 index = 10;
4320 bm.serial(index);
4321 bm.invert();
4322 bm.seek(0, NLMISC::IStream::begin);
4323 impulseGuildAscensor(bm);
4324 return true;
4327 NLMISC_COMMAND(testDuelInvite, "","")
4329 NLMISC::CBitMemStream bm;
4330 if (bm.isReading()) bm.invert();
4331 uint32 index = 10;
4332 bm.serial(index);
4333 bm.invert();
4334 bm.seek(0, NLMISC::IStream::begin);
4335 impulseDuelInvitation(bm);
4336 return true;
4339 //NLMISC_COMMAND(receiveId, "","<num> <name>")
4341 // uint32 index;
4342 // fromString(args[0], index);
4343 // ucstring ucstr = args[1]; // OLD
4345 // vector<bool> code;
4347 //#ifdef OLD_STRING_SYSTEM
4348 // ChatMngr.getDynamicDB().add( index, ucstr, code );
4349 //#else
4350 // // TRAP // WE MUST NEVER CALL THIS COMMAND ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!
4351 // nlstop;
4352 //#endif
4354 // return true;
4357 NLMISC_COMMAND(testOutpostChooseSide, "","b b u32 u32")
4359 if(args.size()<4)
4360 return false;
4361 NLMISC::CBitMemStream bm;
4362 if (bm.isReading()) bm.invert();
4363 bool playerGuildInConflict;
4364 fromString(args[0], playerGuildInConflict);
4365 bool playerGuildIsAttacker;
4366 fromString(args[1], playerGuildIsAttacker);
4367 bm.serial(playerGuildInConflict);
4368 bm.serial(playerGuildIsAttacker);
4369 uint32 ownerGuildNameId;
4370 fromString(args[2], ownerGuildNameId);
4371 bm.serial( ownerGuildNameId );
4372 uint32 attackerGuildNameId;
4373 fromString(args[3], attackerGuildNameId);
4374 bm.serial( attackerGuildNameId );
4375 uint32 declTimer= 100;
4376 bm.serial( declTimer );
4378 bm.invert();
4379 bm.seek(0, NLMISC::IStream::begin);
4380 impulseOutpostChooseSide(bm);
4381 return true;
4384 NLMISC_COMMAND(testUserPopup, "","u32 u32")
4386 if(args.size()<2)
4387 return false;
4388 NLMISC::CBitMemStream bm;
4389 if (bm.isReading()) bm.invert();
4390 uint32 titleId;
4391 fromString(args[0], titleId);
4392 bm.serial( titleId );
4393 uint32 textId;
4394 fromString(args[1], textId);
4395 bm.serial( textId );
4397 bm.invert();
4398 bm.seek(0, NLMISC::IStream::begin);
4399 impulseUserPopup(bm);
4400 return true;
4404 #endif