[Character] Convert Delete/Load/Remove/Save of Character AA to Repositories (#3849)

* [Character] Convert Delete/Load/Remove/Save of Character AA to Repositories

- Convert `DeleteCharacterAAs`, `LoadAlternateAdvancement`, `RemoveExpendedAA` and `SaveAA` to repositories.
- Add `AACategory` namespace for AA Categories.
- Cleanup some logic/formatting in modified methods.

* Move namespace.
This commit is contained in:
Alex King 2024-01-07 00:30:04 -05:00 committed by GitHub
parent aa39ac8023
commit fd787af53a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 234 additions and 141 deletions

View File

@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_CHARACTER_ALTERNATE_ABILITIES_REPOSITORY_H
@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseCharacterAlternateAbilitiesRepository {
public:
struct CharacterAlternateAbilities {
@ -116,8 +117,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
character_alternate_abilities_id
)
);
@ -348,6 +350,68 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const CharacterAlternateAbilities &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.aa_id));
v.push_back(std::to_string(e.aa_value));
v.push_back(std::to_string(e.charges));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<CharacterAlternateAbilities> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.aa_id));
v.push_back(std::to_string(e.aa_value));
v.push_back(std::to_string(e.charges));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_CHARACTER_ALTERNATE_ABILITIES_REPOSITORY_H

View File

@ -39,6 +39,8 @@ Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
#include "bot.h"
#include "../common/repositories/character_alternate_abilities_repository.h"
extern WorldServer worldserver;
extern QueryServ* QServ;
@ -510,35 +512,38 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *tar, uint32 d
delete made_npc;
}
void Client::ResetAA() {
void Client::ResetAA()
{
SendClearAA();
RefundAA();
memset(&m_pp.aa_array[0], 0, sizeof(AA_Array) * MAX_PP_AA_ARRAY);
int i = 0;
for(auto &rank_value : aa_ranks) {
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value.first, rank_value.second.first);
auto ability = ability_rank.first;
auto rank = ability_rank.second;
int slot_id = 0;
if(!rank) {
for (auto& rank_value: aa_ranks) {
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value.first, rank_value.second.first);
auto ability = ability_rank.first;
auto rank = ability_rank.second;
if (!rank) {
continue;
}
m_pp.aa_array[i].AA = rank_value.first;
m_pp.aa_array[i].value = rank_value.second.first;
m_pp.aa_array[i].charges = rank_value.second.second;
++i;
m_pp.aa_array[slot_id].AA = rank_value.first;
m_pp.aa_array[slot_id].value = rank_value.second.first;
m_pp.aa_array[slot_id].charges = rank_value.second.second;
++slot_id;
}
for(int i = 0; i < _maxLeaderAA; ++i)
m_pp.leader_abilities.ranks[i] = 0;
for (int slot_id = 0; slot_id < _maxLeaderAA; ++slot_id) {
m_pp.leader_abilities.ranks[slot_id] = 0;
}
m_pp.group_leadership_points = 0;
m_pp.raid_leadership_points = 0;
m_pp.group_leadership_exp = 0;
m_pp.raid_leadership_exp = 0;
m_pp.raid_leadership_points = 0;
m_pp.group_leadership_exp = 0;
m_pp.raid_leadership_exp = 0;
database.DeleteCharacterAAs(CharacterID());
database.DeleteCharacterLeadershipAbilities(CharacterID());
@ -833,31 +838,31 @@ void Client::RefundAA() {
int refunded = 0;
auto rank_value = aa_ranks.begin();
while(rank_value != aa_ranks.end()) {
while (rank_value != aa_ranks.end()) {
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value->first, rank_value->second.first);
auto ability = ability_rank.first;
auto rank = ability_rank.second;
auto ability = ability_rank.first;
auto rank = ability_rank.second;
if(!ability) {
if (!ability) {
++rank_value;
continue;
}
if(ability->charges > 0 && rank_value->second.second < 1) {
if (ability->charges > 0 && rank_value->second.second < 1) {
++rank_value;
continue;
}
if(ability->grant_only) {
if (ability->grant_only) {
++rank_value;
continue;
}
refunded += rank->total_cost;
rank_value = aa_ranks.erase(rank_value);
rank_value = aa_ranks.erase(rank_value);
}
if(refunded > 0) {
if (refunded > 0) {
m_pp.aapoints += refunded;
SaveAA();
Save();
@ -1438,40 +1443,42 @@ void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
bool ZoneDatabase::LoadAlternateAdvancement(Client *c) {
c->ClearAAs();
std::string query = StringFormat(
"SELECT "
"aa_id, "
"aa_value, "
"charges "
"FROM "
"`character_alternate_abilities` "
"WHERE `id` = %u", c->CharacterID());
MySQLRequestResult results = database.QueryDatabase(query);
int i = 0;
for(auto row = results.begin(); row != results.end(); ++row) {
uint32 aa = Strings::ToUnsignedInt(row[0]);
uint32 value = Strings::ToUnsignedInt(row[1]);
uint32 charges = Strings::ToUnsignedInt(row[2]);
const auto& l = CharacterAlternateAbilitiesRepository::GetWhere(
database,
fmt::format(
"`id` = {}",
c->CharacterID()
)
);
auto rank = zone->GetAlternateAdvancementRank(aa);
if(!rank) {
uint32 slot_id = 0;
for (const auto& e : l) {
const uint16 aa_id = e.aa_id;
const uint16 aa_value = e.aa_value;
const uint16 charges = e.charges;
auto rank = zone->GetAlternateAdvancementRank(aa_id);
if (!rank) {
continue;
}
auto ability = rank->base_ability;
if(!ability) {
if (!ability) {
continue;
}
rank = ability->GetRankByPointsSpent(value);
rank = ability->GetRankByPointsSpent(aa_value);
if(c->CanUseAlternateAdvancementRank(rank)) {
c->GetPP().aa_array[i].AA = aa;
c->GetPP().aa_array[i].value = value;
c->GetPP().aa_array[i].charges = charges;
c->SetAA(aa, value, charges);
i++;
if (c->CanUseAlternateAdvancementRank(rank)) {
c->GetPP().aa_array[slot_id].AA = aa_id;
c->GetPP().aa_array[slot_id].value = aa_value;
c->GetPP().aa_array[slot_id].charges = charges;
c->SetAA(aa_id, aa_value, charges);
slot_id++;
}
}
@ -1556,56 +1563,61 @@ uint32 Mob::GetAAByAAID(uint32 aa_id, uint32 *charges) const {
return 0;
}
bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges) {
if(zone) {
AA::Ability *ability = zone->GetAlternateAdvancementAbilityByRank(rank_id);
bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges)
{
if (zone) {
auto a = zone->GetAlternateAdvancementAbilityByRank(rank_id);
if(!ability) {
if (!a) {
return false;
}
if(new_value > ability->GetMaxLevel(this)) {
if(new_value > a->GetMaxLevel(this)) {
return false;
}
aa_ranks[ability->id] = std::make_pair(new_value, charges);
aa_ranks[a->id] = std::make_pair(new_value, charges);
}
return true;
}
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank)
{
if (!rank) {
return false;
}
AA::Ability *ability = rank->base_ability;
const auto a = rank->base_ability;
if(!ability)
return false;
if(!(ability->classes & (1 << GetClass()))) {
if (!a) {
return false;
}
// Passive and Active Shroud AAs
// For now we skip them
if(ability->category == 3 || ability->category == 4) {
if (!(a->classes & (1 << GetClass()))) {
return false;
}
// Passive and Active Shroud AAs, skip for now
if (
a->category == AACategory::ShroudPassive ||
a->category == AACategory::ShroudActive
) {
return false;
}
//the one titanium hack i will allow
//just to make sure we dont crash the client with newer aas
//we'll exclude any expendable ones
if(IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskTitaniumAndEarlier) {
if(ability->charges > 0) {
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskTitaniumAndEarlier) {
if (a->charges > 0) {
return false;
}
}
int expansion = RuleI(Expansion, CurrentExpansion);
bool use_expansion_aa = RuleB(Expansion, UseCurrentExpansionAAOnly);
const int expansion = RuleI(Expansion, CurrentExpansion);
const bool use_expansion_aa = RuleB(Expansion, UseCurrentExpansionAAOnly);
if (use_expansion_aa && expansion >= 0) {
if (rank->expansion > expansion) {
return false;
@ -1617,36 +1629,35 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
if (rank->expansion && !(CastToClient()->GetPP().expansions & (1 << (rank->expansion - 1)))) {
return false;
}
}
else if (IsBot()) {
} else if (IsBot()) {
if (rank->expansion && !(CastToBot()->GetExpansionBitmask() & (1 << (rank->expansion - 1)))) {
return false;
}
}
else {
} else {
if (rank->expansion && !(RuleI(World, ExpansionSettings) & (1 << (rank->expansion - 1)))) {
return false;
}
}
auto race = GetPlayerRaceValue(GetBaseRace());
race = race > 16 ? 1 : race;
if(!(ability->races & (1 << (race - 1)))) {
race = race > PLAYER_RACE_COUNT ? Race::Human : race;
if (!(a->races & (1 << (race - 1)))) {
return false;
}
auto deity = GetDeityBit();
if(!(ability->deities & deity)) {
const auto deity = GetDeityBit();
if (!(a->deities & deity)) {
return false;
}
if(IsClient() && CastToClient()->Admin() < ability->status) {
if (IsClient() && CastToClient()->Admin() < a->status) {
return false;
}
if(GetBaseRace() == 522) {
//drakkin_heritage
if(!(ability->drakkin_heritage & (1 << GetDrakkinHeritage()))) {
if (GetBaseRace() == Race::Drakkin) {
if (!(a->drakkin_heritage & (1 << GetDrakkinHeritage()))) {
return false;
}
}
@ -1654,13 +1665,15 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
return true;
}
bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant) {
AA::Ability *ability = rank->base_ability;
bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant)
{
auto a = rank->base_ability;
if(!ability)
if (!a) {
return false;
}
if(!CanUseAlternateAdvancementRank(rank)) {
if (!CanUseAlternateAdvancementRank(rank)) {
return false;
}
@ -1668,54 +1681,53 @@ bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price,
return false;
}
//You can't purchase grant only AAs they can only be assigned
if(check_grant && ability->grant_only) {
// You cannot purchase grant only AAs they can only be assigned
if (check_grant && a->grant_only) {
return false;
}
//check level req
if(rank->level_req > GetLevel()) {
if (rank->level_req > GetLevel()) {
return false;
}
uint32 current_charges = 0;
auto points = GetAA(rank->id, &current_charges);
uint32 current_charges = 0;
const uint32 points = GetAA(rank->id, &current_charges);
//check that we are on previous rank already (if exists)
//grant ignores the req to own the previous rank.
if(check_grant && rank->prev) {
if(points != rank->prev->current_value) {
if (check_grant && rank->prev) {
if (points != rank->prev->current_value) {
return false;
}
}
//check that we aren't already on this rank or one ahead of us
if(points >= rank->current_value) {
if (points >= rank->current_value) {
return false;
}
//if expendable only let us purchase if we have no charges already
//not quite sure on how this functions client side atm
//I intend to look into it later to make sure the behavior is right
if(ability->charges > 0 && current_charges > 0) {
if (a->charges > 0 && current_charges > 0) {
return false;
}
//check prereqs
for(auto &prereq : rank->prereqs) {
for (auto &prereq: rank->prereqs) {
AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.first);
if(prereq_ability) {
if (prereq_ability) {
auto ranks = GetAA(prereq_ability->first_rank_id);
if(ranks < prereq.second) {
if (ranks < prereq.second) {
return false;
}
}
}
//check price, if client
if(check_price && IsClient()) {
if(rank->cost > CastToClient()->GetAAPoints()) {
if (check_price && IsClient()) {
if (rank->cost > CastToClient()->GetAAPoints()) {
return false;
}
}

View File

@ -1525,6 +1525,19 @@ enum { //values of AA_Action.action
aaActionBuy = 3
};
namespace AACategory {
constexpr int None = -1;
constexpr int Passive = 1;
constexpr int Progression = 2;
constexpr int ShroudPassive = 3;
constexpr int ShroudActive = 4;
constexpr int VeteranReward = 5;
constexpr int Tradeskill = 6;
constexpr int Expendable = 7;
constexpr int RacialInnate = 8;
constexpr int EverQuest = 9;
}
class Timer;
class Mob;
class SwarmPet {

View File

@ -58,6 +58,7 @@ extern volatile bool RunLoops;
#include "mob_movement_manager.h"
#include "cheat_manager.h"
#include "../common/repositories/character_alternate_abilities_repository.h"
#include "../common/repositories/account_flags_repository.h"
#include "../common/repositories/bug_reports_repository.h"
#include "../common/repositories/char_recipe_list_repository.h"
@ -586,45 +587,52 @@ void Client::ReportConnectingState() {
};
}
bool Client::SaveAA() {
std::string iquery;
int spentpoints = 0;
int i = 0;
for(auto &rank : aa_ranks) {
AA::Ability *ability = zone->GetAlternateAdvancementAbility(rank.first);
if(!ability)
bool Client::SaveAA()
{
std::vector<CharacterAlternateAbilitiesRepository::CharacterAlternateAbilities> v;
uint32 aa_points_spent = 0;
auto e = CharacterAlternateAbilitiesRepository::NewEntity();
for (auto &rank : aa_ranks) {
auto a = zone->GetAlternateAdvancementAbility(rank.first);
if (!a) {
continue;
}
if(rank.second.first > 0) {
AA::Rank *r = ability->GetRankByPointsSpent(rank.second.first);
if(!r)
if (rank.second.first > 0) {
auto r = a->GetRankByPointsSpent(rank.second.first);
if (!r) {
continue;
spentpoints += r->total_cost;
if(i == 0) {
iquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)"
" VALUES (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
} else {
iquery += StringFormat(", (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
}
i++;
aa_points_spent += r->total_cost;
e.id = character_id;
e.aa_id = a->first_rank_id;
e.aa_value = rank.second.first;
e.charges = rank.second.second;
v.emplace_back(e);
}
}
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
m_pp.aapoints_spent = aa_points_spent + m_epp.expended_aa;
if(iquery.length() > 0) {
database.QueryDatabase(iquery);
}
return true;
return CharacterAlternateAbilitiesRepository::ReplaceMany(database, v);
}
void Client::RemoveExpendedAA(int aa_id)
{
database.QueryDatabase(StringFormat("DELETE from `character_alternate_abilities` WHERE `id` = %d and `aa_id` = %d", character_id, aa_id));
CharacterAlternateAbilitiesRepository::DeleteWhere(
database,
fmt::format(
"`id` = {} AND `aa_id` = {}",
CharacterID(),
aa_id
)
);
}
bool Client::Save(uint8 iCommitNow) {

View File

@ -32,6 +32,7 @@
#include "../common/repositories/character_potionbelt_repository.h"
#include "../common/repositories/character_bandolier_repository.h"
#include "../common/repositories/character_currency_repository.h"
#include "../common/repositories/character_alternate_abilities_repository.h"
#include <ctime>
#include <iostream>
@ -1272,15 +1273,6 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru
);
}
bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges){
std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)"
" VALUES (%u, %u, %u, %u)",
character_id, aa_id, current_level, charges);
auto results = QueryDatabase(rquery);
LogDebug("Saving AA for character ID: [{}], aa_id: [{}] current_level: [{}]", character_id, aa_id, current_level);
return true;
}
bool ZoneDatabase::SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){
if (!IsValidSpell(spell_id)) {
return false;
@ -1347,10 +1339,15 @@ bool ZoneDatabase::DeleteCharacterLeadershipAbilities(uint32 character_id)
return CharacterLeadershipAbilitiesRepository::DeleteOne(*this, character_id);
}
bool ZoneDatabase::DeleteCharacterAAs(uint32 character_id){
std::string query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u AND `aa_id` NOT IN(SELECT a.first_rank_id FROM aa_ability a WHERE a.grant_only != 0)", character_id);
QueryDatabase(query);
return true;
bool ZoneDatabase::DeleteCharacterAAs(uint32 character_id)
{
return CharacterAlternateAbilitiesRepository::DeleteWhere(
*this,
fmt::format(
"`id` = {} AND `aa_id` NOT IN (SELECT a.first_rank_id FROM aa_ability a WHERE a.grant_only != 0)",
character_id
)
);
}
bool ZoneDatabase::DeleteCharacterMaterialColor(uint32 character_id)

View File

@ -444,7 +444,6 @@ public:
bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(Client* c, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);