From c5a90adb396e239683601f57a1d30abf13582935 Mon Sep 17 00:00:00 2001 From: Trevius Date: Sat, 22 Nov 2014 00:22:12 -0600 Subject: [PATCH] Grouping with Mercenaries is considerably less buggy. --- zone/client.cpp | 186 +++++++++++++++++++++++- zone/client.h | 6 +- zone/client_packet.cpp | 306 +++++++++++----------------------------- zone/client_process.cpp | 5 +- zone/groups.cpp | 146 ++++++++++++++----- zone/groups.h | 3 +- zone/merc.cpp | 238 +++++++++++++++++++++---------- zone/merc.h | 1 + zone/questmgr.cpp | 2 +- zone/spells.cpp | 2 +- zone/worldserver.cpp | 71 +++++----- zone/zonedb.cpp | 12 +- 12 files changed, 595 insertions(+), 383 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index f09d24039..f555a26e8 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -3218,6 +3218,10 @@ void Client::LinkDead() { entity_list.MessageGroup(this,true,15,"%s has gone linkdead.",GetName()); GetGroup()->DelMember(this); + if (GetMerc()) + { + GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); + } } Raid *raid = entity_list.GetRaidByClient(this); if(raid){ @@ -4139,6 +4143,184 @@ void Client::UpdateLFP() { worldserver.UpdateLFP(CharacterID(), LFPMembers); } +bool Client::GroupFollow(Client* inviter) { + + if (inviter) + { + isgrouped = true; + Raid* raid = entity_list.GetRaidByClient(inviter); + Raid* iraid = entity_list.GetRaidByClient(this); + + //inviter has a raid don't do group stuff instead do raid stuff! + if (raid) + { + // Suspend the merc while in a raid (maybe a rule could be added for this) + if (GetMerc()) + GetMerc()->Suspend(); + + uint32 groupToUse = 0xFFFFFFFF; + for (int x = 0; x < MAX_RAID_MEMBERS; x++) + { + if (raid->members[x].member) + { + //this assumes the inviter is in the zone + if (raid->members[x].member == inviter){ + groupToUse = raid->members[x].GroupNumber; + break; + } + } + } + if (iraid == raid) + { + //both in same raid + uint32 ngid = raid->GetGroup(inviter->GetName()); + if (raid->GroupCount(ngid) < 6) + { + raid->MoveMember(GetName(), ngid); + raid->SendGroupDisband(this); + //raid->SendRaidGroupAdd(GetName(), ngid); + //raid->SendGroupUpdate(this); + raid->GroupUpdate(ngid); //break + } + return false; + } + if (raid->RaidCount() < MAX_RAID_MEMBERS) + { + if (raid->GroupCount(groupToUse) < 6) + { + raid->SendRaidCreate(this); + raid->SendMakeLeaderPacketTo(raid->leadername, this); + raid->AddMember(this, groupToUse); + raid->SendBulkRaid(this); + //raid->SendRaidGroupAdd(GetName(), groupToUse); + //raid->SendGroupUpdate(this); + raid->GroupUpdate(groupToUse); //break + if (raid->IsLocked()) + { + raid->SendRaidLockTo(this); + } + return false; + } + else + { + raid->SendRaidCreate(this); + raid->SendMakeLeaderPacketTo(raid->leadername, this); + raid->AddMember(this); + raid->SendBulkRaid(this); + if (raid->IsLocked()) + { + raid->SendRaidLockTo(this); + } + return false; + } + } + } + + Group* group = entity_list.GetGroupByClient(inviter); + + if (!group) + { + //Make new group + group = new Group(inviter); + + if (!group) + { + return false; + } + + entity_list.AddGroup(group); + + if (group->GetID() == 0) + { + Message(13, "Unable to get new group id. Cannot create group."); + inviter->Message(13, "Unable to get new group id. Cannot create group."); + return false; + } + + //now we have a group id, can set inviter's id + database.SetGroupID(inviter->GetName(), group->GetID(), inviter->CharacterID(), false); + database.SetGroupLeaderName(group->GetID(), inviter->GetName()); + group->UpdateGroupAAs(); + + //Invite the inviter into the group first.....dont ask + if (inviter->GetClientVersion() < EQClientSoD) + { + EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); + GroupJoin_Struct* outgj = (GroupJoin_Struct*)outapp->pBuffer; + strcpy(outgj->membername, inviter->GetName()); + strcpy(outgj->yourname, inviter->GetName()); + outgj->action = groupActInviteInitial; // 'You have formed the group'. + group->GetGroupAAs(&outgj->leader_aas); + inviter->QueuePacket(outapp); + safe_delete(outapp); + } + else + { + // SoD and later + inviter->SendGroupCreatePacket(); + inviter->SendGroupLeaderChangePacket(inviter->GetName()); + inviter->SendGroupJoinAcknowledge(); + } + + } + + if (!group) + { + return false; + } + + // Remove merc from old group before adding client to the new one + if (GetMerc() && GetMerc()->HasGroup()) + { + GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); + } + + if (!group->AddMember(this)) + { + // If failed to add client to new group, regroup with merc + if (GetMerc()) + { + GetMerc()->MercJoinClientGroup(); + } + else + { + isgrouped = false; + } + return false; + } + + if (GetClientVersion() >= EQClientSoD) + { + SendGroupJoinAcknowledge(); + } + + // Temporary hack for SoD, as things seem to work quite differently + if (inviter->IsClient() && inviter->GetClientVersion() >= EQClientSoD) + { + database.RefreshGroupFromDB(inviter); + } + + // Add the merc back into the new group if possible + if (GetMerc()) + { + GetMerc()->MercJoinClientGroup(); + } + + if (inviter->IsLFP()) + { + // If the player who invited us to a group is LFP, have them update world now that we have joined their group. + inviter->UpdateLFP(); + } + + database.RefreshGroupFromDB(this); + group->SendHPPacketsTo(this); + //send updates to clients out of zone... + group->SendGroupJoinOOZ(this); + return true; + } + return false; +} + uint16 Client::GetPrimarySkillValue() { SkillUseTypes skill = HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill @@ -7412,13 +7594,15 @@ void Client::SendMercPersonalInfo() } if (MERC_DEBUG > 0) Message(7, "Mercenary Debug: SendMercPersonalInfo Send Successful"); + + SendMercMerchantResponsePacket(0); } else { if (MERC_DEBUG > 0) Message(7, "Mercenary Debug: SendMercPersonalInfo Send Failed Due to no MercData for %i", GetMercInfo().MercTemplateID); } - SendMercMerchantResponsePacket(0); + } void Client::SendClearMercInfo() diff --git a/zone/client.h b/zone/client.h index 4ffe6d57d..72e69e8eb 100644 --- a/zone/client.h +++ b/zone/client.h @@ -208,7 +208,7 @@ public: Client(EQStreamInterface * ieqs); ~Client(); - //abstract virtual function implementations requird by base abstract class + //abstract virtual function implementations required by base abstract class virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, @@ -710,7 +710,7 @@ public: void UnscribeSpellAll(bool update_client = true); void UntrainDisc(int slot, bool update_client = true); void UntrainDiscAll(bool update_client = true); - bool SpellGlobalCheck(uint16 Spell_ID, uint16 Char_ID); + bool SpellGlobalCheck(uint16 Spell_ID, uint32 Char_ID); uint32 GetCharMaxLevelFromQGlobal(); inline bool IsSitting() const {return (playeraction == 1);} @@ -1098,6 +1098,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst); void RemoveGroupXTargets(); void RemoveAutoXTargets(); void ShowXTargets(Client *c); + bool GroupFollow(Client* inviter); void InitializeMercInfo(); bool CheckCanSpawnMerc(uint32 template_id); @@ -1105,6 +1106,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst); bool CheckCanRetainMerc(uint32 upkeep); bool CheckCanUnsuspendMerc(); bool DismissMerc(uint32 MercID); + bool MercOnlyOrNoGroup(); inline uint32 GetMercID() const { return mercid; } inline uint8 GetMercSlot() const { return mercSlot; } void SetMercID( uint32 newmercid) { mercid = newmercid; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d8f23f8f7..238f324f2 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1637,7 +1637,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) } //else, somebody from our group is already here... if (!group) - database.SetGroupID(GetName(), 0, CharacterID()); //cannot re-establish group, kill it + database.SetGroupID(GetName(), 0, CharacterID(), false); //cannot re-establish group, kill it } else { //no group id @@ -6403,7 +6403,10 @@ void Client::Handle_OP_GroupCancelInvite(const EQApplicationPacket *app) safe_delete(pack); } - database.SetGroupID(GetName(), 0, CharacterID()); + if (!GetMerc()) + { + database.SetGroupID(GetName(), 0, CharacterID(), false); + } return; } @@ -6433,7 +6436,8 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app) GroupGeneric_Struct* gd = (GroupGeneric_Struct*)app->pBuffer; Raid *raid = entity_list.GetRaidByClient(this); - if (raid){ + if (raid) + { Mob* memberToDisband = nullptr; if (!raid->IsGroupLeader(GetName())) @@ -6500,93 +6504,80 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app) } } #endif - if ((group->IsLeader(this) && (GetTarget() == 0 || GetTarget() == this)) || (group->GroupCount()<3)) { + if (group->GroupCount() < 3) + { group->DisbandGroup(); - if (GetMerc() != nullptr) + if (GetMerc()) GetMerc()->Suspend(); } - else { + else if (group->IsLeader(this) && GetTarget() == nullptr) + { + if (group->GroupCount() > 2 && GetMerc() && !GetMerc()->IsSuspended()) + { + group->DisbandGroup(); + GetMerc()->MercJoinClientGroup(); + } + else + { + group->DisbandGroup(); + if (GetMerc()) + GetMerc()->Suspend(); + } + } + else if (group->IsLeader(this) && GetTarget() == this) + { + LeaveGroup(); + if (GetMerc() && !GetMerc()->IsSuspended()) + { + GetMerc()->MercJoinClientGroup(); + } + } + else + { Mob* memberToDisband = nullptr; memberToDisband = GetTarget(); if (!memberToDisband) memberToDisband = entity_list.GetMob(gd->name2); - if (memberToDisband) { - if (group->IsLeader(this)) { + if (memberToDisband) + { + if (group->IsLeader(this)) + { // the group leader can kick other members out of the group... - //group->DelMember(memberToDisband,false); if (memberToDisband->IsClient()) { group->DelMember(memberToDisband, false); Client* memberClient = memberToDisband->CastToClient(); Merc* memberMerc = memberToDisband->CastToClient()->GetMerc(); - if (memberClient && memberMerc && group) + if (memberClient && memberMerc) { - if (!memberMerc->IsGrouped() && !memberClient->IsGrouped()) { - Group *g = new Group(memberClient); - - entity_list.AddGroup(g); - - if (g->GetID() == 0) { - safe_delete(g); - return; - } - if (Merc::AddMercToGroup(memberMerc, g)) { - database.SetGroupLeaderName(g->GetID(), memberClient->GetName()); - g->SaveGroupLeaderAA(); - database.SetGroupID(memberClient->GetName(), g->GetID(), memberClient->CharacterID()); - database.SetGroupID(memberMerc->GetName(), g->GetID(), memberClient->CharacterID(), true); - database.RefreshGroupFromDB(memberClient); - } - } + memberMerc->MercJoinClientGroup(); } } - else if (memberToDisband->IsMerc()) { + else if (memberToDisband->IsMerc()) + { memberToDisband->CastToMerc()->Suspend(); } } - else { + else + { // ...but other members can only remove themselves group->DelMember(this, false); - if (!IsGrouped() && GetMerc() != nullptr) { - if (!IsGrouped()) { - Group *g = new Group(this); - - if (!g) { - delete g; - g = nullptr; - return; - } - - entity_list.AddGroup(g); - - if (g->GetID() == 0) { - safe_delete(g); - return; - } - - if (Merc::AddMercToGroup(GetMerc(), g)) { - database.SetGroupLeaderName(g->GetID(), this->GetName()); - g->SaveGroupLeaderAA(); - database.SetGroupID(this->GetName(), g->GetID(), this->CharacterID()); - database.SetGroupID(GetMerc()->GetName(), g->GetID(), this->CharacterID(), true); - database.RefreshGroupFromDB(this); - } - else - { - if (GetMerc()) - GetMerc()->Depop(); - } - } + if (GetMerc() && !GetMerc()->IsSuspended()) + { + GetMerc()->MercJoinClientGroup(); } } } else + { LogFile->write(EQEMuLog::Error, "Failed to remove player from group. Unable to find player named %s in player group", gd->name2); + } } - if (LFP) { + if (LFP) + { // If we are looking for players, update to show we are on our own now. UpdateLFP(); } @@ -6616,157 +6607,22 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app) GroupGeneric_Struct* gf = (GroupGeneric_Struct*)app->pBuffer; Mob* inviter = entity_list.GetClientByName(gf->name1); - - if (inviter != nullptr && inviter->IsClient()) { - isgrouped = true; - strn0cpy(gf->name1, inviter->GetName(), 64); - strn0cpy(gf->name2, this->GetName(), 64); - - Raid* raid = entity_list.GetRaidByClient(inviter->CastToClient()); - Raid* iraid = entity_list.GetRaidByClient(this); - - //inviter has a raid don't do group stuff instead do raid stuff! - if (raid){ - // Suspend the merc while in a raid (maybe a rule could be added for this) - if (GetMerc()) - GetMerc()->Suspend(); - - uint32 groupToUse = 0xFFFFFFFF; - for (int x = 0; x < MAX_RAID_MEMBERS; x++){ - if (raid->members[x].member){ //this assumes the inviter is in the zone - if (raid->members[x].member == inviter->CastToClient()){ - groupToUse = raid->members[x].GroupNumber; - break; - } - } - } - if (iraid == raid){ //both in same raid - uint32 ngid = raid->GetGroup(inviter->GetName()); - if (raid->GroupCount(ngid) < 6){ - raid->MoveMember(GetName(), ngid); - raid->SendGroupDisband(this); - //raid->SendRaidGroupAdd(GetName(), ngid); - //raid->SendGroupUpdate(this); - raid->GroupUpdate(ngid); //break - } - return; - } - if (raid->RaidCount() < MAX_RAID_MEMBERS){ - if (raid->GroupCount(groupToUse) < 6){ - raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); - raid->AddMember(this, groupToUse); - raid->SendBulkRaid(this); - //raid->SendRaidGroupAdd(GetName(), groupToUse); - //raid->SendGroupUpdate(this); - raid->GroupUpdate(groupToUse); //break - if (raid->IsLocked()) { - raid->SendRaidLockTo(this); - } - return; - } - else{ - raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); - raid->AddMember(this); - raid->SendBulkRaid(this); - if (raid->IsLocked()) { - raid->SendRaidLockTo(this); - } - return; - } - } + + // Inviter and Invitee are in the same zone + if (inviter != nullptr && inviter->IsClient()) + { + if (GroupFollow(inviter->CastToClient())) + { + strn0cpy(gf->name1, inviter->GetName(), sizeof(gf->name1)); + strn0cpy(gf->name2, GetName(), sizeof(gf->name2)); + inviter->CastToClient()->QueuePacket(app);//notify inviter the client accepted } - - Group* group = entity_list.GetGroupByClient(inviter->CastToClient()); - - if (!group){ - //Make new group - group = new Group(inviter); - if (!group) - return; - entity_list.AddGroup(group); - - if (group->GetID() == 0) { - Message(13, "Unable to get new group id. Cannot create group."); - inviter->Message(13, "Unable to get new group id. Cannot create group."); - return; - } - - //now we have a group id, can set inviter's id - database.SetGroupID(inviter->GetName(), group->GetID(), inviter->CastToClient()->CharacterID()); - database.SetGroupLeaderName(group->GetID(), inviter->GetName()); - - group->UpdateGroupAAs(); - - //Invite the inviter into the group first.....dont ask - if (inviter->CastToClient()->GetClientVersion() < EQClientSoD) - { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); - GroupJoin_Struct* outgj = (GroupJoin_Struct*)outapp->pBuffer; - strcpy(outgj->membername, inviter->GetName()); - strcpy(outgj->yourname, inviter->GetName()); - outgj->action = groupActInviteInitial; // 'You have formed the group'. - group->GetGroupAAs(&outgj->leader_aas); - inviter->CastToClient()->QueuePacket(outapp); - safe_delete(outapp); - } - else - { - // SoD and later - // - inviter->CastToClient()->SendGroupCreatePacket(); - - inviter->CastToClient()->SendGroupLeaderChangePacket(inviter->GetName()); - - inviter->CastToClient()->SendGroupJoinAcknowledge(); - } - - } - if (!group) - return; - - inviter->CastToClient()->QueuePacket(app);//notify inviter the client accepted - - if (!group->AddMember(this)) - return; - - if (inviter->CastToClient()->IsLFP()) { - // If the player who invited us to a group is LFP, have them update world now that we have joined - // their group. - inviter->CastToClient()->UpdateLFP(); - } - - if (GetClientVersion() >= EQClientSoD) - SendGroupJoinAcknowledge(); - - database.RefreshGroupFromDB(this); - group->SendHPPacketsTo(this); - - // Temporary hack for SoD, as things seem to work quite differently - if (inviter->CastToClient()->GetClientVersion() >= EQClientSoD) - database.RefreshGroupFromDB(inviter->CastToClient()); - - // Add the merc back into the new group - if (GetMerc()) { - if (Merc::AddMercToGroup(GetMerc(), group)) { - database.SetGroupID(GetMerc()->GetName(), group->GetID(), inviter->CastToClient()->CharacterID(), true); - database.RefreshGroupFromDB(this); - } - } - - //send updates to clients out of zone... - ServerPacket* pack = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); - ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack->pBuffer; - gj->gid = group->GetID(); - gj->zoneid = zone->GetZoneID(); - gj->instance_id = zone->GetInstanceID(); - strcpy(gj->member_name, GetName()); - worldserver.SendPacket(pack); - safe_delete(pack); } else if (inviter == nullptr) { + // Inviter is in another zone - Remove merc from group now if any + LeaveGroup(); + ServerPacket* pack = new ServerPacket(ServerOP_GroupFollow, sizeof(ServerGroupFollow_Struct)); ServerGroupFollow_Struct *sgfs = (ServerGroupFollow_Struct *)pack->pBuffer; sgfs->CharacterID = CharacterID(); @@ -6801,10 +6657,11 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) return; } - if (Invitee) { - if (Invitee->IsClient()) { - if ((!Invitee->IsGrouped() && !Invitee->IsRaidGrouped()) || - (Invitee->GetGroup() && Invitee->CastToClient()->GetMerc() && Invitee->GetGroup()->GroupCount() == 2)) + if (Invitee) + { + if (Invitee->IsClient()) + { + if(Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped()) { if (app->GetOpcode() == OP_GroupInvite2) { @@ -9507,7 +9364,8 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app) Merc* merc = GetMerc(); GetMercInfo().State = option; - if (merc) { + if (merc) + { uint8 numStances = 0; //get number of available stances for the current merc @@ -9519,10 +9377,11 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app) } MercTemplate* mercTemplate = zone->GetMercTemplate(GetMerc()->GetMercTemplateID()); - if (mercTemplate) { - + if (mercTemplate) + { //check to see if selected option is a valid stance slot (option is the slot the stance is in, not the actual stance) - if (option >= 0 && option < numStances) { + if (option >= 0 && option < numStances) + { merc->SetStance(mercTemplate->Stances[option]); GetMercInfo().Stance = mercTemplate->Stances[option]; @@ -9710,7 +9569,7 @@ void Client::Handle_OP_MercenaryDismiss(const EQApplicationPacket *app) Message(7, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command); // Handle the dismiss here... - DismissMerc(GetMercInfo().mercid); // GetMercID() + DismissMerc(GetMercInfo().mercid); } @@ -9744,10 +9603,12 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app) MercTemplate* merc_template = zone->GetMercTemplate(merc_template_id); - if (merc_template) { + if (merc_template) + { Mob* merchant = entity_list.GetNPCByID(merchant_id); - if (!CheckCanHireMerc(merchant, merc_template_id)) { + if (!CheckCanHireMerc(merchant, merc_template_id)) + { return; } @@ -9762,7 +9623,8 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app) SpawnMerc(merc, true); merc->Save(); - if (RuleB(Mercs, ChargeMercPurchaseCost)) { + if (RuleB(Mercs, ChargeMercPurchaseCost)) + { uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold TakeMoneyFromPP(cost, true); } @@ -9770,12 +9632,14 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app) // 0 is approved hire request SendMercMerchantResponsePacket(0); } - else { + else + { //merc failed to spawn SendMercMerchantResponsePacket(3); } } - else { + else + { //merc doesn't exist in db SendMercMerchantResponsePacket(2); } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 2f46a5688..13973df91 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -245,7 +245,6 @@ bool Client::Process() { if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended) { - //CheckMercSuspendTimer(); if(p_timers.Expired(&database, pTimerMercSuspend, false)) { CheckMercSuspendTimer(); @@ -746,9 +745,9 @@ bool Client::Process() { { entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName()); mygroup->MemberZoned(this); - if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == mygroup) + if (GetMerc() && GetMerc()->HasGroup()) { - mygroup->DelMember(GetMerc()); + GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); } } diff --git a/zone/groups.cpp b/zone/groups.cpp index fb1f4204e..2e7fb3cfe 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -203,28 +203,34 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu } } -bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 CharacterID) +bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 CharacterID, bool ismerc) { bool InZone = true; - bool ismerc = false; // This method should either be passed a Mob*, if the new member is in this zone, or a nullptr Mob* // and the name and CharacterID of the new member, if they are out of zone. - // if(!newmember && !NewMemberName) - return false; + { + return false; + } if(GroupCount() >= MAX_GROUP_MEMBERS) //Sanity check for merging groups together. + { return false; + } if(!newmember) + { InZone = false; + } else { NewMemberName = newmember->GetCleanName(); if(newmember->IsClient()) + { CharacterID = newmember->CastToClient()->CharacterID(); + } if(newmember->IsMerc()) { Client* owner = newmember->CastToMerc()->GetMercOwner(); @@ -232,18 +238,20 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte { CharacterID = owner->CastToClient()->CharacterID(); NewMemberName = newmember->GetName(); - ismerc = true; } + ismerc = true; } } - uint32 i = 0; - // See if they are already in the group - // + uint32 i = 0; for (i = 0; i < MAX_GROUP_MEMBERS; ++i) + { if(!strcasecmp(membername[i], NewMemberName)) + { return false; + } + } // Put them in the group for (i = 0; i < MAX_GROUP_MEMBERS; ++i) @@ -251,17 +259,20 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte if (membername[i][0] == '\0') { if(InZone) + { members[i] = newmember; - + } + strcpy(membername[i], NewMemberName); + MemberRoles[i] = 0; break; } } + // Is this even possible based on the above loops? Remove? if (i == MAX_GROUP_MEMBERS) + { return false; - - strcpy(membername[i], NewMemberName); - MemberRoles[i] = 0; + } int x=1; @@ -270,11 +281,12 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, NewMemberName); gj->action = groupActJoin; - gj->leader_aas = LeaderAbilities; - for (i = 0;i < MAX_GROUP_MEMBERS; i++) { - if (members[i] != nullptr && members[i] != newmember) { + for (i = 0;i < MAX_GROUP_MEMBERS; i++) + { + if (members[i] != nullptr && members[i] != newmember) + { //fill in group join & send it if(members[i]->IsMerc()) { @@ -284,18 +296,23 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte { strcpy(gj->yourname, members[i]->GetCleanName()); } - if(members[i]->IsClient()) { + if(members[i]->IsClient()) + { members[i]->CastToClient()->QueuePacket(outapp); - //put new member into existing person's list + //put new member into existing group members' list(s) strcpy(members[i]->CastToClient()->GetPP().groupMembers[this->GroupCount()-1], NewMemberName); } - //put this existing person into the new member's list - if(InZone && newmember->IsClient()) { + //put existing group member(s) into the new member's list + if(InZone && newmember->IsClient()) + { if(IsLeader(members[i])) + { strcpy(newmember->CastToClient()->GetPP().groupMembers[0], members[i]->GetCleanName()); - else { + } + else + { strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName()); x++; } @@ -337,7 +354,9 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte #endif //BOTS } else + { database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc); + } safe_delete(outapp); @@ -512,6 +531,30 @@ void Group::MemberZoned(Mob* removemob) { mentoree = nullptr; } +void Group::SendGroupJoinOOZ(Mob* NewMember) { + + if (NewMember == nullptr) + { + return; + } + + if (!NewMember->HasGroup()) + { + return; + } + + //send updates to clients out of zone... + ServerPacket* pack = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); + ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack->pBuffer; + gj->gid = GetID(); + gj->zoneid = zone->GetZoneID(); + gj->instance_id = zone->GetInstanceID(); + strcpy(gj->member_name, NewMember->GetName()); + worldserver.SendPacket(pack); + safe_delete(pack); + +} + bool Group::DelMemberOOZ(const char *Name) { if(!Name) return false; @@ -619,7 +662,8 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender) #endif //BOTS } - if (!ignoresender) { + if (!ignoresender) + { strcpy(gu->yourname,oldmember->GetCleanName()); strcpy(gu->membername,oldmember->GetCleanName()); gu->action = groupActLeave; @@ -629,7 +673,18 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender) } if(oldmember->IsClient()) - database.SetGroupID(oldmember->GetCleanName(), 0, oldmember->CastToClient()->CharacterID()); + { + database.SetGroupID(oldmember->GetCleanName(), 0, oldmember->CastToClient()->CharacterID(), false); + } + + if(oldmember->IsMerc()) + { + Client* owner = oldmember->CastToMerc()->GetMercOwner(); + if(owner) + { + database.SetGroupID(oldmember->GetName(), 0, owner->CharacterID(), true); + } + } oldmember->SetGrouped(false); disbandcheck = true; @@ -819,20 +874,33 @@ void Group::DisbandGroup() { Client *Leader = nullptr; uint32 i; - for (i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (members[i] == nullptr) { + for (i = 0; i < MAX_GROUP_MEMBERS; i++) + { + if (members[i] == nullptr) + { continue; } - if (members[i]->IsClient()) { + if (members[i]->IsClient()) + { if(IsLeader(members[i])) + { Leader = members[i]->CastToClient(); + } strcpy(gu->yourname, members[i]->GetName()); - database.SetGroupID(members[i]->GetName(), 0, members[i]->CastToClient()->CharacterID()); + database.SetGroupID(members[i]->GetName(), 0, members[i]->CastToClient()->CharacterID(), false); members[i]->CastToClient()->QueuePacket(outapp); SendMarkedNPCsToMember(members[i]->CastToClient(), true); - + } + + if (members[i]->IsMerc()) + { + Client* owner = members[i]->CastToMerc()->GetMercOwner(); + if(owner) + { + database.SetGroupID(members[i]->GetName(), 0, owner->CharacterID(), true); + } } members[i]->SetGrouped(false); @@ -852,9 +920,12 @@ void Group::DisbandGroup() { entity_list.RemoveGroup(GetID()); if(GetID() != 0) + { database.ClearGroup(GetID()); + } - if(Leader && (Leader->IsLFP())) { + if(Leader && (Leader->IsLFP())) + { Leader->UpdateLFP(); } @@ -936,8 +1007,12 @@ uint8 Group::GroupCount() { uint8 MemberCount = 0; for(uint8 i = 0; i < MAX_GROUP_MEMBERS; ++i) + { if(membername[i][0]) + { ++MemberCount; + } + } return MemberCount; } @@ -1071,7 +1146,14 @@ void Client::LeaveGroup() { if(g) { - if(g->GroupCount() < 3) + int32 MemberCount = g->GroupCount(); + // Account for both client and merc leaving the group + if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g) + { + MemberCount -= 1; + } + + if(MemberCount < 3) { g->DisbandGroup(); } @@ -1080,17 +1162,17 @@ void Client::LeaveGroup() { g->DelMember(this); if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g) { - g->DelMember(GetMerc()); + GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); } } } else { //force things a little - database.SetGroupID(GetName(), 0, CharacterID()); + database.SetGroupID(GetName(), 0, CharacterID(), false); if (GetMerc()) { - database.SetGroupID(GetMerc()->GetName(), 0, CharacterID()); + database.SetGroupID(GetMerc()->GetName(), 0, CharacterID(), true); } } diff --git a/zone/groups.h b/zone/groups.h index 951d8881a..a0b17229b 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -51,7 +51,7 @@ public: Group(uint32 gid); ~Group(); - bool AddMember(Mob* newmember, const char* NewMemberName = nullptr, uint32 CharacterID = 0); + bool AddMember(Mob* newmember, const char* NewMemberName = nullptr, uint32 CharacterID = 0, bool ismerc = false); void AddMember(const char* NewMemberName); void SendUpdate(uint32 type,Mob* member); void SendLeadershipAAUpdate(); @@ -63,6 +63,7 @@ public: bool IsGroupMember(const char *Name); bool Process(); bool IsGroup() { return true; } + void SendGroupJoinOOZ(Mob* NewMember); void CastGroupSpell(Mob* caster,uint16 spellid); void GroupBardPulse(Mob* caster,uint16 spellid); void SplitExp(uint32 exp, Mob* other); diff --git a/zone/merc.cpp b/zone/merc.cpp index 077705de9..94d129b14 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1287,8 +1287,8 @@ bool Merc::Process() if (GetDepop()) { - //SetMercCharacterID(0); - //SetOwnerID(0); + SetMercCharacterID(0); + SetOwnerID(0); return false; } @@ -1297,7 +1297,8 @@ bool Merc::Process() //return false; //merc can live after client dies, not sure how long } - if(IsSuspended()) { + if(IsSuspended()) + { return false; } @@ -5368,12 +5369,14 @@ bool Client::CheckCanRetainMerc(uint32 upkeep) { bool Client::CheckCanSpawnMerc(uint32 template_id) { // Check if mercs are enabled globally - if(!RuleB(Mercs, AllowMercs)) { + if(!RuleB(Mercs, AllowMercs)) + { return false; } // Check if zone allows mercs - if(!zone->AllowMercs()) { + if(!zone->AllowMercs()) + { SendMercResponsePackets(3); return false; } @@ -5381,31 +5384,36 @@ bool Client::CheckCanSpawnMerc(uint32 template_id) { MercTemplate* mercTemplate = zone->GetMercTemplate(template_id); // Invalid merc data - if(!mercTemplate) { + if(!mercTemplate) + { SendMercResponsePackets(11); return false; } // Check client version - if(GetClientVersion() < mercTemplate->ClientVersion) { + if(GetClientVersion() < mercTemplate->ClientVersion) + { SendMercResponsePackets(3); return false; } // Check for raid - if(HasRaid()) { + if(HasRaid()) + { SendMercResponsePackets(4); return false; } // Check group size - if(HasGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) { + if(GetGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) // database.GroupCount(GetGroup()->GetID()) + { SendMercResponsePackets(8); return false; } // Check in combat - if(GetAggroCount() > 0) { + if(GetAggroCount() > 0) + { SendMercResponsePackets(9); return false; } @@ -5584,6 +5592,10 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) { if (!merc || !CheckCanSpawnMerc(merc->GetMercTemplateID())) { + if (merc) + { + merc->Suspend(); + } return; } @@ -5618,9 +5630,7 @@ bool Merc::Suspend() { mercOwner->GetMercInfo().Stance = GetStance(); Save(); mercOwner->GetMercTimer()->Disable(); - mercOwner->SendMercSuspendResponsePacket(mercOwner->GetMercInfo().SuspendedTime); - mercOwner->SendMercTimer(this); Depop(); @@ -5634,6 +5644,25 @@ bool Merc::Suspend() { return true; } +bool Client::MercOnlyOrNoGroup() { + + if (!GetGroup()) + { + return true; + } + if (GetMerc()) + { + if (GetMerc()->HasGroup() && GetMerc()->GetGroup() == GetGroup()) + { + if (GetGroup()->GroupCount() < 3) + { + return true; + } + } + } + return false; +} + bool Merc::Unsuspend(bool setMaxStats) { Client* mercOwner = nullptr; @@ -5657,65 +5686,15 @@ bool Merc::Unsuspend(bool setMaxStats) { mercOwner->SendMercenaryUnsuspendPacket(0); mercOwner->SendMercenaryUnknownPacket(1); mercOwner->GetMercInfo().SuspendedTime = 0; + // Reset the upkeep timer + mercOwner->GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); mercOwner->GetMercTimer()->Start(RuleI(Mercs, UpkeepIntervalMS)); - mercOwner->GetMercTimer()->SetTimer(mercOwner->GetMercInfo().MercTimerRemaining); + //mercOwner->GetMercTimer()->SetTimer(mercOwner->GetMercInfo().MercTimerRemaining); mercOwner->SendMercTimer(this); if(!mercOwner->GetPTimers().Expired(&database, pTimerMercSuspend, false)) mercOwner->GetPTimers().Clear(&database, pTimerMercSuspend); - //mercOwner->SendMercPersonalInfo(); - Group* g = entity_list.GetGroupByClient(mercOwner); - - //nobody from our group is here... start a new group - if(!g) - { - g = new Group(mercOwner); - - if(!g) { - delete g; - g = nullptr; - return false; - } - - entity_list.AddGroup(g); - - if(g->GetID() == 0) { - delete g; - g = nullptr; - return false; - } - - if(AddMercToGroup(this, g)) - { - entity_list.AddGroup(g, g->GetID()); - database.SetGroupLeaderName(g->GetID(), mercOwner->GetName()); - database.SetGroupID(mercOwner->GetName(), g->GetID(), mercOwner->CharacterID()); - database.SetGroupID(this->GetName(), g->GetID(), mercOwner->CharacterID(), true); - database.RefreshGroupFromDB(mercOwner); - g->SaveGroupLeaderAA(); - loaded = true; - } - else - { - g->DisbandGroup(); - } - } - else if (AddMercToGroup(this, mercOwner->GetGroup())) - { - // Group already exists - database.SetGroupID(GetName(), mercOwner->GetGroup()->GetID(), mercOwner->CharacterID(), true); - database.RefreshGroupFromDB(mercOwner); - - loaded = true; - } - else - { - if(MERC_DEBUG > 0) - mercOwner->Message(7, "Mercenary failed to join the group - Suspending"); - - Suspend(); - } - + MercJoinClientGroup(); if(loaded) { @@ -5788,7 +5767,7 @@ void Merc::Depop() { entity_list.RemoveFromHateLists(this); - if(HasGroup()) + if(GetGroup()) { RemoveMercFromGroup(this, GetGroup()); } @@ -5820,7 +5799,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { if(group->DelMember(merc, true)) { if(merc->GetMercCharacterID() != 0) + { database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true); + } } if(group->GroupCount() <= 1 && ZoneLoaded) @@ -5830,6 +5811,17 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { } else { + // A merc is group leader - Disband and re-group each member with their mercs + for(int i = 0; i < MAX_GROUP_MEMBERS; i++) + { + if(!group->members[i]) + continue; + + if(!group->members[i]->IsClient()) + continue; + + group->members[i]->CastToClient()->LeaveGroup(); + } for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { if(!group->members[i]) @@ -5838,15 +5830,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { if(!group->members[i]->IsMerc()) continue; - Merc* groupmerc = group->members[i]->CastToMerc(); - - //groupmerc->SetOwnerID(0); - if (!groupmerc->IsSuspended()) - { - groupmerc->Suspend(); - database.SetGroupID(groupmerc->GetCleanName(), 0, groupmerc->GetMercCharacterID(), true); - } + group->members[i]->CastToMerc()->MercJoinClientGroup(); } + // Group should be removed by now, but just in case: group->DisbandGroup(); } @@ -5857,16 +5843,112 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { return Result; } +bool Merc::MercJoinClientGroup() { + + Client* mercOwner = nullptr; + + if(GetMercOwner()) + { + mercOwner = GetMercOwner(); + } + + if(!mercOwner) + { + Suspend(); + return false; + } + + if(GetID()) + { + if (HasGroup()) + { + RemoveMercFromGroup(this, GetGroup()); + } + + Group* g = entity_list.GetGroupByClient(mercOwner); + + //nobody from our group is here... start a new group + if(!g) + { + g = new Group(mercOwner); + + if(!g) + { + delete g; + g = nullptr; + return false; + } + + entity_list.AddGroup(g); + + if(g->GetID() == 0) + { + delete g; + g = nullptr; + return false; + } + + if(AddMercToGroup(this, g)) + { + entity_list.AddGroup(g, g->GetID()); + database.SetGroupLeaderName(g->GetID(), mercOwner->GetName()); + database.SetGroupID(mercOwner->GetName(), g->GetID(), mercOwner->CharacterID(), false); + database.SetGroupID(this->GetName(), g->GetID(), mercOwner->CharacterID(), true); + database.RefreshGroupFromDB(mercOwner); + g->SaveGroupLeaderAA(); + if(MERC_DEBUG > 0) + mercOwner->Message(7, "Mercenary Debug: Mercenary joined new group."); + } + else + { + g->DisbandGroup(); + Suspend(); + + if(MERC_DEBUG > 0) + mercOwner->Message(7, "Mercenary Debug: Mercenary disbanded new group."); + } + + } + else if (AddMercToGroup(this, mercOwner->GetGroup())) + { + // Group already exists + database.SetGroupID(GetName(), mercOwner->GetGroup()->GetID(), mercOwner->CharacterID(), true); + database.RefreshGroupFromDB(mercOwner); + // Update members that are out of zone + GetGroup()->SendGroupJoinOOZ(this); + + if(MERC_DEBUG > 0) + mercOwner->Message(7, "Mercenary Debug: Mercenary joined existing group."); + } + else + { + Suspend(); + + if(MERC_DEBUG > 0) + mercOwner->Message(7, "Mercenary Debug: Mercenary failed to join the group - Suspending"); + } + } + + return true; +} + bool Merc::AddMercToGroup(Merc* merc, Group* group) { bool Result = false; if(merc && group) { - // Remove merc from current group if any - if(merc->HasGroup()) { + // Remove merc from current group if it's not the destination group + if(merc->HasGroup()) + { + if(merc->GetGroup() == group && merc->GetMercOwner()) + { + // Merc is already in the destination group + merc->SetFollowID(merc->GetMercOwner()->GetID()); + return true; + } merc->RemoveMercFromGroup(merc, merc->GetGroup()); } //Try and add the member, followed by checking if the merc owner exists. - if(group->AddMember(merc) && merc->GetMercOwner() != nullptr) + if(group->AddMember(merc) && merc->GetMercOwner()) { merc->SetFollowID(merc->GetMercOwner()->GetID()); Result = true; diff --git a/zone/merc.h b/zone/merc.h index 433c614fc..eca59ba24 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -138,6 +138,7 @@ public: bool Spawn(Client *owner); bool Suspend(); bool Unsuspend(bool setMaxStats); + bool MercJoinClientGroup(); void Zone(); virtual void Depop(); virtual bool Save(); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 46d2deb34..dc9d6d8f6 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -907,7 +907,7 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { uint16 book_slot, count; uint16 curspell; - uint16 Char_ID = initiator->CharacterID(); + uint32 Char_ID = initiator->CharacterID(); bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); bool SpellGlobalCheckResult = 0; diff --git a/zone/spells.cpp b/zone/spells.cpp index 315fe8712..06c28adaa 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4928,7 +4928,7 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) { return -1; //default } -bool Client::SpellGlobalCheck(uint16 spell_ID, uint16 char_ID) { +bool Client::SpellGlobalCheck(uint16 spell_ID, uint32 char_ID) { std::string spell_Global_Name; int spell_Global_Value; diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index be0a1a193..eb717f89a 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -831,12 +831,11 @@ void WorldServer::Process() { } case ServerOP_GroupInvite: { // A player in another zone invited a player in this zone to join their group. - // GroupInvite_Struct* gis = (GroupInvite_Struct*)pack->pBuffer; Mob *Invitee = entity_list.GetMob(gis->invitee_name); - if(Invitee && Invitee->IsClient() && !Invitee->IsGrouped() && !Invitee->IsRaidGrouped()) + if(Invitee && Invitee->IsClient() && Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped()) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct)); memcpy(outapp->pBuffer, gis, sizeof(GroupInvite_Struct)); @@ -848,7 +847,6 @@ void WorldServer::Process() { } case ServerOP_GroupFollow: { // Player in another zone accepted a group invitation from a player in this zone. - // ServerGroupFollow_Struct* sgfs = (ServerGroupFollow_Struct*) pack->pBuffer; Mob* Inviter = entity_list.GetClientByName(sgfs->gf.name1); @@ -857,12 +855,15 @@ void WorldServer::Process() { { Group* group = entity_list.GetGroupByClient(Inviter->CastToClient()); - if(!group){ - + if(!group) + { + //Make new group group = new Group(Inviter); - if(!group) + if (!group) + { break; + } entity_list.AddGroup(group); @@ -871,10 +872,8 @@ void WorldServer::Process() { break; } - database.SetGroupID(Inviter->GetName(), group->GetID(), Inviter->CastToClient()->CharacterID()); - + database.SetGroupID(Inviter->GetName(), group->GetID(), Inviter->CastToClient()->CharacterID(), false); database.SetGroupLeaderName(group->GetID(), Inviter->GetName()); - group->UpdateGroupAAs(); if(Inviter->CastToClient()->GetClientVersion() < EQClientSoD) @@ -891,25 +890,22 @@ void WorldServer::Process() { else { // SoD and later - // Inviter->CastToClient()->SendGroupCreatePacket(); Inviter->CastToClient()->SendGroupLeaderChangePacket(Inviter->GetName()); Inviter->CastToClient()->SendGroupJoinAcknowledge(); } } + if(!group) + { break; + } EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct)); - GroupGeneric_Struct *gg = (GroupGeneric_Struct *)outapp->pBuffer; - strn0cpy(gg->name1, sgfs->gf.name1, sizeof(gg->name1)); - strn0cpy(gg->name2, sgfs->gf.name2, sizeof(gg->name2)); - Inviter->CastToClient()->QueuePacket(outapp); - safe_delete(outapp); if(!group->AddMember(nullptr, sgfs->gf.name2, sgfs->CharacterID)) @@ -919,46 +915,35 @@ void WorldServer::Process() { Inviter->CastToClient()->UpdateLFP(); ServerPacket* pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); - ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack2->pBuffer; - gj->gid = group->GetID(); - gj->zoneid = zone->GetZoneID(); - gj->instance_id = zone->GetInstanceID(); - strn0cpy(gj->member_name, sgfs->gf.name2, sizeof(gj->member_name)); - worldserver.SendPacket(pack2); - safe_delete(pack2); + + // Send acknowledgement back to the Invitee to let them know we have added them to the group. - // ServerPacket* pack3 = new ServerPacket(ServerOP_GroupFollowAck, sizeof(ServerGroupFollowAck_Struct)); - ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack3->pBuffer; - strn0cpy(sgfas->Name, sgfs->gf.name2, sizeof(sgfas->Name)); - worldserver.SendPacket(pack3); - safe_delete(pack3); } break; } case ServerOP_GroupFollowAck: { // The Inviter (in another zone) has successfully added the Invitee (in this zone) to the group. - // ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack->pBuffer; - Client *c = entity_list.GetClientByName(sgfas->Name); + Client *client = entity_list.GetClientByName(sgfas->Name); - if(!c) + if(!client) break; - uint32 groupid = database.GetGroupID(c->GetName()); + uint32 groupid = database.GetGroupID(client->GetName()); Group* group = nullptr; @@ -974,26 +959,30 @@ void WorldServer::Process() { entity_list.AddGroup(group, groupid); else group = nullptr; - } //else, somebody from our group is already here... + } if(group) - group->UpdatePlayer(c); + group->UpdatePlayer(client); else { - if(c->GetMerc()) - database.SetGroupID(c->GetMerc()->GetCleanName(), 0, c->CharacterID(), true); - database.SetGroupID(c->GetName(), 0, c->CharacterID()); //cannot re-establish group, kill it + if(client->GetMerc()) + database.SetGroupID(client->GetMerc()->GetCleanName(), 0, client->CharacterID(), true); + database.SetGroupID(client->GetName(), 0, client->CharacterID(), false); //cannot re-establish group, kill it } } if(group) { - database.RefreshGroupFromDB(c); + if (client->GetMerc()) + { + client->GetMerc()->MercJoinClientGroup(); + } + database.RefreshGroupFromDB(client); - group->SendHPPacketsTo(c); + group->SendHPPacketsTo(client); - // If the group leader is not set, pull the group leader infomrmation from the database. + // If the group leader is not set, pull the group leader information from the database. if(!group->GetLeader()) { char ln[64]; @@ -1019,6 +1008,10 @@ void WorldServer::Process() { } } + else if (client->GetMerc()) + { + client->GetMerc()->MercJoinClientGroup(); + } break; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index bfbdb7424..3599a3ff0 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2563,18 +2563,22 @@ void ZoneDatabase::RefreshGroupFromDB(Client *client){ std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %d", group->GetID()); auto results = QueryDatabase(query); if (!results.Success()) - printf("Error in group update query: %s\n", results.ErrorMessage().c_str()); - else + { + printf("Error in group update query: %s\n", results.ErrorMessage().c_str()); + } + else + { for (auto row = results.begin(); row != results.end(); ++row) { if(index >= 6) - continue; + continue; if(strcmp(client->GetName(), row[0]) == 0) - continue; + continue; strcpy(gu->membername[index], row[0]); index++; } + } client->QueuePacket(outapp); safe_delete(outapp);