mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
* basic evolving items framework created * Implement evolving tab in the inventory window * Implement experience and number of kills * Move zone evolving map to a evolvingitemsmanager class * rework gm commands * rework GetInventory * wip * wip loot testing * Fix Duplicate Message * reworked evolving item looting, swapping, etc * reworked const functions for evolving methods * Functioning Player Trade of evolving items test item_id is 89550 * First pass of Final Result link working * First pass of item upgrading when reaching 100% * Add strings and logic for displaying the evolving item xp transfer window in Corathus * Prototype of xp transfer window sending items * WIP for evolve xp transfer * WIP for evolve xp transfer. First tests passed * XP Transfer Cleanup * XP Transfer Cleanup * Add Rule for evolving items equip timer/ default is 30 secs * Add logging and player events Add logging and player events * Formatting * Database updates * Updates for linux build * Perl/Cleanup * Command cleanup * Lua * Added a crash condition check if final item id is blank or not found. * Review Changes Updates to resolve review comments and a rebase. * migrate to content_db for items_evolving_details migrate to content_db for items_evolving_details * Simplify, don't hit database unless evolving * Update 2025_01_19_items_evolving_details.sql * Update client.cpp * Update manifest with items_evolving_details * character_id vs char_id * Remove _Struct from structs * Remove license header in evolving.cpp * Move evolving constants from eq_constants.h to evolving.h since it is more specific * Update database_schema.h * General cleanup * Be more specific with `evolving_items` vs `evolving` --------- Co-authored-by: Kinglykrab <kinglykrab@gmail.com> Co-authored-by: Akkadius <akkadius1@gmail.com>
304 lines
8.4 KiB
C++
304 lines
8.4 KiB
C++
#include "evolving_items.h"
|
|
#include "item_instance.h"
|
|
#include "events/player_event_logs.h"
|
|
#include "repositories/character_evolving_items_repository.h"
|
|
|
|
EvolvingItemsManager::EvolvingItemsManager()
|
|
{
|
|
m_db = nullptr;
|
|
m_content_db = nullptr;
|
|
}
|
|
|
|
void EvolvingItemsManager::LoadEvolvingItems() const
|
|
{
|
|
auto const &results = ItemsEvolvingDetailsRepository::All(*m_content_db);
|
|
|
|
if (results.empty()) {
|
|
return;
|
|
}
|
|
|
|
std::ranges::transform(
|
|
results.begin(),
|
|
results.end(),
|
|
std::inserter(
|
|
evolving_items_manager.GetEvolvingItemsCache(),
|
|
evolving_items_manager.GetEvolvingItemsCache().end()
|
|
),
|
|
[](const ItemsEvolvingDetailsRepository::ItemsEvolvingDetails &x) {
|
|
return std::make_pair(x.item_id, x);
|
|
}
|
|
);
|
|
}
|
|
|
|
void EvolvingItemsManager::SetDatabase(Database *db)
|
|
{
|
|
m_db = db;
|
|
}
|
|
|
|
void EvolvingItemsManager::SetContentDatabase(Database *db)
|
|
{
|
|
m_content_db = db;
|
|
}
|
|
|
|
double EvolvingItemsManager::CalculateProgression(const uint64 current_amount, const uint32 item_id)
|
|
{
|
|
if (!evolving_items_manager.GetEvolvingItemsCache().contains(item_id)) {
|
|
return 0;
|
|
}
|
|
|
|
return evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount > 0
|
|
? static_cast<double>(current_amount)
|
|
/ static_cast<double>(evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount) * 100
|
|
: 0;
|
|
}
|
|
|
|
void EvolvingItemsManager::DoLootChecks(const uint32 char_id, const uint16 slot_id, const EQ::ItemInstance &inst) const
|
|
{
|
|
inst.SetEvolveEquipped(false);
|
|
if (inst.IsEvolving() && slot_id <= EQ::invslot::EQUIPMENT_END && slot_id >= EQ::invslot::EQUIPMENT_BEGIN) {
|
|
inst.SetEvolveEquipped(true);
|
|
}
|
|
|
|
if (!inst.IsEvolving()) {
|
|
return;
|
|
}
|
|
|
|
if (!inst.GetEvolveUniqueID()) {
|
|
auto e = CharacterEvolvingItemsRepository::NewEntity();
|
|
|
|
e.character_id = char_id;
|
|
e.item_id = inst.GetID();
|
|
e.equipped = inst.GetEvolveEquipped();
|
|
e.final_item_id = evolving_items_manager.GetFinalItemID(inst);
|
|
|
|
auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e);
|
|
e.id = r.id;
|
|
|
|
inst.SetEvolveUniqueID(e.id);
|
|
inst.SetEvolveCharID(e.character_id);
|
|
inst.SetEvolveItemID(e.item_id);
|
|
inst.SetEvolveFinalItemID(e.final_item_id);
|
|
|
|
return;
|
|
}
|
|
|
|
CharacterEvolvingItemsRepository::SetEquipped(*m_db, inst.GetEvolveUniqueID(), inst.GetEvolveEquipped());
|
|
}
|
|
|
|
uint32 EvolvingItemsManager::GetFinalItemID(const EQ::ItemInstance &inst) const
|
|
{
|
|
const auto start_iterator = std::ranges::find_if(
|
|
evolving_items_manager.GetEvolvingItemsCache().cbegin(),
|
|
evolving_items_manager.GetEvolvingItemsCache().cend(),
|
|
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
|
|
return a.second.item_evo_id == inst.GetEvolveLoreID();
|
|
}
|
|
);
|
|
|
|
if (start_iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) {
|
|
return 0;
|
|
}
|
|
|
|
const auto final_id = std::ranges::max_element(
|
|
start_iterator,
|
|
evolving_items_manager.GetEvolvingItemsCache().cend(),
|
|
[&](
|
|
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a,
|
|
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &b
|
|
) {
|
|
return a.second.item_evo_id == b.second.item_evo_id &&
|
|
a.second.item_evolve_level < b.second.item_evolve_level;
|
|
}
|
|
);
|
|
|
|
return final_id->first;
|
|
}
|
|
|
|
uint32 EvolvingItemsManager::GetNextEvolveItemID(const EQ::ItemInstance &inst) const
|
|
{
|
|
int8 const current_level = inst.GetEvolveLvl();
|
|
|
|
const auto iterator = std::ranges::find_if(
|
|
evolving_items_manager.GetEvolvingItemsCache().cbegin(),
|
|
evolving_items_manager.GetEvolvingItemsCache().cend(),
|
|
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
|
|
return a.second.item_evo_id == inst.GetEvolveLoreID() &&
|
|
a.second.item_evolve_level == current_level + 1;
|
|
}
|
|
);
|
|
|
|
if (iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) {
|
|
return 0;
|
|
}
|
|
|
|
return iterator->first;
|
|
}
|
|
|
|
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails EvolvingItemsManager::GetEvolveItemDetails(const uint64 unique_id)
|
|
{
|
|
if (GetEvolvingItemsCache().contains(unique_id)) {
|
|
return GetEvolvingItemsCache().at(unique_id);
|
|
}
|
|
|
|
return ItemsEvolvingDetailsRepository::NewEntity();
|
|
}
|
|
|
|
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> EvolvingItemsManager::GetEvolveIDItems(
|
|
const uint32 evolve_id
|
|
)
|
|
{
|
|
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> e{};
|
|
|
|
for (auto const &[key, value]: GetEvolvingItemsCache()) {
|
|
if (value.item_evo_id == evolve_id) {
|
|
e.push_back(value);
|
|
}
|
|
}
|
|
|
|
std::ranges::sort(
|
|
e.begin(),
|
|
e.end(),
|
|
[&](
|
|
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &a,
|
|
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &b
|
|
) {
|
|
return a.item_evolve_level < b.item_evolve_level;
|
|
}
|
|
);
|
|
|
|
return e;
|
|
}
|
|
|
|
uint64 EvolvingItemsManager::GetTotalEarnedXP(const EQ::ItemInstance &inst)
|
|
{
|
|
if (!inst) {
|
|
return 0;
|
|
}
|
|
|
|
uint64 xp = inst.GetEvolveCurrentAmount();
|
|
auto evolve_id_item_cache = GetEvolveIDItems(inst.GetEvolveLoreID());
|
|
auto current_level = inst.GetEvolveLvl();
|
|
|
|
for (auto const &i: evolve_id_item_cache) {
|
|
if (i.item_evolve_level < current_level) {
|
|
xp += i.required_amount;
|
|
}
|
|
}
|
|
|
|
return xp;
|
|
}
|
|
|
|
EvolveGetNextItem EvolvingItemsManager::GetNextItemByXP(const EQ::ItemInstance &inst_in, const int64 in_xp)
|
|
{
|
|
EvolveGetNextItem ets{};
|
|
const auto evolve_items = GetEvolveIDItems(inst_in.GetEvolveLoreID());
|
|
uint32 max_transfer_level = 0;
|
|
int64 xp = in_xp;
|
|
|
|
for (auto const &e: evolve_items) {
|
|
if (e.item_evolve_level < inst_in.GetEvolveLvl()) {
|
|
continue;
|
|
}
|
|
|
|
int64 have = 0;
|
|
if (e.item_evolve_level == inst_in.GetEvolveLvl()) {
|
|
have = inst_in.GetEvolveCurrentAmount();
|
|
}
|
|
|
|
const auto required = e.required_amount;
|
|
const int64 need = required - have;
|
|
const int64 balance = xp - need;
|
|
|
|
if (balance <= 0) {
|
|
ets.new_current_amount = have + xp;
|
|
ets.new_item_id = e.item_id;
|
|
ets.from_current_amount = 0;
|
|
ets.max_transfer_level = max_transfer_level;
|
|
return ets;
|
|
}
|
|
|
|
xp = balance;
|
|
max_transfer_level += 1;
|
|
|
|
ets.new_current_amount = required;
|
|
ets.new_item_id = e.item_id;
|
|
ets.from_current_amount = balance - required;
|
|
ets.max_transfer_level = max_transfer_level;
|
|
}
|
|
|
|
return ets;
|
|
}
|
|
|
|
EvolveTransfer EvolvingItemsManager::DetermineTransferResults(
|
|
const EQ::ItemInstance &inst_from,
|
|
const EQ::ItemInstance &inst_to
|
|
)
|
|
{
|
|
EvolveTransfer ets{};
|
|
|
|
auto evolving_details_inst_from = evolving_items_manager.GetEvolveItemDetails(inst_from.GetID());
|
|
auto evolving_details_inst_to = evolving_items_manager.GetEvolveItemDetails(inst_to.GetID());
|
|
|
|
if (!evolving_details_inst_from.id || !evolving_details_inst_to.id) {
|
|
return ets;
|
|
}
|
|
|
|
if (evolving_details_inst_from.type == evolving_details_inst_to.type) {
|
|
uint32 compatibility = 0;
|
|
uint64 xp = 0;
|
|
if (evolving_details_inst_from.sub_type == evolving_details_inst_to.sub_type) {
|
|
compatibility = 100;
|
|
}
|
|
else {
|
|
compatibility = 30;
|
|
}
|
|
|
|
xp = evolving_items_manager.GetTotalEarnedXP(inst_from) * compatibility / 100;
|
|
auto results = evolving_items_manager.GetNextItemByXP(inst_to, xp);
|
|
|
|
ets.item_from_id = evolving_items_manager.GetFirstItemInLoreGroup(inst_from.GetEvolveLoreID());
|
|
ets.item_from_current_amount = results.from_current_amount;
|
|
ets.item_to_id = results.new_item_id;
|
|
ets.item_to_current_amount = results.new_current_amount;
|
|
ets.compatibility = compatibility;
|
|
ets.max_transfer_level = results.max_transfer_level;
|
|
}
|
|
|
|
return ets;
|
|
}
|
|
|
|
uint32 EvolvingItemsManager::GetFirstItemInLoreGroup(const uint32 lore_id)
|
|
{
|
|
for (auto const &[key, value]: GetEvolvingItemsCache()) {
|
|
if (value.item_evo_id == lore_id && value.item_evolve_level == 1) {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32 EvolvingItemsManager::GetFirstItemInLoreGroupByItemID(const uint32 item_id)
|
|
{
|
|
for (auto const &[key, value]: GetEvolvingItemsCache()) {
|
|
if (value.item_id == item_id) {
|
|
for (auto const &[key2, value2]: GetEvolvingItemsCache()) {
|
|
if (value2.item_evo_id == value.item_evo_id && value2.item_evolve_level == 1) {
|
|
return key;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void EvolvingItemsManager::LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e)
|
|
{
|
|
e.item_id = inst.GetID();
|
|
e.item_name = inst.GetItem() ? inst.GetItem()->Name : std::string();
|
|
e.level = inst.GetEvolveLvl();
|
|
e.progression = inst.GetEvolveProgression();
|
|
e.unique_id = inst.GetEvolveUniqueID();
|
|
}
|