mirror of
https://github.com/araxiaonline/mod-mythic-plus.git
synced 2026-06-13 03:02:24 -04:00
added many methods related to increasing a players rank
This commit is contained in:
@@ -3,8 +3,11 @@
|
||||
#include "WorldDatabase.h"
|
||||
#include "Player.h"
|
||||
#include "MpLogger.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpConstants.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
/**
|
||||
* Table schema for upgrade ranks populated by go script:
|
||||
@@ -85,7 +88,7 @@ int32 AdvancementMgr::LoadAdvencementRanks() {
|
||||
uint32 chanceCost2 = fields[15].Get<uint32>();
|
||||
uint32 chanceCost3 = fields[16].Get<uint32>();
|
||||
|
||||
// Should add validator... but let's do it without and trust the o-DB-wan-kenobee
|
||||
// Should add validator... but let's do it without and trust in the o-DB-Wan-kenobe
|
||||
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
|
||||
|
||||
// List of all ranks keyed by rank, advancementId
|
||||
@@ -93,7 +96,7 @@ int32 AdvancementMgr::LoadAdvencementRanks() {
|
||||
.rank = upgradeRank,
|
||||
.advancementId = advancement,
|
||||
.materialCost = std::unordered_map<uint32, uint32>(),
|
||||
.rollCost = std::make_tuple(chanceCost1, chanceCost2, chanceCost3),
|
||||
.rollCost = {chanceCost1, chanceCost2, chanceCost3},
|
||||
.lowRange = std::make_pair(minIncrease1, maxIncrease1),
|
||||
.midRange = std::make_pair(minIncrease2, maxIncrease2),
|
||||
.highRange = std::make_pair(minIncrease3, maxIncrease3)
|
||||
@@ -132,7 +135,7 @@ int32 AdvancementMgr::LoadPlayerAdvancements(Player* player) {
|
||||
upgradeRank,
|
||||
diceSpent
|
||||
FROM mp_player_advancements
|
||||
WHERE guid = ?
|
||||
WHERE guid = {}
|
||||
)";
|
||||
|
||||
QueryResult result = CharacterDatabase.Query(query, player->GetGUID().GetCounter());
|
||||
@@ -151,12 +154,277 @@ int32 AdvancementMgr::LoadPlayerAdvancements(Player* player) {
|
||||
uint32 diceSpent = fields[4].Get<uint32>();
|
||||
|
||||
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
|
||||
MpPlayerRank playerRank = MpPlayerRank();
|
||||
playerRank.rank = upgradeRank;
|
||||
playerRank.advancementId = advancement;
|
||||
playerRank.diceSpent = diceSpent;
|
||||
playerRank.bonus = bonus;
|
||||
|
||||
// List of all ranks keyed by rank, advancementId
|
||||
_playerAdvancements[guid][advancement] = upgradeRank;
|
||||
_playerAdvancements[guid][advancement] = playerRank;
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return result->GetRowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Material Types from the database into memory
|
||||
*/
|
||||
int32 AdvancementMgr::LoadPlayerAdvancements(Player* player) {
|
||||
|
||||
constexpr std::string_view query = R"(
|
||||
SELECT
|
||||
guid,
|
||||
advancementId,
|
||||
bonus,
|
||||
upgradeRank,
|
||||
diceSpent
|
||||
FROM mp_player_advancements
|
||||
WHERE guid = {}
|
||||
)";
|
||||
|
||||
QueryResult result = CharacterDatabase.Query(query, player->GetGUID().GetCounter());
|
||||
|
||||
// If the player does not have any upgrades just return not a problem until they purchase one.
|
||||
if(!result) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
Field* fields = result->Fetch();
|
||||
uint32 guid = fields[0].Get<uint32>();
|
||||
uint32 advancementId = fields[1].Get<uint32>();
|
||||
float bonus = fields[2].Get<float>();
|
||||
uint32 upgradeRank = fields[3].Get<uint32>();
|
||||
uint32 diceSpent = fields[4].Get<uint32>();
|
||||
|
||||
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
|
||||
MpPlayerRank playerRank = MpPlayerRank();
|
||||
playerRank.rank = upgradeRank;
|
||||
playerRank.advancementId = advancement;
|
||||
playerRank.diceSpent = diceSpent;
|
||||
playerRank.bonus = bonus;
|
||||
|
||||
// List of all ranks keyed by rank, advancementId
|
||||
_playerAdvancements[guid][advancement] = playerRank;
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return result->GetRowCount();
|
||||
}
|
||||
|
||||
MpAdvancementRank* AdvancementMgr::GetAdvancementRank(uint32 rank, MpAdvancements advancement)
|
||||
{
|
||||
auto key = std::make_pair(rank, advancement);
|
||||
if (_advancementRanks.contains(key))
|
||||
{
|
||||
return &_advancementRanks.at(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
MpLogger::error("Advancment Id {} and rank {} could not be found", rank, advancement);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MpPlayerRank* AdvancementMgr::GetPlayerAdvancementRank(Player* player, MpAdvancements advancement)
|
||||
{
|
||||
if(!player) {
|
||||
MpLogger::error("Could not retrieve player advancement for null player {}", player->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_playerAdvancements.contains(player->GetGUID().GetCounter()) && _playerAdvancements[player->GetGUID().GetCounter()].contains(advancement))
|
||||
{
|
||||
return &_playerAdvancements[player->GetGUID().GetCounter()][advancement];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
// Validators to make sure inputs are correct to perform the upgrade
|
||||
if(!player) {
|
||||
MpLogger::error("Could not upgrade advancement for player, player was nullpointer");
|
||||
return false;
|
||||
}
|
||||
if(diceCostLevel < 1 || diceCostLevel > 3) {
|
||||
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for player {}", diceCostLevel, player->GetName());
|
||||
return false;
|
||||
}
|
||||
if(itemEntry1 == 0) {
|
||||
MpLogger::error("Material1 can not be 0 can not perform advancement upgrade for player {} Advancment {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
MpPlayerRank* playerRank = GetPlayerAdvancementRank(player, advancement);
|
||||
|
||||
// IF there is not create the base struct and add to the player map for this advancement
|
||||
if(!playerRank) {
|
||||
MpPlayerRank newPlayerRank;
|
||||
newPlayerRank.advancementId = advancement;
|
||||
|
||||
auto& playerAdvMap = _playerAdvancements[player->GetGUID().GetCounter()];
|
||||
playerAdvMap.emplace(advancement, newPlayerRank);
|
||||
playerRank = &playerAdvMap.at(advancement);
|
||||
}
|
||||
|
||||
if(playerRank->rank == MP_MAX_ADVANCEMENT_RANK) {
|
||||
MpLogger::error("Player {} has reached the maximum rank for advancement {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 newRank = playerRank->rank + 1;
|
||||
MpAdvancementRank* advancementRank = GetAdvancementRank(newRank, advancement);
|
||||
if(!advancementRank->IsValid()) {
|
||||
MpLogger::error("Advancement {} rank {} could not be found", advancement, newRank);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the player has the items needed to upgrade this advancement, then remove the items from the player inventory and apply the upgrade
|
||||
if(!_PlayerHasItems(player, advancementRank, diceCostLevel, itemEntry1, itemEntry2, itemEntry3)) {
|
||||
MpLogger::info("Player {} does not have the required items to upgrade advancement {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Charge the player the cost of the upgrade
|
||||
_ChargeItemCost(player, advancementRank, diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
|
||||
|
||||
// Finally get the bonus to apply for the player
|
||||
float roll = _RollAdvancement(advancementRank, diceCostLevel);
|
||||
|
||||
// Update the player advancement rank in memory and database
|
||||
playerRank->rank = newRank;
|
||||
playerRank->diceSpent += advancementRank->rollCost[diceCostLevel];
|
||||
playerRank->bonus += roll;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancementMgr::ResetPlayerAdvancements(Player* player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************
|
||||
*
|
||||
* Private Methods
|
||||
*
|
||||
******************/
|
||||
|
||||
void AdvancementMgr::_ResetPlayerAdvancement(Player* player, MpAdvancements advancement)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Roll them stats DnD style.
|
||||
float AdvancementMgr::_RollAdvancement(MpAdvancementRank* advancementRank, uint32 diceCostLevel)
|
||||
{
|
||||
uint32 min, max;
|
||||
|
||||
switch (diceCostLevel)
|
||||
{
|
||||
case 1:
|
||||
min = advancementRank->lowRange.first;
|
||||
max = advancementRank->lowRange.second;
|
||||
break;
|
||||
case 2:
|
||||
min = advancementRank->midRange.first;
|
||||
max = advancementRank->midRange.second;
|
||||
break;
|
||||
case 3:
|
||||
min = advancementRank->highRange.first;
|
||||
max = advancementRank->highRange.second;
|
||||
break;
|
||||
default:
|
||||
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for rank roll", diceCostLevel, advancementRank->rank);
|
||||
break;
|
||||
}
|
||||
|
||||
return frand(min, max);
|
||||
}
|
||||
|
||||
// Checks the players inventory to validate they have the required items to perform an upgrade based on the set cost for the passed in level.
|
||||
bool AdvancementMgr::_PlayerHasItems(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
// Check if player has the required dice to upgrade the advancement if not do nothing.
|
||||
uint32 diceCost = advancementRank->materialCost.at(diceCostLevel);
|
||||
if(!player->HasItemCount(MpConstants::ANCIENT_DICE, diceCost)) {
|
||||
MpLogger::info("Player {} does not have enough dice to upgrade advancement {}", player->GetName(), advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the passed in item for materialId 1 is valid and the player has enough to purchase.
|
||||
if(itemEntry1 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry1)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry1, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry1, advancementRank->materialCost[itemEntry1])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry1, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(itemEntry2 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry2)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry2, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry2, advancementRank->materialCost[itemEntry2])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry2, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(itemEntry3 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry3)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry3, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry3, advancementRank->materialCost[itemEntry3])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry3, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove all items required for the upgrade.
|
||||
void AdvancementMgr::_ChargeItemCost(Player *player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
uint32 diceCost = advancementRank->materialCost[diceCostLevel];
|
||||
Item* item = player->GetItemByEntry(MpConstants::ANCIENT_DICE);
|
||||
item->SetCount(item->GetCount() - diceCost);
|
||||
item->SendUpdateToPlayer(player);
|
||||
|
||||
// Remove the material from the player inventory
|
||||
if(itemEntry1 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry1);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry1]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
if(itemEntry2 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry2);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry2]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
if(itemEntry3 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry3);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry3]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ enum MpAdvancements {
|
||||
MP_ADV_RESIST_NATURE = 6,
|
||||
MP_ADV_RESIST_FROST = 7,
|
||||
MP_ADV_RESIST_SHADOW = 8,
|
||||
MP_ADV_RESIST_ARCANE = 9
|
||||
MP_ADV_RESIST_ARCANE = 9,
|
||||
MP_ADV_MAX = 10
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -31,14 +32,43 @@ struct MpAdvancementRank
|
||||
MpAdvancements advancementId;
|
||||
std::unordered_map<uint32 /*item_entry*/,uint32 /*quantity*/> materialCost;
|
||||
|
||||
std::tuple<uint32 /*low-cost*/, uint32 /*mid-cost*/, uint32 /*high-cost*/> rollCost;
|
||||
std::array<int, 3> rollCost; // 0 = low, 1 = mid, 2 = high
|
||||
|
||||
// Range of status based on bet dice roll.
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> lowRange;
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> midRange;
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> highRange;
|
||||
|
||||
// Used to validate this struct is set correctly
|
||||
bool IsValid() {
|
||||
return (rank > 0 && advancementId >= 0 && advancementId < MP_ADV_MAX);
|
||||
}
|
||||
|
||||
// Check if the map has an the item entry for the passed in material
|
||||
bool HasMaterial(uint32 itemEntry) {
|
||||
return materialCost.contains(itemEntry);
|
||||
}
|
||||
};
|
||||
|
||||
// Struct is used for tracking player advancement bonuses for improving stats
|
||||
struct MpPlayerRank
|
||||
{
|
||||
uint32 rank;
|
||||
MpAdvancements advancementId;
|
||||
uint32 diceSpent;
|
||||
float bonus;
|
||||
|
||||
MpPlayerRank() : rank(0), diceSpent(0), bonus(0.0f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* This singleton class is responsible for managing the advancement system
|
||||
* used to improve player stats enough to challenge harder difficulties on existing dungeons.
|
||||
*
|
||||
* Advancements are purchased by players using based on the mp_material_type table with a "bet"
|
||||
* on dice roll. This enables players to increase their stats in a random way that is not
|
||||
* guaranteed to be successful. (Similar to how DND stats rolls work on character creation. )
|
||||
*/
|
||||
class AdvancementMgr
|
||||
{
|
||||
|
||||
@@ -46,7 +76,10 @@ class AdvancementMgr
|
||||
std::map<std::pair<uint32 /*rank*/, MpAdvancements>, MpAdvancementRank> _advancementRanks;
|
||||
|
||||
// Map of player advancements [player_guid][advancement_id] = rank
|
||||
std::unordered_map<uint32 /*player_guid*/, std::unordered_map<MpAdvancements, uint32 /*rank*/>> _playerAdvancements;
|
||||
std::unordered_map<uint32 /*player_guid*/, std::unordered_map<MpAdvancements, MpPlayerRank>> _playerAdvancements;
|
||||
|
||||
// Map of different material types used fo advancing stats for players
|
||||
std::unordered_map<uint32 /*material_id*/, std::vector<uint32> /* item entries */> _materialTypes;
|
||||
|
||||
public:
|
||||
static AdvancementMgr* instance() {
|
||||
@@ -54,15 +87,50 @@ public:
|
||||
return &instance;
|
||||
}
|
||||
|
||||
// Loads advancement information from the database into memory when players are logged in or server starts.
|
||||
int32 LoadAdvencementRanks();
|
||||
int32 LoadMaterialTypes();
|
||||
int32 LoadPlayerAdvancements(Player* player);
|
||||
|
||||
// Methods for looking up advancment rank data
|
||||
MpAdvancementRank* GetAdvancementRank(uint32 rank, MpAdvancements advancement);
|
||||
|
||||
// Methods for updating and setting data related to current player advancements
|
||||
MpPlayerRank* AdvancementMgr::GetPlayerAdvancementRank(Player* player, MpAdvancements advancement);
|
||||
|
||||
/**
|
||||
* This upgrades a player Advancement on the server side, which will handle the following actions:
|
||||
* 1. Validating player has enough dice and materials to upgrade the advancement
|
||||
* 2. Rolling the dice to see what bonus is rewarded
|
||||
* 3. Removing the dice and materials from the player inventory
|
||||
* 4. Updating the player advancement rank in memory and database
|
||||
*
|
||||
* Since different materials can be used for each advancement, at the moment only support one material type from the list. supporting
|
||||
* mixed materials is more complicated and the UI to support it is much more complex, while this is not as nice it is much simpler to implement.
|
||||
* That means all materials have to be selected and passed in at the time of making this call.
|
||||
*/
|
||||
bool UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
// Used to reset all advancements for a specific player
|
||||
bool ResetPlayerAdvancements(Player* player);
|
||||
|
||||
private:
|
||||
AdvancementMgr() {}
|
||||
~AdvancementMgr() {}
|
||||
|
||||
};
|
||||
// Will reset all the player advancements and refund the spent dice and material with a penalty for the reset.
|
||||
void _ResetPlayerAdvancement(Player* player, MpAdvancements advancement);
|
||||
|
||||
// Rolls the dice to see how much a bonus is given based on the dice spend level
|
||||
float _RollAdvancement(MpAdvancementRank* advancementRank, uint32 diceCostLevel);
|
||||
|
||||
// Determines if a player has required items to upgrade
|
||||
bool _PlayerHasItems(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
// Removes items from player inventory based on the required advancement rank.
|
||||
void _ChargeItemCost(Player *player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
};
|
||||
|
||||
#define sAdvancementMgr AdvancementMgr::instance()
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user