Changed: Merge code from private repository
This commit is contained in:
parent
cf3dec5af6
commit
a5e23cb0f9
15 changed files with 857 additions and 52 deletions
|
@ -49,7 +49,7 @@ NL_INSTANCE_COUNTER_IMPL(CBackupInterfaceSingleton);
|
||||||
// method used to update stuff on config file reload / variable change
|
// method used to update stuff on config file reload / variable change
|
||||||
void onSaveShardRootModified( NLMISC::IVariable &var );
|
void onSaveShardRootModified( NLMISC::IVariable &var );
|
||||||
// configuration variables - to be setup in cfg files
|
// configuration variables - to be setup in cfg files
|
||||||
CVariable<string> SaveShardRoot("variables", "SaveShardRoot", "Root directory of all files saved by any shard", "", 0, true, onSaveShardRootModified, false);
|
CVariable<string> SaveShardRootGameShare("variables", "SaveShardRoot", "Root directory of all files saved by any shard", "", 0, true, onSaveShardRootModified, false);
|
||||||
|
|
||||||
// stats variables
|
// stats variables
|
||||||
CVariable<NLMISC::TTime> BSLastAckTime("BSIF", "BSLastAckTime", "The timestamp of the last ack received from backup system", 0, 0, true);
|
CVariable<NLMISC::TTime> BSLastAckTime("BSIF", "BSLastAckTime", "The timestamp of the last ack received from backup system", 0, 0, true);
|
||||||
|
@ -103,15 +103,15 @@ void CBackupInterfaceSingleton::init()
|
||||||
|
|
||||||
_ShardDependentBsi.init("BS");
|
_ShardDependentBsi.init("BS");
|
||||||
_ShardDependentBsi.setRemotePath( IService::getInstance()->SaveFilesDirectory.toString() );
|
_ShardDependentBsi.setRemotePath( IService::getInstance()->SaveFilesDirectory.toString() );
|
||||||
_ShardDependentBsi.setLocalPath( CPath::standardizePath( SaveShardRoot.get() ) + IService::getInstance()->SaveFilesDirectory.toString() );
|
_ShardDependentBsi.setLocalPath( CPath::standardizePath( SaveShardRootGameShare.get() ) + IService::getInstance()->SaveFilesDirectory.toString() );
|
||||||
|
|
||||||
_GlobalBsi.init("BS");
|
_GlobalBsi.init("BS");
|
||||||
_GlobalBsi.setRemotePath( string() );
|
_GlobalBsi.setRemotePath( string() );
|
||||||
_GlobalBsi.setLocalPath( SaveShardRoot.get() );
|
_GlobalBsi.setLocalPath( SaveShardRootGameShare.get() );
|
||||||
|
|
||||||
// _PDBsi.init("PDBS");
|
// _PDBsi.init("PDBS");
|
||||||
// _PDBsi.setRemotePath( IService::getInstance()->SaveFilesDirectory.toString() );
|
// _PDBsi.setRemotePath( IService::getInstance()->SaveFilesDirectory.toString() );
|
||||||
// _PDBsi.setLocalPath( CPath::standardizePath( SaveShardRoot.get() ) + IService::getInstance()->SaveFilesDirectory.toString() );
|
// _PDBsi.setLocalPath( CPath::standardizePath( SaveShardRootGameShare.get() ) + IService::getInstance()->SaveFilesDirectory.toString() );
|
||||||
|
|
||||||
IService::getInstance()->setDirectoryChangeCallback( this );
|
IService::getInstance()->setDirectoryChangeCallback( this );
|
||||||
}
|
}
|
||||||
|
@ -357,9 +357,9 @@ void CBackupInterfaceSingleton::onVariableChanged( NLMISC::IVariable &var )
|
||||||
if ( var.getName() == "SaveFilesDirectory" )
|
if ( var.getName() == "SaveFilesDirectory" )
|
||||||
{
|
{
|
||||||
_ShardDependentBsi.setRemotePath( var.toString() );
|
_ShardDependentBsi.setRemotePath( var.toString() );
|
||||||
_ShardDependentBsi.setLocalPath( CPath::standardizePath( SaveShardRoot.get() ) + var.toString() );
|
_ShardDependentBsi.setLocalPath( CPath::standardizePath( SaveShardRootGameShare.get() ) + var.toString() );
|
||||||
// _PDBsi.setRemotePath( var.toString() );
|
// _PDBsi.setRemotePath( var.toString() );
|
||||||
// _PDBsi.setLocalPath( CPath::standardizePath( SaveShardRoot.get() ) + var.toString() );
|
// _PDBsi.setLocalPath( CPath::standardizePath( SaveShardRootGameShare.get() ) + var.toString() );
|
||||||
}
|
}
|
||||||
else if ( var.getName() == "SaveShardRoot" )
|
else if ( var.getName() == "SaveShardRoot" )
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ NLMISC::CVariable<std::string> BSFileSubst("backup", "BSFileSubst", "file read/w
|
||||||
NLMISC::CVariable<bool> VerboseLog("backup", "VerboseLog", "Activate verbose logging of BS activity", false);
|
NLMISC::CVariable<bool> VerboseLog("backup", "VerboseLog", "Activate verbose logging of BS activity", false);
|
||||||
NLMISC::CVariable<bool> UseTempFile("backup", "UseTempFile", "Flag the use of temporary file for safe write or append operation", true, true);
|
NLMISC::CVariable<bool> UseTempFile("backup", "UseTempFile", "Flag the use of temporary file for safe write or append operation", true, true);
|
||||||
|
|
||||||
extern NLMISC::CVariable<std::string> SaveShardRoot;
|
extern NLMISC::CVariable<std::string> SaveShardRootBackupService;
|
||||||
|
|
||||||
bool bsstrincmp(const char* s1, const char* s2, int n)
|
bool bsstrincmp(const char* s1, const char* s2, int n)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ bool bsstrincmp(const char* s1, const char* s2, int n)
|
||||||
|
|
||||||
std::string getBackupFileName(const std::string& filename)
|
std::string getBackupFileName(const std::string& filename)
|
||||||
{
|
{
|
||||||
return SaveShardRoot.get() + filename;
|
return SaveShardRootBackupService.get() + filename;
|
||||||
/* // BSFilePrefix and BSFileSubst are deprecated
|
/* // BSFilePrefix and BSFileSubst are deprecated
|
||||||
if (BSFilePrefix.get().empty())
|
if (BSFilePrefix.get().empty())
|
||||||
return filename;
|
return filename;
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct CBackupMsgSaveFileRecv
|
||||||
|
|
||||||
|
|
||||||
extern CDirectoryRateStat DirStats;
|
extern CDirectoryRateStat DirStats;
|
||||||
extern NLMISC::CVariable<std::string> SaveShardRoot;
|
extern NLMISC::CVariable<std::string> SaveShardRootBackupService;
|
||||||
|
|
||||||
using namespace NLNET;
|
using namespace NLNET;
|
||||||
using namespace NLMISC;
|
using namespace NLMISC;
|
||||||
|
@ -542,7 +542,7 @@ static CMessage getFileClassImp( CMessage& msgin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// In case something like getPathContent() has returned full paths, make paths relative to match the requested filenames
|
// In case something like getPathContent() has returned full paths, make paths relative to match the requested filenames
|
||||||
fdc.stripFilename(SaveShardRoot.get());
|
fdc.stripFilename(SaveShardRootBackupService.get());
|
||||||
|
|
||||||
// compose the output message
|
// compose the output message
|
||||||
CMessage msgout("BS_FILE_CLASS");
|
CMessage msgout("BS_FILE_CLASS");
|
||||||
|
|
|
@ -30,7 +30,7 @@ using namespace NLNET;
|
||||||
|
|
||||||
CDirectoryRateStat DirStats;
|
CDirectoryRateStat DirStats;
|
||||||
|
|
||||||
extern CVariable<string> SaveShardRoot;
|
extern CVariable<string> SaveShardRootBackupService;
|
||||||
|
|
||||||
|
|
||||||
NLMISC_COMMAND(displayFileStats, "display file read/write stats for the last minute", "")
|
NLMISC_COMMAND(displayFileStats, "display file read/write stats for the last minute", "")
|
||||||
|
@ -74,9 +74,9 @@ NLMISC_COMMAND ( dumpCharacterFile, "dump the content of the save file for a cha
|
||||||
{
|
{
|
||||||
// just output the list of available shard id
|
// just output the list of available shard id
|
||||||
vector<string> shards;
|
vector<string> shards;
|
||||||
CPath::getPathContent(SaveShardRoot, false, true, false, shards);
|
CPath::getPathContent(SaveShardRootBackupService, false, true, false, shards);
|
||||||
|
|
||||||
log.displayNL("Listing %u available shard id in path '%s':", shards.size(), SaveShardRoot.c_str());
|
log.displayNL("Listing %u available shard id in path '%s':", shards.size(), SaveShardRootBackupService.c_str());
|
||||||
for (uint i=0; i<shards.size(); ++i)
|
for (uint i=0; i<shards.size(); ++i)
|
||||||
{
|
{
|
||||||
string id = shards[i];
|
string id = shards[i];
|
||||||
|
@ -107,7 +107,7 @@ NLMISC_COMMAND ( dumpCharacterFile, "dump the content of the save file for a cha
|
||||||
useFilter = true;
|
useFilter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string fileName = SaveShardRoot.toString()+"/"+args[0]+"/characters/account_"+args[1]+"_"+args[2]+"_pdr.bin";
|
string fileName = SaveShardRootBackupService.toString()+"/"+args[0]+"/characters/account_"+args[1]+"_"+args[2]+"_pdr.bin";
|
||||||
if (!CFile::isExists(fileName))
|
if (!CFile::isExists(fileName))
|
||||||
{
|
{
|
||||||
log.displayNL("The file '%s' (located here '%s') cannot be found in '%s' backup directory",
|
log.displayNL("The file '%s' (located here '%s') cannot be found in '%s' backup directory",
|
||||||
|
|
|
@ -169,8 +169,7 @@ void cbOnSaveShardRootModified( NLMISC::IVariable& var )
|
||||||
}
|
}
|
||||||
|
|
||||||
CVariable<string> IncrementalBackupDirectory("backup", "IncrementalBackupDirectory", "Directory to find incremental backuped archives", "", 0, true);
|
CVariable<string> IncrementalBackupDirectory("backup", "IncrementalBackupDirectory", "Directory to find incremental backuped archives", "", 0, true);
|
||||||
// (SaveShardRoot from game_share/backup_service_interface.cpp is not instanciated because the nothing is used from that file)
|
CVariable<string> SaveShardRootBackupService("backup", "SaveShardRoot", "Root directory of all saved data by BS", "/home/nevrax/save_shard", 0, true, cbOnSaveShardRootModified); // (SaveShardRoot from game_share/backup_service_interface.cpp is not instanciated because the nothing is used from that file)
|
||||||
extern CVariable<string> SaveShardRoot;
|
|
||||||
CVariable<string> SaveTemplatePath("backup", "SaveTemplatePath", "Directory to find saves (with shard and account replacement strings)", "$shard/characters/account_$userid_$charid$ext", 0, true);
|
CVariable<string> SaveTemplatePath("backup", "SaveTemplatePath", "Directory to find saves (with shard and account replacement strings)", "$shard/characters/account_$userid_$charid$ext", 0, true);
|
||||||
CVariable<string> SaveExtList("backup", "SaveExtList", "List of possible extensions for save files (space separated)", "_pdr.bin _pdr.xml .bin", 0, true);
|
CVariable<string> SaveExtList("backup", "SaveExtList", "List of possible extensions for save files (space separated)", "_pdr.bin _pdr.xml .bin", 0, true);
|
||||||
|
|
||||||
|
@ -210,7 +209,7 @@ void cbGetSaveList(CMemStream &msgin, TSockId host)
|
||||||
explode(str, string("%%"), params, true);
|
explode(str, string("%%"), params, true);
|
||||||
|
|
||||||
string incrementalDir = IncrementalBackupDirectory.get();
|
string incrementalDir = IncrementalBackupDirectory.get();
|
||||||
string saveShardRoot = SaveShardRoot.get();
|
string saveShardRoot = SaveShardRootBackupService.get();
|
||||||
string templatePath = SaveTemplatePath.get();
|
string templatePath = SaveTemplatePath.get();
|
||||||
string extList = SaveExtList.get();
|
string extList = SaveExtList.get();
|
||||||
|
|
||||||
|
@ -293,7 +292,7 @@ void cbRestoreSave(CMemStream &msgin, TSockId host)
|
||||||
|
|
||||||
explode(str, string("%%"), params, true);
|
explode(str, string("%%"), params, true);
|
||||||
|
|
||||||
string saveShardRoot = SaveShardRoot.get();
|
string saveShardRoot = SaveShardRootBackupService.get();
|
||||||
string templatePath = SaveTemplatePath.get();
|
string templatePath = SaveTemplatePath.get();
|
||||||
|
|
||||||
string shard;
|
string shard;
|
||||||
|
@ -368,7 +367,7 @@ void cbCopyOverSave(CMemStream &msgin, TSockId host)
|
||||||
|
|
||||||
explode(str, string("%%"), params, true);
|
explode(str, string("%%"), params, true);
|
||||||
|
|
||||||
string saveShardRoot = SaveShardRoot.get();
|
string saveShardRoot = SaveShardRootBackupService.get();
|
||||||
string templatePath = SaveTemplatePath.get();
|
string templatePath = SaveTemplatePath.get();
|
||||||
string extList = SaveExtList.get();
|
string extList = SaveExtList.get();
|
||||||
|
|
||||||
|
|
|
@ -268,10 +268,6 @@ void CCreatureSetUrlImp::callback(const string &, NLNET::TServiceId sid)
|
||||||
uint32 program = c->getBotChatProgram();
|
uint32 program = c->getBotChatProgram();
|
||||||
if(!(program & (1<<BOTCHATTYPE::WebPageFlag)))
|
if(!(program & (1<<BOTCHATTYPE::WebPageFlag)))
|
||||||
{
|
{
|
||||||
if(program != 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
program |= 1 << BOTCHATTYPE::WebPageFlag;
|
program |= 1 << BOTCHATTYPE::WebPageFlag;
|
||||||
c->setBotChatProgram(program);
|
c->setBotChatProgram(program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ public:
|
||||||
void cancelAFK();
|
void cancelAFK();
|
||||||
CCreature * getInterlocutor();
|
CCreature * getInterlocutor();
|
||||||
CModuleParent & getModuleParent();
|
CModuleParent & getModuleParent();
|
||||||
void sendSystemMessage( const std::string & msg, const TVectorParamCheck & params = TVectorParamCheck() );
|
void sendSystemMessage( const std::string & msg, const TVectorParamCheck & params);
|
||||||
|
void sendSystemMessage( const std::string & msg);
|
||||||
void sendDynamicMessageToChatGroup( const std::string & msg, CChatGroup::TGroupType type, const TVectorParamCheck & params = TVectorParamCheck() );
|
void sendDynamicMessageToChatGroup( const std::string & msg, CChatGroup::TGroupType type, const TVectorParamCheck & params = TVectorParamCheck() );
|
||||||
uint64 getMoney();
|
uint64 getMoney();
|
||||||
void spendMoney(uint64 money);
|
void spendMoney(uint64 money);
|
||||||
|
|
|
@ -33,9 +33,13 @@
|
||||||
#include "mission_manager/mission_guild.h"
|
#include "mission_manager/mission_guild.h"
|
||||||
#include "guild_manager/guild_manager.h"
|
#include "guild_manager/guild_manager.h"
|
||||||
#include "guild_manager/guild.h"
|
#include "guild_manager/guild.h"
|
||||||
|
#include "building_manager/building_manager.h"
|
||||||
|
#include "building_manager/building_physical.h"
|
||||||
|
|
||||||
#include "admin.h"
|
#include "admin.h"
|
||||||
#include "creature_manager/creature_manager.h"
|
#include "creature_manager/creature_manager.h"
|
||||||
|
#include "world_instances.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace NLMISC;
|
using namespace NLMISC;
|
||||||
using namespace NLNET;
|
using namespace NLNET;
|
||||||
|
@ -553,3 +557,677 @@ NLMISC_COMMAND(addMission,"Add mission to character","<character_id> <Mission gi
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Commands used by ARK
|
||||||
|
|
||||||
|
|
||||||
|
CInventoryPtr getInventory(CCharacter *c, const string &inv)
|
||||||
|
{
|
||||||
|
CInventoryPtr inventoryPtr = NULL;
|
||||||
|
if (!inv.empty())
|
||||||
|
{
|
||||||
|
INVENTORIES::TInventory selectedInv = INVENTORIES::toInventory(inv);
|
||||||
|
switch (selectedInv)
|
||||||
|
{
|
||||||
|
case INVENTORIES::temporary:
|
||||||
|
case INVENTORIES::bag:
|
||||||
|
case INVENTORIES::equipment:
|
||||||
|
case INVENTORIES::pet_animal1:
|
||||||
|
case INVENTORIES::pet_animal2:
|
||||||
|
case INVENTORIES::pet_animal3:
|
||||||
|
case INVENTORIES::pet_animal4:
|
||||||
|
case INVENTORIES::guild:
|
||||||
|
case INVENTORIES::player_room:
|
||||||
|
inventoryPtr = c->getInventory(selectedInv);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// No-op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inventoryPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getEid, "get entitiy id of entity", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
log.displayNL("%s", c->getId().toString().c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getItemList, "get list of named items of character by filter", "<uid> [bag sheet quantity_min quantity_max quality_min quality_max extra_infos]")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
std::vector<INVENTORIES::TInventory> inventories;
|
||||||
|
|
||||||
|
string selected_inv = "*";
|
||||||
|
string filter = "*";
|
||||||
|
uint32 quantity_min = 0;
|
||||||
|
uint32 quantity_max = 999;
|
||||||
|
uint32 quality_min = 0;
|
||||||
|
uint32 quality_max = 999;
|
||||||
|
|
||||||
|
string extra;
|
||||||
|
|
||||||
|
if (args.size() > 1)
|
||||||
|
selected_inv = args[1];
|
||||||
|
|
||||||
|
if (args.size() > 2)
|
||||||
|
filter = args[2];
|
||||||
|
|
||||||
|
if (args.size() > 3)
|
||||||
|
fromString(args[3], quantity_min);
|
||||||
|
|
||||||
|
if (args.size() > 4)
|
||||||
|
fromString(args[4], quantity_max);
|
||||||
|
|
||||||
|
if (args.size() > 5)
|
||||||
|
fromString(args[5], quality_min);
|
||||||
|
|
||||||
|
if (args.size() > 6)
|
||||||
|
fromString(args[6], quality_max);
|
||||||
|
|
||||||
|
if (args.size() > 7)
|
||||||
|
extra = args[7];
|
||||||
|
|
||||||
|
string msg;
|
||||||
|
|
||||||
|
if (selected_inv != "*")
|
||||||
|
{
|
||||||
|
std::vector<string> invs;
|
||||||
|
NLMISC::splitString(selected_inv, ",", invs);
|
||||||
|
for (uint32 i=0; i<invs.size(); i++)
|
||||||
|
{
|
||||||
|
INVENTORIES::TInventory selectedInv = INVENTORIES::toInventory(invs[i]);
|
||||||
|
if (selectedInv != INVENTORIES::UNDEFINED)
|
||||||
|
inventories.push_back(selectedInv);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inventories.push_back(INVENTORIES::equipment);
|
||||||
|
inventories.push_back(INVENTORIES::bag);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal1);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal2);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal3);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal4);
|
||||||
|
inventories.push_back(INVENTORIES::guild);
|
||||||
|
inventories.push_back(INVENTORIES::player_room);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventories.empty()) {
|
||||||
|
log.displayNL("ERR: invalid inventories");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i=0; i<inventories.size(); i++)
|
||||||
|
{
|
||||||
|
CInventoryPtr childSrc = c->getInventory(inventories[i]);
|
||||||
|
if (childSrc != NULL)
|
||||||
|
{
|
||||||
|
uint32 k = 0;
|
||||||
|
log.displayNL("#%s", INVENTORIES::toString(inventories[i]).c_str());
|
||||||
|
|
||||||
|
for ( uint j = 0; j < childSrc->getSlotCount(); j++ )
|
||||||
|
{
|
||||||
|
CGameItemPtr itemPtr = childSrc->getItem(j);
|
||||||
|
if (itemPtr != NULL)
|
||||||
|
{
|
||||||
|
string sheet = itemPtr->getSheetId().toString();
|
||||||
|
if (testWildCard(sheet, filter))
|
||||||
|
{
|
||||||
|
uint32 item_stack = itemPtr->getStackSize();
|
||||||
|
uint32 item_quality = itemPtr->quality();
|
||||||
|
if (item_stack >= quantity_min && item_stack <= quantity_max
|
||||||
|
&& item_quality >= quality_min && item_quality <= quality_max)
|
||||||
|
{
|
||||||
|
string item_stats = toString("%3d|%s|", j, sheet.c_str());
|
||||||
|
if (!extra.empty())
|
||||||
|
itemPtr->getStats(extra, item_stats);
|
||||||
|
log.displayNL(item_stats.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getNamedItemList, "get list of named items of character by filter", "<uid> [bag named quantity_min quantity_max quality_min quality_max extra_infos]")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
std::vector<INVENTORIES::TInventory> inventories;
|
||||||
|
|
||||||
|
string selected_inv = "*";
|
||||||
|
string filter = "*";
|
||||||
|
uint32 quantity_min = 0;
|
||||||
|
uint32 quantity_max = 999;
|
||||||
|
uint32 quality_min = 0;
|
||||||
|
uint32 quality_max = 999;
|
||||||
|
|
||||||
|
string extra;
|
||||||
|
|
||||||
|
if (args.size() > 1)
|
||||||
|
selected_inv = args[1];
|
||||||
|
|
||||||
|
if (args.size() > 2)
|
||||||
|
filter = args[2];
|
||||||
|
|
||||||
|
if (args.size() > 3)
|
||||||
|
fromString(args[3], quantity_min);
|
||||||
|
|
||||||
|
if (args.size() > 4)
|
||||||
|
fromString(args[4], quantity_max);
|
||||||
|
|
||||||
|
if (args.size() > 5)
|
||||||
|
fromString(args[5], quality_min);
|
||||||
|
|
||||||
|
if (args.size() > 6)
|
||||||
|
fromString(args[6], quality_max);
|
||||||
|
|
||||||
|
if (args.size() > 7)
|
||||||
|
extra = args[7];
|
||||||
|
|
||||||
|
string msg;
|
||||||
|
|
||||||
|
if (selected_inv != "*")
|
||||||
|
{
|
||||||
|
std::vector<string> invs;
|
||||||
|
NLMISC::splitString(selected_inv, ",", invs);
|
||||||
|
for (uint32 i=0; i<invs.size(); i++)
|
||||||
|
{
|
||||||
|
INVENTORIES::TInventory selectedInv = INVENTORIES::toInventory(invs[i]);
|
||||||
|
if (selectedInv != INVENTORIES::UNDEFINED)
|
||||||
|
inventories.push_back(selectedInv);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inventories.push_back(INVENTORIES::equipment);
|
||||||
|
inventories.push_back(INVENTORIES::bag);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal1);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal2);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal3);
|
||||||
|
inventories.push_back(INVENTORIES::pet_animal4);
|
||||||
|
inventories.push_back(INVENTORIES::guild);
|
||||||
|
inventories.push_back(INVENTORIES::player_room);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i=0; i<inventories.size(); i++)
|
||||||
|
{
|
||||||
|
CInventoryPtr childSrc = c->getInventory(inventories[i]);
|
||||||
|
if (childSrc != NULL)
|
||||||
|
{
|
||||||
|
uint32 k = 0;
|
||||||
|
log.displayNL("#%s", INVENTORIES::toString(inventories[i]).c_str());
|
||||||
|
|
||||||
|
for ( uint j = 0; j < childSrc->getSlotCount(); j++ )
|
||||||
|
{
|
||||||
|
CGameItemPtr itemPtr = childSrc->getItem(j);
|
||||||
|
if (itemPtr != NULL)
|
||||||
|
{
|
||||||
|
string phraseId = itemPtr->getPhraseId();
|
||||||
|
if (!phraseId.empty() && testWildCard(phraseId, filter))
|
||||||
|
{
|
||||||
|
uint32 item_stack = itemPtr->getStackSize();
|
||||||
|
uint32 item_quality = itemPtr->quality();
|
||||||
|
if (item_stack >= quantity_min && item_stack <= quantity_max
|
||||||
|
&& item_quality >= quality_min && item_quality <= quality_max)
|
||||||
|
{
|
||||||
|
string item_stats = toString("%3d|%s|", j, phraseId.c_str());
|
||||||
|
if (!extra.empty())
|
||||||
|
itemPtr->getStats(extra, item_stats);
|
||||||
|
log.displayNL(item_stats.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(deleteInventoryItems, "Delete items from a characters inventory", "<uid> <sheetnames> <quality> <quantity>")
|
||||||
|
{
|
||||||
|
if (args.size () < 5)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: Invalid number of parameters. Parameters: <inventory> <sheetnames> <quality> <quantity>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
std::map<string, uint32> need_items;
|
||||||
|
|
||||||
|
std::vector<string> sheet_names;
|
||||||
|
NLMISC::splitString(args[1], ",", sheet_names);
|
||||||
|
std::vector<string> qualities;
|
||||||
|
NLMISC::splitString(args[2], ",", qualities);
|
||||||
|
std::vector<string> quantities;
|
||||||
|
NLMISC::splitString(args[3], ",", quantities);
|
||||||
|
|
||||||
|
for (uint32 i=0; i < std::min(quantities.size(), std::min(qualities.size(), sheet_names.size())); i++)
|
||||||
|
{
|
||||||
|
uint32 quantity = 0;
|
||||||
|
fromString(quantities[i], quantity);
|
||||||
|
need_items.insert(make_pair(sheet_names[i]+":"+qualities[i], quantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<uint32, uint32> slots;
|
||||||
|
std::map<string, uint32>::iterator itNeedItems;
|
||||||
|
|
||||||
|
// Save list of slots and quantities to delete
|
||||||
|
CInventoryPtr inventory = c->getInventory(INVENTORIES::bag);
|
||||||
|
if (inventory != NULL)
|
||||||
|
{
|
||||||
|
for ( uint32 j = 0; j < inventory->getSlotCount(); j++ )
|
||||||
|
{
|
||||||
|
CGameItemPtr itemPtr = inventory->getItem(j);
|
||||||
|
if (itemPtr != NULL)
|
||||||
|
{
|
||||||
|
string sheet = itemPtr->getSheetId().toString();
|
||||||
|
uint32 item_quality = itemPtr->quality();
|
||||||
|
itNeedItems = need_items.find(sheet+":"+NLMISC::toString("%d", item_quality));
|
||||||
|
if (itNeedItems != need_items.end() && (*itNeedItems).second > 0)
|
||||||
|
{
|
||||||
|
nlinfo("Found : %s %d", sheet.c_str(), item_quality);
|
||||||
|
uint32 quantity = std::min((*itNeedItems).second, itemPtr->getStackSize());
|
||||||
|
slots.insert(make_pair(j, quantity));
|
||||||
|
(*itNeedItems).second -= quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all items has been found
|
||||||
|
for ( itNeedItems = need_items.begin(); itNeedItems != need_items.end(); ++itNeedItems )
|
||||||
|
{
|
||||||
|
if ((*itNeedItems).second != 0) {
|
||||||
|
nlinfo("Missing : %s", (*itNeedItems).first.c_str());
|
||||||
|
log.displayNL("ERR: Not enough items.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delete them
|
||||||
|
for ( std::map<uint32, uint32>::iterator it = slots.begin(); it != slots.end(); ++it )
|
||||||
|
{
|
||||||
|
nlinfo("Deleting... %d, %d", (*it).first, (*it).second);
|
||||||
|
inventory->deleteStackItem((*it).first, (*it).second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getPosition, "get position of entity", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
double x = 0, y = 0, z = 0, h = 0;
|
||||||
|
sint32 cell = 0;
|
||||||
|
|
||||||
|
x = c->getState().X / 1000.;
|
||||||
|
y = c->getState().Y / 1000.;
|
||||||
|
z = c->getState().Z / 1000.;
|
||||||
|
h = c->getState().Heading;
|
||||||
|
|
||||||
|
TDataSetRow dsr = c->getEntityRowId();
|
||||||
|
CMirrorPropValueRO<TYPE_CELL> srcCell( TheDataset, dsr, DSPropertyCELL );
|
||||||
|
cell = srcCell;
|
||||||
|
|
||||||
|
log.displayNL("%.2f|%.2f|%.2f|%.4f|%d", x, y, z, h, cell);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getFame, "get fame of player", "<uid> faction")
|
||||||
|
{
|
||||||
|
|
||||||
|
if (args.size () < 2)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid arg count");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
uint32 factionIndex = CStaticFames::getInstance().getFactionIndex(args[1]);
|
||||||
|
if (factionIndex == CStaticFames::INVALID_FACTION_INDEX)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid fame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sint32 fame = CFameInterface::getInstance().getFameIndexed(c->getId(), factionIndex);
|
||||||
|
log.displayNL("%d", fame);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getFames, "get fames of player", "<uid> faction1,faction2,faction3,...")
|
||||||
|
{
|
||||||
|
|
||||||
|
if (args.size () < 2)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid arg count");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
string sfames;
|
||||||
|
|
||||||
|
std::pair<PVP_CLAN::TPVPClan, PVP_CLAN::TPVPClan> allegiance = c->getAllegiance();
|
||||||
|
log.displayNL("%s", PVP_CLAN::toString(allegiance.first).c_str());
|
||||||
|
log.displayNL("%s", PVP_CLAN::toString(allegiance.second).c_str());
|
||||||
|
log.displayNL("%d", c->getOrganization());
|
||||||
|
|
||||||
|
std::vector<string> fames;
|
||||||
|
NLMISC::splitString(args[1], ",", fames);
|
||||||
|
for (uint32 i=0; i<fames.size(); i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32 factionIndex = CStaticFames::getInstance().getFactionIndex(fames[i]);
|
||||||
|
if (factionIndex == CStaticFames::INVALID_FACTION_INDEX)
|
||||||
|
log.displayNL("ERR: invalid fame");
|
||||||
|
else
|
||||||
|
log.displayNL("%d", CFameInterface::getInstance().getFameIndexed(c->getId(), factionIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getTarget, "get target of player", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
const CEntityId &target = c->getTarget();
|
||||||
|
string msg = target.toString()+"|";
|
||||||
|
|
||||||
|
if (target == CEntityId::Unknown)
|
||||||
|
{
|
||||||
|
log.displayNL("0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.getType() == RYZOMID::creature)
|
||||||
|
msg += "c|";
|
||||||
|
else if (target.getType() == RYZOMID::npc)
|
||||||
|
msg += "n|";
|
||||||
|
else if (target.getType() == RYZOMID::player)
|
||||||
|
msg += "p|";
|
||||||
|
else
|
||||||
|
msg += "0";
|
||||||
|
|
||||||
|
if (target.getType() == RYZOMID::player)
|
||||||
|
{
|
||||||
|
CCharacter * cTarget = dynamic_cast<CCharacter*>(CEntityBaseManager::getEntityBasePtr(target));
|
||||||
|
if (cTarget) {
|
||||||
|
msg += cTarget->getName().toString()+"|";
|
||||||
|
|
||||||
|
if (c->getGuildId() != 0 && c->getGuildId() == cTarget->getGuildId())
|
||||||
|
msg += "g|";
|
||||||
|
else
|
||||||
|
msg += "0|";
|
||||||
|
|
||||||
|
if (c->getTeamId() != CTEAM::InvalidTeamId && c->getTeamId() == cTarget->getTeamId())
|
||||||
|
msg += "t";
|
||||||
|
else
|
||||||
|
msg += "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.displayNL(msg.c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getMoney, "get money of player", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
string value = toString("%"NL_I64"u", c->getMoney());
|
||||||
|
|
||||||
|
log.displayNL(value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getPvpPoints, "get pvp points of player", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
string value = toString("%u", c->getPvpPoint());
|
||||||
|
|
||||||
|
log.displayNL(value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(getCivCultOrg, "get civ cult and organization of player", "<uid>")
|
||||||
|
{
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
std::pair<PVP_CLAN::TPVPClan, PVP_CLAN::TPVPClan> allegiance = c->getAllegiance();
|
||||||
|
|
||||||
|
|
||||||
|
log.displayNL("%s|%s|%u", PVP_CLAN::toString(allegiance.first).c_str(), PVP_CLAN::toString(allegiance.second).c_str(), c->getOrganization());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(accessPowo, "give access to the powo", "<uid> player_name number")
|
||||||
|
{
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
IBuildingPhysical * building;
|
||||||
|
if (args.size () >= 3)
|
||||||
|
building = CBuildingManager::getInstance()->getBuildingPhysicalsByName("building_instance_ZO_player_11"+args[2]);
|
||||||
|
else
|
||||||
|
building = CBuildingManager::getInstance()->getBuildingPhysicalsByName("building_instance_ZO_player_111");
|
||||||
|
|
||||||
|
|
||||||
|
if ( building )
|
||||||
|
{
|
||||||
|
|
||||||
|
if (building->getTemplate()->Type == BUILDING_TYPES::Player)
|
||||||
|
{
|
||||||
|
|
||||||
|
CBuildingPhysicalPlayer * buildingPlayer = dynamic_cast<CBuildingPhysicalPlayer *>( building );
|
||||||
|
|
||||||
|
CEntityBase *entityBase = PlayerManager.getCharacterByName(CShardNames::getInstance().makeFullNameFromRelative(c->getHomeMainlandSessionId(), args[2]));
|
||||||
|
if (buildingPlayer && entityBase)
|
||||||
|
{
|
||||||
|
CBuildingManager::getInstance()->removePlayerFromRoom( c );
|
||||||
|
uint16 ownerId = buildingPlayer->getOwnerIdx( entityBase->getId() );
|
||||||
|
sint32 cell;
|
||||||
|
buildingPlayer->addUser(c, 0, ownerId, cell);
|
||||||
|
c->setPowoCell(cell);
|
||||||
|
CBuildingManager::getInstance()->setRoomLifeTime(cell, TGameCycle(NLMISC::TGameTime(4*60*60) / CTickEventHandler::getGameTimeStep()));
|
||||||
|
log.displayNL("%d", cell);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.displayNL("ERR: invalid number");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.displayNL("ERR: invalid number");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(slide, "slide to the powo", "<uid> x y cell [z] [h]")
|
||||||
|
{
|
||||||
|
|
||||||
|
if (args.size () < 4)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid arg count");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
string value = args[1];
|
||||||
|
|
||||||
|
sint32 x;
|
||||||
|
sint32 y;
|
||||||
|
sint32 cell = c->getPowoCell();
|
||||||
|
sint32 z = 0;
|
||||||
|
float h = 0;
|
||||||
|
|
||||||
|
fromString(args[1], x);
|
||||||
|
x *= 1000;
|
||||||
|
fromString(args[2], y);
|
||||||
|
y *= 1000;
|
||||||
|
if (args[3] != "*")
|
||||||
|
fromString(args[3], cell);
|
||||||
|
|
||||||
|
if (args.size() >= 5)
|
||||||
|
{
|
||||||
|
fromString(args[4], z);
|
||||||
|
z *= 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.size() >= 6)
|
||||||
|
fromString(args[5], h);
|
||||||
|
|
||||||
|
c->teleportCharacter(x,y,z,false,true,h,0xFF,cell);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NLMISC_COMMAND(spawn, "spawn entity", "<uid> quantity sheet dispersion orientation groupname x y look cell")
|
||||||
|
{
|
||||||
|
|
||||||
|
if (args.size () < 10)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid arg count");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_ACTIVE_CHARACTER
|
||||||
|
|
||||||
|
|
||||||
|
uint32 instanceNumber = 0;
|
||||||
|
sint32 x = 0;
|
||||||
|
sint32 y = 0;
|
||||||
|
sint32 z = c->getZ();
|
||||||
|
sint32 cell = 0;
|
||||||
|
sint32 orientation = 6666; // used to specify a random orientation
|
||||||
|
|
||||||
|
uint32 nbBots;
|
||||||
|
fromString(args[1], nbBots);
|
||||||
|
if (nbBots<=0)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid bot count");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NLMISC::CSheetId sheetId(args[2]);
|
||||||
|
if (sheetId == NLMISC::CSheetId::Unknown)
|
||||||
|
sheetId = args[2] + ".creature";
|
||||||
|
if (sheetId == NLMISC::CSheetId::Unknown)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
double dispersionRadius = 10.;
|
||||||
|
if (args.size()>3)
|
||||||
|
{
|
||||||
|
fromString(args[3], dispersionRadius);
|
||||||
|
if (dispersionRadius < 0.) {
|
||||||
|
log.displayNL("ERR: invalid dispersion");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spawnBots = true;
|
||||||
|
|
||||||
|
if (args.size()>4)
|
||||||
|
{
|
||||||
|
if (args[4] == "self")
|
||||||
|
{
|
||||||
|
orientation = (sint32)(c->getHeading() * 1000.0);
|
||||||
|
}
|
||||||
|
else if (args[4] != "random")
|
||||||
|
{
|
||||||
|
NLMISC::fromString(args[4], orientation);
|
||||||
|
orientation = (sint32)((double)orientation / 360.0 * (NLMISC::Pi * 2.0) * 1000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string botsName = args[5];
|
||||||
|
|
||||||
|
float userX;
|
||||||
|
NLMISC::fromString(args[6], userX);
|
||||||
|
x = (sint32)(userX * 1000.0);
|
||||||
|
|
||||||
|
float userY;
|
||||||
|
NLMISC::fromString(args[7], userY);
|
||||||
|
y = (sint32)(userY * 1000.0);
|
||||||
|
|
||||||
|
string look = args[8];
|
||||||
|
NLMISC::fromString(args[9], cell);
|
||||||
|
|
||||||
|
// See if another AI instance has been specified
|
||||||
|
if (botsName.find("@") != string::npos)
|
||||||
|
{
|
||||||
|
string continent = botsName.substr(0, botsName.find('@'));
|
||||||
|
uint32 nr = CUsedContinent::instance().getInstanceForContinent(continent);
|
||||||
|
if (nr == ~0)
|
||||||
|
{
|
||||||
|
log.displayNL("ERR: invalid continent");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
instanceNumber = nr;
|
||||||
|
botsName = botsName.substr(botsName.find('@') + 1, botsName.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
CEntityId playerId = c->getId();
|
||||||
|
|
||||||
|
CMessage msgout("EVENT_CREATE_NPC_GROUP");
|
||||||
|
uint32 messageVersion = 1;
|
||||||
|
msgout.serial(messageVersion);
|
||||||
|
msgout.serial(instanceNumber);
|
||||||
|
msgout.serial(playerId);
|
||||||
|
msgout.serial(x);
|
||||||
|
msgout.serial(y);
|
||||||
|
msgout.serial(z);
|
||||||
|
msgout.serial(orientation);
|
||||||
|
msgout.serial(nbBots);
|
||||||
|
msgout.serial(sheetId);
|
||||||
|
msgout.serial(dispersionRadius);
|
||||||
|
msgout.serial(spawnBots);
|
||||||
|
msgout.serial(botsName);
|
||||||
|
msgout.serial(look);
|
||||||
|
msgout.serial(cell);
|
||||||
|
CWorldInstances::instance().msgToAIInstance2(instanceNumber, msgout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -181,7 +181,7 @@ void CDamageScoreTable::addPlayerDamage(TDataSetRow playerRowId, uint32 damage)
|
||||||
void CDamageScoreTable::addCreatureDamage(TDataSetRow creatureRowId, uint32 damage)
|
void CDamageScoreTable::addCreatureDamage(TDataSetRow creatureRowId, uint32 damage)
|
||||||
{
|
{
|
||||||
nlassert(damage > 0);
|
nlassert(damage > 0);
|
||||||
|
/*
|
||||||
CCreatureDamageScore * creatureScore = getCreatureDamageScore(creatureRowId);
|
CCreatureDamageScore * creatureScore = getCreatureDamageScore(creatureRowId);
|
||||||
if (creatureScore == NULL)
|
if (creatureScore == NULL)
|
||||||
{
|
{
|
||||||
|
@ -193,6 +193,7 @@ void CDamageScoreTable::addCreatureDamage(TDataSetRow creatureRowId, uint32 dama
|
||||||
{
|
{
|
||||||
creatureScore->TotalDamage += damage;
|
creatureScore->TotalDamage += damage;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -1694,7 +1695,7 @@ bool CDamageScoreManager::playerInFactionPvP(const CCharacter * playerChar, PVP_
|
||||||
CPVPVersusZone * zone = dynamic_cast<CPVPVersusZone *>(const_cast<CPVPInterface &>(playerChar->getPVPInterface()).getPVPSession());
|
CPVPVersusZone * zone = dynamic_cast<CPVPVersusZone *>(const_cast<CPVPInterface &>(playerChar->getPVPInterface()).getPVPSession());
|
||||||
if (zone != NULL)
|
if (zone != NULL)
|
||||||
{
|
{
|
||||||
PVP_CLAN::TPVPClan factionInZone = zone->getCharacterClan(playerChar->getId());
|
/*PVP_CLAN::TPVPClan factionInZone = zone->getCharacterClan(playerChar->getId());
|
||||||
if (factionInZone == PVP_CLAN::Neutral)
|
if (factionInZone == PVP_CLAN::Neutral)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1705,7 +1706,7 @@ bool CDamageScoreManager::playerInFactionPvP(const CCharacter * playerChar, PVP_
|
||||||
|
|
||||||
if (withFactionPoints)
|
if (withFactionPoints)
|
||||||
*withFactionPoints = zone->giveFactionPoints();
|
*withFactionPoints = zone->giveFactionPoints();
|
||||||
|
*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,12 +117,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/// Gets at maximum MAX_SEEN_ENTITIES entities contained in the cell
|
/// Gets at maximum MAX_SEEN_ENTITIES entities contained in the cell
|
||||||
CVisionEntry* addEntities(CVisionEntry* fillPtr, CVisionEntry* endPtr, uint32 cellMask, uint32 distance)
|
CVisionEntry* addEntities(CVisionEntry* fillPtr, CVisionEntry* endPtr, uint32 cellMask, uint32 distance, bool indoor, CWorldEntity *player)
|
||||||
{
|
{
|
||||||
CWorldEntity *ent = _EntitiesList.getHead();
|
CWorldEntity *ent = _EntitiesList.getHead();
|
||||||
while (ent != NULL && fillPtr < endPtr)
|
while (ent != NULL && fillPtr < endPtr)
|
||||||
{
|
{
|
||||||
sint32 mask = cellMask & (sint32)(ent->WhoSeesMe);
|
sint32 mask = cellMask & (sint32)(ent->WhoSeesMe);
|
||||||
|
if (mask && indoor && (float)(player->X()-ent->X())*(float)(player->X()-ent->X()) + (float)(player->Y()-ent->Y())*(float)(player->Y()-ent->Y()) > 15625000000)
|
||||||
|
mask = 0;
|
||||||
|
|
||||||
//if (!ent->IsInvisibleToPlayer && mask != 0)
|
//if (!ent->IsInvisibleToPlayer && mask != 0)
|
||||||
if (mask != 0)
|
if (mask != 0)
|
||||||
{
|
{
|
||||||
|
@ -136,12 +139,15 @@ public:
|
||||||
return fillPtr;
|
return fillPtr;
|
||||||
}
|
}
|
||||||
/// Gets at maximum MAX_SEEN_ENTITIES entities contained in the cell
|
/// Gets at maximum MAX_SEEN_ENTITIES entities contained in the cell
|
||||||
CVisionEntry* addObjects(CVisionEntry* fillPtr, CVisionEntry* endPtr, uint32 cellMask, uint32 distance)
|
CVisionEntry* addObjects(CVisionEntry* fillPtr, CVisionEntry* endPtr, uint32 cellMask, uint32 distance, bool indoor, CWorldEntity *player)
|
||||||
{
|
{
|
||||||
CWorldEntity *ent = _ObjectsList.getHead();
|
CWorldEntity *ent = _ObjectsList.getHead();
|
||||||
while (ent != NULL && fillPtr < endPtr)
|
while (ent != NULL && fillPtr < endPtr)
|
||||||
{
|
{
|
||||||
sint32 mask = cellMask & (sint32)(ent->WhoSeesMe);
|
sint32 mask = cellMask & (sint32)(ent->WhoSeesMe);
|
||||||
|
if (mask && indoor && (float)(player->X()-ent->X())*(float)(player->X()-ent->X()) + (float)(player->Y()-ent->Y())*(float)(player->Y()-ent->Y()) > 15625000000)
|
||||||
|
mask = 0;
|
||||||
|
|
||||||
//if (!ent->IsInvisibleToPlayer && mask != 0)
|
//if (!ent->IsInvisibleToPlayer && mask != 0)
|
||||||
if (mask != 0)
|
if (mask != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -493,7 +493,9 @@ void cbEntityTeleportation( CMessage& msgin, const string &serviceName, NLNET::T
|
||||||
|
|
||||||
id.serial( msgin );
|
id.serial( msgin );
|
||||||
TDataSetRow index = CWorldPositionManager::getEntityIndex(id);
|
TDataSetRow index = CWorldPositionManager::getEntityIndex(id);
|
||||||
BOMB_IF(IsRingShard && !index.isValid(),"Ignoring request to TP entity withe invalid data set row: "<<id.toString(),return);
|
|
||||||
|
if (!index.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
// if no position provided, teleport entity to nowhere
|
// if no position provided, teleport entity to nowhere
|
||||||
if (msgin.getPos() == (sint32)msgin.length())
|
if (msgin.getPos() == (sint32)msgin.length())
|
||||||
|
@ -544,6 +546,10 @@ void cbEntityTeleportation( CMessage& msgin, const string &serviceName, NLNET::T
|
||||||
cell = 0;
|
cell = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 move_to_new_cell = 0;
|
||||||
|
if (msgin.getPos() != (sint32)msgin.length())
|
||||||
|
msgin.serial(move_to_new_cell);
|
||||||
|
|
||||||
if (IsRingShard)
|
if (IsRingShard)
|
||||||
{
|
{
|
||||||
// update the ring vision universe position
|
// update the ring vision universe position
|
||||||
|
@ -560,14 +566,22 @@ void cbEntityTeleportation( CMessage& msgin, const string &serviceName, NLNET::T
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (move_to_new_cell == 1)
|
||||||
|
{
|
||||||
|
nlinfo("MSG: Sliding entity %d to cell %d) at tick: %d",index.getIndex(),cell,tick);
|
||||||
|
CWorldPositionManager::updateEntityPosition(CWorldPositionManager::getEntityPtr(index), cell);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlinfo("MSG: Teleporting entity %d to continent %d cell %d (%d, %d, %d) at tick: %d",index.getIndex(),continent,cell,x,y,z,tick);
|
||||||
CWorldPositionManager::teleport(index, x, y, z, t, continent, cell, tick);
|
CWorldPositionManager::teleport(index, x, y, z, t, continent, cell, tick);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// lock entity after a real teleport
|
// lock entity after a real teleport
|
||||||
CWorldPositionManager::lock(index, 10);
|
CWorldPositionManager::lock(index, 10);
|
||||||
|
|
||||||
nlinfo("MSG: Teleporting entity %d to continent %d (%d, %d, %d) at tick: %d",index.getIndex(),continent,x,y,z,tick);
|
|
||||||
} // cbEntityTeleportation //
|
} // cbEntityTeleportation //
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2183,14 +2183,18 @@ void CWorldPositionManager::movePlayer(CWorldEntity *entity, sint32 x, sint32 y,
|
||||||
// Get the proper speed
|
// Get the proper speed
|
||||||
CMirrorPropValueRO<TYPE_RUNSPEED> maxSpeed( TheDataset, entity->Index, DSPropertyCURRENT_RUN_SPEED );
|
CMirrorPropValueRO<TYPE_RUNSPEED> maxSpeed( TheDataset, entity->Index, DSPropertyCURRENT_RUN_SPEED );
|
||||||
float limitSpeedToUse = maxSpeed();
|
float limitSpeedToUse = maxSpeed();
|
||||||
|
// Get the proper speed of master
|
||||||
|
CMirrorPropValueRO<TYPE_RUNSPEED> maxSpeedMaster( TheDataset, master->Index, DSPropertyCURRENT_RUN_SPEED );
|
||||||
|
float mountWalkSpeed = maxSpeedMaster();
|
||||||
if ( entity != master )
|
if ( entity != master )
|
||||||
{
|
{
|
||||||
// If the player is on a mount, handle the hunger of the mount
|
// If the player is on a mount, handle the hunger of the mount
|
||||||
if ( (movVector.x > 0.001) && (movVector.y > 0.001) )
|
// if ( (movVector.x > 0.001) && (movVector.y > 0.001) )
|
||||||
{
|
{
|
||||||
CMirrorPropValueRO<TYPE_WALKSPEED> walkSpeed( TheDataset, entity->Index, DSPropertyCURRENT_WALK_SPEED );
|
CMirrorPropValueRO<TYPE_WALKSPEED> walkSpeed( TheDataset, entity->Index, DSPropertyCURRENT_WALK_SPEED );
|
||||||
CSpeedLimit speedLimit( TheDataset, entity->Index );
|
CSpeedLimit speedLimit( TheDataset, entity->Index );
|
||||||
limitSpeedToUse = speedLimit.getSpeedLimit( walkSpeed, maxSpeed );
|
limitSpeedToUse = speedLimit.getSpeedLimit( walkSpeed, maxSpeed );
|
||||||
|
mountWalkSpeed = walkSpeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2201,18 +2205,20 @@ void CWorldPositionManager::movePlayer(CWorldEntity *entity, sint32 x, sint32 y,
|
||||||
|
|
||||||
// Check player speed
|
// Check player speed
|
||||||
// only consider (x,y) motion for speed and position correction
|
// only consider (x,y) motion for speed and position correction
|
||||||
if (master->PlayerInfos != NULL && master->PlayerInfos->CheckSpeed && CheckPlayerSpeed && fabs(movVector.x)+fabs(movVector.y) > maxDist)
|
if (master->PlayerInfos != NULL /*&& master->PlayerInfos->CheckSpeed && CheckPlayerSpeed && fabs(movVector.x)+fabs(movVector.y) > maxDist*/)
|
||||||
{
|
{
|
||||||
double movNorm = sqr(movVector.x)+sqr(movVector.y); // already done if (entity != master) but here is a rare overspeed case
|
double movNorm = sqr(movVector.x)+sqr(movVector.y); // already done if (entity != master) but here is a rare overspeed case
|
||||||
|
|
||||||
if (movNorm > sqr(maxDist))
|
if (movNorm > sqr(maxDist))
|
||||||
{
|
{
|
||||||
if (VerboseSpeedAbuse)
|
if (movNorm > sqr(5 * SecuritySpeedFactor * CTickEventHandler::getGameTimeStep() * ticksSinceLastUpdate)) {
|
||||||
{
|
|
||||||
nlwarning("CWorldPositionManager::movePlayer%s: limited speed (movNorm=%.2f, movMax=%.2f, maxSpeed=%.2f)", entity->Id.toString().c_str(), sqrt(movNorm), maxDist, limitSpeedToUse*0.001*SecuritySpeedFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
movVector *= (maxDist / sqrt(movNorm));
|
movVector *= (maxDist / sqrt(movNorm));
|
||||||
|
nlwarning("Player limitSpeed=%2.f, entitySpeed=%.2f, masterSpeed=%.2f", limitSpeedToUse, maxSpeed(), mountWalkSpeed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlwarning("Player limitSpeed=%2.f, entitySpeed=%.2f, masterSpeed=%.2f", limitSpeedToUse, maxSpeed(), mountWalkSpeed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2268,9 +2274,9 @@ void CWorldPositionManager::movePlayer(CWorldEntity *entity, sint32 x, sint32 y,
|
||||||
if (diff2d.sqrnorm() > 1.0 )
|
if (diff2d.sqrnorm() > 1.0 )
|
||||||
{
|
{
|
||||||
correctPos = true;
|
correctPos = true;
|
||||||
if (VerboseSpeedAbuse)
|
if (true/*VerboseSpeedAbuse*/)
|
||||||
{
|
{
|
||||||
nlwarning("CWorldPositionManager::movePlayer%s: corrected position: real=(%.1f,%.1f) targeted=(%.1f,%.1f)", master->Id.toString().c_str(), finalPos.x, finalPos.y, targetPos.x, targetPos.y);
|
nlwarning("PlayerAbuse %s real=(%.1f,%.1f) targeted=(%.1f,%.1f)", master->Id.toString().c_str(), finalPos.x, finalPos.y, targetPos.x, targetPos.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1580,6 +1580,14 @@ string CMissionData::genPreRequisites()
|
||||||
ret += NL;
|
ret += NL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!_ReqCharacterAge.empty())
|
||||||
|
{
|
||||||
|
ret += "req_character_age : "+_ReqCharacterAge+NL;
|
||||||
|
}
|
||||||
|
if (!_ReqMaxPlayerID.empty())
|
||||||
|
{
|
||||||
|
ret += "req_max_player_id : "+_ReqMaxPlayerID+NL;
|
||||||
|
}
|
||||||
if (!_ReqSeason.empty())
|
if (!_ReqSeason.empty())
|
||||||
{
|
{
|
||||||
ret += "req_season : "+_ReqSeason+NL;
|
ret += "req_season : "+_ReqSeason+NL;
|
||||||
|
@ -2019,6 +2027,10 @@ void CMissionData::parsePrerequisites(NLLIGO::IPrimitive *prim)
|
||||||
_ReqGrade = getProperty(prim, "require_guild_grade", true, false);
|
_ReqGrade = getProperty(prim, "require_guild_grade", true, false);
|
||||||
// team size
|
// team size
|
||||||
_ReqTeamSize = getProperty(prim, "require_team_size", true, false);
|
_ReqTeamSize = getProperty(prim, "require_team_size", true, false);
|
||||||
|
// character minimum age
|
||||||
|
_ReqCharacterAge = getProperty(prim, "require_character_age", true, false);
|
||||||
|
// maximum player ID
|
||||||
|
_ReqMaxPlayerID = getProperty(prim, "require_max_player_id", true, false);
|
||||||
// brick
|
// brick
|
||||||
vs = getPropertyArray(prim, "require_brick_knowledge", true, false);
|
vs = getPropertyArray(prim, "require_brick_knowledge", true, false);
|
||||||
for (uint i=0; i<vs.size(); ++i)
|
for (uint i=0; i<vs.size(); ++i)
|
||||||
|
|
|
@ -388,6 +388,8 @@ private:
|
||||||
std::string _ReqGrade;
|
std::string _ReqGrade;
|
||||||
std::string _ReqTeamSize;
|
std::string _ReqTeamSize;
|
||||||
std::vector<std::string> _ReqBrick;
|
std::vector<std::string> _ReqBrick;
|
||||||
|
std::string _ReqCharacterAge;
|
||||||
|
std::string _ReqMaxPlayerID;
|
||||||
std::string _ReqSeason;
|
std::string _ReqSeason;
|
||||||
// bool _ReqEncycloTasksDone;
|
// bool _ReqEncycloTasksDone;
|
||||||
std::string _ReqEncyclo;
|
std::string _ReqEncyclo;
|
||||||
|
|
|
@ -1844,6 +1844,13 @@ struct TKillRaceInfo
|
||||||
TCompilerVarName Quantity;
|
TCompilerVarName Quantity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TKillPlayerInfo
|
||||||
|
{
|
||||||
|
TCompilerVarName ClanName;
|
||||||
|
TCompilerVarName MinLevel;
|
||||||
|
TCompilerVarName MaxLevel;
|
||||||
|
TCompilerVarName Quantity;
|
||||||
|
};
|
||||||
|
|
||||||
class CContentKill : public CContentObjective
|
class CContentKill : public CContentObjective
|
||||||
{
|
{
|
||||||
|
@ -1856,6 +1863,7 @@ class CContentKill : public CContentObjective
|
||||||
TCompilerVarName _KillFactionName;
|
TCompilerVarName _KillFactionName;
|
||||||
TCompilerVarName _KillFactionQuantity;
|
TCompilerVarName _KillFactionQuantity;
|
||||||
vector<string> _PredefVarName;
|
vector<string> _PredefVarName;
|
||||||
|
vector<TKillPlayerInfo> _KillPlayers;
|
||||||
TCompilerVarName _Place;
|
TCompilerVarName _Place;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1924,7 +1932,22 @@ class CContentKill : public CContentObjective
|
||||||
predef[0].resize(2);
|
predef[0].resize(2);
|
||||||
predef[0][0] = _KillFactionName;
|
predef[0][0] = _KillFactionName;
|
||||||
predef[0][1] = _KillFactionQuantity;
|
predef[0][1] = _KillFactionQuantity;
|
||||||
|
}
|
||||||
|
else if(!_KillPlayers.empty())
|
||||||
|
{
|
||||||
|
numEntry = _KillPlayers.size();
|
||||||
|
predef.resize(numEntry);
|
||||||
|
for (uint i=0; i<numEntry; ++i)
|
||||||
|
{
|
||||||
|
predef[i].resize(4*(i+1));
|
||||||
|
for (uint j=0; j<i+1; ++j)
|
||||||
|
{
|
||||||
|
predef[i][j*4] = _KillPlayers[j].ClanName;
|
||||||
|
predef[i][j*4+1] = _KillPlayers[j].MinLevel;
|
||||||
|
predef[i][j*4+2] = _KillPlayers[j].MaxLevel;
|
||||||
|
predef[i][j*4+3] = _KillPlayers[j].Quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add optional place
|
// add optional place
|
||||||
|
@ -1995,6 +2018,33 @@ public:
|
||||||
npcname.initWithText(toString("npc%u", i+1), STRING_MANAGER::bot, md, prim, vs[i]);
|
npcname.initWithText(toString("npc%u", i+1), STRING_MANAGER::bot, md, prim, vs[i]);
|
||||||
_KillNpcs.push_back(npcname);
|
_KillNpcs.push_back(npcname);
|
||||||
}
|
}
|
||||||
|
vs = md.getPropertyArray(prim, "clan_name/min_level/max_level/quantity", true, false);
|
||||||
|
for (uint i=0; i<vs.size(); ++i)
|
||||||
|
{
|
||||||
|
vector<string> args;
|
||||||
|
explode(vs[i], string(" "), args, true);
|
||||||
|
if (args.size() != 4)
|
||||||
|
{
|
||||||
|
string err = toString("Invalid player clan infos in '%s', need <clan_name> <min_level> <max_level> <quantity>", vs[i].c_str());
|
||||||
|
throw EParseException(prim, err.c_str());
|
||||||
|
}
|
||||||
|
if (atoi(args[1].c_str()) >= atoi(args[2].c_str()))
|
||||||
|
{
|
||||||
|
string err = toString("Invalid player clan infos in '%s', need <min_level> lower than <max_level>", vs[i].c_str());
|
||||||
|
throw EParseException(prim, err.c_str());
|
||||||
|
}
|
||||||
|
if (atoi(args[3].c_str()) <= 0)
|
||||||
|
{
|
||||||
|
string err = toString("Invalid player clan infos in '%s', need <quantity> upper than 0", vs[i].c_str());
|
||||||
|
throw EParseException(prim, err.c_str());
|
||||||
|
}
|
||||||
|
TKillPlayerInfo kp;
|
||||||
|
kp.ClanName.initWithText(toString("clan%u", i+1), STRING_MANAGER::clan, md, prim, args[0]);
|
||||||
|
kp.MinLevel.initWithText(toString("minlvl%u", i+1), STRING_MANAGER::integer, md, prim, args[1]);
|
||||||
|
kp.MaxLevel.initWithText(toString("maxlvl%u", i+1), STRING_MANAGER::integer, md, prim, args[2]);
|
||||||
|
kp.Quantity.initWithText(toString("quantity%u", i+1), STRING_MANAGER::integer, md, prim, args[3]);
|
||||||
|
_KillPlayers.push_back(kp);
|
||||||
|
}
|
||||||
|
|
||||||
s = md.getProperty(prim, "npc_by_name/quantity", false, false);
|
s = md.getProperty(prim, "npc_by_name/quantity", false, false);
|
||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
|
@ -2058,6 +2108,12 @@ public:
|
||||||
throw EParseException(prim, "Merging of multiple kill mode is forbidden !");
|
throw EParseException(prim, "Merging of multiple kill mode is forbidden !");
|
||||||
check = true;
|
check = true;
|
||||||
}
|
}
|
||||||
|
if (!_KillPlayers.empty())
|
||||||
|
{
|
||||||
|
if (check)
|
||||||
|
throw EParseException(prim, "Merging of multiple kill mode is forbidden !");
|
||||||
|
check = true;
|
||||||
|
}
|
||||||
|
|
||||||
_Place.init("p", STRING_MANAGER::place, md, prim, "place");
|
_Place.init("p", STRING_MANAGER::place, md, prim, "place");
|
||||||
|
|
||||||
|
@ -2117,6 +2173,16 @@ public:
|
||||||
{
|
{
|
||||||
ret += "kill_faction : "+_KillFactionName+" "+_KillFactionQuantity;
|
ret += "kill_faction : "+_KillFactionName+" "+_KillFactionQuantity;
|
||||||
}
|
}
|
||||||
|
else if (!_KillPlayers.empty())
|
||||||
|
{
|
||||||
|
ret += "kill_player : ";
|
||||||
|
for (uint i=0; i<_KillPlayers.size(); ++i)
|
||||||
|
{
|
||||||
|
ret += _KillPlayers[i].ClanName+" "+_KillPlayers[i].MinLevel+" "+_KillPlayers[i].MaxLevel+" "+_KillPlayers[i].Quantity;
|
||||||
|
if (i < _KillPlayers.size()-1)
|
||||||
|
{ret += "; ";}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!_Place.empty())
|
if (!_Place.empty())
|
||||||
ret += " : "+_Place;
|
ret += " : "+_Place;
|
||||||
|
@ -2130,6 +2196,30 @@ public:
|
||||||
};
|
};
|
||||||
REGISTER_STEP_CONTENT(CContentKill, "kill");
|
REGISTER_STEP_CONTENT(CContentKill, "kill");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
class CContentKillFamedPlayer : public CContentObjective
|
||||||
|
{
|
||||||
|
vector<TKillFamedPlayerInfo> _Clans;
|
||||||
|
|
||||||
|
virtual void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef)
|
||||||
|
{
|
||||||
|
numEntry = _Clans.size();
|
||||||
|
predef.resize(numEntry);
|
||||||
|
for (uint i=0; i<numEntry; ++i)
|
||||||
|
{
|
||||||
|
predef[i].resize(4*(i+1));
|
||||||
|
for (uint j=0; j<i+1; ++j)
|
||||||
|
{
|
||||||
|
predef[i][j*4] = _Clans[j].ClanName;
|
||||||
|
predef[i][j*4+1] = _Clans[j].MinLevel;
|
||||||
|
predef[i][j*4+2] = _Clans[j].MaxLevel;
|
||||||
|
predef[i][j*4+3] = _Clans[j].Quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
class CContentTalkTo : public CContentObjective
|
class CContentTalkTo : public CContentObjective
|
||||||
{
|
{
|
||||||
TCompilerVarName _BotName;
|
TCompilerVarName _BotName;
|
||||||
|
|
Loading…
Reference in a new issue