diff --git a/code/ryzom/server/src/ai_service/ai_bot.cpp b/code/ryzom/server/src/ai_service/ai_bot.cpp index 7e7f78526..4950ebd29 100644 --- a/code/ryzom/server/src/ai_service/ai_bot.cpp +++ b/code/ryzom/server/src/ai_service/ai_bot.cpp @@ -345,6 +345,23 @@ void CSpawnBot::sheetChanged() // CMirrors::initSheet(dataSetRow(), getPersistent().getSheet()->SheetId()); } +void CSpawnBot::sendInfoToEGS() const +{ + if (!EGSHasMirrorReady) + return; + + const uint32& maxHp = getPersistent().getCustomMaxHp(); + if (maxHp > 0.f) + { + CChangeCreatureMaxHPMsg& msgList = CAIS::instance().getCreatureChangeMaxHP(); + + msgList.Entities.push_back(dataSetRow()); + msgList.MaxHp.push_back((uint32)(maxHp)); + msgList.SetFull.push_back((uint8)(1)); + } +} + + ////////////////////////////////////////////////////////////////////////////// // CBot // ////////////////////////////////////////////////////////////////////////////// @@ -359,6 +376,7 @@ CBot::CBot(CGroup* owner, CAIAliasDescriptionNode* alias) , _SetSheetData(NULL) , _Observers(NULL) , _ProfileData(NULL) +, _CustomMaxHp(0) { } @@ -372,6 +390,7 @@ CBot::CBot(CGroup* owner, uint32 alias, std::string const& name) , _SetSheetData(NULL) , _Observers(NULL) , _ProfileData(NULL) +, _CustomMaxHp(0.f) { } diff --git a/code/ryzom/server/src/ai_service/ai_bot.h b/code/ryzom/server/src/ai_service/ai_bot.h index ceea47efe..f016d943c 100644 --- a/code/ryzom/server/src/ai_service/ai_bot.h +++ b/code/ryzom/server/src/ai_service/ai_bot.h @@ -69,7 +69,7 @@ public: virtual void setTheta(CAngle theta); - virtual void sendInfoToEGS() const = 0; + virtual void sendInfoToEGS() const; CBot& getPersistent() const; @@ -244,6 +244,9 @@ public: const ucstring& getCustomName() const { return _CustomName; } void setCustomName(const ucstring &name) { _CustomName = name; } + const uint32& getCustomMaxHp() const { return _CustomMaxHp; } + void setCustomMaxHp(const uint32 &maxHp) { _CustomMaxHp = maxHp; } + virtual void setClientSheet(const std::string & clientSheetName); // Can be redefine by NpcGroup in case of a BotNpc with a fauna sheet but that we don't want the name to ignore @@ -273,6 +276,7 @@ private: bool _Healer; bool _BuildingBot; ucstring _CustomName; + uint32 _CustomMaxHp; CTimer _SetSheetTimer; struct CSetSheetData { diff --git a/code/ryzom/server/src/ai_service/ai_bot_npc.cpp b/code/ryzom/server/src/ai_service/ai_bot_npc.cpp index 04e6e05ac..a87b05865 100644 --- a/code/ryzom/server/src/ai_service/ai_bot_npc.cpp +++ b/code/ryzom/server/src/ai_service/ai_bot_npc.cpp @@ -62,6 +62,8 @@ void CSpawnBotNpc::sendInfoToEGS() const if (!EGSHasMirrorReady) return; + CSpawnBot::sendInfoToEGS(); + TGenNpcDescMsgImp msg; msg.setEntityIndex(dataSetRow()); diff --git a/code/ryzom/server/src/ai_service/ai_grp_npc.cpp b/code/ryzom/server/src/ai_service/ai_grp_npc.cpp index 87f5e8953..937a6f421 100644 --- a/code/ryzom/server/src/ai_service/ai_grp_npc.cpp +++ b/code/ryzom/server/src/ai_service/ai_grp_npc.cpp @@ -1113,6 +1113,29 @@ void CGroupNpc::setOutpostSide(OUTPOSTENUMS::TPVPSide side) } } +void CGroupNpc::setOutpostFactions(OUTPOSTENUMS::TPVPSide side) +{ + // Attack only the declared ennemies of the outpost + if (side == OUTPOSTENUMS::OutpostOwner) + { + // Bots factions + faction ().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); + friendFaction().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); + ennemyFaction().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); + // Players faction + ennemyFaction().addProperty(NLMISC::toString("outpost:%s:attacker", getAliasString().c_str())); + } + if (side == OUTPOSTENUMS::OutpostAttacker) + { + // Bots factions + faction ().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); + friendFaction().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); + ennemyFaction().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); + // Players faction + ennemyFaction().addProperty(NLMISC::toString("outpost:%s:defender", getAliasString().c_str())); + } +} + void CGroupNpc::setFactionAttackableAbove(std::string faction, sint32 threshold, bool botAttackable) { if (botAttackable) diff --git a/code/ryzom/server/src/ai_service/ai_grp_npc.h b/code/ryzom/server/src/ai_service/ai_grp_npc.h index 916ae54b8..bac75d1a9 100644 --- a/code/ryzom/server/src/ai_service/ai_grp_npc.h +++ b/code/ryzom/server/src/ai_service/ai_grp_npc.h @@ -231,6 +231,7 @@ public: void setColour(uint8 colour); void setOutpostSide(OUTPOSTENUMS::TPVPSide side); + void setOutpostFactions(OUTPOSTENUMS::TPVPSide side); bool isRingGrp() const { return _RingGrp;} private: diff --git a/code/ryzom/server/src/ai_service/ai_outpost.cpp b/code/ryzom/server/src/ai_service/ai_outpost.cpp index c6eb0ff5a..10bfa1162 100644 --- a/code/ryzom/server/src/ai_service/ai_outpost.cpp +++ b/code/ryzom/server/src/ai_service/ai_outpost.cpp @@ -870,25 +870,8 @@ void COutpost::createSquad(CGroupDesc const* groupDesc, COu }*/ grp->setOutpostSide(side); - // Attack only the declared ennemies of the outpost - if (side==OUTPOSTENUMS::OutpostOwner) - { - // Bots factions - grp->faction ().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); - grp->friendFaction().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); - grp->ennemyFaction().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); - // Players faction - grp->ennemyFaction().addProperty(NLMISC::toString("outpost:%s:attacker", getAliasString().c_str())); - } - if (side==OUTPOSTENUMS::OutpostAttacker) - { - // Bots factions - grp->faction ().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); - grp->friendFaction().addProperty(NLMISC::toString("outpost:%s:bot_attacker", getAliasString().c_str())); - grp->ennemyFaction().addProperty(NLMISC::toString("outpost:%s:bot_defender", getAliasString().c_str())); - // Players faction - grp->ennemyFaction().addProperty(NLMISC::toString("outpost:%s:defender", getAliasString().c_str())); - } + grp->setOutpostFactions(side); + grp->_AggroRange = 25; grp->_UpdateNbTicks = 10; grp->respawnTime() = respawTimeGC; diff --git a/code/ryzom/server/src/ai_service/nf_grp.cpp b/code/ryzom/server/src/ai_service/nf_grp.cpp index d57f80174..fde5a557c 100644 --- a/code/ryzom/server/src/ai_service/nf_grp.cpp +++ b/code/ryzom/server/src/ai_service/nf_grp.cpp @@ -1522,11 +1522,14 @@ void setMaxHP_ff_(CStateInstance* entity, CScriptStack& stack) if (!bot->isSpawned()) continue; - CSpawnBot* const sbot = bot->getSpawnObj(); - - msgList.Entities.push_back(sbot->dataSetRow()); - msgList.MaxHp.push_back((uint32)(maxHp)); - msgList.SetFull.push_back((uint8)(setFull?1:0)); + if (maxHp > 0) + { + CSpawnBot* const sbot = bot->getSpawnObj(); + msgList.Entities.push_back(sbot->dataSetRow()); + msgList.MaxHp.push_back((uint32)(maxHp)); + msgList.SetFull.push_back((uint8)(setFull?1:0)); + } + bot->setCustomMaxHp((uint32)maxHp); } } diff --git a/code/ryzom/server/src/ai_service/nf_grp_npc.cpp b/code/ryzom/server/src/ai_service/nf_grp_npc.cpp index 2b3f9d249..0672269fc 100644 --- a/code/ryzom/server/src/ai_service/nf_grp_npc.cpp +++ b/code/ryzom/server/src/ai_service/nf_grp_npc.cpp @@ -124,6 +124,51 @@ void setFactionProp_ss_(CStateInstance* entity, CScriptStack& stack) } } +void setOupostMode_ss_(CStateInstance* entity, CScriptStack& stack) +{ + std::string sideStr = stack.top(); stack.pop(); + std::string aliasStr = stack.top(); + CGroupNpc* const npcGroup = dynamic_cast(entity->getGroup()); + if ( ! npcGroup) + { + nlwarning("setOutpostMode on a non Npc Group, doesnt work"); + return; + } + + OUTPOSTENUMS::TPVPSide side; + if (sideStr == "attacker") + { + side = OUTPOSTENUMS::OutpostAttacker; + } + else if (sideStr == "owner") + { + side = OUTPOSTENUMS::OutpostOwner; + } + else + { + nlwarning("setOutpostMode: invalid side"); + } + + npcGroup->setOutpostSide(side); + npcGroup->setOutpostFactions(side); + FOREACH(botIt, CCont, npcGroup->bots()) + { + CBot* bot = *botIt; + CBotNpc* botNpc = NLMISC::safe_cast(bot); + if (botNpc) + { + CSpawnBotNpc* spawnBotNpc = botNpc->getSpawn(); + if (spawnBotNpc) + { + spawnBotNpc->setOutpostSide(side); + spawnBotNpc->setOutpostAlias(LigoConfig.aliasFromString(aliasStr)); + } + } + } + if (npcGroup->isSpawned()) + npcGroup->getSpawnObj()->sendInfoToEGS(); +} + //---------------------------------------------------------------------------- /** @page code @@ -2749,6 +2794,7 @@ std::map nfGetNpcGroupNativeFunctions() #define REGISTER_NATIVE_FUNC(cont, func) cont.insert(std::make_pair(std::string(#func), &func)) REGISTER_NATIVE_FUNC(functions, setFactionProp_ss_); + REGISTER_NATIVE_FUNC(functions, setOupostMode_ss_); REGISTER_NATIVE_FUNC(functions, moveToZone_ss_); REGISTER_NATIVE_FUNC(functions, setActivity_s_); REGISTER_NATIVE_FUNC(functions, startWander_f_); diff --git a/code/ryzom/server/src/ai_service/npc_description_msg.cpp b/code/ryzom/server/src/ai_service/npc_description_msg.cpp index 414eeae67..a5a90ad29 100644 --- a/code/ryzom/server/src/ai_service/npc_description_msg.cpp +++ b/code/ryzom/server/src/ai_service/npc_description_msg.cpp @@ -831,10 +831,9 @@ void TGenNpcDescMsgImp::setChat(const CNpcChatProfileImp& chatProfile) _ContextOptions = chatProfile.getContextOptions(); // ContextOptionsTitles = chatProfile.getContextOptionsTitles(); // ContextOptionsDetails = chatProfile.getContextOptionsDetails(); - // As I don't remembre why I did an insert instead of an affectation I let it commented here. -// vector const& chatOptionalProperties = chatProfile.getOptionalProperties(); -// OptionalProperties.insert(OptionalProperties.end(), chatOptionalProperties.begin(), chatOptionalProperties.end()); - _OptionalProperties = chatProfile.getOptionalProperties(); + + vector const& chatOptionalProperties = chatProfile.getOptionalProperties(); + _OptionalProperties.insert(_OptionalProperties.end(), chatOptionalProperties.begin(), chatOptionalProperties.end()); _Outpost = chatProfile.getOutpost(); _Organization = chatProfile.getOrganization(); diff --git a/code/ryzom/server/src/backup_service/backup_file_access.cpp b/code/ryzom/server/src/backup_service/backup_file_access.cpp index 7ff04884b..d039a147d 100644 --- a/code/ryzom/server/src/backup_service/backup_file_access.cpp +++ b/code/ryzom/server/src/backup_service/backup_file_access.cpp @@ -431,6 +431,15 @@ IFileAccess::TReturnCode CWriteFile::execute(CFileAccessManager& manager) return MinorFailure; } + NLMISC::COFile flog; + std::string str = getBackupFileName(Filename)+"\n"; + if(str.find("characters")!=std::string::npos) + { + flog.open(getBackupFileName("new_save.txt"), true); + flog.serialBuffer((uint8*)&(str[0]), str.size()); + flog.close(); + } + return Success; } diff --git a/code/ryzom/server/src/entities_game_service/admin.cpp b/code/ryzom/server/src/entities_game_service/admin.cpp index f7b164fcc..4ce0d093a 100644 --- a/code/ryzom/server/src/entities_game_service/admin.cpp +++ b/code/ryzom/server/src/entities_game_service/admin.cpp @@ -49,6 +49,7 @@ #include "game_share/outpost.h" #include "game_share/visual_slot_manager.h" #include "game_share/shard_names.h" +#include "game_share/http_client.h" #include "server_share/log_command_gen.h" #include "server_share/r2_vision.h" @@ -180,8 +181,9 @@ AdminCommandsInit[] = "validateRespawnPoint", true, "summonPet", true, "connectUserChannel", true, - "updateTarget", true, + "updateTarget", true, "resetName", true, + "showOnline", true, // Web commands managment "webExecCommand", true, @@ -212,7 +214,7 @@ AdminCommandsInit[] = "learnBrick", true, "unlearnBrick", true, "learnPhrase", true, - "learnAllForagePhrases", true, + "learnAllForagePhrases", true, "learnAllFaberPlans", true, "logXpGain", true, "memorizePhrase", true, @@ -312,7 +314,7 @@ AdminCommandsInit[] = "setGuildChargePoint", false, "characterInventoryDump", true, "deleteInventoryItem", true, - "setSimplePhrase", false, + "setSimplePhrase", false, // PUT HERE THE VARIABLE / COMMAND THAT ARE TEMPORARY // remove when message of the day interface is ready @@ -323,8 +325,8 @@ AdminCommandsInit[] = "EntitiesNoActionFailure", false, "EntitiesNoCastBreak", false, "EntitiesNoResist", false, - "lockItem", true, - "setTeamLeader", true, + "lockItem", true, + "setTeamLeader", true, // aggroable state "Aggro", true, @@ -388,7 +390,7 @@ AdminCommandsInit[] = "eventSetBotURLName", true, "eventSpawnToxic", true, "eventNpcSay", true, - "eventSetBotFacing", true, + "eventSetBotFacing", true, "eventGiveControl", true, "eventLeaveControl", true, @@ -422,7 +424,7 @@ bool getAIInstanceFromGroupName(string& groupName, uint32& instanceNumber) return false; } instanceNumber = nr; - groupName = groupName.substr(groupName.find('@'), groupName.size()); + groupName = groupName.substr(groupName.find('@') + 1, groupName.size()); } return true; } @@ -460,6 +462,7 @@ void initAdmin () cmd.Name = AdminCommandsInit[i].Name; cmd.AddEId = AdminCommandsInit[i].AddEId; cmd.Priv = DefaultPriv; + cmd.Audit = false; AdminCommands.push_back(cmd); } @@ -525,9 +528,9 @@ static void loadCommandsPrivileges(const string & fileName, bool init) CSString fullLine = line; - // only extract the first 2 params + // only extract the first 4 params CVectorSString params; - for (uint i = 0; !line.empty() && i < 2; i++) + for (uint i = 0; !line.empty() && i < 4; i++) { string param = line.strtok(" \t"); if (param.empty()) @@ -546,7 +549,7 @@ static void loadCommandsPrivileges(const string & fileName, bool init) { // this is a forward } - else if (params.size() > 2) + else if (params.size() > 3) { nlwarning("ADMIN: invalid entry: '%s'.", fullLine.c_str()); continue; @@ -563,15 +566,23 @@ static void loadCommandsPrivileges(const string & fileName, bool init) params.push_back(""); } + if (params.size() < 4) + { + // no audit specified + params.push_back(""); + } + const string & cmdName = params[0]; const string & forward = params[1]; const string & cmdPriv = params[2]; + const bool & audit = (params[3] == "audit"); CAdminCommand * cmd = findAdminCommand(cmdName); if (cmd) { cmd->Priv = cmdPriv; cmd->ForwardToservice = forward.substr(1, forward.size()-2); + cmd->Audit = audit; nlinfo("ADMIN: command '%s' forwarded to [%s] has new privileges '%s'.", cmdName.c_str(), cmd->ForwardToservice.c_str(), cmdPriv.c_str()); } else @@ -2376,16 +2387,18 @@ NLMISC_COMMAND(getPetAnimalSatiety,"Get the satiety of pet animal (petIndex in 0 return true; } -NLMISC_COMMAND(setPetAnimalName, "Set the name of a pet animal (petIndex in 0..3)"," ") +NLMISC_COMMAND(setPetAnimalName, "Set the name of a pet animal"," []") { - if (args.size () < 3) return false; + if (args.size () < 2) return false; GET_CHARACTER if ( c ) { uint petIndex; fromString(args[1], petIndex); - ucstring customName = args[2]; + ucstring customName; + if (args.size () == 3) + customName = args[2]; c->setAnimalName(petIndex, customName); } @@ -2932,6 +2945,29 @@ NLMISC_DYNVARIABLE (uint32, RyzomDate, "Current ryzom date") // // // +void audit(const CAdminCommand *cmd, const string &rawCommand, const CEntityId &eid, const string &name, const string &targetName) +{ + if (cmd == NULL) + return; + + CConfigFile::CVar *varHost = IService::getInstance()->ConfigFile.getVarPtr("AdminCommandAuditHost"); + CConfigFile::CVar *varPage = IService::getInstance()->ConfigFile.getVarPtr("AdminCommandAuditPage"); + + if (varHost == NULL || varPage == NULL) + return; + + string host = varHost->asString(); + string page = varPage->asString(); + + if (host == "" || page == "") + return; + + char params[1024]; + sprintf(params, "action=audit&cmd=%s&raw=%s&name=(%s,%s)&target=%s", cmd->Name.c_str(), rawCommand.c_str(), eid.toString().c_str(), name.c_str(), targetName.c_str()); + + IThread *thread = IThread::create(new CHttpPostTask(host, page, params)); + thread->start(); +} // all admin /a /b commands executed by the client go in this callback void cbClientAdmin (NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId) @@ -3062,6 +3098,8 @@ void cbClientAdmin (NLNET::CMessage& msgin, const std::string &serviceName, NLNE res = (string)cs_res; nlinfo ("ADMIN: Player (%s,%s) will execute client admin command '%s' on target %s", eid.toString().c_str(), csName.c_str(), res.c_str(), targetName.c_str()); + audit(cmd, res, eid, csName, targetName); + CLightMemDisplayer *CmdDisplayer = new CLightMemDisplayer("CmdDisplayer"); CLog *CmdLogger = new CLog( CLog::LOG_NO ); CmdLogger->addDisplayer( CmdDisplayer ); @@ -3585,8 +3623,11 @@ NLMISC_COMMAND( killMob, "kill a mob ( /a killMob )", "" ) } if ( !creature->getContextualProperty().directAccessForStructMembers().attackable() ) { - CCharacter::sendDynamicSystemMessage( eid, "CSR_NOT_ATTACKABLE" ); - return true; + if ( ! creature->checkFactionAttackable(c->getId())) + { + CCharacter::sendDynamicSystemMessage( eid, "CSR_NOT_ATTACKABLE" ); + return true; + } } creature->getScores()._PhysicalScores[SCORES::hit_points].Current = 0; return true; @@ -5442,35 +5483,148 @@ NLMISC_COMMAND (webExecCommand, "Execute a web command", " 5 ) return false; - - sint32 x; - sint32 y; - sint32 z; - float t; - fromString(command_args[1], x); - fromString(command_args[2], y); - fromString(command_args[3], z); - if (command_args.size() > 4) + if (command_args.size () < 2) return false; + + bool pvpValid = (c->getPvPRecentActionFlag() == false || c->getPVPFlag() == false); + if (command_args.size () > 3 && command_args[3] == "1" && !pvpValid) { - fromString(command_args[4], t); + CCharacter::sendDynamicSystemMessage(c->getEntityRowId(), "PVP_TP_FORBIDEN"); + return true; + } + + string value = command_args[1]; + + vector res; + sint32 x = 0, y = 0, z = 0; + float h = 0; + if ( value.find(',') != string::npos ) // Position x,y,z,a + { + explode (value, string(","), res); + if (res.size() >= 2) + { + fromString(res[0], x); + x *= 1000; + fromString(res[1], y); + y *= 1000; + } + if (res.size() >= 3) + { + fromString(res[2], z); + z *= 1000; + } + if (res.size() >= 4) + fromString(res[3], h); } else { - t = c->getState().Heading; + if ( value.find(".creature") != string::npos ) + { + CSheetId creatureSheetId(value); + if( creatureSheetId != CSheetId::Unknown ) + { + double minDistance = -1.; + CCreature * creature = NULL; + + TMapCreatures::const_iterator it; + const TMapCreatures& creatures = CreatureManager.getCreature(); + for( it = creatures.begin(); it != creatures.end(); ++it ) + { + CSheetId sheetId = (*it).second->getType(); + if( sheetId == creatureSheetId ) + { + double distance = PHRASE_UTILITIES::getDistance( c->getEntityRowId(), (*it).second->getEntityRowId() ); + if( !creature || (creature && distance < minDistance) ) + { + creature = (*it).second; + minDistance = distance; + } + } + } + if( creature ) + { + x = creature->getState().X(); + y = creature->getState().Y(); + z = creature->getState().Z(); + h = creature->getState().Heading(); + } + } + else + { + nlwarning (" '%s' is an invalid creature", value.c_str()); + } + } + else + { + + CEntityBase *entityBase = PlayerManager.getCharacterByName (CShardNames::getInstance().makeFullNameFromRelative(c->getHomeMainlandSessionId(), value)); + if (entityBase == 0) + { + // try to find the bot name + vector aliases; + CAIAliasTranslator::getInstance()->getNPCAliasesFromName( value, aliases ); + if ( aliases.empty() ) + { + nldebug (" Ignoring attempt to teleport because no NPC found matching name '%s'", value.c_str()); + return true; + } + + TAIAlias alias = aliases[0]; + + const CEntityId & botId = CAIAliasTranslator::getInstance()->getEntityId (alias); + if ( botId != CEntityId::Unknown ) + { + entityBase = CreatureManager.getCreature (botId); + } + else + { + nlwarning ("'%s' has no eId. Is it Spawned???", value.c_str()); + return true; + } + + } + if (entityBase != 0) + { + x = entityBase->getState().X + sint32 (cos (entityBase->getState ().Heading) * 2000); + y = entityBase->getState().Y + sint32 (sin (entityBase->getState ().Heading) * 2000); + z = entityBase->getState().Z; + h = entityBase->getState().Heading; + } + } } - NLNET::CMessage msgout( "TELEPORT_PLAYER" ); - msgout.serial( const_cast(c->getId()) ); - msgout.serial( const_cast(x) ); - msgout.serial( const_cast(y) ); - msgout.serial( const_cast(z) ); - msgout.serial( const_cast(t) ); - sendMessageViaMirror( "EGS", msgout ); + if (x == 0 && y == 0 && z == 0) + { + nlwarning ("'%s' is a bad value for position, don't change position", value.c_str()); + return true; + } + + CContinent * cont = CZoneManager::getInstance().getContinent(x,y); + + bool allowPetTp = false; + if (command_args.size () == 3 && command_args[2] == "1") + allowPetTp = true; + + if (allowPetTp) + c->allowNearPetTp(); + else + c->forbidNearPetTp(); + + // Respawn player if dead + if (c->isDead()) + { + PROGRESSIONPVP::CCharacterProgressionPVP::getInstance()->playerRespawn(c); + // apply respawn effects because user is dead + c->applyRespawnEffects(); + } + + c->teleportCharacter(x,y,z,allowPetTp,true,h); + + if ( cont ) + { + c->getRespawnPoints().addDefaultRespawnPoint( CONTINENT::TContinent(cont->getId()) ); + } } //************************************************* @@ -8434,6 +8588,21 @@ NLMISC_COMMAND (resetName, "Reset your name; undo a temporary rename", " ") +{ + if (args.size() < 2) return false; + GET_CHARACTER; + + uint8 mode = 0; + NLMISC::fromString(args[1], mode); + if (mode < NB_FRIEND_VISIBILITY) + { + c->setFriendVisibility((TFriendVisibility)mode); + } + return true; +} + //---------------------------------------------------------------------------- NLMISC_COMMAND (lockItem, "Lock/unlock item in inventory", " ") { diff --git a/code/ryzom/server/src/entities_game_service/admin.h b/code/ryzom/server/src/entities_game_service/admin.h index efacb20cf..5a00850aa 100644 --- a/code/ryzom/server/src/entities_game_service/admin.h +++ b/code/ryzom/server/src/entities_game_service/admin.h @@ -34,6 +34,7 @@ struct CAdminCommand bool AddEId; std::string Priv; std::string ForwardToservice; + bool Audit; }; // diff --git a/code/ryzom/server/src/entities_game_service/building_manager/building_physical.cpp b/code/ryzom/server/src/entities_game_service/building_manager/building_physical.cpp index ed469b9b5..9e93b7ed9 100644 --- a/code/ryzom/server/src/entities_game_service/building_manager/building_physical.cpp +++ b/code/ryzom/server/src/entities_game_service/building_manager/building_physical.cpp @@ -336,6 +336,10 @@ bool CBuildingPhysicalGuild::isUserAllowed(CCharacter * user, uint16 ownerId, ui nlassert( user ); nlassert( ownerId < _Guilds.size() ); nlassert( roomIdx < _Template->Rooms.size() ); + + if (user->isDead()) + return false; + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if ( !guild ) return false; @@ -530,6 +534,9 @@ bool CBuildingPhysicalPlayer::isUserAllowed(CCharacter * user, uint16 ownerId, u nlassert(user); nlassert(ownerId < _Players.size() ); + if (user->isDead()) + return false; + CCharacter * owner = PlayerManager.getChar( _Players[ownerId] ); if (owner) return ( (user->getId() == _Players[ownerId]) || owner->playerHaveRoomAccess(user->getId()) ); diff --git a/code/ryzom/server/src/entities_game_service/building_manager/destination.cpp b/code/ryzom/server/src/entities_game_service/building_manager/destination.cpp index 99cb34839..51f159489 100644 --- a/code/ryzom/server/src/entities_game_service/building_manager/destination.cpp +++ b/code/ryzom/server/src/entities_game_service/building_manager/destination.cpp @@ -307,6 +307,10 @@ bool CRoomDestination::isUserAllowed(CCharacter * user,uint16 ownerIdx) #ifdef NL_DEBUG nlassert(user); #endif + + if (user && user->isDead()) + return false; + CMirrorPropValueRO mirrorCell( TheDataset, user->getEntityRowId(), DSPropertyCELL ); sint32 cell = mirrorCell; const IRoomInstance * room = CBuildingManager::getInstance()->getRoomInstanceFromCell( cell ); @@ -423,6 +427,9 @@ bool CExitDestination::build( const NLLIGO::IPrimitive* prim,const NLLIGO::IPrim //---------------------------------------------------------------------------- bool CExitDestination::isUserAllowed(CCharacter * user, uint16 ownerIdx) { + if (user && user->isDead()) + return false; + CMirrorPropValueRO mirrorCell( TheDataset, user->getEntityRowId(), DSPropertyCELL ); sint32 cell = mirrorCell; const IRoomInstance * room = CBuildingManager::getInstance()->getRoomInstanceFromCell( cell ); diff --git a/code/ryzom/server/src/entities_game_service/client_messages.cpp b/code/ryzom/server/src/entities_game_service/client_messages.cpp index d56345f5b..9c40edc4a 100644 --- a/code/ryzom/server/src/entities_game_service/client_messages.cpp +++ b/code/ryzom/server/src/entities_game_service/client_messages.cpp @@ -1114,9 +1114,8 @@ void cbClientMoveInContactLists( NLNET::CMessage& msgin, const std::string &serv if (listOrigin == 0) { NLMISC::CEntityId eid= c->getFriendByContactId(contactIdOrigin); - // allows the whole operation or nothing if player is not present - CCharacter * other = PlayerManager.getChar( eid ); - if(other) + // allows the whole operation or nothing if player does not exist + if (eid != CEntityId::Unknown) { c->removePlayerFromFriendListByEntityId(eid); c->addPlayerToIgnoreList(eid); @@ -1124,15 +1123,14 @@ void cbClientMoveInContactLists( NLNET::CMessage& msgin, const std::string &serv else { // player not found => message - PHRASE_UTILITIES::sendDynamicSystemMessage( c->getEntityRowId(), "OPERATION_OFFLINE"); + PHRASE_UTILITIES::sendDynamicSystemMessage( c->getEntityRowId(), "OPERATION_NOTEXIST"); } } else { NLMISC::CEntityId eid= c->getIgnoreByContactId(contactIdOrigin); // allows the whole operation or nothing if player is not present - CCharacter * other = PlayerManager.getChar( eid ); - if(other) + if(eid != CEntityId::Unknown) { c->removePlayerFromIgnoreListByEntityId(eid); c->addPlayerToFriendList(eid); @@ -1140,7 +1138,7 @@ void cbClientMoveInContactLists( NLNET::CMessage& msgin, const std::string &serv else { // player not found => message - PHRASE_UTILITIES::sendDynamicSystemMessage( c->getEntityRowId(), "OPERATION_OFFLINE"); + PHRASE_UTILITIES::sendDynamicSystemMessage( c->getEntityRowId(), "OPERATION_NOTEXIST"); } } } @@ -2544,7 +2542,7 @@ void cbClientWho( NLNET::CMessage& msgin, const std::string &serviceName, NLNET: return; } - bool havePriv = p->havePriv(":DEV:SGM:GM:"); + bool havePriv = p->havePriv(":DEV:SGM:GM:EM:"); bool hasChannel = false; nbAnswers = 0; @@ -2578,9 +2576,10 @@ void cbClientWho( NLNET::CMessage& msgin, const std::string &serviceName, NLNET: if (!playerNames.empty()) { - CCharacter::sendDynamicSystemMessage( id, "WHO_CHANNEL_INTRO" ); - //playerNames = "Players in channel \"" + opt + "\":" + playerNames; SM_STATIC_PARAMS_1(params, STRING_MANAGER::literal); + params[0].Literal = opt; + CCharacter::sendDynamicSystemMessage( id, "WHO_CHANNEL_INTRO", params); + //playerNames = "Players in channel \"" + opt + "\":" + playerNames; params[0].Literal = playerNames; CCharacter::sendDynamicSystemMessage( id, "LITERAL", params ); return; diff --git a/code/ryzom/server/src/entities_game_service/creature_manager/creature.cpp b/code/ryzom/server/src/entities_game_service/creature_manager/creature.cpp index 46a4f9766..fbda3f415 100644 --- a/code/ryzom/server/src/entities_game_service/creature_manager/creature.cpp +++ b/code/ryzom/server/src/entities_game_service/creature_manager/creature.cpp @@ -2060,9 +2060,9 @@ uint32 CCreature::tickUpdate() setBars(); } - // test again as effects can kill the entity (dots...) - if (isDead()) - { + // test again as effects can kill the entity (dots...) + if (isDead()) + { deathOccurs(); } diff --git a/code/ryzom/server/src/entities_game_service/creature_manager/creature_manager.cpp b/code/ryzom/server/src/entities_game_service/creature_manager/creature_manager.cpp index 556ebf921..3def0fde0 100644 --- a/code/ryzom/server/src/entities_game_service/creature_manager/creature_manager.cpp +++ b/code/ryzom/server/src/entities_game_service/creature_manager/creature_manager.cpp @@ -253,7 +253,7 @@ void CChangeCreatureHPImp::callback(const string &, NLNET::TServiceId sid) //-------------------------------------------------------------- -// CChangeCreatureMaxHPImp ::callback() +// CCreatureSetUrlImp ::callback() //-------------------------------------------------------------- void CCreatureSetUrlImp::callback(const string &, NLNET::TServiceId sid) { diff --git a/code/ryzom/server/src/entities_game_service/entity_manager/entity_callbacks.cpp b/code/ryzom/server/src/entities_game_service/entity_manager/entity_callbacks.cpp index 93d9553c3..d969a4405 100644 --- a/code/ryzom/server/src/entities_game_service/entity_manager/entity_callbacks.cpp +++ b/code/ryzom/server/src/entities_game_service/entity_manager/entity_callbacks.cpp @@ -504,6 +504,7 @@ void cbClientReady( CMessage& msgin, const std::string &serviceName, NLNET::TSer if (!IsRingShard && player->havePriv(AlwaysInvisiblePriv)) { c->setWhoSeesMe(uint64(0)); + c->setInvisibility(true); } TheDataset.declareEntity( entityIndex ); // after the writing of properties to mirror @@ -676,8 +677,26 @@ void finalizeClientReady( uint32 userId, uint32 index ) // for GM player, trigger a 'infos' command to remember their persistent state if (!PlayerManager.getPlayer(uint32(c->getId().getShortId())>>4)->getUserPriv().empty()) - CCommandRegistry::getInstance().execute(toString("infos %s", c->getId().toString().c_str()).c_str(), InfoLog(), true); - + { + string res = toString("infos %s", c->getId().toString().c_str()).c_str(); + CLightMemDisplayer *CmdDisplayer = new CLightMemDisplayer("CmdDisplayer"); + CLog *CmdLogger = new CLog( CLog::LOG_NO ); + CmdLogger->addDisplayer( CmdDisplayer ); + NLMISC::ICommand::execute(res, *CmdLogger, true); + const std::deque &strs = CmdDisplayer->lockStrings (); + for (uint i = 0; i < strs.size(); i++) + { + InfoLog->displayNL("%s", trim(strs[i]).c_str()); + + SM_STATIC_PARAMS_1(params,STRING_MANAGER::literal); + params[0].Literal = trim(strs[i]); + CCharacter::sendDynamicSystemMessage( c->getId(), "LITERAL", params ); + } + CmdDisplayer->unlockStrings(); + CmdLogger->removeDisplayer (CmdDisplayer); + delete CmdDisplayer; + delete CmdLogger; + } c->setFinalized(true); } // finalizeClientReady // diff --git a/code/ryzom/server/src/entities_game_service/game_item_manager/player_inv_xchg.cpp b/code/ryzom/server/src/entities_game_service/game_item_manager/player_inv_xchg.cpp index c497886bc..79d2b40c1 100644 --- a/code/ryzom/server/src/entities_game_service/game_item_manager/player_inv_xchg.cpp +++ b/code/ryzom/server/src/entities_game_service/game_item_manager/player_inv_xchg.cpp @@ -88,6 +88,13 @@ bool CExchangeView::putItemInExchange(uint32 bagSlot, uint32 exchangeSlot, uint3 if (item->getLockedByOwner()) return false; + // You cannot exchange genesis named items + if (item->getPhraseId().find("genesis_") == 0) + { + nlwarning("Character %s tries to sell '%s'", getCharacter()->getId().toString().c_str(), item->getPhraseId().c_str() ); + return false; + } + if( getCharacter()->isAnActiveXpCatalyser(item) ) return false; diff --git a/code/ryzom/server/src/entities_game_service/guild_manager/guild.cpp b/code/ryzom/server/src/entities_game_service/guild_manager/guild.cpp index 766e0f54f..4e9b81911 100644 --- a/code/ryzom/server/src/entities_game_service/guild_manager/guild.cpp +++ b/code/ryzom/server/src/entities_game_service/guild_manager/guild.cpp @@ -953,6 +953,14 @@ void CGuild::putItem( CCharacter * user, uint32 slot, uint32 quantity, uint16 se return; } + // You cannot exchange genesis named items + if (item->getPhraseId().find("genesis_") == 0) + { + nlwarning("Character %s tries to put in guild '%s'", user->getId().toString().c_str(), item->getPhraseId().c_str() ); + CCharacter::sendDynamicSystemMessage( user->getId(),"GUILD_ITEM_CANT_BE_PUT" ); + return; + } + // try to move the required quantity of the item if ( CInventoryBase::moveItem( user->getInventory(INVENTORIES::bag), slot, diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_talk.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_talk.cpp index 5920db67c..7647e7906 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_talk.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_talk.cpp @@ -98,16 +98,35 @@ class CMissionStepTalk : public IMissionStepTemplate uint processEvent( const TDataSetRow & userRow, const CMissionEvent & event,uint subStepIndex,const TDataSetRow & giverRow ) { + string webAppUrl; + _User = PlayerManager.getChar(getEntityIdFromRow(userRow)); + + if (_IsDynamic && _User != NULL) + { + vector params = _User->getCustomMissionParams(_Dynamic); + if (params.size() < 2) + { + LOGMISSIONSTEPERROR("talk_to : invalid npc name"); + return 0; + } + else + { + webAppUrl = params[0]; + } + } + // not check here : they are done befor. If a talk event comes here, the step is complete if( event.Type == CMissionEvent::Talk ) { + if (!webAppUrl.empty() && _User != NULL) + _User->validateDynamicMissionStep(webAppUrl); LOGMISSIONSTEPSUCCESS("talk_to"); return 1; } return 0; } - + void getInitState( std::vector& ret ) { ret.clear(); diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/aura_effect.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/aura_effect.cpp index 29d86be52..f068bb5eb 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/aura_effect.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/aura_effect.cpp @@ -29,6 +29,8 @@ #include "team_manager/team_manager.h" #include "player_manager/player_manager.h" #include "player_manager/player.h" +#include "creature_manager/creature_manager.h" +#include "creature_manager/creature.h" #include "phrase_manager/area_effect.h" #include "aura_effect.h" @@ -213,6 +215,15 @@ bool CAuraRootEffect::isEntityValidTarget(CEntityBase *entity, CEntityBase *crea return true; } + CCreature * creature = CreatureManager.getCreature( entity->getId() ); + if (creature && creator) + { + if (creature->checkFactionAttackable( creator->getId() )) + { + return true; + } + } + return false; }// isEntityValidTarget // diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.cpp index 0056a8407..7fdf972c2 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.cpp @@ -28,9 +28,13 @@ #include "player_manager/character.h" #include "player_manager/player_manager.h" #include "player_manager/player.h" +#include "creature_manager/creature_manager.h" +#include "creature_manager/creature.h" #include "range_selector.h" #include "phrase_manager/effect_factory.h" +extern CCreatureManager CreatureManager; + using namespace std; using namespace NLMISC; using namespace NLNET; @@ -76,7 +80,7 @@ void CBounceEffect::removed() //-------------------------------------------------------------- // CBounceEffect::getTargetForBounce() //-------------------------------------------------------------- -CEntityBase *CBounceEffect::getTargetForBounce() const +CEntityBase *CBounceEffect::getTargetForBounce(CEntityBase *actor) const { // get entities around if (!_AffectedEntity) @@ -99,7 +103,7 @@ CEntityBase *CBounceEffect::getTargetForBounce() const for (uint i = 0; i < entities.size() ; ++i) { - if ( entities[i] && ( entities[i] != (CEntityBase*)(_AffectedEntity) ) && isEntityValidTarget(entities[i]) ) + if ( entities[i] && ( entities[i] != (CEntityBase*)(_AffectedEntity) ) && isEntityValidTarget(entities[i], actor) ) { selectedEntities.push_back(entities[i]); } @@ -118,17 +122,29 @@ CEntityBase *CBounceEffect::getTargetForBounce() const //-------------------------------------------------------------- // CBounceEffect::isEntityValidTarget() //-------------------------------------------------------------- -bool CBounceEffect::isEntityValidTarget(CEntityBase *entity) const +bool CBounceEffect::isEntityValidTarget(CEntityBase *entity, CEntityBase *actor) const { #ifdef NL_DEBUG nlassert(entity); #endif + if (entity->isDead()) + return false; + if (entity->getId().getType() == RYZOMID::player) return true; if ( entity->getContextualProperty().getValue().attackable() ) return true; + + CCreature * creature = CreatureManager.getCreature( entity->getId() ); + if (creature && actor) + { + if (creature->checkFactionAttackable( actor->getId() )) + { + return true; + } + } return false; } // checkTargetValidity // diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.h b/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.h index fdc9a71e6..fbb63f44e 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.h +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/bounce_effect.h @@ -61,11 +61,11 @@ public: virtual void removed(); /// get entity on which the attack is redirected - CEntityBase *getTargetForBounce() const; + CEntityBase *getTargetForBounce(CEntityBase *actor) const; private: /// check entity is a valid target - bool isEntityValidTarget(CEntityBase *entity) const; + bool isEntityValidTarget(CEntityBase *entity, CEntityBase *actor) const; private: /// affected entity diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/combat_phrase.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/combat_phrase.cpp index 0d9dcb35f..71c40d394 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/combat_phrase.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/combat_phrase.cpp @@ -4633,7 +4633,7 @@ void CCombatPhrase::applyBounceEffect(CEntityBase *actingEntity, sint32 attacker } #endif - CEntityBase *bounceTarget = bounceEffect->getTargetForBounce(); + CEntityBase *bounceTarget = bounceEffect->getTargetForBounce(actingEntity); if (!bounceTarget) return; diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.cpp index 2f75eecd9..6e0205fa6 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.cpp @@ -28,6 +28,8 @@ #include "player_manager/character.h" #include "player_manager/player_manager.h" #include "player_manager/player.h" +#include "creature_manager/creature_manager.h" +#include "creature_manager/creature.h" #include "range_selector.h" #include "phrase_manager/effect_factory.h" @@ -68,14 +70,15 @@ bool CDamageAuraEffect::update(CTimerEvent * event, bool applyEffect) { // get entities in surrouding area CRangeSelector entitiesSelector; - entitiesSelector.buildDisc( CEntityBaseManager::getEntityBasePtr(getCreatorRowId()), _AffectedEntity->getX(), _AffectedEntity->getY(), _AuraRadius, EntityMatrix, true ); + CEntityBase * actor = CEntityBaseManager::getEntityBasePtr(getCreatorRowId()); + entitiesSelector.buildDisc( actor, _AffectedEntity->getX(), _AffectedEntity->getY(), _AuraRadius, EntityMatrix, true ); // create or update effect on entities returned const vector &entities = entitiesSelector.getEntities(); const uint size = (uint)entities.size(); for (uint i = 0; i < size ; ++i) { - if (entities[i] && (entities[i] != (CEntityBase*)_AffectedEntity) && isEntityValidTarget(entities[i]) ) + if (entities[i] && (entities[i] != (CEntityBase*)_AffectedEntity) && isEntityValidTarget(entities[i], actor) ) { CEntityBase *entity = entities[i]; @@ -133,7 +136,7 @@ void CDamageAuraEffect::removed() //-------------------------------------------------------------- // CDamageAuraEffect::removed() //-------------------------------------------------------------- -bool CDamageAuraEffect::isEntityValidTarget(CEntityBase *entity) const +bool CDamageAuraEffect::isEntityValidTarget(CEntityBase *entity, CEntityBase *actor) const { #ifdef NL_DEBUG nlassert(entity); @@ -153,6 +156,15 @@ bool CDamageAuraEffect::isEntityValidTarget(CEntityBase *entity) const else retValue = false; + CCreature * creature = CreatureManager.getCreature( entity->getId() ); + if (retValue == false && creature && actor) + { + if (creature->checkFactionAttackable( actor->getId() )) + { + retValue = true; + } + } + if (retValue) { // check entity isn't invulnerable diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.h b/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.h index 37bcd4a13..02712b068 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.h +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/damage_aura_effect.h @@ -82,7 +82,7 @@ public: private: /// check entity is a valid target - bool isEntityValidTarget(CEntityBase *entity) const; + bool isEntityValidTarget(CEntityBase *entity, CEntityBase *actor) const; private: /// cycle lenght in ticks diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/magic_action_attack.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/magic_action_attack.cpp index 32a16b78d..92b001aaa 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/magic_action_attack.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/magic_action_attack.cpp @@ -704,7 +704,7 @@ void CMagicActionBasicDamage::launch( { CBounceEffect *bounceEffect = safe_cast (& (*effect)); bool bounce = false; - CEntityBase *bounceTarget = bounceEffect->getTargetForBounce(); + CEntityBase *bounceTarget = bounceEffect->getTargetForBounce(actor); if (bounceTarget) { bounce = true; diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/phrase_utilities_functions.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/phrase_utilities_functions.cpp index 48dcc4b98..6b1393d4f 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/phrase_utilities_functions.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/phrase_utilities_functions.cpp @@ -1547,15 +1547,21 @@ bool testOffensiveActionAllowed( const NLMISC::CEntityId &actorId, const NLMISC: return true; else { - CEntityBase* actor = CreatureManager.getCreature( actorId ); + CCreature* actor = CreatureManager.getCreature( actorId ); if (!actor) return false; if (!actor->getContextualProperty().directAccessForStructMembers().attackable()) { - // actor is a guard or similar so cannot harm a player or a non attackable creature + // actor is a guard or similar so cannot harm a player or a non attackable creature, unless faction attackable if (targetId.getType() == RYZOMID::player || !target->getContextualProperty().directAccessForStructMembers().attackable()) + { + if ( actor->checkFactionAttackable( targetId ) ) + { + return true; + } return false; + } else return true; } @@ -1570,7 +1576,9 @@ bool testOffensiveActionAllowed( const NLMISC::CEntityId &actorId, const NLMISC: } } - switch ( targetId.getType() ) + + RYZOMID::TTypeId targetType = (RYZOMID::TTypeId)targetId.getType(); + switch ( targetType ) { case RYZOMID::player: { @@ -1593,7 +1601,8 @@ bool testOffensiveActionAllowed( const NLMISC::CEntityId &actorId, const NLMISC: case RYZOMID::mount: case RYZOMID::npc: { - if (actorId.getType() == RYZOMID::player) + RYZOMID::TTypeId type = (RYZOMID::TTypeId)actorId.getType(); + if (type == RYZOMID::player) { CCharacter* actor = PlayerManager.getChar( actorId ); if ( ! actor ) @@ -1718,7 +1727,11 @@ bool validateSpellTarget( const TDataSetRow &actorRowId, const TDataSetRow &targ // player can only heal other players if ( getEntityIdFromRow(actorRowId).getType() == RYZOMID::player && target->getId().getType() != RYZOMID::player ) { - if (target->getContextualProperty().directAccessForStructMembers().attackable() ) + CEntityBase * actor = CEntityBaseManager::getEntityBasePtr( actorRowId ); + CCreature * creature = CreatureManager.getCreature( target->getId() ); + bool bFactionAttackable = (actor && creature && creature->checkFactionAttackable( actor->getId())); + + if (bFactionAttackable || target->getContextualProperty().directAccessForStructMembers().attackable() ) { errorCode = "MAGIC_CANNOT_CAST_ON_ENEMY"; // nldebug("validateSpellTarget for entity %s returning false because %s MAGIC_CANNOT_CAST_ON_ENEMY",getEntityIdFromRow(actorRowId).toString().c_str(),TheDataset.getEntityId(targetRowId).toString().c_str()); diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/special_power_taunt.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/special_power_taunt.cpp index f2866a6af..6ffef15b7 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/special_power_taunt.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/special_power_taunt.cpp @@ -34,7 +34,7 @@ #include "player_manager/character.h" #include "world_instances.h" #include "player_manager/player.h" - +#include "creature_manager/creature_manager.h" #include "egs_sheets/egs_sheets.h" ////////////// @@ -49,6 +49,7 @@ using namespace NLNET; ////////////// extern CRandom RandomGenerator; extern CPlayerManager PlayerManager; +extern CCreatureManager CreatureManager; //-------------------------------------------------------------- @@ -130,10 +131,14 @@ bool CSpecialPowerTaunt::validate(std::string &errorCode) } if (!entity->getContextualProperty().directAccessForStructMembers().attackable()) { - PHRASE_UTILITIES::sendDynamicSystemMessage(_ActorRowId, "POWER_TAUNT_TARGET_NOT_ATTACKABLE"); + CCreature * creature = CreatureManager.getCreature( entity->getId() ); + if ( ! creature->checkFactionAttackable(actor->getId())) + { + PHRASE_UTILITIES::sendDynamicSystemMessage(_ActorRowId, "POWER_TAUNT_TARGET_NOT_ATTACKABLE"); - DEBUGLOG(" Target not attackable"); - return false; + DEBUGLOG(" Target not attackable"); + return false; + } } return true; diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character.cpp b/code/ryzom/server/src/entities_game_service/player_manager/character.cpp index 40e6e20cb..b493d041b 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/character.cpp @@ -596,6 +596,8 @@ CCharacter::CCharacter(): CEntityBase(false), _CurrentParryLevel = 1; _BaseParryLevel = 1; + _BaseResistance = 1; + _SkillUsedForDodge = SKILLS::SF; _CurrentParrySkill = BarehandCombatSkill; @@ -671,6 +673,8 @@ CCharacter::CCharacter(): CEntityBase(false), _CustomMissionsParams.clear(); + _FriendVisibility = VisibleToAll; + initDatabase(); } // CCharacter // @@ -1414,6 +1418,7 @@ uint32 CCharacter::tickUpdate() } } + bool updatePVP = false; { H_AUTO(CharacterUpdateOutpost); @@ -1425,6 +1430,7 @@ uint32 CCharacter::tickUpdate() { stopOutpostLeavingTimer(); setOutpostAlias(0); + updatePVP = true; } CSmartPtr outpost = COutpostManager::getInstance().getOutpostFromAlias( outpostAlias ); @@ -1435,10 +1441,12 @@ uint32 CCharacter::tickUpdate() { stopOutpostLeavingTimer(); setOutpostAlias(0); + updatePVP = true; } else { outpost->fillCharacterOutpostDB(this); + updatePVP = true; } } } @@ -1447,26 +1455,27 @@ uint32 CCharacter::tickUpdate() { H_AUTO(CharacterUpdatePVPMode); - if (_PVPSafeLastTimeChange + 20 < CTickEventHandler::getGameCycle()) + if (_PVPSafeLastTimeChange + 20 < CTickEventHandler::getGameCycle() || updatePVP) { - bool update = false; _PVPSafeLastTimeChange = CTickEventHandler::getGameCycle(); if (_PVPSafeLastTime != getSafeInPvPSafeZone()) { _PVPSafeLastTime = !_PVPSafeLastTime; - update = true; + updatePVP = true; } if (_PVPInSafeZoneLastTime != CPVPManager2::getInstance()->inSafeZone(getPosition())) { _PVPInSafeZoneLastTime = !_PVPInSafeZoneLastTime; - update = true; + updatePVP = true; } - if (update) { + if (updatePVP) + { CPVPManager2::getInstance()->setPVPModeInMirror(this); updatePVPClanVP(); + _HaveToUpdatePVPMode = false; } } @@ -1484,7 +1493,7 @@ uint32 CCharacter::tickUpdate() if( getPvPRecentActionFlag() == false ) { - CMirrorPropValue propPvpMode( TheDataset, TheDataset.getDataSetRow(_Id), DSPropertyPVP_MODE ); + CMirrorPropValue propPvpMode( TheDataset, TheDataset.getDataSetRow(_Id), DSPropertyEVENT_FACTION_ID ); if( propPvpMode.getValue()&PVP_MODE::PvpFactionFlagged ) { CPVPManager2::getInstance()->setPVPModeInMirror(this); @@ -1721,6 +1730,8 @@ void CCharacter::deathOccurs( void ) CPVPManager2::getInstance()->playerDies(this); + CBuildingManager::getInstance()->removeTriggerRequest(getEntityRowId()); + if( _TimeDeath < CTickEventHandler::getGameTime() ) { if (_Mode.getValue().Mode == MBEHAV::DEATH) @@ -2878,14 +2889,7 @@ void CCharacter::postLoadTreatment() { tickets[ slot ] = true; - // init pet inventory - const uint32 petMaxWeight = 0xFFFFFFFF; // no weight limit - const uint32 petMaxBulk = _PlayerPets[ i ].getAnimalMaxBulk(); - - const INVENTORIES::TInventory petInvId = (INVENTORIES::TInventory)(i + INVENTORIES::pet_animal); - CPetInventory *petInventory = dynamic_cast ((CInventoryBase*)_Inventory[petInvId]); - if (petInventory) - petInventory->initPetInventory( i, petMaxWeight, petMaxBulk ); + initPetInventory(i); } } } @@ -3000,6 +3004,13 @@ void CCharacter::postLoadTreatment() computeMiscBonus(); } + CPlayer * p = PlayerManager.getPlayer(PlayerManager.getPlayerId( getId() )); + if (!p->isTrialPlayer()) + { + CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setLevel(_PropertyDatabase, 250); + CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setCount(_PropertyDatabase, 999); + } + { H_AUTO(CItemServiceManager); CItemServiceManager::getInstance()->initPersistentServices(this); @@ -5200,15 +5211,10 @@ bool CCharacter::addCharacterAnimal( const CSheetId& PetTicket, uint32 Price, CG pet.Slot = ptr->getInventorySlot(); // init pet inventory - const uint32 petMaxWeight = 0xFFFFFFFF; // no weight limit - const uint32 petMaxBulk = _PlayerPets[ i ].getAnimalMaxBulk(); - - const INVENTORIES::TInventory petInvId = (INVENTORIES::TInventory)(i + INVENTORIES::pet_animal); - CPetInventory *petInventory = dynamic_cast ((CInventoryBase*)_Inventory[petInvId]); - if (petInventory) - petInventory->initPetInventory( i, petMaxWeight, petMaxBulk ); - else + if ( ! initPetInventory( i )) + { return false; + } return spawnCharacterAnimal( i ); } @@ -6356,7 +6362,7 @@ void CCharacter::removePetCharacterAfterDeath( uint32 index ) { TLogContext_Item_PetDespawn logContext(_Id); // pet founded - if( index < MAX_PACK_ANIMAL ) + if( index < MAX_INVENTORY_ANIMAL ) { // reset despawn timer // _PropertyDatabase.setProp( _DataIndexReminder->PACK_ANIMAL.BEAST[index].DESPAWN, 0 ); @@ -6765,12 +6771,15 @@ void CCharacter::setAnimalName( uint8 petIndex, ucstring customName ) animal.setCustomName(customName); sendPetCustomNameToClient(petIndex); - - TDataSetRow row = animal.SpawnedPets; - NLNET::CMessage msgout("CHARACTER_NAME"); - msgout.serial(row); - msgout.serial(customName); - sendMessageViaMirror("IOS", msgout); + + if ( ! customName.empty()) + { + TDataSetRow row = animal.SpawnedPets; + NLNET::CMessage msgout("CHARACTER_NAME"); + msgout.serial(row); + msgout.serial(customName); + sendMessageViaMirror("IOS", msgout); + } } //----------------------------------------------------------------------------- @@ -6932,7 +6941,10 @@ double CCharacter::addXpToSkillInternal( double XpGain, const std::string& ContS uint32 ringCatalyserLvl = 0; uint32 ringCatalyserCount = 0; - if( addXpMode != AddXpToSkillBranch ) + // Don't take away cats if free trial limit reached and there is no DP. + bool bConsumeCats = ! ( bFreeTrialLimitReached && _DeathPenalties->isNull() ); + + if( bConsumeCats && (addXpMode != AddXpToSkillBranch) ) { if( _XpCatalyserSlot != INVENTORIES::INVALID_INVENTORY_SLOT ) { @@ -6952,6 +6964,12 @@ double CCharacter::addXpToSkillInternal( double XpGain, const std::string& ContS } } } + + if (!p->isTrialPlayer()) + { + xpBonus = XpGain; + } + XpGain += xpBonus + ringXpBonus; // update death penalty @@ -8869,7 +8887,7 @@ void CCharacter::setDatabase() _IneffectiveAuras.activate(); _ConsumableOverdoseEndDates.activate(); // init the RRPs - //RingRewarsdPoints.initDb(); + //RingRewardPoints.initDb(); }// setDatabase // @@ -8931,7 +8949,8 @@ void CCharacter::startTradeItemSession( uint16 session ) nlwarning("fame %u is INVALID",(uint)bot->getRace() ); fame = MinFameToTrade; } - else if ( fame < MinFameToTrade && bot->getOrganization() != getOrganization() ) + + if ( (bot->getOrganization() == 0 && fame < MinFameToTrade) || (bot->getOrganization() != 0 && bot->getOrganization() != getOrganization()) ) { SM_STATIC_PARAMS_1(params, STRING_MANAGER::bot); params[0].setEIdAIAlias( _CurrentInterlocutor, CAIAliasTranslator::getInstance()->getAIAlias(_CurrentInterlocutor) ); @@ -8939,6 +8958,9 @@ void CCharacter::startTradeItemSession( uint16 session ) npcTellToPlayerEx( bot->getEntityRowId(),_EntityRowId,txt ); return; } + else if (bot->getOrganization() != 0 && bot->getOrganization() == getOrganization()) + fame = 0; + float fameFactor = 1.0f; if(bot->getForm()->getFaction() != CStaticFames::INVALID_FACTION_INDEX) @@ -9036,7 +9058,8 @@ void CCharacter::startTradePhrases(uint16 session) { nlwarning("fame %u is INVALID",(uint)bot->getRace() ); } - if ( fame < MinFameToTrade && bot->getOrganization() != getOrganization() ) + + if ( (bot->getOrganization() == 0 && fame < MinFameToTrade) || (bot->getOrganization() != 0 && bot->getOrganization() != getOrganization()) ) { SM_STATIC_PARAMS_1(params, STRING_MANAGER::bot); params[0].setEIdAIAlias( _CurrentInterlocutor, CAIAliasTranslator::getInstance()->getAIAlias(_CurrentInterlocutor) ); @@ -9045,7 +9068,6 @@ void CCharacter::startTradePhrases(uint16 session) return; } - // *** Set right rolemaster flags and race in Database uint8 flags = 0; if( bot->isSellingCharacteristics() ) @@ -9806,7 +9828,8 @@ void CCharacter::sellItem( INVENTORIES::TInventory inv, uint32 slot, uint32 quan nlwarning("fame %u is INVALID",(uint)bot->getRace() ); fame = MinFameToTrade; } - else if ( fame < MinFameToTrade && bot->getOrganization() != getOrganization() ) + + if ( (bot->getOrganization() == 0 && fame < MinFameToTrade) || (bot->getOrganization() != 0 && bot->getOrganization() != getOrganization()) ) { SM_STATIC_PARAMS_1(params, STRING_MANAGER::bot); params[0].setEIdAIAlias( _CurrentInterlocutor, CAIAliasTranslator::getInstance()->getAIAlias(_CurrentInterlocutor) ); @@ -9818,6 +9841,8 @@ void CCharacter::sellItem( INVENTORIES::TInventory inv, uint32 slot, uint32 quan return; } + else if (bot->getOrganization() != 0 && bot->getOrganization() == getOrganization()) + fame = 0; CInventoryPtr child = _Inventory[ inv ]; if( child->getSlotCount() > slot && child->getItem( slot ) != NULL ) @@ -9853,6 +9878,13 @@ void CCharacter::sellItem( INVENTORIES::TInventory inv, uint32 slot, uint32 quan return; } + // You cannot exchange genesis named items + if (item->getPhraseId().find("genesis_") == 0) + { + nlwarning("Character %s tries to sell '%s'", _Id.toString().c_str(), item->getPhraseId().c_str() ); + return; + } + if( ! ITEMFAMILY::isSellableByPlayer( itemForm->Family ) ) { nlwarning(" character %s try to sell an unsealable item %s, must not permited by client", _Id.toString().c_str(), sheet.toString().c_str() ); @@ -10206,7 +10238,7 @@ void CCharacter::setOrganizationStatus(uint32 status) //----------------------------------------------------------------------------- void CCharacter::changeOrganizationStatus(sint32 status) { - if (status < 0 && abs(status) > _OrganizationStatus) + if (status < 0 && abs(status) > (sint32)_OrganizationStatus) _OrganizationStatus = 0; else _OrganizationStatus += status; @@ -10216,7 +10248,7 @@ void CCharacter::changeOrganizationStatus(sint32 status) //----------------------------------------------------------------------------- void CCharacter::changeOrganizationPoints(sint32 points) { - if (points < 0 && abs(points) > _OrganizationPoints) + if (points < 0 && abs(points) > (sint32)_OrganizationPoints) _OrganizationPoints = 0; else _OrganizationPoints += points; @@ -11161,14 +11193,14 @@ bool CCharacter::validateExchange() sint32 ticketDelta = c->_ExchangeView->getPetTicketExchanged( ITEM_TYPE::MEKTOUB_PACKER_TICKET ) - _ExchangeView->getPetTicketExchanged( ITEM_TYPE::MEKTOUB_PACKER_TICKET ); if( !checkAnimalCount( packerSheet, false, ticketDelta ) ) { - sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX()"); + sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX"); c->sendDynamicSystemMessage(c->getId(), "ANIMAL_INTERLOCUTOR_HAVE_MAX"); invalidateExchange(); return false; } if( !c->checkAnimalCount( packerSheet, false, -ticketDelta ) ) { - c->sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX()"); + c->sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX"); sendDynamicSystemMessage(c->getId(), "ANIMAL_INTERLOCUTOR_HAVE_MAX"); invalidateExchange(); return false; @@ -11180,14 +11212,14 @@ bool CCharacter::validateExchange() sint32 ticketDelta = c->_ExchangeView->getPetTicketExchanged(ITEM_TYPE::MEKTOUB_MOUNT_TICKET) - _ExchangeView->getPetTicketExchanged(ITEM_TYPE::MEKTOUB_MOUNT_TICKET); if( !checkAnimalCount( mountSheet, false, ticketDelta ) ) { - sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX()"); + sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX"); c->sendDynamicSystemMessage(c->getId(), "ANIMAL_INTERLOCUTOR_HAVE_MAX"); invalidateExchange(); return false; } if( !c->checkAnimalCount( mountSheet, false, -ticketDelta ) ) { - c->sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX()"); + c->sendDynamicSystemMessage(getId(), "ANIMAL_PLAYER_HAVE_MAX"); sendDynamicSystemMessage(c->getId(), "ANIMAL_INTERLOCUTOR_HAVE_MAX"); invalidateExchange(); return false; @@ -11285,21 +11317,23 @@ void CCharacter::removeExchangeItems(vector& itemRemoved, vector< // addExchangeItems // //----------------------------------------------- -void CCharacter::addExchangeItems(CCharacter* trader,vector& itemToAdd, vector< CPetAnimal >& playerPetsAdd) +void CCharacter::addExchangeItems(CCharacter* trader,vector& itemToAdd, vector< CPetAnimal >& playerPetsAdded) { // inform AI CPetSetOwner msgAI; bool updatePetDataBase = false; - for( uint32 p = 0; p < playerPetsAdd.size(); ++p ) + for( uint32 p = 0; p < playerPetsAdded.size(); ++p ) { sint32 i = getFreePetSlot(); if( i >= 0 ) { - _PlayerPets[ i ] = playerPetsAdd[ p ]; + _PlayerPets[ i ] = playerPetsAdded[ p ]; _PlayerPets[ i ].OwnerId = _Id; + initPetInventory(i); + if( _PlayerPets[ i ].PetStatus == CPetAnimal::waiting_spawn ) { spawnCharacterAnimal( i ); @@ -13567,7 +13601,7 @@ void CCharacter::sendUrl(const string &url, const string &salt) if (!salt.empty()) { string checksum = salt+url; - control = "&hmac="+getHMacSHA1((uint8*)&url[0], (uint32)url.size(), (uint8*)&salt[0], (uint32)salt.size()).toString();; + control = "&hmac="+getHMacSHA1((uint8*)&url[0], (uint32)url.size(), (uint8*)&salt[0], (uint32)salt.size()).toString(); } nlinfo(url.c_str()); @@ -14309,16 +14343,14 @@ void CCharacter::setAuraFlagDates() const NLMISC::TGameCycle time = CTickEventHandler::getGameCycle(); uint32 flag = BRICK_FLAGS::Aura - BRICK_FLAGS::BeginPowerFlags; - if ( (_ForbidAuraUseEndDate > time) && (_ForbidAuraUseEndDate - time < 72000) ) - { - _PowerFlagTicks[flag].StartTick = _ForbidAuraUseStartDate; - _PowerFlagTicks[flag].EndTick = _ForbidAuraUseEndDate; - } - else - { - _PowerFlagTicks[flag].StartTick = 0; - _PowerFlagTicks[flag].EndTick = 0; + if ( (_ForbidAuraUseEndDate < time) || (_ForbidAuraUseEndDate - time > 72000) ) + { + _ForbidAuraUseStartDate = 0; + _ForbidAuraUseEndDate = 0; } + _PowerFlagTicks[flag].StartTick = _ForbidAuraUseStartDate; + _PowerFlagTicks[flag].EndTick = _ForbidAuraUseEndDate; + } // setAuraFlagDates // @@ -14605,28 +14637,32 @@ uint32 CCharacter::getCarriedWeight() } //-------------------------------------------------------------- -// CCharacter::getResistScore() +// CCharacter::getMagicResistance() +//-------------------------------------------------------------- +uint32 CCharacter::getMagicResistance(RESISTANCE_TYPE::TResistanceType magicResistanceType) const +{ + uint32 val = getUnclampedMagicResistance(magicResistanceType); + NLMISC::clamp( val, (uint32)0, (uint32)((_BaseResistance + MaxMagicResistanceBonus) * 100) ); + return val; +} + +//-------------------------------------------------------------- +// CCharacter::getMagicResistance() //-------------------------------------------------------------- uint32 CCharacter::getMagicResistance(EFFECT_FAMILIES::TEffectFamily effectFamily) { RESISTANCE_TYPE::TResistanceType resistanceType = EFFECT_FAMILIES::getAssociatedResistanceType(effectFamily); - if(resistanceType==RESISTANCE_TYPE::None) - return 0; - else - return _MagicResistance[resistanceType]; -} // getResistScore // + return getMagicResistance(resistanceType); +} //-------------------------------------------------------------- -// CCharacter::getResistScore() +// CCharacter::getMagicResistance() //-------------------------------------------------------------- uint32 CCharacter::getMagicResistance(DMGTYPE::EDamageType dmgType) { RESISTANCE_TYPE::TResistanceType resistanceType = DMGTYPE::getAssociatedResistanceType(dmgType); - if(resistanceType==RESISTANCE_TYPE::None) - return 0; - else - return _MagicResistance[resistanceType]; -} // getResistScore // + return getMagicResistance(resistanceType); +} //-------------------------------------------------------------- // addPlayerToFriendList @@ -14650,20 +14686,52 @@ void CCharacter::addPlayerToIgnoreList(const ucstring &name) TCharConnectionState CCharacter::isFriendCharVisualyOnline(const NLMISC::CEntityId &friendId) { TCharConnectionState ret = ccs_offline; + if (CEntityIdTranslator::getInstance()->isEntityOnline(friendId)) { if ( PlayerManager.hasBetterCSRGrade(friendId, _Id, true)) + { // better CSR grade return always 'offline' status return ccs_offline; + } ret = ccs_online; } + // Handle friend preference setting + CCharacter *friendChar = PlayerManager.getChar(friendId); + if (friendChar != NULL) + { + volatile TFriendVisibility friendMode = friendChar->getFriendVisibility(); + switch (friendMode) + { + case VisibleToGuildOnly: + { + uint32 fgid = friendChar->getGuildId(); + uint32 mgid = this->getGuildId(); + bool inSameGuild = (mgid != 0) && (fgid == mgid); + if ( ! inSameGuild) + { + return ccs_offline; + } + } + break; + case VisibleToGuildAndFriends: + if (this->isIgnoredBy(friendId)) + { + return ccs_offline; + } + break; + case VisibleToAll: // fallthrough + default: + break; // no-op + } + } + // Additional online check for ring shard : // - a contact is online only if it is in the same ring session if (ret == ccs_online && IsRingShard) { - CCharacter *friendChar = PlayerManager.getChar(friendId); if (friendChar == NULL) // not found ! set offline ret = ccs_offline; else @@ -14849,7 +14917,7 @@ void CCharacter::addPlayerToFriendList(const NLMISC::CEntityId &id) // if player not found if (id == CEntityId::Unknown) { - PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_OFFLINE"); + PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_NOTEXIST"); return; } @@ -14921,12 +14989,12 @@ void CCharacter::addPlayerToLeagueList(const NLMISC::CEntityId &id) // if player not found if (id == CEntityId::Unknown) { - PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_OFFLINE"); + PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_NOTEXIST"); return; } // check not already in list - const uint size = _LeagueList.size(); + const uint size = (uint)_LeagueList.size(); for ( uint i =0 ; i < size ; ++i) { if ( _LeagueList[i].EntityId.getShortId() == id.getShortId()) @@ -14990,14 +15058,12 @@ void CCharacter::addPlayerToLeagueList(const NLMISC::CEntityId &id) //-------------------------------------------------------------- void CCharacter::addPlayerToIgnoreList(const NLMISC::CEntityId &id) { - // if player not found - // Boris 2006-09-19 : allow adding offline player to ignore list -// if (id == CEntityId::Unknown || PlayerManager.getChar(id)==NULL) -// { -// // player not found => message -// PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_OFFLINE"); -// return; -// } + if (id == CEntityId::Unknown) + { + // player not found => message + PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "OPERATION_NOTEXIST"); + return; + } // check not already ignored const uint size = (uint)_IgnoreList.size(); @@ -15416,25 +15482,50 @@ void CCharacter::contactListRefChange(const NLMISC::CEntityId &id, TConctactList } +//-------------------------------------------------------------- +// CCharacter::isIgnoredBy() +//-------------------------------------------------------------- +bool CCharacter::isIgnoredBy(const NLMISC::CEntityId &id) +{ + const uint size = (uint)_IsIgnoredBy.size(); + for (uint i = 0; i < size; ++i) + { + if (_IsIgnoredBy[i].getShortId() == id.getShortId()) + { + return true; + } + } + return false; +} + +//-------------------------------------------------------------- +// CCharacter::isFriendOf() +//-------------------------------------------------------------- +bool CCharacter::isFriendOf(const NLMISC::CEntityId &id) +{ + const uint size = (uint)_IsFriendOf.size(); + for (uint i = 0 ; i < size ; ++i) + { + if (_IsFriendOf[i].getShortId() == id.getShortId()) + { + return true; + } + } + return false; +} //-------------------------------------------------------------- // CCharacter::referencedAsFriendBy() //-------------------------------------------------------------- void CCharacter::referencedAsFriendBy( const NLMISC::CEntityId &id) { - // check this entity isn't already in the list - const uint size = (uint)_IsFriendOf.size(); - for ( uint i =0 ; i < size ; ++i) + if (isFriendOf(id)) { - if ( _IsFriendOf[i].getShortId() == id.getShortId()) - { - return; - } + return; } // not found -> add it _IsFriendOf.push_back(id); - } //-------------------------------------------------------------- @@ -17454,6 +17545,18 @@ void CCharacter::pvpActionMade() //----------------------------------------------------------------------------- void CCharacter::setPVPFlagDatabase() { + // Fix for when negative ticks were saved + if ( (_PVPRecentActionTime > CTickEventHandler::getGameCycle()) + || (_PVPFlagLastTimeChange > CTickEventHandler::getGameCycle()) + || (_PVPFlagTimeSettedOn > CTickEventHandler::getGameCycle() + TimeForSetPVPFlag) ) + { + _PVPRecentActionTime = 0; + _PVPFlagLastTimeChange = 0; + _PVPFlagTimeSettedOn = 0; + _PVPSafeLastTimeChange = 0; + _PVPFlag = false; + } + uint32 activationTime; if( _PVPFlag == true ) activationTime = _PVPFlagLastTimeChange + TimeForSetPVPFlag; @@ -17788,6 +17891,7 @@ void CCharacter::setOutpostAlias( uint32 id ) CBankAccessor_PLR::getCHARACTER_INFO().getPVP_OUTPOST().setRIGHT_TO_BANISH(_PropertyDatabase, hasRightToBanish ); CPVPManager2::getInstance()->setPVPModeInMirror(this); + updatePVPClanVP(); } //----------------------------------------------------------------------------- @@ -18539,48 +18643,49 @@ void CCharacter::updateMagicProtectionAndResistance() _MaxAbsorption = (getSkillBaseValue(getBestSkill()) * MaxAbsorptionFactor) / 100; // magic resistance - sint32 baseResistance = (sint32)(_Skills._Skills[SKILLS::SF].MaxLvlReached * MagicResistFactorForCombatSkills) + MagicResistSkillDelta; - if( baseResistance < ((sint32)(_Skills._Skills[SKILLS::SM].MaxLvlReached * MagicResistFactorForMagicSkills) + MagicResistSkillDelta) ) - baseResistance = (sint32)(_Skills._Skills[SKILLS::SM].MaxLvlReached * MagicResistFactorForMagicSkills) + MagicResistSkillDelta; - if( baseResistance < ((sint32)(_Skills._Skills[SKILLS::SH].MaxLvlReached * MagicResistFactorForForageSkills) + MagicResistSkillDelta) ) - baseResistance = (sint32)(_Skills._Skills[SKILLS::SH].MaxLvlReached * MagicResistFactorForForageSkills) + MagicResistSkillDelta; - clamp(baseResistance, 0, 225); + _BaseResistance = (sint32)(_Skills._Skills[SKILLS::SF].MaxLvlReached * MagicResistFactorForCombatSkills) + MagicResistSkillDelta; + + sint32 magicResist = ((sint32)(_Skills._Skills[SKILLS::SM].MaxLvlReached * MagicResistFactorForMagicSkills) + MagicResistSkillDelta); + _BaseResistance = max(_BaseResistance, magicResist); + + sint32 forageResist = ((sint32)(_Skills._Skills[SKILLS::SH].MaxLvlReached * MagicResistFactorForForageSkills) + MagicResistSkillDelta); + _BaseResistance = max(_BaseResistance, forageResist); + clamp(_BaseResistance, 0, 225); + + // set up base for( uint32 i = 0; i < RESISTANCE_TYPE::NB_RESISTANCE_TYPE; ++i ) { - _MagicResistance[i]= (uint32)baseResistance * 100; + _MagicResistance[i]= (uint32)_BaseResistance * 100; + } - switch(i) - { - case RESISTANCE_TYPE::Desert: - if( _Race == EGSPD::CPeople::Fyros ) - { - _MagicResistance[i] += HominRacialResistance * 100; - } + // correct for race + switch ( _Race) + { + case EGSPD::CPeople::Fyros: + _MagicResistance[RESISTANCE_TYPE::Desert] += HominRacialResistance * 100; break; - case RESISTANCE_TYPE::Forest: - if( _Race == EGSPD::CPeople::Matis ) - { - _MagicResistance[i] += HominRacialResistance * 100; - } + + case EGSPD::CPeople::Matis: + _MagicResistance[RESISTANCE_TYPE::Forest] += HominRacialResistance * 100; break; - case RESISTANCE_TYPE::Lacustre: - if( _Race == EGSPD::CPeople::Tryker ) - { - _MagicResistance[i] += HominRacialResistance * 100; - } + + case EGSPD::CPeople::Tryker: + _MagicResistance[RESISTANCE_TYPE::Lacustre] += HominRacialResistance * 100; break; - case RESISTANCE_TYPE::Jungle: - if( _Race == EGSPD::CPeople::Zorai ) - { - _MagicResistance[i] += HominRacialResistance * 100; - } + + case EGSPD::CPeople::Zorai: + _MagicResistance[RESISTANCE_TYPE::Jungle] += HominRacialResistance * 100; break; + default: break; - } + } + + // correct for current region + for( uint32 i = 0; i < RESISTANCE_TYPE::NB_RESISTANCE_TYPE; ++i ) + { _MagicResistance[i] = (uint32)((sint32)max( (sint32)0, ((sint32)_MagicResistance[i]) + getRegionResistanceModifier((RESISTANCE_TYPE::TResistanceType)i) * (sint32)100)); - clamp( _MagicResistance[i], (uint32)0, (uint32)((baseResistance + MaxMagicResistanceBonus) * 100) ); } // protection @@ -18663,7 +18768,7 @@ void CCharacter::updateMagicProtectionAndResistance() for (uint i=0; i(_MagicResistance[i])); + CBankAccessor_PLR::getCHARACTER_INFO().getMAGIC_RESISTANCE().getArray(i).setVALUE(_PropertyDatabase, checkedCast(getUnclampedMagicResistance((RESISTANCE_TYPE::TResistanceType)i))); } // _PropertyDatabase.setProp("CHARACTER_INFO:MAGIC_RESISTANCE:Desert", _MagicResistance[RESISTANCE_TYPE::Desert]); // _PropertyDatabase.setProp("CHARACTER_INFO:MAGIC_RESISTANCE:Forest", _MagicResistance[RESISTANCE_TYPE::Forest]); @@ -20120,7 +20225,9 @@ void CCharacter::setEnterCriticalZoneProposalQueueId(uint32 queueId) uint32 CCharacter::getMagicProtection( PROTECTION_TYPE::TProtectionType magicProtectionType ) const { - uint32 val = getUnclampedMagicProtection(magicProtectionType); NLMISC::clamp( val, (uint32)0, MaxMagicProtection ); return val; + uint32 val = getUnclampedMagicProtection(magicProtectionType); + NLMISC::clamp( val, (uint32)0, MaxMagicProtection ); + return val; } @@ -20612,3 +20719,21 @@ void CCharacter::sendNpcMissionGiverTimer(bool force) CUnifiedNetwork::getInstance()->send( NLNET::TServiceId(_Id.getDynamicId()), msgout ); } } + +//------------------------------------------------------------------------------ + +bool CCharacter::initPetInventory(uint8 index) +{ + // init pet inventory + const uint32 petMaxWeight = 0xFFFFFFFF; // no weight limit + const uint32 petMaxBulk = _PlayerPets[ index ].getAnimalMaxBulk(); + + const INVENTORIES::TInventory petInvId = (INVENTORIES::TInventory)(index + INVENTORIES::pet_animal); + CPetInventory *petInventory = dynamic_cast ((CInventoryBase*)_Inventory[petInvId]); + if (petInventory) + { + petInventory->initPetInventory( index, petMaxWeight, petMaxBulk ); + return true; + } + return false; +} \ No newline at end of file diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character.h b/code/ryzom/server/src/entities_game_service/player_manager/character.h index 1322490e1..f2ba0944b 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character.h +++ b/code/ryzom/server/src/entities_game_service/player_manager/character.h @@ -395,6 +395,15 @@ struct CXpProgressInfos } }; +enum TFriendVisibility +{ + VisibleToAll = 0, // Visible to all people who have me on their friends list, even if I am ignoring them. + VisibleToGuildAndFriends, // Visible to people in my guild and those that have me on their friends list. + VisibleToGuildOnly, // Only visible to people in my guild. + NB_FRIEND_VISIBILITY + +}; + /** * CCharacter @@ -1023,14 +1032,14 @@ public: // Same but nearly empty void setDummyStartCharacteristics(); - /** - * Eval Specialization for return Characteristics value - * - * \param value is the value to parse. - * \param result is the result to fill if the value has been succesfully parsed. - * \return UnknownValue if the value is not known, ValueError is the value evaluation failed or NoError - * if it has been parsed. - */ + /** + * Eval Specialization for return Characteristics value + * + * \param value is the value to parse. + * \param result is the result to fill if the value has been succesfully parsed. + * \return UnknownValue if the value is not known, ValueError is the value evaluation failed or NoError + * if it has been parsed. + */ virtual TReturnState evalValue (const char *value, double &result, uint32 userData); /// Add a pact @@ -2259,6 +2268,9 @@ public: // return unclamped magic resistance of a character uint32 getUnclampedMagicResistance( RESISTANCE_TYPE::TResistanceType magicResistanceType ) const; + // return clamped magic resistance of a character + uint32 getMagicResistance(RESISTANCE_TYPE::TResistanceType magicResistanceType) const; + /// return NbNonNullClassificationTypesSkillMod uint8 getNbNonNullClassificationTypesSkillMod() const; @@ -2381,6 +2393,7 @@ public: uint32 getLastConnectedDate() const; uint32 getPlayedTime() const; uint32 getOrganization() const; + uint32 getOrganizationStatus() const; const std::list& getLastLogStats() const; void updateConnexionStat(); void setDisconnexionTime(); @@ -2692,6 +2705,10 @@ private: void contactListRefChange(const NLMISC::CEntityId &id, TConctactListAction actionType); + /// return true if player is ignored by the given entity + bool isIgnoredBy(const NLMISC::CEntityId &id); + /// return true if given entity has player on friend list + bool isFriendOf(const NLMISC::CEntityId &id); /// player is referenced as friend by the given entity void referencedAsFriendBy( const NLMISC::CEntityId &id); /// player is no longer referenced as friend by the given entity @@ -2767,7 +2784,7 @@ private: void removeExchangeItems(std::vector& itemRemoved, std::vector< CPetAnimal >& PlayerPetsRemoved); // add the items gained during an exchange - void addExchangeItems(CCharacter* trader,std::vector& itemToAdd, std::vector< CPetAnimal >& PlayerPetsAdd); + void addExchangeItems(CCharacter* trader,std::vector& itemToAdd, std::vector< CPetAnimal >& PlayerPetsAdded); /// get creator name dynamic string Id uint32 getCreatorNameId( const NLMISC::CEntityId &creatorId); @@ -2895,6 +2912,9 @@ private: */ double addXpToSkillInternal( double XpGain, const std::string& ContSkill, TAddXpToSkillMode addXpMode, std::map &gainBySkill ); + /// Initialize the specified pet inventory, if it is valid + bool initPetInventory(uint8 index); + /////////////////// // Public members /////////////////// @@ -2948,6 +2968,12 @@ public: void setFinalized(bool isFinalized) { _LoadingFinish = isFinalized; }; bool isFinalized() const { return _LoadingFinish; }; + void setFriendVisibility(TFriendVisibility val) { _FriendVisibility = val; } + const TFriendVisibility& getFriendVisibility() const { return _FriendVisibility; } + + void setFriendVisibilitySave(uint8 val) { if (val < NB_FRIEND_VISIBILITY) _FriendVisibility = (TFriendVisibility)val; } + uint8 getFriendVisibilitySave() const { return (uint8)_FriendVisibility; } + ////////////////// // Private members ////////////////// @@ -3407,6 +3433,8 @@ private: // current resistance for each type of magic resistance uint32 _MagicResistance[RESISTANCE_TYPE::NB_RESISTANCE_TYPE]; + sint32 _BaseResistance; + /// currently consumed item slot sint32 _ConsumedItemSlot; /// currently consumed item inventory @@ -3516,6 +3544,8 @@ private: TAIAlias _LastCreatedNpcGroup; + TFriendVisibility _FriendVisibility; + // :KLUDGE: ICDBStructNode non-const 'coz getName and getParent are not // const methods. See CCDBSynchronised::getICDBStructNodeFromName for more // info. diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character_inlines.h b/code/ryzom/server/src/entities_game_service/player_manager/character_inlines.h index 8e5b93c9a..7e2cd4248 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character_inlines.h +++ b/code/ryzom/server/src/entities_game_service/player_manager/character_inlines.h @@ -902,6 +902,12 @@ inline uint32 CCharacter::getOrganization() const } +inline uint32 CCharacter::getOrganizationStatus() const +{ + return _OrganizationStatus; +} + + //------------------------------------------------------------------------------ inline const std::list& CCharacter::getLastLogStats() const diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp b/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp index 6e37976d0..67a8ba0ce 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp @@ -822,6 +822,13 @@ void CCharacter::moveItem(INVENTORIES::TInventory srcInvId, uint32 srcSlot, INVE if ((!srcForm->DropOrSell && !canPutNonDropableItemInInventory(dstInvId)) || isAnActiveXpCatalyser(srcItem)) return; + // You cannot exchange genesis named items + if (srcItem->getPhraseId().find("genesis_") == 0 && !canPutNonDropableItemInInventory(dstInvId)) + { + nlwarning("Character %s tries to move '%s' to inv %u", _Id.toString().c_str(), srcItem->getPhraseId().c_str(), dstInvId ); + return; + } + // cannot move a pet animal ticket if (srcForm->Family == ITEMFAMILY::PET_ANIMAL_TICKET) return; @@ -3035,12 +3042,16 @@ void CCharacter::stopUseItem( bool isRingCatalyser ) } else { - PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "XP_CATALYSER_NO_MORE_ACTIVE"); - _RingXpCatalyserSlot = INVENTORIES::INVALID_INVENTORY_SLOT; -// _PropertyDatabase.setProp( "CHARACTER_INFO:RING_XP_CATALYSER:Level", 0 ); - CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setLevel(_PropertyDatabase, 0 ); -// _PropertyDatabase.setProp( "CHARACTER_INFO:RING_XP_CATALYSER:Count", 0 ); - CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setCount(_PropertyDatabase, 0 ); + CPlayer * p = PlayerManager.getPlayer(PlayerManager.getPlayerId( getId() )); + BOMB_IF(p == NULL,"Failed to find player record for character: "<isTrialPlayer()) { + PHRASE_UTILITIES::sendDynamicSystemMessage( _EntityRowId, "XP_CATALYSER_NO_MORE_ACTIVE"); + _RingXpCatalyserSlot = INVENTORIES::INVALID_INVENTORY_SLOT; + // _PropertyDatabase.setProp( "CHARACTER_INFO:RING_XP_CATALYSER:Level", 0 ); + CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setLevel(_PropertyDatabase, 0 ); + // _PropertyDatabase.setProp( "CHARACTER_INFO:RING_XP_CATALYSER:Count", 0 ); + CBankAccessor_PLR::getCHARACTER_INFO().getRING_XP_CATALYSER().setCount(_PropertyDatabase, 0 ); + } } } diff --git a/code/ryzom/server/src/entities_game_service/player_manager/persistent_player_data.cpp b/code/ryzom/server/src/entities_game_service/player_manager/persistent_player_data.cpp index 34d1a4911..703261a56 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/persistent_player_data.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/persistent_player_data.cpp @@ -570,6 +570,7 @@ static void prepareCharacterPositionForStore ( COfflineEntityState & state, cons PROP2(Invisible, bool, getInvisibility(), setInvisibility(val)) \ PROP2(Aggroable, sint8, getAggroableSave(), setAggroableSave(val)) \ PROP2(GodMode, bool, getGodModeSave(), setGodModeSave(val)) \ + PROP2(FriendVisibility, uint8, getFriendVisibilitySave(), setFriendVisibilitySave(val)) \ //#pragma message( PERSISTENT_GENERATION_MESSAGE ) diff --git a/code/ryzom/server/src/entities_game_service/player_manager/player_manager.cpp b/code/ryzom/server/src/entities_game_service/player_manager/player_manager.cpp index d0af3d808..befc0d95c 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/player_manager.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/player_manager.cpp @@ -2597,6 +2597,7 @@ NLMISC_COMMAND(setPriv,"set a privilege to a user using his user id, must be in else if (p->havePriv(AlwaysInvisiblePriv)) { c->setWhoSeesMe(uint64(0)); + c->setInvisibility(true); } } } diff --git a/code/ryzom/server/src/entities_game_service/progression/progression_pvp.cpp b/code/ryzom/server/src/entities_game_service/progression/progression_pvp.cpp index 6f4bd95f7..698148710 100644 --- a/code/ryzom/server/src/entities_game_service/progression/progression_pvp.cpp +++ b/code/ryzom/server/src/entities_game_service/progression/progression_pvp.cpp @@ -1203,7 +1203,7 @@ void CDamageScoreManager::playerDeath(CCharacter * victimChar, const CCharacter CCharacter * winnerChar = PlayerManager.getChar(players[k]); BOMB_IF(winnerChar == NULL, "invalid winner!", continue); - PVP_CLAN::TPVPClan winnerFaction; + PVP_CLAN::TPVPClan winnerFaction = PVP_CLAN::None; bool winnerGainFactionPoints = true; if (!canPlayerWinPoints(winnerChar, victimChar)) diff --git a/code/ryzom/server/src/entities_game_service/pvp_manager/pvp.cpp b/code/ryzom/server/src/entities_game_service/pvp_manager/pvp.cpp index c389c2096..aa6fd024f 100644 --- a/code/ryzom/server/src/entities_game_service/pvp_manager/pvp.cpp +++ b/code/ryzom/server/src/entities_game_service/pvp_manager/pvp.cpp @@ -231,7 +231,7 @@ void CPVPInterface::setPVPModeInMirror() const if ( !TheDataset.isAccessible(_Owner->getEntityRowId()) ) return; - CMirrorPropValue propPvpMode( TheDataset, _Owner->getEntityRowId(), DSPropertyPVP_MODE ); + CMirrorPropValue propPvpMode( TheDataset, _Owner->getEntityRowId(), DSPropertyEVENT_FACTION_ID ); if (_PVPSession) { diff --git a/code/ryzom/server/src/entities_game_service/pvp_manager/pvp_manager_2.cpp b/code/ryzom/server/src/entities_game_service/pvp_manager/pvp_manager_2.cpp index 2b54d7a75..3d09bc9fd 100644 --- a/code/ryzom/server/src/entities_game_service/pvp_manager/pvp_manager_2.cpp +++ b/code/ryzom/server/src/entities_game_service/pvp_manager/pvp_manager_2.cpp @@ -393,9 +393,10 @@ void CPVPManager2::sendChannelUsers(TChanID channel, CCharacter * user, bool out TDataSetRow senderRow = TheDataset.getDataSetRow(user->getId()); if (outputToSys) { - CCharacter::sendDynamicSystemMessage( user->getId(), "WHO_CHANNEL_INTRO" ); - //players = "Players in channel \"" + getUserDynChannel(channel) + "\": " + players; + string channelName = DynChatEGS.getChanNameFromID(channel); SM_STATIC_PARAMS_1(params, STRING_MANAGER::literal); + params[0].Literal = channelName; + CCharacter::sendDynamicSystemMessage( user->getId(), "WHO_CHANNEL_INTRO" ); params[0].Literal = players; CCharacter::sendDynamicSystemMessage( user->getId(), "LITERAL", params ); } @@ -522,14 +523,14 @@ void CPVPManager2::removeFactionChannelForCharacter(TChanID channel, CCharacter _CharacterUserChannels.insert(make_pair(user->getId(), currentChannels)); } } + } - TChannelsCharacter::iterator cit = _UserChannelCharacters.find(channel); - if (cit != _UserChannelCharacters.end()) - { - std::vector lst = _UserChannelCharacters[channel]; - lst.erase(find(lst.begin(), lst.end(), user->getId())); - _UserChannelCharacters[channel] = lst; - } + TChannelsCharacter::iterator cit = _UserChannelCharacters.find(channel); + if (cit != _UserChannelCharacters.end()) + { + std::vector lst = _UserChannelCharacters[channel]; + lst.erase(find(lst.begin(), lst.end(), user->getId())); + _UserChannelCharacters[channel] = lst; } } } @@ -642,13 +643,11 @@ void CPVPManager2::setPVPModeInMirror( const CCharacter * user ) const } } - CMirrorPropValue propPvpMode( TheDataset, user->getEntityRowId(), DSPropertyPVP_MODE ); - CMirrorPropValue propPvpMode2( TheDataset, user->getEntityRowId(), DSPropertyEVENT_FACTION_ID ); + //CMirrorPropValue propPvpMode( TheDataset, user->getEntityRowId(), DSPropertyPVP_MODE ); + CMirrorPropValue propPvpMode( TheDataset, user->getEntityRowId(), DSPropertyEVENT_FACTION_ID ); if (propPvpMode.getValue() != pvpMode) { - nlinfo("New pvp Mode : %d", pvpMode); propPvpMode = pvpMode; - propPvpMode2 = pvpMode; } } @@ -775,7 +774,6 @@ bool CPVPManager2::isCurativeActionValid( CCharacter * actor, CEntityBase * targ PVP_RELATION::TPVPRelation pvpRelation = getPVPRelation( actor, target, true ); bool actionValid; - nlinfo("Pvp relation = %d", pvpRelation); switch( pvpRelation ) { case PVP_RELATION::Ally : diff --git a/code/ryzom/server/src/general_utilities_service/gus_utils.cpp b/code/ryzom/server/src/general_utilities_service/gus_utils.cpp index a5f98115a..94b4fac5b 100644 --- a/code/ryzom/server/src/general_utilities_service/gus_utils.cpp +++ b/code/ryzom/server/src/general_utilities_service/gus_utils.cpp @@ -45,6 +45,74 @@ using namespace NLNET; namespace GUS { + //----------------------------------------------------------------------------- + // cleanPath - convert a path to standardised format + //----------------------------------------------------------------------------- + + CSString cleanPath(const CSString& path,bool addTrailingSlash) + { + CSString result; + + // split the path up into its component elements + CVectorSString pathComponents; + path.unquoteIfQuoted().splitByOneOfSeparators("/\\",pathComponents,false,false,true,false,true); + + // iterate over path components collapsing '.' and '..' entries + for (uint32 i=0;i a:/bcd/efg/ (no change) + // - a:\bcd\efg => a:/bcd/efg/ + // - \bcd\\efg => /bcd/efg/ + // - \\bcd\efg => //bcd/efg/ + // - \bcd\.\efg => /bcd/efg/ + // - \bcd\..\efg => /efg/ + // - bcd\..\efg => efg/ + // - bcd\..\..\efg => ../efg/ + // - \bcd\..\..\efg => /efg/ (NOTE: the redundant '..' entry is lost due to leading '\') + // + NLMISC::CSString cleanPath(const NLMISC::CSString& path,bool addTrailingSlash); + + // execute a command on a remote service void executeRemoteCommand(NLNET::TServiceId sid,const NLMISC::CSString& cmdLine); void executeRemoteCommand(const char* serviceName,const NLMISC::CSString& cmdLine); diff --git a/code/ryzom/server/src/general_utilities_service/rs_remote_saves.h b/code/ryzom/server/src/general_utilities_service/rs_remote_saves.h index bd4c66882..bfd784074 100644 --- a/code/ryzom/server/src/general_utilities_service/rs_remote_saves.h +++ b/code/ryzom/server/src/general_utilities_service/rs_remote_saves.h @@ -69,7 +69,7 @@ namespace SAVES { public: virtual ~CRemoteSavesManager() {} - + static CRemoteSavesManager* getInstance(); // interface used by CRemoteSavesInterface objects in their ctor to declare themselves diff --git a/code/ryzom/server/src/patchman_service/patchman_tester.h b/code/ryzom/server/src/patchman_service/patchman_tester.h index f6ad14fac..1610e0d6b 100644 --- a/code/ryzom/server/src/patchman_service/patchman_tester.h +++ b/code/ryzom/server/src/patchman_service/patchman_tester.h @@ -39,7 +39,7 @@ namespace PATCHMAN { public: virtual ~CPatchmanTester() {} - + // this is a singleton so it has a getInstance() method to get to the singleton instance static CPatchmanTester& getInstance();