Grouping with Mercenaries is considerably less buggy.

This commit is contained in:
Trevius 2014-11-22 00:22:12 -06:00
parent b5c6b47639
commit c5a90adb39
12 changed files with 595 additions and 383 deletions

View File

@ -3218,6 +3218,10 @@ void Client::LinkDead()
{ {
entity_list.MessageGroup(this,true,15,"%s has gone linkdead.",GetName()); entity_list.MessageGroup(this,true,15,"%s has gone linkdead.",GetName());
GetGroup()->DelMember(this); GetGroup()->DelMember(this);
if (GetMerc())
{
GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
}
} }
Raid *raid = entity_list.GetRaidByClient(this); Raid *raid = entity_list.GetRaidByClient(this);
if(raid){ if(raid){
@ -4139,6 +4143,184 @@ void Client::UpdateLFP() {
worldserver.UpdateLFP(CharacterID(), LFPMembers); 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() uint16 Client::GetPrimarySkillValue()
{ {
SkillUseTypes skill = HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill 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) if (MERC_DEBUG > 0)
Message(7, "Mercenary Debug: SendMercPersonalInfo Send Successful"); Message(7, "Mercenary Debug: SendMercPersonalInfo Send Successful");
SendMercMerchantResponsePacket(0);
} }
else else
{ {
if (MERC_DEBUG > 0) if (MERC_DEBUG > 0)
Message(7, "Mercenary Debug: SendMercPersonalInfo Send Failed Due to no MercData for %i", GetMercInfo().MercTemplateID); Message(7, "Mercenary Debug: SendMercPersonalInfo Send Failed Due to no MercData for %i", GetMercInfo().MercTemplateID);
} }
SendMercMerchantResponsePacket(0);
} }
void Client::SendClearMercInfo() void Client::SendClearMercInfo()

View File

@ -208,7 +208,7 @@ public:
Client(EQStreamInterface * ieqs); Client(EQStreamInterface * ieqs);
~Client(); ~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 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 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, 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 UnscribeSpellAll(bool update_client = true);
void UntrainDisc(int slot, bool update_client = true); void UntrainDisc(int slot, bool update_client = true);
void UntrainDiscAll(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(); uint32 GetCharMaxLevelFromQGlobal();
inline bool IsSitting() const {return (playeraction == 1);} inline bool IsSitting() const {return (playeraction == 1);}
@ -1098,6 +1098,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst);
void RemoveGroupXTargets(); void RemoveGroupXTargets();
void RemoveAutoXTargets(); void RemoveAutoXTargets();
void ShowXTargets(Client *c); void ShowXTargets(Client *c);
bool GroupFollow(Client* inviter);
void InitializeMercInfo(); void InitializeMercInfo();
bool CheckCanSpawnMerc(uint32 template_id); bool CheckCanSpawnMerc(uint32 template_id);
@ -1105,6 +1106,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst);
bool CheckCanRetainMerc(uint32 upkeep); bool CheckCanRetainMerc(uint32 upkeep);
bool CheckCanUnsuspendMerc(); bool CheckCanUnsuspendMerc();
bool DismissMerc(uint32 MercID); bool DismissMerc(uint32 MercID);
bool MercOnlyOrNoGroup();
inline uint32 GetMercID() const { return mercid; } inline uint32 GetMercID() const { return mercid; }
inline uint8 GetMercSlot() const { return mercSlot; } inline uint8 GetMercSlot() const { return mercSlot; }
void SetMercID( uint32 newmercid) { mercid = newmercid; } void SetMercID( uint32 newmercid) { mercid = newmercid; }

View File

@ -1637,7 +1637,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
} //else, somebody from our group is already here... } //else, somebody from our group is already here...
if (!group) 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 else { //no group id
@ -6403,7 +6403,10 @@ void Client::Handle_OP_GroupCancelInvite(const EQApplicationPacket *app)
safe_delete(pack); safe_delete(pack);
} }
database.SetGroupID(GetName(), 0, CharacterID()); if (!GetMerc())
{
database.SetGroupID(GetName(), 0, CharacterID(), false);
}
return; return;
} }
@ -6433,7 +6436,8 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
GroupGeneric_Struct* gd = (GroupGeneric_Struct*)app->pBuffer; GroupGeneric_Struct* gd = (GroupGeneric_Struct*)app->pBuffer;
Raid *raid = entity_list.GetRaidByClient(this); Raid *raid = entity_list.GetRaidByClient(this);
if (raid){ if (raid)
{
Mob* memberToDisband = nullptr; Mob* memberToDisband = nullptr;
if (!raid->IsGroupLeader(GetName())) if (!raid->IsGroupLeader(GetName()))
@ -6500,93 +6504,80 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
} }
} }
#endif #endif
if ((group->IsLeader(this) && (GetTarget() == 0 || GetTarget() == this)) || (group->GroupCount()<3)) { if (group->GroupCount() < 3)
{
group->DisbandGroup(); group->DisbandGroup();
if (GetMerc() != nullptr) if (GetMerc())
GetMerc()->Suspend(); 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; Mob* memberToDisband = nullptr;
memberToDisband = GetTarget(); memberToDisband = GetTarget();
if (!memberToDisband) if (!memberToDisband)
memberToDisband = entity_list.GetMob(gd->name2); memberToDisband = entity_list.GetMob(gd->name2);
if (memberToDisband) { if (memberToDisband)
if (group->IsLeader(this)) { {
if (group->IsLeader(this))
{
// the group leader can kick other members out of the group... // the group leader can kick other members out of the group...
//group->DelMember(memberToDisband,false);
if (memberToDisband->IsClient()) if (memberToDisband->IsClient())
{ {
group->DelMember(memberToDisband, false); group->DelMember(memberToDisband, false);
Client* memberClient = memberToDisband->CastToClient(); Client* memberClient = memberToDisband->CastToClient();
Merc* memberMerc = memberToDisband->CastToClient()->GetMerc(); Merc* memberMerc = memberToDisband->CastToClient()->GetMerc();
if (memberClient && memberMerc && group) if (memberClient && memberMerc)
{ {
if (!memberMerc->IsGrouped() && !memberClient->IsGrouped()) { memberMerc->MercJoinClientGroup();
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);
}
}
} }
} }
else if (memberToDisband->IsMerc()) { else if (memberToDisband->IsMerc())
{
memberToDisband->CastToMerc()->Suspend(); memberToDisband->CastToMerc()->Suspend();
} }
} }
else { else
{
// ...but other members can only remove themselves // ...but other members can only remove themselves
group->DelMember(this, false); group->DelMember(this, false);
if (!IsGrouped() && GetMerc() != nullptr) { if (GetMerc() && !GetMerc()->IsSuspended())
if (!IsGrouped()) { {
Group *g = new Group(this); GetMerc()->MercJoinClientGroup();
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();
}
}
} }
} }
} }
else else
{
LogFile->write(EQEMuLog::Error, "Failed to remove player from group. Unable to find player named %s in player group", gd->name2); 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. // If we are looking for players, update to show we are on our own now.
UpdateLFP(); UpdateLFP();
} }
@ -6616,157 +6607,22 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app)
GroupGeneric_Struct* gf = (GroupGeneric_Struct*)app->pBuffer; GroupGeneric_Struct* gf = (GroupGeneric_Struct*)app->pBuffer;
Mob* inviter = entity_list.GetClientByName(gf->name1); Mob* inviter = entity_list.GetClientByName(gf->name1);
if (inviter != nullptr && inviter->IsClient()) { // Inviter and Invitee are in the same zone
isgrouped = true; if (inviter != nullptr && inviter->IsClient())
strn0cpy(gf->name1, inviter->GetName(), 64); {
strn0cpy(gf->name2, this->GetName(), 64); if (GroupFollow(inviter->CastToClient()))
{
Raid* raid = entity_list.GetRaidByClient(inviter->CastToClient()); strn0cpy(gf->name1, inviter->GetName(), sizeof(gf->name1));
Raid* iraid = entity_list.GetRaidByClient(this); strn0cpy(gf->name2, GetName(), sizeof(gf->name2));
inviter->CastToClient()->QueuePacket(app);//notify inviter the client accepted
//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;
}
}
} }
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) 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)); ServerPacket* pack = new ServerPacket(ServerOP_GroupFollow, sizeof(ServerGroupFollow_Struct));
ServerGroupFollow_Struct *sgfs = (ServerGroupFollow_Struct *)pack->pBuffer; ServerGroupFollow_Struct *sgfs = (ServerGroupFollow_Struct *)pack->pBuffer;
sgfs->CharacterID = CharacterID(); sgfs->CharacterID = CharacterID();
@ -6801,10 +6657,11 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
return; return;
} }
if (Invitee) { if (Invitee)
if (Invitee->IsClient()) { {
if ((!Invitee->IsGrouped() && !Invitee->IsRaidGrouped()) || if (Invitee->IsClient())
(Invitee->GetGroup() && Invitee->CastToClient()->GetMerc() && Invitee->GetGroup()->GroupCount() == 2)) {
if(Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped())
{ {
if (app->GetOpcode() == OP_GroupInvite2) if (app->GetOpcode() == OP_GroupInvite2)
{ {
@ -9507,7 +9364,8 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
Merc* merc = GetMerc(); Merc* merc = GetMerc();
GetMercInfo().State = option; GetMercInfo().State = option;
if (merc) { if (merc)
{
uint8 numStances = 0; uint8 numStances = 0;
//get number of available stances for the current merc //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()); 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) //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]); merc->SetStance(mercTemplate->Stances[option]);
GetMercInfo().Stance = 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); Message(7, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command);
// Handle the dismiss here... // 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); MercTemplate* merc_template = zone->GetMercTemplate(merc_template_id);
if (merc_template) { if (merc_template)
{
Mob* merchant = entity_list.GetNPCByID(merchant_id); Mob* merchant = entity_list.GetNPCByID(merchant_id);
if (!CheckCanHireMerc(merchant, merc_template_id)) { if (!CheckCanHireMerc(merchant, merc_template_id))
{
return; return;
} }
@ -9762,7 +9623,8 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
SpawnMerc(merc, true); SpawnMerc(merc, true);
merc->Save(); merc->Save();
if (RuleB(Mercs, ChargeMercPurchaseCost)) { if (RuleB(Mercs, ChargeMercPurchaseCost))
{
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true); TakeMoneyFromPP(cost, true);
} }
@ -9770,12 +9632,14 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
// 0 is approved hire request // 0 is approved hire request
SendMercMerchantResponsePacket(0); SendMercMerchantResponsePacket(0);
} }
else { else
{
//merc failed to spawn //merc failed to spawn
SendMercMerchantResponsePacket(3); SendMercMerchantResponsePacket(3);
} }
} }
else { else
{
//merc doesn't exist in db //merc doesn't exist in db
SendMercMerchantResponsePacket(2); SendMercMerchantResponsePacket(2);
} }

View File

@ -245,7 +245,6 @@ bool Client::Process() {
if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended) if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended)
{ {
//CheckMercSuspendTimer();
if(p_timers.Expired(&database, pTimerMercSuspend, false)) if(p_timers.Expired(&database, pTimerMercSuspend, false))
{ {
CheckMercSuspendTimer(); CheckMercSuspendTimer();
@ -746,9 +745,9 @@ bool Client::Process() {
{ {
entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName()); entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName());
mygroup->MemberZoned(this); mygroup->MemberZoned(this);
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == mygroup) if (GetMerc() && GetMerc()->HasGroup())
{ {
mygroup->DelMember(GetMerc()); GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
} }
} }

View File

@ -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 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* // 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. // and the name and CharacterID of the new member, if they are out of zone.
//
if(!newmember && !NewMemberName) if(!newmember && !NewMemberName)
return false; {
return false;
}
if(GroupCount() >= MAX_GROUP_MEMBERS) //Sanity check for merging groups together. if(GroupCount() >= MAX_GROUP_MEMBERS) //Sanity check for merging groups together.
{
return false; return false;
}
if(!newmember) if(!newmember)
{
InZone = false; InZone = false;
}
else else
{ {
NewMemberName = newmember->GetCleanName(); NewMemberName = newmember->GetCleanName();
if(newmember->IsClient()) if(newmember->IsClient())
{
CharacterID = newmember->CastToClient()->CharacterID(); CharacterID = newmember->CastToClient()->CharacterID();
}
if(newmember->IsMerc()) if(newmember->IsMerc())
{ {
Client* owner = newmember->CastToMerc()->GetMercOwner(); Client* owner = newmember->CastToMerc()->GetMercOwner();
@ -232,18 +238,20 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
{ {
CharacterID = owner->CastToClient()->CharacterID(); CharacterID = owner->CastToClient()->CharacterID();
NewMemberName = newmember->GetName(); NewMemberName = newmember->GetName();
ismerc = true;
} }
ismerc = true;
} }
} }
uint32 i = 0;
// See if they are already in the group // See if they are already in the group
// uint32 i = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; ++i) for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if(!strcasecmp(membername[i], NewMemberName)) if(!strcasecmp(membername[i], NewMemberName))
{
return false; return false;
}
}
// Put them in the group // Put them in the group
for (i = 0; i < MAX_GROUP_MEMBERS; ++i) 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 (membername[i][0] == '\0')
{ {
if(InZone) if(InZone)
{
members[i] = newmember; members[i] = newmember;
}
strcpy(membername[i], NewMemberName);
MemberRoles[i] = 0;
break; break;
} }
} }
// Is this even possible based on the above loops? Remove?
if (i == MAX_GROUP_MEMBERS) if (i == MAX_GROUP_MEMBERS)
{
return false; return false;
}
strcpy(membername[i], NewMemberName);
MemberRoles[i] = 0;
int x=1; int x=1;
@ -270,11 +281,12 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer;
strcpy(gj->membername, NewMemberName); strcpy(gj->membername, NewMemberName);
gj->action = groupActJoin; gj->action = groupActJoin;
gj->leader_aas = LeaderAbilities; gj->leader_aas = LeaderAbilities;
for (i = 0;i < MAX_GROUP_MEMBERS; i++) { for (i = 0;i < MAX_GROUP_MEMBERS; i++)
if (members[i] != nullptr && members[i] != newmember) { {
if (members[i] != nullptr && members[i] != newmember)
{
//fill in group join & send it //fill in group join & send it
if(members[i]->IsMerc()) if(members[i]->IsMerc())
{ {
@ -284,18 +296,23 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
{ {
strcpy(gj->yourname, members[i]->GetCleanName()); strcpy(gj->yourname, members[i]->GetCleanName());
} }
if(members[i]->IsClient()) { if(members[i]->IsClient())
{
members[i]->CastToClient()->QueuePacket(outapp); 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); strcpy(members[i]->CastToClient()->GetPP().groupMembers[this->GroupCount()-1], NewMemberName);
} }
//put this existing person into the new member's list //put existing group member(s) into the new member's list
if(InZone && newmember->IsClient()) { if(InZone && newmember->IsClient())
{
if(IsLeader(members[i])) if(IsLeader(members[i]))
{
strcpy(newmember->CastToClient()->GetPP().groupMembers[0], members[i]->GetCleanName()); strcpy(newmember->CastToClient()->GetPP().groupMembers[0], members[i]->GetCleanName());
else { }
else
{
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName()); strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName());
x++; x++;
} }
@ -337,7 +354,9 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
#endif //BOTS #endif //BOTS
} }
else else
{
database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc); database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc);
}
safe_delete(outapp); safe_delete(outapp);
@ -512,6 +531,30 @@ void Group::MemberZoned(Mob* removemob) {
mentoree = nullptr; 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) { bool Group::DelMemberOOZ(const char *Name) {
if(!Name) return false; if(!Name) return false;
@ -619,7 +662,8 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
#endif //BOTS #endif //BOTS
} }
if (!ignoresender) { if (!ignoresender)
{
strcpy(gu->yourname,oldmember->GetCleanName()); strcpy(gu->yourname,oldmember->GetCleanName());
strcpy(gu->membername,oldmember->GetCleanName()); strcpy(gu->membername,oldmember->GetCleanName());
gu->action = groupActLeave; gu->action = groupActLeave;
@ -629,7 +673,18 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
} }
if(oldmember->IsClient()) 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); oldmember->SetGrouped(false);
disbandcheck = true; disbandcheck = true;
@ -819,20 +874,33 @@ void Group::DisbandGroup() {
Client *Leader = nullptr; Client *Leader = nullptr;
uint32 i; uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) { for (i = 0; i < MAX_GROUP_MEMBERS; i++)
if (members[i] == nullptr) { {
if (members[i] == nullptr)
{
continue; continue;
} }
if (members[i]->IsClient()) { if (members[i]->IsClient())
{
if(IsLeader(members[i])) if(IsLeader(members[i]))
{
Leader = members[i]->CastToClient(); Leader = members[i]->CastToClient();
}
strcpy(gu->yourname, members[i]->GetName()); 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); members[i]->CastToClient()->QueuePacket(outapp);
SendMarkedNPCsToMember(members[i]->CastToClient(), true); 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); members[i]->SetGrouped(false);
@ -852,9 +920,12 @@ void Group::DisbandGroup() {
entity_list.RemoveGroup(GetID()); entity_list.RemoveGroup(GetID());
if(GetID() != 0) if(GetID() != 0)
{
database.ClearGroup(GetID()); database.ClearGroup(GetID());
}
if(Leader && (Leader->IsLFP())) { if(Leader && (Leader->IsLFP()))
{
Leader->UpdateLFP(); Leader->UpdateLFP();
} }
@ -936,8 +1007,12 @@ uint8 Group::GroupCount() {
uint8 MemberCount = 0; uint8 MemberCount = 0;
for(uint8 i = 0; i < MAX_GROUP_MEMBERS; ++i) for(uint8 i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if(membername[i][0]) if(membername[i][0])
{
++MemberCount; ++MemberCount;
}
}
return MemberCount; return MemberCount;
} }
@ -1071,7 +1146,14 @@ void Client::LeaveGroup() {
if(g) 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(); g->DisbandGroup();
} }
@ -1080,17 +1162,17 @@ void Client::LeaveGroup() {
g->DelMember(this); g->DelMember(this);
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g) if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g)
{ {
g->DelMember(GetMerc()); GetMerc()->RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup());
} }
} }
} }
else else
{ {
//force things a little //force things a little
database.SetGroupID(GetName(), 0, CharacterID()); database.SetGroupID(GetName(), 0, CharacterID(), false);
if (GetMerc()) if (GetMerc())
{ {
database.SetGroupID(GetMerc()->GetName(), 0, CharacterID()); database.SetGroupID(GetMerc()->GetName(), 0, CharacterID(), true);
} }
} }

View File

@ -51,7 +51,7 @@ public:
Group(uint32 gid); Group(uint32 gid);
~Group(); ~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 AddMember(const char* NewMemberName);
void SendUpdate(uint32 type,Mob* member); void SendUpdate(uint32 type,Mob* member);
void SendLeadershipAAUpdate(); void SendLeadershipAAUpdate();
@ -63,6 +63,7 @@ public:
bool IsGroupMember(const char *Name); bool IsGroupMember(const char *Name);
bool Process(); bool Process();
bool IsGroup() { return true; } bool IsGroup() { return true; }
void SendGroupJoinOOZ(Mob* NewMember);
void CastGroupSpell(Mob* caster,uint16 spellid); void CastGroupSpell(Mob* caster,uint16 spellid);
void GroupBardPulse(Mob* caster,uint16 spellid); void GroupBardPulse(Mob* caster,uint16 spellid);
void SplitExp(uint32 exp, Mob* other); void SplitExp(uint32 exp, Mob* other);

View File

@ -1287,8 +1287,8 @@ bool Merc::Process()
if (GetDepop()) if (GetDepop())
{ {
//SetMercCharacterID(0); SetMercCharacterID(0);
//SetOwnerID(0); SetOwnerID(0);
return false; return false;
} }
@ -1297,7 +1297,8 @@ bool Merc::Process()
//return false; //merc can live after client dies, not sure how long //return false; //merc can live after client dies, not sure how long
} }
if(IsSuspended()) { if(IsSuspended())
{
return false; return false;
} }
@ -5368,12 +5369,14 @@ bool Client::CheckCanRetainMerc(uint32 upkeep) {
bool Client::CheckCanSpawnMerc(uint32 template_id) { bool Client::CheckCanSpawnMerc(uint32 template_id) {
// Check if mercs are enabled globally // Check if mercs are enabled globally
if(!RuleB(Mercs, AllowMercs)) { if(!RuleB(Mercs, AllowMercs))
{
return false; return false;
} }
// Check if zone allows mercs // Check if zone allows mercs
if(!zone->AllowMercs()) { if(!zone->AllowMercs())
{
SendMercResponsePackets(3); SendMercResponsePackets(3);
return false; return false;
} }
@ -5381,31 +5384,36 @@ bool Client::CheckCanSpawnMerc(uint32 template_id) {
MercTemplate* mercTemplate = zone->GetMercTemplate(template_id); MercTemplate* mercTemplate = zone->GetMercTemplate(template_id);
// Invalid merc data // Invalid merc data
if(!mercTemplate) { if(!mercTemplate)
{
SendMercResponsePackets(11); SendMercResponsePackets(11);
return false; return false;
} }
// Check client version // Check client version
if(GetClientVersion() < mercTemplate->ClientVersion) { if(GetClientVersion() < mercTemplate->ClientVersion)
{
SendMercResponsePackets(3); SendMercResponsePackets(3);
return false; return false;
} }
// Check for raid // Check for raid
if(HasRaid()) { if(HasRaid())
{
SendMercResponsePackets(4); SendMercResponsePackets(4);
return false; return false;
} }
// Check group size // Check group size
if(HasGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) { if(GetGroup() && GetGroup()->GroupCount() >= MAX_GROUP_MEMBERS) // database.GroupCount(GetGroup()->GetID())
{
SendMercResponsePackets(8); SendMercResponsePackets(8);
return false; return false;
} }
// Check in combat // Check in combat
if(GetAggroCount() > 0) { if(GetAggroCount() > 0)
{
SendMercResponsePackets(9); SendMercResponsePackets(9);
return false; return false;
} }
@ -5584,6 +5592,10 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) {
if (!merc || !CheckCanSpawnMerc(merc->GetMercTemplateID())) if (!merc || !CheckCanSpawnMerc(merc->GetMercTemplateID()))
{ {
if (merc)
{
merc->Suspend();
}
return; return;
} }
@ -5618,9 +5630,7 @@ bool Merc::Suspend() {
mercOwner->GetMercInfo().Stance = GetStance(); mercOwner->GetMercInfo().Stance = GetStance();
Save(); Save();
mercOwner->GetMercTimer()->Disable(); mercOwner->GetMercTimer()->Disable();
mercOwner->SendMercSuspendResponsePacket(mercOwner->GetMercInfo().SuspendedTime); mercOwner->SendMercSuspendResponsePacket(mercOwner->GetMercInfo().SuspendedTime);
mercOwner->SendMercTimer(this); mercOwner->SendMercTimer(this);
Depop(); Depop();
@ -5634,6 +5644,25 @@ bool Merc::Suspend() {
return true; 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) { bool Merc::Unsuspend(bool setMaxStats) {
Client* mercOwner = nullptr; Client* mercOwner = nullptr;
@ -5657,65 +5686,15 @@ bool Merc::Unsuspend(bool setMaxStats) {
mercOwner->SendMercenaryUnsuspendPacket(0); mercOwner->SendMercenaryUnsuspendPacket(0);
mercOwner->SendMercenaryUnknownPacket(1); mercOwner->SendMercenaryUnknownPacket(1);
mercOwner->GetMercInfo().SuspendedTime = 0; mercOwner->GetMercInfo().SuspendedTime = 0;
// Reset the upkeep timer
mercOwner->GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
mercOwner->GetMercTimer()->Start(RuleI(Mercs, UpkeepIntervalMS)); mercOwner->GetMercTimer()->Start(RuleI(Mercs, UpkeepIntervalMS));
mercOwner->GetMercTimer()->SetTimer(mercOwner->GetMercInfo().MercTimerRemaining); //mercOwner->GetMercTimer()->SetTimer(mercOwner->GetMercInfo().MercTimerRemaining);
mercOwner->SendMercTimer(this); mercOwner->SendMercTimer(this);
if(!mercOwner->GetPTimers().Expired(&database, pTimerMercSuspend, false)) if(!mercOwner->GetPTimers().Expired(&database, pTimerMercSuspend, false))
mercOwner->GetPTimers().Clear(&database, pTimerMercSuspend); mercOwner->GetPTimers().Clear(&database, pTimerMercSuspend);
//mercOwner->SendMercPersonalInfo(); MercJoinClientGroup();
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();
}
if(loaded) if(loaded)
{ {
@ -5788,7 +5767,7 @@ void Merc::Depop() {
entity_list.RemoveFromHateLists(this); entity_list.RemoveFromHateLists(this);
if(HasGroup()) if(GetGroup())
{ {
RemoveMercFromGroup(this, GetGroup()); RemoveMercFromGroup(this, GetGroup());
} }
@ -5820,7 +5799,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
if(group->DelMember(merc, true)) if(group->DelMember(merc, true))
{ {
if(merc->GetMercCharacterID() != 0) if(merc->GetMercCharacterID() != 0)
{
database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true); database.SetGroupID(merc->GetName(), 0, merc->GetMercCharacterID(), true);
}
} }
if(group->GroupCount() <= 1 && ZoneLoaded) if(group->GroupCount() <= 1 && ZoneLoaded)
@ -5830,6 +5811,17 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
} }
else 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++) for(int i = 0; i < MAX_GROUP_MEMBERS; i++)
{ {
if(!group->members[i]) if(!group->members[i])
@ -5838,15 +5830,9 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
if(!group->members[i]->IsMerc()) if(!group->members[i]->IsMerc())
continue; continue;
Merc* groupmerc = group->members[i]->CastToMerc(); group->members[i]->CastToMerc()->MercJoinClientGroup();
//groupmerc->SetOwnerID(0);
if (!groupmerc->IsSuspended())
{
groupmerc->Suspend();
database.SetGroupID(groupmerc->GetCleanName(), 0, groupmerc->GetMercCharacterID(), true);
}
} }
// Group should be removed by now, but just in case:
group->DisbandGroup(); group->DisbandGroup();
} }
@ -5857,16 +5843,112 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
return Result; 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 Merc::AddMercToGroup(Merc* merc, Group* group) {
bool Result = false; bool Result = false;
if(merc && group) { if(merc && group) {
// Remove merc from current group if any // Remove merc from current group if it's not the destination group
if(merc->HasGroup()) { 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()); merc->RemoveMercFromGroup(merc, merc->GetGroup());
} }
//Try and add the member, followed by checking if the merc owner exists. //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()); merc->SetFollowID(merc->GetMercOwner()->GetID());
Result = true; Result = true;

View File

@ -138,6 +138,7 @@ public:
bool Spawn(Client *owner); bool Spawn(Client *owner);
bool Suspend(); bool Suspend();
bool Unsuspend(bool setMaxStats); bool Unsuspend(bool setMaxStats);
bool MercJoinClientGroup();
void Zone(); void Zone();
virtual void Depop(); virtual void Depop();
virtual bool Save(); virtual bool Save();

View File

@ -907,7 +907,7 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
uint16 book_slot, count; uint16 book_slot, count;
uint16 curspell; uint16 curspell;
uint16 Char_ID = initiator->CharacterID(); uint32 Char_ID = initiator->CharacterID();
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals); bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
bool SpellGlobalCheckResult = 0; bool SpellGlobalCheckResult = 0;

View File

@ -4928,7 +4928,7 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
return -1; //default 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; std::string spell_Global_Name;
int spell_Global_Value; int spell_Global_Value;

View File

@ -831,12 +831,11 @@ void WorldServer::Process() {
} }
case ServerOP_GroupInvite: { case ServerOP_GroupInvite: {
// A player in another zone invited a player in this zone to join their group. // A player in another zone invited a player in this zone to join their group.
//
GroupInvite_Struct* gis = (GroupInvite_Struct*)pack->pBuffer; GroupInvite_Struct* gis = (GroupInvite_Struct*)pack->pBuffer;
Mob *Invitee = entity_list.GetMob(gis->invitee_name); 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)); EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct));
memcpy(outapp->pBuffer, gis, sizeof(GroupInvite_Struct)); memcpy(outapp->pBuffer, gis, sizeof(GroupInvite_Struct));
@ -848,7 +847,6 @@ void WorldServer::Process() {
} }
case ServerOP_GroupFollow: { case ServerOP_GroupFollow: {
// Player in another zone accepted a group invitation from a player in this zone. // Player in another zone accepted a group invitation from a player in this zone.
//
ServerGroupFollow_Struct* sgfs = (ServerGroupFollow_Struct*) pack->pBuffer; ServerGroupFollow_Struct* sgfs = (ServerGroupFollow_Struct*) pack->pBuffer;
Mob* Inviter = entity_list.GetClientByName(sgfs->gf.name1); Mob* Inviter = entity_list.GetClientByName(sgfs->gf.name1);
@ -857,12 +855,15 @@ void WorldServer::Process() {
{ {
Group* group = entity_list.GetGroupByClient(Inviter->CastToClient()); Group* group = entity_list.GetGroupByClient(Inviter->CastToClient());
if(!group){ if(!group)
{
//Make new group
group = new Group(Inviter); group = new Group(Inviter);
if(!group) if (!group)
{
break; break;
}
entity_list.AddGroup(group); entity_list.AddGroup(group);
@ -871,10 +872,8 @@ void WorldServer::Process() {
break; 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()); database.SetGroupLeaderName(group->GetID(), Inviter->GetName());
group->UpdateGroupAAs(); group->UpdateGroupAAs();
if(Inviter->CastToClient()->GetClientVersion() < EQClientSoD) if(Inviter->CastToClient()->GetClientVersion() < EQClientSoD)
@ -891,25 +890,22 @@ void WorldServer::Process() {
else else
{ {
// SoD and later // SoD and later
//
Inviter->CastToClient()->SendGroupCreatePacket(); Inviter->CastToClient()->SendGroupCreatePacket();
Inviter->CastToClient()->SendGroupLeaderChangePacket(Inviter->GetName()); Inviter->CastToClient()->SendGroupLeaderChangePacket(Inviter->GetName());
Inviter->CastToClient()->SendGroupJoinAcknowledge(); Inviter->CastToClient()->SendGroupJoinAcknowledge();
} }
} }
if(!group) if(!group)
{
break; break;
}
EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct)); EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct));
GroupGeneric_Struct *gg = (GroupGeneric_Struct *)outapp->pBuffer; GroupGeneric_Struct *gg = (GroupGeneric_Struct *)outapp->pBuffer;
strn0cpy(gg->name1, sgfs->gf.name1, sizeof(gg->name1)); strn0cpy(gg->name1, sgfs->gf.name1, sizeof(gg->name1));
strn0cpy(gg->name2, sgfs->gf.name2, sizeof(gg->name2)); strn0cpy(gg->name2, sgfs->gf.name2, sizeof(gg->name2));
Inviter->CastToClient()->QueuePacket(outapp); Inviter->CastToClient()->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
if(!group->AddMember(nullptr, sgfs->gf.name2, sgfs->CharacterID)) if(!group->AddMember(nullptr, sgfs->gf.name2, sgfs->CharacterID))
@ -919,46 +915,35 @@ void WorldServer::Process() {
Inviter->CastToClient()->UpdateLFP(); Inviter->CastToClient()->UpdateLFP();
ServerPacket* pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); ServerPacket* pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct));
ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack2->pBuffer; ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack2->pBuffer;
gj->gid = group->GetID(); gj->gid = group->GetID();
gj->zoneid = zone->GetZoneID(); gj->zoneid = zone->GetZoneID();
gj->instance_id = zone->GetInstanceID(); gj->instance_id = zone->GetInstanceID();
strn0cpy(gj->member_name, sgfs->gf.name2, sizeof(gj->member_name)); strn0cpy(gj->member_name, sgfs->gf.name2, sizeof(gj->member_name));
worldserver.SendPacket(pack2); worldserver.SendPacket(pack2);
safe_delete(pack2); safe_delete(pack2);
// Send acknowledgement back to the Invitee to let them know we have added them to the group. // 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)); ServerPacket* pack3 = new ServerPacket(ServerOP_GroupFollowAck, sizeof(ServerGroupFollowAck_Struct));
ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack3->pBuffer; ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack3->pBuffer;
strn0cpy(sgfas->Name, sgfs->gf.name2, sizeof(sgfas->Name)); strn0cpy(sgfas->Name, sgfs->gf.name2, sizeof(sgfas->Name));
worldserver.SendPacket(pack3); worldserver.SendPacket(pack3);
safe_delete(pack3); safe_delete(pack3);
} }
break; break;
} }
case ServerOP_GroupFollowAck: { case ServerOP_GroupFollowAck: {
// The Inviter (in another zone) has successfully added the Invitee (in this zone) to the group. // The Inviter (in another zone) has successfully added the Invitee (in this zone) to the group.
//
ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack->pBuffer; 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; break;
uint32 groupid = database.GetGroupID(c->GetName()); uint32 groupid = database.GetGroupID(client->GetName());
Group* group = nullptr; Group* group = nullptr;
@ -974,26 +959,30 @@ void WorldServer::Process() {
entity_list.AddGroup(group, groupid); entity_list.AddGroup(group, groupid);
else else
group = nullptr; group = nullptr;
} //else, somebody from our group is already here... }
if(group) if(group)
group->UpdatePlayer(c); group->UpdatePlayer(client);
else else
{ {
if(c->GetMerc()) if(client->GetMerc())
database.SetGroupID(c->GetMerc()->GetCleanName(), 0, c->CharacterID(), true); database.SetGroupID(client->GetMerc()->GetCleanName(), 0, client->CharacterID(), true);
database.SetGroupID(c->GetName(), 0, c->CharacterID()); //cannot re-establish group, kill it database.SetGroupID(client->GetName(), 0, client->CharacterID(), false); //cannot re-establish group, kill it
} }
} }
if(group) 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()) if(!group->GetLeader())
{ {
char ln[64]; char ln[64];
@ -1019,6 +1008,10 @@ void WorldServer::Process() {
} }
} }
else if (client->GetMerc())
{
client->GetMerc()->MercJoinClientGroup();
}
break; break;
} }

View File

@ -2563,18 +2563,22 @@ void ZoneDatabase::RefreshGroupFromDB(Client *client){
std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %d", group->GetID()); std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %d", group->GetID());
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) 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) { for (auto row = results.begin(); row != results.end(); ++row) {
if(index >= 6) if(index >= 6)
continue; continue;
if(strcmp(client->GetName(), row[0]) == 0) if(strcmp(client->GetName(), row[0]) == 0)
continue; continue;
strcpy(gu->membername[index], row[0]); strcpy(gu->membername[index], row[0]);
index++; index++;
} }
}
client->QueuePacket(outapp); client->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);