/* * Group.h * Source file for groups * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Permission to use, modify and distribute is granted via the * Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License * http://creativecommons.org/licenses/by-nc-sa/3.0/ * * Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ // Mud includes #include "mud.h" #include "group.h" // C++ Includes #include <iomanip> //################################################################################ //# Group methods for groups //################################################################################ Group::Group(Creature* pLeader) { //if(pLeader.inGroup()) // throw(std::runtime_error("Error: Leader already in another group\n")); flags = 0; add(pLeader); leader = pLeader; groupType = GROUP_DEFAULT; if(pLeader->pFlagIsSet(P_XP_DIVIDE)) setFlag(GROUP_SPLIT_EXPERIENCE); if(pLeader->pFlagIsSet(P_GOLD_SPLIT)) setFlag(GROUP_SPLIT_GOLD); name = bstring(leader->getName()) + "'s group"; description = "A group, lead by " + bstring(leader->getName()); // Register us in the server's list of groups gServer->registerGroup(this); } Group::~Group() { // Unregister us from the server's list of groups removeAll(); gServer->unRegisterGroup(this); } //******************************************************************************** //* Add //******************************************************************************** // Adds a creature to the group, and adds his pets too if the addPets parameter // is set bool Group::add(Creature* newMember, bool addPets) { Group* oldGroup = newMember->getGroup(false); if(oldGroup && oldGroup != this) { oldGroup->remove(newMember); oldGroup = NULL; } // No adding someone twice if(!oldGroup) { newMember->setGroup(this); members.push_back(newMember); } if(addPets) { for(Monster* mons : newMember->pets) { add(mons); } } newMember->setGroupStatus(GROUP_MEMBER); return(true); } //******************************************************************************** //* remove //******************************************************************************** // Removes a creature from the group, adjusts leadership if necessary // and disbands the group if necessary // // Returns: true - The group was deleted and is no longer valid // false - The group still exists bool Group::remove(Creature* toRemove) { CreatureList::iterator it = std::find(members.begin(), members.end(), toRemove); if(it != members.end()) { toRemove->setGroup(NULL); toRemove->setGroupStatus(GROUP_NO_STATUS); // Iterator is invalid now, do not try to access it after this members.erase(it); // Remove any pets this player had in the group for(Monster* mons : toRemove->pets) { if(remove(mons)) return(true); } // See if the group should be disbanded if(this->getSize(false, false) <= 1) return(disband()); // We've already checked for a disband, now check for a leadership change if(toRemove == leader) { leader = this->getMember(1, false); // Something's wrong here if(!leader) { std::cout << "Couldn't find a replacement leader.\n"; return(disband()); } leader->setGroupStatus(GROUP_LEADER); leader->print("You are now the group leader.\n"); sendToAll(bstring(leader->getName()) + " is now the group leader.\n", leader); } } return(false); } //******************************************************************************** //* disband //******************************************************************************** // Removes all players from a group and deletes it bool Group::disband() { sendToAll("Your group has been disbanded.\n"); removeAll(); delete this; return(true); } //******************************************************************************** //* remove //******************************************************************************** // Removes all players from a group (but does not delete it) void Group::removeAll() { for(Creature* crt : members) { crt->setGroup(NULL); crt->setGroupStatus(GROUP_NO_STATUS); } members.clear(); } //******************************************************************************** //* size //******************************************************************************** // Returns the absolute size of the group int Group::size() { int count=0; for(Creature* crt : members) { if(crt->getGroupStatus() >= GROUP_MEMBER) count++; } return(count); } //******************************************************************************** //* getSize //******************************************************************************** // Parameters: countDmInvis - Should we count DM invis players or not? // membersOnly - Should we count only members, or include invited people as well // Returns: The number of players in the group int Group::getSize(bool countDmInvis, bool membersOnly) { int count=0; for(Creature* crt : members) { if((countDmInvis || !crt->pFlagIsSet(P_DM_INVIS)) && crt->isPlayer() && (crt->getGroupStatus() >= GROUP_MEMBER || ! membersOnly)) count++; } return(count); } //******************************************************************************** //* getNumInSameRoup //******************************************************************************** // Returns the number of group members in the same room as the target int Group::getNumInSameRoom(Creature* target) { int count=0; for(Creature* crt : members) { if(crt != target && target->inSameRoom(crt)) count++; } return(count); } //******************************************************************************** //* getNumPlyInSameRoup //******************************************************************************** // Returns the number of group members (players) in the same room as the target int Group::getNumPlyInSameRoom(Creature* target) { int count=0; for(Creature* crt : members) { if(crt != target && crt->isPlayer() && target->inSameRoom(crt)) count++; } return(count); } //******************************************************************************** //* getMember //******************************************************************************** // Parameters: countDmInvis - Should we count DM invis players or not? // Returns: The chosen players in the group Creature* Group::getMember(int num, bool countDmInvis) { int count=0; for(Creature* crt : members) { if((countDmInvis || !crt->pFlagIsSet(P_DM_INVIS)) && crt->isPlayer() && crt->getGroupStatus() >= GROUP_MEMBER) count++; if(count == num) return(crt); } return(NULL); } //******************************************************************************** //* getMember //******************************************************************************** // Parameters: name - Name (possibly partial) of the match we're looking for // num - Number in the list for a match // Searcher - The creature doing the search (allows nulls) // includePets - Include pets in the search // Returns: A pointer to the creature, if found Creature* Group::getMember(bstring name, int num, Creature* searcher, bool includePets) { int match = 0; for(Creature* crt : members) { if(!crt->isPlayer() && !includePets) continue; if(crt->getGroupStatus() < GROUP_MEMBER) continue; if(!searcher || !searcher->canSee(crt)) continue; if(keyTxtEqual(crt, name.c_str())) { if(++match == num) { return(crt); } } } return(NULL); } //******************************************************************************** //* inGroup //******************************************************************************** // Returns: Is the target in this group? bool Group::inGroup(Creature* target) { if(std::find(members.begin(), members.end(), target) == members.end()) return(false); else return(true); } //******************************************************************************** //* SendToAll //******************************************************************************** // Parameters: sendToInvited - Are invited members counted as in the group or not? // Send msg to everyone in the group except ignore void Group::sendToAll(bstring msg, Creature* ignore, bool sendToInvited) { for(Creature* crt : members) { if(!crt->isPet() && crt != ignore && (sendToInvited || crt->getGroupStatus() >= GROUP_MEMBER )) { *crt << ColorOn << msg << ColorOff; } } } //******************************************************************************** //* setGroupType //******************************************************************************** void Group::setGroupType(GroupType newType) { groupType = newType; } //******************************************************************************** //* setName //******************************************************************************** void Group::setName(bstring newName) { // Test validity of name here name = newName; } //******************************************************************************** //* setLeader //******************************************************************************** bool Group::setLeader(Creature* newLeader) { //if(newLeader->getGroup() != this) // return(false); leader->setGroupStatus(GROUP_MEMBER); newLeader->setGroupStatus(GROUP_LEADER); leader = newLeader; return(true); } //******************************************************************************** //* setDescription //******************************************************************************** void Group::setDescription(bstring newDescription) { // Test validity of description here description = newDescription; } //******************************************************************************** //* getGroupType //******************************************************************************** GroupType Group::getGroupType() { return(groupType); } //******************************************************************************** //* getLeader //******************************************************************************** Creature* Group::getLeader() { return(leader); } //******************************************************************************** //* getName //******************************************************************************** bstring& Group::getName() { return(name); } //******************************************************************************** //* getDescription //******************************************************************************** bstring& Group::getDescription() { return(description); } //******************************************************************************** //* GetGroup //******************************************************************************** // Parameter: bool inGroup - true - only return the group if they're at least a member // false - return the group if they're an invitee as well Group* Creature::getGroup(bool inGroup) { if(inGroup && groupStatus < GROUP_MEMBER) return(NULL); return(group); } //******************************************************************************** //* SetGroup //******************************************************************************** void Creature::setGroup(Group* newGroup) { // Remove from existing group (Shouldn't happen) if(group && newGroup != NULL) { std::cout << "Setting group for " << getName() << " but they already have a group." << std::endl; } group = newGroup; } //******************************************************************************** //* SetGroupStatus //******************************************************************************** void Creature::setGroupStatus(GroupStatus newStatus) { groupStatus = newStatus; } //******************************************************************************** //* GetGroupStatus //******************************************************************************** GroupStatus Creature::getGroupStatus() { return(groupStatus); } //******************************************************************************** //* InSameGroup //******************************************************************************** bool Creature::inSameGroup(Creature* target) { if(!target) return(false); return(getGroup() == target->getGroup()); } //******************************************************************************** //* GetGroupLeader //******************************************************************************** Creature* Creature::getGroupLeader() { group = getGroup(); if(!group) return(NULL); return(group->getLeader()); } //******************************************************************************** //* Group Flags //******************************************************************************** void Group::setFlag(int flag) { if(flag <= GROUP_NO_FLAG || flag >= GROUP_MAX_FLAG) return; flags |= (1 << flag); } void Group::clearFlag(int flag) { if(flag <= GROUP_NO_FLAG || flag >= GROUP_MAX_FLAG) return; flags &= ~(1 << flag); } bool Group::flagIsSet(int flag) { return(flags & (1 << flag)); } //################################################################################ //# Server methods for groups //################################################################################ bool Server::registerGroup(Group* toRegister) { std::cout << "Registering " << toRegister->getName() << std::endl; groups.push_back(toRegister); return(true); } bool Server::unRegisterGroup(Group* toUnRegister) { std::cout << "Unregistering " << toUnRegister->getName() << std::endl; groups.remove(toUnRegister); return(true); } //################################################################################ //# Stream Operators and toString methods //################################################################################ //******************************************************************************** //* GetGroupTypeStr //******************************************************************************** bstring Group::getGroupTypeStr() { switch(getGroupType()) { case GROUP_PUBLIC: default: return("(Public)"); break; case GROUP_INVITE_ONLY: return("(Invite Only)"); break; case GROUP_PRIVATE: return("(Private)"); break; } return("**Unknown**"); } //******************************************************************************** //* GetGroupTypeStr //******************************************************************************** bstring displayPref(bstring name, bool set) { return(name + (set ? "^gon^x" : "^roff^x")); } bstring Group::getFlagsDisplay() { std::ostringstream oStr; oStr << displayPref("Group Experience Split: ", flagIsSet(GROUP_SPLIT_EXPERIENCE)); oStr << ", "; oStr << displayPref("Split Gold: ", flagIsSet(GROUP_SPLIT_GOLD)); oStr << "."; return(oStr.str()); } //******************************************************************************** //* GetGroupList //******************************************************************************** // Returns the group listing used for displaying to staff bstring Server::getGroupList() { std::ostringstream oStr; int i=1; for(Group* group : groups) { oStr << i++ << ") " << group->getName() << " " << group->getGroupTypeStr() << std::endl << group; } return(oStr.str()); } //******************************************************************************** //* GetGroupTypeStr //******************************************************************************** // Returns the group listing used for displaying to group members bstring Group::getGroupList(Creature* viewer) { int i = 0; std::ostringstream oStr; for(Creature* target : members) { if(!viewer->isStaff() && (target->pFlagIsSet(P_DM_INVIS) || (target->isEffected("incognito") && !viewer->inSameRoom(target)))) continue; bool isPet = target->isPet(); oStr << ++i << ") "; if(!viewer->pFlagIsSet(P_NO_EXTRA_COLOR) && viewer->isEffected("know-aura") && target->getGroupStatus() != GROUP_INVITED) oStr << target->alignColor(); if(isPet) oStr << target->getMaster()->getName() << "'s " << target->getName(); else oStr << target->getName(); oStr << "^x"; if(target == leader) { oStr << " (Leader)"; } else if(target->getGroupStatus() == GROUP_INVITED) { oStr << " (Invited).\n"; continue; } if( viewer->isCt() || (isPet && !target->getMaster()->flagIsSet(P_NO_SHOW_STATS)) || (!isPet && !target->pFlagIsSet(P_NO_SHOW_STATS)) || (isPet && target->getMaster() == viewer) || (!isPet && target == viewer)) { oStr << " - " << (target->hp.getCur() < target->hp.getMax() && !viewer->pFlagIsSet(P_NO_EXTRA_COLOR) ? "^R" : "") << std::setw(3) << target->hp.getCur() << "^x/" << std::setw(3) << target->hp.getMax() << " Hp - " << std::setw(3) << target->mp.getCur() << "/" << std::setw(3) << target->mp.getMax() << " Mp"; if(!isPet) { if(target->isEffected("blindness")) oStr << ", Blind"; if(target->isEffected("drunkenness")) oStr << ", Drunk"; if(target->isEffected("confusion")) oStr << ", Confused"; if(target->isDiseased()) oStr << ", Diseased"; if(target->isEffected("petrification")) oStr << ", Petrified"; if(target->isPoisoned()) oStr << ", Poisoned"; if(target->isEffected("silence")) oStr << ", Silenced"; if(target->flagIsSet(P_SLEEPING)) oStr << ", Sleeping"; else if(target->flagIsSet(P_UNCONSCIOUS)) oStr << ", Unconscious"; if(target->isEffected("wounded")) oStr << ", Wounded"; } oStr << "."; } oStr << "\n"; } return(oStr.str()); } std::ostream& operator<<(std::ostream& out, const Group* group) { if(group) out << (*group); return(out); } std::ostream& operator<<(std::ostream& out, const Group& group) { int i = 0; for(Creature* crt : group.members) { out << "\t" << ++i << ") " << crt->getName(); if(crt->getGroupStatus() == GROUP_LEADER) out << " (Leader)"; else if(crt->getGroupStatus() == GROUP_INVITED) out << " (Invited)"; out << std::endl; } return(out); }