mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-22 16:28:28 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c966f26ac1 | |||
| fe66c24352 | |||
| bdcded7d45 | |||
| f939f25aa1 | |||
| 401f1038f3 | |||
| 95c6560e7c | |||
| 59f645b5c3 | |||
| bbfed8300c | |||
| 07c762068f | |||
| 6525051d2d | |||
| b7f94e8315 | |||
| d1f368ab7f | |||
| 1f3ac2dc4f | |||
| 7a226ca4ef | |||
| 119151c0e3 | |||
| faa8a492f7 | |||
| 2926b4df78 | |||
| 986eda44aa | |||
| b2f71f16fc | |||
| 861eac3660 | |||
| a376bc4471 | |||
| e83d0942ad | |||
| 31abaf8016 | |||
| 0acad18067 | |||
| 90c37390f1 | |||
| dba494cd8e | |||
| 37ced4b003 | |||
| d13c725a74 | |||
| 25826c6686 | |||
| 1a27127c39 | |||
| 75698a809f | |||
| 37a7b7fc41 | |||
| f21cc170df | |||
| d47bf687d0 | |||
| 035c51944f | |||
| c2ebc2540a | |||
| c82f1b9afc | |||
| 15684567cf | |||
| 533dc997fd | |||
| 03b30d5c7a | |||
| d89f9bdcc7 |
@@ -68,3 +68,4 @@ compile_flags.txt
|
||||
|
||||
# CMake Files
|
||||
cmake-build-relwithdebinfo/*
|
||||
skill-caps.diff
|
||||
|
||||
@@ -1,3 +1,87 @@
|
||||
## [22.62.1] 1/27/2025
|
||||
|
||||
### Memory Leak
|
||||
|
||||
* Revert "Change raw pointer to unique_ptr to avoid potential leak in dbg stream" ([#4616](https://github.com/EQEmu/Server/pull/4616)) @Akkadius 2025-01-27
|
||||
|
||||
### Performance
|
||||
|
||||
* Re-use ClientUpdate packet memory ([#4619](https://github.com/EQEmu/Server/pull/4619)) @Akkadius 2025-01-27
|
||||
* Re-use OP_Animation packet ([#4621](https://github.com/EQEmu/Server/pull/4621)) @Akkadius 2025-01-27
|
||||
* Re-use OP_Damage packet memory ([#4625](https://github.com/EQEmu/Server/pull/4625)) @Akkadius 2025-01-27
|
||||
* Re-use OP_HPUpdate packet memory ([#4622](https://github.com/EQEmu/Server/pull/4622)) @Akkadius 2025-01-27
|
||||
* Re-use OP_PlayerStateAdd packet memory ([#4626](https://github.com/EQEmu/Server/pull/4626)) @Akkadius 2025-01-27
|
||||
* Re-use OP_SendFindableNPCs packet memory ([#4623](https://github.com/EQEmu/Server/pull/4623)) @Akkadius 2025-01-27
|
||||
|
||||
### Repop
|
||||
|
||||
* Make #repop instant ([#4620](https://github.com/EQEmu/Server/pull/4620)) @Akkadius 2025-01-27
|
||||
|
||||
## [22.62.0] 1/26/2025
|
||||
|
||||
### Bazaar
|
||||
|
||||
* Improve Bazaar Search Performance ([#4615](https://github.com/EQEmu/Server/pull/4615)) @neckkola 2025-01-27
|
||||
|
||||
### CLI
|
||||
|
||||
* Add --skip-backup to world database:updates ([#4605](https://github.com/EQEmu/Server/pull/4605)) @Akkadius 2025-01-22
|
||||
|
||||
### Database
|
||||
|
||||
* Change npc_types walkspeed to be of type float ([#4589](https://github.com/EQEmu/Server/pull/4589)) @Akkadius 2025-01-07
|
||||
|
||||
### Databuckets
|
||||
|
||||
* Add Account Scoped Databuckets ([#4603](https://github.com/EQEmu/Server/pull/4603)) @Akkadius 2025-01-21
|
||||
* Implement Nested Databuckets ([#4604](https://github.com/EQEmu/Server/pull/4604)) @Akkadius 2025-01-27
|
||||
|
||||
### Feature
|
||||
|
||||
* Add Alternate Bazaar Search Approach ([#4600](https://github.com/EQEmu/Server/pull/4600)) @neckkola 2025-01-20
|
||||
* Add Support for Item Previews ([#4599](https://github.com/EQEmu/Server/pull/4599)) @Kinglykrab 2025-01-20
|
||||
* Evolving Item Support for RoF2 ([#4496](https://github.com/EQEmu/Server/pull/4496)) @neckkola 2025-01-20
|
||||
* Implement Custom Pet Names ([#4594](https://github.com/EQEmu/Server/pull/4594)) @catapultam-habeo 2025-01-22
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add Bazaar BulkSendTrader Limit for RoF2 ([#4590](https://github.com/EQEmu/Server/pull/4590)) @neckkola 2025-01-08
|
||||
* CLI help menu from parsing correctly in World @Akkadius 2025-01-22
|
||||
* Delete later in RemoveItem second case @Akkadius 2025-01-25
|
||||
* Fix query error in character_evolving_items @Akkadius 2025-01-21
|
||||
* Repair a memory leak in #summonitem ([#4591](https://github.com/EQEmu/Server/pull/4591)) @neckkola 2025-01-08
|
||||
* Repair an incorrect safe_delete call memory leak. ([#4588](https://github.com/EQEmu/Server/pull/4588)) @neckkola 2025-01-07
|
||||
* Repair levers opening the Evolving XP Transfer Window ([#4607](https://github.com/EQEmu/Server/pull/4607)) @neckkola 2025-01-23
|
||||
* Update a few Bazaar RoF2 routines for memory leaks ([#4592](https://github.com/EQEmu/Server/pull/4592)) @neckkola 2025-01-08
|
||||
* Update database version to match manifest @Akkadius 2025-01-21
|
||||
* Update trader add/remove packets to limits for RoF2 ([#4595](https://github.com/EQEmu/Server/pull/4595)) @neckkola 2025-01-19
|
||||
|
||||
### Linux
|
||||
|
||||
* Implement KSM Kernel Samepage Merging with Maps ([#4601](https://github.com/EQEmu/Server/pull/4601)) @Akkadius 2025-01-21
|
||||
|
||||
### Memory Leak
|
||||
|
||||
* Change raw pointer to unique_ptr to avoid potential leak in dbg stream ([#4616](https://github.com/EQEmu/Server/pull/4616)) @KimLS 2025-01-27
|
||||
* Fix leak in BuyTraderItemOutsideBazaar ([#4609](https://github.com/EQEmu/Server/pull/4609)) @Akkadius 2025-01-24
|
||||
* Fix leak in Client::RemoveDuplicateLore ([#4614](https://github.com/EQEmu/Server/pull/4614)) @Akkadius 2025-01-24
|
||||
* Fix leak in NPC::RemoveItem ([#4611](https://github.com/EQEmu/Server/pull/4611)) @Akkadius 2025-01-24
|
||||
* Fix leak in QuestManager::varlink ([#4610](https://github.com/EQEmu/Server/pull/4610)) @Akkadius 2025-01-24
|
||||
* Fix leaks in Client::Handle_OP_AugmentItem ([#4612](https://github.com/EQEmu/Server/pull/4612)) @Akkadius 2025-01-24
|
||||
* Fix memory leak in Client::Handle_OP_MoveMultipleItems ([#4613](https://github.com/EQEmu/Server/pull/4613)) @Akkadius 2025-01-24
|
||||
|
||||
### Performance
|
||||
|
||||
* Client / NPC Position Update Optimizations ([#4602](https://github.com/EQEmu/Server/pull/4602)) @Akkadius 2025-01-21
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add SetAAEXPPercentage to Perl/Lua ([#4597](https://github.com/EQEmu/Server/pull/4597)) @Kinglykrab 2025-01-19
|
||||
|
||||
### Zone
|
||||
|
||||
* Implement zone player count sharding ([#4536](https://github.com/EQEmu/Server/pull/4536)) @Akkadius 2025-01-08
|
||||
|
||||
## [22.61.0] 1/6/2025
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -36,12 +36,14 @@
|
||||
#include "../../common/file.h"
|
||||
#include "../../common/events/player_event_logs.h"
|
||||
#include "../../common/skill_caps.h"
|
||||
#include "../../common/evolving_items.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
void ExportSpells(SharedDatabase *db);
|
||||
void ExportSkillCaps(SharedDatabase *db);
|
||||
|
||||
@@ -30,12 +30,14 @@
|
||||
#include "../../common/repositories/base_data_repository.h"
|
||||
#include "../../common/file.h"
|
||||
#include "../../common/events/player_event_logs.h"
|
||||
#include "../../common/evolving_items.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
void ImportSpells(SharedDatabase *db);
|
||||
void ImportSkillCaps(SharedDatabase *db);
|
||||
|
||||
@@ -39,6 +39,7 @@ SET(common_sources
|
||||
event_sub.cpp
|
||||
events/player_event_logs.cpp
|
||||
events/player_event_discord_formatter.cpp
|
||||
evolving_items.cpp
|
||||
expedition_lockout_timer.cpp
|
||||
extprofile.cpp
|
||||
discord/discord_manager.cpp
|
||||
@@ -97,6 +98,7 @@ SET(common_sources
|
||||
json/json.hpp
|
||||
json/jsoncpp.cpp
|
||||
zone_store.cpp
|
||||
memory/ksm.hpp
|
||||
net/console_server.cpp
|
||||
net/console_server_connection.cpp
|
||||
net/crc32.cpp
|
||||
@@ -172,6 +174,7 @@ SET(repositories
|
||||
repositories/base/base_character_currency_repository.h
|
||||
repositories/base/base_character_data_repository.h
|
||||
repositories/base/base_character_disciplines_repository.h
|
||||
repositories/base/base_character_evolving_items_repository.h
|
||||
repositories/base/base_character_expedition_lockouts_repository.h
|
||||
repositories/base/base_character_exp_modifiers_repository.h
|
||||
repositories/base/base_character_inspect_messages_repository.h
|
||||
@@ -240,6 +243,7 @@ SET(repositories
|
||||
repositories/base/base_inventory_snapshots_repository.h
|
||||
repositories/base/base_ip_exemptions_repository.h
|
||||
repositories/base/base_items_repository.h
|
||||
repositories/base/base_items_evolving_details_repository.h
|
||||
repositories/base/base_ldon_trap_entries_repository.h
|
||||
repositories/base/base_ldon_trap_templates_repository.h
|
||||
repositories/base/base_level_exp_mods_repository.h
|
||||
@@ -355,6 +359,7 @@ SET(repositories
|
||||
repositories/character_currency_repository.h
|
||||
repositories/character_data_repository.h
|
||||
repositories/character_disciplines_repository.h
|
||||
repositories/character_evolving_items_repository.h
|
||||
repositories/character_expedition_lockouts_repository.h
|
||||
repositories/character_exp_modifiers_repository.h
|
||||
repositories/character_inspect_messages_repository.h
|
||||
@@ -423,6 +428,7 @@ SET(repositories
|
||||
repositories/inventory_snapshots_repository.h
|
||||
repositories/ip_exemptions_repository.h
|
||||
repositories/items_repository.h
|
||||
repositories/items_evolving_details_repository.h
|
||||
repositories/ldon_trap_entries_repository.h
|
||||
repositories/ldon_trap_templates_repository.h
|
||||
repositories/level_exp_mods_repository.h
|
||||
@@ -555,6 +561,7 @@ SET(common_headers
|
||||
events/player_event_discord_formatter.h
|
||||
events/player_events.h
|
||||
event_sub.h
|
||||
evolving_items.h
|
||||
expedition_lockout_timer.h
|
||||
extprofile.h
|
||||
faction.h
|
||||
|
||||
+246
-284
@@ -6,7 +6,8 @@
|
||||
|
||||
std::vector<BazaarSearchResultsFromDB_Struct>
|
||||
Bazaar::GetSearchResults(
|
||||
SharedDatabase &db,
|
||||
Database &db,
|
||||
Database &content_db,
|
||||
BazaarSearchCriteria_Struct search,
|
||||
uint32 char_zone_id,
|
||||
int32 char_zone_instance_id
|
||||
@@ -31,7 +32,132 @@ Bazaar::GetSearchResults(
|
||||
char_zone_instance_id
|
||||
);
|
||||
|
||||
std::string search_criteria_trader("TRUE ");
|
||||
static std::map<uint8, uint32> item_slot_searches_new = {
|
||||
{EQ::invslot::slotCharm, 1},
|
||||
{EQ::invslot::slotEar1, 2},
|
||||
{EQ::invslot::slotHead, 4},
|
||||
{EQ::invslot::slotFace, 8},
|
||||
{EQ::invslot::slotEar2, 16},
|
||||
{EQ::invslot::slotNeck, 32},
|
||||
{EQ::invslot::slotShoulders, 64},
|
||||
{EQ::invslot::slotArms, 128},
|
||||
{EQ::invslot::slotBack, 256},
|
||||
{EQ::invslot::slotWrist1, 512},
|
||||
{EQ::invslot::slotWrist2, 1024},
|
||||
{EQ::invslot::slotRange, 2048},
|
||||
{EQ::invslot::slotHands, 4096},
|
||||
{EQ::invslot::slotPrimary, 8192},
|
||||
{EQ::invslot::slotSecondary, 16384},
|
||||
{EQ::invslot::slotFinger1, 32768},
|
||||
{EQ::invslot::slotFinger2, 65536},
|
||||
{EQ::invslot::slotChest, 131072},
|
||||
{EQ::invslot::slotLegs, 262144},
|
||||
{EQ::invslot::slotFeet, 524288},
|
||||
{EQ::invslot::slotWaist, 1048576},
|
||||
{EQ::invslot::slotPowerSource, 2097152},
|
||||
{EQ::invslot::slotAmmo, 4194304},
|
||||
};
|
||||
|
||||
struct ItemSearchType {
|
||||
EQ::item::ItemType type;
|
||||
std::string condition;
|
||||
};
|
||||
|
||||
std::vector<ItemSearchType> item_search_types_new = {
|
||||
{EQ::item::ItemType::ItemTypeBook, " AND (items.itemclass = 2 or items.itemclass = 31)"},
|
||||
{EQ::item::ItemType::ItemTypeContainer, " AND (items.itemclass = 1 or items.itemclass = 67)"},
|
||||
{EQ::item::ItemType::ItemTypeAllEffects, " AND (items.scrolleffect > 0 && items.scrolleffect < 65000)"},
|
||||
{EQ::item::ItemType::ItemTypeUnknown9, " AND items.worneffect = 998"},
|
||||
{EQ::item::ItemType::ItemTypeUnknown10, " AND (items.worneffect >= 1298 && items.worneffect <= 1307)"},
|
||||
{EQ::item::ItemType::ItemTypeFocusEffect, " AND items.focuseffect > 0"},
|
||||
{EQ::item::ItemType::ItemTypeArmor, " AND items.itemtype = 10"},
|
||||
{EQ::item::ItemType::ItemType1HBlunt, " AND items.itemtype = 3"},
|
||||
{EQ::item::ItemType::ItemType1HPiercing, " AND items.itemtype = 2"},
|
||||
{EQ::item::ItemType::ItemType1HSlash, " AND items.itemtype = 0"},
|
||||
{EQ::item::ItemType::ItemType2HBlunt, " AND items.itemtype = 4"},
|
||||
{EQ::item::ItemType::ItemType2HSlash, " AND items.itemtype = 1"},
|
||||
{EQ::item::ItemType::ItemTypeBow, " AND items.itemtype = 5"},
|
||||
{EQ::item::ItemType::ItemTypeShield, " AND items.itemtype = 8"},
|
||||
{EQ::item::ItemType::ItemTypeMisc, " AND items.itemtype = 11"},
|
||||
{EQ::item::ItemType::ItemTypeFood, " AND items.itemtype = 14"},
|
||||
{EQ::item::ItemType::ItemTypeDrink, " AND items.itemtype = 15"},
|
||||
{EQ::item::ItemType::ItemTypeLight, " AND items.itemtype = 16"},
|
||||
{EQ::item::ItemType::ItemTypeCombinable, " AND items.itemtype = 17"},
|
||||
{EQ::item::ItemType::ItemTypeBandage, " AND items.itemtype = 18"},
|
||||
{EQ::item::ItemType::ItemTypeSmallThrowing, " AND (items.itemtype = 19 OR items.itemtype = 7)"},
|
||||
{EQ::item::ItemType::ItemTypeSpell, " AND items.itemtype = 20"},
|
||||
{EQ::item::ItemType::ItemTypePotion, " AND items.itemtype = 21"},
|
||||
{EQ::item::ItemType::ItemTypeBrassInstrument, " AND items.itemtype = 25"},
|
||||
{EQ::item::ItemType::ItemTypeWindInstrument, " AND items.itemtype = 23"},
|
||||
{EQ::item::ItemType::ItemTypeStringedInstrument, " AND items.itemtype = 24"},
|
||||
{EQ::item::ItemType::ItemTypePercussionInstrument, " AND items.itemtype = 26"},
|
||||
{EQ::item::ItemType::ItemTypeArrow, " AND items.itemtype = 27"},
|
||||
{EQ::item::ItemType::ItemTypeJewelry, " AND items.itemtype = 29"},
|
||||
{EQ::item::ItemType::ItemTypeNote, " AND items.itemtype = 32"},
|
||||
{EQ::item::ItemType::ItemTypeKey, " AND items.itemtype = 33"},
|
||||
{EQ::item::ItemType::ItemType2HPiercing, " AND items.itemtype = 35"},
|
||||
{EQ::item::ItemType::ItemTypeAlcohol, " AND items.itemtype = 38"},
|
||||
{EQ::item::ItemType::ItemTypeMartial, " AND items.itemtype = 45"},
|
||||
{EQ::item::ItemType::ItemTypeAugmentation, " AND items.itemtype = 54"},
|
||||
{EQ::item::ItemType::ItemTypeAlternateAbility, " AND items.itemtype = 57"},
|
||||
{EQ::item::ItemType::ItemTypeCount, " AND items.itemtype = 65"},
|
||||
{EQ::item::ItemType::ItemTypeCollectible, " AND items.itemtype = 66"}
|
||||
};
|
||||
|
||||
// item stat searches
|
||||
struct ItemStatSearch {
|
||||
std::string query_string;
|
||||
EQ::skills::SkillType skill_type;
|
||||
};
|
||||
|
||||
std::map<uint32, ItemStatSearch> item_stat_searches_new = {
|
||||
{STAT_AC, {" items.ac" , static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_AGI, {" items.aagi", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_CHA, {" items.acha", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_DEX, {" items.adex", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_INT, {" items.aint", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_STA, {" items.asta", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_STR, {" items.astr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_WIS, {" items.awis", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_COLD, {" items.cr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_DISEASE, {" items.dr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_FIRE, {" items.fr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_MAGIC, {" items.mr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_POISON, {" items.pr", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HP, {" items.hp", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_MANA, {" items.mana", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_ENDURANCE, {" items.endur", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_ATTACK, {" items.attack", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HP_REGEN, {" items.regen", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_MANA_REGEN, {" items.manaregen", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HASTE, {" items.haste", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_DAMAGE_SHIELD, {" items.damageshield", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_DS_MITIGATION, {" items.dsmitigation", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEAL_AMOUNT, {" items.healamt", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_SPELL_DAMAGE, {" items.spelldmg", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_CLAIRVOYANCE, {" items.clairvoyance", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_AGILITY, {" items.heroic_agi", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_CHARISMA, {" items.heroic_cha", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_DEXTERITY, {" items.heroic_dex", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_INTELLIGENCE, {" items.heroic_int", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_STAMINA, {" items.heroic_sta", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_STRENGTH, {" items.heroic_str", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_HEROIC_WISDOM, {" items.heroic_wis", static_cast<EQ::skills::SkillType>(0)} },
|
||||
{STAT_BASH, {" items.skillmodvalue", EQ::skills::SkillBash} },
|
||||
{STAT_BACKSTAB, {" items.backstabdmg", EQ::skills::SkillBackstab} },
|
||||
{STAT_DRAGON_PUNCH, {" items.skillmodvalue", EQ::skills::SkillDragonPunch} },
|
||||
{STAT_EAGLE_STRIKE, {" items.skillmodvalue", EQ::skills::SkillEagleStrike} },
|
||||
{STAT_FLYING_KICK, {" items.skillmodvalue", EQ::skills::SkillFlyingKick} },
|
||||
{STAT_KICK, {" items.skillmodvalue", EQ::skills::SkillKick} },
|
||||
{STAT_ROUND_KICK, {" items.skillmodvalue", EQ::skills::SkillRoundKick} },
|
||||
{STAT_TIGER_CLAW, {" items.skillmodvalue", EQ::skills::SkillTigerClaw} },
|
||||
{STAT_FRENZY, {" items.skillmodvalue", EQ::skills::SkillFrenzy} },
|
||||
};
|
||||
|
||||
bool convert = false;
|
||||
std::string search_criteria_trader("TRUE");
|
||||
std::string field_criteria_items("FALSE");
|
||||
std::string where_criteria_items(" TRUE ");
|
||||
|
||||
if (search.search_scope == NonRoFBazaarSearchScope) {
|
||||
search_criteria_trader.append(
|
||||
@@ -51,8 +177,24 @@ Bazaar::GetSearchResults(
|
||||
);
|
||||
}
|
||||
else if (search.trader_id > 0) {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
||||
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
||||
if (search.trader_id >= TraderRepository::TRADER_CONVERT_ID) {
|
||||
convert = true;
|
||||
search_criteria_trader.append(fmt::format(
|
||||
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
|
||||
Zones::BAZAAR,
|
||||
search.trader_id - TraderRepository::TRADER_CONVERT_ID)
|
||||
);
|
||||
}
|
||||
else {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
||||
}
|
||||
}
|
||||
else {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
||||
}
|
||||
}
|
||||
|
||||
if (search.min_cost != 0) {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
|
||||
}
|
||||
@@ -60,301 +202,121 @@ Bazaar::GetSearchResults(
|
||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
|
||||
}
|
||||
|
||||
// not yet implemented
|
||||
// if (search.prestige != 0) {
|
||||
// 0xffffffff prestige only, 0xfffffffe non-prestige, 0 all
|
||||
// search_criteria.append(fmt::format(" AND items.type = {} ", search.prestige));
|
||||
// }
|
||||
if (search.slot != std::numeric_limits<uint32>::max()) {
|
||||
if (item_slot_searches_new.contains(search.slot)) {
|
||||
where_criteria_items.append(
|
||||
fmt::format(" AND items.slots & {0} = {0}", item_slot_searches_new[search.slot]));
|
||||
}
|
||||
}
|
||||
|
||||
std::string query = fmt::format(
|
||||
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
|
||||
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
|
||||
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6, trader.char_zone_instance_id "
|
||||
"FROM trader, character_data "
|
||||
"WHERE {} AND trader.char_id = character_data.id "
|
||||
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
|
||||
search_criteria_trader.c_str()
|
||||
);
|
||||
if (search.type != std::numeric_limits<uint32>::max()) {
|
||||
for (auto const &[type, condition]: item_search_types_new) {
|
||||
if (type == search.type) {
|
||||
where_criteria_items.append(condition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (search.race != std::numeric_limits<uint32>::max()) {
|
||||
where_criteria_items.append(
|
||||
fmt::format(" AND items.races & {0} = {0}", GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race))));
|
||||
}
|
||||
|
||||
if (search._class != std::numeric_limits<uint32>::max()) {
|
||||
where_criteria_items.append(fmt::format(" AND items.classes & {0} = {0}", GetPlayerClassBit(search._class)));
|
||||
}
|
||||
|
||||
if (search.item_stat != std::numeric_limits<uint32>::max()) {
|
||||
if (item_stat_searches_new.contains(search.item_stat)) {
|
||||
field_criteria_items = fmt::format("{}", item_stat_searches_new[search.item_stat].query_string);
|
||||
if (item_stat_searches_new[search.item_stat].skill_type) {
|
||||
where_criteria_items.append(
|
||||
fmt::format(" AND items.skillmodtype = {} ", item_stat_searches_new[search.item_stat].skill_type));
|
||||
}
|
||||
else {
|
||||
where_criteria_items.append(
|
||||
fmt::format(" AND {} > 0 ", item_stat_searches_new[search.item_stat].query_string));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (search.augment) {
|
||||
where_criteria_items.append(fmt::format(
|
||||
" AND (items.augslot1type = {0} OR "
|
||||
"items.augslot2type = {0} OR "
|
||||
"items.augslot3type = {0} OR "
|
||||
"items.augslot4type = {0} OR "
|
||||
"items.augslot5type = {0} OR "
|
||||
"items.augslot6type = {0})",
|
||||
search.augment)
|
||||
);
|
||||
}
|
||||
|
||||
if (search.min_level != 1) {
|
||||
where_criteria_items.append(fmt::format(" AND items.reclevel >= {}", search.min_level));
|
||||
}
|
||||
|
||||
if (search.max_level != 100) {
|
||||
where_criteria_items.append(fmt::format(" AND items.reclevel <= {}", search.max_level));
|
||||
}
|
||||
|
||||
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
|
||||
std::vector<std::string> trader_items_ids{};
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader);
|
||||
if (trader_results.empty()) {
|
||||
LogTradingDetail("Bazaar - No traders found in bazaar search.");
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
struct ItemSearchType {
|
||||
EQ::item::ItemType type;
|
||||
bool condition;
|
||||
};
|
||||
for (auto const &i: trader_results) {
|
||||
trader_items_ids.push_back(std::to_string(i.trader.item_id));
|
||||
}
|
||||
|
||||
struct AddititiveSearchCriteria {
|
||||
bool should_check;
|
||||
bool condition;
|
||||
};
|
||||
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
|
||||
content_db,
|
||||
trader_items_ids,
|
||||
std::string(search.item_name),
|
||||
field_criteria_items,
|
||||
where_criteria_items
|
||||
);
|
||||
|
||||
if (item_results.empty()) {
|
||||
LogError("Bazaar - No items found in bazaar search.");
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
all_entries.reserve(trader_results.size());
|
||||
|
||||
for (auto const& t:trader_results) {
|
||||
if (!item_results.contains(t.trader.item_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto row: results) {
|
||||
BazaarSearchResultsFromDB_Struct r{};
|
||||
r.count = 1;
|
||||
r.trader_id = t.trader.char_id;
|
||||
r.serial_number = t.trader.item_sn;
|
||||
r.cost = t.trader.item_cost;
|
||||
r.slot_id = t.trader.slot_id;
|
||||
r.sum_charges = t.trader.item_charges;
|
||||
r.stackable = item_results.at(t.trader.item_id).stackable;
|
||||
r.icon_id = item_results.at(t.trader.item_id).icon;
|
||||
r.trader_zone_id = t.trader.char_zone_id;
|
||||
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
|
||||
r.trader_entity_id = t.trader.char_entity_id;
|
||||
r.serial_number_RoF = fmt::format("{:016}\0", t.trader.item_sn);
|
||||
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
|
||||
r.trader_name = fmt::format("{:.63}\0", t.trader_name);
|
||||
r.item_stat = item_results.at(t.trader.item_id).stats;
|
||||
|
||||
r.item_id = Strings::ToInt(row[2]);
|
||||
r.charges = Strings::ToInt(row[4]);
|
||||
|
||||
auto item = db.GetItem(r.item_id);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 aug_slot_1 = Strings::ToUnsignedInt(row[11]);
|
||||
uint32 aug_slot_2 = Strings::ToUnsignedInt(row[12]);
|
||||
uint32 aug_slot_3 = Strings::ToUnsignedInt(row[13]);
|
||||
uint32 aug_slot_4 = Strings::ToUnsignedInt(row[14]);
|
||||
uint32 aug_slot_5 = Strings::ToUnsignedInt(row[15]);
|
||||
uint32 aug_slot_6 = Strings::ToUnsignedInt(row[16]);
|
||||
|
||||
std::unique_ptr<EQ::ItemInstance> inst(
|
||||
db.CreateItem(
|
||||
item,
|
||||
r.charges,
|
||||
aug_slot_1,
|
||||
aug_slot_2,
|
||||
aug_slot_3,
|
||||
aug_slot_4,
|
||||
aug_slot_5,
|
||||
aug_slot_6
|
||||
)
|
||||
);
|
||||
|
||||
if (!inst->GetItem()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r.count = Strings::ToInt(row[0]);
|
||||
r.trader_id = Strings::ToInt(row[1]);
|
||||
r.serial_number = Strings::ToInt(row[3]);
|
||||
r.cost = Strings::ToInt(row[5]);
|
||||
r.slot_id = Strings::ToInt(row[6]);
|
||||
r.sum_charges = Strings::ToInt(row[7]);
|
||||
r.stackable = item->Stackable;
|
||||
r.icon_id = item->Icon;
|
||||
r.trader_zone_id = Strings::ToInt(row[8]);
|
||||
r.trader_zone_instance_id = Strings::ToInt(row[17]);
|
||||
r.trader_entity_id = Strings::ToInt(row[9]);
|
||||
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
|
||||
r.item_name = fmt::format("{:.63}\0", item->Name);
|
||||
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
|
||||
|
||||
LogTradingDetail(
|
||||
"Searching against item [{}] ({}) for trader [{}]",
|
||||
item->Name,
|
||||
item->ID,
|
||||
r.trader_name
|
||||
);
|
||||
|
||||
// item stat searches
|
||||
std::map<uint32, uint32> item_stat_searches = {
|
||||
|
||||
{STAT_AC, inst->GetItemArmorClass(true)},
|
||||
{STAT_AGI, static_cast<uint32>(inst->GetItemAgi(true))},
|
||||
{STAT_CHA, static_cast<uint32>(inst->GetItemCha(true))},
|
||||
{STAT_DEX, static_cast<uint32>(inst->GetItemDex(true))},
|
||||
{STAT_INT, static_cast<uint32>(inst->GetItemInt(true))},
|
||||
{STAT_STA, static_cast<uint32>(inst->GetItemSta(true))},
|
||||
{STAT_STR, static_cast<uint32>(inst->GetItemStr(true))},
|
||||
{STAT_WIS, static_cast<uint32>(inst->GetItemWis(true))},
|
||||
{STAT_COLD, static_cast<uint32>(inst->GetItemCR(true))},
|
||||
{STAT_DISEASE, static_cast<uint32>(inst->GetItemDR(true))},
|
||||
{STAT_FIRE, static_cast<uint32>(inst->GetItemFR(true))},
|
||||
{STAT_MAGIC, static_cast<uint32>(inst->GetItemMR(true))},
|
||||
{STAT_POISON, static_cast<uint32>(inst->GetItemPR(true))},
|
||||
{STAT_HP, static_cast<uint32>(inst->GetItemHP(true))},
|
||||
{STAT_MANA, static_cast<uint32>(inst->GetItemMana(true))},
|
||||
{STAT_ENDURANCE, static_cast<uint32>(inst->GetItemEndur(true))},
|
||||
{STAT_ATTACK, static_cast<uint32>(inst->GetItemAttack(true))},
|
||||
{STAT_HP_REGEN, static_cast<uint32>(inst->GetItemRegen(true))},
|
||||
{STAT_MANA_REGEN, static_cast<uint32>(inst->GetItemManaRegen(true))},
|
||||
{STAT_HASTE, static_cast<uint32>(inst->GetItemHaste(true))},
|
||||
{STAT_DAMAGE_SHIELD, static_cast<uint32>(inst->GetItemDamageShield(true))},
|
||||
{STAT_DS_MITIGATION, static_cast<uint32>(inst->GetItemDSMitigation(true))},
|
||||
{STAT_HEAL_AMOUNT, static_cast<uint32>(inst->GetItemHealAmt(true))},
|
||||
{STAT_SPELL_DAMAGE, static_cast<uint32>(inst->GetItemSpellDamage(true))},
|
||||
{STAT_CLAIRVOYANCE, static_cast<uint32>(inst->GetItemClairvoyance(true))},
|
||||
{STAT_HEROIC_AGILITY, static_cast<uint32>(inst->GetItemHeroicAgi(true))},
|
||||
{STAT_HEROIC_CHARISMA, static_cast<uint32>(inst->GetItemHeroicCha(true))},
|
||||
{STAT_HEROIC_DEXTERITY, static_cast<uint32>(inst->GetItemHeroicDex(true))},
|
||||
{STAT_HEROIC_INTELLIGENCE, static_cast<uint32>(inst->GetItemHeroicInt(true))},
|
||||
{STAT_HEROIC_STAMINA, static_cast<uint32>(inst->GetItemHeroicSta(true))},
|
||||
{STAT_HEROIC_STRENGTH, static_cast<uint32>(inst->GetItemHeroicStr(true))},
|
||||
{STAT_HEROIC_WISDOM, static_cast<uint32>(inst->GetItemHeroicWis(true))},
|
||||
{STAT_BASH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillBash, true))},
|
||||
{STAT_BACKSTAB, static_cast<uint32>(inst->GetItemBackstabDamage(true))},
|
||||
{STAT_DRAGON_PUNCH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillDragonPunch, true))},
|
||||
{STAT_EAGLE_STRIKE, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillEagleStrike, true))},
|
||||
{STAT_FLYING_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFlyingKick, true))},
|
||||
{STAT_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillKick, true))},
|
||||
{STAT_ROUND_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillRoundKick, true))},
|
||||
{STAT_TIGER_CLAW, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillTigerClaw, true))},
|
||||
{STAT_FRENZY, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFrenzy, true))},
|
||||
};
|
||||
|
||||
r.item_stat = item_stat_searches.contains(search.item_stat) ? item_stat_searches[search.item_stat] : 0;
|
||||
if (item_stat_searches.contains(search.item_stat) && item_stat_searches[search.item_stat] <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static std::map<uint8, uint32> item_slot_searches = {
|
||||
{EQ::invslot::slotCharm, 1},
|
||||
{EQ::invslot::slotEar1, 2},
|
||||
{EQ::invslot::slotHead, 4},
|
||||
{EQ::invslot::slotFace, 8},
|
||||
{EQ::invslot::slotEar2, 16},
|
||||
{EQ::invslot::slotNeck, 32},
|
||||
{EQ::invslot::slotShoulders, 64},
|
||||
{EQ::invslot::slotArms, 128},
|
||||
{EQ::invslot::slotBack, 256},
|
||||
{EQ::invslot::slotWrist1, 512},
|
||||
{EQ::invslot::slotWrist2, 1024},
|
||||
{EQ::invslot::slotRange, 2048},
|
||||
{EQ::invslot::slotHands, 4096},
|
||||
{EQ::invslot::slotPrimary, 8192},
|
||||
{EQ::invslot::slotSecondary, 16384},
|
||||
{EQ::invslot::slotFinger1, 32768},
|
||||
{EQ::invslot::slotFinger2, 65536},
|
||||
{EQ::invslot::slotChest, 131072},
|
||||
{EQ::invslot::slotLegs, 262144},
|
||||
{EQ::invslot::slotFeet, 524288},
|
||||
{EQ::invslot::slotWaist, 1048576},
|
||||
{EQ::invslot::slotPowerSource, 2097152},
|
||||
{EQ::invslot::slotAmmo, 4194304},
|
||||
};
|
||||
|
||||
auto GetEquipmentSlotBit = [&](uint32 slot) -> uint32 {
|
||||
return item_slot_searches.contains(slot) ? item_slot_searches[slot] : 0;
|
||||
};
|
||||
|
||||
auto FindItemAugSlot = [&]() -> bool {
|
||||
for (auto const &s: inst->GetItem()->AugSlotType) {
|
||||
return s == search.augment;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// item type searches
|
||||
std::vector<ItemSearchType> item_search_types = {
|
||||
{EQ::item::ItemType::ItemTypeAll, true},
|
||||
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
|
||||
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer ||
|
||||
item->IsClassBag()},
|
||||
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
|
||||
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
|
||||
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
|
||||
{EQ::item::ItemType::ItemTypeFocusEffect, item->Focus.Effect > 0},
|
||||
{EQ::item::ItemType::ItemTypeArmor, item->ItemType == EQ::item::ItemType::ItemTypeArmor},
|
||||
{EQ::item::ItemType::ItemType1HBlunt, item->ItemType == EQ::item::ItemType::ItemType1HBlunt},
|
||||
{EQ::item::ItemType::ItemType1HPiercing, item->ItemType == EQ::item::ItemType::ItemType1HPiercing},
|
||||
{EQ::item::ItemType::ItemType1HSlash, item->ItemType == EQ::item::ItemType::ItemType1HSlash},
|
||||
{EQ::item::ItemType::ItemType2HBlunt, item->ItemType == EQ::item::ItemType::ItemType2HBlunt},
|
||||
{EQ::item::ItemType::ItemType2HSlash, item->ItemType == EQ::item::ItemType::ItemType2HSlash},
|
||||
{EQ::item::ItemType::ItemTypeBow, item->ItemType == EQ::item::ItemType::ItemTypeBow},
|
||||
{EQ::item::ItemType::ItemTypeShield, item->ItemType == EQ::item::ItemType::ItemTypeShield},
|
||||
{EQ::item::ItemType::ItemTypeMisc, item->ItemType == EQ::item::ItemType::ItemTypeMisc},
|
||||
{EQ::item::ItemType::ItemTypeFood, item->ItemType == EQ::item::ItemType::ItemTypeFood},
|
||||
{EQ::item::ItemType::ItemTypeDrink, item->ItemType == EQ::item::ItemType::ItemTypeDrink},
|
||||
{EQ::item::ItemType::ItemTypeLight, item->ItemType == EQ::item::ItemType::ItemTypeLight},
|
||||
{EQ::item::ItemType::ItemTypeCombinable, item->ItemType == EQ::item::ItemType::ItemTypeCombinable},
|
||||
{EQ::item::ItemType::ItemTypeBandage, item->ItemType == EQ::item::ItemType::ItemTypeBandage},
|
||||
{EQ::item::ItemType::ItemTypeSmallThrowing, item->ItemType == EQ::item::ItemType::ItemTypeSmallThrowing ||
|
||||
item->ItemType == EQ::item::ItemType::ItemTypeLargeThrowing},
|
||||
{EQ::item::ItemType::ItemTypeSpell, item->ItemType == EQ::item::ItemType::ItemTypeSpell},
|
||||
{EQ::item::ItemType::ItemTypePotion, item->ItemType == EQ::item::ItemType::ItemTypePotion},
|
||||
{EQ::item::ItemType::ItemTypeBrassInstrument, item->ItemType == EQ::item::ItemType::ItemTypeBrassInstrument},
|
||||
{EQ::item::ItemType::ItemTypeWindInstrument, item->ItemType == EQ::item::ItemType::ItemTypeWindInstrument},
|
||||
{EQ::item::ItemType::ItemTypeStringedInstrument, item->ItemType == EQ::item::ItemType::ItemTypeStringedInstrument},
|
||||
{EQ::item::ItemType::ItemTypePercussionInstrument, item->ItemType == EQ::item::ItemType::ItemTypePercussionInstrument},
|
||||
{EQ::item::ItemType::ItemTypeArrow, item->ItemType == EQ::item::ItemType::ItemTypeArrow},
|
||||
{EQ::item::ItemType::ItemTypeJewelry, item->ItemType == EQ::item::ItemType::ItemTypeJewelry},
|
||||
{EQ::item::ItemType::ItemTypeNote, item->ItemType == EQ::item::ItemType::ItemTypeNote},
|
||||
{EQ::item::ItemType::ItemTypeKey, item->ItemType == EQ::item::ItemType::ItemTypeKey},
|
||||
{EQ::item::ItemType::ItemType2HPiercing, item->ItemType == EQ::item::ItemType::ItemType2HPiercing},
|
||||
{EQ::item::ItemType::ItemTypeAlcohol, item->ItemType == EQ::item::ItemType::ItemTypeAlcohol},
|
||||
{EQ::item::ItemType::ItemTypeMartial, item->ItemType == EQ::item::ItemType::ItemTypeMartial},
|
||||
{EQ::item::ItemType::ItemTypeAugmentation, item->ItemType == EQ::item::ItemType::ItemTypeAugmentation},
|
||||
{EQ::item::ItemType::ItemTypeAlternateAbility, item->ItemType == EQ::item::ItemType::ItemTypeAlternateAbility},
|
||||
{EQ::item::ItemType::ItemTypeCount, item->ItemType == EQ::item::ItemType::ItemTypeCount},
|
||||
{EQ::item::ItemType::ItemTypeCollectible, item->ItemType == EQ::item::ItemType::ItemTypeCollectible}
|
||||
};
|
||||
|
||||
bool met_filter = false;
|
||||
bool has_filter = false;
|
||||
|
||||
for (auto &i: item_search_types) {
|
||||
if (i.type == search.type) {
|
||||
has_filter = true;
|
||||
if (i.condition) {
|
||||
LogTradingDetail("Item [{}] met search criteria for type [{}]", item->Name, uint8(i.type));
|
||||
met_filter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (has_filter && !met_filter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Add catch-all item type filter for specific item types
|
||||
|
||||
// item additive searches
|
||||
std::vector<AddititiveSearchCriteria> item_additive_searches = {
|
||||
{
|
||||
.should_check = search.min_level != 1 && inst->GetItemRequiredLevel(true) > 0,
|
||||
.condition = inst->GetItemRequiredLevel(true) >= search.min_level
|
||||
},
|
||||
{
|
||||
.should_check = search.max_level != 1 && inst->GetItemRequiredLevel(true) > 0,
|
||||
.condition = inst->GetItemRequiredLevel(true) <= search.max_level
|
||||
},
|
||||
{
|
||||
.should_check = !std::string(search.item_name).empty(),
|
||||
.condition = Strings::ContainsLower(item->Name, search.item_name)
|
||||
},
|
||||
{
|
||||
.should_check = search._class != 0xFFFFFFFF,
|
||||
.condition = static_cast<bool>(item->Classes & GetPlayerClassBit(search._class))
|
||||
},
|
||||
{
|
||||
.should_check = search.race != 0xFFFFFFFF,
|
||||
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))
|
||||
},
|
||||
{
|
||||
.should_check = search.augment != 0,
|
||||
.condition = FindItemAugSlot()
|
||||
},
|
||||
{
|
||||
.should_check = search.slot != 0xFFFFFFFF,
|
||||
.condition = static_cast<bool>(item->Slots & GetEquipmentSlotBit(search.slot))
|
||||
},
|
||||
};
|
||||
|
||||
bool should_add = true;
|
||||
|
||||
for (auto &i: item_additive_searches) {
|
||||
LogTradingDetail(
|
||||
"Checking item [{}] for search criteria - should_check [{}] condition [{}]",
|
||||
item->Name,
|
||||
i.should_check,
|
||||
i.condition
|
||||
);
|
||||
if (i.should_check && !i.condition) {
|
||||
should_add = false;
|
||||
continue;
|
||||
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
|
||||
if (convert || (r.trader_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)) {
|
||||
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!should_add) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
|
||||
all_entries.push_back(r);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -3,11 +3,13 @@
|
||||
|
||||
#include <vector>
|
||||
#include "shareddb.h"
|
||||
#include "../../common/item_instance.h"
|
||||
|
||||
class Bazaar {
|
||||
public:
|
||||
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id);
|
||||
GetSearchResults(Database &content_db, Database &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "../common/repositories/raid_members_repository.h"
|
||||
#include "../common/repositories/reports_repository.h"
|
||||
#include "../common/repositories/variables_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
|
||||
// Disgrace: for windows compile
|
||||
@@ -313,6 +314,12 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& p = CharacterPetNameRepository::GetWhere(*this, where_filter);
|
||||
if (!p.empty()) {
|
||||
LogInfo("Account [{}] requested name [{}] but name is already taken by an Pet", account_id, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto e = CharacterDataRepository::NewEntity();
|
||||
|
||||
e.account_id = account_id;
|
||||
|
||||
@@ -169,7 +169,10 @@ bool DatabaseUpdate::UpdateManifest(
|
||||
LogSys.EnableMySQLErrorLogs();
|
||||
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
|
||||
|
||||
if (!missing_migrations.empty()) {
|
||||
if (!missing_migrations.empty() && m_skip_backup) {
|
||||
LogInfo("Skipping database backup");
|
||||
}
|
||||
else if (!missing_migrations.empty()) {
|
||||
LogInfo("Automatically backing up database before applying updates");
|
||||
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
|
||||
auto s = DatabaseDumpService();
|
||||
@@ -271,6 +274,13 @@ DatabaseUpdate *DatabaseUpdate::SetContentDatabase(Database *db)
|
||||
return this;
|
||||
}
|
||||
|
||||
DatabaseUpdate *DatabaseUpdate::SetSkipBackup(bool skip)
|
||||
{
|
||||
m_skip_backup = skip;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
|
||||
{
|
||||
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
|
||||
|
||||
@@ -29,12 +29,15 @@ public:
|
||||
|
||||
DatabaseUpdate *SetDatabase(Database *db);
|
||||
DatabaseUpdate *SetContentDatabase(Database *db);
|
||||
DatabaseUpdate *SetSkipBackup(bool skip);
|
||||
bool HasPendingUpdates();
|
||||
private:
|
||||
bool m_skip_backup = false;
|
||||
Database *m_database;
|
||||
Database *m_content_database;
|
||||
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
|
||||
void InjectBotsVersionColumn();
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_DATABASE_UPDATE_H
|
||||
|
||||
@@ -5782,7 +5782,603 @@ CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
|
||||
ALTER TABLE `trader`
|
||||
ADD COLUMN `char_zone_instance_id` INT NULL DEFAULT '0' AFTER `char_zone_id`;
|
||||
)"
|
||||
}
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9287,
|
||||
.description = "2024_11_26_bazaar_find_trader.sql",
|
||||
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'walkspeed'",
|
||||
.condition = "missing",
|
||||
.match = "float",
|
||||
.sql = R"(
|
||||
ALTER TABLE `npc_types` MODIFY COLUMN `walkspeed` float NOT NULL DEFAULT 0;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9288,
|
||||
.description = "2024_11_10_zone_player_partitioning.sql",
|
||||
.check = "SHOW CREATE TABLE `zone`",
|
||||
.condition = "missing",
|
||||
.match = "shard_at_player_count",
|
||||
.sql = R"(
|
||||
ALTER TABLE `zone`
|
||||
ADD COLUMN `shard_at_player_count` int(11) NULL DEFAULT 0 AFTER `seconds_before_idle`;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9289,
|
||||
.description = "2025_01_19_evolving_items__character_evolving_items",
|
||||
.check = "SHOW TABLES LIKE 'character_evolving_items'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
CREATE TABLE `character_evolving_items` (
|
||||
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`character_id` INT(10) UNSIGNED NULL DEFAULT '0',
|
||||
`item_id` INT(10) UNSIGNED NULL DEFAULT '0',
|
||||
`activated` TINYINT(1) UNSIGNED NULL DEFAULT '0',
|
||||
`equipped` TINYINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
`current_amount` BIGINT(20) NULL DEFAULT '0',
|
||||
`progression` DOUBLE(22,0) NULL DEFAULT '0',
|
||||
`final_item_id` INT(10) UNSIGNED NULL DEFAULT '0',
|
||||
`deleted_at` DATETIME NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
AUTO_INCREMENT=1
|
||||
;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9290,
|
||||
.description = "2025_01_19_evolving_items__items_evolving_details",
|
||||
.check = "SHOW TABLES LIKE 'items_evolving_details'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
CREATE TABLE `items_evolving_details` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`item_evo_id` int(10) unsigned DEFAULT 0 COMMENT 'items.evoid',
|
||||
`item_evolve_level` int(10) unsigned DEFAULT 0 COMMENT 'items.evolvinglevel',
|
||||
`item_id` int(10) unsigned DEFAULT 0 COMMENT 'items.id',
|
||||
`type` int(10) unsigned DEFAULT 0,
|
||||
`sub_type` int(10) unsigned DEFAULT 0,
|
||||
`required_amount` bigint(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
|
||||
INSERT INTO `items_evolving_details` VALUES
|
||||
(1,1000,1,86900,99,1,0),
|
||||
(2,1000,2,86901,99,1,0),
|
||||
(3,1000,3,86902,99,1,0),
|
||||
(4,1000,4,86903,99,1,0),
|
||||
(5,1000,5,86904,99,1,0),
|
||||
(6,1001,1,86910,99,1,0),
|
||||
(7,1001,2,86911,99,1,0),
|
||||
(8,1001,3,86912,99,1,0),
|
||||
(9,1001,4,86913,99,1,0),
|
||||
(10,1001,5,86914,99,1,0),
|
||||
(11,1001,6,86915,99,1,0),
|
||||
(12,1001,7,86916,99,1,0),
|
||||
(13,1002,1,86920,99,1,0),
|
||||
(14,1002,2,86921,99,1,0),
|
||||
(15,1002,3,86922,99,1,0),
|
||||
(16,1002,4,86923,99,1,0),
|
||||
(17,1002,5,86924,99,1,0),
|
||||
(18,1002,6,86925,99,1,0),
|
||||
(19,1002,7,86926,99,1,0),
|
||||
(20,1003,1,86930,99,1,0),
|
||||
(21,1003,2,86931,99,1,0),
|
||||
(22,1003,3,86932,99,1,0),
|
||||
(23,1003,4,86933,99,1,0),
|
||||
(24,1003,5,86934,99,1,0),
|
||||
(25,1003,6,86935,99,1,0),
|
||||
(26,1004,1,86940,99,1,0),
|
||||
(27,1004,2,86941,99,1,0),
|
||||
(28,1004,3,86942,99,1,0),
|
||||
(29,1004,4,86943,99,1,0),
|
||||
(30,1004,5,86944,99,1,0),
|
||||
(31,1004,6,86945,99,1,0),
|
||||
(32,1005,1,86950,99,1,0),
|
||||
(33,1005,2,86951,99,1,0),
|
||||
(34,1005,3,86952,99,1,0),
|
||||
(35,1005,4,86953,99,1,0),
|
||||
(36,1005,5,86954,99,1,0),
|
||||
(37,1005,6,86955,99,1,0),
|
||||
(38,1005,7,86956,99,1,0),
|
||||
(39,1006,1,86960,99,1,0),
|
||||
(40,1006,2,86961,99,1,0),
|
||||
(41,1006,3,86962,99,1,0),
|
||||
(42,1006,4,86963,99,1,0),
|
||||
(43,1006,5,86964,99,1,0),
|
||||
(44,1006,6,86965,99,1,0),
|
||||
(45,1006,7,86966,99,1,0),
|
||||
(46,1007,1,86970,99,1,0),
|
||||
(47,1007,2,86971,99,1,0),
|
||||
(48,1007,3,86972,99,1,0),
|
||||
(49,1007,4,86973,99,1,0),
|
||||
(50,1007,5,86974,99,1,0),
|
||||
(51,1007,6,86975,99,1,0),
|
||||
(52,1007,7,86976,99,1,0),
|
||||
(53,1008,1,86980,99,1,0),
|
||||
(54,1008,2,86981,99,1,0),
|
||||
(55,1008,3,86982,99,1,0),
|
||||
(56,1008,4,86983,99,1,0),
|
||||
(57,1008,5,86984,99,1,0),
|
||||
(58,1009,1,86990,99,1,0),
|
||||
(59,1009,2,86991,99,1,0),
|
||||
(60,1009,3,86992,99,1,0),
|
||||
(61,1009,4,86993,99,1,0),
|
||||
(62,1009,5,86994,99,1,0),
|
||||
(63,1009,6,86995,99,1,0),
|
||||
(64,1009,7,86996,99,1,0),
|
||||
(65,1009,8,86997,99,1,0),
|
||||
(66,1009,9,86998,99,1,0),
|
||||
(67,1009,10,86999,99,1,0),
|
||||
(68,1010,1,90001,99,1,0),
|
||||
(69,1010,2,90002,99,1,0),
|
||||
(70,1010,3,90003,99,1,0),
|
||||
(71,1010,6,90006,99,1,0),
|
||||
(72,1010,7,90007,99,1,0),
|
||||
(73,1010,8,90008,99,1,0),
|
||||
(74,1010,10,90010,99,1,0),
|
||||
(75,1050,1,89270,99,1,0),
|
||||
(76,1050,2,89271,99,1,0),
|
||||
(77,1050,3,89272,99,1,0),
|
||||
(78,1050,4,89273,99,1,0),
|
||||
(79,1050,5,89274,99,1,0),
|
||||
(80,1050,6,89275,99,1,0),
|
||||
(81,1051,1,89280,99,1,0),
|
||||
(82,1051,2,89281,99,1,0),
|
||||
(83,1051,3,89282,99,1,0),
|
||||
(84,1051,4,89283,99,1,0),
|
||||
(85,1051,5,89284,99,1,0),
|
||||
(86,1052,1,89290,99,1,0),
|
||||
(87,1052,2,89291,99,1,0),
|
||||
(88,1052,3,89292,99,1,0),
|
||||
(89,1052,4,89293,99,1,0),
|
||||
(90,1052,5,89294,99,1,0),
|
||||
(91,1052,6,89295,99,1,0),
|
||||
(92,1052,7,89296,99,1,0),
|
||||
(93,1053,1,89300,99,1,0),
|
||||
(94,1053,2,89301,99,1,0),
|
||||
(95,1053,3,89302,99,1,0),
|
||||
(96,1053,4,89303,99,1,0),
|
||||
(97,1053,5,89304,99,1,0),
|
||||
(98,1053,6,89305,99,1,0),
|
||||
(99,1053,7,89306,99,1,0),
|
||||
(100,1053,8,89307,99,1,0),
|
||||
(101,1053,9,89308,99,1,0),
|
||||
(102,1054,1,89310,99,1,0),
|
||||
(103,1054,2,89311,99,1,0),
|
||||
(104,1054,3,89312,99,1,0),
|
||||
(105,1054,4,89313,99,1,0),
|
||||
(106,1054,5,89314,99,1,0),
|
||||
(107,1054,6,89315,99,1,0),
|
||||
(108,1055,1,89320,99,1,0),
|
||||
(109,1055,2,89321,99,1,0),
|
||||
(110,1055,3,89322,99,1,0),
|
||||
(111,1055,4,89323,99,1,0),
|
||||
(112,1055,5,89324,99,1,0),
|
||||
(113,1055,6,89325,99,1,0),
|
||||
(114,1055,7,89326,99,1,0),
|
||||
(115,1056,1,89330,99,1,0),
|
||||
(116,1056,2,89331,99,1,0),
|
||||
(117,1056,3,89332,99,1,0),
|
||||
(118,1056,4,89333,99,1,0),
|
||||
(119,1056,5,89334,99,1,0),
|
||||
(120,1057,1,89340,99,1,0),
|
||||
(121,1057,2,89341,99,1,0),
|
||||
(122,1057,3,89342,99,1,0),
|
||||
(123,1057,4,89343,99,1,0),
|
||||
(124,1057,5,89344,99,1,0),
|
||||
(125,1057,6,89345,99,1,0),
|
||||
(126,1057,7,89346,99,1,0),
|
||||
(127,1057,8,89347,99,1,0),
|
||||
(128,1058,1,89350,99,1,0),
|
||||
(129,1058,2,89351,99,1,0),
|
||||
(130,1058,3,89352,99,1,0),
|
||||
(131,1058,4,89353,99,1,0),
|
||||
(132,1058,5,89354,99,1,0),
|
||||
(133,1058,6,89355,99,1,0),
|
||||
(134,1058,7,89356,99,1,0),
|
||||
(135,1059,1,89360,99,1,0),
|
||||
(136,1059,2,89361,99,1,0),
|
||||
(137,1059,3,89362,99,1,0),
|
||||
(138,1060,1,89490,99,1,0),
|
||||
(139,1060,2,89491,99,1,0),
|
||||
(140,1060,3,89492,99,1,0),
|
||||
(141,1061,1,89500,99,1,0),
|
||||
(142,1061,2,89501,99,1,0),
|
||||
(143,1061,3,89502,99,1,0),
|
||||
(144,1062,1,89510,99,1,0),
|
||||
(145,1062,2,89511,99,1,0),
|
||||
(146,1062,3,89512,99,1,0),
|
||||
(147,1063,1,89520,99,1,0),
|
||||
(148,1063,2,89521,99,1,0),
|
||||
(149,1063,3,89522,99,1,0),
|
||||
(150,1064,1,89530,99,1,0),
|
||||
(151,1064,2,89531,99,1,0),
|
||||
(152,1064,3,89532,99,1,0),
|
||||
(153,1065,1,89540,99,1,0),
|
||||
(154,1065,2,89541,99,1,0),
|
||||
(155,1065,3,89542,99,1,0),
|
||||
(156,1066,1,89550,3,274,500),
|
||||
(157,1066,2,89551,3,274,1000),
|
||||
(158,1066,3,89552,3,274,2000),
|
||||
(159,1067,1,89560,99,1,0),
|
||||
(160,1067,2,89561,99,1,0),
|
||||
(161,1067,3,89562,99,1,0),
|
||||
(162,1069,1,85571,99,1,0),
|
||||
(163,1069,2,85572,99,1,0),
|
||||
(164,1069,3,85573,99,1,0),
|
||||
(165,1200,1,95001,99,1,0),
|
||||
(166,1200,2,95002,99,1,0),
|
||||
(167,1200,3,95003,99,1,0),
|
||||
(168,1200,4,95004,99,1,0),
|
||||
(169,1200,5,95005,99,1,0),
|
||||
(170,1200,6,95006,99,1,0),
|
||||
(171,1200,7,95007,99,1,0),
|
||||
(172,1201,1,95008,99,1,0),
|
||||
(173,1201,2,95009,99,1,0),
|
||||
(174,1201,3,95010,99,1,0),
|
||||
(175,1201,4,95011,99,1,0),
|
||||
(176,1201,5,95012,99,1,0),
|
||||
(177,1201,6,95013,99,1,0),
|
||||
(178,1201,7,95014,99,1,0),
|
||||
(179,1202,1,95015,99,1,0),
|
||||
(180,1202,2,95016,99,1,0),
|
||||
(181,1202,3,95017,99,1,0),
|
||||
(182,1202,4,95018,99,1,0),
|
||||
(183,1202,5,95019,99,1,0),
|
||||
(184,1202,6,95020,99,1,0),
|
||||
(185,1202,7,95021,99,1,0),
|
||||
(186,1203,1,95022,99,1,0),
|
||||
(187,1203,2,95023,99,1,0),
|
||||
(188,1203,3,95024,99,1,0),
|
||||
(189,1203,4,95025,99,1,0),
|
||||
(190,1203,5,95026,99,1,0),
|
||||
(191,1203,6,95027,99,1,0),
|
||||
(192,1203,7,95028,99,1,0),
|
||||
(193,1204,1,95029,99,1,0),
|
||||
(194,1204,2,95030,99,1,0),
|
||||
(195,1204,3,95031,99,1,0),
|
||||
(196,1204,4,95032,99,1,0),
|
||||
(197,1204,5,95033,99,1,0),
|
||||
(198,1204,6,95034,99,1,0),
|
||||
(199,1204,7,95035,99,1,0),
|
||||
(200,1205,1,95036,99,1,0),
|
||||
(201,1205,2,95037,99,1,0),
|
||||
(202,1205,3,95038,99,1,0),
|
||||
(203,1205,4,95039,99,1,0),
|
||||
(204,1205,5,95040,99,1,0),
|
||||
(205,1205,6,95041,99,1,0),
|
||||
(206,1205,7,95042,99,1,0),
|
||||
(207,1206,1,95043,99,1,0),
|
||||
(208,1206,2,95044,99,1,0),
|
||||
(209,1206,3,95045,99,1,0),
|
||||
(210,1206,4,95046,99,1,0),
|
||||
(211,1206,5,95047,99,1,0),
|
||||
(212,1206,6,95048,99,1,0),
|
||||
(213,1206,7,95049,99,1,0),
|
||||
(214,1207,1,95050,99,1,0),
|
||||
(215,1207,2,95051,99,1,0),
|
||||
(216,1207,3,95052,99,1,0),
|
||||
(217,1207,4,95053,99,1,0),
|
||||
(218,1207,5,95054,99,1,0),
|
||||
(219,1207,6,95055,99,1,0),
|
||||
(220,1207,7,95056,99,1,0),
|
||||
(221,1208,1,95057,99,1,0),
|
||||
(222,1208,2,95058,99,1,0),
|
||||
(223,1208,3,95059,99,1,0),
|
||||
(224,1208,4,95060,99,1,0),
|
||||
(225,1208,5,95061,99,1,0),
|
||||
(226,1208,6,95062,99,1,0),
|
||||
(227,1208,7,95063,99,1,0),
|
||||
(228,1209,1,95064,99,1,0),
|
||||
(229,1209,2,95065,99,1,0),
|
||||
(230,1209,3,95066,99,1,0),
|
||||
(231,1209,4,95067,99,1,0),
|
||||
(232,1209,5,95068,99,1,0),
|
||||
(233,1209,6,95069,99,1,0),
|
||||
(234,1209,7,95070,99,1,0),
|
||||
(235,1210,1,95071,99,1,0),
|
||||
(236,1210,2,95072,99,1,0),
|
||||
(237,1210,3,95073,99,1,0),
|
||||
(238,1210,4,95074,99,1,0),
|
||||
(239,1210,5,95075,99,1,0),
|
||||
(240,1210,6,95076,99,1,0),
|
||||
(241,1210,7,95077,99,1,0),
|
||||
(242,1211,1,85612,1,1,100000),
|
||||
(243,1211,2,85613,1,1,200000),
|
||||
(244,1211,3,85614,1,1,300000),
|
||||
(245,1214,1,80035,99,1,0),
|
||||
(246,1301,1,102700,99,1,0),
|
||||
(247,1301,4,102703,99,1,0),
|
||||
(248,1302,1,102704,99,1,0),
|
||||
(249,1302,2,102705,99,1,0),
|
||||
(250,1303,1,102706,99,1,0),
|
||||
(251,1303,2,102707,99,1,0),
|
||||
(252,1303,3,102708,99,1,0),
|
||||
(253,1304,1,102709,99,1,0),
|
||||
(254,1304,5,102713,99,1,0),
|
||||
(255,1305,1,102714,99,1,0),
|
||||
(256,1306,1,102716,99,1,0),
|
||||
(257,1306,5,102720,99,1,0),
|
||||
(258,1307,1,102721,99,1,0),
|
||||
(259,1307,3,102723,99,1,0),
|
||||
(260,1308,1,102724,99,1,0),
|
||||
(261,1309,1,102727,99,1,0),
|
||||
(262,1309,2,102728,99,1,0),
|
||||
(263,1310,1,102729,99,1,0),
|
||||
(264,1310,3,102731,99,1,0),
|
||||
(265,1311,1,102732,99,1,0),
|
||||
(266,1311,4,102735,99,1,0),
|
||||
(267,1312,1,102736,99,1,0),
|
||||
(268,1312,3,102738,99,1,0),
|
||||
(269,1313,1,102739,99,1,0),
|
||||
(270,1314,1,102743,99,1,0),
|
||||
(271,1314,2,102744,99,1,0),
|
||||
(272,1314,3,102745,99,1,0),
|
||||
(273,1315,1,102746,99,1,0),
|
||||
(274,1315,2,102747,99,1,0),
|
||||
(275,1316,1,102748,99,1,0),
|
||||
(276,1316,5,102752,99,1,0),
|
||||
(277,1317,1,102753,99,1,0),
|
||||
(278,1318,1,102756,99,1,0),
|
||||
(279,1319,1,102759,99,1,0),
|
||||
(280,1319,3,102761,99,1,0),
|
||||
(281,1320,1,102762,99,1,0),
|
||||
(282,1321,1,102765,99,1,0),
|
||||
(283,1321,2,102766,99,1,0),
|
||||
(284,1321,3,102767,99,1,0),
|
||||
(285,1322,1,102768,99,1,0),
|
||||
(286,1322,2,102769,99,1,0),
|
||||
(287,1322,3,102770,99,1,0),
|
||||
(288,1323,1,102771,99,1,0),
|
||||
(289,1324,1,102774,99,1,0),
|
||||
(290,1400,1,102800,99,1,0),
|
||||
(291,1401,1,102807,99,1,0),
|
||||
(292,1401,7,102813,99,1,0),
|
||||
(293,1402,1,102814,99,1,0),
|
||||
(294,1402,7,102820,99,1,0),
|
||||
(295,1403,1,102821,99,1,0),
|
||||
(296,1404,1,102828,99,1,0),
|
||||
(297,1405,1,102835,99,1,0),
|
||||
(298,1406,1,102842,99,1,0),
|
||||
(299,1408,1,109310,99,1,0),
|
||||
(300,1408,5,109314,99,1,0),
|
||||
(301,1409,1,109315,99,1,0),
|
||||
(302,1409,5,109319,99,1,0),
|
||||
(303,1410,1,109320,99,1,0),
|
||||
(304,1410,5,109324,99,1,0),
|
||||
(305,1411,1,109325,99,1,0),
|
||||
(306,1411,5,109329,99,1,0),
|
||||
(307,1412,1,109330,99,1,0),
|
||||
(308,1412,5,109334,99,1,0),
|
||||
(309,1413,1,109335,99,1,0),
|
||||
(310,1413,5,109339,99,1,0),
|
||||
(311,1414,1,109340,99,1,0),
|
||||
(312,1414,5,109344,99,1,0),
|
||||
(313,1415,1,109345,99,1,0),
|
||||
(314,1415,5,109349,99,1,0),
|
||||
(315,1416,1,109350,99,1,0),
|
||||
(316,1416,2,109351,99,1,0),
|
||||
(317,1416,5,109354,99,1,0),
|
||||
(318,1417,1,109355,99,1,0),
|
||||
(319,1417,5,109359,99,1,0),
|
||||
(320,1418,1,109360,99,1,0),
|
||||
(321,1418,5,109364,99,1,0),
|
||||
(322,1419,1,109365,99,1,0),
|
||||
(323,1419,3,109367,99,1,0),
|
||||
(324,1419,5,109369,99,1,0),
|
||||
(325,1420,1,109370,99,1,0),
|
||||
(326,1420,5,109374,99,1,0),
|
||||
(327,1421,1,109375,99,1,0),
|
||||
(328,1421,5,109379,99,1,0),
|
||||
(329,1422,1,109380,99,1,0),
|
||||
(330,1422,5,109384,99,1,0),
|
||||
(331,1423,1,109385,99,1,0),
|
||||
(332,1423,2,109386,99,1,0),
|
||||
(333,1423,5,109389,99,1,0),
|
||||
(334,1436,1,120378,99,1,0),
|
||||
(335,1436,2,120379,99,1,0),
|
||||
(336,1436,3,120380,99,1,0),
|
||||
(337,1436,4,120381,99,1,0),
|
||||
(338,1436,5,120382,99,1,0),
|
||||
(339,1436,6,120383,99,1,0),
|
||||
(340,1436,7,120384,99,1,0),
|
||||
(341,1436,8,120385,99,1,0),
|
||||
(342,1436,9,120386,99,1,0),
|
||||
(343,1436,10,120387,99,1,0),
|
||||
(344,1436,11,120388,99,1,0),
|
||||
(345,1436,12,120389,99,1,0),
|
||||
(346,1436,13,120390,99,1,0),
|
||||
(347,1436,14,120391,99,1,0),
|
||||
(348,1436,15,120392,99,1,0),
|
||||
(349,1436,16,120393,99,1,0),
|
||||
(350,1436,17,120394,99,1,0),
|
||||
(351,1436,18,120395,99,1,0),
|
||||
(352,1436,19,120396,99,1,0),
|
||||
(353,1436,20,120397,99,1,0),
|
||||
(354,1440,1,56992,99,1,0),
|
||||
(355,1440,2,56993,99,1,0),
|
||||
(356,1440,3,56994,99,1,0),
|
||||
(357,1440,4,56995,99,1,0),
|
||||
(358,1440,5,56996,99,1,0),
|
||||
(359,1441,1,132787,99,1,0),
|
||||
(360,1441,2,132788,99,1,0),
|
||||
(361,1441,3,132789,99,1,0),
|
||||
(362,1441,4,132790,99,1,0),
|
||||
(363,1441,5,132791,99,1,0),
|
||||
(364,1441,6,132792,99,1,0),
|
||||
(365,1441,7,132793,99,1,0),
|
||||
(366,1441,8,132794,99,1,0),
|
||||
(367,1441,9,132795,99,1,0),
|
||||
(368,1441,10,132796,99,1,0),
|
||||
(369,1441,11,132797,99,1,0),
|
||||
(370,1441,13,132799,99,1,0),
|
||||
(371,1441,14,132800,99,1,0),
|
||||
(372,1441,15,132801,99,1,0),
|
||||
(373,1441,16,132802,99,1,0),
|
||||
(374,1441,17,132803,99,1,0),
|
||||
(375,1441,18,132804,99,1,0),
|
||||
(376,1441,19,132805,99,1,0),
|
||||
(377,1441,20,132806,99,1,0),
|
||||
(378,1442,1,133137,99,1,0),
|
||||
(379,1442,2,133138,99,1,0),
|
||||
(380,1442,3,133139,99,1,0),
|
||||
(381,1442,4,133140,99,1,0),
|
||||
(382,1442,10,133146,99,1,0),
|
||||
(383,1442,11,133147,99,1,0),
|
||||
(384,1442,12,133148,99,1,0),
|
||||
(385,1442,13,133149,99,1,0),
|
||||
(386,1442,14,133150,99,1,0),
|
||||
(387,1442,15,133151,99,1,0),
|
||||
(388,1442,16,133152,99,1,0),
|
||||
(389,1442,17,133153,99,1,0),
|
||||
(390,1442,18,133154,99,1,0),
|
||||
(391,1442,19,133155,99,1,0),
|
||||
(392,1442,20,133156,99,1,0),
|
||||
(393,1443,1,133406,99,1,0),
|
||||
(394,1443,2,133407,99,1,0),
|
||||
(395,1443,3,133408,99,1,0),
|
||||
(396,1443,4,133409,99,1,0),
|
||||
(397,1443,5,133410,99,1,0),
|
||||
(398,1443,6,133411,99,1,0),
|
||||
(399,1443,7,133412,99,1,0),
|
||||
(400,1443,8,133413,99,1,0),
|
||||
(401,1443,9,133414,99,1,0),
|
||||
(402,1443,10,133415,99,1,0),
|
||||
(403,1443,11,133416,99,1,0),
|
||||
(404,1443,12,133417,99,1,0),
|
||||
(405,1443,13,133418,99,1,0),
|
||||
(406,1443,14,133419,99,1,0),
|
||||
(407,1443,15,133420,99,1,0),
|
||||
(408,1443,16,133421,99,1,0),
|
||||
(409,1443,17,133422,99,1,0),
|
||||
(410,1443,18,133423,99,1,0),
|
||||
(411,1443,19,133424,99,1,0),
|
||||
(412,1443,20,133425,99,1,0),
|
||||
(413,1444,1,94938,99,1,0),
|
||||
(414,1444,2,94939,99,1,0),
|
||||
(415,1444,3,94940,99,1,0),
|
||||
(416,1444,4,94941,99,1,0),
|
||||
(417,1444,5,94942,99,1,0),
|
||||
(418,1444,6,94943,99,1,0),
|
||||
(419,1444,7,94944,99,1,0),
|
||||
(420,1444,8,94945,99,1,0),
|
||||
(421,1444,9,94946,99,1,0),
|
||||
(422,1444,10,94947,99,1,0),
|
||||
(423,1444,11,94948,99,1,0),
|
||||
(424,1444,12,94949,99,1,0),
|
||||
(425,1444,13,94950,99,1,0),
|
||||
(426,1444,14,94951,99,1,0),
|
||||
(427,1444,15,94952,99,1,0),
|
||||
(428,1444,16,94953,99,1,0),
|
||||
(429,1444,17,94954,99,1,0),
|
||||
(430,1444,18,94955,99,1,0),
|
||||
(431,1444,19,94956,99,1,0),
|
||||
(432,1444,20,94957,99,1,0),
|
||||
(433,1445,1,98858,99,1,0),
|
||||
(434,1445,2,98859,99,1,0),
|
||||
(435,1445,3,98860,99,1,0),
|
||||
(436,1445,4,98861,99,1,0),
|
||||
(437,1445,5,98862,99,1,0);
|
||||
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9291,
|
||||
.description = "2025_01_21_add_remove_zone_fields",
|
||||
.check = "SHOW COLUMNS FROM `zone` LIKE 'client_update_range'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE zone DROP COLUMN IF EXISTS npc_update_range;
|
||||
ALTER TABLE zone DROP COLUMN IF EXISTS max_movement_update_range;
|
||||
ALTER TABLE `zone` ADD COLUMN `client_update_range` int(11) NOT NULL DEFAULT 600 AFTER `npc_max_aggro_dist`;
|
||||
)",
|
||||
.content_schema_update = true,
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9292,
|
||||
.description = "2025_01_21_data_buckets_account_id",
|
||||
.check = "SHOW COLUMNS FROM `data_buckets` LIKE 'account_id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `data_buckets`
|
||||
ADD COLUMN `account_id` bigint(11) NULL DEFAULT 0 AFTER `expires`,
|
||||
DROP INDEX `keys`,
|
||||
ADD UNIQUE INDEX `keys` (`key`, `character_id`, `npc_id`, `bot_id`, `account_id`) USING BTREE;
|
||||
|
||||
-- Add the INDEX for character_id and key
|
||||
ALTER TABLE `data_buckets` ADD KEY `idx_account_id_key` (`account_id`, `key`);
|
||||
)",
|
||||
.content_schema_update = false
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9293,
|
||||
.description = "2025_01_10_create_pet_names_table.sql",
|
||||
.check = "SHOW TABLES LIKE 'character_pet_name'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
CREATE TABLE `character_pet_name` (
|
||||
`character_id` INT(11) NOT NULL PRIMARY KEY,
|
||||
`name` VARCHAR(64) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
)",
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9294,
|
||||
.description = "2025_01_26_items_table_bazaar_search_indexes.sql",
|
||||
.check = "SHOW CREATE TABLE `items`",
|
||||
.condition = "missing",
|
||||
.match = "idx_slots_reclevel",
|
||||
.sql = R"(
|
||||
-- indexes for the `items` table
|
||||
CREATE INDEX idx_slots_reclevel ON items (slots, reclevel);
|
||||
CREATE INDEX idx_itemclass_itemtype ON items (itemclass, itemtype);
|
||||
CREATE INDEX idx_augment_slots ON items (
|
||||
augslot1type,
|
||||
augslot2type,
|
||||
augslot3type,
|
||||
augslot4type,
|
||||
augslot5type,
|
||||
augslot6type
|
||||
);
|
||||
CREATE INDEX idx_races_classes ON items (races, classes);
|
||||
|
||||
-- common stat fields
|
||||
CREATE INDEX idx_item_ac ON items (ac);
|
||||
CREATE INDEX idx_item_hp ON items (hp);
|
||||
CREATE INDEX idx_item_mana ON items (mana);
|
||||
CREATE INDEX idx_item_reclevel ON items (reclevel);
|
||||
CREATE INDEX idx_item_type_skill ON items (itemtype, skillmodtype);
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9295,
|
||||
.description = "2025_01_26_trader_table_bazaar_search_indexes.sql",
|
||||
.check = "SHOW CREATE TABLE `trader`",
|
||||
.condition = "missing",
|
||||
.match = "idx_trader_item",
|
||||
.sql = R"(
|
||||
-- indexes for the `trader` table
|
||||
CREATE INDEX idx_trader_item ON trader (item_id, item_cost);
|
||||
CREATE INDEX idx_trader_char ON trader (char_id, char_zone_id, char_zone_instance_id);
|
||||
CREATE INDEX idx_trader_item_sn ON trader (item_sn);
|
||||
CREATE INDEX idx_trader_item_cost ON trader (item_cost);
|
||||
CREATE INDEX idx_trader_active_transaction ON trader (active_transaction);
|
||||
)",
|
||||
.content_schema_update = false
|
||||
},
|
||||
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
// ManifestEntry{
|
||||
// .version = 9228,
|
||||
|
||||
@@ -114,7 +114,9 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
|
||||
timeval tv{};
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
return (i.start_time + i.duration) <= tv.tv_sec;
|
||||
// Use uint64_t for the addition to prevent overflow
|
||||
uint64_t expiration_time = static_cast<uint64_t>(i.start_time) + static_cast<uint64_t>(i.duration);
|
||||
return expiration_time <= tv.tv_sec;
|
||||
}
|
||||
|
||||
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
||||
@@ -469,15 +471,13 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
|
||||
|
||||
void Database::DeleteInstance(uint16 instance_id)
|
||||
{
|
||||
// I'm not sure why this isn't in here but we should add it in a later change and make sure it's tested
|
||||
// InstanceListRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||
|
||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
|
||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace DatabaseSchema {
|
||||
{"character_enabledtasks", "charid"},
|
||||
{"character_expedition_lockouts", "character_id"},
|
||||
{"character_exp_modifiers", "character_id"},
|
||||
{"character_evolving_items", "character_id"},
|
||||
{"character_inspect_messages", "id"},
|
||||
{"character_instance_safereturns", "character_id"},
|
||||
{"character_item_recast", "id"},
|
||||
@@ -63,6 +64,7 @@ namespace DatabaseSchema {
|
||||
{"character_pet_buffs", "char_id"},
|
||||
{"character_pet_info", "char_id"},
|
||||
{"character_pet_inventory", "char_id"},
|
||||
{"character_pet_name", "character_id"},
|
||||
{"character_peqzone_flags", "id"},
|
||||
{"character_potionbelt", "id"},
|
||||
{"character_skills", "id"},
|
||||
@@ -124,6 +126,7 @@ namespace DatabaseSchema {
|
||||
"character_enabledtasks",
|
||||
"character_expedition_lockouts",
|
||||
"character_exp_modifiers",
|
||||
"character_evolving_items",
|
||||
"character_inspect_messages",
|
||||
"character_instance_safereturns",
|
||||
"character_item_recast",
|
||||
@@ -212,6 +215,7 @@ namespace DatabaseSchema {
|
||||
"ground_spawns",
|
||||
"horses",
|
||||
"items",
|
||||
"items_evolving_details",
|
||||
"ldon_trap_entries",
|
||||
"ldon_trap_templates",
|
||||
"lootdrop",
|
||||
|
||||
+9
-2
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
|
||||
N(OP_AltCurrencyPurchase),
|
||||
N(OP_AltCurrencyReclaim),
|
||||
N(OP_AltCurrencySell),
|
||||
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
|
||||
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
|
||||
N(OP_Animation),
|
||||
N(OP_AnnoyingZoneUnknown),
|
||||
N(OP_ApplyPoison),
|
||||
@@ -77,6 +77,7 @@ N(OP_CashReward),
|
||||
N(OP_CastSpell),
|
||||
N(OP_ChangeSize),
|
||||
N(OP_ChannelMessage),
|
||||
N(OP_ChangePetName),
|
||||
N(OP_CharacterCreate),
|
||||
N(OP_CharacterCreateRequest),
|
||||
N(OP_CharInventory),
|
||||
@@ -162,6 +163,7 @@ N(OP_EnduranceUpdate),
|
||||
N(OP_EnterChat),
|
||||
N(OP_EnterWorld),
|
||||
N(OP_EnvDamage),
|
||||
N(OP_EvolveItem),
|
||||
N(OP_ExpansionInfo),
|
||||
N(OP_ExpUpdate),
|
||||
N(OP_FaceChange),
|
||||
@@ -283,12 +285,15 @@ N(OP_InspectMessageUpdate),
|
||||
N(OP_InspectRequest),
|
||||
N(OP_InstillDoubt),
|
||||
N(OP_InterruptCast),
|
||||
N(OP_InvokeChangePetName),
|
||||
N(OP_InvokeChangePetNameImmediate),
|
||||
N(OP_ItemLinkClick),
|
||||
N(OP_ItemLinkResponse),
|
||||
N(OP_ItemLinkText),
|
||||
N(OP_ItemName),
|
||||
N(OP_ItemPacket),
|
||||
N(OP_ItemPreview),
|
||||
N(OP_ItemPreviewRequest),
|
||||
N(OP_ItemRecastDelay),
|
||||
N(OP_ItemVerifyReply),
|
||||
N(OP_ItemVerifyRequest),
|
||||
@@ -400,6 +405,8 @@ N(OP_PetitionSearchText),
|
||||
N(OP_PetitionUnCheckout),
|
||||
N(OP_PetitionUpdate),
|
||||
N(OP_PickPocket),
|
||||
N(OP_PickZone),
|
||||
N(OP_PickZoneWindow),
|
||||
N(OP_PlayerProfile),
|
||||
N(OP_PlayerStateAdd),
|
||||
N(OP_PlayerStateRemove),
|
||||
@@ -514,7 +521,7 @@ N(OP_ShopPlayerSell),
|
||||
N(OP_ShopSendParcel),
|
||||
N(OP_ShopDeleteParcel),
|
||||
N(OP_ShopRespondParcel),
|
||||
N(OP_ShopRetrieveParcel),
|
||||
N(OP_ShopRetrieveParcel),
|
||||
N(OP_ShopParcelIcon),
|
||||
N(OP_ShopRequest),
|
||||
N(OP_SimpleMessage),
|
||||
|
||||
@@ -1114,4 +1114,5 @@ enum ExpSource
|
||||
namespace DoorType {
|
||||
constexpr uint32 BuyerStall = 155;
|
||||
}
|
||||
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
+14
-6
@@ -47,6 +47,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
ClientUnknown::constants::EXPANSION_BIT,
|
||||
ClientUnknown::constants::EXPANSIONS_MASK,
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL
|
||||
),
|
||||
/*[ClientVersion::Client62] =*/
|
||||
@@ -55,6 +56,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
Client62::constants::EXPANSION_BIT,
|
||||
Client62::constants::EXPANSIONS_MASK,
|
||||
Client62::INULL,
|
||||
Client62::INULL,
|
||||
Client62::INULL
|
||||
),
|
||||
/*[ClientVersion::Titanium] =*/
|
||||
@@ -63,7 +65,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
Titanium::constants::EXPANSION_BIT,
|
||||
Titanium::constants::EXPANSIONS_MASK,
|
||||
Titanium::constants::CHARACTER_CREATION_LIMIT,
|
||||
Titanium::constants::SAY_LINK_BODY_SIZE
|
||||
Titanium::constants::SAY_LINK_BODY_SIZE,
|
||||
Titanium::INULL
|
||||
),
|
||||
/*[ClientVersion::SoF] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
@@ -71,7 +74,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
SoF::constants::EXPANSION_BIT,
|
||||
SoF::constants::EXPANSIONS_MASK,
|
||||
SoF::constants::CHARACTER_CREATION_LIMIT,
|
||||
SoF::constants::SAY_LINK_BODY_SIZE
|
||||
SoF::constants::SAY_LINK_BODY_SIZE,
|
||||
SoF::INULL
|
||||
),
|
||||
/*[ClientVersion::SoD] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
@@ -79,7 +83,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
SoD::constants::EXPANSION_BIT,
|
||||
SoD::constants::EXPANSIONS_MASK,
|
||||
SoD::constants::CHARACTER_CREATION_LIMIT,
|
||||
SoD::constants::SAY_LINK_BODY_SIZE
|
||||
SoD::constants::SAY_LINK_BODY_SIZE,
|
||||
SoD::INULL
|
||||
),
|
||||
/*[ClientVersion::UF] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
@@ -87,7 +92,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
UF::constants::EXPANSION_BIT,
|
||||
UF::constants::EXPANSIONS_MASK,
|
||||
UF::constants::CHARACTER_CREATION_LIMIT,
|
||||
UF::constants::SAY_LINK_BODY_SIZE
|
||||
UF::constants::SAY_LINK_BODY_SIZE,
|
||||
UF::INULL
|
||||
),
|
||||
/*[ClientVersion::RoF] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
@@ -95,7 +101,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
RoF::constants::EXPANSION_BIT,
|
||||
RoF::constants::EXPANSIONS_MASK,
|
||||
RoF::constants::CHARACTER_CREATION_LIMIT,
|
||||
RoF::constants::SAY_LINK_BODY_SIZE
|
||||
RoF::constants::SAY_LINK_BODY_SIZE,
|
||||
RoF::INULL
|
||||
),
|
||||
/*[ClientVersion::RoF2] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
@@ -103,7 +110,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
RoF2::constants::EXPANSION_BIT,
|
||||
RoF2::constants::EXPANSIONS_MASK,
|
||||
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
||||
RoF2::constants::SAY_LINK_BODY_SIZE
|
||||
RoF2::constants::SAY_LINK_BODY_SIZE,
|
||||
RoF2::constants::MAX_BAZAAR_TRADERS
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
+5
-2
@@ -42,6 +42,7 @@ namespace EQ
|
||||
uint32 ExpansionsMask;
|
||||
int16 CharacterCreationLimit;
|
||||
size_t SayLinkBodySize;
|
||||
uint32 BazaarTraderLimit;
|
||||
|
||||
LookupEntry(const LookupEntry *lookup_entry) { }
|
||||
LookupEntry(
|
||||
@@ -49,13 +50,15 @@ namespace EQ
|
||||
uint32 ExpansionBit,
|
||||
uint32 ExpansionsMask,
|
||||
int16 CharacterCreationLimit,
|
||||
size_t SayLinkBodySize
|
||||
size_t SayLinkBodySize,
|
||||
uint32 BazaarTraderLimit
|
||||
) :
|
||||
Expansion(Expansion),
|
||||
ExpansionBit(ExpansionBit),
|
||||
ExpansionsMask(ExpansionsMask),
|
||||
CharacterCreationLimit(CharacterCreationLimit),
|
||||
SayLinkBodySize(SayLinkBodySize)
|
||||
SayLinkBodySize(SayLinkBodySize),
|
||||
BazaarTraderLimit(BazaarTraderLimit)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -5819,6 +5819,21 @@ struct ChangeSize_Struct
|
||||
/*16*/
|
||||
};
|
||||
|
||||
struct ChangePetName_Struct {
|
||||
/*00*/ char new_pet_name[64];
|
||||
/*40*/ char pet_owner_name[64];
|
||||
/*80*/ int response_code;
|
||||
};
|
||||
|
||||
enum ChangePetNameResponse : int {
|
||||
Denied = 0, // 5167 You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name.
|
||||
Accepted = 1, // 5976 Your request for a name change was successful.
|
||||
Timeout = -3, // 5979 You must wait longer before submitting another name request. Please try again in a few minutes.
|
||||
NotEligible = -4, // 5980 Your character is not eligible for a name change.
|
||||
Pending = -5, // 5193 You already have a name change pending. Please wait until it is fully processed before attempting another name change.
|
||||
Unhandled = -1
|
||||
};
|
||||
|
||||
// New OpCode/Struct for SoD+
|
||||
struct GroupMakeLeader_Struct
|
||||
{
|
||||
@@ -6440,6 +6455,90 @@ struct BuylineItemDetails_Struct {
|
||||
uint32 item_quantity;
|
||||
};
|
||||
|
||||
struct PickZoneEntry_Struct {
|
||||
int16 zone_id;
|
||||
int16 unknown;
|
||||
int32 player_count;
|
||||
int32 instance_id;
|
||||
};
|
||||
|
||||
struct PickZoneWindow_Struct {
|
||||
char padding000[64];
|
||||
int64 session_id;
|
||||
int8 option_count;
|
||||
char padding073[23];
|
||||
PickZoneEntry_Struct entries[10];
|
||||
};
|
||||
|
||||
struct PickZone_Struct {
|
||||
int64 session_id;
|
||||
int32 selection_id;
|
||||
};
|
||||
|
||||
struct EvolveItemToggle {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint64 unique_id;
|
||||
uint32 percentage;
|
||||
uint32 activated;
|
||||
};
|
||||
|
||||
struct EvolveXPWindowReceive {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint64 item1_unique_id;
|
||||
uint64 item2_unique_id;
|
||||
};
|
||||
|
||||
struct EvolveItemMessaging {
|
||||
uint32 action;
|
||||
char serialized_data[];
|
||||
};
|
||||
|
||||
struct EvolveXPWindowSend {
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint64 item1_unique_id;
|
||||
/*012*/ uint64 item2_unique_id;
|
||||
/*020*/ uint32 compatibility;
|
||||
/*024*/ uint32 max_transfer_level;
|
||||
/*028*/ uint8 item1_present;
|
||||
/*029*/ uint8 item2_present;
|
||||
/*030*/ std::string serialize_item_1;
|
||||
/*034*/ std::string serialize_item_2;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(item1_unique_id),
|
||||
CEREAL_NVP(item2_unique_id),
|
||||
CEREAL_NVP(compatibility),
|
||||
CEREAL_NVP(max_transfer_level),
|
||||
CEREAL_NVP(item1_present),
|
||||
CEREAL_NVP(item2_present),
|
||||
CEREAL_NVP(serialize_item_1),
|
||||
CEREAL_NVP(serialize_item_2)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct EvolveTransfer {
|
||||
uint32 item_from_id;
|
||||
uint32 item_from_current_amount;
|
||||
uint32 item_to_id;
|
||||
uint32 item_to_current_amount;
|
||||
uint32 compatibility;
|
||||
uint32 max_transfer_level;
|
||||
};
|
||||
|
||||
struct EvolveGetNextItem {
|
||||
uint32 new_item_id;
|
||||
uint64 new_current_amount;
|
||||
uint64 from_current_amount;
|
||||
uint32 max_transfer_level;
|
||||
};
|
||||
|
||||
// Restore structure packing to default
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@@ -142,6 +142,9 @@ namespace Logs {
|
||||
EqTime,
|
||||
Corpses,
|
||||
XTargets,
|
||||
EvolveItem,
|
||||
PositionUpdate,
|
||||
KSM,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@@ -242,7 +245,10 @@ namespace Logs {
|
||||
"Zoning",
|
||||
"EqTime",
|
||||
"Corpses",
|
||||
"XTargets"
|
||||
"XTargets",
|
||||
"EvolveItem",
|
||||
"PositionUpdate",
|
||||
"KSM" // Kernel Samepage Merging
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,16 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogEvolveItem(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::General, Logs::EvolveItem))\
|
||||
OutF(LogSys, Logs::General, Logs::EvolveItem, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogEvolveItemDetail(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::Detail, Logs::EvolveItem))\
|
||||
OutF(LogSys, Logs::Detail, Logs::EvolveItem, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGuilds(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::General, Logs::Guilds))\
|
||||
OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
@@ -844,6 +854,26 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPositionUpdate(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::General, Logs::PositionUpdate))\
|
||||
OutF(LogSys, Logs::General, Logs::PositionUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPositionUpdateDetail(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PositionUpdate))\
|
||||
OutF(LogSys, Logs::Detail, Logs::PositionUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define LogKSM(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::General, Logs::KSM))\
|
||||
OutF(LogSys, Logs::General, Logs::KSM, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogKSMDetail(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::Detail, Logs::KSM))\
|
||||
OutF(LogSys, Logs::Detail, Logs::KSM, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(debug_level, log_category))\
|
||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
|
||||
@@ -707,6 +707,7 @@ void PlayerEventLogs::SetSettingsDefaults()
|
||||
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
|
||||
m_settings[PlayerEvent::EVOLVE_ITEM].event_enabled = 1;
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace PlayerEvent {
|
||||
PARCEL_RETRIEVE,
|
||||
PARCEL_DELETE,
|
||||
BARTER_TRANSACTION,
|
||||
EVOLVE_ITEM,
|
||||
MAX // dont remove
|
||||
};
|
||||
|
||||
@@ -124,7 +125,8 @@ namespace PlayerEvent {
|
||||
"Parcel Item Sent",
|
||||
"Parcel Item Retrieved",
|
||||
"Parcel Prune Routine",
|
||||
"Barter Transaction"
|
||||
"Barter Transaction",
|
||||
"Evolve Item Update"
|
||||
};
|
||||
|
||||
// Generic struct used by all events
|
||||
@@ -1115,6 +1117,29 @@ namespace PlayerEvent {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct EvolveItem {
|
||||
std::string status;
|
||||
uint32 item_id;
|
||||
uint64 unique_id;
|
||||
std::string item_name;
|
||||
uint32 level;
|
||||
double progression;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(status),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(unique_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(level),
|
||||
CEREAL_NVP(progression)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //EQEMU_PLAYER_EVENTS_H
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
#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();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef EVOLVING_H
|
||||
#define EVOLVING_H
|
||||
|
||||
#include "shareddb.h"
|
||||
#include "events/player_events.h"
|
||||
#include "repositories/items_evolving_details_repository.h"
|
||||
|
||||
namespace EQ {
|
||||
class ItemInstance;
|
||||
}
|
||||
|
||||
namespace EvolvingItems {
|
||||
namespace Actions {
|
||||
constexpr int8 UPDATE_ITEMS = 0;
|
||||
constexpr int8 TRANSFER_WINDOW_OPEN = 1;
|
||||
constexpr int8 TRANSFER_WINDOW_DETAILS = 2;
|
||||
constexpr int8 TRANSFER_XP = 3;
|
||||
constexpr int8 FINAL_RESULT = 4;
|
||||
}
|
||||
|
||||
namespace Types {
|
||||
constexpr int8 AMOUNT_OF_EXP = 1;
|
||||
constexpr int8 NUMBER_OF_KILLS = 2;
|
||||
constexpr int8 SPECIFIC_MOB_RACE = 3;
|
||||
constexpr int8 SPECIFIC_ZONE_ID = 4;
|
||||
}
|
||||
|
||||
namespace SubTypes {
|
||||
constexpr int8 ALL_EXP = 0;
|
||||
constexpr int8 SOLO_EXP = 1;
|
||||
constexpr int8 GROUP_EXP = 2;
|
||||
constexpr int8 RAID_EXP = 3;
|
||||
}
|
||||
}
|
||||
|
||||
class EvolvingItemsManager
|
||||
{
|
||||
public:
|
||||
EvolvingItemsManager();
|
||||
void SetDatabase(Database *db);
|
||||
void SetContentDatabase(Database *db);
|
||||
|
||||
void LoadEvolvingItems() const;
|
||||
void DoLootChecks(uint32 char_id, uint16 slot_id, const EQ::ItemInstance &inst) const;
|
||||
uint32 GetFinalItemID(const EQ::ItemInstance &inst) const;
|
||||
uint32 GetNextEvolveItemID(const EQ::ItemInstance &inst) const;
|
||||
uint32 GetFirstItemInLoreGroup(uint32 lore_id);
|
||||
uint32 GetFirstItemInLoreGroupByItemID(uint32 item_id);
|
||||
uint64 GetTotalEarnedXP(const EQ::ItemInstance &inst);
|
||||
static double CalculateProgression(uint64 current_amount, uint32 item_id);
|
||||
static void LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e);
|
||||
|
||||
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails GetEvolveItemDetails(uint64 id);
|
||||
EvolveTransfer DetermineTransferResults(const EQ::ItemInstance& inst_from, const EQ::ItemInstance& inst_to);
|
||||
EvolveGetNextItem GetNextItemByXP(const EQ::ItemInstance &inst_in, int64 in_xp);
|
||||
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails>& GetEvolvingItemsCache() { return evolving_items_cache; }
|
||||
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> GetEvolveIDItems(uint32 evolve_id);
|
||||
|
||||
private:
|
||||
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> evolving_items_cache;
|
||||
Database * m_db;
|
||||
Database * m_content_db;
|
||||
};
|
||||
|
||||
extern EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
#endif //EVOLVING_H
|
||||
@@ -344,6 +344,8 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
|
||||
source_item_instance->SetEvolveEquipped(false);
|
||||
if ((destination_slot >= invslot::EQUIPMENT_BEGIN && destination_slot <= invslot::EQUIPMENT_END)) {
|
||||
auto source_item = source_item_instance->GetItem();
|
||||
if (!source_item) {
|
||||
@@ -362,6 +364,9 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapLevel;
|
||||
return false;
|
||||
}
|
||||
if (source_item_instance->IsEvolving() > 0) {
|
||||
source_item_instance->SetEvolveEquipped(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +375,8 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
|
||||
destination_item_instance->SetEvolveEquipped(false);
|
||||
if ((source_slot >= invslot::EQUIPMENT_BEGIN && source_slot <= invslot::EQUIPMENT_END)) {
|
||||
auto destination_item = destination_item_instance->GetItem();
|
||||
if (!destination_item) {
|
||||
@@ -388,6 +395,9 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapLevel;
|
||||
return false;
|
||||
}
|
||||
if (destination_item_instance->IsEvolving()) {
|
||||
destination_item_instance->SetEvolveEquipped(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1402,6 +1412,8 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
|
||||
int16 result = INVALID_INDEX;
|
||||
int16 parentSlot = INVALID_INDEX;
|
||||
|
||||
inst->SetEvolveEquipped(false);
|
||||
|
||||
if (slot_id == invslot::slotCursor) {
|
||||
// Replace current item on cursor, if exists
|
||||
m_cursor.pop(); // no memory delete, clients of this function know what they are doing
|
||||
@@ -1410,6 +1422,9 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
|
||||
}
|
||||
else if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
|
||||
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) != 0) {
|
||||
if (inst->IsEvolving()) {
|
||||
inst->SetEvolveEquipped(true);
|
||||
}
|
||||
m_worn[slot_id] = inst;
|
||||
result = slot_id;
|
||||
}
|
||||
@@ -1808,3 +1823,182 @@ int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItem(const EQ::ItemData *it
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//This function has the same flaw as noted above
|
||||
// Helper functions for evolving items
|
||||
int16 EQ::InventoryProfile::HasEvolvingItem(uint64 evolve_unique_id, uint8 quantity, uint8 where)
|
||||
{
|
||||
int16 slot_id = INVALID_INDEX;
|
||||
|
||||
// Altered by Father Nitwit to support a specification of
|
||||
// where to search, with a default value to maintain compatibility
|
||||
|
||||
// Check each inventory bucket
|
||||
if (where & invWhereWorn) {
|
||||
slot_id = _HasEvolvingItem(m_worn, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (where & invWherePersonal) {
|
||||
slot_id = _HasEvolvingItem(m_inv, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (where & invWhereBank) {
|
||||
slot_id = _HasEvolvingItem(m_bank, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (where & invWhereSharedBank) {
|
||||
slot_id = _HasEvolvingItem(m_shbank, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (where & invWhereTrading) {
|
||||
slot_id = _HasEvolvingItem(m_trade, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||
if (where & invWhereCursor) {
|
||||
// Check cursor queue
|
||||
slot_id = _HasEvolvingItem(m_cursor, evolve_unique_id, quantity);
|
||||
if (slot_id != INVALID_INDEX) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
// Internal Method: Checks an inventory bucket for a particular evolving item unique id
|
||||
int16 EQ::InventoryProfile::_HasEvolvingItem(
|
||||
std::map<int16, ItemInstance *> &bucket, uint64 evolve_unique_id, uint8 quantity)
|
||||
{
|
||||
uint32 quantity_found = 0;
|
||||
|
||||
for (auto const &[key, value]: bucket) {
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key <= EQ::invslot::POSSESSIONS_END && key >= EQ::invslot::POSSESSIONS_BEGIN) {
|
||||
if (((uint64) 1 << key & m_lookup->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (key <= EQ::invslot::BANK_END && key >= EQ::invslot::BANK_BEGIN) {
|
||||
if (key - EQ::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize.Bank) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (value->GetEvolveUniqueID() == evolve_unique_id) {
|
||||
quantity_found += value->GetCharges() <= 0 ? 1 : value->GetCharges();
|
||||
if (quantity_found >= quantity) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value->IsClassBag()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto const &[bag_key, bag_value]: *value->GetContents()) {
|
||||
if (!bag_value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bag_value->GetEvolveUniqueID() == evolve_unique_id) {
|
||||
quantity_found += bag_value->GetCharges() <= 0 ? 1 : bag_value->GetCharges();
|
||||
if (quantity_found >= quantity) {
|
||||
return CalcSlotId(key, bag_key);
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (bag_value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
// Internal Method: Checks an inventory queue type bucket for a particular item
|
||||
int16 EQ::InventoryProfile::_HasEvolvingItem(ItemInstQueue &iqueue, uint64 evolve_unique_id, uint8 quantity)
|
||||
{
|
||||
// The downfall of this (these) queue procedure is that callers presume that when an item is
|
||||
// found, it is presented as being available on the cursor. In cases of a parity check, this
|
||||
// is sufficient. However, in cases where referential criteria is considered, this can lead
|
||||
// to unintended results. Funtionality should be observed when referencing the return value
|
||||
// of this query
|
||||
|
||||
uint32 quantity_found = 0;
|
||||
|
||||
for (auto const &inst: iqueue) {
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst->GetEvolveUniqueID() == evolve_unique_id) {
|
||||
quantity_found += inst->GetCharges() <= 0 ? 1 : inst->GetCharges();
|
||||
if (quantity_found >= quantity) {
|
||||
return invslot::slotCursor;
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (inst->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inst->IsClassBag()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto const &[bag_key, bag_value]: *inst->GetContents()) {
|
||||
if (!bag_value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bag_value->GetEvolveUniqueID() == evolve_unique_id) {
|
||||
quantity_found += bag_value->GetCharges() <= 0 ? 1 : bag_value->GetCharges();
|
||||
if (quantity_found >= quantity) {
|
||||
return CalcSlotId(invslot::slotCursor, bag_key);
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (bag_value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||
break;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
|
||||
inline std::list<EQ::ItemInstance*>::const_iterator cbegin() { return m_list.cbegin(); }
|
||||
inline std::list<EQ::ItemInstance*>::const_iterator cend() { return m_list.cend(); }
|
||||
inline std::list<EQ::ItemInstance*>::iterator begin() { return m_list.begin(); }
|
||||
inline std::list<EQ::ItemInstance*>::iterator end() { return m_list.end(); }
|
||||
|
||||
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
|
||||
inline bool empty() { return m_list.empty(); }
|
||||
@@ -211,6 +213,13 @@ namespace EQ
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
|
||||
std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
|
||||
static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
|
||||
|
||||
std::map<int16, ItemInstance*>& GetWorn() { return m_worn; }
|
||||
std::map<int16, ItemInstance*>& GetPersonal() { return m_inv; }
|
||||
int16 HasEvolvingItem(uint64 evolve_unique_id, uint8 quantity, uint8 where);
|
||||
|
||||
inline int16 PushItem(int16 slot_id, ItemInstance* inst) { return _PutItem(slot_id, inst); }
|
||||
|
||||
protected:
|
||||
///////////////////////////////
|
||||
// Protected Methods
|
||||
@@ -233,6 +242,8 @@ namespace EQ
|
||||
int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);
|
||||
int16 _HasItemByLoreGroup(std::map<int16, ItemInstance*>& bucket, uint32 loregroup);
|
||||
int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup);
|
||||
int16 _HasEvolvingItem(std::map<int16, ItemInstance*>& bucket, uint64 evolve_unique_id, uint8 quantity);
|
||||
int16 _HasEvolvingItem(ItemInstQueue& iqueue, uint64 evolve_unique_id, uint8 quantity);
|
||||
|
||||
|
||||
// Player inventory
|
||||
|
||||
+56
-51
@@ -25,6 +25,7 @@
|
||||
#include "rulesys.h"
|
||||
#include "shareddb.h"
|
||||
#include "strings.h"
|
||||
#include "evolving_items.h"
|
||||
|
||||
//#include "../common/light_source.h"
|
||||
|
||||
@@ -76,6 +77,10 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
||||
m_color = m_item->Color;
|
||||
}
|
||||
|
||||
if (IsEvolving()) {
|
||||
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
||||
}
|
||||
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
}
|
||||
|
||||
@@ -95,6 +100,10 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
|
||||
m_color = 0;
|
||||
}
|
||||
|
||||
if (IsEvolving()) {
|
||||
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
||||
}
|
||||
|
||||
m_SerialNumber = GetNextItemInstSerialNumber();
|
||||
}
|
||||
|
||||
@@ -146,7 +155,6 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
||||
|
||||
m_exp = copy.m_exp;
|
||||
m_evolveLvl = copy.m_evolveLvl;
|
||||
m_activated = copy.m_activated;
|
||||
|
||||
if (copy.m_scaledItem) {
|
||||
m_scaledItem = new ItemData(*copy.m_scaledItem);
|
||||
@@ -154,12 +162,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
||||
m_scaledItem = nullptr;
|
||||
}
|
||||
|
||||
if (copy.m_evolveInfo) {
|
||||
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
|
||||
} else {
|
||||
m_evolveInfo = nullptr;
|
||||
}
|
||||
|
||||
m_evolving_details = copy.m_evolving_details;
|
||||
m_scaling = copy.m_scaling;
|
||||
m_ornamenticon = copy.m_ornamenticon;
|
||||
m_ornamentidfile = copy.m_ornamentidfile;
|
||||
@@ -174,7 +177,6 @@ EQ::ItemInstance::~ItemInstance()
|
||||
Clear();
|
||||
safe_delete(m_item);
|
||||
safe_delete(m_scaledItem);
|
||||
safe_delete(m_evolveInfo);
|
||||
}
|
||||
|
||||
// Query item type
|
||||
@@ -1030,29 +1032,6 @@ void EQ::ItemInstance::ScaleItem() {
|
||||
m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself.
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::EvolveOnAllKills() const {
|
||||
return (m_evolveInfo && m_evolveInfo->AllKills);
|
||||
}
|
||||
|
||||
int8 EQ::ItemInstance::GetMaxEvolveLvl() const {
|
||||
if (m_evolveInfo)
|
||||
return m_evolveInfo->MaxLvl;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 EQ::ItemInstance::GetKillsNeeded(uint8 currentlevel) {
|
||||
uint32 kills = -1; // default to -1 (max uint32 value) because this value is usually divided by, so we don't want to ever return zero.
|
||||
if (m_evolveInfo)
|
||||
if (currentlevel != m_evolveInfo->MaxLvl)
|
||||
kills = m_evolveInfo->LvlKills[currentlevel - 1];
|
||||
|
||||
if (kills == 0)
|
||||
kills = -1;
|
||||
|
||||
return kills;
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) {
|
||||
Timer t(time);
|
||||
t.Start(time, false);
|
||||
@@ -1951,28 +1930,54 @@ void EQ::ItemInstance::ClearGUIDMap()
|
||||
{
|
||||
guids.clear();
|
||||
}
|
||||
//
|
||||
// class EvolveInfo
|
||||
//
|
||||
EvolveInfo::EvolveInfo() {
|
||||
// nothing here yet
|
||||
|
||||
bool EQ::ItemInstance::TransferOwnership(Database &db, const uint32 to_char_id) const
|
||||
{
|
||||
if (!to_char_id || !IsEvolving()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetEvolveCharID(to_char_id);
|
||||
CharacterEvolvingItemsRepository::UpdateCharID(db, GetEvolveUniqueID(), to_char_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10) {
|
||||
FirstItem = first;
|
||||
MaxLvl = max;
|
||||
AllKills = allkills;
|
||||
LvlKills[0] = L2;
|
||||
LvlKills[1] = L3;
|
||||
LvlKills[2] = L4;
|
||||
LvlKills[3] = L5;
|
||||
LvlKills[4] = L6;
|
||||
LvlKills[5] = L7;
|
||||
LvlKills[6] = L8;
|
||||
LvlKills[7] = L9;
|
||||
LvlKills[8] = L10;
|
||||
uint32 EQ::ItemInstance::GetAugmentEvolveUniqueID(uint8 augment_index) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto item = GetItem(augment_index);
|
||||
if (item) {
|
||||
return item->GetEvolveUniqueID();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EvolveInfo::~EvolveInfo() {
|
||||
|
||||
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) const{
|
||||
Timer t(time);
|
||||
t.Start(time, false);
|
||||
m_timers[name] = t;
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
|
||||
{
|
||||
if (!IsEvolving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_evolving_details.equipped = in;
|
||||
if (in && !GetTimers().contains("evolve")) {
|
||||
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
||||
return;
|
||||
}
|
||||
|
||||
if (in) {
|
||||
GetTimers().at("evolve").SetTimer(RuleI(EvolvingItems, DelayUponEquipping));
|
||||
return;
|
||||
}
|
||||
|
||||
GetTimers().at("evolve").Disable();
|
||||
}
|
||||
|
||||
+56
-48
@@ -23,6 +23,7 @@
|
||||
|
||||
#ifndef COMMON_ITEM_INSTANCE_H
|
||||
#define COMMON_ITEM_INSTANCE_H
|
||||
#include "evolving_items.h"
|
||||
|
||||
|
||||
class ItemParse; // Parses item packets
|
||||
@@ -34,6 +35,7 @@ class EvolveInfo; // Stores information about an evolving item family
|
||||
#include "../common/bodytypes.h"
|
||||
#include "../common/deity.h"
|
||||
#include "../common/memory_buffer.h"
|
||||
#include "../common/repositories/character_evolving_items_repository.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -205,13 +207,9 @@ namespace EQ
|
||||
bool IsDroppable(bool recurse = true) const;
|
||||
|
||||
bool IsScaling() const { return m_scaling; }
|
||||
bool IsEvolving() const { return (m_evolveLvl >= 1); }
|
||||
uint32 GetExp() const { return m_exp; }
|
||||
void SetExp(uint32 exp) { m_exp = exp; }
|
||||
void AddExp(uint32 exp) { m_exp += exp; }
|
||||
bool IsActivated() { return m_activated; }
|
||||
void SetActivated(bool activated) { m_activated = activated; }
|
||||
int8 GetEvolveLvl() const { return m_evolveLvl; }
|
||||
void SetScaling(bool v) { m_scaling = v; }
|
||||
uint32 GetOrnamentationIcon() const { return m_ornamenticon; }
|
||||
void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; }
|
||||
@@ -226,9 +224,6 @@ namespace EQ
|
||||
|
||||
void Initialize(SharedDatabase *db = nullptr);
|
||||
void ScaleItem();
|
||||
bool EvolveOnAllKills() const;
|
||||
int8 GetMaxEvolveLvl() const;
|
||||
uint32 GetKillsNeeded(uint8 currentlevel);
|
||||
|
||||
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; }
|
||||
void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); }
|
||||
@@ -236,8 +231,9 @@ namespace EQ
|
||||
inline int32 GetSerialNumber() const { return m_SerialNumber; }
|
||||
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
|
||||
|
||||
std::map<std::string, ::Timer>& GetTimers() { return m_timers; }
|
||||
std::map<std::string, ::Timer>& GetTimers() const { return m_timers; }
|
||||
void SetTimer(std::string name, uint32 time);
|
||||
void SetTimer(std::string name, uint32 time) const;
|
||||
void StopTimer(std::string name);
|
||||
void ClearTimers();
|
||||
|
||||
@@ -312,6 +308,34 @@ namespace EQ
|
||||
static void AddGUIDToMap(uint64 existing_serial_number);
|
||||
static void ClearGUIDMap();
|
||||
|
||||
// evolving items stuff
|
||||
CharacterEvolvingItemsRepository::CharacterEvolvingItems &GetEvolvingDetails() const { return m_evolving_details; }
|
||||
|
||||
int8 GetEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingLevel; } return false; }
|
||||
bool IsEvolving() const { if (GetItem()) { return GetItem()->EvolvingItem; } return false; }
|
||||
int8 GetMaxEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingMax; } return false; }
|
||||
bool GetEvolveActivated() const { return m_evolving_details.activated ? true : false; }
|
||||
bool GetEvolveEquipped() const { return m_evolving_details.equipped ? true : false; }
|
||||
double GetEvolveProgression() const { return m_evolving_details.progression; }
|
||||
uint64 GetEvolveUniqueID() const { return m_evolving_details.id; }
|
||||
uint32 GetEvolveCharID() const { return m_evolving_details.character_id; }
|
||||
uint32 GetEvolveItemID() const { return m_evolving_details.item_id; }
|
||||
uint32 GetEvolveLoreID() const { if (GetItem()) { return GetItem()->EvolvingID; } return false; }
|
||||
uint64 GetEvolveCurrentAmount() const { return m_evolving_details.current_amount; }
|
||||
uint32 GetEvolveFinalItemID() const { return m_evolving_details.final_item_id; }
|
||||
uint32 GetAugmentEvolveUniqueID(uint8 augment_index) const;
|
||||
void SetEvolveEquipped(const bool in) const;
|
||||
void SetEvolveActivated(const bool in) const { m_evolving_details.activated = in; }
|
||||
void SetEvolveProgression(const double in) const { m_evolving_details.progression = in; }
|
||||
void SetEvolveUniqueID(const uint64 in) const { m_evolving_details.id = in; }
|
||||
void SetEvolveCharID(const uint32 in) const { m_evolving_details.character_id = in; }
|
||||
void SetEvolveItemID(const uint32 in) const { m_evolving_details.item_id = in; }
|
||||
void SetEvolveCurrentAmount(const uint64 in) const { m_evolving_details.current_amount = in; }
|
||||
void SetEvolveAddToCurrentAmount(const uint64 in) const { m_evolving_details.current_amount += in; }
|
||||
void SetEvolveFinalItemID(const uint32 in) const { m_evolving_details.final_item_id = in; }
|
||||
bool TransferOwnership(Database& db, const uint32 to_char_id) const;
|
||||
void CalculateEvolveProgression() const { m_evolving_details.progression = evolving_items_manager.CalculateProgression(GetEvolveCurrentAmount(), GetID()); }
|
||||
|
||||
protected:
|
||||
//////////////////////////
|
||||
// Protected Members
|
||||
@@ -323,48 +347,32 @@ namespace EQ
|
||||
|
||||
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
|
||||
|
||||
ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item
|
||||
const ItemData* m_item {nullptr}; // Ptr to item data
|
||||
int16 m_charges {0}; // # of charges for chargeable items
|
||||
uint32 m_price {0}; // Bazaar /trader price
|
||||
uint32 m_color {0};
|
||||
uint32 m_merchantslot {0};
|
||||
int16 m_currentslot {0};
|
||||
bool m_attuned {false};
|
||||
int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited
|
||||
int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar.
|
||||
uint32 m_exp {0};
|
||||
int8 m_evolveLvl {0};
|
||||
bool m_activated {false};
|
||||
ItemData* m_scaledItem {nullptr};
|
||||
::EvolveInfo* m_evolveInfo {nullptr};
|
||||
bool m_scaling {false};
|
||||
uint32 m_ornamenticon {0};
|
||||
uint32 m_ornamentidfile {0};
|
||||
uint32 m_new_id_file {0};
|
||||
uint32 m_ornament_hero_model {0};
|
||||
uint32 m_recast_timestamp {0};
|
||||
int m_task_delivered_count {0};
|
||||
ItemInstTypes m_use_type{ItemInstNormal};// Usage type for item
|
||||
const ItemData * m_item{nullptr}; // Ptr to item data
|
||||
int16 m_charges{0}; // # of charges for chargeable items
|
||||
uint32 m_price{0}; // Bazaar /trader price
|
||||
uint32 m_color{0};
|
||||
uint32 m_merchantslot{0};
|
||||
int16 m_currentslot{0};
|
||||
bool m_attuned{false};
|
||||
int32 m_merchantcount{1};//number avaliable on the merchant, -1=unlimited
|
||||
int32 m_SerialNumber{0}; // Unique identifier for this instance of an item. Needed for Bazaar.
|
||||
uint32 m_exp{0};
|
||||
int8 m_evolveLvl{0};
|
||||
ItemData * m_scaledItem{nullptr};
|
||||
bool m_scaling{false};
|
||||
uint32 m_ornamenticon{0};
|
||||
uint32 m_ornamentidfile{0};
|
||||
uint32 m_new_id_file{0};
|
||||
uint32 m_ornament_hero_model{0};
|
||||
uint32 m_recast_timestamp{0};
|
||||
int m_task_delivered_count{0};
|
||||
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{};
|
||||
|
||||
// Items inside of this item (augs or contents) {};
|
||||
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
|
||||
std::map<std::string, std::string> m_custom_data {};
|
||||
std::map<std::string, ::Timer> m_timers {};
|
||||
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
|
||||
std::map<std::string, std::string> m_custom_data {};
|
||||
mutable std::map<std::string, ::Timer> m_timers {};
|
||||
};
|
||||
}
|
||||
|
||||
class EvolveInfo {
|
||||
public:
|
||||
friend class EQ::ItemInstance;
|
||||
//temporary
|
||||
uint16 LvlKills[9];
|
||||
uint32 FirstItem;
|
||||
uint8 MaxLvl;
|
||||
bool AllKills;
|
||||
|
||||
EvolveInfo();
|
||||
EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
|
||||
~EvolveInfo();
|
||||
};
|
||||
|
||||
#endif /*COMMON_ITEM_INSTANCE_H*/
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
#ifndef EQEMU_KSM_HPP
|
||||
#define EQEMU_KSM_HPP
|
||||
|
||||
#include "../eqemu_logsys.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h> // For _aligned_malloc, _aligned_free
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h> // For madvise
|
||||
#include <unistd.h> // For sysconf, sbrk
|
||||
#endif
|
||||
|
||||
|
||||
// Page-aligned allocator for std::vector
|
||||
template <typename T>
|
||||
class PageAlignedAllocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
PageAlignedAllocator() noexcept = default;
|
||||
template <typename U>
|
||||
PageAlignedAllocator(const PageAlignedAllocator<U>&) noexcept {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
void* ptr = nullptr;
|
||||
size_t size = n * sizeof(T);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Simply allocate memory without alignment
|
||||
ptr = malloc(size);
|
||||
if (!ptr) throw std::bad_alloc();
|
||||
#else
|
||||
size_t alignment = getPageSize(); // Get the system's page size
|
||||
if (posix_memalign(&ptr, alignment, size) != 0) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
return static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) noexcept {
|
||||
free(p);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t getPageSize() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return sysInfo.dwPageSize; // Page size in bytes
|
||||
#else
|
||||
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Kernel Samepage Merging (KSM) functionality
|
||||
namespace KSM {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows-specific placeholder functions (no-op)
|
||||
inline void CheckPageAlignment(void* ptr) {
|
||||
}
|
||||
|
||||
inline void* AllocatePageAligned(size_t size) {
|
||||
return memset(malloc(size), 0, size);
|
||||
}
|
||||
|
||||
inline void MarkMemoryForKSM(void* start, size_t size) {
|
||||
}
|
||||
|
||||
inline void AlignHeapToPageBoundary() {
|
||||
}
|
||||
|
||||
inline void* MarkHeapStart() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline size_t MeasureHeapUsage(void* start) {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
// Linux-specific functionality
|
||||
inline void CheckPageAlignment(void* ptr) {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
if (reinterpret_cast<uintptr_t>(ptr) % page_size == 0) {
|
||||
LogKSMDetail("Memory is page-aligned [{}]", ptr);
|
||||
} else {
|
||||
LogKSMDetail("Memory is NOT page-aligned [{}]", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void* AllocatePageAligned(size_t size) {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
void* aligned_ptr = nullptr;
|
||||
if (posix_memalign(&aligned_ptr, page_size, size) != 0) {
|
||||
LogKSM("Failed to allocate page-aligned memory on Linux. page_size [{}] size [{}] bytes", page_size, size);
|
||||
}
|
||||
std::memset(aligned_ptr, 0, size);
|
||||
return aligned_ptr;
|
||||
}
|
||||
|
||||
inline void MarkMemoryForKSM(void* start, size_t size) {
|
||||
if (madvise(start, size, MADV_MERGEABLE) == 0) {
|
||||
LogKSM("Marked memory for KSM | start [{}] size [{}] bytes", start, size);
|
||||
} else {
|
||||
perror("madvise failed");
|
||||
}
|
||||
}
|
||||
|
||||
inline void AlignHeapToPageBoundary() {
|
||||
size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size == 0) {
|
||||
LogKSM("Failed to retrieve page size SC_PAGESIZE [{}]", page_size);
|
||||
return;
|
||||
}
|
||||
|
||||
void* current_break = sbrk(0);
|
||||
if (current_break == (void*)-1) {
|
||||
LogKSM("Failed to retrieve the current program break");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t current_address = reinterpret_cast<uintptr_t>(current_break);
|
||||
size_t misalignment = current_address % page_size;
|
||||
|
||||
if (misalignment != 0) {
|
||||
size_t adjustment = page_size - misalignment;
|
||||
if (sbrk(adjustment) == (void*)-1) {
|
||||
LogKSM("Failed to align heap to page boundary. adjustment [{}] bytes", adjustment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogKSMDetail("Heap aligned to next page boundary. Current break [{}]", sbrk(0));
|
||||
}
|
||||
|
||||
inline void* MarkHeapStart() {
|
||||
void* current_pos = sbrk(0);
|
||||
AlignHeapToPageBoundary();
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
inline size_t MeasureHeapUsage(void* start) {
|
||||
void* current_break = sbrk(0);
|
||||
return static_cast<char*>(current_break) - static_cast<char*>(start);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
inline size_t getPageSize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return sysInfo.dwPageSize; // Page size in bytes
|
||||
#else
|
||||
return static_cast<size_t>(sysconf(_SC_PAGESIZE)); // POSIX page size
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void PageAlignVectorAligned(std::vector<T, PageAlignedAllocator<T>>& vec) {
|
||||
if (vec.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t page_size = getPageSize();
|
||||
void* start = vec.data();
|
||||
size_t size = vec.size() * sizeof(T);
|
||||
|
||||
// Check if the memory is page-aligned
|
||||
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
|
||||
// Allocate a new aligned vector
|
||||
std::vector<T, PageAlignedAllocator<T>> aligned_vec(vec.get_allocator());
|
||||
aligned_vec.reserve(vec.capacity()); // Match capacity to avoid reallocation during copy
|
||||
|
||||
// Copy elements from the original vector
|
||||
aligned_vec.insert(aligned_vec.end(), vec.begin(), vec.end());
|
||||
|
||||
// Swap the aligned vector with the original vector
|
||||
vec.swap(aligned_vec);
|
||||
|
||||
// Clear the temporary aligned vector to free its memory
|
||||
aligned_vec.clear();
|
||||
|
||||
// Verify the new alignment
|
||||
start = vec.data();
|
||||
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
|
||||
throw std::runtime_error("Failed to align vector memory to page boundaries.");
|
||||
}
|
||||
|
||||
LogKSMDetail("Vector reallocated to ensure page alignment. start [{}] size [{}] bytes", start, size);
|
||||
} else {
|
||||
LogKSMDetail("Vector is already page-aligned. start [{}] size [{}] bytes", start, size);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// Mark memory for KSM (only on non-Windows systems)
|
||||
MarkMemoryForKSM(start, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EQEMU_KSM_HPP
|
||||
@@ -250,6 +250,7 @@ IN(OP_TraderBuy, TraderBuy_Struct);
|
||||
IN(OP_Trader, Trader_ShowItems_Struct);
|
||||
IN(OP_GMFind, GMSummon_Struct);
|
||||
IN(OP_PickPocket, PickPocket_Struct);
|
||||
IN(OP_PickZone, PickZone_Struct);
|
||||
IN(OP_Bind_Wound, BindWound_Struct);
|
||||
INr(OP_TrackTarget);
|
||||
INr(OP_Track);
|
||||
|
||||
@@ -5188,7 +5188,14 @@ namespace RoF
|
||||
|
||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||
|
||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
||||
strn0cpy(
|
||||
hdr.unknown000,
|
||||
fmt::format(
|
||||
"{:016}\0",
|
||||
packet_type == ItemPacketInvalid ? 0 : inst->GetSerialNumber()
|
||||
).c_str(),
|
||||
sizeof(hdr.unknown000)
|
||||
);
|
||||
|
||||
hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1);
|
||||
hdr.unknown004 = 0;
|
||||
|
||||
+108
-19
@@ -433,7 +433,9 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||
VARSTRUCT_SKIP_TYPE(uint32, eq);
|
||||
}
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
safe_delete(in);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -468,8 +470,8 @@ namespace RoF2
|
||||
}
|
||||
|
||||
auto p_size = 41 * results.size() + name_size + 14;
|
||||
auto buffer = std::make_unique<char[]>(p_size);
|
||||
auto bufptr = buffer.get();
|
||||
auto buffer = new char[p_size];
|
||||
auto bufptr = buffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id);
|
||||
@@ -487,10 +489,11 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat
|
||||
}
|
||||
|
||||
safe_delete(in->pBuffer);
|
||||
safe_delete_array(in->pBuffer);
|
||||
in->size = p_size;
|
||||
in->pBuffer = (uchar *) buffer.get();
|
||||
in->pBuffer = (uchar*)buffer;
|
||||
dest->QueuePacket(in);
|
||||
safe_delete(in);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -500,21 +503,22 @@ namespace RoF2
|
||||
break;
|
||||
}
|
||||
case WelcomeMessage: {
|
||||
auto buffer = std::make_unique<char[]>(sizeof(structs::BazaarWelcome_Struct));
|
||||
auto buffer = new char[sizeof(structs::BazaarWelcome_Struct)];
|
||||
auto emu = (BazaarWelcome_Struct *) in->pBuffer;
|
||||
auto eq = (structs::BazaarWelcome_Struct *) buffer.get();
|
||||
auto eq = (structs::BazaarWelcome_Struct *) buffer;
|
||||
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage;
|
||||
eq->num_of_traders = emu->traders;
|
||||
eq->num_of_items = emu->items;
|
||||
|
||||
safe_delete(in->pBuffer);
|
||||
safe_delete_array(in->pBuffer);
|
||||
in->SetOpcode(OP_TraderShop);
|
||||
in->size = sizeof(structs::BazaarWelcome_Struct);
|
||||
in->pBuffer = (uchar *) buffer.get();
|
||||
in->pBuffer = (uchar *)buffer;
|
||||
|
||||
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||
dest->QueuePacket(in);
|
||||
safe_delete(in);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -892,7 +896,9 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id);
|
||||
VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str());
|
||||
}
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
safe_delete(inapp);
|
||||
break;
|
||||
}
|
||||
case Barter_RemoveFromMerchantWindow: {
|
||||
@@ -963,6 +969,7 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity);
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
safe_delete(inapp);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1343,6 +1350,58 @@ namespace RoF2
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_EvolveItem)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
auto action = *reinterpret_cast<uint32 *>(in->pBuffer);
|
||||
|
||||
switch (action) {
|
||||
case EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS: {
|
||||
auto emu = reinterpret_cast<EvolveItemMessaging *>(in->pBuffer);
|
||||
|
||||
EvolveXPWindowSend e{};
|
||||
EQ::Util::MemoryStreamReader ss(emu->serialized_data, in->size - sizeof(emu->action));
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(e);
|
||||
|
||||
auto item_1 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
|
||||
*>(e.serialize_item_1.data())->inst);
|
||||
auto item_2 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
|
||||
*>(e.serialize_item_2.data())->inst);
|
||||
|
||||
EQ::OutBuffer ob;
|
||||
|
||||
SerializeItem(ob, item_1, 0, 0, ItemPacketMerchant);
|
||||
SerializeItem(ob, item_2, 0, 0, ItemPacketMerchant);
|
||||
|
||||
auto out = std::make_unique<EQApplicationPacket>(
|
||||
OP_EvolveItem,
|
||||
sizeof(EvolveXPWindowSendDetails_Struct) + ob.size()
|
||||
);
|
||||
auto data = reinterpret_cast<EvolveXPWindowSendDetails_Struct *>(out->pBuffer);
|
||||
|
||||
data->action = e.action;
|
||||
data->compatibility = e.compatibility;
|
||||
data->max_transfer_level = e.max_transfer_level;
|
||||
data->item1_unique_id = e.item1_unique_id;
|
||||
data->item2_unique_id = e.item2_unique_id;
|
||||
data->item1_present = e.item1_present;
|
||||
data->item2_present = e.item2_present;
|
||||
|
||||
memcpy(data->serialize_data, ob.str().data(), ob.size());
|
||||
dest->QueuePacket(out.get());
|
||||
safe_delete(in);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_ExpansionInfo)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpansionInfo_Struct);
|
||||
@@ -2046,6 +2105,33 @@ namespace RoF2
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_ItemPreviewRequest)
|
||||
{
|
||||
EQApplicationPacket* in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
uchar* in_buf = in->pBuffer;
|
||||
|
||||
auto int_item = (EQ::InternalSerializedItem_Struct*) in_buf;
|
||||
|
||||
EQ::OutBuffer buf;
|
||||
EQ::OutBuffer::pos_type last_pos = buf.tellp();
|
||||
|
||||
SerializeItem(buf, (const EQ::ItemInstance*) int_item->inst, int_item->slot_id, 0, ItemPacketInvalid);
|
||||
if (buf.tellp() == last_pos) {
|
||||
LogNetcode("RoF2::ENCODE(OP_ItemPreviewRequest) Serialization failed");
|
||||
safe_delete_array(in_buf);
|
||||
safe_delete(in);
|
||||
return;
|
||||
}
|
||||
|
||||
in->size = buf.size();
|
||||
in->pBuffer = buf.detach();
|
||||
|
||||
safe_delete_array(in_buf);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_ItemVerifyReply)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct);
|
||||
@@ -6398,6 +6484,11 @@ namespace RoF2
|
||||
hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0);
|
||||
hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber());
|
||||
hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0;
|
||||
if (item->EvolvingItem) {
|
||||
hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword
|
||||
hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword
|
||||
}
|
||||
|
||||
hdr.last_cast_time = inst->GetRecastTimestamp();
|
||||
hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254)
|
||||
? 0xFFFFFFFF
|
||||
@@ -6411,18 +6502,15 @@ namespace RoF2
|
||||
ob.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader));
|
||||
|
||||
if (item->EvolvingItem > 0) {
|
||||
RoF2::structs::EvolvingItem evotop;
|
||||
RoF2::structs::EvolvingItem_Struct evotop;
|
||||
|
||||
evotop.unknown001 = 0;
|
||||
evotop.unknown002 = 0;
|
||||
evotop.unknown003 = 0;
|
||||
evotop.unknown004 = 0;
|
||||
evotop.evoLevel = item->EvolvingLevel;
|
||||
evotop.progress = 0;
|
||||
evotop.Activated = 1;
|
||||
evotop.evomaxlevel = item->EvolvingMax;
|
||||
evotop.final_item_id = inst->GetEvolveFinalItemID();
|
||||
evotop.evolve_level = item->EvolvingLevel;
|
||||
evotop.progress = inst->GetEvolveProgression();
|
||||
evotop.activated = inst->GetEvolveActivated();
|
||||
evotop.evolve_max_level = item->EvolvingMax;
|
||||
|
||||
ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
|
||||
ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem_Struct));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6796,12 +6884,13 @@ namespace RoF2
|
||||
iqbs.Heirloom = 0;
|
||||
iqbs.Placeable = 0;
|
||||
iqbs.unknown28 = -1;
|
||||
iqbs.unknown29 = packet_type == ItemPacketInvalid ? 0xFF : 0;
|
||||
iqbs.unknown30 = -1;
|
||||
iqbs.NoZone = 0;
|
||||
iqbs.NoGround = 0;
|
||||
iqbs.unknown37a = 0; // (guessed position) New to RoF2
|
||||
iqbs.unknown38 = 0;
|
||||
iqbs.unknown39 = 1;
|
||||
iqbs.unknown39 = packet_type == ItemPacketInvalid ? 0 : 1;;
|
||||
|
||||
ob.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct));
|
||||
|
||||
|
||||
@@ -272,6 +272,7 @@ namespace RoF2
|
||||
|
||||
const size_t SAY_LINK_BODY_SIZE = 56;
|
||||
const uint32 MAX_GUILD_ID = 50000;
|
||||
const uint32 MAX_BAZAAR_TRADERS = 600;
|
||||
|
||||
} /*constants*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -70,6 +70,7 @@ E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_EvolveItem)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
E(OP_GMLastName)
|
||||
@@ -91,6 +92,7 @@ E(OP_InspectBuffs)
|
||||
E(OP_InspectRequest)
|
||||
E(OP_ItemLinkResponse)
|
||||
E(OP_ItemPacket)
|
||||
E(OP_ItemPreviewRequest)
|
||||
E(OP_ItemVerifyReply)
|
||||
E(OP_LeadershipExpUpdate)
|
||||
E(OP_LogServer)
|
||||
|
||||
@@ -4746,16 +4746,13 @@ struct ItemSerializationHeader
|
||||
uint8 isEvolving;
|
||||
};
|
||||
|
||||
struct EvolvingItem {
|
||||
uint8 unknown001;
|
||||
uint8 unknown002;
|
||||
uint8 unknown003;
|
||||
uint8 unknown004;
|
||||
int32 evoLevel;
|
||||
struct EvolvingItem_Struct {
|
||||
uint32 final_item_id;
|
||||
int32 evolve_level;
|
||||
double progress;
|
||||
uint8 Activated;
|
||||
int32 evomaxlevel;
|
||||
uint8 unknown005[4];
|
||||
uint8 activated;
|
||||
int32 evolve_max_level;
|
||||
uint8 unknown005[4];
|
||||
};
|
||||
|
||||
struct ItemSerializationHeaderFinish
|
||||
@@ -5428,6 +5425,32 @@ struct Parcel_Struct
|
||||
};
|
||||
}; /*structs*/
|
||||
|
||||
struct EvolveItemToggle_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint64 unique_id;
|
||||
uint32 percentage;
|
||||
uint32 activated;
|
||||
};
|
||||
|
||||
struct EvolveXPWindowReceive_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint64 item1_unique_id;
|
||||
uint64 item2_unique_id;
|
||||
};
|
||||
|
||||
struct EvolveXPWindowSendDetails_Struct {
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint64 item1_unique_id;
|
||||
/*012*/ uint64 item2_unique_id;
|
||||
/*020*/ uint32 compatibility;
|
||||
/*024*/ uint32 max_transfer_level;
|
||||
/*028*/ uint8 item1_present;
|
||||
/*029*/ uint8 item2_present;
|
||||
/*030*/ char serialize_data[];
|
||||
};
|
||||
|
||||
}; /*RoF2*/
|
||||
|
||||
#endif /*COMMON_ROF2_STRUCTS_H*/
|
||||
|
||||
@@ -286,8 +286,8 @@ namespace Titanium
|
||||
|
||||
const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER
|
||||
|
||||
const size_t SAY_LINK_BODY_SIZE = 45;
|
||||
const uint32 MAX_GUILD_ID = 1500;
|
||||
const size_t SAY_LINK_BODY_SIZE = 45;
|
||||
const uint32 MAX_GUILD_ID = 1500;
|
||||
|
||||
} /*constants*/
|
||||
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This repository was automatically generated and is NOT to be modified directly.
|
||||
* Any repository modifications are meant to be made to the repository extending the base.
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
|
||||
#define EQEMU_BASE_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseCharacterEvolvingItemsRepository {
|
||||
public:
|
||||
struct CharacterEvolvingItems {
|
||||
uint64_t id;
|
||||
uint32_t character_id;
|
||||
uint32_t item_id;
|
||||
uint8_t activated;
|
||||
uint8_t equipped;
|
||||
int64_t current_amount;
|
||||
double progression;
|
||||
uint32_t final_item_id;
|
||||
time_t deleted_at;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"character_id",
|
||||
"item_id",
|
||||
"activated",
|
||||
"equipped",
|
||||
"current_amount",
|
||||
"progression",
|
||||
"final_item_id",
|
||||
"deleted_at",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"character_id",
|
||||
"item_id",
|
||||
"activated",
|
||||
"equipped",
|
||||
"current_amount",
|
||||
"progression",
|
||||
"final_item_id",
|
||||
"UNIX_TIMESTAMP(deleted_at)",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("character_evolving_items");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems NewEntity()
|
||||
{
|
||||
CharacterEvolvingItems e{};
|
||||
|
||||
e.id = 0;
|
||||
e.character_id = 0;
|
||||
e.item_id = 0;
|
||||
e.activated = 0;
|
||||
e.equipped = 0;
|
||||
e.current_amount = 0;
|
||||
e.progression = 0;
|
||||
e.final_item_id = 0;
|
||||
e.deleted_at = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems GetCharacterEvolvingItems(
|
||||
const std::vector<CharacterEvolvingItems> &character_evolving_itemss,
|
||||
int character_evolving_items_id
|
||||
)
|
||||
{
|
||||
for (auto &character_evolving_items : character_evolving_itemss) {
|
||||
if (character_evolving_items.id == character_evolving_items_id) {
|
||||
return character_evolving_items;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems FindOne(
|
||||
Database& db,
|
||||
int character_evolving_items_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_evolving_items_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
CharacterEvolvingItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
|
||||
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int character_evolving_items_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
character_evolving_items_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const CharacterEvolvingItems &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.character_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.activated));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.equipped));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.current_amount));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.progression));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.final_item_id));
|
||||
v.push_back(columns[8] + " = FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems InsertOne(
|
||||
Database& db,
|
||||
CharacterEvolvingItems e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.activated));
|
||||
v.push_back(std::to_string(e.equipped));
|
||||
v.push_back(std::to_string(e.current_amount));
|
||||
v.push_back(std::to_string(e.progression));
|
||||
v.push_back(std::to_string(e.final_item_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
e = NewEntity();
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static int InsertMany(
|
||||
Database& db,
|
||||
const std::vector<CharacterEvolvingItems> &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.character_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.activated));
|
||||
v.push_back(std::to_string(e.equipped));
|
||||
v.push_back(std::to_string(e.current_amount));
|
||||
v.push_back(std::to_string(e.progression));
|
||||
v.push_back(std::to_string(e.final_item_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<CharacterEvolvingItems> All(Database& db)
|
||||
{
|
||||
std::vector<CharacterEvolvingItems> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterEvolvingItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
|
||||
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<CharacterEvolvingItems> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<CharacterEvolvingItems> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {}",
|
||||
BaseSelect(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterEvolvingItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
|
||||
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {}",
|
||||
TableName(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int Truncate(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"TRUNCATE TABLE {}",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int64 GetMaxId(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||
PrimaryKey(),
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||
}
|
||||
|
||||
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COUNT(*) FROM {} {}",
|
||||
TableName(),
|
||||
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||
)
|
||||
);
|
||||
|
||||
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 CharacterEvolvingItems &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.activated));
|
||||
v.push_back(std::to_string(e.equipped));
|
||||
v.push_back(std::to_string(e.current_amount));
|
||||
v.push_back(std::to_string(e.progression));
|
||||
v.push_back(std::to_string(e.final_item_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
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<CharacterEvolvingItems> &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.character_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.activated));
|
||||
v.push_back(std::to_string(e.equipped));
|
||||
v.push_back(std::to_string(e.current_amount));
|
||||
v.push_back(std::to_string(e.progression));
|
||||
v.push_back(std::to_string(e.final_item_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
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_EVOLVING_ITEMS_REPOSITORY_H
|
||||
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
* DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This repository was automatically generated and is NOT to be modified directly.
|
||||
* Any repository modifications are meant to be made to the repository extending the base.
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_PET_NAME_REPOSITORY_H
|
||||
#define EQEMU_BASE_CHARACTER_PET_NAME_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseCharacterPetNameRepository {
|
||||
public:
|
||||
struct CharacterPetName {
|
||||
int32_t character_id;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("character_id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"character_id",
|
||||
"name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"character_id",
|
||||
"name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("character_pet_name");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static CharacterPetName NewEntity()
|
||||
{
|
||||
CharacterPetName e{};
|
||||
|
||||
e.character_id = 0;
|
||||
e.name = "";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static CharacterPetName GetCharacterPetName(
|
||||
const std::vector<CharacterPetName> &character_pet_names,
|
||||
int character_pet_name_id
|
||||
)
|
||||
{
|
||||
for (auto &character_pet_name : character_pet_names) {
|
||||
if (character_pet_name.character_id == character_pet_name_id) {
|
||||
return character_pet_name;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static CharacterPetName FindOne(
|
||||
Database& db,
|
||||
int character_pet_name_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_pet_name_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
CharacterPetName e{};
|
||||
|
||||
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int character_pet_name_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
character_pet_name_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const CharacterPetName &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.character_id));
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.character_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static CharacterPetName InsertOne(
|
||||
Database& db,
|
||||
CharacterPetName e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.character_id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
e = NewEntity();
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static int InsertMany(
|
||||
Database& db,
|
||||
const std::vector<CharacterPetName> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<CharacterPetName> All(Database& db)
|
||||
{
|
||||
std::vector<CharacterPetName> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterPetName e{};
|
||||
|
||||
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<CharacterPetName> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<CharacterPetName> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {}",
|
||||
BaseSelect(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterPetName e{};
|
||||
|
||||
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {}",
|
||||
TableName(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int Truncate(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"TRUNCATE TABLE {}",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int64 GetMaxId(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||
PrimaryKey(),
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||
}
|
||||
|
||||
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COUNT(*) FROM {} {}",
|
||||
TableName(),
|
||||
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||
)
|
||||
);
|
||||
|
||||
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 CharacterPetName &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
|
||||
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<CharacterPetName> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
|
||||
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_PET_NAME_REPOSITORY_H
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
std::string key_;
|
||||
std::string value;
|
||||
uint32_t expires;
|
||||
int64_t account_id;
|
||||
int64_t character_id;
|
||||
int64_t npc_id;
|
||||
int64_t bot_id;
|
||||
@@ -36,6 +37,7 @@ public:
|
||||
CEREAL_NVP(key_),
|
||||
CEREAL_NVP(value),
|
||||
CEREAL_NVP(expires),
|
||||
CEREAL_NVP(account_id),
|
||||
CEREAL_NVP(character_id),
|
||||
CEREAL_NVP(npc_id),
|
||||
CEREAL_NVP(bot_id)
|
||||
@@ -55,6 +57,7 @@ public:
|
||||
"`key`",
|
||||
"value",
|
||||
"expires",
|
||||
"account_id",
|
||||
"character_id",
|
||||
"npc_id",
|
||||
"bot_id",
|
||||
@@ -68,6 +71,7 @@ public:
|
||||
"`key`",
|
||||
"value",
|
||||
"expires",
|
||||
"account_id",
|
||||
"character_id",
|
||||
"npc_id",
|
||||
"bot_id",
|
||||
@@ -115,6 +119,7 @@ public:
|
||||
e.key_ = "";
|
||||
e.value = "";
|
||||
e.expires = 0;
|
||||
e.account_id = 0;
|
||||
e.character_id = 0;
|
||||
e.npc_id = 0;
|
||||
e.bot_id = 0;
|
||||
@@ -158,9 +163,10 @@ public:
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -197,9 +203,10 @@ public:
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.expires));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.character_id));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.npc_id));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.bot_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.account_id));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.character_id));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.npc_id));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.bot_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -225,6 +232,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.npc_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
@@ -261,6 +269,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.npc_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
@@ -301,9 +310,10 @@ public:
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -332,9 +342,10 @@ public:
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
|
||||
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
|
||||
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -413,6 +424,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.npc_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
@@ -442,6 +454,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.npc_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
|
||||
@@ -0,0 +1,451 @@
|
||||
/**
|
||||
* DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This repository was automatically generated and is NOT to be modified directly.
|
||||
* Any repository modifications are meant to be made to the repository extending the base.
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
#define EQEMU_BASE_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseItemsEvolvingDetailsRepository {
|
||||
public:
|
||||
struct ItemsEvolvingDetails {
|
||||
uint32_t id;
|
||||
uint32_t item_evo_id;
|
||||
uint32_t item_evolve_level;
|
||||
uint32_t item_id;
|
||||
uint32_t type;
|
||||
uint32_t sub_type;
|
||||
int64_t required_amount;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"item_evo_id",
|
||||
"item_evolve_level",
|
||||
"item_id",
|
||||
"type",
|
||||
"sub_type",
|
||||
"required_amount",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"item_evo_id",
|
||||
"item_evolve_level",
|
||||
"item_id",
|
||||
"type",
|
||||
"sub_type",
|
||||
"required_amount",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("items_evolving_details");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static ItemsEvolvingDetails NewEntity()
|
||||
{
|
||||
ItemsEvolvingDetails e{};
|
||||
|
||||
e.id = 0;
|
||||
e.item_evo_id = 0;
|
||||
e.item_evolve_level = 0;
|
||||
e.item_id = 0;
|
||||
e.type = 0;
|
||||
e.sub_type = 0;
|
||||
e.required_amount = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static ItemsEvolvingDetails GetItemsEvolvingDetails(
|
||||
const std::vector<ItemsEvolvingDetails> &items_evolving_detailss,
|
||||
int items_evolving_details_id
|
||||
)
|
||||
{
|
||||
for (auto &items_evolving_details : items_evolving_detailss) {
|
||||
if (items_evolving_details.id == items_evolving_details_id) {
|
||||
return items_evolving_details;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static ItemsEvolvingDetails FindOne(
|
||||
Database& db,
|
||||
int items_evolving_details_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
items_evolving_details_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
ItemsEvolvingDetails e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int items_evolving_details_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
items_evolving_details_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const ItemsEvolvingDetails &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.item_evo_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.item_evolve_level));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.type));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.sub_type));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.required_amount));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static ItemsEvolvingDetails InsertOne(
|
||||
Database& db,
|
||||
ItemsEvolvingDetails e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.item_evo_id));
|
||||
v.push_back(std::to_string(e.item_evolve_level));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.sub_type));
|
||||
v.push_back(std::to_string(e.required_amount));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
e = NewEntity();
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static int InsertMany(
|
||||
Database& db,
|
||||
const std::vector<ItemsEvolvingDetails> &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.item_evo_id));
|
||||
v.push_back(std::to_string(e.item_evolve_level));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.sub_type));
|
||||
v.push_back(std::to_string(e.required_amount));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<ItemsEvolvingDetails> All(Database& db)
|
||||
{
|
||||
std::vector<ItemsEvolvingDetails> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
ItemsEvolvingDetails e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<ItemsEvolvingDetails> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<ItemsEvolvingDetails> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {}",
|
||||
BaseSelect(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
ItemsEvolvingDetails e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {}",
|
||||
TableName(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int Truncate(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"TRUNCATE TABLE {}",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int64 GetMaxId(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||
PrimaryKey(),
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||
}
|
||||
|
||||
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT COUNT(*) FROM {} {}",
|
||||
TableName(),
|
||||
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||
)
|
||||
);
|
||||
|
||||
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 ItemsEvolvingDetails &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.item_evo_id));
|
||||
v.push_back(std::to_string(e.item_evolve_level));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.sub_type));
|
||||
v.push_back(std::to_string(e.required_amount));
|
||||
|
||||
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<ItemsEvolvingDetails> &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.item_evo_id));
|
||||
v.push_back(std::to_string(e.item_evolve_level));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.sub_type));
|
||||
v.push_back(std::to_string(e.required_amount));
|
||||
|
||||
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_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
@@ -111,12 +111,13 @@ public:
|
||||
int32_t fast_regen_mana;
|
||||
int32_t fast_regen_endurance;
|
||||
int32_t npc_max_aggro_dist;
|
||||
uint32_t max_movement_update_range;
|
||||
uint32_t client_update_range;
|
||||
int32_t underworld_teleport_index;
|
||||
int32_t lava_damage;
|
||||
int32_t min_lava_damage;
|
||||
uint8_t idle_when_empty;
|
||||
uint32_t seconds_before_idle;
|
||||
int32_t shard_at_player_count;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -219,12 +220,13 @@ public:
|
||||
"fast_regen_mana",
|
||||
"fast_regen_endurance",
|
||||
"npc_max_aggro_dist",
|
||||
"max_movement_update_range",
|
||||
"client_update_range",
|
||||
"underworld_teleport_index",
|
||||
"lava_damage",
|
||||
"min_lava_damage",
|
||||
"idle_when_empty",
|
||||
"seconds_before_idle",
|
||||
"shard_at_player_count",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -323,12 +325,13 @@ public:
|
||||
"fast_regen_mana",
|
||||
"fast_regen_endurance",
|
||||
"npc_max_aggro_dist",
|
||||
"max_movement_update_range",
|
||||
"client_update_range",
|
||||
"underworld_teleport_index",
|
||||
"lava_damage",
|
||||
"min_lava_damage",
|
||||
"idle_when_empty",
|
||||
"seconds_before_idle",
|
||||
"shard_at_player_count",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -461,12 +464,13 @@ public:
|
||||
e.fast_regen_mana = 180;
|
||||
e.fast_regen_endurance = 180;
|
||||
e.npc_max_aggro_dist = 600;
|
||||
e.max_movement_update_range = 600;
|
||||
e.client_update_range = 600;
|
||||
e.underworld_teleport_index = 0;
|
||||
e.lava_damage = 50;
|
||||
e.min_lava_damage = 10;
|
||||
e.idle_when_empty = 1;
|
||||
e.seconds_before_idle = 60;
|
||||
e.shard_at_player_count = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -595,12 +599,13 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -725,12 +730,13 @@ public:
|
||||
v.push_back(columns[89] + " = " + std::to_string(e.fast_regen_mana));
|
||||
v.push_back(columns[90] + " = " + std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(columns[91] + " = " + std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.max_movement_update_range));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.client_update_range));
|
||||
v.push_back(columns[93] + " = " + std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(columns[94] + " = " + std::to_string(e.lava_damage));
|
||||
v.push_back(columns[95] + " = " + std::to_string(e.min_lava_damage));
|
||||
v.push_back(columns[96] + " = " + std::to_string(e.idle_when_empty));
|
||||
v.push_back(columns[97] + " = " + std::to_string(e.seconds_before_idle));
|
||||
v.push_back(columns[98] + " = " + std::to_string(e.shard_at_player_count));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -844,12 +850,13 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
v.push_back(std::to_string(e.idle_when_empty));
|
||||
v.push_back(std::to_string(e.seconds_before_idle));
|
||||
v.push_back(std::to_string(e.shard_at_player_count));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -971,12 +978,13 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
v.push_back(std::to_string(e.idle_when_empty));
|
||||
v.push_back(std::to_string(e.seconds_before_idle));
|
||||
v.push_back(std::to_string(e.shard_at_player_count));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -1102,12 +1110,13 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -1224,12 +1233,13 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -1396,12 +1406,13 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
v.push_back(std::to_string(e.idle_when_empty));
|
||||
v.push_back(std::to_string(e.seconds_before_idle));
|
||||
v.push_back(std::to_string(e.shard_at_player_count));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -1516,12 +1527,13 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
v.push_back(std::to_string(e.idle_when_empty));
|
||||
v.push_back(std::to_string(e.seconds_before_idle));
|
||||
v.push_back(std::to_string(e.shard_at_player_count));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -80,6 +80,93 @@ public:
|
||||
|
||||
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
|
||||
}
|
||||
|
||||
struct InstancePlayerCount {
|
||||
int32_t instance_id;
|
||||
uint32_t zone_id;
|
||||
uint32_t player_count;
|
||||
};
|
||||
|
||||
static std::vector<InstancePlayerCount> GetInstanceZonePlayerCounts(Database& db, int zone_id) {
|
||||
std::vector<InstancePlayerCount> zone_player_counts;
|
||||
|
||||
uint64_t shard_instance_duration = 3155760000;
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT
|
||||
zone_id,
|
||||
0 AS instance_id,
|
||||
COUNT(id) AS player_count
|
||||
FROM
|
||||
character_data
|
||||
WHERE
|
||||
zone_instance = 0
|
||||
AND zone_id = {}
|
||||
AND last_login >= UNIX_TIMESTAMP(NOW()) - 600
|
||||
GROUP BY
|
||||
zone_id
|
||||
ORDER BY
|
||||
zone_id, player_count DESC
|
||||
), zone_id);
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
InstancePlayerCount e{};
|
||||
e.zone_id = std::stoi(row[0]);
|
||||
e.instance_id = 0;
|
||||
e.player_count = std::stoi(row[2]);
|
||||
zone_player_counts.push_back(e);
|
||||
}
|
||||
|
||||
if (zone_player_counts.empty()) {
|
||||
InstancePlayerCount e{};
|
||||
e.zone_id = zone_id;
|
||||
e.instance_id = 0;
|
||||
e.player_count = 0;
|
||||
zone_player_counts.push_back(e);
|
||||
}
|
||||
|
||||
// duration 3155760000 is for shards explicitly
|
||||
query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
i.id AS instance_id,
|
||||
i.zone AS zone_id,
|
||||
COUNT(c.id) AS player_count
|
||||
FROM
|
||||
instance_list i
|
||||
LEFT JOIN
|
||||
character_data c
|
||||
ON
|
||||
i.zone = c.zone_id
|
||||
AND i.id = c.zone_instance
|
||||
AND c.last_login >= UNIX_TIMESTAMP(NOW()) - 600
|
||||
AND (i.start_time + i.duration >= UNIX_TIMESTAMP(NOW()) OR i.never_expires = 0)
|
||||
AND i.duration = {}
|
||||
WHERE
|
||||
i.zone IS NOT NULL AND i.zone = {}
|
||||
GROUP BY
|
||||
i.id, i.zone, i.version
|
||||
ORDER BY
|
||||
i.id ASC;
|
||||
), shard_instance_duration, zone_id
|
||||
);
|
||||
|
||||
results = db.QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0) {
|
||||
return zone_player_counts;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
InstancePlayerCount e{};
|
||||
e.instance_id = std::stoi(row[0]);
|
||||
e.zone_id = std::stoi(row[1]);
|
||||
e.player_count = std::stoi(row[2]);
|
||||
zone_player_counts.push_back(e);
|
||||
}
|
||||
|
||||
return zone_player_counts;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#ifndef EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
|
||||
#define EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_character_evolving_items_repository.h"
|
||||
|
||||
#include <boost/tuple/tuple_comparison.hpp>
|
||||
|
||||
class CharacterEvolvingItemsRepository: public BaseCharacterEvolvingItemsRepository {
|
||||
public:
|
||||
// Custom extended repository methods here
|
||||
|
||||
static CharacterEvolvingItems SetCurrentAmountAndProgression(Database& db, const uint64 id, const uint64 amount, const double progression)
|
||||
{
|
||||
auto e = FindOne(db, id);
|
||||
if (e.id == 0) {
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
e.current_amount = amount;
|
||||
e.progression = progression;
|
||||
e.deleted_at = 0;
|
||||
UpdateOne(db, e);
|
||||
return e;
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems SetEquipped(Database& db, const uint64 id, const bool equipped)
|
||||
{
|
||||
auto e = FindOne(db, id);
|
||||
if (e.id == 0) {
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
e.equipped = equipped;
|
||||
e.deleted_at = 0;
|
||||
UpdateOne(db, e);
|
||||
return e;
|
||||
}
|
||||
|
||||
static CharacterEvolvingItems SoftDelete(Database& db, const uint64 id)
|
||||
{
|
||||
auto e = FindOne(db, id);
|
||||
if (e.id == 0) {
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
e.deleted_at = time(nullptr);
|
||||
UpdateOne(db, e);
|
||||
return e;
|
||||
}
|
||||
|
||||
static bool UpdateCharID(Database &db, const uint64 id, const uint32 to_char_id)
|
||||
{
|
||||
auto e = FindOne(db, id);
|
||||
if (e.id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
e.character_id = to_char_id;
|
||||
e.deleted_at = 0;
|
||||
return UpdateOne(db, e);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
|
||||
#define EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_character_pet_name_repository.h"
|
||||
|
||||
class CharacterPetNameRepository: public BaseCharacterPetNameRepository {
|
||||
public:
|
||||
// Custom extended repository methods here
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
#define EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_items_evolving_details_repository.h"
|
||||
|
||||
class ItemsEvolvingDetailsRepository: public BaseItemsEvolvingDetailsRepository {
|
||||
public:
|
||||
// Custom extended repository methods here
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
class ItemsRepository: public BaseItemsRepository {
|
||||
public:
|
||||
struct Bazaar_Results {
|
||||
uint32 item_id;
|
||||
std::string name;
|
||||
bool stackable;
|
||||
uint32 icon;
|
||||
uint32 stats;
|
||||
};
|
||||
|
||||
static std::vector<int32> GetItemIDsBySearchCriteria(
|
||||
Database& db,
|
||||
std::string search_string,
|
||||
@@ -37,6 +45,51 @@ public:
|
||||
return item_id_list;
|
||||
}
|
||||
|
||||
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
|
||||
Database& db,
|
||||
const std::vector<std::string> &search_ids,
|
||||
const std::string &name,
|
||||
const std::string &field_criteria_items,
|
||||
const std::string &where_criteria_items,
|
||||
const uint32 query_limit = 0
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, name, stackable, icon, {} "
|
||||
"FROM items "
|
||||
"WHERE `name` LIKE '%%{}%%' AND {} AND id IN({}) "
|
||||
"ORDER BY id ASC",
|
||||
field_criteria_items,
|
||||
Strings::Escape(name),
|
||||
where_criteria_items,
|
||||
Strings::Implode(",", search_ids)
|
||||
);
|
||||
|
||||
if (query_limit >= 1) {
|
||||
query += fmt::format(" LIMIT {}", query_limit);
|
||||
}
|
||||
|
||||
std::unordered_map<uint32, Bazaar_Results> item_list;
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return item_list;
|
||||
}
|
||||
|
||||
item_list.reserve(results.RowCount());
|
||||
for (auto row : results) {
|
||||
Bazaar_Results br{};
|
||||
br.item_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
br.name = row[1] ? row[1] : "";
|
||||
br.stackable = atoi(row[2]) ? true : false;
|
||||
br.icon = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
br.stats = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
|
||||
item_list.emplace(br.item_id, br);
|
||||
}
|
||||
|
||||
return item_list;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
class TraderRepository : public BaseTraderRepository {
|
||||
public:
|
||||
static constexpr uint32 TRADER_CONVERT_ID = 4000000000;
|
||||
|
||||
struct DistinctTraders_Struct {
|
||||
uint32 trader_id;
|
||||
@@ -27,6 +28,11 @@ public:
|
||||
std::vector<DistinctTraders_Struct> traders{};
|
||||
};
|
||||
|
||||
struct BazaarTraderSearch_Struct {
|
||||
Trader trader;
|
||||
std::string trader_name;
|
||||
};
|
||||
|
||||
struct WelcomeData_Struct {
|
||||
uint32 count_of_traders;
|
||||
uint32 count_of_items;
|
||||
@@ -40,15 +46,24 @@ public:
|
||||
int32 char_zone_instance_id
|
||||
);
|
||||
|
||||
static BulkTraders_Struct GetDistinctTraders(Database &db)
|
||||
static BulkTraders_Struct GetDistinctTraders(
|
||||
Database &db,
|
||||
uint32 char_zone_instance_id,
|
||||
uint32 max_results = std::numeric_limits<uint32>::max()
|
||||
)
|
||||
{
|
||||
BulkTraders_Struct all_entries{};
|
||||
std::vector<DistinctTraders_Struct> distinct_traders;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
auto results = db.QueryDatabase(fmt::format(
|
||||
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
|
||||
"FROM trader AS t "
|
||||
"JOIN character_data AS c ON t.char_id = c.id;"
|
||||
"JOIN character_data AS c ON t.char_id = c.id "
|
||||
"WHERE t.char_zone_instance_id = {} "
|
||||
"ORDER BY t.char_zone_instance_id ASC "
|
||||
"LIMIT {}",
|
||||
char_zone_instance_id,
|
||||
max_results)
|
||||
);
|
||||
|
||||
distinct_traders.reserve(results.RowCount());
|
||||
@@ -224,6 +239,85 @@ public:
|
||||
|
||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||
}
|
||||
|
||||
static DistinctTraders_Struct GetTraderByInstanceAndSerialnumber(
|
||||
Database &db,
|
||||
uint32 instance_id,
|
||||
const char *serial_number
|
||||
)
|
||||
{
|
||||
DistinctTraders_Struct trader{};
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT t.id, t.char_id, c.name "
|
||||
"FROM trader AS t "
|
||||
"JOIN character_data AS c ON c.id = t.char_id "
|
||||
"WHERE t.char_zone_id = 151 AND t.char_zone_instance_id = {} AND t.item_sn = {} LIMIT 1",
|
||||
instance_id,
|
||||
serial_number
|
||||
);
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return trader;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
std::string name = row[2];
|
||||
trader.trader_id = Strings::ToUnsignedInt(row[1]);
|
||||
trader.trader_name = row[2] ? row[2] : "";
|
||||
|
||||
return trader;
|
||||
}
|
||||
|
||||
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
|
||||
Database &db,
|
||||
std::string &search_criteria_trader
|
||||
)
|
||||
{
|
||||
std::vector<BazaarTraderSearch_Struct> all_entries{};
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT trader.*, c.`name` FROM `trader` INNER JOIN character_data AS c ON trader.char_id = c.id "
|
||||
"WHERE {} ORDER BY trader.char_id ASC",
|
||||
search_criteria_trader
|
||||
);
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
BazaarTraderSearch_Struct e{};
|
||||
|
||||
e.trader.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.trader.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.trader.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.trader.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||
e.trader.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
|
||||
e.trader.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||
e.trader.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||
e.trader.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||
e.trader.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.trader.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.trader.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||
e.trader.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
|
||||
e.trader_name = row[17] ? row[17] : std::string("");
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_TRADER_REPOSITORY_H
|
||||
|
||||
@@ -372,6 +372,7 @@ RULE_INT(Zone, FishingChance, 399, "Chance of fishing from zone table vs global
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
||||
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Map)
|
||||
@@ -829,6 +830,7 @@ RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a ba
|
||||
RULE_INT(Bazaar, VoucherDeliveryCost, 200, "Number of vouchers for direct delivery for a bazaar purchase. Default is 200 vouchers. RoF+ Only.")
|
||||
RULE_BOOL(Bazaar, EnableParcelDelivery, true, "Enable bazaar purchases via parcel delivery. Default is True.")
|
||||
RULE_INT(Bazaar, MaxBuyerInventorySearchResults, 200, "Maximum number of search results when a Buyer searches the global item list. Default is 200. RoF+ Only.")
|
||||
RULE_BOOL(Bazaar, UseAlternateBazaarSearch, false, "Allows the bazaar search window to search across bazaar shards. Default is false.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mail)
|
||||
@@ -1037,6 +1039,13 @@ RULE_INT(Parcel, ParcelMaxItems, 50, "The maximum number of parcels a player is
|
||||
RULE_INT(Parcel, ParcelPruneDelay, 30, "The number of days after which a parcel is deleted. Items are lost!")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(EvolvingItems)
|
||||
RULE_REAL(EvolvingItems, PercentOfSoloExperience, 0.1, "Percentage of solo experience allocated to evolving items that require experience.")
|
||||
RULE_REAL(EvolvingItems, PercentOfGroupExperience, 0.1, "Percentage of group experience allocated to evolving items that require experience.")
|
||||
RULE_REAL(EvolvingItems, PercentOfRaidExperience, 0.1, "Percentage of solo experience allocated to evolving items that require experience.")
|
||||
RULE_INT(EvolvingItems, DelayUponEquipping, 30000, "Delay in ms before an evolving item will earn rewards after equipping. Default is 30000ms or 30s.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
+68
-12
@@ -37,11 +37,13 @@
|
||||
#include "strings.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "data_verification.h"
|
||||
#include "evolving_items.h"
|
||||
#include "repositories/criteria/content_filter_criteria.h"
|
||||
#include "repositories/account_repository.h"
|
||||
#include "repositories/faction_association_repository.h"
|
||||
#include "repositories/starting_items_repository.h"
|
||||
#include "path_manager.h"
|
||||
#include "../zone/client.h"
|
||||
#include "repositories/loottable_repository.h"
|
||||
#include "repositories/character_item_recast_repository.h"
|
||||
#include "repositories/character_corpses_repository.h"
|
||||
@@ -645,15 +647,23 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overloaded: Retrieve character inventory based on character id (zone entry)
|
||||
bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
//bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
bool SharedDatabase::GetInventory(Client *c)
|
||||
{
|
||||
if (!char_id || !inv)
|
||||
if (!c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 char_id = c->CharacterID();
|
||||
EQ::InventoryProfile &inv = c->GetInv();
|
||||
|
||||
// Retrieve character inventory
|
||||
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`;", char_id));
|
||||
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`", char_id));
|
||||
auto e_results = CharacterEvolvingItemsRepository::GetWhere(
|
||||
*this, fmt::format("`character_id` = '{}' AND `deleted_at` IS NULL", char_id)
|
||||
);
|
||||
|
||||
if (results.empty()) {
|
||||
LogError("Error loading inventory for char_id {} from the database.", char_id);
|
||||
return false;
|
||||
@@ -667,8 +677,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
|
||||
const auto timestamps = GetItemRecastTimestamps(char_id);
|
||||
auto cv_conflict = false;
|
||||
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
||||
const auto pmask = inv.GetLookup()->PossessionsBitmask;
|
||||
const auto bank_size = inv.GetLookup()->InventoryTypeSize.Bank;
|
||||
|
||||
std::vector<InventoryRepository::Inventory> queue{};
|
||||
for (auto &row: results) {
|
||||
@@ -785,9 +795,55 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
}
|
||||
}
|
||||
|
||||
if (item->EvolvingItem) {
|
||||
if (slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END) {
|
||||
inst->SetEvolveEquipped(true);
|
||||
}
|
||||
|
||||
auto t = std::ranges::find_if(
|
||||
e_results.cbegin(),
|
||||
e_results.cend(),
|
||||
[&](const CharacterEvolvingItemsRepository::CharacterEvolvingItems &x) {
|
||||
return x.item_id == item_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (t == std::end(e_results)) {
|
||||
auto e = CharacterEvolvingItemsRepository::NewEntity();
|
||||
|
||||
e.character_id = char_id;
|
||||
e.item_id = item_id;
|
||||
e.equipped = inst->GetEvolveEquipped();
|
||||
e.final_item_id = evolving_items_manager.GetFinalItemID(*inst);
|
||||
|
||||
auto r = CharacterEvolvingItemsRepository::InsertOne(*this, e);
|
||||
e.id = r.id;
|
||||
e_results.push_back(e);
|
||||
|
||||
inst->SetEvolveUniqueID(e.id);
|
||||
inst->SetEvolveCharID(e.character_id);
|
||||
inst->SetEvolveItemID(e.item_id);
|
||||
inst->SetEvolveActivated(e.activated);
|
||||
inst->SetEvolveEquipped(e.equipped);
|
||||
inst->SetEvolveCurrentAmount(e.current_amount);
|
||||
inst->CalculateEvolveProgression();
|
||||
inst->SetEvolveFinalItemID(e.final_item_id);
|
||||
}
|
||||
else {
|
||||
inst->SetEvolveUniqueID(t->id);
|
||||
inst->SetEvolveCharID(t->character_id);
|
||||
inst->SetEvolveItemID(t->item_id);
|
||||
inst->SetEvolveActivated(t->activated);
|
||||
inst->SetEvolveEquipped(t->equipped);
|
||||
inst->SetEvolveCurrentAmount(t->current_amount);
|
||||
inst->CalculateEvolveProgression();
|
||||
inst->SetEvolveFinalItemID(t->final_item_id);
|
||||
}
|
||||
}
|
||||
|
||||
int16 put_slot_id;
|
||||
if (slot_id >= 8000 && slot_id <= 8999) {
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
put_slot_id = inv.PushCursor(*inst);
|
||||
}
|
||||
else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||
// Admins: please report any occurrences of this error
|
||||
@@ -797,10 +853,10 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
item_id,
|
||||
slot_id
|
||||
);
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
put_slot_id = inv.PushCursor(*inst);
|
||||
}
|
||||
else {
|
||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||
put_slot_id = inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
|
||||
row.guid = inst->GetSerialNumber();
|
||||
@@ -825,8 +881,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||
char_name,
|
||||
char_id,
|
||||
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
||||
(inv->GMInventory() ? "true" : "false")
|
||||
EQ::versions::MobVersionName(inv.InventoryVersion()),
|
||||
(inv.GMInventory() ? "true" : "false")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -837,7 +893,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
EQ::ItemInstance::ClearGUIDMap();
|
||||
|
||||
// Retrieve shared inventory
|
||||
return GetSharedBank(char_id, inv, true);
|
||||
return GetSharedBank(char_id, &inv, true);
|
||||
}
|
||||
|
||||
// Overloaded: Retrieve character inventory based on account_id and character name (char select)
|
||||
|
||||
+3
-1
@@ -28,6 +28,8 @@
|
||||
#include "fixed_memory_variable_hash_set.h"
|
||||
#include "say_link.h"
|
||||
#include "repositories/command_subsettings_repository.h"
|
||||
#include "repositories/items_evolving_details_repository.h"
|
||||
#include "../common/repositories/character_evolving_items_repository.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -103,7 +105,7 @@ public:
|
||||
bool GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is_charid);
|
||||
int32 GetSharedPlatinum(uint32 account_id);
|
||||
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add);
|
||||
bool GetInventory(uint32 char_id, EQ::InventoryProfile *inv);
|
||||
bool GetInventory(Client* c);
|
||||
bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated
|
||||
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
|
||||
uint32 GetItemRecastTimestamp(uint32 char_id, uint32 recast_type);
|
||||
|
||||
@@ -86,6 +86,9 @@ struct BenchTimer
|
||||
void reset() { start_time = clock::now(); }
|
||||
// this is seconds
|
||||
double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); }
|
||||
std::chrono::milliseconds::rep elapsedMilliseconds() { return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_time).count(); }
|
||||
std::chrono::microseconds::rep elapsedMicroseconds() { return std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start_time).count(); }
|
||||
std::chrono::nanoseconds::rep elapsedNanoseconds() { return std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now() - start_time).count(); }
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
|
||||
};
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.61.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.62.1-dev" // always append -dev to the current version for custom-builds
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
@@ -42,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9286
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9295
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||
|
||||
#endif
|
||||
|
||||
@@ -676,12 +676,6 @@ int ZoneStore::GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
||||
return z ? z->npc_max_aggro_dist : DEFAULT_ZONE_MAX_AGGRO_DISTANCE;
|
||||
}
|
||||
|
||||
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||
{
|
||||
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
||||
return z ? z->max_movement_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
|
||||
}
|
||||
|
||||
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
|
||||
{
|
||||
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
||||
|
||||
@@ -94,7 +94,6 @@ public:
|
||||
int GetZoneFastRegenMana(uint32 zone_id, int version = 0);
|
||||
int GetZoneFastRegenEndurance(uint32 zone_id, int version = 0);
|
||||
int GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version = 0);
|
||||
uint32 GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version = 0);
|
||||
int8 GetZoneMinimumExpansion(uint32 zone_id, int version = 0);
|
||||
int8 GetZoneMaximumExpansion(uint32 zone_id, int version = 0);
|
||||
const std::string GetZoneContentFlags(uint32 zone_id, int version = 0);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.61.0",
|
||||
"version": "22.62.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -33,12 +33,14 @@
|
||||
#include "../common/zone_store.h"
|
||||
#include "../common/path_manager.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/evolving_items.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
|
||||
@@ -261,6 +261,7 @@ OP_ItemPacket=0x368e
|
||||
OP_ItemLinkResponse=0x70c0
|
||||
OP_ItemLinkClick=0x4cef
|
||||
OP_ItemPreview=0x6b5c
|
||||
OP_ItemPreviewRequest=0x7f80
|
||||
OP_NewSpawn=0x6097
|
||||
OP_Track=0x17e5
|
||||
OP_TrackTarget=0x695e
|
||||
@@ -566,7 +567,7 @@ OP_RaidUpdate=0x3973
|
||||
OP_RaidJoin=0x0000
|
||||
OP_RaidDelegateAbility=0x2b33
|
||||
OP_MarkRaidNPC=0x5a58
|
||||
OP_RaidClearNPCMarks=0x20d3
|
||||
OP_RaidClearNPCMarks=0x20d3
|
||||
|
||||
# Button-push commands
|
||||
OP_Taunt=0x2703
|
||||
@@ -728,3 +729,18 @@ OP_InitialHPUpdate=0x0000
|
||||
#aura related
|
||||
OP_UpdateAura=0x1456
|
||||
OP_RemoveTrap=0x71da
|
||||
|
||||
OP_PickZoneWindow=0x72d8
|
||||
OP_PickZone=0xaaba
|
||||
|
||||
#evolve item related
|
||||
OP_EvolveItem=0x7cfb
|
||||
|
||||
# This is bugged in ROF2
|
||||
# OP_InvokeChangePetNameImmediate is supposed to write DisablePetNameChangeReminder=0 to reset the 'nag reminder'
|
||||
# It actually sets DisableNameChangeReminder=0 (player name change nag reminder). Additionally, clicking the
|
||||
# 'Don't remind me later' button sets DisableNameChangeReminder=1
|
||||
# This can be fixed with a client patch.
|
||||
OP_InvokeChangePetNameImmediate=0x046d
|
||||
OP_InvokeChangePetName=0x4506
|
||||
OP_ChangePetName=0x5dab
|
||||
@@ -11,6 +11,6 @@ require (
|
||||
github.com/golang/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
)
|
||||
|
||||
@@ -14,8 +14,8 @@ golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
+1201
-1201
File diff suppressed because it is too large
Load Diff
@@ -11,13 +11,13 @@ void WorldserverCLI::CopyCharacter(int argc, char **argv, argh::parser &cmd, std
|
||||
"destination_account_name"
|
||||
};
|
||||
std::vector<std::string> options = {};
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
std::string source_character_name = cmd(2).str();
|
||||
std::string destination_character_name = cmd(3).str();
|
||||
std::string destination_account_name = cmd(4).str();
|
||||
|
||||
@@ -24,12 +24,12 @@ void WorldserverCLI::DatabaseDump(int argc, char **argv, argh::parser &cmd, std:
|
||||
"--compress"
|
||||
};
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
auto s = new DatabaseDumpService();
|
||||
bool dump_all = cmd[{"-a", "--all"}];
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@ void WorldserverCLI::DatabaseUpdates(int argc, char **argv, argh::parser &cmd, s
|
||||
{
|
||||
description = "Runs database updates manually";
|
||||
|
||||
std::vector<std::string> options = {
|
||||
"--skip-backup",
|
||||
};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
DatabaseUpdate update;
|
||||
update.SetDatabase(&database)
|
||||
->SetSkipBackup(cmd[{"--skip-backup"}] )
|
||||
->SetContentDatabase(&content_db)
|
||||
->CheckDbUpdates();
|
||||
}
|
||||
|
||||
+19
-1
@@ -1,6 +1,8 @@
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
#include <iomanip>
|
||||
#include "../../common/events/player_events.h"
|
||||
#include "../../common/memory/ksm.hpp"
|
||||
|
||||
void WorldserverCLI::TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
@@ -10,5 +12,21 @@ void WorldserverCLI::TestCommand(int argc, char **argv, argh::parser &cmd, std::
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void* start_marker = KSM::MarkHeapStart();
|
||||
std::cout << "Start marker: " << start_marker << "\n";
|
||||
|
||||
std::vector<std::string> vec = {};
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
vec.push_back("Some random string");
|
||||
}
|
||||
|
||||
// Measure allocated memory size
|
||||
size_t allocated_size = KSM::MeasureHeapUsage(start_marker);
|
||||
// Convert to MB as a float and output with precision
|
||||
double allocated_size_mb = static_cast<double>(allocated_size) / (1024 * 1024);
|
||||
std::cout << std::fixed << std::setprecision(3)
|
||||
<< "Allocated size: " << allocated_size_mb << " MB\n";
|
||||
|
||||
// Mark memory for KSM
|
||||
KSM::MarkMemoryForKSM(start_marker, allocated_size);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "client.h"
|
||||
#include "worlddb.h"
|
||||
#include "wguild_mgr.h"
|
||||
#include "../common/evolving_items.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h>
|
||||
@@ -111,6 +112,7 @@ WorldContentService content_service;
|
||||
WebInterfaceList web_interface;
|
||||
PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
void CatchSignal(int sig_num);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ SET(zone_sources
|
||||
botspellsai.cpp
|
||||
cheat_manager.cpp
|
||||
client.cpp
|
||||
client_evolving_items.cpp
|
||||
client_bot.cpp
|
||||
client_mods.cpp
|
||||
client_packet.cpp
|
||||
|
||||
+21
-27
@@ -2559,16 +2559,12 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
const uint8 killed_level = GetLevel();
|
||||
|
||||
if (GetClass() == Class::LDoNTreasure) { // open chest
|
||||
auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct));
|
||||
|
||||
auto a = (Animation_Struct*) outapp->pBuffer;
|
||||
|
||||
static EQApplicationPacket p(OP_Animation, sizeof(Animation_Struct));
|
||||
auto a = (Animation_Struct*) p.pBuffer;
|
||||
a->spawnid = GetID();
|
||||
a->action = 0x0F;
|
||||
a->speed = 10;
|
||||
|
||||
entity_list.QueueCloseClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
entity_list.QueueCloseClients(this, &p);
|
||||
}
|
||||
|
||||
auto app = new EQApplicationPacket(OP_Death, sizeof(Death_Struct));
|
||||
@@ -2815,7 +2811,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
if (con_level != ConsiderColor::Gray) {
|
||||
if (!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) {
|
||||
give_exp_client->AddEXP(ExpSource::Kill, final_exp, con_level);
|
||||
give_exp_client->AddEXP(ExpSource::Kill, final_exp, con_level, false, this);
|
||||
|
||||
if (
|
||||
killer_mob &&
|
||||
@@ -3415,15 +3411,15 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
|
||||
|
||||
attacker->Damage(this, -DS, spellid, EQ::skills::SkillAbjuration/*hackish*/, false);
|
||||
//we can assume there is a spell now
|
||||
auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
CombatDamage_Struct* cds = (CombatDamage_Struct*)outapp->pBuffer;
|
||||
cds->target = attacker->GetID();
|
||||
cds->source = GetID();
|
||||
cds->type = spellbonuses.DamageShieldType;
|
||||
cds->spellid = 0x0;
|
||||
cds->damage = DS;
|
||||
entity_list.QueueCloseClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
static EQApplicationPacket p(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
auto b = (CombatDamage_Struct *) p.pBuffer;
|
||||
b->target = attacker->GetID();
|
||||
b->source = GetID();
|
||||
b->type = spellbonuses.DamageShieldType;
|
||||
b->spellid = 0x0;
|
||||
b->damage = DS;
|
||||
entity_list.QueueCloseClients(this, &p);
|
||||
}
|
||||
else if (DS > 0 && !spell_ds) {
|
||||
//we are healing the attacker...
|
||||
@@ -4540,8 +4536,8 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
|
||||
//send damage packet...
|
||||
if (!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done above
|
||||
auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer;
|
||||
static EQApplicationPacket p(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
auto a = (CombatDamage_Struct *) p.pBuffer;
|
||||
a->target = GetID();
|
||||
|
||||
if (!attacker) {
|
||||
@@ -4622,7 +4618,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
if (!FromDamageShield) {
|
||||
entity_list.QueueCloseClients(
|
||||
attacker, /* Sender */
|
||||
outapp, /* packet */
|
||||
&p, /* packet */
|
||||
false, /* Skip Sender */
|
||||
((IsValidSpell(spell_id)) ? RuleI(Range, SpellMessages) : RuleI(Range, DamageMessages)),
|
||||
0, /* don't skip anyone on spell */
|
||||
@@ -4696,11 +4692,11 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
filter = FilterMyMisses;
|
||||
|
||||
if (attacker->IsClient()) {
|
||||
attacker->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
|
||||
attacker->CastToClient()->QueuePacket(&p, true, CLIENT_CONNECTED, filter);
|
||||
} else {
|
||||
entity_list.QueueCloseClients(
|
||||
attacker, /* Sender */
|
||||
outapp, /* packet */
|
||||
&p, /* packet */
|
||||
false, /* Skip Sender */
|
||||
(
|
||||
IsValidSpell(spell_id) ?
|
||||
@@ -4755,7 +4751,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
a->type = DamageTypeSpell;
|
||||
entity_list.QueueCloseClients(
|
||||
this, /* Sender */
|
||||
outapp, /* packet */
|
||||
&p, /* packet */
|
||||
false, /* Skip Sender */
|
||||
range, /* distance packet travels at the speed of sound */
|
||||
0, /* don't skip anyone on spell */
|
||||
@@ -4766,7 +4762,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
else {
|
||||
//I dont think any filters apply to damage affecting us
|
||||
if (IsClient()) {
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
CastToClient()->QueuePacket(&p);
|
||||
}
|
||||
|
||||
// Send normal message to observers
|
||||
@@ -4776,7 +4772,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
if (!owner || (owner && !owner->IsClient())) {
|
||||
entity_list.QueueCloseClients(
|
||||
this, /* Sender */
|
||||
outapp, /* packet */
|
||||
&p, /* packet */
|
||||
true, /* Skip Sender */
|
||||
range, /* distance packet travels at the speed of sound */
|
||||
(IsValidSpell(spell_id) && skill_used != EQ::skills::SkillTigerClaw) ? 0 : skip,
|
||||
@@ -4786,8 +4782,6 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
else {
|
||||
//else, it is a buff tic...
|
||||
|
||||
+5
-4
@@ -735,21 +735,22 @@ bool Aura::Process()
|
||||
|
||||
if (movement_type == AuraMovement::Follow && GetPosition() != owner->GetPosition() && movement_timer.Check()) {
|
||||
m_Position = owner->GetPosition();
|
||||
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto spu = (PlayerPositionUpdateServer_Struct *) app->pBuffer;
|
||||
|
||||
static EQApplicationPacket packet(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto spu = (PlayerPositionUpdateServer_Struct *) packet.pBuffer;
|
||||
|
||||
MakeSpawnUpdate(spu);
|
||||
auto it = spawned_for.begin();
|
||||
while (it != spawned_for.end()) {
|
||||
auto client = entity_list.GetClientByID(*it);
|
||||
if (client) {
|
||||
client->QueuePacket(app);
|
||||
client->QueuePacket(&packet);
|
||||
++it;
|
||||
}
|
||||
else {
|
||||
it = spawned_for.erase(it);
|
||||
}
|
||||
}
|
||||
safe_delete(app);
|
||||
}
|
||||
// TODO: waypoints?
|
||||
|
||||
|
||||
@@ -7390,39 +7390,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param close_mobs
|
||||
* @param scanning_mob
|
||||
*/
|
||||
void EntityList::ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob)
|
||||
{
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
close_mobs.clear();
|
||||
|
||||
for (auto& e : mob_list) {
|
||||
auto mob = e.second;
|
||||
|
||||
if (!mob->IsClient()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->GetID() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
|
||||
if (distance <= scan_range) {
|
||||
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
|
||||
}
|
||||
else if (mob->GetAggroRange() >= scan_range) {
|
||||
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
|
||||
}
|
||||
}
|
||||
|
||||
LogAIScanCloseDetail("Close Client Mob List Size [{}] for mob [{}]", close_mobs.size(), scanning_mob->GetCleanName());
|
||||
}
|
||||
|
||||
uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid) {
|
||||
|
||||
uint8 need_healed = 0;
|
||||
|
||||
+287
-40
@@ -66,6 +66,7 @@ extern volatile bool RunLoops;
|
||||
#include "../common/repositories/character_spells_repository.h"
|
||||
#include "../common/repositories/character_disciplines_repository.h"
|
||||
#include "../common/repositories/character_data_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
#include "../common/repositories/discovered_items_repository.h"
|
||||
#include "../common/repositories/inventory_repository.h"
|
||||
#include "../common/repositories/keyring_repository.h"
|
||||
@@ -157,7 +158,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
endupkeep_timer(1000),
|
||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||
m_client_npc_aggro_scan_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||
m_client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
||||
m_client_bulk_npc_pos_update_timer(60 * 1000),
|
||||
tribute_timer(Tribute_duration),
|
||||
proximity_timer(ClientProximity_interval),
|
||||
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
|
||||
@@ -402,6 +403,7 @@ Client::~Client() {
|
||||
|
||||
mMovementManager->RemoveClient(this);
|
||||
|
||||
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Account, AccountID());
|
||||
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Client, CharacterID());
|
||||
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
@@ -1827,7 +1829,7 @@ void Client::FriendsWho(char *FriendsString) {
|
||||
Message(0, "Error: World server disconnected");
|
||||
else {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString));
|
||||
new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString));
|
||||
ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer;
|
||||
FriendsWho->FromID = GetID();
|
||||
strcpy(FriendsWho->FromName, GetName());
|
||||
@@ -2208,7 +2210,7 @@ void Client::Stand() {
|
||||
}
|
||||
|
||||
void Client::Sit() {
|
||||
SetAppearance(eaSitting, false);
|
||||
SetAppearance(eaSitting, false);
|
||||
}
|
||||
|
||||
void Client::ChangeLastName(std::string last_name) {
|
||||
@@ -4391,6 +4393,83 @@ void Client::KeyRingList()
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::IsPetNameChangeAllowed() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
|
||||
auto b = DataBucket::GetData(k);
|
||||
if (!b.value.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::InvokeChangePetName(bool immediate) {
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet_op = immediate ? OP_InvokeChangePetNameImmediate : OP_InvokeChangePetName;
|
||||
|
||||
auto outapp = new EQApplicationPacket(packet_op, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::GrantPetNameChange() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
k.value = "true";
|
||||
DataBucket::SetData(k);
|
||||
|
||||
InvokeChangePetName(true);
|
||||
}
|
||||
|
||||
void Client::ClearPetNameChange() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
|
||||
DataBucket::DeleteData(k);
|
||||
}
|
||||
|
||||
bool Client::ChangePetName(std::string new_name)
|
||||
{
|
||||
if (new_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pet = GetPet();
|
||||
if (!pet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pet->GetName() == new_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!database.CheckNameFilter(new_name) || database.IsNameUsed(new_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CharacterPetNameRepository::ReplaceOne(
|
||||
database,
|
||||
CharacterPetNameRepository::CharacterPetName{
|
||||
.character_id = static_cast<int32_t>(CharacterID()),
|
||||
.name = new_name
|
||||
}
|
||||
);
|
||||
|
||||
pet->TempName(new_name.c_str());
|
||||
|
||||
ClearPetNameChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::IsDiscovered(uint32 item_id) {
|
||||
const auto& l = DiscoveredItemsRepository::GetWhere(
|
||||
database,
|
||||
@@ -5627,13 +5706,13 @@ bool Client::TryReward(uint32 claim_id)
|
||||
|
||||
if (amt == 1) {
|
||||
query = StringFormat("DELETE FROM account_rewards "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
} else {
|
||||
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
@@ -8366,7 +8445,7 @@ int Client::GetQuiverHaste(int delay)
|
||||
for (int r = EQ::invslot::GENERAL_BEGIN; r <= EQ::invslot::GENERAL_END; r++) {
|
||||
pi = GetInv().GetItem(r);
|
||||
if (pi && pi->IsClassBag() && pi->GetItem()->BagType == EQ::item::BagTypeQuiver &&
|
||||
pi->GetItem()->BagWR > 0)
|
||||
pi->GetItem()->BagWR > 0)
|
||||
break;
|
||||
if (r == EQ::invslot::GENERAL_END)
|
||||
// we will get here if we don't find a valid quiver
|
||||
@@ -9840,7 +9919,7 @@ const ExpeditionLockoutTimer* Client::GetExpeditionLockout(
|
||||
for (const auto& expedition_lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !expedition_lockout.IsExpired()) &&
|
||||
expedition_lockout.IsSameLockout(expedition_name, event_name))
|
||||
expedition_lockout.IsSameLockout(expedition_name, event_name))
|
||||
{
|
||||
return &expedition_lockout;
|
||||
}
|
||||
@@ -9855,7 +9934,7 @@ std::vector<ExpeditionLockoutTimer> Client::GetExpeditionLockouts(
|
||||
for (const auto& lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !lockout.IsExpired()) &&
|
||||
lockout.GetExpeditionName() == expedition_name)
|
||||
lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
lockouts.emplace_back(lockout);
|
||||
}
|
||||
@@ -12939,50 +13018,77 @@ void Client::SendTopLevelInventory()
|
||||
}
|
||||
}
|
||||
|
||||
// On a normal basis we limit mob movement updates based on distance
|
||||
// This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
|
||||
//
|
||||
// For very large zones we will also force a full update based on distance
|
||||
//
|
||||
// We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
|
||||
// to full stop when they are actually still pathing
|
||||
void Client::CheckSendBulkClientPositionUpdate()
|
||||
void Client::CheckSendBulkNpcPositions()
|
||||
{
|
||||
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
|
||||
float update_range = RuleI(Range, MobCloseScanDistance);
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= update_range;
|
||||
bool is_ready_to_update = (
|
||||
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
m_client_bulk_npc_pos_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
);
|
||||
|
||||
if (IsMoving() && is_ready_to_update) {
|
||||
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
||||
|
||||
int updated_count = 0;
|
||||
int skipped_count = 0;
|
||||
if (is_ready_to_update) {
|
||||
auto &mob_movement_manager = MobMovementManager::Get();
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
|
||||
for (auto &it : mob_list) {
|
||||
Mob *entity = it.second;
|
||||
if (!entity->IsNPC()) {
|
||||
for (auto &e: entity_list.GetMobList()) {
|
||||
Mob *mob = e.second;
|
||||
if (!mob->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int animation_speed = 0;
|
||||
if (entity->IsMoving()) {
|
||||
if (entity->IsRunning()) {
|
||||
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
|
||||
if (mob->IsMoving()) {
|
||||
if (mob->IsRunning()) {
|
||||
animation_speed = (mob->IsFeared() ? mob->GetFearSpeed() : mob->GetRunspeed());
|
||||
}
|
||||
else {
|
||||
animation_speed = entity->GetWalkspeed();
|
||||
animation_speed = mob->GetWalkspeed();
|
||||
}
|
||||
}
|
||||
|
||||
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
|
||||
// if we have seen this mob before, and it hasn't moved, skip it
|
||||
if (m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (m_last_seen_mob_position[mob->GetID()] == mob->GetPosition()) {
|
||||
LogPositionUpdateDetail(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
GetCleanName()
|
||||
);
|
||||
skipped_count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mob_movement_manager.SendCommandToClients(
|
||||
mob,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
animation_speed,
|
||||
ClientRangeAny,
|
||||
this
|
||||
);
|
||||
|
||||
updated_count++;
|
||||
}
|
||||
|
||||
LogPositionUpdate(
|
||||
"[{}] Sent [{}] bulk updated NPC positions, skipped [{}] distance_moved [{}] update_range [{}]",
|
||||
GetCleanName(),
|
||||
updated_count,
|
||||
skipped_count,
|
||||
distance_moved,
|
||||
update_range
|
||||
);
|
||||
|
||||
m_last_position_before_bulk_update = GetPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||
|
||||
@@ -13037,19 +13143,19 @@ void Client::ClientToNpcAggroProcess()
|
||||
const std::vector<int16>& Client::GetInventorySlots()
|
||||
{
|
||||
static const std::vector<std::pair<int16, int16>> slots = {
|
||||
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
|
||||
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
|
||||
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END },
|
||||
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
|
||||
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
|
||||
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
|
||||
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
|
||||
{EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END},
|
||||
{EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END},
|
||||
{EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
|
||||
{EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END},
|
||||
{EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END},
|
||||
{EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END},
|
||||
{EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END},
|
||||
};
|
||||
|
||||
static std::vector<int16> slot_ids;
|
||||
|
||||
if (slot_ids.empty()) {
|
||||
for (const auto& [begin, end] : slots) {
|
||||
for (const auto &[begin, end]: slots) {
|
||||
for (int16 slot_id = begin; slot_id <= end; ++slot_id) {
|
||||
slot_ids.emplace_back(slot_id);
|
||||
}
|
||||
@@ -13058,3 +13164,144 @@ const std::vector<int16>& Client::GetInventorySlots()
|
||||
|
||||
return slot_ids;
|
||||
}
|
||||
|
||||
void Client::ShowZoneShardMenu()
|
||||
{
|
||||
auto z = GetZone(GetZoneID());
|
||||
if (z && !z->shard_at_player_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto results = CharacterDataRepository::GetInstanceZonePlayerCounts(database, GetZoneID());
|
||||
LogZoning("Zone sharding results count [{}]", results.size());
|
||||
|
||||
if (results.empty()) {
|
||||
Message(Chat::White, "No zone shards found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!results.empty()) {
|
||||
Message(Chat::White, "Available Zone Shards:");
|
||||
}
|
||||
|
||||
int number = 1;
|
||||
for (auto &e: results) {
|
||||
std::string teleport_link = Saylink::Silent(
|
||||
fmt::format("#zoneshard {} {}", e.zone_id, (e.instance_id == 0 ? -1 : e.instance_id)),
|
||||
"Teleport"
|
||||
);
|
||||
|
||||
std::string yours;
|
||||
if (e.zone_id == GetZoneID() && e.instance_id == GetInstanceID()) {
|
||||
teleport_link = "Teleport";
|
||||
yours = " (Yours)";
|
||||
}
|
||||
|
||||
Message(
|
||||
Chat::White, fmt::format(
|
||||
" --> [{}] #{} {} ({}) [{}/{}] players {}",
|
||||
teleport_link,
|
||||
number,
|
||||
z->long_name,
|
||||
e.instance_id,
|
||||
e.player_count,
|
||||
z->shard_at_player_count,
|
||||
yours
|
||||
).c_str()
|
||||
);
|
||||
number++;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetAAEXPPercentage(uint8 percentage)
|
||||
{
|
||||
const uint32 before_percentage = m_epp.perAA;
|
||||
|
||||
if (before_percentage > 0 && percentage == 0) {
|
||||
MessageString(Chat::White, AA_OFF);
|
||||
}
|
||||
else if (before_percentage == 0 && percentage > 0) {
|
||||
MessageString(Chat::White, AA_ON);
|
||||
}
|
||||
|
||||
m_epp.perAA = EQ::Clamp(static_cast<int>(percentage), 0, 100);
|
||||
|
||||
SendAlternateAdvancementStats();
|
||||
SendAlternateAdvancementTable();
|
||||
}
|
||||
|
||||
void Client::BroadcastPositionUpdate()
|
||||
{
|
||||
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
|
||||
|
||||
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
spu->spawn_id = GetID();
|
||||
spu->x_pos = FloatToEQ19(GetX());
|
||||
spu->y_pos = FloatToEQ19(GetY());
|
||||
spu->z_pos = FloatToEQ19(GetZ());
|
||||
spu->heading = FloatToEQ12(GetHeading());
|
||||
spu->delta_x = FloatToEQ13(0);
|
||||
spu->delta_y = FloatToEQ13(0);
|
||||
spu->delta_z = FloatToEQ13(0);
|
||||
spu->delta_heading = FloatToEQ10(0);
|
||||
spu->animation = 0;
|
||||
|
||||
entity_list.QueueCloseClients(this, &outapp, true, zone->GetClientUpdateRange());
|
||||
|
||||
Group *g = GetGroup();
|
||||
if (g) {
|
||||
for (auto &m: g->members) {
|
||||
if (m && m->IsClient() && m != this) {
|
||||
m->CastToClient()->QueuePacket(&outapp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucket(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetData(k).value;
|
||||
}
|
||||
|
||||
void Client::SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
k.expires = expiration;
|
||||
k.value = bucket_value;
|
||||
|
||||
DataBucket::SetData(k);
|
||||
}
|
||||
|
||||
void Client::DeleteAccountBucket(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
DataBucket::DeleteData(k);
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucketExpires(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetDataExpires(k);
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucketRemaining(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetDataRemaining(k);
|
||||
}
|
||||
|
||||
+43
-7
@@ -72,6 +72,7 @@ namespace EQ
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
#include "../common/guild_base.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
#include "../common/repositories/character_evolving_items_repository.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// since windows defines these within windef.h (which windows.h include)
|
||||
@@ -294,7 +295,7 @@ public:
|
||||
void SendBazaarDone(uint32 trader_id);
|
||||
void SendBulkBazaarTraders();
|
||||
void SendBulkBazaarBuyers();
|
||||
void DoBazaarInspect(const BazaarInspect_Struct &in);
|
||||
void DoBazaarInspect(BazaarInspect_Struct &in);
|
||||
void SendBazaarDeliveryCosts();
|
||||
static std::string DetermineMoneyString(uint64 copper);
|
||||
|
||||
@@ -306,6 +307,11 @@ public:
|
||||
void KeyRingAdd(uint32 item_id);
|
||||
bool KeyRingCheck(uint32 item_id);
|
||||
void KeyRingList();
|
||||
bool IsPetNameChangeAllowed();
|
||||
void GrantPetNameChange();
|
||||
void ClearPetNameChange();
|
||||
void InvokeChangePetName(bool immediate = true);
|
||||
bool ChangePetName(std::string new_name);
|
||||
bool IsClient() const override { return true; }
|
||||
bool IsOfClientBot() const override { return true; }
|
||||
bool IsOfClientBotMerc() const override { return true; }
|
||||
@@ -333,7 +339,6 @@ public:
|
||||
const char *message9 = nullptr);
|
||||
void Tell_StringID(uint32 string_id, const char *who, const char *message);
|
||||
void SendColoredText(uint32 color, std::string message);
|
||||
void SendBazaarResults(uint32 trader_id, uint32 in_class, uint32 in_race, uint32 item_stat, uint32 item_slot, uint32 item_type, char item_name[64], uint32 min_price, uint32 max_price);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity, TraderRepository::Trader &trader);
|
||||
void DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
@@ -692,6 +697,8 @@ public:
|
||||
void SetAAEXPModifier(uint32 zone_id, float aa_modifier, int16 instance_version = -1);
|
||||
void SetEXPModifier(uint32 zone_id, float exp_modifier, int16 instance_version = -1);
|
||||
|
||||
void SetAAEXPPercentage(uint8 percentage);
|
||||
|
||||
bool UpdateLDoNPoints(uint32 theme_id, int points);
|
||||
void SetLDoNPoints(uint32 theme_id, uint32 points);
|
||||
void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; }
|
||||
@@ -708,13 +715,13 @@ public:
|
||||
void SendCrystalCounts();
|
||||
|
||||
uint64 GetExperienceForKill(Mob *against);
|
||||
void AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||
void AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false, NPC* npc = nullptr);
|
||||
uint64 CalcEXP(uint8 conlevel = 0xFF, bool ignore_mods = false);
|
||||
void CalculateNormalizedAAExp(uint64 &add_aaxp, uint8 conlevel, bool resexp);
|
||||
void CalculateStandardAAExp(uint64 &add_aaxp, uint8 conlevel, bool resexp);
|
||||
void CalculateLeadershipExp(uint64 &add_exp, uint8 conlevel);
|
||||
void CalculateExp(uint64 in_add_exp, uint64 &add_exp, uint64 &add_aaxp, uint8 conlevel, bool resexp);
|
||||
void SetEXP(ExpSource exp_source, uint64 set_exp, uint64 set_aaxp, bool resexp = false);
|
||||
void SetEXP(ExpSource exp_source, uint64 set_exp, uint64 set_aaxp, bool resexp = false, NPC* npc = nullptr);
|
||||
void AddLevelBasedExp(ExpSource exp_source, uint8 exp_percentage, uint8 max_level = 0, bool ignore_mods = false);
|
||||
void SetLeadershipEXP(uint64 group_exp, uint64 raid_exp);
|
||||
void AddLeadershipEXP(uint64 group_exp, uint64 raid_exp);
|
||||
@@ -1128,6 +1135,10 @@ public:
|
||||
void SetTrader(bool status) { trader = status; }
|
||||
uint16 GetTraderID() { return trader_id; }
|
||||
void SetTraderID(uint16 id) { trader_id = id; }
|
||||
void SetTraderCount(uint32 no) { m_trader_count = no; }
|
||||
uint32 GetTraderCount() { return m_trader_count; }
|
||||
void IncrementTraderCount() { m_trader_count += 1; }
|
||||
void DecrementTraderCount() { m_trader_count > 0 ? m_trader_count -= 1 : m_trader_count = 0; }
|
||||
|
||||
eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; }
|
||||
void SetFilter(eqFilterType filter_id, eqFilterMode filter_mode) { ClientFilters[filter_id] = filter_mode; }
|
||||
@@ -1163,7 +1174,7 @@ public:
|
||||
void Escape(); //keep or quest function
|
||||
void DisenchantSummonedBags(bool client_update = true);
|
||||
void RemoveNoRent(bool client_update = true);
|
||||
void RemoveDuplicateLore(bool client_update = true);
|
||||
void RemoveDuplicateLore();
|
||||
void MoveSlotNotAllowed(bool client_update = true);
|
||||
virtual bool RangedAttack(Mob* other, bool CanDoubleAttack = false);
|
||||
virtual void ThrowingAttack(Mob* other, bool CanDoubleAttack = false);
|
||||
@@ -1810,6 +1821,25 @@ public:
|
||||
void RecordKilledNPCEvent(NPC *n);
|
||||
|
||||
uint32 GetEXPForLevel(uint16 check_level);
|
||||
|
||||
// Evolving Item Info
|
||||
void ProcessEvolvingItem(const uint64 exp, const Mob* mob);
|
||||
void SendEvolvingPacket(int8 action, const CharacterEvolvingItemsRepository::CharacterEvolvingItems &item);
|
||||
void DoEvolveItemToggle(const EQApplicationPacket* app);
|
||||
void DoEvolveItemDisplayFinalResult(const EQApplicationPacket* app);
|
||||
bool DoEvolveCheckProgression(const EQ::ItemInstance &inst);
|
||||
void SendEvolveXPWindowDetails(const EQApplicationPacket* app);
|
||||
void DoEvolveTransferXP(const EQApplicationPacket* app);
|
||||
void SendEvolveXPTransferWindow();
|
||||
void SendEvolveTransferResults(const EQ::ItemInstance &inst_from, const EQ::ItemInstance &inst_to, const EQ::ItemInstance &inst_from_new, const EQ::ItemInstance &inst_to_new, const uint32 compatibility, const uint32 max_transfer_level);
|
||||
|
||||
// Account buckets
|
||||
std::string GetAccountBucket(std::string bucket_name);
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
|
||||
void DeleteAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucketExpires(std::string bucket_name);
|
||||
std::string GetAccountBucketRemaining(std::string bucket_name);
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
@@ -1946,6 +1976,7 @@ private:
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
uint8 mercSlot; // selected merc slot
|
||||
uint32 m_trader_count{};
|
||||
uint32 m_buyer_id;
|
||||
uint32 m_barter_time;
|
||||
int32 m_parcel_platinum;
|
||||
@@ -1968,6 +1999,8 @@ private:
|
||||
|
||||
uint16 m_door_tool_entity_id;
|
||||
uint16 m_object_tool_entity_id;
|
||||
|
||||
|
||||
public:
|
||||
uint16 GetDoorToolEntityId() const;
|
||||
void SetDoorToolEntityId(uint16 door_tool_entity_id);
|
||||
@@ -2065,12 +2098,13 @@ private:
|
||||
Timer m_client_npc_aggro_scan_timer;
|
||||
void CheckClientToNpcAggroTimer();
|
||||
void ClientToNpcAggroProcess();
|
||||
void BroadcastPositionUpdate();
|
||||
|
||||
// bulk position updates
|
||||
glm::vec4 m_last_position_before_bulk_update;
|
||||
Timer m_client_zone_wide_full_position_update_timer;
|
||||
Timer m_client_bulk_npc_pos_update_timer;
|
||||
Timer m_position_update_timer;
|
||||
void CheckSendBulkClientPositionUpdate();
|
||||
void CheckSendBulkNpcPositions();
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
@@ -2236,6 +2270,8 @@ private:
|
||||
public:
|
||||
const std::string &GetMailKeyFull() const;
|
||||
const std::string &GetMailKey() const;
|
||||
void ShowZoneShardMenu();
|
||||
void Handle_OP_ChangePetName(const EQApplicationPacket *app);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,451 @@
|
||||
#include "../common/evolving_items.h"
|
||||
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/global_define.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
void Client::DoEvolveItemToggle(const EQApplicationPacket *app)
|
||||
{
|
||||
const auto in = reinterpret_cast<EvolveItemToggle *>(app->pBuffer);
|
||||
auto item = CharacterEvolvingItemsRepository::FindOne(database, in->unique_id);
|
||||
|
||||
LogEvolveItemDetail(
|
||||
"Character ID <green>[{}] requested to set evolve item with unique id <yellow>[{}] to status <yellow>[{}]",
|
||||
CharacterID(),
|
||||
in->unique_id,
|
||||
in->activated
|
||||
);
|
||||
|
||||
if (!item.id) {
|
||||
LogEvolveItemDetail(
|
||||
"Character ID <green>[{}] toggle evolve item unique id <yellow>[{}] failed", CharacterID(), in->unique_id);
|
||||
return;
|
||||
}
|
||||
|
||||
item.activated = in->activated;
|
||||
const auto inst = GetInv().GetItem(GetInv().HasItem(item.item_id));
|
||||
inst->SetEvolveActivated(item.activated ? true : false);
|
||||
|
||||
CharacterEvolvingItemsRepository::ReplaceOne(database, item);
|
||||
|
||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, item);
|
||||
}
|
||||
|
||||
void Client::SendEvolvingPacket(const int8 action, const CharacterEvolvingItemsRepository::CharacterEvolvingItems &item)
|
||||
{
|
||||
auto out = std::make_unique<EQApplicationPacket>(OP_EvolveItem, sizeof(EvolveItemToggle));
|
||||
const auto data = reinterpret_cast<EvolveItemToggle *>(out->pBuffer);
|
||||
|
||||
LogEvolveItemDetail(
|
||||
"Character ID <green>[{}] requested info for evolving item with unique id <yellow>[{}] status <yellow>[{}] "
|
||||
"percentage <yellow>[{}]",
|
||||
CharacterID(),
|
||||
item.id,
|
||||
item.activated,
|
||||
item.progression
|
||||
);
|
||||
|
||||
data->action = action;
|
||||
data->unique_id = item.id;
|
||||
data->percentage = item.progression;
|
||||
data->activated = item.activated;
|
||||
|
||||
QueuePacket(out.get());
|
||||
|
||||
LogEvolveItem(
|
||||
"Sent evolve item with unique id <yellow>[{}] status <yellow>[{}] percentage <yellow>[{}] to Character ID "
|
||||
"<green>[{}]",
|
||||
data->unique_id,
|
||||
data->activated,
|
||||
data->percentage,
|
||||
CharacterID()
|
||||
);
|
||||
}
|
||||
|
||||
void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
||||
{
|
||||
std::vector<const EQ::ItemInstance *> queue{};
|
||||
|
||||
for (auto &[key, inst]: GetInv().GetWorn()) {
|
||||
LogEvolveItemDetail(
|
||||
"CharacterID <green>[{}] found equipped item ID <yellow>[{}]", CharacterID(), inst->GetID());
|
||||
if (!inst->IsEvolving() || !inst->GetEvolveActivated()) {
|
||||
LogEvolveItemDetail(
|
||||
"CharacterID <green>[{}], item ID <yellow>[{}] not an evolving item.", CharacterID(), inst->GetID());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst->GetTimers().contains("evolve") && !inst->GetTimers().at("evolve").Check()) {
|
||||
LogEvolveItemDetail(
|
||||
"CharacterID <green>[{}], item ID <yellow>[{}] timer not yet expired. <red>[{}] secs remaining.",
|
||||
CharacterID(),
|
||||
inst->GetID(),
|
||||
inst->GetTimers().at("evolve").GetRemainingTime() / 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const type = evolving_items_manager.GetEvolvingItemsCache().at(inst->GetID()).type;
|
||||
auto const sub_type = evolving_items_manager.GetEvolvingItemsCache().at(inst->GetID()).sub_type;
|
||||
|
||||
LogEvolveItemDetail(
|
||||
"CharacterID <green>[{}] item id <green>[{}] type {} sub_type {} is Evolving. Continue processing...",
|
||||
CharacterID(),
|
||||
inst->GetID(),
|
||||
type,
|
||||
sub_type);
|
||||
|
||||
switch (type) {
|
||||
case EvolvingItems::Types::AMOUNT_OF_EXP: {
|
||||
LogEvolveItemDetail("Type <green>[{}] Processing sub_type", type);
|
||||
if (sub_type == EvolvingItems::SubTypes::ALL_EXP ||
|
||||
(sub_type == EvolvingItems::SubTypes::GROUP_EXP && IsGrouped())) {
|
||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfGroupExperience) / 100);
|
||||
}
|
||||
else if (
|
||||
sub_type == EvolvingItems::SubTypes::ALL_EXP ||
|
||||
(sub_type == EvolvingItems::SubTypes::RAID_EXP && IsRaidGrouped())) {
|
||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfRaidExperience) / 100);
|
||||
}
|
||||
else if (
|
||||
sub_type == EvolvingItems::SubTypes::ALL_EXP || sub_type == EvolvingItems::SubTypes::SOLO_EXP) {
|
||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfSoloExperience) / 100);
|
||||
}
|
||||
|
||||
inst->CalculateEvolveProgression();
|
||||
|
||||
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
||||
database, inst->GetEvolveUniqueID(), inst->GetEvolveCurrentAmount(), inst->GetEvolveProgression());
|
||||
if (!e.id) {
|
||||
break;
|
||||
}
|
||||
|
||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||
|
||||
LogEvolveItem(
|
||||
"Processing Complete for item id <green>[{1}] Type 1 Amount of EXP - SubType <yellow>[{0}] - "
|
||||
"Assigned <yellow>[{2}] of exp to <green>[{1}]",
|
||||
sub_type,
|
||||
inst->GetID(),
|
||||
exp * 0.001
|
||||
);
|
||||
|
||||
if (inst->GetEvolveProgression() >= 100) {
|
||||
queue.push_back(inst);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EvolvingItems::Types::SPECIFIC_MOB_RACE: {
|
||||
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
||||
if (mob && mob->GetRace() == sub_type) {
|
||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||
inst->SetEvolveAddToCurrentAmount(1);
|
||||
inst->CalculateEvolveProgression();
|
||||
|
||||
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
||||
database,
|
||||
inst->GetEvolveUniqueID(),
|
||||
inst->GetEvolveCurrentAmount(),
|
||||
inst->GetEvolveProgression());
|
||||
if (!e.id) {
|
||||
break;
|
||||
}
|
||||
|
||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||
|
||||
LogEvolveItem(
|
||||
"Processing Complete for item id <green>[{1}] Type 3 Specific Mob Race - SubType <yellow>[{0}] "
|
||||
"- Increased count by 1 for <green>[{1}]",
|
||||
sub_type,
|
||||
inst->GetID()
|
||||
);
|
||||
}
|
||||
|
||||
if (inst->GetEvolveProgression() >= 100) {
|
||||
queue.push_back(inst);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EvolvingItems::Types::SPECIFIC_ZONE_ID: {
|
||||
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
||||
if (mob && mob->GetZoneID() == sub_type) {
|
||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||
inst->SetEvolveAddToCurrentAmount(1);
|
||||
inst->CalculateEvolveProgression();
|
||||
|
||||
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
||||
database,
|
||||
inst->GetEvolveUniqueID(),
|
||||
inst->GetEvolveCurrentAmount(),
|
||||
inst->GetEvolveProgression());
|
||||
if (!e.id) {
|
||||
break;
|
||||
}
|
||||
|
||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||
|
||||
LogEvolveItem(
|
||||
"Processing Complete for item id <green>[{1}] Type 4 Specific Zone ID - SubType <yellow>[{0}] "
|
||||
"- Increased count by 1 for <green>[{1}]",
|
||||
sub_type,
|
||||
inst->GetID()
|
||||
);
|
||||
}
|
||||
|
||||
if (inst->GetEvolveProgression() >= 100) {
|
||||
queue.push_back(inst);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!queue.empty()) {
|
||||
for (auto const &i: queue) {
|
||||
DoEvolveCheckProgression(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::DoEvolveItemDisplayFinalResult(const EQApplicationPacket *app)
|
||||
{
|
||||
const auto in = reinterpret_cast<EvolveItemToggle *>(app->pBuffer);
|
||||
|
||||
const uint32 item_id = static_cast<uint32>(in->unique_id & 0xFFFFFFFF);
|
||||
if (item_id == 0) {
|
||||
LogEvolveItem("Error - Item ID of final evolve item is blank.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQ::ItemInstance> const inst(database.CreateItem(item_id));
|
||||
|
||||
LogEvolveItemDetail(
|
||||
"Character ID <green>[{}] requested to view final evolve item id <yellow>[{}] for evolve item id <yellow>[{}]",
|
||||
CharacterID(),
|
||||
item_id,
|
||||
evolving_items_manager.GetFirstItemInLoreGroupByItemID(item_id));
|
||||
|
||||
inst->SetEvolveProgression(100);
|
||||
|
||||
if (inst) {
|
||||
LogEvolveItemDetail(
|
||||
"Sending final result for item id <yellow>[{}] to Character ID <green>[{}]", item_id, CharacterID());
|
||||
SendItemPacket(0, inst.get(), ItemPacketViewLink);
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::DoEvolveCheckProgression(const EQ::ItemInstance &inst)
|
||||
{
|
||||
if (inst.GetEvolveProgression() < 100 || inst.GetEvolveLvl() == inst.GetMaxEvolveLvl()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto new_item_id = evolving_items_manager.GetNextEvolveItemID(inst);
|
||||
if (!new_item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQ::ItemInstance> const new_inst(database.CreateItem(new_item_id));
|
||||
|
||||
PlayerEvent::EvolveItem e{};
|
||||
|
||||
RemoveItemBySerialNumber(inst.GetSerialNumber());
|
||||
evolving_items_manager.LoadPlayerEvent(inst, e);
|
||||
e.status = "Evolved Item due to obtaining progression - Old Evolve Item removed from inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
PushItemOnCursor(*new_inst, true);
|
||||
evolving_items_manager.LoadPlayerEvent(*new_inst, e);
|
||||
e.status = "Evolved Item due to obtaining progression - New Evolve Item placed in inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
MessageString(Chat::Yellow, EVOLVE_ITEM_EVOLVED, inst.GetItem()->Name);
|
||||
|
||||
LogEvolveItem(
|
||||
"Evolved item id <red>[{}] into item id <green>[{}] for Character ID <green>[{}]",
|
||||
inst.GetID(),
|
||||
new_inst->GetID(),
|
||||
CharacterID());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::SendEvolveXPTransferWindow()
|
||||
{
|
||||
auto out = std::make_unique<EQApplicationPacket>(OP_EvolveItem, sizeof(EvolveItemToggle));
|
||||
const auto data = reinterpret_cast<EvolveItemToggle *>(out->pBuffer);
|
||||
|
||||
data->action = 1;
|
||||
|
||||
QueuePacket(out.get());
|
||||
}
|
||||
|
||||
void Client::SendEvolveXPWindowDetails(const EQApplicationPacket *app)
|
||||
{
|
||||
const auto in = reinterpret_cast<EvolveXPWindowReceive *>(app->pBuffer);
|
||||
|
||||
const auto item_1_slot =
|
||||
GetInv().HasEvolvingItem(in->item1_unique_id, 1, invWherePersonal | invWhereWorn | invWhereCursor);
|
||||
const auto item_2_slot =
|
||||
GetInv().HasEvolvingItem(in->item2_unique_id, 1, invWherePersonal | invWhereWorn | invWhereCursor);
|
||||
|
||||
if (item_1_slot == INVALID_INDEX || item_2_slot == INVALID_INDEX) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto inst_from = GetInv().GetItem(item_1_slot);
|
||||
const auto inst_to = GetInv().GetItem(item_2_slot);
|
||||
|
||||
if (!inst_from || !inst_to) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto results = evolving_items_manager.DetermineTransferResults(*inst_from, *inst_to);
|
||||
|
||||
if (!results.item_from_id || !results.item_to_id) {
|
||||
SendEvolveTransferResults(*inst_from, *inst_to, *inst_from, *inst_to, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQ::ItemInstance> const inst_from_new(database.CreateItem(results.item_from_id));
|
||||
std::unique_ptr<EQ::ItemInstance> const inst_to_new(database.CreateItem(results.item_to_id));
|
||||
if (!inst_from_new || !inst_to_new) {
|
||||
SendEvolveTransferResults(*inst_from, *inst_to, *inst_from, *inst_to, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
inst_from_new->SetEvolveCurrentAmount(results.item_from_current_amount);
|
||||
inst_from_new->CalculateEvolveProgression();
|
||||
inst_to_new->SetEvolveCurrentAmount(results.item_to_current_amount);
|
||||
inst_to_new->CalculateEvolveProgression();
|
||||
|
||||
SendEvolveTransferResults(
|
||||
*inst_from, *inst_to, *inst_from_new, *inst_to_new, results.compatibility, results.max_transfer_level);
|
||||
}
|
||||
|
||||
void Client::DoEvolveTransferXP(const EQApplicationPacket *app)
|
||||
{
|
||||
const auto in = reinterpret_cast<EvolveXPWindowReceive *>(app->pBuffer);
|
||||
|
||||
const auto item_1_slot =
|
||||
GetInv().HasEvolvingItem(in->item1_unique_id, 1, invWherePersonal | invWhereWorn | invWhereCursor);
|
||||
const auto item_2_slot =
|
||||
GetInv().HasEvolvingItem(in->item2_unique_id, 1, invWherePersonal | invWhereWorn | invWhereCursor);
|
||||
|
||||
if (item_1_slot == INVALID_INDEX || item_2_slot == INVALID_INDEX) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto inst_from = GetInv().GetItem(item_1_slot);
|
||||
const auto inst_to = GetInv().GetItem(item_2_slot);
|
||||
|
||||
if (!inst_from || !inst_to) {
|
||||
Message(Chat::Red, "Transfer Failed. Incompatible Items.");
|
||||
LogEvolveItem("Transfer Failed for Character ID <green>[{}]", CharacterID());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto results = evolving_items_manager.DetermineTransferResults(*inst_from, *inst_to);
|
||||
|
||||
if (!results.item_from_id || !results.item_to_id) {
|
||||
Message(Chat::Red, "Transfer Failed. Incompatible Items.");
|
||||
LogEvolveItem("Transfer Failed for Character ID <green>[{}]", CharacterID());
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<const EQ::ItemInstance> const inst_from_new(database.CreateItem(results.item_from_id));
|
||||
std::unique_ptr<const EQ::ItemInstance> const inst_to_new(database.CreateItem(results.item_to_id));
|
||||
|
||||
if (!inst_from_new || !inst_to_new) {
|
||||
Message(Chat::Red, "Transfer Failed. Incompatible Items.");
|
||||
LogEvolveItem("Transfer Failed for Character ID <green>[{}]", CharacterID());
|
||||
return;
|
||||
}
|
||||
|
||||
inst_from_new->SetEvolveCurrentAmount(results.item_from_current_amount);
|
||||
inst_from_new->CalculateEvolveProgression();
|
||||
inst_to_new->SetEvolveCurrentAmount(results.item_to_current_amount);
|
||||
inst_to_new->CalculateEvolveProgression();
|
||||
|
||||
PlayerEvent::EvolveItem e{};
|
||||
|
||||
RemoveItemBySerialNumber(inst_from->GetSerialNumber());
|
||||
evolving_items_manager.LoadPlayerEvent(*inst_from, e);
|
||||
e.status = "Transfer XP - Original FROM Evolve Item removed from inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
PushItemOnCursor(*inst_from_new, true);
|
||||
evolving_items_manager.LoadPlayerEvent(*inst_from_new, e);
|
||||
e.status = "Transfer XP - Updated FROM item placed in inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
RemoveItemBySerialNumber(inst_to->GetSerialNumber());
|
||||
evolving_items_manager.LoadPlayerEvent(*inst_to, e);
|
||||
e.status = "Transfer XP - Original TO Evolve Item removed from inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
PushItemOnCursor(*inst_to_new, true);
|
||||
evolving_items_manager.LoadPlayerEvent(*inst_to_new, e);
|
||||
e.status = "Transfer XP - Updated TO Evolve item placed in inventory.";
|
||||
RecordPlayerEventLog(PlayerEvent::EVOLVE_ITEM, e);
|
||||
|
||||
LogEvolveItem(
|
||||
"Evolve Transfer XP resulted in evolved item id <red>[{}] into item id <green>[{}] for Character ID "
|
||||
"<green>[{}]",
|
||||
inst_to->GetID(),
|
||||
inst_to_new->GetID(),
|
||||
CharacterID()
|
||||
);
|
||||
}
|
||||
|
||||
void Client::SendEvolveTransferResults(
|
||||
const EQ::ItemInstance &inst_from,
|
||||
const EQ::ItemInstance &inst_to,
|
||||
const EQ::ItemInstance &inst_from_new,
|
||||
const EQ::ItemInstance &inst_to_new,
|
||||
const uint32 compatibility,
|
||||
const uint32 max_transfer_level)
|
||||
{
|
||||
std::stringstream ss;
|
||||
cereal::BinaryOutputArchive ar(ss);
|
||||
|
||||
EvolveXPWindowSend e{};
|
||||
e.action = EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS;
|
||||
e.compatibility = compatibility;
|
||||
e.item1_unique_id = inst_from.GetEvolveUniqueID();
|
||||
e.item2_unique_id = inst_to.GetEvolveUniqueID();
|
||||
e.max_transfer_level = max_transfer_level;
|
||||
e.item1_present = 1;
|
||||
e.item2_present = 1;
|
||||
e.serialize_item_1 = inst_from_new.Serialize(0);
|
||||
e.serialize_item_2 = inst_to_new.Serialize(0);
|
||||
|
||||
{
|
||||
ar(e);
|
||||
}
|
||||
|
||||
uint32 packet_size = sizeof(EvolveItemMessaging) + ss.str().length();
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> out(new EQApplicationPacket(OP_EvolveItem, packet_size));
|
||||
const auto data = reinterpret_cast<EvolveItemMessaging *>(out->pBuffer);
|
||||
|
||||
data->action = EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS;
|
||||
memcpy(data->serialized_data, ss.str().data(), ss.str().length());
|
||||
|
||||
QueuePacket(out.get());
|
||||
|
||||
ss.str("");
|
||||
ss.clear();
|
||||
}
|
||||
+167
-27
@@ -66,6 +66,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/guild_tributes_repository.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/character_stats_record_repository.h"
|
||||
@@ -80,7 +81,6 @@ extern PetitionList petition_list;
|
||||
extern EntityList entity_list;
|
||||
typedef void (Client::*ClientPacketProc)(const EQApplicationPacket *app);
|
||||
|
||||
|
||||
//Use a map for connecting opcodes since it dosent get used a lot and is sparse
|
||||
std::map<uint32, ClientPacketProc> ConnectingOpcodes;
|
||||
//Use a static array for connected, for speed
|
||||
@@ -161,6 +161,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_CancelTrade] = &Client::Handle_OP_CancelTrade;
|
||||
ConnectedOpcodes[OP_CastSpell] = &Client::Handle_OP_CastSpell;
|
||||
ConnectedOpcodes[OP_ChannelMessage] = &Client::Handle_OP_ChannelMessage;
|
||||
ConnectedOpcodes[OP_ChangePetName] = &Client::Handle_OP_ChangePetName;
|
||||
ConnectedOpcodes[OP_ClearBlockedBuffs] = &Client::Handle_OP_ClearBlockedBuffs;
|
||||
ConnectedOpcodes[OP_ClearNPCMarks] = &Client::Handle_OP_ClearNPCMarks;
|
||||
ConnectedOpcodes[OP_ClearSurname] = &Client::Handle_OP_ClearSurname;
|
||||
@@ -208,6 +209,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_Emote] = &Client::Handle_OP_Emote;
|
||||
ConnectedOpcodes[OP_EndLootRequest] = &Client::Handle_OP_EndLootRequest;
|
||||
ConnectedOpcodes[OP_EnvDamage] = &Client::Handle_OP_EnvDamage;
|
||||
ConnectedOpcodes[OP_EvolveItem] = &Client::Handle_OP_EvolveItem;
|
||||
ConnectedOpcodes[OP_FaceChange] = &Client::Handle_OP_FaceChange;
|
||||
ConnectedOpcodes[OP_FeignDeath] = &Client::Handle_OP_FeignDeath;
|
||||
ConnectedOpcodes[OP_FindPersonRequest] = &Client::Handle_OP_FindPersonRequest;
|
||||
@@ -283,6 +285,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_ItemLinkResponse] = &Client::Handle_OP_ItemLinkResponse;
|
||||
ConnectedOpcodes[OP_ItemName] = &Client::Handle_OP_ItemName;
|
||||
ConnectedOpcodes[OP_ItemPreview] = &Client::Handle_OP_ItemPreview;
|
||||
ConnectedOpcodes[OP_ItemPreviewRequest] = &Client::Handle_OP_ItemPreviewRequest;
|
||||
ConnectedOpcodes[OP_ItemVerifyRequest] = &Client::Handle_OP_ItemVerifyRequest;
|
||||
ConnectedOpcodes[OP_ItemViewUnknown] = &Client::Handle_OP_Ignore;
|
||||
ConnectedOpcodes[OP_Jump] = &Client::Handle_OP_Jump;
|
||||
@@ -339,6 +342,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd;
|
||||
ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove;
|
||||
ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket;
|
||||
ConnectedOpcodes[OP_PickZone] = &Client::Handle_OP_PickZone;
|
||||
ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse;
|
||||
ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt;
|
||||
ConnectedOpcodes[OP_PurchaseLeadershipAA] = &Client::Handle_OP_PurchaseLeadershipAA;
|
||||
@@ -818,6 +822,10 @@ void Client::CompleteConnect()
|
||||
CharacterID()
|
||||
)
|
||||
);
|
||||
|
||||
if (IsPetNameChangeAllowed()) {
|
||||
InvokeChangePetName(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
@@ -941,6 +949,11 @@ void Client::CompleteConnect()
|
||||
ShowDevToolsMenu();
|
||||
}
|
||||
|
||||
auto z = GetZone(GetZoneID(), GetInstanceVersion());
|
||||
if (z && z->shard_at_player_count > 0 && !RuleB(Zone, ZoneShardQuestMenuOnly)) {
|
||||
ShowZoneShardMenu();
|
||||
}
|
||||
|
||||
// shared tasks memberlist
|
||||
if (RuleB(TaskSystem, EnableTaskSystem) && GetTaskState()->HasActiveSharedTask()) {
|
||||
|
||||
@@ -964,6 +977,16 @@ void Client::CompleteConnect()
|
||||
RecordStats();
|
||||
AutoGrantAAPoints();
|
||||
|
||||
// set initial position for mob tracking
|
||||
m_last_seen_mob_position.reserve(entity_list.GetMobList().size());
|
||||
for (auto& mob : entity_list.GetMobList()) {
|
||||
if (!mob.second->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_last_seen_mob_position[mob.second->GetID()] = mob.second->GetPosition();
|
||||
}
|
||||
|
||||
// enforce some rules..
|
||||
if (!CanEnterZone()) {
|
||||
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
||||
@@ -1303,7 +1326,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
// set to full support in case they're a gm with items in disabled expansion slots...but, have their gm flag off...
|
||||
// item loss will occur when they use the 'empty' slots, if this is not done
|
||||
m_inv.SetGMInventory(true);
|
||||
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
|
||||
loaditems = database.GetInventory(this); /* Load Character Inventory */
|
||||
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
|
||||
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
|
||||
database.LoadCharacterMaterialColor(cid, &m_pp); /* Load Character Material */
|
||||
@@ -1858,8 +1881,9 @@ void Client::Handle_OP_AAAction(const EQApplicationPacket *app)
|
||||
PurchaseAlternateAdvancementRank(action->ability);
|
||||
}
|
||||
else if (action->action == aaActionDisableEXP) { //Turn Off AA Exp
|
||||
if (m_epp.perAA > 0)
|
||||
if (m_epp.perAA > 0) {
|
||||
MessageString(Chat::White, AA_OFF);
|
||||
}
|
||||
|
||||
m_epp.perAA = 0;
|
||||
SendAlternateAdvancementStats();
|
||||
@@ -3228,11 +3252,11 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
if (!new_aug) { // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x.
|
||||
LogError("AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor");
|
||||
Message(Chat::Red, "Error: No augment found on cursor for inserting.");
|
||||
return;
|
||||
break;
|
||||
} else {
|
||||
if (!RuleB(Inventory, AllowMultipleOfSameAugment) && tobe_auged->ContainsAugmentByID(new_aug->GetID())) {
|
||||
Message(Chat::Red, "Error: Cannot put multiple of the same augment in an item.");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -3316,7 +3340,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
in_augment->augment_index
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
item_one_to_push = tobe_auged->Clone();
|
||||
@@ -3388,7 +3412,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
}
|
||||
} else {
|
||||
Message(Chat::Red, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
|
||||
@@ -3421,7 +3445,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
if (!PutItemInInventory(EQ::invslot::slotCursor, *item_two_to_push, true)) {
|
||||
LogError("Problem returning augment to player's cursor after safe removal");
|
||||
Message(Chat::Yellow, "Error: Failed to return augment after removal from item!");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -3466,7 +3490,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
in_augment->augment_index
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
tobe_auged->DeleteAugment(in_augment->augment_index);
|
||||
@@ -3487,6 +3511,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
if (material != EQ::textures::materialInvalid) {
|
||||
SendWearChange(material);
|
||||
}
|
||||
|
||||
break;
|
||||
default: // Unknown
|
||||
LogInventory(
|
||||
@@ -3500,9 +3525,12 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
);
|
||||
break;
|
||||
}
|
||||
safe_delete(item_one_to_push);
|
||||
safe_delete(item_two_to_push);
|
||||
} else {
|
||||
Object::HandleAugmentation(this, in_augment, m_tradeskill_object); // Delegate to tradeskill object to perform combine
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4550,6 +4578,27 @@ void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ChangePetName(const EQApplicationPacket *app) {
|
||||
if (app->size != sizeof(ChangePetName_Struct)) {
|
||||
LogError("Got OP_ChangePetName of incorrect size. Expected [{}], got [{}].", sizeof(ChangePetName_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto p = (ChangePetName_Struct *) app->pBuffer;
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
p->response_code = ChangePetNameResponse::NotEligible;
|
||||
QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
p->response_code = ChangePetNameResponse::Denied;
|
||||
if (ChangePetName(p->new_pet_name)) {
|
||||
p->response_code = ChangePetNameResponse::Accepted;
|
||||
}
|
||||
|
||||
QueuePacket(app);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ClearBlockedBuffs(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!RuleB(Spells, EnableBlockedBuffs))
|
||||
@@ -4793,11 +4842,10 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
|
||||
cmob->SetDelta(boat_delta);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
|
||||
static EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto *ppus = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
|
||||
cmob->MakeSpawnUpdate(ppus);
|
||||
entity_list.QueueCloseClients(cmob, outapp, true, 300, this, false);
|
||||
safe_delete(outapp);
|
||||
entity_list.QueueCloseClients(cmob, &outapp, true, 300, this, false);
|
||||
|
||||
/* Update the boat's position on the server, without sending an update */
|
||||
cmob->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading));
|
||||
@@ -4948,7 +4996,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
CheckScanCloseMobsMovingTimer();
|
||||
}
|
||||
|
||||
CheckSendBulkClientPositionUpdate();
|
||||
CheckSendBulkNpcPositions();
|
||||
|
||||
int32 new_animation = ppu->animation;
|
||||
|
||||
@@ -4971,15 +5019,15 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
m_Position.w = new_heading;
|
||||
|
||||
/* Broadcast update to other clients */
|
||||
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
|
||||
static EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
|
||||
|
||||
MakeSpawnUpdate(position_update);
|
||||
|
||||
if (gm_hide_me) {
|
||||
entity_list.QueueClientsStatus(this, outapp, true, Admin(), AccountStatus::Max);
|
||||
entity_list.QueueClientsStatus(this, &outapp, true, Admin(), AccountStatus::Max);
|
||||
} else {
|
||||
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
|
||||
entity_list.QueueCloseClients(this, &outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -4988,12 +5036,10 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
Raid *raid = GetRaid();
|
||||
|
||||
if (raid) {
|
||||
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
raid->QueueClients(this, &outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
} else if (group) {
|
||||
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
group->QueueClients(this, &outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (zone->watermap) {
|
||||
@@ -9293,6 +9339,30 @@ void Client::Handle_OP_ItemPreview(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ItemPreviewRequest(const EQApplicationPacket* app)
|
||||
{
|
||||
VERIFY_PACKET_LENGTH(OP_ItemPreviewRequest, app, ItemPreview_Struct);
|
||||
auto ips = (ItemPreview_Struct*) app->pBuffer;
|
||||
const EQ::ItemData* item = database.GetItem(ips->itemid);
|
||||
|
||||
if (item) {
|
||||
EQ::ItemInstance* inst = database.CreateItem(item);
|
||||
if (inst) {
|
||||
std::string packet = inst->Serialize(-1);
|
||||
auto outapp = new EQApplicationPacket(OP_ItemPreviewRequest, packet.length());
|
||||
memcpy(outapp->pBuffer, packet.c_str(), packet.length());
|
||||
|
||||
#if EQDEBUG >= 9
|
||||
DumpPacket(outapp);
|
||||
#endif
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
||||
{
|
||||
using EQ::spells::CastingSlot;
|
||||
@@ -10741,7 +10811,12 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
InterrogateInventory(this, true, false, true, error);
|
||||
}
|
||||
|
||||
return;
|
||||
for (int slot : {mi->to_slot, mi->from_slot}) {
|
||||
auto item = GetInv().GetItem(slot);
|
||||
if (item && item->IsEvolving()) {
|
||||
CharacterEvolvingItemsRepository::UpdateOne(database, item->GetEvolvingDetails());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
|
||||
@@ -10808,6 +10883,7 @@ void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
|
||||
InterrogateInventory(this, true, false, true, error);
|
||||
}
|
||||
}
|
||||
safe_delete(mi);
|
||||
}
|
||||
// This is the swap.
|
||||
// Client behavior is just to move stacks without combining them
|
||||
@@ -11839,6 +11915,17 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app)
|
||||
SendPickPocketResponse(victim, 0, PickPocketFailed);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PickZone(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(PickZone_Struct)) {
|
||||
LogDebug("Size mismatch in OP_PickZone expected [{}] got [{}]", sizeof(PickZone_Struct), app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||
{
|
||||
|
||||
@@ -15512,6 +15599,26 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
// Client has elected to buy an item from a Trader
|
||||
//
|
||||
auto in = (TraderBuy_Struct *) app->pBuffer;
|
||||
|
||||
if (RuleB(Bazaar, UseAlternateBazaarSearch) && in->trader_id >= TraderRepository::TRADER_CONVERT_ID) {
|
||||
auto trader = TraderRepository::GetTraderByInstanceAndSerialnumber(
|
||||
database,
|
||||
in->trader_id - TraderRepository::TRADER_CONVERT_ID,
|
||||
in->serial_number
|
||||
);
|
||||
|
||||
if (!trader.trader_id) {
|
||||
LogTrading("Unable to convert trader id for {} and serial number {}. Trader Buy aborted.",
|
||||
in->trader_id - TraderRepository::TRADER_CONVERT_ID,
|
||||
in->serial_number
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
in->trader_id = trader.trader_id;
|
||||
strn0cpy(in->seller_name, trader.trader_name.c_str(), sizeof(in->seller_name));
|
||||
}
|
||||
|
||||
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||
|
||||
switch (in->method) {
|
||||
@@ -16637,13 +16744,12 @@ bool Client::CanTradeFVNoDropItem()
|
||||
|
||||
void Client::SendMobPositions()
|
||||
{
|
||||
auto p = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto *s = (PlayerPositionUpdateServer_Struct *) p->pBuffer;
|
||||
static EQApplicationPacket p(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto *s = (PlayerPositionUpdateServer_Struct *) p.pBuffer;
|
||||
for (auto &m: entity_list.GetMobList()) {
|
||||
m.second->MakeSpawnUpdate(s);
|
||||
QueuePacket(p, false);
|
||||
QueuePacket(&p, false);
|
||||
}
|
||||
safe_delete(p);
|
||||
}
|
||||
|
||||
struct RecordKillCheck {
|
||||
@@ -17147,3 +17253,37 @@ void Client::Handle_OP_ShopRetrieveParcel(const EQApplicationPacket *app)
|
||||
auto parcel_in = (ParcelRetrieve_Struct *)app->pBuffer;
|
||||
DoParcelRetrieve(*parcel_in);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_EvolveItem(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(EvolveItemToggle)) {
|
||||
LogError(
|
||||
"Received Handle_OP_EvolveItem packet. Expected size {}, received size {}.",
|
||||
sizeof(EvolveItemToggle),
|
||||
app->size
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto in = reinterpret_cast<EvolveItemToggle *>(app->pBuffer);
|
||||
|
||||
switch (in->action) {
|
||||
case EvolvingItems::Actions::UPDATE_ITEMS: {
|
||||
DoEvolveItemToggle(app);
|
||||
break;
|
||||
}
|
||||
case EvolvingItems::Actions::FINAL_RESULT: {
|
||||
DoEvolveItemDisplayFinalResult(app);
|
||||
break;
|
||||
}
|
||||
case EvolvingItems::Actions::TRANSFER_XP: {
|
||||
DoEvolveTransferXP(app);
|
||||
break;
|
||||
}
|
||||
case EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS: {
|
||||
SendEvolveXPWindowDetails(app);
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
void Handle_OP_Emote(const EQApplicationPacket *app);
|
||||
void Handle_OP_EndLootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_EnvDamage(const EQApplicationPacket *app);
|
||||
void Handle_OP_EvolveItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_FaceChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_FeignDeath(const EQApplicationPacket *app);
|
||||
void Handle_OP_FindPersonRequest(const EQApplicationPacket *app);
|
||||
@@ -188,6 +189,7 @@
|
||||
void Handle_OP_ItemLinkResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemName(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemPreview(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemPreviewRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Jump(const EQApplicationPacket *app);
|
||||
void Handle_OP_KeyRing(const EQApplicationPacket *app);
|
||||
@@ -242,6 +244,7 @@
|
||||
void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app);
|
||||
void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app);
|
||||
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
||||
void Handle_OP_PickZone(const EQApplicationPacket *app);
|
||||
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||
|
||||
@@ -122,7 +122,7 @@ bool Client::Process() {
|
||||
|
||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||
if (!IsMoving() && m_position_update_timer.Check()) {
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
BroadcastPositionUpdate();
|
||||
}
|
||||
|
||||
if (mana_timer.Check())
|
||||
@@ -764,7 +764,7 @@ void Client::BulkSendInventoryItems()
|
||||
RemoveNoRent(false);
|
||||
}
|
||||
|
||||
RemoveDuplicateLore(false);
|
||||
RemoveDuplicateLore();
|
||||
MoveSlotNotAllowed(false);
|
||||
|
||||
EQ::OutBuffer ob;
|
||||
|
||||
@@ -126,6 +126,7 @@ int command_init(void)
|
||||
command_add("enablerecipe", "[Recipe ID] - Enables a Recipe", AccountStatus::QuestTroupe, command_enablerecipe) ||
|
||||
command_add("entityvariable", "[clear|delete|set|view] - Modify entity variables for yourself or your target", AccountStatus::GMAdmin, command_entityvariable) ||
|
||||
command_add("exptoggle", "[Toggle] - Toggle your or your target's experience gain.", AccountStatus::QuestTroupe, command_exptoggle) ||
|
||||
command_add("evolve", "Evolving Item manipulation commands. Use argument help for more info.", AccountStatus::Steward, command_evolvingitems) ||
|
||||
command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", AccountStatus::QuestTroupe, command_faction) ||
|
||||
command_add("factionassociation", "[factionid] [amount] - triggers a faction hits via association", AccountStatus::GMLeadAdmin, command_faction_association) ||
|
||||
command_add("feature", "Change your or your target's feature's temporarily", AccountStatus::QuestTroupe, command_feature) ||
|
||||
@@ -243,6 +244,7 @@ int command_init(void)
|
||||
command_add("zone", "[Zone ID|Zone Short Name] [X] [Y] [Z] - Teleport to specified Zone by ID or Short Name (coordinates are optional)", AccountStatus::Guide, command_zone) ||
|
||||
command_add("zonebootup", "[ZoneServerID] [shortname] - Make a zone server boot a specific zone", AccountStatus::GMLeadAdmin, command_zonebootup) ||
|
||||
command_add("zoneinstance", "[Instance ID] [X] [Y] [Z] - Teleport to specified Instance by ID (coordinates are optional)", AccountStatus::Guide, command_zone_instance) ||
|
||||
command_add("zoneshard", "[zone] [instance_id] - Teleport explicitly to a zone shard", AccountStatus::Player, command_zone_shard) ||
|
||||
command_add("zoneshutdown", "[shortname] - Shut down a zone server", AccountStatus::GMLeadAdmin, command_zoneshutdown) ||
|
||||
command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave)
|
||||
) {
|
||||
@@ -825,6 +827,7 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/entityvariable.cpp"
|
||||
#include "gm_commands/exptoggle.cpp"
|
||||
#include "gm_commands/faction.cpp"
|
||||
#include "gm_commands/evolving_items.cpp"
|
||||
#include "gm_commands/feature.cpp"
|
||||
#include "gm_commands/find.cpp"
|
||||
#include "gm_commands/fish.cpp"
|
||||
@@ -936,4 +939,5 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/zonebootup.cpp"
|
||||
#include "gm_commands/zoneshutdown.cpp"
|
||||
#include "gm_commands/zone_instance.cpp"
|
||||
#include "gm_commands/zone_shard.cpp"
|
||||
#include "gm_commands/zsave.cpp"
|
||||
|
||||
@@ -38,6 +38,7 @@ void SendShowInventorySubCommands(Client *c);
|
||||
void SendFixMobSubCommands(Client *c);
|
||||
void SendDataBucketsSubCommands(Client *c);
|
||||
void SendParcelsSubCommands(Client *c);
|
||||
void SendEvolvingItemsSubCommands(Client *c);
|
||||
|
||||
// Commands
|
||||
void command_acceptrules(Client *c, const Seperator *sep);
|
||||
@@ -80,6 +81,7 @@ void command_emptyinventory(Client *c, const Seperator *sep);
|
||||
void command_enablerecipe(Client *c, const Seperator *sep);
|
||||
void command_entityvariable(Client *c, const Seperator *sep);
|
||||
void command_exptoggle(Client *c, const Seperator *sep);
|
||||
void command_evolvingitems(Client *c, const Seperator *sep);
|
||||
void command_faction(Client *c, const Seperator *sep);
|
||||
void command_faction_association(Client *c, const Seperator *sep);
|
||||
void command_feature(Client *c, const Seperator *sep);
|
||||
@@ -195,6 +197,7 @@ void command_wpadd(Client *c, const Seperator *sep);
|
||||
void command_worldwide(Client *c, const Seperator *sep);
|
||||
void command_zone(Client *c, const Seperator *sep);
|
||||
void command_zone_instance(Client *c, const Seperator *sep);
|
||||
void command_zone_shard(Client *c, const Seperator *sep);
|
||||
void command_zonebootup(Client *c, const Seperator *sep);
|
||||
void command_zoneshutdown(Client *c, const Seperator *sep);
|
||||
void command_zopp(Client *c, const Seperator *sep);
|
||||
|
||||
+153
-39
@@ -1,12 +1,15 @@
|
||||
#include "data_bucket.h"
|
||||
#include "entity.h"
|
||||
#include "zonedb.h"
|
||||
#include "mob.h"
|
||||
#include "worldserver.h"
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include "../common/json/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
extern WorldServer worldserver;
|
||||
const std::string NESTED_KEY_DELIMITER = ".";
|
||||
|
||||
std::vector<DataBucketsRepository::DataBuckets> g_data_bucket_cache = {};
|
||||
|
||||
@@ -16,6 +19,7 @@ void DataBucket::SetData(const std::string &bucket_key, const std::string &bucke
|
||||
.key = bucket_key,
|
||||
.value = bucket_value,
|
||||
.expires = expires_time,
|
||||
.account_id = 0,
|
||||
.character_id = 0,
|
||||
.npc_id = 0,
|
||||
.bot_id = 0
|
||||
@@ -24,8 +28,13 @@ void DataBucket::SetData(const std::string &bucket_key, const std::string &bucke
|
||||
DataBucket::SetData(k);
|
||||
}
|
||||
|
||||
void DataBucket::SetData(const DataBucketKey &k)
|
||||
void DataBucket::SetData(const DataBucketKey &k_)
|
||||
{
|
||||
DataBucketKey k = k_; // copy the key so we can modify it
|
||||
if (k.key.find(NESTED_KEY_DELIMITER) != std::string::npos) {
|
||||
k.key = Strings::Split(k.key, NESTED_KEY_DELIMITER).front();
|
||||
}
|
||||
|
||||
auto b = DataBucketsRepository::NewEntity();
|
||||
auto r = GetData(k, true);
|
||||
// if we have an entry, use it
|
||||
@@ -37,6 +46,9 @@ void DataBucket::SetData(const DataBucketKey &k)
|
||||
if (k.character_id > 0) {
|
||||
b.character_id = k.character_id;
|
||||
}
|
||||
else if (k.account_id > 0) {
|
||||
b.account_id = k.account_id;
|
||||
}
|
||||
else if (k.npc_id > 0) {
|
||||
b.npc_id = k.npc_id;
|
||||
}
|
||||
@@ -56,9 +68,48 @@ void DataBucket::SetData(const DataBucketKey &k)
|
||||
|
||||
b.expires = expires_time_unix;
|
||||
b.value = k.value;
|
||||
b.key_ = k.key;
|
||||
|
||||
// Check for nested keys (keys with dots)
|
||||
if (k_.key.find(NESTED_KEY_DELIMITER) != std::string::npos) {
|
||||
// Retrieve existing JSON or create a new one
|
||||
std::string existing_value = r.id > 0 ? r.value : "{}";
|
||||
json json_value = json::object();
|
||||
|
||||
try {
|
||||
json_value = json::parse(existing_value);
|
||||
} catch (json::parse_error &e) {
|
||||
LogError("Failed to parse JSON for key [{}]: {}", k_.key, e.what());
|
||||
json_value = json::object(); // Reset to an empty object on error
|
||||
}
|
||||
|
||||
// Recursively merge new key-value pair into the JSON object
|
||||
auto nested_keys = Strings::Split(k_.key, NESTED_KEY_DELIMITER);
|
||||
json *current = &json_value;
|
||||
|
||||
for (size_t i = 0; i < nested_keys.size(); ++i) {
|
||||
const std::string &key_part = nested_keys[i];
|
||||
if (i == nested_keys.size() - 1) {
|
||||
// Set the value at the final key
|
||||
(*current)[key_part] = k_.value;
|
||||
} else {
|
||||
// Traverse or create nested objects
|
||||
if (!current->contains(key_part)) {
|
||||
(*current)[key_part] = json::object();
|
||||
} else if (!(*current)[key_part].is_object()) {
|
||||
// If key exists but is not an object, reset to object to avoid conflicts
|
||||
(*current)[key_part] = json::object();
|
||||
}
|
||||
current = &(*current)[key_part];
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize JSON back to string
|
||||
b.value = json_value.dump();
|
||||
b.key_ = nested_keys.front(); // Use the top-level key
|
||||
}
|
||||
|
||||
if (bucket_id) {
|
||||
|
||||
// update the cache if it exists
|
||||
if (CanCache(k)) {
|
||||
for (auto &e: g_data_bucket_cache) {
|
||||
@@ -72,7 +123,6 @@ void DataBucket::SetData(const DataBucketKey &k)
|
||||
DataBucketsRepository::UpdateOne(database, b);
|
||||
}
|
||||
else {
|
||||
b.key_ = k.key;
|
||||
b = DataBucketsRepository::InsertOne(database, b);
|
||||
|
||||
// add to cache if it doesn't exist
|
||||
@@ -88,25 +138,70 @@ std::string DataBucket::GetData(const std::string &bucket_key)
|
||||
return GetData(DataBucketKey{.key = bucket_key}).value;
|
||||
}
|
||||
|
||||
DataBucketsRepository::DataBuckets DataBucket::ExtractNestedValue(
|
||||
const DataBucketsRepository::DataBuckets &bucket,
|
||||
const std::string &full_key)
|
||||
{
|
||||
auto nested_keys = Strings::Split(full_key, NESTED_KEY_DELIMITER);
|
||||
json json_value;
|
||||
|
||||
try {
|
||||
json_value = json::parse(bucket.value); // Parse the JSON
|
||||
} catch (json::parse_error &ex) {
|
||||
LogError("Failed to parse JSON for key [{}]: {}", bucket.key_, ex.what());
|
||||
return DataBucketsRepository::NewEntity(); // Return empty entity on parse error
|
||||
}
|
||||
|
||||
// Start from the top-level key (e.g., "progression")
|
||||
json *current = &json_value;
|
||||
|
||||
// Traverse the JSON structure
|
||||
for (const auto &key_part: nested_keys) {
|
||||
LogDataBuckets("Looking for key part [{}] in JSON", key_part);
|
||||
|
||||
if (!current->contains(key_part)) {
|
||||
LogDataBuckets("Key part [{}] not found in JSON for [{}]", key_part, full_key);
|
||||
return DataBucketsRepository::NewEntity();
|
||||
}
|
||||
|
||||
current = &(*current)[key_part];
|
||||
}
|
||||
|
||||
// Create a new entity with the extracted value
|
||||
DataBucketsRepository::DataBuckets result = bucket; // Copy the original bucket
|
||||
result.value = current->is_string() ? current->get<std::string>() : current->dump();
|
||||
return result;
|
||||
}
|
||||
|
||||
// GetData fetches bucket data from the database or cache if it exists
|
||||
// if the bucket doesn't exist, it will be added to the cache as a miss
|
||||
// if ignore_misses_cache is true, the bucket will not be added to the cache as a miss
|
||||
// the only place we should be ignoring the misses cache is on the initial read during SetData
|
||||
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, bool ignore_misses_cache)
|
||||
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_, bool ignore_misses_cache)
|
||||
{
|
||||
DataBucketKey k = k_; // Copy the key so we can modify it
|
||||
|
||||
bool is_nested_key = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos;
|
||||
|
||||
// Extract the top-level key for nested keys
|
||||
if (is_nested_key) {
|
||||
k.key = Strings::Split(k.key, NESTED_KEY_DELIMITER).front();
|
||||
}
|
||||
|
||||
LogDataBuckets(
|
||||
"Getting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
|
||||
bool can_cache = CanCache(k);
|
||||
|
||||
// check the cache first if we can cache
|
||||
// Attempt to retrieve the value from the cache
|
||||
if (can_cache) {
|
||||
for (const auto &e: g_data_bucket_cache) {
|
||||
for (const auto &e : g_data_bucket_cache) {
|
||||
if (CheckBucketMatch(e, k)) {
|
||||
if (e.expires > 0 && e.expires < std::time(nullptr)) {
|
||||
LogDataBuckets("Attempted to read expired key [{}] removing from cache", e.key_);
|
||||
@@ -114,43 +209,39 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
return DataBucketsRepository::NewEntity();
|
||||
}
|
||||
|
||||
// this is a bucket miss, return empty entity
|
||||
// we still cache bucket misses, so we don't have to hit the database
|
||||
if (e.id == 0) {
|
||||
return DataBucketsRepository::NewEntity();
|
||||
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
|
||||
|
||||
if (is_nested_key) {
|
||||
return ExtractNestedValue(e, k_.key);
|
||||
}
|
||||
|
||||
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the value from the database
|
||||
auto r = DataBucketsRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"{} `key` = '{}' LIMIT 1",
|
||||
" {} `key` = '{}' LIMIT 1",
|
||||
DataBucket::GetScopedDbFilters(k),
|
||||
k.key
|
||||
)
|
||||
);
|
||||
|
||||
if (r.empty()) {
|
||||
|
||||
// if we're ignoring the misses cache, don't add to the cache
|
||||
// the only place this is ignored is during the initial read of SetData
|
||||
bool add_to_misses_cache = !ignore_misses_cache && can_cache;
|
||||
if (add_to_misses_cache) {
|
||||
// Handle cache misses
|
||||
if (!ignore_misses_cache && can_cache) {
|
||||
size_t size_before = g_data_bucket_cache.size();
|
||||
|
||||
// cache bucket misses, so we don't have to hit the database
|
||||
// when scripts try to read a bucket that doesn't exist
|
||||
g_data_bucket_cache.emplace_back(
|
||||
DataBucketsRepository::DataBuckets{
|
||||
.id = 0,
|
||||
.key_ = k.key,
|
||||
.value = "",
|
||||
.expires = 0,
|
||||
.account_id = k.account_id,
|
||||
.character_id = k.character_id,
|
||||
.npc_id = k.npc_id,
|
||||
.bot_id = k.bot_id
|
||||
@@ -158,8 +249,9 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
);
|
||||
|
||||
LogDataBuckets(
|
||||
"Key [{}] not found in database, adding to cache as a miss character_id [{}] npc_id [{}] bot_id [{}] cache size before [{}] after [{}]",
|
||||
"Key [{}] not found in database, adding to cache as a miss account_id [{}] character_id [{}] npc_id [{}] bot_id [{}] cache size before [{}] after [{}]",
|
||||
k.key,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id,
|
||||
k.bot_id,
|
||||
@@ -168,22 +260,21 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
);
|
||||
}
|
||||
|
||||
return {};
|
||||
return DataBucketsRepository::NewEntity();
|
||||
}
|
||||
|
||||
auto bucket = r.front();
|
||||
|
||||
// if the entry has expired, delete it
|
||||
if (bucket.expires > 0 && bucket.expires < (long long) std::time(nullptr)) {
|
||||
// If the entry has expired, delete it
|
||||
if (bucket.expires > 0 && bucket.expires < static_cast<long long>(std::time(nullptr))) {
|
||||
DeleteData(k);
|
||||
return {};
|
||||
return DataBucketsRepository::NewEntity();
|
||||
}
|
||||
|
||||
// add to cache if it doesn't exist
|
||||
// Add the value to the cache if it doesn't exist
|
||||
if (can_cache) {
|
||||
bool has_cache = false;
|
||||
|
||||
for (auto &e: g_data_bucket_cache) {
|
||||
for (const auto &e : g_data_bucket_cache) {
|
||||
if (e.id == bucket.id) {
|
||||
has_cache = true;
|
||||
break;
|
||||
@@ -195,6 +286,11 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
}
|
||||
}
|
||||
|
||||
// Handle nested key extraction
|
||||
if (is_nested_key) {
|
||||
return ExtractNestedValue(bucket, k_.key);
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
@@ -216,8 +312,6 @@ bool DataBucket::DeleteData(const std::string &bucket_key)
|
||||
// GetDataBuckets bulk loads all data buckets for a mob
|
||||
bool DataBucket::GetDataBuckets(Mob *mob)
|
||||
{
|
||||
DataBucketLoadType::Type t{};
|
||||
|
||||
const uint32 id = mob->GetMobTypeIdentifier();
|
||||
|
||||
if (!id) {
|
||||
@@ -225,14 +319,13 @@ bool DataBucket::GetDataBuckets(Mob *mob)
|
||||
}
|
||||
|
||||
if (mob->IsBot()) {
|
||||
t = DataBucketLoadType::Bot;
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Bot, {id});
|
||||
}
|
||||
else if (mob->IsClient()) {
|
||||
t = DataBucketLoadType::Client;
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Account, {id});
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Client, {id});
|
||||
}
|
||||
|
||||
BulkLoadEntitiesToCache(t, {id});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,9 +347,10 @@ bool DataBucket::DeleteData(const DataBucketKey &k)
|
||||
);
|
||||
|
||||
LogDataBuckets(
|
||||
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
||||
"Deleting bucket key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id,
|
||||
size_before,
|
||||
@@ -277,9 +371,10 @@ bool DataBucket::DeleteData(const DataBucketKey &k)
|
||||
std::string DataBucket::GetDataExpires(const DataBucketKey &k)
|
||||
{
|
||||
LogDataBuckets(
|
||||
"Getting bucket expiration key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket expiration key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
@@ -295,9 +390,10 @@ std::string DataBucket::GetDataExpires(const DataBucketKey &k)
|
||||
std::string DataBucket::GetDataRemaining(const DataBucketKey &k)
|
||||
{
|
||||
LogDataBuckets(
|
||||
"Getting bucket remaining key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket remaining key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
@@ -320,6 +416,13 @@ std::string DataBucket::GetScopedDbFilters(const DataBucketKey &k)
|
||||
query.emplace_back("character_id = 0");
|
||||
}
|
||||
|
||||
if (k.account_id > 0) {
|
||||
query.emplace_back(fmt::format("account_id = {}", k.account_id));
|
||||
}
|
||||
else {
|
||||
query.emplace_back("account_id = 0");
|
||||
}
|
||||
|
||||
if (k.npc_id > 0) {
|
||||
query.emplace_back(fmt::format("npc_id = {}", k.npc_id));
|
||||
}
|
||||
@@ -346,6 +449,7 @@ bool DataBucket::CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe,
|
||||
return (
|
||||
dbe.key_ == k.key &&
|
||||
dbe.bot_id == k.bot_id &&
|
||||
dbe.account_id == k.account_id &&
|
||||
dbe.character_id == k.character_id &&
|
||||
dbe.npc_id == k.npc_id
|
||||
);
|
||||
@@ -364,6 +468,9 @@ void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector
|
||||
if (t == DataBucketLoadType::Bot) {
|
||||
has_cache = e.bot_id == ids[0];
|
||||
}
|
||||
else if (t == DataBucketLoadType::Account) {
|
||||
has_cache = e.account_id == ids[0];
|
||||
}
|
||||
else if (t == DataBucketLoadType::Client) {
|
||||
has_cache = e.character_id == ids[0];
|
||||
}
|
||||
@@ -384,6 +491,9 @@ void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector
|
||||
case DataBucketLoadType::Client:
|
||||
column = "character_id";
|
||||
break;
|
||||
case DataBucketLoadType::Account:
|
||||
column = "account_id";
|
||||
break;
|
||||
default:
|
||||
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
|
||||
break;
|
||||
@@ -442,6 +552,7 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type type, uint32 id)
|
||||
[&](DataBucketsRepository::DataBuckets &e) {
|
||||
return (
|
||||
(type == DataBucketLoadType::Bot && e.bot_id == id) ||
|
||||
(type == DataBucketLoadType::Account && e.account_id == id) ||
|
||||
(type == DataBucketLoadType::Client && e.character_id == id)
|
||||
);
|
||||
}
|
||||
@@ -481,6 +592,7 @@ void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
|
||||
g_data_bucket_cache.end(),
|
||||
[&](DataBucketsRepository::DataBuckets &ce) {
|
||||
return ce.id == 0 && ce.key_ == e.key_ &&
|
||||
ce.account_id == e.account_id &&
|
||||
ce.character_id == e.character_id &&
|
||||
ce.npc_id == e.npc_id &&
|
||||
ce.bot_id == e.bot_id;
|
||||
@@ -516,6 +628,8 @@ void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
|
||||
return e.bot_id == id;
|
||||
case DataBucketLoadType::Client:
|
||||
return e.character_id == id;
|
||||
case DataBucketLoadType::Account:
|
||||
return e.account_id == id;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -539,7 +653,7 @@ void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
|
||||
// npcs (ids) can be in multiple zones so we can't cache locally to the zone
|
||||
bool DataBucket::CanCache(const DataBucketKey &key)
|
||||
{
|
||||
if (key.character_id > 0 || key.bot_id > 0) {
|
||||
if (key.character_id > 0 || key.account_id > 0 || key.bot_id > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -12,20 +12,23 @@ struct DataBucketKey {
|
||||
std::string key;
|
||||
std::string value;
|
||||
std::string expires;
|
||||
int64_t character_id;
|
||||
int64_t npc_id;
|
||||
int64_t bot_id;
|
||||
int64_t account_id = 0;
|
||||
int64_t character_id = 0;
|
||||
int64_t npc_id = 0;
|
||||
int64_t bot_id = 0;
|
||||
};
|
||||
|
||||
namespace DataBucketLoadType {
|
||||
enum Type : uint8 {
|
||||
Bot,
|
||||
Account,
|
||||
Client,
|
||||
MaxType
|
||||
};
|
||||
|
||||
static const std::string Name[Type::MaxType] = {
|
||||
"Bot",
|
||||
"Account",
|
||||
"Client",
|
||||
};
|
||||
}
|
||||
@@ -42,9 +45,9 @@ public:
|
||||
static bool GetDataBuckets(Mob *mob);
|
||||
|
||||
// scoped bucket methods
|
||||
static void SetData(const DataBucketKey &k);
|
||||
static void SetData(const DataBucketKey &k_);
|
||||
static bool DeleteData(const DataBucketKey &k);
|
||||
static DataBucketsRepository::DataBuckets GetData(const DataBucketKey &k, bool ignore_misses_cache = false);
|
||||
static DataBucketsRepository::DataBuckets GetData(const DataBucketKey &k_, bool ignore_misses_cache = false);
|
||||
static std::string GetDataExpires(const DataBucketKey &k);
|
||||
static std::string GetDataRemaining(const DataBucketKey &k);
|
||||
static std::string GetScopedDbFilters(const DataBucketKey &k);
|
||||
@@ -60,6 +63,8 @@ public:
|
||||
static void ClearCache();
|
||||
static void DeleteFromCache(uint64 id, DataBucketLoadType::Type type);
|
||||
static bool CanCache(const DataBucketKey &key);
|
||||
static DataBucketsRepository::DataBuckets
|
||||
ExtractNestedValue(const DataBucketsRepository::DataBuckets &bucket, const std::string &full_key);
|
||||
};
|
||||
|
||||
#endif //EQEMU_DATABUCKET_H
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/evolving_items.h"
|
||||
#include "../common/repositories/criteria/content_filter_criteria.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -610,6 +611,10 @@ void Doors::HandleClick(Client *sender, uint8 trigger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetOpenType() == 40 && sender->GetZoneID() == Zones::CORATHUS) {
|
||||
sender->SendEvolveXPTransferWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void Doors::Open(Mob *sender, bool alt_mode)
|
||||
|
||||
@@ -77,6 +77,8 @@ public:
|
||||
|
||||
bool IsDoorBlacklisted();
|
||||
|
||||
const char* GetDoorZone() const { return m_zone_name; }
|
||||
|
||||
private:
|
||||
bool GetIsDoorBlacklisted();
|
||||
|
||||
|
||||
@@ -5653,16 +5653,6 @@ int Perl__GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 Perl__GetZoneMinimumExpansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@@ -6112,8 +6102,6 @@ void perl_register_quest()
|
||||
package.add("GetZoneMaximumExpansion", (int8(*)(uint32, int))&Perl__GetZoneMaximumExpansion);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32, int))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32, int))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32, int))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMinimumClip", (float(*)(uint32))&Perl__GetZoneMinimumClip);
|
||||
|
||||
+41
-52
@@ -1717,15 +1717,6 @@ void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *a
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sender
|
||||
* @param app
|
||||
* @param ignore_sender
|
||||
* @param distance
|
||||
* @param skipped_mob
|
||||
* @param is_ack_required
|
||||
* @param filter
|
||||
*/
|
||||
void EntityList::QueueCloseClients(
|
||||
Mob *sender,
|
||||
const EQApplicationPacket *app,
|
||||
@@ -1742,7 +1733,7 @@ void EntityList::QueueCloseClients(
|
||||
}
|
||||
|
||||
if (distance <= 0) {
|
||||
distance = 600;
|
||||
distance = zone->GetClientUpdateRange();
|
||||
}
|
||||
|
||||
float distance_squared = distance * distance;
|
||||
@@ -2878,6 +2869,8 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
|
||||
);
|
||||
|
||||
it->second->m_close_mobs.erase(entity_id);
|
||||
it->second->m_last_seen_mob_position.erase(entity_id);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
@@ -2931,6 +2924,9 @@ void EntityList::RemoveAuraFromMobs(Mob *aura)
|
||||
// All of the above makes a tremendous impact on the bottom line of cpu cycle performance because we run an order of magnitude
|
||||
// less checks by focusing our hot path logic down to a very small subset of relevant entities instead of looping an entire
|
||||
// entity list (zone wide)
|
||||
|
||||
BenchTimer g_scan_bench_timer;
|
||||
|
||||
void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
{
|
||||
if (!scanning_mob) {
|
||||
@@ -2941,7 +2937,9 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
return;
|
||||
}
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
||||
g_scan_bench_timer.reset();
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
// Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
|
||||
// Assuming mob_list.size() as an upper bound for reservation.
|
||||
@@ -2957,7 +2955,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
continue;
|
||||
}
|
||||
|
||||
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
|
||||
float distance = Distance(scanning_mob->GetPosition(), mob->GetPosition());
|
||||
if (distance <= scan_range || mob->GetAggroRange() >= scan_range) {
|
||||
// add mob to scanning_mob's close list and vice versa
|
||||
// check if the mob is already in the close mobs list before inserting
|
||||
@@ -2969,10 +2967,11 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
}
|
||||
|
||||
LogAIScanClose(
|
||||
"[{}] Scanning close list > list_size [{}] moving [{}]",
|
||||
"[{}] Scanning close list > list_size [{}] moving [{}] elapsed [{}] us",
|
||||
scanning_mob->GetCleanName(),
|
||||
scanning_mob->m_close_mobs.size(),
|
||||
scanning_mob->IsMoving() ? "true" : "false"
|
||||
scanning_mob->IsMoving() ? "true" : "false",
|
||||
g_scan_bench_timer.elapsedMicroseconds()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5320,15 +5319,12 @@ void EntityList::SendFindableNPCList(Client *c)
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct));
|
||||
|
||||
FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer;
|
||||
|
||||
fnpcs->Unknown109 = 0x16;
|
||||
fnpcs->Unknown110 = 0x06;
|
||||
fnpcs->Unknown111 = 0x24;
|
||||
|
||||
fnpcs->Action = 0;
|
||||
static EQApplicationPacket p(OP_SendFindableNPCs, sizeof(FindableNPC_Struct));
|
||||
auto b = (FindableNPC_Struct*) p.pBuffer;
|
||||
b->Unknown109 = 0x16;
|
||||
b->Unknown110 = 0x06;
|
||||
b->Unknown111 = 0x24;
|
||||
b->Action = 0;
|
||||
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
@@ -5336,50 +5332,47 @@ void EntityList::SendFindableNPCList(Client *c)
|
||||
NPC *n = it->second;
|
||||
|
||||
if (n->IsFindable()) {
|
||||
fnpcs->EntityID = n->GetID();
|
||||
strn0cpy(fnpcs->Name, n->GetCleanName(), sizeof(fnpcs->Name));
|
||||
strn0cpy(fnpcs->LastName, n->GetLastName(), sizeof(fnpcs->LastName));
|
||||
fnpcs->Race = n->GetRace();
|
||||
fnpcs->Class = n->GetClass();
|
||||
b->EntityID = n->GetID();
|
||||
strn0cpy(b->Name, n->GetCleanName(), sizeof(b->Name));
|
||||
strn0cpy(b->LastName, n->GetLastName(), sizeof(b->LastName));
|
||||
b->Race = n->GetRace();
|
||||
b->Class = n->GetClass();
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
c->QueuePacket(&p);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void EntityList::UpdateFindableNPCState(NPC *n, bool Remove)
|
||||
{
|
||||
if (!n || !n->IsFindable())
|
||||
if (!n || !n->IsFindable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct));
|
||||
static EQApplicationPacket p(OP_SendFindableNPCs, sizeof(FindableNPC_Struct));
|
||||
auto b = (FindableNPC_Struct *) p.pBuffer;
|
||||
b->Unknown109 = 0x16;
|
||||
b->Unknown110 = 0x06;
|
||||
b->Unknown111 = 0x24;
|
||||
|
||||
FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer;
|
||||
|
||||
fnpcs->Unknown109 = 0x16;
|
||||
fnpcs->Unknown110 = 0x06;
|
||||
fnpcs->Unknown111 = 0x24;
|
||||
|
||||
fnpcs->Action = Remove ? 1: 0;
|
||||
fnpcs->EntityID = n->GetID();
|
||||
strn0cpy(fnpcs->Name, n->GetCleanName(), sizeof(fnpcs->Name));
|
||||
strn0cpy(fnpcs->LastName, n->GetLastName(), sizeof(fnpcs->LastName));
|
||||
fnpcs->Race = n->GetRace();
|
||||
fnpcs->Class = n->GetClass();
|
||||
b->Action = Remove ? 1 : 0;
|
||||
b->EntityID = n->GetID();
|
||||
strn0cpy(b->Name, n->GetCleanName(), sizeof(b->Name));
|
||||
strn0cpy(b->LastName, n->GetLastName(), sizeof(b->LastName));
|
||||
b->Race = n->GetRace();
|
||||
b->Class = n->GetClass();
|
||||
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
Client *c = it->second;
|
||||
if (c && (c->ClientVersion() >= EQ::versions::ClientVersion::SoD))
|
||||
c->QueuePacket(outapp);
|
||||
if (c && (c->ClientVersion() >= EQ::versions::ClientVersion::SoD)) {
|
||||
c->QueuePacket(&p);
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void EntityList::HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode)
|
||||
@@ -5759,10 +5752,6 @@ void EntityList::ReloadMerchants() {
|
||||
* then we return the full list
|
||||
*
|
||||
* See comments @EntityList::ScanCloseMobs for system explanation
|
||||
*
|
||||
* @param mob
|
||||
* @param distance
|
||||
* @return
|
||||
*/
|
||||
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
|
||||
{
|
||||
|
||||
@@ -631,8 +631,6 @@ private:
|
||||
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
|
||||
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
|
||||
|
||||
void ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob);
|
||||
|
||||
void GetBotList(std::list<Bot*> &b_list);
|
||||
private:
|
||||
std::list<Bot*> bot_list;
|
||||
|
||||
+6
-5
@@ -497,7 +497,7 @@ void Client::CalculateExp(uint64 in_add_exp, uint64 &add_exp, uint64 &add_aaxp,
|
||||
add_exp = GetEXP() + add_exp;
|
||||
}
|
||||
|
||||
void Client::AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
void Client::AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel, bool resexp, NPC* npc) {
|
||||
if (!IsEXPEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -574,10 +574,10 @@ void Client::AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel, boo
|
||||
}
|
||||
|
||||
// Now update our character's normal and AA xp
|
||||
SetEXP(exp_source, exp, aaexp, resexp);
|
||||
SetEXP(exp_source, exp, aaexp, resexp, npc);
|
||||
}
|
||||
|
||||
void Client::SetEXP(ExpSource exp_source, uint64 set_exp, uint64 set_aaxp, bool isrezzexp) {
|
||||
void Client::SetEXP(ExpSource exp_source, uint64 set_exp, uint64 set_aaxp, bool isrezzexp, NPC* npc) {
|
||||
uint64 current_exp = GetEXP();
|
||||
uint64 current_aa_exp = GetAAXP();
|
||||
uint64 total_current_exp = current_exp + current_aa_exp;
|
||||
@@ -677,6 +677,7 @@ void Client::SetEXP(ExpSource exp_source, uint64 set_exp, uint64 set_aaxp, bool
|
||||
}
|
||||
}
|
||||
}
|
||||
ProcessEvolvingItem(exp_gained, npc);
|
||||
} else if(total_add_exp < total_current_exp) { //only loss message if you lose exp, no message if you gained/lost nothing.
|
||||
uint64 exp_lost = current_exp - set_exp;
|
||||
float exp_percent = (float)((float)exp_lost / (float)(GetEXPForLevel(GetLevel() + 1) - GetEXPForLevel(GetLevel())))*(float)100;
|
||||
@@ -1205,7 +1206,7 @@ void Group::SplitExp(ExpSource exp_source, const uint64 exp, Mob* other) {
|
||||
if (diff >= max_diff) {
|
||||
const uint64 tmp = (m->GetLevel() + 3) * (m->GetLevel() + 3) * 75 * 35 / 10;
|
||||
const uint64 tmp2 = group_experience / member_count;
|
||||
m->CastToClient()->AddEXP(exp_source, tmp < tmp2 ? tmp : tmp2, consider_level);
|
||||
m->CastToClient()->AddEXP(exp_source, tmp < tmp2 ? tmp : tmp2, consider_level, false, other->CastToNPC());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1256,7 +1257,7 @@ void Raid::SplitExp(ExpSource exp_source, const uint64 exp, Mob* other) {
|
||||
if (diff >= max_diff) {
|
||||
const uint64 tmp = (m.member->GetLevel() + 3) * (m.member->GetLevel() + 3) * 75 * 35 / 10;
|
||||
const uint64 tmp2 = (raid_experience / member_modifier) + 1;
|
||||
m.member->AddEXP(exp_source, tmp < tmp2 ? tmp : tmp2, consider_level);
|
||||
m.member->AddEXP(exp_source, tmp < tmp2 ? tmp : tmp2, consider_level, false, other->CastToNPC());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
#include "../client.h"
|
||||
#include "../command.h"
|
||||
#include "../../common/evolving_items.h"
|
||||
|
||||
void command_evolvingitems(Client *c, const Seperator *sep)
|
||||
{
|
||||
const uint16 arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
SendEvolvingItemsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
|
||||
Client* t = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
t = c->GetTarget()->CastToClient();
|
||||
}
|
||||
|
||||
const bool is_item = !strcasecmp(sep->arg[1], "item");
|
||||
const bool is_target = !strcasecmp(sep->arg[1], "target");
|
||||
|
||||
if (!is_item && !is_target) {
|
||||
SendEvolvingItemsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_target) {
|
||||
if (arguments > 1) {
|
||||
c->Message(Chat::White, "Usage: #evolve target");
|
||||
} else {
|
||||
c->Message(Chat::Red, "Worn Items");
|
||||
for (auto const &[key, value]: t->GetInv().GetWorn()) {
|
||||
if (!value->IsEvolving()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = evolving_items_manager.GetEvolvingItemsCache().at(value->GetID());
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Evolving Items | {:0d}",
|
||||
value->GetID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Unique ID | {:0d}",
|
||||
value->GetEvolveUniqueID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Final Item ID | {:0d}",
|
||||
value->GetEvolveFinalItemID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Activated | {}",
|
||||
value->GetEvolveActivated() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Equipped | {}",
|
||||
value->GetEvolveEquipped() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Current Amount | {:0d}",
|
||||
value->GetEvolveCurrentAmount()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Required Amount | {:0d}",
|
||||
item.required_amount
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Progression (%) | {:.2f}",
|
||||
value->GetEvolveProgression()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Type | {}",
|
||||
item.type
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Subtype | {}",
|
||||
item.sub_type
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer | {}",
|
||||
value->GetTimers().at("evolve").Enabled()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer Remaining | {}",
|
||||
value->GetTimers().at("evolve").GetRemainingTime()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
c->Message(Chat::Red, "Personal Items");
|
||||
for (auto const &[key, value]: t->GetInv().GetPersonal()) {
|
||||
if (!value->IsEvolving()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = evolving_items_manager.GetEvolvingItemsCache().at(value->GetID());
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Evolving Items | {:0d}",
|
||||
value->GetID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Unique ID | {:0d}",
|
||||
value->GetEvolveUniqueID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Final Item ID | {:0d}",
|
||||
value->GetEvolveFinalItemID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Activated | {}",
|
||||
value->GetEvolveActivated() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Equipped | {}",
|
||||
value->GetEvolveEquipped() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Current Amount | {:0d}",
|
||||
value->GetEvolveCurrentAmount()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Required Amount | {:0d}",
|
||||
item.required_amount
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Progression (%) | {:.2f}",
|
||||
value->GetEvolveProgression()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Type | {}",
|
||||
item.type
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Subtype | {}",
|
||||
item.sub_type
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer | {}",
|
||||
value->GetTimers().at("evolve").Enabled()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer Remaining | {}",
|
||||
value->GetTimers().at("evolve").GetRemainingTime()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (is_item) {
|
||||
if (arguments > 2) {
|
||||
c->Message(Chat::White, "Usage: #evolve item item_id");
|
||||
} else if (sep->IsNumber(2)) {
|
||||
auto item_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
auto item = c->GetInv().GetItem(c->GetInv().HasItem(item_id));
|
||||
if (item) {
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Evolving Items | {:0d}",
|
||||
item->GetID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Slot | {:0d}",
|
||||
c->GetInv().HasItem(item_id)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Activated | {}",
|
||||
item->GetEvolveActivated() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Equipped | {}",
|
||||
item->GetEvolveEquipped() ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Unique ID | {:0d}",
|
||||
item->GetEvolveUniqueID()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Progression (%) | {:.2f}",
|
||||
item->GetEvolveProgression()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer | {}",
|
||||
item->GetTimers().at("evolve").Enabled()
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Timer Remaining | {}",
|
||||
item->GetTimers().at("evolve").GetRemainingTime()
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"Item {} could not be found in your inventory.",
|
||||
item_id
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
SendEvolvingItemsSubCommands(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendEvolvingItemsSubCommands(Client *c)
|
||||
{
|
||||
c->Message(Chat::White, "#evolve item item_id (Shows evolve values within the iteminstance)");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#evolve target (Shows evolve values within the target's cache - Must have a player target selected.)"
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,19 @@ void command_loc(Client *c, const Seperator *sep)
|
||||
|
||||
auto target_position = target->GetPosition();
|
||||
|
||||
// check los benchmark
|
||||
BenchTimer timer;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
zone->zonemap->CheckLoS(c->GetPosition(), target_position);
|
||||
}
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"CheckLoS benchmark took [{}]",
|
||||
timer.elapsed()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
|
||||
@@ -132,4 +132,6 @@ void command_summonitem(Client *c, const Seperator *sep)
|
||||
item_link
|
||||
).c_str()
|
||||
);
|
||||
|
||||
safe_delete(new_item);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "../client.h"
|
||||
|
||||
void command_zone_shard(Client *c, const Seperator *sep)
|
||||
{
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments || !sep->IsNumber(1)) {
|
||||
if (!RuleB(Zone, ZoneShardQuestMenuOnly)) {
|
||||
c->ShowZoneShardMenu();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->GetAggroCount() > 0) {
|
||||
c->Message(Chat::White, "You cannot request a shard change while in combat.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string zone_input = sep->arg[1];
|
||||
uint32 zone_id = 0;
|
||||
|
||||
// if input is id
|
||||
if (Strings::IsNumber(zone_input)) {
|
||||
zone_id = Strings::ToInt(zone_input);
|
||||
|
||||
// validate
|
||||
if (zone_id != 0 && !GetZone(zone_id)) {
|
||||
c->Message(Chat::White, fmt::format("Could not find zone by id [{}]", zone_id).c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// validate
|
||||
if (!zone_store.GetZone(zone_input)) {
|
||||
c->Message(Chat::White, fmt::format("Could not find zone by short_name [{}]", zone_input).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// validate we got id
|
||||
zone_id = ZoneID(zone_input);
|
||||
if (zone_id == 0) {
|
||||
c->Message(Chat::White, fmt::format("Could not find zone id by short_name [{}]", zone_input).c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto z = GetZone(zone_id);
|
||||
if (z && z->shard_at_player_count == 0) {
|
||||
c->Message(Chat::White, "Zone does not have sharding enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto instance_id = sep->arg[2] ? Strings::ToBigInt(sep->arg[2]) : 0;
|
||||
if (instance_id < -1) {
|
||||
c->Message(Chat::White, "You must enter a valid Instance ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (zone_id == c->GetZoneID() && c->GetInstanceID() == instance_id) {
|
||||
c->Message(Chat::White, "You are already in this shard.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (zone_id != c->GetZoneID()) {
|
||||
c->Message(Chat::White, "You must request a shard change from the zone you are currently in.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto results = CharacterDataRepository::GetInstanceZonePlayerCounts(database, c->GetZoneID());
|
||||
if (results.size() <= 1) {
|
||||
c->Message(Chat::White, "No shards found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance_id > 0) {
|
||||
if (!database.CheckInstanceExists(instance_id)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Instance ID {} does not exist.",
|
||||
instance_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto instance_zone_id = database.GetInstanceZoneID(instance_id);
|
||||
if (!instance_zone_id) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Instance ID {} not found or zone is set to null.",
|
||||
instance_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance_zone_id != zone_id) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Instance Zone ID {} does not match zone ID {}.",
|
||||
instance_id,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!database.CheckInstanceByCharID(instance_id, c->CharacterID())) {
|
||||
database.AddClientToInstance(instance_id, c->CharacterID());
|
||||
}
|
||||
|
||||
if (!database.VerifyInstanceAlive(instance_id, c->CharacterID())) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Instance ID {} expired.",
|
||||
instance_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
c->MovePC(
|
||||
zone_id,
|
||||
instance_id,
|
||||
c->GetX(),
|
||||
c->GetY(),
|
||||
c->GetZ(),
|
||||
c->GetHeading(),
|
||||
0,
|
||||
ZoneSolicited
|
||||
);
|
||||
}
|
||||
+76
-93
@@ -25,6 +25,7 @@
|
||||
#include "zonedb.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "bot.h"
|
||||
#include "../common/evolving_items.h"
|
||||
#include "../common/repositories/character_corpse_items_repository.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
@@ -1091,7 +1092,11 @@ void Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_up
|
||||
}
|
||||
// end QS code
|
||||
|
||||
bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
|
||||
uint64 evolve_id = m_inv[slot_id]->GetEvolveUniqueID();
|
||||
bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
|
||||
if (isDeleted && evolve_id && (slot_id > EQ::invslot::TRADE_END || slot_id < EQ::invslot::TRADE_BEGIN)) {
|
||||
CharacterEvolvingItemsRepository::SoftDelete(database, evolve_id);
|
||||
}
|
||||
|
||||
const EQ::ItemInstance* inst = nullptr;
|
||||
if (slot_id == EQ::invslot::slotCursor) {
|
||||
@@ -1143,6 +1148,8 @@ void Client::DeleteItemInInventory(int16 slot_id, int16 quantity, bool client_up
|
||||
bool Client::PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update)
|
||||
{
|
||||
LogInventory("Putting item [{}] ([{}]) on the cursor", inst.GetItem()->Name, inst.GetItem()->ID);
|
||||
|
||||
evolving_items_manager.DoLootChecks(CharacterID(), EQ::invslot::slotCursor, inst);
|
||||
m_inv.PushCursor(inst);
|
||||
|
||||
if (client_update) {
|
||||
@@ -1163,9 +1170,9 @@ bool Client::PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, boo
|
||||
if (slot_id == EQ::invslot::slotCursor) { // don't trust macros before conditional statements...
|
||||
return PushItemOnCursor(inst, client_update);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
}
|
||||
|
||||
evolving_items_manager.DoLootChecks(CharacterID(), slot_id, inst);
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
|
||||
if (client_update)
|
||||
{
|
||||
@@ -1173,15 +1180,16 @@ bool Client::PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, boo
|
||||
//SendWearChange(EQ::InventoryProfile::CalcMaterialFromSlot(slot_id));
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
|
||||
if (slot_id == EQ::invslot::slotCursor) {
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
return database.SaveCursor(CharacterID(), s, e);
|
||||
}
|
||||
else {
|
||||
return database.SaveInventory(CharacterID(), &inst, slot_id);
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
return database.SaveInventory(CharacterID(), &inst, slot_id);
|
||||
|
||||
//CalcBonuses(); // this never fires??
|
||||
// a lot of wasted checks and calls coded above...
|
||||
}
|
||||
|
||||
@@ -1191,6 +1199,8 @@ void Client::PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, Loo
|
||||
|
||||
bool cursor_empty = m_inv.CursorEmpty();
|
||||
|
||||
evolving_items_manager.DoLootChecks(CharacterID(), slot_id, inst);
|
||||
|
||||
if (slot_id == EQ::invslot::slotCursor) {
|
||||
m_inv.PushCursor(inst);
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
@@ -2969,107 +2979,72 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
|
||||
// Two new methods to alleviate perpetual login desyncs
|
||||
void Client::RemoveDuplicateLore(bool client_update)
|
||||
void Client::RemoveDuplicateLore()
|
||||
{
|
||||
for (auto slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
for (auto slot_id : GetInventorySlots()) {
|
||||
if ((((uint64) 1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from slot [{}]", inst->GetItem()->Name, slot_id);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EQ::invslot::GENERAL_BEGIN; slot_id <= EQ::invslot::GENERAL_END; ++slot_id) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
// ignore shared bank slots
|
||||
if (slot_id >= EQ::invslot::SHARED_BANK_BEGIN && slot_id <= EQ::invslot::SHARED_BANK_END) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slot_id >= EQ::invbag::SHARED_BANK_BAGS_BEGIN && slot_id <= EQ::invbag::SHARED_BANK_BAGS_END) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// slot gets handled in a queue
|
||||
if (slot_id == EQ::invslot::slotCursor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// temporarily move the item off of the slot
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from slot [{}]", inst->GetItem()->Name, slot_id);
|
||||
LogError(
|
||||
"Lore Duplication Error | Deleting [{}] ({}) from slot [{}] client [{}]",
|
||||
inst->GetItem()->Name,
|
||||
inst->GetItem()->ID,
|
||||
slot_id,
|
||||
GetCleanName()
|
||||
);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
safe_delete(inst);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
|
||||
// if no lore conflict, put the item back in the slot
|
||||
m_inv.PushItem(slot_id, inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EQ::invbag::GENERAL_BAGS_BEGIN; slot_id <= EQ::invbag::CURSOR_BAG_END; ++slot_id) {
|
||||
auto temp_slot = EQ::invslot::GENERAL_BEGIN + ((slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from slot [{}]", inst->GetItem()->Name, slot_id);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; ++slot_id) {
|
||||
if ((slot_id - EQ::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from slot [{}]", inst->GetItem()->Name, slot_id);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EQ::invbag::BANK_BAGS_BEGIN; slot_id <= EQ::invbag::BANK_BAGS_END; ++slot_id) {
|
||||
auto temp_slot = (slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from slot [{}]", inst->GetItem()->Name, slot_id);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items
|
||||
|
||||
if (!m_inv.CursorEmpty()) {
|
||||
std::list<EQ::ItemInstance*> local_1;
|
||||
std::list<EQ::ItemInstance*> local_2;
|
||||
|
||||
while (!m_inv.CursorEmpty()) {
|
||||
auto inst = m_inv.PopItem(EQ::invslot::slotCursor);
|
||||
if (inst == nullptr) { continue; }
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
local_1.push_back(inst);
|
||||
}
|
||||
|
||||
for (auto iter = local_1.begin(); iter != local_1.end(); ++iter) {
|
||||
auto inst = *iter;
|
||||
if (inst == nullptr) { continue; }
|
||||
for (auto inst: local_1) {
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from `Limbo`", inst->GetItem()->Name);
|
||||
LogError(
|
||||
"Lore Duplication Error | Deleting [{}] ({}) from `Limbo` client [{}]",
|
||||
inst->GetItem()->Name,
|
||||
inst->GetItem()->ID,
|
||||
GetCleanName()
|
||||
);
|
||||
safe_delete(inst);
|
||||
}
|
||||
else {
|
||||
@@ -3078,17 +3053,25 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
}
|
||||
local_1.clear();
|
||||
|
||||
for (auto iter = local_2.begin(); iter != local_2.end(); ++iter) {
|
||||
auto inst = *iter;
|
||||
if (inst == nullptr) { continue; }
|
||||
for (auto inst: local_2) {
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
if (!inst->GetItem()->LoreFlag ||
|
||||
((inst->GetItem()->LoreGroup == -1) && (m_inv.HasItem(inst->GetID(), 0, invWhereCursor) == INVALID_INDEX)) ||
|
||||
(inst->GetItem()->LoreGroup && (~inst->GetItem()->LoreGroup) && (m_inv.HasItemByLoreGroup(inst->GetItem()->LoreGroup, invWhereCursor) == INVALID_INDEX))
|
||||
((inst->GetItem()->LoreGroup == -1) &&
|
||||
(m_inv.HasItem(inst->GetID(), 0, invWhereCursor) == INVALID_INDEX)) ||
|
||||
(inst->GetItem()->LoreGroup && (~inst->GetItem()->LoreGroup) &&
|
||||
(m_inv.HasItemByLoreGroup(inst->GetItem()->LoreGroup, invWhereCursor) == INVALID_INDEX))
|
||||
) {
|
||||
m_inv.PushCursor(*inst);
|
||||
}
|
||||
else {
|
||||
LogInventory("Lore Duplication Error: Deleting [{}] from `Limbo`", inst->GetItem()->Name);
|
||||
LogError(
|
||||
"Lore Duplication Error | Deleting [{}] ({}) from `Limbo` client [{}]",
|
||||
inst->GetItem()->Name,
|
||||
inst->GetItem()->ID,
|
||||
GetCleanName()
|
||||
);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
+5
-1
@@ -687,6 +687,7 @@ void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot)
|
||||
LootItem *item = *cur;
|
||||
if (item->item_id == item_id && slot <= 0 && quantity <= 0) {
|
||||
m_loot_items.erase(cur);
|
||||
safe_delete(item);
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) { SendAppearancePacket(AppearanceType::Light, GetActiveLightType()); }
|
||||
return;
|
||||
@@ -695,7 +696,10 @@ void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot)
|
||||
if (item->charges <= quantity) {
|
||||
m_loot_items.erase(cur);
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) { SendAppearancePacket(AppearanceType::Light, GetActiveLightType()); }
|
||||
if (UpdateActiveLight()) {
|
||||
SendAppearancePacket(AppearanceType::Light, GetActiveLightType());
|
||||
}
|
||||
safe_delete(item);
|
||||
}
|
||||
else {
|
||||
item->charges -= quantity;
|
||||
|
||||
+68
-4
@@ -3436,13 +3436,14 @@ void Lua_Client::AreaTaunt(float range, int bonus_hate)
|
||||
entity_list.AETaunt(self, range, bonus_hate);
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetInventorySlots(lua_State* L) {
|
||||
luabind::object Lua_Client::GetInventorySlots(lua_State* L)
|
||||
{
|
||||
auto lua_table = luabind::newtable(L);
|
||||
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
int index = 1;
|
||||
for (const int16& slot_id : self->GetInventorySlots()) {
|
||||
auto self = reinterpret_cast<NativeType *>(d_);
|
||||
int index = 1;
|
||||
for (const int16 &slot_id: self->GetInventorySlots()) {
|
||||
lua_table[index] = slot_id;
|
||||
index++;
|
||||
}
|
||||
@@ -3451,6 +3452,60 @@ luabind::object Lua_Client::GetInventorySlots(lua_State* L) {
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
void Lua_Client::ShowZoneShardMenu()
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->ShowZoneShardMenu();
|
||||
}
|
||||
|
||||
void Lua_Client::GrantPetNameChange()
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->GrantPetNameChange();
|
||||
}
|
||||
|
||||
void Lua_Client::SetAAEXPPercentage(uint8 percentage)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAAEXPPercentage(percentage);
|
||||
}
|
||||
|
||||
void Lua_Client::SetAccountBucket(std::string bucket_name, std::string bucket_value)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAccountBucket(bucket_name, bucket_value);
|
||||
}
|
||||
|
||||
void Lua_Client::SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAccountBucket(bucket_name, bucket_value, expiration);
|
||||
}
|
||||
|
||||
void Lua_Client::DeleteAccountBucket(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->DeleteAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucket(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucketExpires(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucketExpires(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucketRemaining(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucketRemaining(bucket_name);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -3519,6 +3574,7 @@ luabind::scope lua_register_client() {
|
||||
.def("CanHaveSkill", (bool(Lua_Client::*)(int))&Lua_Client::CanHaveSkill)
|
||||
.def("CashReward", &Lua_Client::CashReward)
|
||||
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
|
||||
.def("GrantPetNameChange", &Lua_Client::GrantPetNameChange)
|
||||
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill)
|
||||
@@ -3539,6 +3595,7 @@ luabind::scope lua_register_client() {
|
||||
.def("CreateTaskDynamicZone", &Lua_Client::CreateTaskDynamicZone)
|
||||
.def("DecreaseByID", (bool(Lua_Client::*)(uint32,int))&Lua_Client::DecreaseByID)
|
||||
.def("DescribeSpecialAbilities", (void(Lua_Client::*)(Lua_NPC))&Lua_Client::DescribeSpecialAbilities)
|
||||
.def("DeleteAccountBucket", (void(Lua_Client::*)(std::string))&Lua_Client::DeleteAccountBucket)
|
||||
.def("DeleteBucket", (void(Lua_Client::*)(std::string))&Lua_Client::DeleteBucket)
|
||||
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int))&Lua_Client::DeleteItemInInventory)
|
||||
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int,bool))&Lua_Client::DeleteItemInInventory)
|
||||
@@ -3617,6 +3674,9 @@ luabind::scope lua_register_client() {
|
||||
.def("GetBotRequiredLevel", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotRequiredLevel)
|
||||
.def("GetBotSpawnLimit", (int(Lua_Client::*)(void))&Lua_Client::GetBotSpawnLimit)
|
||||
.def("GetBotSpawnLimit", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotSpawnLimit)
|
||||
.def("GetAccountBucket", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucket)
|
||||
.def("GetAccountBucketExpires", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucketExpires)
|
||||
.def("GetAccountBucketRemaining", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucketRemaining)
|
||||
.def("GetBucket", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucket)
|
||||
.def("GetBucketExpires", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketExpires)
|
||||
.def("GetBucketRemaining", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketRemaining)
|
||||
@@ -3883,6 +3943,7 @@ luabind::scope lua_register_client() {
|
||||
.def("SetAAEXPModifier", (void(Lua_Client::*)(float))&Lua_Client::SetAAEXPModifier)
|
||||
.def("SetAAEXPModifier", (void(Lua_Client::*)(uint32,float))&Lua_Client::SetAAEXPModifier)
|
||||
.def("SetAAEXPModifier", (void(Lua_Client::*)(uint32,float,int16))&Lua_Client::SetAAEXPModifier)
|
||||
.def("SetAAEXPPercentage", (void(Lua_Client::*)(uint8))&Lua_Client::SetAAEXPPercentage)
|
||||
.def("SetAAPoints", (void(Lua_Client::*)(int))&Lua_Client::SetAAPoints)
|
||||
.def("SetAATitle", (void(Lua_Client::*)(std::string))&Lua_Client::SetAATitle)
|
||||
.def("SetAATitle", (void(Lua_Client::*)(std::string,bool))&Lua_Client::SetAATitle)
|
||||
@@ -3908,6 +3969,8 @@ luabind::scope lua_register_client() {
|
||||
.def("SetBotRequiredLevel", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotRequiredLevel)
|
||||
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int))&Lua_Client::SetBotSpawnLimit)
|
||||
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotSpawnLimit)
|
||||
.def("SetAccountBucket", (void(Lua_Client::*)(std::string,std::string))&Lua_Client::SetAccountBucket)
|
||||
.def("SetAccountBucket", (void(Lua_Client::*)(std::string,std::string,std::string))&Lua_Client::SetAccountBucket)
|
||||
.def("SetBucket", (void(Lua_Client::*)(std::string,std::string))&Lua_Client::SetBucket)
|
||||
.def("SetBucket", (void(Lua_Client::*)(std::string,std::string,std::string))&Lua_Client::SetBucket)
|
||||
.def("SetClientMaxLevel", (void(Lua_Client::*)(int))&Lua_Client::SetClientMaxLevel)
|
||||
@@ -3970,6 +4033,7 @@ luabind::scope lua_register_client() {
|
||||
.def("SetTint", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetTint)
|
||||
.def("SetTitleSuffix", (void(Lua_Client::*)(const char *))&Lua_Client::SetTitleSuffix)
|
||||
.def("SetZoneFlag", (void(Lua_Client::*)(uint32))&Lua_Client::SetZoneFlag)
|
||||
.def("ShowZoneShardMenu", (void(Lua_Client::*)(void))&Lua_Client::ShowZoneShardMenu)
|
||||
.def("Signal", (void(Lua_Client::*)(int))&Lua_Client::Signal)
|
||||
.def("Sit", (void(Lua_Client::*)(void))&Lua_Client::Sit)
|
||||
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)
|
||||
|
||||
@@ -510,6 +510,15 @@ public:
|
||||
void AreaTaunt(float range);
|
||||
void AreaTaunt(float range, int bonus_hate);
|
||||
luabind::object GetInventorySlots(lua_State* L);
|
||||
void SetAAEXPPercentage(uint8 percentage);
|
||||
|
||||
// account data buckets
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value);
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
|
||||
void DeleteAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucketExpires(std::string bucket_name);
|
||||
std::string GetAccountBucketRemaining(std::string bucket_name);
|
||||
|
||||
void ApplySpell(int spell_id);
|
||||
void ApplySpell(int spell_id, int duration);
|
||||
@@ -587,6 +596,8 @@ public:
|
||||
void DialogueWindow(std::string markdown);
|
||||
|
||||
bool ReloadDataBuckets();
|
||||
void ShowZoneShardMenu();
|
||||
void GrantPetNameChange();
|
||||
|
||||
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
||||
|
||||
@@ -4668,16 +4668,6 @@ int lua_get_zone_npc_maximum_aggro_distance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 lua_get_zone_minimum_expansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@@ -6287,8 +6277,6 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("get_zone_fast_regen_endurance", (int(*)(uint32,int))&lua_get_zone_fast_regen_endurance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32,int))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32,int))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32,int))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_maximum_expansion", (int8(*)(uint32))&lua_get_zone_maximum_expansion),
|
||||
|
||||
+105
-6
@@ -255,11 +255,6 @@ int8 Lua_ItemInst::GetMaxEvolveLvl() {
|
||||
return self->GetMaxEvolveLvl();
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetKillsNeeded(uint8 current_level) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetKillsNeeded(current_level);
|
||||
}
|
||||
|
||||
Lua_ItemInst Lua_ItemInst::Clone() {
|
||||
Lua_Safe_Call_Class(Lua_ItemInst);
|
||||
return Lua_ItemInst(self->Clone(), true);
|
||||
@@ -348,6 +343,96 @@ std::string Lua_ItemInst::GetItemLink()
|
||||
return linker.GenerateLink();
|
||||
}
|
||||
|
||||
void Lua_ItemInst::AddEvolveAmount(uint64 amount)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetEvolveAddToCurrentAmount(amount);
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetAugmentEvolveUniqueID(uint8 slot_id)
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetAugmentEvolveUniqueID(slot_id);
|
||||
}
|
||||
|
||||
bool Lua_ItemInst::GetEvolveActivated()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetEvolveActivated();
|
||||
}
|
||||
|
||||
uint64 Lua_ItemInst::GetEvolveAmount()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveCurrentAmount();
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetEvolveCharacterID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveCharID();
|
||||
}
|
||||
|
||||
bool Lua_ItemInst::GetEvolveEquipped()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetEvolveEquipped();
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetEvolveFinalItemID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveFinalItemID();
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetEvolveItemID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveItemID();
|
||||
}
|
||||
|
||||
int8 Lua_ItemInst::GetEvolveLevel()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveLvl();
|
||||
}
|
||||
|
||||
uint32 Lua_ItemInst::GetEvolveLoreID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveLoreID();
|
||||
}
|
||||
|
||||
float Lua_ItemInst::GetEvolveProgression()
|
||||
{
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetEvolveProgression();
|
||||
}
|
||||
|
||||
uint64 Lua_ItemInst::GetEvolveUniqueID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetEvolveUniqueID();
|
||||
}
|
||||
|
||||
bool Lua_ItemInst::IsEvolving()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsEvolving();
|
||||
}
|
||||
|
||||
void Lua_ItemInst::SetEvolveAmount(uint64 amount)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetEvolveCurrentAmount(amount);
|
||||
}
|
||||
|
||||
void Lua_ItemInst::SetEvolveProgression(float amount)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetEvolveProgression(amount);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_iteminst() {
|
||||
return luabind::class_<Lua_ItemInst>("ItemInst")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -356,12 +441,14 @@ luabind::scope lua_register_iteminst() {
|
||||
.property("null", &Lua_ItemInst::Null)
|
||||
.property("valid", &Lua_ItemInst::Valid)
|
||||
.def("AddExp", (void(Lua_ItemInst::*)(uint32))&Lua_ItemInst::AddExp)
|
||||
.def("AddEvolveAmount", (void(Lua_ItemInst::*)(uint64))&Lua_ItemInst::AddEvolveAmount)
|
||||
.def("ClearTimers", (void(Lua_ItemInst::*)(void))&Lua_ItemInst::ClearTimers)
|
||||
.def("Clone", (Lua_ItemInst(Lua_ItemInst::*)(void))&Lua_ItemInst::Clone)
|
||||
.def("ContainsAugmentByID", (bool(Lua_ItemInst::*)(uint32))&Lua_ItemInst::ContainsAugmentByID)
|
||||
.def("CountAugmentByID", (int(Lua_ItemInst::*)(uint32))&Lua_ItemInst::CountAugmentByID)
|
||||
.def("DeleteCustomData", (void(Lua_ItemInst::*)(const std::string &))&Lua_ItemInst::DeleteCustomData)
|
||||
.def("GetAugment", (Lua_ItemInst(Lua_ItemInst::*)(int))&Lua_ItemInst::GetAugment)
|
||||
.def("GetAugmentEvolveUniqueID", (uint32(Lua_ItemInst::*)(uint8))&Lua_ItemInst::GetAugmentEvolveUniqueID)
|
||||
.def("GetAugmentIDs", (luabind::object(Lua_ItemInst::*)(lua_State*))&Lua_ItemInst::GetAugmentIDs)
|
||||
.def("GetAugmentItemID", (uint32(Lua_ItemInst::*)(int))&Lua_ItemInst::GetAugmentItemID)
|
||||
.def("GetAugmentType", (int(Lua_ItemInst::*)(void))&Lua_ItemInst::GetAugmentType)
|
||||
@@ -370,13 +457,22 @@ luabind::scope lua_register_iteminst() {
|
||||
.def("GetCustomData", (std::string(Lua_ItemInst::*)(const std::string &))&Lua_ItemInst::GetCustomData)
|
||||
.def("GetCustomDataString", (std::string(Lua_ItemInst::*)(void))&Lua_ItemInst::GetCustomDataString)
|
||||
.def("GetExp", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetExp)
|
||||
.def("GetEvolveActivated", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveActivated)
|
||||
.def("GetEvolveAmount", (uint64(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveAmount)
|
||||
.def("GetEvolveCharacterID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveCharacterID)
|
||||
.def("GetEvolveEquipped", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveEquipped)
|
||||
.def("GetEvolveFinalItemID", (uint64(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveFinalItemID)
|
||||
.def("GetEvolveItemID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveItemID)
|
||||
.def("GetEvolveLevel", (int8(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveLevel)
|
||||
.def("GetEvolveLoreID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveLoreID)
|
||||
.def("GetEvolveProgression", (float(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveProgression)
|
||||
.def("GetEvolveUniqueID", (uint64(Lua_ItemInst::*)(void))&Lua_ItemInst::GetEvolveUniqueID)
|
||||
.def("GetID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetID)
|
||||
.def("GetItem", (Lua_Item(Lua_ItemInst::*)(void))&Lua_ItemInst::GetItem)
|
||||
.def("GetItem", (Lua_ItemInst(Lua_ItemInst::*)(uint8))&Lua_ItemInst::GetItem)
|
||||
.def("GetItemID", (uint32(Lua_ItemInst::*)(int))&Lua_ItemInst::GetItemID)
|
||||
.def("GetItemLink", (std::string(Lua_ItemInst::*)(void))&Lua_ItemInst::GetItemLink)
|
||||
.def("GetItemScriptID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetItemScriptID)
|
||||
.def("GetKillsNeeded", (uint32(Lua_ItemInst::*)(int))&Lua_ItemInst::GetKillsNeeded)
|
||||
.def("GetMaxEvolveLvl", (int(Lua_ItemInst::*)(void))&Lua_ItemInst::GetMaxEvolveLvl)
|
||||
.def("GetName", (std::string(Lua_ItemInst::*)(void))&Lua_ItemInst::GetName)
|
||||
.def("GetPrice", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetPrice)
|
||||
@@ -389,6 +485,7 @@ luabind::scope lua_register_iteminst() {
|
||||
.def("IsAugmented", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::IsAugmented)
|
||||
.def("IsEquipable", (bool(Lua_ItemInst::*)(int16))&Lua_ItemInst::IsEquipable)
|
||||
.def("IsEquipable", (bool(Lua_ItemInst::*)(uint16,uint16))&Lua_ItemInst::IsEquipable)
|
||||
.def("IsEvolving", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::IsEvolving)
|
||||
.def("IsExpendable", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::IsExpendable)
|
||||
.def("IsInstNoDrop", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::IsInstNoDrop)
|
||||
.def("IsStackable", (bool(Lua_ItemInst::*)(void))&Lua_ItemInst::IsStackable)
|
||||
@@ -404,6 +501,8 @@ luabind::scope lua_register_iteminst() {
|
||||
.def("SetCustomData", (void(Lua_ItemInst::*)(const std::string&,float))&Lua_ItemInst::SetCustomData)
|
||||
.def("SetCustomData", (void(Lua_ItemInst::*)(const std::string&,int))&Lua_ItemInst::SetCustomData)
|
||||
.def("SetCustomData", (void(Lua_ItemInst::*)(const std::string&,const std::string&))&Lua_ItemInst::SetCustomData)
|
||||
.def("SetEvolveAmount", (void(Lua_ItemInst::*)(uint64))&Lua_ItemInst::SetEvolveAmount)
|
||||
.def("SetEvolveProgression", (void(Lua_ItemInst::*)(float))&Lua_ItemInst::SetEvolveProgression)
|
||||
.def("SetExp", (void(Lua_ItemInst::*)(uint32))&Lua_ItemInst::SetExp)
|
||||
.def("SetInstNoDrop", (void(Lua_ItemInst::*)(bool))&Lua_ItemInst::SetInstNoDrop)
|
||||
.def("SetPrice", (void(Lua_ItemInst::*)(uint32))&Lua_ItemInst::SetPrice)
|
||||
|
||||
+15
-1
@@ -77,7 +77,6 @@ public:
|
||||
void SetExp(uint32 exp);
|
||||
void AddExp(uint32 exp);
|
||||
int8 GetMaxEvolveLvl();
|
||||
uint32 GetKillsNeeded(uint8 current_level);
|
||||
Lua_ItemInst Clone();
|
||||
void SetTimer(std::string name, uint32 time);
|
||||
void StopTimer(std::string name);
|
||||
@@ -91,6 +90,21 @@ public:
|
||||
void ItemSay(const char* text, uint8 language_id);
|
||||
luabind::object GetAugmentIDs(lua_State* L);
|
||||
std::string GetItemLink();
|
||||
void AddEvolveAmount(uint64 amount);
|
||||
uint32 GetAugmentEvolveUniqueID(uint8 slot_id);
|
||||
bool GetEvolveActivated();
|
||||
uint64 GetEvolveAmount();
|
||||
uint32 GetEvolveCharacterID();
|
||||
bool GetEvolveEquipped();
|
||||
uint32 GetEvolveFinalItemID();
|
||||
uint32 GetEvolveItemID();
|
||||
int8 GetEvolveLevel();
|
||||
uint32 GetEvolveLoreID();
|
||||
float GetEvolveProgression();
|
||||
uint64 GetEvolveUniqueID();
|
||||
bool IsEvolving();
|
||||
void SetEvolveAmount(uint64 amount);
|
||||
void SetEvolveProgression(float amount);
|
||||
|
||||
private:
|
||||
bool cloned_;
|
||||
|
||||
+3
-1
@@ -896,6 +896,7 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("Weblink", static_cast<int>(OP_Weblink)),
|
||||
luabind::value("InspectMessageUpdate", static_cast<int>(OP_InspectMessageUpdate)),
|
||||
luabind::value("ItemPreview", static_cast<int>(OP_ItemPreview)),
|
||||
luabind::value("ItemPreviewRequest", static_cast<int>(OP_ItemPreviewRequest)),
|
||||
luabind::value("MercenaryDataRequest", static_cast<int>(OP_MercenaryDataRequest)),
|
||||
luabind::value("MercenaryDataResponse", static_cast<int>(OP_MercenaryDataResponse)),
|
||||
luabind::value("MercenaryHire", static_cast<int>(OP_MercenaryHire)),
|
||||
@@ -915,7 +916,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("Marquee", static_cast<int>(OP_Marquee)),
|
||||
luabind::value("ClientTimeStamp", static_cast<int>(OP_ClientTimeStamp)),
|
||||
luabind::value("GuildPromote", static_cast<int>(OP_GuildPromote)),
|
||||
luabind::value("Fling", static_cast<int>(OP_Fling))
|
||||
luabind::value("Fling", static_cast<int>(OP_Fling)),
|
||||
luabind::value("PickZoneWindow", static_cast<int>(OP_PickZoneWindow))
|
||||
)];
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "task_manager.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "embparser.h"
|
||||
#include "../common/evolving_items.h"
|
||||
#include "lua_parser.h"
|
||||
#include "questmgr.h"
|
||||
#include "npc_scale_manager.h"
|
||||
@@ -110,6 +111,7 @@ PathManager path;
|
||||
PlayerEventLogs player_event_logs;
|
||||
DatabaseUpdate database_update;
|
||||
SkillCaps skill_caps;
|
||||
EvolvingItemsManager evolving_items_manager;
|
||||
|
||||
const SPDat_Spell_Struct* spells;
|
||||
int32 SPDAT_RECORDS = -1;
|
||||
@@ -387,6 +389,11 @@ int main(int argc, char **argv)
|
||||
title_manager.LoadTitles();
|
||||
content_db.LoadTributes();
|
||||
|
||||
// Load evolving item data
|
||||
evolving_items_manager.SetDatabase(&database);
|
||||
evolving_items_manager.SetContentDatabase(&content_db);
|
||||
evolving_items_manager.LoadEvolvingItems();
|
||||
|
||||
database.GetDecayTimes(npcCorpseDecayTimes);
|
||||
|
||||
if (!EQ::ProfanityManager::LoadProfanityList(&database)) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "raycast_mesh.h"
|
||||
#include "zone.h"
|
||||
#include "../common/file.h"
|
||||
#include "../common/memory/ksm.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
@@ -953,6 +954,7 @@ bool Map::LoadV2(FILE *f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Map::RotateVertex(glm::vec3 &v, float rx, float ry, float rz) {
|
||||
glm::vec3 nv = v;
|
||||
|
||||
|
||||
+26
-34
@@ -125,10 +125,11 @@ Mob::Mob(
|
||||
tmHidden(-1),
|
||||
mitigation_ac(0),
|
||||
m_specialattacks(eSpecialAttacks::None),
|
||||
attack_anim_timer(500),
|
||||
attack_anim_timer(100),
|
||||
position_update_melee_push_timer(500),
|
||||
hate_list_cleanup_timer(6000),
|
||||
m_scan_close_mobs_timer(6000),
|
||||
m_see_close_mobs_timer(1000),
|
||||
m_mob_check_moving_timer(1000),
|
||||
bot_attack_flag_timer(10000)
|
||||
{
|
||||
@@ -1521,16 +1522,12 @@ void Mob::SendHPUpdate(bool force_update_all)
|
||||
last_hp
|
||||
);
|
||||
|
||||
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
|
||||
auto *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer;
|
||||
|
||||
hp_packet_client->cur_hp = static_cast<uint32>(CastToClient()->GetHP() - itembonuses.HP);
|
||||
hp_packet_client->spawn_id = GetID();
|
||||
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
|
||||
|
||||
CastToClient()->QueuePacket(client_packet);
|
||||
|
||||
safe_delete(client_packet);
|
||||
static EQApplicationPacket p(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
|
||||
auto b = (SpawnHPUpdate_Struct*) p.pBuffer;
|
||||
b->cur_hp = static_cast<uint32>(CastToClient()->GetHP() - itembonuses.HP);
|
||||
b->spawn_id = GetID();
|
||||
b->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
|
||||
CastToClient()->QueuePacket(&p);
|
||||
|
||||
ResetHPUpdateTimer();
|
||||
|
||||
@@ -3539,24 +3536,21 @@ void Mob::DoAnim(const int animation_id, int animation_speed, bool ackreq, eqFil
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct));
|
||||
auto *a = (Animation_Struct *) outapp->pBuffer;
|
||||
|
||||
static EQApplicationPacket p(OP_Animation, sizeof(Animation_Struct));
|
||||
auto a = (Animation_Struct*) p.pBuffer;
|
||||
a->spawnid = GetID();
|
||||
a->action = animation_id;
|
||||
a->speed = animation_speed ? animation_speed : 10;
|
||||
|
||||
entity_list.QueueCloseClients(
|
||||
this, /* Sender */
|
||||
outapp, /* Packet */
|
||||
&p, /* Packet */
|
||||
false, /* Ignore Sender */
|
||||
RuleI(Range, Anims),
|
||||
0, /* Skip this mob */
|
||||
ackreq, /* Packet ACK */
|
||||
filter /* eqFilterType filter */
|
||||
);
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::ShowBuffs(Client* c) {
|
||||
@@ -7716,28 +7710,26 @@ bool Mob::CanRaceEquipItem(uint32 item_id)
|
||||
|
||||
void Mob::SendAddPlayerState(PlayerState new_state)
|
||||
{
|
||||
auto app = new EQApplicationPacket(OP_PlayerStateAdd, sizeof(PlayerState_Struct));
|
||||
auto ps = (PlayerState_Struct *)app->pBuffer;
|
||||
static EQApplicationPacket p(OP_PlayerStateAdd, sizeof(PlayerState_Struct));
|
||||
auto b = (PlayerState_Struct *) p.pBuffer;
|
||||
|
||||
ps->spawn_id = GetID();
|
||||
ps->state = static_cast<uint32>(new_state);
|
||||
b->spawn_id = GetID();
|
||||
b->state = static_cast<uint32>(new_state);
|
||||
|
||||
AddPlayerState(ps->state);
|
||||
entity_list.QueueClients(nullptr, app);
|
||||
safe_delete(app);
|
||||
AddPlayerState(b->state);
|
||||
entity_list.QueueClients(nullptr, &p);
|
||||
}
|
||||
|
||||
void Mob::SendRemovePlayerState(PlayerState old_state)
|
||||
{
|
||||
auto app = new EQApplicationPacket(OP_PlayerStateRemove, sizeof(PlayerState_Struct));
|
||||
auto ps = (PlayerState_Struct *)app->pBuffer;
|
||||
static EQApplicationPacket p(OP_PlayerStateRemove, sizeof(PlayerState_Struct));
|
||||
auto b = (PlayerState_Struct *) p.pBuffer;
|
||||
|
||||
ps->spawn_id = GetID();
|
||||
ps->state = static_cast<uint32>(old_state);
|
||||
b->spawn_id = GetID();
|
||||
b->state = static_cast<uint32>(old_state);
|
||||
|
||||
RemovePlayerState(ps->state);
|
||||
entity_list.QueueClients(nullptr, app);
|
||||
safe_delete(app);
|
||||
RemovePlayerState(b->state);
|
||||
entity_list.QueueClients(nullptr, &p);
|
||||
}
|
||||
|
||||
int32 Mob::GetMeleeMitigation() {
|
||||
@@ -8612,15 +8604,15 @@ std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float distance)
|
||||
void Mob::ClearDataBucketCache()
|
||||
{
|
||||
if (IsOfClientBot()) {
|
||||
uint64 id = 0;
|
||||
uint64 id = 0;
|
||||
DataBucketLoadType::Type t{};
|
||||
if (IsBot()) {
|
||||
id = CastToBot()->GetBotID();
|
||||
t = DataBucketLoadType::Bot;
|
||||
t = DataBucketLoadType::Bot;
|
||||
}
|
||||
else if (IsClient()) {
|
||||
id = CastToClient()->CharacterID();
|
||||
t = DataBucketLoadType::Client;
|
||||
t = DataBucketLoadType::Client;
|
||||
}
|
||||
|
||||
DataBucket::DeleteFromCache(id, t);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user