mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Implement group mentor, leadership exp sharing (SoF+ only)
Currently only works in normal groups Some decisions: the EXP will be rounded in the favor of the group leader No idea how live actually handles it.
This commit is contained in:
parent
223d06645d
commit
e8eb774458
@ -1,5 +1,8 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 10/18/2014==
|
||||
demonstar55: Implement group mentor, sharing leadership exp (SoF+ only)
|
||||
|
||||
== 10/16/2014 ==
|
||||
Uleat: Fixed the auto-conversion view naming error and renamed the views in the script files. Added a fix sql for databases that auto-converted.
|
||||
Fix SQL: ../sql/git/bots/deprecated/2014_10_16_Lower_Case_View_Fix.sql
|
||||
|
||||
@ -2963,7 +2963,7 @@ void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
return;
|
||||
}
|
||||
|
||||
query = StringFormat("INSERT INTO group_leaders(gid, leadername, marknpc, leadershipaa, maintank, assist, puller) VALUES(%u, '%s', '', '', '', '', '')",
|
||||
query = StringFormat("INSERT INTO group_leaders(gid, leadername, marknpc, leadershipaa, maintank, assist, puller, mentoree, mentor_percent) VALUES(%u, '%s', '', '', '', '', '', '', '0')",
|
||||
gid, EscapeString(name).c_str());
|
||||
result = QueryDatabase(query);
|
||||
|
||||
@ -2972,8 +2972,9 @@ void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
}
|
||||
}
|
||||
|
||||
char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank, char* assist, char* puller, char *marknpc, GroupLeadershipAA_Struct* GLAA){
|
||||
std::string query = StringFormat("SELECT `leadername`, `maintank`, `assist`, `puller`, `marknpc`, `leadershipaa` FROM `group_leaders` WHERE `gid` = %lu",(unsigned long)gid);
|
||||
char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank, char* assist, char* puller, char *marknpc, char *mentoree, int *mentor_percent, GroupLeadershipAA_Struct* GLAA)
|
||||
{
|
||||
std::string query = StringFormat("SELECT `leadername`, `maintank`, `assist`, `puller`, `marknpc`, `mentoree`, `mentor_percent`, `leadershipaa` FROM `group_leaders` WHERE `gid` = %lu",(unsigned long)gid);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || results.RowCount() == 0) {
|
||||
@ -2992,6 +2993,12 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
|
||||
if(marknpc)
|
||||
marknpc[0] = '\0';
|
||||
|
||||
if (mentoree)
|
||||
mentoree[0] = '\0';
|
||||
|
||||
if (mentor_percent)
|
||||
*mentor_percent = 0;
|
||||
|
||||
return leaderbuf;
|
||||
}
|
||||
|
||||
@ -3012,8 +3019,14 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
|
||||
if(marknpc)
|
||||
strcpy(marknpc, row[4]);
|
||||
|
||||
if(GLAA && results.LengthOfColumn(5) == sizeof(GroupLeadershipAA_Struct))
|
||||
memcpy(GLAA, row[5], sizeof(GroupLeadershipAA_Struct));
|
||||
if (mentoree)
|
||||
strcpy(mentoree, row[5]);
|
||||
|
||||
if (mentor_percent)
|
||||
*mentor_percent = atoi(row[6]);
|
||||
|
||||
if(GLAA && results.LengthOfColumn(7) == sizeof(GroupLeadershipAA_Struct))
|
||||
memcpy(GLAA, row[7], sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
return leaderbuf;
|
||||
}
|
||||
|
||||
@ -203,7 +203,7 @@ public:
|
||||
|
||||
void SetGroupLeaderName(uint32 gid, const char* name);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, 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 ClearGroupLeader(uint32 gid = 0);
|
||||
|
||||
|
||||
|
||||
@ -207,6 +207,7 @@ N(OP_GroupInvite2),
|
||||
N(OP_GroupLeaderChange),
|
||||
N(OP_GroupLeadershipAAUpdate),
|
||||
N(OP_GroupMakeLeader),
|
||||
N(OP_GroupMentor),
|
||||
N(OP_GroupRoles),
|
||||
N(OP_GroupUpdate),
|
||||
N(OP_GroupUpdateB),
|
||||
|
||||
@ -2231,6 +2231,12 @@ struct GroupLeaderChange_Struct
|
||||
/*128*/ char Unknown128[20];
|
||||
};
|
||||
|
||||
struct GroupMentor_Struct {
|
||||
/*000*/ int percent;
|
||||
/*004*/ char name[64];
|
||||
/*068*/
|
||||
};
|
||||
|
||||
struct FaceChange_Struct {
|
||||
/*000*/ uint8 haircolor;
|
||||
/*001*/ uint8 beardcolor;
|
||||
|
||||
@ -500,6 +500,7 @@ OP_GroupRoles=0x047c
|
||||
OP_GroupMakeLeader=0x4129
|
||||
OP_DoGroupLeadershipAbility=0x17d7
|
||||
OP_GroupLeadershipAAUpdate=0x6567
|
||||
OP_GroupMentor=0x56DB
|
||||
|
||||
# LFG/LFP Opcodes
|
||||
OP_LFGCommand=0x4463
|
||||
|
||||
@ -486,6 +486,7 @@ OP_GroupDisbandOther=0x162d
|
||||
OP_GroupLeaderChange=0x7545
|
||||
OP_GroupRoles=0x6b67
|
||||
OP_GroupMakeLeader=0x6087
|
||||
OP_GroupMentor=0x1224
|
||||
# LFG/LFP Opcodes
|
||||
OP_LFGCommand=0x3288 # C
|
||||
OP_LFGGetMatchesRequest=0x5613 # C
|
||||
|
||||
@ -452,6 +452,7 @@ OP_GroupDelete=0x0000 #
|
||||
OP_CancelInvite=0x596C #Trevius 03/02/09
|
||||
OP_GroupFollow2=0x59D4 #Xinu 02/20/09
|
||||
OP_GroupInvite2=0x07F6 #Xinu 02/20/09
|
||||
OP_GroupMentor=0x9EF3
|
||||
|
||||
#LFG/LFP Opcodes
|
||||
OP_LFGCommand=0x5D81 #Trevius 01/16/09
|
||||
|
||||
@ -489,6 +489,7 @@ OP_GroupDisbandOther=0x49f6 # C
|
||||
OP_GroupLeaderChange=0x0c33 # C
|
||||
OP_GroupRoles=0x116d # C
|
||||
OP_GroupMakeLeader=0x5851
|
||||
OP_GroupMentor=0x292f
|
||||
|
||||
# LFG/LFP Opcodes
|
||||
OP_LFGCommand=0x2c38 # C
|
||||
|
||||
2
utils/sql/git/required/2014_10_18_group_mentor.sql
Normal file
2
utils/sql/git/required/2014_10_18_group_mentor.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE `group_leaders` ADD `mentoree` VARCHAR(64) NOT NULL;
|
||||
ALTER TABLE `group_leaders` ADD `mentor_percent` INT(4) DEFAULT 0 NOT NULL;
|
||||
@ -234,6 +234,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_GroupInvite] = &Client::Handle_OP_GroupInvite;
|
||||
ConnectedOpcodes[OP_GroupInvite2] = &Client::Handle_OP_GroupInvite2;
|
||||
ConnectedOpcodes[OP_GroupMakeLeader] = &Client::Handle_OP_GroupMakeLeader;
|
||||
ConnectedOpcodes[OP_GroupMentor] = &Client::Handle_OP_GroupMentor;
|
||||
ConnectedOpcodes[OP_GroupRoles] = &Client::Handle_OP_GroupRoles;
|
||||
ConnectedOpcodes[OP_GroupUpdate] = &Client::Handle_OP_GroupUpdate;
|
||||
ConnectedOpcodes[OP_GuildBank] = &Client::Handle_OP_GuildBank;
|
||||
@ -1635,9 +1636,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
}
|
||||
} //else, somebody from our group is already here...
|
||||
|
||||
if (group)
|
||||
group->UpdatePlayer(this);
|
||||
else
|
||||
if (!group)
|
||||
database.SetGroupID(GetName(), 0, CharacterID()); //cannot re-establish group, kill it
|
||||
|
||||
}
|
||||
@ -1656,9 +1655,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
char AssistName[64];
|
||||
char PullerName[64];
|
||||
char NPCMarkerName[64];
|
||||
char mentoree_name[64];
|
||||
int mentor_percent;
|
||||
GroupLeadershipAA_Struct GLAA;
|
||||
memset(ln, 0, 64);
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, &GLAA));
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, mentoree_name, &mentor_percent, &GLAA));
|
||||
Client *c = entity_list.GetClientByName(ln);
|
||||
if (c)
|
||||
group->SetLeader(c);
|
||||
@ -1668,6 +1669,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
group->SetPuller(PullerName);
|
||||
group->SetNPCMarker(NPCMarkerName);
|
||||
group->SetGroupAAs(&GLAA);
|
||||
group->SetGroupMentor(mentor_percent, mentoree_name);
|
||||
|
||||
//group->NotifyMainTank(this, 1);
|
||||
//group->NotifyMainAssist(this, 1);
|
||||
@ -1679,6 +1681,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
group->SendLeadershipAAUpdate();
|
||||
|
||||
}
|
||||
group->UpdatePlayer(this);
|
||||
LFG = false;
|
||||
}
|
||||
|
||||
@ -6858,6 +6861,27 @@ void Client::Handle_OP_GroupMakeLeader(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_GroupMentor(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(GroupMentor_Struct)) {
|
||||
LogFile->write(EQEMuLog::Error, "Wrong size: OP_GroupMentor, size=%i, expected %i", app->size, sizeof(GroupMentor_Struct));
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
GroupMentor_Struct *gms = (GroupMentor_Struct *)app->pBuffer;
|
||||
Group *group = GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
gms->name[63] = '\0';
|
||||
|
||||
if (strlen(gms->name))
|
||||
group->SetGroupMentor(gms->percent, gms->name);
|
||||
else
|
||||
group->ClearGroupMentor();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_GroupRoles(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(GroupRole_Struct)) {
|
||||
|
||||
@ -138,6 +138,7 @@
|
||||
void Handle_OP_GroupInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupInvite2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupMakeLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupMentor(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupRoles(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildBank(const EQApplicationPacket *app);
|
||||
|
||||
17
zone/exp.cpp
17
zone/exp.cpp
@ -133,7 +133,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
}
|
||||
}
|
||||
|
||||
if(IsLeadershipEXPOn() && ((conlevel == CON_BLUE) || (conlevel == CON_WHITE) || (conlevel == CON_YELLOW) || (conlevel == CON_RED))) {
|
||||
if(IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) {
|
||||
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
|
||||
|
||||
if(GetGroup())
|
||||
@ -141,8 +141,19 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
if((m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()))
|
||||
&& (RuleI(Character, KillsPerGroupLeadershipAA) > 0))
|
||||
{
|
||||
AddLeadershipEXP(GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA), 0);
|
||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
||||
Client *mentoree = GetGroup()->GetMentoree();
|
||||
if (GetGroup()->GetMentorPercent() && mentoree &&
|
||||
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
|
||||
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
|
||||
exp -= mentor_exp;
|
||||
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
|
||||
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
if (exp > 0) { // possible if you mentor 100% to the other client
|
||||
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
|
||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
}
|
||||
else
|
||||
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
||||
|
||||
@ -46,6 +46,7 @@ Group::Group(uint32 gid)
|
||||
: GroupIDConsumer(gid)
|
||||
{
|
||||
leader = nullptr;
|
||||
mentoree = nullptr;
|
||||
memset(members,0,sizeof(Mob*) * MAX_GROUP_MEMBERS);
|
||||
AssistTargetID = 0;
|
||||
TankTargetID = 0;
|
||||
@ -81,6 +82,7 @@ Group::Group(Mob* leader)
|
||||
TankTargetID = 0;
|
||||
PullerTargetID = 0;
|
||||
memset(&LeaderAbilities, 0, sizeof(GroupLeadershipAA_Struct));
|
||||
mentoree = nullptr;
|
||||
uint32 i;
|
||||
for(i=0;i<MAX_GROUP_MEMBERS;i++)
|
||||
{
|
||||
@ -467,6 +469,11 @@ bool Group::UpdatePlayer(Mob* update){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// mentoree isn't set, the name has a length and the name is ours! update the pointer
|
||||
if (update->IsClient() && !mentoree && mentoree_name.length() && !mentoree_name.compare(update->GetName()))
|
||||
mentoree = update->CastToClient();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -500,6 +507,9 @@ void Group::MemberZoned(Mob* removemob) {
|
||||
|
||||
if(removemob->IsClient() && HasRole(removemob, RolePuller))
|
||||
SetGroupPullerTarget(0);
|
||||
|
||||
if (removemob->IsClient() && removemob == mentoree)
|
||||
mentoree = nullptr;
|
||||
}
|
||||
|
||||
bool Group::DelMemberOOZ(const char *Name) {
|
||||
@ -528,6 +538,8 @@ bool Group::DelMemberOOZ(const char *Name) {
|
||||
}
|
||||
ClearAllNPCMarks();
|
||||
}
|
||||
if (Name == mentoree_name)
|
||||
ClearGroupMentor();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -642,6 +654,9 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
|
||||
UnDelegatePuller(oldmember->GetName());
|
||||
}
|
||||
|
||||
if (oldmember->GetName() == mentoree_name)
|
||||
ClearGroupMentor();
|
||||
|
||||
if(oldmember->IsClient())
|
||||
SendMarkedNPCsToMember(oldmember->CastToClient(), true);
|
||||
|
||||
@ -1736,6 +1751,31 @@ void Group::SetGroupPullerTarget(Mob *m)
|
||||
}
|
||||
}
|
||||
|
||||
void Group::SetGroupMentor(int percent, char *name)
|
||||
{
|
||||
mentoree_name = name;
|
||||
mentor_percent = percent;
|
||||
Client *client = entity_list.GetClientByName(name);
|
||||
|
||||
mentoree = client ? client : nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET mentoree = '%s', mentor_percent = %i WHERE gid = %i LIMIT 1",
|
||||
mentoree_name.c_str(), mentor_percent, GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Group::ClearGroupMentor()
|
||||
{
|
||||
mentoree_name.clear();
|
||||
mentor_percent = 0;
|
||||
mentoree = nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET mentoree = '', mentor_percent = 0 WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Group::NotifyAssistTarget(Client *c)
|
||||
{
|
||||
// Send a packet to the specified client notifying them of the group target selected by the Main Assist.
|
||||
|
||||
@ -132,6 +132,11 @@ public:
|
||||
const char *GetClientNameByIndex(uint8 index);
|
||||
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
||||
|
||||
void SetGroupMentor(int percent, char *name);
|
||||
void ClearGroupMentor();
|
||||
inline int GetMentorPercent() { return mentor_percent; }
|
||||
inline Client *GetMentoree() { return mentoree; }
|
||||
|
||||
Mob* members[MAX_GROUP_MEMBERS];
|
||||
char membername[MAX_GROUP_MEMBERS][64];
|
||||
uint8 MemberRoles[MAX_GROUP_MEMBERS];
|
||||
@ -151,6 +156,9 @@ private:
|
||||
uint16 PullerTargetID;
|
||||
uint16 MarkedNPCs[MAX_MARKED_NPCS];
|
||||
|
||||
std::string mentoree_name;
|
||||
Client *mentoree;
|
||||
int mentor_percent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1001,9 +1001,11 @@ void WorldServer::Process() {
|
||||
char AssistName[64];
|
||||
char PullerName[64];
|
||||
char NPCMarkerName[64];
|
||||
char mentoree_name[64];
|
||||
int mentor_percent;
|
||||
GroupLeadershipAA_Struct GLAA;
|
||||
memset(ln, 0, 64);
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, &GLAA));
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, mentoree_name, &mentor_percent, &GLAA));
|
||||
Client *lc = entity_list.GetClientByName(ln);
|
||||
if(lc)
|
||||
group->SetLeader(lc);
|
||||
@ -1013,6 +1015,7 @@ void WorldServer::Process() {
|
||||
group->SetPuller(PullerName);
|
||||
group->SetNPCMarker(NPCMarkerName);
|
||||
group->SetGroupAAs(&GLAA);
|
||||
group->SetGroupMentor(mentor_percent, mentoree_name);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -2534,7 +2534,7 @@ void ZoneDatabase::RefreshGroupFromDB(Client *client){
|
||||
gu->action = groupActUpdate;
|
||||
|
||||
strcpy(gu->yourname, client->GetName());
|
||||
GetGroupLeadershipInfo(group->GetID(), gu->leadersname, nullptr, nullptr, nullptr, nullptr, &gu->leader_aas);
|
||||
GetGroupLeadershipInfo(group->GetID(), gu->leadersname, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &gu->leader_aas);
|
||||
gu->NPCMarkerID = group->GetNPCMarkerID();
|
||||
|
||||
int index = 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user