mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Rework how XTarget auto haters work
This should cause the auto haters to be shared with other toons who might be interested (group/raid) like live. There maybe some bugs since there is a lot of complex interactions here.
This commit is contained in:
parent
8177f7d9bb
commit
9f4604ec3e
@ -122,6 +122,7 @@ SET(zone_sources
|
||||
water_map_v2.cpp
|
||||
waypoints.cpp
|
||||
worldserver.cpp
|
||||
xtargetautohaters.cpp
|
||||
zone.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
@ -215,6 +216,7 @@ SET(zone_headers
|
||||
water_map_v1.h
|
||||
water_map_v2.h
|
||||
worldserver.h
|
||||
xtargetautohaters.h
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
|
||||
@ -2432,9 +2432,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
Mob* mypet = this->GetPet();
|
||||
Mob* myowner = this->GetOwner();
|
||||
Mob* targetmob = this->GetTarget();
|
||||
bool on_hatelist = CheckAggro(other);
|
||||
|
||||
if(other){
|
||||
bool on_hatelist = CheckAggro(other);
|
||||
AddRampage(other);
|
||||
if (on_hatelist) { // odd reason, if you're not on the hate list, subtlety etc don't apply!
|
||||
// Spell Casting Subtlety etc
|
||||
@ -2510,7 +2510,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
|
||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||
|
||||
if(other->IsClient())
|
||||
if(other->IsClient() && !on_hatelist)
|
||||
other->CastToClient()->AddAutoXTarget(this);
|
||||
|
||||
#ifdef BOTS
|
||||
@ -2549,7 +2549,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
if(!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
{
|
||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||
if(owner->IsClient())
|
||||
if(owner->IsClient() && !CheckAggro(owner))
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
194
zone/client.cpp
194
zone/client.cpp
@ -310,6 +310,8 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
}
|
||||
MaxXTargets = 5;
|
||||
XTargetAutoAddHaters = true;
|
||||
m_autohatermgr.SetOwner(this, nullptr, nullptr);
|
||||
m_activeautohatermgr = &m_autohatermgr;
|
||||
LoadAccountFlags();
|
||||
|
||||
initial_respawn_selection = 0;
|
||||
@ -4159,6 +4161,18 @@ bool Client::GroupFollow(Client* inviter) {
|
||||
}
|
||||
if (raid->RaidCount() < MAX_RAID_MEMBERS)
|
||||
{
|
||||
// okay, so we now have a single client (this) joining a group in a raid
|
||||
// And they're not already in the raid (which is above and doesn't need xtarget shit)
|
||||
if (!GetXTargetAutoMgr()->empty()) {
|
||||
raid->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr());
|
||||
GetXTargetAutoMgr()->clear();
|
||||
RemoveAutoXTargets();
|
||||
}
|
||||
|
||||
SetXTargetAutoMgr(GetXTargetAutoMgr());
|
||||
if (!GetXTargetAutoMgr()->empty())
|
||||
SetDirtyAutoHaters();
|
||||
|
||||
if (raid->GroupCount(groupToUse) < 6)
|
||||
{
|
||||
raid->SendRaidCreate(this);
|
||||
@ -4234,7 +4248,9 @@ bool Client::GroupFollow(Client* inviter) {
|
||||
inviter->SendGroupLeaderChangePacket(inviter->GetName());
|
||||
inviter->SendGroupJoinAcknowledge();
|
||||
}
|
||||
|
||||
group->GetXTargetAutoMgr()->merge(*inviter->GetXTargetAutoMgr());
|
||||
inviter->GetXTargetAutoMgr()->clear();
|
||||
inviter->SetXTargetAutoMgr(group->GetXTargetAutoMgr());
|
||||
}
|
||||
|
||||
if (!group)
|
||||
@ -7171,12 +7187,12 @@ void Client::UpdateClientXTarget(Client *c)
|
||||
}
|
||||
}
|
||||
|
||||
// IT IS NOT SAFE TO CALL THIS IF IT'S NOT INITIAL AGGRO
|
||||
void Client::AddAutoXTarget(Mob *m, bool send)
|
||||
{
|
||||
if(!XTargettingAvailable() || !XTargetAutoAddHaters)
|
||||
return;
|
||||
m_activeautohatermgr->increment_count(m);
|
||||
|
||||
if(IsXTarget(m))
|
||||
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m))
|
||||
return;
|
||||
|
||||
for(int i = 0; i < GetMaxXTargets(); ++i)
|
||||
@ -7195,60 +7211,15 @@ void Client::AddAutoXTarget(Mob *m, bool send)
|
||||
|
||||
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
|
||||
{
|
||||
if (!XTargettingAvailable())
|
||||
return;
|
||||
|
||||
bool HadFreeAutoSlotsBefore = false;
|
||||
|
||||
int FreedAutoSlots = 0;
|
||||
|
||||
if (m->GetID() == 0)
|
||||
return;
|
||||
|
||||
m_activeautohatermgr->decrement_count(m);
|
||||
// now we may need to clean up our CurrentTargetNPC entries
|
||||
for (int i = 0; i < GetMaxXTargets(); ++i) {
|
||||
if (OnlyAutoSlots && XTargets[i].Type != Auto)
|
||||
continue;
|
||||
|
||||
if (XTargets[i].ID == m->GetID()) {
|
||||
if (XTargets[i].Type == CurrentTargetNPC)
|
||||
XTargets[i].Type = Auto;
|
||||
|
||||
if (XTargets[i].Type == Auto)
|
||||
++FreedAutoSlots;
|
||||
|
||||
if (XTargets[i].Type == CurrentTargetNPC && XTargets[i].ID == m->GetID()) {
|
||||
XTargets[i].Type = Auto;
|
||||
XTargets[i].ID = 0;
|
||||
XTargets[i].dirty = true;
|
||||
} else {
|
||||
if (XTargets[i].Type == Auto && XTargets[i].ID == 0)
|
||||
HadFreeAutoSlotsBefore = true;
|
||||
}
|
||||
}
|
||||
|
||||
// move shit up! If the removed NPC was in a CurrentTargetNPC slot it becomes Auto
|
||||
// and we need to potentially fill it
|
||||
std::queue<int> empty_slots;
|
||||
for (int i = 0; i < GetMaxXTargets(); ++i) {
|
||||
if (XTargets[i].Type != Auto)
|
||||
continue;
|
||||
|
||||
if (XTargets[i].ID == 0) {
|
||||
empty_slots.push(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (XTargets[i].ID != 0 && !empty_slots.empty()) {
|
||||
int temp = empty_slots.front();
|
||||
std::swap(XTargets[i], XTargets[temp]);
|
||||
XTargets[i].dirty = XTargets[temp].dirty = true;
|
||||
empty_slots.pop();
|
||||
empty_slots.push(i);
|
||||
}
|
||||
}
|
||||
// If there are more mobs aggro on us than we had auto-hate slots, add one of those haters into the slot(s) we
|
||||
// just freed up.
|
||||
if (!HadFreeAutoSlotsBefore && FreedAutoSlots)
|
||||
entity_list.RefreshAutoXTargets(this);
|
||||
SendXTargetUpdates();
|
||||
}
|
||||
|
||||
void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name)
|
||||
@ -7405,6 +7376,123 @@ void Client::ShowXTargets(Client *c)
|
||||
|
||||
for(int i = 0; i < GetMaxXTargets(); ++i)
|
||||
c->Message(0, "Xtarget Slot: %i, Type: %2i, ID: %4i, Name: %s", i, XTargets[i].Type, XTargets[i].ID, XTargets[i].Name);
|
||||
auto &list = GetXTargetAutoMgr()->get_list();
|
||||
// yeah, I kept having to do something for debugging to tell if managers were the same object or not :P
|
||||
// so lets use the address as an "ID"
|
||||
c->Message(0, "XTargetAutoMgr ID %p size %d", GetXTargetAutoMgr(), list.size());
|
||||
int count = 0;
|
||||
for (auto &e : list) {
|
||||
c->Message(0, "spawn id %d count %d", e.spawn_id, e.count);
|
||||
count++;
|
||||
if (count == 20) { // lets not spam too many ...
|
||||
c->Message(0, " ... ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ProcessXTargetAutoHaters()
|
||||
{
|
||||
if (!XTargettingAvailable())
|
||||
return;
|
||||
|
||||
// move shit up! If the removed NPC was in a CurrentTargetNPC slot it becomes Auto
|
||||
// and we need to potentially fill it
|
||||
std::queue<int> empty_slots;
|
||||
for (int i = 0; i < GetMaxXTargets(); ++i) {
|
||||
if (XTargets[i].Type != Auto)
|
||||
continue;
|
||||
|
||||
if (XTargets[i].ID != 0 && !GetXTargetAutoMgr()->contains_mob(XTargets[i].ID)) {
|
||||
XTargets[i].ID = 0;
|
||||
XTargets[i].dirty = true;
|
||||
}
|
||||
|
||||
if (XTargets[i].ID == 0) {
|
||||
empty_slots.push(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (XTargets[i].ID != 0 && !empty_slots.empty()) {
|
||||
int temp = empty_slots.front();
|
||||
std::swap(XTargets[i], XTargets[temp]);
|
||||
XTargets[i].dirty = XTargets[temp].dirty = true;
|
||||
empty_slots.pop();
|
||||
empty_slots.push(i);
|
||||
}
|
||||
}
|
||||
// okay, now we need to check if we have any empty slots and if we have aggro
|
||||
// We make the assumption that if we shuffled the NPCs up that they're still on the aggro
|
||||
// list in the same order. We could probably do this better and try to calc if
|
||||
// there are new NPCs for our empty slots on the manager, but ahhh fuck it.
|
||||
if (!empty_slots.empty() && !GetXTargetAutoMgr()->empty() && XTargetAutoAddHaters) {
|
||||
auto &haters = GetXTargetAutoMgr()->get_list();
|
||||
for (auto &e : haters) {
|
||||
auto *mob = entity_list.GetMob(e.spawn_id);
|
||||
if (!IsXTarget(mob)) {
|
||||
auto slot = empty_slots.front();
|
||||
empty_slots.pop();
|
||||
XTargets[slot].dirty = true;
|
||||
XTargets[slot].ID = mob->GetID();
|
||||
strn0cpy(XTargets[slot].Name, mob->GetCleanName(), 64);
|
||||
}
|
||||
if (empty_slots.empty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_dirtyautohaters = false;
|
||||
SendXTargetUpdates();
|
||||
}
|
||||
|
||||
// This function is called when a client is added to a group
|
||||
// Group leader joining isn't handled by this function
|
||||
void Client::JoinGroupXTargets(Group *g)
|
||||
{
|
||||
if (!g)
|
||||
return;
|
||||
|
||||
if (!GetXTargetAutoMgr()->empty()) {
|
||||
g->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr());
|
||||
GetXTargetAutoMgr()->clear();
|
||||
RemoveAutoXTargets();
|
||||
}
|
||||
|
||||
SetXTargetAutoMgr(g->GetXTargetAutoMgr());
|
||||
|
||||
if (!GetXTargetAutoMgr()->empty())
|
||||
SetDirtyAutoHaters();
|
||||
}
|
||||
|
||||
// This function is called when a client leaves a group
|
||||
void Client::LeaveGroupXTargets(Group *g)
|
||||
{
|
||||
if (!g)
|
||||
return;
|
||||
|
||||
SetXTargetAutoMgr(nullptr); // this will set it back to our manager
|
||||
RemoveAutoXTargets();
|
||||
entity_list.RefreshAutoXTargets(this); // this will probably break the temporal ordering, but whatever
|
||||
// We now have a rebuilt, valid auto hater manager, so we need to demerge from the groups
|
||||
if (!GetXTargetAutoMgr()->empty()) {
|
||||
GetXTargetAutoMgr()->demerge(*g->GetXTargetAutoMgr()); // this will remove entries where we only had aggro
|
||||
SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called when a client leaves a group
|
||||
void Client::LeaveRaidXTargets(Raid *r)
|
||||
{
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
SetXTargetAutoMgr(nullptr); // this will set it back to our manager
|
||||
RemoveAutoXTargets();
|
||||
entity_list.RefreshAutoXTargets(this); // this will probably break the temporal ordering, but whatever
|
||||
// We now have a rebuilt, valid auto hater manager, so we need to demerge from the groups
|
||||
if (!GetXTargetAutoMgr()->empty()) {
|
||||
GetXTargetAutoMgr()->demerge(*r->GetXTargetAutoMgr()); // this will remove entries where we only had aggro
|
||||
SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetMaxXTargets(uint8 NewMax)
|
||||
|
||||
@ -48,6 +48,7 @@ namespace EQEmu
|
||||
#include "../common/inventory_profile.h"
|
||||
#include "../common/guilds.h"
|
||||
//#include "../common/item_data.h"
|
||||
#include "xtargetautohaters.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "merc.h"
|
||||
@ -1122,6 +1123,13 @@ public:
|
||||
void RemoveGroupXTargets();
|
||||
void RemoveAutoXTargets();
|
||||
void ShowXTargets(Client *c);
|
||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return m_activeautohatermgr; } // will be either raid or group or self
|
||||
inline void SetXTargetAutoMgr(XTargetAutoHaters *in) { if (in) m_activeautohatermgr = in; else m_activeautohatermgr = &m_autohatermgr; }
|
||||
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
|
||||
void ProcessXTargetAutoHaters(); // fixes up our auto haters
|
||||
void JoinGroupXTargets(Group *g);
|
||||
void LeaveGroupXTargets(Group *g);
|
||||
void LeaveRaidXTargets(Raid *r);
|
||||
bool GroupFollow(Client* inviter);
|
||||
inline bool GetRunMode() const { return runmode; }
|
||||
|
||||
@ -1546,8 +1554,11 @@ private:
|
||||
|
||||
uint8 MaxXTargets;
|
||||
bool XTargetAutoAddHaters;
|
||||
bool m_dirtyautohaters;
|
||||
|
||||
struct XTarget_Struct XTargets[XTARGET_HARDCAP];
|
||||
XTargetAutoHaters m_autohatermgr;
|
||||
XTargetAutoHaters *m_activeautohatermgr;
|
||||
|
||||
Timer ItemTickTimer;
|
||||
Timer ItemQuestTimer;
|
||||
|
||||
@ -575,6 +575,11 @@ void Client::CompleteConnect()
|
||||
}
|
||||
}
|
||||
raid->SendGroupLeadershipAA(this, grpID); // this may get sent an extra time ...
|
||||
|
||||
SetXTargetAutoMgr(raid->GetXTargetAutoMgr());
|
||||
if (!GetXTargetAutoMgr()->empty())
|
||||
SetDirtyAutoHaters();
|
||||
|
||||
if (raid->IsLocked())
|
||||
raid->SendRaidLockTo(this);
|
||||
}
|
||||
@ -1548,8 +1553,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
// we purchased a new one while out-of-zone.
|
||||
if (group->IsLeader(this))
|
||||
group->SendLeadershipAAUpdate();
|
||||
|
||||
}
|
||||
JoinGroupXTargets(group);
|
||||
group->UpdatePlayer(this);
|
||||
LFG = false;
|
||||
}
|
||||
@ -10806,7 +10811,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
g->DisbandGroup();
|
||||
g->JoinRaidXTarget(r);
|
||||
g->DisbandGroup(true);
|
||||
r->GroupUpdate(freeGroup);
|
||||
}
|
||||
else{
|
||||
@ -10871,7 +10877,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
ig->DisbandGroup();
|
||||
ig->JoinRaidXTarget(r, true);
|
||||
ig->DisbandGroup(true);
|
||||
r->GroupUpdate(groupFree);
|
||||
groupFree = r->GetFreeGroup();
|
||||
}
|
||||
@ -10924,10 +10931,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
g->DisbandGroup();
|
||||
g->JoinRaidXTarget(r);
|
||||
g->DisbandGroup(true);
|
||||
r->GroupUpdate(groupFree);
|
||||
}
|
||||
else
|
||||
else // target does not have a group
|
||||
{
|
||||
if (ig){
|
||||
r = new Raid(i);
|
||||
@ -10981,14 +10989,15 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
r->SendRaidCreate(this);
|
||||
r->SendMakeLeaderPacketTo(r->leadername, this);
|
||||
r->SendBulkRaid(this);
|
||||
ig->JoinRaidXTarget(r, true);
|
||||
r->AddMember(this);
|
||||
ig->DisbandGroup();
|
||||
ig->DisbandGroup(true);
|
||||
r->GroupUpdate(0);
|
||||
if (r->IsLocked()) {
|
||||
r->SendRaidLockTo(this);
|
||||
}
|
||||
}
|
||||
else{
|
||||
else{ // neither has a group
|
||||
r = new Raid(i);
|
||||
entity_list.AddRaid(r);
|
||||
r->SetRaidDetails();
|
||||
@ -14087,6 +14096,7 @@ void Client::Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
XTargetAutoAddHaters = app->ReadUInt8(0);
|
||||
SetDirtyAutoHaters();
|
||||
}
|
||||
|
||||
void Client::Handle_OP_XTargetOpen(const EQApplicationPacket *app)
|
||||
|
||||
@ -681,6 +681,12 @@ bool Client::Process() {
|
||||
Message(0, "Your enemies have forgotten you!");
|
||||
}
|
||||
|
||||
if (client_state == CLIENT_CONNECTED) {
|
||||
if (m_dirtyautohaters)
|
||||
ProcessXTargetAutoHaters();
|
||||
// aggro meter stuff should live here
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1404,15 +1404,15 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets)
|
||||
if (!m)
|
||||
continue;
|
||||
|
||||
m->RemoveFromHateList(mob);
|
||||
|
||||
if (RemoveFromXTargets) {
|
||||
if (m->IsClient())
|
||||
if (m->IsClient() && mob->CheckAggro(m))
|
||||
m->CastToClient()->RemoveXTarget(mob, false);
|
||||
// FadingMemories calls this function passing the client.
|
||||
else if (mob->IsClient())
|
||||
else if (mob->IsClient() && m->CheckAggro(mob))
|
||||
mob->CastToClient()->RemoveXTarget(m, false);
|
||||
}
|
||||
|
||||
m->RemoveFromHateList(mob);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2557,6 +2557,8 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
|
||||
it->second->RemoveFromHateList(mob);
|
||||
else
|
||||
it->second->SetHateAmountOnEnt(mob, 1);
|
||||
if (mob->IsClient())
|
||||
mob->CastToClient()->RemoveXTarget(it->second, false); // gotta do book keeping
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
@ -64,6 +64,8 @@ Group::Group(uint32 gid)
|
||||
MarkedNPCs[i] = 0;
|
||||
|
||||
NPCMarkerID = 0;
|
||||
|
||||
m_autohatermgr.SetOwner(nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
//creating a new group
|
||||
@ -94,6 +96,7 @@ Group::Group(Mob* leader)
|
||||
MarkedNPCs[i] = 0;
|
||||
|
||||
NPCMarkerID = 0;
|
||||
m_autohatermgr.SetOwner(nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
Group::~Group()
|
||||
@ -346,6 +349,9 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
|
||||
database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc);
|
||||
}
|
||||
|
||||
if (newmember && newmember->IsClient())
|
||||
newmember->CastToClient()->JoinGroupXTargets(this);
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
return true;
|
||||
@ -718,8 +724,10 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
if (oldmember->GetName() == mentoree_name)
|
||||
ClearGroupMentor();
|
||||
|
||||
if(oldmember->IsClient())
|
||||
if(oldmember->IsClient()) {
|
||||
SendMarkedNPCsToMember(oldmember->CastToClient(), true);
|
||||
oldmember->CastToClient()->LeaveGroupXTargets(this);
|
||||
}
|
||||
|
||||
if(GroupCount() < 3)
|
||||
{
|
||||
@ -872,7 +880,7 @@ uint32 Group::GetTotalGroupDamage(Mob* other) {
|
||||
return total;
|
||||
}
|
||||
|
||||
void Group::DisbandGroup() {
|
||||
void Group::DisbandGroup(bool joinraid) {
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct));
|
||||
|
||||
GroupUpdate_Struct* gu = (GroupUpdate_Struct*) outapp->pBuffer;
|
||||
@ -899,6 +907,8 @@ void Group::DisbandGroup() {
|
||||
database.SetGroupID(members[i]->GetCleanName(), 0, members[i]->CastToClient()->CharacterID(), false);
|
||||
members[i]->CastToClient()->QueuePacket(outapp);
|
||||
SendMarkedNPCsToMember(members[i]->CastToClient(), true);
|
||||
if (!joinraid)
|
||||
members[i]->CastToClient()->LeaveGroupXTargets(this);
|
||||
}
|
||||
|
||||
if (members[i]->IsMerc())
|
||||
@ -2292,6 +2302,30 @@ void Group::UpdateXTargetMarkedNPC(uint32 Number, Mob *m)
|
||||
|
||||
}
|
||||
|
||||
void Group::SetDirtyAutoHaters()
|
||||
{
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
if (members[i] && members[i]->IsClient())
|
||||
members[i]->CastToClient()->SetDirtyAutoHaters();
|
||||
}
|
||||
|
||||
void Group::JoinRaidXTarget(Raid *raid, bool first)
|
||||
{
|
||||
if (!GetXTargetAutoMgr()->empty())
|
||||
raid->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr());
|
||||
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||
if (members[i] && members[i]->IsClient()) {
|
||||
auto *client = members[i]->CastToClient();
|
||||
if (!first)
|
||||
client->RemoveAutoXTargets();
|
||||
client->SetXTargetAutoMgr(raid->GetXTargetAutoMgr());
|
||||
if (!client->GetXTargetAutoMgr()->empty())
|
||||
client->SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Group::SetMainTank(const char *NewMainTankName)
|
||||
{
|
||||
MainTankName = NewMainTankName;
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "../common/types.h"
|
||||
|
||||
#include "mob.h"
|
||||
#include "xtargetautohaters.h"
|
||||
|
||||
class Client;
|
||||
class EQApplicationPacket;
|
||||
@ -58,7 +59,7 @@ public:
|
||||
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
|
||||
bool DelMemberOOZ(const char *Name);
|
||||
bool DelMember(Mob* oldmember,bool ignoresender = false);
|
||||
void DisbandGroup();
|
||||
void DisbandGroup(bool joinraid = false);
|
||||
void GetMemberList(std::list<Mob*>& member_list, bool clear_list = true);
|
||||
void GetClientList(std::list<Client*>& client_list, bool clear_list = true);
|
||||
#ifdef BOTS
|
||||
@ -140,6 +141,9 @@ public:
|
||||
void ChangeLeader(Mob* newleader);
|
||||
const char *GetClientNameByIndex(uint8 index);
|
||||
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
||||
void SetDirtyAutoHaters();
|
||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
||||
void JoinRaidXTarget(Raid *raid, bool first = false);
|
||||
|
||||
void SetGroupMentor(int percent, char *name);
|
||||
void ClearGroupMentor();
|
||||
@ -168,6 +172,8 @@ private:
|
||||
std::string mentoree_name;
|
||||
Client *mentoree;
|
||||
int mentor_percent;
|
||||
|
||||
XTargetAutoHaters m_autohatermgr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -43,6 +43,8 @@ Raid::Raid(uint32 raidID)
|
||||
memset(leadername, 0, 64);
|
||||
locked = false;
|
||||
LootType = 4;
|
||||
|
||||
m_autohatermgr.SetOwner(nullptr, nullptr, this);
|
||||
}
|
||||
|
||||
Raid::Raid(Client* nLeader)
|
||||
@ -60,6 +62,8 @@ Raid::Raid(Client* nLeader)
|
||||
strn0cpy(leadername, nLeader->GetName(), 64);
|
||||
locked = false;
|
||||
LootType = 4;
|
||||
|
||||
m_autohatermgr.SetOwner(nullptr, nullptr, this);
|
||||
}
|
||||
|
||||
Raid::~Raid()
|
||||
@ -121,6 +125,26 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
c->SetRaidGrouped(true);
|
||||
SendRaidMOTD(c);
|
||||
|
||||
// xtarget shit ..........
|
||||
if (group == RAID_GROUPLESS) {
|
||||
if (rleader) {
|
||||
GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr());
|
||||
c->GetXTargetAutoMgr()->clear();
|
||||
c->SetXTargetAutoMgr(GetXTargetAutoMgr());
|
||||
} else {
|
||||
if (!c->GetXTargetAutoMgr()->empty()) {
|
||||
GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr());
|
||||
c->GetXTargetAutoMgr()->clear();
|
||||
c->RemoveAutoXTargets();
|
||||
}
|
||||
|
||||
c->SetXTargetAutoMgr(GetXTargetAutoMgr());
|
||||
|
||||
if (!c->GetXTargetAutoMgr()->empty())
|
||||
c->SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
@ -143,8 +167,10 @@ void Raid::RemoveMember(const char *characterName)
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if(client)
|
||||
if(client) {
|
||||
client->SetRaidGrouped(false);
|
||||
client->LeaveRaidXTargets(this);
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
@ -1672,3 +1698,11 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c)
|
||||
group_mentor[group_id].mentoree = c;
|
||||
}
|
||||
|
||||
void Raid::SetDirtyAutoHaters()
|
||||
{
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
if (members[i].member)
|
||||
members[i].member->SetDirtyAutoHaters();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "groups.h"
|
||||
#include "xtargetautohaters.h"
|
||||
|
||||
class Client;
|
||||
class EQApplicationPacket;
|
||||
@ -230,6 +231,9 @@ public:
|
||||
inline int GetMentorPercent(uint32 group_id) { return group_mentor[group_id].mentor_percent; }
|
||||
inline Client *GetMentoree(uint32 group_id) { return group_mentor[group_id].mentoree; }
|
||||
|
||||
void SetDirtyAutoHaters();
|
||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
||||
|
||||
RaidMember members[MAX_RAID_MEMBERS];
|
||||
char leadername[64];
|
||||
protected:
|
||||
@ -244,6 +248,8 @@ protected:
|
||||
GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS];
|
||||
|
||||
GroupMentor group_mentor[MAX_RAID_GROUPS];
|
||||
|
||||
XTargetAutoHaters m_autohatermgr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -897,6 +897,9 @@ void WorldServer::Process() {
|
||||
Inviter->CastToClient()->SendGroupLeaderChangePacket(Inviter->GetName());
|
||||
Inviter->CastToClient()->SendGroupJoinAcknowledge();
|
||||
}
|
||||
group->GetXTargetAutoMgr()->merge(*Inviter->CastToClient()->GetXTargetAutoMgr());
|
||||
Inviter->CastToClient()->GetXTargetAutoMgr()->clear();
|
||||
Inviter->CastToClient()->SetXTargetAutoMgr(group->GetXTargetAutoMgr());
|
||||
}
|
||||
|
||||
if(!group)
|
||||
@ -1011,6 +1014,7 @@ void WorldServer::Process() {
|
||||
group->SetGroupMentor(mentor_percent, mentoree_name);
|
||||
|
||||
}
|
||||
client->JoinGroupXTargets(group);
|
||||
}
|
||||
else if (client->GetMerc())
|
||||
{
|
||||
@ -1109,6 +1113,7 @@ void WorldServer::Process() {
|
||||
r->SendRaidRemoveAll(rga->playername);
|
||||
Client *rem = entity_list.GetClientByName(rga->playername);
|
||||
if(rem){
|
||||
rem->LeaveRaidXTargets(r);
|
||||
r->SendRaidDisband(rem);
|
||||
}
|
||||
r->LearnMembers();
|
||||
|
||||
112
zone/xtargetautohaters.cpp
Normal file
112
zone/xtargetautohaters.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include "xtargetautohaters.h"
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "raids.h"
|
||||
#include "groups.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void XTargetAutoHaters::increment_count(Mob *in)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
auto it = std::find_if(m_haters.begin(), m_haters.end(),
|
||||
[&in](const HatersCount &c) { return c.spawn_id == in->GetID(); });
|
||||
|
||||
// we are on the list, we just need to increment the count
|
||||
if (it != m_haters.end()) {
|
||||
it->count++;
|
||||
return;
|
||||
}
|
||||
// We are not on the list
|
||||
HatersCount c;
|
||||
c.spawn_id = in->GetID();
|
||||
c.count = 1;
|
||||
|
||||
m_haters.push_back(c);
|
||||
// trigger event on owner
|
||||
if (m_client)
|
||||
m_client->SetDirtyAutoHaters();
|
||||
else if (m_group)
|
||||
m_group->SetDirtyAutoHaters();
|
||||
else if (m_raid)
|
||||
m_raid->SetDirtyAutoHaters();
|
||||
}
|
||||
|
||||
void XTargetAutoHaters::decrement_count(Mob *in)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
auto it = std::find_if(m_haters.begin(), m_haters.end(),
|
||||
[&in](const HatersCount &c) { return c.spawn_id == in->GetID(); });
|
||||
|
||||
// we are not on the list ... shouldn't happen
|
||||
if (it == m_haters.end())
|
||||
return;
|
||||
it->count--;
|
||||
if (it->count == 0) {
|
||||
m_haters.erase(it);
|
||||
if (m_client)
|
||||
m_client->SetDirtyAutoHaters();
|
||||
else if (m_group)
|
||||
m_group->SetDirtyAutoHaters();
|
||||
else if (m_raid)
|
||||
m_raid->SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
void XTargetAutoHaters::merge(XTargetAutoHaters &other)
|
||||
{
|
||||
bool trigger = false;
|
||||
for (auto &e : other.m_haters) {
|
||||
auto it = std::find_if(m_haters.begin(), m_haters.end(),
|
||||
[&e](const HatersCount &c) { return e.spawn_id == c.spawn_id; });
|
||||
if (it != m_haters.end()) {
|
||||
it->count += e.count;
|
||||
continue;
|
||||
}
|
||||
m_haters.push_back(e);
|
||||
trigger = true;
|
||||
}
|
||||
|
||||
if (trigger) {
|
||||
if (m_client)
|
||||
m_client->SetDirtyAutoHaters();
|
||||
else if (m_group)
|
||||
m_group->SetDirtyAutoHaters();
|
||||
else if (m_raid)
|
||||
m_raid->SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
// demerge this from other. other belongs to group/raid you just left
|
||||
void XTargetAutoHaters::demerge(XTargetAutoHaters &other)
|
||||
{
|
||||
bool trigger = false;
|
||||
for (auto &e : m_haters) {
|
||||
auto it = std::find_if(other.m_haters.begin(), other.m_haters.end(),
|
||||
[&e](const HatersCount &c) { return e.spawn_id == c.spawn_id; });
|
||||
if (it != other.m_haters.end()) {
|
||||
it->count -= e.count;
|
||||
if (it->count == 0) {
|
||||
trigger = true;
|
||||
other.m_haters.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trigger) {
|
||||
if (other.m_client)
|
||||
other.m_client->SetDirtyAutoHaters();
|
||||
else if (other.m_group)
|
||||
other.m_group->SetDirtyAutoHaters();
|
||||
else if (other.m_raid)
|
||||
other.m_raid->SetDirtyAutoHaters();
|
||||
}
|
||||
}
|
||||
|
||||
bool XTargetAutoHaters::contains_mob(int spawn_id)
|
||||
{
|
||||
auto it = std::find_if(m_haters.begin(), m_haters.end(),
|
||||
[spawn_id](const HatersCount &c) { return c.spawn_id == spawn_id; });
|
||||
return it != m_haters.end();
|
||||
}
|
||||
|
||||
48
zone/xtargetautohaters.h
Normal file
48
zone/xtargetautohaters.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef XTARGETAUTOHATERS_H
|
||||
#define XTARGETAUTOHATERS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Mob;
|
||||
class Client;
|
||||
class Group;
|
||||
class Raid;
|
||||
|
||||
class XTargetAutoHaters {
|
||||
struct HatersCount {
|
||||
int spawn_id;
|
||||
int count;
|
||||
};
|
||||
public:
|
||||
XTargetAutoHaters() : m_client(nullptr), m_group(nullptr), m_raid(nullptr) {}
|
||||
XTargetAutoHaters(Client *co, Group *go, Raid *ro) : m_client(co), m_group(go), m_raid(ro) {}
|
||||
~XTargetAutoHaters() {}
|
||||
|
||||
void merge(XTargetAutoHaters &other);
|
||||
void demerge(XTargetAutoHaters &other);
|
||||
void increment_count(Mob *in);
|
||||
void decrement_count(Mob *in);
|
||||
|
||||
bool contains_mob(int spawn_id);
|
||||
|
||||
inline const std::vector<HatersCount> &get_list() { return m_haters; }
|
||||
inline void SetOwner(Client *c, Group *g, Raid *r) {m_client = c; m_group = g; m_raid = r; }
|
||||
inline void clear() { m_haters.clear(); }
|
||||
inline bool empty() { return m_haters.empty(); }
|
||||
|
||||
private:
|
||||
/* This will contain all of the mobs that are possible to fill in an autohater
|
||||
* slot. This keeps track of ALL MOBS for a client or group or raid
|
||||
* This list needs to be merged when you join group/raid/etc
|
||||
*/
|
||||
std::vector<HatersCount> m_haters;
|
||||
|
||||
// So this is the object that owns us ... only 1 shouldn't be null
|
||||
Client *m_client;
|
||||
Group *m_group;
|
||||
Raid *m_raid;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !XTARGETAUTOHATERS_H */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user