Compare commits

...
Sign in to create a new pull request.

13 commits

Author SHA1 Message Date
Chris Miles
8175ae6187 [Release] 23.10.3 2025-09-17 01:31:48 -05:00
Chris Miles
e8f4ffd628 [Release] 23.10.2 2025-09-17 00:52:31 -05:00
Chris Miles
0447618f7e hotfix: merge fix 2025-09-17 00:50:03 -05:00
Chris Miles
e71ce001ff Hotfix: revert #4996 2025-09-17 00:47:42 -05:00
Alex King
1575a2af40
[Hotfix] Fixed Mail Key Bug (#5015)
* [Hotfix] Fixed Mail Key Bug

* Release
2025-09-16 22:52:57 -04:00
JJ
4b69df646c
[Release] 23.10.0 (#5014)
* Update CHANGELOG.md

* Update version.h

* Update package.json
2025-09-16 11:35:03 -04:00
Alex King
044b9c1420
[Repositories] Convert Mail Key to Repositories (#5007)
* [Repositories] Convert Mail Key to Repositories

* Update shareddb.cpp

---------

Co-authored-by: JJ <3617814+joligario@users.noreply.github.com>
2025-09-15 14:23:48 -04:00
Alex King
0bbb5b90e7
[Repositories] Convert Total Time Played to Repositories (#5008) 2025-09-15 09:14:59 -04:00
Alex King
6506ad5b51
[Quest API] Add EVENT_CHARM_START and EVENT_CHARM_END (#5013) 2025-09-15 09:14:46 -04:00
Alex King
dcaa0ecdaa
[Quest API] Add Identifiers to Get/Modify NPC Stat Methods (#5012) 2025-09-15 09:14:29 -04:00
Mitch Freeman
9b143132be
[Bug Fix] Fix Several Evolving Item Bugs (#4992)
* Add sending evolving items via parcels
Send, retrieve and inspect tested ok

* Sell evolving items to a merchant and purchase tested ok.

* Fix a problem with potions and quantity
2025-09-07 22:51:39 -04:00
Mitch Freeman
231bf8b4ec
Update database_update_manifest.cpp (#5011) 2025-09-07 19:13:00 -04:00
Alex King
dee58f9a91
[Repositories] Convert Shared Bank Platinum to Repositories (#5006) 2025-09-01 21:39:24 -04:00
25 changed files with 2283 additions and 2535 deletions

View file

@ -1,3 +1,84 @@
## [23.10.3] 9/16/2025
### Hotfix
* Hotfix crashes occurring in #4987. @Akkadius 2025-09-17
## [23.10.2] 9/16/2025
### Hotfix
* Revert #4996 as it was causing critical issues with spells that needs to be further investigated. @Akkadius 2025-09-17
## [23.10.1] 9/16/2025
### Hotfix
* Fixed Mail Key Bug ([#5015](https://github.com/EQEmu/Server/pull/5015)) @Kinglykrab 2025-09-16
## [23.10.0] 9/15/2025
### Build
* Fix Linking with GCC ([#4969](https://github.com/EQEmu/Server/pull/4969)) @solar984 2025-08-03
### Code
* Add #npcedit npc_tint_id Help Message ([#4982](https://github.com/EQEmu/Server/pull/4982)) @Kinglykrab 2025-08-17
* Cleanup #show ip_lookup Message ([#5005](https://github.com/EQEmu/Server/pull/5005)) @Kinglykrab 2025-08-30
* Fix #set race 0 Message ([#5004](https://github.com/EQEmu/Server/pull/5004)) @Kinglykrab 2025-08-30
* Fix Issues with Strings::Commify and Mob::SendStatsWindow ([#4984](https://github.com/EQEmu/Server/pull/4984)) @Kinglykrab 2025-08-17
* Remove Attributions ([#4988](https://github.com/EQEmu/Server/pull/4988)) @KimLS 2025-08-16
* Remove Unused errorname Variable ([#5001](https://github.com/EQEmu/Server/pull/5001)) @Kinglykrab 2025-08-29
### Commands
* Add #find account Subcommand ([#4981](https://github.com/EQEmu/Server/pull/4981)) @Kinglykrab 2025-08-17
* Add #show keyring Subcommand ([#4973](https://github.com/EQEmu/Server/pull/4973)) @Kinglykrab 2025-08-03
* Add #task complete Saylink to #task show ([#4985](https://github.com/EQEmu/Server/pull/4985)) @Kinglykrab 2025-08-17
### Constants
* Change Race Changes to Race Namespace ([#5000](https://github.com/EQEmu/Server/pull/5000)) @Kinglykrab 2025-08-30
* Convert SE Defines to SpellEffect Namespace ([#4999](https://github.com/EQEmu/Server/pull/4999)) @Kinglykrab 2025-08-30
### Database
* Add `heal_amount` to `character_stats_record` ([#4986](https://github.com/EQEmu/Server/pull/4986)) @Kinglykrab 2025-08-17
### Fixes
* Fix #show recipe uint16 Cap ([#4978](https://github.com/EQEmu/Server/pull/4978)) @Kinglykrab 2025-08-11
* Fix Race 474 for Titanium ([#4979](https://github.com/EQEmu/Server/pull/4979)) @regneq 2025-08-11
* Fix Recipe Inspect Bug ([#4994](https://github.com/EQEmu/Server/pull/4994)) @Kinglykrab 2025-08-30
* Fix Several Evolving Item Bugs ([#4992](https://github.com/EQEmu/Server/pull/4992)) @neckkola 2025-09-08
* Fix Task Reloading ([#5002](https://github.com/EQEmu/Server/pull/5002)) @Kinglykrab 2025-08-29
### Loginserver
* Fix Legacy World When Using Local DB ([#4970](https://github.com/EQEmu/Server/pull/4970)) @solar984 2025-08-03
### Pets
* Add Pet Constants and Methods ([#4987](https://github.com/EQEmu/Server/pull/4987)) @Kinglykrab 2025-08-17
### Quest API
* Add EVENT_CHARM_START and EVENT_CHARM_END ([#5013](https://github.com/EQEmu/Server/pull/5013)) @Kinglykrab 2025-09-15
* Add GetKeyRing() to Perl/Lua ([#4980](https://github.com/EQEmu/Server/pull/4980)) @Kinglykrab 2025-08-17
* Add GetNPCTintIndex() to Perl/Lua ([#4983](https://github.com/EQEmu/Server/pull/4983)) @Kinglykrab 2025-08-17
* Add GetTimers() and GetPausedTimers() to Perl/Lua ([#4965](https://github.com/EQEmu/Server/pull/4965)) @Kinglykrab 2025-08-03
* Add Identifiers to Get/Modify NPC Stat Methods ([#5012](https://github.com/EQEmu/Server/pull/5012)) @Kinglykrab 2025-09-15
### Repositories
* Convert Character Inspect Messages to Repositories ([#4997](https://github.com/EQEmu/Server/pull/4997)) @Kinglykrab 2025-08-30
* Convert Damage Shield Types to Repositories ([#4995](https://github.com/EQEmu/Server/pull/4995)) @Kinglykrab 2025-08-30
* Convert Item Loading to Repositories ([#4998](https://github.com/EQEmu/Server/pull/4998)) @Kinglykrab 2025-08-30
* Convert Mail Key to Repositories ([#5007](https://github.com/EQEmu/Server/pull/5007)) @Kinglykrab 2025-09-15
* Convert Shared Bank Platinum to Repositories ([#5006](https://github.com/EQEmu/Server/pull/5006)) @Kinglykrab 2025-09-02
* Convert Spell Loading to Repositories ([#4996](https://github.com/EQEmu/Server/pull/4996)) @Kinglykrab 2025-08-30
* Convert Total Time Played to Repositories ([#5008](https://github.com/EQEmu/Server/pull/5008)) @Kinglykrab 2025-09-15
## [23.9.1] 8/2/2025
### Hotfix

View file

@ -7173,24 +7173,19 @@ ADD COLUMN `heal_amount` int(11) NULL DEFAULT 0 AFTER `spell_damage`;
},
ManifestEntry{
.version = 9328,
.description = "2025_08_27_spells_new_column_names.sql",
.check = "SHOW COLUMNS FROM `spells_new` LIKE 'feedbackable'",
.description = "2025_08_22_character_parcel_updates.sql",
.check = "SHOW COLUMNS FROM `character_parcels` LIKE 'evolve_amount'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `spells_new`
CHANGE COLUMN `field160` `feedbackable` int(11) NOT NULL DEFAULT 0 AFTER `npc_no_los`,
CHANGE COLUMN `field198` `no_detrimental_spell_aggro` int(11) NOT NULL DEFAULT 0 AFTER `not_extendable`,
CHANGE COLUMN `field209` `no_resist` int(11) NULL DEFAULT 0 AFTER `rank`,
CHANGE COLUMN `field217` `override_crit_chance` int(11) NULL DEFAULT 0 AFTER `field216`,
CHANGE COLUMN `field220` `no_heal_damage_item_mod` int(11) NULL DEFAULT 0 AFTER `maxtargets`,
CHANGE COLUMN `field221` `caster_requirement_id` int(11) NULL DEFAULT 0 AFTER `no_heal_damage_item_mod`,
CHANGE COLUMN `field222` `spell_class` int(11) NULL DEFAULT 0 AFTER `caster_requirement_id`,
CHANGE COLUMN `field223` `spell_subclass` int(11) NULL DEFAULT 0 AFTER `spell_class`,
CHANGE COLUMN `field232` `no_remove` int(11) NOT NULL DEFAULT 0 AFTER `min_range`;
)"
}
ALTER TABLE `character_parcels`
ADD COLUMN `evolve_amount` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `quantity`;
ALTER TABLE `character_parcels_containers`
ADD COLUMN `evolve_amount` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `quantity`;
)",
.content_schema_update = false
},
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
// .version = 9228,

View file

@ -74,6 +74,10 @@ void EvolvingItemsManager::DoLootChecks(const uint32 char_id, const uint16 slot_
e.item_id = inst.GetID();
e.equipped = inst.GetEvolveEquipped();
e.final_item_id = EvolvingItemsManager::Instance()->GetFinalItemID(inst);
if (inst.GetEvolveCurrentAmount() > 0) {
e.current_amount = inst.GetEvolveCurrentAmount();
inst.CalculateEvolveProgression();
}
auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e);
e.id = r.id;

View file

@ -6481,7 +6481,7 @@ 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) {
if (item->EvolvingItem && packet_type != ItemPacketParcel && packet_type != ItemPacketMerchant) {
hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword
hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword
}
@ -6500,6 +6500,7 @@ namespace RoF2
if (item->EvolvingItem > 0) {
RoF2::structs::EvolvingItem_Struct evotop;
inst->CalculateEvolveProgression();
evotop.final_item_id = inst->GetEvolveFinalItemID();
evotop.evolve_level = item->EvolvingLevel;

View file

@ -30,6 +30,7 @@ public:
uint32_t aug_slot_5;
uint32_t aug_slot_6;
uint32_t quantity;
uint32_t evolve_amount;
};
static std::string PrimaryKey()
@ -51,6 +52,7 @@ public:
"aug_slot_5",
"aug_slot_6",
"quantity",
"evolve_amount",
};
}
@ -68,6 +70,7 @@ public:
"aug_slot_5",
"aug_slot_6",
"quantity",
"evolve_amount",
};
}
@ -108,17 +111,18 @@ public:
{
CharacterParcelsContainers e{};
e.id = 0;
e.parcels_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.quantity = 0;
e.id = 0;
e.parcels_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.quantity = 0;
e.evolve_amount = 0;
return e;
}
@ -155,17 +159,18 @@ public:
if (results.RowCount() == 1) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
return e;
}
@ -209,6 +214,7 @@ public:
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
auto results = db.QueryDatabase(
fmt::format(
@ -241,6 +247,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
auto results = db.QueryDatabase(
fmt::format(
@ -281,6 +288,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@ -314,17 +322,18 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@ -349,17 +358,18 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = 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.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@ -445,6 +455,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
auto results = db.QueryDatabase(
fmt::format(
@ -478,6 +489,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}

View file

@ -30,6 +30,7 @@ public:
uint32_t aug_slot_6;
uint32_t slot_id;
uint32_t quantity;
uint32_t evolve_amount;
std::string from_name;
std::string note;
time_t sent_date;
@ -54,6 +55,7 @@ public:
"aug_slot_6",
"slot_id",
"quantity",
"evolve_amount",
"from_name",
"note",
"sent_date",
@ -74,6 +76,7 @@ public:
"aug_slot_6",
"slot_id",
"quantity",
"evolve_amount",
"from_name",
"note",
"UNIX_TIMESTAMP(sent_date)",
@ -117,20 +120,21 @@ public:
{
CharacterParcels e{};
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.slot_id = 0;
e.quantity = 0;
e.from_name = "";
e.note = "";
e.sent_date = 0;
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.slot_id = 0;
e.quantity = 0;
e.evolve_amount = 0;
e.from_name = "";
e.note = "";
e.sent_date = 0;
return e;
}
@ -167,20 +171,21 @@ public:
if (results.RowCount() == 1) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : "";
e.note = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
return e;
}
@ -224,9 +229,10 @@ public:
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[9] + " = " + std::to_string(e.slot_id));
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = '" + Strings::Escape(e.from_name) + "'");
v.push_back(columns[12] + " = '" + Strings::Escape(e.note) + "'");
v.push_back(columns[13] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[12] + " = '" + Strings::Escape(e.from_name) + "'");
v.push_back(columns[13] + " = '" + Strings::Escape(e.note) + "'");
v.push_back(columns[14] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@ -259,6 +265,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -302,6 +309,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -338,20 +346,21 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : "";
e.note = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@ -376,20 +385,21 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcels e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : "";
e.note = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char_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.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.from_name = row[12] ? row[12] : "";
e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@ -475,6 +485,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -511,6 +522,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");

File diff suppressed because it is too large Load diff

View file

@ -191,6 +191,22 @@ public:
return character_ids;
}
static uint32_t GetTotalTimePlayed(Database& db, uint32_t account_id)
{
auto query = fmt::format(
"SELECT SUM(time_played) FROM `character_data` WHERE `account_id` = {}",
account_id
);
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return 0;
}
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
};
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H

View file

@ -122,66 +122,41 @@ bool SharedDatabase::SetGMFlymode(uint32 account_id, uint8 flymode)
return a.id > 0;
}
uint32 SharedDatabase::GetTotalTimeEntitledOnAccount(uint32 AccountID) {
uint32 EntitledTime = 0;
const std::string query = StringFormat("SELECT `time_played` FROM `character_data` WHERE `account_id` = %u", AccountID);
auto results = QueryDatabase(query);
for (auto& row = results.begin(); row != results.end(); ++row) {
EntitledTime += Strings::ToUnsignedInt(row[0]);
}
return EntitledTime;
}
void SharedDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
void SharedDatabase::SetMailKey(uint32 character_id, uint32 ip_address, uint32 mail_key)
{
char mail_key[17];
std::string full_mail_key;
if (RuleB(Chat, EnableMailKeyIPVerification) == true) {
sprintf(mail_key, "%08X%08X", IPAddress, MailKey);
}
else {
sprintf(mail_key, "%08X", MailKey);
if (RuleB(Chat, EnableMailKeyIPVerification)) {
full_mail_key = fmt::format("{:08X}{:08X}", ip_address, mail_key);
} else {
full_mail_key = fmt::format("{:08X}", mail_key);
}
const std::string query = StringFormat(
"UPDATE character_data SET mailkey = '%s' WHERE id = '%i'",
mail_key, CharID
);
auto e = CharacterDataRepository::FindOne(*this, character_id);
if (!e.id) {
LogError("Failed to find character_id [{}] when setting mailkey", character_id);
return;
}
const auto results = QueryDatabase(query);
if (!results.Success()) {
LogError("SharedDatabase::SetMailKey({}, {}) : {}", CharID, mail_key, results.ErrorMessage().c_str());
e.mailkey = full_mail_key;
if (!CharacterDataRepository::UpdateOne(*this, e)) {
LogError("Failed to set mailkey to [{}] for character_id [{}]", full_mail_key, character_id);
}
}
SharedDatabase::MailKeys SharedDatabase::GetMailKey(int character_id)
SharedDatabase::MailKeys SharedDatabase::GetMailKey(uint32 character_id)
{
const std::string query = StringFormat("SELECT `mailkey` FROM `character_data` WHERE `id`='%i' LIMIT 1", character_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return MailKeys{};
auto e = CharacterDataRepository::FindOne(*this, character_id);
if (!e.id) {
return MailKeys{ };
}
if (!results.RowCount()) {
Log(Logs::General,
Logs::ClientLogin,
"Error: Mailkey for character id [%i] does not exist or could not be found",
character_id
);
return MailKeys{};
}
auto &row = results.begin();
if (row != results.end()) {
std::string mail_key = row[0];
return MailKeys{
.mail_key = mail_key.substr(8),
.mail_key_full = mail_key
};
}
return MailKeys{};
return MailKeys{
.mail_key = e.mailkey.substr(8),
.mail_key_full = e.mailkey
};
}
bool SharedDatabase::SaveCursor(
@ -448,27 +423,20 @@ bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id)
);
}
int32 SharedDatabase::GetSharedPlatinum(uint32 account_id)
{
const auto query = fmt::format("SELECT sharedplat FROM account WHERE id = {}", account_id);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return 0;
}
const auto& e = AccountRepository::FindOne(*this, account_id);
auto row = results.begin();
return Strings::ToInt(row[0]);
return e.sharedplat;
}
bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) {
const std::string query = StringFormat("UPDATE account SET sharedplat = sharedplat + %i WHERE id = %i", amount_to_add, account_id);
const auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
bool SharedDatabase::AddSharedPlatinum(uint32 account_id, int amount)
{
auto e = AccountRepository::FindOne(*this, account_id);
return true;
e.sharedplat += amount;
return AccountRepository::UpdateOne(*this, e);
}
bool SharedDatabase::SetStartingItems(
@ -1662,9 +1630,16 @@ const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) {
return nullptr; // nothing here for now... database and/or sharemem pulls later
}
int SharedDatabase::GetMaxSpellID()
{
return SpellsNewRepository::GetMaxId(*this);
int SharedDatabase::GetMaxSpellID() {
const std::string query = "SELECT MAX(id) FROM spells_new";
auto results = QueryDatabase(query);
if (!results.Success()) {
return -1;
}
auto& row = results.begin();
return Strings::ToInt(row[0]);
}
bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp) {
@ -1696,247 +1671,173 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
*static_cast<uint32*>(data) = max_spells;
SPDat_Spell_Struct *sp = reinterpret_cast<SPDat_Spell_Struct*>(static_cast<char*>(data) + sizeof(uint32));
const auto& l = SpellsNewRepository::All(*this);
const std::string query = "SELECT * FROM spells_new ORDER BY id ASC";
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (l.empty()) {
if(results.ColumnCount() <= SPELL_LOAD_FIELD_COUNT) {
LogSpells("Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT([{}])", SPELL_LOAD_FIELD_COUNT);
return;
}
}
for (const auto& e : l) {
if (e.id >= max_spells) {
int counter = 0;
for (auto& row = results.begin(); row != results.end(); ++row) {
const int tempid = Strings::ToInt(row[0]);
if(tempid >= max_spells) {
LogSpells("Non fatal error: spell.id >= max_spells, ignoring");
continue;
}
sp[e.id].id = e.id;
++counter;
sp[tempid].id = tempid;
strn0cpy(sp[tempid].name, row[1], sizeof(sp[tempid].name));
strn0cpy(sp[tempid].player_1, row[2], sizeof(sp[tempid].player_1));
strn0cpy(sp[tempid].teleport_zone, row[3], sizeof(sp[tempid].teleport_zone));
strn0cpy(sp[tempid].you_cast, row[4], sizeof(sp[tempid].you_cast));
strn0cpy(sp[tempid].other_casts, row[5], sizeof(sp[tempid].other_casts));
strn0cpy(sp[tempid].cast_on_you, row[6], sizeof(sp[tempid].cast_on_you));
strn0cpy(sp[tempid].cast_on_other, row[7], sizeof(sp[tempid].cast_on_other));
strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades));
strn0cpy(sp[e.id].name, e.name.c_str(), sizeof(sp[e.id].name));
strn0cpy(sp[e.id].player_1, e.player_1.c_str(), sizeof(sp[e.id].player_1));
strn0cpy(sp[e.id].teleport_zone, e.teleport_zone.c_str(), sizeof(sp[e.id].teleport_zone));
strn0cpy(sp[e.id].you_cast, e.you_cast.c_str(), sizeof(sp[e.id].you_cast));
strn0cpy(sp[e.id].other_casts, e.other_casts.c_str(), sizeof(sp[e.id].other_casts));
strn0cpy(sp[e.id].cast_on_you, e.cast_on_you.c_str(), sizeof(sp[e.id].cast_on_you));
strn0cpy(sp[e.id].cast_on_other, e.cast_on_other.c_str(), sizeof(sp[e.id].cast_on_other));
strn0cpy(sp[e.id].spell_fades, e.spell_fades.c_str(), sizeof(sp[e.id].spell_fades));
sp[tempid].range = Strings::ToFloat(row[9]);
sp[tempid].aoe_range = Strings::ToFloat(row[10]);
sp[tempid].push_back = Strings::ToFloat(row[11]);
sp[tempid].push_up = Strings::ToFloat(row[12]);
sp[tempid].cast_time=Strings::ToUnsignedInt(row[13]);
sp[tempid].recovery_time=Strings::ToUnsignedInt(row[14]);
sp[tempid].recast_time=Strings::ToUnsignedInt(row[15]);
sp[tempid].buff_duration_formula=Strings::ToUnsignedInt(row[16]);
sp[tempid].buff_duration=Strings::ToUnsignedInt(row[17]);
sp[tempid].aoe_duration=Strings::ToUnsignedInt(row[18]);
sp[tempid].mana=Strings::ToInt(row[19]);
sp[e.id].range = e.range_;
sp[e.id].aoe_range = e.aoerange;
sp[e.id].push_back = e.pushback;
sp[e.id].push_up = e.pushup;
sp[e.id].cast_time = e.cast_time;
sp[e.id].recovery_time = e.recovery_time;
sp[e.id].recast_time = e.recast_time;
sp[e.id].buff_duration_formula = e.buffdurationformula;
sp[e.id].buff_duration = e.buffduration;
sp[e.id].aoe_duration = e.AEDuration;
sp[e.id].mana = e.mana;
int y=0;
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].base_value[y]=Strings::ToInt(row[20+y]); // effect_base_value
sp[e.id].base_value[0] = e.effect_base_value1;
sp[e.id].base_value[1] = e.effect_base_value2;
sp[e.id].base_value[2] = e.effect_base_value3;
sp[e.id].base_value[3] = e.effect_base_value4;
sp[e.id].base_value[4] = e.effect_base_value5;
sp[e.id].base_value[5] = e.effect_base_value6;
sp[e.id].base_value[6] = e.effect_base_value7;
sp[e.id].base_value[7] = e.effect_base_value8;
sp[e.id].base_value[8] = e.effect_base_value9;
sp[e.id].base_value[9] = e.effect_base_value10;
sp[e.id].base_value[10] = e.effect_base_value11;
sp[e.id].base_value[11] = e.effect_base_value12;
for(y=0; y < EFFECT_COUNT; y++)
sp[tempid].limit_value[y]=Strings::ToInt(row[32+y]); // effect_limit_value
sp[e.id].limit_value[0] = e.effect_limit_value1;
sp[e.id].limit_value[1] = e.effect_limit_value2;
sp[e.id].limit_value[2] = e.effect_limit_value3;
sp[e.id].limit_value[3] = e.effect_limit_value4;
sp[e.id].limit_value[4] = e.effect_limit_value5;
sp[e.id].limit_value[5] = e.effect_limit_value6;
sp[e.id].limit_value[6] = e.effect_limit_value7;
sp[e.id].limit_value[7] = e.effect_limit_value8;
sp[e.id].limit_value[8] = e.effect_limit_value9;
sp[e.id].limit_value[9] = e.effect_limit_value10;
sp[e.id].limit_value[10] = e.effect_limit_value11;
sp[e.id].limit_value[11] = e.effect_limit_value12;
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].max_value[y]=Strings::ToInt(row[44+y]);
sp[e.id].max_value[0] = e.max1;
sp[e.id].max_value[1] = e.max2;
sp[e.id].max_value[2] = e.max3;
sp[e.id].max_value[3] = e.max4;
sp[e.id].max_value[4] = e.max5;
sp[e.id].max_value[5] = e.max6;
sp[e.id].max_value[6] = e.max7;
sp[e.id].max_value[7] = e.max8;
sp[e.id].max_value[8] = e.max9;
sp[e.id].max_value[9] = e.max10;
sp[e.id].max_value[10] = e.max11;
sp[e.id].max_value[11] = e.max12;
for(y=0; y< 4;y++)
sp[tempid].component[y]=Strings::ToInt(row[58+y]);
sp[e.id].component[0] = e.components1;
sp[e.id].component[1] = e.components2;
sp[e.id].component[2] = e.components3;
sp[e.id].component[3] = e.components4;
for(y=0; y< 4;y++)
sp[tempid].component_count[y]=Strings::ToInt(row[62+y]);
sp[e.id].component_count[0] = e.component_counts1;
sp[e.id].component_count[1] = e.component_counts2;
sp[e.id].component_count[2] = e.component_counts3;
sp[e.id].component_count[3] = e.component_counts4;
for(y=0; y< 4;y++)
sp[tempid].no_expend_reagent[y]=Strings::ToInt(row[66+y]);
sp[e.id].no_expend_reagent[0] = e.NoexpendReagent1;
sp[e.id].no_expend_reagent[1] = e.NoexpendReagent2;
sp[e.id].no_expend_reagent[2] = e.NoexpendReagent3;
sp[e.id].no_expend_reagent[3] = e.NoexpendReagent4;
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].formula[y]=Strings::ToUnsignedInt(row[70+y]);
sp[e.id].formula[0] = e.formula1;
sp[e.id].formula[1] = e.formula2;
sp[e.id].formula[2] = e.formula3;
sp[e.id].formula[3] = e.formula4;
sp[e.id].formula[4] = e.formula5;
sp[e.id].formula[5] = e.formula6;
sp[e.id].formula[6] = e.formula7;
sp[e.id].formula[7] = e.formula8;
sp[e.id].formula[8] = e.formula9;
sp[e.id].formula[9] = e.formula10;
sp[e.id].formula[10] = e.formula11;
sp[e.id].formula[11] = e.formula12;
sp[tempid].good_effect=Strings::ToInt(row[83]);
sp[tempid].activated=Strings::ToInt(row[84]);
sp[tempid].resist_type=Strings::ToInt(row[85]);
sp[e.id].good_effect = e.goodEffect;
sp[e.id].activated = e.Activated;
sp[e.id].resist_type = e.resisttype;
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].effect_id[y]=Strings::ToInt(row[86+y]);
sp[e.id].effect_id[0] = e.effectid1;
sp[e.id].effect_id[1] = e.effectid2;
sp[e.id].effect_id[2] = e.effectid3;
sp[e.id].effect_id[3] = e.effectid4;
sp[e.id].effect_id[4] = e.effectid5;
sp[e.id].effect_id[5] = e.effectid6;
sp[e.id].effect_id[6] = e.effectid7;
sp[e.id].effect_id[7] = e.effectid8;
sp[e.id].effect_id[8] = e.effectid9;
sp[e.id].effect_id[9] = e.effectid10;
sp[e.id].effect_id[10] = e.effectid11;
sp[e.id].effect_id[11] = e.effectid12;
sp[tempid].target_type = static_cast<SpellTargetType>(Strings::ToInt(row[98]));
sp[tempid].base_difficulty=Strings::ToInt(row[99]);
sp[e.id].target_type = static_cast<SpellTargetType>(e.targettype);
int tmp_skill = Strings::ToInt(row[100]);
sp[e.id].base_difficulty = e.basediff;
if (tmp_skill < 0 || tmp_skill > EQ::skills::HIGHEST_SKILL)
sp[tempid].skill = EQ::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated
else
sp[tempid].skill = static_cast<EQ::skills::SkillType>(tmp_skill);
sp[e.id].skill = (
EQ::ValueWithin(e.skill, 0, EQ::skills::HIGHEST_SKILL) ?
static_cast<EQ::skills::SkillType>(e.skill) :
EQ::skills::SkillBegging
);
sp[tempid].zone_type=Strings::ToInt(row[101]);
sp[tempid].environment_type=Strings::ToInt(row[102]);
sp[tempid].time_of_day=Strings::ToInt(row[103]);
sp[e.id].zone_type = e.zonetype;
sp[e.id].environment_type = e.EnvironmentType;
sp[e.id].time_of_day = e.TimeOfDay;
for(y=0; y < Class::PLAYER_CLASS_COUNT;y++)
sp[tempid].classes[y]=Strings::ToInt(row[104+y]);
sp[e.id].classes[0] = e.classes1;
sp[e.id].classes[1] = e.classes2;
sp[e.id].classes[2] = e.classes3;
sp[e.id].classes[3] = e.classes4;
sp[e.id].classes[4] = e.classes5;
sp[e.id].classes[5] = e.classes6;
sp[e.id].classes[6] = e.classes7;
sp[e.id].classes[7] = e.classes8;
sp[e.id].classes[8] = e.classes9;
sp[e.id].classes[9] = e.classes10;
sp[e.id].classes[10] = e.classes11;
sp[e.id].classes[11] = e.classes12;
sp[e.id].classes[12] = e.classes13;
sp[e.id].classes[13] = e.classes14;
sp[e.id].classes[14] = e.classes15;
sp[e.id].classes[15] = e.classes16;
sp[tempid].casting_animation=Strings::ToInt(row[120]);
sp[tempid].spell_affect_index=Strings::ToInt(row[123]);
sp[tempid].disallow_sit=Strings::ToInt(row[124]);
sp[tempid].deity_agnostic=Strings::ToInt(row[125]);
sp[e.id].casting_animation = e.CastingAnim;
sp[e.id].spell_affect_index = e.SpellAffectIndex;
sp[e.id].disallow_sit = e.disallow_sit;
for (y = 0; y < 16; y++)
sp[tempid].deities[y]=Strings::ToInt(row[126+y]);
sp[e.id].deity_agnostic = e.deities0; // Agnostic
sp[e.id].deities[0] = e.deities1; // Bertoxxulous
sp[e.id].deities[1] = e.deities2; // Brell Serilis
sp[e.id].deities[2] = e.deities3; // Cazic Thule
sp[e.id].deities[3] = e.deities4; // Erollsi Marr
sp[e.id].deities[4] = e.deities5; // Bristlebane
sp[e.id].deities[5] = e.deities6; // Innoruuk
sp[e.id].deities[6] = e.deities7; // Karana
sp[e.id].deities[7] = e.deities8; // Mithaniel Marr
sp[e.id].deities[8] = e.deities9; // Prexius
sp[e.id].deities[9] = e.deities10; // Quellious
sp[e.id].deities[10] = e.deities11; // Rallos Zek
sp[e.id].deities[11] = e.deities12; // Rodcet Nife
sp[e.id].deities[12] = e.deities13; // Solusek Ro
sp[e.id].deities[13] = e.deities14; // The Tribunal
sp[e.id].deities[14] = e.deities15; // Tunare
sp[e.id].deities[15] = e.deities16; // Veeshan
sp[tempid].new_icon=Strings::ToInt(row[144]);
sp[tempid].uninterruptable=Strings::ToBool(row[146]);
sp[tempid].resist_difficulty=Strings::ToInt(row[147]);
sp[tempid].unstackable_dot = Strings::ToBool(row[148]);
sp[tempid].recourse_link = Strings::ToUnsignedInt(row[150]);
sp[tempid].no_partial_resist = Strings::ToBool(row[151]);
sp[e.id].new_icon = e.new_icon;
sp[e.id].uninterruptable = e.uninterruptable;
sp[e.id].resist_difficulty = e.ResistDiff;
sp[e.id].unstackable_dot = e.dot_stacking_exempt;
sp[e.id].recourse_link = e.RecourseLink;
sp[e.id].no_partial_resist = e.no_partial_resist;
sp[e.id].short_buff_box = e.short_buff_box;
sp[e.id].description_id = e.descnum;
sp[e.id].type_description_id = e.typedescnum;
sp[e.id].effect_description_id = e.effectdescnum;
sp[e.id].npc_no_los = e.npc_no_los;
sp[e.id].feedbackable = e.feedbackable;
sp[e.id].reflectable = e.reflectable;
sp[e.id].bonus_hate = e.bonushate;
sp[e.id].ldon_trap = e.ldon_trap;
sp[e.id].endurance_cost = e.EndurCost;
sp[e.id].timer_id = e.EndurTimerIndex;
sp[e.id].is_discipline = e.IsDiscipline;
sp[e.id].hate_added = e.HateAdded;
sp[e.id].endurance_upkeep = e.EndurUpkeep;
sp[e.id].hit_number_type = e.numhits;
sp[e.id].hit_number = e.numhitstype;
sp[e.id].pvp_resist_base = e.pvpresistbase;
sp[e.id].pvp_resist_per_level = e.pvpresistcalc;
sp[e.id].pvp_resist_cap = e.pvpresistcap;
sp[e.id].spell_category = e.spell_category;
sp[e.id].pvp_duration = e.pvp_duration;
sp[e.id].pvp_duration_cap = e.pvp_duration_cap;
sp[e.id].pcnpc_only_flag = e.pcnpc_only_flag;
sp[e.id].cast_not_standing = e.cast_not_standing;
sp[e.id].can_mgb = e.can_mgb;
sp[e.id].dispel_flag = e.nodispell;
sp[e.id].min_resist = e.MinResist;
sp[e.id].max_resist = e.MaxResist;
sp[e.id].viral_targets = e.viral_targets;
sp[e.id].viral_timer = e.viral_timer;
sp[e.id].nimbus_effect = e.nimbuseffect;
sp[e.id].directional_start = e.ConeStartAngle;
sp[e.id].directional_end = e.ConeStopAngle;
sp[e.id].sneak = e.sneaking;
sp[e.id].not_focusable = e.not_extendable;
sp[tempid].short_buff_box = Strings::ToInt(row[154]);
sp[tempid].description_id = Strings::ToInt(row[155]);
sp[tempid].type_description_id = Strings::ToInt(row[156]);
sp[tempid].effect_description_id = Strings::ToInt(row[157]);
sp[e.id].no_detrimental_spell_aggro = e.no_detrimental_spell_aggro;
sp[tempid].npc_no_los = Strings::ToBool(row[159]);
sp[tempid].feedbackable = Strings::ToBool(row[160]);
sp[tempid].reflectable = Strings::ToBool(row[161]);
sp[tempid].bonus_hate=Strings::ToInt(row[162]);
sp[e.id].suspendable = e.suspendable;
sp[e.id].viral_range = e.viral_range;
sp[e.id].song_cap = e.songcap;
sp[e.id].no_block = e.no_block;
sp[e.id].spell_group = e.spellgroup;
sp[e.id].rank = e.rank_;
sp[e.id].no_resist = e.no_resist;
sp[e.id].cast_restriction = e.CastRestriction;
sp[e.id].allow_rest = e.allowrest;
sp[e.id].can_cast_in_combat = e.InCombat;
sp[e.id].can_cast_out_of_combat = e.OutofCombat;
sp[e.id].override_crit_chance = e.override_crit_chance;
sp[e.id].aoe_max_targets = e.aemaxtargets;
sp[e.id].no_heal_damage_item_mod = e.no_heal_damage_item_mod;
sp[e.id].caster_requirement_id = e.caster_requirement_id;
sp[e.id].spell_class = e.spell_class;
sp[e.id].spell_subclass = e.spell_subclass;
sp[e.id].persist_death = e.persistdeath;
sp[e.id].min_distance = e.min_dist;
sp[e.id].min_distance_mod = e.min_dist_mod;
sp[e.id].max_distance = e.max_dist;
sp[e.id].max_distance_mod = e.max_dist_mod;
sp[e.id].min_range = e.min_range;
sp[e.id].no_remove = e.no_remove;
sp[e.id].damage_shield_type = 0;
sp[tempid].ldon_trap = Strings::ToBool(row[165]);
sp[tempid].endurance_cost= Strings::ToInt(row[166]);
sp[tempid].timer_id= Strings::ToInt(row[167]);
sp[tempid].is_discipline = Strings::ToBool(row[168]);
sp[tempid].hate_added= Strings::ToInt(row[173]);
sp[tempid].endurance_upkeep=Strings::ToInt(row[174]);
sp[tempid].hit_number_type = Strings::ToInt(row[175]);
sp[tempid].hit_number = Strings::ToInt(row[176]);
sp[tempid].pvp_resist_base= Strings::ToInt(row[177]);
sp[tempid].pvp_resist_per_level= Strings::ToInt(row[178]);
sp[tempid].pvp_resist_cap= Strings::ToInt(row[179]);
sp[tempid].spell_category= Strings::ToInt(row[180]);
sp[tempid].pvp_duration = Strings::ToInt(row[181]);
sp[tempid].pvp_duration_cap = Strings::ToInt(row[182]);
sp[tempid].pcnpc_only_flag= Strings::ToInt(row[183]);
sp[tempid].cast_not_standing = Strings::ToInt(row[184]) != 0;
sp[tempid].can_mgb= Strings::ToBool(row[185]);
sp[tempid].dispel_flag = Strings::ToInt(row[186]);
sp[tempid].min_resist = Strings::ToInt(row[189]);
sp[tempid].max_resist = Strings::ToInt(row[190]);
sp[tempid].viral_targets = Strings::ToInt(row[191]);
sp[tempid].viral_timer = Strings::ToInt(row[192]);
sp[tempid].nimbus_effect = Strings::ToInt(row[193]);
sp[tempid].directional_start = Strings::ToFloat(row[194]);
sp[tempid].directional_end = Strings::ToFloat(row[195]);
sp[tempid].sneak = Strings::ToBool(row[196]);
sp[tempid].not_focusable = Strings::ToBool(row[197]);
sp[tempid].no_detrimental_spell_aggro = Strings::ToBool(row[198]);
sp[tempid].suspendable = Strings::ToBool(row[200]);
sp[tempid].viral_range = Strings::ToInt(row[201]);
sp[tempid].song_cap = Strings::ToInt(row[202]);
sp[tempid].no_block = Strings::ToInt(row[205]);
sp[tempid].spell_group=Strings::ToInt(row[207]);
sp[tempid].rank = Strings::ToInt(row[208]);
sp[tempid].no_resist=Strings::ToInt(row[209]);
sp[tempid].cast_restriction = Strings::ToInt(row[211]);
sp[tempid].allow_rest = Strings::ToBool(row[212]);
sp[tempid].can_cast_in_combat = Strings::ToBool(row[213]);
sp[tempid].can_cast_out_of_combat = Strings::ToBool(row[214]);
sp[tempid].override_crit_chance = Strings::ToInt(row[217]);
sp[tempid].aoe_max_targets = Strings::ToInt(row[218]);
sp[tempid].no_heal_damage_item_mod = Strings::ToInt(row[219]);
sp[tempid].caster_requirement_id = Strings::ToInt(row[220]);
sp[tempid].spell_class = Strings::ToInt(row[221]);
sp[tempid].spell_subclass = Strings::ToInt(row[222]);
sp[tempid].persist_death = Strings::ToBool(row[224]);
sp[tempid].min_distance = Strings::ToFloat(row[227]);
sp[tempid].min_distance_mod = Strings::ToFloat(row[228]);
sp[tempid].max_distance = Strings::ToFloat(row[229]);
sp[tempid].max_distance_mod = Strings::ToFloat(row[230]);
sp[tempid].min_range = Strings::ToFloat(row[231]);
sp[tempid].no_remove = Strings::ToBool(row[232]);
sp[tempid].damage_shield_type = 0;
}
LoadDamageShieldTypes(sp);
@ -1969,7 +1870,18 @@ void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const Insp
uint32 SharedDatabase::GetSpellsCount()
{
return SpellsNewRepository::Count(*this);
auto results = QueryDatabase("SELECT count(*) FROM spells_new");
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto& row = results.begin();
if (row[0]) {
return Strings::ToUnsignedInt(row[0]);
}
return 0;
}
uint32 SharedDatabase::GetItemsCount()

View file

@ -82,15 +82,14 @@ public:
bool UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected);
bool UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned);
bool GetCommandSubSettings(std::vector<CommandSubsettingsRepository::CommandSubsettings> &command_subsettings);
uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID);
bool SetGMInvul(uint32 account_id, bool gminvul);
bool SetGMFlymode(uint32 account_id, uint8 flymode);
void SetMailKey(int CharID, int IPAddress, int MailKey);
void SetMailKey(uint32 character_id, uint32 ip_address, uint32 mail_key);
struct MailKeys {
std::string mail_key;
std::string mail_key_full;
};
MailKeys GetMailKey(int character_id);
MailKeys GetMailKey(uint32 character_id);
bool SaveCursor(
uint32 char_id,
std::list<EQ::ItemInstance *>::const_iterator &start,
@ -104,7 +103,7 @@ public:
bool VerifyInventory(uint32 account_id, int16 slot_id, const EQ::ItemInstance *inst);
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 AddSharedPlatinum(uint32 account_id, int amount);
bool GetInventory(Client* c);
bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);

View file

@ -1600,6 +1600,7 @@ namespace SpellEffect {
// number. note that the id field is counted as 0, this way the numbers
// here match the numbers given to sep in the loading function net.cpp
//
#define SPELL_LOAD_FIELD_COUNT 236
struct SPDat_Spell_Struct
{

View file

@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "23.9.1-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "23.10.3-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__

View file

@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "23.9.1",
"version": "23.10.3",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"

View file

@ -985,7 +985,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
safe_delete(outapp);
// set mailkey - used for duration of character session
int mail_key = EQ::Random::Instance()->Int(1, INT_MAX);
uint32 mail_key = EQ::Random::Instance()->Int(1, INT_MAX);
database.SetMailKey(charid, GetIP(), mail_key);
if (UCSServerAvailable_) {

File diff suppressed because it is too large Load diff

View file

@ -1571,7 +1571,7 @@ void Client::OPMoveCoin(const EQApplicationPacket* app)
if (from_bucket == &m_pp.platinum_shared)
amount_to_add = 0 - amount_to_take;
database.SetSharedPlatinum(AccountID(),amount_to_add);
database.AddSharedPlatinum(AccountID(),amount_to_add);
}
}
else{

View file

@ -854,6 +854,66 @@ struct DataBucketCache
uint32_t bucket_expires;
};
// Defines based on the RoF2 Client
#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window
#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window
#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window
#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window
#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window
#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window
#define PET_SIT 6 // 0x06 - /pet sit or Pet Window
#define PET_SITDOWN 7 // 0x07 - /pet sit on
#define PET_STANDUP 8 // 0x08 - /pet sit off
#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented
#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented
#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented
#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window
#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on
#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off
#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window, won't add to hate list unless attacking
#define PET_HOLD_ON 16 // 0x10 - /pet hold on
#define PET_HOLD_OFF 17 // 0x11 - /pet hold off
#define PET_GHOLD 18 // 0x12 - /pet ghold, will never add to hate list unless told to
#define PET_GHOLD_ON 19 // 0x13 - /pet ghold on
#define PET_GHOLD_OFF 20 // 0x14 - /pet ghold off
#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window
#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on
#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off
#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window
#define PET_FOCUS_ON 25 // 0x19 - /pet focus on
#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off
#define PET_FEIGN 27 // 0x1b - /pet feign
#define PET_BACKOFF 28 // 0x1c - /pet back off
#define PET_GETLOST 29 // 0x1d - /pet get lost
#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client /pet target in modern clients but doesn't send packet
#define PET_REGROUP 31 // 0x1f - /pet regroup, acts like classic hold. Stops attack and moves back to guard/you but doesn't clear hate list
#define PET_REGROUP_ON 32 // 0x20 - /pet regroup on, turns on regroup
#define PET_REGROUP_OFF 33 // 0x21 - /pet regroup off, turns off regroup
#define PET_MAXCOMMANDS PET_REGROUP_OFF + 1
// can change the state of these buttons with a packet
#define PET_BUTTON_SIT 0
#define PET_BUTTON_STOP 1
#define PET_BUTTON_REGROUP 2
#define PET_BUTTON_FOLLOW 3
#define PET_BUTTON_GUARD 4
#define PET_BUTTON_TAUNT 5
#define PET_BUTTON_HOLD 6
#define PET_BUTTON_GHOLD 7
#define PET_BUTTON_FOCUS 8
#define PET_BUTTON_SPELLHOLD 9
enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath };
typedef enum {
petFamiliar, //only listens to /pet get lost
petAnimation, //does not listen to any commands
petOther,
petCharmed,
petNPCFollow,
petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands
petNone = 0xFF // not a pet
} PetTypeOld;
#endif

View file

@ -208,6 +208,8 @@ const char* QuestEventSubroutines[_LargestEventID] = {
"EVENT_SPELL_BLOCKED",
"EVENT_READ_ITEM",
"EVENT_PET_COMMAND",
"EVENT_CHARM_START",
"EVENT_CHARM_END",
// Add new events before these or Lua crashes
"EVENT_SPELL_EFFECT_BOT",

View file

@ -146,6 +146,8 @@ typedef enum {
EVENT_SPELL_BLOCKED,
EVENT_READ_ITEM,
EVENT_PET_COMMAND,
EVENT_CHARM_START,
EVENT_CHARM_END,
// Add new events before these or Lua crashes
EVENT_SPELL_EFFECT_BOT,

View file

@ -6992,7 +6992,9 @@ luabind::scope lua_register_events() {
luabind::value("entity_variable_update", static_cast<int>(EVENT_ENTITY_VARIABLE_UPDATE)),
luabind::value("aa_loss", static_cast<int>(EVENT_AA_LOSS)),
luabind::value("read", static_cast<int>(EVENT_READ_ITEM)),
luabind::value("pet_command", static_cast<int>(EVENT_PET_COMMAND))
luabind::value("pet_command", static_cast<int>(EVENT_PET_COMMAND)),
luabind::value("charm_start", static_cast<int>(EVENT_CHARM_START)),
luabind::value("charm_end", static_cast<int>(EVENT_CHARM_END))
)];
}

View file

@ -189,7 +189,9 @@ const char *LuaEvents[_LargestEventID] = {
"event_aa_loss",
"event_spell_blocked",
"event_read_item",
"event_pet_command"
"event_pet_command",
"event_charm_start",
"event_charm_end"
};
extern Zone *zone;
@ -266,6 +268,8 @@ LuaParser::LuaParser() {
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_npc_entity_variable;
NPCArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_npc_spell_blocked;
NPCArgumentDispatch[EVENT_PET_COMMAND] = handle_npc_pet_command;
NPCArgumentDispatch[EVENT_CHARM_START] = handle_npc_single_mob;
NPCArgumentDispatch[EVENT_CHARM_END] = handle_npc_single_mob;
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;

View file

@ -2274,9 +2274,9 @@ void NPC::SetLevel(uint8 in_level, bool command)
void NPC::ModifyNPCStat(const std::string& stat, const std::string& value)
{
auto stat_lower = Strings::ToLower(stat);
const std::string& stat_lower = Strings::ToLower(stat);
auto variable_key = fmt::format(
const std::string& variable_key = fmt::format(
"modify_stat_{}",
stat_lower
);
@ -2288,40 +2288,24 @@ void NPC::ModifyNPCStat(const std::string& stat, const std::string& value)
if (stat_lower == "ac") {
AC = Strings::ToInt(value);
CalcAC();
return;
}
else if (stat_lower == "str") {
} else if (stat_lower == "str") {
STR = Strings::ToInt(value);
return;
}
else if (stat_lower == "sta") {
} else if (stat_lower == "sta") {
STA = Strings::ToInt(value);
return;
}
else if (stat_lower == "agi") {
} else if (stat_lower == "agi") {
AGI = Strings::ToInt(value);
CalcAC();
return;
}
else if (stat_lower == "dex") {
} else if (stat_lower == "dex") {
DEX = Strings::ToInt(value);
return;
}
else if (stat_lower == "wis") {
} else if (stat_lower == "wis") {
WIS = Strings::ToInt(value);
CalcMaxMana();
return;
}
else if (stat_lower == "int" || stat_lower == "_int") {
} else if (stat_lower == "int" || stat_lower == "_int") {
INT = Strings::ToInt(value);
CalcMaxMana();
return;
}
else if (stat_lower == "cha") {
} else if (stat_lower == "cha") {
CHA = Strings::ToInt(value);
return;
}
else if (stat_lower == "max_hp") {
} else if (stat_lower == "max_hp") {
base_hp = Strings::ToBigInt(value);
CalcMaxHP();
@ -2329,45 +2313,27 @@ void NPC::ModifyNPCStat(const std::string& stat, const std::string& value)
current_hp = max_hp;
}
return;
}
else if (stat_lower == "max_mana") {
} else if (stat_lower == "max_mana") {
npc_mana = Strings::ToUnsignedBigInt(value);
CalcMaxMana();
if (current_mana > max_mana) {
current_mana = max_mana;
}
return;
}
else if (stat_lower == "mr") {
} else if (stat_lower == "mr") {
MR = Strings::ToInt(value);
return;
}
else if (stat_lower == "fr") {
} else if (stat_lower == "fr") {
FR = Strings::ToInt(value);
return;
}
else if (stat_lower == "cr") {
} else if (stat_lower == "cr") {
CR = Strings::ToInt(value);
return;
}
else if (stat_lower == "cor") {
} else if (stat_lower == "cor") {
Corrup = Strings::ToInt(value);
return;
}
else if (stat_lower == "pr") {
} else if (stat_lower == "pr") {
PR = Strings::ToInt(value);
return;
}
else if (stat_lower == "dr") {
} else if (stat_lower == "dr") {
DR = Strings::ToInt(value);
return;
}
else if (stat_lower == "phr") {
} else if (stat_lower == "phr") {
PhR = Strings::ToInt(value);
return;
}
else if (stat_lower == "runspeed") {
} else if (stat_lower == "runspeed") {
runspeed = Strings::ToFloat(value);
base_runspeed = (int) (runspeed * 40.0f);
base_walkspeed = base_runspeed * 100 / 265;
@ -2375,297 +2341,229 @@ void NPC::ModifyNPCStat(const std::string& stat, const std::string& value)
base_fearspeed = base_runspeed * 100 / 127;
fearspeed = ((float) base_fearspeed) * 0.025f;
CalcBonuses();
return;
}
else if (stat_lower == "special_attacks") {
} else if (stat_lower == "special_attacks") {
NPCSpecialAttacks(value.c_str(), 0, true);
return;
}
else if (stat_lower == "special_abilities") {
} else if (stat_lower == "special_abilities") {
ProcessSpecialAbilities(value);
return;
}
else if (stat_lower == "attack_speed") {
} else if (stat_lower == "attack_speed") {
attack_speed = Strings::ToFloat(value);
CalcBonuses();
return;
}
else if (stat_lower == "attack_delay") {
} else if (stat_lower == "attack_delay") {
/* TODO: fix DB */
attack_delay = Strings::ToInt(value) * 100;
CalcBonuses();
return;
}
else if (stat_lower == "atk") {
} else if (stat_lower == "atk") {
ATK = Strings::ToInt(value);
return;
}
else if (stat_lower == "accuracy") {
} else if (stat_lower == "accuracy") {
accuracy_rating = Strings::ToInt(value);
return;
}
else if (stat_lower == "avoidance") {
} else if (stat_lower == "avoidance") {
avoidance_rating = Strings::ToInt(value);
return;
}
else if (stat_lower == "trackable") {
} else if (stat_lower == "trackable") {
trackable = Strings::ToInt(value);
return;
}
else if (stat_lower == "min_hit") {
min_dmg = Strings::ToInt(value);
} else if (stat_lower == "min_hit") {
min_dmg = Strings::ToInt(value);
// Clamp max_dmg to be >= min_dmg
max_dmg = std::max(min_dmg, max_dmg);
max_dmg = std::max(min_dmg, max_dmg);
base_damage = round((max_dmg - min_dmg) / 1.9);
min_damage = min_dmg - round(base_damage / 10.0);
return;
}
else if (stat_lower == "max_hit") {
max_dmg = Strings::ToInt(value);
} else if (stat_lower == "max_hit") {
max_dmg = Strings::ToInt(value);
// Clamp min_dmg to be <= max_dmg
min_dmg = std::min(min_dmg, max_dmg);
min_dmg = std::min(min_dmg, max_dmg);
base_damage = round((max_dmg - min_dmg) / 1.9);
min_damage = min_dmg - round(base_damage / 10.0);
return;
}
else if (stat_lower == "attack_count") {
} else if (stat_lower == "attack_count") {
attack_count = Strings::ToInt(value);
return;
}
else if (stat_lower == "see_invis") {
} else if (stat_lower == "see_invis") {
see_invis = Strings::ToInt(value);
return;
}
else if (stat_lower == "see_invis_undead") {
} else if (stat_lower == "see_invis_undead") {
see_invis_undead = Strings::ToInt(value);
return;
}
else if (stat_lower == "see_hide") {
} else if (stat_lower == "see_hide") {
see_hide = Strings::ToInt(value);
return;
}
else if (stat_lower == "see_improved_hide") {
} else if (stat_lower == "see_improved_hide") {
see_improved_hide = Strings::ToInt(value);
return;
}
else if (stat_lower == "hp_regen") {
} else if (stat_lower == "hp_regen") {
hp_regen = Strings::ToBigInt(value);
return;
}
else if (stat_lower == "hp_regen_per_second") {
} else if (stat_lower == "hp_regen_per_second") {
hp_regen_per_second = Strings::ToBigInt(value);
return;
}
else if (stat_lower == "mana_regen") {
} else if (stat_lower == "mana_regen") {
mana_regen = Strings::ToBigInt(value);
return;
}
else if (stat_lower == "level") {
} else if (stat_lower == "level") {
SetLevel(Strings::ToInt(value));
return;
}
else if (stat_lower == "aggro") {
} else if (stat_lower == "aggro") {
pAggroRange = Strings::ToFloat(value);
return;
}
else if (stat_lower == "assist") {
} else if (stat_lower == "assist") {
pAssistRange = Strings::ToFloat(value);
return;
}
else if (stat_lower == "slow_mitigation") {
} else if (stat_lower == "slow_mitigation") {
slow_mitigation = Strings::ToInt(value);
return;
}
else if (stat_lower == "loottable_id") {
} else if (stat_lower == "loottable_id") {
m_loottable_id = Strings::ToFloat(value);
return;
}
else if (stat_lower == "healscale") {
} else if (stat_lower == "healscale") {
healscale = Strings::ToFloat(value);
return;
}
else if (stat_lower == "spellscale") {
} else if (stat_lower == "spellscale") {
spellscale = Strings::ToFloat(value);
return;
}
else if (stat_lower == "npc_spells_id") {
} else if (stat_lower == "npc_spells_id") {
AI_AddNPCSpells(Strings::ToInt(value));
return;
}
else if (stat_lower == "npc_spells_effects_id") {
} else if (stat_lower == "npc_spells_effects_id") {
AI_AddNPCSpellsEffects(Strings::ToInt(value));
CalcBonuses();
return;
}
else if (stat_lower == "heroic_strikethrough") {
} else if (stat_lower == "heroic_strikethrough") {
heroic_strikethrough = Strings::ToInt(value);
return;
}
else if (stat_lower == "keeps_sold_items") {
} else if (stat_lower == "keeps_sold_items") {
SetKeepsSoldItems(Strings::ToBool(value));
return;
} else if (stat_lower == "charm_ac") {
charm_ac = Strings::ToInt(value);
} else if (stat_lower == "charm_min_dmg") {
charm_min_dmg = Strings::ToInt(value);
} else if (stat_lower == "charm_max_dmg") {
charm_max_dmg = Strings::ToInt(value);
} else if (stat_lower == "charm_attack_delay") {
charm_attack_delay = Strings::ToInt(value);
} else if (stat_lower == "charm_accuracy_rating") {
charm_accuracy_rating = Strings::ToInt(value);
} else if (stat_lower == "charm_avoidance_rating") {
charm_avoidance_rating = Strings::ToInt(value);
} else if (stat_lower == "charm_atk") {
charm_atk = Strings::ToInt(value);
} else if (stat_lower == "default_ac") {
default_ac = Strings::ToInt(value);
} else if (stat_lower == "default_min_dmg") {
default_min_dmg = Strings::ToInt(value);
} else if (stat_lower == "default_max_dmg") {
default_max_dmg = Strings::ToInt(value);
} else if (stat_lower == "default_attack_delay") {
default_attack_delay = Strings::ToInt(value);
} else if (stat_lower == "default_accuracy_rating") {
default_accuracy_rating = Strings::ToInt(value);
} else if (stat_lower == "default_avoidance_rating") {
default_avoidance_rating = Strings::ToInt(value);
} else if (stat_lower == "default_atk") {
default_atk = Strings::ToInt(value);
}
}
float NPC::GetNPCStat(const std::string& stat)
{
const std::string& stat_lower = Strings::ToLower(stat);
if (auto stat_lower = Strings::ToLower(stat); stat_lower == "ac") {
if (stat_lower == "ac") {
return AC;
}
else if (stat_lower == "str") {
} else if (stat_lower == "str") {
return STR;
}
else if (stat_lower == "sta") {
} else if (stat_lower == "sta") {
return STA;
}
else if (stat_lower == "agi") {
} else if (stat_lower == "agi") {
return AGI;
}
else if (stat_lower == "dex") {
} else if (stat_lower == "dex") {
return DEX;
}
else if (stat_lower == "wis") {
} else if (stat_lower == "wis") {
return WIS;
}
else if (stat_lower == "int" || stat_lower == "_int") {
} else if (stat_lower == "int" || stat_lower == "_int") {
return INT;
}
else if (stat_lower == "cha") {
} else if (stat_lower == "cha") {
return CHA;
}
else if (stat_lower == "max_hp") {
} else if (stat_lower == "max_hp") {
return base_hp;
}
else if (stat_lower == "max_mana") {
} else if (stat_lower == "max_mana") {
return npc_mana;
}
else if (stat_lower == "mr") {
} else if (stat_lower == "mr") {
return MR;
}
else if (stat_lower == "fr") {
} else if (stat_lower == "fr") {
return FR;
}
else if (stat_lower == "cr") {
} else if (stat_lower == "cr") {
return CR;
}
else if (stat_lower == "cor") {
} else if (stat_lower == "cor") {
return Corrup;
}
else if (stat_lower == "phr") {
} else if (stat_lower == "phr") {
return PhR;
}
else if (stat_lower == "pr") {
} else if (stat_lower == "pr") {
return PR;
}
else if (stat_lower == "dr") {
} else if (stat_lower == "dr") {
return DR;
}
else if (stat_lower == "runspeed") {
} else if (stat_lower == "runspeed") {
return runspeed;
}
else if (stat_lower == "attack_speed") {
} else if (stat_lower == "attack_speed") {
return attack_speed;
}
else if (stat_lower == "attack_delay") {
} else if (stat_lower == "attack_delay") {
return attack_delay;
}
else if (stat_lower == "atk") {
} else if (stat_lower == "atk") {
return ATK;
}
else if (stat_lower == "accuracy") {
} else if (stat_lower == "accuracy") {
return accuracy_rating;
}
else if (stat_lower == "avoidance") {
} else if (stat_lower == "avoidance") {
return avoidance_rating;
}
else if (stat_lower == "trackable") {
} else if (stat_lower == "trackable") {
return trackable;
}
else if (stat_lower == "min_hit") {
} else if (stat_lower == "min_hit") {
return min_dmg;
}
else if (stat_lower == "max_hit") {
} else if (stat_lower == "max_hit") {
return max_dmg;
}
else if (stat_lower == "attack_count") {
} else if (stat_lower == "attack_count") {
return attack_count;
}
else if (stat_lower == "see_invis") {
} else if (stat_lower == "see_invis") {
return see_invis;
}
else if (stat_lower == "see_invis_undead") {
} else if (stat_lower == "see_invis_undead") {
return see_invis_undead;
}
else if (stat_lower == "see_hide") {
} else if (stat_lower == "see_hide") {
return see_hide;
}
else if (stat_lower == "see_improved_hide") {
} else if (stat_lower == "see_improved_hide") {
return see_improved_hide;
}
else if (stat_lower == "hp_regen") {
} else if (stat_lower == "hp_regen") {
return hp_regen;
}
else if (stat_lower == "hp_regen_per_second") {
} else if (stat_lower == "hp_regen_per_second") {
return hp_regen_per_second;
}
else if (stat_lower == "mana_regen") {
} else if (stat_lower == "mana_regen") {
return mana_regen;
}
else if (stat_lower == "level") {
} else if (stat_lower == "level") {
return GetOrigLevel();
}
else if (stat_lower == "aggro") {
} else if (stat_lower == "aggro") {
return pAggroRange;
}
else if (stat_lower == "assist") {
} else if (stat_lower == "assist") {
return pAssistRange;
}
else if (stat_lower == "slow_mitigation") {
} else if (stat_lower == "slow_mitigation") {
return slow_mitigation;
}
else if (stat_lower == "loottable_id") {
} else if (stat_lower == "loottable_id") {
return m_loottable_id;
}
else if (stat_lower == "healscale") {
} else if (stat_lower == "healscale") {
return healscale;
}
else if (stat_lower == "spellscale") {
} else if (stat_lower == "spellscale") {
return spellscale;
}
else if (stat_lower == "npc_spells_id") {
} else if (stat_lower == "npc_spells_id") {
return npc_spells_id;
}
else if (stat_lower == "npc_spells_effects_id") {
} else if (stat_lower == "npc_spells_effects_id") {
return npc_spells_effects_id;
}
else if (stat_lower == "heroic_strikethrough") {
} else if (stat_lower == "heroic_strikethrough") {
return heroic_strikethrough;
}
else if (stat_lower == "keeps_sold_items") {
} else if (stat_lower == "keeps_sold_items") {
return keeps_sold_items;
}
//default values
else if (stat_lower == "default_ac") {
} else if (stat_lower == "default_ac") {
return default_ac;
}
else if (stat_lower == "default_min_hit") {
} else if (stat_lower == "default_min_hit") {
return default_min_dmg;
}
else if (stat_lower == "default_max_hit") {
} else if (stat_lower == "default_max_hit") {
return default_max_dmg;
}
else if (stat_lower == "default_attack_delay") {
} else if (stat_lower == "default_attack_delay") {
return default_attack_delay;
}
else if (stat_lower == "default_accuracy") {
} else if (stat_lower == "default_accuracy") {
return default_accuracy_rating;
}
else if (stat_lower == "default_avoidance") {
} else if (stat_lower == "default_avoidance") {
return default_avoidance_rating;
}
else if (stat_lower == "default_atk") {
} else if (stat_lower == "default_atk") {
return default_atk;
} else if (stat_lower == "charm_ac") {
return charm_ac;
} else if (stat_lower == "charm_min_hit") {
return charm_min_dmg;
} else if (stat_lower == "charm_max_hit") {
return charm_max_dmg;
} else if (stat_lower == "charm_attack_delay") {
return charm_attack_delay;
} else if (stat_lower == "charm_accuracy") {
return charm_accuracy_rating;
} else if (stat_lower == "charm_avoidance") {
return charm_avoidance_rating;
} else if (stat_lower == "charm_atk") {
return charm_atk;
}
return 0.0f;
@ -3387,62 +3285,55 @@ void NPC::DepopSwarmPets()
}
}
void NPC::ModifyStatsOnCharm(bool is_charm_removed)
void NPC::ModifyStatsOnCharm(bool remove_charm, Mob* charmer)
{
if (is_charm_removed) {
if (charm_ac) {
AC = default_ac;
}
if (charm_attack_delay) {
attack_delay = default_attack_delay;
}
if (charm_accuracy_rating) {
accuracy_rating = default_accuracy_rating;
}
if (charm_avoidance_rating) {
avoidance_rating = default_avoidance_rating;
}
if (charm_atk) {
ATK = default_atk;
}
if (charm_min_dmg || charm_max_dmg) {
base_damage = round((default_max_dmg - default_min_dmg) / 1.9);
min_damage = default_min_dmg - round(base_damage / 10.0);
}
if (RuleB(Spells, CharmDisablesSpecialAbilities)) {
ProcessSpecialAbilities(default_special_abilities);
}
SetAttackTimer();
CalcAC();
return;
if (!remove_charm && parse->HasQuestSub(GetNPCTypeID(), EVENT_CHARM_START)) {
parse->EventNPC(EVENT_CHARM_START, this, charmer, "", 0);
} else if (remove_charm && parse->HasQuestSub(GetNPCTypeID(), EVENT_CHARM_END)) {
parse->EventNPC(EVENT_CHARM_END, this, charmer, "", 0);
}
if (charm_ac) {
AC = charm_ac;
const int new_ac = remove_charm ? default_ac : charm_ac;
const int new_attack_delay = remove_charm ? default_attack_delay : charm_attack_delay;
const int new_accuracy_rating = remove_charm ? default_accuracy_rating : charm_accuracy_rating;
const int new_avoidance_rating = remove_charm ? default_avoidance_rating : charm_avoidance_rating;
const int new_atk = remove_charm ? default_atk : charm_atk;
const int new_min_dmg = remove_charm ? default_min_dmg : charm_min_dmg;
const int new_max_dmg = remove_charm ? default_max_dmg : charm_max_dmg;
if (new_ac) {
AC = new_ac;
}
if (charm_attack_delay) {
attack_delay = charm_attack_delay;
if (new_attack_delay) {
attack_delay = new_attack_delay;
}
if (charm_accuracy_rating) {
accuracy_rating = charm_accuracy_rating;
if (new_accuracy_rating) {
accuracy_rating = new_accuracy_rating;
}
if (charm_avoidance_rating) {
avoidance_rating = charm_avoidance_rating;
if (new_avoidance_rating) {
avoidance_rating = new_avoidance_rating;
}
if (charm_atk) {
ATK = charm_atk;
if (new_atk) {
ATK = new_atk;
}
if (charm_min_dmg || charm_max_dmg) {
base_damage = round((charm_max_dmg - charm_min_dmg) / 1.9);
min_damage = charm_min_dmg - round(base_damage / 10.0);
if (new_min_dmg || new_max_dmg) {
base_damage = std::round((new_max_dmg - new_min_dmg) / 1.9);
min_damage = new_min_dmg - std::round(base_damage / 10.0);
}
if (RuleB(Spells, CharmDisablesSpecialAbilities)) {
ClearSpecialAbilities();
if (remove_charm) {
ProcessSpecialAbilities(default_special_abilities);
} else {
ClearSpecialAbilities();
}
}
// the rest of the stats aren't cached, so lets just do these two instead of full CalcBonuses()
SetAttackTimer();
CalcAC();
}

View file

@ -346,7 +346,7 @@ public:
int64 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; }
inline const char* GetAmmoIDfile() const { return ammo_idfile; }
void ModifyStatsOnCharm(bool is_charm_removed);
void ModifyStatsOnCharm(bool remove_charm, Mob* charmer);
//waypoint crap
int GetMaxWp() const { return max_wp; }

View file

@ -61,6 +61,7 @@ void Client::SendBulkParcels()
inst->SetCharges(p.second.quantity);
inst->SetMerchantCount(1);
inst->SetMerchantSlot(p.second.slot_id);
inst->SetEvolveCurrentAmount(p.second.evolve_amount);
if (inst->IsStackable()) {
inst->SetCharges(p.second.quantity);
}
@ -164,6 +165,7 @@ void Client::SendParcel(Parcel_Struct &parcel_in)
inst->SetCharges(p.quantity);
inst->SetMerchantCount(1);
inst->SetMerchantSlot(p.slot_id);
inst->SetEvolveCurrentAmount(p.evolve_amount);
if (inst->IsStackable()) {
inst->SetCharges(p.quantity);
}
@ -381,23 +383,23 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
return;
}
uint32 quantity{};
uint32 quantity = 1;
if (inst->IsStackable()) {
quantity = parcel_in->quantity;
}
else {
quantity = inst->GetCharges() >= 0 ? inst->GetCharges() : parcel_in->quantity;
} else if (inst->GetItem()->MaxCharges > 0) {
quantity = inst->GetCharges();
}
CharacterParcelsRepository::CharacterParcels parcel_out{};
parcel_out.from_name = GetName();
parcel_out.note = parcel_in->note;
parcel_out.sent_date = time(nullptr);
parcel_out.quantity = quantity;
parcel_out.item_id = inst->GetID();
parcel_out.char_id = send_to_client.at(0).char_id;
parcel_out.slot_id = next_slot;
parcel_out.id = 0;
parcel_out.from_name = GetName();
parcel_out.note = parcel_in->note;
parcel_out.sent_date = time(nullptr);
parcel_out.quantity = quantity;
parcel_out.item_id = inst->GetID();
parcel_out.char_id = send_to_client.at(0).char_id;
parcel_out.slot_id = next_slot;
parcel_out.evolve_amount = inst->GetEvolveCurrentAmount();
parcel_out.id = 0;
if (inst->IsAugmented()) {
auto augs = inst->GetAugmentIDs();
@ -445,7 +447,9 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
cpc.aug_slot_5 = augs.at(4);
cpc.aug_slot_6 = augs.at(5);
}
cpc.quantity = kv.second->GetCharges() >= 0 ? kv.second->GetCharges() : 1;
cpc.quantity = kv.second->GetCharges() >= 0 ? kv.second->GetCharges() : 1;
cpc.evolve_amount = kv.second->GetEvolveCurrentAmount();
all_entries.push_back(cpc);
}
CharacterParcelsContainersRepository::InsertMany(database, all_entries);
@ -679,6 +683,8 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
return;
}
inst->SetEvolveCurrentAmount(p->second.evolve_amount);
if (inst->IsStackable()) {
inst->SetCharges(item_quantity > 0 ? item_quantity : 1);
}
@ -715,6 +721,8 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
return;
}
item->SetEvolveCurrentAmount(i.evolve_amount);
if (CheckLoreConflict(item->GetItem())) {
if (RuleB(Parcel, DeleteOnDuplicate)) {
MessageString(Chat::Yellow, PARCEL_DUPLICATE_DELETE, inst->GetItem()->Name);

View file

@ -835,12 +835,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
SendAppearancePacket(AppearanceType::Pet, caster->GetID(), true, true);
}
if (IsClient())
{
if (IsClient()) {
CastToClient()->AI_Start();
} else if(IsNPC()) {
CastToNPC()->SetPetSpellID(0); //not a pet spell.
CastToNPC()->ModifyStatsOnCharm(false);
} else if (IsNPC()) {
CastToNPC()->SetPetSpellID(0); //not a pet spell.
CastToNPC()->ModifyStatsOnCharm(false, caster);
}
bool bBreak = false;
@ -4418,10 +4417,9 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
case SpellEffect::Charm:
{
if(IsNPC())
{
if (IsNPC()) {
CastToNPC()->RestoreGuardSpotCharm();
CastToNPC()->ModifyStatsOnCharm(true);
CastToNPC()->ModifyStatsOnCharm(true, GetOwner());
}
SendAppearancePacket(AppearanceType::Pet, 0, true, true);