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]; };