diff --git a/code/ryzom/server/src/ai_service/ai.cpp b/code/ryzom/server/src/ai_service/ai.cpp index b51f1279c..ed8926f5b 100644 --- a/code/ryzom/server/src/ai_service/ai.cpp +++ b/code/ryzom/server/src/ai_service/ai.cpp @@ -423,6 +423,15 @@ void CAIS::update() _CreatureChangeHPList.Entities.clear(); _CreatureChangeHPList.DeltaHp.clear(); } + if (!_CreatureChangeMaxHPList.Entities.empty()) + { + nlassert(_CreatureChangeMaxHPList.Entities.size()==_CreatureChangeMaxHPList.MaxHp.size()); + nlassert(_CreatureChangeMaxHPList.Entities.size()==_CreatureChangeMaxHPList.SetFull.size()); + _CreatureChangeMaxHPList.send("EGS"); + _CreatureChangeMaxHPList.Entities.clear(); + _CreatureChangeMaxHPList.MaxHp.clear(); + _CreatureChangeMaxHPList.SetFull.clear(); + } } // diff --git a/code/ryzom/server/src/ai_service/ai.h b/code/ryzom/server/src/ai_service/ai.h index f06271c17..aed47f262 100644 --- a/code/ryzom/server/src/ai_service/ai.h +++ b/code/ryzom/server/src/ai_service/ai.h @@ -221,6 +221,11 @@ public: { return _CreatureChangeHPList; } + + CChangeCreatureMaxHPMsg &getCreatureChangeMaxHP() + { + return _CreatureChangeMaxHPList; + } enum TSearchType { @@ -288,6 +293,7 @@ private: // Faunas descriptions to be sent each frame CFaunaBotDescription _FaunaDescriptionList; CChangeCreatureHPMsg _CreatureChangeHPList; + CChangeCreatureMaxHPMsg _CreatureChangeMaxHPList; /// The emot identifiers std::map _EmotNames; diff --git a/code/ryzom/server/src/ai_service/ai_bot.cpp b/code/ryzom/server/src/ai_service/ai_bot.cpp index 31ce2fce0..03e2a68db 100644 --- a/code/ryzom/server/src/ai_service/ai_bot.cpp +++ b/code/ryzom/server/src/ai_service/ai_bot.cpp @@ -61,7 +61,7 @@ CAIInstance* CSpawnBot::getAIInstance() const void CSpawnBot::setVisualPropertiesName() { CBot& botRef = CSpawnBot::getPersistent(); - std::string name = botRef.getName(); + ucstring name = botRef.getName(); if (CVisualPropertiesInterface::UseIdForName) { @@ -85,7 +85,7 @@ void CSpawnBot::setVisualPropertiesName() if (! botRef.getFaunaBotUseBotName()) //false by default { if (botRef.getSheet()->ForceDisplayCreatureName()) - return; + return; // the npc name is displayed as a fauna } @@ -403,8 +403,8 @@ std::vector CBot::getMultiLineInfoString() const pushTitle(container, "CBot"); pushEntry(container, "id=" + getIndexString()); container.back() += " eid=" + getEntityIdString(); - container.back() += " alias=" + getAliasTreeOwner()->getAliasString(); - container.back() += " name=" + getName(); + container.back() += " alias=" + getAliasTreeOwner()->getAliasString() + " raw alias=" + NLMISC::toString(getAliasTreeOwner()->getAlias()); + pushEntry(container, " name=" + getName()); if (isSheetValid()) container.back() += " sheet=" + NLMISC::CFile::getFilenameWithoutExtension(getSheet()->SheetId().toString()); pushEntry(container, "fullname=" + getFullName()); diff --git a/code/ryzom/server/src/ai_service/ai_bot.h b/code/ryzom/server/src/ai_service/ai_bot.h index d74442b83..3156edb82 100644 --- a/code/ryzom/server/src/ai_service/ai_bot.h +++ b/code/ryzom/server/src/ai_service/ai_bot.h @@ -95,7 +95,7 @@ public: virtual float getAggroPropagationRadius() const; //@} - void setVisualPropertiesName(); + virtual void setVisualPropertiesName(); // as there not a lot of prop (1 or 2, maybe 3) stores in this comportment, we don't need hash. bool getProp(size_t Id, uint32& value) const; @@ -241,8 +241,8 @@ public: NLMISC::CEntityId createEntityId() const; - const std::string& getCustomName() const { return _CustomName; } - void setCustomName(const std::string &name) { _CustomName = name; } + const ucstring& getCustomName() const { return _CustomName; } + void setCustomName(const ucstring &name) { _CustomName = name; } virtual void setClientSheet(const std::string & clientSheetName); @@ -272,7 +272,7 @@ private: bool _IgnoreOffensiveActions; bool _Healer; bool _BuildingBot; - std::string _CustomName; + ucstring _CustomName; 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 f56a745db..a8175cc9a 100644 --- a/code/ryzom/server/src/ai_service/ai_bot_npc.cpp +++ b/code/ryzom/server/src/ai_service/ai_bot_npc.cpp @@ -274,9 +274,12 @@ std::vector CSpawnBotNpc::getMultiLineInfoString() const else { vector const& missions = _CurrentChatProfile.getMissions(); - pushEntry(container, "missions: " + NLMISC::toString("%u", missions[0])); - for (size_t i=1; ifindMissionName(missions[i]); + pushEntry(container, NLMISC::toString(" %u (%s)", missions[i], name.c_str())); + } } pushFooter(container); diff --git a/code/ryzom/server/src/ai_service/ai_bot_pet.cpp b/code/ryzom/server/src/ai_service/ai_bot_pet.cpp index e6177fda1..6e0747933 100644 --- a/code/ryzom/server/src/ai_service/ai_bot_pet.cpp +++ b/code/ryzom/server/src/ai_service/ai_bot_pet.cpp @@ -16,6 +16,7 @@ #include "stdpch.h" #include "ai_bot_pet.h" +#include "visual_properties_interface.h" #include "nel/misc/random.h" #include "ai_grp_pet.h" @@ -92,3 +93,28 @@ CSpawnGroupPet& CSpawnBotPet::spawnGrp() { return static_cast(CSpawnBot::spawnGrp()); } + +void CSpawnBotPet::setVisualPropertiesName() +{ + CBotPet& botRef = CSpawnBotPet::getPersistent(); + ucstring name = botRef.getName(); + + if (CVisualPropertiesInterface::UseIdForName) + { + name = NLMISC::toString("AI:%s", botRef.getIndexString().c_str()); + } + + if (name.empty() && CVisualPropertiesInterface::ForceNames) + { + name = NLMISC::CFile::getFilenameWithoutExtension(botRef.getSheet()->SheetId().toString().c_str()); + } + + if (!botRef.getCustomName().empty()) + name = botRef.getCustomName(); + + // no name the bot will appear without name on the client. + if (name.empty()) + return; + + CVisualPropertiesInterface::setName(dataSetRow(), name); +} diff --git a/code/ryzom/server/src/ai_service/ai_bot_pet.h b/code/ryzom/server/src/ai_service/ai_bot_pet.h index 34eacd039..67a448ee0 100644 --- a/code/ryzom/server/src/ai_service/ai_bot_pet.h +++ b/code/ryzom/server/src/ai_service/ai_bot_pet.h @@ -65,6 +65,8 @@ public: CPathPosition& pathPos() { return _PathPos; } uint32 _DeathTime; + + void setVisualPropertiesName(); private: diff --git a/code/ryzom/server/src/ai_service/ai_instance.cpp b/code/ryzom/server/src/ai_service/ai_instance.cpp index 5fd8e878a..240af6da3 100644 --- a/code/ryzom/server/src/ai_service/ai_instance.cpp +++ b/code/ryzom/server/src/ai_service/ai_instance.cpp @@ -653,7 +653,7 @@ static float randomAngle() return val; } -CGroupNpc* CAIInstance::eventCreateNpcGroup(uint nbBots, NLMISC::CSheetId const& sheetId, CAIVector const& pos, double dispersionRadius, bool spawnBots, double orientation, const std::string &botsName) +CGroupNpc* CAIInstance::eventCreateNpcGroup(uint nbBots, NLMISC::CSheetId const& sheetId, CAIVector const& pos, double dispersionRadius, bool spawnBots, double orientation, const std::string &botsName, const std::string &look) { if (!_EventNpcManager) return NULL; @@ -689,10 +689,13 @@ CGroupNpc* CAIInstance::eventCreateNpcGroup(uint nbBots, NLMISC::CSheetId const& CBotNpc* const bot = NLMISC::safe_cast(grp->bots()[i]); bot->setSheet(sheet); + if (!look.empty()) + bot->setClientSheet(look); bot->equipmentInit(); bot->initEnergy(/*groupEnergyCoef()*/0); CAIVector rpos(pos); - if (i!=0) + // Spawn all randomly except if only 1 bot + if (nbBots > 1) { RYAI_MAP_CRUNCH::CWorldMap const& worldMap = CWorldContainer::getWorldMap(); RYAI_MAP_CRUNCH::CWorldPosition wp; @@ -857,6 +860,7 @@ void cbEventCreateNpcGroup( NLNET::CMessage& msgin, const std::string &serviceNa double dispersionRadius; bool spawnBots; std::string botsName; + std::string look; msgin.serial(messageVersion); nlassert(messageVersion==1); msgin.serial(instanceNumber); @@ -869,10 +873,11 @@ void cbEventCreateNpcGroup( NLNET::CMessage& msgin, const std::string &serviceNa msgin.serial(dispersionRadius); msgin.serial(spawnBots); msgin.serial(botsName); + msgin.serial(look); CAIInstance* instance = CAIS::instance().getAIInstance(instanceNumber); if (instance) { - CGroupNpc* npcGroup = instance->eventCreateNpcGroup(nbBots, sheetId, CAIVector((double)x/1000., (double)y/1000.), dispersionRadius, spawnBots, (double)orientation/1000., botsName); + CGroupNpc* npcGroup = instance->eventCreateNpcGroup(nbBots, sheetId, CAIVector((double)x/1000., (double)y/1000.), dispersionRadius, spawnBots, (double)orientation/1000., botsName, look); if (npcGroup != NULL) { _PlayersLastCreatedNpcGroup[playerId] = npcGroup->getName(); diff --git a/code/ryzom/server/src/ai_service/ai_instance.h b/code/ryzom/server/src/ai_service/ai_instance.h index ce53d0559..6540620d9 100644 --- a/code/ryzom/server/src/ai_service/ai_instance.h +++ b/code/ryzom/server/src/ai_service/ai_instance.h @@ -207,7 +207,7 @@ public: return NULL; } - CGroupNpc* eventCreateNpcGroup(uint nbBots, NLMISC::CSheetId const& sheetId, CAIVector const& pos, double dispersionRadius, bool spawnBots, double orientation, const std::string &botsName); + CGroupNpc* eventCreateNpcGroup(uint nbBots, NLMISC::CSheetId const& sheetId, CAIVector const& pos, double dispersionRadius, bool spawnBots, double orientation, const std::string &botsName, const std::string &look); /// create a new easter egg CBotEasterEgg* createEasterEgg(uint32 easterEggId, NLMISC::CSheetId const& sheetId, std::string const& botName, double x, double y, double z, double heading, const std::string& look); diff --git a/code/ryzom/server/src/ai_service/ai_mgr_pet.cpp b/code/ryzom/server/src/ai_service/ai_mgr_pet.cpp index e72a88abc..31e01d143 100644 --- a/code/ryzom/server/src/ai_service/ai_mgr_pet.cpp +++ b/code/ryzom/server/src/ai_service/ai_mgr_pet.cpp @@ -290,6 +290,11 @@ void CPetSpawnMsgImp::callback(std::string const& name, NLNET::TServiceId id) } botPet->setSheet(sheet); + + if (!CustomName.empty()) + { + botPet->setCustomName(CustomName); + } if (!botPet->spawn()) { @@ -314,7 +319,7 @@ void CPetSpawnMsgImp::callback(std::string const& name, NLNET::TServiceId id) #endif return; } - + botPet->getSpawn()->setAIProfile(new CAIPetProfileStand(botPet->getSpawn())); confirmMsg.PetMirrorRow = botPet->getSpawn()->dataSetRow(); diff --git a/code/ryzom/server/src/ai_service/ai_outpost.cpp b/code/ryzom/server/src/ai_service/ai_outpost.cpp index 0ef71b2ee..ed2c62b77 100644 --- a/code/ryzom/server/src/ai_service/ai_outpost.cpp +++ b/code/ryzom/server/src/ai_service/ai_outpost.cpp @@ -873,14 +873,20 @@ void COutpost::createSquad(CGroupDesc const* groupDesc, COu // Attack only the declared ennemies of the outpost if (side==OUTPOSTENUMS::OutpostOwner) { - // grp->faction ().addProperty(NLMISC::toString("outpost:%s:defender", getAliasString().c_str())); - // grp->friendFaction().addProperty(NLMISC::toString("outpost:%s:defender", getAliasString().c_str())); + // 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) { - // grp->faction ().addProperty(NLMISC::toString("outpost:%s:attacker", getAliasString().c_str())); - // grp->friendFaction().addProperty(NLMISC::toString("outpost:%s:attacker", getAliasString().c_str())); + // 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->_AggroRange = 25; diff --git a/code/ryzom/server/src/ai_service/ai_profile_npc.cpp b/code/ryzom/server/src/ai_service/ai_profile_npc.cpp index a97beb24f..e47003cb6 100644 --- a/code/ryzom/server/src/ai_service/ai_profile_npc.cpp +++ b/code/ryzom/server/src/ai_service/ai_profile_npc.cpp @@ -1562,7 +1562,7 @@ void CGrpProfileGoToPoint::updateProfile(uint ticksSinceLastUpdate) dx+=dir.x; dy+=dir.y; - // 4 rangées. + // 4 rows CAIVector idealPos=groupPosition; if (botIndex>=_NbBotInNormalShape) { @@ -2054,7 +2054,7 @@ void CGrpProfileFollowRoute::updateProfile(uint ticksSinceLastUpdate) dx+=dir.x; dy+=dir.y; - // 4 rangées. + // 4 rows CAIVector idealPos=groupPosition; if (botIndex>=_NbBotInNormalShape) { @@ -2299,6 +2299,94 @@ void CGrpProfileStandOnVertices::updateProfile(uint ticksSinceLastUpdate) } } +////////////////////////////////////////////////////////////////////////////// +// CGrpProfileFollowPlayer // +////////////////////////////////////////////////////////////////////////////// +CGrpProfileFollowPlayer::CGrpProfileFollowPlayer(CProfileOwner* owner, TDataSetRow const& playerRow, uint32 dispersionRadius) +: CMoveProfile(owner) +, _PlayerRow(playerRow) +, _DispersionRadius(dispersionRadius) +, _PathPos(CAngle(0)) +, _PathCont(NLMISC::safe_cast(owner)->getAStarFlag()) +{ + PROFILE_LOG("group", "follow player", "ctor", ""); + _Status = CFollowPath::FOLLOWING; +} + +bool CGrpProfileFollowPlayer::destinationReach() const +{ + return _Status == CFollowPath::FOLLOW_ARRIVED + || _Status==CFollowPath::FOLLOW_NO_PATH; +} + +void CGrpProfileFollowPlayer::beginProfile() +{ + _Status = CFollowPath::FOLLOWING; +} + +// TODO: this doesn't work very well at all... +void CGrpProfileFollowPlayer::updateProfile(uint ticksSinceLastUpdate) +{ + H_AUTO(CGrpProfileFollowPlayerUpdate); + CFollowPathContext fpcGrpFollowPlayerUpdate("CGrpProfileFollowPlayerUpdate"); + + // check all bot to see if there need to move + CSpawnGroupNpc* grp = static_cast(static_cast(_Grp)); + CGroupNpc &pgrp = grp->getPersistent(); + + CBotPlayer* plrPtr = dynamic_cast(CAIS::instance().getEntityPhysical(_PlayerRow)); + + if ( ! plrPtr) { + nlwarning("CGrpProfileFollowPlayer: No valid player position to follow"); + return; + } + + _PathCont.setDestination(plrPtr->wpos()); + _PathPos._Angle = plrPtr->theta(); + + for (uint i = 0; i < pgrp.bots().size(); ++i) + { + CBotNpc* bot = static_cast(pgrp.bots()[i]); + if (!bot) + continue; + + // check current bot state + CSpawnBotNpc *sbot = bot->getSpawn(); + if (!sbot) + continue; + + // Need to wait for a correct position before moving? + CAIVector const& dest = _PathCont.getDestination(); + if (dest.x()==0 || dest.y()==0) + return; + + static const std::string runParameter("running"); + float dist; + if (sbot->getPersistent().getOwner()->getSpawnObj()->checkProfileParameter(runParameter)) + dist = sbot->runSpeed()*ticksSinceLastUpdate; + else + dist = sbot->walkSpeed()*ticksSinceLastUpdate; + + // Move + CFollowPath::TFollowStatus const status = CFollowPath::getInstance()->followPath( + sbot, + _PathPos, + _PathCont, + dist, + 0.f, + 0.5f); + + if (status==CFollowPath::FOLLOW_NO_PATH) + { + nlwarning("Problem with following player"); + } + + + } +} + + + ////////////////////////////////////////////////////////////////////////////// // CGrpProfileIdle // ////////////////////////////////////////////////////////////////////////////// @@ -3687,10 +3775,14 @@ bool CGrpProfileFaction::entityHavePartOfFactions(CAIEntityPhysical const* entit std::set::const_iterator it, end = factionsSet.end(); for (it=factionsSet.begin(); it!=end; ++it) { - std::string fameFaction = scriptFactionToFameFaction(CStringMapper::unmap(*it)); + string factionInfos = CStringMapper::unmap(*it); + string fameFaction = scriptFactionToFameFaction(factionInfos); // sint32 fame = CFameInterface::getInstance().getFameOrCivilisationFame(entity->getEntityId(), CStringMapper::map(fameFaction)); sint32 const fame = entity->getFame(fameFaction); - if (fame!=NO_FAME && fame>0) + sint32 const value = scriptFactionToFameFactionValue(factionInfos); + bool gt = scriptFactionToFameFactionGreaterThan(factionInfos); + if ((fame != NO_FAME && gt && fame > value) || + (fame != NO_FAME && !gt && fame < value)) { // nldebug("Entity has faction %s", CStringMapper::unmap(*it).c_str()); return true; @@ -3731,12 +3823,41 @@ std::string CGrpProfileFaction::scriptFactionToFameFaction(std::string name) ret += "_"; ret += name[i]-'A'+'a'; } + else if (name[i] == '>' || name[i] == '<') + { + return ret; + } else + { ret += name[i]; + } } return ret; } +bool CGrpProfileFaction::scriptFactionToFameFactionGreaterThan(string name) +{ + if (name.find("<") != string::npos) + return false; + + return true; +} + +sint32 CGrpProfileFaction::scriptFactionToFameFactionValue(string name) +{ + size_t start = name.find(">"); + if (start == string::npos) + { + start = name.find("<"); + if (start == string::npos) + return 0; + } + + sint32 value; + NLMISC::fromString(name.substr(start+1), value); + return value*6000; +} + std::string CGrpProfileFaction::fameFactionToScriptFaction(std::string name) { std::string ret = "Famous"; @@ -3772,9 +3893,9 @@ void CGrpProfileFaction::checkTargetsAround() CPropertySetWithExtraList const& thisEnnemyFactions = thisGrpNpc.ennemyFaction(); // We don't assist or attack players if our friends/ennemies are not in factions - bool const assistPlayers = thisFriendFactions.containsPartOfStrict(_FameFactions); + bool const assistPlayers = (thisFriendFactions.containsPartOfStrictFilter("Famous*") || thisFriendFactions.have(AITYPES::CPropertyId("Player"))); bool const assistBots = !thisFriendFactions.empty() && !bNoAssist; - bool const attackPlayers = (!thisEnnemyFactions.extraSetEmpty()) || thisEnnemyFactions.containsPartOfStrict(_FameFactions) || thisEnnemyFactions.containsPartOfStrictFilter("outpost:*"); + bool const attackPlayers = (!thisEnnemyFactions.extraSetEmpty()) || thisEnnemyFactions.containsPartOfStrictFilter("Famous*") || thisEnnemyFactions.have(AITYPES::CPropertyId("Player")) || thisEnnemyFactions.containsPartOfStrictFilter("outpost:*"); bool const attackBots = !thisEnnemyFactions.empty(); CAIVision Vision; diff --git a/code/ryzom/server/src/ai_service/ai_profile_npc.h b/code/ryzom/server/src/ai_service/ai_profile_npc.h index e46f1b4be..9fed6e662 100644 --- a/code/ryzom/server/src/ai_service/ai_profile_npc.h +++ b/code/ryzom/server/src/ai_service/ai_profile_npc.h @@ -628,6 +628,49 @@ private: CAITimer _Timer; }; +class CGrpProfileFollowPlayer : +public CMoveProfile +{ +public: + CGrpProfileFollowPlayer(CProfileOwner* owner, TDataSetRow const& playerRow, uint32 dispersionRadius); + virtual ~CGrpProfileFollowPlayer() {}; + + void setBotStandProfile(AITYPES::TProfiles botStandProfileType, IAIProfileFactory* botStandProfileFactory); + + /// @name IAIProfile implementation + //@{ + virtual void beginProfile(); + virtual void updateProfile(uint ticksSinceLastUpdate); + virtual void endProfile() {}; + virtual AITYPES::TProfiles getAIProfileType() const { return AITYPES::BOT_FOLLOW_POS; } + virtual std::string getOneLineInfoString() const { return std::string("follow_player group profile"); } + //@} + + void stateChangeProfile() {}; + bool destinationReach() const; + + void addBot (CBot* bot) {}; + void removeBot (CBot* bot) {}; + CPathCont* getPathCont (CBot const* bot) { return NULL; }; + + +protected: +private: + /// the profile type to apply to bot standing between two deplacement + AITYPES::TProfiles _BotStandProfileType; + /// the profile factory to apply to bot standing between two deplacement + IAIProfileFactory*_BotStandProfileFactory; + + CFollowPath::TFollowStatus _Status; + CPathPosition _PathPos; + CPathCont _PathCont; + CAIVector _LastPos; + + TDataSetRow _PlayerRow; + uint32 _DispersionRadius; +}; + + ////////////////////////////////////////////////////////////////////////////// // CGrpProfileIdle // ////////////////////////////////////////////////////////////////////////////// @@ -792,6 +835,10 @@ public: static std::string scriptFactionToFameFaction(std::string name); static std::string fameFactionToScriptFaction(std::string name); + static bool scriptFactionToFameFactionGreaterThan(std::string name); + static sint32 scriptFactionToFameFactionValue(std::string name); + + private: CAITimer _checkTargetTimer; bool bNoAssist; diff --git a/code/ryzom/server/src/ai_service/commands.cpp b/code/ryzom/server/src/ai_service/commands.cpp index 3803462cd..a85e8fe1c 100644 --- a/code/ryzom/server/src/ai_service/commands.cpp +++ b/code/ryzom/server/src/ai_service/commands.cpp @@ -259,7 +259,7 @@ NLMISC_COMMAND(eventCreateNpcGroup, "create an event npc group", " std::string botsName; if (args.size()>8) botsName = args[8]; - aiInstance->eventCreateNpcGroup(nbBots, sheetId, CAIVector(x, y), dispersionRadius, spawnBots, orientation, botsName); + aiInstance->eventCreateNpcGroup(nbBots, sheetId, CAIVector(x, y), dispersionRadius, spawnBots, orientation, botsName, ""); return true; } diff --git a/code/ryzom/server/src/ai_service/generic_logic_action.cpp b/code/ryzom/server/src/ai_service/generic_logic_action.cpp index 5bcb13fca..64c620cb6 100644 --- a/code/ryzom/server/src/ai_service/generic_logic_action.cpp +++ b/code/ryzom/server/src/ai_service/generic_logic_action.cpp @@ -3013,7 +3013,10 @@ public: } if(!_Id) - npcChatToChannelSentence(bot->dataSetRow(),CChatGroup::say,_Sentence); + { + ucstring ucstr = _Sentence; + npcChatToChannelSentence(bot->dataSetRow(),CChatGroup::say, ucstr); + } else { if(!_Arg) diff --git a/code/ryzom/server/src/ai_service/messages.cpp b/code/ryzom/server/src/ai_service/messages.cpp index 64730a1b7..092ab39f8 100644 --- a/code/ryzom/server/src/ai_service/messages.cpp +++ b/code/ryzom/server/src/ai_service/messages.cpp @@ -697,7 +697,8 @@ void CMessages::init() TRANSPORT_CLASS_REGISTER (CReportStaticAIInstanceMsg); TRANSPORT_CLASS_REGISTER (CReportAIInstanceDespawnMsg); TRANSPORT_CLASS_REGISTER (CWarnBadInstanceMsgImp); - + TRANSPORT_CLASS_REGISTER (CCreatureSetUrlMsg); + TRANSPORT_CLASS_REGISTER (CChangeCreatureMaxHPMsg) TRANSPORT_CLASS_REGISTER (CChangeCreatureHPMsg); TRANSPORT_CLASS_REGISTER (CChangeCreatureModeMsgImp); TRANSPORT_CLASS_REGISTER (CQueryEgs); @@ -770,10 +771,10 @@ void CAIAskForInfosOnEntityImp::callback (const std::string &name, NLNET::TServi } break; default: + std::vector strings = phys->getMultiLineInfoString(); + msg.Infos.insert(msg.Infos.end(), strings.begin(), strings.end()); break; } - std::vector strings = phys->getMultiLineInfoString(); - msg.Infos.insert(msg.Infos.end(), strings.begin(), strings.end()); } else { diff --git a/code/ryzom/server/src/ai_service/nf_grp.cpp b/code/ryzom/server/src/ai_service/nf_grp.cpp index 572a589cb..eabe61fd4 100644 --- a/code/ryzom/server/src/ai_service/nf_grp.cpp +++ b/code/ryzom/server/src/ai_service/nf_grp.cpp @@ -1497,6 +1497,41 @@ void setAutoSpawn_f_(CStateInstance* entity, CScriptStack& stack) // HP related methods /** @page code +@subsection setMaxHP_ff_ +Sets the Max HP level of each bot of the group. + +Arguments: f(MaxHp) f(SetFull) -> +@param[in] MaxHP is the new maximum HP for each bot +@param[in] SetFull if not 0, will set the HP to the new maximum + +@code +()setMaxHP(50000,1); +@endcode + +*/ +// CGroup +void setMaxHP_ff_(CStateInstance* entity, CScriptStack& stack) +{ + bool setFull = ((float)stack.top() != 0.f); stack.pop(); + float maxHp = ((float)stack.top()); stack.pop(); + + CChangeCreatureMaxHPMsg& msgList = CAIS::instance().getCreatureChangeMaxHP(); + + FOREACH(bot, CCont, entity->getGroup()->bots()) + { + 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)); + } +} + +/** @page code + @subsection setHPLevel_f_ Sets the current HP level of each bot of the group. @@ -1573,10 +1608,42 @@ void setHPScale_f_(CStateInstance* entity, CScriptStack& stack) } } +//---------------------------------------------------------------------------- +// Url related method +/** @page code +@subsection setUrl_ss_ +Sets the name and url of right-click action +Arguments: s(actionName),s(url) -> +@param[in] actionName of action when player mouse over +@param[in] url of action when player mouse over +@code +()setUrl("Click on Me", "http://www.domain.com/script.php"); +@endcode +*/ +// CGroup +void setUrl_ss_(CStateInstance* entity, CScriptStack& stack) +{ + std::string url = (std::string)stack.top();stack.pop(); + std::string actionName = (std::string)stack.top();stack.pop(); + + CCreatureSetUrlMsg msg; + FOREACH(botIt, CCont, entity->getGroup()->bots()) + { + CSpawnBot* pbot = botIt->getSpawnObj(); + if (pbot!=NULL) + { + msg.Entities.push_back(pbot->dataSetRow()); + } + } + + msg.ActionName = actionName; + msg.Url = url; + msg.send(egsString); +} @@ -1870,7 +1937,7 @@ Arguments: s(parameterName) -> @param[in] parameterName is a the id of the parameter to add @code -()addProfileParameter("running"); // équivalent à un parameter "running" dans la primitive du groupe +()addProfileParameter("running"); // equivalent to "running" parameter in group primitive @endcode */ @@ -1898,7 +1965,7 @@ Arguments: s(parameterName),s(parameterContent) -> @param[in] parameterContent is the value of the parameter @code -()addProfileParameter("foo", "bar"); // équivalent à un parameter "foo:bar" dans la primitive du groupe +()addProfileParameter("foo", "bar"); // equivalent to "foo:bar" parameter in group primitive @endcode */ @@ -1927,7 +1994,7 @@ Arguments: s(parameterName),f(parameterContent) -> @param[in] parameterContent is the value of the parameter @code -()addProfileParameter("foo", 0.5); // équivalent à un parameter "foo:0.5" dans la primitive du groupe +()addProfileParameter("foo", 0.5); // equivalent to "foo:0.5" parameter in group primitive @endcode */ @@ -4456,6 +4523,37 @@ void setSheet_s_(CStateInstance* entity, CScriptStack& stack) } } +//---------------------------------------------------------------------------- +/** @page code + +@subsection setClientSheet_s_ +Change the client sheet of a creature + +Arguments: -> s(sheetName) + +@code +()setClientSheet('ccdeb2'); + +@endcode + +*/ +void setClientSheet_s_(CStateInstance* entity, CScriptStack& stack) +{ + string sheetname = stack.top(); + stack.pop(); + + if (sheetname.find(".creature") == string::npos) + sheetname += ".creature"; + + FOREACH(itBot, CCont, entity->getGroup()->bots()) + { + CBot* bot = *itBot; + if (bot) + { + bot->setClientSheet(sheetname); + } + } +} /****************************************************************************/ @@ -4581,6 +4679,62 @@ void setConditionSuccess_f_(CStateInstance* entity, CScriptStack& stack) CAILogicDynamicIfHelper::setConditionSuccess(conditionState); } +inline +static float randomAngle() +{ + uint32 const maxLimit = CAngle::PI*2; + float val = (float)CAIS::rand32(maxLimit); + return val; +} + +//---------------------------------------------------------------------------- +/** @page code + +@subsection facing_f_ + +The npc will face the given direction + + +Arguments: f(direction) +@param[in] direction is the new angle of the bot in radians + +@code +()facing(3.14); +@endcode + +*/ + +// CStateInstance +void facing_f_(CStateInstance* entity, CScriptStack& stack) +{ + float const theta = (float)stack.top(); stack.pop(); + CGroup* group = entity->getGroup(); + + bool bRandomAngle = false; + if (theta > (NLMISC::Pi * 2.0) || theta < (-NLMISC::Pi * 2.0)) + bRandomAngle = true; + + if (group->isSpawned()) + { + FOREACH(itBot, CCont, group->bots()) + { + CBot* bot = *itBot; + if (bot) + { + if (bot->isSpawned()) + { + CSpawnBot *spawnBot = bot->getSpawnObj(); + + if (bRandomAngle) + spawnBot->setTheta(randomAngle()); + else + spawnBot->setTheta(theta); + + } + } + } + } +} std::map nfGetGroupNativeFunctions() { @@ -4628,6 +4782,7 @@ std::map nfGetGroupNativeFunctions() REGISTER_NATIVE_FUNC(functions, clearAggroList__); REGISTER_NATIVE_FUNC(functions, setMode_s_); REGISTER_NATIVE_FUNC(functions, setAutoSpawn_f_); + REGISTER_NATIVE_FUNC(functions, setMaxHP_ff_); REGISTER_NATIVE_FUNC(functions, setHPLevel_f_); REGISTER_NATIVE_FUNC(functions, setHPScale_f_); REGISTER_NATIVE_FUNC(functions, scaleHP_f_); @@ -4651,10 +4806,11 @@ std::map nfGetGroupNativeFunctions() REGISTER_NATIVE_FUNC(functions, getEventParam_f_f); REGISTER_NATIVE_FUNC(functions, getEventParam_f_s); REGISTER_NATIVE_FUNC(functions, setSheet_s_); + REGISTER_NATIVE_FUNC(functions, setClientSheet_s_); REGISTER_NATIVE_FUNC(functions, setHealer_f_); REGISTER_NATIVE_FUNC(functions, setConditionSuccess_f_); - - + REGISTER_NATIVE_FUNC(functions, facing_f_); + REGISTER_NATIVE_FUNC(functions, setUrl_ss_); // Boss functions (custom text) REGISTER_NATIVE_FUNC(functions, phraseBegin__); @@ -4699,10 +4855,7 @@ std::map nfGetGroupNativeFunctions() REGISTER_NATIVE_FUNC(functions, teleportPlayer_sffff_); REGISTER_NATIVE_FUNC(functions, summonPlayer_fs_); - - - #undef REGISTER_NATIVE_FUNC return functions; 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 d8ae543a5..2ea93b625 100644 --- a/code/ryzom/server/src/ai_service/nf_grp_npc.cpp +++ b/code/ryzom/server/src/ai_service/nf_grp_npc.cpp @@ -462,7 +462,7 @@ Arguments: f(Radius) -> @param[in] Radius dispersion of wander activity @code -()startWander(100); // Gives a wander activity to the group with dispersion of 100 +()startMoving(100,-100,10); // Moves the group to 100,-100 with radius of 10 @endcode */ @@ -501,6 +501,56 @@ void startMoving_fff_(CStateInstance* entity, CScriptStack& stack) return; } +//---------------------------------------------------------------------------- +/** @page code + +@subsection followPlayer_sf_ +Set activity to follow the given player + +Arguments: s(PlayerEid) f(Radius) -> +@param[in] PlayerEid id of player to follow +@param[in] Radius dispersion of wander activity + +@code +()followPlayer("(0x0002015bb4:01:88:88)",10); +@endcode + +*/ +// Spawned CGroupNpc not in a family behaviour +void followPlayer_sf_(CStateInstance* entity, CScriptStack& stack) +{ + uint32 dispersionRadius = (uint32)(float&)stack.top(); stack.pop(); + NLMISC::CEntityId playerId = NLMISC::CEntityId((std::string)stack.top()); + + IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner(); + CAIInstance* const aiInstance = dynamic_cast(managerParent); + if (!aiInstance) + return; + + if (!entity) { nlwarning("followPlayer failed!"); return; } + + CGroupNpc* group = dynamic_cast(entity->getGroup()); + if (!group) + { nlwarning("followPlayer failed: no NPC group"); + return; + } + CSpawnGroupNpc* spawnGroup = group->getSpawnObj(); + if (!spawnGroup) + { nlwarning("followPlayer failed: no spawned group"); + return; + } + + if (playerId == CEntityId::Unknown) + { + nlwarning("followPlayer failed: unknown player"); + DEBUG_STOP; + return; + } + + spawnGroup->movingProfile().setAIProfile(new CGrpProfileFollowPlayer(spawnGroup, TheDataset.getDataSetRow(playerId), dispersionRadius)); + + return; +} //---------------------------------------------------------------------------- @@ -2179,14 +2229,11 @@ void facing_cscs_(CStateInstance* entity, CScriptStack& stack) // bot1->setTheta(bot1->pos().angleTo(bot2->pos())); } - //---------------------------------------------------------------------------- /** @page code @subsection npcSay_css_ -A new entry of the npc contextual menu will propose to the targeter player to talk to the npc. - Make a npc say a text There are 3 type of text @@ -2201,9 +2248,9 @@ Arguments: c(group), s(botname), s(text), -> @code (@group)group_name.context(); -()emote(@group, "bob", "DSS_1601 RtEntryText_6") ;// Send To dss -()emote(@group, "bob", "RAW Ca farte?"); // phrase direcly send to IOS as raw (for debug) -()emote(@group, "bob", "answer_group_no_m"); //phrase id +()npcSay(@group, "bob", "DSS_1601 RtEntryText_6") ;// Send To dss +()npcSay(@group, "bob", "RAW Ca farte?"); // phrase direcly send to IOS as raw (for debug) +()npcSay(@group, "bob", "answer_group_no_m"); //phrase id @endcode @@ -2214,6 +2261,34 @@ Arguments: c(group), s(botname), s(text), -> #include "game_share/chat_group.h" #include "game_share/send_chat.h" +void execSayHelper(CSpawnBot *spawnBot, NLMISC::CSString text, CChatGroup::TGroupType mode = CChatGroup::say) +{ + if (spawnBot) + { + NLMISC::CSString prefix = text.left(4); + if (prefix=="DSS_") + { + + NLMISC::CSString phrase = text.right(text.length() - 4); + NLMISC::CSString idStr = phrase.strtok(" ",false,false,false,false); + uint32 scenarioId = atoi(idStr.c_str()); + forwardToDss(spawnBot->dataSetRow(), mode, phrase, scenarioId); + return; + } + + if (prefix=="RAW ") + { + std::string phrase = text.right(text.length()-4); + ucstring ucstr = phrase; + npcChatToChannelSentence(spawnBot->dataSetRow(), mode, ucstr); + return; + } + + //Classic phrase ID + npcChatToChannel(spawnBot->dataSetRow(), mode, text); + } +} + void npcSay_css_(CStateInstance* entity, CScriptStack& stack) { string text = (string)stack.top(); stack.pop(); @@ -2224,29 +2299,58 @@ void npcSay_css_(CStateInstance* entity, CScriptStack& stack) if (!spawnBot) { return; } + execSayHelper(spawnBot, text); +} - std::string prefix =NLMISC::CSString (text).left(4); - if(prefix=="DSS_") - { - - NLMISC::CSString phrase = NLMISC::CSString (text).right((uint)text.length()-4); - NLMISC::CSString idStr = phrase.strtok(" ",false,false,false,false); - uint32 scenarioId; - NLMISC::fromString(idStr, scenarioId); - forwardToDss(spawnBot->dataSetRow(), CChatGroup::say, phrase, scenarioId); - return; - } - - if (prefix=="RAW ") - { - NLMISC::CSString phrase = NLMISC::CSString (text).right((uint)text.length()-4); - npcChatToChannelSentence(spawnBot->dataSetRow(),CChatGroup::say, phrase); - return; - } +//---------------------------------------------------------------------------- +/** @page code - //Classic phrase ID - npcChatToChannel(spawnBot->dataSetRow(), CChatGroup::say, text); - return; +@subsection npcSay_ss_ + +Make a npc say a text + +Arguments: s(text), s(mode) -> +@param[in] text is the text to say. prefix with ID: to use an id +@param[in] mode is the mode to use (say, shout) + +@code +()npcSay("Hello!","say"); // phrase direcly send to IOS as raw +()npcSay("ID:answer_group_no_m","shout"); // phrase id +@endcode + +*/ + +void npcSay_ss_(CStateInstance* entity, CScriptStack& stack) +{ + std::string sMode = (std::string)stack.top(); stack.pop(); + std::string text = (std::string)stack.top(); stack.pop(); + + CChatGroup::TGroupType mode = CChatGroup::say; + mode = CChatGroup::stringToGroupType(sMode); + CGroup* group = entity->getGroup(); + + if (group->isSpawned()) + { + FOREACH(itBot, CCont, group->bots()) + { + CBot* bot = *itBot; + if (bot) + { + if (bot->isSpawned()) + { + CSpawnBot *spawnBot = bot->getSpawnObj(); + std::string prefix = NLMISC::CSString(text).left(3); + if (NLMISC::nlstricmp(prefix.c_str(), "id:") == 0) { + text = NLMISC::CSString(text).right(text.length()-3); + execSayHelper(spawnBot, text, mode); + } + else { + execSayHelper(spawnBot, "RAW " + text, mode); + } + } + } + } + } } @@ -2514,6 +2618,7 @@ void rename_s_(CStateInstance* entity, CScriptStack& stack) msgout.serial(row); msgout.serial(name); sendMessageViaMirror("IOS", msgout); + bot->setCustomName(name); } } } @@ -2650,6 +2755,7 @@ std::map nfGetNpcGroupNativeFunctions() REGISTER_NATIVE_FUNC(functions, startMoving_fff_); REGISTER_NATIVE_FUNC(functions, waitInZone_s_); REGISTER_NATIVE_FUNC(functions, stopMoving__); + REGISTER_NATIVE_FUNC(functions, followPlayer_sf_); REGISTER_NATIVE_FUNC(functions, wander__); REGISTER_NATIVE_FUNC(functions, setAttackable_f_); REGISTER_NATIVE_FUNC(functions, setPlayerAttackable_f_); @@ -2687,6 +2793,7 @@ std::map nfGetNpcGroupNativeFunctions() REGISTER_NATIVE_FUNC(functions, rename_s_); REGISTER_NATIVE_FUNC(functions, vpx_s_); REGISTER_NATIVE_FUNC(functions, npcSay_css_); + REGISTER_NATIVE_FUNC(functions, npcSay_ss_); REGISTER_NATIVE_FUNC(functions, dssMessage_fsss_); REGISTER_NATIVE_FUNC(functions, despawnBotByAlias_s_); REGISTER_NATIVE_FUNC(functions, giveReward_ssssc_); diff --git a/code/ryzom/server/src/ai_service/nf_static.cpp b/code/ryzom/server/src/ai_service/nf_static.cpp index fa1699b4b..4523d3e1d 100644 --- a/code/ryzom/server/src/ai_service/nf_static.cpp +++ b/code/ryzom/server/src/ai_service/nf_static.cpp @@ -1000,8 +1000,8 @@ void setSimplePhrase_ss_(CStateInstance* entity, CScriptStack& stack) phraseContent2 += "]}"; ucstring ucPhraseContent; -// ucPhraseContent.fromUtf8(phraseContent2); // utf-8 version - ucPhraseContent = phraseContent2; // iso-8859-1 version + ucPhraseContent.fromUtf8(phraseContent2); // utf-8 version + //ucPhraseContent = phraseContent2; // iso-8859-1 version NLNET::CMessage msgout("SET_PHRASE"); msgout.serial(phraseName); @@ -1009,6 +1009,33 @@ void setSimplePhrase_ss_(CStateInstance* entity, CScriptStack& stack) sendMessageViaMirror("IOS", msgout); } +void setSimplePhrase_sss_(CStateInstance* entity, CScriptStack& stack) +{ + std::string lang = (std::string)stack.top(); + stack.pop(); + std::string phraseContent = (std::string)stack.top(); + stack.pop(); + std::string phraseName = (std::string)stack.top(); + stack.pop(); + + std::string phraseContent2; + phraseContent2 += phraseName; + phraseContent2 += "(){["; + phraseContent2 += phraseContent; + phraseContent2 += "]}"; + + ucstring ucPhraseContent; + ucPhraseContent.fromUtf8(phraseContent2); // utf-8 version + //ucPhraseContent = phraseContent2; // iso-8859-1 version + + NLNET::CMessage msgout("SET_PHRASE_LANG"); + msgout.serial(phraseName); + msgout.serial(ucPhraseContent); + msgout.serial(lang); + sendMessageViaMirror("IOS", msgout); +} + + //---------------------------------------------------------------------------- /** @page code @@ -1330,6 +1357,7 @@ std::map nfGetStaticNativeFunctions() REGISTER_NATIVE_FUNC(functions, getNamedEntityProp_ss_s); REGISTER_NATIVE_FUNC(functions, destroyNamedEntity_s_); REGISTER_NATIVE_FUNC(functions, setSimplePhrase_ss_); + REGISTER_NATIVE_FUNC(functions, setSimplePhrase_sss_); REGISTER_NATIVE_FUNC(functions, dataGetVar_s_s); REGISTER_NATIVE_FUNC(functions, dataGetVar_s_f); REGISTER_NATIVE_FUNC(functions, dataSetVar_ss_); 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 70989be8d..ebe7701a7 100644 --- a/code/ryzom/server/src/ai_service/npc_description_msg.cpp +++ b/code/ryzom/server/src/ai_service/npc_description_msg.cpp @@ -788,6 +788,13 @@ bool CNpcChatProfileImp::parseChatArgs(CAIInstance *aiInstance, const std::strin return true; } + // organization entry + if (NLMISC::nlstricmp(keyword, "organization") == 0) + { + NLMISC::fromString(tail, _Organization); + return true; + } + // if no match found throw an error return false; } @@ -830,4 +837,5 @@ void TGenNpcDescMsgImp::setChat(const CNpcChatProfileImp& chatProfile) _OptionalProperties = chatProfile.getOptionalProperties(); _Outpost = chatProfile.getOutpost(); + _Organization = chatProfile.getOrganization(); } diff --git a/code/ryzom/server/src/ai_service/npc_description_msg.h b/code/ryzom/server/src/ai_service/npc_description_msg.h index e29bdfd13..14c94e9b1 100644 --- a/code/ryzom/server/src/ai_service/npc_description_msg.h +++ b/code/ryzom/server/src/ai_service/npc_description_msg.h @@ -36,7 +36,7 @@ public: CNpcChatProfileImp(const CNpcChatProfileImp &other0,const CNpcChatProfileImp &other1); // interface for setting up chat info - void clear() { clearShopInfo(); clearMissions(); clearCellZones(); clearContextOption(); _OptionalProperties.clear(); } + void clear() { clearShopInfo(); clearMissions(); clearCellZones(); clearContextOption(); clearWeb(); _OptionalProperties.clear(); } void clearShopInfo() { _ShopTypes.clear(); @@ -56,6 +56,11 @@ public: } void clearCellZones() { _CellZones.clear(); } void clearMissions() { _Missions.clear(); } + void clearWeb() + { + _WebPage.clear(); + _WebPageName.clear(); + } bool add(CAIInstance *aiInstance, const std::string &chatArgs) { return parseChatArgs(aiInstance, chatArgs); } void addMission(uint32 mission) { _Missions.push_back(mission); } void clearContextOption() { _ContextOptions.clear(); } diff --git a/code/ryzom/server/src/ai_service/script_compiler.cpp b/code/ryzom/server/src/ai_service/script_compiler.cpp index aabe5889c..03d0fe336 100644 --- a/code/ryzom/server/src/ai_service/script_compiler.cpp +++ b/code/ryzom/server/src/ai_service/script_compiler.cpp @@ -1083,25 +1083,33 @@ CSmartPtr CCompiler::compileCode (const std::vector=str.size()) + size_t index = str.find("//",0); + if (index == string::npos) + code += str; + else { + // We have a potential comment. Now check if it is quoted or not + bool inQuote = false; + uint i = 0; + for (;;) { - firstIndex=string::npos; - break; - } + if ('"' == str[i]) + inQuote = !inQuote; - if (str.at(firstIndex)=='/') - { - code+=str.substr(0, firstIndex-1); - break; + if ( !inQuote && ('/' == str[i]) ) + { + ++i; + if ('/' == str[i]) + break; + + code += '/'; + } + code += str[i]; + ++i; + if (str.size() == i) + break; } - firstIndex=str.find_first_of("/",firstIndex); } - if (firstIndex==string::npos) - code+=str; + code+="\n "; // additional .. } code+="}"; diff --git a/code/ryzom/server/src/ai_service/script_compiler_native_func.cpp b/code/ryzom/server/src/ai_service/script_compiler_native_func.cpp index 17bc605c4..dc6b36861 100644 --- a/code/ryzom/server/src/ai_service/script_compiler_native_func.cpp +++ b/code/ryzom/server/src/ai_service/script_compiler_native_func.cpp @@ -221,10 +221,12 @@ arguments. - @ref moveToZone_ss_ - @ref waitInZone_s_ - @ref stopMoving__ +- @ref followPlayer_sf_ - @ref wander__ - @ref downScaleHP_f_ - @ref upScaleHP_f_ - @ref scaleHP_f_ +- @ref setMaxHP_ff_ - @ref setHPLevel_f_ - @ref addHP_f_ - @ref aiAction_s_ diff --git a/code/ryzom/server/src/ai_service/visual_properties_interface.cpp b/code/ryzom/server/src/ai_service/visual_properties_interface.cpp index e495319f4..20d79f038 100644 --- a/code/ryzom/server/src/ai_service/visual_properties_interface.cpp +++ b/code/ryzom/server/src/ai_service/visual_properties_interface.cpp @@ -69,7 +69,7 @@ void CVisualPropertiesInterface::release() } // set different visual properties for a bot. -void CVisualPropertiesInterface::setName(const TDataSetRow& dataSetRow,std::string name) +void CVisualPropertiesInterface::setName(const TDataSetRow& dataSetRow, ucstring name) { if (!IOSHasMirrorReady) return; @@ -77,8 +77,6 @@ void CVisualPropertiesInterface::setName(const TDataSetRow& dataSetRow,std::stri NLNET::CMessage msgout("CHARACTER_NAME"); CEntityId eid=CMirrors::DataSet->getEntityId(dataSetRow); msgout.serial (const_cast(dataSetRow)); - ucstring uname; - uname.fromUtf8(name); - msgout.serial (uname); // Daniel: TODO update all name dependencies to ucstring in your service. + msgout.serial (name); sendMessageViaMirror("IOS",msgout); } diff --git a/code/ryzom/server/src/ai_service/visual_properties_interface.h b/code/ryzom/server/src/ai_service/visual_properties_interface.h index 75d5c5a6d..d814e91da 100644 --- a/code/ryzom/server/src/ai_service/visual_properties_interface.h +++ b/code/ryzom/server/src/ai_service/visual_properties_interface.h @@ -39,7 +39,7 @@ public: static void release(); // set different visual properties for an entity - static void setName(const TDataSetRow& dataSetRow,std::string name); + static void setName(const TDataSetRow& dataSetRow, ucstring name); // static void setMode(CAIEntityId id,MBEHAV::EMode mode); // static void setBehaviour(CAIEntityId id,MBEHAV::EBehaviour behaviour); diff --git a/code/ryzom/server/src/entities_game_service/admin.cpp b/code/ryzom/server/src/entities_game_service/admin.cpp index 502128805..801b6dd22 100644 --- a/code/ryzom/server/src/entities_game_service/admin.cpp +++ b/code/ryzom/server/src/entities_game_service/admin.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see . - // // User Privilege set in the mysql database must be like that ":GM:" or "" or ":GM:ADMIN:" .... // @@ -52,8 +51,6 @@ #include "game_share/shard_names.h" #include "server_share/log_command_gen.h" #include "server_share/r2_vision.h" -#include "server_share/log_item_gen.h" -#include "server_share/log_character_gen.h" #include "egs_sheets/egs_sheets.h" #include "egs_sheets/egs_static_rolemaster_phrase.h" @@ -75,6 +72,8 @@ #include "team_manager/team_manager.h" #include "world_instances.h" #include "egs_variables.h" +#include "building_manager/building_manager.h" +#include "building_manager/building_physical.h" #include "player_manager/gm_tp_pending_command.h" #include "guild_manager/guild_manager.h" #include "guild_manager/guild.h" @@ -104,6 +103,10 @@ #include "modules/shard_unifier_client.h" #include "modules/client_command_forwarder.h" #include "modules/guild_unifier.h" +#include "server_share/log_command_gen.h" +#include "server_share/log_item_gen.h" +#include "server_share/log_character_gen.h" +#include "server_share/used_continent.h" // // Externs @@ -162,6 +165,9 @@ AdminCommandsInit[] = { // player character accessible commands "teamInvite", true, + "setLeague", true, + "leagueInvite", true, + "leagueKick", true, "guildInvite", true, "roomInvite", true, "roomKick", true, @@ -174,6 +180,8 @@ AdminCommandsInit[] = "validateRespawnPoint", true, "summonPet", true, "connectUserChannel", true, + "updateTarget", true, + "resetName", true, // Web commands managment "webExecCommand", true, @@ -216,6 +224,7 @@ AdminCommandsInit[] = "allowSummonPet", true, "setPetAnimalSatiety", true, "getPetAnimalSatiety", true, + "setPetAnimalName", true, "taskPass", true, "setFamePlayer", true, "guildMOTD", true, @@ -230,7 +239,7 @@ AdminCommandsInit[] = "renamePlayerForEvent", true, "renamePlayer", true, "renameGuild", true, - "setGuildDescription", true, + "setGuildDescription", false, "setGuildIcon", false, "killMob", true, "changeVar", true, @@ -295,12 +304,15 @@ AdminCommandsInit[] = "Position", true, "Priv", true, "PriviledgePVP", true, + "FullPVP", true, "FBT", true, "RyzomDate", false, "RyzomTime", false, "addGuildXp", false, "setGuildChargePoint", false, - + "characterInventoryDump", true, + "deleteInventoryItem", true, + "setSimplePhrase", false, // PUT HERE THE VARIABLE / COMMAND THAT ARE TEMPORARY // remove when message of the day interface is ready @@ -311,6 +323,8 @@ AdminCommandsInit[] = "EntitiesNoActionFailure", false, "EntitiesNoCastBreak", false, "EntitiesNoResist", false, + "lockItem", true, + "setTeamLeader", true, // aggroable state "Aggro", true, @@ -373,6 +387,15 @@ AdminCommandsInit[] = "eventSetBotURL", true, "eventSetBotURLName", true, "eventSpawnToxic", true, + "eventNpcSay", true, + "eventSetBotFacing", true, + "eventGiveControl", true, + "eventLeaveControl", true, + + "setOrganization", true, + "setOrganizationStatus", true, + + "addGuildBuilding", true, }; static vector AdminCommands; @@ -387,6 +410,22 @@ static void loadCommandsPrivileges(const string & fileName, bool init); void cbRemoteClientCallback (uint32 rid, const std::string &cmd, const std::string &entityNames); // +// get AI instance and remove it form the group name +bool getAIInstanceFromGroupName(string& groupName, uint32& instanceNumber) +{ + if (groupName.find("@") != string::npos) + { + string continent = groupName.substr(0, groupName.find('@')); + uint32 nr = CUsedContinent::instance().getInstanceForContinent(continent); + if (nr == ~0) + { + return false; + } + instanceNumber = nr; + groupName = groupName.substr(groupName.find('@'), groupName.size()); + } + return true; +} CAdminCommand * findAdminCommand(const string & name) { @@ -432,6 +471,7 @@ void initCommandsPrivileges(const std::string & fileName) { H_AUTO(initCommandsPrivileges); + initSalt(); loadCommandsPrivileges(fileName, true); } @@ -553,43 +593,46 @@ void initPositionFlags(const std::string & fileName) PositionFlagsFileName = fileName; } -string getSalt() +struct SaltFileLoadCallback: public IBackupFileReceiveCallback { - if (Salt.empty()) + std::string FileName; + + SaltFileLoadCallback(const std::string& fileName): FileName(fileName) {} + + virtual void callback(const CFileDescription& fileDescription, NLMISC::IStream& dataStream) { - string fileNameAndPath = Bsi.getLocalPath() + "salt.txt"; - if (CFile::fileExists(fileNameAndPath)) - { - FILE* f; - string fileName; - - // open the file - f=fopen(fileNameAndPath.c_str(),"rb"); - if (f == NULL) - { - nlinfo("Failed to open file for reading: %s", fileName.c_str() ); - return false; - } - - CSString input; - // read the file content into a buffer - uint32 size=NLMISC::CFile::getFileSize(f); - input.resize(size); - uint32 readSize= (uint32)fread(&input[0],1,size,f); - fclose(f); - Salt = input; - return Salt; - } - return ""; + // if the file isn't found then just give up + DROP_IF(fileDescription.FileName.empty()," file not found: "<< FileName, return); + + dataStream.serial(Salt); + nlinfo("Salt loaded : %s", Salt.c_str()); } +}; + +void initSalt() +{ + H_AUTO(initSalt); + + string fileNameAndPath = Bsi.getLocalPath() + "salt_egs.txt"; + if (CFile::fileExists(fileNameAndPath)) + { + nlinfo("Salt loading : salt_egs.txt"); + Bsi.syncLoadFile("salt_egs.txt", new SaltFileLoadCallback("salt_egs.txt")); + } +} + +const string &getSalt() +{ + if (Salt.empty()) Salt = "abcdefghijklmnopqrstuvwxyz0123456"; + return Salt; } void saveSalt(const string salt) { Salt = salt; - CBackupMsgSaveFile msg("salt.txt", CBackupMsgSaveFile::SaveFile, Bsi ); - msg.DataMsg.serialBuffer((uint8*)Salt.c_str(), (uint)Salt.size()); + CBackupMsgSaveFile msg("salt_egs.txt", CBackupMsgSaveFile::SaveFile, Bsi ); + msg.DataMsg.serial(Salt); Bsi.sendFile(msg); } @@ -1087,11 +1130,16 @@ ENTITY_VARIABLE(Position, "Position of a player (in meter) ,[, explode (value, string(","), res); if (res.size() >= 2) { - x = atoi (res[0].c_str()) * 1000; - y = atoi (res[1].c_str()) * 1000; + fromString(res[0], x); + x *= 1000; + fromString(res[1], y); + y *= 1000; } if (res.size() >= 3) - z = atoi (res[2].c_str()) * 1000; + { + fromString(res[2], z); + z *= 1000; + } } else { @@ -2222,13 +2270,19 @@ NLMISC_COMMAND(addPetAnimal,"Add pet animal to character"," ") { CGameItemPtr item = c->createItemInInventoryFreeSlot(INVENTORIES::bag, 1, 1, ticket); if( item != 0 ) - c->addCharacterAnimal( ticket, 0, item ); - return true; - } - else - { - log.displayNL(" command, unknown pet ticket '%s'", args[1].c_str() ); + { + if ( ! c->addCharacterAnimal( ticket, 0, item )) + { + item.deleteItem(); + return false; + } + return true; + } + + log.displayNL(" command, cannot create item in bag '%s'", args[1].c_str() ); } + + log.displayNL(" command, unknown pet ticket '%s'", args[1].c_str() ); } return false; @@ -2271,7 +2325,9 @@ NLMISC_COMMAND(setPetAnimalSatiety,"Set the satiety of pet animal (petIndex in 0 if ( addressee ) { CHECK_RIGHT( addressee, c ); - CCharacter::sendDynamicSystemMessage( addressee->getId(), result ); + SM_STATIC_PARAMS_1(params, STRING_MANAGER::literal); + params[0].Literal = trim(result); + CCharacter::sendDynamicSystemMessage(addressee->getId(), "LITERAL", params); } else result += " nameForAnswer not found"; @@ -2283,7 +2339,7 @@ NLMISC_COMMAND(setPetAnimalSatiety,"Set the satiety of pet animal (petIndex in 0 return true; } -NLMISC_COMMAND(getPetAnimalSatiety,"Set the satiety of pet animal (petIndex in 0..3)"," []") +NLMISC_COMMAND(getPetAnimalSatiety,"Get the satiety of pet animal (petIndex in 0..3)"," []") { if (args.size () < 2) return false; GET_CHARACTER @@ -2307,7 +2363,9 @@ NLMISC_COMMAND(getPetAnimalSatiety,"Set the satiety of pet animal (petIndex in 0 if ( addressee ) { CHECK_RIGHT( addressee, c ); - CCharacter::sendDynamicSystemMessage( addressee->getId(), result ); + SM_STATIC_PARAMS_1(params, STRING_MANAGER::literal); + params[0].Literal = trim(result); + CCharacter::sendDynamicSystemMessage(addressee->getId(), "LITERAL", params); } else result += " nameForAnswer not found"; @@ -2318,6 +2376,22 @@ NLMISC_COMMAND(getPetAnimalSatiety,"Set the satiety of pet animal (petIndex in 0 return true; } +NLMISC_COMMAND(setPetAnimalName, "Set the name of a pet animal (petIndex in 0..3)"," ") +{ + if (args.size () < 3) return false; + GET_CHARACTER + + if ( c ) + { + uint petIndex; + fromString(args[1], petIndex); + ucstring customName = args[2]; + c->setAnimalName(petIndex, customName); + } + + return true; +} + NLMISC_COMMAND (addSkillPoints, "add skill points of given type (Fight = 0, Magic = 1,Craft = 2, Harvest = 3)", " ") { if (args.size () < 3) return false; @@ -2330,7 +2404,8 @@ NLMISC_COMMAND (addSkillPoints, "add skill points of given type (Fight = 0, Magi return false; } - uint32 nbSP = atoi (args[2].c_str()); + uint32 nbSP; + fromString(args[2], nbSP); c->addSP( nbSP, type ); @@ -3723,7 +3798,7 @@ NLMISC_COMMAND( failMission, "force mission failure", "" ) //---------------------------------------------------------------------------- NLMISC_COMMAND( progressMission, "force mission progression", "[repeat]") { - if ( args.size() != 2 || args.size() != 3 ) + if ( args.size() != 2 && args.size() != 3 ) return false; GET_CHARACTER; @@ -3964,15 +4039,15 @@ NLMISC_COMMAND (targetInfos, "give infos on the target", "") //---------------------------------------------------------------------------- NLMISC_COMMAND (infos, "give info on character (GodMode, Invisible...)", "") { - CSString str("GM STATUS: "); + CSString str("INFO: "); GET_CHARACTER if( c->invulnerableMode() ) { - str << "INVULNERABLE MODE "; + str << "INVULNERABLE_MODE "; } if( c->godMode() ) { - str << "GOD MODE "; + str << "GOD_MODE "; } else { @@ -3988,31 +4063,29 @@ NLMISC_COMMAND (infos, "give info on character (GodMode, Invisible...)", "") { if (IsRingShard) { - str << "INVISIBLE(" <getWhoSeesMe()) << ")"; + str << "INVISIBLE(" <getWhoSeesMe()) << ") "; } else { - str << "INVISIBLE"; + str << "INVISIBLE "; } } if ( IsRingShard && R2_VISION::extractVisionLevel(c->getWhoSeesMe())!=R2_VISION::VISIBLE ) { - str << "SEEINVIS(" << R2_VISION::extractVisionLevel(c->getWhoSeesMe()) << ")"; + str << "SEEINVIS(" << R2_VISION::extractVisionLevel(c->getWhoSeesMe()) << ") "; } if (c->getAggroableSave()) { - str << " AGGROABLE"; + str << "AGGROABLE "; } else { - str << " NOT_AGGROABLE"; + str << "NOT_AGGROABLE "; } - SM_STATIC_PARAMS_1(params,STRING_MANAGER::literal); - params[0].Literal = str; - CCharacter::sendDynamicSystemMessage( eid,"LITERAL", params ); + log.displayNL(str.c_str()); return true; } @@ -4156,7 +4229,7 @@ ENTITY_VARIABLE(Invisible, "Invisibility of a player") } //---------------------------------------------------------------------------- -NLMISC_COMMAND(broadcast,"[repeat= or during=