Changed: #1135 Merge changes from Ryzom patch 1.10

This commit is contained in:
kervala 2010-10-18 20:02:31 +02:00
parent caf6017dac
commit 45ae9114b5
35 changed files with 2190 additions and 408 deletions

View file

@ -359,6 +359,13 @@ CCharacterCL::CCharacterCL()
_EventFactionId = 0;
_PvpMode = PVP_MODE::None;
_PvpClan = PVP_CLAN::None;
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
{
_PvpAllies[i] = false;
_PvpEnemies[i] = false;
}
_OutpostId = 0;
_OutpostSide = OUTPOSTENUMS::UnknownPVPSide;
@ -1853,12 +1860,16 @@ void CCharacterCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle &/* game
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyPvpClan(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
_PvpClan = PVP_CLAN::TPVPClan(prop);
if (_PvpClan >= PVP_CLAN::NbClans)
// get fames signs from prop
for (uint8 fameIdx = 0; fameIdx < 7; fameIdx++)
{
//nlwarning("updateVisualPropertyPvpClan: received invalid PvP clan: %"NL_I64"u", prop);
_PvpClan = PVP_CLAN::None;
_PvpAllies[fameIdx] = prop & (1 << 2*fameIdx);
_PvpEnemies[fameIdx] = prop & (1 << ((2*fameIdx)+1));
}
_ClanCivMaxFame = PVP_CLAN::TPVPClan((prop & (0x03 << 2*7)) >> 2*7);
_ClanCultMaxFame = PVP_CLAN::TPVPClan(4 + ((prop & (0x03 << 2*8)) >> 2*8));
buildInSceneInterface();
} // updateVisualPropertyPvpClan //

View file

@ -373,6 +373,44 @@ public:
virtual PVP_CLAN::TPVPClan getPvpClan() const { return _PvpClan; }
void setPvpClan(PVP_CLAN::TPVPClan clan) { _PvpClan=clan; }
virtual PVP_CLAN::TPVPClan getClanCivMaxFame() const { return _ClanCivMaxFame; }
void setClanCivMaxFame(PVP_CLAN::TPVPClan clan) { _ClanCivMaxFame=clan; }
virtual PVP_CLAN::TPVPClan getClanCultMaxFame() const { return _ClanCultMaxFame; }
void setClanCultMaxFame(PVP_CLAN::TPVPClan clan) { _ClanCultMaxFame=clan; }
virtual bool isPvpAlly(uint8 faction) const { if (faction < PVP_CLAN::NbClans) return _PvpAllies[faction]; else return false; }
virtual bool isPvpEnnemy(uint8 faction) const { if (faction < PVP_CLAN::NbClans) return _PvpEnemies[faction]; else return false; }
virtual bool isPvpMarauder() const
{
for (uint8 i = 0; i < 4; i++)
if (!_PvpEnemies[i])
return false;
return true;
}
virtual bool isPvpTrytonist() const
{
if (_PvpEnemies[4] && _PvpEnemies[6])
return true;
return false;
}
virtual bool isPvpPrimas() const
{
if (_PvpAllies[4] && _PvpAllies[6])
return true;
return false;
}
virtual bool isPvpRanger() const
{
for (uint8 i = 0; i < 4; i++)
if (!_PvpAllies[i])
return false;
return true;
}
virtual uint16 getOutpostId() const { return _OutpostId; }
virtual OUTPOSTENUMS::TPVPSide getOutpostSide() const { return _OutpostSide; }
@ -690,6 +728,10 @@ protected:
uint32 _EventFactionId;
uint8 _PvpMode;
PVP_CLAN::TPVPClan _PvpClan;
PVP_CLAN::TPVPClan _ClanCivMaxFame;
PVP_CLAN::TPVPClan _ClanCultMaxFame;
bool _PvpAllies[PVP_CLAN::NbClans];
bool _PvpEnemies[PVP_CLAN::NbClans];
uint16 _OutpostId;
OUTPOSTENUMS::TPVPSide _OutpostSide;

View file

@ -40,6 +40,7 @@
#include "game_share/generic_xml_msg_mngr.h"
#include "game_share/msg_client_server.h"
#include "game_share/chat_group.h"
#include "interface_v3/skill_manager.h"
using namespace std;
using namespace NLMISC;
@ -948,19 +949,29 @@ void CClientChatManager::buildTellSentence(const ucstring &sender, const ucstrin
else
{
ucstring name = CEntityCL::removeTitleAndShardFromName(sender);
ucstring csr;
// special case where there is only a title, very rare case for some NPC
if (name.empty())
{
// we need the gender to display the correct title
CCharacterCL *entity = dynamic_cast<CCharacterCL*>(EntitiesMngr.getEntityByName(sender, true, true));
bool bWoman = entity && entity->getGender() == GSGENDER::female;
name = STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(CEntityCL::getTitleFromName(sender), bWoman);
}
else
{
// Does the char have a CSR title?
csr = CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender)) ? ucstring("(CSR) ") : ucstring("");
}
result = name + ucstring(" ") + CI18N::get("tellsYou") + ucstring(": ") + msg;
ucstring cur_time;
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
result = cur_time + csr + name + ucstring(" ") + CI18N::get("tellsYou") + ucstring(": ") + msg;
}
}
@ -992,27 +1003,41 @@ void CClientChatManager::buildChatSentence(TDataSetIndex /* compressedSenderInde
// Format the sentence with the provided sender name
ucstring senderName = CEntityCL::removeTitleAndShardFromName(sender);
// Add time if not a &bbl&
ucstring cur_time;
if (cat.toString() != "&bbl&")
{
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
}
ucstring csr;
// Does the char have a CSR title?
csr = CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender)) ? ucstring("(CSR) ") : ucstring("");
if (UserEntity && senderName == UserEntity->getDisplayName())
{
// the player talks
// The player talks
switch(type)
{
case CChatGroup::shout:
result = cat + CI18N::get("youShout") + ucstring(" : ") + finalMsg;
result = cat + cur_time + csr + CI18N::get("youShout") + ucstring(": ") + finalMsg;
break;
default:
result = cat + CI18N::get("youSay") + ucstring(" : ") + finalMsg;
result = cat + cur_time + csr + CI18N::get("youSay") + ucstring(": ") + finalMsg;
break;
}
}
else
{
// special case where there is only a title, very rare case for some NPC
// Special case where there is only a title, very rare case for some NPC
if (senderName.empty())
{
// we need the gender to display the correct title
CCharacterCL *entity = dynamic_cast<CCharacterCL*>(EntitiesMngr.getEntityByName(sender, true, true));
// We need the gender to display the correct title
bool bWoman = entity && entity->getGender() == GSGENDER::female;
senderName = STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(CEntityCL::getTitleFromName(sender), bWoman);
@ -1021,10 +1046,10 @@ void CClientChatManager::buildChatSentence(TDataSetIndex /* compressedSenderInde
switch(type)
{
case CChatGroup::shout:
result = cat + senderName + ucstring(" ") + CI18N::get("heShout") + ucstring(" : ") + finalMsg;
result = cat + cur_time + csr + senderName + ucstring(" ") + CI18N::get("heShout") + ucstring(": ") + finalMsg;
break;
default:
result = cat + senderName + ucstring(" ") + CI18N::get("heSays") + ucstring(" : ") + finalMsg;
result = cat + cur_time + csr + senderName + ucstring(" ") + CI18N::get("heSays") + ucstring(": ") + finalMsg;
break;
}
}
@ -1157,7 +1182,13 @@ class CHandlerTell : public IActionHandler
prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
ucstring finalMsg;
CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, false);
finalMsg += CI18N::get("youTell") + ": ";
ucstring cur_time;
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : "";
finalMsg += cur_time + csr + CI18N::get("youTell") + ": ";
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, true);
finalMsg += message;
@ -1238,6 +1269,14 @@ void CClientChatManager::updateChatModeAndButton(uint mode)
case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break;
case CChatGroup::team: if (teamActive) pUserBut->setHardText("uiFilterTeam"); break;
case CChatGroup::guild: if (guildActive) pUserBut->setHardText("uiFilterGuild"); break;
case CChatGroup::dyn_chat:
uint32 index = PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex();
uint32 textId = pIM->getDbProp("SERVER:DYN_CHAT:CHANNEL"+toString(index)+":NAME")->getValue32();
ucstring title;
STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
pUserBut->setHardText(title.toUtf8());
break;
// NB: user chat cannot have yubo_chat target
}
pUserBut->setActive(true);
@ -1276,6 +1315,12 @@ class CHandlerTalk : public IActionHandler
text.fromUtf8 (getParam (sParams, "text"));
// text = getParam (sParams, "text");
// Parse any tokens in the text
if ( ! CInterfaceManager::parseTokens(text))
{
return;
}
// Find the base group
if ((mode<CChatGroup::nbChatMode) && !text.empty())
{
@ -1292,7 +1337,7 @@ class CHandlerTalk : public IActionHandler
else
{
CInterfaceManager *im = CInterfaceManager::getInstance();
im->displaySystemInfo (ucstring(cmd+" : ")+CI18N::get ("uiCommandNotExists"));
im->displaySystemInfo (ucstring(cmd+": ")+CI18N::get ("uiCommandNotExists"));
}
}
else

View file

@ -125,7 +125,7 @@ extern CClientChatManager ChatMngr;
extern ULandscape *Landscape;
extern UScene *Scene;
extern CLog g_log;
extern CEntityManager EntitiesMngr;
///////////////
// Variables //
@ -342,6 +342,317 @@ NLMISC_COMMAND(random, "Roll a dice and say the result around","[<min>] <max>")
return true;
}
//-----------------------------------------------
// 'dumpShapePos' : Dump Last Added Shape Pos
//-----------------------------------------------
NLMISC_COMMAND(dumpShapePos, "Dump Last Added Shape Pos.", "")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
CInterfaceManager *IM = CInterfaceManager::getInstance();
CVector pos = ShapeAddedByCommand.back().getPos();
IM->displaySystemInfo(ucstring(toString("Shape Pos = %f, %f, %f", pos.x, pos.y, pos.z)));
return true;
}
//-----------------------------------------------
// 'clearShape' : Remove all shapes added with the 'shape' command
//-----------------------------------------------
NLMISC_COMMAND(clearShape, "Remove all shapes added with the 'shape' command.", "")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
if (!Scene) return false;
for(uint k = 0; k < ShapeAddedByCommand.size(); ++k)
{
Scene->deleteInstance(ShapeAddedByCommand[k]);
}
ShapeAddedByCommand.clear();
return true;
}
//-----------------------------------------------------
// 'setShapeX' : Set X position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeX, "Set X position for last created shape.", "<x coordinate>")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
bool valid_coord;
if (args[0][0] == '+')
valid_coord = fromString(args[0].substr(1), coord);
else
valid_coord = fromString(args[0], coord);
if (!valid_coord)
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
if (args[0][0] == '+')
pos.x += coord;
else
pos.x = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------------
// 'setShapeY' : Set Y position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeY, "Set Y position for last created shape.", "<y coordinate>")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
bool valid_coord;
if (args[0][0] == '+')
valid_coord = fromString(args[0].substr(1), coord);
else
valid_coord = fromString(args[0], coord);
if (!valid_coord)
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
if (args[0][0] == '+')
pos.y += coord;
else
pos.y = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------------
// 'setShapeZ' : Set Z position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeZ, "Set Z position for last created shape.", "<z coordinate>")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
bool valid_coord;
if (args[0][0] == '+')
valid_coord = fromString(args[0].substr(1), coord);
else
valid_coord = fromString(args[0], coord);
if (!valid_coord)
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
if (args[0][0] == '+')
pos.z += coord;
else
pos.z = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------------
// 'setShapeDir' : Set direction angle for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeDir, "Set direction angle for last created shape.", "<angle>")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float angle;
if (!fromString(args[0], angle))
{
nlwarning("Can't get angle");
return false;
}
CMatrix dir;
dir.identity();
CVector vangle = CVector(sin(angle), cos(angle), 0.f);
CVector vi = vangle^CVector(0.f, 0.f, 1.f);
CVector vk = vi^vangle;
dir.setRot(vi, vangle, vk, true);
// Set Orientation : User Direction should be normalized.
ShapeAddedByCommand.back().setRotQuat(dir.getRot());
return true;
}
//-----------------------------------------------
// 'shape' : Add a shape in the scene.
//-----------------------------------------------
NLMISC_COMMAND(shape, "Add a shape in the scene.", "<shape file>")
{
#if FINAL_VERSION
if (!hasPrivilegeDEV() &&
!hasPrivilegeSGM() &&
!hasPrivilegeGM() &&
!hasPrivilegeVG() &&
!hasPrivilegeSG() &&
!hasPrivilegeG() &&
!hasPrivilegeEM() &&
!hasPrivilegeEG())
return true;
#endif // FINAL_VERSION
if(args.size() < 1)
{
nlwarning("Command 'shape': need at least 1 parameter, try '/help shape' for more details.");
return false;
}
if (!Scene)
{
nlwarning("No scene available");
return false;
}
UInstance instance = Scene->createInstance(args[0]);
if(!instance.empty())
{
ShapeAddedByCommand.push_back(instance);
// Set the position
instance.setPos(UserEntity->pos());
instance.setClusterSystem(UserEntity->getClusterSystem()); // for simplicity, assume it is in the same
// cluster system than the user
// Compute the direction Matrix
CMatrix dir;
dir.identity();
CVector vi = UserEntity->dir()^CVector(0.f, 0.f, 1.f);
CVector vk = vi^UserEntity->dir();
dir.setRot(vi, UserEntity->dir(), vk, true);
// Set Orientation : User Direction should be normalized.
instance.setRotQuat(dir.getRot());
// if the shape is a particle system, additionnal parameters are user params
UParticleSystemInstance psi;
psi.cast (instance);
if (!psi.empty())
{
// set each user param that is present
for(uint k = 0; k < 4; ++k)
{
if (args.size() >= (k + 2))
{
float uparam;
if (fromString(args[k + 1], uparam))
{
psi.setUserParam(k, uparam);
}
else
{
nlwarning("Cant read param %d", k);
}
}
}
}
}
else
{
nlwarning("Command 'shape': cannot find the shape %s.", args[0].c_str());
}
// Command Well Done
return true;
}
NLMISC_COMMAND(bugReport, "Call the bug report tool with dump", "<AddScreenshot>")
{
const char *brname[] = { "bug_report.exe", "bug_report_r.exe", "bug_report_rd.exe", "bug_report_df.exe", "bug_report_d.exe" };
@ -908,6 +1219,10 @@ static bool talkInChan(uint32 nb,std::vector<std::string>args)
PeopleInterraction.talkInDynamicChannel(nb,ucstring(tmp));
return true;
}
else
{
ChatMngr.updateChatModeAndButton(CChatGroup::dyn_chat);
}
return false;
}
@ -3467,156 +3782,6 @@ NLMISC_COMMAND(dist2side, "Change the distance to the side for a given sheet.",
//-----------------------------------------------
// 'clearShape' : Remove all shapes added with the 'shape' command
//-----------------------------------------------
NLMISC_COMMAND(clearShape, "Remove all shapes added with the 'shape' command.", "")
{
if (!Scene) return false;
for(uint k = 0; k < ShapeAddedByCommand.size(); ++k)
{
Scene->deleteInstance(ShapeAddedByCommand[k]);
}
ShapeAddedByCommand.clear();
return true;
}
//-----------------------------------------------------
// 'setShapeX' : Set X position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeX, "Set X position for last created shape.", "<x coordinate>")
{
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
if (!fromString(args[0], coord))
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
pos.x = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------------
// 'setShapeY' : Set Y position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeY, "Set Y position for last created shape.", "<y coordinate>")
{
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
if (!fromString(args[0], coord))
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
pos.y = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------------
// 'setShapeZ' : Set Z position for last created shape
//-----------------------------------------------------
NLMISC_COMMAND(setShapeZ, "Set Z position for last created shape.", "<z coordinate>")
{
if (args.size() != 1) return false;
if (ShapeAddedByCommand.empty())
{
nlwarning("No shape created yet");
return false;
}
float coord;
if (!fromString(args[0], coord))
{
nlwarning("Can't get position");
return false;
}
CVector pos = ShapeAddedByCommand.back().getPos();
pos.z = coord;
ShapeAddedByCommand.back().setPos(pos);
return true;
}
//-----------------------------------------------
// 'shape' : Add a shape in the scene.
//-----------------------------------------------
NLMISC_COMMAND(shape, "Add a shape in the scene.", "<shape file>")
{
if(args.size() < 1)
{
nlwarning("Command 'shape': need at least 1 parameter, try '/help shape' for more details.");
return false;
}
if (!Scene)
{
nlwarning("No scene available");
return false;
}
UInstance instance = Scene->createInstance(args[0]);
if(!instance.empty())
{
ShapeAddedByCommand.push_back(instance);
// Set the position
instance.setPos(UserEntity->pos());
instance.setClusterSystem(UserEntity->getClusterSystem()); // for simplicity, assume it is in the same
// cluster system than the user
// Compute the direction Matrix
CMatrix dir;
dir.identity();
CVector vi = UserEntity->dir()^CVector(0.f, 0.f, 1.f);
CVector vk = vi^UserEntity->dir();
dir.setRot(vi, UserEntity->dir(), vk, true);
// Set Orientation : User Direction should be normalized.
instance.setRotQuat(dir.getRot());
// if the shape is a particle system, additionnal parameters are user params
UParticleSystemInstance psi;
psi.cast (instance);
if (!psi.empty())
{
// set each user param that is present
for(uint k = 0; k < 4; ++k)
{
if (args.size() >= (k + 2))
{
float uparam;
if (fromString(args[k + 1], uparam))
{
psi.setUserParam(k, uparam);
}
else
{
nlwarning("Cant read param %d", k);
}
}
}
}
}
else
nlwarning("Command 'shape': cannot find the shape %s.", args[0].c_str());
// Command Well Done
return true;
}
// Change the parent of an entity. 'parent slot' not defined remove the current parent.
NLMISC_COMMAND(parent, "Change the parent of an entity.", "<slot> [<parent slot>]")
{

View file

@ -777,7 +777,7 @@ void contextExtractRM(bool rightClick, bool dblClick)
return;
if( ClientCfg.DblClickMode && !dblClick)
return;
UserEntity->moveToExtractionPhrase(SlotUnderCursor, MaxExtractionDistance, ~0, ~0, true );
UserEntity->moveToExtractionPhrase(SlotUnderCursor, MaxExtractionDistance, std::numeric_limits<uint>::max(), std::numeric_limits<uint>::max(), true );
}
//-----------------------------------------------

View file

@ -494,6 +494,90 @@ void CEntityManager::reinit()
initialize(_NbMaxEntity);
}
CShapeInstanceReference CEntityManager::createInstance(const string& shape, const CVector &pos, const string& text, const string& url, bool bbox_active)
{
CShapeInstanceReference nullinstref(UInstance(), string(""), string(""));
if (!Scene) return nullinstref;
UInstance instance = Scene->createInstance(shape);
if (text.empty())
bbox_active = false;
CShapeInstanceReference instref = CShapeInstanceReference(instance, text, url, bbox_active);
if(!instance.empty())
{
_ShapeInstances.push_back(instref);
}
return instref;
}
bool CEntityManager::removeInstances()
{
if (!Scene) return false;
// Remove all instances.
for(uint i=0; i<_ShapeInstances.size(); ++i)
{
if (!_ShapeInstances[i].Instance.empty())
Scene->deleteInstance(_ShapeInstances[i].Instance);
}
_ShapeInstances.clear();
return true;
}
CShapeInstanceReference CEntityManager::getShapeInstanceUnderPos(float x, float y)
{
CShapeInstanceReference selectedInstance(UInstance(), string(""), string(""));
_LastInstanceUnderPos= NULL;
// If not initialised, return
if (_ShapeInstances.empty())
return selectedInstance;
// build the ray
CMatrix camMatrix = MainCam.getMatrix();
CFrustum camFrust = MainCam.getFrustum();
CViewport viewport = Driver->getViewport();
// Get the Ray made by the mouse.
CVector pos, dir;
viewport.getRayWithPoint(x, y, pos, dir, camMatrix, camFrust);
// Normalize the direction.
dir.normalize();
// **** Get instances with box intersecting the ray.
float bestDist = 255;
for(uint i=0; i<_ShapeInstances.size(); i++)
{
if (_ShapeInstances[i].BboxActive)
{
H_AUTO(RZ_Client_GEUP_box_intersect)
// if intersect the bbox
NLMISC::CAABBox bbox;
//= _ShapeInstances[i].SelectionBox;
_ShapeInstances[i].Instance.getShapeAABBox(bbox);
if (bbox.getCenter() == CVector::Null)
{
bbox.setMinMax(CVector(-0.3f, -0.3f, -0.3f)+_ShapeInstances[i].Instance.getPos(), CVector(0.3f, 0.3f, 0.3f)+_ShapeInstances[i].Instance.getPos());
}
else
{
bbox.setMinMax((bbox.getMin()*_ShapeInstances[i].Instance.getScale().x)+_ShapeInstances[i].Instance.getPos(), (bbox.getMax()*_ShapeInstances[i].Instance.getScale().x)+_ShapeInstances[i].Instance.getPos());
}
if(bbox.intersect(pos, pos+dir*15.0f))
{
float dist = (bbox.getCenter()-pos).norm();
if (dist < bestDist)
{
selectedInstance = _ShapeInstances[i];
bestDist = dist;
}
}
}
}
return selectedInstance;
}
//-----------------------------------------------
// Create an entity according to the slot and the form.
// \param uint slot : slot for the entity.

View file

@ -85,8 +85,28 @@ public:
uint Slot;
};
/*
* Class to make cache shape instances
*/
class CShapeInstanceReference
{
public:
CShapeInstanceReference (NL3D::UInstance instance, const string &text, const string &url, bool bbox_active=true)
{
Instance = instance;
ContextText = text;
ContextURL = url;
BboxActive = bbox_active;
}
NL3D::UInstance Instance;
string ContextText;
string ContextURL;
bool BboxActive;
};
/**
* Class to manage entities.
* Class to manage entities and shapes instances.
* \author Guillaume PUZIN
* \author Nevrax France
* \date 2001
@ -106,6 +126,9 @@ private:
std::vector<CEntityReference> _ActiveEntities;
std::vector<CEntityReference> _VisibleEntities;
/// Shapes Instances caches
std::vector<CShapeInstanceReference> _ShapeInstances;
typedef struct
{
NLMISC::TGameCycle GC;
@ -123,6 +146,8 @@ private:
// For selection. NB: the pointer is just a cache. Must not be accessed
CEntityCL *_LastEntityUnderPos;
NL3D::UInstance _LastInstanceUnderPos;
//////////////
//// DEBUG ///
uint _NbUser;
@ -174,6 +199,11 @@ public:
/// Release + initialize
void reinit();
CShapeInstanceReference createInstance(const string& shape, const CVector &pos, const string &text, const string &url, bool active=true);
bool removeInstances();
CShapeInstanceReference getShapeInstanceUnderPos(float x, float y);
/**
* Create an entity according to the slot and the form.
* \param uint slot : slot for the entity.

View file

@ -2511,12 +2511,20 @@ NLMISC::CRGBA CEntityCL::getColor () const
{
if (isEnemy())
{
if (getPvpMode()&PVP_MODE::PvpFactionFlagged || getPvpMode()&PVP_MODE::PvpChallenge)
return _PvpEnemyColor;
else
return CRGBA::CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A);
}
}
// neutral pvp
if (isNeutralPVP())
{
if (isInTeam())
return _PvpAllyInTeamColor;
if (isInGuild())
return _PvpAllyInGuildColor;
return _PvpNeutralColor;
}
// ally
@ -2526,7 +2534,11 @@ NLMISC::CRGBA CEntityCL::getColor () const
return _PvpAllyInTeamColor;
if(isInGuild())
return _PvpAllyInGuildColor;
if (getPvpMode()&PVP_MODE::PvpFactionFlagged)
return _PvpAllyColor;
else
return CRGBA::CRGBA(min(255, _PvpAllyColor.R+150), min(255, _PvpAllyColor.G+150), min(255, _PvpAllyColor.B+150),_PvpAllyColor.A);
}
// neutral
if (isInTeam())
@ -2795,9 +2807,11 @@ void CEntityCL::updateIsInTeam ()
presentProp && presentProp->getValueBool() )
{
_IsInTeam= true;
buildInSceneInterface();
return;
}
}
buildInSceneInterface();
}
//-----------------------------------------------
@ -3051,13 +3065,15 @@ void CEntityCL::updateVisiblePostPos(const NLMISC::TTime &/* currentTimeInMs */,
position = pos().asVector();
position.z= _SelectBox.getMin().z;
mat.setPos(position);
mat.setRot(dirMatrix());
_StateFX.setTransformMode(NL3D::UTransformable::DirectMatrix);
_StateFX.setMatrix(mat);
if (skeleton())
_StateFX.setClusterSystem(skeleton()->getClusterSystem());
}
else if (!_SelectionFX.empty() || !_MouseOverFX.empty())
if (!_SelectionFX.empty() || !_MouseOverFX.empty())
{
// Build a matrix for the fx
NLMISC::CMatrix mat;

View file

@ -686,7 +686,7 @@ public:
virtual bool isNeutralPVP() const { return false; }
/// Return true if this player has the viewing properties of a friend (inscene bars...)
virtual bool isViewedAsFriend() const { return isNeutral() || isFriend(); }
virtual bool isViewedAsFriend() const { return isNeutral() || isFriend() || isInTeam() || isInGuild(); }
/// Return the People for the entity (unknown by default)
virtual EGSPD::CPeople::TPeople people() const;
@ -760,6 +760,12 @@ public:
return _Title;
}
/// Return the raw unparsed entity title
const ucstring getTitleRaw() const
{
return ucstring(_TitleRaw);
}
/// Return true if this entity has a reserved title
bool hasReservedTitle() const { return _HasReservedTitle; }

View file

@ -1364,6 +1364,10 @@ void loadBackgroundBitmap (TBackground background)
string ext = CFile::getExtension (ClientCfg.Launch_BG);
string filename;
if (frand(2.0) < 1)
filename = name+"_0."+ext;
else
filename = name+"_1."+ext;
switch (background)
{
case ElevatorBackground:
@ -1397,13 +1401,6 @@ void loadBackgroundBitmap (TBackground background)
filename = ClientCfg.Loading_BG;
break;
default:
/*
if (frand(2.0) < 1)
filename = name+"_0."+ext;
else
filename = name+"_1."+ext;
*/
filename = name+"."+ext;
break;
}

View file

@ -2440,6 +2440,174 @@ class CAHTarget : public IActionHandler
};
REGISTER_ACTION_HANDLER (CAHTarget, "target");
class CAHAddShape : public IActionHandler
{
virtual void execute (CCtrlBase * /* pCaller */, const string &Params)
{
string sShape = getParam(Params, "shape");
if(sShape.empty())
{
nlwarning("Command 'add_shape': need at least the parameter shape.");
return;
}
if (!Scene)
{
nlwarning("No scene available");
return;
}
double x = UserEntity->pos().x;
double y = UserEntity->pos().y;
double z = UserEntity->pos().z;
CVector userDir = UserEntity->dir();
float s = 1.0f;
string skeleton = getParam(Params, "skeleton");
string c = getParam(Params, "text");
string u = getParam(Params, "url");
string texture_name = getParam(Params, "texture");
string highlight = getParam(Params, "texture");
string transparency = getParam(Params, "transparency");
if (!getParam(Params, "x").empty())
fromString(getParam(Params, "x"), x);
if (!getParam(Params, "y").empty())
fromString(getParam(Params, "y"), y);
if (!getParam(Params, "z").empty())
fromString(getParam(Params, "z"), z);
if (!getParam(Params, "scale").empty())
fromString(getParam(Params, "scale"), s);
if (!getParam(Params, "angle").empty())
{
float a;
fromString(getParam(Params, "angle"), a);
userDir = CVector(sin(a), cos(a), 0.f);
}
bool have_shapes = true;
bool first_shape = true;
while(have_shapes)
{
string shape;
string::size_type index = sShape.find(string(" "));
// multiple shapes/fx
if (index != string::npos)
{
shape = sShape.substr(0, index);
sShape = sShape.substr(index+1);
} else {
shape = sShape;
have_shapes = false;
}
CShapeInstanceReference instref = EntitiesMngr.createInstance(shape, CVector((float)x, (float)y, (float)z), c, u, first_shape);
UInstance instance = instref.Instance;
if(!instance.empty())
{
for(uint j=0;j<instance.getNumMaterials();j++)
{
if (highlight.empty())
{
instance.getMaterial(j).setAmbient(CRGBA(0,0,0,255));
instance.getMaterial(j).setShininess( 10.0f );
instance.getMaterial(j).setEmissive(CRGBA(255,255,255,255));
}
else
{
instance.getMaterial(j).setAmbient(CRGBA(0,0,0,255));
instance.getMaterial(j).setEmissive(CRGBA(255,0,0,255));
instance.getMaterial(j).setShininess( 1000.0f );
}
if (!texture_name.empty() && first_shape)
{
sint numStages = instance.getMaterial(j).getLastTextureStage() + 1;
for(sint l = 0; l < numStages; l++)
{
if (instance.getMaterial(j).isTextureFile((uint) l))
{
instance.getMaterial(j).setTextureFileName(texture_name, (uint) l);
}
}
}
}
first_shape = false;
if (transparency.empty())
::makeInstanceTransparent(instance, 255, false);
else
::makeInstanceTransparent(instance, 100, true);
instance.setClusterSystem(UserEntity->getClusterSystem()); // for simplicity, assume it is in the same
// cluster system than the user
// Compute the direction Matrix
CMatrix dir;
dir.identity();
CVector vi = userDir^CVector(0.f, 0.f, 1.f);
CVector vk = vi^userDir;
dir.setRot(vi, userDir, vk, true);
// Set Orientation : User Direction should be normalized.
if (!skeleton.empty())
{
USkeleton skel = Scene->createSkeleton(skeleton);
if (!skel.empty())
{
skel.bindSkin(instance);
skel.setClusterSystem(UserEntity->getClusterSystem());
skel.setScale(skel.getScale()*s);
skel.setPos(CVector((float)x, (float)y, (float)z));
skel.setRotQuat(dir.getRot());
}
} else {
instance.setScale(instance.getScale()*s);
instance.setPos(CVector((float)x, (float)y, (float)z));
instance.setRotQuat(dir.getRot());
}
// if the shape is a particle system, additionnal parameters are user params
UParticleSystemInstance psi;
psi.cast (instance);
/*if (!psi.empty())
{
// set each user param that is present
for(uint k = 0; k < 4; ++k)
{
if (args.size() >= (k + 2))
{
float uparam;
if (fromString(args[k + 1], uparam))
{
psi.setUserParam(k, uparam);
}
else
{
nlwarning("Cant read param %d", k);
}
}
}
}*/
}
else
nlwarning("Command 'add_shape': cannot find the shape %s.", sShape.c_str());
}
return;
}
};
REGISTER_ACTION_HANDLER (CAHAddShape, "add_shape");
class CAHRemoveShapes : public IActionHandler
{
virtual void execute (CCtrlBase * /* pCaller */, const string &Params)
{
EntitiesMngr.removeInstances();
}
};
REGISTER_ACTION_HANDLER (CAHRemoveShapes, "remove_shapes");
// ***************************************************************************
// See also CHandlerTeamTarget
class CAHTargetTeammateShortcut : public IActionHandler

View file

@ -104,7 +104,9 @@ static void setupMissionHelp(CSheetHelpSetup &setup);
#define INFO_LIST_BRICK_REQUIREMENT "list_brick_requirement"
#define INFO_GROUP_MP_STAT "mp_stats"
#define INFO_GROUP_CHAR_3D "char3d"
#define INFO_ITEM_PREVIEW "item_preview"
#define INFO_ITEM_PREVIEW_SCENE_3D "scene_item_preview"
#define ITEM_PREVIEW_WIDTH 200
// ***************************************************************************
std::deque<uint> CInterfaceHelp::_ActiveWindows;
@ -2178,6 +2180,14 @@ void resetSheetHelp(CSheetHelpSetup &setup)
{
listItem->setActive(false);
}
// Hide the item preview by default
CInterfaceElement *elt= group->getElement(group->getId()+setup.PrefixForExtra+INFO_ITEM_PREVIEW);
if(elt)
{
elt->setActive(false);
}
// Hide the list of brick by default
IListSheetBase *listBrick= dynamic_cast<IListSheetBase*>(group->getElement(group->getId()+setup.PrefixForExtra+INFO_LIST_BRICK));
if(listBrick)
@ -2268,6 +2278,151 @@ void setupCosmetic(CSheetHelpSetup &setup, CItemSheet *pIS)
}
}
// ***************************************************************************
void setupItemPreview(CSheetHelpSetup &setup, CItemSheet *pIS)
{
nlassert(pIS);
CInterfaceManager *pIM = CInterfaceManager::getInstance();
CCDBNodeBranch *dbBranch = pIM->getDbBranch( setup.SrcSheet->getSheet() );
CInterfaceElement *elt = setup.HelpWindow->getElement(setup.HelpWindow->getId()+setup.PrefixForExtra+INFO_ITEM_PREVIEW);
if (elt == NULL)
return;
CInterfaceGroup *ig = dynamic_cast<CInterfaceGroup*>(elt);
if ( ! ig)
{
return;
}
static sint32 helpWidth = setup.HelpWindow->getW();
bool scene_inactive = ! pIM->getDbProp("UI:SAVE:SHOW_3D_ITEM_PREVIEW")->getValueBool();
if (scene_inactive ||
(pIS->Family != ITEMFAMILY::ARMOR &&
pIS->Family != ITEMFAMILY::MELEE_WEAPON &&
pIS->Family != ITEMFAMILY::RANGE_WEAPON &&
pIS->Family != ITEMFAMILY::SHIELD))
{
setup.HelpWindow->setW(helpWidth);
ig->setActive(false);
return;
}
else
{
setup.HelpWindow->setW(helpWidth + ITEM_PREVIEW_WIDTH);
ig->setActive(true);
}
CInterface3DScene *sceneI = dynamic_cast<CInterface3DScene *>(ig->getGroup("scene_item_preview"));
if (!sceneI)
{
nlwarning("Can't retrieve character 3d view, or bad type");
ig->setActive(false);
return;
}
CInterface3DCharacter *char3DI = NULL;
if (sceneI->getCharacter3DCount() != 0)
char3DI = sceneI->getCharacter3D(0);
if (char3DI == NULL)
{
nlwarning("Can't retrieve char 3D Interface");
ig->setActive(false);
return;
}
CInterface3DCamera *camera = sceneI->getCamera(0);
if (camera == NULL)
{
nlwarning("Can't retrieve camera");
ig->setActive(false);
return;
}
SCharacter3DSetup c3Ds;
CCharacterSummary cs;
SCharacter3DSetup::setupCharacterSummaryFromSERVERDB( cs );
float camHeight = -0.85f;
if (pIS->Family == ITEMFAMILY::ARMOR)
{
if (pIS->ItemType == ITEM_TYPE::LIGHT_BOOTS || pIS->ItemType == ITEM_TYPE::MEDIUM_BOOTS || pIS->ItemType == ITEM_TYPE::HEAVY_BOOTS)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropB.PropertySubData.FeetModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::FEET_SLOT );
cs.VisualPropB.PropertySubData.FeetColor = color->getValue32();
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
camHeight = -1.15f;
}
else if (pIS->ItemType == ITEM_TYPE::LIGHT_GLOVES || pIS->ItemType == ITEM_TYPE::MEDIUM_GLOVES || pIS->ItemType == ITEM_TYPE::HEAVY_GLOVES)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropB.PropertySubData.HandsModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::HANDS_SLOT );
cs.VisualPropB.PropertySubData.HandsColor = color->getValue32();
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
//cs.VisualPropB.PropertySubData.HandsColor = pIS->Color;
}
else if (pIS->ItemType == ITEM_TYPE::LIGHT_SLEEVES || pIS->ItemType == ITEM_TYPE::MEDIUM_SLEEVES || pIS->ItemType == ITEM_TYPE::HEAVY_SLEEVES)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropA.PropertySubData.ArmModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::ARMS_SLOT );
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
SCharacter3DSetup::setDB("UI:TEMP:CHAR3D:VPA:ARMCOLOR", pIS->Color);
//cs.VisualPropA.PropertySubData.ArmColor = pIS->Color;
camHeight = -0.55f;
}
else if (pIS->ItemType == ITEM_TYPE::LIGHT_PANTS || pIS->ItemType == ITEM_TYPE::MEDIUM_PANTS || pIS->ItemType == ITEM_TYPE::HEAVY_PANTS)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropA.PropertySubData.TrouserModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::LEGS_SLOT );
cs.VisualPropA.PropertySubData.TrouserColor = color->getValue32();
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
camHeight = -1.00f;
}
else if (pIS->ItemType == ITEM_TYPE::LIGHT_VEST || pIS->ItemType == ITEM_TYPE::MEDIUM_VEST || pIS->ItemType == ITEM_TYPE::HEAVY_VEST)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropA.PropertySubData.JacketModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::CHEST_SLOT );
cs.VisualPropA.PropertySubData.JacketColor = color->getValue32();
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
camHeight = -0.55f;
}
else if (pIS->ItemType == ITEM_TYPE::HEAVY_HELMET)
{
CCDBNodeLeaf *color = dbBranch->getLeaf( setup.SrcSheet->getSheet()+":USER_COLOR", false );
cs.VisualPropA.PropertySubData.HatModel = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::HEAD_SLOT );
cs.VisualPropA.PropertySubData.HatColor = color->getValue32();
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
camHeight = -0.35f;
}
}
else if (pIS->Family == ITEMFAMILY::SHIELD)
{
cs.VisualPropA.PropertySubData.WeaponLeftHand = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::LEFT_HAND_SLOT );
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
}
else if (pIS->Family == ITEMFAMILY::MELEE_WEAPON || pIS->Family == ITEMFAMILY::RANGE_WEAPON)
{
cs.VisualPropA.PropertySubData.WeaponRightHand = CVisualSlotManager::getInstance()->sheet2Index( CSheetId(setup.SrcSheet->getSheetId()), SLOTTYPE::RIGHT_HAND_SLOT );
SCharacter3DSetup::setupDBFromCharacterSummary("UI:TEMP:CHAR3D", cs);
}
else
nlwarning("<setupItemPreview> Invalid armour or weapon item type '%s'", ITEM_TYPE::toString( pIS->ItemType ).c_str() );
if (camera == NULL)
return;
camera->setTgtZ(camHeight);
char3DI->setAnim(CAnimationStateSheet::Idle);
}
// ***************************************************************************
void refreshItemHelp(CSheetHelpSetup &setup)
{
@ -2291,6 +2446,9 @@ void refreshItemHelp(CSheetHelpSetup &setup)
// ---- Cosmetic only
setupCosmetic (setup, pIS);
// ---- item preview
setupItemPreview(setup, pIS);
}
// if this is a R2 plot item, Add comment and description

View file

@ -312,8 +312,7 @@ void CChatTargetFilter::msgEntered(const ucstring &msg, CChatWindow *chatWindow)
else if (!_TargetPlayer.empty())
{
// the target must be a player, make a tell on him
// TODO: adapt this to unicode when this is OK on server side
ChatMngr.tell(_TargetPlayer.toString(), msg.toString());
ChatMngr.tell(_TargetPlayer.toString(), msg);
// direct output in the chat
chatWindow->displayLocalPlayerTell(msg);
}

View file

@ -472,7 +472,13 @@ void CChatWindow::displayLocalPlayerTell(const ucstring &msg, uint numBlinks /*=
CInterfaceProperty prop;
prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
encodeColorTag(prop.getRGBA(), finalMsg, false);
finalMsg += CI18N::get("youTell") + ": ";
ucstring cur_time;
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : "";
finalMsg += cur_time + csr + CI18N::get("youTell") + ": ";
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
encodeColorTag(prop.getRGBA(), finalMsg, true);
finalMsg += msg;
@ -1241,6 +1247,13 @@ public:
return;
}
// Parse any tokens in the text
if ( ! CInterfaceManager::parseTokens(text))
{
pEB->setInputString (string(""));
return;
}
// if, it s a command, execute it and don't send the command to the server
if(text[0] == '/')
{
@ -1256,7 +1269,7 @@ public:
else
{
CInterfaceManager *im = CInterfaceManager::getInstance();
im->displaySystemInfo (ucstring(cmd+" : ")+CI18N::get ("uiCommandNotExists"));
im->displaySystemInfo (ucstring(cmd+": ")+CI18N::get ("uiCommandNotExists"));
}
}
else

View file

@ -45,6 +45,10 @@ extern "C"
#include "lua_ihm.h"
#include "../time_client.h"
#include "nel/misc/i18n.h"
#include "nel/misc/md5.h"
#include "nel/3d/texture_file.h"
#include "nel/misc/big_file.h"
using namespace std;
using namespace NLMISC;
@ -107,15 +111,106 @@ void CGroupHTML::addImageDownload(const string &url, CViewBase *img)
curl_easy_setopt(curl, CURLOPT_FILE, fp);
curl_multi_add_handle(MultiCurl, curl);
Curls.push_back(CImageDownload(curl, url, fp, img));
Curls.push_back(CDataDownload(curl, url, fp, ImgType, img));
#ifdef LOG_DL
nlwarning("adding handle %x, %d curls", curl, Curls.size());
#endif
RunningCurls++;
}
// Call this evenly to check if an image in downloaded and then display it
void CGroupHTML::checkImageDownload()
void CGroupHTML::initImageDownload()
{
#ifdef LOG_DL
nlwarning("Init Image Download");
#endif
/*
// Get current flag
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
// Turn on leak-checking bit
tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF;
// Set flag to the new value
_CrtSetDbgFlag( tmpFlag );
*/
string pathName = "cache";
if ( ! CFile::isExists( pathName ) )
CFile::createDirectory( pathName );
}
// Get an url and return the local filename with the path where the bnp should be
string CGroupHTML::localBnpName(const string &url)
{
size_t lastIndex = url.find_last_of("/");
string dest = "user/"+url.substr(lastIndex+1);
return dest;
}
// Add a bnp download request in the multi_curl
void CGroupHTML::addBnpDownload(const string &url, const string &action)
{
// Search if we are not already downloading this url.
for(uint i = 0; i < Curls.size(); i++)
{
if(Curls[i].url == url)
{
#ifdef LOG_DL
nlwarning("already downloading '%s'", url.c_str());
#endif
return;
}
}
CURL *curl = curl_easy_init();
if (!MultiCurl || !curl)
return;
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
string dest = localBnpName(url);
#ifdef LOG_DL
nlwarning("add to download '%s' dest '%s'", url.c_str(), dest.c_str());
#endif
// create the local file
if (NLMISC::CFile::fileExists(dest))
{
if (action == "override" || action == "delete")
{
CFile::setRWAccess(dest);
NLMISC::CFile::deleteFile(dest.c_str());
}
}
if (action != "delete")
{
FILE *fp = fopen (dest.c_str(), "wb");
if (fp == NULL)
{
nlwarning("Can't open file '%s' for writing: code=%d '%s'", dest.c_str (), errno, strerror(errno));
return;
}
curl_easy_setopt(curl, CURLOPT_FILE, fp);
curl_multi_add_handle(MultiCurl, curl);
Curls.push_back(CDataDownload(curl, url, fp, BnpType, NULL));
#ifdef LOG_DL
nlwarning("adding handle %x, %d curls", curl, Curls.size());
#endif
RunningCurls++;
}
}
void CGroupHTML::initBnpDownload()
{
#ifdef LOG_DL
nlwarning("Init Bnp Download");
#endif
string pathName = "user";
if ( ! CFile::isExists( pathName ) )
CFile::createDirectory( pathName );
}
// Call this evenly to check if an element is downloaded and then manage it
void CGroupHTML::checkDownloads()
{
//nlassert(_CrtCheckMemory());
@ -142,7 +237,7 @@ void CGroupHTML::checkImageDownload()
{
if (msg->msg == CURLMSG_DONE)
{
for (vector<CImageDownload>::iterator it=Curls.begin(); it<Curls.end(); it++)
for (vector<CDataDownload>::iterator it=Curls.begin(); it<Curls.end(); it++)
{
if(msg->easy_handle == it->curl)
{
@ -156,15 +251,23 @@ void CGroupHTML::checkImageDownload()
#endif
curl_easy_cleanup(it->curl);
string image = localImageName(it->url);
string file;
if(CURLE_OK != res || r < 200 || r >= 300)
if (it->type == ImgType)
file = localImageName(it->url)+".tmp";
else
file = localBnpName(it->url);
if(res != CURLE_OK || r < 200 || r >= 300)
{
NLMISC::CFile::deleteFile((image+".tmp").c_str());
NLMISC::CFile::deleteFile(file.c_str());
}
else
{
string finalUrl;
if (it->type == ImgType)
{
string image = localImageName(it->url);
CFile::moveFile(image.c_str(), (image+".tmp").c_str());
if (lookupLocalFile (finalUrl, image.c_str(), false))
{
@ -179,9 +282,9 @@ void CGroupHTML::checkImageDownload()
CCtrlButton *btn = dynamic_cast<CCtrlButton*>(it->imgs[i]);
if(btn)
{
#ifdef LOG_DL
#ifdef LOG_DL
nlwarning("refresh new downloading image %d button %p", i, it->imgs[i]);
#endif
#endif
btn->setTexture (image);
btn->setTexturePushed(image);
btn->invalidateCoords();
@ -195,9 +298,9 @@ void CGroupHTML::checkImageDownload()
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(it->imgs[i]);
if(btm)
{
#ifdef LOG_DL
#ifdef LOG_DL
nlwarning("refresh new downloading image %d image %p", i, it->imgs[i]);
#endif
#endif
btm->setTexture (image);
btm->invalidateCoords();
btm->invalidateContent();
@ -209,6 +312,27 @@ void CGroupHTML::checkImageDownload()
}
}
}
else
{
if (lookupLocalFile (finalUrl, file.c_str(), false))
{
nlinfo("BNPCHECK : downloaded");
bool memoryCompressed = CPath::isMemoryCompressed();
if (memoryCompressed)
{
CPath::memoryUncompress();
}
CPath::addSearchPath("user/", true, false, NULL);
if (memoryCompressed)
{
CPath::memoryCompress();
}
CInterfaceManager *pIM = CInterfaceManager::getInstance();
pIM->executeLuaScript("game:onBnpDownloadFinish()", true);
}
}
}
Curls.erase(it);
break;
@ -220,32 +344,11 @@ void CGroupHTML::checkImageDownload()
RunningCurls = NewRunningCurls;
}
void CGroupHTML::initImageDownload()
void CGroupHTML::releaseDownloads()
{
#ifdef LOG_DL
nlwarning("Init Image Download");
#endif
MultiCurl = curl_multi_init();
RunningCurls = 0;
/*
// Get current flag
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
// Turn on leak-checking bit
tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF;
// Set flag to the new value
_CrtSetDbgFlag( tmpFlag );
*/
string pathName = "cache";
if ( ! CFile::isExists( pathName ) )
CFile::createDirectory( pathName );
}
void CGroupHTML::releaseImageDownload()
{
#ifdef LOG_DL
nlwarning("Release Image Download");
nlwarning("Release Downloads");
#endif
if(MultiCurl)
curl_multi_cleanup(MultiCurl);
@ -1251,6 +1354,21 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c
endParagraph();
_UL.push_back(true);
break;
case HTML_OBJECT:
_ObjectType = "";
_ObjectData = "";
_ObjectMD5Sum = "";
_ObjectAction = "";
if (present[HTML_OBJECT_TYPE] && value[HTML_OBJECT_TYPE])
_ObjectType = value[HTML_OBJECT_TYPE];
if (present[HTML_OBJECT_DATA] && value[HTML_OBJECT_DATA])
_ObjectData = value[HTML_OBJECT_DATA];
if (present[HTML_OBJECT_ID] && value[HTML_OBJECT_ID])
_ObjectMD5Sum = value[HTML_OBJECT_ID];
if (present[HTML_OBJECT_STANDBY] && value[HTML_OBJECT_STANDBY])
_ObjectAction = value[HTML_OBJECT_STANDBY];
break;
}
}
}
@ -1371,6 +1489,14 @@ void CGroupHTML::endElement (uint element_number)
popIfNotEmpty (_UL);
}
break;
case HTML_OBJECT:
if (_ObjectType=="application/ryzom-data")
{
if (!_ObjectData.empty())
{
addBnpDownload(_ObjectData, _ObjectAction);
}
}
}
}
}
@ -1483,7 +1609,11 @@ CGroupHTML::CGroupHTML(const TCtorParam &param)
DefaultBackgroundBitmapView = "bg";
clearContext();
MultiCurl = curl_multi_init();
RunningCurls = 0;
initImageDownload();
initBnpDownload();
}
// ***************************************************************************
@ -2313,9 +2443,14 @@ CCtrlButton *CGroupHTML::addButton(CCtrlButton::EType type, const std::string &/
ctrlButton->setActionOnLeftClick (actionHandler);
ctrlButton->setParamsOnLeftClick (actionHandlerParams);
// Translate the tooltip
// Translate the tooltip or display raw text (tooltip from webig)
if (tooltip)
ctrlButton->setDefaultContextHelp (CI18N::get (tooltip));
{
if (CI18N::hasTranslation(tooltip))
ctrlButton->setDefaultContextHelp (CI18N::get(tooltip));
else
ctrlButton->setDefaultContextHelp (ucstring(tooltip));
}
getParagraph()->addChild (ctrlButton);
paragraphChange ();
@ -2913,7 +3048,7 @@ void CGroupHTML::handle ()
void CGroupHTML::draw ()
{
checkImageDownload();
checkDownloads();
CGroupScrollText::draw ();
}

View file

@ -293,6 +293,8 @@ protected :
// the script to execute
std::string _LuaScript;
bool _ParsingBnpUrl;
std::string _BnpUrl;
// Someone is conecting. We got problem with libwww : 2 connection requests can deadlock the client.
static CGroupHTML *_ConnectingLock;
@ -481,6 +483,12 @@ protected :
bool _SelectOption;
ucstring _SelectOptionStr;
// Current node is a object
std::string _ObjectType;
std::string _ObjectData;
std::string _ObjectMD5Sum;
std::string _ObjectAction;
// Get last char
ucchar getLastChar() const;
@ -527,25 +535,38 @@ private:
static ucstring decodeHTMLEntities(const ucstring &str);
// ImageDownload system
enum TDataType {ImgType= 0, BnpType};
struct CImageDownload
struct CDataDownload
{
CImageDownload(CURL *c, const std::string &u, FILE *f, CViewBase *i) : curl(c), url(u), fp(f) { imgs.push_back(i); }
CDataDownload(CURL *c, const std::string &u, FILE *f, TDataType t, CViewBase *i) : curl(c), url(u), fp(f), type(t) { imgs.push_back(i); }
CURL *curl;
std::string url;
TDataType type;
FILE *fp;
std::vector<CViewBase *> imgs;
};
std::vector<CImageDownload> Curls;
std::vector<CDataDownload> Curls;
CURLM *MultiCurl;
int RunningCurls;
void initImageDownload();
void releaseImageDownload();
void checkImageDownload();
void addImageDownload(const std::string &url, CViewBase *img);
std::string localImageName(const std::string &url);
// BnpDownload system
void initBnpDownload();
void checkBnpDownload();
void addBnpDownload(const std::string &url, const std::string &action);
std::string localBnpName(const std::string &url);
void releaseDownloads();
void checkDownloads();
};
// adapter group that store y offset for inputs inside an html form

View file

@ -514,6 +514,13 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity)
if (!isForageSource)
{
CViewBase * invisibleLogo = info->getView("invisible_logo");
if (entity->isUser() && invisibleLogo)
{
bool invisible = pIM->getDbProp("SERVER:USER:IS_INVISIBLE")->getValueBool();
invisibleLogo->setActive(invisible);
}
// Get the target bitmap
CViewBase *target = leftGroup->getView ("target");
if (target)
@ -532,23 +539,89 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity)
info->_MissionTarget = bitmap;
}
// set or inactive pvp logos
CViewBase * pvpCivLogo = info->getView ("pvp_faction_civ_logo");
CViewBase * pvpCultLogo = info->getView ("pvp_faction_cult_logo");
CPlayerCL * pPlayer = dynamic_cast<CPlayerCL*>(entity);
if (pPlayer != NULL && needPvPLogo)
if (pPlayer == NULL)
needPvPLogo = false;
// set or inactive pvp logos
bool needCivPvpLogo = needPvPLogo;
bool needCultPvpLogo = needPvPLogo;
if (pPlayer != NULL && needPvPLogo && pvpCivLogo && pvpCultLogo)
{
CViewBase * pvpFactionLogo = info->getView ("pvp_faction_logo");
if (pvpFactionLogo)
uint8 civToDisplay = (uint8)(pPlayer->getClanCivMaxFame() & 0xFF);
uint8 cultToDisplay = (uint8)(pPlayer->getClanCultMaxFame() & 0xFF);
if (!entity->isUser())
{
if( pPlayer->getPvpMode()&PVP_MODE::PvpFaction || pPlayer->getPvpMode()&PVP_MODE::PvpFactionFlagged)
// Check if are Civ Allies
for (uint8 i = 0; i < 4; i++)
if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpAlly(i)) ||
(pPlayer->isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) )
civToDisplay = i;
// Check if are Civ Ennemies
for (uint8 i = 0; i < 4; i++)
if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) ||
(pPlayer->isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) )
civToDisplay = i;
// Check if are Cult Allies
for (uint8 i = 4; i < 7; i++)
if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpAlly(i)) ||
(pPlayer->isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) )
cultToDisplay = i;
// Check if are Cult Ennemies
for (uint8 i = 4; i < 7; i++)
if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) ||
(pPlayer->isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) )
cultToDisplay = i;
}
if ((pPlayer->getPvpMode() & PVP_MODE::PvpFaction) || (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged))
{
CViewBitmap * pvpFactionLogoBmp = dynamic_cast<CViewBitmap *>(pvpFactionLogo);
if( pvpFactionLogoBmp )
pvpFactionLogoBmp->setTexture( pIM->getDefine(PVP_CLAN::toIconDefineString(pPlayer->getPvpClan())) );
CViewBitmap * pvpCivLogoBmp = dynamic_cast<CViewBitmap *>(pvpCivLogo);
if( pvpCivLogoBmp )
{
if (pPlayer->isPvpAlly(civToDisplay))
if (pPlayer->isPvpRanger())
pvpCivLogoBmp->setTexture("pvp_ally_ranger.tga");
else
pvpCivLogoBmp->setTexture("pvp_ally_"+toString(civToDisplay)+".tga");
else if (pPlayer->isPvpEnnemy(civToDisplay))
if (pPlayer->isPvpMarauder())
pvpCivLogoBmp->setTexture("pvp_enemy_marauder.tga");
else
pvpCivLogoBmp->setTexture("pvp_enemy_"+toString(civToDisplay)+".tga");
else
needCivPvpLogo = false;
}
CViewBitmap * pvpCultLogoBmp = dynamic_cast<CViewBitmap *>(pvpCultLogo);
if( pvpCultLogoBmp )
{
if (pPlayer->isPvpAlly(cultToDisplay))
if (pPlayer->isPvpPrimas())
pvpCultLogoBmp->setTexture("pvp_ally_primas.tga");
else
pvpCultLogoBmp->setTexture("pvp_ally_"+toString(cultToDisplay)+".tga");
else if (pPlayer->isPvpEnnemy(cultToDisplay))
if (pPlayer->isPvpTrytonist())
pvpCultLogoBmp->setTexture("pvp_enemy_trytonist.tga");
else
pvpCultLogoBmp->setTexture("pvp_enemy_"+toString(cultToDisplay)+".tga");
else
needCultPvpLogo = false;
}
}
else
{
pvpFactionLogo->setActive(false);
}
needCivPvpLogo = false;
needCultPvpLogo = false;
}
CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo");
@ -563,7 +636,7 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity)
CViewBase * pvpDuelLogo = info->getView ("pvp_duel_logo");
if (pvpDuelLogo)
{
if( !(pPlayer->getPvpMode()&PVP_MODE::PvpDuel) )
if( !(pPlayer->getPvpMode()&PVP_MODE::PvpDuel || pPlayer->getPvpMode()&PVP_MODE::PvpChallenge) )
{
pvpDuelLogo->setActive(false);
}
@ -571,11 +644,6 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity)
}
else
{
// unactive pvp logos
CViewBase * pvpFactionLogo = info->getView ("pvp_faction_logo");
if (pvpFactionLogo)
pvpFactionLogo->setActive(false);
CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo");
if (pvpOutpostLogo)
pvpOutpostLogo->setActive(false);
@ -584,6 +652,13 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity)
if (pvpDuelLogo)
pvpDuelLogo->setActive(false);
}
if (pvpCivLogo)
pvpCivLogo->setActive(needCivPvpLogo);
if (pvpCultLogo)
pvpCultLogo->setActive(needCultPvpLogo);
}
// No bar and no string ?

View file

@ -47,6 +47,7 @@
using namespace std;
using namespace NLMISC;
extern CPeopleInterraction PeopleInterraction;
NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListAscensor, std::string, "list_sheet_guild");
@ -68,6 +69,7 @@ NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListAscensor, std::string, "list_sheet
#define TEMPLATE_GUILD_MEMBER_NAME "name"
#define TEMPLATE_GUILD_MEMBER_GRADE "grade"
#define TEMPLATE_GUILD_MEMBER_SCORE "score"
#define TEMPLATE_GUILD_MEMBER_ENTER_DATE "enter_date"
#define MENU_GUILD_MEMBER "ui:interface:menu_member"
#define WIN_ASCENSOR "ui:interface:ascensor_teleport_list"
@ -109,16 +111,53 @@ static inline bool lt_member_grade(const SGuildMember &m1, const SGuildMember &m
return m1.Grade < m2.Grade;
}
static inline bool lt_member_online(const SGuildMember &m1, const SGuildMember &m2)
{
if (m1.Online == m2.Online)
{
return lt_member_grade(m1, m2);
}
// Compare online status
switch (m1.Online)
{
case ccs_online:
// m1 is < if m1 is online
return true;
break;
case ccs_online_abroad:
// m1 is < if m2 is offline
return (m2.Online == ccs_offline);
break;
case ccs_offline:
default:
// m2 is always < if m1 is offline
return false;
break;
}
}
// ***************************************************************************
void CGuildManager::sortGuildMembers()
void CGuildManager::sortGuildMembers(TSortOrder order)
{
if (_GuildMembers.size() < 2) return;
// First sort by name
switch (order)
{
default:
case sort_grade:
sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_name);
// Second sort by grade
stable_sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_grade);
break;
case sort_name:
sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_name);
break;
case sort_online:
sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_name);
stable_sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_online);
break;
}
}
bool CGuildManager::isProxy()
@ -715,8 +754,9 @@ class CAHGuildSheetOpen : public IActionHandler
// *** Update Members, if necessary
if(updateMembers)
{
CGuildManager::TSortOrder order = (CGuildManager::TSortOrder)(pIM->getDbProp("UI:SAVE:GUILD_LIST:SORT_ORDER")->getValue32());
// Sort the members in Guild Manager
pGM->sortGuildMembers();
pGM->sortGuildMembers(order);
// update member count view
const vector<SGuildMember> &rGuildMembers = pGM->getGuildMembers();
@ -784,6 +824,21 @@ class CAHGuildSheetOpen : public IActionHandler
}
}
// Enter Date
CViewText *pViewEnterDate = dynamic_cast<CViewText*>(pLine->getView(TEMPLATE_GUILD_MEMBER_ENTER_DATE));
if (pViewEnterDate != NULL)
{
CRyzomTime rt;
rt.updateRyzomClock(rGuildMembers[i].EnterDate);
ucstring str = toString("%04d", rt.getRyzomYear()) + " ";
str += CI18N::get("uiJenaYear") + " : ";
str += CI18N::get("uiAtysianCycle") + " ";
str += toString("%01d", rt.getRyzomCycle()+1) +", ";
str += CI18N::get("ui"+MONTH::toString( (MONTH::EMonth)rt.getRyzomMonthInCurrentCycle() )) + ", ";
str += toString("%02d", rt.getRyzomDayOfMonth()+1);
pViewEnterDate->setText(str);
}
// Add to the list
pLine->setParent (pParent);
pParent->addChild (pLine);
@ -852,15 +907,7 @@ class CAHGuildSheetMenuOpen : public IActionHandler
return;
}
// *** Check with the grade of the local player wich types of actions we can do on the player selected
// Grade less or equal cant do anything
if (pGM->getGrade() >= rGuildMembers[nLineNb].Grade)
{
// Close
pIM->disableModalWindow();
return;
}
// enable or disable menu entries
if (pGM->isProxy())
@ -871,7 +918,11 @@ class CAHGuildSheetMenuOpen : public IActionHandler
else
{
// Depending on the grade we can do things or other
if (pGM->getGrade() == EGSPD::CGuildGrade::Leader)
// Grade less or equal can't do anything
if (pGM->getGrade() >= rGuildMembers[nLineNb].Grade)
setRights(false, false, false, false, false, false, false);
else if (pGM->getGrade() == EGSPD::CGuildGrade::Leader)
setRights(true, true, true, true, true, true, true);
else if (pGM->getGrade() == EGSPD::CGuildGrade::HighOfficer)
setRights(false, false, true, true, true, true, true);
@ -928,6 +979,70 @@ static void sendMsgSetGrade(EGSPD::CGuildGrade::TGuildGrade Grade)
}
}
// ***************************************************************************
// Sort the guild member list
class CAHGuildSheetSortGuildList : public IActionHandler
{
public:
void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
{
CInterfaceManager* pIM= CInterfaceManager::getInstance();
CGuildManager::TSortOrder order = (CGuildManager::TSortOrder)(pIM->getDbProp("UI:SAVE:GUILD_LIST:SORT_ORDER")->getValue32());
order = (CGuildManager::TSortOrder)(order + 1);
if (order == CGuildManager::END_SORT_ORDER)
{
order = CGuildManager::START_SORT_ORDER;
}
pIM->getDbProp("UI:SAVE:GUILD_LIST:SORT_ORDER")->setValue32((sint32)order);
pIM->runActionHandler("guild_sheet_open", NULL, toString("update_members=1"));
}
};
REGISTER_ACTION_HANDLER(CAHGuildSheetSortGuildList, "sort_guild_list");
// ***************************************************************************
// Invoke the 'tell' command on a contact from its menu
// The tell command is displayed in the 'around me' window
class CAHGuildSheetTellMember : public IActionHandler
{
public:
void execute (CCtrlBase * pCaller, const std::string &/* sParams */)
{
CInterfaceManager *pIM = CInterfaceManager::getInstance();
CGuildManager *pGM = CGuildManager::getInstance();
const vector<SGuildMember> &rGuildMembers = pGM->getGuildMembers();
// *** Check and retrieve the current member index (index in the member list)
CCtrlBase *ctrlLaunchingModal= pIM->getCtrlLaunchingModal();
if (pCaller == NULL)
{
// Error -> Close
return;
}
string sId = pCaller->getId();
sId = sId.substr(sId.rfind('m')+1,sId.size());
sint32 nLineNb;
fromString(sId, nLineNb);
if ((nLineNb < 0) || (nLineNb >= (sint32)rGuildMembers.size()))
{
// Error -> Close
return;
}
MemberIndexSelected= nLineNb;
MemberNameSelected = rGuildMembers[nLineNb].Name;
CPeopleInterraction::displayTellInMainChat(MemberNameSelected);
}
// Current selection
static sint32 MemberIndexSelected; // Index of the member selected when left clicked
static ucstring MemberNameSelected; // Name of the member selected when lef clicked
};
REGISTER_ACTION_HANDLER(CAHGuildSheetTellMember, "guild_tell_member");
sint32 CAHGuildSheetTellMember::MemberIndexSelected= -1;
ucstring CAHGuildSheetTellMember::MemberNameSelected;
// ***************************************************************************
class CAHGuildSheetSetLeader : public IActionHandler
{

View file

@ -98,7 +98,16 @@ public:
const SGuild &getGuild() { return _Guild; }
const std::vector<SGuildMember> &getGuildMembers() { return _GuildMembers; }
void sortGuildMembers();
enum TSortOrder
{
sort_grade,
START_SORT_ORDER = sort_grade,
sort_name,
sort_online,
END_SORT_ORDER
};
void sortGuildMembers(TSortOrder order = sort_grade);
/// Check if the guild is a proxified guild (not managed on the actual shard)
bool isProxy();

View file

@ -506,7 +506,10 @@ void CInterface3DScene::draw ()
for (i = 0; i < _Characters.size(); ++i)
_Characters[i]->setClusterSystem ((UInstanceGroup*)-1);
for (i = 0; i < _Shapes.size(); ++i)
{
if (!_Shapes[i]->getShape().empty())
_Shapes[i]->getShape().setClusterSystem ((UInstanceGroup*)-1);
}
for (i = 0; i < _FXs.size(); ++i)
if (!_FXs[i]->getPS().empty())
_FXs[i]->getPS().setClusterSystem ((UInstanceGroup*)-1);
@ -1344,7 +1347,20 @@ std::string CInterface3DShape::getName() const
// ----------------------------------------------------------------------------
void CInterface3DShape::setName (const std::string &ht)
{
string lwrname = strlwr(ht);
if (ht.empty())
{
CInterface3DScene *pI3DS = dynamic_cast<CInterface3DScene*>(_Parent);
nlassert(pI3DS != NULL);
if (!_Instance.empty())
{
pI3DS->getScene()->deleteInstance(_Instance);
}
return;
_Name.clear();
}
string lwrname = toLower(ht);
if (lwrname != _Name)
{
CInterface3DScene *pI3DS = dynamic_cast<CInterface3DScene*>(_Parent);

View file

@ -101,6 +101,7 @@
#include "../entity_animation_manager.h" // for emotes
#include "../net_manager.h" // for emotes
#include "../client_chat_manager.h" // for emotes
#include "../entities.h"
#include "chat_text_manager.h"
#include "../npc_icon.h"
@ -1288,6 +1289,18 @@ void CInterfaceManager::updateFrameEvents()
pVT = dynamic_cast<CViewText*>(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*>(getElementFromId("ui:interface:compass:clock:time"));
if (pVT != NULL)
{
if (pVT->getActive())
{
str = getTimestampHuman("%H:%M");
pVT->setText(str);
}
}
}
}
@ -6274,3 +6287,300 @@ void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode *localNod
}
}
// ------------------------------------------------------------------------------------------------
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 == string::npos) ||
(end_pos == string::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) < 0)
{
// 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);
token_subject = token_vector[0];
if (token_vector.size() == 1)
{
splitUCString(token_subject, ucstring("/"), param_vector);
token_subject = param_vector[0];
token_param = ucstring("name");
}
else
{
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[0];
}
}
// 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 = CInterfaceManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH ":%hu:NAME", indexInTeam ), false);
if (pNL && pNL->getValueBool() )
{
// There is a character corresponding to this index
pNL = CInterfaceManager::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 = (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;
}
// Only care about gender if it's a humanoid.
GSGENDER::EGender gender = GSGENDER::neutral;
if (pTokenSubjectEntity->isUser() || pTokenSubjectEntity->isPlayer() || pTokenSubjectEntity->isNPC())
{
CCharacterCL *pC = (CCharacterCL*)(pTokenSubjectEntity);
if (pC)
{
gender = pC->getGender();
}
}
// 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 all occurances of token with the replacement
size_t token_whole_pos = str.find(token_whole);
start_pos = 0;
// Only do extra replacement if using default
extra_replacement = (token_replacement == token_default) ? extra_replacement : 0;
while (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();
token_whole_pos = str.find(token_whole, start_pos);
}
}
ucstr = str;
return true;;
}

View file

@ -712,6 +712,14 @@ public:
void updateTooltipCoords();
/** Returns a human readable timestamp with the given format.
*/
static char* getTimestampHuman(const char* format = "[%H:%M:%S] ");
/** Parses any tokens in the ucstring like $t$ or $g()$
*/
static bool parseTokens(ucstring& ucstr);
// ------------------------------------------------------------------------------------------------
private:

View file

@ -25,6 +25,7 @@
#include "nel/misc/algo.h"
#include "nel/misc/mem_stream.h"
#include "nel/misc/factory.h"
#include "nel/misc/big_file.h"
#include "game_share/xml_auto_ptr.h"
@ -106,6 +107,7 @@
#include "../commands.h"
#include "lua_helper.h"
#include "lua_ihm.h"
#include "../r2/editor.h"
#ifdef LUA_NEVRAX_VERSION
#include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger
@ -114,6 +116,23 @@ const uint32 UI_CACHE_SERIAL_CHECK = (uint32) 'IUG_';
using namespace NLMISC;
void badLuaParseMessageBox()
{
NL3D::UDriver::TMessageBoxId ret = Driver->systemMessageBox( "LUA files reading failed!\n"
"Some LUA files are corrupted, moved or may have been removed.\n"
"Ryzom may need to be restarted to run properly.\n"
"Would you like to quit now?",
"LUA reading failed!",
NL3D::UDriver::yesNoType,
NL3D::UDriver::exclamationIcon);
if (ret == NL3D::UDriver::yesId)
{
extern void quitCrashReport ();
quitCrashReport ();
exit (EXIT_FAILURE);
}
}
void saveXMLTree(COFile &f, xmlNodePtr node)
{
// save node name
@ -494,10 +513,16 @@ static void interfaceScriptAsMemStream(const std::string &script, CMemStream &de
}
// ----------------------------------------------------------------------------
bool CInterfaceParser::parseInterface (const std::vector<std::string> & strings, bool reload, bool isFilename)
bool CInterfaceParser::parseInterface (const std::vector<std::string> & strings, bool reload, bool isFilename, bool checkInData)
{
bool ok;
bool needCheck = checkInData;
#if !FINAL_VERSION
needCheck = false;
#endif
// TestYoyo. UnHide For Parsing Profile
/*
NLMISC::CHTimer::startBench();
@ -524,7 +549,19 @@ bool CInterfaceParser::parseInterface (const std::vector<std::string> & strings,
{
//get the first file document pointer
firstFileName = *it;
if (!file.open (CPath::lookup(firstFileName)))
string filename = CPath::lookup(firstFileName);
bool isInData = false;
if (filename.find ("@") != string::npos)
{
vector<string> bigFilePaths;
CBigFile::getInstance().getBigFilePaths(bigFilePaths);
if (CBigFile::getInstance().getBigFileName(filename.substr(0, filename.find ("@"))) != "data/"+filename.substr(0, filename.find ("@")))
isInData = false;
else
isInData = true;
}
if ((needCheck && !isInData) || !file.open (CPath::lookup(firstFileName)))
{
// todo hulud interface syntax error
nlwarning ("could not open file %s, skipping xml parsing",firstFileName.c_str());
@ -929,8 +966,11 @@ bool CInterfaceParser::parseXMLDocument(xmlNodePtr root, bool reload)
else if ( !strcmp((char*)root->name,"lua") )
{
if(!parseLUAScript(root))
{
badLuaParseMessageBox();
nlwarning ("could not parse 'lua'");
}
}
root = root->next;
}
@ -4648,6 +4688,13 @@ void CInterfaceParser::uninitLUA()
bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error)
{
// get file
bool needCheck = true;
#if !FINAL_VERSION
needCheck = false;
#endif
string pathName= CPath::lookup(fileName, false);
if(pathName.empty())
{
@ -4655,6 +4702,20 @@ bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error)
return false;
}
bool isInData = false;
if (pathName.find ("@") != string::npos)
{
if (CBigFile::getInstance().getBigFileName(pathName.substr(0, pathName.find ("@"))) != "data/"+pathName.substr(0, pathName.find ("@")))
isInData = false;
else
isInData = true;
}
if (needCheck && !isInData)
{
return false;
}
// Parse script
nlassert(_LuaState);
try

View file

@ -103,7 +103,7 @@ public:
* \param isFilename true if xmlFileNames array contains the names of the xml file, false, if each
* array is a script itself
*/
bool parseInterface (const std::vector<std::string> &xmlFileNames, bool reload, bool isFilename = true);
bool parseInterface (const std::vector<std::string> &xmlFileNames, bool reload, bool isFilename = true, bool checkInData = false);
bool parseXMLDocument (xmlNodePtr root, bool reload);

View file

@ -4287,7 +4287,14 @@ void CLuaIHM::tell(const ucstring &player, const ucstring &msg)
{
if (!msg.empty())
{
ChatMngr.tell(player.toUtf8(), msg);
// Parse any tokens in the message.
ucstring msg_modified = msg;
// Parse any tokens in the text
if ( ! CInterfaceManager::parseTokens(msg_modified))
{
return;
}
ChatMngr.tell(player.toUtf8(), msg_modified);
}
else
{

View file

@ -18,6 +18,7 @@
#include "stdpch.h"
// client
#include "../string_manager_client.h"
#include "people_interraction.h"
#include "interface_expr.h"
#include "interface_manager.h"
@ -756,6 +757,7 @@ void CPeopleInterraction::createGuildChat()
chatDesc.Title = "uiGuildChat";
chatDesc.Listener = &GuildChatEntryHandler;
chatDesc.Localize = true;
chatDesc.Savable = true;
chatDesc.Id = "guild_chat";
chatDesc.AHOnCloseButton = "proc";
chatDesc.AHOnCloseButtonParams = "guild_chat_proc_close";
@ -774,6 +776,7 @@ void CPeopleInterraction::createYuboChat()
chatDesc.Title = "uiYuboChat";
chatDesc.Listener = &YuboChatEntryHandler;
chatDesc.Localize = true;
chatDesc.Savable = true;
chatDesc.Id = "yubo_chat";
chatDesc.AHOnCloseButton = "proc";
chatDesc.AHOnCloseButtonParams = "yubo_chat_proc_close";
@ -781,6 +784,7 @@ void CPeopleInterraction::createYuboChat()
YuboChat = getChatWndMgr().createChatWindow(chatDesc);
if (!YuboChat) return;
YuboChat->setMenu(STD_CHAT_SOURCE_MENU);
}
@ -795,6 +799,7 @@ void CPeopleInterraction::createDynamicChats()
DynamicChatEntryHandler[i].DbIndex= i;
chatDesc.Listener = &DynamicChatEntryHandler[i];
chatDesc.Localize = false;
chatDesc.Savable = true;
chatDesc.ChatTemplate ="dynamic_chat_id";
chatDesc.ChatTemplateParams.push_back(make_pair(string("dyn_chat_nb"),toString(i)));
chatDesc.Id = string("dynamic_chat") + toString(i);
@ -804,6 +809,8 @@ void CPeopleInterraction::createDynamicChats()
chatDesc.HeaderColor = "UI:SAVE:WIN:COLORS:MEM";
DynamicChat[i] = getChatWndMgr().createChatWindow(chatDesc);
if (!DynamicChat[i]) continue;
DynamicChat[i]->setMenu(STD_CHAT_SOURCE_MENU);
}
}
@ -956,7 +963,23 @@ class CHandlerChatGroupFilter : public IActionHandler
case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break;
case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break;
case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break;
// NB: user chat cannot have yubo_chat or dyn_chat target
case CChatGroup::dyn_chat:
uint32 index = PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex();
uint32 textId = pIM->getDbProp("SERVER:DYN_CHAT:CHANNEL"+toString(index)+":NAME")->getValue32();
ucstring title;
STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
if (title.empty())
{
// Dyn channel not available yet, so set to around
PeopleInterraction.TheUserChat.Filter.setTargetGroup(CChatGroup::arround);
pUserBut->setHardText("uiFilterAround");
}
else
{
pUserBut->setHardText(title.toUtf8());
}
break;
// NB: user chat cannot have yubo_chat target
}
pUserBut->setActive(true);
@ -1276,6 +1299,10 @@ void CPeopleInterraction::initContactLists( const std::vector<uint32> &vFriendLi
for (uint i = 0; i < vIgnoreListName.size(); ++i)
addContactInList(contactIdPool++, vIgnoreListName[i], ccs_offline, 1);
updateAllFreeTellerHeaders();
CInterfaceManager* pIM= CInterfaceManager::getInstance();
CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
FriendList.sortEx(order);
}
//=================================================================================================================
@ -1758,6 +1785,20 @@ void CPeopleInterraction::talkInDynamicChannel(uint32 channelNb,ucstring sentenc
}
}
//=================================================================================================================
void CPeopleInterraction::displayTellInMainChat(const ucstring &playerName)
{
//CChatWindow *chat = PeopleInterraction.MainChat.Window;
CChatWindow *chat = PeopleInterraction.ChatGroup.Window;
if (!chat) return;
chat->getContainer()->setActive (true);
// make the container blink
chat->getContainer()->enableBlink(2);
// TODO : center the view on the newly created container ?
// display a new command '/name' in the chat. The player must enter a new unique name for the party chat.
chat->setCommand("tell " + playerName + " ", false);
chat->setKeyboardFocus();
}
/////////////////////////////////////
// ACTION HANDLERS FOR PEOPLE LIST //
@ -1945,22 +1986,6 @@ public:
};
REGISTER_ACTION_HANDLER( CHandlerRemoveContact, "remove_contact");
//=================================================================================================================
static void displayTellInMainChat(const ucstring &playerName)
{
//CChatWindow *chat = PeopleInterraction.MainChat.Window;
CChatWindow *chat = PeopleInterraction.ChatGroup.Window;
if (!chat) return;
chat->getContainer()->setActive (true);
// make the container blink
chat->getContainer()->enableBlink(2);
// TODO : center the view on the newly created container ?
// display a new command '/name' in the chat. The player must enter a new unique name for the party chat.
chat->setCommand("tell " + playerName + " ", false);
chat->setKeyboardFocus();
}
//=================================================================================================================
// Invoke the 'tell' command on a contact from its menu
// The tell command is displayed in the 'around me' window
@ -1974,7 +1999,7 @@ public:
uint peopleIndex;
if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex))
{
displayTellInMainChat(list->getName(peopleIndex));
CPeopleInterraction::displayTellInMainChat(list->getName(peopleIndex));
}
}
};
@ -1996,7 +2021,7 @@ class CHandlerTellContact : public IActionHandler
uint peopleIndex;
if (PeopleInterraction.getPeopleFromContainerID(gc->getId(), list, peopleIndex))
{
displayTellInMainChat(list->getName(peopleIndex));
CPeopleInterraction::displayTellInMainChat(list->getName(peopleIndex));
}
}
@ -2150,9 +2175,20 @@ class CHandlerSortContacts : public IActionHandler
public:
void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */)
{
CInterfaceManager* pIM= CInterfaceManager::getInstance();
nlinfo("Load Order : %d", pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
order = (CPeopleList::TSortOrder)(order + 1);
if (order == CPeopleList::END_SORT_ORDER) {
order = CPeopleList::START_SORT_ORDER;
}
nlinfo("Save Order : %d", order);
pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->setValue32((sint32)order);
CPeopleList *pl = PeopleInterraction.getPeopleListFromCurrentMenu();
if (pl)
pl->sort();
pl->sortEx(order);
}
};
REGISTER_ACTION_HANDLER( CHandlerSortContacts, "sort_contacts");
@ -2441,6 +2477,30 @@ public:
if (pMenuUniverse) pMenuUniverse->setGrayed (false);
if (pMenuTeam) pMenuTeam->setGrayed (!teamActive);
if (pMenuGuild) pMenuGuild->setGrayed (!guildActive);
// Remove existing dynamic chats
while (pMenu->getNumLine() > 5)
pMenu->deleteLine(pMenu->getNumLine()-1);
// Add dynamic chats
uint insertion_index = 0;
for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
{
string s = toString(i);
uint32 textId = im->getDbProp("SERVER:DYN_CHAT:CHANNEL"+s+":NAME")->getValue32();
bool active = (textId != 0);
if (active)
{
uint32 canWrite = im->getDbProp("SERVER:DYN_CHAT:CHANNEL"+s+":WRITE_RIGHT")->getValue32();
if (canWrite != 0)
{
ucstring title;
STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
pMenu->addLineAtIndex(5 + insertion_index, title+" @{T8}/"+s, "chat_target_selected", "dyn"+s, "dyn"+s);
insertion_index++;
}
}
}
}
// activate the menu
@ -2465,28 +2525,42 @@ class CHandlerChatTargetSelected : public IActionHandler
CChatTargetFilter &cf = fc->Filter;
// Team
if (nlstricmp(sParams, "team") == 0)
{
cf.setTargetGroup(CChatGroup::team);
}
// Guild
if (nlstricmp(sParams, "guild") == 0)
else if (nlstricmp(sParams, "guild") == 0)
{
cf.setTargetGroup(CChatGroup::guild);
}
// Say
if (nlstricmp(sParams, "say") == 0)
else if (nlstricmp(sParams, "say") == 0)
{
cf.setTargetGroup(CChatGroup::say);
}
// Shout
if (nlstricmp(sParams, "shout") == 0)
else if (nlstricmp(sParams, "shout") == 0)
{
cf.setTargetGroup(CChatGroup::shout);
}
// Region
if (nlstricmp(sParams, "region") == 0)
else if (nlstricmp(sParams, "region") == 0)
{
cf.setTargetGroup(CChatGroup::region);
}
// Universe
if (nlstricmp(sParams, "universe") == 0)
else if (nlstricmp(sParams, "universe") == 0)
{
cf.setTargetGroup(CChatGroup::universe);
}
else
{
for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++) {
if (nlstricmp(sParams, "dyn"+toString("%d", i)) == 0) {
cf.setTargetGroup(CChatGroup::dyn_chat, i);
}
}
}
// Case of user chat in grouped chat window
if (cw == PeopleInterraction.ChatGroup.Window)
@ -2593,6 +2667,25 @@ class CHandlerSelectChatSource : public IActionHandler
// select main chat menu
menu = dynamic_cast<CGroupMenu *>(im->getElementFromId(MAIN_CHAT_SOURCE_MENU));
// Remove all unused dynamic channels and set the names
for (uint i = 0; i < CChatGroup::MaxDynChanPerPlayer; i++)
{
string s = toString(i);
CViewTextMenu *pVTM = dynamic_cast<CViewTextMenu *>(im->getElementFromId(MAIN_CHAT_SOURCE_MENU+":tab:dyn"+s));
if (pVTM)
{
uint32 textId = im->getDbProp("SERVER:DYN_CHAT:CHANNEL"+s+":NAME")->getValue32();
bool active = (textId != 0);
pVTM->setActive(active);
if (active)
{
ucstring title;
STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title);
pVTM->setText("["+s+"] " + title);
}
}
}
// Menu with Filters
CChatGroupWindow *pWin = pi.getChatGroupWindow();
if (pWin->getTabIndex() == 5) // (5 == user) -> complete menu

View file

@ -256,6 +256,8 @@ public:
void updateAllFreeTellerHeaders();
void removeAllFreeTellers();
static void displayTellInMainChat(const ucstring &playerName);
private:
// create various chat & people lists
void createTeamChat();

View file

@ -185,6 +185,85 @@ sint CPeopleList::getIndexFromContainerID(const std::string &id) const
return -1;
}
//==================================================================
bool CPeopleList::sortExByContactId(const CPeople& a, const CPeople& b)
{
return (a.ContactId < b.ContactId);
}
//==================================================================
bool CPeopleList::sortExByName(const CPeople& a, const CPeople& b)
{
ucstring name_a = toUpper(a.getName());
ucstring name_b = toUpper(b.getName());
return (name_a < name_b);
}
//==================================================================
bool CPeopleList::sortExByOnline(const CPeople& a, const CPeople& b)
{
ucstring name_a = toUpper(a.getName());
ucstring name_b = toUpper(b.getName());
// We want order: online/alpha, offworld/alpha, offline/alpha
if (a.Online == b.Online) {
return (name_a < name_b);
}
else {
// Compare online status
switch (a.Online) {
case ccs_online:
// a is > if a is online
return true;
break;
case ccs_online_abroad:
// a is > if b is offline
return (b.Online == ccs_offline);
break;
case ccs_offline:
default:
// b is always > if a is offline
return false;
break;
}
}
// Should not get here so just return something
return true;
}
//==================================================================
void CPeopleList::sortEx(TSortOrder order)
{
// remove all people from the father container
if (!_BaseContainer) return;
uint k;
for(k = 0; k < _Peoples.size(); ++k)
{
_BaseContainer->detachContainer(_Peoples[k].Container);
}
switch (order) {
default:
case sort_index:
std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByContactId);
break;
case sort_name:
std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByName);
break;
case sort_online:
std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByOnline);
break;
}
for(k = 0; k < _Peoples.size(); ++k)
{
_BaseContainer->attachContainer(_Peoples[k].Container);
}
}
//==================================================================
void CPeopleList::sort()
{
@ -384,7 +463,14 @@ void CPeopleList::displayLocalPlayerTell(uint index,const ucstring &msg,uint num
nlwarning("<CPeopleList::displayLocalPlayerTell> can't get group list.");
return;
}
ucstring finalMsg = /*UserEntity->getName() + " " +*/ CI18N::get("youTell") + ": " + msg;
ucstring cur_time;
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : "";
ucstring finalMsg = cur_time + csr + CI18N::get("youTell") + ": " + msg;
// display msg with good color
CInterfaceProperty prop;
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
@ -788,12 +874,19 @@ class CHandlerContactEntry : public IActionHandler
if(text.size() == 0)
return;
// Parse any tokens in the text
if ( ! CInterfaceManager::parseTokens(text))
{
pEB->setInputString (string(""));
return;
}
// is it a command ?
if(text[0] == '/')
{
CChatWindow::_ChatWindowLaunchingCommand = NULL; // no CChatWindow instance there ..
// TODO : have NLMISC::ICommand accept unicode strings
std::string str = text.toString().substr(1);
std::string str = text.toUtf8().substr(1);
NLMISC::ICommand::execute( str, g_log );
pEB->setInputString (string(""));
return;
@ -804,6 +897,7 @@ class CHandlerContactEntry : public IActionHandler
CGroupContainer *gc = pCaller->getParent()->getEnclosingContainer();
// title gives the name of the player
ucstring playerName = gc->getUCTitle();
// Simply do a tell on the player
ChatMngr.tell(playerName.toString(), text);
pEB->setInputString (string(""));
@ -816,8 +910,9 @@ class CHandlerContactEntry : public IActionHandler
}
// Retrieve name of the container in the list
string str = gc->getId().substr(0,gc->getId().rfind('_'));
if (str != "ui:interface:free_chat")
string ui_interface_free_chat = "ui:interface:free_chat";
string str = gc->getId().substr(0, ui_interface_free_chat.length());
if (str != ui_interface_free_chat)
{
string str2 = gc->getId().substr(gc->getId().rfind('_')+1,gc->getId().size());
str = str.substr(0,str.rfind('_'));
@ -839,7 +934,13 @@ class CHandlerContactEntry : public IActionHandler
prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," ");
ucstring final;
CChatWindow::encodeColorTag(prop.getRGBA(), final, false);
final += CI18N::get("youTell")+": ";
ucstring cur_time;
if (CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false)->getValueBool())
{
cur_time = CInterfaceManager::getTimestampHuman();
}
ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : "";
final += cur_time + csr + CI18N::get("youTell")+": ";
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
CChatWindow::encodeColorTag(prop.getRGBA(), final, true);
final += text;

View file

@ -81,6 +81,18 @@ public:
ucstring getName(uint index) const;
// Sort people alphabetically
void sort();
enum TSortOrder
{
sort_index = 0,
START_SORT_ORDER = sort_index,
sort_name,
sort_online,
END_SORT_ORDER
};
void sortEx(TSortOrder order);
/** Add a people to the list, and returns its index or -1 if the creation failed
* If this is a team mate, tells its index so that ic can be bound to the database in the right location
*/
@ -165,6 +177,10 @@ private:
void updatePeopleMenu(uint index);
// from CGroupContainer::IChildrenObs
virtual void childrenMoved(uint srcIndex, uint destIndex, CGroupContainer *children);
static bool sortExByContactId(const CPeople& a, const CPeople& b);
static bool sortExByName(const CPeople& a, const CPeople& b);
static bool sortExByOnline(const CPeople& a, const CPeople& b);
};
#endif

View file

@ -224,7 +224,7 @@ void CViewBitmap::setTexture(const std::string & TxName)
// CInterfaceManager *pIM = CInterfaceManager::getInstance();
// CViewRenderer &rVR = pIM->getViewRenderer();
_TextureId.setTexture (TxName.c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight);
_TextureId.setTexture (TxName.c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false);
}
// ----------------------------------------------------------------------------

View file

@ -344,16 +344,22 @@ void CLightCycleManager::setHour(float hour, const CWeatherManagerClient &wm, NL
}
_Touched = false;
// Set the Sun color
// Set the Sun color only if not indoor
if (ContinentMngr.cur()->Indoor)
{
Scene->setSunAmbient(CRGBA(150, 150, 150, 255));
}
else
{
CRGBA color;
color.add(_LastDiffuse, lightningColor);
Scene->setLightGroupColor (LightGroupDay, color);
// Set the Night color
float nightLevel = _LightLevel*255.f;
clamp (nightLevel, 0, 255);
color.set ((uint8)nightLevel, (uint8)nightLevel, (uint8)nightLevel);
Scene->setLightGroupColor (LightGroupNight, color);
}
if (Landscape)
{

View file

@ -606,7 +606,7 @@ static CInterfaceChatDisplayer InterfaceChatDisplayer;
void CInterfaceChatDisplayer::colorizeSender(ucstring &text, const ucstring &senderName, CRGBA baseColor)
{
// find the sender/text separator to put color tags
ucstring::size_type pos = text.find(ucchar(':'));
ucstring::size_type pos = senderName.length() - 1;
if (pos != ucstring::npos)
{
ucstring str;
@ -635,14 +635,17 @@ void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, c
bool bubbleWanted = true;
// Subtract rawMessage from ucstr so that the 'sender' part remains.
ucstring senderPart = ucstr.luabind_substr(0, ucstr.length() - rawMessage.length());
// search a "{no_bubble}" tag
{
ucstring::size_type index = finalString.find (ucstring("{no_bubble}"));
const size_t tokenSize= 11; // strlen de "{no_bubble}"
ucstring::size_type index = finalString.find(ucstring("{no_bubble}"));
const size_t tokenSize= 11; // length of "{no_bubble}"
if (index != ucstring::npos)
{
bubbleWanted = false;
finalString = finalString.substr (0, index) + finalString.substr(index+tokenSize,finalString.size());
finalString = finalString.luabind_substr(0, index) + finalString.substr(index+tokenSize,finalString.size());
}
}
@ -654,9 +657,9 @@ void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, c
// Remove all {break}
for(;;)
{
ucstring::size_type index = finalString.find (ucstring("{break}"));
ucstring::size_type index = finalString.find(ucstring("{break}"));
if (index == ucstring::npos) break;
finalString = finalString.substr (0, index) + finalString.substr(index+7,finalString.size());
finalString = finalString.luabind_substr(0, index) + finalString.luabind_substr(index+7,finalString.size());
}
// select DB
@ -696,7 +699,15 @@ void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, c
if (mode != CChatGroup::system)
{
// find the sender/text separator to put color tags
colorizeSender(finalString, senderName, col);
if (senderPart.empty() && stringCategory == "emt")
{
size_t pos = finalString.find(ucstring(": "), 0);
if (pos != ucstring::npos)
{
senderPart = finalString.luabind_substr(0, pos + 2);
}
}
colorizeSender(finalString, senderPart, col);
}
// play associated fx if any
@ -839,10 +850,15 @@ void CInterfaceChatDisplayer::displayTell(/*TDataSetIndex senderIndex, */const u
prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," ");
bool windowVisible;
colorizeSender(finalString, senderName, prop.getRGBA());
ucstring goodSenderName = CEntityCL::removeTitleAndShardFromName(senderName);
// The sender part is up to and including the first ":" after the goodSenderName
ucstring::size_type pos = finalString.find(goodSenderName);
pos = finalString.find(':', pos);
pos = finalString.find(' ', pos);
ucstring senderPart = finalString.substr(0, pos+1);
colorizeSender(finalString, senderPart, prop.getRGBA());
PeopleInterraction.ChatInput.Tell.displayTellMessage(/*senderIndex, */finalString, goodSenderName, prop.getRGBA(), 2, &windowVisible);
// Open the free teller window
@ -1764,6 +1780,14 @@ void impulseTeamContactStatus(NLMISC::CBitMemStream &impulse)
// 0<=FriendList (actually ignore list does not show online state)
PeopleInterraction.updateContactInList(contactId, online, 0);
// Resort the contact list if needed
CInterfaceManager* pIM= CInterfaceManager::getInstance();
CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(pIM->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32());
if (order == CPeopleList::sort_online)
{
PeopleInterraction.FriendList.sortEx(order);
}
}// impulseTeamContactStatus //
@ -3069,7 +3093,7 @@ void impulseItemCloseRoomInventory(NLMISC::CBitMemStream &impulse)
void impulseUserBars(NLMISC::CBitMemStream &impulse)
{
uint8 msgNumber;
sint16 hp, sap, sta, focus;
sint32 hp, sap, sta, focus;
impulse.serial(msgNumber);
impulse.serial(hp);
impulse.serial(sap);
@ -3164,7 +3188,6 @@ private:
if(contentStr.size()>=6 && contentStr[0]=='W' && contentStr[1]=='E' && contentStr[2]=='B'
&& contentStr[3]==' ' && contentStr[4]==':' && contentStr[5]==' ' )
{
ucstring web_app;
uint i;
const uint digitStart= 6;
const uint digitMaxEnd= (uint)contentStr.size();
@ -3176,17 +3199,16 @@ private:
if(contentStr[i] == ' ')
break;
}
nlinfo("%d", i);
if(i != digitMaxEnd)
web_app = contentStr.substr(digitStart, i-digitStart);
{
ucstring web_app = contentStr.substr(digitStart, i-digitStart);
contentStr = ucstring("http://atys.ryzom.com/start/")+web_app+ucstring(".php?")+contentStr.substr(i+1);
}
else
{
web_app = ucstring("index");
contentStr = "";
i = digitStart;
nlinfo("no app");
}
contentStr = ucstring("http://atys.ryzom.com/start/")+web_app+ucstring(".php?")+contentStr.substr(i+1);
nlinfo("contentStr = %s", contentStr.toString().c_str());
}
else if(contentStr.size()>=5 && contentStr[0]=='@' && contentStr[1]=='{' && contentStr[2]=='W')
{
@ -3218,14 +3240,21 @@ private:
{
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:webig"));
pGC->setActive(true);
if (contentStr.empty())
{
pGC->setActive(false);
}
else
{
pGC->setActive(true);
string url = contentStr.toString();
addWebIGParams(url);
groupHtml->browse(url.c_str());
pIM->setTopWindow(pGC);
}
}
}
else
{
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:server_message_box"));

View file

@ -227,15 +227,21 @@ bool CPlayerCL::isEnemy () const
}
// Faction
if( getPvpMode()&PVP_MODE::PvpFactionFlagged &&
(UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged) )
if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) &&
(UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged))
{
if( CFactionWarManager::getInstance()->areFactionsInWar(getPvpClan(),UserEntity->getPvpClan()) )
// Check if is not ally
if (!isInTeam() && !isInGuild())
{
// Check for each Clan if is in opposition
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
{
if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) || (isPvpAlly(i) && UserEntity->isPvpEnnemy(i)))
return true;
}
}
}
return false;
} // isEnemy //
@ -293,15 +299,24 @@ bool CPlayerCL::isAlly() const
}
// Faction
if( getPvpMode()&PVP_MODE::PvpFactionFlagged &&
if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) &&
(UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged))
{
if( getPvpClan()!=PVP_CLAN::Neutral && UserEntity->getPvpClan()!=PVP_CLAN::Neutral )
{
if( getPvpClan()==UserEntity->getPvpClan() )
{
if (isInTeam() && isInGuild())
return true;
// Check for each Clan if is in opposition
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
{
if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) || (isPvpAlly(i) && UserEntity->isPvpEnnemy(i)))
return false;
}
// Check for each Clan if is in same clan
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
{
if ((isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) || (isPvpAlly(i) && UserEntity->isPvpAlly(i)))
return true;
}
}
@ -365,20 +380,20 @@ bool CPlayerCL::isNeutralPVP() const
return true;
}
// Faction
if( getPvpMode()&PVP_MODE::PvpFactionFlagged )
if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) &&
(UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged))
{
// if only target is in faction pvp
if( !(UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged) )
// Check for each Clan if is in opposition or same
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
{
return true;
if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) ||
(isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) ||
(isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) ||
(isPvpAlly(i) && UserEntity->isPvpAlly(i)))
return false;
}
// else if factions not in war
if( CFactionWarManager::getInstance()->areFactionsInWar(getPvpClan(),UserEntity->getPvpClan())==false )
{
return true;
}
}
return false;
}

View file

@ -198,6 +198,16 @@ CUserEntity::~CUserEntity()
_MountSpeeds.release();
CInterfaceManager *pIM = CInterfaceManager::getInstance();
{
CCDBNodeLeaf *node = pIM->getDbProp("SERVER:USER:IS_INVISIBLE", false);
if (node)
{
ICDBNode::CTextId textId;
node->removeObserver(&_InvisibleObs, textId);
}
}
for(uint i=0;i<EGSPD::CSPType::EndSPType;i++)
{
CCDBNodeLeaf *node= pIM->getDbProp(toString("SERVER:USER:SKILL_POINTS_%d:VALUE", i), false);
@ -347,8 +357,17 @@ bool CUserEntity::build(const CEntitySheet *sheet) // virtual
// Rebuild interface
buildInSceneInterface ();
// Add an observer on skill points
// Add observer on invisible property
CInterfaceManager *pIM = CInterfaceManager::getInstance();
{
CCDBNodeLeaf *node = pIM->getDbProp("SERVER:USER:IS_INVISIBLE", false);
if (node) {
ICDBNode::CTextId textId;
node->addObserver(&_InvisibleObs, textId);
}
}
// Add an observer on skill points
for(uint i=0;i<EGSPD::CSPType::EndSPType;i++)
{
_SkillPointObs[i].SpType= i;
@ -3664,6 +3683,11 @@ void CUserEntity::load() // virtual
//---------------------------------------------------
void CUserEntity::CInvisibleObserver::update(ICDBNode* node)
{
UserEntity->buildInSceneInterface();
}
//---------------------------------------------------
void CUserEntity::CSkillPointsObserver::update(ICDBNode* node )
{

View file

@ -589,7 +589,12 @@ protected:
};
CSkillPointsObserver _SkillPointObs[EGSPD::CSPType::EndSPType];
class CInvisibleObserver : public ICDBNode::IPropertyObserver
{
public :
virtual void update(ICDBNode* node);
};
CInvisibleObserver _InvisibleObs;
/// Fame observer
class CFameObserver : public ICDBNode::IPropertyObserver