// ====================================================================== // // GroupObject.cpp // // Copyright 2002 Sony Online Entertainment // // ====================================================================== #include "serverGame/FirstServerGame.h" #include "serverGame/GroupObject.h" #include "UnicodeUtils.h" #include "serverGame/Chat.h" #include "serverGame/ConfigServerGame.h" #include "serverGame/ContainerInterface.h" #include "serverGame/CreatureObject.h" #include "serverGame/GameServer.h" #include "serverGame/GroupController.h" #include "serverGame/GroupMissionCriticalObjectsBuilder.h" #include "serverGame/GroupWaypointBuilder.h" #include "serverGame/GroupStringId.h" #include "serverGame/ObjectTracker.h" #include "serverGame/ObserveTracker.h" #include "serverGame/PlayerCreatureController.h" #include "serverGame/PlayerObject.h" #include "serverGame/GroupUpdateObserver.h" #include "serverGame/ServerGroupObjectTemplate.h" #include "serverGame/ServerWorld.h" #include "serverGame/ServerUniverse.h" #include "serverGame/ShipObject.h" #include "serverScript/GameScriptObject.h" #include "serverScript/ScriptParameters.h" #include "serverNetworkMessages/GroupMemberParam.h" #include "sharedFoundation/ConstCharCrcLowerString.h" #include "sharedFoundation/Crc.h" #include "sharedFoundation/GameControllerMessage.h" #include "sharedGame/ProsePackage.h" #include "sharedGame/SharedObjectTemplate.h" #include "sharedLog/Log.h" #include "sharedObject/Controller.h" #include "sharedObject/ObjectTemplateList.h" #include "sharedObject/NetworkIdManager.h" #include "sharedObject/SlotIdManager.h" #include "sharedObject/SlottedContainer.h" #include "sharedObject/VolumeContainer.h" #include "sharedNetworkMessages/MessageQueueGenericValueType.h" // ====================================================================== SharedObjectTemplate const *GroupObject::m_defaultSharedTemplate = 0; // ====================================================================== namespace GroupObjectNamespace { // ---------------------------------------------------------------------- unsigned int const cs_maximumNumberInGroup = 8; char const * const DEFAULT_GROUP_TEMPLATE = "object/group/group.iff"; std::map s_leaderMap; static const std::string cs_emptyString; // ---------------------------------------------------------------------- std::string const &getChatRoomPrefix() { static std::string prefix = std::string("SWG.") + GameServer::getInstance().getClusterName() + ".group."; return prefix; } // ---------------------------------------------------------------------- std::string const &getChatRoomSuffix() { static std::string suffix(".GroupChat"); return suffix; } // ---------------------------------------------------------------------- } using namespace GroupObjectNamespace; // ====================================================================== GroupObject::GroupObject(ServerGroupObjectTemplate const *newTemplate) : UniverseObject(newTemplate), m_groupName(), m_groupMembers(), m_groupShipFormationMembers(), m_groupPOBShipAndOwners(), m_groupLevel(), m_groupMemberLevels(), m_groupMemberProfessions(), m_formationNameCrc(Crc::crcNull), m_allMembers(), m_nonPCMembers(), m_lootMaster(), m_lootRule(0), m_groupPickupTimer(std::make_pair(0, 0)), m_groupPickupLocation(std::make_pair("", Vector())) { m_groupMembers.setSourceObject(this); m_groupShipFormationMembers.setSourceObject(this); m_groupPOBShipAndOwners.setSourceObject(this); m_lootMaster.setSourceObject(this); addMembersToPackages(); ObjectTracker::addGroupObject(); } // ---------------------------------------------------------------------- GroupObject::~GroupObject() { if (!GameServer::getInstance().getDone()) { for (GroupMemberVector::const_iterator i = m_groupMembers.begin(); i != m_groupMembers.end(); ++i) onGroupMemberRemoved((*i).first, true); } if (isInWorld()) removeFromWorld(); ObjectTracker::removeGroupObject(); } // ---------------------------------------------------------------------- Controller* GroupObject::createDefaultController() { Controller* controller = new GroupController(this); setController(controller); return controller; } // ---------------------------------------------------------------------- bool GroupObject::isVisibleOnClient(const Client &) const { // Group objects are visible to all clients which are observing them, just which clients observe them // are strictly managed to assure this. See GroupUpdateObserver for how this is done. return true; } // ---------------------------------------------------------------------- /** * Returns a shared template if none was given for this object. * * @return the shared template */ const SharedObjectTemplate * GroupObject::getDefaultSharedTemplate() const { static const ConstCharCrcLowerString templateName("object/group/base/shared_group_default.iff"); if (!m_defaultSharedTemplate) { m_defaultSharedTemplate = safe_cast(ObjectTemplateList::fetch(templateName)); WARNING_STRICT_FATAL(!m_defaultSharedTemplate, ("Cannot create default shared object template %s", templateName.getString())); if (m_defaultSharedTemplate) ExitChain::add(removeDefaultTemplate, "GroupObject::removeDefaultTemplate"); } return m_defaultSharedTemplate; } // ---------------------------------------------------------------------- /** * Cleans up the default shared template. */ void GroupObject::removeDefaultTemplate() { if (!m_defaultSharedTemplate) { m_defaultSharedTemplate->releaseReference(); m_defaultSharedTemplate = 0; } } // ---------------------------------------------------------------------- void GroupObject::addToLeaderMap(NetworkId const &leaderId, NetworkId const &groupId) // static { s_leaderMap[leaderId] = groupId; } // ---------------------------------------------------------------------- void GroupObject::removeFromLeaderMap(NetworkId const &leaderId, NetworkId const &groupId) // static { std::map::iterator i = s_leaderMap.find(leaderId); if (i != s_leaderMap.end() && (*i).second == groupId) s_leaderMap.erase(i); } // ---------------------------------------------------------------------- NetworkId GroupObject::getGroupIdForLeader(NetworkId const &leaderId) // static { NetworkId groupId = NetworkId::cms_invalid; std::map::iterator i = s_leaderMap.find(leaderId); if (i != s_leaderMap.end()) groupId = (*i).second; return groupId; } // ---------------------------------------------------------------------- void GroupObject::createAllGroupChatRooms() // static { if (ServerUniverse::getInstance().isAuthoritative()) { for (std::map::const_iterator i = s_leaderMap.begin(); i != s_leaderMap.end(); ++i) { ServerObject const * const so = safe_cast(NetworkIdManager::getObjectById((*i).second)); if (so) { GroupObject const * const groupObject = so->asGroupObject(); if (groupObject) groupObject->createGroupChatRoom(); } } } } // ---------------------------------------------------------------------- int GroupObject::maximumMembersInGroup() { return cs_maximumNumberInGroup; } // ---------------------------------------------------------------------- void GroupObject::createGroup(GroupMemberParam const & leader, GroupMemberParamVector const & members) { // If the leader already is leading a group, treat this as the specified member joining instead. GroupObject *group = 0; { std::map::const_iterator i = s_leaderMap.find(leader.m_memberId); if (i != s_leaderMap.end()) { Object *groupObj = NetworkIdManager::getObjectById((*i).second); if (groupObj) { ServerObject *groupServerObj = groupObj->asServerObject(); if (groupServerObj) group = groupServerObj->asGroupObject(); } } } if (!group) { group = safe_cast(ServerWorld::createNewObject(DEFAULT_GROUP_TEMPLATE, Transform::identity, 0, false)); group->addToWorld(); group->addGroupMember(leader); group->makeLootMaster(leader.m_memberId); } int const numberOfMembers = static_cast(members.size()); for (int i = 0; i < numberOfMembers; ++i) { group->addGroupMember(members[i]); } } // ---------------------------------------------------------------------- void GroupObject::setupUniverse() { } // ---------------------------------------------------------------------- void GroupObject::getGroupMemberIds(std::vector &members) const { for (GroupMemberVector::const_iterator i = m_groupMembers.begin(); i != m_groupMembers.end(); ++i) members.push_back((*i).first); } // ---------------------------------------------------------------------- NetworkId const &GroupObject::getGroupLeaderId() const { if (m_groupMembers.size()) return (*m_groupMembers.begin()).first; return NetworkId::cms_invalid; } // ---------------------------------------------------------------------- std::string const &GroupObject::getGroupLeaderName() const { static std::string nullStr; if (m_groupMembers.size()) return (*m_groupMembers.begin()).second; return nullStr; } // ---------------------------------------------------------------------- bool GroupObject::isGroupFull() const { return m_groupMembers.size() == cs_maximumNumberInGroup; } // ---------------------------------------------------------------------- int GroupObject::getPCMemberCount() const { if (m_groupMembers.size() > m_nonPCMembers.size()) return static_cast(m_groupMembers.size() - m_nonPCMembers.size()); return 0; } // ---------------------------------------------------------------------- bool GroupObject::isMemberPC(NetworkId const & memberId) const { return !m_nonPCMembers.contains(memberId); } // ---------------------------------------------------------------------- bool GroupObject::doesGroupHaveRoomFor(int additionalMembers) const { additionalMembers = std::max(0, additionalMembers); return (m_groupMembers.size() + additionalMembers) <= cs_maximumNumberInGroup; } // ---------------------------------------------------------------------- void GroupObject::makeLeader(NetworkId const &newLeaderId) { if (!isMemberPC(newLeaderId)) { return; } if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_groupMakeLeader, 0.0f, new MessageQueueGenericValueType(newLeaderId), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { // swap the specified person with the first person in the group for (unsigned int pos = 1; pos < m_groupMembers.size(); ++pos) { if (m_groupMembers.get(pos).first == newLeaderId) { GroupUpdateObserver updater(this, Archive::ADOO_generic); GroupMember tempMember = m_groupMembers.get(pos); m_groupMembers.set(pos, m_groupMembers.get(0)); m_groupMembers.set(0, tempMember); int16 tempMemberLevel = m_groupMemberLevels.get(pos); m_groupMemberLevels.set(pos, m_groupMemberLevels.get(0)); m_groupMemberLevels.set(0, tempMemberLevel); uint8 tempMemberProfession = m_groupMemberProfessions.get(pos); m_groupMemberProfessions.set(pos, m_groupMemberProfessions.get(0)); m_groupMemberProfessions.set(0, tempMemberProfession); GroupShipFormationMember tempMemberShip = m_groupShipFormationMembers.get(pos); m_groupShipFormationMembers.set(pos, m_groupShipFormationMembers.get(0)); m_groupShipFormationMembers.set(0, tempMemberShip); break; } } } } // ---------------------------------------------------------------------- void GroupObject::setGroupName(std::string const &groupName) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_groupSetName, 0.0f, new MessageQueueGenericValueType(groupName), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { m_groupName = groupName; } } // ---------------------------------------------------------------------- void GroupObject::addGroupMember(GroupMemberParam const & member) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_groupAddMember, 0.0f, new MessageQueueGenericValueType(member), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { if (isGroupFull()) { Chat::sendSystemMessage(member.m_memberName, GroupStringId::SID_GROUP_JOIN_FULL, Unicode::String()); return; } // Don't try to add someone if they are already a member if (isGroupMember(member.m_memberId)) { return; } GroupUpdateObserver updater(this, Archive::ADOO_generic); m_groupMembers.push_back(std::make_pair(member.m_memberId, member.m_memberName)); m_allMembers.insert(member.m_memberId); if (!member.m_memberIsPC) m_nonPCMembers.insert(member.m_memberId); m_groupShipFormationMembers.push_back(std::make_pair(member.m_memberShipId, m_groupShipFormationMembers.size())); if ((member.m_memberShipId.isValid()) && (member.m_memberShipIsPOB) && (member.m_memberOwnsPOB)) { bool POBShipIsAdded = false; int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].first == member.m_memberShipId) { POBShipIsAdded = true; } } if (!POBShipIsAdded) { m_groupPOBShipAndOwners.push_back(std::make_pair(member.m_memberShipId, member.m_memberId)); } } m_groupMemberLevels.push_back(static_cast(member.m_memberDifficulty)); m_groupMemberProfessions.push_back(static_cast(member.m_memberProfession)); calcGroupLevel(); if (m_groupMembers.size() == 1) createGroupChatRoom(); addToGroupChatRoom(member.m_memberName); addToGroupVoiceChatRoom(member.m_memberId, member.m_memberName); } } // ---------------------------------------------------------------------- GroupMemberParam const GroupObject::createGroupMemberParamForMember(NetworkId const & memberId) const { std::string const & memberName = getMemberName(memberId); int const memberLevel = getMemberLevel(memberId); LfgCharacterData::Profession const memberProfession = static_cast(getMemberProfession(memberId)); bool const memberIsPC = !m_nonPCMembers.contains(memberId); NetworkId const & memberShipId = getMemberShip(memberId); bool const memberShipIsPOB = memberShipId.isValid() && getShipIsPOB(memberShipId); bool const memberOwnsPOB = memberShipId.isValid() && memberShipId == getPOBShipOwnedByMember(memberId); return GroupMemberParam(memberId, memberName, memberLevel, memberProfession, memberIsPC, memberShipId, memberShipIsPOB, memberOwnsPOB); } // ---------------------------------------------------------------------- void GroupObject::removeGroupMember(NetworkId const &memberId) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_groupRemoveMember, 0.0f, new MessageQueueGenericValueType(memberId), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { GroupUpdateObserver updater(this, Archive::ADOO_generic); for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { GroupMember const & member = m_groupMembers.get(i); if (member.first == memberId) { removeFromGroupChatRoom(member.second); removeFromGroupVoiceChatRoom(memberId, member.second); m_groupMembers.erase(i); m_allMembers.erase(memberId); m_nonPCMembers.erase(memberId); m_groupShipFormationMembers.erase(i); m_groupMemberLevels.erase(i); m_groupMemberProfessions.erase(i); calcGroupLevel(); for (unsigned int j = 0; j < m_groupPOBShipAndOwners.size(); ++j) { if (m_groupPOBShipAndOwners.get(j).second == memberId) { m_groupPOBShipAndOwners.erase(j); break; } } break; } } if (m_groupMembers.size() < 2) { disbandGroup(); } else { NetworkId firstNonPet = getGroupLeaderId(); if (!isMemberPC(firstNonPet)) { unsigned int const numberOfGroupMembers = m_groupMembers.size(); for (unsigned int i = 1; i < numberOfGroupMembers; ++i) { if (isMemberPC(m_groupMembers.get(i).first)) { firstNonPet = m_groupMembers.get(i).first; break; } } if (isMemberPC(firstNonPet)) { makeLeader(firstNonPet); } } if (getLootMasterId() == memberId) { m_lootMaster = getGroupLeaderId(); } } } } // ---------------------------------------------------------------------- void GroupObject::disbandGroup() { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_groupDisband, 0.0f, 0, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else if (!getKill()) { for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { GroupMember const & member = m_groupMembers.get(i); removeFromGroupVoiceChatRoom(member.first, member.second); } permanentlyDestroy(DeleteReasons::Player); m_groupMembers.clear(); m_allMembers.clear(); m_nonPCMembers.clear(); m_groupShipFormationMembers.clear(); m_groupPOBShipAndOwners.clear(); destroyGroupChatRoom(); } } // ---------------------------------------------------------------------- std::string GroupObject::getChatRoomPath() const { return getChatRoomPrefix() + getNetworkId().getValueString() + getChatRoomSuffix(); } // ---------------------------------------------------------------------- std::string GroupObject::getVoiceChatDisplayName() const { static std::string displayName("GroupChat"); return displayName; } // ---------------------------------------------------------------------- std::string GroupObject::getChatName(std::string const &memberName) const { std::string firstName; size_t pos = 0; Unicode::getFirstToken(memberName, 0, pos, firstName); return firstName; } // ---------------------------------------------------------------------- void GroupObject::createGroupChatRoom() const { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("Creating group chat room %s (group id %s)", getChatRoomPath().c_str(), getNetworkId().getValueString().c_str())); Chat::createRoom("System", false, getChatRoomPath(), getNetworkId().getValueString()); //TODO: temporary separation of voice and text Chat::requestGetChannel(getChatRoomPath(), getVoiceChatDisplayName()); } // ---------------------------------------------------------------------- void GroupObject::destroyGroupChatRoom() const { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("Destroying group chat room %s (group id %s)", getChatRoomPath().c_str(), getNetworkId().getValueString().c_str())); Chat::destroyRoom(getChatRoomPath()); Chat::requestDestroyChannel(getChatRoomPath()); } // ---------------------------------------------------------------------- bool GroupObject::chatRoomCreated() const { return hasAttributeAttained(1); } // ---------------------------------------------------------------------- void GroupObject::setChatRoomCreated() { setAttributeAttained(1); } // ---------------------------------------------------------------------- void GroupObject::addToGroupChatRoom(std::string const &memberName) const { // note: if the room has not already been created, everyone will be added when the notification of its creation arrives. if (chatRoomCreated() && memberName.find("(") == std::string::npos) { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("Invite and enter: member %s (group id %s), chat room %s", getChatName(memberName).c_str(), getNetworkId().getValueString().c_str(), getChatRoomPath().c_str())); Chat::invite(getChatName(memberName), getChatRoomPath()); Chat::enterRoom(getChatName(memberName), getChatRoomPath(), false, false); } } // ---------------------------------------------------------------------- void GroupObject::addToGroupVoiceChatRoom(NetworkId const & memberId, std::string const & memberName) const { //TODO: temporary separation of voice and text Chat::requestAddClientToChannel(memberId, getChatName(memberName), getChatRoomPath(), true); } // ---------------------------------------------------------------------- void GroupObject::removeFromGroupChatRoom(std::string const &memberName) const { if (memberName.find("(") == std::string::npos) { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("Exit and uninvite: member %s (group id %s), chat room %s", getChatName(memberName).c_str(), getNetworkId().getValueString().c_str(), getChatRoomPath().c_str())); Chat::exitRoom(getChatName(memberName), getChatRoomPath()); Chat::uninvite(getChatName(memberName), getChatRoomPath()); } } // ---------------------------------------------------------------------- void GroupObject::removeFromGroupVoiceChatRoom(NetworkId const & memberId, std::string const & memberName) const { //TODO: temporary separation of voice and text Chat::requestRemoveClientFromChannel(memberId, memberName, getChatRoomPath()); } // ---------------------------------------------------------------------- void GroupObject::sendGroupChat(NetworkId const &memberId, Unicode::String const &text) const { bool sent = false; for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { if (m_groupMembers.get(i).first == memberId) { sent = true; if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("sendGroupChat: member %s (group id %s), chat room %s, text %s", getChatName(m_groupMembers.get(i).second).c_str(), getNetworkId().getValueString().c_str(), getChatRoomPath().c_str(), Unicode::wideToNarrow(text).c_str())); Chat::sendToRoom(getChatName(m_groupMembers.get(i).second), getChatRoomPath(), text, Unicode::String()); } } if (!sent && ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("sendGroupChat could not find member id %s (group id %s)", memberId.getValueString().c_str(), getNetworkId().getValueString().c_str())); } // ---------------------------------------------------------------------- void GroupObject::onGroupChatRoomCreated() { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("group chat room created (group id %s)", getNetworkId().getValueString().c_str())); setChatRoomCreated(); for (unsigned int i = 0; i < m_groupMembers.size(); ++i) addToGroupChatRoom(m_groupMembers.get(i).second); } // ---------------------------------------------------------------------- void GroupObject::onGroupVoiceChatRoomCreated() { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("group voice chat room created (group id %s)", getNetworkId().getValueString().c_str())); for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { GroupMember const & member = m_groupMembers.get(i); addToGroupVoiceChatRoom(member.first, member.second); } } // ---------------------------------------------------------------------- void GroupObject::onChatRoomCreate(std::string const &path) // static { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("onChatRoomCreate (%s)", path.c_str())); std::string const &prefix = getChatRoomPrefix(); // is it a group channel? if (!path.compare(0, prefix.length(), prefix)) { // it's a group channel, so extract the networkId NetworkId id(path.substr(prefix.length(), path.length()-prefix.length()-getChatRoomSuffix().length())); Object *obj = NetworkIdManager::getObjectById(id); if (obj) { ServerObject *serverObject = obj->asServerObject(); if (serverObject) { GroupObject *groupObject = serverObject->asGroupObject(); if (groupObject && groupObject->isAuthoritative()) groupObject->onGroupChatRoomCreated(); } } } } // ---------------------------------------------------------------------- void GroupObject::onVoiceChatRoomCreate(std::string const &name) // static { if (ConfigServerGame::getDebugGroupChat()) LOG("GroupChat", ("onVoiceChatRoomCreate (%s)", name.c_str())); std::string const &prefix = getChatRoomPrefix(); // is it a group channel? if (!name.compare(0, prefix.length(), prefix)) { // it's a group channel, so extract the networkId std::string strid = name.substr(prefix.length()); NetworkId id(strid); Object *obj = NetworkIdManager::getObjectById(id); if (obj) { ServerObject *serverObject = obj->asServerObject(); if (serverObject) { GroupObject *groupObject = serverObject->asGroupObject(); if (groupObject && groupObject->isAuthoritative()) groupObject->onGroupVoiceChatRoomCreated(); } } } } // ---------------------------------------------------------------------- void GroupObject::getAttributes(stdvector >::fwd &data) const { UniverseObject::getAttributes(data); } // ---------------------------------------------------------------------- void GroupObject::calcGroupLevel() { FATAL(!isAuthoritative(), ("calcGroupLevel called on nonauth group")); int maxPlayerLevel = 0; int groupLevel = 0; const unsigned int numMembers = m_groupMembers.size(); if (numMembers > 0) { for (unsigned int i = 0; i < numMembers; ++i) { if (isMemberPC(m_groupMembers.get(i).first)) { const int memberLevel = m_groupMemberLevels.get(i); maxPlayerLevel = (maxPlayerLevel < memberLevel) ? memberLevel : maxPlayerLevel; } } groupLevel = maxPlayerLevel; } m_groupLevel = static_cast(groupLevel); } // ---------------------------------------------------------------------- void GroupObject::setMemberLevel(NetworkId const &memberId, int memberLevel) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_setGroupMemberDifficulty, 0.0f, new MessageQueueGenericValueType >(std::make_pair(memberId, memberLevel)), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { if (m_groupMembers.get(i).first == memberId) { m_groupMemberLevels.set(i, static_cast(memberLevel)); calcGroupLevel(); } } } } // ---------------------------------------------------------------------- void GroupObject::setMemberProfession(NetworkId const &memberId, uint8 profession) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_setGroupMemberProfession, 0.0f, new MessageQueueGenericValueType >(std::make_pair(memberId, static_cast(profession))), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { for (unsigned int i = 0; i < m_groupMembers.size(); ++i) { if (m_groupMembers.get(i).first == memberId) { m_groupMemberProfessions.set(i, profession); } } } } // ---------------------------------------------------------------------- void GroupObject::onGroupMemberConnect(NetworkId const &memberId) { // try to add them to the group chat room again for (unsigned int i = 0; i < m_groupMembers.size(); ++i) if (m_groupMembers.get(i).first == memberId) { GroupMember const & member = m_groupMembers.get(i); addToGroupChatRoom(member.second); addToGroupVoiceChatRoom(member.first, member.second); } } // ---------------------------------------------------------------------- GroupObject *GroupObject::asGroupObject() { return this; } // ---------------------------------------------------------------------- GroupObject const *GroupObject::asGroupObject() const { return this; } // ---------------------------------------------------------------------- void GroupObject::onGroupMemberRemoved(NetworkId const &memberId, bool disbanding) { // have removed members with clients unobserve the group object, clear their group id, and get remove or disband messages Object *o = NetworkIdManager::getObjectById(memberId); if (o) { ServerObject *so = o->asServerObject(); if (so) { CreatureObject *creature = so->asCreatureObject(); if (creature && creature->isAuthoritative()) { if (creature->getGroup() == this) { if (creature->getScriptObject()) { ScriptParams scriptParams; scriptParams.addParam(getNetworkId()); IGNORE_RETURN(creature->getScriptObject()->trigAllScripts(Scripting::TRIG_REMOVED_FROM_GROUP, scriptParams)); if (disbanding) { IGNORE_RETURN(creature->getScriptObject()->trigAllScripts(Scripting::TRIG_GROUP_DISBANDED, scriptParams)); } } creature->setGroup(0, disbanding); Client *client = creature->getClient(); if (client) { ObserveTracker::onClientLeftGroup(*client, *this); ProsePackage pp; pp.stringId = disbanding ? GroupStringId::SID_GROUP_DISBANDED : GroupStringId::SID_GROUP_REMOVED; Chat::sendSystemMessage(*creature, pp); } //-- Update just the creature. The group will be updated in ~GroupMemberObserver GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*creature, false); if (creature->isPlayerControlled()) { PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creature); if (playerObject) GroupWaypointBuilder::updateGroupWaypoints(*playerObject, false); } } } } } } // ---------------------------------------------------------------------- void GroupObject::setFormationNameCrc(uint32 const formationNameCrc) { m_formationNameCrc.set(formationNameCrc); } // ---------------------------------------------------------------------- void GroupObject::setShipForMember(NetworkId const & memberId, NetworkId const & shipId) { if (isAuthoritative()) { FATAL((m_groupMembers.size() != m_groupShipFormationMembers.size()), ("GroupObject::setShipForMember: m_groupMembers should always be the same size as m_groupShipFormationMembers")); int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == memberId) { GroupShipFormationMember data = m_groupShipFormationMembers[i]; data.first = shipId; m_groupShipFormationMembers.set(i, data); return; } } } else { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_setGroupShipForMember, 0.0f, new MessageQueueGenericValueType >(std::make_pair(memberId, shipId)), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } } // ---------------------------------------------------------------------- void GroupObject::setShipFormationSlotForMember(NetworkId const & memberId, int const formationSlot) { if (isAuthoritative()) { FATAL((m_groupMembers.size() != m_groupShipFormationMembers.size()), ("GroupObject::setShipForMember: m_groupMembers should always be the same size as m_groupShipFormationMembers")); int const numberOfGroupMembers = m_groupMembers.size(); int previousFormationSlotOwnerIndex = -1; int newFormationSlotOwnerIndex = -1; for (int i = 0; i < numberOfGroupMembers; ++i) { // find the previous owner of this slot if (m_groupShipFormationMembers[i].second == formationSlot) { previousFormationSlotOwnerIndex = i; } // find the next owner of this slot if (m_groupMembers[i].first == memberId) { newFormationSlotOwnerIndex = i; } } // set the previous owner's slot to the current member's slot // and then set the member's slot to the new value. // since we always set the slot values in ::addGroupMember // we can just swap the slots to keep someone from sitting // in 2 slots at the same time. if (newFormationSlotOwnerIndex > -1) { GroupShipFormationMember data = m_groupShipFormationMembers[newFormationSlotOwnerIndex]; int const slotToSwapOccupantTo = data.second; data.second = formationSlot; m_groupShipFormationMembers.set(newFormationSlotOwnerIndex, data); if (previousFormationSlotOwnerIndex > -1) { GroupShipFormationMember previousData = m_groupShipFormationMembers[previousFormationSlotOwnerIndex]; previousData.second = slotToSwapOccupantTo; m_groupShipFormationMembers.set(previousFormationSlotOwnerIndex, previousData); } } } else { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_setGroupShipFormationSlotForMember, 0.0f, new MessageQueueGenericValueType >(std::make_pair(memberId, formationSlot)), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } } // ---------------------------------------------------------------------- void GroupObject::addPOBShipAndOwner(NetworkId const & shipId, NetworkId const & ownerId) { if (isAuthoritative()) { // make sure that the POB ship isn't already in the list int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].first == shipId) { if (m_groupPOBShipAndOwners[i].second != ownerId) { GroupPOBShipAndOwner data = m_groupPOBShipAndOwners[i]; data.second = ownerId; m_groupPOBShipAndOwners.set(i, data); } return; } } // add if doesn't exist m_groupPOBShipAndOwners.push_back(std::make_pair(shipId, ownerId)); } else { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_addGroupPOBShipAndOwner, 0.0f, new MessageQueueGenericValueType >(std::make_pair(shipId, ownerId)), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } } // ---------------------------------------------------------------------- void GroupObject::removePOBShip(NetworkId const & shipId) { if (isAuthoritative()) { int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].first == shipId) { m_groupPOBShipAndOwners.erase(i); break; } } } else { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_removeGroupPOBShip, 0.0f, new MessageQueueGenericValueType(shipId), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } } // ---------------------------------------------------------------------- NetworkId const & GroupObject::getPOBShipOwnedByMember(NetworkId const & memberId) const { int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].second == memberId) { return m_groupPOBShipAndOwners[i].first; } } return NetworkId::cms_invalid; } // ---------------------------------------------------------------------- NetworkId const & GroupObject::getPOBShipMemberIsContainedIn(NetworkId const & memberId) const { NetworkId const & shipId = getMemberShip(memberId); if (shipId.isValid()) { int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].first == shipId) { return shipId; } } } return NetworkId::cms_invalid; } // ---------------------------------------------------------------------- NetworkId const & GroupObject::getMemberShip(NetworkId const & memberId) const { int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == memberId) { return m_groupShipFormationMembers[i].first; } } return NetworkId::cms_invalid; } // ---------------------------------------------------------------------- std::string const & GroupObject::getMemberName(NetworkId const & memberId) const { int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == memberId) { return m_groupMembers.get(i).second; } } return cs_emptyString; } // ---------------------------------------------------------------------- int GroupObject::getMemberLevel(NetworkId const & memberId) const { int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == memberId) { return m_groupMemberLevels.get(i); } } return 0; } // ---------------------------------------------------------------------- int GroupObject::getMemberLevelByMemberIndex(unsigned int memberIndex) const { if (memberIndex < m_groupMembers.size()) return m_groupMemberLevels.get(memberIndex); return 0; } // ---------------------------------------------------------------------- uint8 GroupObject::getMemberProfession(NetworkId const & memberId) const { int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == memberId) { return m_groupMemberProfessions.get(i); } } return static_cast(LfgCharacterData::Prof_Unknown); } // ---------------------------------------------------------------------- uint8 GroupObject::getMemberProfessionByMemberIndex(unsigned int memberIndex) const { if (memberIndex < m_groupMembers.size()) return m_groupMemberProfessions.get(memberIndex); return static_cast(LfgCharacterData::Prof_Unknown); } // ---------------------------------------------------------------------- bool GroupObject::getShipIsPOB(NetworkId const & shipId) const { int const numberOfGroupPOBShipAndOwners = m_groupPOBShipAndOwners.size(); for (int i = 0; i < numberOfGroupPOBShipAndOwners; ++i) { if (m_groupPOBShipAndOwners[i].first == shipId) { return true; } } return false; } // ---------------------------------------------------------------------- NetworkId const & GroupObject::getLootMasterId() const { return m_lootMaster.get(); } // ---------------------------------------------------------------------- void GroupObject::makeLootMaster(NetworkId const & newLootMasterId) { if (!isMemberPC(newLootMasterId)) { return; } if (!isAuthoritative()) { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_groupMakeLootMaster, 0.0f, new MessageQueueGenericValueType(newLootMasterId), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { GroupUpdateObserver updater(this, Archive::ADOO_generic); int const numberOfGroupMembers = m_groupMembers.size(); for (int i = 0; i < numberOfGroupMembers; ++i) { if (m_groupMembers[i].first == newLootMasterId) { m_lootMaster = newLootMasterId; break; } } } } // ---------------------------------------------------------------------- int GroupObject::getLootRule() const { return m_lootRule.get(); } // ---------------------------------------------------------------------- void GroupObject::setLootRule(int const rule) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller != 0) { controller->appendMessage( CM_groupSetLootRule, 0.0f, new MessageQueueGenericValueType(rule), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { m_lootRule = static_cast(rule); } } // ---------------------------------------------------------------------- unsigned int GroupObject::getSecondsLeftOnGroupPickup() const { std::pair const & groupPickupTimer = m_groupPickupTimer.get(); if ((groupPickupTimer.first > 0) && (groupPickupTimer.second > 0)) { time_t const timeNow = ::time(NULL); if (groupPickupTimer.second > timeNow) return (groupPickupTimer.second - (int)timeNow); } return 0; } // ---------------------------------------------------------------------- void GroupObject::setGroupPickupTimer(time_t startTime, time_t endTime) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_setGroupPickupTimer, 0.0f, new MessageQueueGenericValueType >(std::make_pair(static_cast(startTime), static_cast(endTime))), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { m_groupPickupTimer.set(std::make_pair(static_cast(startTime), static_cast(endTime))); } } // ---------------------------------------------------------------------- void GroupObject::setGroupPickupLocation(std::string const & planetName, Vector const & location) { if (!isAuthoritative()) { Controller *controller = getController(); if (controller) { controller->appendMessage( CM_setGroupPickupLocation, 0.0f, new MessageQueueGenericValueType >(std::make_pair(planetName, location)), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); } } else { m_groupPickupLocation.set(std::make_pair(planetName, location)); } } // ---------------------------------------------------------------------- void GroupObject::reenterGroupChatRoom(CreatureObject const &who) const { if (who.getGroup() != this) return; std::string firstName; size_t pos = 0; IGNORE_RETURN(Unicode::getFirstToken(Unicode::wideToNarrow(who.getObjectName()), 0, pos, firstName)); std::string const groupChatRoomPath = getChatRoomPath(); Chat::exitRoom(firstName, groupChatRoomPath); Chat::uninvite(firstName, groupChatRoomPath); Chat::invite(firstName, groupChatRoomPath); Chat::enterRoom(firstName, groupChatRoomPath, false, false); } // ======================================================================