4327 lines
131 KiB
C++
4327 lines
131 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
/////////////
|
|
// INCLUDE //
|
|
/////////////
|
|
#include "stdpch.h"
|
|
// Game Share
|
|
#include "game_share/generic_xml_msg_mngr.h"
|
|
#include "game_share/msg_client_server.h"
|
|
#include "game_share/bot_chat_types.h"
|
|
#include "game_share/news_types.h"
|
|
#include "game_share/mode_and_behaviour.h"
|
|
#include "game_share/chat_group.h"
|
|
#include "game_share/character_summary.h"
|
|
#include "game_share/sphrase_com.h"
|
|
#include "game_share/msg_client_server.h"
|
|
#include "game_share/ryzom_database_banks.h"
|
|
#include "game_share/msg_encyclopedia.h"
|
|
#include "game_share/prerequisit_infos.h"
|
|
#include "game_share/permanent_ban_magic_number.h"
|
|
#include "game_share/item_special_effect.h"
|
|
#include "game_share/combat_flying_text.h"
|
|
#include "game_share/shard_names.h"
|
|
// Client.
|
|
#include "interface_v3/group_list.h"
|
|
#include "interface_v3/interface_manager.h"
|
|
#include "net_manager.h"
|
|
#include "client_cfg.h"
|
|
#include "entities.h"
|
|
#include "client_chat_manager.h"
|
|
#include "world_database_manager.h"
|
|
#include "continent_manager.h"
|
|
#include "motion/user_controls.h"
|
|
#include "interface_v3/bot_chat_manager.h"
|
|
#include "interface_v3/bot_chat_page_all.h"
|
|
#include "interface_v3/bot_chat_page_trade.h"
|
|
#include "interface_v3/bot_chat_page_create_guild.h"
|
|
#include "interface_v3/obs_huge_list.h"
|
|
#include "string_manager_client.h"
|
|
#include "interface_v3/people_interraction.h"
|
|
#include "interface_v3/bot_chat_manager.h"
|
|
#include "interface_v3/bot_chat_page_all.h"
|
|
#include "interface_v3/view_text_id.h"
|
|
#include "interface_v3/ctrl_text_button.h"
|
|
#include "interface_v3/input_handler_manager.h"
|
|
#include "interface_v3/guild_manager.h"
|
|
#include "interface_v3/skill_manager.h"
|
|
#include "misc.h"
|
|
#include "interface_v3/inventory_manager.h"
|
|
#include "interface_v3/sphrase_manager.h"
|
|
#include "outpost_manager.h"
|
|
#include "interface_v3/encyclopedia_manager.h"
|
|
#include "user_entity.h"
|
|
#include "init_main_loop.h"
|
|
#include "interface_v3/group_map.h"
|
|
#include "sound_manager.h"
|
|
#include "interface_v3/group_compas.h"
|
|
#include "interface_v3/group_html_webig.h"
|
|
#include "interface_v3/bar_manager.h"
|
|
#include "permanent_ban.h"
|
|
#include "global.h"
|
|
#include "connection.h"
|
|
#include "faction_war_manager.h"
|
|
#include "far_tp.h"
|
|
#include "input.h"
|
|
#include "r2/editor.h"
|
|
#include "game_share/r2_share_itf.h"
|
|
#include "game_share/r2_types.h"
|
|
#include "npc_icon.h"
|
|
|
|
// Std.
|
|
#include <vector>
|
|
|
|
|
|
#define OLD_STRING_SYSTEM
|
|
#define BAR_STEP_TP 2
|
|
|
|
///////////
|
|
// USING //
|
|
///////////
|
|
using namespace NLMISC;
|
|
using namespace NL3D;
|
|
using namespace std;
|
|
|
|
|
|
extern bool FirstFrame;
|
|
extern void selectTipsOfTheDay (uint tips);
|
|
|
|
|
|
////////////
|
|
// GLOBAL //
|
|
////////////
|
|
CGenericXmlMsgHeaderManager GenericMsgHeaderMngr; // Manage messages
|
|
#ifdef CLIENT_MULTI
|
|
CNetManagerMulti NetMngr; // Manage the connection.
|
|
#else
|
|
CNetManager NetMngr; // Manage the connection.
|
|
#endif
|
|
|
|
bool UseFemaleTitles = false;
|
|
|
|
bool serverReceivedReady = false;
|
|
|
|
static const std::string PLAYER_EXCHANGE_INVITATION_DIALOG = "ui:interface:accept_trade_invitation";
|
|
|
|
// Hierarchical timer
|
|
H_AUTO_DECL ( RZ_Client_Net_Mngr_Update )
|
|
|
|
////////////
|
|
// EXTERN //
|
|
////////////
|
|
extern bool noUserChar; // \todo GUIGUI : do this better.
|
|
extern bool userChar; // \todo GUIGUI : do this better.
|
|
extern std::vector<CCharacterSummary> CharacterSummaries;
|
|
extern uint8 ServerPeopleActive;
|
|
extern uint8 ServerCareerActive;
|
|
extern vector<CMainlandSummary> Mainlands;
|
|
extern bool UserCharPosReceived;
|
|
extern CGenericXmlMsgHeaderManager GenericMsgHeaderMngr;
|
|
extern CClientChatManager ChatMngr;
|
|
|
|
extern bool CharNameValidArrived;
|
|
extern bool CharNameValid;
|
|
bool IsInRingSession = false;
|
|
TSessionId HighestMainlandSessionId; // highest in the position stack
|
|
|
|
extern const char *CDBBankNames[INVALID_CDB_BANK+1];
|
|
|
|
void cbImpulsionGatewayOpen(NLMISC::CBitMemStream &bms);
|
|
void cbImpulsionGatewayMessage(NLMISC::CBitMemStream &bms);
|
|
void cbImpulsionGatewayClose(NLMISC::CBitMemStream &bms);
|
|
|
|
|
|
|
|
///////////////
|
|
// FUNCTIONS //
|
|
///////////////
|
|
|
|
void impulseDatabaseInitPlayer(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
try
|
|
{
|
|
sint32 p = impulse.getPos();
|
|
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// read delta
|
|
IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer );
|
|
IngameDbMngr.setInitPacketReceived();
|
|
nlinfo( "DB_INIT:PLR done (%u bytes)", impulse.getPos()-p );
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
BOMB( NLMISC::toString( "Problem while decoding a DB_INIT:PLR msg, skipped: %s", e.what() ), return );
|
|
}
|
|
}
|
|
|
|
void impulseDatabaseUpdatePlayer(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
try
|
|
{
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// read delta
|
|
IngameDbMngr.readDelta( serverTick, impulse, CDBPlayer ); // unlike on the server, here there is only one unified CCDBSynchronized object
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
|
|
BOMB( NLMISC::toString( "Problem while decoding a DB_UPDATE_PLR msg, skipped: %s", e.what() ), return );
|
|
}
|
|
}
|
|
|
|
template <class CInventoryCategoryTemplate>
|
|
void updateInventoryFromStream(NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges);
|
|
|
|
void impulseDatabaseUpdateBank(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 bank = INVALID_CDB_BANK;
|
|
try
|
|
{
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// decode bank
|
|
uint nbits;
|
|
FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
|
|
impulse.serial( bank, nbits );
|
|
|
|
// read delta
|
|
IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
|
|
|
|
// read guild inventory update
|
|
if ( bank == CDBGuild )
|
|
{
|
|
updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:UPDATE_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
|
|
}
|
|
}
|
|
|
|
void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 bank = INVALID_CDB_BANK;
|
|
try
|
|
{
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// decode bank
|
|
uint nbits;
|
|
FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
|
|
impulse.serial( bank, nbits );
|
|
|
|
// read delta
|
|
IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank );
|
|
nldebug( "CDB: DB_GROUP:INIT_BANK %s", CDBBankNames[bank] );
|
|
|
|
// read guild inventory update
|
|
if ( bank == CDBGuild )
|
|
{
|
|
updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForGuild*)NULL, false );
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:INIT_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
|
|
}
|
|
}
|
|
|
|
void impulseDatabaseResetBank(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 bank = INVALID_CDB_BANK;
|
|
try
|
|
{
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// read the bank to reset
|
|
uint nbits;
|
|
FILL_nbits_WITH_NB_BITS_FOR_CDBBANK
|
|
impulse.serial( bank, nbits );
|
|
|
|
// reset the bank
|
|
IngameDbMngr.getNodePtr()->resetBank( serverTick, (TCDBBank)bank );
|
|
nldebug( "CDB: DB_GROUP:RESET_BANK %s", CDBBankNames[bank] );
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:RESET_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return );
|
|
}
|
|
}
|
|
|
|
static void readPrivileges(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlassert(impulse.isReading());
|
|
// nico : temporarily uses a try block here to avoid prb with people having updated client and not the server
|
|
try
|
|
{
|
|
impulse.serial(UserPrivileges);
|
|
}
|
|
catch(const EStreamOverflow &)
|
|
{
|
|
nlwarning("User privileges not serialised, assuming none");
|
|
UserPrivileges = "";
|
|
}
|
|
}
|
|
|
|
void impulseNoUserChar(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received NO_USER_CHAR
|
|
//nlinfo("impulseCallBack : Received CONNECTION:NO_USER_CHAR");
|
|
|
|
impulse.serial(ServerPeopleActive);
|
|
impulse.serial(ServerCareerActive);
|
|
readPrivileges(impulse);
|
|
impulse.serialCont(Mainlands);
|
|
CharacterSummaries.clear();
|
|
noUserChar = true;
|
|
|
|
LoginSM.pushEvent(CLoginStateMachine::ev_no_user_char);
|
|
|
|
updatePatcherPriorityBasedOnCharacters();
|
|
}
|
|
|
|
void impulseFarTP(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received FAR_TP
|
|
TSessionId sessionId;
|
|
impulse.serial(sessionId);
|
|
//nlinfo("impulseCallback : Received CONNECTION:FAR_TP %u", sessionId.asInt());
|
|
bool bailOutIfSessionVanished;
|
|
impulse.serial(bailOutIfSessionVanished);
|
|
FarTP.requestFarTPToSession(sessionId, PlayerSelectedSlot, CFarTP::JoinSession, bailOutIfSessionVanished);
|
|
}
|
|
|
|
|
|
static std::string lookupSrcKeyFile(const std::string &src)
|
|
{
|
|
if (CFile::isExists("save/" + src)) return "save/" + src;
|
|
return CPath::lookup(src, false);
|
|
}
|
|
|
|
void copyKeySet(const std::string &srcPath, const std::string &destPath)
|
|
{
|
|
// can't use CFile copyFile here, because src may be in a bnp file
|
|
std::string srcStr;
|
|
srcStr.resize(CFile::getFileSize(srcPath));
|
|
if (srcStr.empty())
|
|
{
|
|
nlwarning("Can't copy keys from %s : file not found or empty");
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
CIFile ifile(srcPath);
|
|
ifile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
|
|
COFile ofile(destPath);
|
|
ofile.serialBuffer((uint8 *) &srcStr[0], (uint)srcStr.size());
|
|
}
|
|
catch(const EStream &)
|
|
{
|
|
nlwarning("Couldn't copy %s to %s to create new character keyset", srcPath.c_str(), destPath.c_str());
|
|
}
|
|
}
|
|
|
|
void impulseUserChars(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received USER_CHARS
|
|
//nlinfo("impulseCallBack : Received CONNECTION:USER_CHARS");
|
|
|
|
impulse.serial(ServerPeopleActive);
|
|
impulse.serial(ServerCareerActive);
|
|
// read characters summary
|
|
CharacterSummaries.clear();
|
|
impulse.serialCont (CharacterSummaries);
|
|
// read shard name summaries
|
|
std::vector<string> shardNames;
|
|
impulse.serialCont (shardNames);
|
|
CShardNames::getInstance().loadShardNames(shardNames);
|
|
// read privileges
|
|
readPrivileges(impulse);
|
|
impulse.serial(FreeTrial);
|
|
FreeTrial = false;
|
|
impulse.serialCont(Mainlands);
|
|
userChar = true;
|
|
|
|
LoginSM.pushEvent(CLoginStateMachine::ev_chars_received);
|
|
|
|
// Create the message for the server to select the first character.
|
|
/* CBitMemStream out;
|
|
if(GenericMsgHeaderMngr.pushNameToStream("CONNECTION:SELECT_CHAR", out))
|
|
{
|
|
CSelectCharMsg SelectCharMsg;
|
|
SelectCharMsg.c = 0; //TODO set here the character choosen by player
|
|
out.serial( SelectCharMsg );
|
|
NetMngr.push(out);
|
|
NetMngr.send(NetMngr.getCurrentServerTick());
|
|
// send CONNECTION:USER_CHARS
|
|
nldebug("impulseCallBack : CONNECTION:SELECT_CHAR sent");
|
|
}
|
|
else
|
|
nlwarning("impulseCallBack : unknown message name : 'CONNECTION:SELECT_CHAR'.");
|
|
|
|
noUserChar = true;
|
|
*/
|
|
|
|
if (!NewKeysCharNameValidated.empty())
|
|
{
|
|
// if there's a new char for which a key set was wanted, create it now
|
|
for (uint k = 0; k < CharacterSummaries.size(); ++k)
|
|
{
|
|
if (toLower(CharacterSummaries[k].Name) == toLower(NewKeysCharNameValidated))
|
|
{
|
|
// first, stripes server name
|
|
copyKeySet(lookupSrcKeyFile(GameKeySet), "save/keys_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
|
|
copyKeySet(lookupSrcKeyFile(RingEditorKeySet), "save/keys_r2ed_" + buildPlayerNameForSaveFile(NewKeysCharNameValidated) + ".xml");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
updatePatcherPriorityBasedOnCharacters();
|
|
}
|
|
|
|
void impulseUserChar(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received USER_CHAR
|
|
//nlinfo("impulseCallBack : Received CONNECTION:USER_CHAR");
|
|
|
|
// Serialize the message
|
|
COfflineEntityState posState;
|
|
extern uint8 ServerSeasonValue;
|
|
extern bool ServerSeasonReceived;
|
|
uint32 userRole;
|
|
CUserCharMsg::read( impulse, posState, ServerSeasonValue, userRole, IsInRingSession, HighestMainlandSessionId, CharFirstConnectedTime, CharPlayedTime );
|
|
ServerSeasonReceived = true; // set the season that will be used when selecting the continent from the position
|
|
|
|
if (UserEntity)
|
|
{
|
|
UserEntity->pos(CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f));
|
|
UserEntity->front(CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f));
|
|
UserEntity->dir(UserEntity->front());
|
|
UserEntity->setHeadPitch(0);
|
|
UserControls.resetCameraDeltaYaw();
|
|
//nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntity->pos().x,UserEntity->pos().y,UserEntity->pos().z,posState.Heading);
|
|
|
|
// Update the position for the vision.
|
|
NetMngr.setReferencePosition(UserEntity->pos());
|
|
}
|
|
else
|
|
{
|
|
UserEntityInitPos = CVectorD((float)posState.X/1000.0f, (float)posState.Y/1000.0f, (float)posState.Z/1000.0f);
|
|
UserEntityInitFront = CVector((float)cos(posState.Heading), (float)sin(posState.Heading), 0.f);
|
|
//nldebug("<impulseUserChar> pos : %f %f %f heading : %f",UserEntityInitPos.x,UserEntityInitPos.y,UserEntityInitPos.z,posState.Heading);
|
|
|
|
// Update the position for the vision.
|
|
NetMngr.setReferencePosition(UserEntityInitPos);
|
|
}
|
|
|
|
UserCharPosReceived = true;
|
|
|
|
// Configure the ring editor
|
|
extern R2::TUserRole UserRoleInSession;
|
|
UserRoleInSession = R2::TUserRole::TValues(userRole);
|
|
ClientCfg.R2EDEnabled = IsInRingSession /*&& (UserRoleInSession.getValue() != R2::TUserRole::ur_player)*/;
|
|
// !!!Do NOT uncomment the following line do the ClientCfg.R2EDEnabled = IsInRingSession && (UserRoleInSession != R2::TUserRole::ur_player);
|
|
// even with UserRoleInSession R2::TUserRole::ur_player the ring features must be activated
|
|
// because if the ring is not activated the dss do not know the existence of the player
|
|
// So we can not kick him, tp to him, tp in to next act ....
|
|
nldebug( "EnableR2Ed = %u, IsInRingSession = %u, UserRoleInSession = %u", (uint)ClientCfg.R2EDEnabled, (uint)IsInRingSession, userRole );
|
|
|
|
updatePatcherPriorityBasedOnCharacters();
|
|
}
|
|
|
|
void impulseCharNameValid(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallBack : Received CONNECTION:VALID_NAME");
|
|
uint8 nTmp;
|
|
impulse.serial(nTmp);
|
|
CharNameValid = ((nTmp != 0) ? true : false);
|
|
CharNameValidArrived = true;
|
|
if (CharNameValid) NewKeysCharNameValidated = NewKeysCharNameWanted;
|
|
}
|
|
|
|
|
|
void checkHandshake( NLMISC::CBitMemStream &impulse )
|
|
{
|
|
// Decode handshake to check versions
|
|
uint16 handshakeVersion;
|
|
uint16 itemSlotVersion;
|
|
impulse.serial( handshakeVersion );
|
|
if ( handshakeVersion > 0 )
|
|
nlerror( "Server handshake version is more recent than client one" );
|
|
impulse.serial( itemSlotVersion );
|
|
if ( itemSlotVersion != INVENTORIES::CItemSlot::getVersion() )
|
|
nlerror( "Handshake: itemSlotVersion mismatch (S:%hu C:%hu)", itemSlotVersion, INVENTORIES::CItemSlot::getVersion() );
|
|
}
|
|
|
|
|
|
void impulseServerReady(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received CONNECTION:READY
|
|
//nlinfo("impulseCallBack : Received CONNECTION:READY");
|
|
|
|
serverReceivedReady = true;
|
|
|
|
checkHandshake( impulse );
|
|
|
|
LoginSM.pushEvent(CLoginStateMachine::ev_ready_received);
|
|
}
|
|
|
|
void impulseShardId(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received SHARD_ID
|
|
|
|
uint32 shardId;
|
|
impulse.serial(shardId);
|
|
ShardId = shardId;
|
|
|
|
string webHost;
|
|
impulse.serial(webHost);
|
|
if (webHost != "")
|
|
{
|
|
WebServer = webHost;
|
|
}
|
|
|
|
nlinfo("WEB: Received SHARD_ID %d, web hosted at '%s', using '%s'", shardId, webHost.c_str(), WebServer.c_str());
|
|
}
|
|
|
|
void impulseServerQuitOk(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// receive CONNECTION:SERVER_QUIT_OK
|
|
if (FarTP.isFarTPInProgress())
|
|
{
|
|
FarTP.onServerQuitOk();
|
|
}
|
|
else
|
|
{
|
|
// ensure first a quit request is really asked
|
|
if(game_exit_request)
|
|
{
|
|
// quit!
|
|
game_exit= true;
|
|
ryzom_exit= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void impulseServerQuitAbort(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// receive CONNECTION:SERVER_QUIT_ABORT
|
|
if (FarTP.isFarTPInProgress())
|
|
{
|
|
FarTP.onServerQuitAbort();
|
|
}
|
|
else
|
|
{
|
|
// abort any quit request
|
|
game_exit_request= false;
|
|
ryzom_exit_request= false;
|
|
}
|
|
}
|
|
|
|
void impulseMailNotification(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
// receive CONNECTION:MAIL_AVAILABLE
|
|
CInterfaceManager::getInstance()->notifyMailAvailable();
|
|
}
|
|
|
|
void impulseForumNotification(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
// receive CONNECTION:GUILD_MESSAGE_AVAILABLE
|
|
CInterfaceManager::getInstance()->notifyForumUpdated();
|
|
|
|
}
|
|
|
|
void impulsePermanentBan(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint64 magicNumber;
|
|
impulse.serial(magicNumber);
|
|
if (magicNumber != PermanentBanMSGMagicNumber) return; // bad msg
|
|
setPermanentBanMarkers(true);
|
|
applyPermanentBanPunishment();
|
|
PermanentlyBanned = true;
|
|
}
|
|
|
|
void impulsePermanentUnban(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint64 magicNumber;
|
|
impulse.serial(magicNumber);
|
|
if (magicNumber != PermanentUnbanMSGMagicNumber) return; // bad msg
|
|
setPermanentBanMarkers(false);
|
|
PermanentlyBanned = false;
|
|
if (UserEntity)
|
|
{
|
|
// allows to walk / run again
|
|
UserEntity->walkVelocity(ClientCfg.Walk);
|
|
UserEntity->runVelocity(ClientCfg.Run);
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
class CInterfaceChatDisplayer : public CClientChatManager::IChatDisplayer
|
|
{
|
|
public:
|
|
virtual void displayChat(TDataSetIndex compressedSenderIndex, const ucstring &ucstr, const ucstring &rawMessage, CChatGroup::TGroupType mode, NLMISC::CEntityId dynChatId, ucstring &senderName, uint bubbleTimer=0);
|
|
virtual void displayTell(/*TDataSetIndex senderIndex, */const ucstring &ucstr, const ucstring &senderName);
|
|
virtual void clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex);
|
|
|
|
private:
|
|
// Add colorization tag for sender name
|
|
void colorizeSender(ucstring &text, const ucstring &senderName, CRGBA baseColor);
|
|
|
|
};
|
|
static CInterfaceChatDisplayer InterfaceChatDisplayer;
|
|
|
|
void CInterfaceChatDisplayer::colorizeSender(ucstring &text, const ucstring &senderName, CRGBA baseColor)
|
|
{
|
|
// find the sender/text separator to put color tags
|
|
ucstring::size_type pos = senderName.length() - 1;
|
|
if (pos != ucstring::npos)
|
|
{
|
|
ucstring str;
|
|
|
|
CInterfaceProperty prop;
|
|
prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
|
|
|
|
CChatWindow::encodeColorTag(prop.getRGBA(), str, false);
|
|
|
|
str += text.substr(0, pos+1);
|
|
|
|
CChatWindow::encodeColorTag(baseColor, str, true);
|
|
|
|
str += text.substr(pos+1);
|
|
|
|
text.swap(str);
|
|
}
|
|
}
|
|
|
|
// display a chat from network to interface
|
|
void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, const ucstring &ucstr, const ucstring &rawMessage, CChatGroup::TGroupType mode, NLMISC::CEntityId dynChatId, ucstring &senderName, uint bubbleTimer)
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
ucstring finalString;
|
|
string stringCategory = getStringCategory(ucstr, finalString);
|
|
|
|
bool bubbleWanted = true;
|
|
|
|
// Subtract rawMessage from ucstr so that the 'sender' part remains.
|
|
ucstring senderPart = ucstr.luabind_substr(0, ucstr.length() - rawMessage.length());
|
|
|
|
// search a "{no_bubble}" tag
|
|
{
|
|
ucstring::size_type index = finalString.find(ucstring("{no_bubble}"));
|
|
const size_t tokenSize= 11; // length of "{no_bubble}"
|
|
if (index != ucstring::npos)
|
|
{
|
|
bubbleWanted = false;
|
|
finalString = finalString.luabind_substr(0, index) + finalString.substr(index+tokenSize,finalString.size());
|
|
}
|
|
}
|
|
|
|
|
|
// **** get color
|
|
CRGBA col;
|
|
if (mode != CChatGroup::system)
|
|
{
|
|
// Remove all {break}
|
|
for(;;)
|
|
{
|
|
ucstring::size_type index = finalString.find(ucstring("{break}"));
|
|
if (index == ucstring::npos) break;
|
|
finalString = finalString.luabind_substr(0, index) + finalString.luabind_substr(index+7,finalString.size());
|
|
}
|
|
|
|
// select DB
|
|
sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
|
|
clamp(dbIndex, (sint32)0 , (sint32)CChatGroup::MaxDynChanPerPlayer);
|
|
string entry="UI:SAVE:CHAT:COLORS:";
|
|
switch(mode)
|
|
{
|
|
case CChatGroup::dyn_chat: entry+="DYN:" + NLMISC::toString(dbIndex); break;
|
|
case CChatGroup::say: entry+="SAY"; break;
|
|
case CChatGroup::shout: entry+="SHOUT"; break;
|
|
case CChatGroup::team: entry+="GROUP"; break;
|
|
case CChatGroup::guild: entry+="CLADE"; break;
|
|
case CChatGroup::civilization: entry+="CIVILIZATION"; break;
|
|
case CChatGroup::territory: entry+="TERRITORY"; break;
|
|
case CChatGroup::universe: entry+="UNIVERSE_NEW"; break;
|
|
case CChatGroup::region: entry+="REGION"; break;
|
|
case CChatGroup::tell: entry+="TELL"; break;
|
|
default: nlwarning("unknown group type"); return;
|
|
}
|
|
|
|
// read DB
|
|
CInterfaceProperty prop;
|
|
prop.readRGBA(entry.c_str()," ");
|
|
col = prop.getRGBA();
|
|
|
|
// Override color if the string contains the color
|
|
if (!stringCategory.empty() && stringCategory != "SYS")
|
|
{
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it;
|
|
it = ClientCfg.SystemInfoParams.find(strlwr(stringCategory));
|
|
if (it != ClientCfg.SystemInfoParams.end())
|
|
{
|
|
col = it->second.Color;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stringCategory == "emt")
|
|
{
|
|
bubbleWanted = false;
|
|
}
|
|
|
|
if (mode != CChatGroup::system)
|
|
{
|
|
// find the sender/text separator to put color tags
|
|
if (senderPart.empty() && stringCategory == "emt")
|
|
{
|
|
size_t pos = finalString.find(ucstring(": "), 0);
|
|
if (pos != ucstring::npos)
|
|
{
|
|
senderPart = finalString.luabind_substr(0, pos + 2);
|
|
}
|
|
}
|
|
colorizeSender(finalString, senderPart, col);
|
|
}
|
|
|
|
// play associated fx if any
|
|
if( !stringCategory.empty() )
|
|
{
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it;
|
|
it = ClientCfg.SystemInfoParams.find( strlwr(stringCategory) );
|
|
if( it != ClientCfg.SystemInfoParams.end() )
|
|
{
|
|
if( !(*it).second.SysInfoFxName.empty() )
|
|
{
|
|
NL3D::UParticleSystemInstance sysInfoFx = FXMngr.instantFX((*it).second.SysInfoFxName);
|
|
if( !sysInfoFx.empty() )
|
|
{
|
|
sysInfoFx.setClusterSystem( UserEntity->getClusterSystem() );
|
|
sysInfoFx.setPos( UserEntity->pos() );
|
|
}
|
|
else
|
|
{
|
|
nlwarning("<CInterfaceChatDisplayer::displayChat> Can't set chat fx %s",(*it).second.SysInfoFxName.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// **** redirect to the correct interface output
|
|
if( stringCategory != "bbl" )
|
|
{
|
|
bool windowVisible;
|
|
if (mode == CChatGroup::system)
|
|
{
|
|
pIM->displaySystemInfo(finalString, stringCategory);
|
|
}
|
|
else if (mode == CChatGroup::guild)
|
|
{
|
|
PeopleInterraction.ChatInput.Guild.displayMessage(finalString, col, 2, &windowVisible);
|
|
}
|
|
else if (mode == CChatGroup::team)
|
|
{
|
|
PeopleInterraction.ChatInput.Team.displayMessage(finalString, col, 2, &windowVisible);
|
|
}
|
|
else if (mode == CChatGroup::region)
|
|
{
|
|
PeopleInterraction.ChatInput.Region.displayMessage(finalString, col, 2, &windowVisible);
|
|
}
|
|
else if (mode == CChatGroup::universe)
|
|
{
|
|
PeopleInterraction.ChatInput.Universe.displayMessage(finalString, col, 2, &windowVisible);
|
|
}
|
|
else if (mode == CChatGroup::dyn_chat)
|
|
{
|
|
// retrieve the DBIndex from the dynamic chat id
|
|
sint32 dbIndex= ChatMngr.getDynamicChannelDbIndexFromId(dynChatId);
|
|
// if found, display, else discarded
|
|
if(dbIndex >= 0 && dbIndex < CChatGroup::MaxDynChanPerPlayer)
|
|
{
|
|
PeopleInterraction.ChatInput.DynamicChat[dbIndex].displayMessage(finalString, col, 2, &windowVisible);
|
|
|
|
// Add dynchannel info before text so that the chat log will show the correct string.
|
|
CCDBNodeLeaf* node = pIM->getDbProp("UI:SAVE:CHAT:SHOW_DYN_CHANNEL_NAME_IN_CHAT_CB", false);
|
|
if (pIM->getLogState())
|
|
{
|
|
// Add dyn chan number before string
|
|
ucstring prefix("[" + NLMISC::toString(dbIndex) + "]");
|
|
// Find position to put the new string
|
|
// After timestamp?
|
|
size_t pos = finalString.find(ucstring("]"));
|
|
size_t colonpos = finalString.find(ucstring(": @{"));
|
|
// If no ] found or if found but after the colon (so part of the user chat)
|
|
if (pos == ucstring::npos || (colonpos < pos))
|
|
{
|
|
// No timestamp, so put it right after the color and add a space
|
|
pos = finalString.find(ucstring("}"));;
|
|
prefix += " ";
|
|
}
|
|
finalString = finalString.substr(0, pos + 1) + prefix + finalString.substr(pos + 1);
|
|
|
|
if (node && node->getValueBool())
|
|
{
|
|
uint32 textId = ChatMngr.getDynamicChannelNameFromDbIndex(dbIndex);
|
|
ucstring title;
|
|
STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
|
|
prefix = title.empty() ? ucstring("") : ucstring(" ") + title;
|
|
pos = finalString.find(ucstring("] "));
|
|
finalString = finalString.substr(0, pos) + prefix + finalString.substr(pos);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Dynamic chat %s not found for message: %s", dynChatId.toString().c_str(), finalString.toString().c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ucstring::size_type index = finalString.find(ucstring("<BPFX>"));
|
|
if (index != ucstring::npos)
|
|
{
|
|
bubbleWanted = false;
|
|
finalString = finalString.substr(index+6,finalString.size());
|
|
ucstring::size_type index2 = finalString.find(ucstring(" "));
|
|
ucstring playerName;
|
|
if (index2 < (finalString.size()-3))
|
|
{
|
|
playerName = finalString.substr(0,index2);
|
|
finalString = finalString.substr(index2+1,finalString.size());
|
|
}
|
|
if (!senderName.empty())
|
|
{
|
|
CEntityCL *senderEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(senderName), true, true);
|
|
if (senderEntity)
|
|
{
|
|
if (senderEntity->Type != CEntityCL::Player)
|
|
{
|
|
if (playerName.empty())
|
|
{
|
|
senderEntity->removeStateFx();
|
|
senderEntity->setStateFx(finalString.toString());
|
|
nlinfo("empty");
|
|
}
|
|
else
|
|
{
|
|
CEntityCL *destEntity = EntitiesMngr.getEntityByName (CEntityCL::removeTitleAndShardFromName(playerName), false, true);
|
|
if (destEntity)
|
|
{
|
|
destEntity->removeStateFx();
|
|
destEntity->setStateFx(finalString.toString());
|
|
nlinfo("no empty");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finalString = "";
|
|
}
|
|
else
|
|
{
|
|
PeopleInterraction.ChatInput.AroundMe.displayMessage(finalString, col, 2, &windowVisible);
|
|
}
|
|
}
|
|
// if tell, bkup sendername
|
|
if (mode == CChatGroup::tell && windowVisible && !senderName.empty())
|
|
{
|
|
PeopleInterraction.LastSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
|
|
}
|
|
}
|
|
|
|
// received CHAT
|
|
//nldebug("<impulseChat> Received CHAT : %s with category %s",finalString.toString().c_str(),stringCategory.c_str());
|
|
|
|
|
|
// **** Process chat entry for the bubbles
|
|
// todo hulud : registering a chat callback would be better than calling this hardcoded action handler
|
|
ucstring finalRawMessage;
|
|
// remove color qualifier from raw string
|
|
getStringCategory(rawMessage, finalRawMessage);
|
|
if (bubbleWanted)
|
|
{
|
|
InSceneBubbleManager.chatOpen(compressedSenderIndex, finalRawMessage, bubbleTimer);
|
|
}
|
|
|
|
// Log
|
|
pIM->log (finalString);
|
|
|
|
}
|
|
|
|
|
|
// display a tell from network to interface
|
|
void CInterfaceChatDisplayer::displayTell(/*TDataSetIndex senderIndex, */const ucstring &ucstr, const ucstring &senderName)
|
|
{
|
|
|
|
ucstring finalString = ucstr;
|
|
|
|
// for now, '&' are removed by server so use another format until a special msg is made
|
|
if (strFindReplace(finalString, ucstring("<R2_INVITE>"), ucstring()))
|
|
{
|
|
CInterfaceManager::getInstance()->executeLuaScript("RingAccessPoint:forceRefresh()");
|
|
}
|
|
|
|
|
|
CInterfaceProperty prop;
|
|
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
|
|
bool windowVisible;
|
|
|
|
ucstring goodSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
|
|
|
|
// The sender part is up to and including the first ":" after the goodSenderName
|
|
ucstring::size_type pos = finalString.find(goodSenderName);
|
|
pos = finalString.find(':', pos);
|
|
pos = finalString.find(' ', pos);
|
|
ucstring senderPart = finalString.substr(0, pos+1);
|
|
colorizeSender(finalString, senderPart, prop.getRGBA());
|
|
|
|
PeopleInterraction.ChatInput.Tell.displayTellMessage(/*senderIndex, */finalString, goodSenderName, prop.getRGBA(), 2, &windowVisible);
|
|
CInterfaceManager::getInstance()->log(finalString);
|
|
|
|
// Open the free teller window
|
|
CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow();
|
|
if (pCGW != NULL)
|
|
pCGW->setActiveFreeTeller(goodSenderName);
|
|
|
|
if (windowVisible && !goodSenderName.empty())
|
|
PeopleInterraction.LastSenderName = goodSenderName;
|
|
}
|
|
|
|
// clear a channel
|
|
void CInterfaceChatDisplayer::clearChannel(CChatGroup::TGroupType mode, uint32 dynChatDbIndex)
|
|
{
|
|
if (mode == CChatGroup::guild) PeopleInterraction.ChatInput.Guild.clearMessages();
|
|
else if (mode == CChatGroup::team) PeopleInterraction.ChatInput.Team.clearMessages();
|
|
else if (mode == CChatGroup::region) PeopleInterraction.ChatInput.Region.clearMessages();
|
|
else if (mode == CChatGroup::arround) PeopleInterraction.ChatInput.AroundMe.clearMessages();
|
|
else if (mode == CChatGroup::universe) PeopleInterraction.ChatInput.Universe.clearMessages();
|
|
else if (mode == CChatGroup::dyn_chat)
|
|
{
|
|
// if correct dbIndex, clear
|
|
if(dynChatDbIndex<CChatGroup::MaxDynChanPerPlayer)
|
|
PeopleInterraction.ChatInput.DynamicChat[dynChatDbIndex].clearMessages();
|
|
else
|
|
nlwarning("Dynamic chat %d not found for clearing", dynChatDbIndex);
|
|
}
|
|
|
|
// don't support other for now (NB: actually used only for dyn_chat)
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void impulseChat(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processChatString(impulse, InterfaceChatDisplayer);
|
|
}
|
|
|
|
void impulseChat2(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processChatString2(impulse, InterfaceChatDisplayer);
|
|
}
|
|
|
|
void impulseTell(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processTellString(impulse, InterfaceChatDisplayer);
|
|
}
|
|
|
|
void impulseFarTell(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processFarTellString(impulse, InterfaceChatDisplayer);
|
|
}
|
|
|
|
|
|
void impulseTell2(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processTellString2(impulse, InterfaceChatDisplayer);
|
|
}
|
|
|
|
void impulseDynString(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
ChatMngr.processChatStringWithNoSender(impulse, CChatGroup::system, InterfaceChatDisplayer);
|
|
}
|
|
|
|
void inpulseDynStringInChatGroup(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CChatGroup::TGroupType type = CChatGroup::say;
|
|
impulse.serialEnum(type);
|
|
ChatMngr.processChatStringWithNoSender(impulse, type, InterfaceChatDisplayer);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
//void impulseAddDynStr(NLMISC::CBitMemStream &impulse)
|
|
//{
|
|
// bool huff = false;
|
|
// impulse.serialBit(huff);
|
|
//
|
|
// uint32 index;
|
|
// ucstring ucstr;
|
|
//
|
|
// impulse.serial( index );
|
|
// impulse.serial( ucstr );
|
|
//
|
|
// vector<bool> code;
|
|
// if( huff )
|
|
// {
|
|
// impulse.serialCont( code );
|
|
// }
|
|
// if (PermanentlyBanned) return;
|
|
// #ifdef OLD_STRING_SYSTEM
|
|
// ChatMngr.getDynamicDB().add( index, ucstr, code );
|
|
// #else
|
|
// nlwarning( "// TRAP // WE MUST NEVER CALL THIS IMPULE ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!" );
|
|
// #endif
|
|
//
|
|
// // received ADD_DYN_STR
|
|
// nlinfo("impulseCallBack : Received ADD_DYN_STR : adding %s at index %d",ucstr.toString().c_str(),index);
|
|
//}
|
|
/*
|
|
string getInterfaceNameFromId (sint botType, sint interfaceId)
|
|
{
|
|
string interfaceName = "ui:interface:bot_chat_";
|
|
|
|
switch (botType)
|
|
{
|
|
case 0: interfaceName += "figurant_"; break;
|
|
case 1: interfaceName += "figurant_presse_"; break;
|
|
case 2: interfaceName += "chef_village_"; break;
|
|
default: interfaceName += "figurant_"; break;
|
|
}
|
|
|
|
switch (interfaceId)
|
|
{
|
|
case BOTCHATTYPE::Intro: interfaceName += "intro"; break;
|
|
case BOTCHATTYPE::FriendlyMainPage: interfaceName += "friendly_main"; break;
|
|
case BOTCHATTYPE::NeutralMainPage: interfaceName += "neutral_main"; break;
|
|
case BOTCHATTYPE::NastyMainPage: interfaceName += "nasty_main"; break;
|
|
case BOTCHATTYPE::MoreNewsPage: interfaceName += "more_news"; break;
|
|
case BOTCHATTYPE::Done: nlinfo ("end of bot chat"); interfaceName = ""; break;
|
|
}
|
|
return interfaceName;
|
|
}
|
|
|
|
static char *shortNews[] = {
|
|
"The wind is sour and brings only bad tidings...", "Kitins have been sighted near the village!", "",
|
|
"The tribe of the Black Circle has recently", "increased its activities in our region.", "",
|
|
"The Black Circle has made an incursion", "into our territory!", "",
|
|
"The Black Circle has been sighted near one", "of our forward posts, deep in dangerous territory.", "",
|
|
"The tide has washed up evil news, friend.", "The Black Circle is active in our region.", "",
|
|
"Our people suffer from a debilitating shortage.", "We are in sore need of KamiBast.", "",
|
|
"The economy is slow and our reserve of", "Live Seed low.", "",
|
|
"We are in sore need of Live Seed", "If there is a Goo epidemic, we shall all perish!", "",
|
|
"Our master mages have gotten wind of", "the growing Kami discontentment", "",
|
|
};
|
|
|
|
static char *longNews[] = {
|
|
"These powerful predators haven't come this near", "to the village since their devastating attack", "over 15 seasons ago!",
|
|
"They are after more KamiBast", "for their occult practices.", "",
|
|
"They have captured", "2 of our fortifications in the bush!", "",
|
|
"They have taken over one of our richest sources", "of KamiBast, and are exploiting it", "for their own occult purposes.",
|
|
"They now hold an important source", "of Live Seed hostage,", "close to one of our forward posts.",
|
|
"We use the magical properties of KamiBast and", "its unusually rich fibers for all our crafts.", "",
|
|
"If we don't harvest new Seed soon,", "we will have no way of purchasing goods", "and resources, beyond what we produce ourselves",
|
|
"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.",
|
|
"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.",
|
|
};
|
|
*/
|
|
/*
|
|
void setFakeNews ()
|
|
{
|
|
char *table[] = { "figurant", "chef_village", "garde", "commercant" };
|
|
|
|
sint rnd = rand ()%(sizeof(shortNews)/sizeof(shortNews[0])/3);
|
|
rnd;
|
|
|
|
for (uint i = 0; i < sizeof(table)/sizeof(table[0]); i++)
|
|
{
|
|
{ // set test for the friendly main
|
|
string iname;
|
|
iname = "ui:interface:bot_chat_";
|
|
iname += table[i];
|
|
iname += "_friendly_main";
|
|
|
|
CInterfaceGroup *inter = CInterfaceManager::getInstance()->getWindowFromId(iname);
|
|
if (inter == NULL)
|
|
{
|
|
nlwarning ("cant find interface 's%'", iname.c_str());
|
|
continue;
|
|
}
|
|
|
|
CViewText *inter2 = (CViewText *)inter->getView("title0");
|
|
nlassert (inter2 != NULL);
|
|
inter2->setText(ucstring(shortNews[rnd*3]));
|
|
|
|
CViewText *inter3 = (CViewText *)inter->getView("title1");
|
|
nlassert (inter3 != NULL);
|
|
inter3->setText(ucstring(shortNews[rnd*3+1]));
|
|
|
|
CViewText *inter4 = (CViewText *)inter->getView("title2");
|
|
nlassert (inter4 != NULL);
|
|
inter4->setText(ucstring(shortNews[rnd*3+2]));
|
|
}
|
|
{ // set test for the neutral main
|
|
string iname;
|
|
iname = "ui:interface:bot_chat_";
|
|
iname += table[i];
|
|
iname += "_neutral_main";
|
|
|
|
CInterfaceGroup *inter = CInterfaceManager::getInstance()->getWindowFromId(iname);
|
|
if (inter == NULL)
|
|
{
|
|
nlwarning ("cant find interface 's%'", iname.c_str());
|
|
continue;
|
|
}
|
|
|
|
CViewText *inter2 = (CViewText *)inter->getView("title0");
|
|
nlassert (inter2 != NULL);
|
|
inter2->setText(ucstring(shortNews[rnd*3]));
|
|
|
|
CViewText *inter3 = (CViewText *)inter->getView("title1");
|
|
nlassert (inter3 != NULL);
|
|
inter3->setText(ucstring(shortNews[rnd*3+1]));
|
|
}
|
|
{ // set test for the more news
|
|
string iname;
|
|
iname = "ui:interface:bot_chat_";
|
|
iname += table[i];
|
|
iname += "_more_news";
|
|
|
|
CInterfaceGroup *inter = CInterfaceManager::getInstance()->getWindowFromId(iname);
|
|
if (inter == NULL)
|
|
{
|
|
nlwarning ("cant find interface 's%'", iname.c_str());
|
|
continue;
|
|
}
|
|
|
|
CViewText *inter2 = (CViewText *)inter->getView("title0");
|
|
nlassert (inter2 != NULL);
|
|
inter2->setText(ucstring(longNews[rnd*3]));
|
|
|
|
CViewText *inter3 = (CViewText *)inter->getView("title1");
|
|
nlassert (inter3 != NULL);
|
|
inter3->setText(ucstring(longNews[rnd*3+1]));
|
|
|
|
CViewText *inter4 = (CViewText *)inter->getView("title2");
|
|
nlassert (inter4 != NULL);
|
|
inter4->setText(ucstring(longNews[rnd*3+2]));
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================
|
|
/** Temp setup for choice list
|
|
*/
|
|
/*
|
|
static void setupBotChatChoiceList(CInterfaceGroup *botChatGroup)
|
|
{
|
|
// Temp for test. Should then be read from server msg
|
|
std::vector<ucstring> choices;
|
|
for(uint k = 0; k < 90; ++k)
|
|
{
|
|
choices.push_back("Choice " + toString(k));
|
|
}
|
|
CBotChat::setChoiceList(botChatGroup, choices, false);
|
|
}
|
|
*/
|
|
|
|
//=========================================
|
|
/** Temp setup for description list
|
|
*/
|
|
/*
|
|
static void setupBotChatDescription(CInterfaceGroup *botChatGroup)
|
|
{
|
|
ucstring desc;
|
|
for(uint k = 0; k < 90; ++k)
|
|
{
|
|
desc += "This is a multi line description. ";
|
|
}
|
|
CBotChat::setDescription(botChatGroup, desc);
|
|
}
|
|
*/
|
|
|
|
//=========================================
|
|
/** Temp setup for bot chat gift
|
|
*/
|
|
/*
|
|
static void setupBotChatBotGift(CInterfaceGroup *botChatGroup)
|
|
{
|
|
// create dummy item in the db
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
im->getDbProp("SERVER:INVENTORY:20:0:SHEET")->setValue32(CSheetId("ai_flesh_poisson.item").asInt());
|
|
im->getDbProp("SERVER:INVENTORY:20:0:QUALITY")->setValue32(0);
|
|
im->getDbProp("SERVER:INVENTORY:20:1:SHEET")->setValue32(CSheetId("fyros_sword_lvl_01_05.item").asInt());
|
|
im->getDbProp("SERVER:INVENTORY:20:1:QUALITY")->setValue32(2);
|
|
CBotChat::setBotGift(botChatGroup, ucstring("Thanks to have succeeded the mission"), ucstring("Here's your reward"), ucstring("The bot has taken the object quest from your inventory"));
|
|
}
|
|
*/
|
|
|
|
//-----------------------------------------------
|
|
// impulseBotChatSetInterface :
|
|
//-----------------------------------------------
|
|
#if 0
|
|
void impulseBotChatSetInterface(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// received ADD_DYN_STR
|
|
|
|
CEntityId user;
|
|
uint32 happyness;
|
|
BOTCHATTYPE::TBotChatInterfaceId interfaceId;
|
|
bool hasNews;
|
|
|
|
impulse.serial (user);
|
|
impulse.serial (happyness);
|
|
|
|
// impulse.serialEnum (interfaceId);
|
|
uint16 interfId;
|
|
impulse.serial(interfId);
|
|
interfaceId = (BOTCHATTYPE::TBotChatInterfaceId)(interfId&0xff);
|
|
uint8 botType = (interfId>>8) & 0xff;
|
|
|
|
impulse.serial (hasNews);
|
|
|
|
nldebug("impulseCallBack : Received BOT_CHAT:SET_INTERFACE interface %d, have news %s, happy %d, bottype %hu", interfaceId, hasNews?"yes":"no", happyness,(uint16)botType);
|
|
|
|
string stringId;
|
|
vector<uint64> args;
|
|
if (hasNews)
|
|
{
|
|
|
|
/* impulse.serial (stringId);
|
|
impulse.serialCont (args);
|
|
nlinfo ("receive the news '%s' with %d args", stringId.c_str(), args.size());
|
|
*/
|
|
// TEMP FOR THE DEMO, DON'T USE THE NETWORK NEW BUT SELECT A NEWS HERE
|
|
/*
|
|
CInterfaceGroup *inter = CInterfaceManager::getInstance()->getWindowFromId("ui:interface:bot_chat_intro");
|
|
nlassert (inter != NULL);
|
|
inter->setActive(true);
|
|
|
|
CViewText *inter2 = (CViewText *)inter->getView("hi");
|
|
nlassert (inter2 != NULL);
|
|
inter2->NetworkTextId.setString("IOS_NEWS_FOOTBALL_SHORT_EEII", &ChatMngr);
|
|
inter2->NetworkTextId.Args.push_back(10);
|
|
inter2->NetworkTextId.Args.push_back(20);
|
|
inter2->NetworkTextId.Args.push_back(1);
|
|
inter2->NetworkTextId.Args.push_back(2);
|
|
*/ }
|
|
|
|
// FOR THE DEMO, find and set a fake news:
|
|
// setFakeNews ();
|
|
|
|
string interfaceName = getInterfaceNameFromId (botType, interfaceId);
|
|
|
|
if(interfaceName.empty())
|
|
{
|
|
nlwarning ("Received an unknown bot chat interface %d", interfaceId);
|
|
}
|
|
else
|
|
{
|
|
CInterfaceGroup *inter = CInterfaceManager::getInstance()->getWindowFromId(interfaceName);
|
|
if (inter == NULL)
|
|
{
|
|
nlwarning ("Can't find interface name '%s' %d", interfaceName.c_str(), interfaceId);
|
|
}
|
|
else
|
|
{
|
|
CInterfaceManager::getInstance()->setBotChatWin(inter);
|
|
if (inter->getActive())
|
|
{
|
|
nlwarning ("Interface %s is already active, not normal!", interfaceName.c_str());
|
|
}
|
|
else
|
|
{
|
|
nlinfo ("server want to me display the bot chat interface %s %d", interfaceName.c_str(), interfaceId);
|
|
inter->setActive(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseBeginTrade :
|
|
//-----------------------------------------------
|
|
void impulseBeginTrade(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
//open trade window
|
|
CInterfaceGroup* win = CInterfaceManager::getInstance()->getWindowFromId("ui:interface:trade");
|
|
if (!win)
|
|
{
|
|
nlwarning("invalid interface ui:interface:trade");
|
|
return;
|
|
}
|
|
win->setActive(true);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseBuyPrice :
|
|
//-----------------------------------------------
|
|
void impulseBuyPrice(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint16 botChatSession;
|
|
uint32 sheetID;
|
|
uint16 quality;
|
|
uint64 price;
|
|
impulse.serial(botChatSession);
|
|
impulse.serial(price);
|
|
impulse.serial(sheetID);
|
|
impulse.serial(quality);
|
|
// no more used
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseDynChatOpen
|
|
//-----------------------------------------------
|
|
void impulseDynChatOpen(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 BotUID; // Compressed Index
|
|
uint32 BotName; // Server string
|
|
vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
|
|
impulse.serial(BotUID);
|
|
impulse.serial(BotName);
|
|
impulse.serialCont(DynStrs);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
/* string sTmp = "impulseCallback : Received BOTCHAT:DYNCHAT_OPEN BotUID:";
|
|
sTmp += toString(BotUID) + " BotName:";
|
|
sTmp += toString(BotName) + " DynStrs:";
|
|
for (uint32 i = 0; i < DynStrs.size(); ++i)
|
|
{
|
|
sTmp += toString(DynStrs[i]);
|
|
if (i != DynStrs.size()-1) sTmp += ",";
|
|
}
|
|
nlinfo(sTmp.c_str());*/
|
|
|
|
InSceneBubbleManager.dynChatOpen(BotUID, BotName, DynStrs);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseDynChatClose
|
|
//-----------------------------------------------
|
|
void impulseDynChatClose(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 BotUID; // Compressed Index
|
|
impulse.serial(BotUID);
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received BOTCHAT:DYNCHAT_CLOSE BotUID:"+toString(BotUID));
|
|
InSceneBubbleManager.dynChatClose(BotUID);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseBeginCast:
|
|
//-----------------------------------------------
|
|
void impulseBeginCast(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//open cast window
|
|
uint32 begin,end;
|
|
impulse.serial(begin);
|
|
impulse.serial(end);
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager* iMngr = CInterfaceManager::getInstance();
|
|
iMngr->getDbProp("UI:VARIABLES:SPELL_CAST")->setValue32(1);
|
|
iMngr->getDbProp("UI:VARIABLES:CAST_BEGIN")->setValue32(begin);
|
|
iMngr->getDbProp("UI:VARIABLES:CAST_END")->setValue32(end);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseCorrectPos :
|
|
// Message from the server to correct the user position because he is not at the same position on the server..
|
|
//-----------------------------------------------
|
|
void impulseCorrectPos(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// TP:CORRECT
|
|
//nlinfo("impulseCallback : Received TP:CORRECT");
|
|
sint32 x, y, z;
|
|
impulse.serial(x);
|
|
impulse.serial(y);
|
|
impulse.serial(z);
|
|
nlinfo("impulseCorrectPos: new user position %d %d %d", x, y, z);
|
|
|
|
if(UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
|
|
{
|
|
// Compute the destination.
|
|
CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
|
|
// Update the position for the vision.
|
|
NetMngr.setReferencePosition(dest);
|
|
// Change the user poisition.
|
|
UserEntity->correctPos(dest);
|
|
}
|
|
}// impulseCorrectPos //
|
|
|
|
class CDummyProgress : public IProgressCallback
|
|
{
|
|
void progress (float /* value */) {}
|
|
};
|
|
|
|
//-----------------------------------------------
|
|
// impulseTP :
|
|
// Message from the server to teleport the user.
|
|
// \warning This function remove the current target. Do no use to correct a position.
|
|
//-----------------------------------------------
|
|
void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason);
|
|
void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason);
|
|
|
|
void impulseTP(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
impulseTPCommon(impulse, false);
|
|
}
|
|
|
|
void impulseTPWithSeason(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
impulseTPCommon(impulse, true);
|
|
}
|
|
|
|
struct SQueuedTP
|
|
{
|
|
NLMISC::CBitMemStream Impulse;
|
|
bool HasSeason;
|
|
|
|
SQueuedTP(const NLMISC::CBitMemStream &impulse, bool hasSeason)
|
|
:Impulse(impulse), HasSeason(hasSeason)
|
|
{
|
|
}
|
|
};
|
|
|
|
// note - this method added by Sadge and Hamster to deal with unexplained recursive calls to impulseTPCommon
|
|
// these calls are provoked by the net manager update which is called during loading
|
|
void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason)
|
|
{
|
|
CNiceInputAuto niceInputs;
|
|
static std::list<SQueuedTP> queuedTPs;
|
|
SQueuedTP thisTP(impulse,hasSeason);
|
|
queuedTPs.push_back(thisTP);
|
|
|
|
BOMB_IF(queuedTPs.size()!=1,NLMISC::toString("Queueing recursive TPs depth=%u",queuedTPs.size()),return);
|
|
|
|
while(!queuedTPs.empty())
|
|
{
|
|
impulseTPCommon2(queuedTPs.front().Impulse,queuedTPs.front().HasSeason);
|
|
queuedTPs.pop_front();
|
|
};
|
|
|
|
}
|
|
|
|
|
|
void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason)
|
|
{
|
|
// choose a default screen if not setuped
|
|
if( LoadingBackground!=ResurectKamiBackground && LoadingBackground!=ResurectKaravanBackground &&
|
|
LoadingBackground!=TeleportKamiBackground && LoadingBackground!=TeleportKaravanBackground)
|
|
LoadingBackground= TeleportKaravanBackground;
|
|
// if resurect but user not dead, choose default. NB: this is a bug, the tp impulse should tell
|
|
// which background to choose. \todo yoyo: this is a temp fix
|
|
if( UserEntity && !UserEntity->isDead() &&
|
|
(LoadingBackground==ResurectKamiBackground || LoadingBackground==ResurectKaravanBackground) )
|
|
LoadingBackground= TeleportKaravanBackground;
|
|
|
|
// Play music according to the background
|
|
if(SoundMngr)
|
|
{
|
|
LoadingMusic.clear();
|
|
if(LoadingBackground==TeleportKamiBackground)
|
|
LoadingMusic= "Kami Teleport.ogg";
|
|
else if(LoadingBackground==TeleportKaravanBackground)
|
|
LoadingMusic= "Karavan Teleport.ogg";
|
|
// if resurection, continue to play death music
|
|
else if(LoadingBackground==ResurectKamiBackground || LoadingBackground==ResurectKaravanBackground)
|
|
{
|
|
// noop
|
|
}
|
|
// default: loading music
|
|
else
|
|
{
|
|
LoadingMusic= "Loading Music Loop.ogg";
|
|
}
|
|
|
|
// start to play
|
|
SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true);
|
|
}
|
|
|
|
// Create the loading texture.
|
|
beginLoading (LoadingBackground);
|
|
|
|
// No ESCAPE key
|
|
UseEscapeDuringLoading = false;
|
|
|
|
// Change the tips
|
|
selectTipsOfTheDay (rand());
|
|
|
|
// start progress bar and display background
|
|
ProgressBar.reset (BAR_STEP_TP);
|
|
ucstring nmsg("Loading...");
|
|
ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) );
|
|
|
|
|
|
// received ADD_DYN_STR
|
|
nlinfo("impulseTP: received a request for a TP.");
|
|
sint32 x, y, z;
|
|
impulse.serial(x);
|
|
impulse.serial(y);
|
|
impulse.serial(z);
|
|
bool useHeading;
|
|
impulse.serialBit( useHeading );
|
|
// Is there an orientation too ?
|
|
if( useHeading )
|
|
{
|
|
float angle;
|
|
impulse.serial(angle);
|
|
nlinfo("impulseTP: to %d %d %d %f", x, y, z, angle);
|
|
CVector ori = CVector((float)cos(angle), (float)sin(angle), 0.0f);
|
|
ori.normalize();
|
|
UserEntity->dir(ori, false, false);
|
|
UserEntity->front(ori, false, false);
|
|
UserEntity->setHeadPitch(0);
|
|
UserControls.resetCameraDeltaYaw();
|
|
}
|
|
else
|
|
nlinfo("impulseTP: to %d %d %d", x, y, z);
|
|
|
|
if (hasSeason)
|
|
{
|
|
extern uint8 ServerSeasonValue;
|
|
extern bool ServerSeasonReceived;
|
|
impulse.serial(ServerSeasonValue);
|
|
ServerSeasonReceived = true;
|
|
}
|
|
|
|
if (ClientCfg.R2EDEnabled)
|
|
{
|
|
R2::getEditor().tpReceived();
|
|
}
|
|
|
|
// Compute the destination.
|
|
CVectorD dest = CVectorD((float)x/1000.0f, (float)y/1000.0f, (float)z/1000.0f);
|
|
// Update the position for the vision.
|
|
NetMngr.setReferencePosition(dest);
|
|
// Change the position of the entity and in Pacs.
|
|
UserEntity->pos(dest);
|
|
|
|
// Fade out the Game Sound
|
|
if(SoundMngr)
|
|
SoundMngr->fadeOutGameSound(ClientCfg.SoundTPFade);
|
|
|
|
|
|
R2::TTeleportContext tpContext = R2::TPContext_Unknown;
|
|
|
|
ucstring tpReason;
|
|
ucstring tpCancelText;
|
|
|
|
try
|
|
{
|
|
R2::TR2TpInfos tpInfos;
|
|
impulse.serial(tpInfos);
|
|
|
|
|
|
if ( tpInfos.UseTpMessage)
|
|
{
|
|
tpReason = CI18N::get(tpInfos.TpReasonId);
|
|
|
|
uint32 size = (uint32)tpInfos.TpReasonParams.size();
|
|
uint32 first = 0;
|
|
CSString str(tpReason.toString());
|
|
for (;first != size ; ++first)
|
|
{
|
|
std::string value = tpInfos.TpReasonParams[first];
|
|
std::string key = NLMISC::toString("%%%u", first +1);
|
|
str = str.replace( key.c_str(), value.c_str());
|
|
}
|
|
tpReason = ucstring(str);
|
|
tpCancelText = CI18N::get(tpInfos.TpCancelTextId);
|
|
tpContext = tpInfos.TpContext;
|
|
}
|
|
|
|
}
|
|
catch (const EStream &)
|
|
{
|
|
tpReason = ucstring("TP Reason");
|
|
tpCancelText = ucstring("Cancel TP"); // for test
|
|
// try to deduce tp context from current editor mode
|
|
switch (R2::getEditor().getMode())
|
|
{
|
|
case R2::CEditor::EditionMode:
|
|
case R2::CEditor::NotInitialized:
|
|
tpContext = R2::TPContext_Unknown;
|
|
tpReason = ucstring();
|
|
tpCancelText = ucstring();
|
|
break;
|
|
case R2::CEditor::GoingToDMMode:
|
|
case R2::CEditor::TestMode:
|
|
case R2::CEditor::DMMode:
|
|
tpContext = R2::TPContext_Edit;
|
|
break;
|
|
case R2::CEditor::AnimationModeLoading:
|
|
case R2::CEditor::AnimationModeWaitingForLoading:
|
|
case R2::CEditor::AnimationModeDm:
|
|
case R2::CEditor::AnimationModeGoingToDm:
|
|
tpContext = R2::TPContext_IslandOwner;
|
|
break;
|
|
case R2::CEditor::AnimationModePlay:
|
|
case R2::CEditor::AnimationModeGoingToPlay:
|
|
default:
|
|
tpContext = R2::TPContext_Mainland;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!tpReason.empty())
|
|
{
|
|
std::string tpIcon;
|
|
switch(tpContext)
|
|
{
|
|
case R2::TPContext_Mainland: tpIcon = "cancel_tp_main_land.tga"; break;
|
|
case R2::TPContext_Edit: tpIcon = "cancel_tp_edit.tga"; break;
|
|
case R2::TPContext_IslandOwner: tpIcon = "cancel_tp_island_owner.tga"; break;
|
|
default: break;
|
|
}
|
|
ProgressBar.setTPMessages(tpReason, tpCancelText, tpIcon);
|
|
}
|
|
|
|
ProgressBar.progress(0);
|
|
// enable hardware mouse to allow to click the buttons
|
|
//bool oldHardwareCursor = IsMouseCursorHardware();
|
|
//InitMouseWithCursor(true);
|
|
// Select the closest continent from the new position.
|
|
ContinentMngr.select(dest, ProgressBar);
|
|
//
|
|
//InitMouseWithCursor(oldHardwareCursor);
|
|
|
|
// reset 'cancel' button
|
|
ProgressBar.setTPMessages(ucstring(), ucstring(), "");
|
|
|
|
|
|
// ProgressBar.enableQuitButton(false); // TMP TMP
|
|
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.
|
|
ProgressBar.finish();
|
|
// ProgressBar.enableQuitButton(true); // TMP TMP
|
|
|
|
// Teleport the User.
|
|
UserEntity->tp(dest);
|
|
|
|
// Msg Received, send an acknowledge after the landscape has been loaded.
|
|
CBitMemStream out;
|
|
if(GenericMsgHeaderMngr.pushNameToStream("TP:ACK", out))
|
|
{
|
|
NetMngr.push(out);
|
|
nlinfo("impulseTP: teleport acknowledge 'TP:ACK' sent.");
|
|
}
|
|
else
|
|
nlwarning("impulseTP: unknown message name : 'TP:ACK'.");
|
|
|
|
|
|
// First frame
|
|
FirstFrame = true;
|
|
|
|
|
|
// if tp canceling was asked, act accordingly
|
|
if (ProgressBar.getTPCancelFlag(true))
|
|
{
|
|
switch(tpContext)
|
|
{
|
|
case R2::TPContext_Mainland:
|
|
CInterfaceManager::getInstance()->runActionHandler("return_to_mainland", NULL);
|
|
break;
|
|
case R2::TPContext_Edit:
|
|
CInterfaceManager::getInstance()->runActionHandler("r2ed_stop_test", NULL);
|
|
break;
|
|
case R2::TPContext_IslandOwner:
|
|
CInterfaceManager::getInstance()->runActionHandler("r2_stop_live", NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
initHardwareCursor(true);
|
|
}// impulseTP //
|
|
|
|
//-----------------------------------------------
|
|
// impulseCombatEngageFailed :
|
|
//-----------------------------------------------
|
|
void impulseCombatEngageFailed(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
nlinfo("impulseCombatEngageFailed: Combat Engage Failed.");
|
|
|
|
// Unlock the motion.
|
|
UserControls.locked(false);
|
|
}// impulseCombatEngageFailed //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamInvitation :
|
|
//-----------------------------------------------
|
|
void impulseTeamInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulseTeamInvitation: received an invitation");
|
|
|
|
uint32 textID;
|
|
impulse.serial(textID);
|
|
if (PermanentlyBanned) return;
|
|
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
pIM->executeLuaScript("game:onTeamInvation("+toString(textID)+")", 0);
|
|
}// impulseTeamInvitation //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamShareOpen
|
|
// The server request that the client opens the team sharing system
|
|
//-----------------------------------------------
|
|
void impulseTeamShareOpen(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
CGroupContainer *gc = dynamic_cast<CGroupContainer*>( im->getElementFromId("ui:interface:team_share"));
|
|
if (!gc) return;
|
|
gc->setActive(true);
|
|
im->setTopWindow(gc);
|
|
gc->updateCoords();
|
|
gc->center();
|
|
}// impulseTeamShareOpen //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamShareInvalid
|
|
// invalidate the player validation. If someone has choosen an item/phrase after the player has validated
|
|
// the player receive this message to let him know that the chance percentage to obtain a specific item has
|
|
// changed and so the player can update its own settings to fit better to what he wants.
|
|
// On the client side we have just to show the valid button. All the resets are done on the server side.
|
|
//-----------------------------------------------
|
|
void impulseTeamShareInvalid(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(pIM->getElementFromId("ui:interface:team_share:content:ok"));
|
|
if (pTB != NULL)
|
|
pTB->setActive(true);
|
|
}// impulseTeamShareInvalid //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamShareClose
|
|
// The server wants to close the team sharing interface (if the sharing has been validated or other reasons)
|
|
//-----------------------------------------------
|
|
void impulseTeamShareClose(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer
|
|
*pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:team_share"));
|
|
if (pGC != NULL)
|
|
pGC->setActive(false);
|
|
CCtrlTextButton *pTB = dynamic_cast<CCtrlTextButton*>(pIM->getElementFromId("ui:interface:team_share:content:ok"));
|
|
if (pTB != NULL)
|
|
pTB->setActive(true);
|
|
}// impulseTeamShareClose //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamContactInit
|
|
// initialize friend list and ignore list from the contact list
|
|
//-----------------------------------------------
|
|
void impulseTeamContactInit(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
vector<uint32> vFriendListName;
|
|
vector<TCharConnectionState> vFriendListOnline;
|
|
vector<ucstring> vIgnoreListName;
|
|
|
|
impulse.serialCont(vFriendListName);
|
|
uint32 nbState;
|
|
impulse.serial(nbState);
|
|
vFriendListOnline.resize(nbState);
|
|
for (uint i=0; i<nbState; ++i)
|
|
{
|
|
impulse.serialShortEnum(vFriendListOnline[i]);
|
|
}
|
|
// impulse.serialCont(vFriendListOnline);
|
|
impulse.serialCont(vIgnoreListName);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received TEAM:CONTACT_INIT nbfriend:%d nbignore:%d", vFriendListName.size(), vIgnoreListName.size());
|
|
|
|
PeopleInterraction.initContactLists(vFriendListName, vFriendListOnline, vIgnoreListName);
|
|
}// impulseTeamContactInit //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamContactCreate
|
|
// create one character from the friend or ignore list
|
|
//-----------------------------------------------
|
|
void impulseTeamContactCreate(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 contactId;
|
|
uint32 nameId;
|
|
TCharConnectionState online = ccs_offline;
|
|
uint8 nList;
|
|
|
|
impulse.serial(contactId);
|
|
impulse.serial(nameId);
|
|
impulse.serialShortEnum(online);
|
|
impulse.serial(nList);
|
|
|
|
// client patch to resolve bad server response when requesting ignore list contact creation
|
|
if (nList == 1) // ignore list
|
|
{
|
|
// prevent adding an empty player to ignore list
|
|
if (nameId == 0) return;
|
|
}
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received TEAM:CONTACT_CREATE %d %d %s %d", contactId, nameId, online?"true":"false", nList);
|
|
|
|
PeopleInterraction.addContactInList(contactId, nameId, online, nList);
|
|
|
|
}// impulseTeamContactStatus //
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamContactStatus
|
|
// update one of the character from the friend list
|
|
//-----------------------------------------------
|
|
void impulseTeamContactStatus(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 contactId;
|
|
TCharConnectionState online = ccs_offline;
|
|
|
|
impulse.serial(contactId);
|
|
impulse.serialShortEnum(online);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received TEAM:CONTACT_STATUS %d %s", contactId, online == ccs_online ?"online": online==ccs_offline?"offline" : "foreign_online");
|
|
|
|
// 0<=FriendList (actually ignore list does not show online state)
|
|
PeopleInterraction.updateContactInList(contactId, online, 0);
|
|
|
|
// Resort the contact list if needed
|
|
CInterfaceManager* pIM= CInterfaceManager::getInstance();
|
|
CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
|
|
|
|
if (order == CPeopleList::sort_online)
|
|
{
|
|
PeopleInterraction.FriendList.sortEx(order);
|
|
}
|
|
}// impulseTeamContactStatus //
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseTeamContactRemove
|
|
// Remove a contact by the server
|
|
//-----------------------------------------------
|
|
void impulseTeamContactRemove(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 contactId;
|
|
uint8 nList;
|
|
|
|
impulse.serial(contactId);
|
|
impulse.serial(nList);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received TEAM:CONTACT_REMOVE %d %d", contactId, nList);
|
|
|
|
PeopleInterraction.removeContactFromList(contactId, nList);
|
|
|
|
}// impulseTeamContactRemove //
|
|
|
|
|
|
//-----------------------------------------------
|
|
// servers sets information of a guild member:
|
|
// u16 ( member index ) u32 (player name ), u8 ( player grade + last bit set if player online ).
|
|
//-----------------------------------------------
|
|
/*void impulseGuildSetMemberInfo(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint16 index;
|
|
impulse.serial(index);
|
|
uint32 guildMemberName;
|
|
impulse.serial(guildMemberName);
|
|
uint8 grade;
|
|
impulse.serial(grade);
|
|
bool online = ((grade&0x80) != 0);
|
|
grade = (grade & 0x7F);
|
|
CGuildManager::getInstance()->set(index, guildMemberName, grade, online);
|
|
}*/
|
|
|
|
//-----------------------------------------------
|
|
// vector of pair( u32 (player name ), u8 ( player grade + last bit set if player online ) )
|
|
//-----------------------------------------------
|
|
/*void impulseGuildInitMemberInfo(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
vector < pair < uint32, uint8 > > AllMembers;
|
|
uint16 nbEntries;
|
|
impulse.serial(nbEntries);
|
|
AllMembers.resize(nbEntries);
|
|
for (uint32 i = 0; i < nbEntries; ++i)
|
|
{
|
|
uint32 name;
|
|
impulse.serial(name);
|
|
uint8 gradeNonline;
|
|
impulse.serial(gradeNonline);
|
|
AllMembers[i].first = name;
|
|
AllMembers[i].second = gradeNonline;
|
|
}
|
|
|
|
CGuildManager::getInstance()->init(AllMembers);
|
|
}*/
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildInvitation
|
|
//-----------------------------------------------
|
|
/*void impulseGuildInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulseGuildInvitation");
|
|
|
|
}*/
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildJoinProposal
|
|
// server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
|
|
//-----------------------------------------------
|
|
void impulseGuildJoinProposal(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
|
|
uint32 phraseID;
|
|
impulse.serial(phraseID);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received GUILD:JOIN_PROPOSAL %d", phraseID);
|
|
|
|
CGuildManager::getInstance()->launchJoinProposal(phraseID);
|
|
/*//activate the pop up window
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
CGroupContainer *gc = dynamic_cast<CGroupContainer *>( im->getElementFromId("ui:interface:join_guild_proposal"));
|
|
if (!gc) return;
|
|
CViewText *vt = dynamic_cast<CViewText*>(gc->getView("invitor_name"));
|
|
if (vt == NULL) return;
|
|
vt->setText(invitor);
|
|
gc->setActive(true);
|
|
im->setTopWindow(gc);
|
|
gc->updateCoords();
|
|
gc->center();
|
|
gc->enableBlink(2);*/
|
|
}// impulseGuildJoinProposal //
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseCloseTempInv
|
|
//-----------------------------------------------
|
|
void impulseCloseTempInv(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CTempInvManager::getInstance()->close();
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseAscencorTeleport
|
|
//-----------------------------------------------
|
|
void impulseAscencorTeleport(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
|
|
} // impulseAscencorTeleport //
|
|
|
|
//-----------------------------------------------
|
|
// impulseEnterCrZoneProposal
|
|
// server sent to client invitation (uint32 invitorNameId, uint32 guildNameId
|
|
//-----------------------------------------------
|
|
void impulseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 phraseID;
|
|
impulse.serial(phraseID);
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received MISSION:ASK_ENTER_CRITICAL %d", phraseID);
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
CGroupContainer *gc = dynamic_cast<CGroupContainer *>( im->getElementFromId("ui:interface:enter_crzone_proposal"));
|
|
if (!gc) return;
|
|
CViewTextID *vti = dynamic_cast<CViewTextID *>(gc->getView("phrase"));
|
|
if (!vti) return;
|
|
vti->setTextId(phraseID);
|
|
gc->setActive(true);
|
|
im->setTopWindow(gc);
|
|
gc->updateCoords();
|
|
gc->center();
|
|
gc->enableBlink(2);
|
|
}// impulseEnterCrZoneProposal //
|
|
|
|
//-----------------------------------------------
|
|
// impulseCloseEnterCrZoneProposal
|
|
// server close proposal interface
|
|
//-----------------------------------------------
|
|
void impulseCloseEnterCrZoneProposal(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// hide interface
|
|
CInterfaceManager* pIM = CInterfaceManager::getInstance();
|
|
CInterfaceGroup *pIG = (CInterfaceGroup*)pIM->getElementFromId ("ui:interface:enter_crzone_proposal");
|
|
if(pIG)
|
|
pIG->setActive(false);
|
|
}// impulseCloseEnterCrZoneProposal //
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseExchangeInvitation :
|
|
//-----------------------------------------------
|
|
void impulseExchangeInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 textID;
|
|
impulse.serial(textID);
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager* iMngr = CInterfaceManager::getInstance();
|
|
|
|
// show the modal window that allow the player to accept / decline the invitation
|
|
CGroupContainer *wnd = dynamic_cast<CGroupContainer *>(iMngr->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
|
|
if (wnd)
|
|
{
|
|
wnd->setActive(true);
|
|
wnd->updateCoords();
|
|
wnd->center();
|
|
wnd->enableBlink(2);
|
|
iMngr->setTopWindow(wnd);
|
|
}
|
|
|
|
CViewTextID *vti = dynamic_cast<CViewTextID *>(wnd->getView("invite_phrase"));
|
|
if (vti)
|
|
{
|
|
vti->setTextId(textID);
|
|
}
|
|
|
|
}// impulseExchangeInvitation //
|
|
|
|
//-----------------------------------------------
|
|
// impulseExchangeCloseInvitation :
|
|
//-----------------------------------------------
|
|
void impulseExchangeCloseInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager* iMngr = CInterfaceManager::getInstance();
|
|
// hide the modal window that allow the player to accept / decline the invitation
|
|
CInterfaceGroup *wnd = dynamic_cast<CInterfaceGroup *>(iMngr->getElementFromId(PLAYER_EXCHANGE_INVITATION_DIALOG));
|
|
if (wnd) wnd->setActive(false);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseMountAbort :
|
|
//-----------------------------------------------
|
|
void impulseMountAbort(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlwarning("impulseMountAbort: Received ANIMALS:MOUNT_ABORT => no more used");
|
|
}// impulseMountAbort //
|
|
|
|
//-----------------------------------------------
|
|
// impulseRyzomTime :
|
|
// Synchronize the ryzom time with the server.
|
|
//-----------------------------------------------
|
|
/*
|
|
void impulseRyzomTime(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulseRyzomTime: Ryzom Time Received");
|
|
uint32 serverTick;
|
|
float ryzomTime;
|
|
uint32 ryzomDay;
|
|
impulse.serial(serverTick);
|
|
impulse.serial(ryzomTime);
|
|
impulse.serial(ryzomDay);
|
|
nlinfo("impulseRyzomTime: Day '%d' Time '%f'.", ryzomDay, ryzomTime);
|
|
|
|
// Initialize
|
|
RT.setOrigin( serverTick, ryzomDay, ryzomTime );
|
|
}// impulseRyzomTime //
|
|
*/
|
|
//-----------------------------------------------
|
|
// impulseWhere :
|
|
// Display server position
|
|
//-----------------------------------------------
|
|
void impulseWhere(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received DEBUG:REPLY_WHERE");
|
|
|
|
sint32 x,y,z;
|
|
impulse.serial(x);
|
|
impulse.serial(y);
|
|
impulse.serial(z);
|
|
if (PermanentlyBanned) return;
|
|
char buf[128];
|
|
|
|
double xf = ((double)x)/1000.0f;
|
|
double yf = ((double)y)/1000.0f;
|
|
double zf = ((double)z)/1000.0f;
|
|
|
|
sprintf(buf,"Your server position is : X= %g Y= %g Z= %g",xf,yf,zf);
|
|
nlinfo(buf);
|
|
CInterfaceManager::getInstance()->displaySystemInfo(ucstring(buf));
|
|
}// impulseWhere //
|
|
|
|
//-----------------------------------------------
|
|
// impulseWho :
|
|
// Display server position
|
|
//-----------------------------------------------
|
|
/*
|
|
void impulseWho(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulseWho Received");
|
|
CInterfaceManager::getInstance()->displaySystemInfo(ucstring("Players currently in the game :"));
|
|
|
|
ucstring name;
|
|
uint32 loginId;
|
|
uint16 dist;
|
|
uint8 dirshort;
|
|
string str;
|
|
while( impulse.getPos() < (sint32)impulse.length() )
|
|
{
|
|
impulse.serial(name);
|
|
impulse.serial(loginId);
|
|
impulse.serial(dist);
|
|
impulse.serial(dirshort);
|
|
|
|
double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
|
|
angle -= NLMISC::Pi;
|
|
nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
|
|
sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
|
|
direction = ((direction%16)+16)%16;
|
|
static const string txts[]=
|
|
{
|
|
"uiW",
|
|
"uiWSW",
|
|
"uiSW",
|
|
"uiSSW",
|
|
"uiS",
|
|
"uiSSE",
|
|
"uiSE",
|
|
"uiESE",
|
|
"uiE",
|
|
"uiENE",
|
|
"uiNE",
|
|
"uiNNE",
|
|
"uiN",
|
|
"uiNNW",
|
|
"uiNW",
|
|
"uiWNW",
|
|
};
|
|
|
|
str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
|
|
CInterfaceManager::getInstance()->displaySystemInfo(ucstring(name + ucstring(str) + CI18N::get(txts[direction])));
|
|
}
|
|
}// impulseWho //
|
|
*/
|
|
|
|
/*
|
|
void impulseWhoGM(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulseWhoGM Received");
|
|
CInterfaceManager::getInstance()->displaySystemInfo(ucstring("Players currently in the game :"));
|
|
|
|
ucstring name;
|
|
uint32 loginId;
|
|
uint16 dist;
|
|
uint8 dirshort;
|
|
string str;
|
|
while( impulse.getPos() < (sint32)impulse.length() )
|
|
{
|
|
impulse.serial(name);
|
|
impulse.serial(loginId);
|
|
impulse.serial(dist);
|
|
impulse.serial(dirshort);
|
|
|
|
double angle = dirshort * 2.0 * NLMISC::Pi / 255.0;
|
|
angle -= NLMISC::Pi;
|
|
nlinfo ("name %s uid %u dist %hu dirshort %hu angle %f", name.toString().c_str(),loginId, dist, (uint16)dirshort, angle);
|
|
sint direction =(sint) floor( 0.5 + ( 8.0 * (angle + NLMISC::Pi)/(NLMISC::Pi) ) );
|
|
direction = ((direction%16)+16)%16;
|
|
static const string txts[]=
|
|
{
|
|
"uiW",
|
|
"uiWSW",
|
|
"uiSW",
|
|
"uiSSW",
|
|
"uiS",
|
|
"uiSSE",
|
|
"uiSE",
|
|
"uiESE",
|
|
"uiE",
|
|
"uiENE",
|
|
"uiNE",
|
|
"uiNNE",
|
|
"uiN",
|
|
"uiNNW",
|
|
"uiNW",
|
|
"uiWNW",
|
|
};
|
|
|
|
str = toString (" - uid %d - distance %hu meters - direction ", loginId, dist);
|
|
CInterfaceManager::getInstance()->displaySystemInfo(ucstring(name + ucstring(str) + CI18N::get(txts[direction])));
|
|
}
|
|
}// impulseWho //
|
|
*/
|
|
//-----------------------------------------------
|
|
// impulseCounter :
|
|
// check UDP validity
|
|
//-----------------------------------------------
|
|
void impulseCounter(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallBack : Received DEBUG:COUNTER");
|
|
try
|
|
{
|
|
uint32 counter;
|
|
impulse.serial(counter);
|
|
|
|
static uint queueTop = 0;
|
|
static deque<bool> queue;
|
|
|
|
if (counter > queueTop)
|
|
{
|
|
queue.resize(queue.size()+counter-queueTop, false);
|
|
queueTop = counter;
|
|
}
|
|
|
|
if (queueTop-counter+1 > queue.size())
|
|
{
|
|
nlinfo("COUNTER: counter %d arrived too late...", counter);
|
|
}
|
|
else
|
|
{
|
|
if (queue[queue.size()-1-(queueTop-counter)])
|
|
{
|
|
nlwarning("COUNTER: Received counter %d more than once !", counter);
|
|
}
|
|
else
|
|
{
|
|
nldebug("COUNTER: set counter %d", counter);
|
|
queue[queue.size()-1-(queueTop-counter)] = true;
|
|
}
|
|
|
|
while (queue.size() > 128)
|
|
{
|
|
if (!queue.front())
|
|
{
|
|
nlwarning("COUNTER: counter %d not received !", queueTop-queue.size()-1);
|
|
}
|
|
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
nlwarning ("Problem while decoding a COUTNER msg, skipped: %s", e.what());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulsePhraseSend :
|
|
// A dyn string (or phrase) is send (so, we receive it)
|
|
//-----------------------------------------------
|
|
void impulsePhraseSend(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
STRING_MANAGER::CStringManagerClient::instance()->receiveDynString(impulse);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseStringResp :
|
|
// Update the local string set
|
|
//-----------------------------------------------
|
|
void impulseStringResp(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 stringId;
|
|
string strUtf8;
|
|
impulse.serial(stringId);
|
|
impulse.serial(strUtf8);
|
|
ucstring str;
|
|
str.fromUtf8(strUtf8);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
STRING_MANAGER::CStringManagerClient::instance()->receiveString(stringId, str);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseReloadCache :
|
|
// reload the string cache
|
|
//-----------------------------------------------
|
|
void impulseReloadCache(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 timestamp;;
|
|
impulse.serial(timestamp);
|
|
if (PermanentlyBanned) return;
|
|
STRING_MANAGER::CStringManagerClient::instance()->loadCache(timestamp);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseBotChatEnd
|
|
// ForceThe end of the bot chat
|
|
//-----------------------------------------------
|
|
void impulseBotChatForceEnd(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// MISSION COMPLETED JOURNAL
|
|
//-----------------------------------------------
|
|
/*
|
|
#define MC_M_CONTAINER "ui:interface:info_player_journal"
|
|
#define MC_S_CONTAINER "ui:interface:ipj_com_missions"
|
|
#define MC_TEMPLATE "tipj_mission_complete"
|
|
//-----------------------------------------------
|
|
CGroupContainer *getMissionCompletedContainer()
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CInterfaceElement *pIE = pIM->getElementFromId(MC_M_CONTAINER);
|
|
CGroupContainer *pGCM = dynamic_cast<CGroupContainer*>(pIE);
|
|
if (pGCM == NULL) return NULL;
|
|
|
|
CGroupList *pList = pGCM->getList();
|
|
CGroupContainer *pGCS = dynamic_cast<CGroupContainer*>(pList->getGroup(MC_S_CONTAINER));
|
|
return pGCS;
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
void clearMissions()
|
|
{
|
|
CGroupContainer *pGCMC = getMissionCompletedContainer();
|
|
CInterfaceGroup *pContent = pGCMC->getGroup("content");
|
|
pContent->clearGroups();
|
|
}
|
|
//-----------------------------------------------
|
|
void addMission(uint32 titleID)
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGCMC = getMissionCompletedContainer();
|
|
if (pGCMC == NULL)
|
|
{
|
|
nlwarning("cannot get container for missions completed");
|
|
return;
|
|
}
|
|
CInterfaceGroup *pContent = pGCMC->getGroup("content");
|
|
|
|
uint32 nNbMission = pContent->getGroups().size();
|
|
vector<pair<string, string> > vArgs;
|
|
|
|
vArgs.push_back(pair<string,string>("id", "mc"+NLMISC::toString(nNbMission)));
|
|
vArgs.push_back(pair<string,string>("mcid", NLMISC::toString(titleID)));
|
|
|
|
if (nNbMission == 0)
|
|
{
|
|
vArgs.push_back(pair<string,string>("posref", "TL TL"));
|
|
vArgs.push_back(pair<string,string>("posparent", "parent"));
|
|
vArgs.push_back(pair<string,string>("y", "0"));
|
|
}
|
|
else
|
|
{
|
|
vArgs.push_back(pair<string,string>("posref", "BL TL"));
|
|
}
|
|
|
|
CInterfaceGroup *pIG = pIM->createGroupInstance(MC_TEMPLATE, pContent->getId(), vArgs);
|
|
if (pIG == NULL)
|
|
{
|
|
nlwarning("cannot create a mission completed");
|
|
return;
|
|
}
|
|
pIG->setParent(pContent);
|
|
if (nNbMission == 0)
|
|
pIG->setParentPos(pContent);
|
|
else
|
|
pIG->setParentPos(pContent->getGroups()[nNbMission-1]);
|
|
pContent->addGroup(pIG);
|
|
}
|
|
*/
|
|
//-----------------------------------------------
|
|
// impulseJournalInitCompletedMissions :
|
|
// initialize the player journal missions for completed missions
|
|
//-----------------------------------------------
|
|
void impulseJournalInitCompletedMissions (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
/*
|
|
vector<uint32> vMissionCompleted;
|
|
impulse.serialCont(vMissionCompleted);
|
|
|
|
clearMissions();
|
|
|
|
for (uint32 i = 0; i < vMissionCompleted.size(); ++i)
|
|
addMission (vMissionCompleted[i]);
|
|
*/
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseJournalInitCompletedMissions :
|
|
// initialize the player journal missions for completed missions
|
|
//-----------------------------------------------
|
|
void impulseJournalUpdateCompletedMissions (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
/*
|
|
uint32 nNewCompletedMission;
|
|
impulse.serial(nNewCompletedMission);
|
|
|
|
addMission (nNewCompletedMission);
|
|
*/
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseJournalCantAbandon :
|
|
// server refuses mission abandon
|
|
//-----------------------------------------------
|
|
void impulseJournalCantAbandon (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
/// reactivate abandon button
|
|
CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:TEMP:MISSION_ABANDON_BUTTON",false);
|
|
if (pNL != NULL)
|
|
pNL->setValue64(1);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
// server add a compass target
|
|
//-----------------------------------------------
|
|
void impulseJournalAddCompass(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
sint32 x;
|
|
sint32 y;
|
|
uint32 text;
|
|
impulse.serial(x);
|
|
impulse.serial(y);
|
|
impulse.serial(text);
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received JOURNAL:ADD_COMPASS %d %d %d", x, y, text);
|
|
CCompassDialogsManager::getInstance().addEntry( x,y,text );
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// server removes a compass target
|
|
//-----------------------------------------------
|
|
void impulseJournalRemoveCompass(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 text;
|
|
impulse.serial(text);
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received JOURNAL:REMOVE_COMPASS %d", text);
|
|
CCompassDialogsManager::getInstance().removeEntry( text );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// the server ask me to execute a command
|
|
//
|
|
void impulseRemoteAdmin (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CLog logDisplayVars;
|
|
CLightMemDisplayer mdDisplayVars;
|
|
logDisplayVars.addDisplayer (&mdDisplayVars);
|
|
mdDisplayVars.setParam (10);
|
|
|
|
uint32 rid;
|
|
impulse.serial (rid);
|
|
string cmd;
|
|
impulse.serial (cmd);
|
|
|
|
// remove the 2 first rc character if exists, only there to say to the EGS that is a remote command
|
|
if (cmd.size()>2 && tolower(cmd[0])=='r' && tolower(cmd[1])=='c')
|
|
cmd = cmd.substr(2);
|
|
|
|
mdDisplayVars.clear ();
|
|
ICommand::execute(cmd, logDisplayVars, !ICommand::isCommand(cmd));
|
|
const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
|
|
|
|
string str;
|
|
if (ICommand::isCommand(cmd))
|
|
{
|
|
for (uint k = 0; k < strs.size(); k++)
|
|
{
|
|
str += strs[k];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strs.size()>0)
|
|
{
|
|
str = strs[0].substr(0,strs[0].size()-1);
|
|
// replace all spaces into underscore because space is a reserved char
|
|
for (uint i = 0; i < str.size(); i++) if (str[i] == ' ') str[i] = '_';
|
|
}
|
|
else
|
|
{
|
|
str = "???";
|
|
}
|
|
}
|
|
mdDisplayVars.unlockStrings();
|
|
|
|
//nlinfo("impulseCallback : Received COMMAND:REMOTE_ADMIN : Server asked me to execute '%s', result is '%s'", cmd.c_str(), str.c_str());
|
|
|
|
CBitMemStream out;
|
|
if(GenericMsgHeaderMngr.pushNameToStream("COMMAND:REMOTE_ADMIN_ANSWER", out))
|
|
{
|
|
out.serial (rid);
|
|
out.serial (cmd);
|
|
out.serial (str);
|
|
NetMngr.push (out);
|
|
//nlinfo("impulseCallback : COMMAND:REMOTE_ADMIN_ANSWER %d %s %s sent", rid, cmd.c_str(), str.c_str());
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildAscensor :
|
|
// server request that the client launch the ascensor interface
|
|
//-----------------------------------------------
|
|
|
|
void impulseGuildAscensor (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received GUILD:ASCENSOR");
|
|
CGuildManager::getInstance()->launchAscensor();
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//impulseGuildLeaveAscensor
|
|
//-----------------------------------------------
|
|
void impulseGuildLeaveAscensor (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received GUILD:LEAVE_ASCENSOR");
|
|
CGuildManager::getInstance()->quitAscensor();
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//impulseGuildAbortCreation
|
|
//-----------------------------------------------
|
|
void impulseGuildAbortCreation (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CBotChatPage *pPage = CBotChatManager::getInstance()->getCurrPage();
|
|
CBotChatPageCreateGuild *pPageCG = dynamic_cast<CBotChatPageCreateGuild*>(pPage);
|
|
if (pPageCG == BotChatPageAll->CreateGuild)
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
}
|
|
|
|
void impulseGuildOpenGuildWindow(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CGuildManager::getInstance()->openGuildWindow();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildOpenInventory
|
|
//-----------------------------------------------
|
|
void impulseGuildOpenInventory (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
pIM->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(1);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildCloseInventory
|
|
//-----------------------------------------------
|
|
void impulseGuildCloseInventory (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
pIM->getDbProp("UI:TEMP:INVENTORY_GUILD_OPENED")->setValue32(0);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildUpdatePlayerTitle
|
|
// server block/unblock some reserved titles
|
|
//-----------------------------------------------
|
|
void impulseGuildUpdatePlayerTitle(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CSkillManager *pSM = CSkillManager::getInstance();
|
|
bool bUnblock;
|
|
impulse.serial(bUnblock);
|
|
vector<uint16> vTitles;
|
|
impulse.serialCont(vTitles);
|
|
if (PermanentlyBanned) return;
|
|
if (bUnblock)
|
|
{
|
|
for (uint32 i = 0; i < vTitles.size(); ++i)
|
|
pSM->unblockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
|
|
}
|
|
else
|
|
{
|
|
for (uint32 i = 0; i < vTitles.size(); ++i)
|
|
pSM->blockTitleFromServer((CHARACTER_TITLE::ECharacterTitle)vTitles[i]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseGuildUseFemaleTitles
|
|
// server activates/deactivates use of female titles
|
|
//-----------------------------------------------
|
|
void impulseGuildUseFemaleTitles(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
impulse.serial( UseFemaleTitles );
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulsePhraseDownLoad
|
|
// server upload the phrases.
|
|
//-----------------------------------------------
|
|
void impulsePhraseDownLoad (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
std::vector<CSPhraseSlot> phrases;
|
|
|
|
// Read Known Phrases
|
|
impulse.serialCont(phrases);
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
for(uint i=0;i<phrases.size();i++)
|
|
{
|
|
if(phrases[i].PhraseSheetId != CSheetId::Unknown)
|
|
{
|
|
CSPhraseCom phraseCom;
|
|
pPM->buildPhraseFromSheet(phraseCom, phrases[i].PhraseSheetId.asInt());
|
|
pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phraseCom);
|
|
}
|
|
else
|
|
{
|
|
pPM->setPhraseNoUpdateDB(phrases[i].KnownSlot, phrases[i].Phrase);
|
|
}
|
|
}
|
|
// must update the DB (NB: if initInGameDone) after all phrase set.
|
|
pPM->updateBookDB();
|
|
|
|
// Then Read Memorized Phrases
|
|
std::vector<CSPhraseMemorySlot> memorizedPhrases;
|
|
impulse.serialCont(memorizedPhrases);
|
|
if (PermanentlyBanned) return;
|
|
for(uint i=0;i<memorizedPhrases.size();i++)
|
|
{
|
|
pPM->memorizePhrase(
|
|
memorizedPhrases[i].MemoryLineId,
|
|
memorizedPhrases[i].MemorySlotId,
|
|
memorizedPhrases[i].PhraseId);
|
|
}
|
|
|
|
// OK.
|
|
extern bool SabrinaPhraseBookLoaded;
|
|
SabrinaPhraseBookLoaded= true;
|
|
|
|
// update gray state, if game inited.
|
|
pPM->updateMemoryBar();
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulsePhraseConfirmBuy
|
|
// server confirm/infirm the buy of botchat phrase.
|
|
//-----------------------------------------------
|
|
void impulsePhraseConfirmBuy (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint16 phraseId;
|
|
bool confirm;
|
|
|
|
impulse.serial(phraseId);
|
|
impulse.serial(confirm);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
CSPhraseManager *pSM= CSPhraseManager::getInstance();
|
|
pSM->receiveBotChatConfirmBuy(phraseId, confirm);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePhraseAckExecuteCyclic
|
|
// server confirm/infirm the cyclic execution of a phrase
|
|
//-----------------------------------------------
|
|
void impulsePhraseAckExecuteCyclic (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint8 counter;
|
|
bool ok;
|
|
|
|
impulse.serial(ok);
|
|
impulse.serial(counter);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
|
|
CSPhraseManager *pSM= CSPhraseManager::getInstance();
|
|
pSM->receiveAckExecuteFromServer(true, counter, ok);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePhraseAckExecuteCyclic
|
|
// server confirm/infirm the execution of a phrase
|
|
//-----------------------------------------------
|
|
void impulsePhraseAckExecuteNext (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint8 counter;
|
|
bool ok;
|
|
|
|
impulse.serial(ok);
|
|
impulse.serial(counter);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
CSPhraseManager *pSM= CSPhraseManager::getInstance();
|
|
pSM->receiveAckExecuteFromServer(false, counter, ok);
|
|
}
|
|
|
|
// Same params as in BOMB_IF
|
|
#ifdef FINAL_VERSION
|
|
#define SKIP_IF(condition,msg,skipAction) if (!(condition)); else skipAction;
|
|
#else
|
|
#define SKIP_IF(condition,msg,skipAction) if (!(condition)) WARN(msg); else skipAction;
|
|
#endif
|
|
|
|
template <class CInventoryCategoryTemplate>
|
|
void updateInventoryFromStream (NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges)
|
|
{
|
|
try
|
|
{
|
|
// get the egs tick of this change
|
|
TGameCycle serverTick;
|
|
impulse.serial(serverTick);
|
|
|
|
// For All inventories
|
|
for ( uint invId=0; invId!=CInventoryCategoryTemplate::NbInventoryIds; ++invId )
|
|
{
|
|
// Presence bit
|
|
bool hasContent;
|
|
impulse.serialBit( hasContent );
|
|
if ( ! hasContent )
|
|
continue;
|
|
|
|
// Number field
|
|
uint32 nbChanges;
|
|
impulse.serial( nbChanges, INVENTORIES::LowNumberBits );
|
|
if ( nbChanges == INVENTORIES::LowNumberBound )
|
|
impulse.serial( nbChanges, 32 );
|
|
|
|
const string invBranchStr = CInventoryCategoryTemplate::getDbStr( (typename CInventoryCategoryTemplate::TInventoryId)invId );
|
|
ICDBNode::CTextId textId( invBranchStr );
|
|
ICDBNode *inventoryNode = IngameDbMngr.getNodePtr()->getNode( textId, false );
|
|
BOMB_IF( !inventoryNode, "Inventory missing in database", return )
|
|
|
|
// List of updates
|
|
for ( uint c=0; c!=nbChanges; ++c )
|
|
{
|
|
// Unpack (the bitmemstream is written from high-order to low-order)
|
|
uint32 iuInfoVersion;
|
|
impulse.serial( iuInfoVersion, 1 );
|
|
if ( iuInfoVersion == 1 )
|
|
{
|
|
uint32 slotIndex;
|
|
impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
|
|
|
|
// Access the database leaf
|
|
CCDBNodeBranch *slotNode = static_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
|
|
ICDBNode *leafNode = slotNode->find( INVENTORIES::InfoVersionStr );
|
|
BOMB_IF( !leafNode, "Inventory slot property missing in database", continue );
|
|
|
|
// Apply or increment Info Version in database
|
|
if ( CInventoryCategoryTemplate::needPlainInfoVersionTransfer() )
|
|
{
|
|
uint32 infoVersion;
|
|
impulse.serial( infoVersion, INVENTORIES::InfoVersionBitSize );
|
|
((CCDBNodeLeaf*)leafNode)->setPropCheckGC( serverTick, infoVersion );
|
|
}
|
|
else
|
|
{
|
|
// NB: don't need to check GC on a info version upgrade, since this is always a delta of +1
|
|
// the order of received of this impulse is not important
|
|
((CCDBNodeLeaf*)leafNode)->setValue64( ((CCDBNodeLeaf*)leafNode)->getValue64() + 1 );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
uint32 iuAll;
|
|
impulse.serial( iuAll, 1 );
|
|
if ( iuAll == 1 )
|
|
{
|
|
INVENTORIES::CItemSlot itemSlot;
|
|
itemSlot.serialAll( impulse, templ );
|
|
//nldebug( "Inv %s Update %u", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex() );
|
|
|
|
// Apply all properties to database
|
|
CCDBNodeBranch *slotNode = static_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
|
|
for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
|
|
{
|
|
CCDBNodeLeaf *leafNode = static_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
|
|
SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
|
|
leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getItemProp( ( INVENTORIES::TItemPropId)i ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint32 iuOneProp;
|
|
impulse.serial( iuOneProp, 1 );
|
|
if ( iuOneProp == 1 )
|
|
{
|
|
INVENTORIES::CItemSlot itemSlot;
|
|
itemSlot.serialOneProp( impulse, templ );
|
|
//nldebug( "Inv %s Prop %u %s", CInventoryCategoryTemplate::InventoryStr[invId], itemSlot.getSlotIndex(), INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId] );
|
|
|
|
// Apply property to database
|
|
CCDBNodeBranch *slotNode = static_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)itemSlot.getSlotIndex() ));
|
|
CCDBNodeLeaf *leafNode = safe_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[itemSlot.getOneProp().ItemPropId]) ));
|
|
SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
|
|
leafNode->setPropCheckGC( serverTick, (sint64)itemSlot.getOneProp().ItemPropValue );
|
|
|
|
}
|
|
else // iuReset
|
|
{
|
|
uint32 slotIndex;
|
|
impulse.serial( slotIndex, CInventoryCategoryTemplate::SlotBitSize );
|
|
//nldebug( "Inv %s Reset %u", CInventoryCategoryTemplate::InventoryStr[invId], slotIndex );
|
|
|
|
// Reset all properties in database
|
|
CCDBNodeBranch *slotNode = static_cast<CCDBNodeBranch*>(inventoryNode->getNode( (uint16)slotIndex ));
|
|
for ( uint i=0; i!=INVENTORIES::NbItemPropId; ++i )
|
|
{
|
|
// Instead of clearing all leaves (by index), we must find and clear only the
|
|
// properties in TItemPropId, because the actual database leaves may have
|
|
// less properties, and because we must not clear the leaf INFO_VERSION.
|
|
CCDBNodeLeaf *leafNode = safe_cast<CCDBNodeLeaf*>(slotNode->find( string(INVENTORIES::CItemSlot::ItemPropStr[i]) ));
|
|
SKIP_IF( !leafNode, "Inventory slot property missing in database", continue );
|
|
leafNode->setPropCheckGC( serverTick, 0 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CInventoryManager::getInstance()->sortBag();
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
nlwarning ("Problem while decoding a DB_UPD_INV msg, skipped: %s", e.what());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseUpdateInventory:
|
|
//-----------------------------------------------
|
|
void impulseUpdateInventory (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
updateInventoryFromStream( impulse, (INVENTORIES::CInventoryCategoryForCharacter*)NULL, true );
|
|
};
|
|
|
|
//-----------------------------------------------
|
|
// impulseInitInventory:
|
|
//-----------------------------------------------
|
|
void impulseInitInventory (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
sint32 p = impulse.getPos();
|
|
impulseUpdateInventory( impulse );
|
|
IngameDbMngr.setInitPacketReceived();
|
|
nlinfo( "DB_INIT:INV done (%u bytes)", impulse.getPos()-p );
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseItemInfoSet:
|
|
//-----------------------------------------------
|
|
void impulseItemInfoSet (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CItemInfos itemInfos;
|
|
impulse.serial(itemInfos);
|
|
|
|
getInventory().onReceiveItemInfo(itemInfos);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseItemInfoRefreshVersion:
|
|
//-----------------------------------------------
|
|
void impulseItemInfoRefreshVersion (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint16 slotId;
|
|
uint8 infoVersion;
|
|
impulse.serial(slotId);
|
|
impulse.serial(infoVersion);
|
|
|
|
getInventory().onRefreshItemInfoVersion(slotId, infoVersion);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulsePrereqInfoSet:
|
|
//-----------------------------------------------
|
|
void impulsePrereqInfoSet (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CPrerequisitInfos prereqInfos;
|
|
uint8 index;
|
|
impulse.serial(prereqInfos);
|
|
impulse.serial(index);
|
|
|
|
//write infos in interface
|
|
CBotChatManager::getInstance()->onReceiveMissionInfo(index, prereqInfos);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseDeathRespawnPoint (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CRespawnPointsMsg msg;
|
|
impulse.serial(msg);
|
|
if (PermanentlyBanned) return;
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupMap *pMap = dynamic_cast<CGroupMap*>(pIM->getElementFromId("ui:interface:respawn_map:content:map_content:actual_map"));
|
|
if (pMap == NULL)
|
|
{
|
|
nlwarning("problem cannot find ui:interface:respawn_map:content:map_content:actual_map");
|
|
return;
|
|
}
|
|
pMap->addRespawnPoints(msg);
|
|
|
|
|
|
pMap = dynamic_cast<CGroupMap*>(pIM->getElementFromId("ui:interface:map:content:map_content:actual_map"));
|
|
if (pMap == NULL)
|
|
{
|
|
nlwarning("problem cannot find ui:interface:map:content:map_content:actual_map");
|
|
return;
|
|
}
|
|
pMap->addRespawnPoints(msg);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseDeathRespawn (NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// TODO : Bring me to life !!!
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// impulseDuelInvitation :
|
|
//-----------------------------------------------
|
|
void impulseDuelInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 textID;
|
|
impulse.serial(textID);
|
|
|
|
//nlinfo("impulseCallback : Received DUEL:INVITATION %d", textID);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:join_duel_proposal"));
|
|
if (pGC == NULL) return;
|
|
CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
|
|
if (pVTID == NULL) return;
|
|
pVTID->setTextId(textID);
|
|
pGC->setActive(true);
|
|
pIM->setTopWindow(pGC);
|
|
pGC->updateCoords();
|
|
pGC->center();
|
|
pGC->enableBlink(2);
|
|
|
|
}// impulseDuelInvitation //
|
|
|
|
//-----------------------------------------------
|
|
// impulseDuelCancelInvitation:
|
|
//-----------------------------------------------
|
|
void impulseDuelCancelInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
//nlinfo("impulseCallback : Received DUEL:CANCEL_INVITATION");
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:join_duel_proposal"));
|
|
if (pGC == NULL) return;
|
|
pGC->setActive(false);
|
|
|
|
}// impulseDuelCancelInvitation //
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPChallengeInvitation :
|
|
//-----------------------------------------------
|
|
void impulsePVPChallengeInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 textID;
|
|
impulse.serial(textID);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//nlinfo("impulseCallback : Received PVP_CHALLENGE:INVITATION %d", textID);
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
|
|
if (pGC == NULL) return;
|
|
CViewTextID *pVTID = dynamic_cast<CViewTextID *>(pGC->getView("invitor_name"));
|
|
if (pVTID == NULL) return;
|
|
pVTID->setTextId(textID);
|
|
pGC->setActive(true);
|
|
pIM->setTopWindow(pGC);
|
|
pGC->updateCoords();
|
|
pGC->center();
|
|
pGC->enableBlink(2);
|
|
|
|
}// impulsePVPChallengeInvitation //
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPChallengeCancelInvitation:
|
|
//-----------------------------------------------
|
|
void impulsePVPChallengeCancelInvitation(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received PVP_CHALLENGE:CANCEL_INVITATION");
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:join_pvp_challenge_proposal"));
|
|
if (pGC == NULL) return;
|
|
pGC->setActive(false);
|
|
|
|
}// impulsePVPChallengeCancelInvitation //
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPFactionPushFactionWar:
|
|
//-----------------------------------------------
|
|
void impulsePVPFactionPushFactionWar(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received PVP_FACTION:PUSH_FACTION_WAR");
|
|
|
|
PVP_CLAN::CFactionWar factionWar;
|
|
impulse.serialEnum(factionWar.Clan1);
|
|
impulse.serialEnum(factionWar.Clan2);
|
|
|
|
CFactionWarManager::getInstance()->addFactionWar(factionWar);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPFactionPopFactionWar:
|
|
//-----------------------------------------------
|
|
void impulsePVPFactionPopFactionWar(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received PVP_FACTION:POP_FACTION_WAR");
|
|
|
|
PVP_CLAN::CFactionWar factionWar;
|
|
impulse.serialEnum(factionWar.Clan1);
|
|
impulse.serialEnum(factionWar.Clan2);
|
|
|
|
CFactionWarManager::getInstance()->stopFactionWar(factionWar);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPFactionFactionWars:
|
|
//-----------------------------------------------
|
|
void impulsePVPFactionFactionWars(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received PVP_FACTION:FACTION_WARS");
|
|
|
|
CFactionWarsMsg factionWars;
|
|
impulse.serial(factionWars);
|
|
|
|
for( uint i=0; i<factionWars.FactionWarOccurs.size(); ++i )
|
|
{
|
|
CFactionWarManager::getInstance()->addFactionWar(factionWars.FactionWarOccurs[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulsePVPChooseClan
|
|
//-----------------------------------------------
|
|
/*
|
|
void impulsePVPChooseClan(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
nlinfo("impulsePVPChooseClan : Received PVP_CLAN:CHOOSE_CLAN");
|
|
|
|
EGSPD::CPeople::TPeople clan1= EGSPD::CPeople::Unknown, clan2= EGSPD::CPeople::Unknown;
|
|
impulse.serialEnum( clan1 );
|
|
impulse.serialEnum( clan2 );
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
//activate the pop up window
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:join_pvp_clan_proposal"));
|
|
if (pGC == NULL) return;
|
|
pGC->setActive(true);
|
|
|
|
CCtrlTextButton * butClan1 = dynamic_cast<CCtrlTextButton*>(pIM->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan1"));
|
|
if( butClan1 == NULL )
|
|
return;
|
|
butClan1->setText( ucstring(EGSPD::CPeople::toString( clan1 )) );
|
|
|
|
CCtrlTextButton * butClan2 = dynamic_cast<CCtrlTextButton*>(pIM->getElementFromId("ui:interface:join_pvp_clan_proposal:content:clan2"));
|
|
if( butClan2 == NULL )
|
|
return;
|
|
butClan2->setText( ucstring(EGSPD::CPeople::toString( clan2 )) );
|
|
}
|
|
*/
|
|
|
|
//-----------------------------------------------
|
|
// impulseEncyclopediaUpdate
|
|
//-----------------------------------------------
|
|
void impulseEncyclopediaUpdate(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received ENCYCLOPEDIA:UPDATE");
|
|
|
|
CEncyclopediaUpdateMsg msg;
|
|
impulse.serial(msg);
|
|
if (PermanentlyBanned) return;
|
|
CEncyclopediaManager::getInstance()->update(msg);
|
|
}// impulseEncyclopediaUpdate //
|
|
|
|
//-----------------------------------------------
|
|
// impulseEncyclopediaInit
|
|
//-----------------------------------------------
|
|
void impulseEncyclopediaInit(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
//nlinfo("impulseCallback : Received ENCYCLOPEDIA:INIT");
|
|
|
|
CEncyclopediaUpdateMsg msg;
|
|
impulse.serial(msg);
|
|
if (PermanentlyBanned) return;
|
|
CEncyclopediaManager::getInstance()->update(msg);
|
|
}// impulseEncyclopediaInit //
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseItemOpenRoomInventory(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
// This is a message because we may do other things there
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
pIM->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(1);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseItemCloseRoomInventory(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
if (PermanentlyBanned) return;
|
|
// This is a message because we may do other things there
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
pIM->getDbProp("UI:TEMP:INVENTORY_ROOM_OPENED")->setValue32(0);
|
|
|
|
// deactivate the pop up window
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:inv_room"));
|
|
if (pGC == NULL) return;
|
|
pGC->setActive(false);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseUserBars(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint8 msgNumber;
|
|
sint32 hp, sap, sta, focus;
|
|
impulse.serial(msgNumber);
|
|
impulse.serial(hp);
|
|
impulse.serial(sap);
|
|
impulse.serial(sta);
|
|
impulse.serial(focus);
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
// Setup the user Bars
|
|
CBarManager::CBarInfo bi;
|
|
CBarManager::getInstance()->setupUserBarInfo(msgNumber, hp, sap, sta, focus);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseOutpostChooseSide(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
// read message
|
|
bool playerGuildInConflict;
|
|
bool playerGuildIsAttacker;
|
|
impulse.serial(playerGuildInConflict);
|
|
impulse.serial(playerGuildIsAttacker);
|
|
uint32 ownerGuildNameId;
|
|
impulse.serial( ownerGuildNameId );
|
|
uint32 attackerGuildNameId;
|
|
impulse.serial( attackerGuildNameId );
|
|
uint32 declTimer;
|
|
impulse.serial( declTimer );
|
|
|
|
// start
|
|
OutpostManager.startPvpJoinProposal(playerGuildInConflict, playerGuildIsAttacker,
|
|
ownerGuildNameId, attackerGuildNameId, declTimer);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
void impulseOutpostDeclareWarAck(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
bool canValidate;
|
|
uint32 docTextId;
|
|
uint32 timeStartAttack;
|
|
|
|
impulse.serial(canValidate);
|
|
impulse.serial(docTextId);
|
|
impulse.serial(timeStartAttack);
|
|
|
|
// write result in Local DB.
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
// ack reception
|
|
CCDBNodeLeaf *node= pIM->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_RECEIVED");
|
|
if(node)
|
|
node->setValueBool(true);
|
|
// set result of ACK
|
|
node= pIM->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_OK");
|
|
if(node)
|
|
node->setValueBool(canValidate);
|
|
node= pIM->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TEXTID");
|
|
if(node)
|
|
node->setValue32(docTextId);
|
|
node= pIM->getDbProp("UI:TEMP:OUTPOST:DECLARE_WAR_ACK_TIME_RANGE_ATT");
|
|
if(node)
|
|
node->setValue32(timeStartAttack);
|
|
}
|
|
|
|
extern void addWebIGParams(string &url, bool trustedDomain);
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
class CServerMessageBoxOnReceiveTextId : public STRING_MANAGER::IStringWaitCallback
|
|
{
|
|
private:
|
|
enum TTextType {TitleType= 0, ContentType, NumTextType};
|
|
uint32 _TextId[NumTextType];
|
|
bool _TextReceived[NumTextType];
|
|
bool _AlreadyDisplayed;
|
|
|
|
// show the window
|
|
void activateMsgBoxWindow()
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
|
|
|
|
// get the content string (should have been received!)
|
|
ucstring contentStr;
|
|
ucstring titleStr;
|
|
if(!pSMC->getDynString(_TextId[ContentType], contentStr))
|
|
return;
|
|
|
|
if(!pSMC->getDynString(_TextId[TitleType], titleStr))
|
|
return;
|
|
|
|
// if the string start with a @{Wxxxx} code, remove it and get the wanted window size
|
|
sint w = 256; // default size to 256 !!
|
|
bool is_webig = false;
|
|
|
|
if(contentStr.size()>=6 && contentStr[0]=='W' && contentStr[1]=='E' && contentStr[2]=='B'
|
|
&& contentStr[3]==' ' && contentStr[4]==':' && contentStr[5]==' ' )
|
|
{
|
|
uint i;
|
|
const uint digitStart= 6;
|
|
const uint digitMaxEnd= (uint)contentStr.size();
|
|
|
|
is_webig = true;
|
|
|
|
for(i = digitStart; i < digitMaxEnd; i++)
|
|
{
|
|
if(contentStr[i] == ' ')
|
|
break;
|
|
}
|
|
if(i != digitMaxEnd)
|
|
{
|
|
ucstring web_app = contentStr.substr(digitStart, i-digitStart);
|
|
contentStr = ucstring("http://"+ClientCfg.WebIgMainDomain+"/start/")+web_app+ucstring(".php?")+contentStr.substr(i+1);
|
|
}
|
|
else
|
|
{
|
|
contentStr = "";
|
|
i = digitStart;
|
|
}
|
|
}
|
|
else if(contentStr.size()>=5 && contentStr[0]=='@' && contentStr[1]=='{' && contentStr[2]=='W')
|
|
{
|
|
uint i;
|
|
const uint digitStart= 3;
|
|
const uint digitMaxEnd= 8;
|
|
for(i=digitStart;i<contentStr.size() && i<digitMaxEnd;i++)
|
|
{
|
|
if(contentStr[i]=='}')
|
|
break;
|
|
}
|
|
if(i!=digitMaxEnd)
|
|
{
|
|
// get the width
|
|
ucstring digitStr= contentStr.substr(digitStart, i-digitStart);
|
|
fromString(digitStr.toString(), w);
|
|
// remove the first tag
|
|
contentStr= contentStr.substr(i+1);
|
|
}
|
|
}
|
|
|
|
// open the message box window or web ig
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
if (is_webig)
|
|
{
|
|
CGroupHTML *groupHtml;
|
|
string group = titleStr.toString();
|
|
// <missing:XXX>
|
|
group = group.substr(9, group.size()-10);
|
|
groupHtml = dynamic_cast<CGroupHTML*>(pIM->getElementFromId("ui:interface:"+group+":content:html"));
|
|
if (!groupHtml)
|
|
{
|
|
groupHtml = dynamic_cast<CGroupHTML*>(pIM->getElementFromId("ui:interface:webig:content:html"));
|
|
group = "webig";
|
|
}
|
|
|
|
if (groupHtml)
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:"+group));
|
|
if (pGC)
|
|
{
|
|
if (contentStr.empty())
|
|
{
|
|
pGC->setActive(false);
|
|
}
|
|
else
|
|
{
|
|
if (group == "webig")
|
|
pGC->setActive(true);
|
|
string url = contentStr.toString();
|
|
addWebIGParams(url, true);
|
|
groupHtml->browse(url.c_str());
|
|
pIM->setTopWindow(pGC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:server_message_box"));
|
|
if (pGC)
|
|
{
|
|
// show the window with correct width
|
|
pGC->setW(w);
|
|
pGC->setActive(true);
|
|
|
|
// must set the text by hand
|
|
CViewText *vt= dynamic_cast<CViewText*>(pIM->getElementFromId(pIM->getDefine("server_message_box_content_view_text")));
|
|
if(vt)
|
|
vt->setTextFormatTaged(contentStr);
|
|
|
|
// open
|
|
pIM->setTopWindow(pGC);
|
|
pGC->invalidateCoords();
|
|
// Yoyo: because of buggued group container, I found that 6 times is a good number....
|
|
for(uint i=0;i<6;i++)
|
|
pGC->updateCoords();
|
|
pGC->center();
|
|
pGC->enableBlink(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
// called when the string is available
|
|
virtual void onDynStringAvailable(uint stringId, const ucstring &value)
|
|
{
|
|
// don't care if already displayed
|
|
if(_AlreadyDisplayed)
|
|
return;
|
|
|
|
// check if one of waited text
|
|
for(uint i=0;i<NumTextType;i++)
|
|
{
|
|
if(stringId==_TextId[i])
|
|
{
|
|
_TextReceived[i]= true;
|
|
}
|
|
}
|
|
|
|
// all received?
|
|
for(uint i=0;i<NumTextType;i++)
|
|
{
|
|
if(!_TextReceived[i])
|
|
return;
|
|
}
|
|
// Yes => display window
|
|
_AlreadyDisplayed= true;
|
|
activateMsgBoxWindow();
|
|
}
|
|
|
|
// start the waiter
|
|
void startWaitTexts(uint32 titleTextId, uint32 docTextId)
|
|
{
|
|
// reset
|
|
_TextId[TitleType]= titleTextId;
|
|
_TextId[ContentType]= docTextId;
|
|
_TextReceived[TitleType]= false;
|
|
_TextReceived[ContentType]= false;
|
|
_AlreadyDisplayed= false;
|
|
|
|
// start to wait receive of those string (NB: they may be already here, but waitDynStrings calls directly the callback in this case)
|
|
STRING_MANAGER::CStringManagerClient *pSMC= STRING_MANAGER::CStringManagerClient::instance();
|
|
pSMC->waitDynString(titleTextId, this);
|
|
pSMC->waitDynString(docTextId, this);
|
|
}
|
|
};
|
|
CServerMessageBoxOnReceiveTextId ServerMessageBoxOnReceiveTextId;
|
|
|
|
|
|
void impulseUserPopup(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 titleTextId;
|
|
uint32 docTextId;
|
|
impulse.serial(titleTextId);
|
|
impulse.serial(docTextId);
|
|
|
|
// setup TEMP DB for title
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
CCDBNodeLeaf *node= pIM->getDbProp("UI:TEMP:SERVER_POPUP:TITLE");
|
|
if(node) node->setValue32(titleTextId);
|
|
|
|
// Open the Popup only when the 2 dyn strings are available
|
|
ServerMessageBoxOnReceiveTextId.startWaitTexts(titleTextId, docTextId);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
//extern void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse);
|
|
void impulseCombatFlyingHpDelta(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 entityID;
|
|
uint32 rgba;
|
|
sint16 hpDelta;
|
|
impulse.serial(entityID);
|
|
impulse.serial(rgba);
|
|
impulse.serial(hpDelta);
|
|
CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
|
|
CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
|
|
if (entity)
|
|
entity->addHPOutput(ucstring(toString("%d", hpDelta)), color);
|
|
}
|
|
|
|
void impulseCombatFlyingTextItemSpecialEffectProc(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 entityID;
|
|
uint32 rgba;
|
|
uint8 effect;
|
|
sint32 param;
|
|
impulse.serial(entityID);
|
|
impulse.serial(rgba);
|
|
impulse.serial(effect);
|
|
impulse.serial(param);
|
|
CRGBA color((uint8)(rgba>>24&255), (uint8)(rgba>>16&255), (uint8)(rgba>>8&255), (uint8)(rgba&255));
|
|
ucstring text = CI18N::get(toString("uiItemSpecialEffectFlyingText%s", ITEM_SPECIAL_EFFECT::toString((ITEM_SPECIAL_EFFECT::TItemSpecialEffect)effect).c_str()));
|
|
strFindReplace(text, "%param", toString("%d", param));
|
|
CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
|
|
if (entity)
|
|
entity->addHPOutput(text, color);
|
|
}
|
|
|
|
void impulseCombatFlyingText(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint32 entityID;
|
|
uint8 tmp;
|
|
impulse.serial(entityID);
|
|
impulse.serial(tmp);
|
|
COMBAT_FLYING_TEXT::TCombatFlyingText type = (COMBAT_FLYING_TEXT::TCombatFlyingText)tmp;
|
|
|
|
CRGBA color(255, 255, 255);
|
|
ucstring text("");
|
|
float dt = 0.0f;
|
|
|
|
switch (type)
|
|
{
|
|
case COMBAT_FLYING_TEXT::TargetDodge: // The target dodged
|
|
color = CRGBA(255, 128, 64);
|
|
text = CI18N::get("uiDodge");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::TargetParry: // The target parried
|
|
color = CRGBA(255, 128, 64);
|
|
text = CI18N::get("uiParry");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::TargetEvade: // Actually the user miss his hit
|
|
color = CRGBA(255, 128, 64);
|
|
text = CI18N::get("uiEvade");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::SelfEvade: // Actually the target miss his hit
|
|
color = CRGBA(255, 255, 0);
|
|
text = CI18N::get("uiEvade");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::TargetResist: // The target resisted magic
|
|
color = CRGBA(255, 128, 64);
|
|
text = CI18N::get("uiResist");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::SelfResist: // The user resisted magic
|
|
color = CRGBA(255, 255, 0);
|
|
text = CI18N::get("uiResist");
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::SelfInterrupt: // the user cast was interupted
|
|
color = CRGBA(200, 0, 0);
|
|
text = CI18N::get("uiInterrupt");
|
|
dt = 0.4f;
|
|
break;
|
|
|
|
case COMBAT_FLYING_TEXT::SelfFailure: // The user failed to cast
|
|
color = CRGBA(200, 0, 0);
|
|
text = CI18N::get("uiFailure");
|
|
break;
|
|
|
|
default: // bad type
|
|
nlwarning("Bad type for COMBAT_FLYING_TEXT:TCombatFlyingText enum");
|
|
break;
|
|
}
|
|
|
|
CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex(entityID);
|
|
if (entity)
|
|
entity->addHPOutput(text, color, dt);
|
|
}
|
|
|
|
void impulseSetSeason(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
extern uint8 ServerSeasonValue;
|
|
extern bool ServerSeasonReceived;
|
|
impulse.serial(ServerSeasonValue);
|
|
ServerSeasonReceived = true;
|
|
}
|
|
|
|
void impulseDssDown(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
FarTP.onDssDown();
|
|
}
|
|
|
|
void impulseSetNpcIconDesc(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
uint8 nb8;
|
|
impulse.serial(nb8);
|
|
bool hasChanged = false;
|
|
for (uint i=0; i!=(uint)nb8; ++i)
|
|
{
|
|
TNPCIconCacheKey npcIconCacheKey;
|
|
impulse.serial(npcIconCacheKey);
|
|
uint32 state;
|
|
impulse.serial(state);
|
|
hasChanged = CNPCIconCache::getInstance().onReceiveMissionAvailabilityForThisChar(npcIconCacheKey, (NPC_ICON::TNPCMissionGiverState)state) || hasChanged; // mind the order to avoid partial evaluation
|
|
}
|
|
if (hasChanged)
|
|
CNPCIconCache::getInstance().refreshIconsOfScene();
|
|
}
|
|
|
|
void impulseServerEventForMissionAvailability(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
CNPCIconCache::getInstance().onEventForMissionAvailabilityForThisChar();
|
|
}
|
|
|
|
void impulseSetNpcIconTimer(NLMISC::CBitMemStream &impulse)
|
|
{
|
|
NLMISC::TGameCycle delay;
|
|
impulse.serial(delay);
|
|
CNPCIconCache::getInstance().setMissionGiverTimer(delay);
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// initializeNetwork :
|
|
//-----------------------------------------------
|
|
void initializeNetwork()
|
|
{
|
|
GenericMsgHeaderMngr.setCallback("DB_UPD_PLR", impulseDatabaseUpdatePlayer);
|
|
GenericMsgHeaderMngr.setCallback("DB_INIT:PLR", impulseDatabaseInitPlayer);
|
|
GenericMsgHeaderMngr.setCallback("DB_UPD_INV", impulseUpdateInventory);
|
|
GenericMsgHeaderMngr.setCallback("DB_INIT:INV", impulseInitInventory);
|
|
GenericMsgHeaderMngr.setCallback("DB_GROUP:UPDATE_BANK", impulseDatabaseUpdateBank);
|
|
GenericMsgHeaderMngr.setCallback("DB_GROUP:INIT_BANK", impulseDatabaseInitBank);
|
|
GenericMsgHeaderMngr.setCallback("DB_GROUP:RESET_BANK", impulseDatabaseResetBank);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:NO_USER_CHAR", impulseNoUserChar);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHARS", impulseUserChars);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:USER_CHAR", impulseUserChar);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:FAR_TP", impulseFarTP);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:READY", impulseServerReady);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:VALID_NAME", impulseCharNameValid);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:SHARD_ID", impulseShardId);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_OK", impulseServerQuitOk);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:SERVER_QUIT_ABORT", impulseServerQuitAbort);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:MAIL_AVAILABLE", impulseMailNotification);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:GUILD_MESSAGE_AVAILABLE", impulseForumNotification);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:PERMANENT_BAN", impulsePermanentBan);
|
|
GenericMsgHeaderMngr.setCallback("CONNECTION:UNBAN", impulsePermanentUnban);
|
|
|
|
GenericMsgHeaderMngr.setCallback("STRING:CHAT", impulseChat);
|
|
GenericMsgHeaderMngr.setCallback("STRING:TELL", impulseTell);
|
|
GenericMsgHeaderMngr.setCallback("STRING:FAR_TELL", impulseFarTell);
|
|
GenericMsgHeaderMngr.setCallback("STRING:CHAT2", impulseChat2);
|
|
GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING", impulseDynString);
|
|
GenericMsgHeaderMngr.setCallback("STRING:DYN_STRING_GROUP", inpulseDynStringInChatGroup);
|
|
GenericMsgHeaderMngr.setCallback("STRING:TELL2", impulseTell2);
|
|
// GenericMsgHeaderMngr.setCallback("STRING:ADD_DYN_STR", impulseAddDynStr);
|
|
GenericMsgHeaderMngr.setCallback("TP:DEST", impulseTP);
|
|
GenericMsgHeaderMngr.setCallback("TP:DEST_WITH_SEASON", impulseTPWithSeason);
|
|
GenericMsgHeaderMngr.setCallback("TP:CORRECT", impulseCorrectPos);
|
|
GenericMsgHeaderMngr.setCallback("COMBAT:ENGAGE_FAILED", impulseCombatEngageFailed);
|
|
GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_OPEN", impulseDynChatOpen);
|
|
GenericMsgHeaderMngr.setCallback("BOTCHAT:DYNCHAT_CLOSE", impulseDynChatClose);
|
|
|
|
GenericMsgHeaderMngr.setCallback("CASTING:BEGIN", impulseBeginCast);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:INVITATION", impulseTeamInvitation);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:SHARE_OPEN", impulseTeamShareOpen);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:SHARE_INVALID", impulseTeamShareInvalid);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:SHARE_CLOSE", impulseTeamShareClose);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_INIT", impulseTeamContactInit);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_CREATE", impulseTeamContactCreate);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_STATUS", impulseTeamContactStatus);
|
|
GenericMsgHeaderMngr.setCallback("TEAM:CONTACT_REMOVE", impulseTeamContactRemove);
|
|
|
|
GenericMsgHeaderMngr.setCallback("EXCHANGE:INVITATION", impulseExchangeInvitation);
|
|
GenericMsgHeaderMngr.setCallback("EXCHANGE:CLOSE_INVITATION", impulseExchangeCloseInvitation);
|
|
GenericMsgHeaderMngr.setCallback("ANIMALS:MOUNT_ABORT", impulseMountAbort);
|
|
|
|
GenericMsgHeaderMngr.setCallback("DEBUG:REPLY_WHERE", impulseWhere);
|
|
GenericMsgHeaderMngr.setCallback("DEBUG:COUNTER", impulseCounter);
|
|
|
|
//
|
|
GenericMsgHeaderMngr.setCallback("STRING_MANAGER:PHRASE_SEND", impulsePhraseSend);
|
|
GenericMsgHeaderMngr.setCallback("STRING_MANAGER:STRING_RESP", impulseStringResp);
|
|
GenericMsgHeaderMngr.setCallback("STRING_MANAGER:RELOAD_CACHE", impulseReloadCache);
|
|
//
|
|
GenericMsgHeaderMngr.setCallback("BOTCHAT:FORCE_END", impulseBotChatForceEnd);
|
|
|
|
GenericMsgHeaderMngr.setCallback("JOURNAL:INIT_COMPLETED_MISSIONS", impulseJournalInitCompletedMissions);
|
|
GenericMsgHeaderMngr.setCallback("JOURNAL:UPDATE_COMPLETED_MISSIONS", impulseJournalUpdateCompletedMissions);
|
|
// GenericMsgHeaderMngr.setCallback("JOURNAL:CANT_ABANDON", impulseJournalCantAbandon);
|
|
|
|
GenericMsgHeaderMngr.setCallback("JOURNAL:ADD_COMPASS", impulseJournalAddCompass);
|
|
GenericMsgHeaderMngr.setCallback("JOURNAL:REMOVE_COMPASS", impulseJournalRemoveCompass);
|
|
|
|
|
|
//GenericMsgHeaderMngr.setCallback("GUILD:SET_MEMBER_INFO", impulseGuildSetMemberInfo);
|
|
//GenericMsgHeaderMngr.setCallback("GUILD:INIT_MEMBER_INFO", impulseGuildInitMemberInfo);
|
|
|
|
GenericMsgHeaderMngr.setCallback("GUILD:JOIN_PROPOSAL", impulseGuildJoinProposal);
|
|
|
|
GenericMsgHeaderMngr.setCallback("GUILD:ASCENSOR", impulseGuildAscensor);
|
|
GenericMsgHeaderMngr.setCallback("GUILD:LEAVE_ASCENSOR", impulseGuildLeaveAscensor);
|
|
GenericMsgHeaderMngr.setCallback("GUILD:ABORT_CREATION", impulseGuildAbortCreation);
|
|
GenericMsgHeaderMngr.setCallback("GUILD:OPEN_GUILD_WINDOW", impulseGuildOpenGuildWindow);
|
|
|
|
GenericMsgHeaderMngr.setCallback("GUILD:OPEN_INVENTORY", impulseGuildOpenInventory);
|
|
GenericMsgHeaderMngr.setCallback("GUILD:CLOSE_INVENTORY", impulseGuildCloseInventory);
|
|
|
|
GenericMsgHeaderMngr.setCallback("GUILD:UPDATE_PLAYER_TITLE", impulseGuildUpdatePlayerTitle);
|
|
GenericMsgHeaderMngr.setCallback("GUILD:USE_FEMALE_TITLES", impulseGuildUseFemaleTitles);
|
|
//GenericMsgHeaderMngr.setCallback("GUILD:INVITATION", impulseGuildInvitation);
|
|
|
|
GenericMsgHeaderMngr.setCallback("HARVEST:CLOSE_TEMP_INVENTORY", impulseCloseTempInv);
|
|
|
|
GenericMsgHeaderMngr.setCallback("COMMAND:REMOTE_ADMIN", impulseRemoteAdmin);
|
|
|
|
GenericMsgHeaderMngr.setCallback("PHRASE:DOWNLOAD", impulsePhraseDownLoad);
|
|
GenericMsgHeaderMngr.setCallback("PHRASE:CONFIRM_BUY", impulsePhraseConfirmBuy);
|
|
GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_CYCLIC_ACK", impulsePhraseAckExecuteCyclic);
|
|
GenericMsgHeaderMngr.setCallback("PHRASE:EXEC_NEXT_ACK", impulsePhraseAckExecuteNext);
|
|
|
|
GenericMsgHeaderMngr.setCallback("ITEM_INFO:SET", impulseItemInfoSet);
|
|
GenericMsgHeaderMngr.setCallback("ITEM_INFO:REFRESH_VERSION", impulseItemInfoRefreshVersion);
|
|
GenericMsgHeaderMngr.setCallback("MISSION_PREREQ:SET", impulsePrereqInfoSet);
|
|
GenericMsgHeaderMngr.setCallback("ITEM:OPEN_ROOM_INVENTORY", impulseItemOpenRoomInventory);
|
|
GenericMsgHeaderMngr.setCallback("ITEM:CLOSE_ROOM_INVENTORY", impulseItemCloseRoomInventory);
|
|
|
|
GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN_POINT", impulseDeathRespawnPoint);
|
|
GenericMsgHeaderMngr.setCallback("DEATH:RESPAWN", impulseDeathRespawn);
|
|
|
|
GenericMsgHeaderMngr.setCallback("DUEL:INVITATION", impulseDuelInvitation);
|
|
GenericMsgHeaderMngr.setCallback("DUEL:CANCEL_INVITATION", impulseDuelCancelInvitation);
|
|
|
|
GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:INVITATION", impulsePVPChallengeInvitation);
|
|
GenericMsgHeaderMngr.setCallback("PVP_CHALLENGE:CANCEL_INVITATION", impulsePVPChallengeCancelInvitation);
|
|
|
|
GenericMsgHeaderMngr.setCallback("PVP_FACTION:PUSH_FACTION_WAR", impulsePVPFactionPushFactionWar);
|
|
GenericMsgHeaderMngr.setCallback("PVP_FACTION:POP_FACTION_WAR", impulsePVPFactionPopFactionWar);
|
|
GenericMsgHeaderMngr.setCallback("PVP_FACTION:FACTION_WARS", impulsePVPFactionFactionWars);
|
|
|
|
|
|
// GenericMsgHeaderMngr.setCallback("PVP_VERSUS:CHOOSE_CLAN", impulsePVPChooseClan);
|
|
|
|
GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:UPDATE", impulseEncyclopediaUpdate);
|
|
GenericMsgHeaderMngr.setCallback("ENCYCLOPEDIA:INIT", impulseEncyclopediaInit);
|
|
|
|
GenericMsgHeaderMngr.setCallback("USER:BARS", impulseUserBars);
|
|
GenericMsgHeaderMngr.setCallback("USER:POPUP", impulseUserPopup);
|
|
|
|
|
|
GenericMsgHeaderMngr.setCallback("MISSION:ASK_ENTER_CRITICAL", impulseEnterCrZoneProposal);
|
|
GenericMsgHeaderMngr.setCallback("MISSION:CLOSE_ENTER_CRITICAL", impulseCloseEnterCrZoneProposal);
|
|
|
|
// Module gateway message
|
|
GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FEOPEN", cbImpulsionGatewayOpen);
|
|
GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:GATEWAY_MSG", cbImpulsionGatewayMessage );
|
|
GenericMsgHeaderMngr.setCallback( "MODULE_GATEWAY:FECLOSE", cbImpulsionGatewayClose );
|
|
|
|
GenericMsgHeaderMngr.setCallback( "OUTPOST:CHOOSE_SIDE", impulseOutpostChooseSide );
|
|
GenericMsgHeaderMngr.setCallback( "OUTPOST:DECLARE_WAR_ACK", impulseOutpostDeclareWarAck );
|
|
|
|
GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_HP_DELTA", impulseCombatFlyingHpDelta );
|
|
GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT_ISE", impulseCombatFlyingTextItemSpecialEffectProc );
|
|
GenericMsgHeaderMngr.setCallback( "COMBAT:FLYING_TEXT", impulseCombatFlyingText );
|
|
|
|
GenericMsgHeaderMngr.setCallback( "SEASON:SET", impulseSetSeason );
|
|
GenericMsgHeaderMngr.setCallback( "RING_MISSION:DSS_DOWN", impulseDssDown );
|
|
|
|
GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_DESC", impulseSetNpcIconDesc );
|
|
GenericMsgHeaderMngr.setCallback( "NPC_ICON:SVR_EVENT_MIS_AVL", impulseServerEventForMissionAvailability );
|
|
GenericMsgHeaderMngr.setCallback( "NPC_ICON:SET_TIMER", impulseSetNpcIconTimer );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
// impulseCallBack :
|
|
// The impulse callback to receive all msg from the frontend.
|
|
//-----------------------------------------------
|
|
void impulseCallBack(NLMISC::CBitMemStream &impulse, sint32 packet, void *arg)
|
|
{
|
|
GenericMsgHeaderMngr.execute(impulse);
|
|
}
|
|
|
|
|
|
////////////
|
|
// METHOD //
|
|
////////////
|
|
//-----------------------------------------------
|
|
// CNetManager :
|
|
// Constructor.
|
|
//-----------------------------------------------
|
|
CNetManager::CNetManager() : CNetworkConnection()
|
|
{
|
|
#ifdef ENABLE_INCOMING_MSG_RECORDER
|
|
_IsReplayStarting = false;
|
|
#endif
|
|
}// CNetManager //
|
|
|
|
//-----------------------------------------------
|
|
// update :
|
|
// Updates the whole connection with the frontend.
|
|
// Call this method evently.
|
|
// \return bool : 'true' if data were sent/received.
|
|
//-----------------------------------------------
|
|
bool CNetManager::update()
|
|
{
|
|
H_AUTO_USE ( RZ_Client_Net_Mngr_Update )
|
|
|
|
#ifdef ENABLE_INCOMING_MSG_RECORDER
|
|
if(_IsReplayStarting)
|
|
return;
|
|
#endif
|
|
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
{
|
|
// Init
|
|
if(_CurrentServerTick == 0)
|
|
{
|
|
if(T1 >= _LCT)
|
|
{
|
|
_MachineTimeAtTick = T1;
|
|
_CurrentClientTime = _MachineTimeAtTick - _LCT;
|
|
_CurrentClientTick = 0;
|
|
_CurrentServerTick = 10;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if((T1 - _MachineTimeAtTick) >= _MsPerTick)
|
|
{
|
|
NLMISC::TGameCycle nbTick = (NLMISC::TGameCycle)((T1 - _MachineTimeAtTick)/_MsPerTick);
|
|
_CurrentClientTick += nbTick;
|
|
_CurrentServerTick += nbTick;
|
|
_MachineTimeAtTick += nbTick*_MsPerTick;
|
|
}
|
|
|
|
// update the smooth server tick for debug
|
|
CNetworkConnection::updateSmoothServerTick();
|
|
|
|
// emulation done
|
|
#ifdef ENABLE_INCOMING_MSG_RECORDER
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
// Update the base class.
|
|
bool result = CNetworkConnection::update();
|
|
// Get changes with the update.
|
|
const vector<CChange> &changes = NetMngr.getChanges();
|
|
|
|
// Manage changes
|
|
vector<CChange>::const_iterator it;
|
|
for(it = changes.begin(); it < changes.end(); ++it)
|
|
{
|
|
const CChange &change = *it;
|
|
// Update a property.
|
|
if(change.Property < AddNewEntity)
|
|
{
|
|
if (!IgnoreEntityDbUpdates || change.ShortId == 0)
|
|
{
|
|
// Update the visual property for the slot.
|
|
EntitiesMngr.updateVisualProperty(change.GameCycle, change.ShortId, change.Property, change.PositionInfo.PredictedInterval);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("CNetManager::update : Skipping EntitiesMngr.updateVisualProperty() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
|
|
}
|
|
}
|
|
// Add New Entity (and remove the old one in the slot).
|
|
else if(change.Property == AddNewEntity)
|
|
{
|
|
if (!IgnoreEntityDbUpdates || change.ShortId == 0)
|
|
{
|
|
// Remove the old entity.
|
|
EntitiesMngr.remove(change.ShortId, false);
|
|
// Create the new entity.
|
|
if(EntitiesMngr.create(change.ShortId, get(change.ShortId), change.NewEntityInfo) == 0)
|
|
nlwarning("CNetManager::update : entity in the slot '%u' has not been created.", change.ShortId);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("CNetManager::update : Skipping EntitiesMngr.create() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
|
|
}
|
|
}
|
|
// Delete an entity
|
|
else if(change.Property == RemoveOldEntity)
|
|
{
|
|
if (!IgnoreEntityDbUpdates || change.ShortId == 0)
|
|
{
|
|
// Remove the old entity.
|
|
EntitiesMngr.remove(change.ShortId, true);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("CNetManager::update : Skipping EntitiesMngr.remove() because IgnoreEntityDbUpdates=%s and change.ShortId=%d", (IgnoreEntityDbUpdates?"true":"false"), change.ShortId);
|
|
}
|
|
}
|
|
// Lag detected.
|
|
else if(change.Property == LagDetected)
|
|
{
|
|
nldebug("CNetManager::update : Lag detected.");
|
|
}
|
|
// Probe received.
|
|
else if(change.Property == ProbeReceived)
|
|
{
|
|
nldebug("CNetManager::update : Probe Received.");
|
|
}
|
|
// Connection ready.
|
|
else if(change.Property == ConnectionReady)
|
|
{
|
|
nldebug("CNetManager::update : Connection Ready.");
|
|
}
|
|
// Property unknown.
|
|
else
|
|
nlwarning("CNetManager::update : The property '%d' is unknown.", change.Property);
|
|
}
|
|
ChatMngr.flushBuffer(InterfaceChatDisplayer);
|
|
// Clear all changes.
|
|
clearChanges();
|
|
|
|
// Update data base server state
|
|
if (IngameDbMngr.getNodePtr())
|
|
{
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
if (im)
|
|
{
|
|
CCDBNodeLeaf *node = im->getDbProp("UI:VARIABLES:PING", false);
|
|
if (node)
|
|
node->setValue32(getPing());
|
|
node = im->getDbProp("UI:VARIABLES:UPLOAD", false);
|
|
if (node)
|
|
node->setValue32((sint32)(getMeanUpload()*1024.f/8.f));
|
|
node = im->getDbProp("UI:VARIABLES:DOWNLOAD", false);
|
|
if (node)
|
|
node->setValue32((sint32)(getMeanDownload()*1024.f/8.f));
|
|
node = im->getDbProp("UI:VARIABLES:PACKETLOST", false);
|
|
if (node)
|
|
node->setValue32((sint32)getMeanPacketLoss());
|
|
node = im->getDbProp("UI:VARIABLES:SERVERSTATE", false);
|
|
if (node)
|
|
node->setValue32((sint32)getConnectionState());
|
|
node = im->getDbProp("UI:VARIABLES:CONNECTION_QUALITY", false);
|
|
if (node)
|
|
node->setValue32((sint32)getConnectionQuality());
|
|
}
|
|
}
|
|
|
|
// Return 'true' if data were sent/received.
|
|
return result;
|
|
|
|
|
|
}// update //
|
|
|
|
//-----------------------------------------------
|
|
// getConnectionQuality :
|
|
//-----------------------------------------------
|
|
bool CNetManager::getConnectionQuality()
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
return true;
|
|
|
|
return CNetworkConnection::getConnectionQuality();
|
|
}// getConnectionQuality //
|
|
|
|
|
|
/**
|
|
* Buffers a bitmemstream, that will be converted into a generic action, to be sent later to the server (at next update).
|
|
*/
|
|
void CNetManager::push(NLMISC::CBitMemStream &msg)
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
return;
|
|
|
|
if (PermanentlyBanned) return;
|
|
|
|
CNetworkConnection::push(msg);
|
|
}
|
|
|
|
/**
|
|
* Buffers a target action
|
|
*/
|
|
void CNetManager::pushTarget(CLFECOMMON::TCLEntityId slot)
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
{
|
|
if(UserEntity->mode() != MBEHAV::COMBAT
|
|
&& UserEntity->mode() != MBEHAV::COMBAT_FLOAT)
|
|
{
|
|
UserEntity->targetSlot(slot);
|
|
}
|
|
return;
|
|
}
|
|
|
|
CNetworkConnection::pushTarget(slot, LHSTATE::NONE);
|
|
}
|
|
|
|
|
|
/**
|
|
* Buffers a pick-up action
|
|
*/
|
|
void CNetManager::pushPickup(CLFECOMMON::TCLEntityId slot, LHSTATE::TLHState lootOrHarvest)
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CNetworkConnection::pushTarget(slot, lootOrHarvest);
|
|
}
|
|
|
|
|
|
/**
|
|
* Send
|
|
*/
|
|
void CNetManager::send(NLMISC::TGameCycle gameCycle)
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
return;
|
|
|
|
// wait till next server is received
|
|
if (_LastSentCycle >= gameCycle)
|
|
{
|
|
//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);
|
|
while (_LastSentCycle >= gameCycle)
|
|
{
|
|
// Update network.
|
|
update();
|
|
// Send dummy info
|
|
send();
|
|
// Do not take all the CPU.
|
|
nlSleep(100);
|
|
|
|
gameCycle = getCurrentServerTick();
|
|
}
|
|
}
|
|
|
|
CNetworkConnection::send(gameCycle);
|
|
}
|
|
|
|
/**
|
|
* Send
|
|
*/
|
|
void CNetManager::send()
|
|
{
|
|
// If the client is in Local Mode -> no network.
|
|
if(ClientCfg.Local)
|
|
return;
|
|
|
|
CNetworkConnection::send();
|
|
}
|
|
|
|
/**
|
|
* Disconnects the current connection
|
|
*/
|
|
void CNetManager::disconnect()
|
|
{
|
|
// If the client is in Local Mode -> no need to disconnect.
|
|
if(ClientCfg.Local)
|
|
return;
|
|
|
|
CNetworkConnection::disconnect();
|
|
}// disconnect //
|
|
|
|
|
|
/**
|
|
* Reset data and init the socket
|
|
*/
|
|
void CNetManager::reinit()
|
|
{
|
|
if(ClientCfg.Local)
|
|
return;
|
|
|
|
IngameDbMngr.resetInitState();
|
|
CNetworkConnection::reinit();
|
|
}
|
|
|
|
void CNetManager::waitForServer()
|
|
{
|
|
sint LastGameCycle = getCurrentServerTick();
|
|
|
|
for(;;)
|
|
{
|
|
// Event server get events
|
|
CInputHandlerManager::getInstance()->pumpEventsNoIM();
|
|
// Update Network.
|
|
update();
|
|
|
|
if (LastGameCycle != (sint) getCurrentServerTick())
|
|
break;
|
|
|
|
nlSleep(100);
|
|
send();
|
|
}
|
|
|
|
}// waitForServer //
|
|
|
|
|
|
#ifdef ENABLE_INCOMING_MSG_RECORDER
|
|
//-----------------------------------------------
|
|
// setReplayingMode :
|
|
//-----------------------------------------------
|
|
void CNetManager::setReplayingMode( bool onOff, const std::string& filename )
|
|
{
|
|
CNetworkConnection::setReplayingMode(onOff, filename);
|
|
_IsReplayStarting = onOff;
|
|
}// setReplayingMode //
|
|
|
|
//-----------------------------------------------
|
|
// startReplay :
|
|
//-----------------------------------------------
|
|
void CNetManager::startReplay()
|
|
{
|
|
// Init Replay
|
|
_MachineTimeAtTick = T1;
|
|
if(_MachineTimeAtTick >= _LCT)
|
|
_CurrentClientTime = _MachineTimeAtTick - _LCT;
|
|
else
|
|
_CurrentClientTime = 0;
|
|
// Replay now in progress.
|
|
_IsReplayStarting = false;
|
|
}// startReplay //
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Create the net managers in CLIENT_MULTI mode
|
|
*/
|
|
void CNetManagerMulti::init( const std::string& cookie, const std::string& addr )
|
|
{
|
|
uint nb, baseCookie;
|
|
NLMISC::CConfigFile::CVar *var = ClientCfg.ConfigFile.getVarPtr( "NbConnections" );
|
|
if ( var )
|
|
nb = var->asInt();
|
|
else
|
|
nb = 1;
|
|
var = ClientCfg.ConfigFile.getVarPtr( "UserId" );
|
|
if ( var )
|
|
baseCookie = var->asInt();
|
|
else
|
|
baseCookie = 0;
|
|
std::vector<std::string> fsAddrs;
|
|
fsAddrs.push_back( addr );
|
|
string portString = addr.substr( addr.find( ':' ) );
|
|
var = ClientCfg.ConfigFile.getVarPtr( "AdditionalFSList" );
|
|
if ( var )
|
|
{
|
|
for ( uint i=0; i!=var->size(); ++i )
|
|
fsAddrs.push_back( var->asString( i ) + portString );
|
|
}
|
|
nlinfo( "CNetManagerMulti: Creating %u connections to %u front-ends, baseCookie=%u...", nb, fsAddrs.size(), baseCookie );
|
|
|
|
for ( uint i=0; i!=nb; ++i )
|
|
{
|
|
CNetManager *nm = new CNetManager();
|
|
string multicook = NLMISC::toString( "%8x|%8x|%8x", 0, 0, baseCookie + i );
|
|
nm->init( multicook, fsAddrs[i % fsAddrs.size()] );
|
|
_NetManagers.push_back( nm );
|
|
}
|
|
}
|
|
|
|
//
|
|
uint32 ShardId = 0;
|
|
std::string WebServer = "";
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////// COMMANDS after should NOT appear IN the FINAL VERSION ///////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#if !FINAL_VERSION
|
|
|
|
// temp : simulate a team msg in local mode
|
|
NLMISC_COMMAND(localTellTeam, "Temp : simulate a tell in local mode", "<people_name> <msg>")
|
|
{
|
|
if (args.empty()) return false;
|
|
ucstring player = args[0];
|
|
std::string msg;
|
|
if (args.size() >= 2)
|
|
{
|
|
msg = args[1];
|
|
for(uint k = 2; k < args.size(); ++k)
|
|
{
|
|
msg += " " + args[k];
|
|
}
|
|
}
|
|
TDataSetIndex dsi = INVALID_DATASET_INDEX;
|
|
InterfaceChatDisplayer.displayChat(dsi, ucstring(msg), ucstring(msg), CChatGroup::team, NLMISC::CEntityId::Unknown, player);
|
|
return true;
|
|
}
|
|
|
|
// temp : simulate a tell in local mode
|
|
NLMISC_COMMAND(localTell, "Temp : simulate a tell in local mode", "<people_name> <msg>")
|
|
{
|
|
if (args.empty()) return false;
|
|
ucstring player = args[0];
|
|
std::string msg;
|
|
if (args.size() >= 2)
|
|
{
|
|
msg = args[1];
|
|
for(uint k = 2; k < args.size(); ++k)
|
|
{
|
|
msg += " " + args[k];
|
|
}
|
|
}
|
|
// TDataSetIndex dsi = INVALID_DATASET_ROW;
|
|
InterfaceChatDisplayer.displayTell(/*dsi, */ucstring(msg), player);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND(testDynChatOpen, "", "")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 BotUID = 22; // Compressed Index
|
|
uint32 BotName = 654; // Server string
|
|
vector<uint32> DynStrs; // 0 - Desc, 1 - Option0, 2 - Option1, etc....
|
|
DynStrs.push_back(16540);
|
|
DynStrs.push_back(11465);
|
|
DynStrs.push_back(12654);
|
|
bm.serial(BotUID);
|
|
bm.serial(BotName);
|
|
bm.serialCont(DynStrs);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseDynChatOpen(bm);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND(testDynChatClose, "", "")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 BotUID = 22; // Compressed Index
|
|
bm.serial(BotUID);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseDynChatClose(bm);
|
|
return true;
|
|
}
|
|
|
|
|
|
NLMISC_COMMAND(testCloseTempInv, "","")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
impulseCloseTempInv(bm);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND(testTeamInvite, "","")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 index = 10;
|
|
bm.serial(index);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseTeamInvitation(bm);
|
|
return true;
|
|
}
|
|
NLMISC_COMMAND(testGuildInvite, "","")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 index = 10;
|
|
bm.serial(index);
|
|
bm.serial(index);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseGuildJoinProposal(bm);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND( testExchangeInvitation, "Test the modal window for invitation exchange", "" )
|
|
{
|
|
CBitMemStream impulse;
|
|
uint32 nameIndex = 0;
|
|
impulse.serial(nameIndex);
|
|
impulse.invert();
|
|
impulseExchangeInvitation(impulse);
|
|
return true;
|
|
}
|
|
|
|
|
|
NLMISC_COMMAND(testAscensor, "Temp : Simulate a GUILD:ASCENSOR message coming from server","")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 index = 10;
|
|
bm.serial(index);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseGuildAscensor(bm);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND(testDuelInvite, "","")
|
|
{
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 index = 10;
|
|
bm.serial(index);
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseDuelInvitation(bm);
|
|
return true;
|
|
}
|
|
|
|
//NLMISC_COMMAND(receiveId, "","<num> <name>")
|
|
//{
|
|
// uint32 index;
|
|
// fromString(args[0], index);
|
|
// ucstring ucstr = args[1];
|
|
//
|
|
// vector<bool> code;
|
|
//
|
|
//#ifdef OLD_STRING_SYSTEM
|
|
// ChatMngr.getDynamicDB().add( index, ucstr, code );
|
|
//#else
|
|
// // TRAP // WE MUST NEVER CALL THIS COMMAND ANYMORE : ALL IS HANDLED BY STRING_MANAGER NOW !!!
|
|
// nlstop;
|
|
//#endif
|
|
//
|
|
// return true;
|
|
//}
|
|
|
|
NLMISC_COMMAND(testOutpostChooseSide, "","b b u32 u32")
|
|
{
|
|
if(args.size()<4)
|
|
return false;
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
bool playerGuildInConflict;
|
|
fromString(args[0], playerGuildInConflict);
|
|
bool playerGuildIsAttacker;
|
|
fromString(args[1], playerGuildIsAttacker);
|
|
bm.serial(playerGuildInConflict);
|
|
bm.serial(playerGuildIsAttacker);
|
|
uint32 ownerGuildNameId;
|
|
fromString(args[2], ownerGuildNameId);
|
|
bm.serial( ownerGuildNameId );
|
|
uint32 attackerGuildNameId;
|
|
fromString(args[3], attackerGuildNameId);
|
|
bm.serial( attackerGuildNameId );
|
|
uint32 declTimer= 100;
|
|
bm.serial( declTimer );
|
|
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseOutpostChooseSide(bm);
|
|
return true;
|
|
}
|
|
|
|
NLMISC_COMMAND(testUserPopup, "","u32 u32")
|
|
{
|
|
if(args.size()<2)
|
|
return false;
|
|
NLMISC::CBitMemStream bm;
|
|
if (bm.isReading()) bm.invert();
|
|
uint32 titleId;
|
|
fromString(args[0], titleId);
|
|
bm.serial( titleId );
|
|
uint32 textId;
|
|
fromString(args[1], textId);
|
|
bm.serial( textId );
|
|
|
|
bm.invert();
|
|
bm.seek(0, NLMISC::IStream::begin);
|
|
impulseUserPopup(bm);
|
|
return true;
|
|
}
|
|
|
|
|
|
#endif
|
|
|