diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/destroy_item.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/destroy_item.html index 366a02977..9eaf62bfd 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/destroy_item.html +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/destroy_item.html @@ -253,6 +253,14 @@ NPC tag name. Used to write in the sys info who destroyed the items

item description. See item_guidelines for the formatting requirements.

+

 

+ +

guild (Boolean): This parameter is only for guild missions. If it is set to true the action is done for the guild (not for the players that completed the mission).

+ +

 

diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/do_mission.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/do_mission.html index 0c516a984..4a480e1b8 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/do_mission.html +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/do_mission.html @@ -160,7 +160,8 @@ mso-ansi-language:EN-US'> 

mission_names: Mission names with the specific mission -objective texts.

+objective texts. The name can be followed by a space and a number representing the number of +times this mission needs to be done (useful for guild missions to specify the number of members needed to complete the mission)

 

diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_fame.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_fame.html index 391814c2b..1921ec67b 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_fame.html +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_fame.html @@ -166,6 +166,13 @@ reduce fame, use a negative figure.

 

+

guild (Boolean): This parameter is only for guild missions. If it is set to true the action is done for the guild (not for the players that completed the mission).

+ +

 

+

Default variables:

diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_item.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_item.html index 96b454cd2..aa4ba81f3 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_item.html +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_item.html @@ -178,11 +178,20 @@ lang=EN-US style='mso-ansi-language:EN-US'>: Array containing given item description. See item_guidelines for the formatting requirements.

+

 

+ +

guild (Boolean): This parameter is only for guild missions. If it is set to true the action is done for the guild (not for the players that completed the mission).

+ +

 

+

Default variables:

diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_money.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_money.html index 88030c8d1..7de97c411 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_money.html +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/recv_money.html @@ -169,6 +169,14 @@ lang=EN-US style='mso-ansi-language:EN-US'>amount: Amount of money to add to the player’s funds. To withdraw money, use a negative figure.

+

 

+ +

guild (Boolean): This parameter is only for guild missions. If it is set to true the action is done for the guild (not for the players that completed the mission).

+ +

 

Default diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/spawn_mission.html b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/spawn_mission.html new file mode 100644 index 000000000..53b4f4cc9 --- /dev/null +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/class_doc/spawn_mission.html @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + +
+ +

spawn_mission

+ +

 

+ +

Properties:

+ +

 

+ +

name: Action name, only used by the +mission designer.

+ +

 

+ +

giver_name: The NPC that gives the mission.

+ +

 

+ +

guild (Boolean): This parameter is only for guild missions. .

+ + +

 

+ +

mission_name: The name of the mission to spawn.

+ +

 

+ + +
+ + + + diff --git a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/world_editor_classes.xml b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/world_editor_classes.xml index 1e4f9d723..5426361fa 100644 --- a/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/world_editor_classes.xml +++ b/code/ryzom/common/data_leveldesign/leveldesign/world_editor_files/world_editor_classes.xml @@ -688,8 +688,6 @@ - - @@ -709,6 +707,7 @@ + @@ -838,14 +837,6 @@ - - - - - - - - @@ -1108,8 +1099,6 @@ - - @@ -1122,10 +1111,6 @@ - - - - @@ -1135,45 +1120,28 @@ - - - - - - - - - + - - - - - - - - - @@ -1182,27 +1150,18 @@ - - - - - - - - - @@ -1212,9 +1171,6 @@ - - - @@ -1223,9 +1179,6 @@ - - - @@ -1233,9 +1186,6 @@ - - - @@ -1243,35 +1193,23 @@ - - - - - - - - - - - - @@ -1304,18 +1242,12 @@ - - - - - - diff --git a/code/ryzom/common/data_leveldesign/primitives/newbieland/guild_missions.primitive b/code/ryzom/common/data_leveldesign/primitives/newbieland/guild_missions.primitive new file mode 100644 index 000000000..568d89398 --- /dev/null +++ b/code/ryzom/common/data_leveldesign/primitives/newbieland/guild_missions.primitive @@ -0,0 +1,448 @@ + + + + + + + class + missions_editor + + + name + guild_missions + + + + audience + guild + + + auto_remove_from_journal + false + + + automatic + false + + + class + mission_tree + + + fail_if_inventory_is_full + false + + + giver_primitive + urban_newbieland.primitive + + + mission_category + Killing + + + mission_description + GUILD_MISSION_DESC + + + mission_giver + $givervar@fullname$ + + + mission_title + GUILD_MISSION_TITLE + + + mono_instance + false + + + name + GUILD_MISSION + + + need_validation + false + + + non_abandonnable + false + + + not_in_journal + false + + + not_proposed + false + + + replayable + true + + + run_only_once + false + + + + class + variables + + + name + variables + + + + class + var_npc + + + npc_function + fct_ranger_leader + + + npc_name + chiang_the_strong + + + var_name + givervar + + + + + + class + pre_requisite + + + name + pre_requisite + + + require_guild_grade + Leader + + + require_guild_membership + true + + + + + + class + alias + + + name + alias + + + + + class + step + + + name + step + + + + class + actions + + + name + pre_actions + + + + class + spawn_mission + + + giver_name + chiang_the_strong + + + guild + true + + + mission_name + SOLO_GUILD_MISSION + + + + + + class + mission_objectives + + + name + objectives + + + + class + do_mission + + + mission_names + SOLO_GUILD_MISSION 2 + + + overload_objective + MIS_DO_MISSION + + + + + class + kill + + + fauna/quantity + chdfa1 2 + + + name + kill chdfa1 2 + + + + + + class + actions + + + name + post_actions + + + + amount + 100 + + + class + recv_money + + + guild + true + + + name + recv_money 100 guild + + + + + amount + 50 + + + class + recv_money + + + + + + + + audience + solo + + + auto_remove_from_journal + false + + + automatic + false + + + class + mission_tree + + + fail_if_inventory_is_full + false + + + giver_primitive + urban_newbieland.primitive + + + mission_category + Killing + + + mission_description + SOLO_GUILD_MISSION_DESC + + + mission_giver + $givervar@fullname$ + + + mission_title + SOLO_GUILD_MISSION_TITLE + + + mono_instance + false + + + name + SOLO_GUILD_MISSION + + + need_validation + false + + + non_abandonnable + false + + + not_in_journal + false + + + not_proposed + true + + + replayable + true + + + run_only_once + false + + + + class + variables + + + name + variables + + + + class + var_npc + + + npc_function + fct_ranger_leader + + + npc_name + chiang_the_strong + + + var_name + givervar + + + + + + class + pre_requisite + + + name + pre_requisite + + + + + + class + alias + + + name + alias + + + + + class + step + + + name + step + + + + class + actions + + + name + pre_actions + + + + + class + mission_objectives + + + name + objectives + + + + class + kill + + + fauna/quantity + chdfa1 1 + + + name + kill chdfa1 1 + + + + + + class + actions + + + name + post_actions + + + + amount + 20 + + + class + recv_money + + + + + + + + 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 56a2606dd..a93bdaeb1 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 @@ -34,6 +34,8 @@ #include "outpost_manager/outpost_manager.h" #include "primitives_parser.h" #include "modules/shard_unifier_client.h" +#include "mission_manager/mission_manager.h" +#include "phrase_manager/phrase_utilities_functions.h" /// todo guild remove entity id translator #include "nel/misc/eid_translator.h" @@ -686,23 +688,193 @@ void CGuild::unregisterGuild() // //} - //---------------------------------------------------------------------------- -void CGuild::removeMission(CMissionGuild * mission, TMissionResult result) +void CGuild::removeMission( uint idx, TMissionResult result) { - /// todo guild mission + if ( idx >= _Missions.size() ) + return; + + /// if the mission was finished, the result is success + if ( _Missions[idx]->getFinished() ) + { + if ( _Missions[idx]->getMissionSuccess() ) + result = mr_success; + else + result = mr_fail; + } + + CMissionTemplate *tpl = CMissionManager::getInstance()->getTemplate(_Missions[idx]->getTemplateId()); + + updateMissionHistories( _Missions[idx]->getTemplateId(), result); + + if ( tpl && !tpl->Tags.NoList ) + { + _Missions[idx]->clearUsersJournalEntry(); + } + + CMissionManager::getInstance()->deInstanciateMission(_Missions[idx]); + delete _Missions[idx]; + _Missions.erase(_Missions.begin() + idx) ; } //---------------------------------------------------------------------------- void CGuild::addSuccessfulMission(CMissionTemplate * templ) { - /// todo guild mission + TMissionHistory &mh = _MissionHistories[templ->Alias]; + mh.Successfull = true; } //---------------------------------------------------------------------------- -bool CGuild::processMissionEvent( CMissionEvent & event, TAIAlias alias ) +void CGuild::clearSuccessfulMissions() { - /// todo guild mission + _MissionHistories.clear(); +} + +//---------------------------------------------------------------------------- +void CGuild::updateMissionHistories(TAIAlias missionAlias, uint32 result) +{ + TMissionHistory &mh = _MissionHistories[missionAlias]; + + switch(result) + { + case mr_success: + case mr_forced: + mh.Successfull = true; + // validate last try date + _MissionHistories[missionAlias].LastSuccessDate = CTickEventHandler::getGameCycle(); + break; + } +} + +//---------------------------------------------------------------------------- +void CGuild::sendDynamicMessageToMembers(const string &msgName, const TVectorParamCheck ¶ms, const set &excluded) const +{ + for ( std::map::const_iterator it = getMembersBegin(); + it != getMembersEnd();++it ) + { + CCharacter * user = PlayerManager.getChar( it->first ); + + if ( excluded.find(it->first) == excluded.end()) + { + const uint32 stringId = STRING_MANAGER::sendStringToClient(TheDataset.getDataSetRow(it->first), msgName, params ); + PHRASE_UTILITIES::sendDynamicSystemMessage(TheDataset.getDataSetRow(it->first), stringId); + } + } +} + +//---------------------------------------------------------------------------- +bool CGuild::processMissionEvent( CMissionEvent & event, TAIAlias alias) +{ + std::list listEvents; + listEvents.push_back(&event); + return processGuildMissionEvent(listEvents, alias); +} + +//---------------------------------------------------------------------------- +bool CGuild::processGuildMissionEvent(std::list< CMissionEvent *> & eventList, TAIAlias missionAlias) +{ + for (uint i = 0; i < _Missions.size(); i++ ) + { + nlassert( _Missions[i] ); + if ( missionAlias == CAIAliasTranslator::Invalid || _Missions[i]->getTemplateId() == missionAlias ) + { + if ( processGuildMissionStepEvent( eventList, _Missions[i]->getTemplateId() ,0xFFFFFFFF) ) + return true; + } + } + return false; +} + +//---------------------------------------------------------------------------- +bool CGuild::processGuildMissionStepEvent(std::list< CMissionEvent*> & eventList, TAIAlias missionAlias, uint32 stepIndex) +{ + CMissionGuild * mission = getMissionByAlias( missionAlias ); + if (!mission ) + { + nlwarning("invalid missionAlias"); + return false; + } + // I don't know if i should pass _EId to this function + CMissionEvent::TResult result = mission->processEvent(TheDataset.getDataSetRow(getHighestGradeOnlineUser()) /*TheDataset.getDataSetRow( _EId)*/ ,eventList,stepIndex ); + if ( result == CMissionEvent::Nothing ) + return false; + else if ( result == CMissionEvent::MissionFailed ) + return true; + + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( mission->getTemplateId() ); + nlassert( templ ); + if ( result == CMissionEvent::MissionEnds ) + { + CMissionEventMissionDone * event = new CMissionEventMissionDone(templ->Alias); + eventList.push_back(event); + + addSuccessfulMission(templ); + + for ( std::map::iterator it = getMembersBegin(); + it != getMembersEnd();++it ) + { + CCharacter * user = PlayerManager.getChar( it->first ); + if ( user ) + { + if ( templ->Tags.NoList == false ) + CCharacter::sendDynamicSystemMessage( user->getEntityRowId(),"EGS_MISSION_SUCCESS"); + } + } + + CMissionManager::getInstance()->missionDoneOnce(templ); + mission->stopChildren(); + + // only remove no list missions, other must be manually removed by user + if ( templ->Tags.NoList || mission->isChained() || templ->Tags.AutoRemove ) + { + mission->updateEncyclopedia(); + removeMission(mission, mr_success); + } + else + { + mission->setSuccessFlag(); + mission->updateUsersJournalEntry(); + } + return true; + } + else if ( result == CMissionEvent::StepEnds ) + { + if ( templ->Tags.NoList == false ) + { + for ( std::map::iterator it = getMembersBegin(); + it != getMembersEnd();++it ) + { + CCharacter * user = PlayerManager.getChar( it->first ); + if ( user ) + { + if ( templ->Tags.NoList == false ) + CCharacter::sendDynamicSystemMessage( user->getEntityRowId(),"EGS_MISSION_STEP_SUCCESS"); + } + } + } + } + mission->updateUsersJournalEntry(); + return true; +} + +//---------------------------------------------------------------------------- +CMissionGuild* CGuild::getMissionByAlias( TAIAlias missionAlias ) +{ + const uint size = (uint)_Missions.size(); + for ( uint i = 0; i < size; i++ ) + { + if ( _Missions[i] && _Missions[i]->getTemplateId() == missionAlias ) + return _Missions[i]; + } + return NULL; +} + +//---------------------------------------------------------------------------- +bool CGuild::isMissionSuccessfull(TAIAlias alias) +{ + std::map::iterator it(_MissionHistories.find(alias)); + if (it != _MissionHistories.end()) + return it->second.Successfull; return false; } @@ -732,10 +904,12 @@ bool CGuild::canAccessToGuildInventory( CCharacter * user ) } //---------------------------------------------------------------------------- -void CGuild::putItem( CGameItemPtr item ) +bool CGuild::putItem( CGameItemPtr item ) { - if (_Inventory->insertItem(item, INVENTORIES::INSERT_IN_FIRST_FREE_SLOT, true) != CInventoryBase::ior_ok) + CInventoryBase::TInventoryOpResult res = _Inventory->insertItem(item, INVENTORIES::INSERT_IN_FIRST_FREE_SLOT, true); + if (res != CInventoryBase::ior_ok) item.deleteItem(); + return res == CInventoryBase::ior_ok; } //---------------------------------------------------------------------------- @@ -856,6 +1030,88 @@ void CGuild::takeItem( CCharacter * user, uint32 slot, uint32 quantity, uint16 s } } +//---------------------------------------------------------------------------- +uint CGuild::selectItems(NLMISC::CSheetId itemSheetId, uint32 quality, std::vector *itemList) +{ + // For all items + uint quantitySelected= 0; + for (uint32 i = 0; i < _Inventory->getSlotCount(); i++) + { + CGameItemPtr item = _Inventory->getItem(i); + if (item == NULL) + continue; + + // if match, append to the list + if (item->getSheetId()==itemSheetId && item->quality()>=quality) + { + quantitySelected+= item->getStackSize(); + if(itemList) + { + CItemSlotId entry; + entry.Slot= i; + entry.Quality= item->quality(); + itemList->push_back(entry); + } + } + } + + return quantitySelected; +} + +//---------------------------------------------------------------------------- +uint CGuild::destroyItems(const std::vector &itemSlotIns, uint32 maxQuantity) +{ + // none to destroy actually? + if(maxQuantity==0 || itemSlotIns.empty()) + return 0; + + // If has to destroy only some of them, must sort to take first the ones of lowest quality + const std::vector *itemSlots= NULL; + std::vector itemSlotSorted; + if(maxQuantity!=uint32(-1)) + { + itemSlotSorted= itemSlotIns; + std::sort(itemSlotSorted.begin(), itemSlotSorted.end()); + itemSlots= &itemSlotSorted; + } + else + { + // just point to the original one + itemSlots= &itemSlotIns; + } + + // destroy items up to the maxquantity wanted + uint index= 0; + uint totalDestroyed= 0; + while(maxQuantity>0 && indexgetStackSize()); + + CGameItemPtr item = _Inventory->removeItem(itemSlot.Slot, quantityToDestroy); + item.deleteItem(); + + // decrease if not infinity + if(maxQuantity!=-1) + maxQuantity-= quantityToDestroy; + + // increase count + totalDestroyed+= quantityToDestroy; + } + + // next slot to destroy + index++; + } + + return totalDestroyed; +} + //---------------------------------------------------------------------------- void CGuild::takeMoney( CCharacter * user, uint64 money, uint16 session ) { diff --git a/code/ryzom/server/src/entities_game_service/guild_manager/guild.h b/code/ryzom/server/src/entities_game_service/guild_manager/guild.h index e740540ca..671f7c17b 100644 --- a/code/ryzom/server/src/entities_game_service/guild_manager/guild.h +++ b/code/ryzom/server/src/entities_game_service/guild_manager/guild.h @@ -27,10 +27,15 @@ #include "outpost_manager/outpost_guild_db_updater.h" #include "guild_interface.h" #include "database_guild.h" +#include "mission_manager/mission_guild.h" class CMissionGuild; class CGuildMember; +/* Storage class for mission history data. +*/ +struct TMissionHistory; + /** * A guild in ryzom @@ -176,9 +181,36 @@ public: ///\name Mission management //@{ - void removeMission(CMissionGuild * mission, TMissionResult result); + void removeMission(CMissionGuild * mission, TMissionResult result) + { + for (uint i = 0; i < _Missions.size(); i++) + { + if ( _Missions[i] == mission ) + { + removeMission(i, result); + } + } + } + void removeMission( uint idx, TMissionResult result); void addSuccessfulMission(CMissionTemplate * templ); + void clearSuccessfulMissions(); + void updateMissionHistories(TAIAlias missionAlias, uint32 result); bool processMissionEvent( CMissionEvent & event, TAIAlias alias = CAIAliasTranslator::Invalid); + bool processGuildMissionEvent(std::list< CMissionEvent * > & eventList, TAIAlias missionAlias ); + bool processGuildMissionStepEvent(std::list< CMissionEvent* > & eventList, TAIAlias missionAlias, uint32 stepIndex); + CMissionGuild* getMissionByAlias( TAIAlias missionAlias ); + bool isMissionSuccessfull(TAIAlias alias); + void sendDynamicMessageToMembers(const std::string &msgName, const TVectorParamCheck ¶ms, const std::set &excluded) const; + ///\return the mission + inline std::vector & getMissions() + { + return _Missions; + } + void addMission(CMissionGuild* guildMission) + { + _Missions.push_back(guildMission); + guildMission->updateUsersJournalEntry(); + } //@} /// inventory management @@ -203,7 +235,23 @@ public: return _Inventory->getItem(slot); } /// add an item in the guild inventory (item can be deleted if not inserted : do not use it anymore in any case!) - void putItem( CGameItemPtr item ); + bool putItem( CGameItemPtr item ); + + class CItemSlotId + { + public: + uint32 Slot; + uint32 Quality; + bool operator<(const CItemSlotId &o) const + { + return Quality *itemList= NULL); + /// destroy a list of items (up to maxQuantity to destroy) + uint destroyItems(const std::vector &itemSlots, uint32 maxQuantity=-1); /// return the inventory (const) const NLMISC::CSmartPtr& getInventory() const { return _Inventory; } @@ -351,6 +399,11 @@ private: /// list of outposts challenged by guild std::vector _ChallengedOutposts; + ///the missions took by the guild + std::vector _Missions; + /// Successful missions + std::map _MissionHistories; + NLMISC_COMMAND_FRIEND( guildDB ); }; #endif // RY_GUILD_H diff --git a/code/ryzom/server/src/entities_game_service/guild_manager/guild_member_module.h b/code/ryzom/server/src/entities_game_service/guild_manager/guild_member_module.h index 4447e356f..46dee0f96 100644 --- a/code/ryzom/server/src/entities_game_service/guild_manager/guild_member_module.h +++ b/code/ryzom/server/src/entities_game_service/guild_manager/guild_member_module.h @@ -99,6 +99,12 @@ public: /// user wanna pick a mission CMissionGuild * pickMission( TAIAlias alias ); + // Function to check if the member can pick a mission. By default only Officer and above can pick a guild mission + virtual bool canPickMission(TAIAlias alias) + { + return false; + } + /// set the version of last sent info of items in guild inventory void setLastSentInfoVersion(uint32 slot, uint8 infoVersion) { diff --git a/code/ryzom/server/src/entities_game_service/guild_manager/guild_officer_module.h b/code/ryzom/server/src/entities_game_service/guild_manager/guild_officer_module.h index 7d6f49096..e31885300 100644 --- a/code/ryzom/server/src/entities_game_service/guild_manager/guild_officer_module.h +++ b/code/ryzom/server/src/entities_game_service/guild_manager/guild_officer_module.h @@ -34,6 +34,14 @@ public: :CGuildMemberModule(proxy,guildMember){} virtual bool canAffectGrade(EGSPD::CGuildGrade::TGuildGrade grade)const; virtual bool canInvite()const; + + // Function to check if the member can pick a mission. + // By default only Officers and above can pick a guild mission. + // So we don't need to implement this function for the other grades + virtual bool canPickMission(TAIAlias alias) + { + return true; + } }; ; diff --git a/code/ryzom/server/src/entities_game_service/mission_client_callbacks.cpp b/code/ryzom/server/src/entities_game_service/mission_client_callbacks.cpp index f0205ed95..52fd214f9 100644 --- a/code/ryzom/server/src/entities_game_service/mission_client_callbacks.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_client_callbacks.cpp @@ -26,6 +26,9 @@ #include "team_manager/team_manager.h" #include "mission_manager/mission_team.h" #include "mission_manager/mission_log.h" +#include "guild_manager/guild_manager.h" +#include "guild_manager/guild.h" +#include "guild_manager/guild_member.h" using namespace std; @@ -222,50 +225,108 @@ void cbClientGroupAbandonMission( NLNET::CMessage& msgin, const std::string &ser CCharacter * user = PlayerManager.getChar( userId ); user->setAfkState(false); - CTeam * team = TeamManager.getRealTeam( user->getTeamId() ); - if ( !team ) - { - MISLOG("user:%s cbClientGroupAbandonMission : Invalid team", userId.toString().c_str()); - return; - } - if ( team->getLeader() != userId ) - { - CCharacter::sendDynamicSystemMessage( user->getEntityRowId(), "REQ_LEADER_TO_ABANDON_MISSION" ); - return; - } - if ( index >= team->getMissions().size() ) + // We check if it's a guild or team mission + if (index < MaxGroupMissionCount) { - MISLOG("user:%s cbClientGroupAbandonMission : Invalid group mission %u ( count %u )", - userId.toString().c_str(), index, team->getMissions().size()); - return; - } - + // Team - CMissionTeam* mission = team->getMissions()[index]; - nlassert(mission); - - if ( mission->getFinished() == false ) - { - CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( mission->getTemplateId() ); - if ( !templ ) + CTeam * team = TeamManager.getRealTeam( user->getTeamId() ); + if ( !team ) { - MISLOG("user:%s cbClientGroupAbandonMission : invalid group mission alias %u", - userId.toString().c_str(), mission->getTemplateId()); + MISLOG("user:%s cbClientGroupAbandonMission : Invalid team", userId.toString().c_str()); return; } - if ( templ->Tags.NonAbandonnable ) + if ( team->getLeader() != userId ) { - MISLOG("user:%s cbClientGroupAbandonMission : group mission alias %u is not abandonnable but user tries to abandon it", - userId.toString().c_str(), mission->getTemplateId()); + CCharacter::sendDynamicSystemMessage( user->getEntityRowId(), "REQ_LEADER_TO_ABANDON_MISSION" ); + return; + } + + if ( index >= team->getMissions().size() ) + { + MISLOG("user:%s cbClientGroupAbandonMission : Invalid group mission %u ( count %u )", + userId.toString().c_str(), index, team->getMissions().size()); return; } - set excluded; - excluded.insert( userId ); - team->sendDynamicMessageToMembers( "ABANDON_GROUP_MISSION",TVectorParamCheck(), excluded ); + + CMissionTeam* mission = team->getMissions()[index]; + nlassert(mission); + + if ( mission->getFinished() == false ) + { + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( mission->getTemplateId() ); + if ( !templ ) + { + MISLOG("user:%s cbClientGroupAbandonMission : invalid group mission alias %u", + userId.toString().c_str(), mission->getTemplateId()); + return; + } + if ( templ->Tags.NonAbandonnable ) + { + MISLOG("user:%s cbClientGroupAbandonMission : group mission alias %u is not abandonnable but user tries to abandon it", + userId.toString().c_str(), mission->getTemplateId()); + return; + } + set excluded; + excluded.insert( userId ); + + team->sendDynamicMessageToMembers( "ABANDON_GROUP_MISSION",TVectorParamCheck(), excluded ); + } + team->removeMission( index, mr_abandon ); + } + else + { + // Guild + // We set the correct index + index = MaxGroupMissionCount - index; + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); + if ( !guild ) + { + MISLOG("user:%s cbClientGroupAbandonMission : Invalid team", userId.toString().c_str()); + return; + } + if ( guild->getLeader()->getIngameEId() != userId ) + { + CCharacter::sendDynamicSystemMessage( user->getEntityRowId(), "REQ_LEADER_TO_ABANDON_MISSION" ); + return; + } + + if ( index >= guild->getMissions().size() ) + { + MISLOG("user:%s cbClientGroupAbandonMission : Invalid group mission %u ( count %u )", + userId.toString().c_str(), index, guild->getMissions().size()); + return; + } + + + CMissionGuild* mission = guild->getMissions()[index]; + nlassert(mission); + + if ( mission->getFinished() == false ) + { + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( mission->getTemplateId() ); + if ( !templ ) + { + MISLOG("user:%s cbClientGroupAbandonMission : invalid group mission alias %u", + userId.toString().c_str(), mission->getTemplateId()); + return; + } + if ( templ->Tags.NonAbandonnable ) + { + MISLOG("user:%s cbClientGroupAbandonMission : group mission alias %u is not abandonnable but user tries to abandon it", + userId.toString().c_str(), mission->getTemplateId()); + return; + } + set excluded; + excluded.insert( userId ); + + guild->sendDynamicMessageToMembers( "ABANDON_GROUP_MISSION",TVectorParamCheck(), excluded ); + } + guild->removeMission( index, mr_abandon ); } - team->removeMission( index, mr_abandon ); } //---------------------------------------------------------------------------- diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_action.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_action.cpp index eb627551d..31cf1ff0f 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_action.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_action.cpp @@ -511,9 +511,9 @@ class CMissionActionRecvItem : public IMissionAction { _SourceLine = line; bool ret = true; - if ( script.size() != 2 && script.size() != 3 ) + if ( script.size() != 2 && script.size() != 3 && script.size() != 4) { - MISLOGSYNTAXERROR(" [] [][:npc_name][:group]"); + MISLOGSYNTAXERROR(" [] [][:npc_name][:group][:guild]"); return false; } vector args; @@ -569,6 +569,17 @@ class CMissionActionRecvItem : public IMissionAction _Group = true; } + // We check for the guild option + _Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + _Guild = true; + break; + } + } + if ( _Quantity == 0 ) { @@ -606,7 +617,7 @@ class CMissionActionRecvItem : public IMissionAction } } } - else if ( !_Group ) + else if ( !_Group && !_Guild) { CCharacter * user = PlayerManager.getChar( entities[0] ); CTeam * team = TeamManager.getRealTeam(user->getTeamId()); @@ -617,141 +628,245 @@ class CMissionActionRecvItem : public IMissionAction } } - - // check free room space in inventory - // NB : in case of group, fail happens only if none in the group have enough free space - sint16 neededSlotCount = 0; - uint32 neededBulk = 0; - CSheetId sheet = ( _SheetId != CSheetId::Unknown )?_SheetId:_Item.getSheetId(); - CGameItemPtr itemTmp = GameItemManager.createItem(sheet, _Quality, true, true); - if (itemTmp != NULL) + // If the case we want to give the item to the guild + if (_Guild) { - neededSlotCount = (sint16) ceil( (float)_Quantity / itemTmp->getMaxStackSize() ); - neededBulk = _Quantity * itemTmp->getStackBulk(); - itemTmp.deleteItem(); + if (entities.size() == 0) + return; + + CCharacter * user = PlayerManager.getChar( entities[0] ); + if (!user) + { + LOGMISSIONACTION("recv_fame : Invalid user"); + return; + } + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId(user->getGuildId()); + if (!guild) + { + LOGMISSIONACTION("recv_fame : Invalid guild id '" + NLMISC::toString(user->getGuildId()) + "'"); + return; + } + + SM_STATIC_PARAMS_3(params, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); + if ( _SheetId != CSheetId::Unknown ) + { + const CStaticItem * form = CSheets::getForm( _SheetId ); + if ( !form ) + { + LOGMISSIONACTION("sheetId '" + _SheetId.toString() + "' is unknown"); + return; + } + if (form->Family != ITEMFAMILY::MISSION_ITEM) + return; + + uint quantity = _Quantity; + while (quantity > 0) + { + CGameItemPtr item = user->createItem(_Quality, quantity, _SheetId); + if (item == NULL) + break; + const uint32 stackSize = item->getStackSize(); + + if (!guild->putItem(item)) + { + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); + if ( templ ) + { + if ( templ->Tags.FailIfInventoryIsFull ) + { + instance->setProcessingState(CMission::ActionFailed); + return; + } + } + } + // from here item maybe NULL (because of autostack) + + quantity -= stackSize; + } + params[2].Int = _Quality; + } + else + { + const CStaticItem * form = CSheets::getForm( _Item.getSheetId() ); + if ( !form ) + { + LOGMISSIONACTION("sheetId '" + _Item.getSheetId().toString() + "' is unknown"); + return; + } + uint quantity = _Quantity; + while (quantity > 0) + { + CGameItemPtr item = _Item.createItem(quantity); + if (item == NULL) + break; + + const uint32 stackSize = item->getStackSize(); + if (!guild->putItem(item)) + { + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); + if ( templ ) + { + if ( templ->Tags.FailIfInventoryIsFull ) + { + instance->setProcessingState(CMission::ActionFailed); + return; + } + } + } + // from here item maybe NULL (because of autostack) + + quantity -= stackSize; + } + params[2].Int = _Item.getQuality(); + } + + params[0].SheetId = _SheetId; + params[1].Int = _Quantity; + + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_GUILD_RECV_ITEM", params); + } } else { - LOGMISSIONACTION("can't get static item from sheet " + sheet.toString()); - return; - } - - - bool fail = true; - for ( uint i = 0; i < entities.size(); i++ ) - { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) + // check free room space in inventory + // NB : in case of group, fail happens only if none in the group have enough free space + sint16 neededSlotCount = 0; + uint32 neededBulk = 0; + CSheetId sheet = ( _SheetId != CSheetId::Unknown )?_SheetId:_Item.getSheetId(); + CGameItemPtr itemTmp = GameItemManager.createItem(sheet, _Quality, true, true); + if (itemTmp != NULL) { - CInventoryPtr invBag = user->getInventory( INVENTORIES::bag ); - sint16 freeSlotcount = invBag->getFreeSlotCount(); - uint32 maxBulk = invBag->getMaxBulk(); - - CInventoryPtr invTemp = user->getInventory( INVENTORIES::temporary ); - if( invTemp ) - { - freeSlotcount -= invTemp->getUsedSlotCount(); - maxBulk -= invTemp->getInventoryBulk(); - } - - if( (neededSlotCount <= freeSlotcount) && ( neededBulk + invBag->getInventoryBulk() <= maxBulk) ) - { - fail = false; - break; - } + neededSlotCount = (sint16) ceil( (float)_Quantity / itemTmp->getMaxStackSize() ); + neededBulk = _Quantity * itemTmp->getStackBulk(); + itemTmp.deleteItem(); } - } - if( fail ) - { - CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); - if ( templ ) + else { - if ( templ->Tags.FailIfInventoryIsFull ) - { - instance->setProcessingState(CMission::ActionFailed); - return; - } + LOGMISSIONACTION("can't get static item from sheet " + sheet.toString()); + return; } - } - for ( uint i = 0; i < entities.size(); i++ ) - { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) + bool fail = true; + for ( uint i = 0; i < entities.size(); i++ ) { - SM_STATIC_PARAMS_3(params, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); - if ( _SheetId != CSheetId::Unknown ) + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) { - const CStaticItem * form = CSheets::getForm( _SheetId ); - if ( !form ) + CInventoryPtr invBag = user->getInventory( INVENTORIES::bag ); + sint16 freeSlotcount = invBag->getFreeSlotCount(); + uint32 maxBulk = invBag->getMaxBulk(); + + CInventoryPtr invTemp = user->getInventory( INVENTORIES::temporary ); + if( invTemp ) { - LOGMISSIONACTION("sheetId '" + _SheetId.toString() + "' is unknown"); + freeSlotcount -= invTemp->getUsedSlotCount(); + maxBulk -= invTemp->getInventoryBulk(); + } + + if( (neededSlotCount <= freeSlotcount) && ( neededBulk + invBag->getInventoryBulk() <= maxBulk) ) + { + fail = false; + break; + } + } + } + if( fail ) + { + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); + if ( templ ) + { + if ( templ->Tags.FailIfInventoryIsFull ) + { + instance->setProcessingState(CMission::ActionFailed); return; } - if (form->Family != ITEMFAMILY::MISSION_ITEM && !user->enterTempInventoryMode(TEMP_INV_MODE::MissionReward)) - continue; + } + } - uint quantity = _Quantity; - while (quantity > 0) + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + SM_STATIC_PARAMS_3(params, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); + if ( _SheetId != CSheetId::Unknown ) { - CGameItemPtr item = user->createItem(_Quality, quantity, _SheetId); - if (item == NULL) - break; - const uint32 stackSize = item->getStackSize(); - - if( form->Family != ITEMFAMILY::MISSION_ITEM ) + const CStaticItem * form = CSheets::getForm( _SheetId ); + if ( !form ) { + LOGMISSIONACTION("sheetId '" + _SheetId.toString() + "' is unknown"); + return; + } + if (form->Family != ITEMFAMILY::MISSION_ITEM && !user->enterTempInventoryMode(TEMP_INV_MODE::MissionReward)) + continue; + + uint quantity = _Quantity; + while (quantity > 0) + { + CGameItemPtr item = user->createItem(_Quality, quantity, _SheetId); + if (item == NULL) + break; + const uint32 stackSize = item->getStackSize(); + + if( form->Family != ITEMFAMILY::MISSION_ITEM ) + { + if (!user->addItemToInventory(INVENTORIES::temporary, item)) + { + item.deleteItem(); + break; + } + } + else + { + if (!user->addItemToInventory(INVENTORIES::bag, item)) + { + item.deleteItem(); + break; + } + } + // from here item maybe NULL (because of autostack) + + quantity -= stackSize; + } + params[2].Int = _Quality; + } + else + { + const CStaticItem * form = CSheets::getForm( _Item.getSheetId() ); + if ( !form ) + { + LOGMISSIONACTION("sheetId '" + _Item.getSheetId().toString() + "' is unknown"); + return; + } + uint quantity = _Quantity; + while (quantity > 0) + { + CGameItemPtr item = _Item.createItem(quantity); + if (item == NULL) + break; + + const uint32 stackSize = item->getStackSize(); if (!user->addItemToInventory(INVENTORIES::temporary, item)) { item.deleteItem(); break; } - } - else - { - if (!user->addItemToInventory(INVENTORIES::bag, item)) - { - item.deleteItem(); - break; - } - } - // from here item maybe NULL (because of autostack) + // from here item maybe NULL (because of autostack) - quantity -= stackSize; + quantity -= stackSize; + } + params[2].Int = _Item.getQuality(); } - params[2].Int = _Quality; + + params[0].SheetId = _SheetId; + params[1].Int = _Quantity; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_ITEM", params); } - else - { - const CStaticItem * form = CSheets::getForm( _Item.getSheetId() ); - if ( !form ) - { - LOGMISSIONACTION("sheetId '" + _Item.getSheetId().toString() + "' is unknown"); - return; - } - uint quantity = _Quantity; - while (quantity > 0) - { - CGameItemPtr item = _Item.createItem(quantity); - if (item == NULL) - break; - - const uint32 stackSize = item->getStackSize(); - if (!user->addItemToInventory(INVENTORIES::temporary, item)) - { - item.deleteItem(); - break; - } - // from here item maybe NULL (because of autostack) - - quantity -= stackSize; - } - params[2].Int = _Item.getQuality(); - } - - params[0].SheetId = _SheetId; - params[1].Int = _Quantity; - PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_ITEM", params); } } }; @@ -760,6 +875,7 @@ class CMissionActionRecvItem : public IMissionAction uint16 _Quantity; CSheetId _SheetId; bool _Group; + bool _Guild; MISSION_ACTION_GETNEWPTR(CMissionActionRecvItem) }; @@ -772,9 +888,9 @@ class CMissionActionRecvNamedItem : public IMissionAction bool buildAction ( uint32 line, const std::vector< std::string > & script, CMissionGlobalParsingData & globalData, CMissionSpecificParsingData & missionData) { _SourceLine = line; - if ( script.size() != 2 && script.size() != 3 ) + if ( script.size() != 2 && script.size() != 3 && script.size() != 4) { - MISLOGSYNTAXERROR(" [] [:group]"); + MISLOGSYNTAXERROR(" [] [:group] [:guild]"); return false; } vector args; @@ -813,6 +929,17 @@ class CMissionActionRecvNamedItem : public IMissionAction _Group = true; } + // We check for the guild option + _Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + _Guild = true; + break; + } + } + if ( _Quantity == 0 ) { MISLOGERROR("quantity = 0"); @@ -848,7 +975,7 @@ class CMissionActionRecvNamedItem : public IMissionAction } } } - else if ( !_Group ) + else if ( !_Group && !_Guild) { CCharacter * user = PlayerManager.getChar( entities[0] ); CTeam * team = TeamManager.getRealTeam(user->getTeamId()); @@ -859,41 +986,34 @@ class CMissionActionRecvNamedItem : public IMissionAction } } - // check free room space in inventory - // NB : in case of group, fail happens only if noone in the group have enough free space - CGameItemPtr itemTmp = CNamedItems::getInstance().createNamedItem(_NamedItem, _Quantity); - if( itemTmp != NULL ) + // If the case we want to give the item to the guild + if (_Guild) { - sint16 neededSlotCount = (sint16) ceil( (float)_Quantity / itemTmp->getMaxStackSize() ); - uint32 neededBulk = _Quantity * itemTmp->getStackBulk(); - itemTmp.deleteItem(); - - bool fail = true; - for ( uint i = 0; i < entities.size(); i++ ) - { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) - { - CInventoryPtr invBag = user->getInventory( INVENTORIES::bag ); - sint16 freeSlotcount = invBag->getFreeSlotCount(); - uint32 maxBulk = invBag->getMaxBulk(); + if (entities.size() == 0) + return; - CInventoryPtr invTemp = user->getInventory( INVENTORIES::temporary ); - if( invTemp ) - { - freeSlotcount -= invTemp->getUsedSlotCount(); - maxBulk -= invTemp->getInventoryBulk(); - } - - if( (neededSlotCount <= freeSlotcount) && ( neededBulk + invBag->getInventoryBulk() <= maxBulk) ) - { - fail = false; - break; - } - } - + CCharacter * user = PlayerManager.getChar( entities[0] ); + if (!user) + { + LOGMISSIONACTION("recv_fame : Invalid user"); + return; } - if( fail ) + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId(user->getGuildId()); + if (!guild) + { + LOGMISSIONACTION("recv_fame : Invalid guild id '" + NLMISC::toString(user->getGuildId()) + "'"); + return; + } + + // add the item to inventory + CGameItemPtr item = CNamedItems::getInstance().createNamedItem(_NamedItem, _Quantity); + if (item == NULL) + { + LOGMISSIONACTION("named item '" + _NamedItem + "' is unknown"); + return; + } + if (!guild->putItem(item)) { CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); if ( templ ) @@ -905,39 +1025,103 @@ class CMissionActionRecvNamedItem : public IMissionAction } } } + else + { + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + SM_STATIC_PARAMS_2(params, STRING_MANAGER::dyn_string_id, STRING_MANAGER::integer); + params[0].StringId = item->sendNameId(user); + params[1].Int = _Quantity; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_GUILD_RECV_NAMED_ITEM", params); + } + } + } } else { - LOGMISSIONACTION("named item '" + _NamedItem + "' is unknown"); - return; - } - - // apply the action to all entities - for ( uint i = 0; i < entities.size(); i++ ) - { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) + // check free room space in inventory + // NB : in case of group, fail happens only if noone in the group have enough free space + CGameItemPtr itemTmp = CNamedItems::getInstance().createNamedItem(_NamedItem, _Quantity); + if( itemTmp != NULL ) { - if (!user->enterTempInventoryMode(TEMP_INV_MODE::MissionReward)) - continue; + sint16 neededSlotCount = (sint16) ceil( (float)_Quantity / itemTmp->getMaxStackSize() ); + uint32 neededBulk = _Quantity * itemTmp->getStackBulk(); + itemTmp.deleteItem(); + + bool fail = true; + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + CInventoryPtr invBag = user->getInventory( INVENTORIES::bag ); + sint16 freeSlotcount = invBag->getFreeSlotCount(); + uint32 maxBulk = invBag->getMaxBulk(); - // add the item to inventory - CGameItemPtr item = CNamedItems::getInstance().createNamedItem(_NamedItem, _Quantity); - if (item == NULL) - { - LOGMISSIONACTION("named item '" + _NamedItem + "' is unknown"); - return; + CInventoryPtr invTemp = user->getInventory( INVENTORIES::temporary ); + if( invTemp ) + { + freeSlotcount -= invTemp->getUsedSlotCount(); + maxBulk -= invTemp->getInventoryBulk(); + } + + if( (neededSlotCount <= freeSlotcount) && ( neededBulk + invBag->getInventoryBulk() <= maxBulk) ) + { + fail = false; + break; + } + } + } - if(!user->addItemToInventory(INVENTORIES::temporary, item)) + if( fail ) { - item.deleteItem(); + CMissionTemplate * templ = CMissionManager::getInstance()->getTemplate( instance->getTemplateId() ); + if ( templ ) + { + if ( templ->Tags.FailIfInventoryIsFull ) + { + instance->setProcessingState(CMission::ActionFailed); + return; + } + } } - else + } + else + { + LOGMISSIONACTION("named item '" + _NamedItem + "' is unknown"); + return; + } + + // apply the action to all entities + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) { - SM_STATIC_PARAMS_2(params, STRING_MANAGER::dyn_string_id, STRING_MANAGER::integer); - params[0].StringId = item->sendNameId(user); - params[1].Int = _Quantity; - PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_NAMED_ITEM", params); + if (!user->enterTempInventoryMode(TEMP_INV_MODE::MissionReward)) + continue; + + // add the item to inventory + CGameItemPtr item = CNamedItems::getInstance().createNamedItem(_NamedItem, _Quantity); + if (item == NULL) + { + LOGMISSIONACTION("named item '" + _NamedItem + "' is unknown"); + return; + } + if(!user->addItemToInventory(INVENTORIES::temporary, item)) + { + item.deleteItem(); + } + else + { + SM_STATIC_PARAMS_2(params, STRING_MANAGER::dyn_string_id, STRING_MANAGER::integer); + params[0].StringId = item->sendNameId(user); + params[1].Int = _Quantity; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_NAMED_ITEM", params); + } } } } @@ -945,6 +1129,7 @@ class CMissionActionRecvNamedItem : public IMissionAction std::string _NamedItem; uint16 _Quantity; bool _Group; + bool _Guild; MISSION_ACTION_GETNEWPTR(CMissionActionRecvNamedItem) }; @@ -1043,9 +1228,9 @@ class CMissionActionDestroyItem : { // Parse the line _SourceLine = line; - if ( script.size() != 2 && script.size() != 3) + if ( script.size() != 2 && script.size() != 3 && script.size() != 4) { - MISLOGSYNTAXERROR(" [] []:[npc_name]"); + MISLOGSYNTAXERROR(" [] []:[npc_name] [:guild]"); return false; } @@ -1060,6 +1245,17 @@ class CMissionActionDestroyItem : ret= false; } + // We check for the guild option + _Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + _Guild = true; + break; + } + } + return ret; } @@ -1074,36 +1270,86 @@ class CMissionActionDestroyItem : instance->getEntities(entities); if ( entities.empty() ) return; - for ( uint i = 0; i < entities.size(); i++ ) + + // If the "guild" parameter is not set, we destroy the items for the users + if (!_Guild) { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) + + for ( uint i = 0; i < entities.size(); i++ ) { - // Select the items in Bag AND mektoub that match the request - vector itemList; - user->selectItems(INVENTORIES::bag, _SheetId, _Quality, &itemList); - for(uint pa=0;paselectItems(INVENTORIES::TInventory(INVENTORIES::pet_animal + pa), _SheetId, _Quality, &itemList); + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + // Select the items in Bag AND mektoub that match the request + vector itemList; + user->selectItems(INVENTORIES::bag, _SheetId, _Quality, &itemList); + for(uint pa=0;paselectItems(INVENTORIES::TInventory(INVENTORIES::pet_animal + pa), _SheetId, _Quality, &itemList); - // Destroy them, up to quantity wanted - // NB: don't care if destroying an item owned by a mektoub is strange because mektoub not near! - uint quantityReallyDestroyed; - quantityReallyDestroyed= user->destroyItems(itemList, _Quantity); + // Destroy them, up to quantity wanted + // NB: don't care if destroying an item owned by a mektoub is strange because mektoub not near! + uint quantityReallyDestroyed; + quantityReallyDestroyed= user->destroyItems(itemList, _Quantity); - // Send message - SM_STATIC_PARAMS_4(params, STRING_MANAGER::bot, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); - TAIAlias botAlias= _Npc; - if(botAlias==CAIAliasTranslator::Invalid) - botAlias= instance->getGiver(); - params[0].setEIdAIAlias(CAIAliasTranslator::getInstance()->getEntityId( botAlias ), botAlias); - params[1].SheetId = _SheetId; - params[2].Int = quantityReallyDestroyed; - params[3].Int = _Quality; - PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_DESTROY_ITEM", params); + // Send message + SM_STATIC_PARAMS_4(params, STRING_MANAGER::bot, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); + TAIAlias botAlias= _Npc; + if(botAlias==CAIAliasTranslator::Invalid) + botAlias= instance->getGiver(); + params[0].setEIdAIAlias(CAIAliasTranslator::getInstance()->getEntityId( botAlias ), botAlias); + params[1].SheetId = _SheetId; + params[2].Int = quantityReallyDestroyed; + params[3].Int = _Quality; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_DESTROY_ITEM", params); + } + } + + } + // We destroy the item in the guild + else + { + CCharacter * user = PlayerManager.getChar( entities[0] ); + if (!user) + { + LOGMISSIONACTION("recv_fame : Invalid user"); + return; + } + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId(user->getGuildId()); + if (!guild) + { + LOGMISSIONACTION("recv_fame : Invalid guild id '" + NLMISC::toString(user->getGuildId()) + "'"); + return; + } + + vector itemList; + guild->selectItems(_SheetId, _Quality, &itemList); + + // Destroy them, up to quantity wanted + uint quantityReallyDestroyed; + quantityReallyDestroyed = guild->destroyItems(itemList, _Quantity); + + // Send message + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + SM_STATIC_PARAMS_4(params, STRING_MANAGER::bot, STRING_MANAGER::item, STRING_MANAGER::integer, STRING_MANAGER::integer); + TAIAlias botAlias= _Npc; + if(botAlias==CAIAliasTranslator::Invalid) + botAlias= instance->getGiver(); + params[0].setEIdAIAlias(CAIAliasTranslator::getInstance()->getEntityId( botAlias ), botAlias); + params[1].SheetId = _SheetId; + params[2].Int = quantityReallyDestroyed; + params[3].Int = _Quality; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_DESTROY_ITEM", params); + } } } }; TAIAlias _Npc; + bool _Guild; MISSION_ACTION_GETNEWPTR(CMissionActionDestroyItem) }; @@ -1607,9 +1853,9 @@ class CMissionActionRecvMoney : public IMissionAction { bool ret = true; _SourceLine = line; - if ( script.size() != 2 ) + if ( script.size() != 2 && script.size() != 3) { - MISLOGSYNTAXERROR(" OR *[;]"); + MISLOGSYNTAXERROR(" [: guild] OR *[;]"); return false; } @@ -1637,6 +1883,18 @@ class CMissionActionRecvMoney : public IMissionAction ret = false; } } + + // We check for the guild option + _Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + _Guild = true; + break; + } + } + return ret; } @@ -1647,22 +1905,67 @@ class CMissionActionRecvMoney : public IMissionAction std::vector entities; instance->getEntities(entities); - uint amount = _Amount / (uint)entities.size(); - if ( amount == 0 || _Amount % entities.size() ) - amount++; - for ( uint i = 0; i < entities.size(); i++ ) + + // If the guild parameter is not set we just divide the money and give it to each entity + if (!_Guild) { - CCharacter * user = PlayerManager.getChar( entities[i] ); - if ( user ) + + uint amount = _Amount / (uint)entities.size(); + if ( amount == 0 || _Amount % entities.size() ) + amount++; + for ( uint i = 0; i < entities.size(); i++ ) { - user->giveMoney( _Amount ); - SM_STATIC_PARAMS_1(params, STRING_MANAGER::integer); - params[0].Int = _Amount; - PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_MONEY",params); + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + user->giveMoney( _Amount ); + SM_STATIC_PARAMS_1(params, STRING_MANAGER::integer); + params[0].Int = _Amount; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_RECV_MONEY",params); + } } + + } + // Else we give the money to the guild + else + { + if (entities.size() == 0) + return; + + CCharacter * user = PlayerManager.getChar( entities[0] ); + if (!user) + { + LOGMISSIONACTION("recv_money : Invalid user"); + return; + } + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId(user->getGuildId()); + if (guild) + { + guild->addMoney(_Amount); + } + else + { + LOGMISSIONACTION("recv_money : Invalid guild id '" + NLMISC::toString(user->getGuildId()) + "'"); + return; + } + + // tell everyone some money has been given to the guild + for ( uint i = 0; i < entities.size(); i++ ) + { + CCharacter * user = PlayerManager.getChar( entities[i] ); + if ( user ) + { + SM_STATIC_PARAMS_1(params, STRING_MANAGER::integer); + params[0].Int = _Amount; + PHRASE_UTILITIES::sendDynamicSystemMessage(user->getEntityRowId(),"MIS_GUILD_RECV_MONEY",params); + } + } + } }; uint _Amount; + bool _Guild; MISSION_ACTION_GETNEWPTR(CMissionActionRecvMoney) }; @@ -1675,9 +1978,9 @@ class CMissionActionRecvFame : public IMissionAction bool buildAction ( uint32 line, const std::vector< std::string > & script, CMissionGlobalParsingData & globalData, CMissionSpecificParsingData & missionData) { _SourceLine = line; - if ( script.size() != 2 ) + if ( script.size() != 2 && script.size() != 3) { - MISLOGSYNTAXERROR(" "); + MISLOGSYNTAXERROR(" [:guild]"); return false; } vector args; @@ -1700,6 +2003,18 @@ class CMissionActionRecvFame : public IMissionAction MISLOGERROR("fame = 0"); return false; } + + // We check for the guild option + _Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + _Guild = true; + break; + } + } + return true; } @@ -1708,20 +2023,63 @@ class CMissionActionRecvFame : public IMissionAction LOGMISSIONACTION("recv_fame"); std::vector entities; instance->getEntities(entities); - for ( uint i = 0; i < entities.size(); i++ ) - { - CEntityId eid = TheDataset.getEntityId(entities[i]); - CFameInterface::getInstance().addFameIndexed(eid, _Faction, _Value, true); - // Make the client refresh the icons on mission giver NPCs, at once - CCharacter *character = PlayerManager.getChar(entities[i]); - if (character) - character->sendEventForMissionAvailabilityCheck(); + // If there is no "guild" parameter we give the fame to every user + if (!_Guild) + { + + for ( uint i = 0; i < entities.size(); i++ ) + { + CEntityId eid = TheDataset.getEntityId(entities[i]); + CFameInterface::getInstance().addFameIndexed(eid, _Faction, _Value, true); + + // Make the client refresh the icons on mission giver NPCs, at once + CCharacter *character = PlayerManager.getChar(entities[i]); + if (character) + character->sendEventForMissionAvailabilityCheck(); + } + + } + // Else we just give it to the guild + else + { + + if (entities.size() == 0) + return; + + CCharacter * user = PlayerManager.getChar( entities[0] ); + if (!user) + { + LOGMISSIONACTION("recv_fame : Invalid user"); + return; + } + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId(user->getGuildId()); + if (guild) + { + CFameInterface::getInstance().addFameIndexed(guild->getEId(), _Faction, _Value, true); + } + else + { + LOGMISSIONACTION("recv_fame : Invalid guild id '" + NLMISC::toString(user->getGuildId()) + "'"); + return; + } + + // tell everyone some money has been given to the guild + for ( uint i = 0; i < entities.size(); i++ ) + { + // Make the client refresh the icons on mission giver NPCs, at once + CCharacter *character = PlayerManager.getChar(entities[i]); + if (character) + character->sendEventForMissionAvailabilityCheck(); + } + } }; uint32 _Faction; sint32 _Value; + bool _Guild; MISSION_ACTION_GETNEWPTR(CMissionActionRecvFame) }; @@ -3695,15 +4053,16 @@ protected: TAIAlias Mission; TAIAlias NPCOwner; // NPC giver the mission have to be attached at spawn time + bool Guild; protected: bool buildAction ( uint32 line, const std::vector< std::string > & script, CMissionGlobalParsingData & globalData, CMissionSpecificParsingData & missionData) { _SourceLine = line; - if ( script.size() != 3 ) + if ( script.size() != 3 && script.size() != 4) { - MISLOGSYNTAXERROR(" : "); + MISLOGSYNTAXERROR(" : [: guild]"); return false; } string name = CMissionParser::getNoBlankString( script[1] ); @@ -3736,6 +4095,17 @@ protected: if (vRet.size() > 0) NPCOwner = vRet[0]; + // We check for the guild option + Guild = false; + for (std::vector< std::string >::const_iterator it = script.begin(); it != script.end(); ++it) + { + if (CMissionParser::getNoBlankString(*it) == "guild") + { + Guild = true; + break; + } + } + return true; } @@ -3746,13 +4116,13 @@ protected: { CAIAliasTranslator::getInstance()->getNPCNameFromAlias(instance->getGiver(), sDebugBotName); nlassert(instance); - CMissionEventAddMission * event = new CMissionEventAddMission( instance->getGiver(), Mission, mainMission ); + CMissionEventAddMission * event = new CMissionEventAddMission( instance->getGiver(), Mission, mainMission, Guild ); eventList.push_back( event ); } else { CAIAliasTranslator::getInstance()->getNPCNameFromAlias(NPCOwner, sDebugBotName); - CMissionEventAddMission * event = new CMissionEventAddMission( NPCOwner, Mission, mainMission ); + CMissionEventAddMission * event = new CMissionEventAddMission( NPCOwner, Mission, mainMission, Guild ); eventList.push_back( event ); } LOGMISSIONACTION("spawn_mission bot:" + sDebugBotName + " newmiss:" + CPrimitivesParser::aliasToString(Mission) diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_event.h b/code/ryzom/server/src/entities_game_service/mission_manager/mission_event.h index d2c879799..34ff36600 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_event.h +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_event.h @@ -429,11 +429,12 @@ protected: class CMissionEventAddMission: public CMissionEvent { public: - CMissionEventAddMission( TAIAlias giver, TAIAlias mission, TAIAlias mainMission ) - :CMissionEvent(AddMission, TDataSetRow()) ,Giver(giver),Mission(mission),MainMission(mainMission) {} + CMissionEventAddMission( TAIAlias giver, TAIAlias mission, TAIAlias mainMission, bool guild ) + :CMissionEvent(AddMission, TDataSetRow()) ,Giver(giver),Mission(mission),MainMission(mainMission), Guild(guild) {} TAIAlias Mission; TAIAlias Giver; TAIAlias MainMission; + bool Guild; protected: friend class CMissionEvent; bool buildFromScript( const std::vector< std::string > & script ,NLMISC::CLog& log){return false;} diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.cpp index d3bb2c106..63b74e997 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.cpp @@ -25,18 +25,83 @@ #include "player_manager/player.h" #include "player_manager/character.h" +using namespace std; +using namespace NLMISC; + NL_INSTANCE_COUNTER_IMPL(CMissionGuild); //---------------------------------------------------------------------------- void CMissionGuild::updateUsersJournalEntry() { - /// todo guild mission + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( _GuildId ); + if (!guild) + { + nlwarning( "cant find guild ID : %d", _GuildId ); + return; + } + + for ( std::map::iterator it = guild->getMembersBegin(); + it != guild->getMembersEnd();++it ) + { + CCharacter * user = PlayerManager.getChar( it->first ); + if ( !user ) + { + nlwarning( "cant find user %s", it->first.toString().c_str() ); + continue; + } + updateUserJournalEntry(*user,"GROUP:"); + } } //---------------------------------------------------------------------------- void CMissionGuild::clearUsersJournalEntry() { - /// todo guild mission + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( _GuildId ); + if (!guild) + { + nlwarning( "cant find guild ID : %d", _GuildId ); + return; + } + + for ( std::map::iterator it = guild->getMembersBegin(); + it != guild->getMembersEnd();++it ) + { + CCharacter * user = PlayerManager.getChar( it->first ); + if ( !user ) + { + nlwarning( "cant find user %s", it->first.toString().c_str() ); + continue; + } + + CBankAccessor_PLR::TGROUP::TMISSIONS::TArray &missionItem = CBankAccessor_PLR::getGROUP().getMISSIONS().getArray(_ClientIndex); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:TYPE",_ClientIndex), 0); + missionItem.setTYPE(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:ICON",_ClientIndex), 0); + missionItem.setICON(user->_PropertyDatabase, CSheetId::Unknown); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:TITLE",_ClientIndex), 0); + missionItem.setTITLE(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:DETAIL_TEXT",_ClientIndex), 0); + missionItem.setDETAIL_TEXT(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:END_DATE",_ClientIndex), 0 ); + missionItem.setEND_DATE(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:BEGIN_DATE",_ClientIndex), 0 ); + missionItem.setBEGIN_DATE(user->_PropertyDatabase, 0); + for (uint i = 0; i < NB_JOURNAL_COORDS; i++) + { + CBankAccessor_PLR::TGROUP::TMISSIONS::TArray::TTARGET &targetItem = missionItem.getTARGET(i); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:TARGET%u:TITLE",_ClientIndex,i), 0); + targetItem.setTITLE(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:TARGET%u:X",_ClientIndex,i), 0); + targetItem.setX(user->_PropertyDatabase, 0); + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:TARGET%u:Y",_ClientIndex,i), 0); + targetItem.setY(user->_PropertyDatabase, 0); + } + for (uint i = 0; i < NB_STEP_PER_MISSION; i++) + { + // user->_PropertyDatabase.setProp( NLMISC::toString( "GROUP:MISSIONS:%u:GOALS:%u:TEXT",_ClientIndex,i), 0); + missionItem.getGOALS().getArray(i).setTEXT(user->_PropertyDatabase, 0); + } + } } diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.h b/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.h index e0c65f2c2..b8635d1d4 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.h +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_guild.h @@ -32,6 +32,7 @@ public: CMissionGuild() : _Chained(false) { } + inline void setGuild( uint32 guildId ); /// override void updateUsersJournalEntry(); /// override @@ -58,6 +59,10 @@ private: bool _Chained; }; +void CMissionGuild::setGuild( uint32 guildId ) +{ + _GuildId = guildId; +} #endif // RY_MISSION_GUILD_H diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_manager.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_manager.cpp index b0bd41ffb..ca5d4bba0 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_manager.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_manager.cpp @@ -44,6 +44,7 @@ #include "egs_utils.h" #include "egs_pd.h" #include "guild_manager/guild_member_module.h" +#include "guild_manager/guild_manager.h" #include "building_manager/building_manager.h" #include "building_manager/room_instance.h" #include "zone_manager.h" @@ -836,25 +837,68 @@ void CMissionManager::instanciateMission(CCharacter* user,TAIAlias alias, TAIAl } else if ( templ->Type == MISSION_DESC::Guild ) { - /// todo guild mission + /// Check to see if we can pick the mission CGuildMemberModule * module; if ( !user->getModuleParent().getModule( module ) ) { MISDBG("%s user not in a guild", sDebugPrefix.c_str()); return; } - inst = module->pickMission( templ->Alias ); - if (!inst) + /* /// This is already checked in the prerequisites + if (!module->pickMission( templ->Alias )) + { + /// Todo : error message for the member return; - /// todo guild mission : see solo - /* - todo guild mission : implement that in module - teamMission->initBasics( giver ); - soloMission->setTeam( user->getTeamId() ); + }*/ + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); + if (!guild) + { + nlwarning( "cant find guild ID : %d", user->getGuildId() ); + return; + } + if ( !templ->Tags.NoList && guild->getMissions().size() >= MaxGuildMissionCount) + { + CCharacter::sendDynamicSystemMessage(user->getId(), "MISSION_MAX_GUILD_REACHED" ); + return; + } + + CMissionGuild * guildMission = EGS_PD_CAST( EGSPD::CMissionGuildPD::create( templ->Alias ) ); + if ( !guildMission ) + { + MISDBG("%s could not create guild mission", sDebugPrefix.c_str()); + return; + } + guildMission->onCreation( giver ); + guildMission->setGuild(user->getGuildId()); + + // Find a suitable client index (for non-invisible missions) + if ( templ->Tags.NoList == false ) + { + uint8 idx = 0; + for ( uint i = MaxGroupMissionCount; i < MaxGroupMissionCount + MaxGuildMissionCount; i++ ) + { + if ( ! CBankAccessor_PLR::getGROUP().getMISSIONS().getArray(i).getTITLE(user->_PropertyDatabase)) + { + idx = i; + break; + } + } + guildMission->setClientIndex( idx ); + } + + // Add mission + guild->addMission( guildMission ); + inst = guildMission; + + /// /!\ Do the same thing that the team missions but with the loop: for ( uint i = MaxGroupMissionCount; i < MaxGroupMissionCount + MaxGuildMissionCount; i++ ) + /// Instead of for ( uint i = 0; i < MaxGroupMissionCount; i++ ), so that we use available space for guild missions + + /*//teamMission->initBasics( giver ); + //soloMission->setTeam( user->getTeamId() ); CGuild * guild = user->getGuild(); if ( guild ) { - mission->getguild if ( guild->getMissions().size() >= MaxGuildMissionCount) { CCharacter::sendDynamicSystemMessage(user->getId(), "MISSION_MAX_GUILD_REACHED" ); @@ -880,8 +924,7 @@ void CMissionManager::instanciateMission(CCharacter* user,TAIAlias alias, TAIAl else { - } - */ + }*/ } else { diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_misc.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_misc.cpp index ff8496eba..03ad33b28 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_misc.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_step_misc.cpp @@ -1141,7 +1141,13 @@ MISSION_REGISTER_STEP(CMissionStepCast,"cast") // ---------------------------------------------------------------------------- class CMissionStepDoMissions : public IMissionStepTemplate { - std::vector< std::string > _Missions; + struct MissionNb + { + std::string Mission; + uint32 NbNeedCompletion; + }; + + std::vector< MissionNb > _Missions; virtual bool buildStep( uint32 line, const std::vector< std::string > & script, CMissionGlobalParsingData & globalData, CMissionSpecificParsingData & missionData ) { @@ -1158,7 +1164,23 @@ class CMissionStepDoMissions : public IMissionStepTemplate _Missions.resize(subs.size()); for ( uint i = 0; i < subs.size(); i++ ) { - _Missions[i] = CMissionParser::getNoBlankString( subs[i] ); + std::vector< std::string > params; + //NLMISC::splitString( subs[i]," \t", params ); + subs[i] = CMissionParser::getNoBlankString(subs[i]); + std::size_t pos = subs[i].find_first_of(" \t"); + std::string str = subs[i].substr(0, pos); + params.push_back(str); + if (pos != std::string::npos) + str = subs[i].substr(pos + 1); + else + str = ""; + params.push_back(str); + //std::size_t pos = _Missions[i].find_first_of(" \t"); + _Missions[i].Mission = CMissionParser::getNoBlankString( params[0] ); + if (params.size() > 1) + NLMISC::fromString(params[1], _Missions[i].NbNeedCompletion); + else + _Missions[i].NbNeedCompletion = 1; } return true; } @@ -1168,7 +1190,7 @@ class CMissionStepDoMissions : public IMissionStepTemplate if ( event.Type == CMissionEvent::MissionDone ) { CMissionEventMissionDone & eventSpe = (CMissionEventMissionDone&)event; - TAIAlias alias = CAIAliasTranslator::getInstance()->getMissionUniqueIdFromName( _Missions[subStepIndex] ); + TAIAlias alias = CAIAliasTranslator::getInstance()->getMissionUniqueIdFromName( _Missions[subStepIndex].Mission ); if ( eventSpe.Mission == alias ) { LOGMISSIONSTEPSUCCESS("mission"); @@ -1181,11 +1203,36 @@ class CMissionStepDoMissions : public IMissionStepTemplate void getInitState( std::vector& ret ) { ret.resize( _Missions.size(), 1 ); + uint32 i = 0; + for (std::vector::const_iterator it = _Missions.begin(); it != _Missions.end(); ++it) + { + ret[i] = it->NbNeedCompletion; + i++; + } } virtual void getTextParams( uint & nbSubSteps,const std::string* & textPtr,TVectorParamCheck& retParams, const std::vector& subStepStates) { - static const std::string stepText = "ERROR_UNSPECIFIED_MISSION_TEXT"; + /*static const std::string stepText = "ERROR_UNSPECIFIED_MISSION_TEXT"; + textPtr = &stepText;*/ + + // Because we can specify the number of times we want a mission to be completed, we specify the parameters + static const std::string stepText = "MIS_DO_MISSION_"; + nlassert( _Missions.size() == subStepStates.size() ); + for ( uint i = 0; i < subStepStates.size(); i++ ) + { + if( subStepStates[i] != 0 ) + { + nbSubSteps++; + retParams.push_back(STRING_MANAGER::TParam()); + retParams.back().Type = STRING_MANAGER::integer; + retParams.back().Int = subStepStates[i]; + + retParams.push_back(STRING_MANAGER::TParam()); + retParams.back().Type = STRING_MANAGER::literal; + retParams.back().Literal = _Missions[i].Mission; + } + } textPtr = &stepText; } bool checkTextConsistency() diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/mission_template.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/mission_template.cpp index dfd516b45..af0686f1e 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/mission_template.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/mission_template.cpp @@ -1307,21 +1307,57 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos else if ( Type == MISSION_DESC::Guild ) { /// todo guild mission - /* - CGuild * guild = user->getGuild(); + + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if ( guild == NULL ) { MISDBG("No guild"); return MISSION_DESC::PreReqFail; + + /*if (logOnFail) + MISDBG("%s No guild", sDebugPrefix.c_str()); + + if (!fillPrereqInfos) + return MISSION_DESC::PreReqFail; + + prereqDesc.Description = STRING_MANAGER::sendStringToClient(user->getEntityRowId(), "MISSION_PREREQ_TEAM", TVectorParamCheck()); + prereqDesc.IsMandatory = true; + prereqDesc.Validated = false; + prereqInfos.Prerequisits.push_back(prereqDesc); + + addedPrereqTexts.insert("MISSION_PREREQ_TEAM"); + + returnValue = MISSION_DESC::PreReqFail; + logOnFail = false;*/ } // check if the mission is already picked for ( uint j = 0 ; j < guild->getMissions().size(); j++ ) { - if ( guild->getMissions()[j]->getTemplate()->Alias == alias ) + if ( guild->getMissions()[j]->getTemplateId() == alias || + guild->getMissions()[j]->getMainMissionTemplateId() == alias) { MISDBG("The guild already own this mission"); return MISSION_DESC::PreReqFail; + + /*if (logOnFail) + MISDBG("%s The guild already own this mission", sDebugPrefix.c_str()); + + if (!fillPrereqInfos) + return MISSION_DESC::PreReqFail; + + if (addedPrereqTexts.find("MISSION_PREREQ_ALREADY_DONE") == addedPrereqTexts.end()) + { + prereqDesc.Description = STRING_MANAGER::sendStringToClient(user->getEntityRowId(), "MISSION_PREREQ_ALREADY_DONE", TVectorParamCheck()); + prereqDesc.IsMandatory = true; + prereqDesc.Validated = false; + prereqInfos.Prerequisits.push_back(prereqDesc); + addedPrereqTexts.insert("MISSION_PREREQ_ALREADY_DONE"); + } + + returnValue = MISSION_DESC::PreReqFail; + logOnFail = false;*/ } + } // check non replayable missions if( !Tags.Replayable ) @@ -1329,11 +1365,29 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos if (guild->isMissionSuccessfull(alias)) // if ( std::find(guild->getSuccessfulMissions().begin(),guild->getSuccessfulMissions().end(), alias) != guild->getSuccessfulMissions().end() ) { - MISDBG("solo non replayable"); + MISDBG("mission non replayable"); return MISSION_DESC::PreReqFail; + + /*if (logOnFail) + MISDBG("%s Guild mission already done and not replayable", sDebugPrefix.c_str()); + + if (!fillPrereqInfos) + return MISSION_DESC::PreReqFailAlreadyDone; + + if (addedPrereqTexts.find("MISSION_PREREQ_ALREADY_DONE") == addedPrereqTexts.end()) + { + prereqDesc.Description = STRING_MANAGER::sendStringToClient(user->getEntityRowId(), "MISSION_PREREQ_ALREADY_DONE", TVectorParamCheck()); + prereqDesc.IsMandatory = true; + prereqDesc.Validated = false; + prereqInfos.Prerequisits.push_back(prereqDesc); + addedPrereqTexts.insert("MISSION_PREREQ_ALREADY_DONE"); + } + + returnValue = MISSION_DESC::PreReqFailAlreadyDone; + logOnFail = false;*/ } } - */ + } else { @@ -1412,7 +1466,7 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos if ( templ->Type == MISSION_DESC::Guild ) { /// todo guild mission - /* + CGuild* guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if ( ! guild ) { MISDBG("Require needed mission at line %u (guild mission but player has no guild)", Prerequisits.NeededMissions[i].Line); @@ -1420,7 +1474,7 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos } if (guild->isMissionSuccessfull(templ->Alias)) break; - */ + } else if ( templ->Type == MISSION_DESC::Solo ) { @@ -1473,15 +1527,14 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos else if ( templ->Type == MISSION_DESC::Guild ) { /// todo guild mission - /* + CGuild* guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if ( !guild ) break; if (!guild->isMissionSuccessfull(templ->Alias)) - - if (!guild || !guild->isMissionSuccessfull(templ->Alias)) - break; - */ + /*if (!guild || !guild->isMissionSuccessfull(templ->Alias)) + break;*/ + } else if ( templ->Type == MISSION_DESC::Solo ) { @@ -1537,8 +1590,8 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos { /// todo guild mission - /* - + + CGuild* guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if ( !guild ) { MISDBG("Require running mission at line %u (guild mission but player has no guild)", Prerequisits.RunningMissions[i].Line ); @@ -1548,12 +1601,12 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos for ( ; k < guild->getMissions().size(); k++ ) { - if ( guild->getMissions()[k]->getTemplate()->Alias == templ->Alias ) + if ( guild->getMissions()[k]->getTemplateId() == templ->Alias ) break; } if (k != guild->getMissions().size()) break; - */ + } else if ( templ->Type == MISSION_DESC::Solo ) { @@ -1651,20 +1704,20 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos { /// todo guild mission - /* - + + CGuild* guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); if(!guild) break; uint k=0; for ( ; k < guild->getMissions().size(); k++ ) { - if ( guild->getMissions()[k]->getTemplate()->Alias == templ->Alias ) + if ( guild->getMissions()[k]->getTemplateId() == templ->Alias ) break; } if (k == guild->getMissions().size()) break; - */ + } else if ( templ->Type == MISSION_DESC::Solo ) { @@ -2041,6 +2094,15 @@ uint32 CMissionTemplate::testPrerequisits( CCharacter * user, CPrerequisitInfos if (!fillPrereqInfos) return MISSION_DESC::PreReqFail; + /*if (addedPrereqTexts.find("GUILD_BUILDING_BAD_GRADE") == addedPrereqTexts.end()) + { + prereqDesc.Description = STRING_MANAGER::sendStringToClient(user->getEntityRowId(), "GUILD_BUILDING_BAD_GRADE", TVectorParamCheck()); + prereqDesc.IsMandatory = true; + prereqDesc.Validated = false; + prereqInfos.Prerequisits.push_back(prereqDesc); + addedPrereqTexts.insert("GUILD_BUILDING_BAD_GRADE"); + }*/ + returnValue = MISSION_DESC::PreReqFail; logOnFail = false; } diff --git a/code/ryzom/server/src/entities_game_service/mission_manager/missions_commands.cpp b/code/ryzom/server/src/entities_game_service/mission_manager/missions_commands.cpp index 78229d3a8..a5f0f863f 100644 --- a/code/ryzom/server/src/entities_game_service/mission_manager/missions_commands.cpp +++ b/code/ryzom/server/src/entities_game_service/mission_manager/missions_commands.cpp @@ -30,7 +30,9 @@ #include "team_manager/team_manager.h" #include "mission_manager/mission_team.h" #include "mission_manager/mission_step_ai.h" +#include "mission_manager/mission_guild.h" #include "guild_manager/guild_manager.h" +#include "guild_manager/guild.h" #include "admin.h" #include "creature_manager/creature_manager.h" @@ -81,10 +83,18 @@ NLMISC_COMMAND(forceJournalUpdate,"force mission journal update","getMissions()[i]->updateUsersJournalEntry(); } } - for (uint i = 0; i < MaxGuildMissionCount; i++) + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( user->getGuildId() ); + if (guild) + { + for ( uint i = 0; i < guild->getMissions().size(); i++ ) + { + guild->getMissions()[i]->updateUsersJournalEntry(); + } + } + /*for (uint i = 0; i < MaxGuildMissionCount; i++) { /// todo guild mission - } + }*/ return true; } // missionProgress // 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 9af9606ea..70c8238ac 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 @@ -1344,6 +1344,22 @@ uint32 CCharacter::tickUpdate() } } + // Adding UpdateCompass for guild missions + { + H_AUTO(CharacterUpdateGuildCompass); + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( _GuildId ); + if ( guild ) + { + const uint size = (uint)guild->getMissions().size(); + for ( uint i = 0; i < size; i++ ) + { + nlassert(guild->getMissions()[i]); + guild->getMissions()[i]->updateCompass(*this, string("")); + guild->getMissions()[i]->updateCompass(*this, string("GROUP:")); + } + } + } + { H_AUTO(CharacterUpdateTargetCoordinatesCompass); // update compass coordinates information @@ -10709,6 +10725,7 @@ void CCharacter::acceptExchange(uint8 exchangeId) } CTeam * team = TeamManager.getRealTeam( _TeamId ); + CGuild* guild = CGuildManager::getInstance()->getGuildFromId( _GuildId ); if (_BotGift == NULL) { nlwarning("Player %s has no bot gift", _Id.toString().c_str()); @@ -10732,6 +10749,15 @@ void CCharacter::acceptExchange(uint8 exchangeId) } mission = team->getMissionByAlias( missionAlias ); } + else if (type == MISSION_DESC::Guild) + { + if (guild == NULL) + { + nlwarning("CCharacter::acceptExchange : character %s -> no guild",_Id.toString().c_str() ); + return; + } + mission = guild->getMissionByAlias( missionAlias ); + } vector vect; vector exchangePlayerPets; @@ -10765,6 +10791,8 @@ void CCharacter::acceptExchange(uint8 exchangeId) processMissionStepUserEvent( eventList,missionAlias,stepIndex ); else if ( type == MISSION_DESC::Group ) team->processTeamMissionStepEvent( eventList,missionAlias,stepIndex ); + else if ( type == MISSION_DESC::Guild ) + guild->processGuildMissionStepEvent( eventList,missionAlias,stepIndex ); eventList.pop_front(); for ( std::list< CMissionEvent* >::iterator it = eventList.begin(); it != eventList.end(); ++it ) processMissionEvent(*(*it)); @@ -10784,6 +10812,8 @@ void CCharacter::acceptExchange(uint8 exchangeId) processMissionStepUserEvent( eventList,missionAlias,stepIndex ); else if ( type == MISSION_DESC::Group ) team->processTeamMissionStepEvent( eventList,missionAlias,stepIndex ); + else if ( type == MISSION_DESC::Guild ) + guild->processGuildMissionStepEvent( eventList,missionAlias,stepIndex ); eventList.pop_front(); for ( std::list< CMissionEvent* >::iterator it = eventList.begin(); it != eventList.end(); ++it ) processMissionEvent(*(*it)); @@ -11616,7 +11646,7 @@ bool CCharacter::processMissionEventList( std::list< CMissionEvent* > & eventLis bool processed = false; bool firstEvent = true; - CGuild * guild = NULL; + CGuild * guild = CGuildManager::getInstance()->getGuildFromId( _GuildId ); while ( !eventList.empty() ) { bool eventProcessed = false; @@ -11628,11 +11658,33 @@ bool CCharacter::processMissionEventList( std::list< CMissionEvent* > & eventLis TAIAlias mission = eventSpe.Mission; TAIAlias giver = eventSpe.Giver; TAIAlias mainMission = eventSpe.MainMission; + bool missionForGuild = eventSpe.Guild; // add mission event are always allocated on heap delete ( CMissionEvent *) ( eventList.front() ); eventList.pop_front(); - CMissionManager::getInstance()->instanciateMission(this, mission, giver ,eventList, mainMission); + + // If the mission is not for guild members we just instanciate it + if (!missionForGuild) + CMissionManager::getInstance()->instanciateMission(this, mission, giver ,eventList, mainMission); + else + { + // We find the guild and each guild members and we instanciate the mission for them + if (guild) + { + for ( std::map::iterator it = guild->getMembersBegin(); + it != guild->getMembersEnd();++it ) + { + CCharacter * guildUser = PlayerManager.getChar( it->first ); + if ( !guildUser ) + { + nlwarning( "cant find user %s", it->first.toString().c_str() ); + continue; + } + CMissionManager::getInstance()->instanciateMission(guildUser, mission, giver ,eventList, mainMission); + } + } + } } // event may have been processed during instanciateMission if ( eventList.empty() ) @@ -11653,6 +11705,13 @@ bool CCharacter::processMissionEventList( std::list< CMissionEvent* > & eventLis eventProcessed = team->processTeamMissionEvent(eventList, alias); } + // THIRD - Check with guild missions (if event not already processed and char belongs to a guild) + if (!eventProcessed)// && (event.Restriction != CMissionEvent::NoGroup)) + { + if (guild != NULL) + eventProcessed = guild->processGuildMissionEvent(eventList, alias); + } + processed |= eventProcessed; // the first event of the list was processed, so we remove it. diff --git a/code/ryzom/tools/leveldesign/mission_compiler_lib/mission_compiler.h b/code/ryzom/tools/leveldesign/mission_compiler_lib/mission_compiler.h index 756b3859d..6f993679b 100644 --- a/code/ryzom/tools/leveldesign/mission_compiler_lib/mission_compiler.h +++ b/code/ryzom/tools/leveldesign/mission_compiler_lib/mission_compiler.h @@ -318,6 +318,11 @@ public: bool isThereAJumpTo(const std::string &stepName); + bool isGuildMission() const + { + return _Guild; + } + private: std::string genPreRequisites(); diff --git a/code/ryzom/tools/leveldesign/mission_compiler_lib/step.h b/code/ryzom/tools/leveldesign/mission_compiler_lib/step.h index e93db4524..fdb1db4be 100644 --- a/code/ryzom/tools/leveldesign/mission_compiler_lib/step.h +++ b/code/ryzom/tools/leveldesign/mission_compiler_lib/step.h @@ -192,6 +192,11 @@ protected: std::vector _RoleplayObj; CPhrase _RoleplayPhrase; bool _HideObj; + + // Option nb_guild_members_needed, available for each objective + /*int _NbGuildMembersNeeded; + + std::string genNbGuildMembersNeededOption(CMissionData &md);*/ public: void init(CMissionData &md, NLLIGO::IPrimitive *prim); diff --git a/code/ryzom/tools/leveldesign/mission_compiler_lib/step_content.cpp b/code/ryzom/tools/leveldesign/mission_compiler_lib/step_content.cpp index c0d78ab74..f327f836a 100644 --- a/code/ryzom/tools/leveldesign/mission_compiler_lib/step_content.cpp +++ b/code/ryzom/tools/leveldesign/mission_compiler_lib/step_content.cpp @@ -142,6 +142,7 @@ REGISTER_STEP_CONTENT(CActionJumpTo, "jump_to"); class CActionRecvMoney : public IStepContent { string _Amount; + bool _Guild; void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -152,12 +153,27 @@ public: { IStepContent::init(md, prim); _Amount = md.getProperty(prim, "amount", true, false); + + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } } string genCode(CMissionData &md) { if (!_Amount.empty()) - return "recv_money : "+_Amount+NL; + { + string ret; + ret = "recv_money : "+_Amount; + if (_Guild) + ret += ": guild"; + ret += NL; + return ret; + } else return string(); } @@ -166,12 +182,79 @@ public: REGISTER_STEP_CONTENT(CActionRecvMoney, "recv_money"); +// --------------------------------------------------------------------------- +class CActionRecvChargePoint : public IStepContent +{ + string _Amount; + + void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) + { + numEntry = 0; + } +public: + void init(CMissionData &md, IPrimitive *prim) + { + IStepContent::init(md, prim); + _Amount = md.getProperty(prim, "charge_points", true, false); + } + + string genCode(CMissionData &md) + { + if (!_Amount.empty()) + { + string ret; + ret = "recv_charge_point : "+_Amount; + ret += NL; + return ret; + } + else + return string(); + } + +}; +REGISTER_STEP_CONTENT(CActionRecvChargePoint, "recv_charge_point"); + + +// --------------------------------------------------------------------------- +class CActionGiveOutpostControl : public IStepContent +{ + string _OutpostName; + + void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) + { + numEntry = 0; + } +public: + void init(CMissionData &md, IPrimitive *prim) + { + IStepContent::init(md, prim); + _OutpostName = md.getProperty(prim, "outpost_name", true, false); + } + + string genCode(CMissionData &md) + { + if (!_OutpostName.empty()) + { + string ret; + ret = "give_control : "+_OutpostName; + ret += NL; + return ret; + } + else + return string(); + } + +}; +REGISTER_STEP_CONTENT(CActionGiveOutpostControl, "give_control"); + + // --------------------------------------------------------------------------- class CActionSpawnMission : public IStepContent { protected: string _MissionName; string _GiverName; + bool _Guild; private: void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -186,17 +269,29 @@ public: if (_GiverName.empty()) { throw EParseException(prim, "giver_name is empty !"); - } + } + + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } } string genCode(CMissionData &md) { + string ret = ""; if (!_MissionName.empty()) - return "spawn_mission : " + _MissionName + " : " + _GiverName + NL; - else - return string(); + { + ret = "spawn_mission : " + _MissionName + " : " + _GiverName; + if (_Guild) + ret += " : guild"; + ret += NL; + } + return ret; } - }; REGISTER_STEP_CONTENT(CActionSpawnMission, "spawn_mission"); @@ -590,6 +685,7 @@ class CActionRecvFame : public IStepContent { string _Faction; string _Fame; + bool _Guild; void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -602,12 +698,27 @@ public: _Faction = md.getProperty(prim, "faction", true, false); _Fame = md.getProperty(prim, "value", true, false); + + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } } string genCode(CMissionData &md) { if (!_Faction.empty() && !_Fame.empty()) - return string("recv_fame : ")+_Faction+" "+_Fame+NL; + { + string ret; + ret = "recv_fame : "+_Faction+" "+_Fame; + if (_Guild) + ret += ": guild"; + ret += NL; + return ret; + } else return string(); } @@ -628,6 +739,7 @@ class CActionRecvItem : public IStepContent vector _Items; bool _QualSpec; bool _Group; + bool _Guild; void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -675,6 +787,13 @@ public: s = md.getProperty(prim, "group", true, false); _Group = (NLMISC::toLower(s) == "true"); + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } IStepContent::init(md, prim); } @@ -693,6 +812,8 @@ public: ret += " : "+_BotGiver; if (_Group) ret += " : group"; + if (_Guild) + ret += ": guild"; ret += NL; } @@ -707,6 +828,7 @@ class CActionRecvNamedItem : public IStepContent { vector _Items; bool _Group; + bool _Guild; void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -743,6 +865,14 @@ public: s = md.getProperty(prim, "group", true, false); _Group = (NLMISC::toLower(s) == "true"); + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } + IStepContent::init(md, prim); } @@ -756,6 +886,8 @@ public: ret += "recv_named_item : "+item.ItemName+" "+item.ItemQuant; if (_Group) ret += " : group"; + if (_Guild) + ret += ": guild"; ret += NL; } @@ -777,6 +909,7 @@ class CActionDestroyItem : public IStepContent string _BotDestroyer; vector _Items; + bool _Guild; void getPredefParam(uint32 &numEntry, CPhrase::TPredefParams &predef) { @@ -821,6 +954,14 @@ public: _Items.push_back(item); } } + + _Guild = md.getProperty(prim, "guild", false, true) == "true"; + // Check: if _Guild is true then check if we are in a guild mission + if (_Guild && !md.isGuildMission()) + { + string err = toString("primitive(%s): 'guild' option true 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + } IStepContent::init(md, prim); } @@ -839,6 +980,8 @@ public: ret +=" "+item.Desc.ItemQual; if (!_BotDestroyer.empty()) ret += " : "+_BotDestroyer; + if (_Guild) + ret += ": guild"; ret += NL; } @@ -1630,6 +1773,20 @@ void CContentObjective::init(CMissionData &md, IPrimitive *prim) _OverloadPhrase.initPhrase(md, prim, _OverloadObj, numEntry, params); // init the roleplay phrase _RoleplayPhrase.initPhrase(md, prim, _RoleplayObj, numEntry, params); + + // check for the 'nb_guild_members_needed' option and see if it's correct for this mission + /*string nbGuildMembersNeeded = md.getProperty(prim, "nb_guild_members_needed", false, true); + if (nbGuildMembersNeeded.empty()) + nbGuildMembersNeeded = "1"; + if (!fromString(nbGuildMembersNeeded.c_str(), _NbGuildMembersNeeded)) + _NbGuildMembersNeeded = 1; + + // Check: + if (!md.isGuildMission() && _NbGuildMembersNeeded != 1) + { + string err = toString("primitive(%s): nb_guild_members_needed != 1 for non guild mission.", prim->getName().c_str()); + throw EParseException(prim, err.c_str()); + }*/ } // --------------------------------------------------------------------------- @@ -1649,6 +1806,20 @@ string CContentObjective::genCode(CMissionData &md) return ret; } +// --------------------------------------------------------------------------- +/*std::string CContentObjective::genNbGuildMembersNeededOption(CMissionData &md) +{ + string ret = ""; + // If we are in a guild mission we add the 'nb_guild_members_needed' option to the script + if (md.isGuildMission()) + { + ret = ": nb_guild_members_needed "; + ret += toString(_NbGuildMembersNeeded); + } + + return ret; +}*/ + // --------------------------------------------------------------------------- string CContentObjective::genPhrase() { @@ -1949,6 +2120,9 @@ public: if (!_Place.empty()) ret += " : "+_Place; + + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2004,6 +2178,8 @@ public: if (!_Phrase.isEmpty()) ret += " : "+_Phrase.genScript(md); + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2078,6 +2254,8 @@ public: { ret += ": "+_Place; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2151,6 +2329,8 @@ public: if (i < _Mps.size()-1) ret += "; "; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2276,6 +2456,8 @@ public: if (i < _Items.size()-1) ret += "; "; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2349,6 +2531,8 @@ public: if (i < _Items.size()-1) ret += "; "; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2479,7 +2663,8 @@ public: if (!_Place.empty()) ret += " : " + _Place; - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2564,6 +2749,8 @@ public: { ret += " : "+_Npc; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2645,6 +2832,8 @@ public: { ret += " : "+_Npc; } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2755,7 +2944,10 @@ public: if (i < _Items.size()-1) ret += "; "; }; - ret += " : "+_Npc +NL; + ret += " : "+_Npc; + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); + ret += NL; return ret; } @@ -2790,7 +2982,10 @@ public: string ret; ret = CContentObjective::genCode(md); - ret += "give_money : "+_Amount+" : "+_Npc+NL; + ret += "give_money : "+_Amount+" : "+_Npc; + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); + ret += NL; return ret; } @@ -2841,7 +3036,8 @@ public: ret += "; "; } } - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2877,7 +3073,8 @@ public: if (_SaveAll) ret += " : save_all"; - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2950,7 +3147,8 @@ public: if (i < _Skills.size()-1) ret += "; "; } - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -2968,9 +3166,12 @@ class CContentMission: public CContentObjective } public: + CContentMission(): _Prim(0) {} + void init(CMissionData &md, IPrimitive *prim) { _Missions = md.getPropertyArray(prim, "mission_names", true, false); + _Prim = prim; CContentObjective::init(md, prim); } @@ -2987,12 +3188,23 @@ public: ret += _Missions[i]; if (i < _Missions.size()-1) ret += "; "; - } + // We check to see if we specified a number after the mission name. If so, we check if it's a guild mission + std::size_t pos = _Missions[i].find_first_of(" \t"); + if (pos != std::string::npos && !md.isGuildMission()) + { + string err = toString("primitive(%s): CContentMission: Number of members needed to complete the mission specified but the mission is not a guild mission.", _Prim->getName().c_str()); + throw EParseException(_Prim, err.c_str()); + } + } + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; } + + IPrimitive *_Prim; }; REGISTER_STEP_CONTENT(CContentMission, "do_mission"); @@ -3026,7 +3238,8 @@ public: if (i < _MsgContent.size()-1) ret += " "; } - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret; @@ -3242,7 +3455,8 @@ public: ret += "ring_scenario : "; ret += _ScenarioTag; - + // Add the 'nb_guild_members_needed' parameter if needed + //ret += CContentObjective::genNbGuildMembersNeededOption(md); ret += NL; return ret;