diff --git a/changelog.txt b/changelog.txt index 6971c932d..ecdc1c62d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,15 @@ Notes: I modifed the behavior of both load and drop bots to fail on the first op 'load_bots.sql' will explicitly add bot schema, while 'drop_bots.sql' will explicitly drop it. I also added a few lines to change a few altered tables back to their original state - as of the date in the file. +== 10/13/2014 == +demonstar55: Partially implement leadership and raids + Currently working: client side only effects and stat bonuses. + Not working: Mark NPC, and other stuff that need extra server side support + Currently only UF tested (Tit and 62 may just work, others need packet work) + +== 10/12/2014 == +Akkadius: Fix for LDON Character Stat load + == 10/11/2014 == demonstar55: Implement Raid MOTD for UF Don't forget 2014_10_11_RaidMOTD.sql! diff --git a/common/database.cpp b/common/database.cpp index b6453d3cb..91a659d5b 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2952,11 +2952,20 @@ char* Database::GetGroupLeaderForLogin(const char* name, char* leaderbuf){ } void Database::SetGroupLeaderName(uint32 gid, const char* name) { - std::string query = StringFormat("REPLACE INTO `group_leaders` SET `gid` = %lu, `leadername` = '%s'",(unsigned long)gid,name); - auto results = QueryDatabase(query); + std::string query = StringFormat("UPDATE group_leaders SET leadername = '%s' WHERE gid = %u", EscapeString(name).c_str(), gid); + auto result = QueryDatabase(query); - if (!results.Success()) - std::cout << "Unable to set group leader: " << results.ErrorMessage() << std::endl; + if(result.RowsAffected() != 0) { + return; + } + + query = StringFormat("INSERT INTO group_leaders(gid, leadername, marknpc, leadershipaa, maintank, assist, puller) VALUES(%u, '%s', '', '', '', '', '')", + gid, EscapeString(name).c_str()); + result = QueryDatabase(query); + + if(!result.Success()) { + LogFile->write(EQEMuLog::Debug, "Error in Database::SetGroupLeaderName: %s", result.ErrorMessage().c_str()); + } } char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank, char* assist, char* puller, char *marknpc, GroupLeadershipAA_Struct* GLAA){ @@ -3163,6 +3172,142 @@ const char* Database::GetRaidLeaderName(uint32 rid) return name; } +// maintank, assist, puller, marknpc currently unused +void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank, + char *assist, char *puller, char *marknpc, GroupLeadershipAA_Struct *GLAA) +{ + std::string query = StringFormat( + "SELECT maintank, assist, puller, marknpc, leadershipaa FROM raid_leaders WHERE gid = %lu AND rid = %lu", + (unsigned long)gid, (unsigned long)rid); + auto results = QueryDatabase(query); + + if (!results.Success() || results.RowCount() == 0) { + if (maintank) + maintank[0] = '\0'; + + if (assist) + assist[0] = '\0'; + + if (puller) + puller[0] = '\0'; + + if (marknpc) + marknpc[0] = '\0'; + + return; + } + + auto row = results.begin(); + + if (maintank) + strcpy(maintank, row[0]); + + if (assist) + strcpy(assist, row[1]); + + if (puller) + strcpy(puller, row[2]); + + if (marknpc) + strcpy(marknpc, row[3]); + + if (GLAA && results.LengthOfColumn(4) == sizeof(GroupLeadershipAA_Struct)) + memcpy(GLAA, row[4], sizeof(GroupLeadershipAA_Struct)); + + return; +} + +// maintank, assist, puller, marknpc currently unused +void Database::GetRaidLeadershipInfo(uint32 rid, char *maintank, + char *assist, char *puller, char *marknpc, RaidLeadershipAA_Struct *RLAA) +{ + std::string query = StringFormat( + "SELECT maintank, assist, puller, marknpc, leadershipaa FROM raid_leaders WHERE gid = %lu AND rid = %lu", + (unsigned long)0xFFFFFFFF, (unsigned long)rid); + auto results = QueryDatabase(query); + + if (!results.Success() || results.RowCount() == 0) { + if (maintank) + maintank[0] = '\0'; + + if (assist) + assist[0] = '\0'; + + if (puller) + puller[0] = '\0'; + + if (marknpc) + marknpc[0] = '\0'; + + return; + } + + auto row = results.begin(); + + if (maintank) + strcpy(maintank, row[0]); + + if (assist) + strcpy(assist, row[1]); + + if (puller) + strcpy(puller, row[2]); + + if (marknpc) + strcpy(marknpc, row[3]); + + if (RLAA && results.LengthOfColumn(4) == sizeof(RaidLeadershipAA_Struct)) + memcpy(RLAA, row[4], sizeof(RaidLeadershipAA_Struct)); + + return; +} + +void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid) +{ + std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '', WHERE gid = %lu AND rid = %lu", + (unsigned long)gid, (unsigned long)rid); + auto results = QueryDatabase(query); + + if (results.RowsAffected() != 0) + return; + + query = StringFormat("INSERT INTO raid_leaders(gid, rid, marknpc, leadershipaa, maintank, assist, puller) VALUES(%lu, %lu, '', '', '', '', '')", + (unsigned long)gid, (unsigned long)rid); + results = QueryDatabase(query); + + if (!results.Success()) + std::cout << "Unable to set raid/group leader: " << results.ErrorMessage() << std::endl; + + return; +} + +// Clearing all raid leaders +void Database::ClearAllRaidLeaders(void) +{ + std::string query("DELETE from raid_leaders"); + auto results = QueryDatabase(query); + + if (!results.Success()) + std::cout << "Unable to clear raid leaders: " << results.ErrorMessage() << std::endl; + + return; +} + +void Database::ClearRaidLeader(uint32 gid, uint32 rid) +{ + if (rid == 0) { + ClearAllRaidLeaders(); + return; + } + + std::string query = StringFormat("DELETE from raid_leaders where gid = %lu and rid = %lu", + (unsigned long)gid, (unsigned long)rid); + auto results = QueryDatabase(query); + + if (!results.Success()) + std::cout << "Unable to clear raid leader: " << results.ErrorMessage() << std::endl; +} + bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id) { //we are not saved to this instance so set our instance to 0 @@ -3699,8 +3844,7 @@ void Database::UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win) QueryDatabase(query); } -bool Database::GetAdventureStats(uint32 char_id, uint32 &guk_w, uint32 &mir_w, uint32 &mmc_w, uint32 &ruj_w, - uint32 &tak_w, uint32 &guk_l, uint32 &mir_l, uint32 &mmc_l, uint32 &ruj_l, uint32 &tak_l) +bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as) { std::string query = StringFormat("SELECT `guk_wins`, `mir_wins`, `mmc_wins`, `ruj_wins`, `tak_wins`, `guk_losses`, " @@ -3715,16 +3859,18 @@ bool Database::GetAdventureStats(uint32 char_id, uint32 &guk_w, uint32 &mir_w, u auto row = results.begin(); - guk_w = atoi(row[0]); - mir_w = atoi(row[1]); - mmc_w = atoi(row[2]); - ruj_w = atoi(row[3]); - tak_w = atoi(row[4]); - guk_l = atoi(row[5]); - mir_l = atoi(row[6]); - mmc_l = atoi(row[7]); - ruj_l = atoi(row[8]); - tak_l = atoi(row[9]); + as->success.guk = atoi(row[0]); + as->success.mir = atoi(row[1]); + as->success.mmc = atoi(row[2]); + as->success.ruj = atoi(row[3]); + as->success.tak = atoi(row[4]); + as->failure.guk = atoi(row[5]); + as->failure.mir = atoi(row[6]); + as->failure.mmc = atoi(row[7]); + as->failure.ruj = atoi(row[8]); + as->failure.tak = atoi(row[9]); + as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak; + as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak; return true; } diff --git a/common/database.h b/common/database.h index a24198ca4..6fa9ef60a 100644 --- a/common/database.h +++ b/common/database.h @@ -174,8 +174,7 @@ public: * Adventure related. */ void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win); - bool GetAdventureStats(uint32 char_id, uint32 &guk_w, uint32 &mir_w, uint32 &mmc_w, uint32 &ruj_w, uint32 &tak_w, - uint32 &guk_l, uint32 &mir_l, uint32 &mmc_l, uint32 &ruj_l, uint32 &tak_l); + bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as); /* * Account Related @@ -215,6 +214,12 @@ public: void ClearRaidDetails(uint32 rid = 0); 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); + 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); + void ClearRaidLeader(uint32 gid = 0xFFFFFFFF, uint32 rid = 0); bool CheckDatabaseConversions(); @@ -274,6 +279,7 @@ private: */ void ClearAllRaids(); void ClearAllRaidDetails(); + void ClearAllRaidLeaders(); }; #endif diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index eda2a5ce8..a78b2afa1 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -759,14 +759,62 @@ struct MovePotionToBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** @@ -3934,6 +3982,15 @@ struct RaidMOTD_Struct { /*136*/ char motd[0]; // max size is 1024, but reply is variable }; +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ char leader_name[64]; +/*132*/ GroupLeadershipAA_Struct group; //unneeded +/*196*/ RaidLeadershipAA_Struct raid; +/*260*/ char Unknown260[128]; //unverified +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/common/patches/client62_structs.h b/common/patches/client62_structs.h index 8c80e34a5..aae4c7919 100644 --- a/common/patches/client62_structs.h +++ b/common/patches/client62_structs.h @@ -611,14 +611,62 @@ struct PotionBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /* diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 49f6c51f1..96ebcaf63 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2613,6 +2613,18 @@ namespace RoF strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == 14) + { + RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; + + outlaa->action = inlaa->action; + strn0cpy(outlaa->player_name, inlaa->player_name, 64); + strn0cpy(outlaa->leader_name, inlaa->leader_name, 64); + memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); + dest->FastQueuePacket(&outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 99dff46cc..e65f2b74d 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -915,14 +915,62 @@ struct PotionBelt_Struct { BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; }; -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** @@ -3999,6 +4047,16 @@ struct RaidMOTD_Struct { /*140*/ char motd[0]; // max size 1024, but reply is variable }; +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ uint32 Unknown068; +/*072*/ char leader_name[64]; +/*136*/ GroupLeadershipAA_Struct group; //unneeded +/*200*/ RaidLeadershipAA_Struct raid; +/*264*/ char Unknown264[128]; +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index edfddabca..134be8008 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1668,6 +1668,18 @@ namespace SoD strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == 14) + { + RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; + + outlaa->action = inlaa->action; + strn0cpy(outlaa->player_name, inlaa->player_name, 64); + strn0cpy(outlaa->leader_name, inlaa->leader_name, 64); + memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); + dest->FastQueuePacket(&outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 53cc148b9..88c0ed91a 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -711,14 +711,62 @@ struct PotionBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** @@ -3567,6 +3615,16 @@ struct RaidMOTD_Struct { /*140*/ char motd[0]; // max size 1024, but reply is variable }; +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ uint32 Unknown068; +/*072*/ char leader_name[64]; +/*136*/ GroupLeadershipAA_Struct group; //unneeded +/*200*/ RaidLeadershipAA_Struct raid; +/*264*/ char Unknown264[128]; +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index bf5046c91..2b4640f29 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1326,6 +1326,18 @@ namespace SoF strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == 14) + { + RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; + + outlaa->action = inlaa->action; + strn0cpy(outlaa->player_name, inlaa->player_name, 64); + strn0cpy(outlaa->leader_name, inlaa->leader_name, 64); + memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); + dest->FastQueuePacket(&outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index c943b5108..a101d3cba 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -689,14 +689,62 @@ struct PotionBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** @@ -3430,6 +3478,16 @@ struct RaidMOTD_Struct { /*140*/ char motd[0]; // max size 1024, but reply is variable }; +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ uint32 Unknown068; +/*072*/ char leader_name[64]; +/*136*/ GroupLeadershipAA_Struct group; //unneeded +/*200*/ RaidLeadershipAA_Struct raid; +/*264*/ char Unknown264[128]; +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 17beb6479..e8e5a9f23 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -619,14 +619,62 @@ struct PotionBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index 03ef16a2a..dd31d749d 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -1940,6 +1940,18 @@ namespace Underfoot strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == 14) + { + RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; + + outlaa->action = inlaa->action; + strn0cpy(outlaa->player_name, inlaa->player_name, 64); + strn0cpy(outlaa->leader_name, inlaa->leader_name, 64); + memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); + dest->FastQueuePacket(&outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index f331d5dbc..2b7163bcf 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -754,14 +754,62 @@ struct PotionBelt_Struct { static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); -struct LeadershipAA_Struct { - uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; -}; struct GroupLeadershipAA_Struct { - uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; }; + struct RaidLeadershipAA_Struct { - uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; }; /** @@ -3628,6 +3676,16 @@ struct RaidMOTD_Struct { /*140*/ char motd[0]; // max size 1024, but reply is variable }; +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ uint32 Unknown068; +/*072*/ char leader_name[64]; +/*136*/ GroupLeadershipAA_Struct group; //unneeded +/*200*/ RaidLeadershipAA_Struct raid; +/*264*/ char Unknown264[128]; +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 16197c0da..e4eb9ba14 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -289,8 +289,10 @@ OP_LeadershipExpToggle=0x3ea6 OP_LeadershipExpUpdate=0x6922 OP_PurchaseLeadershipAA=0x1962 OP_UpdateLeadershipAA=0x56aa -OP_MarkNPC=0x2d9f +OP_MarkNPC=0x1a6c +OP_MarkRaidNPC=0x2d9f #unimplemented OP_ClearNPCMarks=0x0d2d +OP_ClearRaidNPCMarks=0x433a #unimplemented OP_DelegateAbility=0x7820 OP_SetGroupTarget=0x118a OP_Charm=0x7118 diff --git a/utils/patches/patch_SoD.conf b/utils/patches/patch_SoD.conf index f0d223edb..472d60e7a 100644 --- a/utils/patches/patch_SoD.conf +++ b/utils/patches/patch_SoD.conf @@ -288,8 +288,10 @@ OP_LeadershipExpToggle=0x34c5 # C OP_LeadershipExpUpdate=0x69d0 # C OP_PurchaseLeadershipAA=0x07b3 # C OP_UpdateLeadershipAA=0x6948 # C -OP_MarkNPC=0x0d4b # C +OP_MarkNPC=0x695c # C +OP_MarkRaidNPC=0x0d4b # C OP_ClearNPCMarks=0x5033 # C +OP_ClearRaidNPCMarks=0x5f55 # C OP_DoGroupLeadershipAbility=0x540b # C OP_GroupLeadershipAAUpdate=0x0c33 OP_DelegateAbility=0x0322 # C diff --git a/utils/patches/patch_SoF.conf b/utils/patches/patch_SoF.conf index 2e039b404..a50c1faf6 100644 --- a/utils/patches/patch_SoF.conf +++ b/utils/patches/patch_SoF.conf @@ -281,8 +281,10 @@ OP_LeadershipExpToggle=0x24D4 #Xinu 02/20/09 OP_LeadershipExpUpdate=0x58b6 #Derision 2009 OP_PurchaseLeadershipAA=0x1408 #Derision 2009 OP_UpdateLeadershipAA=0x7abf #Derision 2009 -OP_MarkNPC=0x00c6 #Derision 2009 +OP_MarkNPC=0x4697 #Derision 2009 +OP_MarkRaidNPC=0x00c6 OP_ClearNPCMarks=0x2ff2 # +OP_ClearRaidNPCMarks=0x56a9 # OP_DoGroupLeadershipAbility=0x5a64 #Derision 2009 OP_DelegateAbility=0x57e3 #Derision 2009 OP_SetGroupTarget=0x1651 #Derision 2009 diff --git a/utils/patches/patch_Underfoot.conf b/utils/patches/patch_Underfoot.conf index 1b65a6481..b7bdbc7e0 100644 --- a/utils/patches/patch_Underfoot.conf +++ b/utils/patches/patch_Underfoot.conf @@ -292,8 +292,10 @@ OP_LeadershipExpToggle=0x5033 # C OP_LeadershipExpUpdate=0x074f # C OP_PurchaseLeadershipAA=0x5f55 # C OP_UpdateLeadershipAA=0x77ed # C -OP_MarkNPC=0x3ec7 # C +OP_MarkNPC=0x66bf +OP_MarkRaidNPC=0x3ec7 # C OP_ClearNPCMarks=0x5c29 # C +OP_ClearRaidNPCMarks=0x2af4 OP_DoGroupLeadershipAbility=0x0068 # C OP_GroupLeadershipAAUpdate=0x167b # C OP_DelegateAbility=0x6e58 # C @@ -656,3 +658,6 @@ OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs OP_InitialHPUpdate=0x0000 # OP_ItemRecastDelay=0x82d7 + +# unhandled +OP_ShieldGroup=0x23a1 diff --git a/utils/sql/git/required/2014_10_13_RaidLeadership.sql b/utils/sql/git/required/2014_10_13_RaidLeadership.sql new file mode 100644 index 000000000..972e09ed5 --- /dev/null +++ b/utils/sql/git/required/2014_10_13_RaidLeadership.sql @@ -0,0 +1,9 @@ +CREATE TABLE `raid_leaders` ( + `gid` int(4) unsigned NOT NULL, + `rid` int(4) unsigned NOT NULL, + `marknpc` varchar(64) NOT NULL, + `maintank` varchar(64) NOT NULL, + `assist` varchar(64) NOT NULL, + `puller` varchar(64) NOT NULL, + `leadershipaa` tinyblob NOT NULL +); diff --git a/world/adventure.cpp b/world/adventure.cpp index 45dd206e5..5f61aa5e9 100644 --- a/world/adventure.cpp +++ b/world/adventure.cpp @@ -358,6 +358,7 @@ void Adventure::Finished(AdventureWinStatus ws) afe.points = 0; } adventure_manager.AddFinishedEvent(afe); + database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter).c_str()), GetTemplate()->theme, (ws != AWS_Lose) ? true : false); } ++iter; diff --git a/world/net.cpp b/world/net.cpp index c7340333e..7973b5872 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -283,6 +283,7 @@ int main(int argc, char** argv) { _log(WORLD__INIT, "Clearing raids.."); database.ClearRaid(); database.ClearRaidDetails(); + database.ClearRaidLeader(); _log(WORLD__INIT, "Loading items.."); if (!database.LoadItems()) _log(WORLD__INIT_ERR, "Error: Could not load item data. But ignoring"); diff --git a/zone/aa.cpp b/zone/aa.cpp index 8af3896d3..d07ed72cf 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1550,6 +1550,41 @@ void Client::ResetAA(){ int Client::GroupLeadershipAAHealthEnhancement() { + if (IsRaidGrouped()) { + int bonus = 0; + Raid *raid = GetRaid(); + if (!raid) + return 0; + uint32 group_id = raid->GetGroup(this); + if (group_id < 12 && raid->GroupCount(group_id) >= 3) { + switch (raid->GetLeadershipAA(groupAAHealthEnhancement, group_id)) { + case 1: + bonus = 30; + break; + case 2: + bonus = 60; + break; + case 3: + bonus = 100; + break; + } + } + if (raid->RaidCount() >= 18) { + switch (raid->GetLeadershipAA(raidAAHealthEnhancement)) { + case 1: + bonus += 30; + break; + case 2: + bonus += 60; + break; + case 3: + bonus += 100; + break; + } + } + return bonus; + } + Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) @@ -1572,6 +1607,41 @@ int Client::GroupLeadershipAAHealthEnhancement() int Client::GroupLeadershipAAManaEnhancement() { + if (IsRaidGrouped()) { + int bonus = 0; + Raid *raid = GetRaid(); + if (!raid) + return 0; + uint32 group_id = raid->GetGroup(this); + if (group_id < 12 && raid->GroupCount(group_id) >= 3) { + switch (raid->GetLeadershipAA(groupAAManaEnhancement, group_id)) { + case 1: + bonus = 30; + break; + case 2: + bonus = 60; + break; + case 3: + bonus = 100; + break; + } + } + if (raid->RaidCount() >= 18) { + switch (raid->GetLeadershipAA(raidAAManaEnhancement)) { + case 1: + bonus += 30; + break; + case 2: + bonus += 60; + break; + case 3: + bonus += 100; + break; + } + } + return bonus; + } + Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) @@ -1594,6 +1664,41 @@ int Client::GroupLeadershipAAManaEnhancement() int Client::GroupLeadershipAAHealthRegeneration() { + if (IsRaidGrouped()) { + int bonus = 0; + Raid *raid = GetRaid(); + if (!raid) + return 0; + uint32 group_id = raid->GetGroup(this); + if (group_id < 12 && raid->GroupCount(group_id) >= 3) { + switch (raid->GetLeadershipAA(groupAAHealthRegeneration, group_id)) { + case 1: + bonus = 4; + break; + case 2: + bonus = 6; + break; + case 3: + bonus = 8; + break; + } + } + if (raid->RaidCount() >= 18) { + switch (raid->GetLeadershipAA(raidAAHealthRegeneration)) { + case 1: + bonus += 4; + break; + case 2: + bonus += 6; + break; + case 3: + bonus += 8; + break; + } + } + return bonus; + } + Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) @@ -1616,6 +1721,53 @@ int Client::GroupLeadershipAAHealthRegeneration() int Client::GroupLeadershipAAOffenseEnhancement() { + if (IsRaidGrouped()) { + int bonus = 0; + Raid *raid = GetRaid(); + if (!raid) + return 0; + uint32 group_id = raid->GetGroup(this); + if (group_id < 12 && raid->GroupCount(group_id) >= 3) { + switch (raid->GetLeadershipAA(groupAAOffenseEnhancement, group_id)) { + case 1: + bonus = 10; + break; + case 2: + bonus = 19; + break; + case 3: + bonus = 28; + break; + case 4: + bonus = 34; + break; + case 5: + bonus = 40; + break; + } + } + if (raid->RaidCount() >= 18) { + switch (raid->GetLeadershipAA(raidAAOffenseEnhancement)) { + case 1: + bonus += 10; + break; + case 2: + bonus += 19; + break; + case 3: + bonus += 28; + break; + case 4: + bonus += 34; + break; + case 5: + bonus += 40; + break; + } + } + return bonus; + } + Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) diff --git a/zone/client.cpp b/zone/client.cpp index a277b9858..3b95c8d77 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1287,7 +1287,7 @@ bool Client::UpdateLDoNPoints(int32 points, uint32 theme) m_pp.ldon_points_ruj += rujpts; m_pp.ldon_points_tak += takpts; points-=splitpts; - // if anything left, recursively loop thru again + // if anything left, recursively loop thru again if (splitpts !=0) UpdateLDoNPoints(splitpts,0); break; @@ -1344,6 +1344,7 @@ bool Client::UpdateLDoNPoints(int32 points, uint32 theme) } } m_pp.ldon_points_available += points; + EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct)); AdventurePoints_Update_Struct* apus = (AdventurePoints_Update_Struct*)outapp->pBuffer; apus->ldon_available_points = m_pp.ldon_points_available; @@ -3669,7 +3670,11 @@ void Client::LogSQL(const char *fmt, ...) { } void Client::GetGroupAAs(GroupLeadershipAA_Struct *into) const { - memcpy(into, &m_pp.leader_abilities, sizeof(GroupLeadershipAA_Struct)); + memcpy(into, &m_pp.leader_abilities.group, sizeof(GroupLeadershipAA_Struct)); +} + +void Client::GetRaidAAs(RaidLeadershipAA_Struct *into) const { + memcpy(into, &m_pp.leader_abilities.raid, sizeof(RaidLeadershipAA_Struct)); } void Client::EnteringMessages(Client* client) diff --git a/zone/client.h b/zone/client.h index 3375d7066..e31c15598 100644 --- a/zone/client.h +++ b/zone/client.h @@ -559,6 +559,9 @@ public: void SendLeadershipEXPUpdate(); bool IsLeadershipEXPOn(); inline int GetLeadershipAA(int AAID) { return m_pp.leader_abilities.ranks[AAID]; } + inline LeadershipAA_Struct &GetLeadershipAA() { return m_pp.leader_abilities; } + inline GroupLeadershipAA_Struct &GetGroupLeadershipAA() { return m_pp.leader_abilities.group; } + inline RaidLeadershipAA_Struct &GetRaidLeadershipAA() { return m_pp.leader_abilities.raid; } int GroupLeadershipAAHealthEnhancement(); int GroupLeadershipAAManaEnhancement(); int GroupLeadershipAAHealthRegeneration(); @@ -585,6 +588,7 @@ public: bool CheckLoreConflict(const Item_Struct* item); void ChangeLastName(const char* in_lastname); void GetGroupAAs(GroupLeadershipAA_Struct *into) const; + void GetRaidAAs(RaidLeadershipAA_Struct *into) const; void ClearGroupAAs(); void UpdateGroupAAs(int32 points, uint32 type); void SacrificeConfirm(Client* caster); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 03d44c903..fdc5e5021 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -546,6 +546,7 @@ void Client::CompleteConnect() raid = new Raid(raidid); if (raid->GetID() != 0){ entity_list.AddRaid(raid, raidid); + raid->LoadLeadership(); // Recreating raid in new zone, get leadership from DB } else raid = nullptr; @@ -566,11 +567,20 @@ void Client::CompleteConnect() raid->SendBulkRaid(this); raid->SendGroupUpdate(this); raid->SendRaidMOTD(this); + if (raid->IsLeader(this)) { // We're a raid leader, lets update just in case! + raid->UpdateRaidAAs(); + raid->SendAllRaidLeadershipAA(); + } uint32 grpID = raid->GetGroup(GetName()); if (grpID < 12){ raid->SendRaidGroupRemove(GetName(), grpID); raid->SendRaidGroupAdd(GetName(), grpID); + if (raid->IsGroupLeader(GetName())) { // group leader same thing! + raid->UpdateGroupAAs(raid->GetGroup(this)); + raid->GroupUpdate(grpID, false); + } } + raid->SendGroupLeadershipAA(this, grpID); // this may get sent an extra time ... if (raid->IsLocked()) raid->SendRaidLockTo(this); } @@ -1406,6 +1416,22 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) database.LoadCharacterLeadershipAA(cid, &m_pp); /* Load Character Leadership AA's */ database.LoadCharacterTribute(cid, &m_pp); /* Load CharacterTribute */ + /* Load AdventureStats */ + AdventureStats_Struct as; + if(database.GetAdventureStats(cid, &as)) + { + m_pp.ldon_wins_guk = as.success.guk; + m_pp.ldon_wins_mir = as.success.mir; + m_pp.ldon_wins_mmc = as.success.mmc; + m_pp.ldon_wins_ruj = as.success.ruj; + m_pp.ldon_wins_tak = as.success.tak; + m_pp.ldon_losses_guk = as.failure.guk; + m_pp.ldon_losses_mir = as.failure.mir; + m_pp.ldon_losses_mmc = as.failure.mmc; + m_pp.ldon_losses_ruj = as.failure.ruj; + m_pp.ldon_losses_tak = as.failure.tak; + } + /* Set item material tint */ for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) if (m_pp.item_tint[i].rgb.use_tint == 1 || m_pp.item_tint[i].rgb.use_tint == 255) @@ -2488,11 +2514,8 @@ void Client::Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app) EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureStatsReply, sizeof(AdventureStats_Struct)); AdventureStats_Struct *as = (AdventureStats_Struct*)outapp->pBuffer; - if (database.GetAdventureStats(CharacterID(), as->success.guk, as->success.mir, as->success.mmc, as->success.ruj, - as->success.tak, as->failure.guk, as->failure.mir, as->failure.mmc, as->failure.ruj, as->failure.tak)) + if (database.GetAdventureStats(CharacterID(), as)) { - as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak; - as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak; m_pp.ldon_wins_guk = as->success.guk; m_pp.ldon_wins_mir = as->success.mir; m_pp.ldon_wins_mmc = as->success.mmc; @@ -5322,6 +5345,8 @@ void Client::Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app) } default: + LogFile->write(EQEMuLog::Debug, "Got unhandled OP_DoGroupLeadershipAbility Ability: %d Parameter: %d", + dglas->Ability, dglas->Parameter); break; } } @@ -10593,10 +10618,23 @@ void Client::Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app) u->pointsleft = m_pp.group_leadership_points; FastQueuePacket(&outapp); - Group *g = GetGroup(); - // Update all group members with the new AA the leader has purchased. - if (g) { + if (IsRaidGrouped()) { + Raid *r = GetRaid(); + if (!r) + return; + if (aaid >= raidAAMarkNPC) { + r->UpdateRaidAAs(); + r->SendAllRaidLeadershipAA(); + } else { + uint32 gid = r->GetGroup(this); + r->UpdateGroupAAs(gid); + r->GroupUpdate(gid, false); + } + } else if (IsGrouped()) { + Group *g = GetGroup(); + if (!g) + return; g->UpdateGroupAAs(); g->SendLeadershipAAUpdate(); } @@ -11215,6 +11253,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { if (strcmp(r->leadername, GetName()) == 0){ r->SetRaidLeader(GetName(), ri->leader_name); + r->UpdateRaidAAs(); + r->SendAllRaidLeadershipAA(); } } break; diff --git a/zone/entity.cpp b/zone/entity.cpp index fd031d618..4a8329639 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4120,15 +4120,10 @@ void EntityList::UnMarkNPC(uint16 ID) // each group to remove the dead mobs entity ID from the groups list of NPCs marked via the // Group Leadership AA Mark NPC ability. // - auto it = client_list.begin(); - while (it != client_list.end()) { - if (it->second) { - Group *g = nullptr; - g = it->second->GetGroup(); - - if (g) - g->UnMarkNPC(ID); - } + auto it = group_list.begin(); + while (it != group_list.end()) { + if (*it) + (*it)->UnMarkNPC(ID); ++it; } } diff --git a/zone/raids.cpp b/zone/raids.cpp index f22267a2f..0adbcdef1 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -29,6 +29,8 @@ Raid::Raid(uint32 raidID) : GroupIDConsumer(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); leader = nullptr; memset(leadername, 0, 64); locked = false; @@ -39,6 +41,8 @@ Raid::Raid(Client* nLeader) : GroupIDConsumer() { 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); leader = nLeader; memset(leadername, 0, 64); strn0cpy(leadername, nLeader->GetName(), 64); @@ -84,8 +88,18 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo LearnMembers(); VerifyRaid(); + if (rleader) { + database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); + UpdateRaidAAs(); + } + if (group != RAID_GROUPLESS && groupleader) { + database.SetRaidGroupLeaderInfo(group, GetID()); + UpdateGroupAAs(group); + } if(group < 12) GroupUpdate(group); + else // get raid AAs, GroupUpdate will handles it otherwise + SendGroupLeadershipAA(c, RAID_GROUPLESS); SendRaidAddAll(c->GetName()); c->SetRaidGrouped(true); @@ -186,6 +200,18 @@ void Raid::SetGroupLeader(const char *who, bool glFlag) safe_delete(pack); } +Client *Raid::GetGroupLeader(uint32 group_id) +{ + if (group_id == RAID_GROUPLESS) + return nullptr; + + for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) + if (members[i].member && members[i].IsGroupLeader && members[i].GroupNumber == group_id) + return members[i].member; + + return nullptr; +} + void Raid::SetRaidLeader(const char *wasLead, const char *name) { std::string query = StringFormat("UPDATE raid_members SET israidleader = 0 WHERE name = '%s'", wasLead); @@ -218,6 +244,59 @@ void Raid::SetRaidLeader(const char *wasLead, const char *name) safe_delete(pack); } +void Raid::SaveGroupLeaderAA(uint32 gid) +{ + char *queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1]; + database.DoEscapeString(queryBuffer, (char*)&group_aa[gid], sizeof(GroupLeadershipAA_Struct)); + + std::string query = "UPDATE raid_leaders SET leadershipaa = '"; + query += queryBuffer; + query += StringFormat("' WHERE gid = %lu AND rid = %lu LIMIT 1", gid, GetID()); + safe_delete_array(queryBuffer); + auto results = database.QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str()); +} + +void Raid::SaveRaidLeaderAA() +{ + char *queryBuffer = new char[sizeof(RaidLeadershipAA_Struct) * 2 + 1]; + database.DoEscapeString(queryBuffer, (char*)&raid_aa, sizeof(RaidLeadershipAA_Struct)); + _hex(NET__ERROR, queryBuffer, sizeof(RaidLeadershipAA_Struct)); + + std::string query = "UPDATE raid_leaders SET leadershipaa = '"; + query += queryBuffer; + query += StringFormat("' WHERE gid = %lu AND rid = %lu LIMIT 1", RAID_GROUPLESS, GetID()); + safe_delete_array(queryBuffer); + auto results = database.QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str()); +} + +void Raid::UpdateGroupAAs(uint32 gid) +{ + Client *gl = GetGroupLeader(gid); + + if (gl) + gl->GetGroupAAs(&group_aa[gid]); + else + memset(&group_aa[gid], 0, sizeof(GroupLeadershipAA_Struct)); + + SaveGroupLeaderAA(gid); +} + +void Raid::UpdateRaidAAs() +{ + Client *rl = GetLeader(); + + if (rl) + rl->GetRaidAAs(&raid_aa); + else + memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct)); + + SaveRaidLeaderAA(); +} + bool Raid::IsGroupLeader(const char *who) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) @@ -1094,6 +1173,7 @@ void Raid::SendGroupUpdate(Client *to) strn0cpy(gu->leadersname, to->GetName(), 64); } strn0cpy(gu->yourname, to->GetName(), 64); + memcpy(&gu->leader_aas, &group_aa[grp], sizeof(GroupLeadershipAA_Struct)); to->FastQueuePacket(&outapp); } @@ -1106,8 +1186,10 @@ void Raid::GroupUpdate(uint32 gid, bool initial) { if(strlen(members[x].membername) > 0){ if(members[x].GroupNumber == gid){ - if(members[x].member) + if(members[x].member) { SendGroupUpdate(members[x].member); + SendGroupLeadershipAA(members[x].member, gid); + } } } } @@ -1244,6 +1326,34 @@ void Raid::SendRaidMOTDToWorld() safe_delete(pack); } +void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) +{ + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); + RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer; + rlaa->action = raidSetLeaderAbilities; + strn0cpy(rlaa->leader_name, c->GetName(), 64); + strn0cpy(rlaa->player_name, c->GetName(), 64); + if (gid != RAID_GROUPLESS) + memcpy(&rlaa->group, &group_aa[gid], sizeof(GroupLeadershipAA_Struct)); + memcpy(&rlaa->raid, &raid_aa, sizeof(RaidLeadershipAA_Struct)); + c->QueuePacket(outapp); + safe_delete(outapp); +} + +void Raid::SendGroupLeadershipAA(uint32 gid) +{ + for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) + if (members[i].member && members[i].GroupNumber == gid) + SendGroupLeadershipAA(members[i].member, gid); +} + +void Raid::SendAllRaidLeadershipAA() +{ + for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) + if (members[i].member) + SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); +} + void Raid::LockRaid(bool lockFlag) { std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu", @@ -1484,3 +1594,11 @@ void Raid::RaidMessage_StringID(Mob* sender, uint32 type, uint32 string_id, cons } } +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]); +} + diff --git a/zone/raids.h b/zone/raids.h index 44952e5da..6e2579367 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -43,8 +43,8 @@ enum { //raid packet types: raidChangeLootType = 11, raidStringID = 12, raidChangeGroupLeader = 13, //136 raid leader, new group leader, group_id? - raidBecomeGroupLeader = 14, //472 - raidUnknown2 = 15, + raidSetLeaderAbilities = 14, //472 + raidSetLeaderData = 15, // 14,15 SoE names, not sure on difference, 14 packet has 0x100 bytes 15 0x214 in addition to raid general raidChangeGroup = 16, //?? len 136 old leader, new leader, 0 (preceeded with a remove2) raidLock = 17, //len 136 leader?, leader, 0 raidUnlock = 18, //len 136 leader?, leader, 0 @@ -79,6 +79,7 @@ enum { //raid command types #define MAX_RAID_GROUPS 12 #define MAX_RAID_MEMBERS 72 +const uint32 RAID_GROUPLESS = 0xFFFFFFFF; struct RaidMember{ char membername[64]; @@ -111,6 +112,7 @@ public: void DisbandRaid(); void MoveMember(const char *name, uint32 newGroup); void SetGroupLeader(const char *who, bool glFlag = true); + Client *GetGroupLeader(uint32 group_id); void RemoveGroupLeader(const char *who); bool IsGroupLeader(const char *who); bool IsRaidMember(const char *name); @@ -203,6 +205,22 @@ public: void QueuePacket(const EQApplicationPacket *app, bool ack_req = true); + // Leadership + void UpdateGroupAAs(uint32 gid); + void SaveGroupLeaderAA(uint32 gid); + void UpdateRaidAAs(); + void SaveRaidLeaderAA(); + void SendGroupLeadershipAA(Client *c, uint32 gid); + void SendGroupLeadershipAA(uint32 gid); + void SendAllRaidLeadershipAA(); + void LoadLeadership(); + inline int GetLeadershipAA(int AAID, uint32 gid = 0) + { if (AAID >= 16) return raid_aa.ranks[AAID - 16]; else return group_aa[gid].ranks[AAID]; } + inline void SetGroupAAs(uint32 gid, GroupLeadershipAA_Struct *glaa) + { memcpy(&group_aa[gid], glaa, sizeof(GroupLeadershipAA_Struct)); } + inline void SetRaidAAs(RaidLeadershipAA_Struct *rlaa) + { memcpy(&raid_aa, rlaa, sizeof(RaidLeadershipAA_Struct)); } + RaidMember members[MAX_RAID_MEMBERS]; char leadername[64]; protected: @@ -213,6 +231,8 @@ protected: bool disbandCheck; bool forceDisband; std::string motd; + RaidLeadershipAA_Struct raid_aa; + GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS]; }; diff --git a/zone/zone.cpp b/zone/zone.cpp index 23aa95f2c..0207b28d4 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -411,7 +411,7 @@ void Zone::LoadTempMerchantData() { "WHERE " "ml.npcid = se.npcid " "AND se.spawngroupid = s2.spawngroupid " - "AND s2.zone = '%s' AND s2.version = %i" + "AND s2.zone = '%s' AND s2.version = %i " "ORDER BY ml.slot ", GetShortName(), GetInstanceVersion()); auto results = database.QueryDatabase(query); if (!results.Success()) {