From a327c91bacd2add6a5c2e3dda71d62733692366a Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 19 Oct 2014 17:20:07 -0400 Subject: [PATCH 1/3] Implement group mentoring while in raids (SoF+ only) Note: This does not allow the raid leader to share raid leader XP and since the raid leader doesn't gain group leadership, they can't share that either. --- common/database.cpp | 22 ++++-- common/database.h | 2 +- .../required/2014_10_19_raid_group_mentor.sql | 2 + zone/client_packet.cpp | 18 ++++- zone/exp.cpp | 17 ++++- zone/raids.cpp | 67 ++++++++++++++++++- zone/raids.h | 14 ++++ 7 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 utils/sql/git/required/2014_10_19_raid_group_mentor.sql diff --git a/common/database.cpp b/common/database.cpp index f36ab1713..599d615a7 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -3191,10 +3191,10 @@ const char* Database::GetRaidLeaderName(uint32 rid) // maintank, assist, puller, marknpc currently unused void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank, - char *assist, char *puller, char *marknpc, GroupLeadershipAA_Struct *GLAA) + char *assist, char *puller, char *marknpc, char *mentoree, int *mentor_percent, GroupLeadershipAA_Struct *GLAA) { std::string query = StringFormat( - "SELECT maintank, assist, puller, marknpc, leadershipaa FROM raid_leaders WHERE gid = %lu AND rid = %lu", + "SELECT maintank, assist, puller, marknpc, mentoree, mentor_percent, leadershipaa FROM raid_leaders WHERE gid = %lu AND rid = %lu", (unsigned long)gid, (unsigned long)rid); auto results = QueryDatabase(query); @@ -3211,6 +3211,12 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank, if (marknpc) marknpc[0] = '\0'; + if (mentoree) + mentoree[0] = '\0'; + + if (mentor_percent) + *mentor_percent = 0; + return; } @@ -3228,8 +3234,14 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank, if (marknpc) strcpy(marknpc, row[3]); - if (GLAA && results.LengthOfColumn(4) == sizeof(GroupLeadershipAA_Struct)) - memcpy(GLAA, row[4], sizeof(GroupLeadershipAA_Struct)); + if (mentoree) + strcpy(mentoree, row[4]); + + if (mentor_percent) + *mentor_percent = atoi(row[5]); + + if (GLAA && results.LengthOfColumn(6) == sizeof(GroupLeadershipAA_Struct)) + memcpy(GLAA, row[6], sizeof(GroupLeadershipAA_Struct)); return; } @@ -3288,7 +3300,7 @@ void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid) if (results.RowsAffected() != 0) return; - query = StringFormat("INSERT INTO raid_leaders(gid, rid, marknpc, leadershipaa, maintank, assist, puller) VALUES(%lu, %lu, '', '', '', '', '')", + query = StringFormat("INSERT INTO raid_leaders(gid, rid, marknpc, leadershipaa, maintank, assist, puller, mentoree, mentor_percent) VALUES(%lu, %lu, '', '', '', '', '', '', 0)", (unsigned long)gid, (unsigned long)rid); results = QueryDatabase(query); diff --git a/common/database.h b/common/database.h index 71a6de9fb..9b388c84a 100644 --- a/common/database.h +++ b/common/database.h @@ -215,7 +215,7 @@ public: uint32 GetRaidID(const char* name); const char *GetRaidLeaderName(uint32 rid); void GetGroupLeadershipInfo(uint32 gid, uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, - GroupLeadershipAA_Struct* GLAA = nullptr); + char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); void GetRaidLeadershipInfo(uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, RaidLeadershipAA_Struct* RLAA = nullptr); void SetRaidGroupLeaderInfo(uint32 gid, uint32 rid); diff --git a/utils/sql/git/required/2014_10_19_raid_group_mentor.sql b/utils/sql/git/required/2014_10_19_raid_group_mentor.sql new file mode 100644 index 000000000..4cb8d5613 --- /dev/null +++ b/utils/sql/git/required/2014_10_19_raid_group_mentor.sql @@ -0,0 +1,2 @@ +ALTER TABLE `raid_leaders` ADD `mentoree` VARCHAR(64) NOT NULL; +ALTER TABLE `raid_leaders` ADD `mentor_percent` INT(4) DEFAULT 0 NOT NULL; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f759c9321..0ec740507 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -576,6 +576,7 @@ void Client::CompleteConnect() if (grpID < 12){ raid->SendRaidGroupRemove(GetName(), grpID); raid->SendRaidGroupAdd(GetName(), grpID); + raid->CheckGroupMentor(grpID, this); if (raid->IsGroupLeader(GetName())) { // group leader same thing! raid->UpdateGroupAAs(raid->GetGroup(this)); raid->GroupUpdate(grpID, false); @@ -6869,10 +6870,25 @@ void Client::Handle_OP_GroupMentor(const EQApplicationPacket *app) return; } GroupMentor_Struct *gms = (GroupMentor_Struct *)app->pBuffer; + gms->name[63] = '\0'; + + if (IsRaidGrouped()) { + Raid *raid = GetRaid(); + if (!raid) + return; + uint32 group_id = raid->GetGroup(this); + if (group_id > 11) + return; + if (strlen(gms->name)) + raid->SetGroupMentor(group_id, gms->percent, gms->name); + else + raid->ClearGroupMentor(group_id); + return; + } + Group *group = GetGroup(); if (!group) return; - gms->name[63] = '\0'; if (strlen(gms->name)) group->SetGroupMentor(gms->percent, gms->name); diff --git a/zone/exp.cpp b/zone/exp.cpp index a06fdc017..0e01a4c0e 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -169,9 +169,20 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { } else { if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) && RuleI(Character, KillsPerGroupLeadershipAA) > 0) { - // mentoring stuff needs to be added here when raids are have support for it - AddLeadershipEXP(0, GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA)); - Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + uint32 group_id = raid->GetGroup(this); + uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); + Client *mentoree = raid->GetMentoree(group_id); + if (raid->GetMentorPercent(group_id) && mentoree && + mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) { + uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f); + exp -= mentor_exp; + mentoree->AddLeadershipEXP(mentor_exp, 0); + mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } + if (exp > 0) { + AddLeadershipEXP(exp, 0); + Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP); + } } else { Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS); } diff --git a/zone/raids.cpp b/zone/raids.cpp index e456d0beb..699bc6b1d 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -31,6 +31,10 @@ Raid::Raid(uint32 raidID) memset(members ,0, (sizeof(RaidMember)*MAX_RAID_MEMBERS)); memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct)); memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS); + for (int i = 0; i < MAX_RAID_GROUPS; i++) { + group_mentor[i].mentor_percent = 0; + group_mentor[i].mentoree = nullptr; + } leader = nullptr; memset(leadername, 0, 64); locked = false; @@ -43,6 +47,10 @@ Raid::Raid(Client* nLeader) memset(members ,0, (sizeof(RaidMember)*MAX_RAID_MEMBERS)); memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct)); memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS); + for (int i = 0; i < MAX_RAID_GROUPS; i++) { + group_mentor[i].mentor_percent = 0; + group_mentor[i].mentoree = nullptr; + } leader = nLeader; memset(leadername, 0, 64); strn0cpy(leadername, nLeader->GetName(), 64); @@ -1482,13 +1490,19 @@ void Raid::MemberZoned(Client *c) if(!c) return; + // Raid::GetGroup() goes over the members as well, this way we go over once + uint32 gid = RAID_GROUPLESS; for(int x = 0; x < MAX_RAID_MEMBERS; x++) { if(members[x].member == c) { members[x].member = nullptr; + gid = members[x].GroupNumber; } } + + if (gid < 12 && group_mentor[gid].mentoree == c) + group_mentor[gid].mentoree = nullptr; } void Raid::SendHPPacketsTo(Client *c) @@ -1597,7 +1611,56 @@ void Raid::LoadLeadership() { database.GetRaidLeadershipInfo(GetID(), nullptr, nullptr, nullptr, nullptr, &raid_aa); - for (uint32 group_id = 0; group_id < MAX_RAID_GROUPS; group_id++) - database.GetGroupLeadershipInfo(group_id, GetID(), nullptr, nullptr, nullptr, nullptr, &group_aa[group_id]); + char mentor_name[64]; + for (uint32 group_id = 0; group_id < MAX_RAID_GROUPS; group_id++) { + database.GetGroupLeadershipInfo(group_id, GetID(), nullptr, nullptr, nullptr, nullptr, + mentor_name, &group_mentor[group_id].mentor_percent, &group_aa[group_id]); + if (strlen(mentor_name)) { + group_mentor[group_id].name = mentor_name; + mentor_name[0] = '\0'; + } + } +} + +void Raid::SetGroupMentor(uint32 group_id, int percent, char *name) +{ + if (group_id > 11) + return; + group_mentor[group_id].name = name; + group_mentor[group_id].mentor_percent = percent; + Client *client = entity_list.GetClientByName(name); + group_mentor[group_id].mentoree = client ? client : nullptr; + + std::string query = StringFormat("UPDATE raid_leaders SET mentoree = '%s', mentor_percent = %i WHERE gid = %i AND rid = %i LIMIT 1", + name, percent, group_id, GetID()); + auto results = database.QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to set raid group mentor: %s\n", results.ErrorMessage().c_str()); +} + +void Raid::ClearGroupMentor(uint32 group_id) +{ + if (group_id > 11) + return; + group_mentor[group_id].name.clear(); + group_mentor[group_id].mentor_percent = 0; + group_mentor[group_id].mentoree = nullptr; + + std::string query = StringFormat("UPDATE raid_leaders SET mentoree = '', mentor_percent = 0 WHERE gid = %i AND rid = %i LIMIT 1", + group_id, GetID()); + auto results = database.QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to clear raid group mentor: %s\n", results.ErrorMessage().c_str()); +} + +// there isn't a nice place to add this in another function, unlike groups +// so we do it here instead +void Raid::CheckGroupMentor(uint32 group_id, Client *c) +{ + if (!c || group_id > 11) + return; + + if (group_mentor[group_id].name == c->GetName()) + group_mentor[group_id].mentoree = c; } diff --git a/zone/raids.h b/zone/raids.h index 6e2579367..eb963ad32 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -92,6 +92,12 @@ struct RaidMember{ bool IsLooter; }; +struct GroupMentor { + std::string name; + Client *mentoree; + int mentor_percent; +}; + class Raid : public GroupIDConsumer { public: Raid(Client *nLeader); @@ -221,6 +227,12 @@ public: inline void SetRaidAAs(RaidLeadershipAA_Struct *rlaa) { memcpy(&raid_aa, rlaa, sizeof(RaidLeadershipAA_Struct)); } + void SetGroupMentor(uint32 group_id, int percent, char *name); + void ClearGroupMentor(uint32 group_id); + void CheckGroupMentor(uint32 group_id, Client *c); // this just checks if we should be fixing the pointer in group mentor struct on zone + 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; } + RaidMember members[MAX_RAID_MEMBERS]; char leadername[64]; protected: @@ -233,6 +245,8 @@ protected: std::string motd; RaidLeadershipAA_Struct raid_aa; GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS]; + + GroupMentor group_mentor[MAX_RAID_GROUPS]; }; From 466eecacc4b97474a21197927ca96715d986bea7 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 19 Oct 2014 18:34:43 -0400 Subject: [PATCH 2/3] Implement Group Inspect Buffs for raids --- changelog.txt | 2 ++ zone/client_packet.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/changelog.txt b/changelog.txt index 1a1c7397a..b6f5f2ad6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 10/19/2014 == Uleat: Updated command #peekinv to display item links properly in RoF clients +demonstar55: Group Mentoring in raids +demonstar55: Inspect Buffs (text only version) works in raid groups == 10/18/2014== demonstar55: Implement group mentor, sharing leadership exp (SoF+ only) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0ec740507..6d9291685 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -5338,6 +5338,17 @@ void Client::Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app) if (!Target || !Target->IsClient()) return; + if (IsRaidGrouped()) { + Raid *raid = GetRaid(); + if (!raid) + return; + uint32 group_id = raid->GetGroup(this); + if (group_id > 11 || raid->GroupCount(group_id) < 3) + return; + Target->CastToClient()->InspectBuffs(this, raid->GetLeadershipAA(groupAAInspectBuffs, group_id)); + return; + } + Group *g = GetGroup(); if (!g || (g->GroupCount() < 3)) From a6ae2ca635508fd40af053d9f957a89fcbec3ec0 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 19 Oct 2014 22:30:11 -0400 Subject: [PATCH 3/3] Switch Inspect Buffs to use the OP code Client 6.2 is SOL until someone find the op for that client --- changelog.txt | 1 + common/emu_oplist.h | 1 + common/eq_packet_structs.h | 5 ++++ common/patches/rof.cpp | 14 +++++++++++ common/patches/rof_ops.h | 1 + common/patches/rof_structs.h | 5 ++++ common/patches/underfoot.cpp | 14 +++++++++++ common/patches/underfoot_ops.h | 1 + common/patches/underfoot_structs.h | 8 +++++++ utils/patches/patch_RoF.conf | 1 + utils/patches/patch_SoD.conf | 1 + utils/patches/patch_SoF.conf | 1 + utils/patches/patch_Titanium.conf | 2 ++ utils/patches/patch_Underfoot.conf | 1 + zone/aa.cpp | 37 ++++++++++++++---------------- 15 files changed, 73 insertions(+), 20 deletions(-) diff --git a/changelog.txt b/changelog.txt index b6f5f2ad6..ed10c7173 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Uleat: Updated command #peekinv to display item links properly in RoF clients demonstar55: Group Mentoring in raids demonstar55: Inspect Buffs (text only version) works in raid groups +demonstar55: Make use of the Inspect Buffs op/packet. 62 SOL until someone finds its op == 10/18/2014== demonstar55: Implement group mentor, sharing leadership exp (SoF+ only) diff --git a/common/emu_oplist.h b/common/emu_oplist.h index c0ca0ca4e..e8ce3b986 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -245,6 +245,7 @@ N(OP_IncreaseStats), N(OP_InitialHPUpdate), N(OP_InitialMobHealth), N(OP_InspectAnswer), +N(OP_InspectBuffs), N(OP_InspectMessageUpdate), N(OP_InspectRequest), N(OP_InstillDoubt), diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index d0792fd37..a5e22e44e 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3968,6 +3968,11 @@ struct MarkNPC_Struct /*08**/ char Name[64]; }; +struct InspectBuffs_Struct { +/*000*/ uint32 spell_id[BUFF_COUNT]; +/*100*/ uint32 tics_remaining[BUFF_COUNT]; +}; + struct RaidGeneral_Struct { /*00*/ uint32 action; //=10 /*04*/ char player_name[64]; //should both be the player's name diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 1fcb74078..3a03b3a62 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1309,6 +1309,20 @@ namespace RoF FINISH_ENCODE(); }*/ + ENCODE(OP_InspectBuffs) + { + ENCODE_LENGTH_EXACT(InspectBuffs_Struct); + SETUP_DIRECT_ENCODE(InspectBuffs_Struct, structs::InspectBuffs_Struct); + + // we go over the internal 25 instead of the packet's since no entry is 0, which it will be already + for (int i = 0; i < BUFF_COUNT; i++) { + OUT(spell_id[i]); + OUT(tics_remaining[i]); + } + + FINISH_ENCODE(); + } + ENCODE(OP_InspectRequest) { ENCODE_LENGTH_EXACT(Inspect_Struct); diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 030c331d6..57ff1f91d 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -44,6 +44,7 @@ E(OP_GuildMemberUpdate) E(OP_GuildsList) E(OP_HPUpdate) E(OP_Illusion) +E(OP_InspectBuffs) E(OP_InspectRequest) E(OP_InterruptCast) E(OP_ItemLinkResponse) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index e65f2b74d..1393b026e 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -2473,6 +2473,11 @@ struct GroupFollow_Struct { // Live Follow Struct /*0152*/ }; +struct InspectBuffs_Struct { +/*000*/ uint32 spell_id[BUFF_COUNT]; +/*168*/ uint32 tics_remaining[BUFF_COUNT]; +}; + struct LFG_Struct { /*000*/ uint32 unknown000; /*004*/ uint32 value; // 0x00 = off 0x01 = on diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index aa342a412..ad850be36 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -1125,6 +1125,20 @@ namespace Underfoot FINISH_ENCODE(); } + ENCODE(OP_InspectBuffs) + { + ENCODE_LENGTH_EXACT(InspectBuffs_Struct); + SETUP_DIRECT_ENCODE(InspectBuffs_Struct, structs::InspectBuffs_Struct); + + // we go over the internal 25 instead of the packet's since no entry is 0, which it will be already + for (int i = 0; i < BUFF_COUNT; i++) { + OUT(spell_id[i]); + OUT(tics_remaining[i]); + } + + FINISH_ENCODE(); + } + ENCODE(OP_InspectRequest) { ENCODE_LENGTH_EXACT(Inspect_Struct); diff --git a/common/patches/underfoot_ops.h b/common/patches/underfoot_ops.h index 28864301d..38cfb79e3 100644 --- a/common/patches/underfoot_ops.h +++ b/common/patches/underfoot_ops.h @@ -34,6 +34,7 @@ E(OP_GroupUpdate) E(OP_GuildMemberList) E(OP_GuildsList) E(OP_Illusion) +E(OP_InspectBuffs) E(OP_InspectRequest) E(OP_ItemLinkResponse) E(OP_ItemPacket) diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index 2b7163bcf..eec3270f5 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -2166,6 +2166,14 @@ struct GroupFollow_Struct { // Underfoot Follow Struct /*0152*/ }; +struct InspectBuffs_Struct { +/*000*/ uint32 spell_id[BUFF_COUNT]; +/*100*/ uint32 filler100[5]; // BUFF_COUNT is really 30... +/*120*/ uint32 tics_remaining[BUFF_COUNT]; +/*220*/ uint32 filler220[5]; // BUFF_COUNT is really 30... +}; + + struct LFG_Struct { /*000*/ uint32 unknown000; /*004*/ uint32 value; // 0x00 = off 0x01 = on diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 6bd486bfa..97098946d 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -501,6 +501,7 @@ OP_GroupMakeLeader=0x4129 OP_DoGroupLeadershipAbility=0x17d7 OP_GroupLeadershipAAUpdate=0x6567 OP_GroupMentor=0x56DB +OP_InspectBuffs=0x01f3 # LFG/LFP Opcodes OP_LFGCommand=0x4463 diff --git a/utils/patches/patch_SoD.conf b/utils/patches/patch_SoD.conf index 0effd1b3c..338ee82e7 100644 --- a/utils/patches/patch_SoD.conf +++ b/utils/patches/patch_SoD.conf @@ -487,6 +487,7 @@ OP_GroupLeaderChange=0x7545 OP_GroupRoles=0x6b67 OP_GroupMakeLeader=0x6087 OP_GroupMentor=0x1224 +OP_InspectBuffs=0x66bf # LFG/LFP Opcodes OP_LFGCommand=0x3288 # C OP_LFGGetMatchesRequest=0x5613 # C diff --git a/utils/patches/patch_SoF.conf b/utils/patches/patch_SoF.conf index 0b53daefd..fc0c716e1 100644 --- a/utils/patches/patch_SoF.conf +++ b/utils/patches/patch_SoF.conf @@ -453,6 +453,7 @@ OP_CancelInvite=0x596C #Trevius 03/02/09 OP_GroupFollow2=0x59D4 #Xinu 02/20/09 OP_GroupInvite2=0x07F6 #Xinu 02/20/09 OP_GroupMentor=0x9EF3 +OP_InspectBuffs=0x3547 #LFG/LFP Opcodes OP_LFGCommand=0x5D81 #Trevius 01/16/09 diff --git a/utils/patches/patch_Titanium.conf b/utils/patches/patch_Titanium.conf index 50e426874..841f77bf5 100644 --- a/utils/patches/patch_Titanium.conf +++ b/utils/patches/patch_Titanium.conf @@ -420,6 +420,8 @@ OP_RaidJoin=0x1f21 # ShowEQ 10/27/05 OP_RaidInvite=0x5891 # ShowEQ 10/27/05 OP_RaidUpdate=0x1f21 # EQEmu 06/29/05 +OP_InspectBuffs=0x4FB6 + OP_ZoneComplete=0x0000 OP_ItemLinkText=0x0000 diff --git a/utils/patches/patch_Underfoot.conf b/utils/patches/patch_Underfoot.conf index 01cc1ad47..56838da65 100644 --- a/utils/patches/patch_Underfoot.conf +++ b/utils/patches/patch_Underfoot.conf @@ -490,6 +490,7 @@ OP_GroupLeaderChange=0x0c33 # C OP_GroupRoles=0x116d # C OP_GroupMakeLeader=0x5851 OP_GroupMentor=0x292f +OP_InspectBuffs=0x105b # LFG/LFP Opcodes OP_LFGCommand=0x2c38 # C diff --git a/zone/aa.cpp b/zone/aa.cpp index d07ed72cf..83a6b7967 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1793,29 +1793,26 @@ int Client::GroupLeadershipAAOffenseEnhancement() void Client::InspectBuffs(Client* Inspector, int Rank) { - if(!Inspector || (Rank == 0)) return; + // At some point the removed the restriction of being a group member for this to work + // not sure when, but the way it's coded now, it wouldn't work with mobs. + if (!Inspector || Rank == 0) + return; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_InspectBuffs, sizeof(InspectBuffs_Struct)); + InspectBuffs_Struct *ib = (InspectBuffs_Struct *)outapp->pBuffer; - Inspector->Message_StringID(0, CURRENT_SPELL_EFFECTS, GetName()); uint32 buff_count = GetMaxTotalSlots(); - for (uint32 i = 0; i < buff_count; ++i) - { - if (buffs[i].spellid != SPELL_UNKNOWN) - { - if(Rank == 1) - Inspector->Message(0, "%s", spells[buffs[i].spellid].name); - else - { - if (spells[buffs[i].spellid].buffdurationformula == DF_Permanent) - Inspector->Message(0, "%s (Permanent)", spells[buffs[i].spellid].name); - else { - char *TempString = nullptr; - MakeAnyLenString(&TempString, "%.1f", static_cast(buffs[i].ticsremaining) / 10.0f); - Inspector->Message_StringID(0, BUFF_MINUTES_REMAINING, spells[buffs[i].spellid].name, TempString); - safe_delete_array(TempString); - } - } - } + uint32 packet_index = 0; + for (uint32 i = 0; i < buff_count; i++) { + if (buffs[i].spellid == SPELL_UNKNOWN) + continue; + ib->spell_id[packet_index] = buffs[i].spellid; + if (Rank > 1) + ib->tics_remaining[packet_index] = spells[buffs[i].spellid].buffdurationformula == DF_Permanent ? 0xFFFFFFFF : buffs[i].ticsremaining; + packet_index++; } + + Inspector->FastQueuePacket(&outapp); } //this really need to be renamed to LoadAAActions()