4024 lines
116 KiB
C++
4024 lines
116 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 "stdpch.h"
|
|
|
|
// Memory
|
|
#include <memory>
|
|
|
|
#include "nel/misc/i_xml.h"
|
|
#include "nel/misc/o_xml.h"
|
|
#include "nel/misc/algo.h"
|
|
|
|
#include "nel/net/tcp_sock.h"
|
|
|
|
// Globals
|
|
#include "interface_manager.h"
|
|
#include "interface_config.h"
|
|
#include "task_bar_manager.h"
|
|
#include "guild_manager.h"
|
|
#include "../client_cfg.h"
|
|
#include "encyclopedia_manager.h"
|
|
// Expr
|
|
#include "nel/gui/interface_expr.h"
|
|
#include "register_interface_elements.h"
|
|
// Action / Observers
|
|
#include "nel/gui/action_handler.h"
|
|
#include "action_handler_misc.h"
|
|
#include "interface_observer.h"
|
|
#include "nel/gui/interface_anim.h"
|
|
#include "interface_ddx.h"
|
|
#include "action_handler_help.h"
|
|
#include "action_handler_item.h"
|
|
// View
|
|
#include "nel/gui/view_bitmap.h"
|
|
//#include "view_bitmap_progress.h"
|
|
#include "view_bitmap_faber_mp.h"
|
|
#include "nel/gui/view_bitmap_combo.h"
|
|
#include "nel/gui/view_text.h"
|
|
#include "nel/gui/view_text_id.h"
|
|
#include "nel/gui/view_text_formated.h"
|
|
// Ctrl
|
|
#include "nel/gui/ctrl_scroll.h"
|
|
#include "nel/gui/ctrl_button.h"
|
|
#include "nel/gui/ctrl_text_button.h"
|
|
// DBCtrl
|
|
#include "dbctrl_sheet.h"
|
|
// Group
|
|
#include "nel/gui/group_list.h"
|
|
#include "nel/gui/group_menu.h"
|
|
#include "nel/gui/group_container.h"
|
|
#include "nel/gui/group_modal.h"
|
|
#include "nel/gui/group_editbox.h"
|
|
#include "group_in_scene_bubble.h"
|
|
#include "group_skills.h"
|
|
#include "group_compas.h"
|
|
#include "nel/gui/group_html.h"
|
|
|
|
// Misc
|
|
#include "../input.h"
|
|
#include "bot_chat_manager.h"
|
|
#include "bot_chat_page_all.h"
|
|
#include "chat_displayer.h"
|
|
#include "skill_manager.h"
|
|
#include "../sound_manager.h"
|
|
#include "../actions.h"
|
|
#include "../actions_client.h"
|
|
|
|
#include "../weather_manager_client.h"
|
|
#include "../weather.h"
|
|
|
|
#include "../user_entity.h"
|
|
#include "../motion/user_controls.h"
|
|
#include "people_interraction.h"
|
|
#include "macrocmd_manager.h"
|
|
#include "inventory_manager.h"
|
|
|
|
#include "../connection.h" // needed for loading config file (PlayerSelectedFileName)
|
|
|
|
#include "sbrick_manager.h"
|
|
#include "sphrase_manager.h"
|
|
#include "bar_manager.h"
|
|
|
|
#include "../continent_manager.h"
|
|
#include "../entity_cl.h"
|
|
#include "../login.h"
|
|
|
|
#include "../sheet_manager.h" // for emotes
|
|
#include "../entity_animation_manager.h" // for emotes
|
|
#include "../net_manager.h" // for emotes
|
|
#include "../client_chat_manager.h" // for emotes
|
|
#include "../entities.h"
|
|
|
|
#include "../../common/src/game_share/ryzom_database_banks.h"
|
|
|
|
#include "chat_text_manager.h"
|
|
#include "../npc_icon.h"
|
|
|
|
#include "nel/gui/lua_helper.h"
|
|
using namespace NLGUI;
|
|
#include "nel/gui/lua_ihm.h"
|
|
#include "lua_ihm_ryzom.h"
|
|
|
|
#include "add_on_manager.h"
|
|
|
|
#include "game_share/r2_share_itf.h"
|
|
|
|
#include "../time_client.h"
|
|
|
|
#include "../r2/editor.h"
|
|
#include "../r2/dmc/client_edition_module.h"
|
|
|
|
#include "../bg_downloader_access.h"
|
|
|
|
#include "parser_modules.h"
|
|
|
|
#include "../global.h"
|
|
#include "user_agent.h"
|
|
|
|
using namespace NLMISC;
|
|
|
|
namespace NLGUI
|
|
{
|
|
extern void luaDebuggerMainLoop();
|
|
}
|
|
|
|
extern CClientChatManager ChatMngr;
|
|
extern CContinentManager ContinentMngr;
|
|
extern bool IsInRingSession;
|
|
extern CEventsListener EventsListener;
|
|
|
|
namespace R2
|
|
{
|
|
extern bool ReloadUIFlag;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
/*
|
|
Version 11: - Dyn chat in user tab
|
|
Version 10: - Last screen resolution serialisation
|
|
Version 9: UI_DB_SAVE_VERSION system
|
|
Version 8: - serialInSceneBubbleInfo (for ignore context help)
|
|
Version 7: - serialMacroMemory
|
|
Version 6: DEPRECATED - Info about friend/ignore list
|
|
Version 5: - Info Windows pos
|
|
Version 4: - User landmark serialisation
|
|
Version 3: - Added a Hack for CInterfaceConfig version miss
|
|
Version 2: - TaskBar serialisation
|
|
Version 1: - people interraction
|
|
Version 0: - base version
|
|
*/
|
|
#define ICFG_STREAM_VERSION 11
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
#define FOREACH(__itvar,__conttype,__contvar) \
|
|
for (__conttype::iterator __itvar(__contvar.begin()),__itvar##end(__contvar.end()); __itvar!=__itvar##end; ++__itvar)
|
|
#endif
|
|
|
|
// ***************************************************************************
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
using namespace NLNET;
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
extern bool loginFinished;
|
|
void setLoginFinished( bool f );
|
|
// Edit actions
|
|
CActionsManager EditActions;
|
|
|
|
CInterfaceManager * CInterfaceManager::_Instance = NULL;
|
|
|
|
CChatDisplayer * ChatDisplayer = NULL;
|
|
|
|
|
|
void initActions();
|
|
void uninitActions();
|
|
|
|
///\todo nico: remove this dummy displayer
|
|
NLMISC::CLog g_log;
|
|
|
|
|
|
////////////
|
|
// GLOBAL //
|
|
////////////
|
|
|
|
// Hierarchical timer
|
|
H_AUTO_DECL ( RZ_Client_Update_Frame_Events )
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// AJM TEMP TEMP TEMP TEMP
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
|
|
// track creation of an interface group
|
|
void CInterfaceManager::DebugTrackGroupsCreated( CInterfaceGroup *pIG )
|
|
{
|
|
// add to set
|
|
_DebugTrackGroupSet.insert( pIG );
|
|
|
|
// add to map and increment create counter
|
|
_DebugTrackGroupMap[pIG] = _DebugTrackGroupCreateCount++;
|
|
}
|
|
|
|
// track destruction of an interface group
|
|
void CInterfaceManager::DebugTrackGroupsDestroyed( CInterfaceGroup *pIG )
|
|
{
|
|
// lookup id of the group being destroyed (for debugging)
|
|
int foo = DebugTrackGroupsGetId( pIG );
|
|
|
|
// remove from set
|
|
setInterfaceGroupPtr::iterator it = _DebugTrackGroupSet.find( pIG );
|
|
if( it == _DebugTrackGroupSet.end() )
|
|
{
|
|
nldebug( "AJM DEBUG: Interface Group %x Destroyed twice", pIG );
|
|
return;
|
|
}
|
|
_DebugTrackGroupSet.erase( pIG );
|
|
|
|
// remove from map and increment destroy counter
|
|
_DebugTrackGroupMap.erase(pIG);
|
|
_DebugTrackGroupDestroyCount++;
|
|
}
|
|
|
|
// display the count of undestroyed interface groups
|
|
void CInterfaceManager::DebugTrackGroupsDump()
|
|
{
|
|
// dump groups
|
|
nldebug( "AJM DEBUG: %d Interface Groups remaining", _DebugTrackGroupCreateCount-_DebugTrackGroupDestroyCount );
|
|
|
|
FOREACH( itIG, mapInterfaceGroupPtr2Int, _DebugTrackGroupMap )
|
|
{
|
|
nldebug( " %d", itIG->second );
|
|
}
|
|
}
|
|
|
|
// return the index for an interface group
|
|
int CInterfaceManager::DebugTrackGroupsGetId( CInterfaceGroup *pIG )
|
|
{
|
|
mapInterfaceGroupPtr2Int::iterator it = _DebugTrackGroupMap.find( pIG );
|
|
if( it != _DebugTrackGroupMap.end() )
|
|
return it->second;
|
|
return -1;
|
|
}
|
|
|
|
#endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
|
|
class CDesktopUpdater : public CWidgetManager::INewScreenSizeHandler
|
|
{
|
|
public:
|
|
void process( uint32 w, uint32 h )
|
|
{
|
|
CInterfaceManager::getInstance()->updateDesktops( w, h );
|
|
}
|
|
};
|
|
|
|
class CDrawDraggedSheet : public CWidgetManager::IOnWidgetsDrawnHandler
|
|
{
|
|
public:
|
|
void process()
|
|
{
|
|
if ( CWidgetManager::getInstance()->getPointer()->show())
|
|
{
|
|
CDBCtrlSheet *pCS = dynamic_cast<CDBCtrlSheet*>( CWidgetManager::getInstance()->getCapturePointerLeft() );
|
|
if ((pCS != NULL) && (pCS->isDragged()))
|
|
{
|
|
sint x= CWidgetManager::getInstance()->getPointer()->getX() - pCS->getDeltaDragX();
|
|
sint y= CWidgetManager::getInstance()->getPointer()->getY() - pCS->getDeltaDragY();
|
|
pCS->drawSheet (x, y, false, false);
|
|
|
|
// if the control support CopyDrag, and if copy key pressed, display a tiny "+"
|
|
if(pCS->canDragCopy() && CInterfaceManager::getInstance()->testDragCopyKey())
|
|
{
|
|
CViewRenderer &rVR = *CViewRenderer::getInstance();
|
|
sint w= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
|
|
sint h= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
|
|
rVR.draw11RotFlipBitmap (pCS->getRenderLayer()+1, x-w/2, y-h/2, 0, false,
|
|
rVR.getSystemTextureId(CViewRenderer::DragCopyTexture));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
class CStringManagerTextProvider : public CViewTextID::IViewTextProvider
|
|
{
|
|
bool getString( uint32 stringId, ucstring &result )
|
|
{
|
|
return STRING_MANAGER::CStringManagerClient::instance()->getString( stringId, result );
|
|
}
|
|
|
|
bool getDynString( uint32 dynStringId, ucstring &result )
|
|
{
|
|
return STRING_MANAGER::CStringManagerClient::instance()->getDynString( dynStringId, result );
|
|
}
|
|
};
|
|
|
|
class CRyzomTextFormatter : public CViewTextFormated::IViewTextFormatter
|
|
{
|
|
public:
|
|
ucstring formatString( const ucstring &inputString, const ucstring ¶mString )
|
|
{
|
|
ucstring formatedResult;
|
|
|
|
// Apply the format
|
|
for(ucstring::const_iterator it = inputString.begin(); it != inputString.end();)
|
|
{
|
|
if (*it == '$')
|
|
{
|
|
++it;
|
|
if (it == inputString.end())
|
|
break;
|
|
|
|
switch(*it)
|
|
{
|
|
case 't': // add text ID
|
|
formatedResult += paramString;
|
|
break;
|
|
|
|
case 'P':
|
|
case 'p': // add player name
|
|
if (ClientCfg.Local)
|
|
{
|
|
formatedResult += ucstring("player");
|
|
}
|
|
else
|
|
{
|
|
if(UserEntity)
|
|
{
|
|
ucstring name = UserEntity->getEntityName();
|
|
if (*it == 'P') setCase(name, CaseUpper);
|
|
formatedResult += name;
|
|
}
|
|
}
|
|
break;
|
|
//
|
|
case 's':
|
|
case 'b': // add bot name
|
|
{
|
|
ucstring botName;
|
|
bool womanTitle = false;
|
|
if (ClientCfg.Local)
|
|
{
|
|
botName = ucstring("NPC");
|
|
}
|
|
else
|
|
{
|
|
CLFECOMMON::TCLEntityId trader = CLFECOMMON::INVALID_SLOT;
|
|
if(UserEntity)
|
|
trader = UserEntity->trader();
|
|
if (trader != CLFECOMMON::INVALID_SLOT)
|
|
{
|
|
CEntityCL *entity = EntitiesMngr.entity(trader);
|
|
if (entity != NULL)
|
|
{
|
|
uint32 nDBid = entity->getNameId();
|
|
if (nDBid != 0)
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
|
|
pSMC->getString(nDBid, botName);
|
|
}
|
|
else
|
|
{
|
|
botName = entity->getDisplayName();
|
|
}
|
|
CCharacterCL *pChar = dynamic_cast<CCharacterCL*>(entity);
|
|
if (pChar != NULL)
|
|
womanTitle = pChar->getGender() == GSGENDER::female;
|
|
}
|
|
}
|
|
}
|
|
// get the title translated
|
|
ucstring sTitleTranslated = botName;
|
|
CStringPostProcessRemoveName spprn;
|
|
spprn.Woman = womanTitle;
|
|
spprn.cbIDStringReceived(sTitleTranslated);
|
|
|
|
botName = CEntityCL::removeTitleAndShardFromName(botName);
|
|
|
|
// short name (with no title such as 'guard', 'merchant' ...)
|
|
if (*it == 's')
|
|
{
|
|
// But if there is no name, display only the title
|
|
if (botName.empty())
|
|
botName = sTitleTranslated;
|
|
}
|
|
else
|
|
{
|
|
// Else we want the title !
|
|
if (!botName.empty())
|
|
botName += " ";
|
|
botName += sTitleTranslated;
|
|
}
|
|
|
|
formatedResult += botName;
|
|
}
|
|
break;
|
|
default:
|
|
formatedResult += (ucchar) '$';
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
else
|
|
{
|
|
formatedResult += (ucchar) *it;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return formatedResult;
|
|
}
|
|
};
|
|
|
|
namespace
|
|
{
|
|
CStringManagerTextProvider SMTextProvider;
|
|
CRyzomTextFormatter RyzomTextFormatter;
|
|
}
|
|
|
|
CInterfaceManager* CInterfaceManager::getInstance()
|
|
{
|
|
if( _Instance == NULL )
|
|
_Instance = new CInterfaceManager();
|
|
return _Instance;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceManager::CInterfaceManager()
|
|
{
|
|
CWidgetManager::getInstance()->registerNewScreenSizeHandler( new CDesktopUpdater() );
|
|
CWidgetManager::getInstance()->registerOnWidgetsDrawnHandler( new CDrawDraggedSheet() );
|
|
|
|
CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
|
|
|
|
parser->setSetupOptionsCallback( this );
|
|
parser->addModule( "scene3d", new CIF3DSceneParser() );
|
|
parser->addModule( "ddx", new CIFDDXParser() );
|
|
parser->addModule( "action_category", new CActionCategoryParser() );
|
|
parser->addModule( "command", new CCommandParser() );
|
|
parser->addModule( "key", new CKeyParser() );
|
|
parser->addModule( "macro", new CMacroParser() );
|
|
parser->setCacheUIParsing( ClientCfg.CacheUIParsing );
|
|
|
|
CViewRenderer::setDriver( Driver );
|
|
CViewRenderer::setTextContext( TextContext );
|
|
CViewRenderer::hwCursorScale = ClientCfg.HardwareCursorScale;
|
|
CViewRenderer::hwCursors = &ClientCfg.HardwareCursors;
|
|
CViewRenderer::getInstance();
|
|
CViewTextID::setTextProvider( &SMTextProvider );
|
|
CViewTextFormated::setFormatter( &RyzomTextFormatter );
|
|
|
|
CGroupHTML::options.trustedDomains = ClientCfg.WebIgTrustedDomains;
|
|
CGroupHTML::options.languageCode = ClientCfg.getHtmlLanguageCode();
|
|
CGroupHTML::options.appName = getUserAgentName();
|
|
CGroupHTML::options.appVersion = getUserAgentVersion();
|
|
CGroupHTML::options.curlMaxConnections = ClientCfg.CurlMaxConnections;
|
|
|
|
NLGUI::CDBManager::getInstance()->resizeBanks( NB_CDB_BANKS );
|
|
interfaceLinkUpdater = new CInterfaceLink::CInterfaceLinkUpdater();
|
|
_ScreenW = _ScreenH = 0;
|
|
_LastInGameScreenW = _LastInGameScreenH = 0;
|
|
_DescTextTarget = NULL;
|
|
_ConfigLoaded = false;
|
|
_LogState = false;
|
|
_KeysLoaded = false;
|
|
CWidgetManager::getInstance()->resetColorProps();
|
|
CWidgetManager::getInstance()->resetAlphaRolloverSpeedProps();
|
|
CWidgetManager::getInstance()->resetGlobalAlphasProps();
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
_EmotesInitialized = false;
|
|
|
|
|
|
// Global initialization
|
|
// *********************
|
|
|
|
// Interface Manager init
|
|
CViewRenderer::getInstance()->checkNewScreenSize();
|
|
{
|
|
uint32 w,h;
|
|
CViewRenderer::getInstance()->getScreenSize(w, h);
|
|
CWidgetManager::getInstance()->setScreenWH(w, h);
|
|
}
|
|
CViewRenderer::getInstance()->init();
|
|
|
|
_CurrentMode = 0;
|
|
|
|
setInGame( false );
|
|
|
|
_LocalSyncActionCounter= 0;
|
|
// 4Bits counter.
|
|
_LocalSyncActionCounterMask= 15;
|
|
|
|
for(uint i=0;i<CHARACTERISTICS::NUM_CHARACTERISTICS;i++)
|
|
{
|
|
_CurrentPlayerCharac[i]= 0;
|
|
}
|
|
|
|
_CheckMailNode = NULL;
|
|
_CheckForumNode = NULL;
|
|
_UpdateWeatherTime = 0;
|
|
|
|
_DBB_UI_DUMMY = NULL;
|
|
_DB_UI_DUMMY_QUANTITY = NULL;
|
|
_DB_UI_DUMMY_QUALITY = NULL;
|
|
_DB_UI_DUMMY_SHEET = NULL;
|
|
_DB_UI_DUMMY_NAMEID = NULL;
|
|
_DB_UI_DUMMY_ENCHANT = NULL;
|
|
_DB_UI_DUMMY_SLOT_TYPE = NULL;
|
|
_DB_UI_DUMMY_PHRASE = NULL;
|
|
_DB_UI_DUMMY_WORNED = NULL;
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID = NULL;
|
|
_DB_UI_DUMMY_FACTION_TYPE = NULL;
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
_DebugTrackGroupSet.clear();
|
|
_DebugTrackGroupMap.clear();
|
|
_DebugTrackGroupCreateCount = 0;
|
|
_DebugTrackGroupDestroyCount = 0;
|
|
#endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceManager::~CInterfaceManager()
|
|
{
|
|
CViewTextID::setTextProvider( NULL );
|
|
CViewTextFormated::setFormatter( NULL );
|
|
reset(); // to flush IDStringWaiters
|
|
|
|
// release the database observers
|
|
releaseServerToLocalAutoCopyObservers();
|
|
|
|
/*
|
|
removeFlushObserver( interfaceLinkUpdater );
|
|
delete interfaceLinkUpdater;
|
|
interfaceLinkUpdater = NULL;
|
|
*/
|
|
_Instance = NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::reset()
|
|
{
|
|
CViewRenderer::getInstance()->reset();
|
|
CWidgetManager::getInstance()->reset();
|
|
|
|
for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
|
|
delete _IDStringWaiters[i];
|
|
_IDStringWaiters.clear();
|
|
CGroupFrame::resetDisplayTypes();
|
|
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// unhook from observers we are tangled up in
|
|
void CInterfaceManager::releaseServerToLocalAutoCopyObservers()
|
|
{
|
|
ServerToLocalAutoCopyInventory.release();
|
|
ServerToLocalAutoCopyExchange.release();
|
|
ServerToLocalAutoCopyContextMenu.release();
|
|
ServerToLocalAutoCopySkillPoints.release();
|
|
}
|
|
|
|
void CInterfaceManager::setInGame( bool i )
|
|
{
|
|
_InGame = i;
|
|
CWidgetManager::getInstance()->setIngame( i );
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::resetShardSpecificData()
|
|
{
|
|
_LocalSyncActionCounter= 0;
|
|
CGroupSkills::InhibitSkillUpFX = true;
|
|
CBarManager::getInstance()->resetShardSpecificData();
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->setEquipInvalidation(0, 0);
|
|
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
|
|
if (pGC != NULL)
|
|
pGC->setActive(false);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::destroy ()
|
|
{
|
|
delete _Instance;
|
|
_Instance = NULL;
|
|
}
|
|
|
|
void CInterfaceManager::initLUA()
|
|
{
|
|
CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
|
|
if( parser->isLuaInitialized() )
|
|
return;
|
|
|
|
parser->initLUA();
|
|
|
|
if( !parser->isLuaInitialized() )
|
|
return;
|
|
|
|
CLuaIHMRyzom::RegisterRyzomFunctions( *( CLuaManager::getInstance().getLuaState() ) );
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initLogin()
|
|
{
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
|
|
if (ClientCfg.XMLLoginInterfaceFiles.empty())
|
|
{
|
|
nlinfo("no xml login config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
nldebug("Textures Login Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesLoginInterface.begin(), end = ClientCfg.TexturesLoginInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Login Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesLoginInterfaceDXTC.begin(), end = ClientCfg.TexturesLoginInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Login Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
|
|
parseInterface (ClientCfg.XMLLoginInterfaceFiles, false);
|
|
|
|
CWidgetManager::getInstance()->updateAllLocalisedElements();
|
|
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:login", true);
|
|
|
|
{
|
|
initActions();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitLogin()
|
|
{
|
|
CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
|
|
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:login", false);
|
|
|
|
parser->removeAll();
|
|
reset();
|
|
|
|
CWidgetManager::getInstance()->setPointer( NULL );
|
|
|
|
CInterfaceLink::removeAllLinks();
|
|
|
|
ICDBNode::CTextId textId("UI");
|
|
NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
|
|
|
|
{
|
|
uninitActions();
|
|
}
|
|
|
|
// Close LUA Scripting
|
|
parser->uninitLUA();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initOutGame()
|
|
{
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
if (ClientCfg.SelectCharacter != -1)
|
|
return;
|
|
|
|
{
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->loadSampleBank(false, "ui_outgame");
|
|
CVector initpos ( 0.0f, 0.0f, 0.0f );
|
|
pMixer->setListenerPos(initpos);
|
|
}
|
|
}
|
|
|
|
|
|
//NLMEMORY::CheckHeap (true);
|
|
|
|
if (ClientCfg.XMLOutGameInterfaceFiles.empty())
|
|
{
|
|
nlinfo("no xml outgame config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
nldebug("Textures OutGame Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterface.begin(), end = ClientCfg.TexturesOutGameInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures OutGame Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterfaceDXTC.begin(), end = ClientCfg.TexturesOutGameInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures OutGame Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
|
|
parseInterface (ClientCfg.XMLOutGameInterfaceFiles, false);
|
|
|
|
CWidgetManager::getInstance()->updateAllLocalisedElements();
|
|
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:outgame", true);
|
|
|
|
// if (!ClientCfg.FSHost.empty())
|
|
// {
|
|
// // Hide the Launch Editor button, it works only with a Shard Unifier and web pages
|
|
// CInterfaceElement *elt = getElementFromId("ui:outgame:edit_session_but");
|
|
// elt->setActive(false);
|
|
// }
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initActions();
|
|
}
|
|
//NLMEMORY::CheckHeap (true);
|
|
|
|
// Initialize the web browser
|
|
{
|
|
CGroupHTML *pGH = dynamic_cast<CGroupHTML*>( CWidgetManager::getInstance()->getElementFromId(GROUP_BROWSER));
|
|
|
|
if (pGH)
|
|
{
|
|
pGH->setActive(true);
|
|
pGH->browse(ClientCfg.PatchletUrl.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitOutGame()
|
|
{
|
|
|
|
if (ClientCfg.SelectCharacter != -1)
|
|
return;
|
|
|
|
CWidgetManager::getInstance()->disableModalWindow();
|
|
|
|
//_Database->display("");
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
|
|
CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
|
|
|
|
NLMISC::TTime initStart;
|
|
initStart = ryzomGetLocalTime ();
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->unloadSampleBank("ui_outgame");
|
|
}
|
|
//nlinfo ("%d seconds for uninitOutGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
initStart = ryzomGetLocalTime ();
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:outgame", false);
|
|
|
|
CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
|
|
//nlinfo ("%d seconds for activateMasterGroup", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
parser->removeAll();
|
|
//nlinfo ("%d seconds for removeAll", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
reset();
|
|
//nlinfo ("%d seconds for reset", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
// reset the mouse pointer to avoid invalid pointer access
|
|
CWidgetManager::getInstance()->setPointer( NULL );
|
|
initStart = ryzomGetLocalTime ();
|
|
CInterfaceLink::removeAllLinks();
|
|
//nlinfo ("%d seconds for removeAllLinks", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
ICDBNode::CTextId textId("UI");
|
|
NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
|
|
//nlinfo ("%d seconds for removeNode", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initStart = ryzomGetLocalTime ();
|
|
uninitActions();
|
|
// nlinfo ("%d seconds for uninitActions", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
}
|
|
|
|
// Close LUA Scripting
|
|
parser->uninitLUA();
|
|
|
|
//NLMEMORY::CheckHeap (true);
|
|
}
|
|
|
|
|
|
void badXMLParseMessageBox()
|
|
{
|
|
NL3D::UDriver *driver = CViewRenderer::getInstance()->getDriver();
|
|
NL3D::UDriver::TMessageBoxId ret = driver->systemMessageBox( "Interface XML reading failed!\n"
|
|
"Some XML files are corrupted and may have been removed.\n"
|
|
"Ryzom may need to be restarted to run properly.\n"
|
|
"Would you like to quit now?",
|
|
"XML reading failed!",
|
|
NL3D::UDriver::yesNoType,
|
|
NL3D::UDriver::exclamationIcon);
|
|
if (ret == NL3D::UDriver::yesId)
|
|
{
|
|
extern void quitCrashReport ();
|
|
quitCrashReport ();
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initInGame()
|
|
{
|
|
setLoginFinished( true );
|
|
_LogState = false;
|
|
|
|
// Whole initInGame profile
|
|
NLMISC::TTime initStart;
|
|
initStart = ryzomGetLocalTime ();
|
|
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->loadSampleBank(false, "ui_ingame");
|
|
}
|
|
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
if (ClientCfg.XMLInterfaceFiles.empty())
|
|
{
|
|
nlinfo("no xml config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
// Textures
|
|
loadIngameInterfaceTextures();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
// Skill Manager Init
|
|
CSkillManager *pSM = CSkillManager::getInstance();
|
|
pSM->initInGame();
|
|
|
|
// SBrick Manager Init
|
|
CSBrickManager *pSBM = CSBrickManager::getInstance();
|
|
pSBM->initInGame();
|
|
pSM->initTitles();
|
|
|
|
// SPhrase Manager DB Init (BEFORE loading). Must be init AFTER skill and brick init
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->initInGame();
|
|
|
|
// UI & keys
|
|
loadUI();
|
|
loadKeys();
|
|
|
|
// Initialize armour color (config.xml)
|
|
CDBCtrlSheet::initArmourColors();
|
|
|
|
// Initialize inventory manager : link to DB and to interface element so must be here
|
|
getInventory().init();
|
|
// Same for temp inventory manager
|
|
CTempInvManager::getInstance();
|
|
// Initialize guild manager
|
|
CGuildManager::getInstance();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
//init chat output
|
|
ChatDisplayer = new CChatDisplayer;
|
|
g_log.addDisplayer (ChatDisplayer);
|
|
NLMISC::ErrorLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::WarningLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::InfoLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::DebugLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::AssertLog->addDisplayer (ChatDisplayer);
|
|
|
|
// load bot chat datas
|
|
//CBotChat::init();
|
|
|
|
// init the bot chat
|
|
nlassert (BotChatPageAll == NULL);
|
|
BotChatPageAll = new CBotChatPageAll;
|
|
BotChatPageAll->init();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
// init the list of people
|
|
PeopleInterraction.init();
|
|
|
|
// flush system msg buffer
|
|
for( uint i=0; i<PeopleInterraction.SystemMessageBuffer.size(); ++i )
|
|
{
|
|
displaySystemInfo(PeopleInterraction.SystemMessageBuffer[i].Str, PeopleInterraction.SystemMessageBuffer[i].Cat);
|
|
}
|
|
PeopleInterraction.SystemMessageBuffer.clear();
|
|
|
|
// Init macro manager
|
|
CMacroCmdManager::getInstance()->initInGame();
|
|
|
|
{
|
|
H_AUTO( RZUpdAll )
|
|
|
|
CWidgetManager::getInstance()->updateAllLocalisedElements(); // To init all things
|
|
}
|
|
|
|
// Interface config
|
|
loadInterfaceConfig();
|
|
|
|
// Must do extra init for people interaction after load
|
|
PeopleInterraction.initAfterLoad();
|
|
|
|
//CBotChatUI::refreshActiveWindows(); // bot chat windows are saved too..
|
|
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:interface", true);
|
|
|
|
// Update the time in the ui database
|
|
_CheckMailNode = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MAIL_WAITING");
|
|
_CheckForumNode = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:FORUM_UPDATED");
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initActions();
|
|
}
|
|
setInGame( true );
|
|
|
|
// Init bubble manager
|
|
InSceneBubbleManager.init();
|
|
|
|
// Init Memory Bar for phraseManager. DB and ctrl gray state
|
|
pPM->updateMemoryBar();
|
|
|
|
// Init emotes
|
|
_EmotesInitialized = false;
|
|
initEmotes();
|
|
|
|
// init chat manager
|
|
ChatMngr.initInGame();
|
|
|
|
// Init FlyingText manager
|
|
FlyingTextManager.initInGame();
|
|
|
|
// Init Bar Manager (HP, SAP etc... Bars)
|
|
CBarManager::getInstance()->initInGame();
|
|
|
|
// Init interface props linked to client time
|
|
initClientTime();
|
|
|
|
// Whole initInGame profile
|
|
nlinfo ("%d seconds for initInGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
// reset the compass target
|
|
CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass"));
|
|
if (gc && gc->isSavedTargetValid())
|
|
{
|
|
gc->setTarget(gc->getSavedTarget());
|
|
}
|
|
|
|
CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHATLOG_STATE", false);
|
|
if (node)
|
|
{
|
|
_LogState = (node->getValue32() != 0);
|
|
}
|
|
|
|
if (_LogState)
|
|
{
|
|
displaySystemInfo(CI18N::get("uiLogTurnedOn"));
|
|
}
|
|
else
|
|
{
|
|
displaySystemInfo(CI18N::get("uiLogTurnedOff"));
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadIngameInterfaceTextures()
|
|
{
|
|
nldebug("Textures Ingame Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesInterface.begin(), end = ClientCfg.TexturesInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Ingame Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesInterfaceDXTC.begin(), end = ClientCfg.TexturesInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Ingame Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadUI()
|
|
{
|
|
// Copy the array of file to load
|
|
vector<string> xmlFilesToParse = getInGameXMLInterfaceFiles();
|
|
|
|
if (!parseInterface (xmlFilesToParse, false))
|
|
{
|
|
badXMLParseMessageBox();
|
|
}
|
|
|
|
configureQuitDialogBox();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::configureQuitDialogBox()
|
|
{
|
|
// Configure the quit dialog box according to the server
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
string quitDialogMainStr = "ui:interface:quit_dialog";
|
|
string quitDialogStr = quitDialogMainStr + ":indent_middle";
|
|
CInterfaceGroup *quitDlg = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(quitDialogStr));
|
|
if (quitDlg)
|
|
{
|
|
CInterfaceElement *eltRet, *eltQuit, *eltQuitNow;
|
|
eltRet = quitDlg->getElement(quitDialogStr+":return_mainland");
|
|
eltQuit = quitDlg->getElement(quitDialogStr+":ryzom");
|
|
eltQuitNow = quitDlg->getElement(quitDialogStr+":ryzom_now");
|
|
sint buttonDeltaY;
|
|
fromString( CWidgetManager::getInstance()->getParser()->getDefine("quit_button_delta_y"), buttonDeltaY);
|
|
extern R2::TUserRole UserRoleInSession;
|
|
|
|
bool sessionOwner = (R2::getEditor().getMode() != R2::CEditor::NotInitialized && R2::getEditor().getDMC().getEditionModule().isSessionOwner());
|
|
|
|
// Show Launch Editor if not in editor mode
|
|
CInterfaceElement *eltCancel = quitDlg->getElement(quitDialogStr+":cancel");
|
|
CInterfaceElement *eltEdit = quitDlg->getElement(quitDialogStr+":launch_editor");
|
|
if (eltEdit)
|
|
{
|
|
if (UserRoleInSession != R2::TUserRole::ur_editor && !sessionOwner)
|
|
{
|
|
eltEdit->setY(buttonDeltaY);
|
|
eltEdit->setActive(true);
|
|
|
|
if (eltCancel)
|
|
(safe_cast<CCtrlTextButton*>(eltCancel))->setText(CI18N::get("uittQuitCancel"));
|
|
}
|
|
else
|
|
{
|
|
eltEdit->setY(0); // prevent from displaying a gap between two shown buttons
|
|
eltEdit->setActive(false);
|
|
|
|
if (eltCancel)
|
|
(safe_cast<CCtrlTextButton*>(eltCancel))->setText(sessionOwner ? CI18N::get("uittQuitCancel") : CI18N::get("uittQuitCancelEditor"));
|
|
}
|
|
}
|
|
|
|
// Other buttons
|
|
if (IsInRingSession || (ClientCfg.Local && ClientCfg.R2EDEnabled))
|
|
{
|
|
// display "return to mainland", unless we are the scenario owner (player or 'aventure master')
|
|
if (eltRet)
|
|
{
|
|
if (!sessionOwner || R2::getEditor().getMode()==R2::CEditor::EditionMode)
|
|
{
|
|
//eltRet->setY(buttonDeltaY);
|
|
const char *textLabel = (UserRoleInSession == R2::TUserRole::ur_editor) ? "uittLeaveEditor" : "uittReturnToMainland";
|
|
(safe_cast<CCtrlTextButton*>(eltRet))->setText(CI18N::get(textLabel));
|
|
eltRet->setY(buttonDeltaY);
|
|
eltRet->setActive(true); // show Return to Mainland / PLAY
|
|
}
|
|
else
|
|
{
|
|
eltRet->setY(0);
|
|
// when an owner of the session, there's an additionnal 'stop' button
|
|
eltRet->setActive(false);
|
|
}
|
|
}
|
|
if (eltQuit)
|
|
{
|
|
eltQuit->setY(0);
|
|
eltQuit->setActive(false);
|
|
}
|
|
if (eltQuitNow)
|
|
{
|
|
eltQuitNow->setY(buttonDeltaY);
|
|
eltQuitNow->setActive(true); // show Quit (Now)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (eltRet)
|
|
{
|
|
eltRet->setY(0); // prevent from displaying a gap between two shown buttons
|
|
eltRet->setActive(false);
|
|
}
|
|
if (eltQuit)
|
|
{
|
|
eltQuit->setY(buttonDeltaY);
|
|
eltQuit->setActive(true); // show Quit (with progress bar)
|
|
}
|
|
if (eltQuitNow)
|
|
{
|
|
eltQuitNow->setY(0);
|
|
eltQuitNow->setActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make all controls have the same size
|
|
CInterfaceGroup *quitDlgMain = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(quitDialogMainStr));
|
|
if ( quitDlgMain )
|
|
{
|
|
|
|
quitDlgMain->invalidateCoords();
|
|
for (uint k = 0; k < 3; ++k)
|
|
{
|
|
quitDlgMain->updateCoords(); // calculate the width of the text buttons
|
|
}
|
|
}
|
|
const std::vector<CCtrlBase*>& controls = quitDlg->getControls();
|
|
sint32 biggestWidth = 0;
|
|
for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
|
|
{
|
|
CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
|
|
if ( ! ctb )
|
|
continue;
|
|
|
|
if ( ctb->getW() > biggestWidth )
|
|
biggestWidth = ctb->getW();
|
|
}
|
|
for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
|
|
{
|
|
CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
|
|
if ( ! ctb )
|
|
continue;
|
|
|
|
ctb->setWMin( biggestWidth );
|
|
}
|
|
|
|
if ( quitDlgMain )
|
|
{
|
|
|
|
quitDlgMain->invalidateCoords();
|
|
for (uint k = 0; k < 3; ++k)
|
|
{
|
|
quitDlgMain->updateCoords(); // calculate the width of the text buttons
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadKeys()
|
|
{
|
|
if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
|
|
return;
|
|
|
|
CMacroCmdManager::getInstance()->removeAllMacros();
|
|
|
|
vector<string> xmlFilesToParse;
|
|
|
|
// Does the keys file exist ?
|
|
string userKeyFileName = "save/keys_"+PlayerSelectedFileName+".xml";
|
|
if (CFile::fileExists(userKeyFileName) && CFile::getFileSize(userKeyFileName) > 0)
|
|
{
|
|
// Load the user key file
|
|
xmlFilesToParse.push_back (userKeyFileName);
|
|
}
|
|
else
|
|
{
|
|
string filename = "save/shared_keys.xml";
|
|
if(CFile::fileExists(filename) && CFile::getFileSize(filename) > 0)
|
|
{
|
|
xmlFilesToParse.push_back(filename);
|
|
}
|
|
}
|
|
// Load the default key (but don't replace existings bounds, see keys.xml "key_def_no_replace")
|
|
xmlFilesToParse.push_back ("keys.xml");
|
|
|
|
if (!parseInterface (xmlFilesToParse, true))
|
|
{
|
|
badXMLParseMessageBox();
|
|
}
|
|
|
|
_KeysLoaded = true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadInterfaceConfig()
|
|
{
|
|
// Load interface.cfg
|
|
if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
|
|
return;
|
|
|
|
string filename = "save/interface_" + PlayerSelectedFileName + ".icfg";
|
|
if (!CFile::fileExists(filename))
|
|
filename = "save/shared_interface.icfg";
|
|
|
|
loadConfig(filename); // Invalidate coords of changed groups
|
|
|
|
_ConfigLoaded = true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitInGame0 ()
|
|
{
|
|
|
|
// Autosave of the keys
|
|
if (_KeysLoaded)
|
|
{
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
string filename = "save/keys_" + PlayerSelectedFileName + ".xml";
|
|
if (!CFile::fileExists(filename) && CFile::fileExists("save/shared_keys.xml"))
|
|
filename = "save/shared_keys.xml";
|
|
|
|
saveKeys(filename);
|
|
}
|
|
_KeysLoaded = false;
|
|
}
|
|
|
|
// Autosave of the interface in interface.cfg
|
|
if (_ConfigLoaded)
|
|
{
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
string filename = "save/interface_" + PlayerSelectedFileName + ".icfg";
|
|
if (!CFile::fileExists(filename) && CFile::fileExists("save/shared_interface.icfg"))
|
|
filename = "save/shared_interface.icfg";
|
|
|
|
saveConfig(filename);
|
|
}
|
|
_ConfigLoaded = false;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitInGame1 ()
|
|
{
|
|
|
|
// release Bar Manager (HP, SAP etc... Bars)
|
|
CBarManager::getInstance()->releaseInGame();
|
|
|
|
// release FlyingTextManager
|
|
FlyingTextManager.releaseInGame();
|
|
|
|
// release chat manager
|
|
ChatMngr.releaseInGame();
|
|
|
|
// Reset the chat text manager
|
|
CChatTextManager::getInstance().reset();
|
|
|
|
// release emotes
|
|
uninitEmotes();
|
|
|
|
// release bubble manager
|
|
InSceneBubbleManager.release();
|
|
|
|
// kill chat displayer
|
|
if( ChatDisplayer )
|
|
{
|
|
DebugLog->removeDisplayer (ChatDisplayer);
|
|
InfoLog->removeDisplayer (ChatDisplayer);
|
|
WarningLog->removeDisplayer (ChatDisplayer);
|
|
ErrorLog->removeDisplayer (ChatDisplayer);
|
|
AssertLog->removeDisplayer (ChatDisplayer);
|
|
g_log.removeDisplayer(ChatDisplayer);
|
|
delete ChatDisplayer;
|
|
ChatDisplayer = NULL;
|
|
}
|
|
|
|
// Release inventory manager
|
|
CInventoryManager::releaseInstance();
|
|
// Same for temp inventory manager
|
|
CTempInvManager::releaseInstance();
|
|
// Release guild manager
|
|
CGuildManager::release();
|
|
|
|
// release bot chat and manager
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
delete BotChatPageAll;
|
|
BotChatPageAll = NULL;
|
|
CBotChatManager::releaseInstance();
|
|
|
|
//release CInterfaceItemEdition
|
|
CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
|
|
CInterfaceItemEdition::releaseInstance();
|
|
|
|
// release task bar manager
|
|
CTaskBarManager::releaseInstance();
|
|
|
|
// People inetrraction release
|
|
PeopleInterraction.release();
|
|
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->unloadSampleBank("ui_ingame");
|
|
}
|
|
|
|
// disable the game_quitting modal window
|
|
CWidgetManager::getInstance()->disableModalWindow();
|
|
|
|
// Remove all interface objects (containers, groups, variables, defines, ...)
|
|
CWidgetManager::getInstance()->activateMasterGroup ("ui:interface", false);
|
|
|
|
CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
|
|
|
|
parser->removeAll();
|
|
reset();
|
|
CInterfaceLink::removeAllLinks();
|
|
|
|
// Release DDX manager, before DB remove
|
|
CDDXManager::getInstance()->release();
|
|
|
|
// Release client time, before DB remove
|
|
releaseClientTime();
|
|
|
|
// remove DB entry
|
|
ICDBNode::CTextId textId("UI");
|
|
NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
|
|
|
|
// Uninit the action manager
|
|
{
|
|
|
|
uninitActions();
|
|
}
|
|
|
|
// uninit phrase mgr
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
pPM->reset();
|
|
CSPhraseManager::releaseInstance(); // must release before BrickManager, SkillManager
|
|
|
|
// uninit brick manager
|
|
// Don't release the instance because must not lost brick map and data
|
|
CSBrickManager::getInstance()->uninitInGame();
|
|
|
|
// Uninit skill manager (after phrase mgr)
|
|
// AJM don't release SkillManager, else impulse msg update guild title will crash :(
|
|
CSkillManager::getInstance()->uninitTitles();
|
|
|
|
// Uninit macro manager
|
|
CMacroCmdManager::getInstance()->uninitInGame();
|
|
|
|
// Release interface help
|
|
CInterfaceHelp::release();
|
|
|
|
// Release guild manager
|
|
CGuildManager::release();
|
|
|
|
// Close LUA Scripting
|
|
parser->uninitLUA();
|
|
|
|
setInGame( false );
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
CWidgetManager::getInstance()->resetColorProps();
|
|
CWidgetManager::getInstance()->resetAlphaRolloverSpeedProps();
|
|
CWidgetManager::getInstance()->resetGlobalAlphasProps();
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
CInterfaceManager::getInstance()->DebugTrackGroupsDump();
|
|
|
|
// NLMEMORY::ReportMemoryLeak();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::flushDebugWindow()
|
|
{
|
|
if (ChatDisplayer != NULL)
|
|
ChatDisplayer->update();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::updateFrameEvents()
|
|
{
|
|
|
|
H_AUTO_USE ( RZ_Client_Update_Frame_Events )
|
|
|
|
flushDebugWindow();
|
|
|
|
// Handle anims done in 2 times because some AH can add or remove anims
|
|
// First ensure we are working on a safe vector and update all anims
|
|
CWidgetManager::getInstance()->updateAnims();
|
|
|
|
IngameDbMngr.flushObserverCalls();
|
|
NLGUI::CDBManager::getInstance()->flushObserverCalls();
|
|
|
|
CWidgetManager::getInstance()->removeFinishedAnims();
|
|
|
|
//
|
|
IngameDbMngr.flushObserverCalls();
|
|
NLGUI::CDBManager::getInstance()->flushObserverCalls();
|
|
|
|
// Handle waiting texts from server
|
|
processServerIDString();
|
|
|
|
if (_InGame)
|
|
{
|
|
// Execute current macro
|
|
CMacroCmdManager::getInstance()->updateMacroExecution();
|
|
|
|
// Update guild handling (check if we have to rebuild)
|
|
CGuildManager::getInstance()->update();
|
|
|
|
// Update contact list with incoming server string ids
|
|
PeopleInterraction.updateWaitingContacts();
|
|
|
|
// Update string if some waiting
|
|
CEncyclopediaManager::getInstance()->updateAllFrame();
|
|
|
|
// Setup the weather setup in the player's map
|
|
if ((T0 - _UpdateWeatherTime) > (1 * 5 * 1000))
|
|
{
|
|
_UpdateWeatherTime = T0;
|
|
ucstring str = CI18N::get ("uiTheSeasonIs") +
|
|
CI18N::get ("uiSeason"+toStringEnum(computeCurrSeason())) +
|
|
CI18N::get ("uiAndTheWeatherIs") +
|
|
CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName);
|
|
|
|
|
|
CViewText *pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:weather"));
|
|
if (pVT != NULL)
|
|
pVT->setText(str);
|
|
|
|
// The date feature is temporarily disabled
|
|
str.clear();
|
|
|
|
// numeric version
|
|
//str = CI18N::get("uiDate");
|
|
//str += toString("%04d", RT.getRyzomYear()) + "/";
|
|
//str += toString("%01d", RT.getRyzomCycle()+1) + " : ";
|
|
//str += toString("%02d", RT.getRyzomMonthInCurrentCycle()+1) + "/";
|
|
//str += toString("%02d", RT.getRyzomDayOfMonth()+1) + " - "; // Start at 1 for January
|
|
//str += toString("%02d", (sint)RT.getRyzomTime()) + " " + CI18N::get("uiMissionTimerHour");
|
|
|
|
// literal version
|
|
// str = CI18N::get("uiDate");
|
|
str += toString("%02d", (sint)RT.getRyzomTime()) + CI18N::get("uiMissionTimerHour") + " - ";
|
|
str += CI18N::get("ui"+WEEKDAY::toString( (WEEKDAY::EWeekDay)RT.getRyzomDayOfWeek() )) + ", ";
|
|
str += CI18N::get("ui"+MONTH::toString( (MONTH::EMonth)RT.getRyzomMonthInCurrentCycle() )) + " ";
|
|
str += toString("%02d", RT.getRyzomDayOfMonth()+1) + ", ";
|
|
str += CI18N::get("uiAtysianCycle" + toString(RT.getRyzomCycle()+1) + "Ordinal") + " " + CI18N::get("uiAtysianCycle") + " ";
|
|
str += toString("%04d", RT.getRyzomYear());
|
|
|
|
pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:time"));
|
|
if (pVT != NULL)
|
|
pVT->setText(str);
|
|
|
|
str.clear();
|
|
// Update the clock in the compass if enabled.
|
|
pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass:clock:time"));
|
|
if (pVT != NULL)
|
|
{
|
|
if (pVT->getActive())
|
|
{
|
|
if (use12hClock())
|
|
str = getTimestampHuman("%I:%M %p");
|
|
else
|
|
str = getTimestampHuman("%H:%M");
|
|
pVT->setText(str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CWidgetManager::getInstance()->sendClockTickEvent();
|
|
|
|
IngameDbMngr.flushObserverCalls();
|
|
NLGUI::CDBManager::getInstance()->flushObserverCalls();
|
|
|
|
// Update SPhrase manager
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->update();
|
|
|
|
// if there's an external lua debugger, update it
|
|
luaDebuggerMainLoop();
|
|
|
|
// handle gc for lua
|
|
CLuaManager::getInstance().getLuaState()->handleGC();
|
|
|
|
CBGDownloaderAccess::getInstance().update();
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::updateFrameViews(NL3D::UCamera camera)
|
|
{
|
|
|
|
H_AUTO ( RZ_Interface_updateFrameViews )
|
|
|
|
if (!camera.empty())
|
|
CViewRenderer::getInstance()->setWorldSpaceFrustum (camera.getFrustum());
|
|
|
|
CWidgetManager::getInstance()->checkCoords();
|
|
drawViews(camera);
|
|
|
|
// The interface manager may change usual Global setup. reset them.
|
|
CViewRenderer::getTextContext()->setShadeColor(CRGBA::Black);
|
|
|
|
}
|
|
|
|
void CInterfaceManager::setupOptions()
|
|
{
|
|
CWidgetManager *wm = CWidgetManager::getInstance();
|
|
wm->setupOptions();
|
|
|
|
// Try to change font if any
|
|
string sFont = wm->getSystemOption( CWidgetManager::OptionFont ).getValStr();
|
|
|
|
if ((!sFont.empty()) && (Driver != NULL))
|
|
resetTextContext(sFont.c_str(), true);
|
|
// Continue to parse the rest of the interface
|
|
|
|
sFont = wm->getSystemOption (CWidgetManager::OptionMonospaceFont).getValStr();
|
|
if ((!sFont.empty()) && (Driver != NULL))
|
|
CViewRenderer::registerFont("monospace", sFont);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::parseInterface (const std::vector<std::string> &xmlFileNames, bool reload, bool isFilename)
|
|
{
|
|
// cache some commonly used db nodes
|
|
_DBB_UI_DUMMY = NLGUI::CDBManager::getInstance()->getDbBranch( "UI:DUMMY" );
|
|
_DB_UI_DUMMY_QUANTITY = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:QUANTITY", true );
|
|
_DB_UI_DUMMY_QUALITY = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:QUALITY", true );
|
|
_DB_UI_DUMMY_SHEET = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:SHEET", true );
|
|
_DB_UI_DUMMY_NAMEID = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:NAMEID", true );
|
|
_DB_UI_DUMMY_ENCHANT = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:ENCHANT", true );
|
|
_DB_UI_DUMMY_SLOT_TYPE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:SLOT_TYPE", true );
|
|
_DB_UI_DUMMY_PHRASE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:PHRASE", true );
|
|
_DB_UI_DUMMY_WORNED = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:WORNED", true );
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:PREREQUISIT_VALID", true );
|
|
_DB_UI_DUMMY_FACTION_TYPE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:FACTION_TYPE", true );
|
|
|
|
_DB_UI_DUMMY_QUANTITY->setValue64(0);
|
|
_DB_UI_DUMMY_QUALITY->setValue64(0);
|
|
_DB_UI_DUMMY_SHEET->setValue64(0);
|
|
_DB_UI_DUMMY_NAMEID->setValue64(0);
|
|
_DB_UI_DUMMY_ENCHANT->setValue64(0);
|
|
_DB_UI_DUMMY_SLOT_TYPE->setValue64(0);
|
|
_DB_UI_DUMMY_PHRASE->setValue64(0);
|
|
_DB_UI_DUMMY_WORNED->setValue64(0);
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID->setValueBool(true);
|
|
_DB_UI_DUMMY_FACTION_TYPE->setValue64(0);
|
|
|
|
return CWidgetManager::getInstance()->getParser()->parseInterface (xmlFileNames, reload, isFilename);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadTextures (const string &textFileName, const string &uvFileName, bool uploadDXTC)
|
|
{
|
|
CViewRenderer::getInstance()->loadTextures (textFileName, uvFileName, uploadDXTC);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::loadConfig (const string &filename)
|
|
{
|
|
// reset the interface
|
|
vector<string> v;
|
|
if (ClientCfg.R2EDEnabled)
|
|
{
|
|
CWidgetManager::getInstance()->runProcedure ("proc_reset_r2ed_interface", NULL, v);
|
|
}
|
|
else
|
|
{
|
|
CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL, v);
|
|
}
|
|
|
|
// By default, consider the reset interface has been set with the current resolution
|
|
{
|
|
uint32 w,h;
|
|
// NB: even if minimzed, getScreenSize() no more return 0 values (return the last setuped screen size)
|
|
CViewRenderer::getInstance()->getScreenSize(w, h);
|
|
// Windows are positioned according to resolution, and we must backup W/H for the system that move windows when the resolution change
|
|
_LastInGameScreenW= w;
|
|
_LastInGameScreenH= h;
|
|
}
|
|
|
|
// if the config file doesn't exist,just quit
|
|
CIFile f;
|
|
string sFileName;
|
|
sFileName = NLMISC::CPath::lookup (filename, false);
|
|
if (sFileName.empty() || !f.open(sFileName))
|
|
return false;
|
|
|
|
|
|
// *** Load the config file
|
|
uint32 nNbMode;
|
|
CInterfaceConfig ic;
|
|
bool lastInGameScreenResLoaded= false;
|
|
try
|
|
{
|
|
sint ver = f.serialVersion(ICFG_STREAM_VERSION);
|
|
|
|
// serial user chats info (serial it before position of windows so that they can be updated properly)
|
|
if (ver >= 1)
|
|
{
|
|
f.serialCheck(NELID("_ICU"));
|
|
if (!PeopleInterraction.loadUserChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user chat saving");
|
|
}
|
|
}
|
|
|
|
// header
|
|
f.serialCheck(NELID("GFCI"));
|
|
f.serial(nNbMode);
|
|
f.serial(_CurrentMode);
|
|
if(ver>=10)
|
|
{
|
|
f.serial(_LastInGameScreenW);
|
|
f.serial(_LastInGameScreenH);
|
|
lastInGameScreenResLoaded= true;
|
|
}
|
|
|
|
// Load All Window configuration of all Modes
|
|
for (uint32 i = 0; i < nNbMode; ++i)
|
|
{
|
|
NLMISC::contReset(_Modes[i]);
|
|
// must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
|
|
// This is because of old system that manipulated desktop image direclty as a mem stream
|
|
CMemStream ms;
|
|
if (!ms.isReading()) ms.invert();
|
|
uint32 length;
|
|
f.serial(length);
|
|
if (length > 0)
|
|
{
|
|
// HACK. if the version is <=2, then the CInterfaceConfig has no serialVersion. append here a 0
|
|
if(ver<=2)
|
|
{
|
|
uint8 *pBuffer = ms.bufferToFill(length+1);
|
|
pBuffer[0]= 0;
|
|
f.serialBuffer(pBuffer+1, length);
|
|
}
|
|
else
|
|
{
|
|
uint8 *pBuffer = ms.bufferToFill(length);
|
|
f.serialBuffer(pBuffer, length);
|
|
}
|
|
}
|
|
ms.seek(0, NLMISC::IStream::begin);
|
|
_Modes[i].serial(ms); // build desktop image from stream
|
|
}
|
|
|
|
// load UI_DB_SAVE_VERSION
|
|
uint32 uiDbSaveVersion= 0; // default to 0 for old version of .icfg
|
|
if(ver>=9)
|
|
{
|
|
f.serial(uiDbSaveVersion);
|
|
}
|
|
|
|
// read database
|
|
ic.streamToDataBase(f, uiDbSaveVersion);
|
|
|
|
|
|
// special for in game: backup last mission because of delayed update
|
|
{
|
|
CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:MISSION_SELECTED", false);
|
|
if (pNL)
|
|
{
|
|
CCDBNodeLeaf *pSelectedMissionBackup = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MISSION_SELECTED_PREV_SESSION", true);
|
|
pSelectedMissionBackup->setValue64(pNL->getValue64());
|
|
}
|
|
}
|
|
//
|
|
|
|
// Deprecated. for Compatibility purpose: Load TaskBar.
|
|
if(ver>=2)
|
|
{
|
|
CTaskBarManager *pTBM= CTaskBarManager::getInstance();
|
|
pTBM->serial(f);
|
|
}
|
|
|
|
// Load user landmarks
|
|
ContinentMngr.serialUserLandMarks(f);
|
|
|
|
CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp( "SERVER:INTERFACES:NB_BONUS_LANDMARKS" );
|
|
if ( pNL )
|
|
{
|
|
ICDBNode::CTextId textId;
|
|
pNL->addObserver( &_LandmarkObs, textId);
|
|
}
|
|
|
|
// Info Windows position.
|
|
if(ver>=5)
|
|
CInterfaceHelp::serialInfoWindows(f);
|
|
else // Default pos
|
|
CInterfaceHelp::resetWindowPos(-100);
|
|
|
|
// Macro On Memory Position
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
if(ver>=7)
|
|
pPM->serialMacroMemory(f);
|
|
|
|
if(ver>=8)
|
|
CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
|
|
|
|
if (ver >= 11)
|
|
{
|
|
if ( ! PeopleInterraction.loadUserDynChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user dyn chat saving");
|
|
}
|
|
}
|
|
}
|
|
catch(const NLMISC::EStream &)
|
|
{
|
|
f.close();
|
|
string sFileNameBackup = sFileName+"backup";
|
|
if (CFile::fileExists(sFileNameBackup))
|
|
CFile::deleteFile(sFileNameBackup);
|
|
CFile::moveFile(sFileNameBackup, sFileName);
|
|
nlwarning("Config loading failed : restore default");
|
|
vector<string> v;
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL, v);
|
|
}
|
|
return false;
|
|
}
|
|
f.close();
|
|
|
|
// *** If saved resolution is different from the current one setuped, must fix positions in _Modes
|
|
if(lastInGameScreenResLoaded)
|
|
{
|
|
// Temporarily set screen to saved size so that positions are correctly calculated
|
|
CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW, _LastInGameScreenH);
|
|
// NB: we are typically InGame here (even though the _InGame flag is not yet set)
|
|
// Use the screen size of the config file. Don't update current UI, just _Modes
|
|
CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(ClientCfg.Width, ClientCfg.Height, false);
|
|
updateDesktops( ClientCfg.Width, ClientCfg.Height );
|
|
}
|
|
|
|
// *** apply the current mode
|
|
_Modes[_CurrentMode].toCurrentDesktop();
|
|
|
|
// *** Apply the NPC icon display mode
|
|
CNPCIconCache::getInstance().init(!ClientCfg.R2EDEnabled && NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CDBLandmarkObs::update(ICDBNode *node)
|
|
{
|
|
ContinentMngr.updateUserLandMarks();
|
|
}
|
|
|
|
|
|
// visitor to send onQuit msg on all element
|
|
class CQuitVisitor : public CInterfaceElementVisitor
|
|
{
|
|
public:
|
|
bool IsR2ED;
|
|
bool BadWindowFound; //
|
|
uint Desktop;
|
|
virtual void visit(CInterfaceElement *elem) { elem->onQuit(); }
|
|
virtual void visitGroup(CInterfaceGroup *group)
|
|
{
|
|
if (!IsR2ED) return;
|
|
if (Desktop != 0) return;
|
|
if (group->getShortId() == "gestionsets")
|
|
{
|
|
if (group->getActive())
|
|
{
|
|
BadWindowFound = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::saveConfig (const string &filename)
|
|
{
|
|
|
|
CQuitVisitor quitVisitor;
|
|
|
|
quitVisitor.IsR2ED = false;
|
|
if (nlstricmp(NLMISC::CFile::getFilename(filename).substr(0, 5), "r2ed_") == 0)
|
|
{
|
|
quitVisitor.IsR2ED = true;
|
|
}
|
|
quitVisitor.BadWindowFound = false;
|
|
|
|
nlinfo( "Saving interface config : %s", filename.c_str() );
|
|
|
|
COFile f;
|
|
|
|
// using temporary file, so no f.close() unless its a success
|
|
if (!f.open(filename, false, false, true)) return false;
|
|
|
|
CInterfaceConfig ic;
|
|
|
|
|
|
|
|
// cleanup all desktops
|
|
for(uint k = 0; k < MAX_NUM_MODES; ++k)
|
|
{
|
|
quitVisitor.Desktop = k;
|
|
setMode(k);
|
|
visit(&quitVisitor);
|
|
CWidgetManager::getInstance()->checkCoords();
|
|
}
|
|
setMode(0);
|
|
setMode(_CurrentMode);
|
|
|
|
if (quitVisitor.BadWindowFound)
|
|
{
|
|
#ifdef NL_DEBUG
|
|
nlassert(0);
|
|
#endif
|
|
// tmp patch : when trying to overwrite the r2ed_ config, if a bad window is found, just do nothing ...
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
_Modes[_CurrentMode].clear();
|
|
if (_Modes[_CurrentMode].isReading()) _Modes[_CurrentMode].invert();
|
|
clearAllEditBox();
|
|
restoreAllContainersBackupPosition();
|
|
ic.interfaceManagerToStream(_Modes[_CurrentMode]);
|
|
*/
|
|
|
|
uint32 i;
|
|
|
|
i = MAX_NUM_MODES;
|
|
try
|
|
{
|
|
f.serialVersion(ICFG_STREAM_VERSION);
|
|
|
|
// serial user chats info (serial it before position of windows so that they can be updated properly)
|
|
f.serialCheck(NELID("_ICU"));
|
|
if (!PeopleInterraction.saveUserChatsInfos(f))
|
|
{
|
|
nlwarning("Config saving failed");
|
|
// couldn't save result so do not continue
|
|
return false;
|
|
}
|
|
|
|
// header
|
|
f.serialCheck(NELID("GFCI"));
|
|
f.serial(i);
|
|
f.serial(_CurrentMode);
|
|
f.serial(_LastInGameScreenW);
|
|
f.serial(_LastInGameScreenH);
|
|
|
|
// Save All Window configuration of all Modes
|
|
for (i = 0; i < MAX_NUM_MODES; ++i)
|
|
{
|
|
// must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
|
|
// This is because of old system that manipulated desktop image direclty as a mem stream
|
|
CMemStream ms;
|
|
if (ms.isReading()) ms.invert();
|
|
_Modes[i].serial(ms);
|
|
uint32 length = ms.length();
|
|
f.serial(length);
|
|
if (length > 0)
|
|
{
|
|
f.serialBuffer(const_cast<uint8 *>(ms.buffer()), length);
|
|
}
|
|
}
|
|
|
|
// write UI_DB_SAVE_VERSION
|
|
uint32 uiDbSaveVersion;
|
|
fromString( CWidgetManager::getInstance()->getParser()->getDefine("UI_DB_SAVE_VERSION"), uiDbSaveVersion);
|
|
f.serial(uiDbSaveVersion);
|
|
|
|
// write database
|
|
ic.dataBaseToStream(f);
|
|
|
|
// Deprecated. for Compatibility purpose: Save TaskBar.
|
|
CTaskBarManager *pTBM= CTaskBarManager::getInstance();
|
|
pTBM->serial(f);
|
|
|
|
// Save user landmarks
|
|
ContinentMngr.serialUserLandMarks(f);
|
|
|
|
// Info Windows position.
|
|
CInterfaceHelp::serialInfoWindows(f);
|
|
|
|
// Macro On Memory Position
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
pPM->serialMacroMemory(f);
|
|
|
|
CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
|
|
|
|
if ( ! PeopleInterraction.saveUserDynChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user dyn chat saving");
|
|
return false;
|
|
}
|
|
|
|
f.close();
|
|
}
|
|
catch(const NLMISC::EStream &)
|
|
{
|
|
nlwarning("Config saving failed.");
|
|
return false;
|
|
}
|
|
|
|
ContinentMngr.serialFOWMaps();
|
|
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::drawViews(NL3D::UCamera camera)
|
|
{
|
|
IngameDbMngr.flushObserverCalls();
|
|
NLGUI::CDBManager::getInstance()->flushObserverCalls();
|
|
|
|
// Update Player characteristics (for Item carac requirement Redifying)
|
|
nlctassert(CHARACTERISTICS::NUM_CHARACTERISTICS==8);
|
|
for (uint i=0; i<CHARACTERISTICS::NUM_CHARACTERISTICS; ++i)
|
|
{
|
|
if (!_CurrentPlayerCharacLeaf[i])
|
|
_CurrentPlayerCharacLeaf[i] = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:CHARACTERISTICS%d:VALUE", i), false);
|
|
|
|
NLMISC::CCDBNodeLeaf *node = NULL;
|
|
|
|
if (_CurrentPlayerCharacLeaf[i])
|
|
node = &*_CurrentPlayerCharacLeaf[i];
|
|
|
|
_CurrentPlayerCharac[i] = node ? node->getValue32() : 0;
|
|
}
|
|
|
|
CWidgetManager::getInstance()->drawViews( camera );
|
|
|
|
// flush obs
|
|
IngameDbMngr.flushObserverCalls();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::handleEvent (const NLGUI::CEventDescriptor& event)
|
|
{
|
|
bool handled = false;
|
|
|
|
handled = CWidgetManager::getInstance()->handleEvent( event );
|
|
|
|
if( event.getType() == NLGUI::CEventDescriptor::mouse )
|
|
{
|
|
NLGUI::CEventDescriptorMouse &eventDesc = (NLGUI::CEventDescriptorMouse&)event;
|
|
|
|
if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup ) && handled )
|
|
{
|
|
// prevent 'click in scene' as mouse was previously captured
|
|
// (more a patch that anything, but 'UserControls' test for 'mouse up'
|
|
// directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
|
|
if( CWidgetManager::getInstance()->getCapturePointerRight() == NULL )
|
|
EventsListener.addUIHandledButtonMask(rightButton);
|
|
}else
|
|
if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup ) && handled )
|
|
{
|
|
// prevent 'click in scene' as mouse was previously captured
|
|
// (more a patch that anything, but 'UserControls' test for 'mouse up'
|
|
// directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
|
|
if( CWidgetManager::getInstance()->getCapturePointerLeft() == NULL )
|
|
EventsListener.addUIHandledButtonMask(leftButton);
|
|
}
|
|
|
|
}
|
|
|
|
IngameDbMngr.flushObserverCalls();
|
|
// event handled?
|
|
return handled;
|
|
}
|
|
|
|
void CInterfaceManager::updateDesktops( uint32 newScreenW, uint32 newScreenH )
|
|
{
|
|
// *** Do it for All Backuped Desktops
|
|
for(uint md=0;md<MAX_NUM_MODES;md++)
|
|
{
|
|
CInterfaceConfig::CDesktopImage &mode= _Modes[md];
|
|
// For all containers of this mode
|
|
for(uint gc=0;gc<mode.GCImages.size();gc++)
|
|
{
|
|
CInterfaceConfig::SCont &gcCont= mode.GCImages[gc];
|
|
// Compute the new coordinate, directly in the X/Y fields of the structure
|
|
CWidgetManager::getInstance()->getNewWindowCoordToNewScreenSize(gcCont.X, gcCont.Y, gcCont.W, gcCont.H ,newScreenW, newScreenH);
|
|
}
|
|
}
|
|
|
|
_LastInGameScreenW = newScreenW;
|
|
_LastInGameScreenH = newScreenH;
|
|
}
|
|
|
|
class InvalidateTextVisitor : public CInterfaceElementVisitor
|
|
{
|
|
public:
|
|
InvalidateTextVisitor( bool reset )
|
|
{
|
|
this->reset = reset;
|
|
}
|
|
|
|
void visitGroup( CInterfaceGroup *group )
|
|
{
|
|
const std::vector< CViewBase* > &vs = group->getViews();
|
|
for( std::vector< CViewBase* >::const_iterator itr = vs.begin(); itr != vs.end(); ++itr )
|
|
{
|
|
CViewText *vt = dynamic_cast< CViewText* >( *itr );
|
|
if( vt != NULL )
|
|
{
|
|
if( reset )
|
|
vt->resetTextIndex();
|
|
vt->updateTextContext();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
bool reset;
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::addServerString (const std::string &sTarget, uint32 id, IStringProcess *cb)
|
|
{
|
|
if (id == 0)
|
|
{
|
|
CInterfaceExprValue val;
|
|
val.setUCString (ucstring(""));
|
|
CInterfaceLink::setTargetProperty (sTarget, val);
|
|
return;
|
|
}
|
|
SIDStringWaiter *pISW = new SIDStringWaiter;
|
|
pISW->Id = id;
|
|
pISW->IdOrString = false;
|
|
pISW->Target = sTarget;
|
|
pISW->Cb = cb;
|
|
_IDStringWaiters.push_back(pISW);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::addServerID (const std::string &sTarget, uint32 id, IStringProcess *cb)
|
|
{
|
|
if (id == 0)
|
|
{
|
|
CInterfaceExprValue val;
|
|
val.setUCString (ucstring(""));
|
|
CInterfaceLink::setTargetProperty (sTarget, val);
|
|
return;
|
|
}
|
|
SIDStringWaiter *pISW = new SIDStringWaiter;
|
|
pISW->Id = id;
|
|
pISW->IdOrString = true;
|
|
pISW->Target = sTarget;
|
|
pISW->Cb = cb;
|
|
_IDStringWaiters.push_back(pISW);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::processServerIDString()
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
|
|
|
|
for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
|
|
{
|
|
bool bAffect = false;
|
|
ucstring ucstrToAffect;
|
|
SIDStringWaiter *pISW = _IDStringWaiters[i];
|
|
if (pISW->IdOrString == true) // ID !
|
|
{
|
|
if (pSMC->getString (pISW->Id, ucstrToAffect))
|
|
bAffect = true;
|
|
}
|
|
else // String !
|
|
{
|
|
if (pSMC->getDynString (pISW->Id, ucstrToAffect))
|
|
bAffect = true;
|
|
}
|
|
|
|
if (bAffect)
|
|
{
|
|
CInterfaceExprValue val;
|
|
bool bValid = true;
|
|
|
|
if (pISW->Cb != NULL)
|
|
{
|
|
bValid = pISW->Cb->cbIDStringReceived(ucstrToAffect);
|
|
delete pISW->Cb;
|
|
}
|
|
|
|
if (bValid)
|
|
{
|
|
val.setUCString (ucstrToAffect);
|
|
CInterfaceLink::setTargetProperty (pISW->Target, val);
|
|
}
|
|
|
|
// Remove entry
|
|
_IDStringWaiters.erase (_IDStringWaiters.begin()+i);
|
|
i--;
|
|
delete pISW;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBoxInternal(const string &msgBoxGroup, const ucstring &text, const string &masterGroup, TCaseMode caseMode)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup));
|
|
CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup + ":text"));
|
|
|
|
if (group && viewText)
|
|
{
|
|
viewText->setCaseMode(caseMode);
|
|
viewText->setText(text);
|
|
CWidgetManager::getInstance()->enableModalWindow(NULL, group);
|
|
// don't understand why but need to update coords here
|
|
group->updateCoords();
|
|
group->updateCoords();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBox(const ucstring &text, const string &masterGroup, TCaseMode caseMode)
|
|
{
|
|
messageBoxInternal("message_box", text, masterGroup, caseMode);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBoxWithHelp(const ucstring &text, const std::string &masterGroup,
|
|
const std::string &ahOnOk, const std::string ¶msOnOk,
|
|
TCaseMode caseMode)
|
|
{
|
|
// replace the procedure "proc_valid_message_box_ok" action
|
|
CWidgetManager::getInstance()->setProcedureAction("proc_message_box_with_help_ok", 1, ahOnOk, paramsOnOk);
|
|
const char *mbName = "message_box_with_help";
|
|
// if no action handler is wanted, then assume that
|
|
// clicking 'ok' do not have any consequence, so allow exiting the message box by clicking
|
|
// outside of it (this behavior is wanted on the login page, to allow to reclick on 'login' without
|
|
// having to click 'ok' in the message box each time)
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + mbName));
|
|
CGroupModal *gm = dynamic_cast<CGroupModal *>(group);
|
|
if (gm)
|
|
{
|
|
gm->ExitClickOut = ahOnOk.empty();
|
|
}
|
|
messageBoxInternal(mbName, text, masterGroup, caseMode);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::validMessageBox(TValidMessageIcon icon, const ucstring &text, const std::string &ahOnOk,
|
|
const std::string ¶msOnOk, const std::string &ahOnCancel, const std::string ¶msOnCancel, const string &masterGroup)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
|
|
CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:text"));
|
|
CViewBitmap *viewBitmap= dynamic_cast<CViewBitmap*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:icon_group:icon"));
|
|
|
|
if (group && viewText)
|
|
{
|
|
// replace the procedure "proc_valid_message_box_ok" action
|
|
CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, paramsOnOk);
|
|
// replace the procedure "proc_valid_message_box_cancel" action
|
|
CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_cancel", 1, ahOnCancel, paramsOnCancel);
|
|
|
|
// set text and icon
|
|
viewText->setText(text);
|
|
if(viewBitmap)
|
|
{
|
|
bool active= true;
|
|
if(icon==QuestionIconMsg)
|
|
viewBitmap->setTexture("brick_default.tga");
|
|
else if(icon==WarningIconMsg)
|
|
viewBitmap->setTexture("W_warning.tga");
|
|
else if(icon==ErrorIconMsg)
|
|
viewBitmap->setTexture("No_Action.tga");
|
|
else
|
|
active= false;
|
|
viewBitmap->setActive(active);
|
|
}
|
|
|
|
// Go
|
|
CWidgetManager::getInstance()->enableModalWindow(NULL, group);
|
|
// don't understand why but need to update coords here
|
|
group->updateCoords();
|
|
group->updateCoords();
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::getCurrentValidMessageBoxOnOk(string &ahOnOk, const std::string &masterGroup)
|
|
{
|
|
// any modal window opened?
|
|
CInterfaceGroup *mw= CWidgetManager::getInstance()->getModalWindow();
|
|
if(!mw)
|
|
return false;
|
|
|
|
// Is this modal window the valid_message_box window?
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
|
|
if(mw==group)
|
|
{
|
|
// Ok, get the current procedure OnOk action
|
|
string dummyParams;
|
|
if( CWidgetManager::getInstance()->getParser()->getProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, dummyParams))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayDebugInfo(const ucstring &str, TSystemInfoMode mode /*=InfoMsg*/)
|
|
{
|
|
if (PeopleInterraction.DebugInfo)
|
|
PeopleInterraction.ChatInput.DebugInfo.displayMessage(str, getDebugInfoColor(mode), 2);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
NLMISC::CRGBA CInterfaceManager::getDebugInfoColor(TSystemInfoMode mode)
|
|
{
|
|
if (_NeutralColor == NULL) // not initialised ?
|
|
{
|
|
#define SYSTEM_INFO_COLOR_DB_PATH "UI:VARIABLES:SYSTEM_INFOS:COLORS"
|
|
_NeutralColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":NEUTRAL");
|
|
_WarningColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":WARNING");
|
|
_ErrorColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":ERROR");
|
|
}
|
|
NLMISC::CRGBA color;
|
|
switch(mode)
|
|
{
|
|
case InfoMsg: color.setPacked(_NeutralColor->getValue32()); break;
|
|
case WarningMsg: color.setPacked(_WarningColor->getValue32()); break;
|
|
case ErrorMsg: color.setPacked(_ErrorColor->getValue32()); break;
|
|
default:
|
|
color = CRGBA::White;
|
|
break;
|
|
}
|
|
return color;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displaySystemInfo(const ucstring &str, const string &cat)
|
|
{
|
|
CClientConfig::SSysInfoParam::TMode mode = CClientConfig::SSysInfoParam::Normal;
|
|
CRGBA color = CRGBA::White;
|
|
|
|
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLower(cat));
|
|
if (it != ClientCfg.SystemInfoParams.end())
|
|
{
|
|
mode = it->second.Mode;
|
|
color = it->second.Color;
|
|
}
|
|
|
|
if (mode != CClientConfig::SSysInfoParam::OverOnly && mode != CClientConfig::SSysInfoParam::Around)
|
|
{
|
|
if (PeopleInterraction.SystemInfo)
|
|
PeopleInterraction.ChatInput.SystemInfo.displayMessage(str, color, 2);
|
|
else
|
|
{
|
|
CPeopleInterraction::CSysMsg sysMsg;
|
|
sysMsg.Str = str;
|
|
sysMsg.Cat = cat;
|
|
PeopleInterraction.SystemMessageBuffer.push_back( sysMsg );
|
|
}
|
|
}
|
|
|
|
if (mode == CClientConfig::SSysInfoParam::Center || mode == CClientConfig::SSysInfoParam::CenterAround)
|
|
InSceneBubbleManager.addMessagePopupCenter(str, color);
|
|
|
|
// If over popup a string at the bottom of the screen
|
|
if ((mode == CClientConfig::SSysInfoParam::Over) || (mode == CClientConfig::SSysInfoParam::OverOnly))
|
|
InSceneBubbleManager.addMessagePopup(str, color);
|
|
else if ( (mode == CClientConfig::SSysInfoParam::Around || mode == CClientConfig::SSysInfoParam::CenterAround)
|
|
&& PeopleInterraction.AroundMe.Window)
|
|
PeopleInterraction.ChatInput.AroundMe.displayMessage(str, color, 2);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CRGBA CInterfaceManager::getSystemInfoColor(const std::string &cat)
|
|
{
|
|
CRGBA col = CRGBA::White;
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLower(cat));
|
|
if (it != ClientCfg.SystemInfoParams.end())
|
|
col = it->second.Color;
|
|
return col;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::launchContextMenuInGame (const std::string &nameOfCM)
|
|
{
|
|
// Launch the context menu in-game: can't appear while dragging an item
|
|
if (CCtrlDraggable::getDraggedSheet() == NULL)
|
|
{
|
|
if ( !CWidgetManager::getInstance()->hasModal() )
|
|
{
|
|
// We must be in-game !
|
|
CInterfaceGroup *pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:interface");
|
|
// TMP nico : try with login screen:
|
|
if (!pMG)
|
|
{
|
|
pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:login");
|
|
}
|
|
if (!pMG)
|
|
{
|
|
pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:outgame");
|
|
}
|
|
if ((pMG != NULL) && (pMG->getActive()))
|
|
{
|
|
CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(nameOfCM);
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pIE);
|
|
if (pIG != NULL)
|
|
{
|
|
CWidgetManager::getInstance()->enableModalWindow (NULL, pIG);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::updateGroupContainerImage(CGroupContainer &gc, uint8 mode)
|
|
{
|
|
if (mode >= MAX_NUM_MODES)
|
|
{
|
|
nlwarning("wrong desktop");
|
|
return;
|
|
}
|
|
_Modes[mode].updateGroupContainerImage(gc);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::removeGroupContainerImage(const std::string &groupName, uint8 mode)
|
|
{
|
|
if (mode >= MAX_NUM_MODES)
|
|
{
|
|
nlwarning("wrong desktop");
|
|
return;
|
|
}
|
|
_Modes[mode].removeGroupContainerImage(groupName);
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setMode(uint8 newMode)
|
|
{
|
|
if (newMode >= MAX_NUM_MODES)
|
|
return;
|
|
|
|
if (newMode == _CurrentMode)
|
|
return;
|
|
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
|
|
// Check if we can change vdesk !
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end(); itw++)
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(*itw);
|
|
if ((pGC != NULL)&&(pGC->getActive()))
|
|
{
|
|
// if this GC is a Full modal window, or if it is a modal son of another GC,
|
|
if (pGC->isModal() || pGC->isModalSon())
|
|
{
|
|
CWidgetManager::getInstance()->setTopWindow(pGC);
|
|
pGC->enableBlink(2);
|
|
return;
|
|
}
|
|
else
|
|
if (pGC->isGrayed())
|
|
{
|
|
// Make the corresponding child blink
|
|
pGC->blinkAllSons();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if there's a special behaviour with current captured ctrl that prevent from changing desktop
|
|
if ( CWidgetManager::getInstance()->getCapturePointerLeft() != NULL)
|
|
{
|
|
if (!CWidgetManager::getInstance()->getCapturePointerLeft()->canChangeVirtualDesktop()) return;
|
|
}
|
|
if ( CWidgetManager::getInstance()->getCapturePointerRight() != NULL)
|
|
{
|
|
if (!CWidgetManager::getInstance()->getCapturePointerRight()->canChangeVirtualDesktop()) return;
|
|
}
|
|
|
|
|
|
_Modes[_CurrentMode].fromCurrentDesktop();
|
|
_Modes[newMode].toCurrentDesktop();
|
|
//CBotChatUI::refreshActiveWindows();
|
|
|
|
_CurrentMode = newMode;
|
|
CWidgetManager::getInstance()->checkCoords();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::resetMode(uint8 newMode)
|
|
{
|
|
if (newMode >= MAX_NUM_MODES)
|
|
return;
|
|
NLMISC::contReset(_Modes[newMode]);
|
|
}
|
|
|
|
|
|
// for dump of interface content
|
|
struct CDumpedGroup
|
|
{
|
|
CInterfaceGroup *Group;
|
|
uint Depth; // depth in the tree
|
|
};
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpUI(bool /* indent */)
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
std::vector<CDumpedGroup> left;
|
|
left.resize(_MasterGroups.size());
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
left[nMasterGroup].Group = _MasterGroups[nMasterGroup].Group;
|
|
left[nMasterGroup].Depth = 0;
|
|
}
|
|
|
|
while (!left.empty())
|
|
{
|
|
CInterfaceGroup *ig = left.back().Group;
|
|
if (ig)
|
|
{
|
|
uint currDepth = left.back().Depth;
|
|
std::string id = ig->getId();
|
|
std::string::size_type pos = id.find_last_of(':');
|
|
if (pos != std::string::npos)
|
|
{
|
|
id = id.substr(pos + 1);
|
|
}
|
|
std::string info(currDepth * 4, ' ');
|
|
info += id;
|
|
info += toString(", address=0x%p", ig);
|
|
nlinfo(info.c_str());
|
|
// dump view & controls for this group
|
|
for(uint k = 0; k < ig->getViews().size(); ++k)
|
|
{
|
|
std::string info(currDepth * 4, ' ');
|
|
info += toString("View %d / %d : ", (int) k + 1, (int) ig->getViews().size());
|
|
if (ig->getViews()[k])
|
|
{
|
|
info += id;
|
|
NLGUI::CViewBase *view = ig->getViews()[k];
|
|
info += toString(", type = %s, address=0x%p", typeid(*view).name(), view);
|
|
}
|
|
else
|
|
{
|
|
info += "<NULL>";
|
|
}
|
|
nlinfo(info.c_str());
|
|
}
|
|
//
|
|
for(uint k = 0; k < ig->getControls().size(); ++k)
|
|
{
|
|
std::string info(currDepth * 4, ' ');
|
|
info += toString("Ctrl %d / %d : ", (int) k + 1, (int) ig->getControls().size());
|
|
if (ig->getControls()[k])
|
|
{
|
|
info += id;
|
|
NLGUI::CCtrlBase *control = ig->getControls()[k];
|
|
info += toString(", type = %s, address=0x%p", typeid(*control).name(), control);
|
|
}
|
|
else
|
|
{
|
|
info += "<NULL>";
|
|
}
|
|
nlinfo(info.c_str());
|
|
}
|
|
|
|
//
|
|
left.pop_back();
|
|
|
|
for(uint k = 0; k < ig->getNumGroup(); ++k)
|
|
{
|
|
CDumpedGroup dg;
|
|
dg.Group = ig->getGroup(k);
|
|
dg.Depth = currDepth + 1;
|
|
left.push_back(dg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUIViewBBoxs(const std::string &uiFilter)
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderView, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUICtrlBBoxs(const std::string &uiFilter)
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderCtrl, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUIGroupBBoxs(const std::string &uiFilter)
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderGroup, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void writeComboActionMap (const CActionsManager &actions, xmlNodePtr node, const string &context)
|
|
{
|
|
// Get the combo defined
|
|
const CActionsManager::TComboActionMap &combos = actions.getComboActionMap ();
|
|
CActionsManager::TComboActionMap::const_iterator ite = combos.begin ();
|
|
while (ite != combos.end ())
|
|
{
|
|
// Key node
|
|
xmlNodePtr keyNode = xmlNewChild ( node, NULL, (const xmlChar*)"key", NULL );
|
|
|
|
// Props
|
|
xmlSetProp (keyNode, (const xmlChar*)"name", (const xmlChar*)CEventKey::getStringFromKey(ite->first.Key).c_str());
|
|
|
|
if (ite->first.KeyButtons&shiftKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"shift", (const xmlChar*)"1");
|
|
if (ite->first.KeyButtons&ctrlKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"ctrl", (const xmlChar*)"1");
|
|
if (ite->first.KeyButtons&altKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"menu", (const xmlChar*)"1");
|
|
|
|
xmlSetProp (keyNode, (const xmlChar*)"action", (const xmlChar*)ite->second.Name.c_str());
|
|
if (!(const xmlChar*)ite->second.Argu.empty())
|
|
xmlSetProp (keyNode, (const xmlChar*)"params", (const xmlChar*)ite->second.Argu.c_str());
|
|
|
|
// Context
|
|
if (!context.empty ())
|
|
xmlSetProp (keyNode, (const xmlChar*)"context", (const xmlChar*)context.c_str());
|
|
|
|
ite++;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void writeMacros (xmlNodePtr node)
|
|
{
|
|
const std::vector<CMacroCmd> ¯os = CMacroCmdManager::getInstance()->getMacros();
|
|
for (uint i = 0; i < macros.size(); ++i)
|
|
{
|
|
macros[i].writeTo(node);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CInterfaceManager::saveKeys(const std::string &filename)
|
|
{
|
|
bool ret = false;
|
|
|
|
try
|
|
{
|
|
COFile file;
|
|
// using temporary file, so no file.close() unless its a success
|
|
if (file.open (filename, false, false, true))
|
|
{
|
|
COXml xmlStream;
|
|
xmlStream.init (&file);
|
|
|
|
xmlDocPtr doc = xmlStream.getDocument ();
|
|
xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
|
|
xmlDocSetRootElement (doc, node);
|
|
|
|
writeComboActionMap (Actions, node, "");
|
|
writeComboActionMap (EditActions, node, RZ_CATEGORY_EDIT);
|
|
|
|
writeMacros (node);
|
|
|
|
// Flush the stream
|
|
xmlStream.flush();
|
|
|
|
// Close the stream
|
|
file.close ();
|
|
|
|
// Done
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
nlwarning ("Can't open the file %s", filename.c_str());
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
nlwarning ("Error while writing the file %s : %s.", filename.c_str(), e.what ());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::deletePlayerConfig (const std::string &playerFileIdent)
|
|
{
|
|
string fileName= "save/interface_" + playerFileIdent + ".icfg";
|
|
return CFile::deleteFile(fileName);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::deletePlayerKeys (const std::string &playerFileIdent)
|
|
{
|
|
string fileName = "save/keys_"+playerFileIdent+".xml";
|
|
string fileNameEditor = "save/keys_r2ed_"+playerFileIdent+".xml";
|
|
return CFile::deleteFile(fileName) && CFile::deleteFile(fileNameEditor);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::log(const ucstring &str, const std::string &cat)
|
|
{
|
|
if (_LogState)
|
|
{
|
|
// Open file with the name of the player
|
|
const string fileName= "save/log_" + PlayerSelectedFileName + ".txt";
|
|
FILE *f = nlfopen(fileName, "at");
|
|
if (f != NULL)
|
|
{
|
|
const string finalString = string(NLMISC::IDisplayer::dateToHumanString()) + " (" + NLMISC::toUpper(cat) + ") * " + str.toUtf8();
|
|
fprintf(f, "%s\n", finalString.c_str());
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::clearAllEditBox()
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
CInterfaceGroup *pIG = *it;
|
|
if (pIG != NULL)
|
|
pIG->clearAllEditBox();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::restoreAllContainersBackupPosition()
|
|
{
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->restoreAllContainersBackupPosition();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::visit(CInterfaceElementVisitor *visitor)
|
|
{
|
|
nlassert(visitor);
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
if (_MasterGroups[nMasterGroup].Group)
|
|
{
|
|
_MasterGroups[nMasterGroup].Group->visit(visitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::incLocalSyncActionCounter()
|
|
{
|
|
_LocalSyncActionCounter++;
|
|
}
|
|
|
|
|
|
|
|
#if !FINAL_VERSION
|
|
|
|
// ***************************************************************************
|
|
NLMISC_COMMAND( localCounter, "Get value of local counter", "" )
|
|
{
|
|
if (args.size() != 0) return false;
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
im->displaySystemInfo(ucstring(toString(im->getLocalSyncActionCounter())));
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
// ***************************************************************************
|
|
|
|
NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
|
|
{
|
|
if (args.size() != 1)
|
|
return false;
|
|
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
|
|
std::vector<std::string> xmlFileNames;
|
|
|
|
if (args[0] == "all")
|
|
xmlFileNames = CInterfaceManager::getInGameXMLInterfaceFiles();
|
|
else
|
|
xmlFileNames.push_back (args[0]);
|
|
|
|
bool result = im->parseInterface (xmlFileNames, true);
|
|
#if !FINAL_VERSION
|
|
if (result)
|
|
CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" loaded successfully.");
|
|
else
|
|
CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" NOT loaded successully.");
|
|
#endif
|
|
|
|
// Invalidate the texts
|
|
CWidgetManager::getInstance()->updateAllLocalisedElements();
|
|
|
|
// reset captures
|
|
CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
|
|
CWidgetManager::getInstance()->setCapturePointerRight(NULL);
|
|
CWidgetManager::getInstance()->setOldCaptureKeyboard(NULL);
|
|
CWidgetManager::getInstance()->setCaptureKeyboard(NULL);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayWebWindow(const string & name, const string & url)
|
|
{
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(name));
|
|
if (pIG != NULL)
|
|
{
|
|
pIG->setActive(true);
|
|
pIG->updateCoords();
|
|
pIG->center();
|
|
}
|
|
|
|
CAHManager::getInstance()->runActionHandler("browse", NULL, "name="+name+":content:html|url="+url);
|
|
}
|
|
/*
|
|
// ***************************************************************************
|
|
class CHandlerDispWebOnQuit : public IActionHandler
|
|
{
|
|
virtual void execute (CCtrlBase *pCaller, const string &Params)
|
|
{
|
|
if (ClientCfg.Local)
|
|
CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, "group=ui:interface:quit_dialog");
|
|
else
|
|
CInterfaceManager::getInstance()->displayWebWindow("ui:interface:web_on_quit", "http://213.208.119.190/igpoll/poll_form.php");
|
|
}
|
|
};
|
|
REGISTER_ACTION_HANDLER (CHandlerDispWebOnQuit, "disp_web_on_quit");
|
|
|
|
// ***************************************************************************
|
|
class CHandlerExitWebOnQuit : public IActionHandler
|
|
{
|
|
virtual void execute (CCtrlBase *pCaller, const string &Params)
|
|
{
|
|
CAHManager::getInstance()->runActionHandler("quit_ryzom", pCaller);
|
|
}
|
|
};
|
|
REGISTER_ACTION_HANDLER (CHandlerExitWebOnQuit, "exit_web_on_quit");
|
|
*/
|
|
|
|
// ***************************************************************************
|
|
// EMOTES
|
|
// ***************************************************************************
|
|
|
|
struct CEmoteEntry
|
|
{
|
|
uint32 EmoteId;
|
|
string Path;
|
|
string Anim;
|
|
bool UsableFromClientUI;
|
|
|
|
bool operator< (const CEmoteEntry & entry) const
|
|
{
|
|
string path1 = Path;
|
|
string path2 = entry.Path;
|
|
|
|
for(;;)
|
|
{
|
|
string::size_type pos1 = path1.find('|');
|
|
string::size_type pos2 = path2.find('|');
|
|
|
|
ucstring s1 = toUpper(CI18N::get(path1.substr(0, pos1)));
|
|
ucstring s2 = toUpper(CI18N::get(path2.substr(0, pos2)));
|
|
|
|
sint result = s1.compare(s2);
|
|
if (result != 0)
|
|
return (result < 0);
|
|
|
|
if (pos1 == string::npos)
|
|
return (pos2 != string::npos);
|
|
if (pos2 == string::npos)
|
|
return false;
|
|
|
|
path1 = path1.substr(pos1 + 1);
|
|
path2 = path2.substr(pos2 + 1);
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
static bool translateEmote(const std::string &id, ucstring &translatedName, std::string &commandName, std::string &commandNameAlt)
|
|
{
|
|
if (CI18N::hasTranslation(id))
|
|
{
|
|
translatedName = CI18N::get(id);
|
|
|
|
// convert command to utf8 since emote translation can have strange chars
|
|
commandName = toLower(translatedName).toUtf8();
|
|
|
|
// replace all spaces by _
|
|
while (strFindReplace(commandName, " ", "_"));
|
|
|
|
// TODO: remove accents
|
|
commandNameAlt = commandName;
|
|
|
|
if (commandNameAlt == commandName) commandNameAlt.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
translatedName = id;
|
|
commandName = id;
|
|
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::initEmotes()
|
|
{
|
|
_EmotesInitialized = true;
|
|
CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
|
|
if (pTELS == NULL)
|
|
return;
|
|
|
|
static list<CEmoteEntry> entries;
|
|
if (entries.empty())
|
|
{
|
|
for (uint i = 0; i < pTELS->TextEmotList.size(); i++)
|
|
{
|
|
CEmoteEntry entry;
|
|
entry.EmoteId = i;
|
|
entry.Path = pTELS->TextEmotList[i].Path;
|
|
entry.Anim = pTELS->TextEmotList[i].Anim;
|
|
entry.UsableFromClientUI = pTELS->TextEmotList[i].UsableFromClientUI;
|
|
entries.push_back(entry);
|
|
}
|
|
entries.sort();
|
|
}
|
|
|
|
// The list of behaviour missnames emotList
|
|
CEmotListSheet *pEmotList = dynamic_cast<CEmotListSheet*>(SheetMngr.get(CSheetId("list.emot")));
|
|
nlassert (pEmotList != NULL);
|
|
nlassert (pEmotList->Emots.size() <= 255);
|
|
|
|
// Get the focus beta tester flag
|
|
bool betaTester = false;
|
|
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CSkillManager *pSM = CSkillManager::getInstance();
|
|
|
|
betaTester = pSM->isTitleUnblocked(CHARACTER_TITLE::FBT);
|
|
string previousMind;
|
|
CGroupSubMenu *pFirstMenu = 0;
|
|
|
|
for (list<CEmoteEntry>::const_iterator it = entries.begin(); it != entries.end(); it++)
|
|
{
|
|
uint32 nEmoteNb = (*it).EmoteId;
|
|
string sState = (*it).Anim;
|
|
string sName = (*it).Path;
|
|
|
|
// Check that the emote can be added to UI
|
|
// ---------------------------------------
|
|
if( (*it).UsableFromClientUI == false )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check the emote reserved for FBT (hardcoded)
|
|
// --------------------------------------------
|
|
if (sState == "FBT" && !betaTester)
|
|
continue;
|
|
|
|
// Get the behaviour from the list of emotes
|
|
// -----------------------------------------
|
|
uint8 nBehav = 255;
|
|
uint32 i, j;
|
|
for (i = 0; i < pEmotList->Emots.size(); ++i)
|
|
if (CAnimationStateSheet::getAnimationStateName(pEmotList->Emots[i]) == sState)
|
|
{
|
|
nBehav = (uint8)i;
|
|
break;
|
|
}
|
|
|
|
// Add to the game context menu
|
|
// ----------------------------
|
|
uint32 nbToken = 1;
|
|
for (i = 0; i < sName.size(); ++i)
|
|
if (sName[i] == '|')
|
|
nbToken++;
|
|
|
|
CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_emote_menu"));
|
|
nlassert(pRootMenu);
|
|
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
nlassert(pMenu);
|
|
|
|
ucstring sTranslatedName;
|
|
std::string sCommandName;
|
|
std::string sCommandNameAlt;
|
|
|
|
// Add to the game context menu
|
|
// ----------------------------
|
|
for (i = 0; i < nbToken; ++i)
|
|
{
|
|
string sTmp;
|
|
if (i != (nbToken-1))
|
|
sTmp = sName.substr(0,sName.find('|'));
|
|
else
|
|
sTmp = sName;
|
|
|
|
// Look if this part of the path is already present
|
|
bool bFound = false;
|
|
for (j = 0; j < pMenu->getNumLine(); ++j)
|
|
{
|
|
if (sTmp == pMenu->getLineId(j))
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (!bFound) // Create it
|
|
{
|
|
if (i != (nbToken-1))
|
|
{
|
|
pMenu->addLine (CI18N::get(sTmp), "", "", sTmp);
|
|
|
|
// Create a sub menu
|
|
CGroupSubMenu *pNewSubMenu = new CGroupSubMenu(CViewBase::TCtorParam());
|
|
pMenu->setSubMenu(j, pNewSubMenu);
|
|
|
|
if (pFirstMenu == 0)
|
|
pFirstMenu = pNewSubMenu;
|
|
}
|
|
else
|
|
{
|
|
translateEmote(sTmp, sTranslatedName, sCommandName, sCommandNameAlt);
|
|
|
|
// Create a line
|
|
pMenu->addLine (sTranslatedName + " (/" + ucstring::makeFromUtf8(sCommandName) + ")", "emote",
|
|
"nb="+toString(nEmoteNb)+"|behav="+toString(nBehav), sTmp);
|
|
}
|
|
}
|
|
|
|
// Jump to sub menu
|
|
if (i != (nbToken-1))
|
|
{
|
|
pMenu = pMenu->getSubMenu(j);
|
|
sName = sName.substr(sName.find('|')+1,sName.size());
|
|
}
|
|
}
|
|
|
|
if (sTranslatedName.empty())
|
|
translateEmote(sName, sTranslatedName, sCommandName, sCommandNameAlt);
|
|
|
|
// Create new command
|
|
// ------------------
|
|
if (!sTranslatedName.empty())
|
|
{
|
|
if(ICommand::exists(sCommandName))
|
|
{
|
|
nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
|
|
}
|
|
else
|
|
{
|
|
CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandName.c_str(), "", "");
|
|
pNewCmd->EmoteNb = nEmoteNb;
|
|
pNewCmd->Behaviour = nBehav;
|
|
_EmoteCmds.push_back(pNewCmd);
|
|
|
|
// add alternative command if defined
|
|
if (!sCommandNameAlt.empty())
|
|
{
|
|
if(ICommand::exists(sCommandNameAlt))
|
|
{
|
|
nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
|
|
}
|
|
else
|
|
{
|
|
CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandNameAlt.c_str(), "", "");
|
|
pNewCmd->EmoteNb = nEmoteNb;
|
|
pNewCmd->Behaviour = nBehav;
|
|
_EmoteCmds.push_back(pNewCmd);
|
|
}
|
|
}
|
|
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
|
|
// Quick-Emote too ?
|
|
for (i = 0; i< pMenu->getNumLine (); i++)
|
|
{
|
|
if (sName == pMenu->getLineId (i))
|
|
{
|
|
// Yeah that's a quick emote too; set command
|
|
pMenu->addLineAtIndex (i,
|
|
"@{FFFF}/" + ucstring::makeFromUtf8(sCommandName),
|
|
"emote", "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav),
|
|
"", "", "", false, false, true);
|
|
|
|
pMenu->removeLine (i+1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("No translation for emote %s", sName.c_str());
|
|
}
|
|
}
|
|
|
|
// Insert separators
|
|
if (pFirstMenu)
|
|
{
|
|
pFirstMenu->addSeparatorAtIndex (0, "Positive");
|
|
pFirstMenu->addSeparatorAtIndex (4, "Neutral");
|
|
pFirstMenu->addSeparatorAtIndex (8, "Negative");
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::uninitEmotes()
|
|
{
|
|
if( !_EmotesInitialized )
|
|
return;
|
|
_EmotesInitialized = false;
|
|
|
|
// reset the emotes menu
|
|
CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
|
|
if (pTELS != NULL && pTELS->TextEmotList.size() > 0)
|
|
{
|
|
// get the emotes menu id
|
|
string sPath = pTELS->TextEmotList[0].Path;
|
|
string sId = sPath.substr(0, sPath.find('|'));
|
|
|
|
// get the emotes menu
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:game_context_menu"));
|
|
if( pRootMenu )
|
|
{
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
for (uint i = 0; i < pMenu->getNumLine(); ++i)
|
|
{
|
|
if (pMenu->getLineId(i) == sId)
|
|
{
|
|
pMenu = pMenu->getSubMenu(i);
|
|
pMenu->reset();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear commands
|
|
for (uint32 i = 0; i < _EmoteCmds.size(); ++i)
|
|
delete _EmoteCmds[i];
|
|
_EmoteCmds.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::updateEmotes()
|
|
{
|
|
uninitEmotes();
|
|
initEmotes();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Just call the action handler with good params
|
|
bool CInterfaceManager::CEmoteCmd::execute(const std::string &/* rawCommandString */, const vector<string> &args, CLog &/* log */, bool /* quiet */, bool /* human */)
|
|
{
|
|
string customPhrase;
|
|
if( args.size() > 0 )
|
|
{
|
|
customPhrase = args[0];
|
|
}
|
|
for(uint i = 1; i < args.size(); ++i )
|
|
{
|
|
customPhrase += " ";
|
|
customPhrase += args[i];
|
|
}
|
|
CAHManager::getInstance()->runActionHandler("emote", NULL, "nb="+toString(EmoteNb)+"|behav="+toString(Behaviour)+"|custom_phrase="+customPhrase);
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::testDragCopyKey()
|
|
{
|
|
// hardcoded for now
|
|
return Driver->AsyncListener.isKeyDown(KeyCONTROL) ||
|
|
Driver->AsyncListener.isKeyDown(KeyLCONTROL) ||
|
|
Driver->AsyncListener.isKeyDown(KeyRCONTROL);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::notifyMailAvailable()
|
|
{
|
|
if (_CheckMailNode != NULL)
|
|
_CheckMailNode->setValue32(1);
|
|
}
|
|
|
|
void CInterfaceManager::notifyForumUpdated()
|
|
{
|
|
if (_CheckForumNode != NULL)
|
|
_CheckForumNode->setValue32(1);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::resetTextIndex()
|
|
{
|
|
uint32 nMasterGroup;
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
|
|
InvalidateTextVisitor inv( true );
|
|
rMG.Group->visitGroupAndChildren( &inv );
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw != rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
pIG->visitGroupAndChildren( &inv );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInterfaceElement *getInterfaceResource(const std::string &key)
|
|
{
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
return CWidgetManager::getInstance()->getElementFromId (key);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
std::vector<std::string> CInterfaceManager::getInGameXMLInterfaceFiles()
|
|
{
|
|
// Original Files
|
|
vector<string> ret;
|
|
ret= ClientCfg.XMLInterfaceFiles;
|
|
|
|
// Resolve any conflict (with CPath scheme, AddOn Should take the precedence)
|
|
// But still preserve order given in XMLInterfaceFiles (important for config.xml for instance)
|
|
set<string> fileSet;
|
|
for(uint i=0;i<ret.size();i++)
|
|
{
|
|
fileSet.insert(ret[i]);
|
|
}
|
|
|
|
// Add R2 Editor .xml. This is removed as it will not be done when initializing CEditor
|
|
// if (ClientCfg.R2EDEnabled)
|
|
// {
|
|
// // Add them to 'ret', only if not already inserted
|
|
// // since parser will crash on any duplicates
|
|
// for(uint i=0;i<ClientCfg.XMLR2EDInterfaceFiles.size();i++)
|
|
// {
|
|
// if(fileSet.find(ClientCfg.XMLR2EDInterfaceFiles[i])==fileSet.end())
|
|
// {
|
|
// fileSet.insert(ClientCfg.XMLR2EDInterfaceFiles[i]);
|
|
// ret.push_back(ClientCfg.XMLR2EDInterfaceFiles[i]);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// Get Addons .xml
|
|
vector<string> adds;
|
|
InterfaceAddOnManager.getFiles("*.xml", adds);
|
|
|
|
// Add them to 'ret', only if not already inserted
|
|
for(uint i=0;i<adds.size();i++)
|
|
{
|
|
if(fileSet.find(adds[i])==fileSet.end())
|
|
{
|
|
fileSet.insert(adds[i]);
|
|
ret.push_back(adds[i]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaString(const std::string &str)
|
|
{
|
|
nlinfo(str.c_str());
|
|
displaySystemInfo(LuaHelperStuff::formatLuaErrorSysInfo(str));
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::getLuaValueInfo(std::string &str, sint index)
|
|
{
|
|
CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
|
|
|
|
sint type= ls.type(index);
|
|
if(type==LUA_TNIL)
|
|
{
|
|
str= "nil";
|
|
}
|
|
else if(type==LUA_TNUMBER)
|
|
{
|
|
str= NLMISC::toString(ls.isInteger(index) ? ls.toInteger(index):ls.toNumber(index));
|
|
}
|
|
else if(type==LUA_TBOOLEAN)
|
|
{
|
|
str= ls.toBoolean(index)?"true":"false";
|
|
}
|
|
else if(type==LUA_TSTRING)
|
|
{
|
|
ls.toString(index, str);
|
|
str= toString("'") + str + toString("'");
|
|
}
|
|
else
|
|
{
|
|
str= ls.getTypename(type);
|
|
str+= ":";
|
|
str+= NLMISC::toString("%p", ls.toPointer(index));
|
|
// If its a table, append the size.
|
|
if(type==LUA_TTABLE)
|
|
{
|
|
ls.pushNil(); // first key
|
|
uint count= 0;
|
|
while (ls.next(index-1))
|
|
{
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
count++;
|
|
}
|
|
str+= NLMISC::toString(" (size=%d)", count);
|
|
}
|
|
// If its a Userdata, try to display UI info
|
|
else if(type==LUA_TUSERDATA)
|
|
{
|
|
if(CLuaIHM::isUIOnStack(ls, index))
|
|
{
|
|
CInterfaceElement *ui= CLuaIHM::getUIOnStack(ls, index);
|
|
str+= NLMISC::toString(" (ui=%p)", ui);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaKeyValueInfo(uint recursTableLevel, uint tabLevel)
|
|
{
|
|
CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
|
|
CLuaStackChecker lsc(&ls);
|
|
|
|
// Dump Key Str
|
|
string key;
|
|
getLuaValueInfo(key, -2);
|
|
// Dump Value Str
|
|
string value;
|
|
getLuaValueInfo(value, -1);
|
|
|
|
// display.
|
|
string res;
|
|
// append tab for table hierarchy
|
|
for(uint i=0;i<tabLevel;i++)
|
|
res+= " ";
|
|
// display key and value
|
|
res+= key + " == " + value;
|
|
dumpLuaString(res);
|
|
|
|
// If the value is a table, and can recurs dumping
|
|
if(recursTableLevel>0 && ls.type(-1)==LUA_TTABLE)
|
|
{
|
|
ls.pushNil(); // first key
|
|
while (ls.next(-2))
|
|
{
|
|
// display the key value pair of this table (recurs)
|
|
dumpLuaKeyValueInfo(recursTableLevel-1, tabLevel+1);
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaState(uint detail)
|
|
{
|
|
CLuaState *_LuaState = CLuaManager::getInstance().getLuaState();
|
|
|
|
// clamp detailed info to 2 (display at max content of eaxh Env of each group)
|
|
clamp(detail, 0U, 2U);
|
|
|
|
// Dump the Memory State
|
|
dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState->getGCCount()));
|
|
dumpLuaString(NLMISC::toString("GC Threshold: %d Kb", _LuaState->getGCThreshold()));
|
|
|
|
// If want to display some detailed info
|
|
if(detail>0)
|
|
{
|
|
CLuaState &ls= *_LuaState;
|
|
CLuaStackChecker lsc(&ls);
|
|
|
|
// *** Dump all Lua Env Tables
|
|
ls.push(IHM_LUA_ENVTABLE);
|
|
ls.getTable(LUA_REGISTRYINDEX); // __ui_envtable
|
|
ls.pushNil(); // first key
|
|
uint count= 0;
|
|
while (ls.next(-2))
|
|
{
|
|
// `key' is at index -2 and `value' at index -1
|
|
dumpLuaKeyValueInfo(detail-1, 1);
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
count++;
|
|
}
|
|
// pop table
|
|
ls.pop();
|
|
|
|
dumpLuaString(NLMISC::toString("Number of EnvTable for ui groups: %d", count));
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::createLocalBranch(const std::string &fileName, NLMISC::IProgressCallback &progressCallBack)
|
|
{
|
|
try
|
|
{
|
|
CIFile file;
|
|
if (file.open (fileName))
|
|
{
|
|
// Init an xml stream
|
|
CIXml read;
|
|
read.init (file);
|
|
|
|
//Parse the parser output!!!
|
|
CCDBNodeBranch *localNode = new CCDBNodeBranch("LOCAL");
|
|
localNode->init( read.getRootNode (), progressCallBack );
|
|
NLGUI::CDBManager::getInstance()->getDB()->attachChild(localNode,"LOCAL");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of inventory
|
|
ServerToLocalAutoCopyInventory.init("INVENTORY");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of exchange
|
|
ServerToLocalAutoCopyExchange.init("EXCHANGE");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of dm (animator) gift
|
|
ServerToLocalAutoCopyDMGift.init("DM_GIFT");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of context menu
|
|
ServerToLocalAutoCopyContextMenu.init("TARGET:CONTEXT_MENU");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of Skill Points
|
|
ServerToLocalAutoCopySkillPoints.init("USER");
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
// Output error
|
|
nlwarning ("CFormLoader: Error while loading the form %s: %s", fileName.c_str(), e.what());
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#ifdef NL_OS_WINDOWS
|
|
# pragma warning (push)
|
|
# pragma warning (disable : 4355) // 'this' used in base member initializer list
|
|
#endif
|
|
CInterfaceManager::CServerToLocalAutoCopy::CServerToLocalAutoCopy() : _LocalObserver(*this), _ServerObserver(*this)
|
|
{
|
|
_ServerCounter= NULL;
|
|
_UpdateList.reserve(300);
|
|
_LocalUpdating= false;
|
|
}
|
|
#ifdef NL_OS_WINDOWS
|
|
# pragma warning (pop)
|
|
#endif
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// unhook from everything we are tangled up in
|
|
void CInterfaceManager::CServerToLocalAutoCopy::release()
|
|
{
|
|
_Nodes.clear();
|
|
_ServerCounter = NULL;
|
|
_ServerNodeMap.clear();
|
|
_LocalNodeMap.clear();
|
|
_UpdateList.clear();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::buildRecursLocalLeaves(CCDBNodeBranch *branch, std::vector<CCDBNodeLeaf*> &leaves)
|
|
{
|
|
for(uint i=0;i<branch->getNbNodes();i++)
|
|
{
|
|
ICDBNode *node= branch->getNode(i);
|
|
if(node)
|
|
{
|
|
CCDBNodeLeaf *leaf= dynamic_cast<CCDBNodeLeaf*>(node);
|
|
if(leaf)
|
|
{
|
|
// just append to list
|
|
leaves.push_back(leaf);
|
|
}
|
|
else
|
|
{
|
|
// recurs if a branch (should be...)
|
|
CCDBNodeBranch *sonBranch= dynamic_cast<CCDBNodeBranch*>(node);
|
|
if(sonBranch)
|
|
buildRecursLocalLeaves(sonBranch, leaves);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::init(const std::string &dbPath)
|
|
{
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
// Get the synchronisation Counter in Server DB
|
|
_ServerCounter= NLGUI::CDBManager::getInstance()->getDbProp(string("SERVER:") + dbPath + ":COUNTER", false);
|
|
|
|
// if found
|
|
if(_ServerCounter)
|
|
{
|
|
ICDBNode::CTextId textId;
|
|
|
|
// **** Add Observers on all nodes
|
|
// add the observers when server node change
|
|
textId = ICDBNode::CTextId( string("SERVER:") + dbPath );
|
|
NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_ServerObserver, textId );
|
|
|
|
// add the observers when local node change
|
|
textId = ICDBNode::CTextId( string("LOCAL:") + dbPath );
|
|
NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_LocalObserver, textId );
|
|
|
|
// **** Init the Nodes shortcut
|
|
// Parse all Local Nodes
|
|
CCDBNodeBranch *localBranch= NLGUI::CDBManager::getInstance()->getDbBranch(string("LOCAL:") + dbPath);
|
|
if(localBranch)
|
|
{
|
|
uint i;
|
|
std::vector<CCDBNodeLeaf*> leaves;
|
|
buildRecursLocalLeaves(localBranch, leaves);
|
|
|
|
// --- build _Nodes
|
|
_Nodes.reserve(leaves.size());
|
|
for(i=0;i<leaves.size();i++)
|
|
{
|
|
CCDBNodeLeaf *localLeaf= leaves[i];
|
|
|
|
// get the SERVER associated node name
|
|
string serverLeafStr= *localLeaf->getName();
|
|
CCDBNodeBranch* parent= localLeaf->getParent();
|
|
while( *parent->getName()!="LOCAL" )
|
|
{
|
|
serverLeafStr= *parent->getName()+":"+serverLeafStr;
|
|
parent= parent->getParent();
|
|
}
|
|
serverLeafStr= "SERVER:" + serverLeafStr;
|
|
|
|
// try then to get this server node
|
|
CCDBNodeLeaf *serverLeaf= NLGUI::CDBManager::getInstance()->getDbProp(serverLeafStr, false);
|
|
if(serverLeaf)
|
|
{
|
|
// Both server and local leaves exist, ok, append to _Nodes
|
|
CNode node;
|
|
node.ServerNode= serverLeaf;
|
|
node.LocalNode= localLeaf;
|
|
_Nodes.push_back(node);
|
|
}
|
|
}
|
|
|
|
// --- Init the maps
|
|
_ServerNodeMap.reserve(leaves.size());
|
|
_LocalNodeMap.reserve(leaves.size());
|
|
// For all valid _Nodes, insert in "map"
|
|
for(i=0;i<_Nodes.size();i++)
|
|
{
|
|
CNodeLocalComp lc;
|
|
CNodeServerComp sc;
|
|
lc.Node= &_Nodes[i];
|
|
sc.Node= &_Nodes[i];
|
|
_LocalNodeMap.push_back(lc);
|
|
_ServerNodeMap.push_back(sc);
|
|
}
|
|
// then sort
|
|
sort(_LocalNodeMap.begin(), _LocalNodeMap.end());
|
|
sort(_ServerNodeMap.begin(), _ServerNodeMap.end());
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::onServerChange(ICDBNode *serverNode)
|
|
{
|
|
if(_Nodes.empty())
|
|
return;
|
|
CCDBNodeLeaf *serverLeaf = safe_cast<CCDBNodeLeaf *>(serverNode);
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
// Add the leaf to the update list. only if not the counter
|
|
if(serverLeaf != _ServerCounter)
|
|
{
|
|
// build the map key
|
|
CNode nodeComp;
|
|
CNodeServerComp sc;
|
|
nodeComp.ServerNode= serverLeaf;
|
|
sc.Node= &nodeComp;
|
|
// try to find the node associated to this server leaf
|
|
uint index= searchLowerBound(_ServerNodeMap, sc);
|
|
// if found
|
|
if( index>0 || _ServerNodeMap[0].Node->ServerNode==serverLeaf )
|
|
{
|
|
CNode *node= _ServerNodeMap[index].Node;
|
|
// if this node is not already inserted
|
|
if(!node->InsertedInUpdateList)
|
|
{
|
|
// insert
|
|
node->InsertedInUpdateList= true;
|
|
_UpdateList.push_back(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the client and server are synchonized.
|
|
if( ClientCfg.Local || pIM->localActionCounterSynchronizedWith(_ServerCounter) )
|
|
{
|
|
// update all leaves
|
|
for(uint i=0;i<_UpdateList.size();i++)
|
|
{
|
|
CNode *node= _UpdateList[i];
|
|
|
|
_LocalUpdating= true;
|
|
node->LocalNode->setValue64(node->ServerNode->getValue64());
|
|
_LocalUpdating= false;
|
|
|
|
// reset inserted flag
|
|
node->InsertedInUpdateList= false;
|
|
}
|
|
|
|
// clear update list
|
|
_UpdateList.clear();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode *localNode)
|
|
{
|
|
if(_Nodes.empty())
|
|
return;
|
|
|
|
// if the local changes because of localLeaf->setValue64() in onServerChange(), no-op !!!
|
|
if(_LocalUpdating)
|
|
return;
|
|
|
|
CCDBNodeLeaf *localLeaf = safe_cast<CCDBNodeLeaf *>(localNode);
|
|
|
|
// Add the leaf to the update list
|
|
// build the map key
|
|
CNode nodeComp;
|
|
CNodeLocalComp lc;
|
|
nodeComp.LocalNode= localLeaf;
|
|
lc.Node= &nodeComp;
|
|
// try to find the node associated to this local leaf
|
|
uint index= searchLowerBound(_LocalNodeMap, lc);
|
|
// if found
|
|
if( index>0 || _LocalNodeMap[0].Node->LocalNode==localLeaf )
|
|
{
|
|
CNode *node= _LocalNodeMap[index].Node;
|
|
// if this node is not already inserted
|
|
if(!node->InsertedInUpdateList)
|
|
{
|
|
// insert
|
|
node->InsertedInUpdateList= true;
|
|
_UpdateList.push_back(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::use12hClock()
|
|
{
|
|
CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false);
|
|
|
|
return (node && node->getValueBool());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
char* CInterfaceManager::getTimestampHuman(const char* format /* "[%H:%M:%S] " */)
|
|
{
|
|
static char cstime[25];
|
|
time_t date;
|
|
time (&date);
|
|
struct tm *tms = localtime(&date);
|
|
if (tms)
|
|
{
|
|
strftime(cstime, 25, format, tms);
|
|
}
|
|
else
|
|
{
|
|
strcpy(cstime, "");
|
|
}
|
|
|
|
return cstime;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse tokens in a chatmessage or emote
|
|
*
|
|
* Valid subjects:
|
|
* $me$
|
|
* $t$
|
|
* $tt$
|
|
* $tm1$..$tm8$
|
|
*
|
|
* Valid parameters:
|
|
* $<subject>.name$
|
|
* $<subject>.title$
|
|
* $<subject>.race$
|
|
* $<subject>.guild$
|
|
* $<subject>.gs(m/f/n)$
|
|
*
|
|
* Default parameter if parameter result is empty:
|
|
* $<subject>.<parameter>/<default>$
|
|
*
|
|
* All \d's in default parameter remove a following character.
|
|
*/
|
|
bool CInterfaceManager::parseTokens(ucstring& ucstr)
|
|
{
|
|
ucstring str = ucstr;
|
|
ucstring start_token("$");
|
|
ucstring end_token("$");
|
|
size_t start_pos = 0;
|
|
size_t end_pos = 1;
|
|
|
|
sint endless_loop_protector = 0;
|
|
while ((start_pos < str.length() - 1) &&
|
|
((start_pos = str.find(start_token, start_pos)) != string::npos))
|
|
{
|
|
endless_loop_protector++;
|
|
if (endless_loop_protector > 100)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Get the whole token substring first
|
|
end_pos = str.find(end_token, start_pos + 1);
|
|
|
|
if ((start_pos == ucstring::npos) ||
|
|
(end_pos == ucstring::npos) ||
|
|
(end_pos <= start_pos + 1))
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = max(start_pos, end_pos);
|
|
continue;
|
|
}
|
|
|
|
// Get everything between the two "$"
|
|
size_t token_start_pos = start_pos + start_token.length();
|
|
size_t token_end_pos = end_pos - end_token.length();
|
|
if (token_start_pos > token_end_pos)
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
ucstring token_whole = str.luabind_substr(start_pos, end_pos - start_pos + 1);
|
|
ucstring token_string = token_whole.luabind_substr(1, token_whole.length() - 2);
|
|
ucstring token_replacement = token_whole;
|
|
ucstring token_default = token_whole;
|
|
|
|
ucstring token_subject;
|
|
ucstring token_param;
|
|
|
|
// Does the token have a parameter?
|
|
// If not it is 'name' by default
|
|
vector<ucstring> token_vector;
|
|
vector<ucstring> param_vector;
|
|
splitUCString(token_string, ucstring("."), token_vector);
|
|
if (token_vector.size() == 0)
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
token_subject = token_vector[0];
|
|
if (token_vector.size() == 1)
|
|
{
|
|
splitUCString(token_subject, ucstring("/"), param_vector);
|
|
token_subject = (param_vector.size() > 0) ? param_vector[0] : ucstring("");
|
|
token_param = ucstring("name");
|
|
}
|
|
else if (token_vector.size() > 1)
|
|
{
|
|
token_param = token_vector[1];
|
|
if (token_param.luabind_substr(0, 3) != ucstring("gs("))
|
|
{
|
|
splitUCString(token_vector[1], ucstring("/"), param_vector);
|
|
token_param = (param_vector.size() > 0) ? param_vector[0] : ucstring("");
|
|
}
|
|
}
|
|
|
|
// Get any default value, if not gs
|
|
sint extra_replacement = 0;
|
|
if (token_param.luabind_substr(0, 3) != ucstring("gs("))
|
|
{
|
|
if (param_vector.size() == 2)
|
|
{
|
|
// Set default value
|
|
token_replacement = param_vector[1];
|
|
// Delete following chars for every '\d' in default
|
|
string::size_type token_replacement_pos;
|
|
while ((token_replacement_pos = token_replacement.find(ucstring("\\d"))) != string::npos)
|
|
{
|
|
token_replacement.replace(token_replacement_pos, 2, ucstring(""));
|
|
extra_replacement++;
|
|
}
|
|
token_default = token_replacement;
|
|
}
|
|
}
|
|
|
|
CEntityCL *pTokenSubjectEntity = NULL;
|
|
|
|
if (token_subject == ucstring("me"))
|
|
{
|
|
pTokenSubjectEntity = static_cast<CEntityCL*>(UserEntity);
|
|
}
|
|
else if (token_subject == ucstring("t"))
|
|
{
|
|
// Target
|
|
uint targetSlot = UserEntity->targetSlot();
|
|
pTokenSubjectEntity = EntitiesMngr.entity(targetSlot);
|
|
}
|
|
else if (token_subject == ucstring("tt"))
|
|
{
|
|
// Target's target
|
|
uint targetSlot = UserEntity->targetSlot();
|
|
CEntityCL *target = EntitiesMngr.entity(targetSlot);
|
|
|
|
if (target)
|
|
{
|
|
// Check the new slot.
|
|
CLFECOMMON::TCLEntityId newSlot = target->targetSlot();
|
|
CEntityCL* pE = EntitiesMngr.entity(newSlot);
|
|
if (pE)
|
|
{
|
|
pTokenSubjectEntity = pE;
|
|
}
|
|
}
|
|
}
|
|
else if ((token_subject.length() == 3) &&
|
|
(token_subject.luabind_substr(0, 2) == ucstring("tm")))
|
|
{
|
|
// Teammate
|
|
uint indexInTeam = 0;
|
|
fromString(token_subject.luabind_substr(2, 1).toString(), indexInTeam);
|
|
|
|
// Make 0-based
|
|
--indexInTeam;
|
|
if (indexInTeam < PeopleInterraction.TeamList.getNumPeople() )
|
|
{
|
|
// Index is the database index (serverIndex() not used for team list)
|
|
CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH ":%hu:NAME", indexInTeam ), false);
|
|
if (pNL && pNL->getValueBool() )
|
|
{
|
|
// There is a character corresponding to this index
|
|
pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString( TEAM_DB_PATH ":%hu:UID", indexInTeam ), false );
|
|
if (pNL)
|
|
{
|
|
CLFECOMMON::TClientDataSetIndex compressedIndex = pNL->getValue32();
|
|
|
|
// Search entity in vision
|
|
CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex( compressedIndex );
|
|
if (entity)
|
|
{
|
|
pTokenSubjectEntity = entity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Unknown token subject, skip it
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
if (pTokenSubjectEntity != NULL)
|
|
{
|
|
// Parse the parameter
|
|
if (token_param == ucstring("name"))
|
|
{
|
|
ucstring name = pTokenSubjectEntity->getDisplayName();
|
|
// special case where there is only a title, very rare case for some NPC
|
|
if (name.empty())
|
|
{
|
|
name = pTokenSubjectEntity->getTitle();
|
|
}
|
|
token_replacement = name.empty() ? token_replacement : name;
|
|
}
|
|
else if (token_param == ucstring("title"))
|
|
{
|
|
ucstring title = pTokenSubjectEntity->getTitle();
|
|
token_replacement = title.empty() ? token_replacement : title;
|
|
}
|
|
else if (token_param == ucstring("race"))
|
|
{
|
|
CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
|
|
if (pC)
|
|
{
|
|
EGSPD::CPeople::TPeople race = pC->people();
|
|
if (race >= EGSPD::CPeople::Playable && race <= EGSPD::CPeople::EndPlayable)
|
|
{
|
|
ucstring srace = NLMISC::CI18N::get("io" + EGSPD::CPeople::toString(race));
|
|
token_replacement = srace.empty() ? token_replacement : srace;
|
|
}
|
|
}
|
|
}
|
|
else if (token_param == ucstring("guild"))
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
|
|
ucstring ucGuildName;
|
|
if (pSMC->getString(pTokenSubjectEntity->getGuildNameID(), ucGuildName))
|
|
{
|
|
token_replacement = ucGuildName.empty() ? token_replacement : ucGuildName;
|
|
}
|
|
}
|
|
else if (token_param.luabind_substr(0, 3) == ucstring("gs(") &&
|
|
token_param.luabind_substr(token_param.length() - 1 , 1) == ucstring(")"))
|
|
{
|
|
// Gender string
|
|
vector<ucstring> strList;
|
|
ucstring gender_string = token_param.luabind_substr(3, token_param.length() - 4);
|
|
splitUCString(gender_string, ucstring("/"), strList);
|
|
|
|
if (strList.size() <= 1)
|
|
{
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
// We only care about the gender if the subject is humanoid.
|
|
GSGENDER::EGender gender = GSGENDER::neutral;
|
|
if (pTokenSubjectEntity->isUser() || pTokenSubjectEntity->isPlayer() || pTokenSubjectEntity->isNPC())
|
|
{
|
|
CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
|
|
if (pC)
|
|
{
|
|
gender = pC->getGender();
|
|
}
|
|
}
|
|
|
|
// The neuter part is optional. Fallback to male if something is wrong.
|
|
GSGENDER::EGender g = ((uint)gender >= strList.size()) ? GSGENDER::male : gender;
|
|
token_replacement = strList[g];
|
|
}
|
|
}
|
|
|
|
if (token_whole == token_replacement)
|
|
{
|
|
// Nothing to replace; show message and exit
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
ucstring message = ucstring(CI18N::get("uiUntranslatedToken"));
|
|
message.replace(message.find(ucstring("%s")), 2, token_whole);
|
|
im->displaySystemInfo(message);
|
|
return false;
|
|
}
|
|
|
|
// Replace token
|
|
size_t token_whole_pos = str.find(token_whole);
|
|
|
|
// Only do extra replacement spaces if using default
|
|
extra_replacement = (token_replacement == token_default) ? extra_replacement : 0;
|
|
if (str.find(token_whole, start_pos) != string::npos)
|
|
{
|
|
str = str.replace(token_whole_pos, token_whole.length() + extra_replacement, token_replacement);
|
|
start_pos = token_whole_pos + token_replacement.length();
|
|
}
|
|
}
|
|
|
|
ucstr = str;
|
|
return true;;
|
|
}
|