diff --git a/changelog.txt b/changelog.txt index 53d02d02d..0091a7583 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 01/08/2015 == +Trevius: Added some extra checks and clean-up related to Groups and Mercenaries. + == 01/07/2015 == Uleat: Excluded text link body from message scrambling in Client::GarbleMessage() Trevius: Mercenaries now load directly from tables only. The vwMercNpcTypes view is no longer required and can be deleted. diff --git a/zone/groups.cpp b/zone/groups.cpp index a6d8be42b..b4f195c74 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -26,23 +26,16 @@ extern EntityList entity_list; extern WorldServer worldserver; -// -// Xorlac: This will need proper synchronization to make it work correctly. -// Also, should investigate client ack for packet to ensure proper synch. -// - /* - note about how groups work: A group contains 2 list, a list of pointers to members and a list of member names. All members of a group should have their -name in the membername array, wether they are in the zone or not. +name in the membername array, whether they are in the zone or not. Only members in this zone will have non-null pointers in the members array. - */ -//create a group which should allready exist in the database +//create a group which should already exist in the database Group::Group(uint32 gid) : GroupIDConsumer(gid) { @@ -112,8 +105,7 @@ Group::~Group() } } -//Cofruben:Split money used in OP_Split. -//Rewritten by Father Nitwit +//Split money used in OP_Split (/split and /autosplit). void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter) { //avoid unneeded work if(copper == 0 && silver == 0 && gold == 0 && platinum == 0) @@ -197,7 +189,7 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu for (i = 0; i < MAX_GROUP_MEMBERS; i++) { if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client - Client *c = members[i]->CastToClient(); + Client *c = members[i]->CastToClient(); //I could not get MoneyOnCorpse to work, so we use this c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true); c->Message(2, msg.c_str()); @@ -368,7 +360,6 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte void Group::AddMember(const char *NewMemberName) { // This method should be called when both the new member and the group leader are in a different zone to this one. - // for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) if(!strcasecmp(membername[i], NewMemberName)) { @@ -395,9 +386,8 @@ void Group::QueuePacket(const EQApplicationPacket *app, bool ack_req) members[i]->CastToClient()->QueuePacket(app, ack_req); } -// solar: sends the rest of the group's hps to member. this is useful when -// someone first joins a group, but otherwise there shouldn't be a need to -// call it +// Sends the rest of the group's hps to member. this is useful when someone +// first joins a group, but otherwise there shouldn't be a need to call it void Group::SendHPPacketsTo(Mob *member) { if(member && member->IsClient()) @@ -459,9 +449,11 @@ void Group::SendHPPacketsFrom(Mob *member) } //updates a group member's client pointer when they zone in -//if the group was in the zone allready +//if the group was in the zone already bool Group::UpdatePlayer(Mob* update){ + bool updateSuccess = false; + VerifyGroup(); uint32 i=0; @@ -487,7 +479,8 @@ bool Group::UpdatePlayer(Mob* update){ { members[i] = update; members[i]->SetGrouped(true); - return true; + updateSuccess = true; + break; } } @@ -495,7 +488,7 @@ bool Group::UpdatePlayer(Mob* update){ if (update->IsClient() && !mentoree && mentoree_name.length() && !mentoree_name.compare(update->GetName())) mentoree = update->CastToClient(); - return false; + return updateSuccess; } @@ -520,6 +513,7 @@ void Group::MemberZoned(Mob* removemob) { } #endif //BOTS } + if(removemob->IsClient() && HasRole(removemob, RoleAssist)) SetGroupAssistTarget(0); @@ -592,7 +586,7 @@ bool Group::DelMemberOOZ(const char *Name) { return false; } -bool Group::DelMember(Mob* oldmember,bool ignoresender) +bool Group::DelMember(Mob* oldmember, bool ignoresender) { if (oldmember == nullptr) { @@ -689,6 +683,8 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender) if(oldmember->IsClient()) oldmember->CastToClient()->QueuePacket(outapp); } + + safe_delete(outapp); if(oldmember->IsClient()) { @@ -707,8 +703,6 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender) oldmember->SetGrouped(false); disbandcheck = true; - safe_delete(outapp); - if(HasRole(oldmember, RoleTank)) { SetGroupTankTarget(0); @@ -998,24 +992,21 @@ void Group::SendLeadershipAAUpdate() // aware of it until they are next in the same zone as the leader. EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); - GroupJoin_Struct* gu = (GroupJoin_Struct*)outapp->pBuffer; - gu->action = groupActAAUpdate; - - uint32 i = 0; - gu->leader_aas = LeaderAbilities; - gu->NPCMarkerID = GetNPCMarkerID(); + uint32 i = 0; for (i = 0;i < MAX_GROUP_MEMBERS; ++i) + { if(members[i] && members[i]->IsClient()) { strcpy(gu->yourname, members[i]->GetName()); strcpy(gu->membername, members[i]->GetName()); members[i]->CastToClient()->QueuePacket(outapp); } + } safe_delete(outapp); } @@ -1037,8 +1028,8 @@ uint8 Group::GroupCount() { uint32 Group::GetHighestLevel() { -uint32 level = 1; -uint32 i; + uint32 level = 1; + uint32 i; for (i = 0; i < MAX_GROUP_MEMBERS; i++) { if (members[i]) @@ -1049,10 +1040,11 @@ uint32 i; } return level; } + uint32 Group::GetLowestLevel() { -uint32 level = 255; -uint32 i; + uint32 level = 255; + uint32 i; for (i = 0; i < MAX_GROUP_MEMBERS; i++) { if (members[i]) @@ -1112,16 +1104,14 @@ void Group::VerifyGroup() { for (i = 0; i < MAX_GROUP_MEMBERS; i++) { if (membername[i][0] == '\0') { #if EQDEBUG >= 7 -LogFile->write(EQEMuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long)GetID(), i); + LogFile->write(EQEMuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long)GetID(), i); #endif members[i] = nullptr; continue; } - //it should be safe to use GetClientByName, but Group is trying - //to be generic, so we'll go for general Mob Mob *them = entity_list.GetMob(membername[i]); - if(them == nullptr && members[i] != nullptr) { //they arnt here anymore.... + if(them == nullptr && members[i] != nullptr) { //they aren't in zone #if EQDEBUG >= 6 LogFile->write(EQEMuLog::Debug, "Member of group %lu named '%s' has disappeared!!", (unsigned long)GetID(), membername[i]); #endif @@ -1143,7 +1133,6 @@ LogFile->write(EQEMuLog::Debug, "Group %lu: Verify %d: Empty.\n", (unsigned long } } - void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, const char* message,const char* message2,const char* message3,const char* message4,const char* message5,const char* message6,const char* message7,const char* message8,const char* message9, uint32 distance) { uint32 i; for (i = 0; i < MAX_GROUP_MEMBERS; i++) { @@ -1152,13 +1141,14 @@ void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, co if(members[i] == sender) continue; + + if(!members[i]->IsClient()) + continue; members[i]->Message_StringID(type, string_id, message, message2, message3, message4, message5, message6, message7, message8, message9, 0); } } - - void Client::LeaveGroup() { Group *g = GetGroup(); @@ -1178,7 +1168,7 @@ void Client::LeaveGroup() { else { g->DelMember(this); - if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g) + if (GetMerc() != nullptr && g == GetMerc()->GetGroup() ) { GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); } @@ -1363,7 +1353,7 @@ void Group::MarkNPC(Mob* Target, int Number) // Send a packet to all group members in this zone causing the client to prefix the Target mob's name // with the specified Number. // - if(!Target || Target->IsClient()) + if(!Target || Target->IsClient() || Target->IsMerc()) return; if((Number < 1) || (Number > MAX_MARKED_NPCS)) @@ -2166,7 +2156,6 @@ int8 Group::GetNumberNeedingHealedInGroup(int8 hpr, bool includePets) { } } - return needHealed; } @@ -2228,7 +2217,7 @@ void Group::ChangeLeader(Mob* newleader) // this changes the current group leader, notifies other members, and updates leadship AA // if the new leader is invalid, do nothing - if (!newleader) + if (!newleader || !newleader->IsClient()) return; Mob* oldleader = GetLeader();