mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-29 14:55:44 +00:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7918fed81c | |||
| ac24c9bf5a | |||
| 7b914c731b | |||
| 7362c0ebb5 | |||
| ae213a4e4b | |||
| 187288f3aa | |||
| abc8c3d886 | |||
| 0b2493beb8 | |||
| 9cebba5911 | |||
| 4478328b2a | |||
| 55a7e1646d | |||
| b6b8491060 | |||
| 850053a136 | |||
| 1aa8758b0a | |||
| b1aa087b9f | |||
| 1e57a0372f | |||
| 9614ea59ec | |||
| 7a648cce16 | |||
| 8640776a21 | |||
| 0c45d3b09e | |||
| 59e4adb117 | |||
| d5a06bfe2e | |||
| 0f0676824c | |||
| caa647dc6b | |||
| 76b9ce0ac1 | |||
| d01d091b47 | |||
| 47ddcb54f1 | |||
| dda0e410ff | |||
| eae05167f8 | |||
| 16f21893a3 | |||
| 4ca724956b | |||
| 217a80ee76 | |||
| 8b166bf5b9 | |||
| 4c614661e7 | |||
| 9392f86333 | |||
| 0d888268a8 | |||
| b044d8533e | |||
| d810cb02c3 | |||
| 992a5cc132 | |||
| c50fda0f73 | |||
| 1b15f16e3e | |||
| 983cc1e82a | |||
| fc79614fac | |||
| d767217461 | |||
| 1310c5d528 | |||
| b253fce0d5 | |||
| 421857026d | |||
| 68f40c9255 | |||
| 0bceee5622 | |||
| cd03152550 | |||
| 316fa54bd8 | |||
| 49957e3269 | |||
| 9638d9af3a | |||
| 87c207e862 | |||
| 2df5f3f55a | |||
| e803d3e1e1 | |||
| fccb205a1d | |||
| f70078d62a | |||
| 34ae3094d6 | |||
| c56742a2a8 | |||
| 3e34447172 | |||
| ca25122bfa | |||
| 13a7532ef8 | |||
| e1344039ff | |||
| 98b137154a | |||
| fc9ef2fb7b | |||
| 6dc661032f | |||
| 2586527157 | |||
| 3a51f04291 | |||
| 66af3d2f63 | |||
| 6bcd8fea18 | |||
| 0d1cbecb55 | |||
| e33e076b2a | |||
| e26d17182e | |||
| 7e40c5bac2 | |||
| ca69cc67e8 | |||
| 099c6d657b | |||
| c0a8fd097e | |||
| a80ab75260 | |||
| c87aadbf0c | |||
| 1be86edf20 | |||
| b49b564940 | |||
| d302b9c02e |
+190
-13
@@ -1,3 +1,180 @@
|
||||
## [22.53.1] 6/16/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix trader mode ([#4397](https://github.com/EQEmu/Server/pull/4397)) @joligario 2024-06-17
|
||||
|
||||
## [22.53.0] 6/14/2024
|
||||
|
||||
### Bug
|
||||
|
||||
* Anon players should not show in /who all ([#4392](https://github.com/EQEmu/Server/pull/4392)) @fryguy503 2024-06-14
|
||||
* Escape should put player into SOS if owned. ([#4388](https://github.com/EQEmu/Server/pull/4388)) @fryguy503 2024-06-07
|
||||
* Prevent Resurrection Spells from being resisted ([#4393](https://github.com/EQEmu/Server/pull/4393)) @fryguy503 2024-06-14
|
||||
|
||||
### Code
|
||||
|
||||
* Cleanup Account Status Code ([#4376](https://github.com/EQEmu/Server/pull/4376)) @Kinglykrab 2024-06-02
|
||||
* Cleanup Body Type Code ([#4366](https://github.com/EQEmu/Server/pull/4366)) @Kinglykrab 2024-06-02
|
||||
* Cleanup Object Type Code ([#4375](https://github.com/EQEmu/Server/pull/4375)) @Kinglykrab 2024-06-14
|
||||
* Remove unused code in emu_constants.h ([#4384](https://github.com/EQEmu/Server/pull/4384)) @Kinglykrab 2024-06-14
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix #goto Target ([#4382](https://github.com/EQEmu/Server/pull/4382)) @Kinglykrab 2024-06-03
|
||||
* Fix Swarm Pet Damage Messages ([#4383](https://github.com/EQEmu/Server/pull/4383)) @Kinglykrab 2024-06-04
|
||||
* Fix for players having empty bazaar window dropdown list, even though trader is tagged as a trader. ([#4391](https://github.com/EQEmu/Server/pull/4391)) @neckkola 2024-06-14
|
||||
* Fix potential trader crash when serialized item not found ([#4386](https://github.com/EQEmu/Server/pull/4386)) @joligario 2024-06-14
|
||||
|
||||
### Rules
|
||||
|
||||
* Add Invisible Augment Rules ([#4385](https://github.com/EQEmu/Server/pull/4385)) @Kinglykrab 2024-06-14
|
||||
* Classic Harm Touch Formula ([#4394](https://github.com/EQEmu/Server/pull/4394)) @fryguy503 2024-06-14
|
||||
* Mend/Sneak allow success tuning ([#4390](https://github.com/EQEmu/Server/pull/4390)) @fryguy503 2024-06-14
|
||||
* Snare Override Movement Bonus ([#4381](https://github.com/EQEmu/Server/pull/4381)) @fryguy503 2024-06-02
|
||||
|
||||
## [22.52.0] 6/1/2024
|
||||
|
||||
### Code
|
||||
|
||||
* Cleanup Bucket Comparison Code ([#4374](https://github.com/EQEmu/Server/pull/4374)) @Kinglykrab 2024-06-02
|
||||
* Cleanup Bug Category Code ([#4367](https://github.com/EQEmu/Server/pull/4367)) @Kinglykrab 2024-06-01
|
||||
* Cleanup Deity Code ([#4363](https://github.com/EQEmu/Server/pull/4363)) @Kinglykrab 2024-06-01
|
||||
* Cleanup Special Ability Code ([#4365](https://github.com/EQEmu/Server/pull/4365)) @Kinglykrab 2024-06-01
|
||||
* Remove unused code in common/eq_constants.h ([#4364](https://github.com/EQEmu/Server/pull/4364)) @Kinglykrab 2024-06-01
|
||||
|
||||
### Combat
|
||||
|
||||
* Adjustments to Crippling Blows/Slay Undead and Confirmed Critical Code ([#4354](https://github.com/EQEmu/Server/pull/4354)) @fryguy503 2024-05-27
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add protection to ensure adventure points award are only attempted on players ([#4371](https://github.com/EQEmu/Server/pull/4371)) @joligario 2024-05-31
|
||||
* Adjust Kick/RoundKick Damage Lower levels ([#4355](https://github.com/EQEmu/Server/pull/4355)) @fryguy503 2024-05-28
|
||||
* Bazaar Search not working correctly for Iksar, Vashir, Drakkin and Froglok races ([#4379](https://github.com/EQEmu/Server/pull/4379)) @neckkola 2024-06-02
|
||||
* Fix Unescaped String in Client::GotoPlayer ([#4373](https://github.com/EQEmu/Server/pull/4373)) @Kinglykrab 2024-06-01
|
||||
|
||||
### NPC Spells
|
||||
|
||||
* Fixed an issue where the repository spell adj value was overriding the spell difficulty default value ([#4370](https://github.com/EQEmu/Server/pull/4370)) @regneq 2024-06-01
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add Item Link Methods to Perl/Lua ([#4359](https://github.com/EQEmu/Server/pull/4359)) @Kinglykrab 2024-06-01
|
||||
|
||||
### Quests
|
||||
|
||||
* Fix Lua encounter double register ([#4369](https://github.com/EQEmu/Server/pull/4369)) @Akkadius 2024-05-31
|
||||
* Fix issue with Lua encounters loading in certain circumstances ([#4378](https://github.com/EQEmu/Server/pull/4378)) @Akkadius 2024-06-01
|
||||
|
||||
### Rules
|
||||
|
||||
* Add Skill Base Damage Rules ([#4360](https://github.com/EQEmu/Server/pull/4360)) @Kinglykrab 2024-06-01
|
||||
|
||||
### Skills
|
||||
|
||||
* Fix caps out of bounds issue ([#4377](https://github.com/EQEmu/Server/pull/4377)) @Akkadius 2024-06-01
|
||||
|
||||
## [22.51.1] 5/27/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Adjust return for perl release check @Akkadius 2024-05-26
|
||||
* Corrected issue with bazaar purchase via parcels where an incorrect quantity would be calculated. ([#4352](https://github.com/EQEmu/Server/pull/4352)) @neckkola 2024-05-27
|
||||
|
||||
### Performance
|
||||
|
||||
* Improve SkillCaps::GetTrainLevel() Efficiency ([#4350](https://github.com/EQEmu/Server/pull/4350)) @Kinglykrab 2024-05-26
|
||||
|
||||
### Rules
|
||||
|
||||
* Legacy Compute Defense against modern agi based defense. ([#4349](https://github.com/EQEmu/Server/pull/4349)) @fryguy503 2024-05-27
|
||||
|
||||
## [22.51.0] 5/26/2024
|
||||
|
||||
### Commands
|
||||
|
||||
* #npcspawn Changes ([#4311](https://github.com/EQEmu/Server/pull/4311)) @twincannon 2024-05-16
|
||||
* Cleanup #resetaa Command ([#4310](https://github.com/EQEmu/Server/pull/4310)) @Kinglykrab 2024-05-22
|
||||
|
||||
### Crash
|
||||
|
||||
* Add validation to RemoveXTarget ([#4324](https://github.com/EQEmu/Server/pull/4324)) @Akkadius 2024-05-25
|
||||
* Fix Zone deconstructor crashes ([#4325](https://github.com/EQEmu/Server/pull/4325)) @Akkadius 2024-05-25
|
||||
* Fix crash issue when dividing by zero in CalcHPRegen ([#4320](https://github.com/EQEmu/Server/pull/4320)) @Akkadius 2024-05-25
|
||||
* Fix crash when map name is null ([#4322](https://github.com/EQEmu/Server/pull/4322)) @Akkadius 2024-05-25
|
||||
* Fix player event crash in ITEM_DESTROY ([#4326](https://github.com/EQEmu/Server/pull/4326)) @Akkadius 2024-05-25
|
||||
* Fix player events reload when out of bounds ([#4321](https://github.com/EQEmu/Server/pull/4321)) @Akkadius 2024-05-25
|
||||
* Fix rarer crash in EntityList::MobProcess ([#4319](https://github.com/EQEmu/Server/pull/4319)) @Akkadius 2024-05-25
|
||||
|
||||
### Feature
|
||||
|
||||
* Add RoF2 Bazaar Support ([#4315](https://github.com/EQEmu/Server/pull/4315)) @neckkola 2024-05-26
|
||||
* Add SE_IncreaseArchery and rules to tune archery ([#4335](https://github.com/EQEmu/Server/pull/4335)) @fryguy503 2024-05-26
|
||||
* Add parcel container support ([#4305](https://github.com/EQEmu/Server/pull/4305)) @neckkola 2024-05-17
|
||||
|
||||
### Fixes
|
||||
|
||||
* Accuracy, Avoidance and Atk adjustments ([#4336](https://github.com/EQEmu/Server/pull/4336)) @fryguy503 2024-05-26
|
||||
* Fix Crash with null Argument in #modifynpcstat ([#4318](https://github.com/EQEmu/Server/pull/4318)) @Kinglykrab 2024-05-24
|
||||
* Fix RemoveAlternateCurrencyValue not updating Client ([#4317](https://github.com/EQEmu/Server/pull/4317)) @Kinglykrab 2024-05-23
|
||||
* Fix Using Bind Wound Above 70% Health ([#4340](https://github.com/EQEmu/Server/pull/4340)) @Kinglykrab 2024-05-26
|
||||
* Fix issue with #hotfix ([#4316](https://github.com/EQEmu/Server/pull/4316)) @Kinglykrab 2024-05-22
|
||||
* Fix issue with #suspend ([#4314](https://github.com/EQEmu/Server/pull/4314)) @Kinglykrab 2024-05-23
|
||||
* Fix issue with KeepOneRecordPerCompletedTask ([#4313](https://github.com/EQEmu/Server/pull/4313)) @Kinglykrab 2024-05-23
|
||||
* Fix mistaken removed RULE_CATEGORY_END() ([#4341](https://github.com/EQEmu/Server/pull/4341)) @fryguy503 2024-05-26
|
||||
* Missed a mob offense section for PR #4328 ([#4331](https://github.com/EQEmu/Server/pull/4331)) @fryguy503 2024-05-26
|
||||
* Raid Targets should not be Blindable as this will break all spell casting AI. ([#4334](https://github.com/EQEmu/Server/pull/4334)) @fryguy503 2024-05-26
|
||||
* When Mounts are allowed to zone, block them from zoning to disallowed zones. ([#4330](https://github.com/EQEmu/Server/pull/4330)) @fryguy503 2024-05-25
|
||||
* When refreshing buffs, attempt to use the same buffslot if the buff still exists. ([#4338](https://github.com/EQEmu/Server/pull/4338)) @fryguy503 2024-05-26
|
||||
|
||||
### Lua Mod
|
||||
|
||||
* Fix issue with SetAAEXP and SetEXP firing when uninitialized ([#4345](https://github.com/EQEmu/Server/pull/4345)) @Akkadius 2024-05-26
|
||||
|
||||
### Merchants
|
||||
|
||||
* Add New Classic Greed/Faction/Charisma Prices Rule ([#4301](https://github.com/EQEmu/Server/pull/4301)) @noudess 2024-05-17
|
||||
|
||||
### Mobs
|
||||
|
||||
* Remove entity type checks from ScanCloseMobs ([#4323](https://github.com/EQEmu/Server/pull/4323)) @Akkadius 2024-05-25
|
||||
|
||||
### NPC Spells
|
||||
|
||||
* Fix an issue where procs wouldn't fire if no spell entries in list ([#4344](https://github.com/EQEmu/Server/pull/4344)) @Akkadius 2024-05-26
|
||||
|
||||
### Perl
|
||||
|
||||
* Linux /opt/eqemu-perl checks when using release binaries ([#4346](https://github.com/EQEmu/Server/pull/4346)) @Akkadius 2024-05-26
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add Zone Uptime Exports to Perl/Lua ([#4339](https://github.com/EQEmu/Server/pull/4339)) @Kinglykrab 2024-05-26
|
||||
|
||||
### Rules
|
||||
|
||||
* Added MeleeMitigation Level Difference Roll Adjusted for level diffs ([#4332](https://github.com/EQEmu/Server/pull/4332)) @fryguy503 2024-05-26
|
||||
* Allow maximum per kill AA amount ([#4329](https://github.com/EQEmu/Server/pull/4329)) @fryguy503 2024-05-25
|
||||
* Allow servers to adjust the filtering threshold for heals from damage (e.g. Mark of Kings). ([#4327](https://github.com/EQEmu/Server/pull/4327)) @fryguy503 2024-05-25
|
||||
* Backstab Haste Correction ([#4337](https://github.com/EQEmu/Server/pull/4337)) @fryguy503 2024-05-26
|
||||
* Mob Offensive and Weapon Skill static tables ([#4328](https://github.com/EQEmu/Server/pull/4328)) @fryguy503 2024-05-25
|
||||
* Remove hard coded initial aggro in favor or an adjustable Rule ([#4333](https://github.com/EQEmu/Server/pull/4333)) @fryguy503 2024-05-26
|
||||
|
||||
### Scripts
|
||||
|
||||
* Fix zone data load ordering issue ([#4343](https://github.com/EQEmu/Server/pull/4343)) @Akkadius 2024-05-26
|
||||
|
||||
### Spells
|
||||
|
||||
* Add content filtering to NPC spells ([#4309](https://github.com/EQEmu/Server/pull/4309)) @Akkadius 2024-05-17
|
||||
|
||||
## [22.50.1] 5/12/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Clear GuildOnlineStatus on world boot ([#4306](https://github.com/EQEmu/Server/pull/4306)) @neckkola 2024-05-12
|
||||
|
||||
## [22.50.0] 5/9/2024
|
||||
|
||||
### Code
|
||||
@@ -1283,7 +1460,7 @@
|
||||
|
||||
### EQTime
|
||||
|
||||
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
|
||||
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
|
||||
|
||||
## [22.34.0] - 11/19/2023
|
||||
|
||||
@@ -2365,7 +2542,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Telnet encoding fix ([#3269](https://github.com/EQEmu/Server/pull/3269)) @Akkadius 2023-04-05
|
||||
|
||||
## [22.9.1] - 04/03/2023
|
||||
## [22.9.1] - 04/03/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2410,7 +2587,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Change to use Pass by reference where valid. ([#3163](https://github.com/EQEmu/Server/pull/3163)) @Aeadoin 2023-04-02
|
||||
|
||||
## [22.9.0] - 04/01/2023
|
||||
## [22.9.0] - 04/01/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2434,7 +2611,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Add missing Luabind definitions to lua_general.cpp ([#3167](https://github.com/EQEmu/Server/pull/3167)) @Kinglykrab 2023-04-01
|
||||
|
||||
## [22.8.2] - 03/30/2023
|
||||
## [22.8.2] - 03/30/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2458,13 +2635,13 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Remove Guild Bank Zone ID Rule ([#3156](https://github.com/EQEmu/Server/pull/3156)) @Kinglykrab 2023-03-29
|
||||
|
||||
## [22.8.1] - 03/27/2023
|
||||
## [22.8.1] - 03/27/2023
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix for NPCs having spells interrupted. ([#3150](https://github.com/EQEmu/Server/pull/3150)) @Aeadoin 2023-03-27
|
||||
|
||||
## [22.8.0] - 03/25/2023
|
||||
## [22.8.0] - 03/25/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2484,7 +2661,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Fix for Items looted from corpses. ([#3147](https://github.com/EQEmu/Server/pull/3147)) @Aeadoin 2023-03-26
|
||||
* Fix for SQL Query in npc_scale_global_base ([#3144](https://github.com/EQEmu/Server/pull/3144)) @Aeadoin 2023-03-26
|
||||
|
||||
## [22.7.0] - 03/24/2023
|
||||
## [22.7.0] - 03/24/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2641,7 +2818,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Add exception handling to converters themselves ([#3029](https://github.com/EQEmu/Server/pull/3029)) @Akkadius 2023-03-05
|
||||
* Add more number formatters ([#2873](https://github.com/EQEmu/Server/pull/2873)) @Kinglykrab 2023-03-04
|
||||
|
||||
## [22.4.5] - 03/03/2023
|
||||
## [22.4.5] - 03/03/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2683,7 +2860,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Add IsFindable() and IsTrackable() to Perl/Lua ([#2996](https://github.com/EQEmu/Server/pull/2996)) @Kinglykrab 2023-03-01
|
||||
* Add IsUnderwaterOnly() to Perl/Lua ([#2995](https://github.com/EQEmu/Server/pull/2995)) @Kinglykrab 2023-03-01
|
||||
|
||||
## [22.4.4] - 02/24/2023
|
||||
## [22.4.4] - 02/24/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2730,7 +2907,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Fix for Lore Conflict ([#2977](https://github.com/EQEmu/Server/pull/2977)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
|
||||
|
||||
## [22.4.3] - 02/21/2023
|
||||
## [22.4.3] - 02/21/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2777,7 +2954,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Add date to optional Drakkin Guktan Faction Update ([#2965](https://github.com/EQEmu/Server/pull/2965)) ([joligario](https://github.com/joligario)) 2023-02-19
|
||||
|
||||
## [22.4.2] - 02/18/2023
|
||||
## [22.4.2] - 02/18/2023
|
||||
|
||||
### Content
|
||||
|
||||
@@ -2799,7 +2976,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Fix regression caused by #2932 ([#2956](https://github.com/EQEmu/Server/pull/2956)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
|
||||
|
||||
## [22.4.1] - 02/17/2023
|
||||
## [22.4.1] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2820,7 +2997,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Fix rare out of bound issue when loading event types ([#2946](https://github.com/EQEmu/Server/pull/2946)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
* Turn off KILLED_NPC (trash) off by default ([#2948](https://github.com/EQEmu/Server/pull/2948)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
|
||||
## [22.4.0] - 02/17/2023
|
||||
## [22.4.0] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "../../common/repositories/skill_caps_repository.h"
|
||||
#include "../../common/file.h"
|
||||
#include "../../common/events/player_event_logs.h"
|
||||
#include "../../common/skill_caps.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
@@ -213,17 +214,16 @@ void ExportSkillCaps(SharedDatabase* db)
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
|
||||
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
|
||||
if (SkillUsable(db, skill_id, class_id)) {
|
||||
uint32 previous_cap = 0;
|
||||
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
|
||||
|
||||
for (
|
||||
uint8 level = 1;
|
||||
level <= SkillCaps::GetSkillCapMaxLevel(class_id, static_cast<EQ::skills::SkillType>(skill_id));
|
||||
level++
|
||||
) {
|
||||
uint32 cap = GetSkill(db, skill_id, class_id, level);
|
||||
if (cap < previous_cap) {
|
||||
cap = previous_cap;
|
||||
|
||||
@@ -2,6 +2,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
|
||||
SET(common_sources
|
||||
base_packet.cpp
|
||||
bazaar.cpp
|
||||
bodytypes.cpp
|
||||
classes.cpp
|
||||
cli/eqemu_command_handler.cpp
|
||||
compression.cpp
|
||||
@@ -178,6 +180,7 @@ SET(repositories
|
||||
repositories/base/base_character_material_repository.h
|
||||
repositories/base/base_character_memmed_spells_repository.h
|
||||
repositories/base/base_character_parcels_repository.h
|
||||
repositories/base/base_character_parcels_containers_repository.h
|
||||
repositories/base/base_character_peqzone_flags_repository.h
|
||||
repositories/base/base_character_pet_buffs_repository.h
|
||||
repositories/base/base_character_pet_info_repository.h
|
||||
@@ -359,6 +362,7 @@ SET(repositories
|
||||
repositories/character_material_repository.h
|
||||
repositories/character_memmed_spells_repository.h
|
||||
repositories/character_parcels_repository.h
|
||||
repositories/character_parcels_containers_repository.h
|
||||
repositories/character_peqzone_flags_repository.h
|
||||
repositories/character_pet_buffs_repository.h
|
||||
repositories/character_pet_info_repository.h
|
||||
@@ -499,6 +503,7 @@ SET(repositories
|
||||
|
||||
SET(common_headers
|
||||
additive_lagged_fibonacci_engine.h
|
||||
bazaar.h
|
||||
base_packet.h
|
||||
bodytypes.h
|
||||
classes.h
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
#include "bazaar.h"
|
||||
|
||||
#include "../../common/item_instance.h"
|
||||
#include "repositories/trader_repository.h"
|
||||
#include <memory>
|
||||
|
||||
std::vector<BazaarSearchResultsFromDB_Struct>
|
||||
Bazaar::GetSearchResults(
|
||||
SharedDatabase &db,
|
||||
BazaarSearchCriteria_Struct search,
|
||||
uint32 char_zone_id
|
||||
)
|
||||
{
|
||||
LogTrading(
|
||||
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
|
||||
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
|
||||
"search_scope [{}] char_zone_id [{}]",
|
||||
search.item_name,
|
||||
search.min_cost,
|
||||
search.max_cost,
|
||||
search.min_level,
|
||||
search.max_level,
|
||||
search.max_results,
|
||||
search.prestige,
|
||||
search.augment,
|
||||
search.trader_entity_id,
|
||||
search.trader_id,
|
||||
search.search_scope,
|
||||
char_zone_id
|
||||
);
|
||||
|
||||
std::string search_criteria_trader("TRUE ");
|
||||
|
||||
if (search.search_scope == NonRoFBazaarSearchScope) {
|
||||
search_criteria_trader.append(
|
||||
fmt::format(
|
||||
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
|
||||
search.trader_entity_id,
|
||||
Zones::BAZAAR
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (search.search_scope == Local_Scope) {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
|
||||
}
|
||||
else if (search.trader_id > 0) {
|
||||
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));
|
||||
}
|
||||
if (search.max_cost != 0) {
|
||||
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));
|
||||
// }
|
||||
|
||||
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 "
|
||||
"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()
|
||||
);
|
||||
|
||||
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
struct ItemSearchType {
|
||||
EQ::item::ItemType type;
|
||||
bool condition;
|
||||
};
|
||||
|
||||
struct AddititiveSearchCriteria {
|
||||
bool should_check;
|
||||
bool condition;
|
||||
};
|
||||
|
||||
for (auto row: results) {
|
||||
BazaarSearchResultsFromDB_Struct r{};
|
||||
|
||||
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_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},
|
||||
{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 (!should_add) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
|
||||
all_entries.push_back(r);
|
||||
}
|
||||
|
||||
if (all_entries.size() > search.max_results) {
|
||||
all_entries.resize(search.max_results);
|
||||
}
|
||||
|
||||
LogTrading("Returning [{}] items from search results", all_entries.size());
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef EQEMU_BAZAAR_H
|
||||
#define EQEMU_BAZAAR_H
|
||||
|
||||
#include <vector>
|
||||
#include "shareddb.h"
|
||||
|
||||
class Bazaar {
|
||||
public:
|
||||
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_BAZAAR_H
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/bodytypes.h"
|
||||
|
||||
std::string BodyType::GetName(uint8 body_type_id)
|
||||
{
|
||||
return IsValid(body_type_id) ? body_type_names[body_type_id] : "UNKNOWN BODY TYPE";
|
||||
}
|
||||
|
||||
bool BodyType::IsValid(uint8 body_type_id)
|
||||
{
|
||||
return body_type_names.find(body_type_id) != body_type_names.end();
|
||||
}
|
||||
+90
-46
@@ -18,52 +18,96 @@
|
||||
#ifndef BODYTYPES_H
|
||||
#define BODYTYPES_H
|
||||
|
||||
typedef enum {
|
||||
BT_Humanoid = 1,
|
||||
BT_Lycanthrope = 2,
|
||||
BT_Undead = 3,
|
||||
BT_Giant = 4,
|
||||
BT_Construct = 5,
|
||||
BT_Extraplanar = 6,
|
||||
BT_Magical = 7, //this name might be a bit off,
|
||||
BT_SummonedUndead = 8,
|
||||
BT_RaidGiant = 9, //Velious era Raid Giant
|
||||
BT_RaidColdain = 10, //Velious era Raid Coldain
|
||||
BT_NoTarget = 11, //no name, can't target this bodytype
|
||||
BT_Vampire = 12,
|
||||
BT_Atenha_Ra = 13,
|
||||
BT_Greater_Akheva = 14,
|
||||
BT_Khati_Sha = 15,
|
||||
BT_Seru = 16,
|
||||
BT_Grieg_Veneficus = 17,
|
||||
BT_Draz_Nurakk = 18,
|
||||
BT_Zek = 19, //"creatures from the Plane of War."
|
||||
BT_Luggald = 20,
|
||||
BT_Animal = 21,
|
||||
BT_Insect = 22,
|
||||
BT_Monster = 23,
|
||||
BT_Summoned = 24, //Elemental?
|
||||
BT_Plant = 25,
|
||||
BT_Dragon = 26,
|
||||
BT_Summoned2 = 27,
|
||||
BT_Summoned3 = 28,
|
||||
BT_Dragon2 = 29, //database data indicates this is a dragon type (kunark and DoN?)
|
||||
BT_VeliousDragon = 30, //might not be a tight set
|
||||
BT_Familiar = 31,
|
||||
BT_Dragon3 = 32,
|
||||
BT_Boxes = 33,
|
||||
BT_Muramite = 34, //tribal dudes
|
||||
// ...
|
||||
BT_NoTarget2 = 60,
|
||||
// ...
|
||||
BT_SwarmPet = 63, //Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
|
||||
BT_MonsterSummon = 64,
|
||||
// 65, trap or effect related?
|
||||
BT_InvisMan = 66, //no name, seen on 'InvisMan', can be /targeted
|
||||
BT_Special = 67
|
||||
} bodyType;
|
||||
/* bodytypes above 64 make the mob not show up */
|
||||
#include "types.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
constexpr int format_as(bodyType type) { return static_cast<int>(type); }
|
||||
// body types above 64 make the mob invisible
|
||||
namespace BodyType {
|
||||
constexpr uint8 Humanoid = 1;
|
||||
constexpr uint8 Lycanthrope = 2;
|
||||
constexpr uint8 Undead = 3;
|
||||
constexpr uint8 Giant = 4;
|
||||
constexpr uint8 Construct = 5;
|
||||
constexpr uint8 Extraplanar = 6;
|
||||
constexpr uint8 Magical = 7; // this name might be a bit off,
|
||||
constexpr uint8 SummonedUndead = 8;
|
||||
constexpr uint8 RaidGiant = 9; // Velious era Raid Giant
|
||||
constexpr uint8 RaidColdain = 10; // Velious era Raid Coldain
|
||||
constexpr uint8 NoTarget = 11; // no name, can't target this bodytype
|
||||
constexpr uint8 Vampire = 12;
|
||||
constexpr uint8 AtenHaRa = 13;
|
||||
constexpr uint8 GreaterAkheva = 14;
|
||||
constexpr uint8 KhatiSha = 15;
|
||||
constexpr uint8 Seru = 16;
|
||||
constexpr uint8 GriegVeneficus = 17;
|
||||
constexpr uint8 DrazNurakk = 18;
|
||||
constexpr uint8 Zek = 19; //"creatures from the Plane of War."
|
||||
constexpr uint8 Luggald = 20;
|
||||
constexpr uint8 Animal = 21;
|
||||
constexpr uint8 Insect = 22;
|
||||
constexpr uint8 Monster = 23;
|
||||
constexpr uint8 Summoned = 24; // Elemental?
|
||||
constexpr uint8 Plant = 25;
|
||||
constexpr uint8 Dragon = 26;
|
||||
constexpr uint8 Summoned2 = 27;
|
||||
constexpr uint8 Summoned3 = 28;
|
||||
constexpr uint8 Dragon2 = 29; // database data indicates this is a dragon type (Kunark and DoN?)
|
||||
constexpr uint8 VeliousDragon = 30; // might not be a tight set
|
||||
constexpr uint8 Familiar = 31;
|
||||
constexpr uint8 Dragon3 = 32;
|
||||
constexpr uint8 Boxes = 33;
|
||||
constexpr uint8 Muramite = 34; // tribal dudes
|
||||
constexpr uint8 NoTarget2 = 60;
|
||||
constexpr uint8 SwarmPet = 63; // Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
|
||||
constexpr uint8 MonsterSummon = 64;
|
||||
constexpr uint8 InvisibleMan = 66; // no name, seen on 'InvisMan', can be /targeted
|
||||
constexpr uint8 Special = 67;
|
||||
|
||||
std::string GetName(uint8 body_type_id);
|
||||
bool IsValid(uint8 body_type_id);
|
||||
}
|
||||
|
||||
static std::map<uint8, std::string> body_type_names = {
|
||||
{ BodyType::Humanoid, "Humanoid" },
|
||||
{ BodyType::Lycanthrope, "Lycanthrope" },
|
||||
{ BodyType::Undead, "Undead" },
|
||||
{ BodyType::Giant, "Giant" },
|
||||
{ BodyType::Construct, "Construct" },
|
||||
{ BodyType::Extraplanar, "Extraplanar" },
|
||||
{ BodyType::Magical, "Magical" },
|
||||
{ BodyType::SummonedUndead, "Summoned Undead" },
|
||||
{ BodyType::RaidGiant, "Raid Giant" },
|
||||
{ BodyType::RaidColdain, "Raid Coldain" },
|
||||
{ BodyType::NoTarget, "Untargetable" },
|
||||
{ BodyType::Vampire, "Vampire" },
|
||||
{ BodyType::AtenHaRa, "Aten Ha Ra" },
|
||||
{ BodyType::GreaterAkheva, "Greater Akheva" },
|
||||
{ BodyType::KhatiSha, "Khati Sha" },
|
||||
{ BodyType::Seru, "Seru" },
|
||||
{ BodyType::GriegVeneficus, "Grieg Veneficus" },
|
||||
{ BodyType::DrazNurakk, "Draz Nurakk" },
|
||||
{ BodyType::Zek, "Zek" },
|
||||
{ BodyType::Luggald, "Luggald" },
|
||||
{ BodyType::Animal, "Animal" },
|
||||
{ BodyType::Insect, "Insect" },
|
||||
{ BodyType::Monster, "Monster" },
|
||||
{ BodyType::Summoned, "Summoned" },
|
||||
{ BodyType::Plant, "Plant" },
|
||||
{ BodyType::Dragon, "Dragon" },
|
||||
{ BodyType::Summoned2, "Summoned 2" },
|
||||
{ BodyType::Summoned3, "Summoned 3" },
|
||||
{ BodyType::Dragon2, "Dragon 2" },
|
||||
{ BodyType::VeliousDragon, "Velious Dragon" },
|
||||
{ BodyType::Familiar, "Familiar" },
|
||||
{ BodyType::Dragon3, "Dragon 3" },
|
||||
{ BodyType::Boxes, "Boxes" },
|
||||
{ BodyType::Muramite, "Muramite" },
|
||||
{ BodyType::NoTarget2, "Untargetable 2" },
|
||||
{ BodyType::SwarmPet, "Swarm Pet" },
|
||||
{ BodyType::MonsterSummon, "Monster Summon" },
|
||||
{ BodyType::InvisibleMan, "Invisible Man" },
|
||||
{ BodyType::Special, "Special" },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+24
-3
@@ -77,6 +77,7 @@
|
||||
#include "zone_store.h"
|
||||
#include "repositories/merchantlist_temp_repository.h"
|
||||
#include "repositories/bot_data_repository.h"
|
||||
#include "repositories/trader_repository.h"
|
||||
|
||||
extern Client client;
|
||||
|
||||
@@ -206,9 +207,19 @@ void Database::LoginIP(uint32 account_id, const std::string& login_ip)
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
int16 Database::CheckStatus(uint32 account_id)
|
||||
int16 Database::GetAccountStatus(uint32 account_id)
|
||||
{
|
||||
return AccountRepository::GetAccountStatus(*this, account_id);
|
||||
auto e = AccountRepository::FindOne(*this, account_id);
|
||||
|
||||
if (e.suspendeduntil > 0 && e.suspendeduntil < std::time(nullptr)) {
|
||||
e.status = 0;
|
||||
e.suspendeduntil = 0;
|
||||
e.suspend_reason = "";
|
||||
|
||||
AccountRepository::UpdateOne(*this, e);
|
||||
}
|
||||
|
||||
return e.status;
|
||||
}
|
||||
|
||||
uint32 Database::CreateAccount(
|
||||
@@ -741,7 +752,7 @@ bool Database::SetVariable(const std::string& name, const std::string& value)
|
||||
auto l = VariablesRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`name` = '{}'",
|
||||
"`varname` = '{}'",
|
||||
Strings::Escape(name)
|
||||
)
|
||||
);
|
||||
@@ -2089,3 +2100,13 @@ void Database::PurgeCharacterParcels()
|
||||
RuleI(Parcel, ParcelPruneDelay)
|
||||
);
|
||||
}
|
||||
|
||||
void Database::ClearGuildOnlineStatus()
|
||||
{
|
||||
GuildMembersRepository::ClearOnlineStatus(*this);
|
||||
}
|
||||
|
||||
void Database::ClearTraderDetails()
|
||||
{
|
||||
TraderRepository::Truncate(*this);
|
||||
}
|
||||
|
||||
+3
-1
@@ -170,7 +170,7 @@ public:
|
||||
bool SetAccountStatus(const std::string& account_name, int16 status);
|
||||
bool SetLocalPassword(uint32 account_id, const std::string& password);
|
||||
bool UpdateLiveChar(const std::string& name, uint32 account_id);
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
int16 GetAccountStatus(uint32 account_id);
|
||||
void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum);
|
||||
uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
|
||||
uint32 CreateAccount(
|
||||
@@ -243,6 +243,8 @@ public:
|
||||
void SetRaidGroupLeaderInfo(uint32 group_id, uint32 raid_id);
|
||||
|
||||
void PurgeAllDeletedDataBuckets();
|
||||
void ClearGuildOnlineStatus();
|
||||
void ClearTraderDetails();
|
||||
|
||||
|
||||
/* Database Variables */
|
||||
|
||||
@@ -5567,6 +5567,99 @@ ADD COLUMN `is_parcel_merchant` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `
|
||||
.sql = R"(
|
||||
ALTER TABLE `character_data`
|
||||
ADD COLUMN `extra_haste` int(11) NOT NULL DEFAULT 0 AFTER `wis`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9276,
|
||||
.description = "2024_05_12_fix_guild_bank_dup_issue.sql",
|
||||
.check = "SHOW COLUMNS FROM `guild_bank` WHERE FIELD = 'qty' AND Type LIKE '%unsigned';",
|
||||
.condition = "not_empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `guild_bank`
|
||||
CHANGE COLUMN `qty` `qty` INT(10) NOT NULL DEFAULT '0' AFTER `itemid`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9277,
|
||||
.description = "2024_05_09_parcel_enable_containers.sql",
|
||||
.check = "SHOW TABLES LIKE 'character_parcels_containers'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
CREATE TABLE `character_parcels_containers` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`parcels_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`slot_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_1` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_2` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_3` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_4` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_5` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`aug_slot_6` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`quantity` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `fk_character_parcels_id` (`parcels_id`) USING BTREE,
|
||||
CONSTRAINT `fk_character_parcels_id` FOREIGN KEY (`parcels_id`) REFERENCES `character_parcels` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
AUTO_INCREMENT=1
|
||||
;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9278,
|
||||
.description = "2024_05_06_npc_greed.sql",
|
||||
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'greed'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `npc_types`
|
||||
ADD COLUMN `greed` tinyint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `merchant_id`;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9279,
|
||||
.description = "2024_05_13_content_flagging_npc_spells_entries.sql",
|
||||
.check = "SHOW COLUMNS FROM `npc_spells_entries` LIKE 'content_flags'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `npc_spells_entries` ADD `min_expansion` tinyint(4) NOT NULL DEFAULT -1;
|
||||
ALTER TABLE `npc_spells_entries` ADD `max_expansion` tinyint(4) NOT NULL DEFAULT -1;
|
||||
ALTER TABLE `npc_spells_entries` ADD `content_flags` varchar(100) NULL;
|
||||
ALTER TABLE `npc_spells_entries` ADD `content_flags_disabled` varchar(100) NULL;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9280,
|
||||
.description = "2024_05_11_update_trader_support.sql",
|
||||
.check = "SHOW COLUMNS FROM `trader` LIKE 'aug_slot_1'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `trader`
|
||||
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||
CHANGE COLUMN `char_id` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
|
||||
CHANGE COLUMN `item_id` `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
|
||||
ADD COLUMN `aug_slot_1` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `item_id`,
|
||||
ADD COLUMN `aug_slot_2` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_1`,
|
||||
ADD COLUMN `aug_slot_3` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_2`,
|
||||
ADD COLUMN `aug_slot_4` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_3`,
|
||||
ADD COLUMN `aug_slot_5` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_4`,
|
||||
ADD COLUMN `aug_slot_6` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_5`,
|
||||
CHANGE COLUMN `serialnumber` `item_sn` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_6`,
|
||||
CHANGE COLUMN `charges` `item_charges` INT(11) NOT NULL DEFAULT '0' AFTER `item_sn`,
|
||||
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `slot_id`,
|
||||
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_entity_id`,
|
||||
ADD COLUMN `active_transaction` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_zone_id`,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace DatabaseSchema {
|
||||
{"character_material", "id"},
|
||||
{"character_memmed_spells", "id"},
|
||||
{"character_parcels", "char_id"},
|
||||
{"character_parcels_containers", "id"},
|
||||
{"character_pet_buffs", "char_id"},
|
||||
{"character_pet_info", "char_id"},
|
||||
{"character_pet_inventory", "char_id"},
|
||||
@@ -130,6 +131,7 @@ namespace DatabaseSchema {
|
||||
"character_material",
|
||||
"character_memmed_spells",
|
||||
"character_parcels",
|
||||
"character_parcels_containers",
|
||||
"character_pet_buffs",
|
||||
"character_pet_info",
|
||||
"character_pet_inventory",
|
||||
|
||||
+6
-70
@@ -19,81 +19,17 @@
|
||||
|
||||
#include "deity.h"
|
||||
|
||||
EQ::deity::DeityTypeBit EQ::deity::GetDeityBitmask(DeityType deity_type)
|
||||
uint32 Deity::GetBitmask(uint32 deity_id)
|
||||
{
|
||||
switch (deity_type) {
|
||||
case DeityBertoxxulous:
|
||||
return bit_DeityBertoxxulous;
|
||||
case DeityBrellSirilis:
|
||||
return bit_DeityBrellSirilis;
|
||||
case DeityCazicThule:
|
||||
return bit_DeityCazicThule;
|
||||
case DeityErollisiMarr:
|
||||
return bit_DeityErollisiMarr;
|
||||
case DeityBristlebane:
|
||||
return bit_DeityBristlebane;
|
||||
case DeityInnoruuk:
|
||||
return bit_DeityInnoruuk;
|
||||
case DeityKarana:
|
||||
return bit_DeityKarana;
|
||||
case DeityMithanielMarr:
|
||||
return bit_DeityMithanielMarr;
|
||||
case DeityPrexus:
|
||||
return bit_DeityPrexus;
|
||||
case DeityQuellious:
|
||||
return bit_DeityQuellious;
|
||||
case DeityRallosZek:
|
||||
return bit_DeityRallosZek;
|
||||
case DeityRodcetNife:
|
||||
return bit_DeityRodcetNife;
|
||||
case DeitySolusekRo:
|
||||
return bit_DeitySolusekRo;
|
||||
case DeityTheTribunal:
|
||||
return bit_DeityTheTribunal;
|
||||
case DeityTunare:
|
||||
return bit_DeityTunare;
|
||||
case DeityVeeshan:
|
||||
return bit_DeityVeeshan;
|
||||
case DeityAgnostic_LB:
|
||||
case DeityAgnostic:
|
||||
return bit_DeityAgnostic;
|
||||
default:
|
||||
return bit_DeityAll;
|
||||
}
|
||||
return IsValid(deity_id) ? deity_bitmasks[deity_id] : Deity::Bitmask::All;
|
||||
}
|
||||
|
||||
const std::map<EQ::deity::DeityType, std::string>& EQ::deity::GetDeityMap()
|
||||
std::string Deity::GetName(uint32 deity_id)
|
||||
{
|
||||
static const std::map<EQ::deity::DeityType, std::string> deity_map = {
|
||||
{ DeityAgnostic, "Agnostic" },
|
||||
{ DeityAgnostic_LB, "Agnostic" },
|
||||
{ DeityBertoxxulous, "Bertoxxulous" },
|
||||
{ DeityBrellSirilis, "Brell Serilis" },
|
||||
{ DeityBristlebane, "Bristlebane" },
|
||||
{ DeityCazicThule, "Cazic-Thule" },
|
||||
{ DeityErollisiMarr, "Erollisi Marr" },
|
||||
{ DeityInnoruuk, "Innoruuk" },
|
||||
{ DeityKarana, "Karana" },
|
||||
{ DeityMithanielMarr, "Mithaniel Marr" },
|
||||
{ DeityPrexus, "Prexus" },
|
||||
{ DeityQuellious, "Quellious" },
|
||||
{ DeityRallosZek, "Rallos Zek" },
|
||||
{ DeityRodcetNife, "Rodcet Nife" },
|
||||
{ DeitySolusekRo, "Solusek Ro" },
|
||||
{ DeityTheTribunal, "The Tribunal" },
|
||||
{ DeityTunare, "Tunare" },
|
||||
{ DeityVeeshan, "Veeshan" }
|
||||
};
|
||||
|
||||
return deity_map;
|
||||
return IsValid(deity_id) ? deity_names[deity_id] : "UNKNOWN DEITY";
|
||||
}
|
||||
|
||||
std::string EQ::deity::GetDeityName(DeityType deity_type)
|
||||
bool Deity::IsValid(uint32 deity_id)
|
||||
{
|
||||
|
||||
if (EQ::deity::GetDeityMap().find(deity_type) != EQ::deity::GetDeityMap().end()) {
|
||||
return EQ::deity::GetDeityMap().find(deity_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return deity_names.find(deity_id) != deity_names.end();
|
||||
}
|
||||
|
||||
+85
-52
@@ -23,62 +23,95 @@
|
||||
#include "types.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
namespace Deity {
|
||||
constexpr uint32 Unknown = 0;
|
||||
constexpr uint32 Agnostic1 = 140;
|
||||
constexpr uint32 Bertoxxulous = 201;
|
||||
constexpr uint32 BrellSirilis = 202;
|
||||
constexpr uint32 CazicThule = 203;
|
||||
constexpr uint32 ErollisiMarr = 204;
|
||||
constexpr uint32 Bristlebane = 205;
|
||||
constexpr uint32 Innoruuk = 206;
|
||||
constexpr uint32 Karana = 207;
|
||||
constexpr uint32 MithanielMarr = 208;
|
||||
constexpr uint32 Prexus = 209;
|
||||
constexpr uint32 Quellious = 210;
|
||||
constexpr uint32 RallosZek = 211;
|
||||
constexpr uint32 RodcetNife = 212;
|
||||
constexpr uint32 SolusekRo = 213;
|
||||
constexpr uint32 TheTribunal = 214;
|
||||
constexpr uint32 Tunare = 215;
|
||||
constexpr uint32 Veeshan = 216;
|
||||
constexpr uint32 Agnostic2 = 396;
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace deity {
|
||||
enum DeityType {
|
||||
DeityUnknown = 0,
|
||||
DeityAgnostic_LB = 140,
|
||||
DeityBertoxxulous = 201,
|
||||
DeityBrellSirilis,
|
||||
DeityCazicThule,
|
||||
DeityErollisiMarr,
|
||||
DeityBristlebane,
|
||||
DeityInnoruuk,
|
||||
DeityKarana,
|
||||
DeityMithanielMarr,
|
||||
DeityPrexus,
|
||||
DeityQuellious,
|
||||
DeityRallosZek,
|
||||
DeityRodcetNife,
|
||||
DeitySolusekRo,
|
||||
DeityTheTribunal,
|
||||
DeityTunare,
|
||||
DeityVeeshan,
|
||||
DeityAgnostic = 396
|
||||
};
|
||||
namespace Bitmask {
|
||||
constexpr uint32 Agnostic = 1;
|
||||
constexpr uint32 Bertoxxulous = 2;
|
||||
constexpr uint32 BrellSirilis = 4;
|
||||
constexpr uint32 CazicThule = 8;
|
||||
constexpr uint32 ErollisiMarr = 16;
|
||||
constexpr uint32 Bristlebane = 32;
|
||||
constexpr uint32 Innoruuk = 64;
|
||||
constexpr uint32 Karana = 128;
|
||||
constexpr uint32 MithanielMarr = 256;
|
||||
constexpr uint32 Prexus = 512;
|
||||
constexpr uint32 Quellious = 1024;
|
||||
constexpr uint32 RallosZek = 2048;
|
||||
constexpr uint32 RodcetNife = 4096;
|
||||
constexpr uint32 SolusekRo = 8192;
|
||||
constexpr uint32 TheTribunal = 16384;
|
||||
constexpr uint32 Tunare = 32768;
|
||||
constexpr uint32 Veeshan = 65536;
|
||||
constexpr uint32 All = std::numeric_limits<uint32>::max();
|
||||
}
|
||||
|
||||
enum DeityTypeBit : uint32 {
|
||||
bit_DeityAgnostic = 0x00000001,
|
||||
bit_DeityBertoxxulous = 0x00000002,
|
||||
bit_DeityBrellSirilis = 0x00000004,
|
||||
bit_DeityCazicThule = 0x00000008,
|
||||
bit_DeityErollisiMarr = 0x00000010,
|
||||
bit_DeityBristlebane = 0x00000020,
|
||||
bit_DeityInnoruuk = 0x00000040,
|
||||
bit_DeityKarana = 0x00000080,
|
||||
bit_DeityMithanielMarr = 0x00000100,
|
||||
bit_DeityPrexus = 0x00000200,
|
||||
bit_DeityQuellious = 0x00000400,
|
||||
bit_DeityRallosZek = 0x00000800,
|
||||
bit_DeityRodcetNife = 0x00001000,
|
||||
bit_DeitySolusekRo = 0x00002000,
|
||||
bit_DeityTheTribunal = 0x00004000,
|
||||
bit_DeityTunare = 0x00008000,
|
||||
bit_DeityVeeshan = 0x00010000,
|
||||
bit_DeityAll = UINT32_MAX
|
||||
};
|
||||
uint32 GetBitmask(uint32 deity_id);
|
||||
std::string GetName(uint32 deity_id);
|
||||
bool IsValid(uint32 deity_id);
|
||||
}
|
||||
|
||||
constexpr int format_as(DeityType type) { return static_cast<int>(type); }
|
||||
static std::map<uint32, std::string> deity_names = {
|
||||
{ Deity::Agnostic1, "Agnostic" },
|
||||
{ Deity::Agnostic2, "Agnostic" },
|
||||
{ Deity::Bertoxxulous, "Bertoxxulous" },
|
||||
{ Deity::BrellSirilis, "Brell Serilis" },
|
||||
{ Deity::Bristlebane, "Bristlebane" },
|
||||
{ Deity::CazicThule, "Cazic-Thule" },
|
||||
{ Deity::ErollisiMarr, "Erollisi Marr" },
|
||||
{ Deity::Innoruuk, "Innoruuk" },
|
||||
{ Deity::Karana, "Karana" },
|
||||
{ Deity::MithanielMarr, "Mithaniel Marr" },
|
||||
{ Deity::Prexus, "Prexus" },
|
||||
{ Deity::Quellious, "Quellious" },
|
||||
{ Deity::RallosZek, "Rallos Zek" },
|
||||
{ Deity::RodcetNife, "Rodcet Nife" },
|
||||
{ Deity::SolusekRo, "Solusek Ro" },
|
||||
{ Deity::TheTribunal, "The Tribunal" },
|
||||
{ Deity::Tunare, "Tunare" },
|
||||
{ Deity::Veeshan, "Veeshan" }
|
||||
};
|
||||
|
||||
extern DeityTypeBit GetDeityBitmask(DeityType deity_type);
|
||||
extern std::string GetDeityName(DeityType deity_type);
|
||||
extern const std::map<DeityType, std::string>& GetDeityMap();
|
||||
|
||||
} /*deity*/
|
||||
|
||||
} /*EQEmu*/
|
||||
static std::map<uint32, uint32> deity_bitmasks = {
|
||||
{ Deity::Agnostic1, Deity::Bitmask::Agnostic },
|
||||
{ Deity::Agnostic2, Deity::Bitmask::Agnostic },
|
||||
{ Deity::Bertoxxulous, Deity::Bitmask::Bertoxxulous },
|
||||
{ Deity::BrellSirilis, Deity::Bitmask::BrellSirilis },
|
||||
{ Deity::CazicThule, Deity::Bitmask::CazicThule },
|
||||
{ Deity::ErollisiMarr, Deity::Bitmask::ErollisiMarr },
|
||||
{ Deity::Bristlebane, Deity::Bitmask::Bristlebane },
|
||||
{ Deity::Innoruuk, Deity::Bitmask::Innoruuk },
|
||||
{ Deity::Karana, Deity::Bitmask::Karana },
|
||||
{ Deity::MithanielMarr, Deity::Bitmask::MithanielMarr },
|
||||
{ Deity::Prexus, Deity::Bitmask::Prexus },
|
||||
{ Deity::Quellious, Deity::Bitmask::Quellious },
|
||||
{ Deity::RallosZek, Deity::Bitmask::RallosZek },
|
||||
{ Deity::RodcetNife, Deity::Bitmask::RodcetNife },
|
||||
{ Deity::SolusekRo, Deity::Bitmask::SolusekRo },
|
||||
{ Deity::TheTribunal, Deity::Bitmask::TheTribunal },
|
||||
{ Deity::Tunare, Deity::Bitmask::Tunare },
|
||||
{ Deity::Veeshan, Deity::Bitmask::Veeshan }
|
||||
};
|
||||
|
||||
#endif /* COMMON_DEITY_H */
|
||||
|
||||
+44
-301
@@ -59,68 +59,25 @@ int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
|
||||
return local_array[inv_type];
|
||||
}
|
||||
|
||||
const char* EQ::bug::CategoryIDToCategoryName(CategoryID category_id) {
|
||||
switch (category_id) {
|
||||
case catVideo:
|
||||
return "Video";
|
||||
case catAudio:
|
||||
return "Audio";
|
||||
case catPathing:
|
||||
return "Pathing";
|
||||
case catQuest:
|
||||
return "Quest";
|
||||
case catTradeskills:
|
||||
return "Tradeskills";
|
||||
case catSpellStacking:
|
||||
return "Spell stacking";
|
||||
case catDoorsPortals:
|
||||
return "Doors/Portals";
|
||||
case catItems:
|
||||
return "Items";
|
||||
case catNPC:
|
||||
return "NPC";
|
||||
case catDialogs:
|
||||
return "Dialogs";
|
||||
case catLoNTCG:
|
||||
return "LoN - TCG";
|
||||
case catMercenaries:
|
||||
return "Mercenaries";
|
||||
case catOther:
|
||||
default:
|
||||
return "Other";
|
||||
uint32 Bug::GetID(const std::string& category_name)
|
||||
{
|
||||
for (const auto& e : bug_category_names) {
|
||||
if (e.second == category_name) {
|
||||
return e.first;
|
||||
}
|
||||
}
|
||||
|
||||
return Bug::Category::Other;
|
||||
}
|
||||
|
||||
EQ::bug::CategoryID EQ::bug::CategoryNameToCategoryID(const char* category_name) {
|
||||
if (!category_name)
|
||||
return catOther;
|
||||
std::string Bug::GetName(uint32 category_id)
|
||||
{
|
||||
return IsValid(category_id) ? bug_category_names[category_id] : "UNKNOWN BUG CATEGORY";
|
||||
}
|
||||
|
||||
if (!strcmp(category_name, "Video"))
|
||||
return catVideo;
|
||||
if (!strcmp(category_name, "Audio"))
|
||||
return catAudio;
|
||||
if (!strcmp(category_name, "Pathing"))
|
||||
return catPathing;
|
||||
if (!strcmp(category_name, "Quest"))
|
||||
return catQuest;
|
||||
if (!strcmp(category_name, "Tradeskills"))
|
||||
return catTradeskills;
|
||||
if (!strcmp(category_name, "Spell stacking"))
|
||||
return catSpellStacking;
|
||||
if (!strcmp(category_name, "Doors/Portals"))
|
||||
return catDoorsPortals;
|
||||
if (!strcmp(category_name, "Items"))
|
||||
return catItems;
|
||||
if (!strcmp(category_name, "NPC"))
|
||||
return catNPC;
|
||||
if (!strcmp(category_name, "Dialogs"))
|
||||
return catDialogs;
|
||||
if (!strcmp(category_name, "LoN - TCG"))
|
||||
return catLoNTCG;
|
||||
if (!strcmp(category_name, "Mercenaries"))
|
||||
return catMercenaries;
|
||||
|
||||
return catOther;
|
||||
bool Bug::IsValid(uint32 category_id)
|
||||
{
|
||||
return bug_category_names.find(category_id) != bug_category_names.end();
|
||||
}
|
||||
|
||||
const char *EQ::constants::GetStanceName(StanceType stance_type) {
|
||||
@@ -249,102 +206,6 @@ std::string EQ::constants::GetFlyModeName(int8 flymode_id)
|
||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||
}
|
||||
|
||||
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
|
||||
{
|
||||
static const std::map<bodyType, std::string> bodytype_map = {
|
||||
{ BT_Humanoid, "Humanoid" },
|
||||
{ BT_Lycanthrope, "Lycanthrope" },
|
||||
{ BT_Undead, "Undead" },
|
||||
{ BT_Giant, "Giant" },
|
||||
{ BT_Construct, "Construct" },
|
||||
{ BT_Extraplanar, "Extraplanar" },
|
||||
{ BT_Magical, "Magical" },
|
||||
{ BT_SummonedUndead, "Summoned Undead" },
|
||||
{ BT_RaidGiant, "Raid Giant" },
|
||||
{ BT_RaidColdain, "Raid Coldain" },
|
||||
{ BT_NoTarget, "Untargetable" },
|
||||
{ BT_Vampire, "Vampire" },
|
||||
{ BT_Atenha_Ra, "Aten Ha Ra" },
|
||||
{ BT_Greater_Akheva, "Greater Akheva" },
|
||||
{ BT_Khati_Sha, "Khati Sha" },
|
||||
{ BT_Seru, "Seru" },
|
||||
{ BT_Grieg_Veneficus, "Grieg Veneficus" },
|
||||
{ BT_Draz_Nurakk, "Draz Nurakk" },
|
||||
{ BT_Zek, "Zek" },
|
||||
{ BT_Luggald, "Luggald" },
|
||||
{ BT_Animal, "Animal" },
|
||||
{ BT_Insect, "Insect" },
|
||||
{ BT_Monster, "Monster" },
|
||||
{ BT_Summoned, "Summoned" },
|
||||
{ BT_Plant, "Plant" },
|
||||
{ BT_Dragon, "Dragon" },
|
||||
{ BT_Summoned2, "Summoned 2" },
|
||||
{ BT_Summoned3, "Summoned 3" },
|
||||
{ BT_Dragon2, "Dragon 2" },
|
||||
{ BT_VeliousDragon, "Velious Dragon" },
|
||||
{ BT_Familiar, "Familiar" },
|
||||
{ BT_Dragon3, "Dragon 3" },
|
||||
{ BT_Boxes, "Boxes" },
|
||||
{ BT_Muramite, "Muramite" },
|
||||
{ BT_NoTarget2, "Untargetable 2" },
|
||||
{ BT_SwarmPet, "Swarm Pet" },
|
||||
{ BT_MonsterSummon, "Monster Summon" },
|
||||
{ BT_InvisMan, "Invisible Man" },
|
||||
{ BT_Special, "Special" },
|
||||
};
|
||||
|
||||
return bodytype_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id)
|
||||
{
|
||||
if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) {
|
||||
return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetAccountStatusMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> account_status_map = {
|
||||
{ AccountStatus::Player, "Player" },
|
||||
{ AccountStatus::Steward, "Steward" },
|
||||
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
|
||||
{ AccountStatus::Guide, "Guide" },
|
||||
{ AccountStatus::QuestTroupe, "Quest Troupe" },
|
||||
{ AccountStatus::SeniorGuide, "Senior Guide" },
|
||||
{ AccountStatus::GMTester, "GM Tester" },
|
||||
{ AccountStatus::EQSupport, "EQ Support" },
|
||||
{ AccountStatus::GMStaff, "GM Staff" },
|
||||
{ AccountStatus::GMAdmin, "GM Admin" },
|
||||
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
|
||||
{ AccountStatus::QuestMaster, "Quest Master" },
|
||||
{ AccountStatus::GMAreas, "GM Areas" },
|
||||
{ AccountStatus::GMCoder, "GM Coder" },
|
||||
{ AccountStatus::GMMgmt, "GM Mgmt" },
|
||||
{ AccountStatus::GMImpossible, "GM Impossible" },
|
||||
{ AccountStatus::Max, "GM Max" }
|
||||
};
|
||||
|
||||
return account_status_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetAccountStatusName(uint8 account_status)
|
||||
{
|
||||
for (
|
||||
auto status_level = EQ::constants::GetAccountStatusMap().rbegin();
|
||||
status_level != EQ::constants::GetAccountStatusMap().rend();
|
||||
++status_level
|
||||
) {
|
||||
if (account_status >= status_level->first) {
|
||||
return status_level->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> consider_level_map = {
|
||||
@@ -435,84 +296,6 @@ std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
|
||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||
}
|
||||
|
||||
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
|
||||
{
|
||||
static const std::map<int, std::string> object_type_map = {
|
||||
{ ObjectTypes::SmallBag, "Small Bag" },
|
||||
{ ObjectTypes::LargeBag, "Large Bag" },
|
||||
{ ObjectTypes::Quiver, "Quiver" },
|
||||
{ ObjectTypes::BeltPouch, "Belt Pouch" },
|
||||
{ ObjectTypes::WristPouch, "Wrist Pouch" },
|
||||
{ ObjectTypes::Backpack, "Backpack" },
|
||||
{ ObjectTypes::SmallChest, "Small Chest" },
|
||||
{ ObjectTypes::LargeChest, "Large Chest" },
|
||||
{ ObjectTypes::Bandolier, "Bandolier" },
|
||||
{ ObjectTypes::Medicine, "Medicine" },
|
||||
{ ObjectTypes::Tinkering, "Tinkering" },
|
||||
{ ObjectTypes::Lexicon, "Lexicon" },
|
||||
{ ObjectTypes::PoisonMaking, "Mortar and Pestle" },
|
||||
{ ObjectTypes::Quest, "Quest" },
|
||||
{ ObjectTypes::MixingBowl, "Mixing Bowl" },
|
||||
{ ObjectTypes::Baking, "Baking" },
|
||||
{ ObjectTypes::Tailoring, "Tailoring" },
|
||||
{ ObjectTypes::Blacksmithing, "Blacksmithing" },
|
||||
{ ObjectTypes::Fletching, "Fletching" },
|
||||
{ ObjectTypes::Brewing, "Brewing" },
|
||||
{ ObjectTypes::JewelryMaking, "Jewelry Making" },
|
||||
{ ObjectTypes::Pottery, "Pottery" },
|
||||
{ ObjectTypes::Kiln, "Kiln" },
|
||||
{ ObjectTypes::KeyMaker, "Key Maker" },
|
||||
{ ObjectTypes::ResearchWIZ, "Lexicon" },
|
||||
{ ObjectTypes::ResearchMAG, "Lexicon" },
|
||||
{ ObjectTypes::ResearchNEC, "Lexicon" },
|
||||
{ ObjectTypes::ResearchENC, "Lexicon" },
|
||||
{ ObjectTypes::Unknown, "Unknown" },
|
||||
{ ObjectTypes::ResearchPractice, "Lexicon" },
|
||||
{ ObjectTypes::Alchemy, "Alchemy" },
|
||||
{ ObjectTypes::HighElfForge, "High Elf Forge" },
|
||||
{ ObjectTypes::DarkElfForge, "Dark Elf Forge" },
|
||||
{ ObjectTypes::OgreForge, "Ogre Forge" },
|
||||
{ ObjectTypes::DwarfForge, "Dwarf Forge" },
|
||||
{ ObjectTypes::GnomeForge, "Gnome Forge" },
|
||||
{ ObjectTypes::BarbarianForge, "Barbarian Forge" },
|
||||
{ ObjectTypes::IksarForge, "Iksar Forge" },
|
||||
{ ObjectTypes::HumanForgeOne, "Human Forge" },
|
||||
{ ObjectTypes::HumanForgeTwo, "Human Forge" },
|
||||
{ ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" },
|
||||
{ ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" },
|
||||
{ ObjectTypes::EruditeTailoring, "Erudite Tailoring" },
|
||||
{ ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" },
|
||||
{ ObjectTypes::WoodElfFletching, "Wood Elf Fletching" },
|
||||
{ ObjectTypes::IksarPottery, "Iksar Pottery" },
|
||||
{ ObjectTypes::Fishing, "Fishing" },
|
||||
{ ObjectTypes::TrollForge, "Troll Forge" },
|
||||
{ ObjectTypes::WoodElfForge, "Wood Elf Forge" },
|
||||
{ ObjectTypes::HalflingForge, "Halfling Forge" },
|
||||
{ ObjectTypes::EruditeForge, "Erudite Forge" },
|
||||
{ ObjectTypes::Merchant, "Merchant" },
|
||||
{ ObjectTypes::FroglokForge, "Froglok Forge" },
|
||||
{ ObjectTypes::Augmenter, "Augmenter" },
|
||||
{ ObjectTypes::Churn, "Churn" },
|
||||
{ ObjectTypes::TransformationMold, "Transformation Mold" },
|
||||
{ ObjectTypes::DetransformationMold, "Detransformation Mold" },
|
||||
{ ObjectTypes::Unattuner, "Unattuner" },
|
||||
{ ObjectTypes::TradeskillBag, "Tradeskill Bag" },
|
||||
{ ObjectTypes::CollectibleBag, "Collectible Bag" },
|
||||
{ ObjectTypes::NoDeposit, "No Deposit" }
|
||||
};
|
||||
|
||||
return object_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetObjectTypeName(int object_type)
|
||||
{
|
||||
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> weather_type_map = {
|
||||
@@ -640,79 +423,14 @@ std::string EQ::constants::GetAppearanceTypeName(uint32 appearance_type)
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
|
||||
std::string SpecialAbility::GetName(int ability_id)
|
||||
{
|
||||
static const std::map<uint32, std::string> special_ability_map = {
|
||||
{ SPECATK_SUMMON, "Summon" },
|
||||
{ SPECATK_ENRAGE, "Enrage" },
|
||||
{ SPECATK_RAMPAGE, "Rampage" },
|
||||
{ SPECATK_AREA_RAMPAGE, "Area Rampage" },
|
||||
{ SPECATK_FLURRY, "Flurry" },
|
||||
{ SPECATK_TRIPLE, "Triple Attack" },
|
||||
{ SPECATK_QUAD, "Quadruple Attack" },
|
||||
{ SPECATK_INNATE_DW, "Dual Wield" },
|
||||
{ SPECATK_BANE, "Bane Attack" },
|
||||
{ SPECATK_MAGICAL, "Magical Attack" },
|
||||
{ SPECATK_RANGED_ATK, "Ranged Attack" },
|
||||
{ UNSLOWABLE, "Immune to Slow" },
|
||||
{ UNMEZABLE, "Immune to Mesmerize" },
|
||||
{ UNCHARMABLE, "Immune to Charm" },
|
||||
{ UNSTUNABLE, "Immune to Stun" },
|
||||
{ UNSNAREABLE, "Immune to Snare" },
|
||||
{ UNFEARABLE, "Immune to Fear" },
|
||||
{ UNDISPELLABLE, "Immune to Dispell" },
|
||||
{ IMMUNE_MELEE, "Immune to Melee" },
|
||||
{ IMMUNE_MAGIC, "Immune to Magic" },
|
||||
{ IMMUNE_FLEEING, "Immune to Fleeing" },
|
||||
{ IMMUNE_MELEE_EXCEPT_BANE, "Immune to Melee except Bane" },
|
||||
{ IMMUNE_MELEE_NONMAGICAL, "Immune to Non-Magical Melee" },
|
||||
{ IMMUNE_AGGRO, "Immune to Aggro" },
|
||||
{ IMMUNE_AGGRO_ON, "Immune to Being Aggro" },
|
||||
{ IMMUNE_CASTING_FROM_RANGE, "Immune to Ranged Spells" },
|
||||
{ IMMUNE_FEIGN_DEATH, "Immune to Feign Death" },
|
||||
{ IMMUNE_TAUNT, "Immune to Taunt" },
|
||||
{ NPC_TUNNELVISION, "Tunnel Vision" },
|
||||
{ NPC_NO_BUFFHEAL_FRIENDS, "Does Not Heal of Buff Allies" },
|
||||
{ IMMUNE_PACIFY, "Immune to Pacify" },
|
||||
{ LEASH, "Leashed" },
|
||||
{ TETHER, "Tethered" },
|
||||
{ DESTRUCTIBLE_OBJECT, "Destructible Object" },
|
||||
{ NO_HARM_FROM_CLIENT, "Immune to Harm from Client" },
|
||||
{ ALWAYS_FLEE, "Always Flees" },
|
||||
{ FLEE_PERCENT, "Flee Percentage" },
|
||||
{ ALLOW_BENEFICIAL, "Allows Beneficial Spells" },
|
||||
{ DISABLE_MELEE, "Melee is Disabled" },
|
||||
{ NPC_CHASE_DISTANCE, "Chase Distance" },
|
||||
{ ALLOW_TO_TANK, "Allowed to Tank" },
|
||||
{ IGNORE_ROOT_AGGRO_RULES, "Ignores Root Aggro" },
|
||||
{ CASTING_RESIST_DIFF, "Casting Resist Difficulty" },
|
||||
{ COUNTER_AVOID_DAMAGE, "Counter Damage Avoidance" },
|
||||
{ PROX_AGGRO, "Proximity Aggro" },
|
||||
{ IMMUNE_RANGED_ATTACKS, "Immune to Ranged Attacks" },
|
||||
{ IMMUNE_DAMAGE_CLIENT, "Immune to Client Damage" },
|
||||
{ IMMUNE_DAMAGE_NPC, "Immune to NPC Damage" },
|
||||
{ IMMUNE_AGGRO_CLIENT, "Immune to Client Aggro" },
|
||||
{ IMMUNE_AGGRO_NPC, "Immune to NPC Aggro" },
|
||||
{ MODIFY_AVOID_DAMAGE, "Modify Damage Avoidance" },
|
||||
{ IMMUNE_FADING_MEMORIES, "Immune to Memory Fades" },
|
||||
{ IMMUNE_OPEN, "Immune to Open" },
|
||||
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
|
||||
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
|
||||
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
|
||||
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
|
||||
};
|
||||
|
||||
return special_ability_map;
|
||||
return IsValid(ability_id) ? special_ability_names[ability_id] : "UNKNOWN SPECIAL ABILITY";
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetSpecialAbilityName(uint32 ability_id)
|
||||
bool SpecialAbility::IsValid(int ability_id)
|
||||
{
|
||||
const auto& a = EQ::constants::GetSpecialAbilityMap().find(ability_id);
|
||||
if (a != EQ::constants::GetSpecialAbilityMap().end()) {
|
||||
return a->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return special_ability_names.find(ability_id) != special_ability_names.end();
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetConsiderColorMap()
|
||||
@@ -736,3 +454,28 @@ std::string EQ::constants::GetConsiderColorName(uint32 consider_color)
|
||||
const auto& c = EQ::constants::GetConsiderColorMap().find(consider_color);
|
||||
return c != EQ::constants::GetConsiderColorMap().end() ? c->second : std::string();
|
||||
}
|
||||
|
||||
std::string AccountStatus::GetName(uint8 account_status)
|
||||
{
|
||||
for (
|
||||
auto e = account_status_names.rbegin();
|
||||
e != account_status_names.rend();
|
||||
++e
|
||||
) {
|
||||
if (account_status >= e->first) {
|
||||
return e->second;
|
||||
}
|
||||
}
|
||||
|
||||
return "UNKNOWN ACCOUNT STATUS";
|
||||
}
|
||||
|
||||
std::string ComparisonType::GetName(uint8 type)
|
||||
{
|
||||
return IsValid(type) ? comparison_types[type] : "UNKNOWN COMPARISON TYPE";
|
||||
}
|
||||
|
||||
bool ComparisonType::IsValid(uint8 type)
|
||||
{
|
||||
return comparison_types.find(type) != comparison_types.end();
|
||||
}
|
||||
|
||||
+241
-200
@@ -26,6 +26,76 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace AccountStatus {
|
||||
constexpr uint8 Player = 0;
|
||||
constexpr uint8 Steward = 10;
|
||||
constexpr uint8 ApprenticeGuide = 20;
|
||||
constexpr uint8 Guide = 50;
|
||||
constexpr uint8 QuestTroupe = 80;
|
||||
constexpr uint8 SeniorGuide = 81;
|
||||
constexpr uint8 GMTester = 85;
|
||||
constexpr uint8 EQSupport = 90;
|
||||
constexpr uint8 GMStaff = 95;
|
||||
constexpr uint8 GMAdmin = 100;
|
||||
constexpr uint8 GMLeadAdmin = 150;
|
||||
constexpr uint8 QuestMaster = 160;
|
||||
constexpr uint8 GMAreas = 170;
|
||||
constexpr uint8 GMCoder = 180;
|
||||
constexpr uint8 GMMgmt = 200;
|
||||
constexpr uint8 GMImpossible = 250;
|
||||
constexpr uint8 Max = 255;
|
||||
|
||||
std::string GetName(uint8 account_status);
|
||||
}
|
||||
|
||||
static std::map<uint8, std::string> account_status_names = {
|
||||
{ AccountStatus::Player, "Player" },
|
||||
{ AccountStatus::Steward, "Steward" },
|
||||
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
|
||||
{ AccountStatus::Guide, "Guide" },
|
||||
{ AccountStatus::QuestTroupe, "Quest Troupe" },
|
||||
{ AccountStatus::SeniorGuide, "Senior Guide" },
|
||||
{ AccountStatus::GMTester, "GM Tester" },
|
||||
{ AccountStatus::EQSupport, "EQ Support" },
|
||||
{ AccountStatus::GMStaff, "GM Staff" },
|
||||
{ AccountStatus::GMAdmin, "GM Admin" },
|
||||
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
|
||||
{ AccountStatus::QuestMaster, "Quest Master" },
|
||||
{ AccountStatus::GMAreas, "GM Areas" },
|
||||
{ AccountStatus::GMCoder, "GM Coder" },
|
||||
{ AccountStatus::GMMgmt, "GM Mgmt" },
|
||||
{ AccountStatus::GMImpossible, "GM Impossible" },
|
||||
{ AccountStatus::Max, "GM Max" }
|
||||
};
|
||||
|
||||
namespace ComparisonType {
|
||||
constexpr uint8 Equal = 0;
|
||||
constexpr uint8 NotEqual = 1;
|
||||
constexpr uint8 GreaterOrEqual = 2;
|
||||
constexpr uint8 LesserOrEqual = 3;
|
||||
constexpr uint8 Greater = 4;
|
||||
constexpr uint8 Lesser = 5;
|
||||
constexpr uint8 Any = 6;
|
||||
constexpr uint8 NotAny = 7;
|
||||
constexpr uint8 Between = 8;
|
||||
constexpr uint8 NotBetween = 9;
|
||||
|
||||
std::string GetName(uint8 type);
|
||||
bool IsValid(uint8 type);
|
||||
}
|
||||
|
||||
static std::map<uint8, std::string> comparison_types = {
|
||||
{ ComparisonType::Equal, "Equal" },
|
||||
{ ComparisonType::NotEqual, "Not Equal" },
|
||||
{ ComparisonType::GreaterOrEqual, "Greater or Equal" },
|
||||
{ ComparisonType::LesserOrEqual, "Lesser or Equal" },
|
||||
{ ComparisonType::Greater, "Greater" },
|
||||
{ ComparisonType::Lesser, "Lesser" },
|
||||
{ ComparisonType::Any, "Any" },
|
||||
{ ComparisonType::NotAny, "Not Any" },
|
||||
{ ComparisonType::Between, "Between" },
|
||||
{ ComparisonType::NotBetween, "Not Between" },
|
||||
};
|
||||
|
||||
// local definitions are the result of using hybrid-client or server-only values and methods
|
||||
namespace EQ
|
||||
@@ -267,70 +337,6 @@ namespace EQ
|
||||
Looting
|
||||
};
|
||||
|
||||
enum ObjectTypes : int {
|
||||
SmallBag,
|
||||
LargeBag,
|
||||
Quiver,
|
||||
BeltPouch,
|
||||
WristPouch,
|
||||
Backpack,
|
||||
SmallChest,
|
||||
LargeChest,
|
||||
Bandolier,
|
||||
Medicine,
|
||||
Tinkering,
|
||||
Lexicon,
|
||||
PoisonMaking,
|
||||
Quest,
|
||||
MixingBowl,
|
||||
Baking,
|
||||
Tailoring,
|
||||
Blacksmithing,
|
||||
Fletching,
|
||||
Brewing,
|
||||
JewelryMaking,
|
||||
Pottery,
|
||||
Kiln,
|
||||
KeyMaker,
|
||||
ResearchWIZ,
|
||||
ResearchMAG,
|
||||
ResearchNEC,
|
||||
ResearchENC,
|
||||
Unknown,
|
||||
ResearchPractice,
|
||||
Alchemy,
|
||||
HighElfForge,
|
||||
DarkElfForge,
|
||||
OgreForge,
|
||||
DwarfForge,
|
||||
GnomeForge,
|
||||
BarbarianForge,
|
||||
IksarForge,
|
||||
HumanForgeOne,
|
||||
HumanForgeTwo,
|
||||
HalflingTailoringOne,
|
||||
HalflingTailoringTwo,
|
||||
EruditeTailoring,
|
||||
WoodElfTailoring,
|
||||
WoodElfFletching,
|
||||
IksarPottery,
|
||||
Fishing,
|
||||
TrollForge,
|
||||
WoodElfForge,
|
||||
HalflingForge,
|
||||
EruditeForge,
|
||||
Merchant,
|
||||
FroglokForge,
|
||||
Augmenter,
|
||||
Churn,
|
||||
TransformationMold,
|
||||
DetransformationMold,
|
||||
Unattuner,
|
||||
TradeskillBag,
|
||||
CollectibleBag,
|
||||
NoDeposit
|
||||
};
|
||||
|
||||
enum WeatherTypes : uint8 {
|
||||
None,
|
||||
Raining,
|
||||
@@ -368,12 +374,6 @@ namespace EQ
|
||||
extern const std::map<int8, std::string>& GetFlyModeMap();
|
||||
std::string GetFlyModeName(int8 flymode_id);
|
||||
|
||||
extern const std::map<bodyType, std::string>& GetBodyTypeMap();
|
||||
std::string GetBodyTypeName(bodyType bodytype_id);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetAccountStatusMap();
|
||||
std::string GetAccountStatusName(uint8 account_status);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
|
||||
std::string GetConsiderLevelName(uint8 consider_level);
|
||||
|
||||
@@ -386,9 +386,6 @@ namespace EQ
|
||||
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
|
||||
std::string GetSpawnAnimationName(uint8 animation_id);
|
||||
|
||||
extern const std::map<int, std::string>& GetObjectTypeMap();
|
||||
std::string GetObjectTypeName(int object_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
|
||||
std::string GetWeatherTypeName(uint8 weather_type);
|
||||
|
||||
@@ -401,9 +398,6 @@ namespace EQ
|
||||
extern const std::map<uint32, std::string>& GetAppearanceTypeMap();
|
||||
std::string GetAppearanceTypeName(uint32 animation_type);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetSpecialAbilityMap();
|
||||
std::string GetSpecialAbilityName(uint32 ability_id);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetConsiderColorMap();
|
||||
std::string GetConsiderColorName(uint32 consider_color);
|
||||
|
||||
@@ -464,37 +458,6 @@ namespace EQ
|
||||
|
||||
} // namespace spells
|
||||
|
||||
namespace bug {
|
||||
enum CategoryID : uint32 {
|
||||
catOther = 0,
|
||||
catVideo,
|
||||
catAudio,
|
||||
catPathing,
|
||||
catQuest,
|
||||
catTradeskills,
|
||||
catSpellStacking,
|
||||
catDoorsPortals,
|
||||
catItems,
|
||||
catNPC,
|
||||
catDialogs,
|
||||
catLoNTCG,
|
||||
catMercenaries
|
||||
};
|
||||
|
||||
enum OptionalInfoFlag : uint32 {
|
||||
infoNoOptionalInfo = 0x0,
|
||||
infoCanDuplicate = 0x1,
|
||||
infoCrashBug = 0x2,
|
||||
infoTargetInfo = 0x4,
|
||||
infoCharacterFlags = 0x8,
|
||||
infoUnknownValue = 0xFFFFFFF0
|
||||
};
|
||||
|
||||
const char* CategoryIDToCategoryName(CategoryID category_id);
|
||||
CategoryID CategoryNameToCategoryID(const char* category_name);
|
||||
|
||||
} // namespace bug
|
||||
|
||||
enum WaypointStatus : int {
|
||||
RoamBoxPauseInProgress = -3,
|
||||
QuestControlNoGrid = -2,
|
||||
@@ -517,26 +480,6 @@ enum ServerLockType : int {
|
||||
Unlock
|
||||
};
|
||||
|
||||
enum AccountStatus : uint8 {
|
||||
Player = 0,
|
||||
Steward = 10,
|
||||
ApprenticeGuide = 20,
|
||||
Guide = 50,
|
||||
QuestTroupe = 80,
|
||||
SeniorGuide = 81,
|
||||
GMTester = 85,
|
||||
EQSupport = 90,
|
||||
GMStaff = 95,
|
||||
GMAdmin = 100,
|
||||
GMLeadAdmin = 150,
|
||||
QuestMaster = 160,
|
||||
GMAreas = 170,
|
||||
GMCoder = 180,
|
||||
GMMgmt = 200,
|
||||
GMImpossible = 250,
|
||||
Max = 255
|
||||
};
|
||||
|
||||
enum Invisibility : uint8 {
|
||||
Visible,
|
||||
Invisible,
|
||||
@@ -588,19 +531,6 @@ enum ReloadWorld : uint8 {
|
||||
ForceRepop
|
||||
};
|
||||
|
||||
enum BucketComparison : uint8 {
|
||||
BucketEqualTo = 0,
|
||||
BucketNotEqualTo,
|
||||
BucketGreaterThanOrEqualTo,
|
||||
BucketLesserThanOrEqualTo,
|
||||
BucketGreaterThan,
|
||||
BucketLesserThan,
|
||||
BucketIsAny,
|
||||
BucketIsNotAny,
|
||||
BucketIsBetween,
|
||||
BucketIsNotBetween
|
||||
};
|
||||
|
||||
enum class EntityFilterType {
|
||||
All,
|
||||
Bots,
|
||||
@@ -614,67 +544,131 @@ enum class ApplySpellType {
|
||||
Raid
|
||||
};
|
||||
|
||||
enum {
|
||||
SPECATK_SUMMON = 1,
|
||||
SPECATK_ENRAGE = 2,
|
||||
SPECATK_RAMPAGE = 3,
|
||||
SPECATK_AREA_RAMPAGE = 4,
|
||||
SPECATK_FLURRY = 5,
|
||||
SPECATK_TRIPLE = 6,
|
||||
SPECATK_QUAD = 7,
|
||||
SPECATK_INNATE_DW = 8,
|
||||
SPECATK_BANE = 9,
|
||||
SPECATK_MAGICAL = 10,
|
||||
SPECATK_RANGED_ATK = 11,
|
||||
UNSLOWABLE = 12,
|
||||
UNMEZABLE = 13,
|
||||
UNCHARMABLE = 14,
|
||||
UNSTUNABLE = 15,
|
||||
UNSNAREABLE = 16,
|
||||
UNFEARABLE = 17,
|
||||
UNDISPELLABLE = 18,
|
||||
IMMUNE_MELEE = 19,
|
||||
IMMUNE_MAGIC = 20,
|
||||
IMMUNE_FLEEING = 21,
|
||||
IMMUNE_MELEE_EXCEPT_BANE = 22,
|
||||
IMMUNE_MELEE_NONMAGICAL = 23,
|
||||
IMMUNE_AGGRO = 24,
|
||||
IMMUNE_AGGRO_ON = 25,
|
||||
IMMUNE_CASTING_FROM_RANGE = 26,
|
||||
IMMUNE_FEIGN_DEATH = 27,
|
||||
IMMUNE_TAUNT = 28,
|
||||
NPC_TUNNELVISION = 29,
|
||||
NPC_NO_BUFFHEAL_FRIENDS = 30,
|
||||
IMMUNE_PACIFY = 31,
|
||||
LEASH = 32,
|
||||
TETHER = 33,
|
||||
DESTRUCTIBLE_OBJECT = 34,
|
||||
NO_HARM_FROM_CLIENT = 35,
|
||||
ALWAYS_FLEE = 36,
|
||||
FLEE_PERCENT = 37,
|
||||
ALLOW_BENEFICIAL = 38,
|
||||
DISABLE_MELEE = 39,
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
COUNTER_AVOID_DAMAGE = 44, // Modify by percent NPC's opponents chance to riposte, block, parry or dodge individually, or for all skills
|
||||
PROX_AGGRO = 45,
|
||||
IMMUNE_RANGED_ATTACKS = 46,
|
||||
IMMUNE_DAMAGE_CLIENT = 47,
|
||||
IMMUNE_DAMAGE_NPC = 48,
|
||||
IMMUNE_AGGRO_CLIENT = 49,
|
||||
IMMUNE_AGGRO_NPC = 50,
|
||||
MODIFY_AVOID_DAMAGE = 51, // Modify by percent the NPCs chance to riposte, block, parry or dodge individually, or for all skills
|
||||
IMMUNE_FADING_MEMORIES = 52,
|
||||
IMMUNE_OPEN = 53,
|
||||
IMMUNE_ASSASSINATE = 54,
|
||||
IMMUNE_HEADSHOT = 55,
|
||||
IMMUNE_AGGRO_BOT = 56,
|
||||
IMMUNE_DAMAGE_BOT = 57,
|
||||
MAX_SPECIAL_ATTACK = 58
|
||||
};
|
||||
namespace SpecialAbility {
|
||||
constexpr int Summon = 1;
|
||||
constexpr int Enrage = 2;
|
||||
constexpr int Rampage = 3;
|
||||
constexpr int AreaRampage = 4;
|
||||
constexpr int Flurry = 5;
|
||||
constexpr int TripleAttack = 6;
|
||||
constexpr int QuadrupleAttack = 7;
|
||||
constexpr int DualWield = 8;
|
||||
constexpr int BaneAttack = 9;
|
||||
constexpr int MagicalAttack = 10;
|
||||
constexpr int RangedAttack = 11;
|
||||
constexpr int SlowImmunity = 12;
|
||||
constexpr int MesmerizeImmunity = 13;
|
||||
constexpr int CharmImmunity = 14;
|
||||
constexpr int StunImmunity = 15;
|
||||
constexpr int SnareImmunity = 16;
|
||||
constexpr int FearImmunity = 17;
|
||||
constexpr int DispellImmunity = 18;
|
||||
constexpr int MeleeImmunity = 19;
|
||||
constexpr int MagicImmunity = 20;
|
||||
constexpr int FleeingImmunity = 21;
|
||||
constexpr int MeleeImmunityExceptBane = 22;
|
||||
constexpr int MeleeImmunityExceptMagical = 23;
|
||||
constexpr int AggroImmunity = 24;
|
||||
constexpr int BeingAggroImmunity = 25;
|
||||
constexpr int CastingFromRangeImmunity = 26;
|
||||
constexpr int FeignDeathImmunity = 27;
|
||||
constexpr int TauntImmunity = 28;
|
||||
constexpr int TunnelVision = 29;
|
||||
constexpr int NoBuffHealFriends = 30;
|
||||
constexpr int PacifyImmunity = 31;
|
||||
constexpr int Leash = 32;
|
||||
constexpr int Tether = 33;
|
||||
constexpr int DestructibleObject = 34;
|
||||
constexpr int HarmFromClientImmunity = 35;
|
||||
constexpr int AlwaysFlee = 36;
|
||||
constexpr int FleePercent = 37;
|
||||
constexpr int AllowBeneficial = 38;
|
||||
constexpr int DisableMelee = 39;
|
||||
constexpr int NPCChaseDistance = 40;
|
||||
constexpr int AllowedToTank = 41;
|
||||
constexpr int IgnoreRootAggroRules = 42;
|
||||
constexpr int CastingResistDifficulty = 43;
|
||||
constexpr int CounterAvoidDamage = 44;
|
||||
constexpr int ProximityAggro = 45;
|
||||
constexpr int RangedAttackImmunity = 46;
|
||||
constexpr int ClientDamageImmunity = 47;
|
||||
constexpr int NPCDamageImmunity = 48;
|
||||
constexpr int ClientAggroImmunity = 49;
|
||||
constexpr int NPCAggroImmunity = 50;
|
||||
constexpr int ModifyAvoidDamage = 51;
|
||||
constexpr int MemoryFadeImmunity = 52;
|
||||
constexpr int OpenImmunity = 53;
|
||||
constexpr int AssassinateImmunity = 54;
|
||||
constexpr int HeadshotImmunity = 55;
|
||||
constexpr int BotAggroImmunity = 56;
|
||||
constexpr int BotDamageImmunity = 57;
|
||||
constexpr int Max = 58;
|
||||
|
||||
constexpr int MaxParameters = 9;
|
||||
|
||||
std::string GetName(int ability_id);
|
||||
bool IsValid(int ability_id);
|
||||
}
|
||||
|
||||
static std::map<int, std::string> special_ability_names = {
|
||||
{ SpecialAbility::Summon, "Summon" },
|
||||
{ SpecialAbility::Enrage, "Enrage" },
|
||||
{ SpecialAbility::Rampage, "Rampage" },
|
||||
{ SpecialAbility::AreaRampage, "Area Rampage" },
|
||||
{ SpecialAbility::Flurry, "Flurry" },
|
||||
{ SpecialAbility::TripleAttack, "Triple Attack" },
|
||||
{ SpecialAbility::QuadrupleAttack, "Quadruple Attack" },
|
||||
{ SpecialAbility::DualWield, "Dual Wield" },
|
||||
{ SpecialAbility::BaneAttack, "Bane Attack" },
|
||||
{ SpecialAbility::MagicalAttack, "Magical Attack" },
|
||||
{ SpecialAbility::RangedAttack, "Ranged Attack" },
|
||||
{ SpecialAbility::SlowImmunity, "Immune to Slow" },
|
||||
{ SpecialAbility::MesmerizeImmunity, "Immune to Mesmerize" },
|
||||
{ SpecialAbility::CharmImmunity, "Immune to Charm" },
|
||||
{ SpecialAbility::StunImmunity, "Immune to Stun" },
|
||||
{ SpecialAbility::SnareImmunity, "Immune to Snare" },
|
||||
{ SpecialAbility::FearImmunity, "Immune to Fear" },
|
||||
{ SpecialAbility::DispellImmunity, "Immune to Dispell" },
|
||||
{ SpecialAbility::MeleeImmunity, "Immune to Melee" },
|
||||
{ SpecialAbility::MagicImmunity, "Immune to Magic" },
|
||||
{ SpecialAbility::FleeingImmunity, "Immune to Fleeing" },
|
||||
{ SpecialAbility::MeleeImmunityExceptBane, "Immune to Melee except Bane" },
|
||||
{ SpecialAbility::MeleeImmunityExceptMagical, "Immune to Non-Magical Melee" },
|
||||
{ SpecialAbility::AggroImmunity, "Immune to Aggro" },
|
||||
{ SpecialAbility::BeingAggroImmunity, "Immune to Being Aggro" },
|
||||
{ SpecialAbility::CastingFromRangeImmunity, "Immune to Ranged Spells" },
|
||||
{ SpecialAbility::FeignDeathImmunity, "Immune to Feign Death" },
|
||||
{ SpecialAbility::TauntImmunity, "Immune to Taunt" },
|
||||
{ SpecialAbility::TunnelVision, "Tunnel Vision" },
|
||||
{ SpecialAbility::NoBuffHealFriends, "Does Not Heal or Buff Allies" },
|
||||
{ SpecialAbility::PacifyImmunity, "Immune to Pacify" },
|
||||
{ SpecialAbility::Leash, "Leashed" },
|
||||
{ SpecialAbility::Tether, "Tethered" },
|
||||
{ SpecialAbility::DestructibleObject, "Destructible Object" },
|
||||
{ SpecialAbility::HarmFromClientImmunity, "Immune to Harm from Client" },
|
||||
{ SpecialAbility::AlwaysFlee, "Always Flees" },
|
||||
{ SpecialAbility::FleePercent, "Flee Percentage" },
|
||||
{ SpecialAbility::AllowBeneficial, "Allows Beneficial Spells" },
|
||||
{ SpecialAbility::DisableMelee, "Melee is Disabled" },
|
||||
{ SpecialAbility::NPCChaseDistance, "Chase Distance" },
|
||||
{ SpecialAbility::AllowedToTank, "Allowed to Tank" },
|
||||
{ SpecialAbility::IgnoreRootAggroRules, "Ignores Root Aggro" },
|
||||
{ SpecialAbility::CastingResistDifficulty, "Casting Resist Difficulty" },
|
||||
{ SpecialAbility::CounterAvoidDamage, "Counter Damage Avoidance" },
|
||||
{ SpecialAbility::ProximityAggro, "Proximity Aggro" },
|
||||
{ SpecialAbility::RangedAttackImmunity, "Immune to Ranged Attacks" },
|
||||
{ SpecialAbility::ClientDamageImmunity, "Immune to Client Damage" },
|
||||
{ SpecialAbility::NPCDamageImmunity, "Immune to NPC Damage" },
|
||||
{ SpecialAbility::ClientAggroImmunity, "Immune to Client Aggro" },
|
||||
{ SpecialAbility::NPCAggroImmunity, "Immune to NPC Aggro" },
|
||||
{ SpecialAbility::ModifyAvoidDamage, "Modify Damage Avoidance" },
|
||||
{ SpecialAbility::MemoryFadeImmunity, "Immune to Memory Fades" },
|
||||
{ SpecialAbility::OpenImmunity, "Immune to Open" },
|
||||
{ SpecialAbility::AssassinateImmunity, "Immune to Assassinate" },
|
||||
{ SpecialAbility::HeadshotImmunity, "Immune to Headshot" },
|
||||
{ SpecialAbility::BotAggroImmunity, "Immune to Bot Aggro" },
|
||||
{ SpecialAbility::BotDamageImmunity, "Immune to Bot Damage" },
|
||||
};
|
||||
|
||||
namespace HeroicBonusBucket
|
||||
{
|
||||
@@ -700,4 +694,51 @@ namespace HeroicBonusBucket
|
||||
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
|
||||
}
|
||||
|
||||
namespace Bug {
|
||||
namespace Category {
|
||||
constexpr uint32 Other = 0;
|
||||
constexpr uint32 Video = 1;
|
||||
constexpr uint32 Audio = 2;
|
||||
constexpr uint32 Pathing = 3;
|
||||
constexpr uint32 Quest = 4;
|
||||
constexpr uint32 Tradeskills = 5;
|
||||
constexpr uint32 SpellStacking = 6;
|
||||
constexpr uint32 DoorsPortals = 7;
|
||||
constexpr uint32 Items = 8;
|
||||
constexpr uint32 NPC = 9;
|
||||
constexpr uint32 Dialogs = 10;
|
||||
constexpr uint32 LoNTCG = 11;
|
||||
constexpr uint32 Mercenaries = 12;
|
||||
}
|
||||
|
||||
namespace InformationFlag {
|
||||
constexpr uint32 None = 0;
|
||||
constexpr uint32 Repeatable = 1;
|
||||
constexpr uint32 Crash = 2;
|
||||
constexpr uint32 TargetInfo = 4;
|
||||
constexpr uint32 CharacterFlags = 8;
|
||||
constexpr uint32 Unknown = 4294967280;
|
||||
}
|
||||
|
||||
uint32 GetID(const std::string& category_name);
|
||||
std::string GetName(uint32 category_id);
|
||||
bool IsValid(uint32 category_id);
|
||||
}
|
||||
|
||||
static std::map<uint32, std::string> bug_category_names = {
|
||||
{ Bug::Category::Other, "Other" },
|
||||
{ Bug::Category::Video, "Video" },
|
||||
{ Bug::Category::Audio, "Audio" },
|
||||
{ Bug::Category::Pathing, "Pathing" },
|
||||
{ Bug::Category::Quest, "Quest" },
|
||||
{ Bug::Category::Tradeskills, "Tradeskills" },
|
||||
{ Bug::Category::SpellStacking, "Spell Stacking" },
|
||||
{ Bug::Category::DoorsPortals, "Doors and Portals" },
|
||||
{ Bug::Category::Items, "Items" },
|
||||
{ Bug::Category::NPC, "NPC" },
|
||||
{ Bug::Category::Dialogs, "Dialogs" },
|
||||
{ Bug::Category::LoNTCG, "LoN - TCG" },
|
||||
{ Bug::Category::Mercenaries, "Mercenaries" }
|
||||
};
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -557,6 +557,7 @@ N(OP_TradeBusy),
|
||||
N(OP_TradeCoins),
|
||||
N(OP_TradeMoneyUpdate),
|
||||
N(OP_Trader),
|
||||
N(OP_TraderBulkSend),
|
||||
N(OP_TraderBuy),
|
||||
N(OP_TraderDelItem),
|
||||
N(OP_TradeRequest),
|
||||
|
||||
+41
-61
@@ -772,67 +772,47 @@ typedef enum {
|
||||
FilterShowSelfOnly
|
||||
} eqFilterMode;
|
||||
|
||||
#define STAT_STR 0
|
||||
#define STAT_STA 1
|
||||
#define STAT_AGI 2
|
||||
#define STAT_DEX 3
|
||||
#define STAT_INT 4
|
||||
#define STAT_WIS 5
|
||||
#define STAT_CHA 6
|
||||
#define STAT_MAGIC 7
|
||||
#define STAT_COLD 8
|
||||
#define STAT_FIRE 9
|
||||
#define STAT_POISON 10
|
||||
#define STAT_DISEASE 11
|
||||
#define STAT_MANA 12
|
||||
#define STAT_HP 13
|
||||
#define STAT_AC 14
|
||||
#define STAT_ENDURANCE 15
|
||||
#define STAT_ATTACK 16
|
||||
#define STAT_HP_REGEN 17
|
||||
#define STAT_MANA_REGEN 18
|
||||
#define STAT_HASTE 19
|
||||
#define STAT_DAMAGE_SHIELD 20
|
||||
|
||||
/*
|
||||
** Recast timer types. Used as an off set to charProfileStruct timers.
|
||||
**
|
||||
** (Another orphaned enumeration...)
|
||||
*/
|
||||
enum RecastTimerTypes
|
||||
{
|
||||
RecTimer_0 = 0,
|
||||
RecTimer_1,
|
||||
RecTimer_WeaponHealClick, // 2
|
||||
RecTimer_MuramiteBaneNukeClick, // 3
|
||||
RecTimer_4,
|
||||
RecTimer_DispellClick, // 5 (also click heal orbs?)
|
||||
RecTimer_Epic, // 6
|
||||
RecTimer_OoWBPClick, // 7
|
||||
RecTimer_VishQuestClassItem, // 8
|
||||
RecTimer_HealPotion, // 9
|
||||
RecTimer_10,
|
||||
RecTimer_11,
|
||||
RecTimer_12,
|
||||
RecTimer_13,
|
||||
RecTimer_14,
|
||||
RecTimer_15,
|
||||
RecTimer_16,
|
||||
RecTimer_17,
|
||||
RecTimer_18,
|
||||
RecTimer_ModRod, // 19
|
||||
_RecTimerCount
|
||||
};
|
||||
|
||||
enum GroupUpdateAction
|
||||
{
|
||||
GUA_Joined = 0,
|
||||
GUA_Left = 1,
|
||||
GUA_LastLeft = 6,
|
||||
GUA_FullGroupInfo = 7,
|
||||
GUA_MakeLeader = 8,
|
||||
GUA_Started = 9
|
||||
};
|
||||
#define STAT_STR 0
|
||||
#define STAT_STA 1
|
||||
#define STAT_AGI 2
|
||||
#define STAT_DEX 3
|
||||
#define STAT_INT 4
|
||||
#define STAT_WIS 5
|
||||
#define STAT_CHA 6
|
||||
#define STAT_MAGIC 7
|
||||
#define STAT_COLD 8
|
||||
#define STAT_FIRE 9
|
||||
#define STAT_POISON 10
|
||||
#define STAT_DISEASE 11
|
||||
#define STAT_MANA 12
|
||||
#define STAT_HP 13
|
||||
#define STAT_AC 14
|
||||
#define STAT_ENDURANCE 15
|
||||
#define STAT_ATTACK 16
|
||||
#define STAT_HP_REGEN 17
|
||||
#define STAT_MANA_REGEN 18
|
||||
#define STAT_HASTE 19
|
||||
#define STAT_DAMAGE_SHIELD 20
|
||||
#define STAT_DS_MITIGATION 22
|
||||
#define STAT_HEAL_AMOUNT 23
|
||||
#define STAT_SPELL_DAMAGE 24
|
||||
#define STAT_CLAIRVOYANCE 25
|
||||
#define STAT_HEROIC_AGILITY 26
|
||||
#define STAT_HEROIC_CHARISMA 27
|
||||
#define STAT_HEROIC_DEXTERITY 28
|
||||
#define STAT_HEROIC_INTELLIGENCE 29
|
||||
#define STAT_HEROIC_STAMINA 30
|
||||
#define STAT_HEROIC_STRENGTH 31
|
||||
#define STAT_HEROIC_WISDOM 32
|
||||
#define STAT_BASH 33
|
||||
#define STAT_BACKSTAB 34
|
||||
#define STAT_DRAGON_PUNCH 35
|
||||
#define STAT_EAGLE_STRIKE 36
|
||||
#define STAT_FLYING_KICK 37
|
||||
#define STAT_KICK 38
|
||||
#define STAT_ROUND_KICK 39
|
||||
#define STAT_TIGER_CLAW 40
|
||||
#define STAT_FRENZY 41
|
||||
|
||||
static const uint8 DamageTypeSomething = 0x1C; //0x1c is something...
|
||||
static const uint8 DamageTypeFalling = 0xFC;
|
||||
|
||||
+197
-72
@@ -31,7 +31,6 @@
|
||||
#include "../cereal/include/cereal/types/string.hpp"
|
||||
#include "../cereal/include/cereal/types/vector.hpp"
|
||||
|
||||
|
||||
static const uint32 BUFF_COUNT = 42;
|
||||
static const uint32 PET_BUFF_COUNT = 30;
|
||||
static const uint32 MAX_MERC = 100;
|
||||
@@ -323,6 +322,7 @@ union
|
||||
bool targetable_with_hotkey;
|
||||
bool show_name;
|
||||
bool guild_show;
|
||||
bool trader;
|
||||
};
|
||||
|
||||
struct PlayerState_Struct {
|
||||
@@ -1119,7 +1119,7 @@ struct PlayerProfile_Struct
|
||||
/*19558*/ uint8 guildAutoconsent; // 0=off, 1=on
|
||||
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
|
||||
/*19564*/ uint32 RestTimer;
|
||||
/*19568*/
|
||||
/*19568*/ uint32 char_id; // Found as part of bazaar revamp (5/15/2024)
|
||||
|
||||
// All player profile packets are translated and this overhead is ignored in out-bound packets
|
||||
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
|
||||
@@ -3002,26 +3002,26 @@ struct EnvDamage2_Struct {
|
||||
//
|
||||
|
||||
enum {
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_CustomerBrowsing = 13,
|
||||
BazaarInspectItem = 18,
|
||||
BazaarSearchDone2 = 19,
|
||||
BazaarInspectItem = 18,
|
||||
BazaarSearchDone2 = 19,
|
||||
BazaarTrader_StartTraderMode2 = 22
|
||||
};
|
||||
|
||||
enum {
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_UpdatePrice = 1,
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
};
|
||||
|
||||
struct BazaarWindowStart_Struct {
|
||||
@@ -3032,31 +3032,41 @@ struct BazaarWindowStart_Struct {
|
||||
|
||||
|
||||
struct BazaarWelcome_Struct {
|
||||
BazaarWindowStart_Struct Beginning;
|
||||
uint32 Traders;
|
||||
uint32 Items;
|
||||
uint32 Unknown012;
|
||||
uint32 Unknown016;
|
||||
uint32 action;
|
||||
uint32 traders;
|
||||
uint32 items;
|
||||
uint32 unknown_012;
|
||||
uint32 unknown_016;
|
||||
};
|
||||
|
||||
struct BazaarSearch_Struct {
|
||||
BazaarWindowStart_Struct Beginning;
|
||||
uint32 TraderID;
|
||||
uint32 Class_;
|
||||
uint32 Race;
|
||||
uint32 ItemStat;
|
||||
uint32 Slot;
|
||||
uint32 Type;
|
||||
char Name[64];
|
||||
uint32 MinPrice;
|
||||
uint32 MaxPrice;
|
||||
uint32 Minlevel;
|
||||
uint32 MaxLlevel;
|
||||
struct BazaarSearchCriteria_Struct {
|
||||
/*000*/ uint32 action{0};
|
||||
/*004*/ uint32 search_scope{0}; // 1 all traders 0 local traders
|
||||
/*008*/ uint32 unknown_008{0};
|
||||
/*012*/ uint32 unknown_012{0};
|
||||
/*016*/ uint32 trader_id{0};
|
||||
/*020*/ uint32 _class{0};
|
||||
/*024*/ uint32 race{0};
|
||||
/*028*/ uint32 item_stat{0};
|
||||
/*032*/ uint32 slot{0};
|
||||
/*036*/ uint32 type{0};
|
||||
/*040*/ char item_name[64]{""};
|
||||
/*104*/ uint32 min_cost{0};
|
||||
/*108*/ uint32 max_cost{0};
|
||||
/*112*/ uint32 min_level{1};
|
||||
/*116*/ uint32 max_level{0};
|
||||
/*120*/ uint32 max_results{0};
|
||||
/*124*/ uint32 prestige{0};
|
||||
/*128*/ uint32 augment{0};
|
||||
/*132*/ uint32 trader_entity_id{0};
|
||||
};
|
||||
struct BazaarInspect_Struct{
|
||||
uint32 ItemID;
|
||||
uint32 Unknown004;
|
||||
char Name[64];
|
||||
|
||||
struct BazaarInspect_Struct {
|
||||
uint32 action;
|
||||
char player_name[64];
|
||||
uint32 serial_number;
|
||||
uint32 item_id;
|
||||
uint32 trader_id;
|
||||
};
|
||||
|
||||
struct NewBazaarInspect_Struct {
|
||||
@@ -3076,6 +3086,14 @@ struct BazaarReturnDone_Struct{
|
||||
uint32 Unknown012;
|
||||
uint32 Unknown016;
|
||||
};
|
||||
|
||||
struct BazaarDeliveryCost_Struct {
|
||||
uint32 action;
|
||||
uint16 voucher_delivery_cost;
|
||||
float parcel_deliver_cost; //percentage of item cost
|
||||
uint32 unknown_010;
|
||||
};
|
||||
|
||||
struct BazaarSearchResults_Struct {
|
||||
/*000*/ BazaarWindowStart_Struct Beginning;
|
||||
/*004*/ uint32 NumItems;
|
||||
@@ -3088,8 +3106,10 @@ struct BazaarSearchResults_Struct {
|
||||
// New fields for SoD+, stripped off when encoding for older clients.
|
||||
char SellerName[64];
|
||||
uint32 ItemID;
|
||||
uint32 ItemID2;
|
||||
};
|
||||
|
||||
|
||||
// Barter/Buyer
|
||||
//
|
||||
//
|
||||
@@ -3389,32 +3409,31 @@ struct WhoAllReturnStruct {
|
||||
};
|
||||
|
||||
struct Trader_Struct {
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint64 Items[80];
|
||||
/*648*/ uint32 ItemCost[80];
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 unknown_004;
|
||||
/*008*/ uint64 items[EQ::invtype::BAZAAR_SIZE];
|
||||
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
|
||||
};
|
||||
|
||||
struct ClickTrader_Struct {
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ int64 SerialNumber[80];
|
||||
/*648*/ uint32 ItemCost[80];
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 unknown_004;
|
||||
/*008*/ int64 serial_number[EQ::invtype::BAZAAR_SIZE] {};
|
||||
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE] {};
|
||||
};
|
||||
|
||||
struct GetItems_Struct{
|
||||
uint32 Items[80];
|
||||
int32 SerialNumber[80];
|
||||
int32 Charges[80];
|
||||
uint32 items[EQ::invtype::BAZAAR_SIZE];
|
||||
int32 serial_number[EQ::invtype::BAZAAR_SIZE];
|
||||
int32 charges[EQ::invtype::BAZAAR_SIZE];
|
||||
};
|
||||
|
||||
struct BecomeTrader_Struct
|
||||
{
|
||||
/*000*/ uint32 ID;
|
||||
/*004*/ uint32 Code;
|
||||
/*008*/ char Name[64];
|
||||
/*072*/ uint32 Unknown072; // Observed 0x33,0x91 etc on zone-in, 0x00 when sent for a new trader after zone-in
|
||||
/*076*/
|
||||
struct BecomeTrader_Struct {
|
||||
uint32 action;
|
||||
uint32 zone_id;
|
||||
uint32 trader_id;
|
||||
uint32 entity_id;
|
||||
char trader_name[64];
|
||||
};
|
||||
|
||||
struct TraderStatus_Struct{
|
||||
@@ -3424,20 +3443,30 @@ struct TraderStatus_Struct{
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct{
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 entity_id;
|
||||
/*008*/ uint32 Unknown08[3];
|
||||
/*020*/
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct{
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*008*/ uint32 ItemID;
|
||||
/*012*/ uint32 AlreadySold;
|
||||
/*016*/ uint32 Price;
|
||||
/*020*/ uint32 Quantity;
|
||||
/*024*/ char ItemName[64];
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 method;
|
||||
/*008*/ uint32 sub_action;
|
||||
/*012*/ uint32 unknown_012;
|
||||
/*016*/ uint32 trader_id;
|
||||
/*020*/ char buyer_name[64];
|
||||
/*084*/ char seller_name[64];
|
||||
/*148*/ char unknown_148[32];
|
||||
/*180*/ char item_name[64];
|
||||
/*244*/ char serial_number[17];
|
||||
/*261*/ char unknown_261[3];
|
||||
/*264*/ uint32 item_id;
|
||||
/*268*/ uint32 price;
|
||||
/*272*/ uint32 already_sold;
|
||||
/*276*/ uint32 unknown_276;
|
||||
/*280*/ uint32 quantity;
|
||||
/*284*/
|
||||
};
|
||||
|
||||
struct TraderItemUpdate_Struct{
|
||||
@@ -3465,15 +3494,15 @@ struct MoneyUpdate_Struct{
|
||||
};
|
||||
|
||||
struct TraderDelItem_Struct{
|
||||
uint32 Unknown000;
|
||||
uint32 TraderID;
|
||||
uint32 ItemID;
|
||||
uint32 Unknown012;
|
||||
uint32 unknown_000;
|
||||
uint32 trader_id;
|
||||
uint32 item_id;
|
||||
uint32 unknown_012;
|
||||
};
|
||||
|
||||
struct TraderClick_Struct{
|
||||
/*000*/ uint32 TraderID;
|
||||
/*004*/ uint32 Code;
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*008*/ uint32 Unknown008;
|
||||
/*012*/ uint32 Approval;
|
||||
/*016*/
|
||||
@@ -5991,6 +6020,102 @@ struct UnderWorld {
|
||||
/* 16 */
|
||||
};
|
||||
|
||||
enum BazaarTraderBarterActions {
|
||||
TraderOff = 0,
|
||||
TraderOn = 1,
|
||||
PriceUpdate = 3,
|
||||
EndTransaction = 4,
|
||||
BazaarSearch = 7,
|
||||
WelcomeMessage = 9,
|
||||
BuyTraderItem = 10,
|
||||
ListTraderItems = 11,
|
||||
CustomerBrowsing = 13,
|
||||
BazaarInspect = 18,
|
||||
ItemMove = 19,
|
||||
TraderAck2 = 22,
|
||||
AddTraderToBazaarWindow = 24,
|
||||
RemoveTraderFromBazaarWindow = 25,
|
||||
ClickTrader = 28,
|
||||
DeliveryCostUpdate = 29
|
||||
};
|
||||
|
||||
enum BazaarPurchaseActions {
|
||||
ByVendor = 0,
|
||||
ByParcel = 1,
|
||||
ByDirectToInventory = 2
|
||||
};
|
||||
|
||||
enum BazaarPurchaseSubActions {
|
||||
Success = 0,
|
||||
Failed = 1,
|
||||
DataOutDated = 3,
|
||||
TooManyParcels = 5,
|
||||
TransactionInProgress = 6,
|
||||
InsufficientFunds = 7
|
||||
};
|
||||
|
||||
enum BazaarSearchScopes {
|
||||
Local_Scope = 0,
|
||||
AllTraders_Scope = 1,
|
||||
NonRoFBazaarSearchScope = 99
|
||||
};
|
||||
|
||||
struct BazaarSearchResultsFromDB_Struct {
|
||||
uint32 count;
|
||||
uint32 trader_id;
|
||||
uint32 item_id;
|
||||
uint32 serial_number;
|
||||
uint32 charges;
|
||||
uint32 cost;
|
||||
uint32 slot_id;
|
||||
uint32 icon_id;
|
||||
uint32 sum_charges;
|
||||
uint32 trader_zone_id;
|
||||
uint32 trader_entity_id;
|
||||
uint32 item_stat;
|
||||
bool stackable;
|
||||
std::string item_name;
|
||||
std::string serial_number_RoF;
|
||||
std::string trader_name;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(count),
|
||||
CEREAL_NVP(trader_id),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(serial_number),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(cost),
|
||||
CEREAL_NVP(slot_id),
|
||||
CEREAL_NVP(icon_id),
|
||||
CEREAL_NVP(sum_charges),
|
||||
CEREAL_NVP(trader_zone_id),
|
||||
CEREAL_NVP(trader_entity_id),
|
||||
CEREAL_NVP(item_stat),
|
||||
CEREAL_NVP(stackable),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(serial_number_RoF),
|
||||
CEREAL_NVP(trader_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BazaarSearchMessaging_Struct {
|
||||
uint32 action;
|
||||
char payload[];
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(payload)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Restore structure packing to default
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@@ -642,6 +642,10 @@ void PlayerEventLogs::ProcessRetentionTruncation()
|
||||
void PlayerEventLogs::ReloadSettings()
|
||||
{
|
||||
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
|
||||
if (e.id >= PlayerEvent::MAX || e.id < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_settings[e.id] = e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
SwapItemFailState &fail_state,
|
||||
uint16 race_id,
|
||||
uint8 class_id,
|
||||
uint16 deity_id,
|
||||
uint32 deity_id,
|
||||
uint8 level
|
||||
) {
|
||||
fail_state = swapInvalid;
|
||||
@@ -354,7 +354,7 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapRaceClass;
|
||||
return false;
|
||||
}
|
||||
if (deity_id && source_item->Deity && !(deity::GetDeityBitmask((deity::DeityType)deity_id) & source_item->Deity)) {
|
||||
if (deity_id && source_item->Deity && !(Deity::GetBitmask(deity_id) & source_item->Deity)) {
|
||||
fail_state = swapDeity;
|
||||
return false;
|
||||
}
|
||||
@@ -380,7 +380,7 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
fail_state = swapRaceClass;
|
||||
return false;
|
||||
}
|
||||
if (deity_id && destination_item->Deity && !(deity::GetDeityBitmask((deity::DeityType)deity_id) & destination_item->Deity)) {
|
||||
if (deity_id && destination_item->Deity && !(Deity::GetBitmask(deity_id) & destination_item->Deity)) {
|
||||
fail_state = swapDeity;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace EQ
|
||||
|
||||
// Swap items in inventory
|
||||
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = Race::Doug, uint8 class_id = Class::None, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = Race::Doug, uint8 class_id = Class::None, uint32 deity_id = Deity::Unknown, uint8 level = 0);
|
||||
|
||||
// Remove item from inventory
|
||||
bool DeleteItem(int16 slot_id, int16 quantity = 0);
|
||||
|
||||
+69
-66
@@ -58,72 +58,75 @@ namespace EQ
|
||||
};
|
||||
|
||||
enum ItemType : uint8 {
|
||||
/*9138*/ ItemType1HSlash = 0,
|
||||
/*9141*/ ItemType2HSlash,
|
||||
/*9140*/ ItemType1HPiercing,
|
||||
/*9139*/ ItemType1HBlunt,
|
||||
/*9142*/ ItemType2HBlunt,
|
||||
/*5504*/ ItemTypeBow, // 5
|
||||
/*----*/ ItemTypeUnknown1,
|
||||
/*----*/ ItemTypeLargeThrowing,
|
||||
/*5505*/ ItemTypeShield,
|
||||
/*5506*/ ItemTypeScroll,
|
||||
/*5507*/ ItemTypeArmor, // 10
|
||||
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
|
||||
/*7564*/ ItemTypeLockPick,
|
||||
/*----*/ ItemTypeUnknown2,
|
||||
/*5509*/ ItemTypeFood,
|
||||
/*5510*/ ItemTypeDrink, // 15
|
||||
/*5511*/ ItemTypeLight,
|
||||
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
|
||||
/*5513*/ ItemTypeBandage,
|
||||
/*----*/ ItemTypeSmallThrowing,
|
||||
/*----*/ ItemTypeSpell, // 20 // spells and tomes
|
||||
/*5514*/ ItemTypePotion,
|
||||
/*----*/ ItemTypeUnknown3,
|
||||
/*0406*/ ItemTypeWindInstrument,
|
||||
/*0407*/ ItemTypeStringedInstrument,
|
||||
/*0408*/ ItemTypeBrassInstrument, // 25
|
||||
/*0405*/ ItemTypePercussionInstrument,
|
||||
/*5515*/ ItemTypeArrow,
|
||||
/*----*/ ItemTypeUnknown4,
|
||||
/*5521*/ ItemTypeJewelry,
|
||||
/*----*/ ItemTypeSkull, // 30
|
||||
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
|
||||
/*5517*/ ItemTypeNote,
|
||||
/*5518*/ ItemTypeKey,
|
||||
/*----*/ ItemTypeCoin,
|
||||
/*5520*/ ItemType2HPiercing, // 35
|
||||
/*----*/ ItemTypeFishingPole,
|
||||
/*----*/ ItemTypeFishingBait,
|
||||
/*5519*/ ItemTypeAlcohol,
|
||||
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
|
||||
/*----*/ ItemTypeCompass, // 40
|
||||
/*----*/ ItemTypeUnknown5,
|
||||
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
|
||||
/*----*/ ItemTypeUnknown6,
|
||||
/*----*/ ItemTypeUnknown7,
|
||||
/*5522*/ ItemTypeMartial, // 45
|
||||
/*----*/ ItemTypeUnknown8,
|
||||
/*----*/ ItemTypeUnknown9,
|
||||
/*----*/ ItemTypeUnknown10,
|
||||
/*----*/ ItemTypeUnknown11,
|
||||
/*----*/ ItemTypeSinging, // 50
|
||||
/*5750*/ ItemTypeAllInstrumentTypes,
|
||||
/*5776*/ ItemTypeCharm,
|
||||
/*----*/ ItemTypeDye,
|
||||
/*----*/ ItemTypeAugmentation,
|
||||
/*----*/ ItemTypeAugmentationSolvent, // 55
|
||||
/*----*/ ItemTypeAugmentationDistiller,
|
||||
/*----*/ ItemTypeUnknown12,
|
||||
/*----*/ ItemTypeFellowshipKit,
|
||||
/*----*/ ItemTypeUnknown13,
|
||||
/*----*/ ItemTypeRecipe, // 60
|
||||
/*----*/ ItemTypeAdvancedRecipe,
|
||||
/*----*/ ItemTypeJournal, // only one(1) database entry
|
||||
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
|
||||
/*5881*/ ItemTypePerfectedAugmentationDistiller,
|
||||
/*----*/ ItemTypeCount
|
||||
/*9138*/ ItemType1HSlash = 0,
|
||||
/*9141*/ ItemType2HSlash,
|
||||
/*9140*/ ItemType1HPiercing,
|
||||
/*9139*/ ItemType1HBlunt,
|
||||
/*9142*/ ItemType2HBlunt,
|
||||
/*5504*/ ItemTypeBow, // 5
|
||||
/*----*/ ItemTypeUnknown1,
|
||||
/*----*/ ItemTypeLargeThrowing,
|
||||
/*5505*/ ItemTypeShield,
|
||||
/*5506*/ ItemTypeScroll,
|
||||
/*5507*/ ItemTypeArmor, // 10
|
||||
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
|
||||
/*7564*/ ItemTypeLockPick,
|
||||
/*----*/ ItemTypeUnknown2,
|
||||
/*5509*/ ItemTypeFood,
|
||||
/*5510*/ ItemTypeDrink, // 15
|
||||
/*5511*/ ItemTypeLight,
|
||||
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
|
||||
/*5513*/ ItemTypeBandage,
|
||||
/*----*/ ItemTypeSmallThrowing,
|
||||
/*----*/ ItemTypeSpell, // 20 // spells and tomes
|
||||
/*5514*/ ItemTypePotion,
|
||||
/*----*/ ItemTypeUnknown3,
|
||||
/*0406*/ ItemTypeWindInstrument,
|
||||
/*0407*/ ItemTypeStringedInstrument,
|
||||
/*0408*/ ItemTypeBrassInstrument, // 25
|
||||
/*0405*/ ItemTypePercussionInstrument,
|
||||
/*5515*/ ItemTypeArrow,
|
||||
/*----*/ ItemTypeUnknown4,
|
||||
/*5521*/ ItemTypeJewelry,
|
||||
/*----*/ ItemTypeSkull, // 30
|
||||
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
|
||||
/*5517*/ ItemTypeNote,
|
||||
/*5518*/ ItemTypeKey,
|
||||
/*----*/ ItemTypeCoin,
|
||||
/*5520*/ ItemType2HPiercing, // 35
|
||||
/*----*/ ItemTypeFishingPole,
|
||||
/*----*/ ItemTypeFishingBait,
|
||||
/*5519*/ ItemTypeAlcohol,
|
||||
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
|
||||
/*----*/ ItemTypeCompass, // 40
|
||||
/*----*/ ItemTypeUnknown5,
|
||||
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
|
||||
/*----*/ ItemTypeUnknown6,
|
||||
/*----*/ ItemTypeUnknown7,
|
||||
/*5522*/ ItemTypeMartial, // 45
|
||||
/*----*/ ItemTypeAllEffects,
|
||||
/*----*/ ItemTypeUnknown9,
|
||||
/*----*/ ItemTypeUnknown10,
|
||||
/*----*/ ItemTypeFocusEffect,
|
||||
/*----*/ ItemTypeSinging, // 50
|
||||
/*5750*/ ItemTypeAllInstrumentTypes,
|
||||
/*5776*/ ItemTypeCharm,
|
||||
/*----*/ ItemTypeDye,
|
||||
/*----*/ ItemTypeAugmentation,
|
||||
/*----*/ ItemTypeAugmentationSolvent, // 55
|
||||
/*----*/ ItemTypeAugmentationDistiller,
|
||||
/*----*/ ItemTypeAlternateAbility,
|
||||
/*----*/ ItemTypeFellowshipKit,
|
||||
/*----*/ ItemTypeUnknown13,
|
||||
/*----*/ ItemTypeRecipe, // 60
|
||||
/*----*/ ItemTypeAdvancedRecipe,
|
||||
/*----*/ ItemTypeJournal, // only one(1) database entry
|
||||
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
|
||||
/*5881*/ ItemTypePerfectedAugmentationDistiller,
|
||||
/*----*/ ItemTypeCount,
|
||||
/*----*/ ItemTypeCollectible,
|
||||
/*----*/ ItemTypeContainer,
|
||||
/*----*/ ItemTypeAll = 0xFF
|
||||
|
||||
/*
|
||||
Unknowns:
|
||||
|
||||
+151
-28
@@ -303,47 +303,34 @@ int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
auto i = invaug::SOCKET_BEGIN;
|
||||
for (; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetItem(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[i] &&
|
||||
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
|
||||
)
|
||||
) {
|
||||
break;
|
||||
for (int16 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
|
||||
if (IsAugmentSlotAvailable(augment_type, slot_id)) {
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
if (!m_item || !m_item->IsClassCommon() || GetItem(slot)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
return (
|
||||
(
|
||||
!GetItem(slot) &&
|
||||
m_item->AugSlotVisible[slot]
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[slot] &&
|
||||
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
||||
)
|
||||
) &&
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[slot] &&
|
||||
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
||||
RuleB(Items, AugmentItemAllowInvisibleAugments) ||
|
||||
m_item->AugSlotVisible[slot]
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve item inside container
|
||||
@@ -1292,7 +1279,7 @@ int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
return race;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) const
|
||||
int EQ::ItemInstance::GetItemBaneDamageBody(uint8 against, bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
@@ -1812,6 +1799,142 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
|
||||
return augments;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemRegen(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->Regen;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemRegen();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemManaRegen(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->ManaRegen;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemManaRegen();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemDamageShield(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->DamageShield;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemDamageShield();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemDSMitigation(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->DSMitigation;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemDSMitigation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemHealAmt(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->HealAmt;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemHealAmt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemSpellDamage(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->SpellDmg;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemSpellDamage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemClairvoyance(bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->Clairvoyance;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemClairvoyance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augments) const
|
||||
{
|
||||
int stat = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
stat = item->ExtraDmgSkill == skill ? item->ExtraDmgAmt : 0;
|
||||
if (augments) {
|
||||
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetAugment(i)) {
|
||||
stat += GetAugment(i)->GetItemSkillsStat(skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
//
|
||||
// class EvolveInfo
|
||||
//
|
||||
|
||||
@@ -265,11 +265,12 @@ namespace EQ
|
||||
// these two are just quick checks
|
||||
int GetItemBaneDamageBody(bool augments = false) const;
|
||||
int GetItemBaneDamageRace(bool augments = false) const;
|
||||
int GetItemBaneDamageBody(bodyType against, bool augments = false) const;
|
||||
int GetItemBaneDamageBody(uint8 against, bool augments = false) const;
|
||||
int GetItemBaneDamageRace(uint16 against, bool augments = false) const;
|
||||
int GetItemMagical(bool augments = false) const;
|
||||
int GetItemHP(bool augments = false) const;
|
||||
int GetItemMana(bool augments = false) const;
|
||||
int GetItemManaRegen(bool augments = false) const;
|
||||
int GetItemEndur(bool augments = false) const;
|
||||
int GetItemAttack(bool augments = false) const;
|
||||
int GetItemStr(bool augments = false) const;
|
||||
@@ -299,6 +300,13 @@ namespace EQ
|
||||
int GetItemHeroicDR(bool augments = false) const;
|
||||
int GetItemHeroicCorrup(bool augments = false) const;
|
||||
int GetItemHaste(bool augments = false) const;
|
||||
int GetItemRegen(bool augments = false) const;
|
||||
int GetItemDamageShield(bool augments = false) const;
|
||||
int GetItemDSMitigation(bool augments = false) const;
|
||||
int GetItemHealAmt(bool augments = false) const;
|
||||
int GetItemSpellDamage(bool augments = false) const;
|
||||
int GetItemClairvoyance(bool augments = false) const;
|
||||
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
||||
uint32 GetItemGuildFavor() const;
|
||||
std::vector<uint32> GetAugmentIDs() const;
|
||||
|
||||
|
||||
+24
-26
@@ -3494,14 +3494,13 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||
|
||||
eq->Code = emu->Code;
|
||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||
for (uint32 i = 0; i < 200; i++)
|
||||
eq->Code = emu->action;
|
||||
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
|
||||
{
|
||||
strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
|
||||
eq->items[i].Unknown18 = 0;
|
||||
if (i < 80) {
|
||||
eq->ItemCost[i] = emu->ItemCost[i];
|
||||
eq->ItemCost[i] = emu->item_cost[i];
|
||||
}
|
||||
else {
|
||||
eq->ItemCost[i] = 0;
|
||||
@@ -3515,9 +3514,9 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
|
||||
eq->Code = emu->Code;
|
||||
eq->Code = emu->action;
|
||||
strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
||||
eq->TraderID = emu->TraderID;
|
||||
eq->TraderID = emu->entity_id;
|
||||
eq->Stacksize = 0;
|
||||
eq->Price = 0;
|
||||
|
||||
@@ -3543,13 +3542,13 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
OUT(action);
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
OUT(item_id);
|
||||
OUT(quantity);
|
||||
OUT(already_sold);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@@ -5041,12 +5040,11 @@ namespace RoF
|
||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||
MEMSET_IN(ClickTrader_Struct);
|
||||
|
||||
emu->Code = eq->Code;
|
||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||
for (uint32 i = 0; i < 80; i++)
|
||||
emu->action = eq->Code;
|
||||
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
|
||||
{
|
||||
emu->SerialNumber[i] = 0; // eq->SerialNumber[i];
|
||||
emu->ItemCost[i] = eq->ItemCost[i];
|
||||
emu->serial_number[i] = 0; // eq->SerialNumber[i];
|
||||
emu->item_cost[i] = eq->ItemCost[i];
|
||||
}
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
@@ -5057,8 +5055,8 @@ namespace RoF
|
||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
MEMSET_IN(Trader_ShowItems_Struct);
|
||||
|
||||
emu->Code = eq->Code;
|
||||
emu->TraderID = eq->TraderID;
|
||||
emu->action = eq->Code;
|
||||
emu->entity_id = eq->TraderID;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@@ -5080,12 +5078,12 @@ namespace RoF
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
MEMSET_IN(TraderBuy_Struct);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
IN(action);
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
+558
-246
@@ -398,51 +398,182 @@ namespace RoF2
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
char *Buffer = (char *)in->pBuffer;
|
||||
uint32 action = *(uint32 *) in->pBuffer;
|
||||
|
||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||
switch (action) {
|
||||
case BazaarSearch: {
|
||||
LogTrading("(RoF2) BazaarSearch action <green>[{}]", action);
|
||||
std::vector<BazaarSearchResultsFromDB_Struct> results{};
|
||||
auto bsms = (BazaarSearchMessaging_Struct *) in->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(bsms->payload),
|
||||
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(results);
|
||||
|
||||
if (SubAction != BazaarSearchResults)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
auto name_size = 0;
|
||||
for (auto const &i: results) {
|
||||
name_size += i.item_name.length() + 1;
|
||||
}
|
||||
|
||||
auto p_size = 41 * results.size() + name_size + 14;
|
||||
auto buffer = std::make_unique<char[]>(p_size);
|
||||
auto bufptr = buffer.get();
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results[0].trader_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.size());
|
||||
|
||||
for (auto i: results) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.trader_id); //trader ID
|
||||
VARSTRUCT_ENCODE_STRING(bufptr, i.serial_number_RoF.c_str()); //serial
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.cost); //cost
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.stackable ? i.charges : i.count); //quantity
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_id); //ID
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.icon_id); //icon
|
||||
VARSTRUCT_ENCODE_STRING(bufptr, i.item_name.c_str()); //name
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat
|
||||
}
|
||||
|
||||
safe_delete(in->pBuffer);
|
||||
in->size = p_size;
|
||||
in->pBuffer = (uchar *) buffer.get();
|
||||
dest->QueuePacket(in);
|
||||
|
||||
break;
|
||||
}
|
||||
case BazaarInspect: {
|
||||
LogTrading("(RoF2) BazaarInspect action <green>[{}]", action);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
break;
|
||||
}
|
||||
case WelcomeMessage: {
|
||||
auto buffer = std::make_unique<char[]>(sizeof(structs::BazaarWelcome_Struct));
|
||||
auto emu = (BazaarWelcome_Struct *) in->pBuffer;
|
||||
auto eq = (structs::BazaarWelcome_Struct *) buffer.get();
|
||||
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage;
|
||||
eq->num_of_traders = emu->traders;
|
||||
eq->num_of_items = emu->items;
|
||||
|
||||
safe_delete(in->pBuffer);
|
||||
in->SetOpcode(OP_TraderShop);
|
||||
in->size = sizeof(structs::BazaarWelcome_Struct);
|
||||
in->pBuffer = (uchar *) buffer.get();
|
||||
|
||||
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||
dest->QueuePacket(in);
|
||||
|
||||
break;
|
||||
}
|
||||
case DeliveryCostUpdate: {
|
||||
auto data = (BazaarDeliveryCost_Struct *) in->pBuffer;
|
||||
LogTrading("(RoF2) Delivery costs updated: vouchers <green>[{}] parcel percentage <green>[{}]",
|
||||
data->voucher_delivery_cost,
|
||||
data->parcel_deliver_cost
|
||||
);
|
||||
data->action = 0;
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
ENCODE(OP_BecomeTrader)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
|
||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
||||
unsigned char *__emu_buffer = inapp->pBuffer;
|
||||
auto in = (BecomeTrader_Struct *) __emu_buffer;
|
||||
|
||||
int EntryCount = in->size / sizeof(BazaarSearchResults_Struct);
|
||||
switch (in->action) {
|
||||
case TraderOff: {
|
||||
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
{
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(structs::BecomeTrader_Struct));
|
||||
auto eq = (structs::BecomeTrader_Struct *) outapp->pBuffer;
|
||||
|
||||
eq->action = TraderOff;
|
||||
eq->entity_id = emu->entity_id;
|
||||
|
||||
LogTrading(
|
||||
"(RoF2) TraderOff action <green>[{}] for entity_id <green>[{}]",
|
||||
eq->action,
|
||||
eq->entity_id
|
||||
);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case TraderOn: {
|
||||
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(structs::BecomeTrader_Struct));
|
||||
auto eq = (structs::BecomeTrader_Struct *) outapp->pBuffer;
|
||||
|
||||
eq->action = TraderOn;
|
||||
eq->entity_id = emu->entity_id;
|
||||
|
||||
LogTrading(
|
||||
"(RoF2) TraderOn action <green>[{}] for entity_id <green>[{}]",
|
||||
eq->action,
|
||||
eq->entity_id
|
||||
);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case AddTraderToBazaarWindow: {
|
||||
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
|
||||
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
|
||||
|
||||
eq->action = emu->action;
|
||||
eq->entity_id = emu->entity_id;
|
||||
eq->trader_id = emu->trader_id;
|
||||
eq->zone_id = emu->zone_id;
|
||||
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||
|
||||
LogTrading(
|
||||
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
|
||||
eq->action,
|
||||
eq->trader_id,
|
||||
eq->entity_id,
|
||||
eq->zone_id
|
||||
);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case RemoveTraderFromBazaarWindow: {
|
||||
auto emu = (BecomeTrader_Struct *) __emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(structs::BazaarWindowRemoveTrader_Struct));
|
||||
auto eq = (structs::BazaarWindowRemoveTrader_Struct *) outapp->pBuffer;
|
||||
|
||||
eq->action = emu->action;
|
||||
eq->trader_id = emu->trader_id;
|
||||
|
||||
LogTrading(
|
||||
"(RoF2) RemoveTraderFromBazaarWindow action <green>[{}] for entity_id <green>[{}]",
|
||||
eq->action,
|
||||
eq->trader_id
|
||||
);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading(
|
||||
"(RoF2) Unhandled action <red>[{}]",
|
||||
in->action
|
||||
);
|
||||
dest->QueuePacket(inapp);
|
||||
}
|
||||
}
|
||||
|
||||
in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct);
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
memset(in->pBuffer, 0, in->size);
|
||||
|
||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer;
|
||||
|
||||
for (int i = 0; i < EntryCount; ++i, ++emu, ++eq)
|
||||
{
|
||||
OUT(Beginning.Action);
|
||||
OUT(SellerID);
|
||||
memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
||||
OUT(NumItems);
|
||||
OUT(ItemID);
|
||||
OUT(SerialNumber);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(Cost);
|
||||
OUT(ItemStat);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_BeginCast)
|
||||
@@ -2591,7 +2722,7 @@ namespace RoF2
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
}
|
||||
|
||||
outapp->WriteUInt32(0); // Unknown
|
||||
outapp->WriteUInt32(emu->char_id); // character_id
|
||||
|
||||
outapp->WriteUInt8(emu->leadAAActive);
|
||||
|
||||
@@ -3586,54 +3717,146 @@ namespace RoF2
|
||||
|
||||
ENCODE(OP_Trader)
|
||||
{
|
||||
if ((*p)->size == sizeof(ClickTrader_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||
uint32 action = *(uint32 *) (*p)->pBuffer;
|
||||
|
||||
eq->Code = emu->Code;
|
||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||
for (uint32 i = 0; i < 200; i++)
|
||||
{
|
||||
eq->items[i].Unknown18 = 0;
|
||||
if (i < 80) {
|
||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016" PRId64, emu->SerialNumber[i]);
|
||||
eq->ItemCost[i] = emu->ItemCost[i];
|
||||
}
|
||||
else {
|
||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0);
|
||||
eq->ItemCost[i] = 0;
|
||||
}
|
||||
switch (action) {
|
||||
case TraderOn: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::BeginTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
LogTrading("(RoF2) TraderOn action <green>[{}] entity_id <green>[{}]", action, eq->entity_id);
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderOff: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if ((*p)->size == sizeof(Trader_ShowItems_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::EndTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
eq->Code = emu->Code;
|
||||
//strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
||||
//snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", 0);
|
||||
eq->TraderID = emu->TraderID;
|
||||
//eq->Stacksize = 0;
|
||||
//eq->Price = 0;
|
||||
LogTrading("(RoF2) TraderOff action <green>[{}] entity_id <green>[{}]", action, eq->entity_id);
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case ListTraderItems: {
|
||||
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_Struct, structs::ClickTrader_Struct);
|
||||
LogTrading("(RoF2) action <green>[{}]", action);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if ((*p)->size == sizeof(TraderStatus_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderStatus_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::ListTraderItems;
|
||||
std::transform(
|
||||
std::begin(emu->items),
|
||||
std::end(emu->items),
|
||||
std::begin(eq->items),
|
||||
[&](const uint32 x) {
|
||||
return x;
|
||||
}
|
||||
);
|
||||
std::copy_n(
|
||||
std::begin(emu->item_cost),
|
||||
EQ::invtype::BAZAAR_SIZE,
|
||||
std::begin(eq->item_cost)
|
||||
);
|
||||
|
||||
eq->Code = emu->Code;
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderAck2: {
|
||||
LogTrading("(RoF2) TraderAck2 action");
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if ((*p)->size == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
ENCODE_FORWARD(OP_TraderBuy);
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
case PriceUpdate: {
|
||||
SETUP_DIRECT_ENCODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||
switch (emu->SubAction) {
|
||||
case BazaarPriceChange_AddItem: {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||
OP_Trader,
|
||||
sizeof(structs::TraderStatus_Struct)
|
||||
);
|
||||
|
||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||
data->action = emu->Action;
|
||||
data->sub_action = BazaarPriceChange_AddItem;
|
||||
LogTrading(
|
||||
"(RoF2) PriceUpdate action <green>[{}] AddItem subaction <yellow>[{}]",
|
||||
data->action,
|
||||
data->sub_action
|
||||
);
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
case BazaarPriceChange_RemoveItem: {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||
OP_Trader,
|
||||
sizeof(structs::TraderStatus_Struct)
|
||||
);
|
||||
|
||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||
data->action = emu->Action;
|
||||
data->sub_action = BazaarPriceChange_RemoveItem;
|
||||
LogTrading(
|
||||
"(RoF2) PriceUpdate action <green>[{}] RemoveItem subaction <yellow>[{}]",
|
||||
data->action,
|
||||
data->sub_action
|
||||
);
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
case BazaarPriceChange_UpdatePrice: {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(
|
||||
OP_Trader,
|
||||
sizeof(structs::TraderStatus_Struct)
|
||||
);
|
||||
|
||||
auto data = (structs::TraderStatus_Struct *) outapp->pBuffer;
|
||||
data->action = emu->Action;
|
||||
data->sub_action = BazaarPriceChange_UpdatePrice;
|
||||
LogTrading(
|
||||
"(RoF2) PriceUpdate action <green>[{}] UpdatePrice subaction <yellow>[{}]",
|
||||
data->action,
|
||||
data->sub_action
|
||||
);
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case BuyTraderItem: {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
auto eq = (structs::TraderBuy_Struct *) in->pBuffer;
|
||||
LogTrading(
|
||||
"(RoF2) BuyTraderItem action <green>[{}] item_id <green>[{}] item_sn <green>[{}] buyer <green>[{}]",
|
||||
action,
|
||||
eq->item_id,
|
||||
eq->serial_number,
|
||||
eq->buyer_name
|
||||
);
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(RoF2) action <red>[{}]", action);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
dest->FastQueuePacket(&in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3641,14 +3864,26 @@ namespace RoF2
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
LogTrading(
|
||||
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
emu->item_id,
|
||||
emu->price,
|
||||
emu->quantity,
|
||||
emu->trader_id
|
||||
);
|
||||
__packet->SetOpcode(OP_TraderShop);
|
||||
OUT(action);
|
||||
OUT(method);
|
||||
OUT(sub_action);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(price);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
OUT_str(buyer_name);
|
||||
OUT_str(seller_name);
|
||||
OUT_str(item_name);
|
||||
OUT_str(serial_number);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@@ -3657,71 +3892,74 @@ namespace RoF2
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) trader_id <green>[{}] item_id <green>[{}]",
|
||||
emu->trader_id,
|
||||
emu->item_id
|
||||
);
|
||||
|
||||
OUT(TraderID);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
LogTrading("ENCODE(OP_TraderDelItem): TraderID [{}], SerialNumber: [{}]", emu->TraderID, emu->ItemID);
|
||||
eq->TraderID = emu->trader_id;
|
||||
auto serial = fmt::format("{:016}\n", emu->item_id);
|
||||
strn0cpy(eq->SerialNumber, serial.c_str(), sizeof(eq->SerialNumber));
|
||||
LogTrading("(RoF2) TraderID <green>[{}], SerialNumber: <green>[{}]", emu->trader_id, emu->item_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderShop)
|
||||
{
|
||||
uint32 psize = (*p)->size;
|
||||
if (psize == sizeof(TraderClick_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
auto action = *(uint32 *) (*p)->pBuffer;
|
||||
|
||||
eq->Code = 28; // Seen on Live
|
||||
OUT(TraderID);
|
||||
OUT(Approval);
|
||||
switch (action) {
|
||||
case ClickTrader: {
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||
action,
|
||||
emu->TraderID
|
||||
);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if (psize == sizeof(BazaarWelcome_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BazaarWelcome_Struct);
|
||||
SETUP_DIRECT_ENCODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
||||
eq->action = structs::RoF2BazaarTraderBuyerActions::ClickTrader; // Seen on Live
|
||||
eq->trader_id = emu->TraderID;
|
||||
eq->unknown_008 = emu->Approval;
|
||||
|
||||
eq->Code = emu->Beginning.Action;
|
||||
eq->EntityID = emu->Unknown012;
|
||||
OUT(Traders);
|
||||
OUT(Items);
|
||||
eq->Traders2 = emu->Traders;
|
||||
eq->Items2 = emu->Items;
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::BuyTraderItem: {
|
||||
ENCODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
LogTrading("ENCODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
||||
eq->Code, eq->Traders, eq->Items);
|
||||
OUT(action);
|
||||
OUT(method);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(price);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
OUT_str(buyer_name);
|
||||
OUT_str(seller_name);
|
||||
OUT_str(item_name);
|
||||
OUT_str(serial_number);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if (psize == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
OUT(Action);
|
||||
OUT(TraderID);
|
||||
|
||||
//memcpy(eq->BuyerName, emu->BuyerName, sizeof(eq->BuyerName));
|
||||
//memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
||||
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(AlreadySold);
|
||||
OUT(Price);
|
||||
OUT(Quantity);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
|
||||
LogTrading("ENCODE(OP_TraderShop): Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("ENCODE(OP_TraderShop): Encode Size Unknown ([{}])", psize);
|
||||
dest->FastQueuePacket(&in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4067,20 +4305,20 @@ namespace RoF2
|
||||
|
||||
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
|
||||
|
||||
Bitfields->gender = emu->gender;
|
||||
Bitfields->ispet = emu->is_pet;
|
||||
Bitfields->afk = emu->afk;
|
||||
Bitfields->anon = emu->anon;
|
||||
Bitfields->gm = emu->gm;
|
||||
Bitfields->sneak = 0;
|
||||
Bitfields->lfg = emu->lfg;
|
||||
Bitfields->invis = emu->invis;
|
||||
Bitfields->linkdead = 0;
|
||||
Bitfields->showhelm = emu->showhelm;
|
||||
Bitfields->trader = 0;
|
||||
Bitfields->targetable = 1;
|
||||
Bitfields->gender = emu->gender;
|
||||
Bitfields->ispet = emu->is_pet;
|
||||
Bitfields->afk = emu->afk;
|
||||
Bitfields->anon = emu->anon;
|
||||
Bitfields->gm = emu->gm;
|
||||
Bitfields->sneak = 0;
|
||||
Bitfields->lfg = emu->lfg;
|
||||
Bitfields->invis = emu->invis;
|
||||
Bitfields->linkdead = 0;
|
||||
Bitfields->showhelm = emu->showhelm;
|
||||
Bitfields->trader = emu->trader ? 1 : 0;
|
||||
Bitfields->targetable = 1;
|
||||
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
||||
Bitfields->showname = ShowName;
|
||||
Bitfields->showname = ShowName;
|
||||
|
||||
if (emu->DestructibleObject)
|
||||
{
|
||||
@@ -4431,6 +4669,7 @@ namespace RoF2
|
||||
char *Buffer = (char *)__packet->pBuffer;
|
||||
|
||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||
LogTrading("(RoF2) action <green>[{}]", SubAction);
|
||||
|
||||
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
|
||||
return;
|
||||
@@ -4440,6 +4679,7 @@ namespace RoF2
|
||||
IN(Beginning.Action);
|
||||
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
||||
IN(SerialNumber);
|
||||
LogTrading("(RoF2) action <green>[{}] serial_number <green>[{}]", eq->Beginning.Action, eq->SerialNumber);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@@ -5331,40 +5571,61 @@ namespace RoF2
|
||||
|
||||
DECODE(OP_Trader)
|
||||
{
|
||||
uint32 psize = __packet->size;
|
||||
if (psize == sizeof(structs::ClickTrader_Struct))
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ClickTrader_Struct);
|
||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||
auto action = *(uint32 *)__packet->pBuffer;
|
||||
|
||||
emu->Code = eq->Code;
|
||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||
for (uint32 i = 0; i < 80; i++)
|
||||
{
|
||||
emu->SerialNumber[i] = 0; // eq->SerialNumber[i];
|
||||
emu->ItemCost[i] = eq->ItemCost[i];
|
||||
switch (action) {
|
||||
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
|
||||
|
||||
emu->action = TraderOn;
|
||||
std::copy_n(eq->item_cost, RoF2::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||
std::transform(
|
||||
std::begin(eq->items),
|
||||
std::end(eq->items),
|
||||
std::begin(emu->serial_number),
|
||||
[&](const structs::TraderItemSerial_Struct x) {
|
||||
return Strings::ToUnsignedBigInt(x.serial_number,0);
|
||||
}
|
||||
);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading("(RoF2) EndTraderMode action <green>[{}]", action);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == sizeof(structs::Trader_ShowItems_Struct))
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
emu->action = TraderOff;
|
||||
emu->entity_id = eq->entity_id;
|
||||
|
||||
emu->Code = eq->Code;
|
||||
emu->TraderID = eq->TraderID;
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::ListTraderItems: {
|
||||
LogTrading("(RoF2) ListTraderItems action <green>[{}]", action);
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::PriceUpdate: {
|
||||
DECODE_LENGTH_EXACT(structs::TraderPriceUpdate_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderPriceUpdate_Struct, structs::TraderPriceUpdate_Struct);
|
||||
LogTrading("(RoF2) PriceUpdate action <green>[{}]", action);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == sizeof(structs::TraderStatus_Struct))
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderStatus_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
||||
emu->Action = PriceUpdate;
|
||||
emu->SerialNumber = Strings::ToUnsignedBigInt(eq->serial_number, 0);
|
||||
if (emu->SerialNumber == 0) {
|
||||
LogTrading("(RoF2) Price change with invalid serial number <red>[{}]", eq->serial_number);
|
||||
}
|
||||
emu->NewPrice = eq->new_price;
|
||||
|
||||
emu->Code = eq->Code; // 11 = Start Trader, 2 = End Trader, 22 = ? - Guessing
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5372,73 +5633,136 @@ namespace RoF2
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
IN(action);
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_TraderShop)
|
||||
{
|
||||
uint32 psize = __packet->size;
|
||||
if (psize == sizeof(structs::TraderClick_Struct))
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
uint32 action = *(uint32 *)__packet->pBuffer;
|
||||
|
||||
IN(Code);
|
||||
IN(TraderID);
|
||||
IN(Approval);
|
||||
LogTrading("DECODE(OP_TraderShop): TraderClick_Struct Code [{}], TraderID [{}], Approval [{}]",
|
||||
eq->Code, eq->TraderID, eq->Approval);
|
||||
switch (action) {
|
||||
case structs::RoF2BazaarTraderBuyerActions::BazaarSearch: {
|
||||
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) BazaarSearch action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == sizeof(structs::BazaarWelcome_Struct))
|
||||
{
|
||||
// Don't think this size gets used in RoF+ - Leaving for now...
|
||||
DECODE_LENGTH_EXACT(structs::BazaarWelcome_Struct);
|
||||
SETUP_DIRECT_DECODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
||||
__packet->SetOpcode(OP_BazaarSearch);
|
||||
emu->action = BazaarSearch;
|
||||
emu->type = eq->type == UINT32_MAX ? UINT8_MAX : eq->type;
|
||||
IN(item_stat);
|
||||
IN(max_cost);
|
||||
IN(min_cost);
|
||||
IN(max_level);
|
||||
IN(min_level);
|
||||
IN(race);
|
||||
IN(slot);
|
||||
IN(trader_id);
|
||||
IN(_class);
|
||||
IN(prestige);
|
||||
IN(search_scope);
|
||||
IN(max_results);
|
||||
IN(augment);
|
||||
IN_str(item_name);
|
||||
|
||||
emu->Beginning.Action = eq->Code;
|
||||
IN(Traders);
|
||||
IN(Items);
|
||||
LogTrading("DECODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
||||
eq->Code, eq->Traders, eq->Items);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::ClickTrader: {
|
||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == sizeof(structs::TraderBuy_Struct))
|
||||
{
|
||||
emu->Code = ClickTrader;
|
||||
emu->TraderID = eq->trader_id;
|
||||
emu->Approval = eq->unknown_008;
|
||||
LogTrading("(RoF2) ClickTrader action <green>[{}], trader_id <green>[{}], approval <green>[{}]",
|
||||
eq->action,
|
||||
eq->trader_id,
|
||||
eq->unknown_008
|
||||
);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::BazaarInspect: {
|
||||
DECODE_LENGTH_EXACT(structs::BazaarInspect_Struct);
|
||||
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
__packet->SetOpcode(OP_BazaarSearch);
|
||||
IN(item_id);
|
||||
IN(trader_id);
|
||||
emu->action = BazaarInspect;
|
||||
emu->serial_number = Strings::ToUnsignedInt(eq->serial_number, 0);
|
||||
if (emu->serial_number == 0) {
|
||||
LogTrading(
|
||||
"(RoF2) trader_id = <green>[{}] requested a BazaarInspect with an invalid serial number of <red>[{}]",
|
||||
eq->trader_id,
|
||||
eq->serial_number
|
||||
);
|
||||
FINISH_DIRECT_DECODE();
|
||||
return;
|
||||
}
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 [{}], Unknown008 [{}], Unknown012 [{}], Unknown076 [{}], Unknown276 [{}]",
|
||||
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
|
||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
|
||||
LogTrading("(RoF2) BazaarInspect action <green>[{}] item_id <green>[{}] serial_number <green>[{}]",
|
||||
action,
|
||||
eq->item_id,
|
||||
eq->serial_number
|
||||
);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
|
||||
__packet->SetOpcode(OP_BazaarSearch);
|
||||
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BazaarTraderBuyerActions::BuyTraderItem: {
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"(RoF2) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == 4)
|
||||
{
|
||||
LogTrading("DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("DECODE(OP_TraderShop): Decode Size Unknown ([{}])", psize);
|
||||
__packet->SetOpcode(OP_TraderBuy);
|
||||
IN(action);
|
||||
IN(method);
|
||||
IN(trader_id);
|
||||
IN(item_id);
|
||||
IN(price);
|
||||
IN(already_sold);
|
||||
IN(quantity);
|
||||
IN_str(buyer_name);
|
||||
IN_str(seller_name);
|
||||
IN_str(item_name);
|
||||
IN_str(serial_number);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(RoF2) Unhandled action <red>[{}]", action);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5541,19 +5865,7 @@ namespace RoF2
|
||||
RoF2::structs::ItemSerializationHeader hdr;
|
||||
|
||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||
|
||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
||||
if (packet_type == ItemPacketParcel) {
|
||||
strn0cpy(
|
||||
hdr.unknown000,
|
||||
fmt::format(
|
||||
"{:03}PAR{:010}\0",
|
||||
inst->GetMerchantSlot(),
|
||||
item->ID
|
||||
).c_str(),
|
||||
sizeof(hdr.unknown000)
|
||||
);
|
||||
}
|
||||
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
|
||||
|
||||
hdr.stacksize =
|
||||
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
|
||||
|
||||
@@ -43,6 +43,7 @@ E(OP_ApplyPoison)
|
||||
E(OP_AugmentInfo)
|
||||
E(OP_Barter)
|
||||
E(OP_BazaarSearch)
|
||||
E(OP_BecomeTrader)
|
||||
E(OP_BeginCast)
|
||||
E(OP_BlockedBuffs)
|
||||
E(OP_Buff)
|
||||
|
||||
+142
-112
@@ -3106,28 +3106,43 @@ struct EnvDamage2_Struct {
|
||||
};
|
||||
|
||||
//Bazaar Stuff
|
||||
enum RoF2BazaarTraderBuyerActions {
|
||||
Zero = 0,
|
||||
BeginTraderMode = 1,
|
||||
EndTraderMode = 2,
|
||||
PriceUpdate = 3,
|
||||
EndTransaction = 4,
|
||||
BazaarSearch = 7,
|
||||
WelcomeMessage = 9,
|
||||
BuyTraderItem = 10,
|
||||
ListTraderItems = 11,
|
||||
BazaarInspect = 18,
|
||||
ClickTrader = 28,
|
||||
ItemMove = 19,
|
||||
ReconcileItems = 20
|
||||
};
|
||||
|
||||
enum {
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_CustomerBrowsing = 13,
|
||||
BazaarInspectItem = 18,
|
||||
BazaarSearchDone2 = 19,
|
||||
BazaarInspectItem = 18,
|
||||
BazaarSearchDone2 = 19,
|
||||
BazaarTrader_StartTraderMode2 = 22
|
||||
};
|
||||
|
||||
enum {
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_UpdatePrice = 1,
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
};
|
||||
|
||||
struct BazaarWindowStart_Struct {
|
||||
@@ -3136,34 +3151,51 @@ struct BazaarWindowStart_Struct {
|
||||
uint16 Unknown002;
|
||||
};
|
||||
|
||||
struct BazaarDeliveryCost_Struct {
|
||||
uint32 action;
|
||||
uint32 voucher_delivery_cost;
|
||||
float parcel_deliver_cost; //percentage of item cost
|
||||
uint32 unknown_010;
|
||||
};
|
||||
|
||||
struct BazaarWelcome_Struct {
|
||||
uint32 Code;
|
||||
uint32 EntityID;
|
||||
uint32 Traders;
|
||||
uint32 Items;
|
||||
uint32 Traders2;
|
||||
uint32 Items2;
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 num_of_traders;
|
||||
uint32 num_of_items;
|
||||
};
|
||||
|
||||
struct BazaarSearch_Struct {
|
||||
BazaarWindowStart_Struct Beginning;
|
||||
uint32 TraderID;
|
||||
uint32 Class_;
|
||||
uint32 Race;
|
||||
uint32 ItemStat;
|
||||
uint32 Slot;
|
||||
uint32 Type;
|
||||
char Name[64];
|
||||
uint32 MinPrice;
|
||||
uint32 MaxPrice;
|
||||
uint32 Minlevel;
|
||||
uint32 MaxLlevel;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint8 search_scope;//1 all traders 0 local traders
|
||||
/*005*/ uint8 unknown_005{0};
|
||||
/*006*/ uint16 unknown_006{0};
|
||||
/*008*/ uint32 unknown_008{0};
|
||||
/*012*/ uint32 unknown_012{0};
|
||||
/*016*/ uint32 trader_id;
|
||||
/*020*/ uint32 _class;
|
||||
/*024*/ uint32 race;
|
||||
/*028*/ uint32 item_stat;
|
||||
/*032*/ uint32 slot;
|
||||
/*036*/ uint32 type;
|
||||
/*040*/ char item_name[64];
|
||||
/*104*/ uint32 min_cost;
|
||||
/*108*/ uint32 max_cost;
|
||||
/*112*/ uint32 min_level;
|
||||
/*116*/ uint32 max_level;
|
||||
/*120*/ uint32 max_results;
|
||||
/*124*/ uint32 prestige;
|
||||
/*128*/ uint32 augment;
|
||||
};
|
||||
struct BazaarInspect_Struct{
|
||||
uint32 ItemID;
|
||||
uint32 Unknown004;
|
||||
char Name[64];
|
||||
|
||||
struct BazaarInspect_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 trader_id;
|
||||
char serial_number[17];
|
||||
char unknown_029[3];
|
||||
uint32 item_id;
|
||||
uint32 unknown_036;
|
||||
};
|
||||
|
||||
struct NewBazaarInspect_Struct {
|
||||
@@ -3184,18 +3216,23 @@ struct BazaarReturnDone_Struct{
|
||||
uint32 Unknown016;
|
||||
};
|
||||
|
||||
struct BazaarSearchResults_Struct {
|
||||
/*000*/ BazaarWindowStart_Struct Beginning;
|
||||
/*004*/ uint32 SellerID;
|
||||
/*008*/ char SellerName[64];
|
||||
/*072*/ uint32 NumItems;
|
||||
/*076*/ uint32 ItemID;
|
||||
/*080*/ uint32 SerialNumber;
|
||||
/*084*/ uint32 Unknown084;
|
||||
/*088*/ char ItemName[64];
|
||||
/*152*/ uint32 Cost;
|
||||
/*156*/ uint32 ItemStat;
|
||||
/*160*/
|
||||
struct BazaarSearchDetails_Struct { //24+name+17
|
||||
/*014*/ uint32 trader_id;
|
||||
/*018*/ char serial_num[17];
|
||||
/*022*/ uint32 cost;
|
||||
/*026*/ uint32 quanity;
|
||||
/*030*/ uint32 id;
|
||||
/*034*/ uint32 icon;
|
||||
/*038*/ char name[1];
|
||||
/*039*/ uint32 stat;
|
||||
};
|
||||
|
||||
struct BazaarSearchResults_Struct { //14
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint16 zone_id;
|
||||
/*006*/ uint32 entity_id;
|
||||
/*010*/ uint32 num_items;
|
||||
/*014*/ BazaarSearchDetails_Struct items[];
|
||||
};
|
||||
|
||||
struct ServerSideFilters_Struct {
|
||||
@@ -3398,21 +3435,26 @@ struct WhoAllPlayerPart4 {
|
||||
};
|
||||
|
||||
struct TraderItemSerial_Struct {
|
||||
char SerialNumber[17];
|
||||
uint8 Unknown18;
|
||||
char serial_number[17];
|
||||
uint8 unknown_018;
|
||||
|
||||
void operator=(uint32 a) {
|
||||
auto _tmp = fmt::format("{:016}", a);
|
||||
strn0cpy(this->serial_number, _tmp.c_str(), sizeof(this->serial_number));
|
||||
}
|
||||
};
|
||||
|
||||
struct Trader_Struct {
|
||||
/*0000*/ uint32 Code;
|
||||
/*0004*/ TraderItemSerial_Struct items[200];
|
||||
/*3604*/ uint32 ItemCost[200];
|
||||
struct BeginTrader_Struct {
|
||||
/*0000*/ uint32 action;
|
||||
/*0004*/ TraderItemSerial_Struct items[200];
|
||||
/*3604*/ uint32 item_cost[200];
|
||||
/*4404*/
|
||||
};
|
||||
|
||||
struct ClickTrader_Struct {
|
||||
/*0000*/ uint32 Code;
|
||||
/*0004*/ TraderItemSerial_Struct items[200];
|
||||
/*3604*/ uint32 ItemCost[200];
|
||||
/*0000*/ uint32 action;
|
||||
/*0004*/ TraderItemSerial_Struct items[200];
|
||||
/*3604*/ uint32 item_cost[200];
|
||||
/*4404*/
|
||||
};
|
||||
|
||||
@@ -3421,67 +3463,55 @@ struct GetItems_Struct {
|
||||
};
|
||||
|
||||
struct BecomeTrader_Struct {
|
||||
uint32 id;
|
||||
uint32 code;
|
||||
uint32 entity_id;
|
||||
uint32 action;
|
||||
};
|
||||
|
||||
struct BazaarWindowRemoveTrader_Struct {
|
||||
uint32 action;
|
||||
uint32 trader_id;
|
||||
};
|
||||
|
||||
struct TraderPriceUpdate_Struct {
|
||||
uint32 action;
|
||||
char serial_number[17];
|
||||
char unknown_021[3];
|
||||
uint32 unknown_024;
|
||||
uint32 new_price;
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct {
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint16 TraderID;
|
||||
/*008*/ uint32 Unknown08;
|
||||
/*012*/
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct_WIP {
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ char SerialNumber[17];
|
||||
/*021*/ uint8 Unknown21;
|
||||
/*022*/ uint16 TraderID;
|
||||
/*026*/ uint32 Stacksize;
|
||||
/*030*/ uint32 Price;
|
||||
/*032*/
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 entity_id;
|
||||
/*008*/ uint32 unknown_008;
|
||||
/*012*/
|
||||
};
|
||||
|
||||
struct TraderStatus_Struct {
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 Uknown04;
|
||||
/*008*/ uint32 Uknown08;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 sub_action;
|
||||
/*008*/ uint32 uknown_008;
|
||||
/*012*/
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Unknown008;
|
||||
/*012*/ uint32 Unknown012;
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char BuyerName[64];
|
||||
/*084*/ char SellerName[64];
|
||||
/*148*/ char Unknown148[32];
|
||||
/*180*/ char ItemName[64];
|
||||
/*244*/ char SerialNumber[16];
|
||||
/*260*/ uint32 Unknown076;
|
||||
/*264*/ uint32 ItemID;
|
||||
/*268*/ uint32 Price;
|
||||
/*272*/ uint32 AlreadySold;
|
||||
/*276*/ uint32 Unknown276;
|
||||
/*280*/ uint32 Quantity;
|
||||
/*284*/
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct_OLD {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Price;
|
||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char ItemName[64];
|
||||
/*084*/ uint32 Unknown076;
|
||||
/*088*/ uint32 ItemID;
|
||||
/*092*/ uint32 AlreadySold;
|
||||
/*096*/ uint32 Quantity;
|
||||
/*100*/ uint32 Unknown092;
|
||||
/*104*/
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 method;
|
||||
/*008*/ uint32 sub_action;
|
||||
/*012*/ uint32 unknown_012;
|
||||
/*016*/ uint32 trader_id;
|
||||
/*020*/ char buyer_name[64];
|
||||
/*084*/ char seller_name[64];
|
||||
/*148*/ char unknown_148[32];
|
||||
/*180*/ char item_name[64];
|
||||
/*244*/ char serial_number[17];
|
||||
/*261*/ char unknown_261[3];
|
||||
/*264*/ uint32 item_id;
|
||||
/*268*/ uint32 price;
|
||||
/*272*/ uint32 already_sold;
|
||||
/*276*/ uint32 unknown_276;
|
||||
/*280*/ uint32 quantity;
|
||||
/*284*/
|
||||
};
|
||||
|
||||
struct TraderItemUpdate_Struct{
|
||||
@@ -3502,15 +3532,15 @@ struct MoneyUpdate_Struct{
|
||||
struct TraderDelItem_Struct{
|
||||
/*000*/ uint32 Unknown000;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*008*/ char SerialNumber[16];
|
||||
/*008*/ char SerialNumber[17];
|
||||
/*024*/ uint32 Unknown012;
|
||||
/*028*/
|
||||
};
|
||||
|
||||
struct TraderClick_Struct{
|
||||
/*000*/ uint32 Code;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*008*/ uint32 Approval;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 trader_id;
|
||||
/*008*/ uint32 unknown_008;
|
||||
/*012*/
|
||||
};
|
||||
|
||||
|
||||
@@ -3376,17 +3376,17 @@ struct TraderStatus_Struct {
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Price;
|
||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char ItemName[64];
|
||||
/*084*/ uint32 Unknown076;
|
||||
/*088*/ uint32 ItemID;
|
||||
/*092*/ uint32 AlreadySold;
|
||||
/*096*/ uint32 Quantity;
|
||||
/*100*/ uint32 Unknown092;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 unknown_004;
|
||||
/*008*/ uint32 price;
|
||||
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 trader_id;
|
||||
/*020*/ char item_name[64];
|
||||
/*084*/ uint32 unknown_076;
|
||||
/*088*/ uint32 item_id;
|
||||
/*092*/ uint32 already_sold;
|
||||
/*096*/ uint32 quantity;
|
||||
/*100*/ uint32 unknown_092;
|
||||
/*104*/
|
||||
};
|
||||
|
||||
|
||||
+13
-13
@@ -2286,13 +2286,13 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
OUT(action);
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
OUT(item_id);
|
||||
OUT(quantity);
|
||||
OUT(already_sold);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@@ -3517,12 +3517,12 @@ namespace SoD
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
MEMSET_IN(TraderBuy_Struct);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
IN(action);
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -2879,20 +2879,21 @@ struct Trader_ShowItems_Struct{
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Price;
|
||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char ItemName[64];
|
||||
/*084*/ uint32 Unknown076;
|
||||
/*088*/ uint32 ItemID;
|
||||
/*092*/ uint32 AlreadySold;
|
||||
/*096*/ uint32 Quantity;
|
||||
/*100*/ uint32 Unknown092;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 unknown_004;
|
||||
/*008*/ uint32 price;
|
||||
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 trader_id;
|
||||
/*020*/ char item_name[64];
|
||||
/*084*/ uint32 unknown_076;
|
||||
/*088*/ uint32 item_id;
|
||||
/*092*/ uint32 already_sold;
|
||||
/*096*/ uint32 quantity;
|
||||
/*100*/ uint32 unknown_092;
|
||||
/*104*/
|
||||
};
|
||||
|
||||
|
||||
struct TraderItemUpdate_Struct{
|
||||
uint32 unknown0;
|
||||
uint32 traderid;
|
||||
|
||||
+16
-16
@@ -270,8 +270,8 @@ namespace SoF
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
|
||||
OUT(ID);
|
||||
OUT(Code);
|
||||
OUT(trader_id);
|
||||
OUT(action);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@@ -1902,13 +1902,13 @@ namespace SoF
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
OUT(action);
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
OUT(item_id);
|
||||
OUT(quantity);
|
||||
OUT(already_sold);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@@ -2349,7 +2349,7 @@ namespace SoF
|
||||
DECODE_LENGTH_EXACT(structs::BugReport_Struct);
|
||||
SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct);
|
||||
|
||||
emu->category_id = EQ::bug::CategoryNameToCategoryID(eq->category_name);
|
||||
emu->category_id = Bug::GetID(eq->category_name);
|
||||
memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
@@ -2908,12 +2908,12 @@ namespace SoF
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
MEMSET_IN(TraderBuy_Struct);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
IN(action);
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -2771,8 +2771,8 @@ struct GetItems_Struct{
|
||||
};
|
||||
|
||||
struct BecomeTrader_Struct{
|
||||
uint32 ID;
|
||||
uint32 Code;
|
||||
uint32 trader_id;
|
||||
uint32 action;
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct{
|
||||
@@ -2782,15 +2782,15 @@ struct Trader_ShowItems_Struct{
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Price;
|
||||
/*008*/ uint32 TraderID;
|
||||
/*012*/ char ItemName[64];
|
||||
/*076*/ uint32 Unknown076;
|
||||
/*080*/ uint32 ItemID;
|
||||
/*084*/ uint32 AlreadySold;
|
||||
/*088*/ uint32 Quantity;
|
||||
/*092*/ uint32 Unknown092;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 price;
|
||||
/*008*/ uint32 trader_id;
|
||||
/*012*/ char item_name[64];
|
||||
/*076*/ uint32 unknown_076;
|
||||
/*080*/ uint32 item_id;
|
||||
/*084*/ uint32 already_sold;
|
||||
/*088*/ uint32 quantity;
|
||||
/*092*/ uint32 unknown_092;
|
||||
};
|
||||
|
||||
struct TraderItemUpdate_Struct{
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
|
||||
|
||||
#define ALLOC_LEN_ENCODE(len) \
|
||||
__packet->pBuffer = new unsigned char[len]; \
|
||||
__packet->pBuffer = new unsigned char[len] {}; \
|
||||
__packet->size = len; \
|
||||
memset(__packet->pBuffer, 0, len); \
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
#define SETUP_DIRECT_DECODE(emu_struct, eq_struct) \
|
||||
unsigned char *__eq_buffer = __packet->pBuffer; \
|
||||
__packet->size = sizeof(emu_struct); \
|
||||
__packet->pBuffer = new unsigned char[__packet->size]; \
|
||||
__packet->pBuffer = new unsigned char[__packet->size] {}; \
|
||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
eq_struct* in = (eq_struct*)__packet->pBuffer; \
|
||||
auto size = strlen(in->var_field); \
|
||||
__packet->size = sizeof(emu_struct) + size + 1; \
|
||||
__packet->pBuffer = new unsigned char[__packet->size]; \
|
||||
__packet->pBuffer = new unsigned char[__packet->size] {}; \
|
||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||
|
||||
|
||||
+399
-70
@@ -32,6 +32,7 @@
|
||||
#include "../strings.h"
|
||||
#include "../item_instance.h"
|
||||
#include "titanium_structs.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../raid.h"
|
||||
#include "../guilds.h"
|
||||
@@ -197,64 +198,135 @@ namespace Titanium
|
||||
|
||||
ENCODE(OP_BazaarSearch)
|
||||
{
|
||||
if (((*p)->size == sizeof(BazaarReturnDone_Struct)) || ((*p)->size == sizeof(BazaarWelcome_Struct))) {
|
||||
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
}
|
||||
|
||||
//consume the packet
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
//store away the emu struct
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
||||
uint32 action = *(uint32 *)in->pBuffer;
|
||||
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(BazaarSearchResults_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d",
|
||||
opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
switch (action) {
|
||||
case BazaarSearch: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(Ti) BazaarSearch action <green>[{}]",
|
||||
action
|
||||
);
|
||||
std::vector<BazaarSearchResultsFromDB_Struct> results {};
|
||||
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(bsms->payload),
|
||||
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(results);
|
||||
|
||||
auto size = results.size() * sizeof(structs::BazaarSearchResults_Struct);
|
||||
auto buffer = new uchar[size];
|
||||
uchar *bufptr = buffer;
|
||||
memset(buffer, 0, size);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::TiBazaarTraderBuyerActions::BazaarSearch);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
||||
bufptr += 4;
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
||||
bufptr += 4;
|
||||
if (row->stackable) {
|
||||
strn0cpy(
|
||||
reinterpret_cast<char *>(bufptr),
|
||||
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
|
||||
64
|
||||
);
|
||||
}
|
||||
else {
|
||||
strn0cpy(
|
||||
reinterpret_cast<char *>(bufptr),
|
||||
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
|
||||
64
|
||||
);
|
||||
}
|
||||
bufptr += 64;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
|
||||
memcpy(outapp->pBuffer, buffer, size);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete_array(buffer);
|
||||
safe_delete(in);
|
||||
break;
|
||||
}
|
||||
case BazaarInspect:
|
||||
case WelcomeMessage: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(Ti) BazaarInspect/WelcomeMessage action <green>[{}]",
|
||||
action
|
||||
);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(Ti) unhandled action <red>[{}]",
|
||||
action
|
||||
);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
}
|
||||
|
||||
//make the EQ struct.
|
||||
in->size = sizeof(structs::BazaarSearchResults_Struct)*entrycount;
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *) in->pBuffer;
|
||||
|
||||
//zero out the packet. We could avoid this memset by setting all fields (including unknowns) in the loop.
|
||||
memset(in->pBuffer, 0, in->size);
|
||||
|
||||
for (int i = 0; i < entrycount; i++, eq++, emu++) {
|
||||
eq->Beginning.Action = emu->Beginning.Action;
|
||||
eq->Beginning.Unknown001 = emu->Beginning.Unknown001;
|
||||
eq->Beginning.Unknown002 = emu->Beginning.Unknown002;
|
||||
eq->NumItems = emu->NumItems;
|
||||
eq->SerialNumber = emu->SerialNumber;
|
||||
eq->SellerID = emu->SellerID;
|
||||
eq->Cost = emu->Cost;
|
||||
eq->ItemStat = emu->ItemStat;
|
||||
strcpy(eq->ItemName, emu->ItemName);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_BecomeTrader)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
uint32 action = *(uint32 *)(*p)->pBuffer;
|
||||
|
||||
OUT(ID);
|
||||
OUT(Code);
|
||||
|
||||
FINISH_ENCODE();
|
||||
switch (action)
|
||||
{
|
||||
case TraderOff:
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(Ti) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
|
||||
"<green>[{}]",
|
||||
emu->action,
|
||||
emu->entity_id,
|
||||
emu->trader_name
|
||||
);
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::Zero;
|
||||
eq->entity_id = emu->entity_id;
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderOn:
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(Ti) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
|
||||
"<green>[{}]",
|
||||
emu->action,
|
||||
emu->entity_id,
|
||||
emu->trader_name
|
||||
);
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
|
||||
eq->entity_id = emu->entity_id;
|
||||
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(Ti) unhandled action <red>[{}] Sending packet as is.",
|
||||
action
|
||||
);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Buff)
|
||||
@@ -734,7 +806,7 @@ namespace Titanium
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case AppearanceType::GuildShow: {
|
||||
FAIL_ENCODE();
|
||||
@@ -2010,32 +2082,170 @@ namespace Titanium
|
||||
|
||||
ENCODE(OP_Trader)
|
||||
{
|
||||
if ((*p)->size != sizeof(TraderBuy_Struct)) {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
}
|
||||
auto action = *(uint32 *) (*p)->pBuffer;
|
||||
|
||||
ENCODE_FORWARD(OP_TraderBuy);
|
||||
switch (action) {
|
||||
case TraderOn: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader BeginTraderMode action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderOff: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader EndTraderMode action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::EndTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case ListTraderItems: {
|
||||
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader ListTraderItems action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::ListTraderItems;
|
||||
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
|
||||
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case BuyTraderItem: {
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case ItemMove: {
|
||||
LogTrading(
|
||||
"Encode OP_Trader ItemMove action <green>[{}]",
|
||||
action
|
||||
);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderBuy)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
emu->item_id,
|
||||
emu->price,
|
||||
emu->quantity,
|
||||
emu->trader_id
|
||||
);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
OUT(action);
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
OUT_str(item_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderShop)
|
||||
{
|
||||
auto action = *(uint32 *)(*p)->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case ClickTrader: {
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
LogTrading(
|
||||
"ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||
action,
|
||||
emu->TraderID
|
||||
);
|
||||
|
||||
eq->action = 0;
|
||||
eq->trader_id = emu->TraderID;
|
||||
eq->approval = emu->Approval;
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case BuyTraderItem: {
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_TributeItem)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
||||
@@ -2286,6 +2496,53 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_BazaarSearch)
|
||||
{
|
||||
uint32 action = *(uint32 *) __packet->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case structs::TiBazaarTraderBuyerActions::BazaarSearch: {
|
||||
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||
|
||||
emu->action = eq->Beginning.Action;
|
||||
emu->item_stat = eq->ItemStat;
|
||||
emu->max_cost = eq->MaxPrice;
|
||||
emu->min_cost = eq->MinPrice;
|
||||
emu->max_level = eq->MaxLlevel;
|
||||
emu->min_level = eq->Minlevel;
|
||||
emu->race = eq->Race;
|
||||
emu->slot = eq->Slot;
|
||||
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
|
||||
emu->trader_entity_id = eq->TraderID;
|
||||
emu->trader_id = 0;
|
||||
emu->_class = eq->Class_;
|
||||
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
|
||||
emu->max_results = RuleI(Bazaar, MaxSearchResults);
|
||||
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::TiBazaarTraderBuyerActions::BazaarInspect: {
|
||||
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||
|
||||
IN(action);
|
||||
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||
IN(serial_number);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::TiBazaarTraderBuyerActions::WelcomeMessage: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(Ti) Unhandled action <red>[{}]", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_Buff)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct);
|
||||
@@ -2310,7 +2567,7 @@ namespace Titanium
|
||||
DECODE_LENGTH_EXACT(structs::BugReport_Struct);
|
||||
SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct);
|
||||
|
||||
emu->category_id = EQ::bug::CategoryNameToCategoryID(eq->category_name);
|
||||
emu->category_id = Bug::GetID(eq->category_name);
|
||||
memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
@@ -2925,18 +3182,90 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Trader)
|
||||
{
|
||||
auto action = (uint32) __packet->pBuffer[0];
|
||||
|
||||
switch (action) {
|
||||
case structs::TiBazaarTraderBuyerActions::BeginTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||
LogTrading(
|
||||
"Decode OP_Trader BeginTraderMode action <red>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
emu->action = TraderOn;
|
||||
emu->unknown_004 = 0;
|
||||
std::copy_n(eq->serial_number, Titanium::invtype::BAZAAR_SIZE, emu->serial_number);
|
||||
std::copy_n(eq->cost, Titanium::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::TiBazaarTraderBuyerActions::EndTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Decode OP_Trader(Ti) EndTraderMode action <red>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
emu->action = TraderOff;
|
||||
IN(entity_id);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::TiBazaarTraderBuyerActions::PriceUpdate:
|
||||
case structs::TiBazaarTraderBuyerActions::ItemMove:
|
||||
case structs::TiBazaarTraderBuyerActions::EndTransaction:
|
||||
case structs::TiBazaarTraderBuyerActions::ListTraderItems: {
|
||||
LogTrading(
|
||||
"Decode OP_Trader(Ti) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
|
||||
action
|
||||
);
|
||||
break;
|
||||
}
|
||||
case structs::TiBazaarTraderBuyerActions::ReconcileItems: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogError("Unhandled(Ti) action <red>[{}] received.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_TraderBuy)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
MEMSET_IN(TraderBuy_Struct);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
IN(action);
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_TraderShop)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
LogTrading(
|
||||
"(Ti) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
|
||||
eq->action,
|
||||
eq->trader_id,
|
||||
eq->approval
|
||||
);
|
||||
|
||||
emu->Code = ClickTrader;
|
||||
emu->TraderID = eq->trader_id;
|
||||
emu->Approval = eq->approval;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ E(OP_TaskDescription)
|
||||
E(OP_Track)
|
||||
E(OP_Trader)
|
||||
E(OP_TraderBuy)
|
||||
E(OP_TraderShop)
|
||||
E(OP_TributeItem)
|
||||
E(OP_VetRewardsAvaliable)
|
||||
E(OP_WearChange)
|
||||
@@ -92,6 +93,7 @@ E(OP_ZoneSpawns)
|
||||
D(OP_AdventureMerchantSell)
|
||||
D(OP_ApplyPoison)
|
||||
D(OP_AugmentItem)
|
||||
D(OP_BazaarSearch)
|
||||
D(OP_Buff)
|
||||
D(OP_Bug)
|
||||
D(OP_CastSpell)
|
||||
@@ -123,7 +125,9 @@ D(OP_ReadBook)
|
||||
D(OP_SetServerFilter)
|
||||
D(OP_ShopPlayerSell)
|
||||
D(OP_ShopRequest)
|
||||
D(OP_Trader)
|
||||
D(OP_TraderBuy)
|
||||
D(OP_TraderShop)
|
||||
D(OP_TradeSkillCombine)
|
||||
D(OP_TributeItem)
|
||||
D(OP_WearChange)
|
||||
|
||||
@@ -2273,24 +2273,29 @@ struct BazaarWelcome_Struct {
|
||||
};
|
||||
|
||||
struct BazaarSearch_Struct {
|
||||
BazaarWindowStart_Struct beginning;
|
||||
uint32 traderid;
|
||||
uint32 class_;
|
||||
uint32 race;
|
||||
uint32 stat;
|
||||
uint32 slot;
|
||||
uint32 type;
|
||||
char name[64];
|
||||
uint32 minprice;
|
||||
uint32 maxprice;
|
||||
uint32 minlevel;
|
||||
uint32 maxlevel;
|
||||
BazaarWindowStart_Struct Beginning;
|
||||
uint32 TraderID;
|
||||
uint32 Class_;
|
||||
uint32 Race;
|
||||
uint32 ItemStat;
|
||||
uint32 Slot;
|
||||
uint32 Type;
|
||||
char Name[64];
|
||||
uint32 MinPrice;
|
||||
uint32 MaxPrice;
|
||||
uint32 Minlevel;
|
||||
uint32 MaxLlevel;
|
||||
};
|
||||
struct BazaarInspect_Struct{
|
||||
|
||||
struct BazaarInspect_Struct {
|
||||
uint32 action;
|
||||
char player_name[64];
|
||||
uint32 unknown_068;
|
||||
uint32 serial_number;
|
||||
uint32 unknown_076;
|
||||
uint32 item_id;
|
||||
uint32 unknown;
|
||||
char name[64];
|
||||
};
|
||||
|
||||
struct BazaarReturnDone_Struct{
|
||||
uint32 type;
|
||||
uint32 traderid;
|
||||
@@ -2298,16 +2303,17 @@ struct BazaarReturnDone_Struct{
|
||||
uint32 unknown12;
|
||||
uint32 unknown16;
|
||||
};
|
||||
|
||||
struct BazaarSearchResults_Struct {
|
||||
BazaarWindowStart_Struct Beginning;
|
||||
uint32 SellerID;
|
||||
uint32 NumItems; // Don't know. Don't know the significance of this field.
|
||||
uint32 SerialNumber;
|
||||
uint32 Unknown016;
|
||||
uint32 Unknown020; // Something to do with stats as well
|
||||
char ItemName[64];
|
||||
uint32 Cost;
|
||||
uint32 ItemStat;
|
||||
uint32 entity_id;
|
||||
uint32 unknown_008;
|
||||
uint32 item_id;
|
||||
uint32 serial_number;
|
||||
uint32 unknown_020;
|
||||
char item_name[64];
|
||||
uint32 item_cost;
|
||||
uint32 item_stat;
|
||||
};
|
||||
|
||||
struct ServerSideFilters_Struct {
|
||||
@@ -2454,11 +2460,18 @@ struct WhoAllReturnStruct {
|
||||
struct WhoAllPlayer player[0];
|
||||
};
|
||||
|
||||
struct BeginTrader_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown04;
|
||||
uint64 serial_number[80];
|
||||
uint32 cost[80];
|
||||
};
|
||||
|
||||
struct Trader_Struct {
|
||||
uint32 code;
|
||||
uint32 itemid[160];
|
||||
uint32 unknown;
|
||||
uint32 itemcost[80];
|
||||
uint32 action;
|
||||
uint32 unknown004;
|
||||
uint64 item_id[80];
|
||||
uint32 item_cost[80];
|
||||
};
|
||||
|
||||
struct ClickTrader_Struct {
|
||||
@@ -2471,27 +2484,28 @@ struct GetItems_Struct{
|
||||
uint32 items[80];
|
||||
};
|
||||
|
||||
struct BecomeTrader_Struct{
|
||||
uint32 ID;
|
||||
uint32 Code;
|
||||
struct BecomeTrader_Struct {
|
||||
uint32 entity_id;
|
||||
uint32 action;
|
||||
char trader_name[64];
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct{
|
||||
uint32 code;
|
||||
uint32 traderid;
|
||||
uint32 action;
|
||||
uint32 entity_id;
|
||||
uint32 unknown08[3];
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Price;
|
||||
/*008*/ uint32 TraderID;
|
||||
/*012*/ char ItemName[64];
|
||||
/*076*/ uint32 Unknown076;
|
||||
/*080*/ uint32 ItemID;
|
||||
/*084*/ uint32 AlreadySold;
|
||||
/*088*/ uint32 Quantity;
|
||||
/*092*/ uint32 Unknown092;
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 price;
|
||||
/*008*/ uint32 trader_id;
|
||||
/*012*/ char item_name[64];
|
||||
/*076*/ uint32 unknown_076;
|
||||
/*080*/ uint32 item_id;
|
||||
/*084*/ uint32 already_sold;
|
||||
/*088*/ uint32 quantity;
|
||||
/*092*/ uint32 unknown_092;
|
||||
};
|
||||
|
||||
|
||||
@@ -2517,8 +2531,9 @@ struct TraderDelItem_Struct{
|
||||
};
|
||||
|
||||
struct TraderClick_Struct{
|
||||
uint32 traderid;
|
||||
uint32 unknown4[2];
|
||||
uint32 trader_id;
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 approval;
|
||||
};
|
||||
|
||||
@@ -3744,6 +3759,21 @@ struct GuildMemberRank_Struct {
|
||||
/*076*/ uint32 alt_banker; //Banker/Alt bit 00 - none 10 - Alt 11 - Alt and Banker 01 - Banker. Banker not functional for RoF2+
|
||||
};
|
||||
|
||||
enum TiBazaarTraderBuyerActions {
|
||||
Zero = 0,
|
||||
BeginTraderMode = 1,
|
||||
EndTraderMode = 2,
|
||||
PriceUpdate = 3,
|
||||
EndTransaction = 4,
|
||||
BazaarSearch = 7,
|
||||
WelcomeMessage = 9,
|
||||
BuyTraderItem = 10,
|
||||
ListTraderItems = 11,
|
||||
BazaarInspect = 18,
|
||||
ItemMove = 19,
|
||||
ReconcileItems = 20
|
||||
};
|
||||
|
||||
}; /*structs*/
|
||||
|
||||
}; /*Titanium*/
|
||||
|
||||
+401
-69
@@ -37,6 +37,8 @@
|
||||
#include "../races.h"
|
||||
#include "../raid.h"
|
||||
#include "../guilds.h"
|
||||
//#include "../repositories/trader_repository.h"
|
||||
#include "../cereal/include/cereal/types/vector.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -307,50 +309,134 @@ namespace UF
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
char *Buffer = (char *)in->pBuffer;
|
||||
uint32 action = *(uint32 *)in->pBuffer;
|
||||
|
||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||
switch (action) {
|
||||
case BazaarSearch: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(UF) BazaarSearch action <green>[{}]",
|
||||
action
|
||||
);
|
||||
std::vector<BazaarSearchResultsFromDB_Struct> results {};
|
||||
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(bsms->payload),
|
||||
in->size - sizeof(BazaarSearchMessaging_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(results);
|
||||
|
||||
if (SubAction != BazaarSearchResults)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
auto size = results.size() * sizeof(BazaarSearchResults_Struct);
|
||||
auto buffer = new uchar[size];
|
||||
uchar *bufptr = buffer;
|
||||
memset(buffer, 0, size);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::UFBazaarTraderBuyerActions::BazaarSearch);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
|
||||
strn0cpy(reinterpret_cast<char *>(bufptr), row->trader_name.c_str(), 64);
|
||||
bufptr += 64;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
|
||||
bufptr += 4;
|
||||
if (row->stackable) {
|
||||
strn0cpy(
|
||||
reinterpret_cast<char *>(bufptr),
|
||||
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
|
||||
64
|
||||
);
|
||||
}
|
||||
else {
|
||||
strn0cpy(
|
||||
reinterpret_cast<char *>(bufptr),
|
||||
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
|
||||
64
|
||||
);
|
||||
}
|
||||
bufptr += 64;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
|
||||
memcpy(outapp->pBuffer, buffer, size);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete_array(buffer);
|
||||
safe_delete(in);
|
||||
break;
|
||||
}
|
||||
case BazaarInspect:
|
||||
case WelcomeMessage: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(UF) BazaarInspect/WelcomeMessage action <green>[{}]",
|
||||
action
|
||||
);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading(
|
||||
"Encode OP_BazaarSearch(UF) unhandled action <red>[{}]",
|
||||
action
|
||||
);
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
ENCODE(OP_BecomeTrader)
|
||||
{
|
||||
uint32 action = *(uint32 *)(*p)->pBuffer;
|
||||
|
||||
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
||||
|
||||
int EntryCount = in->size / sizeof(BazaarSearchResults_Struct);
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
switch (action)
|
||||
{
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
case TraderOff:
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(UF) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
|
||||
"<green>[{}]",
|
||||
emu->action,
|
||||
emu->entity_id,
|
||||
emu->trader_name
|
||||
);
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::Zero;
|
||||
eq->entity_id = emu->entity_id;
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderOn:
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
||||
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(UF) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
|
||||
"<green>[{}]",
|
||||
emu->action,
|
||||
emu->entity_id,
|
||||
emu->trader_name
|
||||
);
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
|
||||
eq->entity_id = emu->entity_id;
|
||||
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LogTrading(
|
||||
"Encode OP_BecomeTrader(UF) unhandled action <red>[{}] Sending packet as is.",
|
||||
action
|
||||
);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
}
|
||||
|
||||
in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct);
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
memset(in->pBuffer, 0, in->size);
|
||||
|
||||
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer;
|
||||
|
||||
for (int i = 0; i < EntryCount; ++i, ++emu, ++eq)
|
||||
{
|
||||
OUT(Beginning.Action);
|
||||
OUT(SellerID);
|
||||
memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
||||
OUT(NumItems);
|
||||
OUT(ItemID);
|
||||
OUT(SerialNumber);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(Cost);
|
||||
OUT(ItemStat);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Buff)
|
||||
@@ -2743,32 +2829,170 @@ namespace UF
|
||||
|
||||
ENCODE(OP_Trader)
|
||||
{
|
||||
if ((*p)->size != sizeof(TraderBuy_Struct)) {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
}
|
||||
auto action = *(uint32 *) (*p)->pBuffer;
|
||||
|
||||
ENCODE_FORWARD(OP_TraderBuy);
|
||||
switch (action) {
|
||||
case TraderOn: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader BeginTraderMode action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case TraderOff: {
|
||||
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader EndTraderMode action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::EndTraderMode;
|
||||
OUT(entity_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case ListTraderItems: {
|
||||
ENCODE_LENGTH_EXACT(Trader_Struct);
|
||||
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader ListTraderItems action <green>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::ListTraderItems;
|
||||
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
|
||||
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case BuyTraderItem: {
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case ItemMove: {
|
||||
LogTrading(
|
||||
"Encode OP_Trader ItemMove action <green>[{}]",
|
||||
action
|
||||
);
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderBuy)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
emu->item_id,
|
||||
emu->price,
|
||||
emu->quantity,
|
||||
emu->trader_id
|
||||
);
|
||||
|
||||
OUT(Action);
|
||||
OUT(Price);
|
||||
OUT(TraderID);
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(Quantity);
|
||||
OUT(AlreadySold);
|
||||
OUT(action);
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
OUT_str(item_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderShop)
|
||||
{
|
||||
auto action = *(uint32 *)(*p)->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case ClickTrader: {
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
LogTrading(
|
||||
"ClickTrader action <green>[{}] trader_id <green>[{}]",
|
||||
action,
|
||||
emu->TraderID
|
||||
);
|
||||
|
||||
eq->action = 0;
|
||||
eq->trader_id = emu->TraderID;
|
||||
eq->approval = emu->Approval;
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
case BuyTraderItem: {
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
|
||||
OUT(price);
|
||||
OUT(trader_id);
|
||||
OUT(item_id);
|
||||
OUT(already_sold);
|
||||
OUT(quantity);
|
||||
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_TributeItem)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
||||
@@ -3040,7 +3264,7 @@ namespace UF
|
||||
Bitfields->targetable = 1;
|
||||
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
||||
Bitfields->statue = 0;
|
||||
Bitfields->trader = 0;
|
||||
Bitfields->trader = emu->trader ? 1 : 0;
|
||||
Bitfields->buyer = 0;
|
||||
|
||||
Bitfields->showname = ShowName;
|
||||
@@ -3363,20 +3587,49 @@ namespace UF
|
||||
|
||||
DECODE(OP_BazaarSearch)
|
||||
{
|
||||
char *Buffer = (char *)__packet->pBuffer;
|
||||
uint32 action = *(uint32 *) __packet->pBuffer;
|
||||
|
||||
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||
switch (action) {
|
||||
case structs::UFBazaarTraderBuyerActions::BazaarSearch: {
|
||||
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
|
||||
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
|
||||
|
||||
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
|
||||
return;
|
||||
emu->action = eq->Beginning.Action;
|
||||
emu->item_stat = eq->ItemStat;
|
||||
emu->max_cost = eq->MaxPrice;
|
||||
emu->min_cost = eq->MinPrice;
|
||||
emu->max_level = eq->MaxLlevel;
|
||||
emu->min_level = eq->Minlevel;
|
||||
emu->race = eq->Race;
|
||||
emu->slot = eq->Slot;
|
||||
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
|
||||
emu->trader_entity_id = eq->TraderID;
|
||||
emu->trader_id = 0;
|
||||
emu->_class = eq->Class_;
|
||||
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
|
||||
emu->max_results = RuleI(Bazaar, MaxSearchResults);
|
||||
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
|
||||
|
||||
SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct);
|
||||
MEMSET_IN(structs::NewBazaarInspect_Struct);
|
||||
IN(Beginning.Action);
|
||||
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
||||
IN(SerialNumber);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::UFBazaarTraderBuyerActions::BazaarInspect: {
|
||||
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
IN(action);
|
||||
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
|
||||
IN(serial_number);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::UFBazaarTraderBuyerActions::WelcomeMessage: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("(UF) Unhandled action <red>[{}]", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_BookButton)
|
||||
@@ -4059,18 +4312,97 @@ namespace UF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Trader)
|
||||
{
|
||||
auto action = (uint32) __packet->pBuffer[0];
|
||||
|
||||
switch (action) {
|
||||
case structs::UFBazaarTraderBuyerActions::BeginTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
|
||||
LogTrading(
|
||||
"Decode OP_Trader BeginTraderMode action <red>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
emu->action = TraderOn;
|
||||
emu->unknown_004 = 0;
|
||||
std::copy_n(eq->serial_number, UF::invtype::BAZAAR_SIZE, emu->serial_number);
|
||||
std::copy_n(eq->cost, UF::invtype::BAZAAR_SIZE, emu->item_cost);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::UFBazaarTraderBuyerActions::EndTraderMode: {
|
||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||
LogTrading(
|
||||
"Decode OP_Trader(UF) EndTraderMode action <red>[{}]",
|
||||
action
|
||||
);
|
||||
|
||||
emu->action = TraderOff;
|
||||
IN(entity_id);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::UFBazaarTraderBuyerActions::PriceUpdate:
|
||||
case structs::UFBazaarTraderBuyerActions::ItemMove:
|
||||
case structs::UFBazaarTraderBuyerActions::EndTransaction:
|
||||
case structs::UFBazaarTraderBuyerActions::ListTraderItems: {
|
||||
LogTrading(
|
||||
"Decode OP_Trader(UF) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
|
||||
action
|
||||
);
|
||||
break;
|
||||
}
|
||||
case structs::UFBazaarTraderBuyerActions::ReconcileItems: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogError("Unhandled(UF) action <red>[{}] received.", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_TraderBuy)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
MEMSET_IN(TraderBuy_Struct);
|
||||
LogTrading(
|
||||
"Decode OP_TraderBuy(UF) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
|
||||
eq->item_id,
|
||||
eq->price,
|
||||
eq->quantity,
|
||||
eq->trader_id
|
||||
);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
emu->action = BuyTraderItem;
|
||||
IN(price);
|
||||
IN(trader_id);
|
||||
IN(item_id);
|
||||
IN(quantity);
|
||||
IN(already_sold);
|
||||
strn0cpy(emu->item_name, eq->item_name, sizeof(eq->item_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_TraderShop)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
LogTrading(
|
||||
"(UF) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
|
||||
eq->action,
|
||||
eq->trader_id,
|
||||
eq->approval
|
||||
);
|
||||
|
||||
emu->Code = ClickTrader;
|
||||
emu->TraderID = eq->trader_id;
|
||||
emu->Approval = eq->approval;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ E(OP_ApplyPoison)
|
||||
E(OP_AugmentInfo)
|
||||
E(OP_Barter)
|
||||
E(OP_BazaarSearch)
|
||||
E(OP_BecomeTrader)
|
||||
E(OP_Buff)
|
||||
E(OP_BuffCreate)
|
||||
E(OP_CancelTrade)
|
||||
@@ -100,6 +101,7 @@ E(OP_TaskDescription)
|
||||
E(OP_Track)
|
||||
E(OP_Trader)
|
||||
E(OP_TraderBuy)
|
||||
E(OP_TraderShop)
|
||||
E(OP_TributeItem)
|
||||
E(OP_VetRewardsAvaliable)
|
||||
E(OP_WearChange)
|
||||
@@ -160,7 +162,9 @@ D(OP_SetServerFilter)
|
||||
D(OP_ShopPlayerBuy)
|
||||
D(OP_ShopPlayerSell)
|
||||
D(OP_ShopRequest)
|
||||
D(OP_Trader)
|
||||
D(OP_TraderBuy)
|
||||
D(OP_TraderShop)
|
||||
D(OP_TradeSkillCombine)
|
||||
D(OP_TributeItem)
|
||||
D(OP_WearChange)
|
||||
|
||||
+75
-39
@@ -2640,23 +2640,23 @@ struct EnvDamage2_Struct {
|
||||
//Bazaar Stuff
|
||||
|
||||
enum {
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_StartTraderMode = 1,
|
||||
BazaarTrader_EndTraderMode = 2,
|
||||
BazaarTrader_UpdatePrice = 3,
|
||||
BazaarTrader_EndTransaction = 4,
|
||||
BazaarSearchResults = 7,
|
||||
BazaarWelcome = 9,
|
||||
BazaarBuyItem = 10,
|
||||
BazaarTrader_ShowItems = 11,
|
||||
BazaarSearchDone = 12,
|
||||
BazaarTrader_CustomerBrowsing = 13
|
||||
};
|
||||
|
||||
enum {
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_Fail = 0,
|
||||
BazaarPriceChange_UpdatePrice = 1,
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
BazaarPriceChange_RemoveItem = 2,
|
||||
BazaarPriceChange_AddItem = 3
|
||||
};
|
||||
|
||||
struct BazaarWindowStart_Struct {
|
||||
@@ -2687,10 +2687,14 @@ struct BazaarSearch_Struct {
|
||||
uint32 Minlevel;
|
||||
uint32 MaxLlevel;
|
||||
};
|
||||
struct BazaarInspect_Struct{
|
||||
uint32 ItemID;
|
||||
uint32 Unknown004;
|
||||
char Name[64];
|
||||
|
||||
struct BazaarInspect_Struct {
|
||||
uint32 action;
|
||||
char player_name[64];
|
||||
uint32 unknown_068;
|
||||
uint32 serial_number;
|
||||
uint32 unknown_076;
|
||||
uint32 item_id;
|
||||
};
|
||||
|
||||
struct NewBazaarInspect_Struct {
|
||||
@@ -2929,10 +2933,17 @@ struct WhoAllPlayerPart4 {
|
||||
};
|
||||
|
||||
struct Trader_Struct {
|
||||
uint32 code;
|
||||
uint32 itemid[160];
|
||||
uint32 unknown;
|
||||
uint32 itemcost[80];
|
||||
uint32 action;
|
||||
uint32 unknown004;
|
||||
uint64 item_id[80];
|
||||
uint32 item_cost[80];
|
||||
};
|
||||
|
||||
struct BeginTrader_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown04;
|
||||
uint64 serial_number[80];
|
||||
uint32 cost[80];
|
||||
};
|
||||
|
||||
struct ClickTrader_Struct {
|
||||
@@ -2945,30 +2956,30 @@ struct GetItems_Struct{
|
||||
uint32 items[80];
|
||||
};
|
||||
|
||||
struct BecomeTrader_Struct{
|
||||
uint32 id;
|
||||
uint32 code;
|
||||
struct BecomeTrader_Struct {
|
||||
uint32 entity_id;
|
||||
uint32 action;
|
||||
char trader_name[64];
|
||||
};
|
||||
|
||||
struct Trader_ShowItems_Struct{
|
||||
uint32 code;
|
||||
uint32 traderid;
|
||||
uint32 action;
|
||||
uint32 entity_id;
|
||||
uint32 unknown08[3];
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Price;
|
||||
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char ItemName[64];
|
||||
/*084*/ uint32 Unknown076;
|
||||
/*088*/ uint32 ItemID;
|
||||
/*092*/ uint32 AlreadySold;
|
||||
/*096*/ uint32 Quantity;
|
||||
/*100*/ uint32 Unknown092;
|
||||
/*104*/
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 price;
|
||||
uint32 unknown_008; // Probably high order bits of a 64 bit price.
|
||||
uint32 trader_id;
|
||||
char item_name[64];
|
||||
uint32 unknown_076;
|
||||
uint32 item_id;
|
||||
uint32 already_sold;
|
||||
uint32 quantity;
|
||||
uint32 unknown_092;
|
||||
};
|
||||
|
||||
struct TraderItemUpdate_Struct{
|
||||
@@ -3002,8 +3013,9 @@ struct TraderDelItem_Struct{
|
||||
};
|
||||
|
||||
struct TraderClick_Struct{
|
||||
uint32 traderid;
|
||||
uint32 unknown4[2];
|
||||
uint32 trader_id;
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 approval;
|
||||
};
|
||||
|
||||
@@ -4674,6 +4686,30 @@ struct SayLinkBodyFrame_Struct {
|
||||
/*050*/
|
||||
};
|
||||
|
||||
struct TraderPriceUpdate_Struct {
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ uint32 sub_action;
|
||||
/*008*/ int32 serial_number;
|
||||
/*012*/ uint32 unknown_012;
|
||||
/*016*/ uint32 new_price;
|
||||
/*020*/ uint32 unknown_016;
|
||||
};
|
||||
|
||||
enum UFBazaarTraderBuyerActions {
|
||||
Zero = 0,
|
||||
BeginTraderMode = 1,
|
||||
EndTraderMode = 2,
|
||||
PriceUpdate = 3,
|
||||
EndTransaction = 4,
|
||||
BazaarSearch = 7,
|
||||
WelcomeMessage = 9,
|
||||
BuyTraderItem = 10,
|
||||
ListTraderItems = 11,
|
||||
BazaarInspect = 18,
|
||||
ItemMove = 19,
|
||||
ReconcileItems = 20
|
||||
};
|
||||
|
||||
}; /*structs*/
|
||||
|
||||
}; /*UF*/
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
/**
|
||||
* 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_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
#define EQEMU_BASE_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseCharacterParcelsContainersRepository {
|
||||
public:
|
||||
struct CharacterParcelsContainers {
|
||||
uint32_t id;
|
||||
uint32_t parcels_id;
|
||||
uint32_t slot_id;
|
||||
uint32_t item_id;
|
||||
uint32_t aug_slot_1;
|
||||
uint32_t aug_slot_2;
|
||||
uint32_t aug_slot_3;
|
||||
uint32_t aug_slot_4;
|
||||
uint32_t aug_slot_5;
|
||||
uint32_t aug_slot_6;
|
||||
uint32_t quantity;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"parcels_id",
|
||||
"slot_id",
|
||||
"item_id",
|
||||
"aug_slot_1",
|
||||
"aug_slot_2",
|
||||
"aug_slot_3",
|
||||
"aug_slot_4",
|
||||
"aug_slot_5",
|
||||
"aug_slot_6",
|
||||
"quantity",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"parcels_id",
|
||||
"slot_id",
|
||||
"item_id",
|
||||
"aug_slot_1",
|
||||
"aug_slot_2",
|
||||
"aug_slot_3",
|
||||
"aug_slot_4",
|
||||
"aug_slot_5",
|
||||
"aug_slot_6",
|
||||
"quantity",
|
||||
};
|
||||
}
|
||||
|
||||
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_parcels_containers");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static CharacterParcelsContainers NewEntity()
|
||||
{
|
||||
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;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static CharacterParcelsContainers GetCharacterParcelsContainers(
|
||||
const std::vector<CharacterParcelsContainers> &character_parcels_containerss,
|
||||
int character_parcels_containers_id
|
||||
)
|
||||
{
|
||||
for (auto &character_parcels_containers : character_parcels_containerss) {
|
||||
if (character_parcels_containers.id == character_parcels_containers_id) {
|
||||
return character_parcels_containers;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static CharacterParcelsContainers FindOne(
|
||||
Database& db,
|
||||
int character_parcels_containers_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_parcels_containers_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
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;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int character_parcels_containers_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
character_parcels_containers_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const CharacterParcelsContainers &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.parcels_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.slot_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_1));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_2));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_3));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_4));
|
||||
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));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static CharacterParcelsContainers InsertOne(
|
||||
Database& db,
|
||||
CharacterParcelsContainers e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.parcels_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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));
|
||||
|
||||
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<CharacterParcelsContainers> &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.parcels_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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));
|
||||
|
||||
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<CharacterParcelsContainers> All(Database& db)
|
||||
{
|
||||
std::vector<CharacterParcelsContainers> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
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;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<CharacterParcelsContainers> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<CharacterParcelsContainers> 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) {
|
||||
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;
|
||||
|
||||
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 CharacterParcelsContainers &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.parcels_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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));
|
||||
|
||||
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<CharacterParcelsContainers> &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.parcels_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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));
|
||||
|
||||
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_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
@@ -19,18 +19,22 @@
|
||||
class BaseNpcSpellsEntriesRepository {
|
||||
public:
|
||||
struct NpcSpellsEntries {
|
||||
uint32_t id;
|
||||
int32_t npc_spells_id;
|
||||
uint16_t spellid;
|
||||
uint32_t type;
|
||||
uint8_t minlevel;
|
||||
uint8_t maxlevel;
|
||||
int16_t manacost;
|
||||
int32_t recast_delay;
|
||||
int16_t priority;
|
||||
int32_t resist_adjust;
|
||||
int16_t min_hp;
|
||||
int16_t max_hp;
|
||||
uint32_t id;
|
||||
int32_t npc_spells_id;
|
||||
uint16_t spellid;
|
||||
uint32_t type;
|
||||
uint8_t minlevel;
|
||||
uint8_t maxlevel;
|
||||
int16_t manacost;
|
||||
int32_t recast_delay;
|
||||
int16_t priority;
|
||||
int32_t resist_adjust;
|
||||
int16_t min_hp;
|
||||
int16_t max_hp;
|
||||
int8_t min_expansion;
|
||||
int8_t max_expansion;
|
||||
std::string content_flags;
|
||||
std::string content_flags_disabled;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -53,6 +57,10 @@ public:
|
||||
"resist_adjust",
|
||||
"min_hp",
|
||||
"max_hp",
|
||||
"min_expansion",
|
||||
"max_expansion",
|
||||
"content_flags",
|
||||
"content_flags_disabled",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,6 +79,10 @@ public:
|
||||
"resist_adjust",
|
||||
"min_hp",
|
||||
"max_hp",
|
||||
"min_expansion",
|
||||
"max_expansion",
|
||||
"content_flags",
|
||||
"content_flags_disabled",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,18 +123,22 @@ public:
|
||||
{
|
||||
NpcSpellsEntries e{};
|
||||
|
||||
e.id = 0;
|
||||
e.npc_spells_id = 0;
|
||||
e.spellid = 0;
|
||||
e.type = 0;
|
||||
e.minlevel = 0;
|
||||
e.maxlevel = 255;
|
||||
e.manacost = -1;
|
||||
e.recast_delay = -1;
|
||||
e.priority = 0;
|
||||
e.resist_adjust = 0;
|
||||
e.min_hp = 0;
|
||||
e.max_hp = 0;
|
||||
e.id = 0;
|
||||
e.npc_spells_id = 0;
|
||||
e.spellid = 0;
|
||||
e.type = 0;
|
||||
e.minlevel = 0;
|
||||
e.maxlevel = 255;
|
||||
e.manacost = -1;
|
||||
e.recast_delay = -1;
|
||||
e.priority = 0;
|
||||
e.resist_adjust = 0;
|
||||
e.min_hp = 0;
|
||||
e.max_hp = 0;
|
||||
e.min_expansion = -1;
|
||||
e.max_expansion = -1;
|
||||
e.content_flags = "";
|
||||
e.content_flags_disabled = "";
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -159,18 +175,22 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
NpcSpellsEntries e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
|
||||
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
|
||||
e.content_flags = row[14] ? row[14] : "";
|
||||
e.content_flags_disabled = row[15] ? row[15] : "";
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -215,6 +235,10 @@ public:
|
||||
v.push_back(columns[9] + " = " + std::to_string(e.resist_adjust));
|
||||
v.push_back(columns[10] + " = " + std::to_string(e.min_hp));
|
||||
v.push_back(columns[11] + " = " + std::to_string(e.max_hp));
|
||||
v.push_back(columns[12] + " = " + std::to_string(e.min_expansion));
|
||||
v.push_back(columns[13] + " = " + std::to_string(e.max_expansion));
|
||||
v.push_back(columns[14] + " = '" + Strings::Escape(e.content_flags) + "'");
|
||||
v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -248,6 +272,10 @@ public:
|
||||
v.push_back(std::to_string(e.resist_adjust));
|
||||
v.push_back(std::to_string(e.min_hp));
|
||||
v.push_back(std::to_string(e.max_hp));
|
||||
v.push_back(std::to_string(e.min_expansion));
|
||||
v.push_back(std::to_string(e.max_expansion));
|
||||
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.content_flags_disabled) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -289,6 +317,10 @@ public:
|
||||
v.push_back(std::to_string(e.resist_adjust));
|
||||
v.push_back(std::to_string(e.min_hp));
|
||||
v.push_back(std::to_string(e.max_hp));
|
||||
v.push_back(std::to_string(e.min_expansion));
|
||||
v.push_back(std::to_string(e.max_expansion));
|
||||
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.content_flags_disabled) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -322,18 +354,22 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
NpcSpellsEntries e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
|
||||
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
|
||||
e.content_flags = row[14] ? row[14] : "";
|
||||
e.content_flags_disabled = row[15] ? row[15] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -358,18 +394,22 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
NpcSpellsEntries e{};
|
||||
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
|
||||
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
|
||||
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
|
||||
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
|
||||
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
|
||||
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
|
||||
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
|
||||
e.content_flags = row[14] ? row[14] : "";
|
||||
e.content_flags_disabled = row[15] ? row[15] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -456,6 +496,10 @@ public:
|
||||
v.push_back(std::to_string(e.resist_adjust));
|
||||
v.push_back(std::to_string(e.min_hp));
|
||||
v.push_back(std::to_string(e.max_hp));
|
||||
v.push_back(std::to_string(e.min_expansion));
|
||||
v.push_back(std::to_string(e.max_expansion));
|
||||
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.content_flags_disabled) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -490,6 +534,10 @@ public:
|
||||
v.push_back(std::to_string(e.resist_adjust));
|
||||
v.push_back(std::to_string(e.min_hp));
|
||||
v.push_back(std::to_string(e.max_hp));
|
||||
v.push_back(std::to_string(e.min_expansion));
|
||||
v.push_back(std::to_string(e.max_expansion));
|
||||
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.content_flags_disabled) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
int64_t mana_regen_rate;
|
||||
uint32_t loottable_id;
|
||||
uint32_t merchant_id;
|
||||
uint8_t greed;
|
||||
uint32_t alt_currency_id;
|
||||
uint32_t npc_spells_id;
|
||||
uint32_t npc_spells_effects_id;
|
||||
@@ -176,6 +177,7 @@ public:
|
||||
"mana_regen_rate",
|
||||
"loottable_id",
|
||||
"merchant_id",
|
||||
"greed",
|
||||
"alt_currency_id",
|
||||
"npc_spells_id",
|
||||
"npc_spells_effects_id",
|
||||
@@ -310,6 +312,7 @@ public:
|
||||
"mana_regen_rate",
|
||||
"loottable_id",
|
||||
"merchant_id",
|
||||
"greed",
|
||||
"alt_currency_id",
|
||||
"npc_spells_id",
|
||||
"npc_spells_effects_id",
|
||||
@@ -478,6 +481,7 @@ public:
|
||||
e.mana_regen_rate = 0;
|
||||
e.loottable_id = 0;
|
||||
e.merchant_id = 0;
|
||||
e.greed = 0;
|
||||
e.alt_currency_id = 0;
|
||||
e.npc_spells_id = 0;
|
||||
e.npc_spells_effects_id = 0;
|
||||
@@ -642,115 +646,116 @@ public:
|
||||
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
|
||||
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
|
||||
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
|
||||
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
|
||||
e.npcspecialattks = row[28] ? row[28] : "";
|
||||
e.special_abilities = row[29] ? row[29] : "";
|
||||
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
|
||||
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
|
||||
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[48] ? row[48] : "IT10";
|
||||
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
|
||||
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
|
||||
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
|
||||
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
|
||||
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
|
||||
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
|
||||
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
|
||||
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
|
||||
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
|
||||
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
|
||||
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
|
||||
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
|
||||
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
|
||||
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
|
||||
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
|
||||
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
|
||||
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
|
||||
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
|
||||
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
|
||||
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
|
||||
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
|
||||
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
|
||||
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
|
||||
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
|
||||
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
|
||||
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
|
||||
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
|
||||
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
|
||||
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
|
||||
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
|
||||
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
|
||||
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
|
||||
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
|
||||
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
|
||||
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
|
||||
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
|
||||
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
|
||||
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
|
||||
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
|
||||
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
|
||||
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
|
||||
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
|
||||
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
|
||||
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
|
||||
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
|
||||
e.npcspecialattks = row[29] ? row[29] : "";
|
||||
e.special_abilities = row[30] ? row[30] : "";
|
||||
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
|
||||
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
|
||||
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[49] ? row[49] : "IT10";
|
||||
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
|
||||
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
|
||||
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
|
||||
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
|
||||
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
|
||||
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
|
||||
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
|
||||
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
|
||||
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
|
||||
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
|
||||
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
|
||||
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
|
||||
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
|
||||
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
|
||||
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
|
||||
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
|
||||
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
|
||||
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
|
||||
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
|
||||
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
|
||||
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
|
||||
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
|
||||
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
|
||||
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
|
||||
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
|
||||
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
|
||||
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
|
||||
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
|
||||
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
|
||||
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
|
||||
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
|
||||
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
|
||||
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
|
||||
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
|
||||
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
|
||||
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
|
||||
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
|
||||
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
|
||||
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
|
||||
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
|
||||
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
|
||||
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
|
||||
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -802,115 +807,116 @@ public:
|
||||
v.push_back(columns[16] + " = " + std::to_string(e.mana_regen_rate));
|
||||
v.push_back(columns[17] + " = " + std::to_string(e.loottable_id));
|
||||
v.push_back(columns[18] + " = " + std::to_string(e.merchant_id));
|
||||
v.push_back(columns[19] + " = " + std::to_string(e.alt_currency_id));
|
||||
v.push_back(columns[20] + " = " + std::to_string(e.npc_spells_id));
|
||||
v.push_back(columns[21] + " = " + std::to_string(e.npc_spells_effects_id));
|
||||
v.push_back(columns[22] + " = " + std::to_string(e.npc_faction_id));
|
||||
v.push_back(columns[23] + " = " + std::to_string(e.adventure_template_id));
|
||||
v.push_back(columns[24] + " = " + std::to_string(e.trap_template));
|
||||
v.push_back(columns[25] + " = " + std::to_string(e.mindmg));
|
||||
v.push_back(columns[26] + " = " + std::to_string(e.maxdmg));
|
||||
v.push_back(columns[27] + " = " + std::to_string(e.attack_count));
|
||||
v.push_back(columns[28] + " = '" + Strings::Escape(e.npcspecialattks) + "'");
|
||||
v.push_back(columns[29] + " = '" + Strings::Escape(e.special_abilities) + "'");
|
||||
v.push_back(columns[30] + " = " + std::to_string(e.aggroradius));
|
||||
v.push_back(columns[31] + " = " + std::to_string(e.assistradius));
|
||||
v.push_back(columns[32] + " = " + std::to_string(e.face));
|
||||
v.push_back(columns[33] + " = " + std::to_string(e.luclin_hairstyle));
|
||||
v.push_back(columns[34] + " = " + std::to_string(e.luclin_haircolor));
|
||||
v.push_back(columns[35] + " = " + std::to_string(e.luclin_eyecolor));
|
||||
v.push_back(columns[36] + " = " + std::to_string(e.luclin_eyecolor2));
|
||||
v.push_back(columns[37] + " = " + std::to_string(e.luclin_beardcolor));
|
||||
v.push_back(columns[38] + " = " + std::to_string(e.luclin_beard));
|
||||
v.push_back(columns[39] + " = " + std::to_string(e.drakkin_heritage));
|
||||
v.push_back(columns[40] + " = " + std::to_string(e.drakkin_tattoo));
|
||||
v.push_back(columns[41] + " = " + std::to_string(e.drakkin_details));
|
||||
v.push_back(columns[42] + " = " + std::to_string(e.armortint_id));
|
||||
v.push_back(columns[43] + " = " + std::to_string(e.armortint_red));
|
||||
v.push_back(columns[44] + " = " + std::to_string(e.armortint_green));
|
||||
v.push_back(columns[45] + " = " + std::to_string(e.armortint_blue));
|
||||
v.push_back(columns[46] + " = " + std::to_string(e.d_melee_texture1));
|
||||
v.push_back(columns[47] + " = " + std::to_string(e.d_melee_texture2));
|
||||
v.push_back(columns[48] + " = '" + Strings::Escape(e.ammo_idfile) + "'");
|
||||
v.push_back(columns[49] + " = " + std::to_string(e.prim_melee_type));
|
||||
v.push_back(columns[50] + " = " + std::to_string(e.sec_melee_type));
|
||||
v.push_back(columns[51] + " = " + std::to_string(e.ranged_type));
|
||||
v.push_back(columns[52] + " = " + std::to_string(e.runspeed));
|
||||
v.push_back(columns[53] + " = " + std::to_string(e.MR));
|
||||
v.push_back(columns[54] + " = " + std::to_string(e.CR));
|
||||
v.push_back(columns[55] + " = " + std::to_string(e.DR));
|
||||
v.push_back(columns[56] + " = " + std::to_string(e.FR));
|
||||
v.push_back(columns[57] + " = " + std::to_string(e.PR));
|
||||
v.push_back(columns[58] + " = " + std::to_string(e.Corrup));
|
||||
v.push_back(columns[59] + " = " + std::to_string(e.PhR));
|
||||
v.push_back(columns[60] + " = " + std::to_string(e.see_invis));
|
||||
v.push_back(columns[61] + " = " + std::to_string(e.see_invis_undead));
|
||||
v.push_back(columns[62] + " = " + std::to_string(e.qglobal));
|
||||
v.push_back(columns[63] + " = " + std::to_string(e.AC));
|
||||
v.push_back(columns[64] + " = " + std::to_string(e.npc_aggro));
|
||||
v.push_back(columns[65] + " = " + std::to_string(e.spawn_limit));
|
||||
v.push_back(columns[66] + " = " + std::to_string(e.attack_speed));
|
||||
v.push_back(columns[67] + " = " + std::to_string(e.attack_delay));
|
||||
v.push_back(columns[68] + " = " + std::to_string(e.findable));
|
||||
v.push_back(columns[69] + " = " + std::to_string(e.STR));
|
||||
v.push_back(columns[70] + " = " + std::to_string(e.STA));
|
||||
v.push_back(columns[71] + " = " + std::to_string(e.DEX));
|
||||
v.push_back(columns[72] + " = " + std::to_string(e.AGI));
|
||||
v.push_back(columns[73] + " = " + std::to_string(e._INT));
|
||||
v.push_back(columns[74] + " = " + std::to_string(e.WIS));
|
||||
v.push_back(columns[75] + " = " + std::to_string(e.CHA));
|
||||
v.push_back(columns[76] + " = " + std::to_string(e.see_hide));
|
||||
v.push_back(columns[77] + " = " + std::to_string(e.see_improved_hide));
|
||||
v.push_back(columns[78] + " = " + std::to_string(e.trackable));
|
||||
v.push_back(columns[79] + " = " + std::to_string(e.isbot));
|
||||
v.push_back(columns[80] + " = " + std::to_string(e.exclude));
|
||||
v.push_back(columns[81] + " = " + std::to_string(e.ATK));
|
||||
v.push_back(columns[82] + " = " + std::to_string(e.Accuracy));
|
||||
v.push_back(columns[83] + " = " + std::to_string(e.Avoidance));
|
||||
v.push_back(columns[84] + " = " + std::to_string(e.slow_mitigation));
|
||||
v.push_back(columns[85] + " = " + std::to_string(e.version));
|
||||
v.push_back(columns[86] + " = " + std::to_string(e.maxlevel));
|
||||
v.push_back(columns[87] + " = " + std::to_string(e.scalerate));
|
||||
v.push_back(columns[88] + " = " + std::to_string(e.private_corpse));
|
||||
v.push_back(columns[89] + " = " + std::to_string(e.unique_spawn_by_name));
|
||||
v.push_back(columns[90] + " = " + std::to_string(e.underwater));
|
||||
v.push_back(columns[91] + " = " + std::to_string(e.isquest));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.emoteid));
|
||||
v.push_back(columns[93] + " = " + std::to_string(e.spellscale));
|
||||
v.push_back(columns[94] + " = " + std::to_string(e.healscale));
|
||||
v.push_back(columns[95] + " = " + std::to_string(e.no_target_hotkey));
|
||||
v.push_back(columns[96] + " = " + std::to_string(e.raid_target));
|
||||
v.push_back(columns[97] + " = " + std::to_string(e.armtexture));
|
||||
v.push_back(columns[98] + " = " + std::to_string(e.bracertexture));
|
||||
v.push_back(columns[99] + " = " + std::to_string(e.handtexture));
|
||||
v.push_back(columns[100] + " = " + std::to_string(e.legtexture));
|
||||
v.push_back(columns[101] + " = " + std::to_string(e.feettexture));
|
||||
v.push_back(columns[102] + " = " + std::to_string(e.light));
|
||||
v.push_back(columns[103] + " = " + std::to_string(e.walkspeed));
|
||||
v.push_back(columns[104] + " = " + std::to_string(e.peqid));
|
||||
v.push_back(columns[105] + " = " + std::to_string(e.unique_));
|
||||
v.push_back(columns[106] + " = " + std::to_string(e.fixed));
|
||||
v.push_back(columns[107] + " = " + std::to_string(e.ignore_despawn));
|
||||
v.push_back(columns[108] + " = " + std::to_string(e.show_name));
|
||||
v.push_back(columns[109] + " = " + std::to_string(e.untargetable));
|
||||
v.push_back(columns[110] + " = " + std::to_string(e.charm_ac));
|
||||
v.push_back(columns[111] + " = " + std::to_string(e.charm_min_dmg));
|
||||
v.push_back(columns[112] + " = " + std::to_string(e.charm_max_dmg));
|
||||
v.push_back(columns[113] + " = " + std::to_string(e.charm_attack_delay));
|
||||
v.push_back(columns[114] + " = " + std::to_string(e.charm_accuracy_rating));
|
||||
v.push_back(columns[115] + " = " + std::to_string(e.charm_avoidance_rating));
|
||||
v.push_back(columns[116] + " = " + std::to_string(e.charm_atk));
|
||||
v.push_back(columns[117] + " = " + std::to_string(e.skip_global_loot));
|
||||
v.push_back(columns[118] + " = " + std::to_string(e.rare_spawn));
|
||||
v.push_back(columns[119] + " = " + std::to_string(e.stuck_behavior));
|
||||
v.push_back(columns[120] + " = " + std::to_string(e.model));
|
||||
v.push_back(columns[121] + " = " + std::to_string(e.flymode));
|
||||
v.push_back(columns[122] + " = " + std::to_string(e.always_aggro));
|
||||
v.push_back(columns[123] + " = " + std::to_string(e.exp_mod));
|
||||
v.push_back(columns[124] + " = " + std::to_string(e.heroic_strikethrough));
|
||||
v.push_back(columns[125] + " = " + std::to_string(e.faction_amount));
|
||||
v.push_back(columns[126] + " = " + std::to_string(e.keeps_sold_items));
|
||||
v.push_back(columns[127] + " = " + std::to_string(e.is_parcel_merchant));
|
||||
v.push_back(columns[19] + " = " + std::to_string(e.greed));
|
||||
v.push_back(columns[20] + " = " + std::to_string(e.alt_currency_id));
|
||||
v.push_back(columns[21] + " = " + std::to_string(e.npc_spells_id));
|
||||
v.push_back(columns[22] + " = " + std::to_string(e.npc_spells_effects_id));
|
||||
v.push_back(columns[23] + " = " + std::to_string(e.npc_faction_id));
|
||||
v.push_back(columns[24] + " = " + std::to_string(e.adventure_template_id));
|
||||
v.push_back(columns[25] + " = " + std::to_string(e.trap_template));
|
||||
v.push_back(columns[26] + " = " + std::to_string(e.mindmg));
|
||||
v.push_back(columns[27] + " = " + std::to_string(e.maxdmg));
|
||||
v.push_back(columns[28] + " = " + std::to_string(e.attack_count));
|
||||
v.push_back(columns[29] + " = '" + Strings::Escape(e.npcspecialattks) + "'");
|
||||
v.push_back(columns[30] + " = '" + Strings::Escape(e.special_abilities) + "'");
|
||||
v.push_back(columns[31] + " = " + std::to_string(e.aggroradius));
|
||||
v.push_back(columns[32] + " = " + std::to_string(e.assistradius));
|
||||
v.push_back(columns[33] + " = " + std::to_string(e.face));
|
||||
v.push_back(columns[34] + " = " + std::to_string(e.luclin_hairstyle));
|
||||
v.push_back(columns[35] + " = " + std::to_string(e.luclin_haircolor));
|
||||
v.push_back(columns[36] + " = " + std::to_string(e.luclin_eyecolor));
|
||||
v.push_back(columns[37] + " = " + std::to_string(e.luclin_eyecolor2));
|
||||
v.push_back(columns[38] + " = " + std::to_string(e.luclin_beardcolor));
|
||||
v.push_back(columns[39] + " = " + std::to_string(e.luclin_beard));
|
||||
v.push_back(columns[40] + " = " + std::to_string(e.drakkin_heritage));
|
||||
v.push_back(columns[41] + " = " + std::to_string(e.drakkin_tattoo));
|
||||
v.push_back(columns[42] + " = " + std::to_string(e.drakkin_details));
|
||||
v.push_back(columns[43] + " = " + std::to_string(e.armortint_id));
|
||||
v.push_back(columns[44] + " = " + std::to_string(e.armortint_red));
|
||||
v.push_back(columns[45] + " = " + std::to_string(e.armortint_green));
|
||||
v.push_back(columns[46] + " = " + std::to_string(e.armortint_blue));
|
||||
v.push_back(columns[47] + " = " + std::to_string(e.d_melee_texture1));
|
||||
v.push_back(columns[48] + " = " + std::to_string(e.d_melee_texture2));
|
||||
v.push_back(columns[49] + " = '" + Strings::Escape(e.ammo_idfile) + "'");
|
||||
v.push_back(columns[50] + " = " + std::to_string(e.prim_melee_type));
|
||||
v.push_back(columns[51] + " = " + std::to_string(e.sec_melee_type));
|
||||
v.push_back(columns[52] + " = " + std::to_string(e.ranged_type));
|
||||
v.push_back(columns[53] + " = " + std::to_string(e.runspeed));
|
||||
v.push_back(columns[54] + " = " + std::to_string(e.MR));
|
||||
v.push_back(columns[55] + " = " + std::to_string(e.CR));
|
||||
v.push_back(columns[56] + " = " + std::to_string(e.DR));
|
||||
v.push_back(columns[57] + " = " + std::to_string(e.FR));
|
||||
v.push_back(columns[58] + " = " + std::to_string(e.PR));
|
||||
v.push_back(columns[59] + " = " + std::to_string(e.Corrup));
|
||||
v.push_back(columns[60] + " = " + std::to_string(e.PhR));
|
||||
v.push_back(columns[61] + " = " + std::to_string(e.see_invis));
|
||||
v.push_back(columns[62] + " = " + std::to_string(e.see_invis_undead));
|
||||
v.push_back(columns[63] + " = " + std::to_string(e.qglobal));
|
||||
v.push_back(columns[64] + " = " + std::to_string(e.AC));
|
||||
v.push_back(columns[65] + " = " + std::to_string(e.npc_aggro));
|
||||
v.push_back(columns[66] + " = " + std::to_string(e.spawn_limit));
|
||||
v.push_back(columns[67] + " = " + std::to_string(e.attack_speed));
|
||||
v.push_back(columns[68] + " = " + std::to_string(e.attack_delay));
|
||||
v.push_back(columns[69] + " = " + std::to_string(e.findable));
|
||||
v.push_back(columns[70] + " = " + std::to_string(e.STR));
|
||||
v.push_back(columns[71] + " = " + std::to_string(e.STA));
|
||||
v.push_back(columns[72] + " = " + std::to_string(e.DEX));
|
||||
v.push_back(columns[73] + " = " + std::to_string(e.AGI));
|
||||
v.push_back(columns[74] + " = " + std::to_string(e._INT));
|
||||
v.push_back(columns[75] + " = " + std::to_string(e.WIS));
|
||||
v.push_back(columns[76] + " = " + std::to_string(e.CHA));
|
||||
v.push_back(columns[77] + " = " + std::to_string(e.see_hide));
|
||||
v.push_back(columns[78] + " = " + std::to_string(e.see_improved_hide));
|
||||
v.push_back(columns[79] + " = " + std::to_string(e.trackable));
|
||||
v.push_back(columns[80] + " = " + std::to_string(e.isbot));
|
||||
v.push_back(columns[81] + " = " + std::to_string(e.exclude));
|
||||
v.push_back(columns[82] + " = " + std::to_string(e.ATK));
|
||||
v.push_back(columns[83] + " = " + std::to_string(e.Accuracy));
|
||||
v.push_back(columns[84] + " = " + std::to_string(e.Avoidance));
|
||||
v.push_back(columns[85] + " = " + std::to_string(e.slow_mitigation));
|
||||
v.push_back(columns[86] + " = " + std::to_string(e.version));
|
||||
v.push_back(columns[87] + " = " + std::to_string(e.maxlevel));
|
||||
v.push_back(columns[88] + " = " + std::to_string(e.scalerate));
|
||||
v.push_back(columns[89] + " = " + std::to_string(e.private_corpse));
|
||||
v.push_back(columns[90] + " = " + std::to_string(e.unique_spawn_by_name));
|
||||
v.push_back(columns[91] + " = " + std::to_string(e.underwater));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.isquest));
|
||||
v.push_back(columns[93] + " = " + std::to_string(e.emoteid));
|
||||
v.push_back(columns[94] + " = " + std::to_string(e.spellscale));
|
||||
v.push_back(columns[95] + " = " + std::to_string(e.healscale));
|
||||
v.push_back(columns[96] + " = " + std::to_string(e.no_target_hotkey));
|
||||
v.push_back(columns[97] + " = " + std::to_string(e.raid_target));
|
||||
v.push_back(columns[98] + " = " + std::to_string(e.armtexture));
|
||||
v.push_back(columns[99] + " = " + std::to_string(e.bracertexture));
|
||||
v.push_back(columns[100] + " = " + std::to_string(e.handtexture));
|
||||
v.push_back(columns[101] + " = " + std::to_string(e.legtexture));
|
||||
v.push_back(columns[102] + " = " + std::to_string(e.feettexture));
|
||||
v.push_back(columns[103] + " = " + std::to_string(e.light));
|
||||
v.push_back(columns[104] + " = " + std::to_string(e.walkspeed));
|
||||
v.push_back(columns[105] + " = " + std::to_string(e.peqid));
|
||||
v.push_back(columns[106] + " = " + std::to_string(e.unique_));
|
||||
v.push_back(columns[107] + " = " + std::to_string(e.fixed));
|
||||
v.push_back(columns[108] + " = " + std::to_string(e.ignore_despawn));
|
||||
v.push_back(columns[109] + " = " + std::to_string(e.show_name));
|
||||
v.push_back(columns[110] + " = " + std::to_string(e.untargetable));
|
||||
v.push_back(columns[111] + " = " + std::to_string(e.charm_ac));
|
||||
v.push_back(columns[112] + " = " + std::to_string(e.charm_min_dmg));
|
||||
v.push_back(columns[113] + " = " + std::to_string(e.charm_max_dmg));
|
||||
v.push_back(columns[114] + " = " + std::to_string(e.charm_attack_delay));
|
||||
v.push_back(columns[115] + " = " + std::to_string(e.charm_accuracy_rating));
|
||||
v.push_back(columns[116] + " = " + std::to_string(e.charm_avoidance_rating));
|
||||
v.push_back(columns[117] + " = " + std::to_string(e.charm_atk));
|
||||
v.push_back(columns[118] + " = " + std::to_string(e.skip_global_loot));
|
||||
v.push_back(columns[119] + " = " + std::to_string(e.rare_spawn));
|
||||
v.push_back(columns[120] + " = " + std::to_string(e.stuck_behavior));
|
||||
v.push_back(columns[121] + " = " + std::to_string(e.model));
|
||||
v.push_back(columns[122] + " = " + std::to_string(e.flymode));
|
||||
v.push_back(columns[123] + " = " + std::to_string(e.always_aggro));
|
||||
v.push_back(columns[124] + " = " + std::to_string(e.exp_mod));
|
||||
v.push_back(columns[125] + " = " + std::to_string(e.heroic_strikethrough));
|
||||
v.push_back(columns[126] + " = " + std::to_string(e.faction_amount));
|
||||
v.push_back(columns[127] + " = " + std::to_string(e.keeps_sold_items));
|
||||
v.push_back(columns[128] + " = " + std::to_string(e.is_parcel_merchant));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -951,6 +957,7 @@ public:
|
||||
v.push_back(std::to_string(e.mana_regen_rate));
|
||||
v.push_back(std::to_string(e.loottable_id));
|
||||
v.push_back(std::to_string(e.merchant_id));
|
||||
v.push_back(std::to_string(e.greed));
|
||||
v.push_back(std::to_string(e.alt_currency_id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.npc_spells_effects_id));
|
||||
@@ -1108,6 +1115,7 @@ public:
|
||||
v.push_back(std::to_string(e.mana_regen_rate));
|
||||
v.push_back(std::to_string(e.loottable_id));
|
||||
v.push_back(std::to_string(e.merchant_id));
|
||||
v.push_back(std::to_string(e.greed));
|
||||
v.push_back(std::to_string(e.alt_currency_id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.npc_spells_effects_id));
|
||||
@@ -1269,115 +1277,116 @@ public:
|
||||
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
|
||||
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
|
||||
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
|
||||
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
|
||||
e.npcspecialattks = row[28] ? row[28] : "";
|
||||
e.special_abilities = row[29] ? row[29] : "";
|
||||
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
|
||||
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
|
||||
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[48] ? row[48] : "IT10";
|
||||
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
|
||||
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
|
||||
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
|
||||
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
|
||||
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
|
||||
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
|
||||
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
|
||||
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
|
||||
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
|
||||
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
|
||||
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
|
||||
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
|
||||
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
|
||||
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
|
||||
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
|
||||
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
|
||||
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
|
||||
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
|
||||
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
|
||||
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
|
||||
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
|
||||
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
|
||||
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
|
||||
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
|
||||
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
|
||||
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
|
||||
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
|
||||
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
|
||||
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
|
||||
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
|
||||
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
|
||||
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
|
||||
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
|
||||
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
|
||||
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
|
||||
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
|
||||
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
|
||||
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
|
||||
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
|
||||
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
|
||||
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
|
||||
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
|
||||
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
|
||||
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
|
||||
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
|
||||
e.npcspecialattks = row[29] ? row[29] : "";
|
||||
e.special_abilities = row[30] ? row[30] : "";
|
||||
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
|
||||
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
|
||||
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[49] ? row[49] : "IT10";
|
||||
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
|
||||
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
|
||||
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
|
||||
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
|
||||
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
|
||||
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
|
||||
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
|
||||
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
|
||||
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
|
||||
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
|
||||
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
|
||||
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
|
||||
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
|
||||
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
|
||||
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
|
||||
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
|
||||
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
|
||||
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
|
||||
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
|
||||
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
|
||||
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
|
||||
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
|
||||
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
|
||||
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
|
||||
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
|
||||
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
|
||||
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
|
||||
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
|
||||
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
|
||||
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
|
||||
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
|
||||
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
|
||||
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
|
||||
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
|
||||
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
|
||||
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
|
||||
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
|
||||
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
|
||||
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
|
||||
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
|
||||
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
|
||||
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
|
||||
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -1421,115 +1430,116 @@ public:
|
||||
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
|
||||
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
|
||||
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
|
||||
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
|
||||
e.npcspecialattks = row[28] ? row[28] : "";
|
||||
e.special_abilities = row[29] ? row[29] : "";
|
||||
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
|
||||
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
|
||||
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[48] ? row[48] : "IT10";
|
||||
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
|
||||
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
|
||||
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
|
||||
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
|
||||
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
|
||||
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
|
||||
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
|
||||
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
|
||||
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
|
||||
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
|
||||
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
|
||||
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
|
||||
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
|
||||
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
|
||||
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
|
||||
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
|
||||
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
|
||||
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
|
||||
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
|
||||
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
|
||||
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
|
||||
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
|
||||
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
|
||||
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
|
||||
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
|
||||
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
|
||||
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
|
||||
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
|
||||
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
|
||||
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
|
||||
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
|
||||
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
|
||||
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
|
||||
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
|
||||
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
|
||||
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
|
||||
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
|
||||
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
|
||||
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
|
||||
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
|
||||
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
|
||||
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
|
||||
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
|
||||
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
|
||||
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
|
||||
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
|
||||
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
|
||||
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
|
||||
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
|
||||
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
|
||||
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
|
||||
e.npcspecialattks = row[29] ? row[29] : "";
|
||||
e.special_abilities = row[30] ? row[30] : "";
|
||||
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
|
||||
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
|
||||
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
|
||||
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
|
||||
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
|
||||
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
|
||||
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
|
||||
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
|
||||
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
|
||||
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
|
||||
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
|
||||
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
|
||||
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
|
||||
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
|
||||
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
|
||||
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
|
||||
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
|
||||
e.ammo_idfile = row[49] ? row[49] : "IT10";
|
||||
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
|
||||
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
|
||||
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
|
||||
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
|
||||
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
|
||||
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
|
||||
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
|
||||
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
|
||||
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
|
||||
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
|
||||
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
|
||||
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
|
||||
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
|
||||
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
|
||||
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
|
||||
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
|
||||
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
|
||||
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
|
||||
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
|
||||
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
|
||||
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
|
||||
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
|
||||
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
|
||||
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
|
||||
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
|
||||
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
|
||||
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
|
||||
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
|
||||
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
|
||||
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
|
||||
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
|
||||
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
|
||||
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
|
||||
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
|
||||
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
|
||||
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
|
||||
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
|
||||
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
|
||||
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
|
||||
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
|
||||
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
|
||||
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
|
||||
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
|
||||
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
|
||||
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
|
||||
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
|
||||
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
|
||||
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
|
||||
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
|
||||
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
|
||||
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
|
||||
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
|
||||
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
|
||||
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
|
||||
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
|
||||
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
|
||||
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
|
||||
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
|
||||
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
|
||||
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
|
||||
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
|
||||
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
|
||||
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
|
||||
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
|
||||
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
|
||||
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
|
||||
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
|
||||
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
|
||||
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
|
||||
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
|
||||
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
|
||||
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
|
||||
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
|
||||
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
|
||||
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
|
||||
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
|
||||
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
|
||||
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
|
||||
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -1623,6 +1633,7 @@ public:
|
||||
v.push_back(std::to_string(e.mana_regen_rate));
|
||||
v.push_back(std::to_string(e.loottable_id));
|
||||
v.push_back(std::to_string(e.merchant_id));
|
||||
v.push_back(std::to_string(e.greed));
|
||||
v.push_back(std::to_string(e.alt_currency_id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.npc_spells_effects_id));
|
||||
@@ -1773,6 +1784,7 @@ public:
|
||||
v.push_back(std::to_string(e.mana_regen_rate));
|
||||
v.push_back(std::to_string(e.loottable_id));
|
||||
v.push_back(std::to_string(e.merchant_id));
|
||||
v.push_back(std::to_string(e.greed));
|
||||
v.push_back(std::to_string(e.alt_currency_id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.npc_spells_effects_id));
|
||||
|
||||
@@ -19,40 +19,70 @@
|
||||
class BaseTraderRepository {
|
||||
public:
|
||||
struct Trader {
|
||||
uint64_t id;
|
||||
uint32_t char_id;
|
||||
uint32_t item_id;
|
||||
uint32_t serialnumber;
|
||||
int32_t charges;
|
||||
uint32_t item_cost;
|
||||
uint32_t aug_slot_1;
|
||||
uint32_t aug_slot_2;
|
||||
uint32_t aug_slot_3;
|
||||
uint32_t aug_slot_4;
|
||||
uint32_t aug_slot_5;
|
||||
uint32_t aug_slot_6;
|
||||
int32_t item_sn;
|
||||
int32_t item_charges;
|
||||
uint64_t item_cost;
|
||||
uint8_t slot_id;
|
||||
uint32_t char_entity_id;
|
||||
uint32_t char_zone_id;
|
||||
int8_t active_transaction;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("char_id");
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"char_id",
|
||||
"item_id",
|
||||
"serialnumber",
|
||||
"charges",
|
||||
"aug_slot_1",
|
||||
"aug_slot_2",
|
||||
"aug_slot_3",
|
||||
"aug_slot_4",
|
||||
"aug_slot_5",
|
||||
"aug_slot_6",
|
||||
"item_sn",
|
||||
"item_charges",
|
||||
"item_cost",
|
||||
"slot_id",
|
||||
"char_entity_id",
|
||||
"char_zone_id",
|
||||
"active_transaction",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"char_id",
|
||||
"item_id",
|
||||
"serialnumber",
|
||||
"charges",
|
||||
"aug_slot_1",
|
||||
"aug_slot_2",
|
||||
"aug_slot_3",
|
||||
"aug_slot_4",
|
||||
"aug_slot_5",
|
||||
"aug_slot_6",
|
||||
"item_sn",
|
||||
"item_charges",
|
||||
"item_cost",
|
||||
"slot_id",
|
||||
"char_entity_id",
|
||||
"char_zone_id",
|
||||
"active_transaction",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,12 +123,22 @@ public:
|
||||
{
|
||||
Trader e{};
|
||||
|
||||
e.char_id = 0;
|
||||
e.item_id = 0;
|
||||
e.serialnumber = 0;
|
||||
e.charges = 0;
|
||||
e.item_cost = 0;
|
||||
e.slot_id = 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.item_sn = 0;
|
||||
e.item_charges = 0;
|
||||
e.item_cost = 0;
|
||||
e.slot_id = 0;
|
||||
e.char_entity_id = 0;
|
||||
e.char_zone_id = 0;
|
||||
e.active_transaction = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -109,7 +149,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &trader : traders) {
|
||||
if (trader.char_id == trader_id) {
|
||||
if (trader.id == trader_id) {
|
||||
return trader;
|
||||
}
|
||||
}
|
||||
@@ -135,12 +175,22 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
Trader e{};
|
||||
|
||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? strtoull(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.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -174,12 +224,21 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.char_id));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.serialnumber));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.charges));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.item_cost));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.slot_id));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.aug_slot_1));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_2));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_3));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
|
||||
v.push_back(columns[9] + " = " + std::to_string(e.item_sn));
|
||||
v.push_back(columns[10] + " = " + std::to_string(e.item_charges));
|
||||
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
|
||||
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
||||
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
|
||||
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
|
||||
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -187,7 +246,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.char_id
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -201,12 +260,22 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.serialnumber));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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.item_sn));
|
||||
v.push_back(std::to_string(e.item_charges));
|
||||
v.push_back(std::to_string(e.item_cost));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.active_transaction));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -217,7 +286,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.char_id = results.LastInsertedID();
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -236,12 +305,22 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.serialnumber));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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.item_sn));
|
||||
v.push_back(std::to_string(e.item_charges));
|
||||
v.push_back(std::to_string(e.item_cost));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.active_transaction));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -275,12 +354,22 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Trader e{};
|
||||
|
||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? strtoull(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.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -305,12 +394,22 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Trader e{};
|
||||
|
||||
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? strtoull(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.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -385,12 +484,22 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.serialnumber));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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.item_sn));
|
||||
v.push_back(std::to_string(e.item_charges));
|
||||
v.push_back(std::to_string(e.item_cost));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.active_transaction));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -413,12 +522,22 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.serialnumber));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
v.push_back(std::to_string(e.aug_slot_1));
|
||||
v.push_back(std::to_string(e.aug_slot_2));
|
||||
v.push_back(std::to_string(e.aug_slot_3));
|
||||
v.push_back(std::to_string(e.aug_slot_4));
|
||||
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.item_sn));
|
||||
v.push_back(std::to_string(e.item_charges));
|
||||
v.push_back(std::to_string(e.item_cost));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.active_transaction));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -64,6 +64,22 @@ public:
|
||||
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
static CharacterData FindByName(
|
||||
Database& db,
|
||||
const std::string& character_name
|
||||
)
|
||||
{
|
||||
auto l = CharacterDataRepository::GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`name` = '{}' LIMIT 1",
|
||||
Strings::Escape(character_name)
|
||||
)
|
||||
);
|
||||
|
||||
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef EQEMU_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
#define EQEMU_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_character_parcels_containers_repository.h"
|
||||
|
||||
class CharacterParcelsContainersRepository: public BaseCharacterParcelsContainersRepository {
|
||||
public:
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* CharacterParcelsContainersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* CharacterParcelsContainersRepository::GetWhereNeverExpires()
|
||||
* CharacterParcelsContainersRepository::GetWhereXAndY()
|
||||
* CharacterParcelsContainersRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
|
||||
@@ -49,8 +49,11 @@ public:
|
||||
// these are the base definitions for command_subsettings and can be over-ridden by the database
|
||||
std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = {
|
||||
{.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"},
|
||||
{.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"},
|
||||
{.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"},
|
||||
{.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"},
|
||||
{.parent_command = "find", .sub_command = "class", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findclass"},
|
||||
{.parent_command = "find", .sub_command = "comparison_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcomparisontype"},
|
||||
{.parent_command = "find", .sub_command = "currency", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcurrency"},
|
||||
{.parent_command = "find", .sub_command = "deity", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "finddeity"},
|
||||
{.parent_command = "find", .sub_command = "emote", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findemote"},
|
||||
@@ -58,9 +61,11 @@ public:
|
||||
{.parent_command = "find", .sub_command = "item", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fi|finditem|itemsearch"},
|
||||
{.parent_command = "find", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findlanguage"},
|
||||
{.parent_command = "find", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fn|findnpc|findnpctype"},
|
||||
{.parent_command = "find", .sub_command = "object_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findobjecttype"},
|
||||
{.parent_command = "find", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrace"},
|
||||
{.parent_command = "find", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrecipe"},
|
||||
{.parent_command = "find", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findskill"},
|
||||
{.parent_command = "find", .sub_command = "special_ability", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fsa|findspecialability"},
|
||||
{.parent_command = "find", .sub_command = "spell", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fs|findspell"},
|
||||
{.parent_command = "find", .sub_command = "task", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findtask"},
|
||||
{.parent_command = "find", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fz|findzone"},
|
||||
|
||||
@@ -190,6 +190,17 @@ public:
|
||||
|
||||
return UpdateOne(db, m);
|
||||
}
|
||||
|
||||
static void ClearOnlineStatus(Database &db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET `online` = 0 "
|
||||
"WHERE `online` = 1;",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_GUILD_MEMBERS_REPOSITORY_H
|
||||
|
||||
@@ -7,43 +7,6 @@
|
||||
|
||||
class ItemsRepository: public BaseItemsRepository {
|
||||
public:
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* ItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* ItemsRepository::GetWhereNeverExpires()
|
||||
* ItemsRepository::GetWhereXAndY()
|
||||
* ItemsRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static std::vector<int32> GetItemIDsBySearchCriteria(
|
||||
Database& db,
|
||||
std::string search_string,
|
||||
@@ -73,6 +36,8 @@ public:
|
||||
|
||||
return item_id_list;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_ITEMS_REPOSITORY_H
|
||||
|
||||
@@ -1,50 +1,224 @@
|
||||
#ifndef EQEMU_TRADER_REPOSITORY_H
|
||||
#define EQEMU_TRADER_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../../common/shareddb.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_trader_repository.h"
|
||||
#include "items_repository.h"
|
||||
#include "../../common/item_data.h"
|
||||
#include "../../common/races.h"
|
||||
#include "../cereal/include/cereal/archives/binary.hpp"
|
||||
#include "../cereal/include/cereal/types/string.hpp"
|
||||
|
||||
class TraderRepository: public BaseTraderRepository {
|
||||
class TraderRepository : public BaseTraderRepository {
|
||||
public:
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* TraderRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* TraderRepository::GetWhereNeverExpires()
|
||||
* TraderRepository::GetWhereXAndY()
|
||||
* TraderRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
struct DistinctTraders_Struct {
|
||||
uint32 trader_id;
|
||||
uint32 zone_id;
|
||||
uint32 entity_id;
|
||||
std::string trader_name;
|
||||
};
|
||||
|
||||
// Custom extended repository methods here
|
||||
struct BulkTraders_Struct {
|
||||
uint32 count{0};
|
||||
uint32 name_length{0};
|
||||
std::vector<DistinctTraders_Struct> traders{};
|
||||
};
|
||||
|
||||
struct WelcomeData_Struct {
|
||||
uint32 count_of_traders;
|
||||
uint32 count_of_items;
|
||||
};
|
||||
|
||||
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||
GetBazaarSearchResults(
|
||||
SharedDatabase &db,
|
||||
BazaarSearchCriteria_Struct search,
|
||||
uint32 char_zone_id
|
||||
);
|
||||
|
||||
static BulkTraders_Struct GetDistinctTraders(Database &db)
|
||||
{
|
||||
BulkTraders_Struct all_entries{};
|
||||
std::vector<DistinctTraders_Struct> distinct_traders;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name "
|
||||
"FROM trader AS t "
|
||||
"JOIN character_data AS c ON t.char_id = c.id;"
|
||||
);
|
||||
|
||||
distinct_traders.reserve(results.RowCount());
|
||||
|
||||
for (auto row: results) {
|
||||
DistinctTraders_Struct e{};
|
||||
|
||||
e.trader_id = Strings::ToInt(row[0]);
|
||||
e.zone_id = Strings::ToInt(row[1]);
|
||||
e.entity_id = Strings::ToInt(row[2]);
|
||||
e.trader_name = row[3] ? row[3] : "";
|
||||
all_entries.name_length += e.trader_name.length() + 1;
|
||||
|
||||
all_entries.traders.push_back(e);
|
||||
}
|
||||
all_entries.count = results.RowCount();
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static WelcomeData_Struct GetWelcomeData(Database &db)
|
||||
{
|
||||
WelcomeData_Struct e{};
|
||||
|
||||
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader;");
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return e;
|
||||
}
|
||||
|
||||
auto r = results.begin();
|
||||
e.count_of_traders = Strings::ToInt(r[0]);
|
||||
e.count_of_items = Strings::ToInt(r[1]);
|
||||
return e;
|
||||
}
|
||||
|
||||
static int UpdateItem(Database &db, uint32 char_id, uint32 new_price, uint32 item_id, uint32 item_charges)
|
||||
{
|
||||
std::vector<BaseTraderRepository::Trader> items{};
|
||||
if (item_charges == 0) {
|
||||
items = GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"char_id = '{}' AND item_id = '{}'",
|
||||
char_id,
|
||||
item_id
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
items = GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"char_id = '{}' AND item_id = '{}' AND item_charges = '{}'",
|
||||
char_id,
|
||||
item_id,
|
||||
item_charges
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (items.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto &i: items) {
|
||||
i.item_cost = new_price;
|
||||
}
|
||||
|
||||
return ReplaceMany(db, items);
|
||||
}
|
||||
|
||||
static Trader GetTraderItem(Database &db, uint32 trader_id, uint32 item_id, uint32 item_cost)
|
||||
{
|
||||
Trader item{};
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT t.char_id, t.item_id, t.serialnumber, t.charges, t.item_cost, t.slot_id, t.entity_id FROM trader AS t "
|
||||
"WHERE t.entity_id = {} AND t.item_id = {} AND t.item_cost = {} "
|
||||
"LIMIT 1;",
|
||||
trader_id,
|
||||
item_id,
|
||||
item_cost
|
||||
);
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return item;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
item.char_id = Strings::ToInt(row[0]);
|
||||
item.item_id = Strings::ToInt(row[1]);
|
||||
item.item_sn = Strings::ToInt(row[2]);
|
||||
item.item_charges = Strings::ToInt(row[3]);
|
||||
item.item_cost = Strings::ToInt(row[4]);
|
||||
item.slot_id = Strings::ToInt(row[5]);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static int UpdateQuantity(Database &db, uint32 char_id, uint32 serial_number, int16 quantity)
|
||||
{
|
||||
const auto trader_item = GetWhere(
|
||||
db,
|
||||
fmt::format("char_id = '{}' AND item_sn = '{}' ", char_id, serial_number)
|
||||
);
|
||||
|
||||
if (trader_item.empty() || trader_item.size() > 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto m = trader_item[0];
|
||||
m.item_charges = quantity;
|
||||
|
||||
return UpdateOne(db, m);
|
||||
}
|
||||
|
||||
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number)
|
||||
{
|
||||
Trader e{};
|
||||
const auto trader_item = GetWhere(
|
||||
db,
|
||||
fmt::format("`item_sn` = '{}' LIMIT 1", serial_number)
|
||||
);
|
||||
|
||||
if (trader_item.empty()) {
|
||||
return e;
|
||||
}
|
||||
else {
|
||||
return trader_item.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
static Trader GetItemBySerialNumber(Database &db, std::string serial_number)
|
||||
{
|
||||
Trader e{};
|
||||
auto sn = Strings::ToUnsignedBigInt(serial_number);
|
||||
const auto trader_item = GetWhere(
|
||||
db,
|
||||
fmt::format("`item_sn` = '{}' LIMIT 1", sn)
|
||||
);
|
||||
|
||||
if (trader_item.empty()) {
|
||||
return e;
|
||||
}
|
||||
else {
|
||||
return trader_item.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
|
||||
{
|
||||
auto e = FindOne(db, id);
|
||||
if (!e.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
e.active_transaction = status == true ? 1 : 0;
|
||||
|
||||
return UpdateOne(db, e);
|
||||
}
|
||||
|
||||
static int DeleteMany(Database &db, const std::vector<Trader> &entries)
|
||||
{
|
||||
std::vector<std::string> delete_ids;
|
||||
|
||||
for (auto const &e: entries) {
|
||||
delete_ids.push_back(std::to_string(e.id));
|
||||
}
|
||||
|
||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_TRADER_REPOSITORY_H
|
||||
|
||||
+39
-1
@@ -226,6 +226,8 @@ RULE_INT(Character, ClearXTargetDelay, 10, "Seconds between uses of the #clearxt
|
||||
RULE_BOOL(Character, PreventMountsFromZoning, false, "Enable to prevent mounts from zoning - Prior to December 15, 2004 this is enabled.")
|
||||
RULE_BOOL(Character, GroupInvitesRequireTarget, false, "Enable to require players to have invitee on target (Disables /invite name) - Classic Style")
|
||||
RULE_BOOL(Character, PlayerTradingLoreFeedback, true, "If enabled, during a player to player trade, if lore items exist, it will output which items.")
|
||||
RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will always succeed its skill check. Default: 199")
|
||||
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -503,8 +505,11 @@ RULE_BOOL(Spells, RequireMnemonicRetention, true, "Enabling will require spell s
|
||||
RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear charm from charm pets and detach buffs.")
|
||||
RULE_BOOL(Spells, ManaTapsRequireNPCMana, false, "Enabling will require target to have mana to tap. Default off as many npc's are caster class with 0 mana and need fixed.")
|
||||
RULE_INT(Spells, HarmTouchCritRatio, 200, "Harmtouch crit bonus, on top of BaseCritRatio")
|
||||
RULE_BOOL(Spells, UseClassicHarmTouchDamage, false, "Use pre 2007 Harm Touch calculations - Default: False")
|
||||
RULE_BOOL(Spells, UseClassicSpellFocus, false, "Enabling will tell the server to handle random focus damage as classic spell imports lack the limit values.")
|
||||
RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to cast mana taps on any class, this will bypass ManaTapsRequireNPCMana rule.")
|
||||
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
|
||||
RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
@@ -520,6 +525,8 @@ RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical h
|
||||
RULE_BOOL(Combat, UseIntervalAC, true, "Switch whether bonuses, armour class, multipliers, classes and caps should be considered in the calculation of damage values")
|
||||
RULE_INT(Combat, PetAttackMagicLevel, 10, "Level at which pets can cause magic damage, no longer used")
|
||||
RULE_INT(Combat, NPCAttackMagicLevel, 10, "Level at which NPC and pets can cause magic damage")
|
||||
RULE_INT(Combat, LevelDifferenceRollCheck, -1, "Level Difference to enable LeverDifferenceRollBonus for MeleeMitigation - Default: -1 is disabled, 20 is common")
|
||||
RULE_REAL(Combat, LevelDifferenceRollBonus, 0.5, "Roll Bonus/Detrement if using LevelDifferenceRollCheck")
|
||||
RULE_BOOL(Combat, EnableFearPathing, true, "Setting whether to use pathing during fear")
|
||||
RULE_BOOL(Combat, FleeGray, true, "If true FleeGrayHPRatio will be used")
|
||||
RULE_INT(Combat, FleeGrayHPRatio, 50, "HP percentage when a Gray NPC begins to flee")
|
||||
@@ -589,6 +596,8 @@ RULE_BOOL(Combat, BackstabIgnoresElemental, false, "Enable or disable Elemental
|
||||
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
|
||||
RULE_INT(Combat, DoubleBackstabLevelRequirement, 55, "Level requirement to enable double backstab attempts. The default is 55.")
|
||||
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
|
||||
RULE_REAL(Combat, ArcheryHitPenalty, 0, "Archery has a hit penalty to try to help balance it with the plethora of long term +hit modifiers for it - Default: 0")
|
||||
RULE_REAL(Combat, ArcheryBaseDamageBonus, 1, "Percentage modifier to base archery Damage 0.5=50% base damage, 1=100%,2=200% - Default: 1")
|
||||
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
|
||||
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
|
||||
RULE_INT(Combat, MaxProcs, 4, "Adjustable maximum number of procs per round, the hard cap is MAX_PROCS (11). Requires mob repop or client zone when changed")
|
||||
@@ -603,6 +612,26 @@ RULE_INT(Combat, StunDuration, 2000, "Duration of stuns in ms. DEFAULT: 2000")
|
||||
RULE_BOOL(Combat, ClientStunMessage, false, "Client stunning NPC produces message. DEFAULT false")
|
||||
RULE_BOOL(Combat, BashTwoHanderUseShoulderAC, false, "Enable to use shoulder AC for bash calculations when two hander is equipped. Unproven if accurate DEFAULT: false")
|
||||
RULE_REAL(Combat, BashACBonusDivisor, 25.0, "this divides the AC value contribution to bash damage, lower to increase damage")
|
||||
RULE_BOOL(Combat, UseMobStaticOffenseSkill, false, "Toggle to enabled the use of a static offense skill for Mobs. DEFAULT: false")
|
||||
RULE_BOOL(Combat, UseEnhancedMobStaticWeaponSkill, false, "Toggle to enabled the use of an enhanced (slightly higher hit rate) static weapon skill for Mobs. DEFAULT: false")
|
||||
RULE_INT(Combat, PCAttackPowerScaling, 100, "Applies scaling to PC Attack Power (75 = 75%). DEFAULT: 100 to not adjust existing Servers")
|
||||
RULE_INT(Combat, PCAccuracyAvoidanceMod2Scale, 100, "Scale Factor for PC Accuracy and Avoidance (Mod2, found on items). Found a value of 100 to make both too strong (75 = x0.75). DEFAULT: 100 to not adjust existing Servers")
|
||||
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
||||
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
||||
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
||||
RULE_REAL(Combat, SlayDamageAdjustment, 0.5, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 0.5")
|
||||
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
|
||||
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
|
||||
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
|
||||
RULE_INT(Combat, BashBaseDamage, 2, "Bash base damage, default is 2")
|
||||
RULE_INT(Combat, DragonPunchBaseDamage, 12, "Dragon Punch base damage, default is 12")
|
||||
RULE_INT(Combat, EagleStrikeBaseDamage, 7, "Eagle Strike base damage, default is 7")
|
||||
RULE_INT(Combat, FlyingKickBaseDamage, 25, "Flying Kick base damage, default is 25")
|
||||
RULE_INT(Combat, FrenzyBaseDamage, 10, "Frenzy base damage, default is 10")
|
||||
RULE_INT(Combat, KickBaseDamage, 3, "Kick base damage, default is 3")
|
||||
RULE_INT(Combat, RoundKickBaseDamage, 5, "Round Kick base damage, default is 5")
|
||||
RULE_INT(Combat, ThrowingBaseDamage, 0, "Throwing base damage, default is 0")
|
||||
RULE_INT(Combat, TigerClawBaseDamage, 4, "Tiger Claw base damage, default is 4")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
@@ -661,6 +690,8 @@ RULE_BOOL(Aggro, NPCAggroMaxDistanceEnabled, true, "If enabled, NPC's will drop
|
||||
RULE_BOOL(Aggro, AggroPlayerPets, false, "If enabled, NPCs will aggro player pets")
|
||||
RULE_BOOL(Aggro, UndeadAlwaysAggro, true, "should undead always aggro?")
|
||||
RULE_INT(Aggro, BardAggroCap, 40, "per song bard aggro cap.")
|
||||
RULE_INT(Aggro, InitialAggroBonus, 100, "Initial Aggro Bonus, Default: 100")
|
||||
RULE_INT(Aggro, InitialPetAggroBonus, 100, "Initial Pet Aggro Bonus, Default 100")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(TaskSystem)
|
||||
@@ -725,7 +756,7 @@ RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal comple
|
||||
RULE_INT(Bots, AutosaveIntervalSeconds, 300, "Number of seconds after which a timer is triggered which stores the bot data. The value 0 means no periodic automatic saving.")
|
||||
RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hit bot owner rather than bot.")
|
||||
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
||||
RULE_BOOL(Bots, BotsCanClickItems, true, "Enabled the ability for bots to click items they have equipped. Default TRUE")
|
||||
RULE_BOOL(Bots, BotsCanClickItems, true, "Enables the ability for bots to click items they have equipped. Default TRUE")
|
||||
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
@@ -754,6 +785,7 @@ RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Merchant)
|
||||
RULE_BOOL(Merchant, UsePriceMod, true, "Use faction/charisma price modifiers")
|
||||
RULE_BOOL(Merchant, UseClassicPriceMod, false, "Must also set UsePriceMod. Negates other rules for vendor price mods.")
|
||||
RULE_REAL(Merchant, SellCostMod, 1.05, "Modifier for NPC sell price")
|
||||
RULE_REAL(Merchant, BuyCostMod, 0.95, "Modifier for NPC buy price")
|
||||
RULE_INT(Merchant, PriceBonusPct, 4, "Determines maximum price bonus from having good faction/CHA. Value is a percent")
|
||||
@@ -769,6 +801,9 @@ RULE_BOOL(Bazaar, AuditTrail, false, "Setting whether a path to the trader shoul
|
||||
RULE_INT(Bazaar, MaxSearchResults, 50, "Maximum number of search results in Bazaar")
|
||||
RULE_BOOL(Bazaar, EnableWarpToTrader, true, "Setting whether teleport to the selected trader should be active")
|
||||
RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in the /barter search")
|
||||
RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a bazaar purchase as a percentage of item cost. Default is 20% of item cost. RoF+ Only.")
|
||||
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_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mail)
|
||||
@@ -813,6 +848,7 @@ RULE_INT(AA, ModernAAScalingAAMinimum, 0, "The minimum number of earned AA befor
|
||||
RULE_INT(AA, ModernAAScalingAALimit, 4000, "The number of earned AA when AA experience scaling ends")
|
||||
RULE_BOOL(AA, SoundForAAEarned, false, "Play sound when AA point earned")
|
||||
RULE_INT(AA, UnusedAAPointCap, -1, "Cap for Unused AA Points. Default: -1. NOTE: DO NOT LOWER THIS WITHOUT KNOWING WHAT YOU ARE DOING. MAY RESULT IN PLAYERS LOSING AAs.")
|
||||
RULE_INT(AA, MaxAAEXPPerKill, -1, "Maximum AA EXP per Kill (3425214 is about 7%) - Default: -1 will disable the check")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Console)
|
||||
@@ -961,6 +997,8 @@ RULE_BOOL(Items, DisableNoRent, false, "Enable this to disable No Rent Items")
|
||||
RULE_BOOL(Items, DisableNoTransfer, false, "Enable this to disable No Transfer Items")
|
||||
RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt Items")
|
||||
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
|
||||
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
|
||||
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Parcel)
|
||||
|
||||
@@ -138,6 +138,9 @@
|
||||
#define ServerOP_RaidMOTD 0x0113
|
||||
#define ServerOP_RaidNote 0x0114
|
||||
|
||||
#define ServerOP_TraderMessaging 0x0120
|
||||
#define ServerOP_BazaarPurchase 0x0121
|
||||
|
||||
#define ServerOP_InstanceUpdateTime 0x014F
|
||||
#define ServerOP_AdventureRequest 0x0150
|
||||
#define ServerOP_AdventureRequestAccept 0x0151
|
||||
@@ -277,6 +280,7 @@
|
||||
#define ServerOP_ReloadLoot 0x4127
|
||||
#define ServerOP_ReloadBaseData 0x4128
|
||||
#define ServerOP_ReloadSkillCaps 0x4129
|
||||
#define ServerOP_ReloadNPCSpells 0x4130
|
||||
|
||||
#define ServerOP_CZDialogueWindow 0x4500
|
||||
#define ServerOP_CZLDoNUpdate 0x4501
|
||||
@@ -1937,6 +1941,27 @@ struct ServerOP_GuildMessage_Struct {
|
||||
char url[2048]{0};
|
||||
};
|
||||
|
||||
struct TraderMessaging_Struct {
|
||||
uint32 action;
|
||||
uint32 zone_id;
|
||||
uint32 trader_id;
|
||||
uint32 entity_id;
|
||||
char trader_name[64];
|
||||
};
|
||||
|
||||
struct BazaarPurchaseMessaging_Struct {
|
||||
TraderBuy_Struct trader_buy_struct;
|
||||
uint32 item_aug_1;
|
||||
uint32 item_aug_2;
|
||||
uint32 item_aug_3;
|
||||
uint32 item_aug_4;
|
||||
uint32 item_aug_5;
|
||||
uint32 item_aug_6;
|
||||
uint32 buyer_id;
|
||||
uint32 item_quantity_available;
|
||||
uint32 id;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
||||
+55
-20
@@ -1,4 +1,14 @@
|
||||
#include "skill_caps.h"
|
||||
#include "timer.h"
|
||||
|
||||
// cache the skill cap max level in the database
|
||||
std::map<uint8_t, int32_t> skill_max_level = {};
|
||||
|
||||
uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
SkillCaps *SkillCaps::SetContentDatabase(Database *db)
|
||||
{
|
||||
@@ -7,21 +17,38 @@ SkillCaps *SkillCaps::SetContentDatabase(Database *db)
|
||||
return this;
|
||||
}
|
||||
|
||||
int32_t SkillCaps::GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id)
|
||||
{
|
||||
// pull the max value defined in the database if it exists
|
||||
auto it = skill_max_level.find((class_id * 1000000) + skill_id);
|
||||
if (it != skill_max_level.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return skill_cap_max_level;
|
||||
}
|
||||
|
||||
SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (!IsPlayerClass(class_id)) {
|
||||
if (!IsPlayerClass(class_id) || static_cast<uint32>(skill_id) > EQ::skills::HIGHEST_SKILL + 1) {
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
auto pos = m_skill_caps.find(key);
|
||||
const uint8 max_level = GetSkillCapMaxLevel(class_id, skill_id);
|
||||
if (level > max_level) {
|
||||
level = max_level;
|
||||
}
|
||||
|
||||
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
uint8 SkillCaps::GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (
|
||||
!IsPlayerClass(class_id) ||
|
||||
@@ -31,21 +58,12 @@ uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
|
||||
for (const auto &e: m_skill_caps) {
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return current_level;
|
||||
}
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return current_level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +85,25 @@ void SkillCaps::LoadSkillCaps()
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
|
||||
const uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
|
||||
m_skill_caps[key] = e;
|
||||
|
||||
const int max_level_key = (e.class_id * 1000000) + e.skill_id;
|
||||
auto it = skill_max_level.find(max_level_key);
|
||||
if (it != skill_max_level.end()) {
|
||||
// Key found, update the value if the new level is higher
|
||||
if (e.level > it->second) {
|
||||
it->second = e.level;
|
||||
}
|
||||
// we never want to exceed the defined rule skill cap max level
|
||||
if (it->second > skill_cap_max_level) {
|
||||
it->second = skill_cap_max_level;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Key not found, insert the new key-value pair
|
||||
skill_max_level[max_level_key] = e.level;
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
|
||||
+2
-1
@@ -10,9 +10,10 @@ class SkillCaps {
|
||||
public:
|
||||
inline void ClearSkillCaps() { m_skill_caps.clear(); }
|
||||
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
void LoadSkillCaps();
|
||||
void ReloadSkillCaps();
|
||||
static int32_t GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id);
|
||||
|
||||
SkillCaps *SetContentDatabase(Database *db);
|
||||
private:
|
||||
|
||||
+24
-18
@@ -127,24 +127,30 @@ bool EQ::skills::IsCastingSkill(SkillType skill)
|
||||
int32 EQ::skills::GetBaseDamage(SkillType skill)
|
||||
{
|
||||
switch (skill) {
|
||||
case SkillBash:
|
||||
return 2;
|
||||
case SkillDragonPunch:
|
||||
return 12;
|
||||
case SkillEagleStrike:
|
||||
return 7;
|
||||
case SkillFlyingKick:
|
||||
return 25;
|
||||
case SkillKick:
|
||||
return 3;
|
||||
case SkillRoundKick:
|
||||
return 5;
|
||||
case SkillTigerClaw:
|
||||
return 4;
|
||||
case SkillFrenzy:
|
||||
return 10;
|
||||
default:
|
||||
return 0;
|
||||
case SkillArchery:
|
||||
return RuleI(Combat, ArcheryBaseDamage);
|
||||
case SkillBackstab:
|
||||
return RuleI(Combat, BackstabBaseDamage);
|
||||
case SkillBash:
|
||||
return RuleI(Combat, BashBaseDamage);
|
||||
case SkillDragonPunch:
|
||||
return RuleI(Combat, DragonPunchBaseDamage);
|
||||
case SkillEagleStrike:
|
||||
return RuleI(Combat, EagleStrikeBaseDamage);
|
||||
case SkillFlyingKick:
|
||||
return RuleI(Combat, FlyingKickBaseDamage);
|
||||
case SkillFrenzy:
|
||||
return RuleI(Combat, FrenzyBaseDamage);
|
||||
case SkillKick:
|
||||
return RuleI(Combat, KickBaseDamage);
|
||||
case SkillRoundKick:
|
||||
return RuleI(Combat, RoundKickBaseDamage);
|
||||
case SkillThrowing:
|
||||
return RuleI(Combat, ThrowingBaseDamage);
|
||||
case SkillTigerClaw:
|
||||
return RuleI(Combat, TigerClawBaseDamage);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -431,6 +431,16 @@ bool IsCharmSpell(uint16 spell_id)
|
||||
return IsEffectInSpell(spell_id, SE_Charm);
|
||||
}
|
||||
|
||||
bool IsResurrectionSicknessSpell(uint16 spell_id) {
|
||||
return (
|
||||
spell_id == SPELL_RESURRECTION_SICKNESS ||
|
||||
spell_id == SPELL_RESURRECTION_SICKNESS2 ||
|
||||
spell_id == SPELL_RESURRECTION_SICKNESS3 ||
|
||||
spell_id == SPELL_RESURRECTION_SICKNESS4 ||
|
||||
spell_id == SPELL_REVIVAL_SICKNESS
|
||||
);
|
||||
}
|
||||
|
||||
bool IsBlindSpell(uint16 spell_id)
|
||||
{
|
||||
return IsEffectInSpell(spell_id, SE_Blind);
|
||||
|
||||
+2
-1
@@ -904,7 +904,7 @@ typedef enum {
|
||||
#define SE_AlterNPCLevel 107 // implemented - not used on live
|
||||
#define SE_Familiar 108 // implemented
|
||||
#define SE_SummonItemIntoBag 109 // implemented - summons stuff into container
|
||||
//#define SE_IncreaseArchery 110 // not used
|
||||
#define SE_IncreaseArchery 110 // implemented
|
||||
#define SE_ResistAll 111 // implemented - Note: Physical Resists are not modified by this effect.
|
||||
#define SE_CastingLevel 112 // implemented
|
||||
#define SE_SummonHorse 113 // implemented
|
||||
@@ -1522,6 +1522,7 @@ bool IsSummonPetSpell(uint16 spell_id);
|
||||
bool IsSummonPCSpell(uint16 spell_id);
|
||||
bool IsPetSpell(uint16 spell_id);
|
||||
bool IsCharmSpell(uint16 spell_id);
|
||||
bool IsResurrectionSicknessSpell(uint16 spell_id);
|
||||
bool IsBlindSpell(uint16 spell_id);
|
||||
bool IsHealthSpell(uint16 spell_id);
|
||||
bool IsCastTimeReductionSpell(uint16 spell_id);
|
||||
|
||||
@@ -745,6 +745,15 @@ bool Strings::Contains(const std::string& subject, const std::string& search)
|
||||
return subject.find(search) != std::string::npos;
|
||||
}
|
||||
|
||||
bool Strings::ContainsLower(const std::string& subject, const std::string& search)
|
||||
{
|
||||
if (subject.length() < search.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ToLower(subject).find(ToLower(search)) != std::string::npos;
|
||||
}
|
||||
|
||||
uint32 Strings::TimeToSeconds(std::string time_string)
|
||||
{
|
||||
if (time_string.empty()) {
|
||||
|
||||
@@ -86,6 +86,7 @@ class Strings {
|
||||
public:
|
||||
static bool Contains(std::vector<std::string> container, const std::string& element);
|
||||
static bool Contains(const std::string& subject, const std::string& search);
|
||||
static bool ContainsLower(const std::string& subject, const std::string& search);
|
||||
static int ToInt(const std::string &s, int fallback = 0);
|
||||
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
|
||||
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.50.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.53.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 9275
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9280
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.50.0",
|
||||
"version": "22.53.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -430,6 +430,7 @@ OP_BazaarSearch=0x39d6
|
||||
OP_TraderDelItem=0x5829
|
||||
OP_BecomeTrader=0x61b3
|
||||
OP_TraderShop=0x31df
|
||||
OP_TraderBulkSend=0x6a96
|
||||
OP_Trader=0x4ef5
|
||||
OP_Barter=0x243a
|
||||
OP_TraderBuy=0x0000
|
||||
|
||||
+24
-35
@@ -282,88 +282,77 @@ void Adventure::IncrementAssassinationCount()
|
||||
void Adventure::Finished(AdventureWinStatus ws)
|
||||
{
|
||||
auto iter = players.begin();
|
||||
while(iter != players.end())
|
||||
{
|
||||
while (iter != players.end()) {
|
||||
ClientListEntry *current = client_list.FindCharacter((*iter).c_str());
|
||||
if(current)
|
||||
{
|
||||
if(current->Online() == CLE_Status::InZone)
|
||||
{
|
||||
auto character_id = database.GetCharacterID(*iter);
|
||||
|
||||
if (character_id == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
if (current->Online() == CLE_Status::InZone) {
|
||||
//We can send our packets only.
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_AdventureFinish, sizeof(ServerAdventureFinish_Struct));
|
||||
auto pack = new ServerPacket(ServerOP_AdventureFinish, sizeof(ServerAdventureFinish_Struct));
|
||||
ServerAdventureFinish_Struct *af = (ServerAdventureFinish_Struct*)pack->pBuffer;
|
||||
strcpy(af->player, (*iter).c_str());
|
||||
af->theme = GetTemplate()->theme;
|
||||
if(ws == AWS_Win)
|
||||
{
|
||||
if (ws == AWS_Win) {
|
||||
af->win = true;
|
||||
af->points = GetTemplate()->win_points;
|
||||
}
|
||||
else if(ws == AWS_SecondPlace)
|
||||
{
|
||||
else if (ws == AWS_SecondPlace) {
|
||||
af->win = true;
|
||||
af->points = GetTemplate()->lose_points;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
af->win = false;
|
||||
af->points = 0;
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(current->zone(), current->instance(), pack);
|
||||
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
database.UpdateAdventureStatsEntry(character_id, GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
delete pack;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
AdventureFinishEvent afe;
|
||||
afe.name = (*iter);
|
||||
if(ws == AWS_Win)
|
||||
{
|
||||
if (ws == AWS_Win) {
|
||||
afe.theme = GetTemplate()->theme;
|
||||
afe.points = GetTemplate()->win_points;
|
||||
afe.win = true;
|
||||
}
|
||||
else if(ws == AWS_SecondPlace)
|
||||
{
|
||||
else if (ws == AWS_SecondPlace) {
|
||||
afe.theme = GetTemplate()->theme;
|
||||
afe.points = GetTemplate()->lose_points;
|
||||
afe.win = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
afe.win = false;
|
||||
afe.points = 0;
|
||||
}
|
||||
adventure_manager.AddFinishedEvent(afe);
|
||||
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
database.UpdateAdventureStatsEntry(character_id, GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
AdventureFinishEvent afe;
|
||||
afe.name = (*iter);
|
||||
if(ws == AWS_Win)
|
||||
{
|
||||
if (ws == AWS_Win) {
|
||||
afe.theme = GetTemplate()->theme;
|
||||
afe.points = GetTemplate()->win_points;
|
||||
afe.win = true;
|
||||
}
|
||||
else if(ws == AWS_SecondPlace)
|
||||
{
|
||||
else if (ws == AWS_SecondPlace) {
|
||||
afe.theme = GetTemplate()->theme;
|
||||
afe.points = GetTemplate()->lose_points;
|
||||
afe.win = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
afe.win = false;
|
||||
afe.points = 0;
|
||||
}
|
||||
adventure_manager.AddFinishedEvent(afe);
|
||||
|
||||
database.UpdateAdventureStatsEntry(database.GetCharacterID((*iter)), GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
database.UpdateAdventureStatsEntry(character_id, GetTemplate()->theme, (ws != AWS_Lose) ? true : false);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ void ClientListEntry::SetOnline(CLE_Status iOnline)
|
||||
"Online status [{}] ({}) status [{}] ({})",
|
||||
AccountName(),
|
||||
AccountID(),
|
||||
CLEStatusString[CLE_Status::Online],
|
||||
CLEStatusString[iOnline],
|
||||
static_cast<int>(iOnline)
|
||||
);
|
||||
|
||||
|
||||
+279
-234
@@ -528,276 +528,321 @@ void ClientList::SendOnlineGuildMembers(uint32 FromID, uint32 GuildID)
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
|
||||
void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_Struct* whom, WorldTCPConnection* connection) {
|
||||
try{
|
||||
LinkedListIterator<ClientListEntry*> iterator(clientlist);
|
||||
LinkedListIterator<ClientListEntry*> countclients(clientlist);
|
||||
ClientListEntry* cle = 0;
|
||||
ClientListEntry* countcle = 0;
|
||||
//char tmpgm[25] = "";
|
||||
//char accinfo[150] = "";
|
||||
char line[300] = "";
|
||||
//char tmpguild[50] = "";
|
||||
//char LFG[10] = "";
|
||||
//uint32 x = 0;
|
||||
int whomlen = 0;
|
||||
if (whom) {
|
||||
// fixes for client converting some queries into a race query instead of zone
|
||||
if (whom->wrace == 221) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "scarlet");
|
||||
}
|
||||
if (whom->wrace == 327) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "crystal");
|
||||
}
|
||||
if (whom->wrace == 103) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "kedge");
|
||||
}
|
||||
if (whom->wrace == 230) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "akheva");
|
||||
}
|
||||
if (whom->wrace == 229) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "netherbian");
|
||||
}
|
||||
try {
|
||||
LinkedListIterator<ClientListEntry*> iterator(clientlist);
|
||||
LinkedListIterator<ClientListEntry*> countclients(clientlist);
|
||||
ClientListEntry* cle = 0;
|
||||
ClientListEntry* countcle = 0;
|
||||
//char tmpgm[25] = "";
|
||||
//char accinfo[150] = "";
|
||||
char line[300] = "";
|
||||
//char tmpguild[50] = "";
|
||||
//char LFG[10] = "";
|
||||
//uint32 x = 0;
|
||||
int whomlen = 0;
|
||||
|
||||
whomlen = strlen(whom->whom);
|
||||
if(whom->wrace == 0x001A) // 0x001A is the old Froglok race number and is sent by the client for /who all froglok
|
||||
whom->wrace = FROGLOK; // This is what EQEmu uses for the Froglok Race number.
|
||||
}
|
||||
|
||||
uint32 totalusers=0;
|
||||
uint32 totallength=0;
|
||||
countclients.Reset();
|
||||
while(countclients.MoreElements()){
|
||||
countcle = countclients.GetData();
|
||||
const char* tmpZone = ZoneName(countcle->zone());
|
||||
if (
|
||||
(countcle->Online() >= CLE_Status::Zoning) &&
|
||||
(!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) &&
|
||||
(whom == 0 || (
|
||||
((countcle->Admin() >= AccountStatus::QuestTroupe && countcle->GetGM()) || whom->gmlookup == 0xFFFF) &&
|
||||
(whom->lvllow == 0xFFFF || (countcle->level() >= whom->lvllow && countcle->level() <= whom->lvlhigh && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
|
||||
(whom->wclass == 0xFFFF || (countcle->class_() == whom->wclass && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
|
||||
(whom->wrace == 0xFFFF || (countcle->race() == whom->wrace && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
|
||||
(whomlen == 0 || (
|
||||
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
|
||||
strncasecmp(countcle->name(),whom->whom, whomlen) == 0 ||
|
||||
(strncasecmp(guild_mgr.GetGuildName(countcle->GuildID()), whom->whom, whomlen) == 0) ||
|
||||
(admin >= AccountStatus::GMAdmin && strncasecmp(countcle->AccountName(), whom->whom, whomlen) == 0)
|
||||
))
|
||||
))
|
||||
) {
|
||||
if((countcle->Anon()>0 && admin >= countcle->Admin() && admin > AccountStatus::Player) || countcle->Anon()==0 ){
|
||||
totalusers++;
|
||||
if(totalusers<=20 || admin >= AccountStatus::GMAdmin)
|
||||
totallength=totallength+strlen(countcle->name())+strlen(countcle->AccountName())+strlen(guild_mgr.GetGuildName(countcle->GuildID()))+5;
|
||||
if (whom) {
|
||||
// fixes for client converting some queries into a race query instead of zone
|
||||
if (whom->wrace == 221) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "scarlet");
|
||||
}
|
||||
else if((countcle->Anon()>0 && admin<=countcle->Admin()) || (countcle->Anon()==0 && !countcle->GetGM())) {
|
||||
totalusers++;
|
||||
if(totalusers<=20 || admin >= AccountStatus::GMAdmin)
|
||||
totallength=totallength+strlen(countcle->name())+strlen(guild_mgr.GetGuildName(countcle->GuildID()))+5;
|
||||
|
||||
if (whom->wrace == 327) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "crystal");
|
||||
}
|
||||
|
||||
if (whom->wrace == 103) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "kedge");
|
||||
}
|
||||
|
||||
if (whom->wrace == 230) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "akheva");
|
||||
}
|
||||
|
||||
if (whom->wrace == 229) {
|
||||
whom->wrace = 0xFFFF;
|
||||
strcpy(whom->whom, "netherbian");
|
||||
}
|
||||
|
||||
whomlen = strlen(whom->whom);
|
||||
|
||||
if (whom->wrace == 0x001A) { // 0x001A is the old Froglok race number and is sent by the client for /who all froglok
|
||||
whom->wrace = FROGLOK; // This is what EQEmu uses for the Froglok Race number.
|
||||
}
|
||||
}
|
||||
countclients.Advance();
|
||||
}
|
||||
uint32 plid=fromid;
|
||||
uint32 playerineqstring=5001;
|
||||
const char line2[]="---------------------------";
|
||||
uint8 unknown35=0x0A;
|
||||
uint32 unknown36=0;
|
||||
uint32 playersinzonestring=5028;
|
||||
if(totalusers>20 && admin<AccountStatus::GMAdmin){
|
||||
totalusers=20;
|
||||
playersinzonestring=5033;
|
||||
}
|
||||
else if(totalusers>1)
|
||||
playersinzonestring=5036;
|
||||
uint32 unknown44[2];
|
||||
unknown44[0]=0;
|
||||
unknown44[1]=0;
|
||||
uint32 unknown52=totalusers;
|
||||
uint32 unknown56=1;
|
||||
auto pack2 = new ServerPacket(ServerOP_WhoAllReply, 64 + totallength + (49 * totalusers));
|
||||
memset(pack2->pBuffer,0,pack2->size);
|
||||
uchar *buffer=pack2->pBuffer;
|
||||
uchar *bufptr=buffer;
|
||||
//memset(buffer,0,pack2->size);
|
||||
memcpy(bufptr,&plid, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&playerineqstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&line2, strlen(line2));
|
||||
bufptr+=strlen(line2);
|
||||
memcpy(bufptr,&unknown35, sizeof(uint8));
|
||||
bufptr+=sizeof(uint8);
|
||||
memcpy(bufptr,&unknown36, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&playersinzonestring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown44[0], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown44[1], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown52, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown56, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&totalusers, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
|
||||
iterator.Reset();
|
||||
int idx=-1;
|
||||
while(iterator.MoreElements()) {
|
||||
cle = iterator.GetData();
|
||||
const char* tmpZone = ZoneName(cle->zone());
|
||||
uint32 totalusers=0;
|
||||
uint32 totallength=0;
|
||||
countclients.Reset();
|
||||
while (countclients.MoreElements()) {
|
||||
countcle = countclients.GetData();
|
||||
const char* tmpZone = ZoneName(countcle->zone());
|
||||
if (
|
||||
(countcle->Online() >= CLE_Status::Zoning) &&
|
||||
(!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) &&
|
||||
(whom == 0 || (
|
||||
((countcle->Admin() >= AccountStatus::QuestTroupe && countcle->GetGM()) || whom->gmlookup == 0xFFFF) &&
|
||||
(whom->lvllow == 0xFFFF ||
|
||||
(countcle->level() >= whom->lvllow && countcle->level() <= whom->lvlhigh &&
|
||||
(countcle->Anon() == 0 || admin > countcle->Admin()))) &&
|
||||
(whom->wclass == 0xFFFF || (countcle->class_() == whom->wclass &&
|
||||
(countcle->Anon() == 0 || admin > countcle->Admin()))) &&
|
||||
(whom->wrace == 0xFFFF ||
|
||||
(countcle->race() == whom->wrace && (countcle->Anon() == 0 || admin > countcle->Admin()))) &&
|
||||
(whomlen == 0 || (
|
||||
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
|
||||
strncasecmp(countcle->name(),whom->whom, whomlen) == 0 ||
|
||||
(strncasecmp(guild_mgr.GetGuildName(countcle->GuildID()), whom->whom, whomlen) == 0) ||
|
||||
(admin >= AccountStatus::GMAdmin && strncasecmp(countcle->AccountName(), whom->whom, whomlen) == 0)
|
||||
))
|
||||
))
|
||||
) {
|
||||
// these blocks can all be condensed but it's simpler to conceptualize this way
|
||||
if ((countcle->Anon()>0 && admin >= countcle->Admin() && admin > AccountStatus::Player) || countcle->Anon()==0 ) {
|
||||
totalusers++;
|
||||
if (totalusers<=20 || admin >= AccountStatus::GMAdmin) {
|
||||
totallength = totallength + strlen(countcle->name()) + strlen(countcle->AccountName()) +
|
||||
strlen(guild_mgr.GetGuildName(countcle->GuildID())) + 5;
|
||||
}
|
||||
} else if (((countcle->Anon() == 1 && admin <= countcle->Admin()) && whomlen != 0 &&
|
||||
strncasecmp(countcle->name(), whom->whom, whomlen) == 0)) {
|
||||
totalusers++;
|
||||
if (totalusers <= 20 || admin >= AccountStatus::GMAdmin) {
|
||||
totallength = totallength + strlen(countcle->name()) + strlen(countcle->AccountName()) +
|
||||
strlen(guild_mgr.GetGuildName(countcle->GuildID())) + 5;
|
||||
}
|
||||
} else if (((countcle->Anon() == 2 && admin <= countcle->Admin()) && whomlen != 0 &&
|
||||
(strncasecmp(countcle->name(), whom->whom, whomlen) == 0 ||
|
||||
strncasecmp(guild_mgr.GetGuildName(countcle->GuildID()), whom->whom, whomlen) == 0))) {
|
||||
totalusers++;
|
||||
if (totalusers <= 20 || admin >= AccountStatus::GMAdmin) {
|
||||
totallength = totallength + strlen(countcle->name()) + strlen(countcle->AccountName()) +
|
||||
strlen(guild_mgr.GetGuildName(countcle->GuildID())) + 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
countclients.Advance();
|
||||
}
|
||||
|
||||
if (
|
||||
(cle->Online() >= CLE_Status::Zoning) &&
|
||||
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
|
||||
(whom == 0 || (
|
||||
((cle->Admin() >= AccountStatus::QuestTroupe && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
|
||||
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whom->wclass == 0xFFFF || (cle->class_() == whom->wclass && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whom->wrace == 0xFFFF || (cle->race() == whom->wrace && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whomlen == 0 || (
|
||||
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
|
||||
strncasecmp(cle->name(),whom->whom, whomlen) == 0 ||
|
||||
(strncasecmp(guild_mgr.GetGuildName(cle->GuildID()), whom->whom, whomlen) == 0) ||
|
||||
(admin >= AccountStatus::GMAdmin && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
|
||||
))
|
||||
))
|
||||
) {
|
||||
line[0] = 0;
|
||||
uint32 rankstring = 0xFFFFFFFF;
|
||||
if((cle->Anon()==1 && cle->GetGM() && cle->Admin()>admin) || (idx>=20 && admin < AccountStatus::GMAdmin)){ //hide gms that are anon from lesser gms and normal players, cut off at 20
|
||||
uint32 plid=fromid;
|
||||
uint32 playerineqstring=5001;
|
||||
const char line2[]="---------------------------";
|
||||
uint8 unknown35=0x0A;
|
||||
uint32 unknown36=0;
|
||||
uint32 playersinzonestring=5028;
|
||||
|
||||
if (totalusers>20 && admin<AccountStatus::GMAdmin) {
|
||||
totalusers=20;
|
||||
playersinzonestring=5033;
|
||||
} else if(totalusers>1) {
|
||||
playersinzonestring=5036;
|
||||
}
|
||||
|
||||
uint32 unknown44[2];
|
||||
unknown44[0]=0;
|
||||
unknown44[1]=0;
|
||||
uint32 unknown52=totalusers;
|
||||
uint32 unknown56=1;
|
||||
auto pack2 = new ServerPacket(ServerOP_WhoAllReply, 64 + totallength + (49 * totalusers));
|
||||
memset(pack2->pBuffer,0,pack2->size);
|
||||
uchar *buffer=pack2->pBuffer;
|
||||
uchar *bufptr=buffer;
|
||||
//memset(buffer,0,pack2->size);
|
||||
memcpy(bufptr,&plid, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&playerineqstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&line2, strlen(line2));
|
||||
bufptr+=strlen(line2);
|
||||
memcpy(bufptr,&unknown35, sizeof(uint8));
|
||||
bufptr+=sizeof(uint8);
|
||||
memcpy(bufptr,&unknown36, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&playersinzonestring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown44[0], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown44[1], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown52, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown56, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&totalusers, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
|
||||
iterator.Reset();
|
||||
int idx=-1;
|
||||
while(iterator.MoreElements()) {
|
||||
cle = iterator.GetData();
|
||||
const char* tmpZone = ZoneName(cle->zone());
|
||||
|
||||
if (
|
||||
(cle->Online() >= CLE_Status::Zoning) &&
|
||||
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
|
||||
(whom == 0 || (
|
||||
((cle->Admin() >= AccountStatus::QuestTroupe && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
|
||||
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whom->wclass == 0xFFFF || (cle->class_() == whom->wclass && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whom->wrace == 0xFFFF || (cle->race() == whom->wrace && (cle->Anon()==0 || admin>cle->Admin()))) &&
|
||||
(whomlen == 0 || (
|
||||
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
|
||||
strncasecmp(cle->name(),whom->whom, whomlen) == 0 ||
|
||||
(strncasecmp(guild_mgr.GetGuildName(cle->GuildID()), whom->whom, whomlen) == 0) ||
|
||||
(admin >= AccountStatus::GMAdmin && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
|
||||
))
|
||||
))
|
||||
) {
|
||||
line[0] = 0;
|
||||
uint32 rankstring = 0xFFFFFFFF;
|
||||
// These lines can be simplified but easier to conceptualize this way
|
||||
if ((cle->Anon()==1 && cle->GetGM() && cle->Admin()>admin) || (idx>=20 && admin < AccountStatus::GMAdmin)) { //hide gms that are anon from lesser gms and normal players, cut off at 20
|
||||
rankstring = 0;
|
||||
iterator.Advance();
|
||||
continue;
|
||||
} else if (cle->Anon() == 1 && cle->Admin()>=admin && (whomlen == 0 || (whomlen !=0 && strncasecmp(cle->name(), whom->whom, whomlen) != 0))) {
|
||||
rankstring = 0;
|
||||
iterator.Advance();
|
||||
continue;
|
||||
} else if (cle->Anon() == 2 && cle->Admin()>=admin && (whomlen == 0 || (whomlen !=0 && strncasecmp(cle->name(), whom->whom, whomlen) != 0 && strncasecmp(guild_mgr.GetGuildName(cle->GuildID()), whom->whom, whomlen) != 0))) {
|
||||
rankstring = 0;
|
||||
iterator.Advance();
|
||||
continue;
|
||||
} else if (cle->GetGM()) {
|
||||
if (cle->Admin() >= AccountStatus::GMImpossible)
|
||||
if (cle->Admin() >= AccountStatus::GMImpossible) {
|
||||
rankstring = 5021;
|
||||
else if (cle->Admin() >= AccountStatus::GMMgmt)
|
||||
} else if (cle->Admin() >= AccountStatus::GMMgmt) {
|
||||
rankstring = 5020;
|
||||
else if (cle->Admin() >= AccountStatus::GMCoder)
|
||||
} else if (cle->Admin() >= AccountStatus::GMCoder) {
|
||||
rankstring = 5019;
|
||||
else if (cle->Admin() >= AccountStatus::GMAreas)
|
||||
} else if (cle->Admin() >= AccountStatus::GMAreas) {
|
||||
rankstring = 5018;
|
||||
else if (cle->Admin() >= AccountStatus::QuestMaster)
|
||||
} else if (cle->Admin() >= AccountStatus::QuestMaster) {
|
||||
rankstring = 5017;
|
||||
else if (cle->Admin() >= AccountStatus::GMLeadAdmin)
|
||||
} else if (cle->Admin() >= AccountStatus::GMLeadAdmin) {
|
||||
rankstring = 5016;
|
||||
else if (cle->Admin() >= AccountStatus::GMAdmin)
|
||||
} else if (cle->Admin() >= AccountStatus::GMAdmin) {
|
||||
rankstring = 5015;
|
||||
else if (cle->Admin() >= AccountStatus::GMStaff)
|
||||
} else if (cle->Admin() >= AccountStatus::GMStaff) {
|
||||
rankstring = 5014;
|
||||
else if (cle->Admin() >= AccountStatus::EQSupport)
|
||||
} else if (cle->Admin() >= AccountStatus::EQSupport) {
|
||||
rankstring = 5013;
|
||||
else if (cle->Admin() >= AccountStatus::GMTester)
|
||||
} else if (cle->Admin() >= AccountStatus::GMTester) {
|
||||
rankstring = 5012;
|
||||
else if (cle->Admin() >= AccountStatus::SeniorGuide)
|
||||
} else if (cle->Admin() >= AccountStatus::SeniorGuide) {
|
||||
rankstring = 5011;
|
||||
else if (cle->Admin() >= AccountStatus::QuestTroupe)
|
||||
} else if (cle->Admin() >= AccountStatus::QuestTroupe) {
|
||||
rankstring = 5010;
|
||||
else if (cle->Admin() >= AccountStatus::Guide)
|
||||
} else if (cle->Admin() >= AccountStatus::Guide) {
|
||||
rankstring = 5009;
|
||||
else if (cle->Admin() >= AccountStatus::ApprenticeGuide)
|
||||
} else if (cle->Admin() >= AccountStatus::ApprenticeGuide) {
|
||||
rankstring = 5008;
|
||||
else if (cle->Admin() >= AccountStatus::Steward)
|
||||
} else if (cle->Admin() >= AccountStatus::Steward) {
|
||||
rankstring = 5007;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
char guildbuffer[67]={0};
|
||||
if (cle->GuildID() != GUILD_NONE && cle->GuildID()>0)
|
||||
sprintf(guildbuffer,"<%s>", guild_mgr.GetGuildName(cle->GuildID()));
|
||||
uint32 formatstring=5025;
|
||||
if(cle->Anon()==1 && (admin<cle->Admin() || admin == AccountStatus::Player))
|
||||
formatstring=5024;
|
||||
else if(cle->Anon()==1 && admin>=cle->Admin() && admin > AccountStatus::Player)
|
||||
formatstring=5022;
|
||||
else if(cle->Anon()==2 && (admin<cle->Admin() || admin == AccountStatus::Player))
|
||||
formatstring=5023;//display guild
|
||||
else if(cle->Anon()==2 && admin>=cle->Admin() && admin > AccountStatus::Player)
|
||||
formatstring=5022;//display everything
|
||||
|
||||
//war* wars2 = (war*)pack2->pBuffer;
|
||||
idx++;
|
||||
char guildbuffer[67]={0};
|
||||
|
||||
uint32 plclass_=0;
|
||||
uint32 pllevel=0;
|
||||
uint32 pidstring=0xFFFFFFFF;//5003;
|
||||
uint32 plrace=0;
|
||||
uint32 zonestring=0xFFFFFFFF;
|
||||
uint32 plzone=0;
|
||||
uint32 unknown80[2];
|
||||
if(cle->Anon()==0 || (admin>=cle->Admin() && admin> AccountStatus::Player)){
|
||||
plclass_=cle->class_();
|
||||
pllevel=cle->level();
|
||||
if(admin>=AccountStatus::GMAdmin)
|
||||
pidstring=5003;
|
||||
plrace=cle->race();
|
||||
zonestring=5006;
|
||||
plzone=cle->zone();
|
||||
}
|
||||
if (cle->GuildID() != GUILD_NONE && cle->GuildID()>0) {
|
||||
sprintf(guildbuffer,"<%s>", guild_mgr.GetGuildName(cle->GuildID()));
|
||||
}
|
||||
|
||||
uint32 formatstring=5025;
|
||||
|
||||
if(admin>=cle->Admin() && admin > AccountStatus::Player)
|
||||
unknown80[0]=cle->Admin();
|
||||
else
|
||||
unknown80[0]=0xFFFFFFFF;
|
||||
unknown80[1]=0xFFFFFFFF;//1035
|
||||
if (cle->Anon()==1 && (admin<cle->Admin() || admin == AccountStatus::Player)) {
|
||||
formatstring=5024;
|
||||
} else if(cle->Anon()==1 && admin>=cle->Admin() && admin > AccountStatus::Player) {
|
||||
formatstring=5022;
|
||||
} else if(cle->Anon()==2 && (admin<cle->Admin() || admin == AccountStatus::Player)) {
|
||||
formatstring=5023;//display guild
|
||||
} else if(cle->Anon()==2 && admin>=cle->Admin() && admin > AccountStatus::Player) {
|
||||
formatstring=5022;//display everything
|
||||
}
|
||||
|
||||
//war* wars2 = (war*)pack2->pBuffer;
|
||||
|
||||
//char plstatus[20]={0};
|
||||
//sprintf(plstatus, "Status %i",cle->Admin());
|
||||
char plname[64]={0};
|
||||
strcpy(plname,cle->name());
|
||||
uint32 plclass_=0;
|
||||
uint32 pllevel=0;
|
||||
uint32 pidstring=0xFFFFFFFF;//5003;
|
||||
uint32 plrace=0;
|
||||
uint32 zonestring=0xFFFFFFFF;
|
||||
uint32 plzone=0;
|
||||
uint32 unknown80[2];
|
||||
|
||||
char placcount[30]={0};
|
||||
if(admin>=cle->Admin() && admin > AccountStatus::Player)
|
||||
strcpy(placcount,cle->AccountName());
|
||||
if (cle->Anon()==0 || (admin>=cle->Admin() && admin> AccountStatus::Player)) {
|
||||
plclass_=cle->class_();
|
||||
pllevel=cle->level();
|
||||
|
||||
memcpy(bufptr,&formatstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&pidstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plname, strlen(plname)+1);
|
||||
bufptr+=strlen(plname)+1;
|
||||
memcpy(bufptr,&rankstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&guildbuffer, strlen(guildbuffer)+1);
|
||||
bufptr+=strlen(guildbuffer)+1;
|
||||
memcpy(bufptr,&unknown80[0], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown80[1], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&zonestring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plzone, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plclass_, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&pllevel, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plrace, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
uint32 ending=0;
|
||||
memcpy(bufptr,&placcount, strlen(placcount)+1);
|
||||
bufptr+=strlen(placcount)+1;
|
||||
ending=207;
|
||||
memcpy(bufptr,&ending, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
if(admin>=AccountStatus::GMAdmin) {
|
||||
pidstring=5003;
|
||||
}
|
||||
plrace=cle->race();
|
||||
zonestring=5006;
|
||||
plzone=cle->zone();
|
||||
}
|
||||
|
||||
if (admin>=cle->Admin() && admin > AccountStatus::Player) {
|
||||
unknown80[0]=cle->Admin();
|
||||
} else {
|
||||
unknown80[0]=0xFFFFFFFF;
|
||||
}
|
||||
|
||||
unknown80[1]=0xFFFFFFFF;//1035
|
||||
|
||||
//char plstatus[20]={0};
|
||||
//sprintf(plstatus, "Status %i",cle->Admin());
|
||||
char plname[64]={0};
|
||||
strcpy(plname,cle->name());
|
||||
|
||||
char placcount[30]={0};
|
||||
if (admin>=cle->Admin() && admin > AccountStatus::Player) {
|
||||
strcpy(placcount,cle->AccountName());
|
||||
}
|
||||
|
||||
memcpy(bufptr,&formatstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&pidstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plname, strlen(plname)+1);
|
||||
bufptr+=strlen(plname)+1;
|
||||
memcpy(bufptr,&rankstring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&guildbuffer, strlen(guildbuffer)+1);
|
||||
bufptr+=strlen(guildbuffer)+1;
|
||||
memcpy(bufptr,&unknown80[0], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&unknown80[1], sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&zonestring, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plzone, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plclass_, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&pllevel, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
memcpy(bufptr,&plrace, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
uint32 ending=0;
|
||||
memcpy(bufptr,&placcount, strlen(placcount)+1);
|
||||
bufptr+=strlen(placcount)+1;
|
||||
ending=207;
|
||||
memcpy(bufptr,&ending, sizeof(uint32));
|
||||
bufptr+=sizeof(uint32);
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
//zoneserver_list.SendPacket(pack2); // NO NO NO WHY WOULD YOU SEND IT TO EVERY ZONE SERVER?!?
|
||||
SendPacket(to,pack2);
|
||||
safe_delete(pack2);
|
||||
}
|
||||
catch(...){
|
||||
|
||||
SendPacket(to,pack2);
|
||||
safe_delete(pack2);
|
||||
} catch(...) {
|
||||
LogInfo("Unknown error in world's SendWhoAll (probably mem error), ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const
|
||||
const std::string& account_name = database.GetAccountName(ret.account_id);
|
||||
|
||||
ret.account_name = account_name;
|
||||
ret.status = database.CheckStatus(ret.account_id);
|
||||
ret.status = database.GetAccountStatus(ret.account_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ std::vector<Reload> reload_types = {
|
||||
Reload{.command = "loot", .opcode = ServerOP_ReloadLoot, .desc = "Loot"},
|
||||
Reload{.command = "merchants", .opcode = ServerOP_ReloadMerchants, .desc = "Merchants"},
|
||||
Reload{.command = "npc_emotes", .opcode = ServerOP_ReloadNPCEmotes, .desc = "NPC Emotes"},
|
||||
Reload{.command = "npc_spells", .opcode = ServerOP_ReloadNPCSpells, .desc = "NPC Spells"},
|
||||
Reload{.command = "objects", .opcode = ServerOP_ReloadObjects, .desc = "Objects"},
|
||||
Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"},
|
||||
Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"},
|
||||
|
||||
@@ -66,7 +66,7 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
|
||||
|
||||
UsertoWorldRequestLegacy_Struct *utwr = (UsertoWorldRequestLegacy_Struct *) p.Data();
|
||||
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
|
||||
int16 status = database.CheckStatus(id);
|
||||
int16 status = database.GetAccountStatus(id);
|
||||
|
||||
LogDebug(
|
||||
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
||||
@@ -146,7 +146,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
||||
|
||||
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct *) p.Data();
|
||||
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
||||
int16 status = database.CheckStatus(id);
|
||||
int16 status = database.GetAccountStatus(id);
|
||||
|
||||
LogDebug(
|
||||
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
|
||||
|
||||
@@ -284,9 +284,13 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
||||
database.ClearRaid();
|
||||
database.ClearRaidDetails();
|
||||
database.ClearRaidLeader();
|
||||
LogInfo("Clearing guild online status");
|
||||
database.ClearGuildOnlineStatus();
|
||||
LogInfo("Clearing inventory snapshots");
|
||||
database.ClearInvSnapshots();
|
||||
LogInfo("Loading items");
|
||||
LogInfo("Clearing trader table details");
|
||||
database.ClearTraderDetails();
|
||||
|
||||
if (!content_db.LoadItems(hotfix_name)) {
|
||||
LogError("Error: Could not load item data. But ignoring");
|
||||
|
||||
+1
-1
@@ -670,7 +670,7 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha
|
||||
{
|
||||
case StartZoneIndex::Odus:
|
||||
{
|
||||
if (in_cc->deity == EQ::deity::DeityCazicThule) // Cazic-Thule Erudites go to Paineel
|
||||
if (in_cc->deity == Deity::CazicThule) // Cazic-Thule Erudites go to Paineel
|
||||
{
|
||||
in_pp->zone_id = Zones::PAINEEL; // paineel
|
||||
in_pp->binds[0].zone_id = Zones::PAINEEL;
|
||||
|
||||
@@ -1410,6 +1410,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_ReloadLevelEXPMods:
|
||||
case ServerOP_ReloadMerchants:
|
||||
case ServerOP_ReloadNPCEmotes:
|
||||
case ServerOP_ReloadNPCSpells:
|
||||
case ServerOP_ReloadObjects:
|
||||
case ServerOP_ReloadPerlExportSettings:
|
||||
case ServerOP_ReloadStaticZoneData:
|
||||
@@ -1423,6 +1424,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_ReloadLoot:
|
||||
case ServerOP_RezzPlayerAccept:
|
||||
case ServerOP_SpawnStatusChange:
|
||||
case ServerOP_TraderMessaging:
|
||||
case ServerOP_UpdateSpawn:
|
||||
case ServerOP_WWDialogueWindow:
|
||||
case ServerOP_WWLDoNUpdate:
|
||||
@@ -1743,6 +1745,18 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_BazaarPurchase: {
|
||||
auto in = (BazaarPurchaseMessaging_Struct *)pack->pBuffer;
|
||||
if (in->trader_buy_struct.trader_id <= 0) {
|
||||
LogTrading(
|
||||
"World Message <red>[{}] received with invalid trader_id <red>[{}]",
|
||||
"ServerOP_BazaarPurchase",
|
||||
in->trader_buy_struct.trader_id
|
||||
);
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(Zones::BAZAAR, pack);
|
||||
}
|
||||
default: {
|
||||
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
||||
DumpPacket(pack->pBuffer, pack->size);
|
||||
|
||||
+15
-13
@@ -167,7 +167,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
||||
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) {
|
||||
swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
|
||||
swarm_pet_npc->SetPetTargetLockID(targ->GetID());
|
||||
swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||
swarm_pet_npc->SetSpecialAbility(SpecialAbility::AggroImmunity, 1);
|
||||
}
|
||||
else {
|
||||
swarm_pet_npc->GetSwarmInfo()->target = 0;
|
||||
@@ -272,7 +272,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
||||
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) {
|
||||
swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
|
||||
swarm_pet_npc->SetPetTargetLockID(targ->GetID());
|
||||
swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||
swarm_pet_npc->SetSpecialAbility(SpecialAbility::AggroImmunity, 1);
|
||||
}
|
||||
else {
|
||||
swarm_pet_npc->GetSwarmInfo()->target = 0;
|
||||
@@ -401,7 +401,7 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *tar, uint32 d
|
||||
made_npc->npc_spells_id = 7;
|
||||
break;
|
||||
case Class::Paladin:
|
||||
//SPECATK_TRIPLE
|
||||
//SpecialAbility::TripleAttack
|
||||
strcpy(made_npc->special_abilities, "6,1");
|
||||
made_npc->current_hp = made_npc->current_hp * 150 / 100;
|
||||
made_npc->max_hp = made_npc->max_hp * 150 / 100;
|
||||
@@ -518,7 +518,7 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *tar, uint32 d
|
||||
|
||||
void Client::ResetAA()
|
||||
{
|
||||
SendClearAA();
|
||||
SendClearPlayerAA();
|
||||
RefundAA();
|
||||
|
||||
memset(&m_pp.aa_array[0], 0, sizeof(AA_Array) * MAX_PP_AA_ARRAY);
|
||||
@@ -540,6 +540,13 @@ void Client::ResetAA()
|
||||
++slot_id;
|
||||
}
|
||||
|
||||
database.DeleteCharacterAAs(CharacterID());
|
||||
}
|
||||
|
||||
void Client::ResetLeadershipAA()
|
||||
{
|
||||
SendClearLeadershipAA();
|
||||
|
||||
for (int slot_id = 0; slot_id < _maxLeaderAA; ++slot_id) {
|
||||
m_pp.leader_abilities.ranks[slot_id] = 0;
|
||||
}
|
||||
@@ -549,16 +556,9 @@ void Client::ResetAA()
|
||||
m_pp.group_leadership_exp = 0;
|
||||
m_pp.raid_leadership_exp = 0;
|
||||
|
||||
database.DeleteCharacterAAs(CharacterID());
|
||||
database.DeleteCharacterLeadershipAbilities(CharacterID());
|
||||
}
|
||||
|
||||
void Client::SendClearAA()
|
||||
{
|
||||
SendClearLeadershipAA();
|
||||
SendClearPlayerAA();
|
||||
}
|
||||
|
||||
void Client::SendClearPlayerAA()
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_ClearAA, 0);
|
||||
@@ -2178,7 +2178,8 @@ void Client::AutoGrantAAPoints() {
|
||||
}
|
||||
}
|
||||
|
||||
SendClearAA();
|
||||
SendClearLeadershipAA();
|
||||
SendClearPlayerAA();
|
||||
SendAlternateAdvancementTable();
|
||||
SendAlternateAdvancementPoints();
|
||||
SendAlternateAdvancementStats();
|
||||
@@ -2211,7 +2212,8 @@ void Client::GrantAllAAPoints(uint8 unlock_level)
|
||||
}
|
||||
|
||||
SaveAA();
|
||||
SendClearAA();
|
||||
SendClearLeadershipAA();
|
||||
SendClearPlayerAA();
|
||||
SendAlternateAdvancementTable();
|
||||
SendAlternateAdvancementPoints();
|
||||
SendAlternateAdvancementStats();
|
||||
|
||||
+17
-17
@@ -222,7 +222,7 @@ void NPC::DescribeAggro(Client *to_who, Mob *mob, bool verbose) {
|
||||
if (
|
||||
GetLevel() < RuleI(Aggro, MinAggroLevel) &&
|
||||
mob->GetLevelCon(GetLevel()) == ConsiderColor::Gray &&
|
||||
GetBodyType() != BT_Undead &&
|
||||
GetBodyType() != BodyType::Undead &&
|
||||
!AlwaysAggro()
|
||||
) {
|
||||
to_who->Message(
|
||||
@@ -412,13 +412,13 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
(
|
||||
!RuleB(Aggro, AggroPlayerPets) ||
|
||||
pet_owner->CastToClient()->GetGM() ||
|
||||
mob->GetSpecialAbility(IMMUNE_AGGRO)
|
||||
mob->GetSpecialAbility(SpecialAbility::AggroImmunity)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsNPC() && mob->IsNPC() && mob->GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
|
||||
if (IsNPC() && mob->IsNPC() && mob->GetSpecialAbility(SpecialAbility::NPCAggroImmunity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -452,8 +452,8 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't aggro new clients if we are already engaged unless PROX_AGGRO is set
|
||||
if (IsEngaged() && (!GetSpecialAbility(PROX_AGGRO) || (GetSpecialAbility(PROX_AGGRO) && !CombatRange(mob)))) {
|
||||
// Don't aggro new clients if we are already engaged unless SpecialAbility::ProximityAggro is set
|
||||
if (IsEngaged() && (!GetSpecialAbility(SpecialAbility::ProximityAggro) || (GetSpecialAbility(SpecialAbility::ProximityAggro) && !CombatRange(mob)))) {
|
||||
LogAggro(
|
||||
"[{}] is in combat, and does not have prox_aggro, or does and is out of combat range with [{}]",
|
||||
GetName(),
|
||||
@@ -496,7 +496,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
RuleB(Aggro, UseLevelAggro) &&
|
||||
(
|
||||
GetLevel() >= RuleI(Aggro, MinAggroLevel) ||
|
||||
GetBodyType() == BT_Undead ||
|
||||
GetBodyType() == BodyType::Undead ||
|
||||
AlwaysAggro() ||
|
||||
(
|
||||
mob->IsClient() &&
|
||||
@@ -524,7 +524,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
} else {
|
||||
if (
|
||||
(
|
||||
(RuleB(Aggro, UndeadAlwaysAggro) && GetBodyType() == BT_Undead) ||
|
||||
(RuleB(Aggro, UndeadAlwaysAggro) && GetBodyType() == BodyType::Undead) ||
|
||||
(GetINT() <= RuleI(Aggro, IntAggroThreshold)) ||
|
||||
AlwaysAggro() ||
|
||||
(
|
||||
@@ -634,19 +634,19 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
if (target->GetSpecialAbility(SpecialAbility::HarmFromClientImmunity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBot() && target->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
|
||||
if (IsBot() && target->GetSpecialAbility(SpecialAbility::BotDamageImmunity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsClient() && target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
|
||||
if (IsClient() && target->GetSpecialAbility(SpecialAbility::ClientDamageImmunity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsNPC() && target->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
|
||||
if (IsNPC() && target->GetSpecialAbility(SpecialAbility::NPCDamageImmunity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -671,9 +671,9 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
||||
target_owner = nullptr;
|
||||
|
||||
//cannot hurt untargetable mobs
|
||||
bodyType bt = target->GetBodyType();
|
||||
uint8 bt = target->GetBodyType();
|
||||
|
||||
if(bt == BT_NoTarget || bt == BT_NoTarget2) {
|
||||
if(bt == BodyType::NoTarget || bt == BodyType::NoTarget2) {
|
||||
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
||||
if (target->IsNPC()) {
|
||||
if (!target->CastToNPC()->GetSwarmOwner()) {
|
||||
@@ -1053,13 +1053,13 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
|
||||
float _zDist = m_Position.z - other->GetZ();
|
||||
_zDist *= _zDist;
|
||||
|
||||
if (GetSpecialAbility(NPC_CHASE_DISTANCE)) {
|
||||
if (GetSpecialAbility(SpecialAbility::NPCChaseDistance)) {
|
||||
|
||||
bool DoLoSCheck = true;
|
||||
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
|
||||
float min_distance = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
|
||||
float max_dist = static_cast<float>(GetSpecialAbilityParam(SpecialAbility::NPCChaseDistance, 0));
|
||||
float min_distance = static_cast<float>(GetSpecialAbilityParam(SpecialAbility::NPCChaseDistance, 1));
|
||||
|
||||
if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2)) {
|
||||
if (GetSpecialAbilityParam(SpecialAbility::NPCChaseDistance, 2)) {
|
||||
DoLoSCheck = false; //Ignore line of sight check
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin(
|
||||
|
||||
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
|
||||
ret.logged_in = true;
|
||||
ret.status = database.CheckStatus(ret.account_id);
|
||||
ret.status = database.GetAccountStatus(ret.account_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+398
-232
@@ -157,15 +157,18 @@ int Mob::compute_tohit(EQ::skills::SkillType skillinuse)
|
||||
{
|
||||
int tohit = GetSkill(EQ::skills::SkillOffense) + 7;
|
||||
tohit += GetSkill(skillinuse);
|
||||
if (IsNPC())
|
||||
|
||||
if (IsNPC()) {
|
||||
if (RuleB(Combat, UseMobStaticOffenseSkill)) {
|
||||
tohit = GetMobFixedWeaponSkill() + GetMobFixedOffenseSkill() + 7;
|
||||
}
|
||||
tohit += CastToNPC()->GetAccuracyRating();
|
||||
if (IsClient()) {
|
||||
} else if (IsClient()) {
|
||||
double reduction = CastToClient()->GetIntoxication() / 2.0;
|
||||
if (reduction > 20.0) {
|
||||
reduction = std::min((110 - reduction) / 100.0, 1.0);
|
||||
tohit = reduction * static_cast<double>(tohit);
|
||||
}
|
||||
else if (IsBerserk()) {
|
||||
} else if (IsBerserk()) {
|
||||
tohit += (GetLevel() * 2) / 5;
|
||||
}
|
||||
}
|
||||
@@ -191,8 +194,15 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
|
||||
// unsure on the stacking order of these effects, rather hard to parse
|
||||
// item mod2 accuracy isn't applied to range? Theory crafting and parses back it up I guess
|
||||
// mod2 accuracy -- flat bonus
|
||||
if (skill != EQ::skills::SkillArchery && skill != EQ::skills::SkillThrowing)
|
||||
if (skill != EQ::skills::SkillArchery && skill != EQ::skills::SkillThrowing) {
|
||||
accuracy += itembonuses.HitChance;
|
||||
} else {
|
||||
// Applying a scale factor as sources suggest Accuracy should reduce number of missing by 0.1% per point, so 150 = 15% reduction in misses.
|
||||
// Based on my calculator 150 Accuracy was reducing misses by too much (closer to 20%)
|
||||
// NOTE: This doesn't mean if you have a 30% miss chance you now miss 15%. It means if you have a 30% miss chance you now have a 30% * (100% - 15%) = 30% * 85% = 25.5% miss chance
|
||||
// Using same scale factor for Avoidance and Accuracy since they impact the formula about the same.
|
||||
accuracy += itembonuses.HitChance * RuleI(Combat, PCAccuracyAvoidanceMod2Scale) / 100;
|
||||
}
|
||||
|
||||
//518 Increase ATK accuracy by percentage, stackable
|
||||
auto atkhit_bonus = itembonuses.Attack_Accuracy_Max_Percent + aabonuses.Attack_Accuracy_Max_Percent + spellbonuses.Attack_Accuracy_Max_Percent;
|
||||
@@ -222,6 +232,11 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
|
||||
aabonuses.HitChanceEffect[skill] +
|
||||
spellbonuses.HitChanceEffect[skill];
|
||||
|
||||
if (skill == EQ::skills::SkillArchery) {
|
||||
hit_bonus += spellbonuses.increase_archery + aabonuses.increase_archery + itembonuses.increase_archery;
|
||||
hit_bonus -= hit_bonus * RuleR(Combat, ArcheryHitPenalty);
|
||||
}
|
||||
|
||||
accuracy = (accuracy * (100 + hit_bonus)) / 100;
|
||||
|
||||
// TODO: April 2003 added an archery/throwing PVP accuracy penalty while moving, should be in here some where,
|
||||
@@ -241,19 +256,44 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
|
||||
int Mob::compute_defense()
|
||||
{
|
||||
int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225;
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
if (IsOfClientBot()) {
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
|
||||
// In new code, AGI becomes a large contributor to avoidance at low levels, since AGI isn't capped by Level but Defense is
|
||||
// A scale factor is implemented for PCs to reduce the effect of AGI at low levels. This isn't applied to NPCs since they can be
|
||||
// easily controlled via the Database.
|
||||
if (RuleB(Combat, LegacyComputeDefense)) {
|
||||
int agi_scale_factor = 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
agi_scale_factor = std::min(1000, static_cast<int>(GetLevel()) * 1000 / 70); // Scales Agi Contribution for PC's Level, max Contribution at Level 70
|
||||
}
|
||||
|
||||
defense += agi_scale_factor * (800 * (GetAGI() - 40)) / 3600 / 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += GetHeroicAGI() / 10;
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance * RuleI(Combat, PCAccuracyAvoidanceMod2Scale) / 100; // item mod2
|
||||
} else {
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
}
|
||||
|
||||
|
||||
//516 SE_AC_Mitigation_Max_Percent
|
||||
auto ac_bonus = itembonuses.AC_Mitigation_Max_Percent + aabonuses.AC_Mitigation_Max_Percent + spellbonuses.AC_Mitigation_Max_Percent;
|
||||
if (ac_bonus)
|
||||
if (ac_bonus) {
|
||||
defense += round(static_cast<double>(defense) * static_cast<double>(ac_bonus) * 0.0001);
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
if (IsNPC())
|
||||
if (IsNPC()) {
|
||||
defense += CastToNPC()->GetAvoidanceRating();
|
||||
}
|
||||
|
||||
if (IsClient()) {
|
||||
double reduction = CastToClient()->GetIntoxication() / 2.0;
|
||||
@@ -398,12 +438,12 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
int counter_parry = 0;
|
||||
int counter_dodge = 0;
|
||||
|
||||
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)) {
|
||||
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 1);
|
||||
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||
counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3);
|
||||
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
||||
if (attacker->GetSpecialAbility(SpecialAbility::CounterAvoidDamage)) {
|
||||
counter_all = attacker->GetSpecialAbilityParam(SpecialAbility::CounterAvoidDamage, 0);
|
||||
counter_riposte = attacker->GetSpecialAbilityParam(SpecialAbility::CounterAvoidDamage, 1);
|
||||
counter_block = attacker->GetSpecialAbilityParam(SpecialAbility::CounterAvoidDamage, 2);
|
||||
counter_parry = attacker->GetSpecialAbilityParam(SpecialAbility::CounterAvoidDamage, 3);
|
||||
counter_dodge = attacker->GetSpecialAbilityParam(SpecialAbility::CounterAvoidDamage, 4);
|
||||
}
|
||||
|
||||
int modify_all = 0;
|
||||
@@ -412,12 +452,12 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||
int modify_parry = 0;
|
||||
int modify_dodge = 0;
|
||||
|
||||
if (GetSpecialAbility(MODIFY_AVOID_DAMAGE)) {
|
||||
modify_all = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 0);
|
||||
modify_riposte = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 1);
|
||||
modify_block = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 2);
|
||||
modify_parry = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 3);
|
||||
modify_dodge = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 4);
|
||||
if (GetSpecialAbility(SpecialAbility::ModifyAvoidDamage)) {
|
||||
modify_all = GetSpecialAbilityParam(SpecialAbility::ModifyAvoidDamage, 0);
|
||||
modify_riposte = GetSpecialAbilityParam(SpecialAbility::ModifyAvoidDamage, 1);
|
||||
modify_block = GetSpecialAbilityParam(SpecialAbility::ModifyAvoidDamage, 2);
|
||||
modify_parry = GetSpecialAbilityParam(SpecialAbility::ModifyAvoidDamage, 3);
|
||||
modify_dodge = GetSpecialAbilityParam(SpecialAbility::ModifyAvoidDamage, 4);
|
||||
}
|
||||
|
||||
/* Heroic Strikethrough Implementation per Dev Quotes (2018):
|
||||
@@ -960,6 +1000,10 @@ int Mob::GetBestMeleeSkill()
|
||||
int Mob::offense(EQ::skills::SkillType skill)
|
||||
{
|
||||
int offense = GetSkill(skill);
|
||||
if (RuleB(Combat, UseMobStaticOffenseSkill) && IsNPC() && !IsPet() && !IsTempPet()) {
|
||||
offense = GetMobFixedWeaponSkill();
|
||||
}
|
||||
|
||||
int stat_bonus = GetSTR();
|
||||
|
||||
switch (skill) {
|
||||
@@ -980,10 +1024,20 @@ int Mob::offense(EQ::skills::SkillType skill)
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat_bonus >= 75)
|
||||
if (stat_bonus >= 75) {
|
||||
offense += (2 * stat_bonus - 150) / 3;
|
||||
}
|
||||
|
||||
// GetATK() = ATK + itembonuses.ATK + spellbonuses.ATK. However, ATK appears to already be itembonuses.ATK + spellbonuses.ATK for PCs, so as is, it is double counting attack
|
||||
// This causes attack to be significantly more important than it should be based on era rule of thumbs. I do not want to change the GetATK() function in case doing so breaks something,
|
||||
// so instead I am just adding a /2 to remedy the double counting. NPCs do not have this issue, so they are broken up.
|
||||
// PCAttackPowerScaling is used to help bring attack power further in line with era estimates.
|
||||
if (IsOfClientBotMerc()) {
|
||||
offense += (GetATK() / 2 + GetPetATKBonusFromOwner()) * RuleI(Combat, PCAttackPowerScaling) / 100;
|
||||
} else {
|
||||
offense += GetATK();
|
||||
}
|
||||
|
||||
offense += GetATK() + GetPetATKBonusFromOwner();
|
||||
return offense;
|
||||
}
|
||||
|
||||
@@ -1039,6 +1093,26 @@ void Mob::MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions
|
||||
|
||||
auto roll = RollD20(hit.offense, mitigation);
|
||||
|
||||
// Add bonus to roll if level difference is sufficient
|
||||
const int level_diff = attacker->GetLevel() - GetLevel();
|
||||
const int level_diff_roll_check = RuleI(Combat, LevelDifferenceRollCheck);
|
||||
|
||||
if (level_diff_roll_check >= 0) {
|
||||
if (level_diff > level_diff_roll_check) {
|
||||
roll += RuleR(Combat, LevelDifferenceRollBonus);
|
||||
|
||||
if (roll > 2.0f) {
|
||||
roll = 2.0f;
|
||||
}
|
||||
} else if (level_diff < (-level_diff_roll_check)) {
|
||||
roll -= RuleR(Combat, LevelDifferenceRollBonus);
|
||||
|
||||
if (roll < 0.1f) {
|
||||
roll = 0.1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +0.5 for rounding, min to 1 dmg
|
||||
hit.damage_done = std::max(static_cast<int>(roll * static_cast<double>(hit.base_damage) + 0.5), 1);
|
||||
|
||||
@@ -1055,13 +1129,13 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
|
||||
int64 banedmg = 0;
|
||||
|
||||
//can't hit invulnerable stuff with weapons.
|
||||
if (against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)) {
|
||||
if (against->GetInvul() || against->GetSpecialAbility(SpecialAbility::MeleeImmunity)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//check to see if our weapons or fists are magical.
|
||||
if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) {
|
||||
if (GetSpecialAbility(SPECATK_MAGICAL)) {
|
||||
if (against->GetSpecialAbility(SpecialAbility::MeleeImmunityExceptMagical)) {
|
||||
if (GetSpecialAbility(SpecialAbility::MagicalAttack)) {
|
||||
dmg = 1;
|
||||
}
|
||||
//On live this occurs for ALL NPC's >= 10
|
||||
@@ -1104,7 +1178,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
|
||||
}
|
||||
|
||||
int eledmg = 0;
|
||||
if (!against->GetSpecialAbility(IMMUNE_MAGIC)) {
|
||||
if (!against->GetSpecialAbility(SpecialAbility::MagicImmunity)) {
|
||||
if (weapon_item && weapon_item->ElemDmgAmt) {
|
||||
//we don't check resist for npcs here
|
||||
eledmg = weapon_item->ElemDmgAmt;
|
||||
@@ -1112,7 +1186,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
|
||||
}
|
||||
}
|
||||
|
||||
if (against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) {
|
||||
if (against->GetSpecialAbility(SpecialAbility::MeleeImmunityExceptBane)) {
|
||||
if (weapon_item) {
|
||||
if (weapon_item->BaneDmgBody == against->GetBodyType()) {
|
||||
banedmg += weapon_item->BaneDmgAmt;
|
||||
@@ -1124,7 +1198,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
|
||||
}
|
||||
|
||||
if (!banedmg) {
|
||||
if (!GetSpecialAbility(SPECATK_BANE))
|
||||
if (!GetSpecialAbility(SpecialAbility::BaneAttack))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
@@ -1159,7 +1233,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
||||
int64 banedmg = 0;
|
||||
int x = 0;
|
||||
|
||||
if (!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE))
|
||||
if (!against || against->GetInvul() || against->GetSpecialAbility(SpecialAbility::MeleeImmunity))
|
||||
return 0;
|
||||
|
||||
// check for items being illegally attained
|
||||
@@ -1187,7 +1261,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
||||
}
|
||||
}
|
||||
|
||||
if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) {
|
||||
if (against->GetSpecialAbility(SpecialAbility::MeleeImmunityExceptMagical)) {
|
||||
if (weapon_item) {
|
||||
// check to see if the weapon is magic
|
||||
bool MagicWeapon = weapon_item->GetItemMagical(true) || spellbonuses.MagicWeapon || itembonuses.MagicWeapon;
|
||||
@@ -1224,7 +1298,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
||||
RuleI(Combat, PetAttackMagicLevel)) { // pets wouldn't actually use this but...
|
||||
dmg = 1; // it gives us an idea if we can hit
|
||||
}
|
||||
else if (MagicGloves || GetSpecialAbility(SPECATK_MAGICAL)) {
|
||||
else if (MagicGloves || GetSpecialAbility(SpecialAbility::MagicalAttack)) {
|
||||
dmg = 1;
|
||||
}
|
||||
else
|
||||
@@ -1254,7 +1328,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
||||
}
|
||||
|
||||
int eledmg = 0;
|
||||
if (!against->GetSpecialAbility(IMMUNE_MAGIC)) {
|
||||
if (!against->GetSpecialAbility(SpecialAbility::MagicImmunity)) {
|
||||
if (weapon_item && weapon_item->GetItem() && weapon_item->GetItemElementalFlag(true))
|
||||
// the client actually has the way this is done, it does not appear to check req!
|
||||
eledmg = against->ResistElementalWeaponDmg(weapon_item);
|
||||
@@ -1264,9 +1338,9 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
||||
(weapon_item->GetItemBaneDamageBody(true) || weapon_item->GetItemBaneDamageRace(true)))
|
||||
banedmg = against->CheckBaneDamage(weapon_item);
|
||||
|
||||
if (against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) {
|
||||
if (against->GetSpecialAbility(SpecialAbility::MeleeImmunityExceptBane)) {
|
||||
if (!banedmg) {
|
||||
if (!GetSpecialAbility(SPECATK_BANE))
|
||||
if (!GetSpecialAbility(SpecialAbility::BaneAttack))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
@@ -2506,7 +2580,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
auto app = new EQApplicationPacket(OP_Death, sizeof(Death_Struct));
|
||||
|
||||
auto d = (Death_Struct*) app->pBuffer;
|
||||
|
||||
|
||||
// Convert last message to color to avoid duplicate damage messages
|
||||
// that occur in these rare cases when this is the death blow.
|
||||
if (IsValidSpell(spell) &&
|
||||
@@ -3082,12 +3156,16 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
// Spell Casting Subtlety etc
|
||||
int64 hatemod = 100 + other->spellbonuses.hatemod + other->itembonuses.hatemod + other->aabonuses.hatemod;
|
||||
|
||||
if (hatemod < 1)
|
||||
if (hatemod < 1) {
|
||||
hatemod = 1;
|
||||
}
|
||||
hate = ((hate * (hatemod)) / 100);
|
||||
}
|
||||
else {
|
||||
hate += 100; // 100 bonus initial aggro
|
||||
} else {
|
||||
if (IsCharmed()){
|
||||
hate += RuleI(Aggro, InitialPetAggroBonus);
|
||||
} else {
|
||||
hate += RuleI(Aggro, InitialAggroBonus);
|
||||
}
|
||||
}
|
||||
|
||||
// Pet that is /pet hold on will not add to their hate list if they're not engaged
|
||||
@@ -3112,19 +3190,19 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) {
|
||||
if (IsFamiliar() || GetSpecialAbility(SpecialAbility::AggroImmunity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) {
|
||||
if (other->IsBot() && GetSpecialAbility(SpecialAbility::BotAggroImmunity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) {
|
||||
if (other->IsClient() && GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
|
||||
if (other->IsNPC() && GetSpecialAbility(SpecialAbility::NPCAggroImmunity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3136,12 +3214,12 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON)) {
|
||||
if (other->GetSpecialAbility(SpecialAbility::BeingAggroImmunity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(NPC_TUNNELVISION)) {
|
||||
int tv_mod = GetSpecialAbilityParam(NPC_TUNNELVISION, 0);
|
||||
if (GetSpecialAbility(SpecialAbility::TunnelVision)) {
|
||||
int tv_mod = GetSpecialAbilityParam(SpecialAbility::TunnelVision, 0);
|
||||
|
||||
Mob *top = GetTarget();
|
||||
if (top && top != other) {
|
||||
@@ -3221,10 +3299,10 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
// cb:2007-08-17
|
||||
// owner must get on list, but he's not actually gained any hate yet
|
||||
if (
|
||||
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(owner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(owner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(owner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
!owner->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!(owner->IsBot() && GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(owner->IsClient() && GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(owner->IsNPC() && GetSpecialAbility(SpecialAbility::NPCAggroImmunity))
|
||||
) {
|
||||
if (owner->IsClient() && !CheckAggro(owner)) {
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
@@ -3237,10 +3315,10 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
if (mypet && !mypet->IsHeld() && !mypet->IsPetStop()) { // I have a pet, add other to it
|
||||
if (
|
||||
!mypet->IsFamiliar() &&
|
||||
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(IsBot() && mypet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(IsClient() && mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(IsNPC() && mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
!mypet->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!(IsBot() && mypet->GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(IsClient() && mypet->GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(IsNPC() && mypet->GetSpecialAbility(SpecialAbility::NPCAggroImmunity))
|
||||
) {
|
||||
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
@@ -3248,10 +3326,10 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
|
||||
if (
|
||||
myowner->IsAIControlled() &&
|
||||
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(myowner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(myowner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(myowner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
!myowner->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!(myowner->IsBot() && GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(myowner->IsClient() && GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(myowner->IsNPC() && GetSpecialAbility(SpecialAbility::NPCAggroImmunity))
|
||||
) {
|
||||
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
@@ -4017,8 +4095,8 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
|
||||
// this should actually happen MUCH sooner, need to investigate though -- good enough for now
|
||||
if ((skill_used == EQ::skills::SkillArchery || skill_used == EQ::skills::SkillThrowing) && GetSpecialAbility(IMMUNE_RANGED_ATTACKS)) {
|
||||
LogCombat("Avoiding [{}] damage due to IMMUNE_RANGED_ATTACKS", damage);
|
||||
if ((skill_used == EQ::skills::SkillArchery || skill_used == EQ::skills::SkillThrowing) && GetSpecialAbility(SpecialAbility::RangedAttackImmunity)) {
|
||||
LogCombat("Avoiding [{}] damage due to SpecialAbility::RangedAttackImmunity", damage);
|
||||
damage = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
@@ -4096,12 +4174,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
Mob* pet = GetPet();
|
||||
pet &&
|
||||
!pet->IsFamiliar() &&
|
||||
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!pet->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!pet->IsEngaged() &&
|
||||
attacker &&
|
||||
!(attacker->IsBot() && pet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(attacker->IsClient() && pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(attacker->IsNPC() && pet->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||
!(attacker->IsBot() && pet->GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(attacker->IsClient() && pet->GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(attacker->IsNPC() && pet->GetSpecialAbility(SpecialAbility::NPCAggroImmunity)) &&
|
||||
attacker != this &&
|
||||
!attacker->IsCorpse() &&
|
||||
!pet->IsGHeld() &&
|
||||
@@ -4385,7 +4463,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
can_stun = false;
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(UNSTUNABLE)) {
|
||||
if (GetSpecialAbility(SpecialAbility::StunImmunity)) {
|
||||
can_stun = false;
|
||||
}
|
||||
}
|
||||
@@ -4515,10 +4593,10 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
//this was done to simplify the code here (since we can only effectively skip one mob on queue)
|
||||
eqFilterType filter;
|
||||
Mob* skip = attacker;
|
||||
if (attacker && attacker->IsPet() && !attacker->IsBot()) {
|
||||
Mob* owner = attacker ? attacker->GetOwner() : nullptr;
|
||||
if (attacker && owner && !attacker->IsBot()) {
|
||||
//attacker is a pet, let pet owners see their pet's damage
|
||||
Mob* owner = attacker->GetOwner();
|
||||
if (owner && owner->IsClient()) {
|
||||
if (owner->IsClient()) {
|
||||
if (FromDamageShield && damage > 0) {
|
||||
//special crap for spell damage, looks hackish to me
|
||||
char val1[20] = { 0 };
|
||||
@@ -4762,7 +4840,7 @@ void Mob::HealDamage(uint64 amount, Mob* caster, uint16 spell_id)
|
||||
else
|
||||
acthealed = amount;
|
||||
|
||||
if (acthealed > 100) {
|
||||
if (acthealed > RuleI(Spells, HealAmountMessageFilterThreshold)) {
|
||||
if (caster) {
|
||||
if (IsBuffSpell(spell_id)) { // hots
|
||||
// message to caster
|
||||
@@ -5110,7 +5188,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
}
|
||||
|
||||
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK)) {
|
||||
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SpecialAbility::RangedAttack)) {
|
||||
rangedattk = true;
|
||||
}
|
||||
|
||||
@@ -5310,6 +5388,101 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::RollMeleeCritCheck(Mob *defender, EQ::skills::SkillType skill)
|
||||
{
|
||||
// We either require an innate crit chance or some SPA 169 to crit
|
||||
bool innate_crit = false;
|
||||
int crit_chance = GetCriticalChanceBonus(skill);
|
||||
// Paladin check
|
||||
if (defender->IsUndeadForSlay()) {
|
||||
crit_chance = crit_chance + GetUndeadSlayRate();
|
||||
}
|
||||
|
||||
if (GetLevel() >= 12) {
|
||||
if (
|
||||
GetClass() == Class::Warrior ||
|
||||
(GetClass() == Class::Ranger && skill == EQ::skills::SkillArchery) ||
|
||||
(GetClass() == Class::Rogue && skill == EQ::skills::SkillThrowing) ||
|
||||
GetClass() == Class::Berserker
|
||||
) {
|
||||
innate_crit = true;
|
||||
}
|
||||
}
|
||||
|
||||
// we have a chance to crit!
|
||||
if (innate_crit || crit_chance) {
|
||||
int difficulty = 0;
|
||||
|
||||
if (skill == EQ::skills::SkillArchery) {
|
||||
difficulty = RuleI(Combat, ArcheryCritDifficulty);
|
||||
} else if (skill == EQ::skills::SkillThrowing) {
|
||||
difficulty = RuleI(Combat, ThrowingCritDifficulty);
|
||||
} else {
|
||||
difficulty = RuleI(Combat, MeleeCritDifficulty);
|
||||
}
|
||||
|
||||
int roll = zone->random.Int(1, difficulty);
|
||||
|
||||
int dex_bonus = GetDEX();
|
||||
|
||||
if (dex_bonus > 255) {
|
||||
dex_bonus = 255 + ((dex_bonus - 255) / 5);
|
||||
}
|
||||
|
||||
dex_bonus += 45; // chances did not match live without a small boost
|
||||
|
||||
// so if we have an innate crit we have a better chance, except for ber throwing
|
||||
if (!innate_crit || (GetClass() == Class::Berserker && skill == EQ::skills::SkillThrowing)) {
|
||||
dex_bonus = dex_bonus * 3 / 5;
|
||||
}
|
||||
|
||||
LogCombat("Crit Chance: dex_bonus ({}) * crit_chance ({}) / 100", dex_bonus, crit_chance);
|
||||
|
||||
if (crit_chance) {
|
||||
dex_bonus += dex_bonus * crit_chance / 100;
|
||||
}
|
||||
|
||||
// check if we crited
|
||||
LogCombat("Final Roll! Difficulty = [{}] -- Dex_Bonus = [{}] ", difficulty, dex_bonus);
|
||||
return (roll < dex_bonus);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Mob::GetUndeadSlayRate()
|
||||
{
|
||||
return aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0];
|
||||
}
|
||||
|
||||
void Mob::DoUndeadSlay(DamageHitInfo &hit, int crit_mod)
|
||||
{
|
||||
|
||||
int slay_damage_bonus = std::max(
|
||||
{ aabonuses.SlayUndead[1], itembonuses.SlayUndead[1], spellbonuses.SlayUndead[1] });
|
||||
|
||||
LogCombatDetail("Slayundead bonus [{}]", slay_damage_bonus);
|
||||
|
||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||
hit.damage_done = (hit.damage_done * slay_damage_bonus * crit_mod) / 100;
|
||||
hit.damage_done = static_cast<int>(hit.damage_done * RuleR(Combat, SlayDamageAdjustment));
|
||||
|
||||
LogCombatDetail("Slayundead damage [{}]", hit.damage_done);
|
||||
|
||||
int slay_sex = GetGender() == Gender::Female ? FEMALE_SLAYUNDEAD : MALE_SLAYUNDEAD;
|
||||
|
||||
entity_list.FilteredMessageString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
slay_sex, /* MessageFormat: %1's holy blade cleanses her target!(%2) */
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done) /* Message2 */
|
||||
);
|
||||
}
|
||||
|
||||
// a lot of good info: http://giline.versus.jp/shiden/damage_e.htm, http://giline.versus.jp/shiden/su.htm
|
||||
void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||
{
|
||||
#ifdef LUA_EQEMU
|
||||
@@ -5336,185 +5509,116 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsNPC() && !RuleB(Combat, NPCCanCrit))
|
||||
if (IsNPC() && !RuleB(Combat, NPCCanCrit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1: Try Slay Undead
|
||||
if (defender->GetBodyType() == BT_Undead || defender->GetBodyType() == BT_SummonedUndead ||
|
||||
defender->GetBodyType() == BT_Vampire) {
|
||||
int SlayRateBonus = aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] + itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] + spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD];
|
||||
if (SlayRateBonus) {
|
||||
float slayChance = static_cast<float>(SlayRateBonus) / 10000.0f;
|
||||
if (zone->random.Roll(slayChance)) {
|
||||
int SlayDmgBonus = std::max(
|
||||
{aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD], itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD], spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] });
|
||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||
hit.damage_done = (hit.damage_done * SlayDmgBonus) / 100;
|
||||
// Step 1: Check if we are critting
|
||||
if (!RollMeleeCritCheck(defender, hit.skill)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Female */
|
||||
if (GetGender() == Gender::Female) {
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
FEMALE_SLAYUNDEAD, /* MessageFormat: %1's holy blade cleanses her target!(%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||
);
|
||||
}
|
||||
/* Males and Neuter */
|
||||
else {
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
MALE_SLAYUNDEAD, /* MessageFormat: %1's holy blade cleanses his target!(%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int crit_mod = EQ::ClampLower((170 + GetCritDmgMod(hit.skill)), 100);
|
||||
|
||||
// Step 2: Calculate damage
|
||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||
int og_damage = hit.damage_done;
|
||||
hit.damage_done = hit.damage_done * crit_mod / 100;
|
||||
|
||||
LogCombatDetail("Crit info: [{}] scaled from: [{}] - IsUndeadForSlay: [{}]", hit.damage_done, og_damage, IsUndeadForSlay() ? "true" : "false");
|
||||
|
||||
// Try Slay Undead
|
||||
if (defender->IsUndeadForSlay()) {
|
||||
float chance = GetUndeadSlayRate() / 100.0f;
|
||||
LogCombatDetail("Trying Undead slay: Chance: [{}]", chance);
|
||||
|
||||
if(zone->random.Roll(chance)) {
|
||||
DoUndeadSlay(hit, crit_mod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2: Try Melee Critical
|
||||
// a lot of good info: http://giline.versus.jp/shiden/damage_e.htm, http://giline.versus.jp/shiden/su.htm
|
||||
// Step 3: Check deadly strike
|
||||
if (GetClass() == Class::Rogue && hit.skill == EQ::skills::SkillThrowing && BehindMob(defender, GetX(), GetY())) {
|
||||
int chance = GetLevel() * 12;
|
||||
if (zone->random.Int(1, 1000) < chance) {
|
||||
// Check assassinate
|
||||
int assassinate_damage = TryAssassinate(defender, hit.skill);
|
||||
|
||||
// We either require an innate crit chance or some SPA 169 to crit
|
||||
bool innate_crit = false;
|
||||
int crit_chance = GetCriticalChanceBonus(hit.skill);
|
||||
if ((GetClass() == Class::Warrior || GetClass() == Class::Berserker) && GetLevel() >= 12)
|
||||
innate_crit = true;
|
||||
else if (GetClass() == Class::Ranger && GetLevel() >= 12 && hit.skill == EQ::skills::SkillArchery)
|
||||
innate_crit = true;
|
||||
else if (GetClass() == Class::Rogue && GetLevel() >= 12 && hit.skill == EQ::skills::SkillThrowing)
|
||||
innate_crit = true;
|
||||
|
||||
// we have a chance to crit!
|
||||
if (innate_crit || crit_chance) {
|
||||
int difficulty = 0;
|
||||
if (hit.skill == EQ::skills::SkillArchery)
|
||||
difficulty = RuleI(Combat, ArcheryCritDifficulty);
|
||||
else if (hit.skill == EQ::skills::SkillThrowing)
|
||||
difficulty = RuleI(Combat, ThrowingCritDifficulty);
|
||||
else
|
||||
difficulty = RuleI(Combat, MeleeCritDifficulty);
|
||||
int roll = zone->random.Int(1, difficulty);
|
||||
|
||||
int dex_bonus = GetDEX();
|
||||
if (dex_bonus > 255)
|
||||
dex_bonus = 255 + ((dex_bonus - 255) / 5);
|
||||
dex_bonus += 45; // chances did not match live without a small boost
|
||||
|
||||
// so if we have an innate crit we have a better chance, except for ber throwing
|
||||
if (!innate_crit || (GetClass() == Class::Berserker && hit.skill == EQ::skills::SkillThrowing))
|
||||
dex_bonus = dex_bonus * 3 / 5;
|
||||
|
||||
if (crit_chance)
|
||||
dex_bonus += dex_bonus * crit_chance / 100;
|
||||
|
||||
// check if we crited
|
||||
if (roll < dex_bonus) {
|
||||
// step 1: check for finishing blow
|
||||
if (TryFinishingBlow(defender, hit.damage_done))
|
||||
if (assassinate_damage) {
|
||||
hit.damage_done = assassinate_damage;
|
||||
return;
|
||||
|
||||
// step 2: calculate damage
|
||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||
int og_damage = hit.damage_done;
|
||||
int crit_mod = 170 + GetCritDmgMod(hit.skill);
|
||||
if (crit_mod < 100) {
|
||||
crit_mod = 100;
|
||||
}
|
||||
|
||||
hit.damage_done = hit.damage_done * crit_mod / 100;
|
||||
LogCombat("Crit success roll [{}] dex chance [{}] og dmg [{}] crit_mod [{}] new dmg [{}]", roll, dex_bonus, og_damage, crit_mod, hit.damage_done);
|
||||
hit.damage_done = hit.damage_done * 200 / 100;
|
||||
|
||||
// step 3: check deadly strike
|
||||
if (GetClass() == Class::Rogue && hit.skill == EQ::skills::SkillThrowing) {
|
||||
if (BehindMob(defender, GetX(), GetY())) {
|
||||
int chance = GetLevel() * 12;
|
||||
if (zone->random.Int(1, 1000) < chance) {
|
||||
// step 3a: check assassinate
|
||||
int assdmg = TryAssassinate(defender, hit.skill); // I don't think this is right
|
||||
if (assdmg) {
|
||||
hit.damage_done = assdmg;
|
||||
return;
|
||||
}
|
||||
hit.damage_done = hit.damage_done * 200 / 100;
|
||||
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
DEADLY_STRIKE, /* MessageFormat: %1 scores a Deadly Strike!(%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 4: check crips
|
||||
// this SPA was reused on live ...
|
||||
bool berserk = spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA;
|
||||
if (!berserk) {
|
||||
if (zone->random.Roll(GetCrippBlowChance())) {
|
||||
berserk = true;
|
||||
} // TODO: Holyforge is suppose to have an innate extra undead chance? 1/5 which matches the SPA crip though ...
|
||||
}
|
||||
|
||||
if (IsBerserk() || berserk) {
|
||||
hit.damage_done += og_damage * 119 / 100;
|
||||
LogCombat("Crip damage [{}]", hit.damage_done);
|
||||
|
||||
entity_list.FilteredMessageCloseString(
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
CRIPPLING_BLOW, /* MessageFormat: %1 lands a Crippling Blow!(%2) */
|
||||
DEADLY_STRIKE, /* MessageFormat: %1 scores a Deadly Strike!(%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||
);
|
||||
itoa(hit.damage_done) /* Message2 */
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Crippling blows also have a chance to stun
|
||||
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
||||
// staggers message.
|
||||
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(UNSTUNABLE)) {
|
||||
defender->Emote("staggers.");
|
||||
defender->Stun(RuleI(Combat, StunDuration));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Step 4: check cripple
|
||||
bool berserk = spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA;
|
||||
|
||||
/* Normal Critical hit message */
|
||||
entity_list.FilteredMessageCloseString(
|
||||
if (!berserk && zone->random.Roll(GetCrippBlowChance())) {
|
||||
berserk = true;
|
||||
}
|
||||
|
||||
if (IsBerserk() || berserk) {
|
||||
hit.damage_done += og_damage * 119 / 100;
|
||||
LogCombatDetail("Crippling damage [{}]", hit.damage_done);
|
||||
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
|
||||
CRIPPLING_BLOW, /* MessageFormat: %1 lands a Crippling Blow!(%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||
itoa(hit.damage_done) /* Message2 */
|
||||
);
|
||||
|
||||
// Crippling blows also have a chance to stun
|
||||
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
||||
// staggers message.
|
||||
if (defender->GetLevel() <= RuleI(Combat, MaximumLevelStunsCripplingBlow) && !defender->GetSpecialAbility(SpecialAbility::StunImmunity)) {
|
||||
entity_list.MessageCloseString(
|
||||
defender,
|
||||
true,
|
||||
RuleI(Range, Emote),
|
||||
Chat::Emote,
|
||||
STAGGERS,
|
||||
GetName()
|
||||
);
|
||||
defender->Stun(RuleI(Combat, StunDuration));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normal Critical hit message */
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
RuleI(Range, CriticalDamage),
|
||||
Chat::MeleeCrit, /* Type: 301 */
|
||||
FilterMeleeCrits, /* FilterType: 12 */
|
||||
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
|
||||
0,
|
||||
GetCleanName(), /* Message1 */
|
||||
itoa(hit.damage_done) /* Message2 */
|
||||
);
|
||||
}
|
||||
|
||||
bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||
@@ -5809,6 +5913,65 @@ const DamageTable &Mob::GetDamageTable() const
|
||||
return which[level - 50];
|
||||
}
|
||||
|
||||
int Mob::GetMobFixedOffenseSkill()
|
||||
{
|
||||
// Due to new code using a combination of Offense and Weapon skill to determine hit, depending on the class
|
||||
// and weapon wielded by a mob, the hit rate of an equal level mob could vary between 15% and 60%, which made
|
||||
// many mobs far too easy. This particular call replaces the class based Offense Skill with a fixed value
|
||||
// equal to that of a Warrior of appropriate Level if UseMobFixedOffenseSkill flag is TRUE.
|
||||
|
||||
int level = EQ::ClampUpper(std::max(1, static_cast<int>(GetLevel())), 60);
|
||||
|
||||
if (level <= 40) {
|
||||
return (level * 5) + 5;
|
||||
} else if (EQ::ValueWithin(level, 41, 50)) {
|
||||
return 210;
|
||||
} else if (EQ::ValueWithin(level, 51, 58)) {
|
||||
return 210 + ((level - 50) * 5);
|
||||
}
|
||||
|
||||
return 252;
|
||||
}
|
||||
|
||||
int Mob::GetMobFixedWeaponSkill()
|
||||
{
|
||||
// Due to new code using a combination of Offense and Weapon skill to determine hit, depending on the class
|
||||
// and weapon wielded by a mob, the hit rate of an equal level mob could vary between 15% and 60%, which made
|
||||
// many mobs far too easy. This particular call replaces the weapon/class based Weapon Skill with a fixed value.
|
||||
// Two tables exist, one equal to a Warrior of appropriate level, and one modified to make hit rate equal to the old code
|
||||
// assuming the UseMobFixedOffenseSkill flag is set TRUE or the mob class is a Warrior (all the the bonus is in Weapon Skill).
|
||||
|
||||
int level = EQ::ClampUpper(std::max(1, static_cast<int>(GetLevel())), 70);
|
||||
|
||||
if (!RuleB(Combat, UseEnhancedMobStaticWeaponSkill)) {
|
||||
if (level <= 39) {
|
||||
return (level * 5) + 5;
|
||||
} else if (EQ::ValueWithin(level, 40, 50)) {
|
||||
return 200;
|
||||
} else if (EQ::ValueWithin(level, 51, 60)) {
|
||||
return 200 + ((level - 50) * 5);
|
||||
} else if (EQ::ValueWithin(level, 61, 65)) {
|
||||
return 250;
|
||||
}
|
||||
|
||||
return 250 + ((level - 65) * 5);
|
||||
}
|
||||
|
||||
if (level <= 39) {
|
||||
return (level * 6) - 1;
|
||||
} else if (EQ::ValueWithin(level, 45, 49)) {
|
||||
return 260;
|
||||
} else if (EQ::ValueWithin(level, 50, 54)) {
|
||||
return (level * 6) + 1;
|
||||
} else if (EQ::ValueWithin(level, 55, 59)) {
|
||||
return (level * 7) + 5;
|
||||
} else if (EQ::ValueWithin(level, 60, 65)) {
|
||||
return (level * 5) + 59;
|
||||
}
|
||||
|
||||
return 330 + (level - 66);
|
||||
}
|
||||
|
||||
void Mob::ApplyDamageTable(DamageHitInfo &hit)
|
||||
{
|
||||
#ifdef LUA_EQEMU
|
||||
@@ -6261,6 +6424,9 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
//Scale Factor for Archery Damage Tuning
|
||||
hit.damage_done *= RuleR(Combat, ArcheryBaseDamageBonus);
|
||||
}
|
||||
|
||||
int extra_mincap = 0;
|
||||
@@ -6319,7 +6485,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
// this appears where they do special attack dmg mods
|
||||
int spec_mod = 0;
|
||||
if (IsSpecialAttack(eSpecialAttacks::Rampage)) {
|
||||
int mod = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2);
|
||||
int mod = GetSpecialAbilityParam(SpecialAbility::Rampage, 2);
|
||||
if (mod > 0)
|
||||
spec_mod = mod;
|
||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||
@@ -6330,7 +6496,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
}
|
||||
}
|
||||
else if (IsSpecialAttack(eSpecialAttacks::AERampage)) {
|
||||
int mod = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2);
|
||||
int mod = GetSpecialAbilityParam(SpecialAbility::AreaRampage, 2);
|
||||
if (mod > 0)
|
||||
spec_mod = mod;
|
||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||
@@ -6633,8 +6799,8 @@ void NPC::SetAttackTimer()
|
||||
|
||||
//special offhand stuff
|
||||
if (i == EQ::invslot::slotSecondary) {
|
||||
// SPECATK_QUAD is uncheesable
|
||||
if (!CanThisClassDualWield() || (HasTwoHanderEquipped() && !GetSpecialAbility(SPECATK_QUAD))) {
|
||||
// SpecialAbility::QuadrupleAttack is uncheesable
|
||||
if (!CanThisClassDualWield() || (HasTwoHanderEquipped() && !GetSpecialAbility(SpecialAbility::QuadrupleAttack))) {
|
||||
attack_dw_timer.Disable();
|
||||
continue;
|
||||
}
|
||||
@@ -6792,18 +6958,18 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts, bool ram
|
||||
// thresholds, and if its truely random, then this should work
|
||||
// out reasonably and will save us compute resources.
|
||||
int32 RandRoll = zone->random.Int(0, 99);
|
||||
if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD))
|
||||
if ((CanThisClassDoubleAttack() || GetSpecialAbility(SpecialAbility::TripleAttack) || GetSpecialAbility(SpecialAbility::QuadrupleAttack))
|
||||
// check double attack, this is NOT the same rules that clients use...
|
||||
&&
|
||||
RandRoll < (GetLevel() + NPCDualAttackModifier)) {
|
||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||
// lets see if we can do a triple attack with the main hand
|
||||
// pets are excluded from triple and quads...
|
||||
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) && !IsPet() &&
|
||||
if ((GetSpecialAbility(SpecialAbility::TripleAttack) || GetSpecialAbility(SpecialAbility::QuadrupleAttack)) && !IsPet() &&
|
||||
RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
|
||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||
// now lets check the quad attack
|
||||
if (GetSpecialAbility(SPECATK_QUAD) && RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
if (GetSpecialAbility(SpecialAbility::QuadrupleAttack) && RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
@@ -6817,9 +6983,9 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts, bool ramp
|
||||
}
|
||||
|
||||
// Mobs will only dual wield w/ the flag or have a secondary weapon
|
||||
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
||||
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
||||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) ||
|
||||
// For now, SpecialAbility::QuadrupleAttack means innate DW when Combat:UseLiveCombatRounds is true
|
||||
if ((GetSpecialAbility(SpecialAbility::DualWield) ||
|
||||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SpecialAbility::QuadrupleAttack))) ||
|
||||
GetEquippedItemFromTextureSlot(EQ::textures::weaponSecondary) != 0) {
|
||||
if (CheckDualWield()) {
|
||||
Attack(target, EQ::invslot::slotSecondary, false, false, false, opts);
|
||||
|
||||
+2
-2
@@ -52,8 +52,8 @@ Beacon::Beacon(const glm::vec4 &in_pos, int lifetime) : Mob(
|
||||
Gender::Male, // in_gender
|
||||
Race::InvisibleMan, // in_race
|
||||
Class::None, // in_class
|
||||
BT_NoTarget, // in_bodytype
|
||||
0, // in_deity
|
||||
BodyType::NoTarget, // in_bodytype
|
||||
Deity::Unknown, // in_deity
|
||||
0, // in_level
|
||||
0, // in_npctype_id
|
||||
0.0f, // in_size
|
||||
|
||||
+23
-3
@@ -2220,7 +2220,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
{
|
||||
// These don't generate the IMMUNE_ATKSPEED message and the icon shows up
|
||||
// but have no effect on the mobs attack speed
|
||||
if (GetSpecialAbility(UNSLOWABLE))
|
||||
if (GetSpecialAbility(SpecialAbility::SlowImmunity))
|
||||
break;
|
||||
|
||||
if (effect_value < 0) //A few spells use negative values(Descriptions all indicate it should be a slow)
|
||||
@@ -2235,6 +2235,12 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_IncreaseArchery:
|
||||
{
|
||||
new_bonus->increase_archery += effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_TotalHP:
|
||||
{
|
||||
new_bonus->FlatMaxHPChange += effect_value;
|
||||
@@ -2432,6 +2438,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
case SE_CastingLevel2:
|
||||
{
|
||||
new_bonus->effective_casting_level += effect_value;
|
||||
|
||||
if (RuleB(Spells, SnareOverridesSpeedBonuses) && effect_value < 0) {
|
||||
new_bonus->movementspeed = effect_value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3350,6 +3360,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
|
||||
case SE_Blind:
|
||||
if (RuleB(Combat, AllowRaidTargetBlind) && IsRaidTarget()) { // do not blind raid targets
|
||||
break;
|
||||
}
|
||||
|
||||
new_bonus->IsBlind = true;
|
||||
break;
|
||||
|
||||
@@ -4147,7 +4161,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) {
|
||||
continue;
|
||||
|
||||
// TEST CODE: test for bazaar trader crashing with charm items
|
||||
if (Trader)
|
||||
if (IsTrader())
|
||||
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
||||
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
||||
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
||||
@@ -4239,7 +4253,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
continue;
|
||||
|
||||
// TEST CODE: test for bazaar trader crashing with charm items
|
||||
if (Trader)
|
||||
if (IsTrader())
|
||||
if (i >= EQ::invbag::GENERAL_BAGS_BEGIN && i <= EQ::invbag::GENERAL_BAGS_END) {
|
||||
EQ::ItemInstance* parent_item = m_inv.GetItem(EQ::InventoryProfile::CalcSlotId(i));
|
||||
if (parent_item && parent_item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)
|
||||
@@ -4533,6 +4547,12 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
if (negate_itembonus) { itembonuses.inhibitmelee = effect_value; }
|
||||
break;
|
||||
|
||||
case SE_IncreaseArchery:
|
||||
if (negate_spellbonus) { spellbonuses.increase_archery = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.increase_archery = effect_value; }
|
||||
if (negate_itembonus) { itembonuses.increase_archery = effect_value; }
|
||||
break;
|
||||
|
||||
case SE_TotalHP:
|
||||
if (negate_spellbonus) { spellbonuses.FlatMaxHPChange = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.FlatMaxHPChange = effect_value; }
|
||||
|
||||
+7
-7
@@ -652,7 +652,7 @@ NPCType *Bot::FillNPCTypeStruct(
|
||||
n->race = botRace;
|
||||
n->class_ = botClass;
|
||||
n->bodytype = 1;
|
||||
n->deity = EQ::deity::DeityAgnostic;
|
||||
n->deity = Deity::Agnostic1;
|
||||
n->level = botLevel;
|
||||
n->npc_spells_id = botSpellsID;
|
||||
n->AC = ac;
|
||||
@@ -712,7 +712,7 @@ NPCType *Bot::CreateDefaultNPCTypeStructForBot(
|
||||
n->race = botRace;
|
||||
n->class_ = botClass;
|
||||
n->bodytype = 1;
|
||||
n->deity = EQ::deity::DeityAgnostic;
|
||||
n->deity = Deity::Agnostic1;
|
||||
n->level = botLevel;
|
||||
n->AC = 12;
|
||||
n->ATK = 75;
|
||||
@@ -2418,14 +2418,14 @@ bool Bot::TryPrimaryWeaponAttacks(Mob* tar, const EQ::ItemInstance* p_item) {
|
||||
}
|
||||
|
||||
if (GetAppearance() == eaDead) { return false; }
|
||||
if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) {
|
||||
if (GetSpecialAbility(SpecialAbility::TripleAttack) && CheckBotDoubleAttack(true)) {
|
||||
|
||||
Attack(tar, EQ::invslot::slotPrimary, true);
|
||||
}
|
||||
|
||||
if (GetAppearance() == eaDead) { return false; }
|
||||
// quad attack, does this belong here??
|
||||
if (GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) {
|
||||
if (GetSpecialAbility(SpecialAbility::QuadrupleAttack) && CheckBotDoubleAttack(true)) {
|
||||
Attack(tar, EQ::invslot::slotPrimary, true);
|
||||
}
|
||||
}
|
||||
@@ -5481,13 +5481,13 @@ bool Bot::IsImmuneToSpell(uint16 spell_id, Mob *caster) {
|
||||
if (!Result) {
|
||||
if (caster->IsBot()) {
|
||||
if (spells[spell_id].target_type == ST_Undead) {
|
||||
if ((GetBodyType() != BT_SummonedUndead) && (GetBodyType() != BT_Undead) && (GetBodyType() != BT_Vampire)) {
|
||||
if ((GetBodyType() != BodyType::SummonedUndead) && (GetBodyType() != BodyType::Undead) && (GetBodyType() != BodyType::Vampire)) {
|
||||
LogSpellsDetail("Bot's target is not an undead");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (spells[spell_id].target_type == ST_Summoned) {
|
||||
if ((GetBodyType() != BT_SummonedUndead) && (GetBodyType() != BT_Summoned) && (GetBodyType() != BT_Summoned2) && (GetBodyType() != BT_Summoned3)) {
|
||||
if ((GetBodyType() != BodyType::SummonedUndead) && (GetBodyType() != BodyType::Summoned) && (GetBodyType() != BodyType::Summoned2) && (GetBodyType() != BodyType::Summoned3)) {
|
||||
LogSpellsDetail("Bot's target is not a summoned creature");
|
||||
return true;
|
||||
}
|
||||
@@ -5635,7 +5635,7 @@ int32 Bot::GenerateBaseManaPoints()
|
||||
|
||||
void Bot::GenerateSpecialAttacks() {
|
||||
if (((GetClass() == Class::Monk) || (GetClass() == Class::Warrior) || (GetClass() == Class::Ranger) || (GetClass() == Class::Berserker)) && (GetLevel() >= 60))
|
||||
SetSpecialAbility(SPECATK_TRIPLE, 1);
|
||||
SetSpecialAbility(SpecialAbility::TripleAttack, 1);
|
||||
}
|
||||
|
||||
bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) {
|
||||
|
||||
+8
-8
@@ -753,19 +753,19 @@ namespace ActionableTarget
|
||||
verified_friendly = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Animal:
|
||||
if (target_mob && target_mob->GetBodyType() == BT_Animal)
|
||||
if (target_mob && target_mob->GetBodyType() == BodyType::Animal)
|
||||
verified_friendly = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Undead:
|
||||
if (target_mob && target_mob->GetBodyType() == BT_Undead)
|
||||
if (target_mob && target_mob->GetBodyType() == BodyType::Undead)
|
||||
verified_friendly = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Summoned:
|
||||
if (target_mob && target_mob->GetBodyType() == BT_Summoned)
|
||||
if (target_mob && target_mob->GetBodyType() == BodyType::Summoned)
|
||||
verified_friendly = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Plant:
|
||||
if (target_mob && target_mob->GetBodyType() == BT_Plant)
|
||||
if (target_mob && target_mob->GetBodyType() == BodyType::Plant)
|
||||
verified_friendly = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Corpse:
|
||||
@@ -800,19 +800,19 @@ namespace ActionableTarget
|
||||
Mob* verified_enemy = nullptr;
|
||||
switch (target_type) {
|
||||
case BCEnum::TT_Animal:
|
||||
if (target_mob->GetBodyType() == BT_Animal)
|
||||
if (target_mob->GetBodyType() == BodyType::Animal)
|
||||
verified_enemy = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Undead:
|
||||
if (target_mob->GetBodyType() == BT_Undead)
|
||||
if (target_mob->GetBodyType() == BodyType::Undead)
|
||||
verified_enemy = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Summoned:
|
||||
if (target_mob->GetBodyType() == BT_Summoned)
|
||||
if (target_mob->GetBodyType() == BodyType::Summoned)
|
||||
verified_enemy = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Plant:
|
||||
if (target_mob->GetBodyType() == BT_Plant)
|
||||
if (target_mob->GetBodyType() == BodyType::Plant)
|
||||
verified_enemy = target_mob;
|
||||
break;
|
||||
case BCEnum::TT_Single:
|
||||
|
||||
@@ -771,9 +771,9 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
}
|
||||
|
||||
if (botClass == Class::Magician || botClass == Class::ShadowKnight || botClass == Class::Necromancer || botClass == Class::Paladin || botClass == Class::Ranger || botClass == Class::Druid || botClass == Class::Cleric) {
|
||||
if (tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire)
|
||||
if (tar->GetBodyType() == BodyType::Undead || tar->GetBodyType() == BodyType::SummonedUndead || tar->GetBodyType() == BodyType::Vampire)
|
||||
botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead);
|
||||
else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3)
|
||||
else if (tar->GetBodyType() == BodyType::Summoned || tar->GetBodyType() == BodyType::Summoned2 || tar->GetBodyType() == BodyType::Summoned3)
|
||||
botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned);
|
||||
}
|
||||
|
||||
@@ -784,7 +784,7 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
stunChance = 50;
|
||||
}
|
||||
|
||||
if (!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) {
|
||||
if (!tar->GetSpecialAbility(SpecialAbility::StunImmunity) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) {
|
||||
botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target);
|
||||
}
|
||||
}
|
||||
|
||||
+192
-38
@@ -95,8 +95,8 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
Gender::Male, // in_gender
|
||||
Race::Doug, // in_race
|
||||
Class::None, // in_class
|
||||
BT_Humanoid, // in_bodytype
|
||||
0, // in_deity
|
||||
BodyType::Humanoid, // in_bodytype
|
||||
Deity::Unknown, // in_deity
|
||||
0, // in_level
|
||||
0, // in_npctype_id
|
||||
0.0f, // in_size
|
||||
@@ -202,11 +202,11 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
ip = eqs->GetRemoteIP();
|
||||
port = ntohs(eqs->GetRemotePort());
|
||||
client_state = CLIENT_CONNECTING;
|
||||
Trader=false;
|
||||
SetTrader(false);
|
||||
Buyer = false;
|
||||
Haste = 0;
|
||||
CustomerID = 0;
|
||||
TraderID = 0;
|
||||
SetCustomerID(0);
|
||||
SetTraderID(0);
|
||||
TrackingID = 0;
|
||||
WID = 0;
|
||||
account_id = 0;
|
||||
@@ -421,8 +421,9 @@ Client::~Client() {
|
||||
if (merc)
|
||||
merc->Depop();
|
||||
|
||||
if(Trader)
|
||||
database.DeleteTraderItem(CharacterID());
|
||||
if(IsTrader()) {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
if(Buyer)
|
||||
ToggleBuyerMode(false);
|
||||
@@ -1849,7 +1850,7 @@ void Client::FriendsWho(char *FriendsString) {
|
||||
void Client::UpdateAdmin(bool from_database) {
|
||||
int16 tmp = admin;
|
||||
if (from_database) {
|
||||
admin = database.CheckStatus(account_id);
|
||||
admin = database.GetAccountStatus(account_id);
|
||||
}
|
||||
|
||||
if (tmp == admin && from_database) {
|
||||
@@ -2163,6 +2164,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.anon = m_pp.anon;
|
||||
ns->spawn.gm = GetGM() ? 1 : 0;
|
||||
ns->spawn.guildID = GuildID();
|
||||
ns->spawn.trader = IsTrader();
|
||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||
// ns->spawn.pvp = GetPVP(false) ? 1 : 0;
|
||||
ns->spawn.show_name = true;
|
||||
@@ -2669,8 +2671,8 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
|
||||
|
||||
if (against_who) {
|
||||
if (
|
||||
against_who->GetSpecialAbility(IMMUNE_AGGRO) ||
|
||||
against_who->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) ||
|
||||
against_who->GetSpecialAbility(SpecialAbility::AggroImmunity) ||
|
||||
against_who->GetSpecialAbility(SpecialAbility::ClientAggroImmunity) ||
|
||||
against_who->IsClient() ||
|
||||
GetLevelCon(against_who->GetLevel()) == ConsiderColor::Gray
|
||||
) {
|
||||
@@ -2801,7 +2803,7 @@ uint16 Client::MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 le
|
||||
return skill_caps.GetSkillCap(class_id, skill_id, level).cap;
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
uint8 Client::GetSkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
@@ -2811,7 +2813,7 @@ uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return skill_caps.GetTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
return skill_caps.GetSkillTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
}
|
||||
|
||||
uint16 Client::GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill)
|
||||
@@ -3199,9 +3201,7 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
percent_base = 70;
|
||||
}
|
||||
|
||||
int percent_bonus = 0;
|
||||
if (percent_base >= 70)
|
||||
percent_bonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + aabonuses.MaxBindWound;
|
||||
int percent_bonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + aabonuses.MaxBindWound;
|
||||
|
||||
int max_percent = percent_base + percent_bonus;
|
||||
if (max_percent < 0)
|
||||
@@ -3220,9 +3220,7 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
else if (GetSkill(EQ::skills::SkillBindWound) >= 12)
|
||||
bindhps = GetSkill(EQ::skills::SkillBindWound) / 4; // 4:1 skill-to-hp ratio
|
||||
|
||||
int bonus_hp_percent = 0;
|
||||
if (percent_base >= 70)
|
||||
bonus_hp_percent = spellbonuses.BindWound + itembonuses.BindWound + aabonuses.BindWound;
|
||||
int bonus_hp_percent = spellbonuses.BindWound + itembonuses.BindWound + aabonuses.BindWound;
|
||||
|
||||
bindhps += (bindhps * bonus_hp_percent) / 100;
|
||||
|
||||
@@ -3237,9 +3235,9 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
bindmob->SendHPUpdate();
|
||||
}
|
||||
else {
|
||||
Message(Chat::Yellow, "You cannot bind wounds above %d%% hitpoints", max_percent);
|
||||
Message(Chat::Yellow, "You cannot bind wounds above %d%% hitpoints.", max_percent);
|
||||
if (bindmob != this && bindmob->IsClient())
|
||||
bindmob->CastToClient()->Message(Chat::Yellow, "You cannot have your wounds bound above %d%% hitpoints", max_percent);
|
||||
bindmob->CastToClient()->Message(Chat::Yellow, "You cannot have your wounds bound above %d%% hitpoints.", max_percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3761,7 +3759,83 @@ void Client::Escape()
|
||||
MessageString(Chat::Skills, ESCAPE);
|
||||
}
|
||||
|
||||
float Client::CalcPriceMod(Mob* other, bool reverse)
|
||||
float Client::CalcClassicPriceMod(Mob* other, bool reverse) {
|
||||
float price_multiplier = 0.8f;
|
||||
|
||||
if (other && other->IsNPC()) {
|
||||
FACTION_VALUE faction_level = GetFactionLevel(CharacterID(), other->CastToNPC()->GetNPCTypeID(), GetRace(), GetClass(), GetDeity(), other->CastToNPC()->GetPrimaryFaction(), other);
|
||||
int32 cha = GetCHA();
|
||||
|
||||
if (faction_level <= FACTION_AMIABLY) {
|
||||
cha += 11; // amiable faction grants a defacto 11 charisma bonus
|
||||
}
|
||||
|
||||
uint8 greed = other->CastToNPC()->GetGreedPercent();
|
||||
|
||||
// Sony's precise algorithm is unknown, but this produces output that is virtually identical
|
||||
if (faction_level <= FACTION_INDIFFERENTLY) {
|
||||
if (cha > 75) {
|
||||
if (greed) {
|
||||
// this is derived from curve fitting to a lot of price data
|
||||
price_multiplier = -0.2487768 + (1.599635 - -0.2487768) / (1 + pow((cha / 135.1495), 1.001983));
|
||||
price_multiplier += (greed + 25u) / 100.0f; // default vendor markup is 25%; anything above that is 'greedy'
|
||||
price_multiplier = 1.0f / price_multiplier;
|
||||
}
|
||||
else {
|
||||
// non-greedy merchants use a linear scale
|
||||
price_multiplier = 1.0f - ((115.0f - cha) * 0.004f);
|
||||
}
|
||||
}
|
||||
else if (cha > 60) {
|
||||
price_multiplier = 1.0f / (1.25f + (greed / 100.0f));
|
||||
}
|
||||
else {
|
||||
price_multiplier = 1.0f / ((1.0f - (cha - 120.0f) / 220.0f) + (greed / 100.0f));
|
||||
}
|
||||
}
|
||||
else { // apprehensive
|
||||
if (cha > 75) {
|
||||
if (greed) {
|
||||
// this is derived from curve fitting to a lot of price data
|
||||
price_multiplier = -0.25f + (1.823662 - -0.25f) / (1 + (cha / 135.0f));
|
||||
price_multiplier += (greed + 25u) / 100.0f; // default vendor markup is 25%; anything above that is 'greedy'
|
||||
price_multiplier = 1.0f / price_multiplier;
|
||||
}
|
||||
else {
|
||||
price_multiplier = (100.0f - (145.0f - cha) / 2.8f) / 100.0f;
|
||||
}
|
||||
}
|
||||
else if (cha > 60) {
|
||||
price_multiplier = 1.0f / (1.4f + greed / 100.0f);
|
||||
}
|
||||
else {
|
||||
price_multiplier = 1.0f / ((1.0f + (143.574 - cha) / 196.434) + (greed / 100.0f));
|
||||
}
|
||||
}
|
||||
|
||||
float maxResult = 1.0f / 1.05; // price reduction caps at this amount
|
||||
if (price_multiplier > maxResult) {
|
||||
price_multiplier = maxResult;
|
||||
}
|
||||
|
||||
if (!reverse) {
|
||||
price_multiplier = 1.0f / price_multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
LogMerchants(
|
||||
"[{}] [{}] items at [{}] price multiplier [{}] [{}]",
|
||||
other->GetName(),
|
||||
reverse ? "buys" : "sells",
|
||||
price_multiplier,
|
||||
reverse ? "from" : "to",
|
||||
GetName()
|
||||
);
|
||||
|
||||
return price_multiplier;
|
||||
}
|
||||
|
||||
float Client::CalcNewPriceMod(Mob* other, bool reverse)
|
||||
{
|
||||
float chaformula = 0;
|
||||
if (other)
|
||||
@@ -3807,6 +3881,17 @@ float Client::CalcPriceMod(Mob* other, bool reverse)
|
||||
return chaformula; //Returns 1.10, expensive stuff!
|
||||
}
|
||||
|
||||
float Client::CalcPriceMod(Mob* other, bool reverse)
|
||||
{
|
||||
float price_mod = CalcNewPriceMod(other, reverse);
|
||||
|
||||
if (RuleB(Merchant, UseClassicPriceMod)) {
|
||||
price_mod = CalcClassicPriceMod(other, reverse);
|
||||
}
|
||||
|
||||
return price_mod;
|
||||
}
|
||||
|
||||
void Client::GetGroupAAs(GroupLeadershipAA_Struct *into) const {
|
||||
memcpy(into, &m_pp.leader_abilities.group, sizeof(GroupLeadershipAA_Struct));
|
||||
}
|
||||
@@ -4975,7 +5060,7 @@ void Client::HandleLDoNOpen(NPC *target)
|
||||
return;
|
||||
}
|
||||
|
||||
if (target->GetSpecialAbility(IMMUNE_OPEN))
|
||||
if (target->GetSpecialAbility(SpecialAbility::OpenImmunity))
|
||||
{
|
||||
LogDebug("[{}] tried to open [{}] but it was immune", GetName(), target->GetName());
|
||||
return;
|
||||
@@ -6372,9 +6457,9 @@ void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra)
|
||||
bool is_delete = spawn_type.find("delete") != std::string::npos;
|
||||
bool is_remove = spawn_type.find("remove") != std::string::npos;
|
||||
bool is_update = spawn_type.find("update") != std::string::npos;
|
||||
bool is_clone = spawn_type.find("clone") != std::string::npos;
|
||||
if (is_add || is_create) {
|
||||
// Add: extra tries to create the NPC ID within the range for the current Zone (Zone ID * 1000)
|
||||
// Create: extra sets the Respawn Timer for add
|
||||
// extra sets the Respawn Timer for add/create
|
||||
content_db.NPCSpawnDB(
|
||||
is_add ? NPCSpawnTypes::AddNewSpawngroup : NPCSpawnTypes::CreateNewSpawn,
|
||||
zone->GetShortName(),
|
||||
@@ -6398,7 +6483,17 @@ void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra)
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion(),
|
||||
this,
|
||||
target_npc->CastToNPC()
|
||||
target_npc->CastToNPC(),
|
||||
extra
|
||||
);
|
||||
} else if (is_clone) {
|
||||
content_db.NPCSpawnDB(
|
||||
NPCSpawnTypes::AddSpawnFromSpawngroup,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion(),
|
||||
this,
|
||||
target_npc->CastToNPC(),
|
||||
extra
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6689,6 +6784,8 @@ bool Client::RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount)
|
||||
const uint32 new_amount = (current_amount - amount);
|
||||
|
||||
alternate_currency[currency_id] = new_amount;
|
||||
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_amount);
|
||||
SendAlternateCurrencyValue(currency_id);
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_ALT_CURRENCY_LOSS)) {
|
||||
const std::string &export_string = fmt::format(
|
||||
@@ -6895,6 +6992,10 @@ void Client::AddAutoXTarget(Mob *m, bool send)
|
||||
|
||||
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
|
||||
{
|
||||
if (!XTargettingAvailable() || !m || !m_activeautohatermgr) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_activeautohatermgr->decrement_count(m);
|
||||
// now we may need to clean up our CurrentTargetNPC entries
|
||||
for (int i = 0; i < GetMaxXTargets(); ++i) {
|
||||
@@ -9069,29 +9170,32 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
|
||||
*
|
||||
* @param player_name
|
||||
*/
|
||||
bool Client::GotoPlayer(std::string player_name)
|
||||
bool Client::GotoPlayer(const std::string& player_name)
|
||||
{
|
||||
const auto& l = CharacterDataRepository::GetWhere(
|
||||
database,
|
||||
fmt::format("name = '{}' AND last_login > (UNIX_TIMESTAMP() - 600) LIMIT 1", player_name)
|
||||
fmt::format(
|
||||
"name = '{}' AND last_login > (UNIX_TIMESTAMP() - 600) LIMIT 1",
|
||||
Strings::Escape(player_name)
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& c = l[0];
|
||||
const auto& e = l.front();
|
||||
|
||||
if (c.zone_instance > 0 && !database.CheckInstanceExists(c.zone_instance)) {
|
||||
if (e.zone_instance > 0 && !database.CheckInstanceExists(e.zone_instance)) {
|
||||
Message(Chat::Yellow, "Instance no longer exists...");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c.zone_instance > 0) {
|
||||
database.AddClientToInstance(c.zone_instance, CharacterID());
|
||||
if (e.zone_instance > 0) {
|
||||
database.AddClientToInstance(e.zone_instance, CharacterID());
|
||||
}
|
||||
|
||||
MovePC(c.zone_id, c.zone_instance, c.x, c.y, c.z, c.heading);
|
||||
MovePC(e.zone_id, e.zone_instance, e.x, e.y, e.z, e.heading);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -9270,6 +9374,7 @@ void Client::ShowDevToolsMenu()
|
||||
|
||||
menu_reload_five += Saylink::Silent("#reload merchants", "Merchants");
|
||||
menu_reload_five += " | " + Saylink::Silent("#reload npc_emotes", "NPC Emotes");
|
||||
menu_reload_five += " | " + Saylink::Silent("#reload npc_spells", "NPC Spells");
|
||||
menu_reload_five += " | " + Saylink::Silent("#reload objects", "Objects");
|
||||
menu_reload_five += " | " + Saylink::Silent("#reload opcodes", "Opcodes");
|
||||
|
||||
@@ -11351,6 +11456,15 @@ void Client::SendReloadCommandMessages() {
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto npc_spells_link = Saylink::Silent("#reload npc_spells");
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Usage: {} - Reloads NPC Spells globally",
|
||||
npc_spells_link
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto objects_link = Saylink::Silent("#reload objects");
|
||||
|
||||
Message(
|
||||
@@ -11672,11 +11786,11 @@ void Client::RegisterBug(BugReport_Struct* r) {
|
||||
b.target_id = r->target_id;
|
||||
b.target_name = r->target_name;
|
||||
b.optional_info_mask = r->optional_info_mask;
|
||||
b._can_duplicate = ((r->optional_info_mask & EQ::bug::infoCanDuplicate) != 0 ? 1 : 0);
|
||||
b._crash_bug = ((r->optional_info_mask & EQ::bug::infoCrashBug) != 0 ? 1 : 0);
|
||||
b._target_info = ((r->optional_info_mask & EQ::bug::infoTargetInfo) != 0 ? 1 : 0);
|
||||
b._character_flags = ((r->optional_info_mask & EQ::bug::infoCharacterFlags) != 0 ? 1 : 0);
|
||||
b._unknown_value = ((r->optional_info_mask & EQ::bug::infoUnknownValue) != 0 ? 1 : 0);
|
||||
b._can_duplicate = ((r->optional_info_mask & Bug::InformationFlag::Repeatable) != 0 ? 1 : 0);
|
||||
b._crash_bug = ((r->optional_info_mask & Bug::InformationFlag::Crash) != 0 ? 1 : 0);
|
||||
b._target_info = ((r->optional_info_mask & Bug::InformationFlag::TargetInfo) != 0 ? 1 : 0);
|
||||
b._character_flags = ((r->optional_info_mask & Bug::InformationFlag::CharacterFlags) != 0 ? 1 : 0);
|
||||
b._unknown_value = ((r->optional_info_mask & Bug::InformationFlag::Unknown) != 0 ? 1 : 0);
|
||||
b.bug_report = r->bug_report;
|
||||
b.system_info = r->system_info;
|
||||
|
||||
@@ -11860,7 +11974,7 @@ void Client::SendPath(Mob* target)
|
||||
RuleB(Bazaar, EnableWarpToTrader) &&
|
||||
target->IsClient() &&
|
||||
(
|
||||
target->CastToClient()->Trader ||
|
||||
target->CastToClient()->IsTrader() ||
|
||||
target->CastToClient()->Buyer
|
||||
)
|
||||
) {
|
||||
@@ -12425,3 +12539,43 @@ uint16 Client::GetSkill(EQ::skills::SkillType skill_id) const
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
|
||||
{
|
||||
EQ::ItemInstance *item = nullptr;
|
||||
static const int16 slots[][2] = {
|
||||
{ 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::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_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 },
|
||||
};
|
||||
int16 removed_count = 0;
|
||||
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
|
||||
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
|
||||
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
|
||||
if (removed_count == quantity) {
|
||||
break;
|
||||
}
|
||||
|
||||
item = GetInv().GetItem(slot_id);
|
||||
if (item && item->GetSerialNumber() == serial_number) {
|
||||
int16 charges = item->IsStackable() ? item->GetCharges() : 0;
|
||||
int16 stack_size = std::max(charges, static_cast<int16>(1));
|
||||
if ((removed_count + stack_size) <= quantity) {
|
||||
removed_count += stack_size;
|
||||
DeleteItemInInventory(slot_id, charges, true);
|
||||
} else {
|
||||
int16 amount_left = (quantity - removed_count);
|
||||
if (amount_left > 0 && stack_size >= amount_left) {
|
||||
removed_count += amount_left;
|
||||
DeleteItemInInventory(slot_id, amount_left, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-18
@@ -69,6 +69,7 @@ namespace EQ
|
||||
#include "../common/events/player_events.h"
|
||||
#include "../common/data_verification.h"
|
||||
#include "../common/repositories/character_parcels_repository.h"
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// since windows defines these within windef.h (which windows.h include)
|
||||
@@ -257,7 +258,7 @@ public:
|
||||
|
||||
void SendChatLineBreak(uint16 color = Chat::White);
|
||||
|
||||
bool GotoPlayer(std::string player_name);
|
||||
bool GotoPlayer(const std::string& player_name);
|
||||
bool GotoPlayerGroup(const std::string& player_name);
|
||||
bool GotoPlayerRaid(const std::string& player_name);
|
||||
|
||||
@@ -280,10 +281,20 @@ public:
|
||||
void AI_Stop();
|
||||
void AI_Process();
|
||||
void AI_SpellCast();
|
||||
void Trader_ShowItems();
|
||||
void TraderShowItems();
|
||||
void Trader_CustomerBrowsing(Client *Customer);
|
||||
void Trader_EndTrader();
|
||||
void Trader_StartTrader();
|
||||
|
||||
void TraderEndTrader();
|
||||
void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||
void SendBazaarDone(uint32 trader_id);
|
||||
void SendBulkBazaarTraders();
|
||||
void DoBazaarInspect(const BazaarInspect_Struct &in);
|
||||
void SendBazaarDeliveryCosts();
|
||||
static std::string DetermineMoneyString(uint64 copper);
|
||||
|
||||
void SendTraderMode(BazaarTraderBarterActions status);
|
||||
void TraderStartTrader(const EQApplicationPacket *app);
|
||||
// void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||
uint8 WithCustomer(uint16 NewCustomer);
|
||||
void KeyRingLoad();
|
||||
void KeyRingAdd(uint32 item_id);
|
||||
@@ -315,15 +326,17 @@ public:
|
||||
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);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity, TraderRepository::Trader &trader);
|
||||
void DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||
EQ::ItemInstance* FindTraderItemBySerialNumber(int32 SerialNumber);
|
||||
void FindAndNukeTraderItem(int32 item_id,int16 quantity,Client* customer,uint16 traderslot);
|
||||
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
|
||||
void FindAndNukeTraderItem(int32 serial_number, int16 quantity, Client* customer, uint16 trader_slot);
|
||||
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, int32 serial_number, int32 item_id = 0);
|
||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs, Client* trader, const EQApplicationPacket* app);
|
||||
void BuyTraderItemOutsideBazaar(TraderBuy_Struct* tbs, const EQApplicationPacket* app);
|
||||
void FinishTrade(
|
||||
Mob *with,
|
||||
bool finalizer = false,
|
||||
@@ -335,7 +348,7 @@ public:
|
||||
void DoParcelCancel();
|
||||
void DoParcelSend(const Parcel_Struct *parcel_in);
|
||||
void DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in);
|
||||
void SendParcel(const Parcel_Struct &parcel);
|
||||
void SendParcel(Parcel_Struct &parcel);
|
||||
void SendParcelStatus();
|
||||
void SendParcelAck();
|
||||
void SendParcelRetrieveAck();
|
||||
@@ -355,6 +368,13 @@ public:
|
||||
int32 FindNextFreeParcelSlot(uint32 char_id);
|
||||
void SendParcelIconStatus();
|
||||
|
||||
void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action);
|
||||
void SendBecomeTrader(BazaarTraderBarterActions action, uint32 trader_id);
|
||||
|
||||
bool IsThereACustomer() const { return customer_id ? true : false; }
|
||||
uint32 GetCustomerID() { return customer_id; }
|
||||
void SetCustomerID(uint32 id) { customer_id = id; }
|
||||
|
||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||
void ShowBuyLines(const EQApplicationPacket *app);
|
||||
void SellToBuyer(const EQApplicationPacket *app);
|
||||
@@ -485,7 +505,7 @@ public:
|
||||
|
||||
void ServerFilter(SetServerFilter_Struct* filter);
|
||||
void BulkSendTraderInventory(uint32 char_id);
|
||||
void SendSingleTraderItem(uint32 char_id, int uniqueid);
|
||||
void SendSingleTraderItem(uint32 char_id, int serial_number);
|
||||
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
||||
|
||||
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
||||
@@ -846,7 +866,7 @@ public:
|
||||
|
||||
uint16 MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skill_id) const { return MaxSkill(skill_id, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
uint8 GetSkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
void MaxSkills();
|
||||
|
||||
void SendTradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid);
|
||||
@@ -1009,8 +1029,8 @@ public:
|
||||
|
||||
//old AA methods that we still use
|
||||
void ResetAA();
|
||||
void ResetLeadershipAA();
|
||||
void RefundAA();
|
||||
void SendClearAA();
|
||||
void SendClearLeadershipAA();
|
||||
void SendClearPlayerAA();
|
||||
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
||||
@@ -1042,6 +1062,7 @@ public:
|
||||
void SetItemCooldown(uint32 item_id, bool use_saved_timer = false, uint32 in_seconds = 1);
|
||||
uint32 GetItemCooldown(uint32 item_id);
|
||||
void RemoveItem(uint32 item_id, uint32 quantity = 1);
|
||||
void RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity = 1);
|
||||
bool SwapItem(MoveItem_Struct* move_in);
|
||||
void SwapItemResync(MoveItem_Struct* move_slots);
|
||||
void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false);
|
||||
@@ -1066,7 +1087,11 @@ public:
|
||||
bool IsValidSlot(uint32 slot);
|
||||
bool IsBankSlot(uint32 slot);
|
||||
|
||||
inline bool IsTrader() const { return(Trader); }
|
||||
bool IsTrader() const { return trader; }
|
||||
void SetTrader(bool status) { trader = status; }
|
||||
uint16 GetTraderID() { return trader_id; }
|
||||
void SetTraderID(uint16 id) { trader_id = id; }
|
||||
|
||||
inline bool IsBuyer() const { return(Buyer); }
|
||||
eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; }
|
||||
void SetFilter(eqFilterType filter_id, eqFilterMode filter_mode) { ClientFilters[filter_id] = filter_mode; }
|
||||
@@ -1126,6 +1151,8 @@ public:
|
||||
void GoFish(bool guarantee = false, bool use_bait = true);
|
||||
void ForageItem(bool guarantee = false);
|
||||
//Calculate vendor price modifier based on CHA: (reverse==selling)
|
||||
float CalcClassicPriceMod(Mob* other = 0, bool reverse = false);
|
||||
float CalcNewPriceMod(Mob* other = 0, bool reverse = false);
|
||||
float CalcPriceMod(Mob* other = 0, bool reverse = false);
|
||||
void ResetTrade();
|
||||
void DropInst(const EQ::ItemInstance* inst);
|
||||
@@ -1797,8 +1824,6 @@ private:
|
||||
void RemoveBandolier(const EQApplicationPacket *app);
|
||||
void SetBandolier(const EQApplicationPacket *app);
|
||||
|
||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
||||
|
||||
int32 CalcItemATKCap() final;
|
||||
int32 CalcHaste();
|
||||
|
||||
@@ -1877,13 +1902,13 @@ private:
|
||||
uint16 controlling_boat_id;
|
||||
uint16 controlled_mob_id;
|
||||
uint16 TrackingID;
|
||||
uint16 CustomerID;
|
||||
uint16 TraderID;
|
||||
bool trader;
|
||||
uint16 trader_id;
|
||||
uint16 customer_id;
|
||||
uint32 account_creation;
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
uint8 mercSlot; // selected merc slot
|
||||
bool Trader;
|
||||
bool Buyer;
|
||||
std::string BuyerWelcomeMessage;
|
||||
int32 m_parcel_platinum;
|
||||
|
||||
@@ -289,7 +289,7 @@ int64 Client::CalcHPRegen(bool bCombat)
|
||||
|
||||
if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
|
||||
auto max_hp = GetMaxHP();
|
||||
int64 fast_regen = 6 * (max_hp / (zone ? zone->newzone_data.fast_regen_hp : 180));
|
||||
int64 fast_regen = 6 * (max_hp / (zone && zone->newzone_data.fast_regen_hp > 0 ? zone->newzone_data.fast_regen_hp : 180));
|
||||
if (base < fast_regen) // weird, but what the client is doing
|
||||
base = fast_regen;
|
||||
}
|
||||
|
||||
+264
-348
@@ -679,7 +679,7 @@ void Client::CompleteConnect()
|
||||
break;
|
||||
}
|
||||
case SE_SummonHorse: {
|
||||
if (RuleB(Character, PreventMountsFromZoning)) {
|
||||
if (RuleB(Character, PreventMountsFromZoning) || !zone->CanCastOutdoor()) {
|
||||
BuffFadeByEffect(SE_SummonHorse);
|
||||
} else {
|
||||
SummonHorse(buffs[j1].spellid);
|
||||
@@ -918,6 +918,10 @@ void Client::CompleteConnect()
|
||||
CastToClient()->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
|
||||
SendBulkBazaarTraders();
|
||||
}
|
||||
|
||||
// TODO: load these states
|
||||
// We at least will set them to the correct state for now
|
||||
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
|
||||
@@ -1074,9 +1078,6 @@ void Client::Handle_Connect_OP_ReqClientSpawn(const EQApplicationPacket *app)
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (strncasecmp(zone->GetShortName(), "bazaar", 6) == 0)
|
||||
SendBazaarWelcome();
|
||||
|
||||
conn_state = ZoneContentsSent;
|
||||
|
||||
return;
|
||||
@@ -3787,7 +3788,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
|
||||
case Barter_BuyerModeOn:
|
||||
{
|
||||
if (!Trader) {
|
||||
if (!IsTrader()) {
|
||||
ToggleBuyerMode(true);
|
||||
}
|
||||
else {
|
||||
@@ -3864,7 +3865,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
|
||||
case Barter_Welcome:
|
||||
{
|
||||
SendBazaarWelcome();
|
||||
//SendBazaarWelcome();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3918,7 +3919,7 @@ void Client::Handle_OP_BazaarInspect(const EQApplicationPacket *app)
|
||||
|
||||
BazaarInspect_Struct* bis = (BazaarInspect_Struct*)app->pBuffer;
|
||||
|
||||
const EQ::ItemData* item = database.GetItem(bis->ItemID);
|
||||
const EQ::ItemData* item = database.GetItem(bis->item_id);
|
||||
|
||||
if (!item) {
|
||||
Message(Chat::Red, "Error: This item does not exist!");
|
||||
@@ -3937,39 +3938,47 @@ void Client::Handle_OP_BazaarInspect(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
|
||||
{
|
||||
uint32 action = *(uint32 *) app->pBuffer;
|
||||
|
||||
if (app->size == sizeof(BazaarSearch_Struct)) {
|
||||
switch (action) {
|
||||
case BazaarSearch: {
|
||||
BazaarSearchCriteria_Struct *bss = (BazaarSearchCriteria_Struct *) app->pBuffer;
|
||||
BazaarSearchCriteria_Struct search_details{};
|
||||
|
||||
BazaarSearch_Struct* bss = (BazaarSearch_Struct*)app->pBuffer;
|
||||
search_details.action = BazaarSearchResults;
|
||||
search_details.augment = bss->augment;
|
||||
search_details._class = bss->_class;
|
||||
search_details.item_stat = bss->item_stat;
|
||||
search_details.min_cost = bss->min_cost;
|
||||
search_details.max_cost = bss->max_cost;
|
||||
search_details.min_level = bss->min_level;
|
||||
search_details.max_level = bss->max_level;
|
||||
search_details.max_results = bss->max_results;
|
||||
search_details.prestige = bss->prestige;
|
||||
search_details.race = bss->race;
|
||||
search_details.search_scope = bss->search_scope;
|
||||
search_details.slot = bss->slot;
|
||||
search_details.trader_entity_id = bss->trader_entity_id;
|
||||
search_details.trader_id = bss->trader_id;
|
||||
search_details.type = bss->type;
|
||||
strn0cpy(search_details.item_name, bss->item_name, sizeof(search_details.item_name));
|
||||
|
||||
SendBazaarResults(bss->TraderID, bss->Class_, bss->Race, bss->ItemStat, bss->Slot, bss->Type,
|
||||
bss->Name, bss->MinPrice * 1000, bss->MaxPrice * 1000);
|
||||
}
|
||||
else if (app->size == sizeof(BazaarWelcome_Struct)) {
|
||||
|
||||
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)app->pBuffer;
|
||||
|
||||
if (bws->Beginning.Action == BazaarWelcome)
|
||||
SendBazaarWelcome();
|
||||
}
|
||||
else if (app->size == sizeof(NewBazaarInspect_Struct)) {
|
||||
|
||||
NewBazaarInspect_Struct *nbis = (NewBazaarInspect_Struct*)app->pBuffer;
|
||||
|
||||
Client *c = entity_list.GetClientByName(nbis->Name);
|
||||
if (c) {
|
||||
EQ::ItemInstance* inst = c->FindTraderItemBySerialNumber(nbis->SerialNumber);
|
||||
if (inst)
|
||||
SendItemPacket(0, inst, ItemPacketViewLink);
|
||||
DoBazaarSearch(search_details);
|
||||
break;
|
||||
}
|
||||
case BazaarInspect: {
|
||||
auto in = (BazaarInspect_Struct *) app->pBuffer;
|
||||
DoBazaarInspect(*in);
|
||||
break;
|
||||
}
|
||||
case WelcomeMessage: {
|
||||
SendBazaarWelcome();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
LogTrading("Malformed BazaarSearch_Struct packet received, ignoring");
|
||||
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_Begging(const EQApplicationPacket *app)
|
||||
@@ -4973,8 +4982,8 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
|
||||
if (cy != m_Position.y || cx != m_Position.x) {
|
||||
// End trader mode if we move
|
||||
if (Trader) {
|
||||
Trader_EndTrader();
|
||||
if (IsTrader()) {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
@@ -5787,21 +5796,19 @@ void Client::Handle_OP_DeleteItem(const EQApplicationPacket *app)
|
||||
|
||||
SetIntoxication(GetIntoxication()+IntoxicationIncrease);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::ITEM_DESTROY) && inst->GetItem()) {
|
||||
auto e = PlayerEvent::DestroyItemEvent{
|
||||
.item_id = inst->GetItem()->ID,
|
||||
.item_name = inst->GetItem()->Name,
|
||||
.charges = inst->GetCharges(),
|
||||
.reason = "Client deleted",
|
||||
};
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::ITEM_DESTROY, e);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteItemInInventory(alc->from_slot, 1);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::ITEM_DESTROY)) {
|
||||
auto e = PlayerEvent::DestroyItemEvent{
|
||||
.item_id = inst->GetItem()->ID,
|
||||
.item_name = inst->GetItem()->Name,
|
||||
.charges = inst->GetCharges(),
|
||||
.reason = "Client deleted",
|
||||
};
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::ITEM_DESTROY, e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app)
|
||||
@@ -10427,7 +10434,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app)
|
||||
|
||||
int mendhp = GetMaxHP() / 4;
|
||||
int currenthp = GetHP();
|
||||
if (zone->random.Int(0, 199) < (int)GetSkill(EQ::skills::SkillMend)) {
|
||||
if (zone->random.Int(0, RuleI(Character, MendAlwaysSucceedValue)) < (int)GetSkill(EQ::skills::SkillMend)) {
|
||||
|
||||
int criticalchance = spellbonuses.CriticalMend + itembonuses.CriticalMend + aabonuses.CriticalMend;
|
||||
|
||||
@@ -11529,8 +11536,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, mypet->GetCleanName());
|
||||
}
|
||||
else {
|
||||
bool immune_aggro = GetSpecialAbility(IMMUNE_AGGRO);
|
||||
mypet->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||
bool has_aggro_immunity = GetSpecialAbility(SpecialAbility::AggroImmunity);
|
||||
mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 1);
|
||||
mypet->WipeHateList();
|
||||
mypet->SetPetOrder(SPO_FeignDeath);
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
@@ -11542,8 +11549,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->InterruptSpell();
|
||||
}
|
||||
|
||||
if (!immune_aggro) {
|
||||
mypet->SetSpecialAbility(IMMUNE_AGGRO, 0);
|
||||
if (!has_aggro_immunity) {
|
||||
mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11875,8 +11882,8 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (victim->IsNPC()) {
|
||||
auto body = victim->GetBodyType();
|
||||
if (body == BT_Humanoid || body == BT_Monster || body == BT_Giant ||
|
||||
body == BT_Lycanthrope) {
|
||||
if (body == BodyType::Humanoid || body == BodyType::Monster || body == BodyType::Giant ||
|
||||
body == BodyType::Lycanthrope) {
|
||||
victim->CastToNPC()->PickPocket(this);
|
||||
return;
|
||||
}
|
||||
@@ -14041,16 +14048,21 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
|
||||
EQ::ItemInstance* inst = database.CreateItem(item, charges);
|
||||
|
||||
int SinglePrice = 0;
|
||||
if (RuleB(Merchant, UsePriceMod))
|
||||
SinglePrice = (item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate * Client::CalcPriceMod(tmp, false));
|
||||
else
|
||||
SinglePrice = (item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate);
|
||||
int single_price = (item->Price * item->SellRate);
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
single_price *= RuleR(Merchant, SellCostMod);
|
||||
}
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
single_price *= Client::CalcPriceMod(tmp, false);
|
||||
}
|
||||
|
||||
if (item->MaxCharges > 1)
|
||||
mpo->price = SinglePrice;
|
||||
mpo->price = single_price;
|
||||
else
|
||||
mpo->price = SinglePrice * mp->quantity;
|
||||
mpo->price = single_price * mp->quantity;
|
||||
|
||||
if (mpo->price < 0)
|
||||
{
|
||||
@@ -14131,7 +14143,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
else {
|
||||
// Update the charges/quantity in the merchant window
|
||||
inst->SetCharges(new_charges);
|
||||
inst->SetPrice(SinglePrice);
|
||||
inst->SetPrice(single_price);
|
||||
inst->SetMerchantSlot(mp->itemslot);
|
||||
inst->SetMerchantCount(new_charges);
|
||||
|
||||
@@ -14310,7 +14322,15 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
for (i = 1; i <= cost_quantity; i++) {
|
||||
price = (uint32)((item->Price * i)*(RuleR(Merchant, BuyCostMod))*Client::CalcPriceMod(vendor, true) + 0.5); // need to round up, because client does it automatically when displaying price
|
||||
price = (uint32)(item->Price * i) * Client::CalcPriceMod(vendor, true);
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
price *= RuleR(Merchant, BuyCostMod);
|
||||
}
|
||||
|
||||
price += 0.5; // need to round up, because client does it automatically when displaying price
|
||||
|
||||
if (price > 4000000000) {
|
||||
cost_quantity = i;
|
||||
mp->quantity = i;
|
||||
@@ -14360,11 +14380,12 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 price = (
|
||||
item->Price *
|
||||
RuleR(Merchant, SellCostMod) *
|
||||
item->SellRate
|
||||
);
|
||||
uint32 price = (item->Price * item->SellRate);
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
price *= RuleR(Merchant, SellCostMod);
|
||||
}
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
price *= Client::CalcPriceMod(vendor, false);
|
||||
@@ -14571,11 +14592,18 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app)
|
||||
mco->command = action; // Merchant command 0x01 = open
|
||||
mco->tab_display = tabs_to_display;
|
||||
|
||||
float buy_cost_mod = 1;
|
||||
|
||||
// Only use the BuyCostMod if we're not using the classic function.
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
buy_cost_mod = RuleR(Merchant, BuyCostMod);
|
||||
}
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
mco->rate = 1 / ((RuleR(Merchant, BuyCostMod)) * Client::CalcPriceMod(tmp, true)); // works
|
||||
mco->rate = 1 / (buy_cost_mod * Client::CalcPriceMod(tmp, true));
|
||||
}
|
||||
else {
|
||||
mco->rate = 1 / (RuleR(Merchant, BuyCostMod));
|
||||
mco->rate = 1 / buy_cost_mod;
|
||||
}
|
||||
|
||||
outapp->priority = 6;
|
||||
@@ -14616,12 +14644,18 @@ void Client::Handle_OP_Sneak(const EQApplicationPacket *app)
|
||||
sa_out->parameter = 0;
|
||||
entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
CheckIncreaseSkill(EQ::skills::SkillSneak, nullptr, 5);
|
||||
}
|
||||
|
||||
float hidechance = ((GetSkill(EQ::skills::SkillSneak) / 300.0f) + .25) * 100;
|
||||
|
||||
if (RuleB(Character, SneakAlwaysSucceedOver100)) {
|
||||
hidechance = std::max(10, (int)GetSkill(EQ::skills::SkillSneak));
|
||||
}
|
||||
|
||||
float random = zone->random.Real(0, 99);
|
||||
|
||||
if (!was && random < hidechance) {
|
||||
sneaking = true;
|
||||
}
|
||||
@@ -14971,9 +15005,9 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
|
||||
|
||||
if (nt) {
|
||||
if (GetGM() || (!nt->IsInvisible(this) && (DistanceSquared(m_Position, nt->GetPosition()) <= TARGETING_RANGE*TARGETING_RANGE))) {
|
||||
if (nt->GetBodyType() == BT_NoTarget2 ||
|
||||
nt->GetBodyType() == BT_Special ||
|
||||
nt->GetBodyType() == BT_NoTarget) {
|
||||
if (nt->GetBodyType() == BodyType::NoTarget2 ||
|
||||
nt->GetBodyType() == BodyType::Special ||
|
||||
nt->GetBodyType() == BodyType::NoTarget) {
|
||||
can_target = false;
|
||||
}
|
||||
else {
|
||||
@@ -15116,8 +15150,8 @@ void Client::Handle_OP_TargetMouse(const EQApplicationPacket *app)
|
||||
GetTarget()->IsTargeted(1);
|
||||
return;
|
||||
}
|
||||
else if (GetTarget()->GetBodyType() == BT_NoTarget2 || GetTarget()->GetBodyType() == BT_Special
|
||||
|| GetTarget()->GetBodyType() == BT_NoTarget)
|
||||
else if (GetTarget()->GetBodyType() == BodyType::NoTarget2 || GetTarget()->GetBodyType() == BodyType::Special
|
||||
|| GetTarget()->GetBodyType() == BodyType::NoTarget)
|
||||
{
|
||||
auto message = fmt::format(
|
||||
"[{}] attempting to target something untargetable [{}] bodytype [{}]",
|
||||
@@ -15475,174 +15509,49 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
//
|
||||
// SoF sends 1 or more unhandled OP_Trader packets of size 96 when a trade has completed.
|
||||
// I don't know what they are for (yet), but it doesn't seem to matter that we ignore them.
|
||||
auto action = *(uint32 *)app->pBuffer;
|
||||
|
||||
|
||||
uint32 max_items = 80;
|
||||
|
||||
/*
|
||||
if (GetClientVersion() >= EQClientRoF)
|
||||
max_items = 200;
|
||||
*/
|
||||
|
||||
//Show Items
|
||||
if (app->size == sizeof(Trader_ShowItems_Struct))
|
||||
{
|
||||
Trader_ShowItems_Struct* sis = (Trader_ShowItems_Struct*)app->pBuffer;
|
||||
|
||||
switch (sis->Code)
|
||||
{
|
||||
case BazaarTrader_EndTraderMode: {
|
||||
Trader_EndTrader();
|
||||
switch (action) {
|
||||
case TraderOff: {
|
||||
TraderEndTrader();
|
||||
LogTrading("End Trader Session");
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_EndTransaction: {
|
||||
|
||||
Client* c = entity_list.GetClientByID(sis->TraderID);
|
||||
if (c)
|
||||
{
|
||||
c->WithCustomer(0);
|
||||
LogTrading("End Transaction");
|
||||
}
|
||||
else
|
||||
LogTrading("Null Client Pointer");
|
||||
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_ShowItems: {
|
||||
Trader_ShowItems();
|
||||
LogTrading("Show Trader Items");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("Unhandled action code in OP_Trader ShowItems_Struct");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (app->size == sizeof(ClickTrader_Struct))
|
||||
{
|
||||
if (Buyer) {
|
||||
Trader_EndTrader();
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
return;
|
||||
}
|
||||
|
||||
ClickTrader_Struct* ints = (ClickTrader_Struct*)app->pBuffer;
|
||||
|
||||
if (ints->Code == BazaarTrader_StartTraderMode)
|
||||
{
|
||||
GetItems_Struct* gis = GetTraderItems();
|
||||
|
||||
LogTrading("Start Trader Mode");
|
||||
// Verify there are no NODROP or items with a zero price
|
||||
bool TradeItemsValid = true;
|
||||
|
||||
for (uint32 i = 0; i < max_items; i++) {
|
||||
|
||||
if (gis->Items[i] == 0) break;
|
||||
|
||||
if (ints->ItemCost[i] == 0) {
|
||||
Message(Chat::Red, "Item in Trader Satchel with no price. Unable to start trader mode");
|
||||
TradeItemsValid = false;
|
||||
break;
|
||||
}
|
||||
const EQ::ItemData *Item = database.GetItem(gis->Items[i]);
|
||||
|
||||
if (!Item) {
|
||||
Message(Chat::Red, "Unexpected error. Unable to start trader mode");
|
||||
TradeItemsValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Item->NoDrop == 0) {
|
||||
Message(Chat::Red, "NODROP Item in Trader Satchel. Unable to start trader mode");
|
||||
TradeItemsValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TradeItemsValid) {
|
||||
Trader_EndTrader();
|
||||
safe_delete(gis);
|
||||
case TraderOn: {
|
||||
if (Buyer) {
|
||||
TraderEndTrader();
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < max_items; i++) {
|
||||
if (database.GetItem(gis->Items[i])) {
|
||||
database.SaveTraderItem(CharacterID(), gis->Items[i], gis->SerialNumber[i],
|
||||
gis->Charges[i], ints->ItemCost[i], i);
|
||||
|
||||
auto inst = FindTraderItemBySerialNumber(gis->SerialNumber[i]);
|
||||
if (inst)
|
||||
inst->SetPrice(ints->ItemCost[i]);
|
||||
}
|
||||
else {
|
||||
//return; //sony doesnt memset so assume done on first bad item
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
safe_delete(gis);
|
||||
|
||||
Trader_StartTrader();
|
||||
|
||||
// This refreshes the Trader window to display the End Trader button
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct));
|
||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)outapp->pBuffer;
|
||||
tss->Code = BazaarTrader_StartTraderMode2;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogTrading("Unknown TraderStruct code of: [{}]\n",
|
||||
ints->Code);
|
||||
|
||||
LogError("Unknown TraderStruct code of: [{}]\n", ints->Code);
|
||||
}
|
||||
}
|
||||
else if (app->size == sizeof(TraderStatus_Struct))
|
||||
{
|
||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
||||
|
||||
LogTrading("Trader Status Code: [{}]", tss->Code);
|
||||
|
||||
switch (tss->Code)
|
||||
{
|
||||
case BazaarTrader_EndTraderMode: {
|
||||
Trader_EndTrader();
|
||||
LogTrading("End Trader Session");
|
||||
TraderStartTrader(app);
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_ShowItems: {
|
||||
Trader_ShowItems();
|
||||
case PriceUpdate:
|
||||
case ItemMove: {
|
||||
LogTrading("Trader Price Update");
|
||||
TraderPriceUpdate(app);
|
||||
break;
|
||||
}
|
||||
case EndTransaction: {
|
||||
auto sis = (Trader_ShowItems_Struct *) app->pBuffer;
|
||||
Client *c = entity_list.GetClientByID(sis->entity_id);
|
||||
if (c) {
|
||||
c->WithCustomer(0);
|
||||
LogTrading("End Transaction");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ListTraderItems: {
|
||||
TraderShowItems();
|
||||
LogTrading("Show Trader Items");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTrading("Unhandled action code in OP_Trader ShowItems_Struct");
|
||||
break;
|
||||
LogError("Unknown size for OP_Trader: [{}]\n", app->size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (app->size == sizeof(TraderPriceUpdate_Struct))
|
||||
{
|
||||
LogTrading("Trader Price Update");
|
||||
HandleTraderPriceUpdate(app);
|
||||
}
|
||||
else {
|
||||
LogTrading("Unknown size for OP_Trader: [{}]\n", app->size);
|
||||
LogError("Unknown size for OP_Trader: [{}]\n", app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
@@ -15651,23 +15560,80 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
//
|
||||
// Client has elected to buy an item from a Trader
|
||||
//
|
||||
if (app->size != sizeof(TraderBuy_Struct)) {
|
||||
LogError("Wrong size: OP_TraderBuy, size=[{}], expected [{}]", app->size, sizeof(TraderBuy_Struct));
|
||||
return;
|
||||
auto in = (TraderBuy_Struct *) app->pBuffer;
|
||||
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||
|
||||
switch (in->method) {
|
||||
case ByVendor: {
|
||||
if (trader) {
|
||||
LogTrading("Buy item directly from vendor id <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||
"serial_number <green>[{}]",
|
||||
in->trader_id,
|
||||
in->item_id,
|
||||
in->quantity,
|
||||
in->serial_number
|
||||
);
|
||||
BuyTraderItem(in, trader, app);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ByParcel: {
|
||||
if (!RuleB(Parcel, EnableParcelMerchants) || !RuleB(Bazaar, EnableParcelDelivery)) {
|
||||
LogTrading(
|
||||
"Bazaar purchase attempt by parcel delivery though 'Parcel:EnableParcelMerchants' or "
|
||||
"'Bazaar::EnableParcelDelivery' not enabled."
|
||||
);
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
"The bazaar parcel delivey system is not enabled on this server. Please visit the vendor directly in the Bazaar."
|
||||
);
|
||||
in->method = ByParcel;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
}
|
||||
LogTrading("Buy item by parcel delivery <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||
"serial_number <green>[{}]",
|
||||
in->trader_id,
|
||||
in->item_id,
|
||||
in->quantity,
|
||||
in->serial_number
|
||||
);
|
||||
BuyTraderItemOutsideBazaar(in, app);
|
||||
break;
|
||||
}
|
||||
case ByDirectToInventory: {
|
||||
if (!RuleB(Parcel, EnableDirectToInventoryDelivery)) {
|
||||
LogTrading("Bazaar purchase attempt by direct inventory delivery though "
|
||||
"'Parcel:EnableDirectToInventoryDelivery' not enabled."
|
||||
);
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not enabled on this server. Please visit the vendor directly."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
}
|
||||
trader = entity_list.GetClientByCharID(in->trader_id);
|
||||
LogTrading("Buy item by direct inventory delivery <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||
"serial_number <green>[{}]",
|
||||
in->trader_id,
|
||||
in->item_id,
|
||||
in->quantity,
|
||||
in->serial_number
|
||||
);
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not yet implemented. Please visit the vendor directly or purchase via parcel delivery."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)) {
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
LogTrading("Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
||||
}
|
||||
else {
|
||||
LogTrading("Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app)
|
||||
@@ -15730,126 +15696,76 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
||||
{
|
||||
// Bazaar Trader:
|
||||
auto in = (TraderClick_Struct *) app->pBuffer;
|
||||
LogTrading("Handle_OP_TraderShop: TraderClick_Struct TraderID [{}], Code [{}], Unknown008 [{}], Approval [{}]",
|
||||
in->TraderID,
|
||||
in->Code,
|
||||
in->Unknown008,
|
||||
in->Approval
|
||||
);
|
||||
|
||||
if (app->size == sizeof(TraderClick_Struct))
|
||||
{
|
||||
switch (in->Code) {
|
||||
case ClickTrader: {
|
||||
LogTrading("Handle_OP_TraderShop case ClickTrader [{}]", in->Code);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
auto data = (TraderClick_Struct *) outapp->pBuffer;
|
||||
auto trader_client = entity_list.GetClientByID(in->TraderID);
|
||||
|
||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||
|
||||
LogTrading("Handle_OP_TraderShop: TraderClick_Struct TraderID [{}], Code [{}], Unknown008 [{}], Approval [{}]",
|
||||
tcs->TraderID, tcs->Code, tcs->Unknown008, tcs->Approval);
|
||||
|
||||
if (tcs->Code == BazaarWelcome)
|
||||
{
|
||||
LogTrading("Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||
SendBazaarWelcome();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||
// browse their goods.
|
||||
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
|
||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||
|
||||
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
||||
|
||||
if (Trader)
|
||||
{
|
||||
outtcs->Approval = Trader->WithCustomer(GetID());
|
||||
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
||||
if (trader_client) {
|
||||
data->Approval = trader_client->WithCustomer(GetID());
|
||||
LogTrading("Client::Handle_OP_TraderShop: Shop Request ([{}]) to ([{}]) with Approval: [{}]",
|
||||
GetCleanName(),
|
||||
trader_client->GetCleanName(),
|
||||
data->Approval
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogTrading("Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||
" returned a nullptr pointer");
|
||||
safe_delete(outapp);
|
||||
" returned a nullptr pointer"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
outtcs->TraderID = tcs->TraderID;
|
||||
data->Code = ClickTrader;
|
||||
data->TraderID = in->TraderID;
|
||||
data->Unknown008 = 0x3f800000;
|
||||
QueuePacket(outapp.get());
|
||||
|
||||
outtcs->Unknown008 = 0x3f800000;
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
if (outtcs->Approval) {
|
||||
BulkSendTraderInventory(Trader->CharacterID());
|
||||
Trader->Trader_CustomerBrowsing(this);
|
||||
TraderID = tcs->TraderID;
|
||||
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
||||
if (data->Approval) {
|
||||
BulkSendTraderInventory(trader_client->CharacterID());
|
||||
trader_client->Trader_CustomerBrowsing(this);
|
||||
SetTraderID(in->TraderID);
|
||||
LogTrading("Client::Handle_OP_TraderShop: Trader Inventory Sent to [{}] from [{}]",
|
||||
GetID(),
|
||||
in->TraderID
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
MessageString(Chat::Yellow, TRADER_BUSY);
|
||||
LogTrading("Client::Handle_OP_TraderShop: Trader Busy");
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if (app->size == sizeof(BazaarWelcome_Struct))
|
||||
{
|
||||
// RoF+
|
||||
// Client requested Bazaar Welcome Info (Trader and Item Total Counts)
|
||||
SendBazaarWelcome();
|
||||
LogTrading("Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||
}
|
||||
else if (app->size == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
// RoF+
|
||||
// Customer has purchased an item from the Trader
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID))
|
||||
{
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
LogTrading("Handle_OP_TraderShop: Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
||||
tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("OP_TraderShop: Null Client Pointer");
|
||||
}
|
||||
}
|
||||
else if (app->size == 4)
|
||||
{
|
||||
// RoF+
|
||||
// Customer has closed the trade window
|
||||
uint32 Command = *((uint32 *)app->pBuffer);
|
||||
|
||||
if (Command == 4)
|
||||
{
|
||||
Client* c = entity_list.GetClientByID(TraderID);
|
||||
TraderID = 0;
|
||||
if (c)
|
||||
{
|
||||
case EndTransaction: {
|
||||
Client *c = entity_list.GetClientByID(GetTraderID());
|
||||
SetTraderID(0);
|
||||
if (c) {
|
||||
c->WithCustomer(0);
|
||||
LogTrading("End Transaction - Code [{}]", Command);
|
||||
LogTrading("End Transaction - Code [{}]", in->Code);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("Null Client Pointer for Trader - Code [{}]", Command);
|
||||
else {
|
||||
LogTrading("Null Client Pointer for Trader - Code [{}]", in->Code);
|
||||
}
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_ShopEndConfirm);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("Unhandled Code [{}]", Command);
|
||||
default: {
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogTrading("Unknown size for OP_TraderShop: [{}]\n", app->size);
|
||||
LogError("Unknown size for OP_TraderShop: [{}]\n", app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
||||
|
||||
+18
-8
@@ -902,9 +902,14 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
|
||||
auto inst = database.CreateItem(item, charges);
|
||||
if (inst) {
|
||||
auto item_price = static_cast<uint32>(item->Price * RuleR(Merchant, SellCostMod) * item->SellRate);
|
||||
auto item_price = static_cast<uint32>(item->Price * item->SellRate);
|
||||
auto item_charges = charges ? charges : 1;
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
item_price *= RuleR(Merchant, SellCostMod);
|
||||
}
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
item_price *= Client::CalcPriceMod(npc);
|
||||
}
|
||||
@@ -948,9 +953,14 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
auto charges = item->MaxCharges;
|
||||
auto inst = database.CreateItem(item, charges);
|
||||
if (inst) {
|
||||
auto item_price = static_cast<uint32>(item->Price * RuleR(Merchant, SellCostMod) * item->SellRate);
|
||||
auto item_price = static_cast<uint32>(item->Price * item->SellRate);
|
||||
auto item_charges = charges ? charges : 1;
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
if (!RuleB(Merchant, UseClassicPriceMod)) {
|
||||
item_price *= RuleR(Merchant, SellCostMod);
|
||||
}
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
item_price *= Client::CalcPriceMod(npc);
|
||||
}
|
||||
@@ -984,22 +994,22 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
uint8 Client::WithCustomer(uint16 NewCustomer){
|
||||
|
||||
if(NewCustomer == 0) {
|
||||
CustomerID = 0;
|
||||
SetCustomerID(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(CustomerID == 0) {
|
||||
CustomerID = NewCustomer;
|
||||
if(GetCustomerID() == 0) {
|
||||
SetCustomerID(NewCustomer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check that the player browsing our wares hasn't gone away.
|
||||
|
||||
Client* c = entity_list.GetClientByID(CustomerID);
|
||||
Client* c = entity_list.GetClientByID(GetCustomerID());
|
||||
|
||||
if(!c) {
|
||||
LogTrading("Previous customer has gone away");
|
||||
CustomerID = NewCustomer;
|
||||
SetCustomerID(NewCustomer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1708,7 +1718,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
|
||||
if (skilllevel == 0) {
|
||||
//this is a new skill..
|
||||
uint16 t_level = SkillTrainLevel(skill, GetClass());
|
||||
uint16 t_level = GetSkillTrainLevel(skill, GetClass());
|
||||
|
||||
if (t_level == 0) {
|
||||
LogSkills("Tried to train a new skill [{}] which is invalid for this race/class.", skill);
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ int command_init(void)
|
||||
command_add("rl", "Reloads logs (alias of #reload logs).", AccountStatus::GMMgmt, command_reload) ||
|
||||
command_add("removeitem", "[Item ID] [Amount] - Removes the specified Item ID by Amount from you or your player target's inventory (Amount defaults to 1 if not used)", AccountStatus::GMAdmin, command_removeitem) ||
|
||||
command_add("repop", "[Force] - Repop the zone with optional force repop", AccountStatus::GMAdmin, command_repop) ||
|
||||
command_add("resetaa", "Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", AccountStatus::GMMgmt, command_resetaa) ||
|
||||
command_add("resetaa", "[aa|leadership] - Resets a player's AAs or Leadership AAs and refunds spent AAs (not Leadership AAs) to unspent, may disconnect player.", AccountStatus::GMMgmt, command_resetaa) ||
|
||||
command_add("resetaa_timer", "[All|Timer ID] - Command to reset AA cooldown timers for you or your player target.", AccountStatus::GMMgmt, command_resetaa_timer) ||
|
||||
command_add("resetdisc_timer", "[All|Timer ID] - Command to reset discipline timers.", AccountStatus::GMMgmt, command_resetdisc_timer) ||
|
||||
command_add("revoke", "[Character Name] [0|1] - Revokes or unrevokes a player's ability to talk in OOC by name (0 = Unrevoke, 1 = Revoke)", AccountStatus::GMMgmt, command_revoke) ||
|
||||
|
||||
@@ -336,6 +336,7 @@ struct StatBonuses {
|
||||
int32 hastetype2;
|
||||
int32 hastetype3;
|
||||
int32 inhibitmelee;
|
||||
int32 increase_archery;
|
||||
float AggroRange; // when calculate just replace original value with this
|
||||
float AssistRange;
|
||||
int32 skillmod[EQ::skills::HIGHEST_SKILL + 1];
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ Corpse::Corpse(
|
||||
npc->GetGender(), // in_gender
|
||||
npc->GetRace(), // in_race
|
||||
npc->GetClass(), // in_class
|
||||
BT_Humanoid, // in_bodytype
|
||||
BodyType::Humanoid, // in_bodytype
|
||||
npc->GetDeity(), // in_deity
|
||||
npc->GetLevel(), // in_level
|
||||
npc->GetNPCTypeID(), // in_npctype_id
|
||||
@@ -189,7 +189,7 @@ Corpse::Corpse(Client *c, int32 rez_exp, KilledByTypes in_killed_by) : Mob(
|
||||
c->GetGender(), // in_gender
|
||||
c->GetRace(), // in_race
|
||||
c->GetClass(), // in_class
|
||||
BT_Humanoid, // in_bodytype
|
||||
BodyType::Humanoid, // in_bodytype
|
||||
c->GetDeity(), // in_deity
|
||||
c->GetLevel(), // in_level
|
||||
0, // in_npctype_id
|
||||
@@ -495,7 +495,7 @@ Corpse::Corpse(
|
||||
gender, // in_gender
|
||||
race, // in_race
|
||||
class_, // in_class
|
||||
BT_Humanoid, // in_bodytype
|
||||
BodyType::Humanoid, // in_bodytype
|
||||
deity, // in_deity
|
||||
level, // in_level
|
||||
0, // in_npctype_id
|
||||
|
||||
+31
-32
@@ -71,20 +71,20 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
|
||||
|
||||
//Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBot() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBot() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) {
|
||||
chance = 100;
|
||||
}
|
||||
|
||||
if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance)
|
||||
if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) {
|
||||
chance = spells[spell_id].override_crit_chance;
|
||||
}
|
||||
|
||||
if (zone->random.Roll(chance)) {
|
||||
Critical = true;
|
||||
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
|
||||
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
|
||||
}
|
||||
|
||||
else if ((IsOfClientBot() && GetClass() == Class::Wizard) || (IsMerc() && GetClass() == CASTERDPS)) {
|
||||
if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
|
||||
} else if ((IsOfClientBot() && GetClass() == Class::Wizard) || (IsMerc() && GetClass() == CASTERDPS)) {
|
||||
if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))) {
|
||||
//Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
|
||||
ratio += zone->random.Int(RuleI(Spells, WizardCritMinimumRandomRatio), RuleI(Spells, WizardCritMaximumRandomRatio));
|
||||
Critical = true;
|
||||
@@ -100,21 +100,32 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
}
|
||||
|
||||
if (Critical) {
|
||||
|
||||
value = base_value*ratio/100;
|
||||
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
|
||||
if (RuleB(Spells, UseClassicHarmTouchDamage)) {
|
||||
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
|
||||
if (IsHarmTouchSpell(spell_id) && GetLevel() > 40) {
|
||||
value -= (GetLevel() - 40) * 20;
|
||||
}
|
||||
|
||||
value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
|
||||
value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio / 100;
|
||||
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBotMerc()) { //Improved Harm Touch
|
||||
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
|
||||
}
|
||||
}
|
||||
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id) / 100;
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id) / 100;
|
||||
|
||||
value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id) / 100) * ratio / 100;
|
||||
value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100) * ratio / 100;
|
||||
|
||||
if (target) {
|
||||
value += int(base_value*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
value += int(base_value*target->GetVulnerability(this, spell_id, 0) / 100) * ratio / 100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id) * ratio / 100;
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
value -= GetFocusEffect(focusFcDamageAmt2, spell_id);
|
||||
@@ -127,9 +138,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value) * ratio / 100;
|
||||
|
||||
}
|
||||
|
||||
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
} else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value) * ratio / 100;
|
||||
}
|
||||
|
||||
@@ -148,30 +157,20 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
MessageString(Chat::SpellCrit, YOU_CRIT_BLAST, itoa(-value));
|
||||
}
|
||||
|
||||
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
|
||||
if (IsHarmTouchSpell(spell_id) && GetLevel() > 40) {
|
||||
value -= (GetLevel() - 40) * 20;
|
||||
}
|
||||
|
||||
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm Touch.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBot()) { //Improved Harm Touch
|
||||
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
//Non Crtical Hit Calculation pathway
|
||||
value = base_value;
|
||||
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id) / 100;
|
||||
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id) / 100;
|
||||
|
||||
value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
||||
value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id)/100;
|
||||
value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id) / 100;
|
||||
value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100;
|
||||
|
||||
if (target) {
|
||||
value += base_value*target->GetVulnerability(this, spell_id, 0)/100;
|
||||
value += base_value*target->GetVulnerability(this, spell_id, 0) / 100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
@@ -614,7 +613,7 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
{
|
||||
// focuses don't affect discipline duration (Except War Cries)
|
||||
if (
|
||||
IsDiscipline(spell_id) &&
|
||||
IsDiscipline(spell_id) &&
|
||||
(
|
||||
spell_id != SPELL_BATTLE_CRY &&
|
||||
spell_id != SPELL_WAR_CRY &&
|
||||
|
||||
+4
-3
@@ -1547,16 +1547,17 @@ void PerlembParser::ExportMobVariables(
|
||||
void PerlembParser::ExportZoneVariables(std::string& package_name)
|
||||
{
|
||||
if (zone) {
|
||||
ExportVar(package_name.c_str(), "zoneid", zone->GetZoneID());
|
||||
ExportVar(package_name.c_str(), "zoneln", zone->GetLongName());
|
||||
ExportVar(package_name.c_str(), "zonesn", zone->GetShortName());
|
||||
ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID());
|
||||
ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion());
|
||||
TimeOfDay_Struct eqTime{ };
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime);
|
||||
ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1);
|
||||
ExportVar(package_name.c_str(), "zoneid", zone->GetZoneID());
|
||||
ExportVar(package_name.c_str(), "zoneln", zone->GetLongName());
|
||||
ExportVar(package_name.c_str(), "zonemin", eqTime.minute);
|
||||
ExportVar(package_name.c_str(), "zonesn", zone->GetShortName());
|
||||
ExportVar(package_name.c_str(), "zonetime", (eqTime.hour - 1) * 100 + eqTime.minute);
|
||||
ExportVar(package_name.c_str(), "zoneuptime", Timer::GetCurrentTime() / 1000);
|
||||
ExportVar(package_name.c_str(), "zoneweather", zone->zone_weather);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -513,7 +513,7 @@ void Perl__sfollow()
|
||||
quest_manager.sfollow();
|
||||
}
|
||||
|
||||
void Perl__changedeity(int deity_id)
|
||||
void Perl__changedeity(uint32 deity_id)
|
||||
{
|
||||
quest_manager.changedeity(deity_id);
|
||||
}
|
||||
@@ -4740,9 +4740,9 @@ std::string Perl__getlanguagename(uint8 language_id)
|
||||
return quest_manager.getlanguagename(language_id);
|
||||
}
|
||||
|
||||
std::string Perl__getbodytypename(uint32 bodytype_id)
|
||||
std::string Perl__getbodytypename(uint8 body_type_id)
|
||||
{
|
||||
return quest_manager.getbodytypename(bodytype_id);
|
||||
return quest_manager.getbodytypename(body_type_id);
|
||||
}
|
||||
|
||||
std::string Perl__getconsiderlevelname(uint8 consider_level)
|
||||
@@ -4940,6 +4940,11 @@ void Perl__set_proximity_range(float x_range, float y_range, float z_range, bool
|
||||
quest_manager.set_proximity_range(x_range, y_range, z_range, enable_say);
|
||||
}
|
||||
|
||||
std::string Perl__varlink(EQ::ItemInstance* inst)
|
||||
{
|
||||
return quest_manager.varlink(inst);
|
||||
}
|
||||
|
||||
std::string Perl__varlink(uint32 item_id)
|
||||
{
|
||||
return quest_manager.varlink(item_id);
|
||||
@@ -5845,9 +5850,9 @@ uint16 Perl__get_class_bitmask(uint8 class_id)
|
||||
return GetPlayerClassBit(class_id);
|
||||
}
|
||||
|
||||
uint32 Perl__get_deity_bitmask(uint16 deity_id)
|
||||
uint32 Perl__get_deity_bitmask(uint32 deity_id)
|
||||
{
|
||||
return static_cast<uint32>(EQ::deity::GetDeityBitmask(static_cast<EQ::deity::DeityType>(deity_id)));
|
||||
return Deity::GetBitmask(deity_id);
|
||||
}
|
||||
|
||||
uint16 Perl__get_race_bitmask(uint16 race_id)
|
||||
@@ -6856,6 +6861,7 @@ void perl_register_quest()
|
||||
package.add("updatetaskactivity", (void(*)(int, int, int))&Perl__updatetaskactivity);
|
||||
package.add("updatetaskactivity", (void(*)(int, int, int, bool))&Perl__updatetaskactivity);
|
||||
package.add("UpdateZoneHeader", &Perl__UpdateZoneHeader);
|
||||
package.add("varlink", (std::string(*)(EQ::ItemInstance*))&Perl__varlink);
|
||||
package.add("varlink", (std::string(*)(uint32))&Perl__varlink);
|
||||
package.add("varlink", (std::string(*)(uint32, int16))&Perl__varlink);
|
||||
package.add("varlink", (std::string(*)(uint32, int16, uint32))&Perl__varlink);
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ Encounter::Encounter(const char *enc_name) : Mob(
|
||||
Gender::Male, // in_gender
|
||||
Race::InvisibleMan, // in_race
|
||||
Class::None, // in_class
|
||||
BT_NoTarget, // in_bodytype
|
||||
0, // in_deity
|
||||
BodyType::NoTarget, // in_bodytype
|
||||
Deity::Unknown, // in_deity
|
||||
0, // in_level
|
||||
0, // in_npcype_id
|
||||
0, // in_size
|
||||
|
||||
+20
-25
@@ -526,7 +526,7 @@ void EntityList::MobProcess()
|
||||
// -- the zone is newly empty and we're allowing mobs to settle
|
||||
if (
|
||||
numclients > 0 || zone->quest_idle_override ||
|
||||
(s2 && s2->PathWhenZoneIdle()) ||
|
||||
(mob && s2 && s2->PathWhenZoneIdle()) ||
|
||||
mob_settle_timer->Enabled()
|
||||
) {
|
||||
mob_dead = !mob->Process();
|
||||
@@ -1544,7 +1544,7 @@ void EntityList::RemoveFromTargetsFadingMemories(Mob *spell_target, bool RemoveF
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->GetSpecialAbility(IMMUNE_FADING_MEMORIES)) {
|
||||
if (mob->GetSpecialAbility(SpecialAbility::MemoryFadeImmunity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2954,11 +2954,6 @@ void EntityList::ScanCloseMobs(
|
||||
|
||||
for (auto &e : mob_list) {
|
||||
auto mob = e.second;
|
||||
|
||||
if (!mob->IsNPC() && !mob->IsClient() && !mob->IsBot() && !mob->IsMerc()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->GetID() <= 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -3643,7 +3638,7 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
||||
while (it != npc_list.end()) {
|
||||
// add Feign Memory check because sometimes weird stuff happens
|
||||
if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ))) {
|
||||
if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) {
|
||||
if (it->second->GetSpecialAbility(SpecialAbility::FeignDeathImmunity)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
@@ -3672,7 +3667,7 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
||||
|
||||
it->second->RemoveFromHateList(targ);
|
||||
|
||||
if (it->second->GetSpecialAbility(SPECATK_RAMPAGE)) {
|
||||
if (it->second->GetSpecialAbility(SpecialAbility::Rampage)) {
|
||||
it->second->RemoveFromRampageList(targ, true);
|
||||
}
|
||||
|
||||
@@ -4389,10 +4384,10 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
|
||||
if (n && n->GetSwarmInfo()) {
|
||||
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
||||
if (
|
||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(other->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(other->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(other->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC))
|
||||
!n->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!(other->IsBot() && n->GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(other->IsClient() && n->GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(other->IsNPC() && n->GetSpecialAbility(SpecialAbility::NPCAggroImmunity))
|
||||
) {
|
||||
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
@@ -4416,10 +4411,10 @@ void EntityList::AddTempPetsToHateListOnOwnerDamage(Mob *owner, Mob* attacker, i
|
||||
attacker &&
|
||||
attacker != n &&
|
||||
!n->IsEngaged() &&
|
||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(attacker->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
|
||||
!(attacker->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
|
||||
!(attacker->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
|
||||
!n->GetSpecialAbility(SpecialAbility::AggroImmunity) &&
|
||||
!(attacker->IsBot() && n->GetSpecialAbility(SpecialAbility::BotAggroImmunity)) &&
|
||||
!(attacker->IsClient() && n->GetSpecialAbility(SpecialAbility::ClientAggroImmunity)) &&
|
||||
!(attacker->IsNPC() && n->GetSpecialAbility(SpecialAbility::NPCAggroImmunity)) &&
|
||||
!attacker->IsTrap() &&
|
||||
!attacker->IsCorpse()
|
||||
) {
|
||||
@@ -5064,7 +5059,7 @@ uint32 EntityList::CheckNPCsClose(Mob *center)
|
||||
while (it != npc_list.end()) {
|
||||
NPC *cur = it->second;
|
||||
if (!cur || cur == center || cur->IsPet() || cur->GetClass() == Class::LDoNTreasure ||
|
||||
cur->GetBodyType() == BT_NoTarget || cur->GetBodyType() == BT_Special) {
|
||||
cur->GetBodyType() == BodyType::NoTarget || cur->GetBodyType() == BodyType::Special) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
@@ -5424,9 +5419,9 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count)
|
||||
while (it != npc_list.end()) {
|
||||
if (!it->second->IsPet()
|
||||
&& it->second->GetClass() != Class::LDoNTreasure
|
||||
&& it->second->GetBodyType() != BT_NoTarget
|
||||
&& it->second->GetBodyType() != BT_NoTarget2
|
||||
&& it->second->GetBodyType() != BT_Special)
|
||||
&& it->second->GetBodyType() != BodyType::NoTarget
|
||||
&& it->second->GetBodyType() != BodyType::NoTarget2
|
||||
&& it->second->GetBodyType() != BodyType::Special)
|
||||
npc_count++;
|
||||
++it;
|
||||
}
|
||||
@@ -5445,9 +5440,9 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count)
|
||||
while (it != npc_list.end()) {
|
||||
if (!it->second->IsPet()
|
||||
&& it->second->GetClass() != Class::LDoNTreasure
|
||||
&& it->second->GetBodyType() != BT_NoTarget
|
||||
&& it->second->GetBodyType() != BT_NoTarget2
|
||||
&& it->second->GetBodyType() != BT_Special)
|
||||
&& it->second->GetBodyType() != BodyType::NoTarget
|
||||
&& it->second->GetBodyType() != BodyType::NoTarget2
|
||||
&& it->second->GetBodyType() != BodyType::Special)
|
||||
npcs[i++] = it->second;
|
||||
++it;
|
||||
}
|
||||
@@ -5525,7 +5520,7 @@ void EntityList::ExpeditionWarning(uint32 minutes_left)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
Mob *EntityList::GetClosestMobByBodyType(Mob *sender, bodyType BodyType, bool skip_client_pets)
|
||||
Mob *EntityList::GetClosestMobByBodyType(Mob *sender, uint8 BodyType, bool skip_client_pets)
|
||||
{
|
||||
|
||||
if (!sender)
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ public:
|
||||
void TryWakeTheDead(Mob* sender, Mob* target, int32 spell_id, uint32 max_distance, uint32 duration, uint32 amount_pets);
|
||||
NPC* GetClosestBanker(Mob* sender, uint32 &distance);
|
||||
void CameraEffect(uint32 duration, float intensity);
|
||||
Mob* GetClosestMobByBodyType(Mob* sender, bodyType BodyType, bool skip_client_pets=false);
|
||||
Mob* GetClosestMobByBodyType(Mob* sender, uint8 BodyType, bool skip_client_pets=false);
|
||||
void ForceGroupUpdate(uint32 gid);
|
||||
void SendGroupLeave(uint32 gid, const char *name);
|
||||
void SendGroupJoin(uint32 gid, const char *name);
|
||||
|
||||
@@ -530,6 +530,11 @@ void Client::AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel, boo
|
||||
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp);
|
||||
}
|
||||
|
||||
// Check for AA XP Cap
|
||||
if (RuleI(AA, MaxAAEXPPerKill) >= 0 && aaexp > RuleI(AA, MaxAAEXPPerKill)) {
|
||||
aaexp = RuleI(AA, MaxAAEXPPerKill);
|
||||
}
|
||||
|
||||
// Get current AA XP total
|
||||
uint32 had_aaexp = GetAAXP();
|
||||
|
||||
|
||||
+7
-7
@@ -44,13 +44,13 @@ void Mob::CheckFlee()
|
||||
}
|
||||
|
||||
//dont bother if we are immune to fleeing
|
||||
if (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) {
|
||||
if (GetSpecialAbility(SpecialAbility::FleeingImmunity) || spellbonuses.ImmuneToFlee) {
|
||||
LogFlee("Mob [{}] is immune to fleeing via special ability or spell bonus", GetCleanName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Undead do not flee
|
||||
if (GetBodyType() == BT_Undead) {
|
||||
if (GetBodyType() == BodyType::Undead) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void Mob::CheckFlee()
|
||||
}
|
||||
|
||||
int hp_ratio = GetIntHPRatio();
|
||||
int flee_ratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists
|
||||
int flee_ratio = GetSpecialAbility(SpecialAbility::FleePercent); // if a special SpecialAbility::FleePercent exists
|
||||
Mob *hate_top = GetHateTop();
|
||||
|
||||
LogFlee("Mob [{}] hp_ratio [{}] flee_ratio [{}]", GetCleanName(), hp_ratio, flee_ratio);
|
||||
@@ -137,10 +137,10 @@ void Mob::CheckFlee()
|
||||
);
|
||||
|
||||
// If we got here we are allowed to roll on flee chance if there is not other hated NPC's in the area.
|
||||
// ALWAYS_FLEE, skip roll
|
||||
// SpecialAbility::AlwaysFlee, skip roll
|
||||
// if FleeIfNotAlone is true, we skip alone check
|
||||
// roll chance
|
||||
if (GetSpecialAbility(ALWAYS_FLEE) ||
|
||||
if (GetSpecialAbility(SpecialAbility::AlwaysFlee) ||
|
||||
((RuleB(Combat, FleeIfNotAlone) || entity_list.GetHatedCount(hate_top, this, true) == 0) &&
|
||||
zone->random.Roll(flee_chance))) {
|
||||
|
||||
@@ -164,14 +164,14 @@ void Mob::ProcessFlee()
|
||||
|
||||
//Stop fleeing if effect is applied after they start to run.
|
||||
//When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee.
|
||||
if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) &&
|
||||
if (flee_mode && (GetSpecialAbility(SpecialAbility::FleeingImmunity) || spellbonuses.ImmuneToFlee) &&
|
||||
!spellbonuses.IsFeared && !spellbonuses.IsBlind) {
|
||||
currently_fleeing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int hpratio = GetIntHPRatio();
|
||||
int fleeratio = GetSpecialAbility(FLEE_PERCENT); // if a special flee_percent exists
|
||||
int fleeratio = GetSpecialAbility(SpecialAbility::FleePercent); // if a special SpecialAbility::FleePercent exists
|
||||
Mob *hate_top = GetHateTop();
|
||||
|
||||
// If no special flee_percent check for Gray or Other con rates
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "../client.h"
|
||||
#include "find/aa.cpp"
|
||||
#include "find/body_type.cpp"
|
||||
#include "find/bug_category.cpp"
|
||||
#include "find/character.cpp"
|
||||
#include "find/class.cpp"
|
||||
#include "find/comparison_type.cpp"
|
||||
#include "find/currency.cpp"
|
||||
#include "find/deity.cpp"
|
||||
#include "find/emote.cpp"
|
||||
@@ -9,10 +12,12 @@
|
||||
#include "find/item.cpp"
|
||||
#include "find/language.cpp"
|
||||
#include "find/npctype.cpp"
|
||||
#include "find/object_type.cpp"
|
||||
#include "find/race.cpp"
|
||||
#include "find/recipe.cpp"
|
||||
#include "find/skill.cpp"
|
||||
#include "find/spell.cpp"
|
||||
#include "find/special_ability.cpp"
|
||||
#include "find/task.cpp"
|
||||
#include "find/zone.cpp"
|
||||
|
||||
@@ -30,8 +35,11 @@ void command_find(Client *c, const Seperator *sep)
|
||||
|
||||
std::vector<Cmd> commands = {
|
||||
Cmd{.cmd = "aa", .u = "aa [Search Criteria]", .fn = FindAA, .a = {"#findaa"}},
|
||||
Cmd{.cmd = "body_type", .u = "body_type [Search Criteria]", .fn = FindBodyType, .a = {"#findbodytype"}},
|
||||
Cmd{.cmd = "bug_category", .u = "bug_category [Search Criteria]", .fn = FindBugCategory, .a = {"#findbugcategory"}},
|
||||
Cmd{.cmd = "character", .u = "character [Search Criteria]", .fn = FindCharacter, .a = {"#findcharacter"}},
|
||||
Cmd{.cmd = "class", .u = "class [Search Criteria]", .fn = FindClass, .a = {"#findclass"}},
|
||||
Cmd{.cmd = "comparison_type", .u = "comparison_type [Search Criteria]", .fn = FindComparisonType, .a = {"#findcomparisontype"}},
|
||||
Cmd{.cmd = "currency", .u = "currency [Search Criteria]", .fn = FindCurrency, .a = {"#findcurrency"}},
|
||||
Cmd{.cmd = "deity", .u = "deity [Search Criteria]", .fn = FindDeity, .a = {"#finddeity"}},
|
||||
Cmd{.cmd = "emote", .u = "emote [Search Criteria]", .fn = FindEmote, .a = {"#findemote"}},
|
||||
@@ -45,9 +53,11 @@ void command_find(Client *c, const Seperator *sep)
|
||||
"#findnpctype"
|
||||
}
|
||||
},
|
||||
Cmd{.cmd = "object_type", .u = "object_type [Search Criteria]", .fn = FindObjectType, .a = {"#findobjecttype"}},
|
||||
Cmd{.cmd = "race", .u = "race [Search Criteria]", .fn = FindRace, .a = {"#findrace"}},
|
||||
Cmd{.cmd = "recipe", .u = "recipe [Search Criteria]", .fn = FindRecipe, .a = {"#findrecipe"}},
|
||||
Cmd{.cmd = "skill", .u = "skill [Search Criteria]", .fn = FindSkill, .a = {"#findskill"}},
|
||||
Cmd{.cmd = "special_ability", .u = "special_ability [Search Criteria]", .fn = FindSpecialAbility, .a = {"#fsa", "#findspecialability"}},
|
||||
Cmd{.cmd = "spell", .u = "spell [Search Criteria]", .fn = FindSpell, .a = {"#fs", "#findspell"}},
|
||||
Cmd{.cmd = "task", .u = "task [Search Criteria]", .fn = FindTask, .a = {"#findtask"}},
|
||||
Cmd{.cmd = "zone", .u = "zone [Search Criteria]", .fn = FindZone, .a = {"#fz", "#findzone"}},
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "../../client.h"
|
||||
|
||||
void FindBodyType(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(2)) {
|
||||
const uint8 body_type_id = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
|
||||
const std::string& body_type_name = BodyType::GetName(body_type_id);
|
||||
if (Strings::EqualFold(body_type_name, "UNKNOWN BODY TYPE")) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Body Type {} does not exist.",
|
||||
body_type_id
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Body Type {} | {}",
|
||||
body_type_id,
|
||||
body_type_name
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||
|
||||
uint32 found_count = 0;
|
||||
|
||||
for (const auto& e : body_type_names) {
|
||||
const std::string& body_type_name_lower = Strings::ToLower(e.second);
|
||||
if (!Strings::Contains(body_type_name_lower, search_criteria)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Body Type {} | {}",
|
||||
e.first,
|
||||
e.second
|
||||
).c_str()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} Body Type{} found matching '{}'.",
|
||||
found_count,
|
||||
found_count != 1 ? "s" : "",
|
||||
sep->argplus[2]
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "../../client.h"
|
||||
|
||||
void FindBugCategory(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(2)) {
|
||||
const uint32 category_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
const std::string& category_name = Bug::GetName(category_id);
|
||||
if (Strings::EqualFold(category_name, "UNKNOWN BUG CATEGORY")) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Bug Category ID {} does not exist.",
|
||||
category_id
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Bug Category {} | {}",
|
||||
category_id,
|
||||
category_name
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||
|
||||
uint32 found_count = 0;
|
||||
|
||||
for (const auto& e : bug_category_names) {
|
||||
const std::string& bug_category_name_lower = Strings::ToLower(e.second);
|
||||
if (!Strings::Contains(bug_category_name_lower, search_criteria)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Bug Category {} | {}",
|
||||
e.first,
|
||||
e.second
|
||||
).c_str()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} Bug Categor{} found matching '{}'.",
|
||||
found_count,
|
||||
found_count != 1 ? "ies" : "y",
|
||||
sep->argplus[2]
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "../../client.h"
|
||||
|
||||
void FindComparisonType(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(2)) {
|
||||
const uint8 type = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
|
||||
const std::string& type_name = ComparisonType::GetName(type);
|
||||
if (Strings::EqualFold(type_name, "UNKNOWN COMPARISON TYPE")) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Comparison Type {} does not exist.",
|
||||
type
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Comparison Type {} | {}",
|
||||
type,
|
||||
type_name
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||
|
||||
uint32 found_count = 0;
|
||||
|
||||
for (const auto& e : comparison_types) {
|
||||
const std::string& type_name_lower = Strings::ToLower(e.second);
|
||||
if (!Strings::Contains(type_name_lower, search_criteria)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Comparison Type {} | {}",
|
||||
e.first,
|
||||
e.second
|
||||
).c_str()
|
||||
);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} Comparison Type{} found matching '{}'.",
|
||||
found_count,
|
||||
found_count != 1 ? "s" : "",
|
||||
sep->argplus[2]
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user