mirror of
https://port.numenaute.org/aleajactaest/khanat-code-old.git
synced 2024-12-25 10:10:52 +00:00
Changed: #1135 Merge changes from Ryzom patch 1.10
This commit is contained in:
parent
e3a648f1ec
commit
5c1aee1509
35 changed files with 2190 additions and 408 deletions
|
@ -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 //
|
||||
|
|
|
@ -372,6 +372,44 @@ public:
|
|||
void setPvpMode(uint8 mode) { _PvpMode=mode; }
|
||||
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>]")
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -2511,12 +2511,20 @@ NLMISC::CRGBA CEntityCL::getColor () const
|
|||
{
|
||||
if (isEnemy())
|
||||
{
|
||||
return _PvpEnemyColor;
|
||||
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;
|
||||
return _PvpAllyColor;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,58 +251,87 @@ 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;
|
||||
CFile::moveFile(image.c_str(), (image+".tmp").c_str());
|
||||
if (lookupLocalFile (finalUrl, image.c_str(), false))
|
||||
if (it->type == ImgType)
|
||||
{
|
||||
for(uint i = 0; i < it->imgs.size(); i++)
|
||||
string image = localImageName(it->url);
|
||||
CFile::moveFile(image.c_str(), (image+".tmp").c_str());
|
||||
if (lookupLocalFile (finalUrl, image.c_str(), false))
|
||||
{
|
||||
// don't display image that are not power of 2
|
||||
uint32 w, h;
|
||||
CBitmap::loadSize (image, w, h);
|
||||
if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures()))
|
||||
image.clear();
|
||||
for(uint i = 0; i < it->imgs.size(); i++)
|
||||
{
|
||||
// don't display image that are not power of 2
|
||||
uint32 w, h;
|
||||
CBitmap::loadSize (image, w, h);
|
||||
if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures()))
|
||||
image.clear();
|
||||
|
||||
CCtrlButton *btn = dynamic_cast<CCtrlButton*>(it->imgs[i]);
|
||||
if(btn)
|
||||
{
|
||||
#ifdef LOG_DL
|
||||
nlwarning("refresh new downloading image %d button %p", i, it->imgs[i]);
|
||||
#endif
|
||||
btn->setTexture (image);
|
||||
btn->setTexturePushed(image);
|
||||
btn->invalidateCoords();
|
||||
btn->invalidateContent();
|
||||
btn->resetInvalidCoords();
|
||||
btn->updateCoords();
|
||||
paragraphChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(it->imgs[i]);
|
||||
if(btm)
|
||||
CCtrlButton *btn = dynamic_cast<CCtrlButton*>(it->imgs[i]);
|
||||
if(btn)
|
||||
{
|
||||
#ifdef LOG_DL
|
||||
nlwarning("refresh new downloading image %d image %p", i, it->imgs[i]);
|
||||
#endif
|
||||
btm->setTexture (image);
|
||||
btm->invalidateCoords();
|
||||
btm->invalidateContent();
|
||||
btm->resetInvalidCoords();
|
||||
btm->updateCoords();
|
||||
#ifdef LOG_DL
|
||||
nlwarning("refresh new downloading image %d button %p", i, it->imgs[i]);
|
||||
#endif
|
||||
btn->setTexture (image);
|
||||
btn->setTexturePushed(image);
|
||||
btn->invalidateCoords();
|
||||
btn->invalidateContent();
|
||||
btn->resetInvalidCoords();
|
||||
btn->updateCoords();
|
||||
paragraphChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
CViewBitmap *btm = dynamic_cast<CViewBitmap*>(it->imgs[i]);
|
||||
if(btm)
|
||||
{
|
||||
#ifdef LOG_DL
|
||||
nlwarning("refresh new downloading image %d image %p", i, it->imgs[i]);
|
||||
#endif
|
||||
btm->setTexture (image);
|
||||
btm->invalidateCoords();
|
||||
btm->invalidateContent();
|
||||
btm->resetInvalidCoords();
|
||||
btm->updateCoords();
|
||||
paragraphChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
@ -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 ¶m)
|
|||
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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,25 +539,91 @@ 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)
|
||||
{
|
||||
CViewBitmap * pvpFactionLogoBmp = dynamic_cast<CViewBitmap *>(pvpFactionLogo);
|
||||
if( pvpFactionLogoBmp )
|
||||
pvpFactionLogoBmp->setTexture( pIM->getDefine(PVP_CLAN::toIconDefineString(pPlayer->getPvpClan())) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pvpFactionLogo->setActive(false);
|
||||
}
|
||||
// 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 * 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
|
||||
{
|
||||
needCivPvpLogo = false;
|
||||
needCultPvpLogo = false;
|
||||
}
|
||||
|
||||
CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo");
|
||||
if (pvpOutpostLogo)
|
||||
{
|
||||
|
@ -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 ?
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
using namespace std;
|
||||
using namespace NLMISC;
|
||||
|
||||
extern CPeopleInterraction PeopleInterraction;
|
||||
|
||||
NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListAscensor, std::string, "list_sheet_guild");
|
||||
|
||||
|
@ -54,26 +55,27 @@ NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListAscensor, std::string, "list_sheet
|
|||
// Interface part
|
||||
// ***************************************************************************
|
||||
|
||||
#define WIN_GUILD "ui:interface:guild"
|
||||
#define WIN_GUILD_CHAT "ui:interface:guild_chat"
|
||||
#define WIN_GUILD_FORUM "ui:interface:guild_forum"
|
||||
#define VIEW_TEXT_GUILD_QUIT "ui:interface:guild:content:tab_guild:quit_guild"
|
||||
#define CTRL_SHEET_GUILD_BLASON "ui:interface:guild:content:tab_guild:blason"
|
||||
#define VIEW_TEXT_GUILD_MEMBER_COUNT "ui:interface:guild:content:tab_guild:member_count"
|
||||
#define WIN_GUILD "ui:interface:guild"
|
||||
#define WIN_GUILD_CHAT "ui:interface:guild_chat"
|
||||
#define WIN_GUILD_FORUM "ui:interface:guild_forum"
|
||||
#define VIEW_TEXT_GUILD_QUIT "ui:interface:guild:content:tab_guild:quit_guild"
|
||||
#define CTRL_SHEET_GUILD_BLASON "ui:interface:guild:content:tab_guild:blason"
|
||||
#define VIEW_TEXT_GUILD_MEMBER_COUNT "ui:interface:guild:content:tab_guild:member_count"
|
||||
|
||||
|
||||
#define LIST_GUILD_MEMBERS "ui:interface:guild:content:tab_guild:list_member:guild_members"
|
||||
#define CTRL_QUIT_GUILD "ui:interface:guild:content:tab_guild:quit_guild"
|
||||
#define TEMPLATE_GUILD_MEMBER "member_template"
|
||||
#define TEMPLATE_GUILD_MEMBER_NAME "name"
|
||||
#define TEMPLATE_GUILD_MEMBER_GRADE "grade"
|
||||
#define TEMPLATE_GUILD_MEMBER_SCORE "score"
|
||||
#define MENU_GUILD_MEMBER "ui:interface:menu_member"
|
||||
#define LIST_GUILD_MEMBERS "ui:interface:guild:content:tab_guild:list_member:guild_members"
|
||||
#define CTRL_QUIT_GUILD "ui:interface:guild:content:tab_guild:quit_guild"
|
||||
#define TEMPLATE_GUILD_MEMBER "member_template"
|
||||
#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"
|
||||
#define WIN_ASCENSOR "ui:interface:ascensor_teleport_list"
|
||||
|
||||
#define WIN_JOIN_PROPOSAL "ui:interface:join_guild_proposal"
|
||||
#define VIEW_JOIN_PROPOSAL_PHRASE "ui:interface:join_guild_proposal:content:inside:phrase"
|
||||
#define WIN_JOIN_PROPOSAL "ui:interface:join_guild_proposal"
|
||||
#define VIEW_JOIN_PROPOSAL_PHRASE "ui:interface:join_guild_proposal:content:inside:phrase"
|
||||
|
||||
CGuildManager* CGuildManager::_Instance = NULL;
|
||||
|
||||
|
@ -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
|
||||
sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_name);
|
||||
|
||||
// Second sort by grade
|
||||
stable_sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_grade);
|
||||
switch (order)
|
||||
{
|
||||
default:
|
||||
case sort_grade:
|
||||
sort(_GuildMembers.begin(), _GuildMembers.end(), lt_member_name);
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
_Shapes[i]->getShape().setClusterSystem ((UInstanceGroup*)-1);
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -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;;
|
||||
}
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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,7 +966,10 @@ 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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -256,6 +256,8 @@ public:
|
|||
|
||||
void updateAllFreeTellerHeaders();
|
||||
void removeAllFreeTellers();
|
||||
|
||||
static void displayTellInMainChat(const ucstring &playerName);
|
||||
private:
|
||||
// create various chat & people lists
|
||||
void createTeamChat();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -344,16 +344,22 @@ void CLightCycleManager::setHour(float hour, const CWeatherManagerClient &wm, NL
|
|||
}
|
||||
_Touched = false;
|
||||
|
||||
// Set the Sun color
|
||||
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);
|
||||
// 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);
|
||||
float nightLevel = _LightLevel*255.f;
|
||||
clamp (nightLevel, 0, 255);
|
||||
color.set ((uint8)nightLevel, (uint8)nightLevel, (uint8)nightLevel);
|
||||
Scene->setLightGroupColor (LightGroupNight, color);
|
||||
}
|
||||
|
||||
if (Landscape)
|
||||
{
|
||||
|
|
|
@ -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,18 +3199,17 @@ 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')
|
||||
{
|
||||
uint i;
|
||||
|
@ -3218,12 +3240,19 @@ private:
|
|||
{
|
||||
|
||||
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIM->getElementFromId("ui:interface:webig"));
|
||||
pGC->setActive(true);
|
||||
|
||||
string url = contentStr.toString();
|
||||
addWebIGParams(url);
|
||||
groupHtml->browse(url.c_str());
|
||||
pIM->setTopWindow(pGC);
|
||||
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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
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 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 (isInTeam() && isInGuild())
|
||||
return true;
|
||||
|
||||
// Check for each Clan if is in opposition
|
||||
for (uint8 i = 0; i < PVP_CLAN::NbClans; i++)
|
||||
{
|
||||
if( getPvpClan()==UserEntity->getPvpClan() )
|
||||
{
|
||||
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,19 +380,19 @@ 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;
|
||||
}
|
||||
// else if factions not in war
|
||||
if( CFactionWarManager::getInstance()->areFactionsInWar(getPvpClan(),UserEntity->getPvpClan())==false )
|
||||
{
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue