mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-30 11:45:46 +00:00
Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9583099ace | |||
| cf3483b402 | |||
| 311af7bbe9 | |||
| be42b73f5c | |||
| f76c798910 | |||
| ae198ae043 | |||
| 520943ebf1 | |||
| 9ac306fe67 | |||
| 7a1d69d0d4 | |||
| c873fe5a22 | |||
| e06b0c4b0c | |||
| ed2130f649 | |||
| 448a33a60c | |||
| 8f86cb353e | |||
| 178129443f | |||
| a7c3b41afc | |||
| a5a568d548 | |||
| e3198edb86 | |||
| 8568cf7d49 | |||
| 1fb7a860a1 | |||
| 7eaee2649e | |||
| a17f467b98 | |||
| 3359839a9b | |||
| 7e51e629f9 | |||
| dc6c28a52d | |||
| 78aee0780a | |||
| bcd943a964 | |||
| 56608e84bd | |||
| 8d23e710ce | |||
| 4d11077b21 | |||
| 5c0bdfdc4c | |||
| 6130e10831 | |||
| c3e1c531d2 | |||
| b52719a535 | |||
| 1af252466f | |||
| 699d22fc28 | |||
| 5d1fe68906 | |||
| 52dcf35425 | |||
| a7550fbd9e | |||
| cc0171dfe1 | |||
| 913c5da70f | |||
| 40fecbfaf5 | |||
| b1646381b0 | |||
| bb1578796b | |||
| 0e5a38f072 | |||
| 39876ab858 | |||
| ff16a76481 | |||
| ffd68eb63d | |||
| 76c1da1aad | |||
| a91e03fa43 | |||
| 453106439f | |||
| 3da24fffa4 | |||
| 8d8ef6d480 | |||
| 1f9c4b3a22 | |||
| 7dfda95d86 | |||
| 40738b29e3 | |||
| 080865faa2 | |||
| e2b545991a | |||
| b7f8d0f179 | |||
| e3588781aa | |||
| e9b84f4d11 | |||
| 4f03970fd1 | |||
| 4979da6932 | |||
| 9987029791 | |||
| eece0a92e3 | |||
| 057f96796a | |||
| f475cecdb1 | |||
| 6296ed6d41 | |||
| ac0f729aa2 | |||
| 2937852cf9 | |||
| 2cf5bae571 | |||
| 2feb05be18 | |||
| 421767e1e5 | |||
| 6e9ff52dce | |||
| aa700f8960 | |||
| 2ef959c5ed | |||
| e49ab924cc | |||
| fc3c691588 | |||
| d465a3deba | |||
| 40c9c8044b | |||
| 70a96ea098 | |||
| d5cbec714e | |||
| 6903205484 | |||
| 4c81321847 | |||
| e5cea73e0c | |||
| 23308192b5 | |||
| 29fdf7e2ae | |||
| 098498dedd | |||
| b6fb8daae8 | |||
| 563f7d5564 | |||
| 1e5abc456b | |||
| 3b0fa015a7 | |||
| c73a1e8bea | |||
| 3bfdc0cf71 | |||
| a23ac4628f | |||
| 5ef4612249 | |||
| 17f66c5d60 | |||
| 51eb95ed31 | |||
| 080abaede1 | |||
| 97e332819d | |||
| 1e41c5517e | |||
| c7a88af11a | |||
| d8ddd0aab9 | |||
| 95cbadade5 | |||
| a85f4fb703 | |||
| e63f34638b | |||
| 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 |
+309
-13
@@ -1,3 +1,299 @@
|
||||
## [22.57.0] 10/20/2024
|
||||
|
||||
### Bots
|
||||
|
||||
* Add "silent" option to ^spawn and mute raid spawn ([#4494](https://github.com/EQEmu/Server/pull/4494)) @nytmyr 2024-10-05
|
||||
* Add attack flag when told to attack ([#4490](https://github.com/EQEmu/Server/pull/4490)) @nytmyr 2024-09-29
|
||||
* Fix timers loading on spawn and zone ([#4516](https://github.com/EQEmu/Server/pull/4516)) @nytmyr 2024-10-20
|
||||
|
||||
### Code
|
||||
|
||||
* Fixed a typo in Zoning.cpp ([#4515](https://github.com/EQEmu/Server/pull/4515)) @carolus21rex 2024-10-20
|
||||
* Optimization Code Cleanup ([#4489](https://github.com/EQEmu/Server/pull/4489)) @Akkadius 2024-09-30
|
||||
* Remove Extra Skill in EQ::skills::GetExtraDamageSkills() ([#4486](https://github.com/EQEmu/Server/pull/4486)) @Kinglykrab 2024-10-03
|
||||
|
||||
### Crash
|
||||
|
||||
* Fixes a crash when the faction_list db table is empty. ([#4511](https://github.com/EQEmu/Server/pull/4511)) @KimLS 2024-10-14
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add character_instance_safereturns to tables_to_zero_id ([#4485](https://github.com/EQEmu/Server/pull/4485)) @Morzain 2024-09-26
|
||||
* Correctly limit max targets of PBAOE ([#4507](https://github.com/EQEmu/Server/pull/4507)) @catapultam-habeo 2024-10-11
|
||||
* FindBestZ selecting false zone floor as bestz - Results in roambox failures ([#4504](https://github.com/EQEmu/Server/pull/4504)) @fryguy503 2024-10-13
|
||||
* Fix #set motd Crash ([#4495](https://github.com/EQEmu/Server/pull/4495)) @Kinglykrab 2024-10-05
|
||||
* Fix `character_exp_modifiers` Default Values ([#4502](https://github.com/EQEmu/Server/pull/4502)) @Kinglykrab 2024-10-09
|
||||
* Fix a display error regarding a few trader/buyer query errors ([#4514](https://github.com/EQEmu/Server/pull/4514)) @neckkola 2024-10-17
|
||||
* Fix Group ID 0 in Group::SaveGroupLeaderAA() ([#4487](https://github.com/EQEmu/Server/pull/4487)) @Kinglykrab 2024-10-03
|
||||
* Fix Mercenary Encounter Crash ([#4509](https://github.com/EQEmu/Server/pull/4509)) @Kinglykrab 2024-10-12
|
||||
* Fix NPC::CanTalk() Crash ([#4499](https://github.com/EQEmu/Server/pull/4499)) @Kinglykrab 2024-10-07
|
||||
* Fix Spells:DefaultAOEMaxTargets Default Value ([#4508](https://github.com/EQEmu/Server/pull/4508)) @Kinglykrab 2024-10-12
|
||||
* Fix Targeted AOE Max Targets Rule ([#4488](https://github.com/EQEmu/Server/pull/4488)) @Kinglykrab 2024-10-03
|
||||
* fixed a bug where it would use npc value instead of faction value in the database. ([#4491](https://github.com/EQEmu/Server/pull/4491)) @regneq 2024-09-29
|
||||
* Master of Disguise should apply to illusions casted by others. ([#4506](https://github.com/EQEmu/Server/pull/4506)) @fryguy503 2024-10-11
|
||||
* Spells - Self Only (Yellow) cast when non group member is targeted ([#4503](https://github.com/EQEmu/Server/pull/4503)) @fryguy503 2024-10-11
|
||||
|
||||
### Loginserver
|
||||
|
||||
* Larion loginserver support ([#4492](https://github.com/EQEmu/Server/pull/4492)) @KimLS 2024-10-03
|
||||
* Login Fatal Error Spamming ([#4476](https://github.com/EQEmu/Server/pull/4476)) @KimLS 2024-10-09
|
||||
|
||||
### Logs
|
||||
|
||||
* Add NPC Trades to Player Events ([#4505](https://github.com/EQEmu/Server/pull/4505)) @Kinglykrab 2024-10-13
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add Buff Fade Methods to Perl/Lua ([#4501](https://github.com/EQEmu/Server/pull/4501)) @Kinglykrab 2024-10-09
|
||||
* Add EVENT_READ_ITEM to Perl/Lua ([#4497](https://github.com/EQEmu/Server/pull/4497)) @Kinglykrab 2024-10-08
|
||||
* Add NPC List Filter Methods to Perl/Lua ([#4493](https://github.com/EQEmu/Server/pull/4493)) @Kinglykrab 2024-10-04
|
||||
* Add Scripting Support to Mercenaries ([#4500](https://github.com/EQEmu/Server/pull/4500)) @Kinglykrab 2024-10-11
|
||||
|
||||
### Rules
|
||||
|
||||
* Add Rule to disable PVP Regions ([#4513](https://github.com/EQEmu/Server/pull/4513)) @Kinglykrab 2024-10-17
|
||||
|
||||
## [22.56.3] 9/23/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix issue with Client::SaveDisciplines() not specifying character ID ([#4481](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-23
|
||||
|
||||
## [22.56.2] 9/20/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix Issue with Database::ReserveName ([#4477](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-20
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add GrantAllAAPoints() Overload To Perl/Lua ([#4474](https://github.com/EQEmu/Server/pull/4474)) @Kinglykrab 2024-09-20
|
||||
|
||||
## [22.56.1] 9/20/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix Untrained Disciplines in Client::SaveDisciplines() ([#4472](https://github.com/EQEmu/Server/pull/4472)) @Kinglykrab 2024-09-13
|
||||
* Fix Infinite Loop in Adventure::Finished() ([#4473](https://github.com/EQEmu/Server/pull/4473)) @oddx2k 2024-09-13
|
||||
|
||||
## [22.56.0] 9/12/2024
|
||||
|
||||
### Code
|
||||
|
||||
* Add IsCloseToBanker method ([#4462](https://github.com/EQEmu/Server/pull/4462)) @Akkadius 2024-08-27
|
||||
|
||||
### Feature
|
||||
|
||||
* Add Rule to Limit Task Update Messages ([#4459](https://github.com/EQEmu/Server/pull/4459)) @Kinglykrab 2024-08-28
|
||||
* Allow NPCs to cast Sacrifice ([#4470](https://github.com/EQEmu/Server/pull/4470)) @fuzzlecutter 2024-09-12
|
||||
* Lazy Load Bank Contents ([#4453](https://github.com/EQEmu/Server/pull/4453)) @catapultam-habeo 2024-08-27
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add RULE_STRING to RuleManager::ResetRules ([#4467](https://github.com/EQEmu/Server/pull/4467)) @Kinglykrab 2024-09-07
|
||||
* Fix Bard Effect in Migration 9237 ([#4468](https://github.com/EQEmu/Server/pull/4468)) @Kinglykrab 2024-09-09
|
||||
* ModernAAScalingEnabled() Calculation Error ([#4469](https://github.com/EQEmu/Server/pull/4469)) @carolus21rex 2024-09-11
|
||||
|
||||
### Performance
|
||||
|
||||
* Move Discipline Loading to Client::CompleteConnect() ([#4466](https://github.com/EQEmu/Server/pull/4466)) @Kinglykrab 2024-09-09
|
||||
|
||||
### Rules
|
||||
|
||||
* Add a Bandolier Swap Delay Rule ([#4465](https://github.com/EQEmu/Server/pull/4465)) @Kinglykrab 2024-09-08
|
||||
|
||||
## [22.55.1] 8/26/2024
|
||||
|
||||
### Code
|
||||
|
||||
* Remove unused methods ([#4449](https://github.com/EQEmu/Server/pull/4449)) @Kinglykrab 2024-08-22
|
||||
|
||||
### Feature
|
||||
|
||||
* Add Character:DefaultGuildRank Rule ([#4438](https://github.com/EQEmu/Server/pull/4438)) @Kinglykrab 2024-08-04
|
||||
* Add Optional Return to EVENT_DAMAGE_TAKEN ([#4454](https://github.com/EQEmu/Server/pull/4454)) @Kinglykrab 2024-08-27
|
||||
* Extend Spell Buckets Functionality ([#4441](https://github.com/EQEmu/Server/pull/4441)) @Kinglykrab 2024-08-22
|
||||
|
||||
### Fixes
|
||||
|
||||
* Apply Race & Class restrictions to Auto-Combines ([#4452](https://github.com/EQEmu/Server/pull/4452)) @catapultam-habeo 2024-08-20
|
||||
* Attune Augments when Equipped ([#4446](https://github.com/EQEmu/Server/pull/4446)) @fryguy503 2024-08-10
|
||||
* Correct missed maxlevel reference in exp.cpp ([#4463](https://github.com/EQEmu/Server/pull/4463)) @N0ctrnl 2024-08-27
|
||||
* Ensure close of Tribute Item search ([#4439](https://github.com/EQEmu/Server/pull/4439)) @joligario 2024-08-04
|
||||
* Fix AddCrystals() in Perl/Lua ([#4445](https://github.com/EQEmu/Server/pull/4445)) @Kinglykrab 2024-08-10
|
||||
* Fix Bot Spell Entries IDs Capping at 32,767 ([#4444](https://github.com/EQEmu/Server/pull/4444)) @Kinglykrab 2024-08-27
|
||||
* Fix Character ID of 0 being inserted into character_stats_record ([#4458](https://github.com/EQEmu/Server/pull/4458)) @Kinglykrab 2024-08-22
|
||||
* Fix Issue with Removed #setfaction Command ([#4448](https://github.com/EQEmu/Server/pull/4448)) @Kinglykrab 2024-08-11
|
||||
* Fix Lua Client FilteredMessage ([#4437](https://github.com/EQEmu/Server/pull/4437)) @Kinglykrab 2024-07-31
|
||||
* Fix client hotbar exchanging items when zoning ([#4460](https://github.com/EQEmu/Server/pull/4460)) @neckkola 2024-08-27
|
||||
* Fix issue with killed mob coordinates ([#4457](https://github.com/EQEmu/Server/pull/4457)) @Kinglykrab 2024-08-22
|
||||
* Imitate Death should also clear zone feign aggro ([#4436](https://github.com/EQEmu/Server/pull/4436)) @fryguy503 2024-07-31
|
||||
* client_max_level allow leveling to end of level ([#4455](https://github.com/EQEmu/Server/pull/4455)) @fryguy503 2024-08-20
|
||||
|
||||
### Improvement
|
||||
|
||||
* Filtered Messages Extension ([#4435](https://github.com/EQEmu/Server/pull/4435)) @fryguy503 2024-07-31
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add AreTasksCompleted() to Perl/Lua. ([#4456](https://github.com/EQEmu/Server/pull/4456)) @Kinglykrab 2024-08-23
|
||||
* Add Area-Based Quest Methods to Perl/Lua ([#4447](https://github.com/EQEmu/Server/pull/4447)) @Kinglykrab 2024-08-27
|
||||
* Add Several Door Methods to Perl/Lua ([#4451](https://github.com/EQEmu/Server/pull/4451)) @Kinglykrab 2024-08-16
|
||||
|
||||
### World
|
||||
|
||||
* Fix slow world bootup bug ([#4461](https://github.com/EQEmu/Server/pull/4461)) @Akkadius 2024-08-27
|
||||
|
||||
## [22.54.0] 7/30/2024
|
||||
|
||||
### Code
|
||||
|
||||
* Cleanup Client File Exporting ([#4348](https://github.com/EQEmu/Server/pull/4348)) @Kinglykrab 2024-07-31
|
||||
* Cleanup Stance Code ([#4368](https://github.com/EQEmu/Server/pull/4368)) @Kinglykrab 2024-07-03
|
||||
* Mask GM Show Buff message behind EntityVariable ([#4419](https://github.com/EQEmu/Server/pull/4419)) @nytmyr 2024-07-22
|
||||
|
||||
### Commands
|
||||
|
||||
* Extend #devtools Functionality ([#4425](https://github.com/EQEmu/Server/pull/4425)) @Kinglykrab 2024-07-23
|
||||
|
||||
### Databuckets
|
||||
|
||||
* Remove memory reserve from bulk load ([#4427](https://github.com/EQEmu/Server/pull/4427)) @Akkadius 2024-07-23
|
||||
|
||||
### Feature
|
||||
|
||||
* Add Barter/Buyer Features ([#4405](https://github.com/EQEmu/Server/pull/4405)) @neckkola 2024-07-30
|
||||
* Add Parcel notification for online players when using the Quest API ([#4418](https://github.com/EQEmu/Server/pull/4418)) @neckkola 2024-07-22
|
||||
* Implement Move Multiple Items ([#4259](https://github.com/EQEmu/Server/pull/4259)) @catapultam-habeo 2024-07-30
|
||||
|
||||
### Fixes
|
||||
|
||||
* Aegolism Spell line stacking ([#4399](https://github.com/EQEmu/Server/pull/4399)) @KayenEQ 2024-07-07
|
||||
* AllowRaidTargetBlind logic backwards ([#4400](https://github.com/EQEmu/Server/pull/4400)) @fryguy503 2024-07-01
|
||||
* AutoSplit unknown bug and cleanup. ([#4401](https://github.com/EQEmu/Server/pull/4401)) @fryguy503 2024-07-07
|
||||
* Corpse Call removing Resurrection Effects ([#4410](https://github.com/EQEmu/Server/pull/4410)) @fryguy503 2024-07-22
|
||||
* Fix #parcels add subcommand ([#4431](https://github.com/EQEmu/Server/pull/4431)) @neckkola 2024-07-29
|
||||
* Fix #setlevel Allowing Skills Above Max ([#4423](https://github.com/EQEmu/Server/pull/4423)) @Kinglykrab 2024-07-23
|
||||
* Fix Bot::SetBotStance ([#4426](https://github.com/EQEmu/Server/pull/4426)) @Kinglykrab 2024-07-23
|
||||
* Fix Client::RemoveTitle ([#4421](https://github.com/EQEmu/Server/pull/4421)) @Kinglykrab 2024-07-23
|
||||
* Fix EVENT_USE_SKILL with Sense Heading ([#4424](https://github.com/EQEmu/Server/pull/4424)) @Kinglykrab 2024-07-23
|
||||
* Fix for random disconnects when a large number of guild members zone or disconnect ([#4402](https://github.com/EQEmu/Server/pull/4402)) @neckkola 2024-07-10
|
||||
* Fix issue with quest::echo and quest::me ([#4433](https://github.com/EQEmu/Server/pull/4433)) @Kinglykrab 2024-07-30
|
||||
* Personal tributes for bard items were not applying correctly ([#4416](https://github.com/EQEmu/Server/pull/4416)) @neckkola 2024-07-16
|
||||
* Potential fix for some undesired ranged explotative behavior. ([#4413](https://github.com/EQEmu/Server/pull/4413)) @fryguy503 2024-07-22
|
||||
* Proximity Aggro for Frustrated and Undead ([#4411](https://github.com/EQEmu/Server/pull/4411)) @fryguy503 2024-07-22
|
||||
* Slay Adjustments ([#4389](https://github.com/EQEmu/Server/pull/4389)) @fryguy503 2024-07-07
|
||||
* Stop DOSing ourselves with OP_WearChange ([#4432](https://github.com/EQEmu/Server/pull/4432)) @catapultam-habeo 2024-07-30
|
||||
* [Quest API] Fix getraididbycharid and getgroupidbycharid ([#4417](https://github.com/EQEmu/Server/pull/4417)) @nytmyr 2024-07-16
|
||||
|
||||
### Improvement
|
||||
|
||||
* Flee Overhaul ([#4407](https://github.com/EQEmu/Server/pull/4407)) @fryguy503 2024-07-30
|
||||
|
||||
### Rules
|
||||
|
||||
* Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs ([#4406](https://github.com/EQEmu/Server/pull/4406)) @nytmyr 2024-07-22
|
||||
|
||||
### Zone Instances
|
||||
|
||||
* Revert " Handle routing to instances when using evac/succor " (#4429) ([#4297](https://github.com/EQEmu/Server/pull/4297)) @Akkadius 2024-07-30
|
||||
|
||||
### Zoning
|
||||
|
||||
* Improve zone routing ([#4428](https://github.com/EQEmu/Server/pull/4428)) @Akkadius 2024-07-30
|
||||
|
||||
## [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
|
||||
@@ -1368,7 +1664,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
|
||||
|
||||
@@ -2450,7 +2746,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
|
||||
|
||||
@@ -2495,7 +2791,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
|
||||
|
||||
@@ -2519,7 +2815,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
|
||||
|
||||
@@ -2543,13 +2839,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
|
||||
|
||||
@@ -2569,7 +2865,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
|
||||
|
||||
@@ -2726,7 +3022,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
|
||||
|
||||
@@ -2768,7 +3064,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
|
||||
|
||||
@@ -2815,7 +3111,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
|
||||
|
||||
@@ -2862,7 +3158,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
|
||||
|
||||
@@ -2884,7 +3180,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
|
||||
|
||||
@@ -2905,7 +3201,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
|
||||
|
||||
|
||||
+39
-140
@@ -29,9 +29,13 @@
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
#include "../../common/repositories/base_data_repository.h"
|
||||
#include "../../common/repositories/db_str_repository.h"
|
||||
#include "../../common/repositories/skill_caps_repository.h"
|
||||
#include "../../common/repositories/spells_new_repository.h"
|
||||
#include "../../common/file.h"
|
||||
#include "../../common/events/player_event_logs.h"
|
||||
#include "../../common/skill_caps.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
@@ -98,25 +102,22 @@ int main(int argc, char **argv)
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
|
||||
std::string arg_1;
|
||||
std::string export_type;
|
||||
|
||||
if (argv[1]) {
|
||||
arg_1 = argv[1];
|
||||
export_type = argv[1];
|
||||
}
|
||||
|
||||
if (arg_1 == "spells") {
|
||||
if (Strings::EqualFold(export_type, "spells")) {
|
||||
ExportSpells(&content_db);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "skills") {
|
||||
} else if (Strings::EqualFold(export_type, "skills")) {
|
||||
ExportSkillCaps(&content_db);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "basedata") {
|
||||
} else if (Strings::EqualFold(export_type, "basedata") || Strings::EqualFold(export_type, "base_data")) {
|
||||
ExportBaseData(&content_db);
|
||||
return 0;
|
||||
}
|
||||
if (arg_1 == "dbstring") {
|
||||
} else if (Strings::EqualFold(export_type, "dbstr") || Strings::EqualFold(export_type, "dbstring")) {
|
||||
ExportDBStrings(&database);
|
||||
return 0;
|
||||
}
|
||||
@@ -131,181 +132,79 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExportSpells(SharedDatabase *db)
|
||||
void ExportSpells(SharedDatabase* db)
|
||||
{
|
||||
LogInfo("Exporting Spells");
|
||||
|
||||
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
std::ofstream file(fmt::format("{}/export/spells_us.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string query = "SELECT * FROM spells_new ORDER BY id";
|
||||
auto results = db->QueryDatabase(query);
|
||||
const auto& lines = SpellsNewRepository::GetSpellFileLines(*db);
|
||||
|
||||
if (results.Success()) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
std::string line;
|
||||
unsigned int fields = results.ColumnCount();
|
||||
for (unsigned int i = 0; i < fields; ++i) {
|
||||
if (i != 0) {
|
||||
line.push_back('^');
|
||||
}
|
||||
const std::string& file_string = Strings::Implode("\n", lines);
|
||||
|
||||
if (row[i] != nullptr) {
|
||||
line += row[i];
|
||||
}
|
||||
}
|
||||
file << file_string;
|
||||
|
||||
fprintf(f, "%s\n", line.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
file.close();
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
|
||||
{
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
|
||||
class_id,
|
||||
skill_id
|
||||
)
|
||||
);
|
||||
|
||||
return !l.empty();
|
||||
}
|
||||
|
||||
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
|
||||
{
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
|
||||
class_id,
|
||||
skill_id,
|
||||
level
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto e = l.front();
|
||||
|
||||
return e.cap;
|
||||
LogInfo("Exported [{}] Spell{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
void ExportSkillCaps(SharedDatabase* db)
|
||||
{
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
const auto& lines = SkillCapsRepository::GetSkillCapFileLines(*db);
|
||||
|
||||
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++) {
|
||||
uint32 cap = GetSkill(db, skill_id, class_id, level);
|
||||
if (cap < previous_cap) {
|
||||
cap = previous_cap;
|
||||
}
|
||||
const std::string& file_string = Strings::Implode("\n", lines);
|
||||
|
||||
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
|
||||
|
||||
previous_cap = cap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
file << file_string;
|
||||
|
||||
file.close();
|
||||
|
||||
LogInfo("Exported [{}] Skill Cap{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
void ExportBaseData(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Base Data");
|
||||
|
||||
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
std::ofstream file(fmt::format("{}/export/BaseData.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string query = "SELECT * FROM base_data ORDER BY level, class";
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
std::string line;
|
||||
unsigned int fields = results.ColumnCount();
|
||||
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
|
||||
if (rowIndex != 0) {
|
||||
line.push_back('^');
|
||||
}
|
||||
const auto& lines = BaseDataRepository::GetBaseDataFileLines(*db);
|
||||
|
||||
if (row[rowIndex] != nullptr) {
|
||||
line += row[rowIndex];
|
||||
}
|
||||
}
|
||||
const std::string& file_string = Strings::Implode("\n", lines);
|
||||
|
||||
fprintf(f, "%s\n", line.c_str());
|
||||
}
|
||||
}
|
||||
file << file_string;
|
||||
|
||||
fclose(f);
|
||||
file.close();
|
||||
|
||||
LogInfo("Exported [{}] Base Data Entr{}", lines.size(), lines.size() != 1 ? "ies" : "y");
|
||||
}
|
||||
|
||||
void ExportDBStrings(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting DB Strings");
|
||||
|
||||
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
std::ofstream file(fmt::format("{}/export/dbstr_us.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f, "Major^Minor^String(New)\n");
|
||||
const std::string query = "SELECT * FROM db_str ORDER BY id, type";
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
std::string line;
|
||||
unsigned int fields = results.ColumnCount();
|
||||
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
|
||||
if (rowIndex != 0) {
|
||||
line.push_back('^');
|
||||
}
|
||||
const auto& lines = DbStrRepository::GetDBStrFileLines(*db);
|
||||
|
||||
if (row[rowIndex] != nullptr) {
|
||||
line += row[rowIndex];
|
||||
}
|
||||
}
|
||||
const std::string& file_string = Strings::Implode("\n", lines);
|
||||
|
||||
fprintf(f, "%s\n", line.c_str());
|
||||
}
|
||||
}
|
||||
file << file_string;
|
||||
|
||||
fclose(f);
|
||||
file.close();
|
||||
|
||||
LogInfo("Exported [{}] Database String{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ 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
|
||||
@@ -157,6 +158,7 @@ SET(repositories
|
||||
repositories/base/base_bugs_repository.h
|
||||
repositories/base/base_bug_reports_repository.h
|
||||
repositories/base/base_buyer_repository.h
|
||||
repositories/base/base_buyer_trade_items_repository.h
|
||||
repositories/base/base_character_activities_repository.h
|
||||
repositories/base/base_character_alternate_abilities_repository.h
|
||||
repositories/base/base_character_alt_currency_repository.h
|
||||
@@ -338,7 +340,8 @@ SET(repositories
|
||||
repositories/books_repository.h
|
||||
repositories/bugs_repository.h
|
||||
repositories/bug_reports_repository.h
|
||||
repositories/buyer_repository.h
|
||||
repositories/buyer_buy_lines_repository.h
|
||||
repositories/buyer_trade_items_repository.h
|
||||
repositories/character_activities_repository.h
|
||||
repositories/character_alternate_abilities_repository.h
|
||||
repositories/character_alt_currency_repository.h
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ Bazaar::GetSearchResults(
|
||||
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));
|
||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
|
||||
}
|
||||
if (search.max_cost != 0) {
|
||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
|
||||
@@ -314,7 +314,7 @@ Bazaar::GetSearchResults(
|
||||
},
|
||||
{
|
||||
.should_check = search.race != 0xFFFFFFFF,
|
||||
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(search.race))
|
||||
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))
|
||||
},
|
||||
{
|
||||
.should_check = search.augment != 0,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../rulesys.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../repositories/instance_list_repository.h"
|
||||
#include "../zone_store.h"
|
||||
|
||||
|
||||
WorldContentService::WorldContentService()
|
||||
@@ -183,8 +184,8 @@ void WorldContentService::ReloadContentFlags()
|
||||
}
|
||||
|
||||
SetContentFlags(set_content_flags);
|
||||
LoadZones();
|
||||
LoadStaticGlobalZoneInstances();
|
||||
zone_store.LoadZones(*m_content_database);
|
||||
}
|
||||
|
||||
Database *WorldContentService::GetDatabase() const
|
||||
@@ -236,18 +237,6 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
|
||||
ReloadContentFlags();
|
||||
}
|
||||
|
||||
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
|
||||
//
|
||||
// example # 1
|
||||
// lavastorm (pre-don) version 0 (classic)
|
||||
// lavastorm (don) version 1
|
||||
// we want to route players to the correct version of lavastorm based on the current server side expansion
|
||||
// in order to do that the simplest and cleanest way we intercept the zoning process and route players to an "instance" of the zone
|
||||
// the reason why we're doing this is because all of the zoning logic already is handled by two keys "zone_id" and "instance_id"
|
||||
// we can leverage static, never expires instances to handle this but to the client they don't see it any other way than a public normal zone
|
||||
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
|
||||
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
||||
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
||||
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
||||
{
|
||||
auto r = FindZone(zc->zoneID, zc->instanceID);
|
||||
@@ -261,93 +250,72 @@ void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
||||
// LoadStaticGlobalZoneInstances loads all static global zone instances
|
||||
// these are zones that are never set to expire and are global
|
||||
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
|
||||
WorldContentService * WorldContentService::LoadStaticGlobalZoneInstances()
|
||||
WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
|
||||
{
|
||||
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
|
||||
m_zone_static_instances = InstanceListRepository::GetWhere(
|
||||
*GetDatabase(),
|
||||
fmt::format("never_expires = 1 AND is_global = 1")
|
||||
);
|
||||
|
||||
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
|
||||
LogInfo("Loaded [{}] zone_instances", m_zone_static_instances.size());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// LoadZones sets the zones for the world content service
|
||||
// this is used for zone routing middleware
|
||||
// we pull the zone list from the zone repository and feed from the zone store for now
|
||||
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
|
||||
WorldContentService * WorldContentService::LoadZones()
|
||||
{
|
||||
m_zones = ZoneRepository::All(*GetContentDatabase());
|
||||
|
||||
LogInfo("Loaded [{}] zones", m_zones.size());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
|
||||
// era contextual routing, multiple version of zones, etc
|
||||
// FindZone handles content and context aware zone routing (middleware)
|
||||
//
|
||||
// this is a middleware function that is meant to be used in the zone change process
|
||||
// this hooks all core zone changes within the server and routes the player to the correct zone
|
||||
// returning a zone_id of non-zero means the middleware will route the player
|
||||
// returning a zone_id of 0 means the middleware will not route the player
|
||||
// this is useful for handling multiple versions of the same zone
|
||||
//
|
||||
// implementation >
|
||||
// the zoning and process spawning logic already is handled by two keys "zone_id" and "instance_id"
|
||||
// we leverage static, never expires instances to handle this and client still sees it as a normal zone
|
||||
//
|
||||
// content awareness >
|
||||
// simply use the zone_id, server content settings and the middleware will handle the rest
|
||||
// you don't have to think about instances in any data tables (use instance_id 0)
|
||||
// you don't have to keep track of instance ids in scripts (use instance_id 0)
|
||||
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
||||
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
||||
//
|
||||
// example >
|
||||
// we want to route players to the correct version of lavastorm based on the current server side expansion (DoesZonePassContentFiltering)
|
||||
// lavastorm (pre-don) version 0 (classic)
|
||||
// zone table entry for version = 0, min_expansion = 0, max_expansion = 8
|
||||
// instance_list table entry for lavastorm has version = 0, is_global = 1, never_expires = 1
|
||||
// lavastorm (don) version 1
|
||||
// zone table entry for version = 1, min_expansion = 9, max_expansion = 99
|
||||
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
|
||||
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
|
||||
{
|
||||
// if there's an active dynamic instance, we don't need to route
|
||||
if (instance_id > 0) {
|
||||
auto inst = InstanceListRepository::FindOne(*GetDatabase(), instance_id);
|
||||
if (inst.id != 0 && !inst.is_global && !inst.never_expires) {
|
||||
return WorldContentService::FindZoneResult{
|
||||
.zone_id = 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
for (const auto &z: zone_store.GetZones()) {
|
||||
for (auto &i: m_zone_static_instances) {
|
||||
if (
|
||||
z.zoneidnumber == zone_id &&
|
||||
DoesZonePassContentFiltering(z) &&
|
||||
i.zone == zone_id &&
|
||||
i.version == z.version) {
|
||||
|
||||
for (auto &z: m_zones) {
|
||||
if (z.zoneidnumber == zone_id) {
|
||||
auto f = ContentFlags{
|
||||
.min_expansion = z.min_expansion,
|
||||
.max_expansion = z.max_expansion,
|
||||
.content_flags = z.content_flags,
|
||||
.content_flags_disabled = z.content_flags_disabled
|
||||
};
|
||||
|
||||
if (DoesPassContentFiltering(f)) {
|
||||
LogInfo(
|
||||
"Attempting to route player to zone [{}] ({}) version [{}] long_name [{}]",
|
||||
z.short_name,
|
||||
z.zoneidnumber,
|
||||
z.version,
|
||||
z.long_name
|
||||
);
|
||||
|
||||
// first pass, explicit match on public static global zone instances
|
||||
for (auto &i: m_zone_instances) {
|
||||
if (i.zone == zone_id && i.version == z.version) {
|
||||
LogInfo(
|
||||
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
||||
i.id,
|
||||
z.short_name,
|
||||
z.zoneidnumber,
|
||||
z.version,
|
||||
z.long_name,
|
||||
i.notes
|
||||
);
|
||||
|
||||
return WorldContentService::FindZoneResult{
|
||||
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
||||
.instance = i,
|
||||
.zone = z
|
||||
};
|
||||
}
|
||||
if (instance_id > 0 && i.id != instance_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
||||
"Routed player to public static instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
||||
i.id,
|
||||
z.short_name,
|
||||
z.zoneidnumber,
|
||||
z.version,
|
||||
z.long_name,
|
||||
z.note
|
||||
i.notes
|
||||
);
|
||||
|
||||
return WorldContentService::FindZoneResult{
|
||||
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
||||
.instance = InstanceListRepository::NewEntity(),
|
||||
.instance = i,
|
||||
.zone = z
|
||||
};
|
||||
}
|
||||
@@ -359,7 +327,7 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
|
||||
|
||||
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
||||
{
|
||||
for (auto &i: m_zone_instances) {
|
||||
for (auto &i: m_zone_static_instances) {
|
||||
if (i.id == instance_id) {
|
||||
return true;
|
||||
}
|
||||
@@ -367,3 +335,15 @@ bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WorldContentService::DoesZonePassContentFiltering(const ZoneRepository::Zone &z)
|
||||
{
|
||||
auto f = ContentFlags{
|
||||
.min_expansion = z.min_expansion,
|
||||
.max_expansion = z.max_expansion,
|
||||
.content_flags = z.content_flags,
|
||||
.content_flags_disabled = z.content_flags_disabled
|
||||
};
|
||||
|
||||
return DoesPassContentFiltering(f);
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ public:
|
||||
WorldContentService * SetExpansionContext();
|
||||
|
||||
bool DoesPassContentFiltering(const ContentFlags& f);
|
||||
bool DoesZonePassContentFiltering(const ZoneRepository::Zone& z);
|
||||
|
||||
WorldContentService * SetDatabase(Database *database);
|
||||
Database *GetDatabase() const;
|
||||
@@ -189,10 +190,8 @@ private:
|
||||
Database *m_content_database;
|
||||
|
||||
// holds a record of the zone table from the database
|
||||
std::vector<ZoneRepository::Zone> m_zones = {};
|
||||
WorldContentService *LoadStaticGlobalZoneInstances();
|
||||
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
|
||||
WorldContentService * LoadZones();
|
||||
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
|
||||
};
|
||||
|
||||
extern WorldContentService content_service;
|
||||
|
||||
+57
-14
@@ -66,6 +66,7 @@
|
||||
#endif
|
||||
|
||||
#include "database.h"
|
||||
#include "data_verification.h"
|
||||
#include "eq_packet_structs.h"
|
||||
#include "extprofile.h"
|
||||
#include "strings.h"
|
||||
@@ -77,6 +78,8 @@
|
||||
#include "zone_store.h"
|
||||
#include "repositories/merchantlist_temp_repository.h"
|
||||
#include "repositories/bot_data_repository.h"
|
||||
#include "repositories/trader_repository.h"
|
||||
#include "repositories/buyer_repository.h"
|
||||
|
||||
extern Client client;
|
||||
|
||||
@@ -282,16 +285,31 @@ bool Database::SetAccountStatus(const std::string& account_name, int16 status)
|
||||
|
||||
bool Database::ReserveName(uint32 account_id, const std::string& name)
|
||||
{
|
||||
const auto& l = CharacterDataRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`name` = '{}'",
|
||||
Strings::Escape(name)
|
||||
)
|
||||
const std::string& where_filter = fmt::format(
|
||||
"`name` = '{}'",
|
||||
Strings::Escape(name)
|
||||
);
|
||||
|
||||
if (!l.empty()) {
|
||||
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
const auto& b = BotDataRepository::GetWhere(*this, where_filter);
|
||||
|
||||
if (!b.empty()) {
|
||||
LogInfo("Account [{}] requested name [{}] but name is already taken by a bot", account_id, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto& c = CharacterDataRepository::GetWhere(*this, where_filter);
|
||||
|
||||
if (!c.empty()) {
|
||||
LogInfo("Account [{}] requested name [{}] but name is already taken by a character", account_id, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& n = NpcTypesRepository::GetWhere(*this, where_filter);
|
||||
|
||||
if (!n.empty()) {
|
||||
LogInfo("Account [{}] requested name [{}] but name is already taken by an NPC", account_id, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -306,13 +324,15 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
|
||||
return false;
|
||||
}
|
||||
|
||||
const int guild_id = RuleI(Character, DefaultGuild);
|
||||
const uint32 guild_id = RuleI(Character, DefaultGuild);
|
||||
const uint8 guild_rank = EQ::Clamp(RuleI(Character, DefaultGuildRank), 0, 8);
|
||||
if (guild_id != 0) {
|
||||
if (e.id) {
|
||||
auto g = GuildMembersRepository::NewEntity();
|
||||
|
||||
g.char_id = e.id;
|
||||
g.guild_id = guild_id;
|
||||
g.rank_ = guild_rank;
|
||||
|
||||
GuildMembersRepository::InsertOne(*this, g);
|
||||
}
|
||||
@@ -1628,16 +1648,29 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
|
||||
uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
||||
{
|
||||
const auto& e = GroupIdRepository::FindOne(*this, character_id);
|
||||
const auto& e = GroupIdRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`character_id` = {}",
|
||||
character_id
|
||||
)
|
||||
);
|
||||
|
||||
return e.character_id ? e.group_id : 0;
|
||||
return e.size() == 1 ? e.front().group_id : 0;
|
||||
}
|
||||
|
||||
uint32 Database::GetRaidIDByCharID(uint32 character_id)
|
||||
{
|
||||
const auto& e = RaidMembersRepository::FindOne(*this, character_id);
|
||||
|
||||
return e.charid ? e.raidid : 0;
|
||||
const auto& e = RaidMembersRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`charid` = {}",
|
||||
character_id
|
||||
)
|
||||
);
|
||||
|
||||
return e.size() == 1 ? e.front().raidid : 0;
|
||||
}
|
||||
|
||||
int64 Database::CountInvSnapshots()
|
||||
@@ -1827,7 +1860,7 @@ bool Database::CopyCharacter(
|
||||
|
||||
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
|
||||
|
||||
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets" };
|
||||
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
|
||||
|
||||
TransactionBegin();
|
||||
|
||||
@@ -2104,3 +2137,13 @@ void Database::ClearGuildOnlineStatus()
|
||||
{
|
||||
GuildMembersRepository::ClearOnlineStatus(*this);
|
||||
}
|
||||
|
||||
void Database::ClearTraderDetails()
|
||||
{
|
||||
TraderRepository::Truncate(*this);
|
||||
}
|
||||
|
||||
void Database::ClearBuyerDetails()
|
||||
{
|
||||
BuyerRepository::DeleteBuyer(*this, 0);
|
||||
}
|
||||
|
||||
@@ -244,6 +244,8 @@ public:
|
||||
|
||||
void PurgeAllDeletedDataBuckets();
|
||||
void ClearGuildOnlineStatus();
|
||||
void ClearTraderDetails();
|
||||
void ClearBuyerDetails();
|
||||
|
||||
|
||||
/* Database Variables */
|
||||
|
||||
@@ -4947,7 +4947,7 @@ UPDATE `aa_ability` SET `auto_grant_enabled` = 1 WHERE `grant_only` = 0 AND `cha
|
||||
.version = 9237,
|
||||
.description = "2023_10_15_import_13th_floor.sql",
|
||||
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
|
||||
.condition = "contains",
|
||||
.condition = "missing",
|
||||
.match = "mediumint",
|
||||
.sql = R"(
|
||||
ALTER TABLE `items`
|
||||
@@ -5660,6 +5660,104 @@ ALTER TABLE `trader`
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9281,
|
||||
.description = "2024_06_24_update_buyer_support.sql",
|
||||
.check = "SHOW COLUMNS FROM `buyer` LIKE 'id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `buyer`
|
||||
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||
CHANGE COLUMN `charid` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
|
||||
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
|
||||
ADD COLUMN `char_name` VARCHAR(64) NULL DEFAULT NULL AFTER `char_entity_id`,
|
||||
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_name`,
|
||||
ADD COLUMN `char_zone_instance_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_zone_id`,
|
||||
ADD COLUMN `transaction_date` DATETIME NULL DEFAULT NULL AFTER `char_zone_instance_id`,
|
||||
ADD COLUMN `welcome_message` VARCHAR(256) NULL DEFAULT NULL AFTER `transaction_date`,
|
||||
DROP COLUMN `buyslot`,
|
||||
DROP COLUMN `itemid`,
|
||||
DROP COLUMN `itemname`,
|
||||
DROP COLUMN `quantity`,
|
||||
DROP COLUMN `price`,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD INDEX `charid` (`char_id`);
|
||||
|
||||
CREATE TABLE `buyer_buy_lines` (
|
||||
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`buyer_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`buy_slot_id` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_id` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_qty` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_price` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`item_name` VARCHAR(64) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `buyerid_charid_buyslotid` (`buyer_id`, `char_id`, `buy_slot_id`) USING BTREE
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
AUTO_INCREMENT=1;
|
||||
|
||||
CREATE TABLE `buyer_trade_items` (
|
||||
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`buyer_buy_lines_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`item_id` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_qty` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_icon` INT(11) NOT NULL DEFAULT '0',
|
||||
`item_name` VARCHAR(64) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `buyerbuylinesid` (`buyer_buy_lines_id`) USING BTREE
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
AUTO_INCREMENT=1;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9282,
|
||||
.description = "2024_08_02_spell_buckets_comparison.sql",
|
||||
.check = "SHOW COLUMNS FROM `spell_buckets` LIKE 'bucket_comparison'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `spell_buckets`
|
||||
CHANGE COLUMN `spellid` `spell_id` int UNSIGNED NOT NULL FIRST,
|
||||
CHANGE COLUMN `key` `bucket_name` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `spell_id`,
|
||||
CHANGE COLUMN `value` `bucket_value` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `bucket_name`,
|
||||
ADD COLUMN `bucket_comparison` tinyint UNSIGNED NOT NULL DEFAULT 0 AFTER `bucket_value`,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`spell_id`) USING BTREE;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9283,
|
||||
.description = "2024_08_05_fix_client_hotbar",
|
||||
.check = "SHOW COLUMNS FROM `inventory` LIKE 'guid'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `inventory`
|
||||
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||
ALTER TABLE `inventory_snapshots`
|
||||
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9284,
|
||||
.description = "2024_10_08_character_exp_modifiers_default.sql",
|
||||
.check = "SHOW CREATE TABLE `character_exp_modifiers`",
|
||||
.condition = "contains",
|
||||
.match = "`exp_modifier` float NOT NULL,",
|
||||
.sql = R"(
|
||||
ALTER TABLE `character_exp_modifiers`
|
||||
MODIFY COLUMN `aa_modifier` float NOT NULL DEFAULT 1.0 AFTER `instance_version`,
|
||||
MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@@ -150,6 +150,17 @@ ADD COLUMN `augment_six` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five
|
||||
.sql = R"(
|
||||
ALTER TABLE `bot_data`
|
||||
ADD COLUMN `extra_haste` mediumint(8) NOT NULL DEFAULT 0 AFTER `wis`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9045,
|
||||
.description = "2024_08_05_bot_spells_entries_unsigned_spell_id.sql",
|
||||
.check = "SHOW COLUMNS FROM `bot_spells_entries` LIKE 'spell_id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `bot_spells_entries`
|
||||
CHANGE COLUMN `spellid` `spell_id` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `npc_spells_id`;
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@@ -36,7 +36,6 @@ namespace DatabaseSchema {
|
||||
{
|
||||
return {
|
||||
{"adventure_stats", "player_id"},
|
||||
{"buyer", "charid"},
|
||||
{"char_recipe_list", "char_id"},
|
||||
{"character_activities", "charid"},
|
||||
{"character_alt_currency", "char_id"},
|
||||
@@ -107,6 +106,8 @@ namespace DatabaseSchema {
|
||||
"adventure_details",
|
||||
"adventure_stats",
|
||||
"buyer",
|
||||
"buyer_buy_lines",
|
||||
"buyer_trade_items",
|
||||
"char_recipe_list",
|
||||
"character_activities",
|
||||
"character_alt_currency",
|
||||
@@ -325,6 +326,9 @@ namespace DatabaseSchema {
|
||||
"banned_ips",
|
||||
"bug_reports",
|
||||
"bugs",
|
||||
"buyer",
|
||||
"buyer_buy_lines",
|
||||
"buyer_trade_items",
|
||||
"completed_shared_task_activity_state",
|
||||
"completed_shared_task_members",
|
||||
"completed_shared_tasks",
|
||||
|
||||
+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 */
|
||||
|
||||
+61
-338
@@ -59,103 +59,40 @@ 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";
|
||||
}
|
||||
}
|
||||
|
||||
EQ::bug::CategoryID EQ::bug::CategoryNameToCategoryID(const char* category_name) {
|
||||
if (!category_name)
|
||||
return catOther;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const char *EQ::constants::GetStanceName(StanceType stance_type) {
|
||||
switch (stance_type) {
|
||||
case stanceUnknown:
|
||||
return "Unknown";
|
||||
case stancePassive:
|
||||
return "Passive";
|
||||
case stanceBalanced:
|
||||
return "Balanced";
|
||||
case stanceEfficient:
|
||||
return "Efficient";
|
||||
case stanceReactive:
|
||||
return "Reactive";
|
||||
case stanceAggressive:
|
||||
return "Aggressive";
|
||||
case stanceAssist:
|
||||
return "Assist";
|
||||
case stanceBurn:
|
||||
return "Burn";
|
||||
case stanceEfficient2:
|
||||
return "Efficient2";
|
||||
case stanceBurnAE:
|
||||
return "BurnAE";
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
||||
if (EQ::ValueWithin(stance_type, EQ::constants::stancePassive, EQ::constants::stanceBurnAE)) {
|
||||
return (stance_type - EQ::constants::stancePassive);
|
||||
uint32 Bug::GetID(const std::string& category_name)
|
||||
{
|
||||
for (const auto& e : bug_category_names) {
|
||||
if (e.second == category_name) {
|
||||
return e.first;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Bug::Category::Other;
|
||||
}
|
||||
|
||||
std::string Bug::GetName(uint32 category_id)
|
||||
{
|
||||
return IsValid(category_id) ? bug_category_names[category_id] : "UNKNOWN BUG CATEGORY";
|
||||
}
|
||||
|
||||
bool Bug::IsValid(uint32 category_id)
|
||||
{
|
||||
return bug_category_names.find(category_id) != bug_category_names.end();
|
||||
}
|
||||
|
||||
std::string Stance::GetName(uint8 stance_id)
|
||||
{
|
||||
return IsValid(stance_id) ? stance_names[stance_id] : "UNKNOWN STANCE";
|
||||
}
|
||||
|
||||
bool Stance::IsValid(uint8 stance_id)
|
||||
{
|
||||
return stance_names.find(stance_id) != stance_names.end();
|
||||
}
|
||||
|
||||
uint8 Stance::GetIndex(uint8 stance_id)
|
||||
{
|
||||
return IsValid(stance_id) ? (stance_id - Stance::Passive) : 0;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetLanguageMap()
|
||||
@@ -249,102 +186,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 +276,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 +403,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 +434,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();
|
||||
}
|
||||
|
||||
+283
-221
@@ -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
|
||||
@@ -204,19 +274,6 @@ namespace EQ
|
||||
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
||||
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
||||
|
||||
enum StanceType : int {
|
||||
stanceUnknown = 0,
|
||||
stancePassive,
|
||||
stanceBalanced,
|
||||
stanceEfficient,
|
||||
stanceReactive,
|
||||
stanceAggressive,
|
||||
stanceAssist,
|
||||
stanceBurn,
|
||||
stanceEfficient2,
|
||||
stanceBurnAE
|
||||
};
|
||||
|
||||
enum BotSpellIDs : int {
|
||||
Warrior = 3001,
|
||||
Cleric,
|
||||
@@ -267,70 +324,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,
|
||||
@@ -356,9 +349,6 @@ namespace EQ
|
||||
Proximity
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetLanguageMap();
|
||||
std::string GetLanguageName(uint8 language_id);
|
||||
|
||||
@@ -368,12 +358,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 +370,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,16 +382,9 @@ 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);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
|
||||
} /*constants*/
|
||||
|
||||
namespace profile {
|
||||
@@ -464,37 +438,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,
|
||||
@@ -508,7 +451,7 @@ namespace EQ
|
||||
Raid,
|
||||
Guild
|
||||
};
|
||||
}; // namespace consent
|
||||
};
|
||||
} /*EQEmu*/
|
||||
|
||||
enum ServerLockType : int {
|
||||
@@ -517,26 +460,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 +511,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 +524,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 +674,92 @@ 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" }
|
||||
};
|
||||
|
||||
namespace Stance {
|
||||
constexpr uint32 Unknown = 0;
|
||||
constexpr uint32 Passive = 1;
|
||||
constexpr uint32 Balanced = 2;
|
||||
constexpr uint32 Efficient = 3;
|
||||
constexpr uint32 Reactive = 4;
|
||||
constexpr uint32 Aggressive = 5;
|
||||
constexpr uint32 Assist = 6;
|
||||
constexpr uint32 Burn = 7;
|
||||
constexpr uint32 Efficient2 = 8;
|
||||
constexpr uint32 AEBurn = 9;
|
||||
|
||||
std::string GetName(uint8 stance_id);
|
||||
uint8 GetIndex(uint8 stance_id);
|
||||
bool IsValid(uint8 stance_id);
|
||||
}
|
||||
|
||||
static std::map<uint32, std::string> stance_names = {
|
||||
{ Stance::Unknown, "Unknown" },
|
||||
{ Stance::Passive, "Passive" },
|
||||
{ Stance::Balanced, "Balanced" },
|
||||
{ Stance::Efficient, "Efficient" },
|
||||
{ Stance::Reactive, "Reactive" },
|
||||
{ Stance::Aggressive, "Aggressive" },
|
||||
{ Stance::Assist, "Assist" },
|
||||
{ Stance::Burn, "Burn" },
|
||||
{ Stance::Efficient2, "Efficient" },
|
||||
{ Stance::AEBurn, "AE Burn" }
|
||||
};
|
||||
|
||||
namespace PCNPCOnlyFlagType {
|
||||
constexpr int PC = 1;
|
||||
constexpr int NPC = 2;
|
||||
}
|
||||
|
||||
namespace BookType {
|
||||
constexpr uint8 Scroll = 0;
|
||||
constexpr uint8 Book = 1;
|
||||
constexpr uint8 ItemInfo = 2;
|
||||
}
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -67,6 +67,7 @@ N(OP_Buff),
|
||||
N(OP_BuffCreate),
|
||||
N(OP_BuffRemoveRequest),
|
||||
N(OP_Bug),
|
||||
N(OP_BuyerItems),
|
||||
N(OP_CameraEffect),
|
||||
N(OP_Camp),
|
||||
N(OP_CancelSneakHide),
|
||||
@@ -533,6 +534,7 @@ N(OP_Stamina),
|
||||
N(OP_Stun),
|
||||
N(OP_Surname),
|
||||
N(OP_SwapSpell),
|
||||
N(OP_SystemFingerprint),
|
||||
N(OP_TargetBuffs),
|
||||
N(OP_TargetCommand),
|
||||
N(OP_TargetHoTT),
|
||||
|
||||
+7
-44
@@ -758,10 +758,10 @@ typedef enum {
|
||||
FilterFocusEffects = 22, //0=show, 1=hide
|
||||
FilterPetSpells = 23, //0=show, 1=hide
|
||||
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
|
||||
FilterUnknown25 = 25,
|
||||
FilterUnknown26 = 26,
|
||||
FilterUnknown27 = 27,
|
||||
FilterUnknown28 = 28,
|
||||
FilterItemSpeech = 25, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterStrikethrough = 26, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterStuns = 27, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterBardSongsOnPets = 28, //0=show, 1=hide // RoF2 Confirmed
|
||||
_FilterCount
|
||||
} eqFilterType;
|
||||
|
||||
@@ -814,46 +814,6 @@ typedef enum {
|
||||
#define STAT_TIGER_CLAW 40
|
||||
#define STAT_FRENZY 41
|
||||
|
||||
/*
|
||||
** 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
|
||||
};
|
||||
|
||||
static const uint8 DamageTypeSomething = 0x1C; //0x1c is something...
|
||||
static const uint8 DamageTypeFalling = 0xFC;
|
||||
static const uint8 DamageTypeSpell = 0xE7;
|
||||
@@ -1169,4 +1129,7 @@ enum ExpSource
|
||||
#define PARCEL_LIMIT 5
|
||||
#define PARCEL_BEGIN_SLOT 1
|
||||
|
||||
namespace DoorType {
|
||||
constexpr uint32 BuyerStall = 155;
|
||||
}
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
+385
-66
@@ -323,6 +323,7 @@ union
|
||||
bool show_name;
|
||||
bool guild_show;
|
||||
bool trader;
|
||||
bool buyer;
|
||||
};
|
||||
|
||||
struct PlayerState_Struct {
|
||||
@@ -1620,6 +1621,32 @@ struct MoveItem_Struct
|
||||
/*0012*/
|
||||
};
|
||||
|
||||
// New for RoF2 - Size: 12
|
||||
struct InventorySlot_Struct
|
||||
{
|
||||
/*000*/ int16 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1
|
||||
/*002*/ int16 Unknown02;
|
||||
/*004*/ int16 Slot;
|
||||
/*006*/ int16 SubIndex;
|
||||
/*008*/ int16 AugIndex; // Guessing - Seen 0xffff
|
||||
/*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID
|
||||
/*012*/
|
||||
};
|
||||
|
||||
struct MultiMoveItemSub_Struct
|
||||
{
|
||||
/*0000*/ InventorySlot_Struct from_slot;
|
||||
/*0012*/ InventorySlot_Struct to_slot;
|
||||
/*0024*/ uint32 number_in_stack;
|
||||
/*0028*/ uint8 unknown[8];
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ uint32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
// both MoveItem_Struct/DeleteItem_Struct server structures will be changing to a structure-based slot format..this will
|
||||
// be used for handling SoF/SoD/etc... time stamps sent using the MoveItem_Struct format. (nothing will be done with this
|
||||
// info at the moment..but, it is forwarded on to the server for handling/future use)
|
||||
@@ -3113,60 +3140,369 @@ struct BazaarSearchResults_Struct {
|
||||
// Barter/Buyer
|
||||
//
|
||||
//
|
||||
enum {
|
||||
Barter_BuyerSearch = 0,
|
||||
Barter_SellerSearch = 1,
|
||||
Barter_BuyerModeOn = 2,
|
||||
Barter_BuyerModeOff = 3,
|
||||
Barter_BuyerItemUpdate = 5,
|
||||
Barter_BuyerItemRemove = 6,
|
||||
Barter_SellItem = 7,
|
||||
#define MAX_BUYER_COMPENSATION_ITEMS 10
|
||||
|
||||
enum BarterBuyerActions {
|
||||
Barter_BuyerSearch = 0,
|
||||
Barter_SellerSearch = 1,
|
||||
Barter_BuyerModeOn = 2,
|
||||
Barter_BuyerModeOff = 3,
|
||||
Barter_BuyerItemStart = 4,
|
||||
Barter_BuyerItemUpdate = 5,
|
||||
Barter_BuyerItemRemove = 6,
|
||||
Barter_SellItem = 7,
|
||||
Barter_SellerTransactionComplete = 8,
|
||||
Barter_BuyerTransactionComplete = 9,
|
||||
Barter_BuyerInspectBegin = 10,
|
||||
Barter_BuyerInspectEnd = 11,
|
||||
Barter_BuyerAppearance = 12,
|
||||
Barter_BuyerInspectWindow = 13,
|
||||
Barter_BarterItemInspect = 14,
|
||||
Barter_SellerBrowsing = 15,
|
||||
Barter_BuyerSearchResults = 16,
|
||||
Barter_Welcome = 17,
|
||||
Barter_WelcomeMessageUpdate = 19,
|
||||
Barter_BuyerItemInspect = 21,
|
||||
Barter_Unknown23 = 23
|
||||
Barter_BuyerTransactionComplete = 9,
|
||||
Barter_BuyerInspectBegin = 10,
|
||||
Barter_BuyerInspectEnd = 11,
|
||||
Barter_BuyerAppearance = 12,
|
||||
Barter_BuyerInspectWindow = 13,
|
||||
Barter_BarterItemInspect = 14,
|
||||
Barter_SellerBrowsing = 15,
|
||||
Barter_BuyerSearchResults = 16,
|
||||
Barter_Welcome = 17,
|
||||
Barter_WelcomeMessageUpdate = 19,
|
||||
Barter_Greeting = 20,
|
||||
Barter_BuyerItemInspect = 21,
|
||||
Barter_OpenBarterWindow = 23,
|
||||
Barter_AddToBarterWindow = 26,
|
||||
Barter_RemoveFromBarterWindow = 27,
|
||||
Barter_RemoveFromMerchantWindow = 50, //Not a client item. Used for internal communications.
|
||||
Barter_FailedTransaction = 51,
|
||||
Barter_BuyerCouldNotBeFound = 52,
|
||||
Barter_FailedBuyerChecks = 53,
|
||||
Barter_SellerCouldNotBeFound = 54,
|
||||
Barter_FailedSellerChecks = 55
|
||||
};
|
||||
|
||||
enum BarterBuyerSubActions {
|
||||
Barter_Success = 0,
|
||||
Barter_Failure = 1,
|
||||
Barter_DataOutOfDate = 4,
|
||||
Barter_SellerDoesNotHaveItem = 6,
|
||||
Barter_SameZone = 8
|
||||
};
|
||||
|
||||
enum BuyerBarter {
|
||||
Off = 0,
|
||||
On = 1
|
||||
};
|
||||
|
||||
struct BuyerRemoveItem_Struct {
|
||||
uint32 action;
|
||||
uint32 buy_slot_id;
|
||||
};
|
||||
|
||||
struct BuyerRemoveItemFromMerchantWindow_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 buy_slot_id;
|
||||
uint32 unknown_012;
|
||||
};
|
||||
|
||||
struct BuyerGeneric_Struct {
|
||||
uint32 action;
|
||||
char payload[];
|
||||
};
|
||||
|
||||
struct BuyerMessaging_Struct {
|
||||
uint32 action;
|
||||
uint32 sub_action;
|
||||
uint32 zone_id;
|
||||
uint32 buyer_id;
|
||||
uint32 buyer_entity_id;
|
||||
char buyer_name[64];
|
||||
uint32 buy_item_id;
|
||||
uint32 buy_item_qty;
|
||||
uint64 buy_item_cost;
|
||||
uint32 buy_item_icon;
|
||||
uint32 seller_entity_id;
|
||||
char seller_name[64];
|
||||
char item_name[64];
|
||||
uint32 slot;
|
||||
uint32 seller_quantity;
|
||||
};
|
||||
|
||||
struct BuyerAddBuyertoBarterWindow_Struct {
|
||||
uint32 action;
|
||||
uint32 zone_id;
|
||||
uint32 buyer_id;
|
||||
uint32 buyer_entity_id;
|
||||
char buyer_name[64];
|
||||
};
|
||||
|
||||
struct BuyerRemoveBuyerFromBarterWindow_Struct {
|
||||
uint32 action;
|
||||
uint32 buyer_id;
|
||||
};
|
||||
|
||||
struct BuyerBrowsing_Struct {
|
||||
uint32 action;
|
||||
char char_name[64];
|
||||
};
|
||||
|
||||
struct BuyerGreeting_Struct {
|
||||
uint32 action;
|
||||
uint32 buyer_id;
|
||||
};
|
||||
|
||||
struct BuyerWelcomeMessageUpdate_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ char WelcomeMessage[256];
|
||||
uint32 action;
|
||||
char welcome_message[256];
|
||||
};
|
||||
|
||||
struct BuyerItemSearch_Struct {
|
||||
/*000*/ uint32 Unknown000;
|
||||
/*004*/ char SearchString[64];
|
||||
struct BuyerLineTradeItems_Struct {
|
||||
uint32 item_id;
|
||||
uint32 item_quantity;
|
||||
uint32 item_icon;
|
||||
std::string item_name;
|
||||
|
||||
void operator*=(uint32 multiplier)
|
||||
{
|
||||
this->item_quantity *= multiplier;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_quantity),
|
||||
CEREAL_NVP(item_icon),
|
||||
CEREAL_NVP(item_name)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerItemSearchResultEntry_Struct {
|
||||
/*000*/ char ItemName[64];
|
||||
/*064*/ uint32 ItemID;
|
||||
/*068*/ uint32 Unknown068;
|
||||
/*072*/ uint32 Unknown072;
|
||||
struct BuyerLineItems_Struct {
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 item_toggle;
|
||||
uint32 item_cost;
|
||||
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(slot),
|
||||
CEREAL_NVP(enabled),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(item_icon),
|
||||
CEREAL_NVP(item_quantity),
|
||||
CEREAL_NVP(item_toggle),
|
||||
CEREAL_NVP(item_cost),
|
||||
CEREAL_NVP(trade_items)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#define MAX_BUYER_ITEMSEARCH_RESULTS 200
|
||||
struct BuyerBuyLines_Struct {
|
||||
uint32 action;
|
||||
union {
|
||||
uint32 no_items;
|
||||
uint32 string_length;
|
||||
};
|
||||
std::vector<BuyerLineItems_Struct> buy_lines;
|
||||
|
||||
struct BuyerItemSearchResults_Struct {
|
||||
uint32 Action;
|
||||
uint32 ResultCount;
|
||||
BuyerItemSearchResultEntry_Struct Results[MAX_BUYER_ITEMSEARCH_RESULTS];
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(no_items),
|
||||
CEREAL_NVP(buy_lines)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerLineSellItem_Struct {
|
||||
uint32 action;
|
||||
uint32 sub_action;
|
||||
uint32 error_code;
|
||||
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
|
||||
uint32 buyer_entity_id;
|
||||
uint32 buyer_id;
|
||||
std::string buyer_name;
|
||||
uint32 seller_entity_id;
|
||||
std::string seller_name;
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
char item_name[64];
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 item_toggle;
|
||||
uint32 item_cost;
|
||||
uint32 no_trade_items;
|
||||
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||
uint32 seller_quantity;
|
||||
uint32 zone_id;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(sub_action),
|
||||
CEREAL_NVP(error_code),
|
||||
CEREAL_NVP(purchase_method),
|
||||
CEREAL_NVP(buyer_entity_id),
|
||||
CEREAL_NVP(buyer_id),
|
||||
CEREAL_NVP(buyer_name),
|
||||
CEREAL_NVP(seller_entity_id),
|
||||
CEREAL_NVP(seller_name),
|
||||
CEREAL_NVP(slot),
|
||||
CEREAL_NVP(enabled),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(item_icon),
|
||||
CEREAL_NVP(item_quantity),
|
||||
CEREAL_NVP(item_toggle),
|
||||
CEREAL_NVP(item_cost),
|
||||
CEREAL_NVP(no_trade_items),
|
||||
CEREAL_NVP(trade_items),
|
||||
CEREAL_NVP(seller_quantity),
|
||||
CEREAL_NVP(zone_id)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerLineItemsSearch_Struct {
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
char item_name[64];
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 item_toggle;
|
||||
uint32 item_cost;
|
||||
uint32 buyer_id;
|
||||
uint32 buyer_entity_id;
|
||||
uint32 buyer_zone_id;
|
||||
uint32 buyer_zone_instance_id;
|
||||
std::string buyer_name;
|
||||
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(slot),
|
||||
CEREAL_NVP(enabled),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(item_icon),
|
||||
CEREAL_NVP(item_quantity),
|
||||
CEREAL_NVP(item_toggle),
|
||||
CEREAL_NVP(item_cost),
|
||||
CEREAL_NVP(buyer_id),
|
||||
CEREAL_NVP(buyer_entity_id),
|
||||
CEREAL_NVP(buyer_zone_id),
|
||||
CEREAL_NVP(buyer_zone_instance_id),
|
||||
CEREAL_NVP(buyer_name),
|
||||
CEREAL_NVP(trade_items)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerLineSearch_Struct {
|
||||
uint32 action;
|
||||
uint32 no_items;
|
||||
std::string search_string;
|
||||
uint32 transaction_id;
|
||||
std::vector<BuyerLineItemsSearch_Struct> buy_line;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(no_items),
|
||||
CEREAL_NVP(search_string),
|
||||
CEREAL_NVP(transaction_id),
|
||||
CEREAL_NVP(buy_line)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerSetAppearance_Struct {
|
||||
uint32 action;
|
||||
uint32 entity_id;
|
||||
uint32 status; // 0 off 1 on
|
||||
char buyer_name[64];
|
||||
};
|
||||
|
||||
struct BarterItemSearchLinkRequest_Struct {
|
||||
uint32 action;
|
||||
uint32 searcher_id;
|
||||
uint32 unknown_008;
|
||||
uint32 unknown_012;
|
||||
uint32 item_id;
|
||||
uint32 unknown_020;
|
||||
};
|
||||
|
||||
struct BuyerInspectRequest_Struct {
|
||||
uint32 action;
|
||||
uint32 buyer_id;
|
||||
uint32 approval;
|
||||
};
|
||||
|
||||
struct BarterSearchRequest_Struct {
|
||||
uint32 Action;
|
||||
char SearchString[64];
|
||||
uint32 SearchID;
|
||||
uint32 action;
|
||||
char search_string[64];
|
||||
uint32 transaction_id;
|
||||
uint32 unknown_072;
|
||||
uint32 buyer_id;
|
||||
uint8 search_scope; //0 All Buyers, 1 Local Buyers
|
||||
uint16 zone_id;
|
||||
};
|
||||
|
||||
struct BuyerItemSearch_Struct {
|
||||
uint32 action;
|
||||
char search_string[64];
|
||||
};
|
||||
|
||||
struct BuyerItemSearchResultEntry_Struct {
|
||||
char item_name[64];
|
||||
uint32 item_id;
|
||||
uint32 item_icon;
|
||||
uint32 unknown_072;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_icon),
|
||||
CEREAL_NVP(unknown_072)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BuyerItemSearchResults_Struct {
|
||||
uint32 action;
|
||||
uint32 result_count;
|
||||
std::vector<BuyerItemSearchResultEntry_Struct> results;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(
|
||||
CEREAL_NVP(action),
|
||||
CEREAL_NVP(result_count),
|
||||
CEREAL_NVP(results)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
//old below here
|
||||
struct BuyerItemSearchLinkRequest_Struct {
|
||||
/*000*/ uint32 Action; // 0x00000015
|
||||
/*004*/ uint32 ItemID;
|
||||
@@ -3174,31 +3510,6 @@ struct BuyerItemSearchLinkRequest_Struct {
|
||||
/*012*/ uint32 Unknown012;
|
||||
};
|
||||
|
||||
struct BarterItemSearchLinkRequest_Struct {
|
||||
/*000*/ uint32 Action; // 0x0000000E
|
||||
/*004*/ uint32 SearcherID;
|
||||
/*008*/ uint32 Unknown008;
|
||||
/*012*/ uint32 Unknown012;
|
||||
/*016*/ uint32 ItemID;
|
||||
/*020*/ uint32 Unknown020;
|
||||
};
|
||||
|
||||
struct BuyerInspectRequest_Struct {
|
||||
uint32 Action;
|
||||
uint32 BuyerID;
|
||||
uint32 Approval;
|
||||
};
|
||||
|
||||
struct BuyerBrowsing_Struct {
|
||||
uint32 Action;
|
||||
char PlayerName[64];
|
||||
};
|
||||
|
||||
struct BuyerRemoveItem_Struct {
|
||||
uint32 Action;
|
||||
uint32 BuySlot;
|
||||
};
|
||||
|
||||
struct ServerSideFilters_Struct {
|
||||
uint8 clientattackfilters; // 0) No, 1) All (players) but self, 2) All (players) but group
|
||||
uint8 npcattackfilters; // 0) No, 1) Ignore NPC misses (all), 2) Ignore NPC Misses + Attacks (all but self), 3) Ignores NPC Misses + Attacks (all but group)
|
||||
@@ -6040,9 +6351,12 @@ enum BazaarTraderBarterActions {
|
||||
};
|
||||
|
||||
enum BazaarPurchaseActions {
|
||||
ByVendor = 0,
|
||||
ByParcel = 1,
|
||||
ByDirectToInventory = 2
|
||||
BazaarByVendor = 0,
|
||||
BazaarByParcel = 1,
|
||||
BazaarByDirectToInventory = 2,
|
||||
BarterByVendor = 0,
|
||||
BarterInBazaar = 1,
|
||||
BarterOutsideBazaar = 2
|
||||
};
|
||||
|
||||
enum BazaarPurchaseSubActions {
|
||||
@@ -6116,6 +6430,11 @@ struct BazaarSearchMessaging_Struct {
|
||||
}
|
||||
};
|
||||
|
||||
struct BuylineItemDetails_Struct {
|
||||
uint64 item_cost;
|
||||
uint32 item_quantity;
|
||||
};
|
||||
|
||||
// Restore structure packing to default
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@@ -789,50 +789,36 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
|
||||
);
|
||||
}
|
||||
|
||||
std::string npc_info = fmt::format(
|
||||
"{} ({})\n",
|
||||
e.npc_name,
|
||||
e.npc_id
|
||||
);
|
||||
|
||||
npc_info += fmt::format(
|
||||
"Is Quest Handin: {}",
|
||||
e.is_quest_handin ? "Yes" : "No"
|
||||
);
|
||||
|
||||
std::vector<DiscordField> f = {};
|
||||
|
||||
|
||||
BuildDiscordField(&f, "NPC", npc_info);
|
||||
|
||||
if (!handin_items_info.empty()) {
|
||||
BuildDiscordField(
|
||||
&f,
|
||||
"Handin Items",
|
||||
fmt::format(
|
||||
"{}",
|
||||
handin_items_info
|
||||
)
|
||||
);
|
||||
BuildDiscordField(&f, "Handin Items", handin_items_info);
|
||||
}
|
||||
|
||||
if (!handin_money_info.empty()) {
|
||||
BuildDiscordField(
|
||||
&f,
|
||||
"Handin Money",
|
||||
fmt::format(
|
||||
"{}",
|
||||
handin_money_info
|
||||
)
|
||||
);
|
||||
BuildDiscordField(&f, "Handin Money", handin_money_info);
|
||||
}
|
||||
|
||||
if (!return_items_info.empty()) {
|
||||
BuildDiscordField(
|
||||
&f,
|
||||
"Return Items",
|
||||
fmt::format(
|
||||
"{}",
|
||||
return_items_info
|
||||
)
|
||||
);
|
||||
BuildDiscordField(&f, "Return Items", return_items_info);
|
||||
}
|
||||
|
||||
if (!return_money_info.empty()) {
|
||||
BuildDiscordField(
|
||||
&f,
|
||||
"Return Money",
|
||||
fmt::format(
|
||||
"{}",
|
||||
return_money_info
|
||||
)
|
||||
);
|
||||
BuildDiscordField(&f, "Return Money", return_money_info);
|
||||
}
|
||||
|
||||
std::vector<DiscordEmbed> embeds = {};
|
||||
|
||||
@@ -654,58 +654,59 @@ const int32_t RETENTION_DAYS_DEFAULT = 7;
|
||||
|
||||
void PlayerEventLogs::SetSettingsDefaults()
|
||||
{
|
||||
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ZONING].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
|
||||
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SAY].event_enabled = 0;
|
||||
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DEATH].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ZONING].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
|
||||
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
|
||||
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
|
||||
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SAY].event_enabled = 0;
|
||||
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DEATH].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
|
||||
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
|
||||
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
|
||||
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_PLAT].event_enabled = 1;
|
||||
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
|
||||
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
|
||||
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace PlayerEvent {
|
||||
GUILD_TRIBUTE_DONATE_PLAT,
|
||||
PARCEL_SEND,
|
||||
PARCEL_RETRIEVE,
|
||||
PARCEL_DELETE,
|
||||
PARCEL_DELETE,
|
||||
BARTER_TRANSACTION,
|
||||
MAX // dont remove
|
||||
};
|
||||
|
||||
@@ -122,7 +123,8 @@ namespace PlayerEvent {
|
||||
"Guild Tribute Donate Platinum",
|
||||
"Parcel Item Sent",
|
||||
"Parcel Item Retrieved",
|
||||
"Parcel Prune Routine"
|
||||
"Parcel Prune Routine",
|
||||
"Barter Transaction"
|
||||
};
|
||||
|
||||
// Generic struct used by all events
|
||||
@@ -858,10 +860,12 @@ namespace PlayerEvent {
|
||||
|
||||
class HandinEntry {
|
||||
public:
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
uint16 charges;
|
||||
bool attuned;
|
||||
uint32 item_id;
|
||||
std::string item_name;
|
||||
std::vector<uint32> augment_ids;
|
||||
std::vector<std::string> augment_names;
|
||||
uint16 charges;
|
||||
bool attuned;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
@@ -870,6 +874,8 @@ namespace PlayerEvent {
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(augment_ids),
|
||||
CEREAL_NVP(augment_names),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(attuned)
|
||||
);
|
||||
@@ -903,6 +909,7 @@ namespace PlayerEvent {
|
||||
HandinMoney handin_money;
|
||||
std::vector<HandinEntry> return_items;
|
||||
HandinMoney return_money;
|
||||
bool is_quest_handin;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
@@ -914,7 +921,8 @@ namespace PlayerEvent {
|
||||
CEREAL_NVP(handin_items),
|
||||
CEREAL_NVP(handin_money),
|
||||
CEREAL_NVP(return_items),
|
||||
CEREAL_NVP(return_money)
|
||||
CEREAL_NVP(return_money),
|
||||
CEREAL_NVP(is_quest_handin)
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1081,6 +1089,32 @@ namespace PlayerEvent {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct BarterTransaction {
|
||||
std::string status;
|
||||
uint32 item_id;
|
||||
uint32 item_quantity;
|
||||
std::string item_name;
|
||||
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||
std::string buyer_name;
|
||||
std::string seller_name;
|
||||
uint64 total_cost;
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(status),
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_quantity),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(trade_items),
|
||||
CEREAL_NVP(buyer_name),
|
||||
CEREAL_NVP(seller_name),
|
||||
CEREAL_NVP(total_cost)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //EQEMU_PLAYER_EVENTS_H
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1743,3 +1743,68 @@ std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
|
||||
|
||||
return augments;
|
||||
}
|
||||
|
||||
std::vector<int16> EQ::InventoryProfile::FindAllFreeSlotsThatFitItem(const EQ::ItemData *item_data)
|
||||
{
|
||||
std::vector<int16> free_slots{};
|
||||
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||
if ((((uint64) 1 << i) & GetLookup()->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inv_item = GetItem(i);
|
||||
|
||||
if (!inv_item) {
|
||||
// Found available slot in personal inventory
|
||||
free_slots.push_back(i);
|
||||
}
|
||||
|
||||
if (inv_item->IsClassBag() &&
|
||||
EQ::InventoryProfile::CanItemFitInContainer(item_data, inv_item->GetItem())) {
|
||||
|
||||
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||
uint8 bag_size = inv_item->GetItem()->BagSlots;
|
||||
|
||||
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||
auto bag_item = GetItem(base_slot_id + bag_slot);
|
||||
if (!bag_item) {
|
||||
// Found available slot within bag
|
||||
free_slots.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return free_slots;
|
||||
}
|
||||
|
||||
int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItem(const EQ::ItemData *item_data)
|
||||
{
|
||||
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||
if ((((uint64) 1 << i) & GetLookup()->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inv_item = GetItem(i);
|
||||
|
||||
if (!inv_item) {
|
||||
// Found available slot in personal inventory
|
||||
return i;
|
||||
}
|
||||
|
||||
if (inv_item->IsClassBag() &&
|
||||
EQ::InventoryProfile::CanItemFitInContainer(item_data, inv_item->GetItem())) {
|
||||
|
||||
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||
uint8 bag_size = inv_item->GetItem()->BagSlots;
|
||||
|
||||
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||
auto bag_item = GetItem(base_slot_id + bag_slot);
|
||||
if (!bag_item) {
|
||||
// Found available slot within bag
|
||||
return base_slot_id + bag_slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -176,6 +176,8 @@ namespace EQ
|
||||
// Locate an available inventory slot
|
||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
||||
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
|
||||
std::vector<int16> FindAllFreeSlotsThatFitItem(const EQ::ItemData *inst);
|
||||
int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst);
|
||||
|
||||
// Calculate slot_id for an item within a bag
|
||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
||||
|
||||
+55
-21
@@ -81,45 +81,79 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets local address - pings google to inspect what interface was used locally
|
||||
* @return
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
std::string IpUtil::GetLocalIPAddress()
|
||||
{
|
||||
char my_ip_address[16];
|
||||
unsigned int my_port;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
char my_ip_address[INET_ADDRSTRLEN];
|
||||
struct sockaddr_in server_address{};
|
||||
struct sockaddr_in my_address{};
|
||||
int sockfd;
|
||||
int sockfd;
|
||||
|
||||
// Connect to server
|
||||
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
// Create a UDP socket
|
||||
#ifdef _WIN32
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == INVALID_SOCKET) {
|
||||
WSACleanup();
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set server_addr
|
||||
// Set server_addr (dummy address)
|
||||
memset(&server_address, 0, sizeof(server_address));
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_addr.s_addr = inet_addr("172.217.160.99");
|
||||
server_address.sin_port = htons(80);
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_addr.s_addr = inet_addr("8.8.8.8"); // Google DNS
|
||||
server_address.sin_port = htons(53); // DNS port
|
||||
|
||||
// Connect to server
|
||||
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
|
||||
close(sockfd);
|
||||
return "";
|
||||
}
|
||||
// Perform a dummy connection to the server (UDP)
|
||||
connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
|
||||
|
||||
// Get my ip address and port
|
||||
// Get my IP address
|
||||
memset(&my_address, 0, sizeof(my_address));
|
||||
socklen_t len = sizeof(my_address);
|
||||
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
|
||||
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
|
||||
my_port = ntohs(my_address.sin_port);
|
||||
|
||||
return fmt::format("{}", my_ip_address);
|
||||
#ifdef _WIN32
|
||||
closesocket(sockfd);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(sockfd);
|
||||
#endif
|
||||
|
||||
LogInfo("Local IP Address [{}]", my_ip_address);
|
||||
|
||||
return std::string(my_ip_address);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets public address
|
||||
* Uses various websites as options to return raw public IP back to the client
|
||||
|
||||
+39
-36
@@ -32,10 +32,11 @@
|
||||
|
||||
//#include <iostream>
|
||||
|
||||
int32 NextItemInstSerialNumber = 1;
|
||||
|
||||
static inline int32 GetNextItemInstSerialNumber() {
|
||||
int32 next_item_serial_number = 1;
|
||||
std::unordered_set<uint64> guids{};
|
||||
|
||||
static inline int32 GetNextItemInstSerialNumber()
|
||||
{
|
||||
// The Bazaar relies on each item a client has up for Trade having a unique
|
||||
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
||||
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
||||
@@ -46,12 +47,18 @@ static inline int32 GetNextItemInstSerialNumber() {
|
||||
// NextItemInstSerialNumber is the next one to hand out.
|
||||
//
|
||||
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
||||
if(NextItemInstSerialNumber >= INT_MAX)
|
||||
NextItemInstSerialNumber = 1;
|
||||
else
|
||||
NextItemInstSerialNumber++;
|
||||
if (next_item_serial_number >= INT32_MAX) {
|
||||
next_item_serial_number = 1;
|
||||
}
|
||||
else {
|
||||
next_item_serial_number++;
|
||||
}
|
||||
|
||||
return NextItemInstSerialNumber;
|
||||
while (guids.contains(next_item_serial_number)) {
|
||||
next_item_serial_number++;
|
||||
}
|
||||
|
||||
return next_item_serial_number;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -303,47 +310,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 +1286,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();
|
||||
@@ -1948,6 +1942,15 @@ int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augmen
|
||||
return stat;
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::AddGUIDToMap(uint64 existing_serial_number)
|
||||
{
|
||||
guids.emplace(existing_serial_number);
|
||||
}
|
||||
|
||||
void EQ::ItemInstance::ClearGUIDMap()
|
||||
{
|
||||
guids.clear();
|
||||
}
|
||||
//
|
||||
// class EvolveInfo
|
||||
//
|
||||
|
||||
@@ -265,7 +265,7 @@ 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;
|
||||
@@ -309,6 +309,8 @@ namespace EQ
|
||||
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
||||
uint32 GetItemGuildFavor() const;
|
||||
std::vector<uint32> GetAugmentIDs() const;
|
||||
static void AddGUIDToMap(uint64 existing_serial_number);
|
||||
static void ClearGUIDMap();
|
||||
|
||||
protected:
|
||||
//////////////////////////
|
||||
|
||||
+523
-32
@@ -356,41 +356,91 @@ namespace RoF2
|
||||
|
||||
ENCODE(OP_Barter)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
char *Buffer = (char *)in->pBuffer;
|
||||
char *buffer = (char *) in->pBuffer;
|
||||
uint32 sub_action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
|
||||
uint32 SubAction = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
||||
switch (sub_action) {
|
||||
case Barter_BuyerAppearance: {
|
||||
auto emu = (BuyerInspectRequest_Struct *) in->pBuffer;
|
||||
|
||||
if (SubAction != Barter_BuyerAppearance)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
auto outapp = new EQApplicationPacket(OP_Barter, sizeof(structs::Buyer_SetAppearance_Struct));
|
||||
auto eq = (structs::Buyer_SetAppearance_Struct *) outapp->pBuffer;
|
||||
|
||||
return;
|
||||
eq->action = structs::RoF2BuyerActions::BuyerAppearance;
|
||||
eq->entity_id = emu->buyer_id;
|
||||
eq->enabled = emu->approval;
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
safe_delete(in);
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemRemove: {
|
||||
auto emu = (BuyerRemoveItem_Struct *) in->pBuffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_BuyerItems, sizeof(structs::BuyerRemoveItem_Struct));
|
||||
auto eq = (structs::BuyerRemoveItem_Struct *) outapp->pBuffer;
|
||||
|
||||
eq->action = structs::RoF2BuyerActions::BuyerModifyBuyLine;
|
||||
eq->slot_id = emu->buy_slot_id;
|
||||
eq->toggle = 0;
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
safe_delete(in);
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerInspectBegin: {
|
||||
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerInspectBegin;
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerInspectEnd: {
|
||||
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerInspectEnd;
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
case Barter_SellerBrowsing: {
|
||||
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerBrowsingBuyLine;
|
||||
dest->FastQueuePacket(&in);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerSearchResults: {
|
||||
BuyerItemSearchResults_Struct bisr{};
|
||||
auto emu = (BuyerGeneric_Struct *) in->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(emu->payload),
|
||||
in->size - sizeof(BuyerGeneric_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(bisr);
|
||||
|
||||
LogTradingDetail("Sending item search results <green>[{}]", bisr.result_count);
|
||||
|
||||
uint32 packet_size = bisr.result_count * sizeof(structs::BuyerItemSearchResultEntry_Struct) + 8;
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_Barter, packet_size);
|
||||
auto eq = (char *) outapp->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSearchResults);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bisr.result_count);
|
||||
for (auto const &i: bisr.results) {
|
||||
strn0cpy(eq, i.item_name, 64);
|
||||
eq += 64;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||
VARSTRUCT_SKIP_TYPE(uint32, eq);
|
||||
}
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogTradingDetail("Unhandled action <red>[{}]", sub_action);
|
||||
dest->FastQueuePacket(&in);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
in->size = 80;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
char Name[64];
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, SubAction);
|
||||
uint32 EntityID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, EntityID);
|
||||
uint8 Toggle = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
||||
VARSTRUCT_DECODE_STRING(Name, Buffer);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, Name);
|
||||
OutBuffer = (char *)in->pBuffer + 72;
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, Toggle);
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_BazaarSearch)
|
||||
@@ -542,8 +592,8 @@ namespace RoF2
|
||||
LogTrading(
|
||||
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
|
||||
eq->action,
|
||||
eq->entity_id,
|
||||
eq->trader_id,
|
||||
eq->entity_id,
|
||||
eq->zone_id
|
||||
);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
@@ -682,6 +732,243 @@ namespace RoF2
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_BuyerItems)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
|
||||
auto action = *(uint32 *) inapp->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case Barter_BuyerItemUpdate: {
|
||||
BuyerLineItems_Struct bl{};
|
||||
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(emu->payload),
|
||||
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(bl);
|
||||
|
||||
//packet size
|
||||
auto packet_size = bl.item_name.length() + 1 + 34;
|
||||
for (auto const &b: bl.trade_items) {
|
||||
packet_size += b.item_name.length() + 1;
|
||||
packet_size += 12;
|
||||
}
|
||||
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||
char *eq = (char *) outapp->pBuffer;
|
||||
auto no_trade_items = bl.trade_items.size();
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerModifyBuyLine);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.slot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, bl.enabled ? 1 : 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_id);
|
||||
VARSTRUCT_ENCODE_STRING(eq, bl.item_name.c_str());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_icon);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, bl.item_toggle ? 1 : 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_cost);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_trade_items);
|
||||
|
||||
for (int i = 0; i < no_trade_items; i++) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_icon);
|
||||
VARSTRUCT_ENCODE_STRING(eq, bl.trade_items[i].item_name.c_str());
|
||||
}
|
||||
dest->QueuePacket(outapp.get());
|
||||
safe_delete(inapp);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerInspectBegin: {
|
||||
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||
|
||||
BuyerLineItems_Struct bli{};
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(emu->payload),
|
||||
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(bli);
|
||||
|
||||
//packet size
|
||||
auto packet_size = bli.item_name.length() + 1 + 34;
|
||||
for (auto const &b: bli.trade_items) {
|
||||
packet_size += b.item_name.length() + 1;
|
||||
packet_size += 12;
|
||||
}
|
||||
|
||||
auto packet = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||
char *eq = (char *) packet->pBuffer;
|
||||
auto no_trade_items = bli.trade_items.size();
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSendBuyLine);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.slot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.slot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, bli.enabled ? 1 : 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_id);
|
||||
VARSTRUCT_ENCODE_STRING(eq, bli.item_name.c_str());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_icon);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, bli.item_toggle ? 1 : 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_cost);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_trade_items);
|
||||
|
||||
for (auto const &i: bli.trade_items) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||
}
|
||||
dest->QueuePacket(packet.get());
|
||||
safe_delete(inapp);
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerSearch: {
|
||||
BuyerLineSearch_Struct bls{};
|
||||
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(emu->payload),
|
||||
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(bls);
|
||||
LogTrading("(RoF2) Barter_BuyerSearch action <green>[{}]", emu->action);
|
||||
|
||||
//Calculate size of packet
|
||||
auto p_size = 0;
|
||||
p_size += 5 * sizeof(uint32) + 1 * sizeof(uint8);
|
||||
p_size += bls.search_string.length() + 1;
|
||||
for (auto const &b: bls.buy_line) {
|
||||
p_size += 6 * sizeof(uint32) + 2 * sizeof(uint8);
|
||||
p_size += strlen(b.item_name) + 1;
|
||||
p_size += b.buyer_name.length() + 1;
|
||||
for (auto const &d: b.trade_items) {
|
||||
if (d.item_id != 0) {
|
||||
p_size += d.item_name.length() + 1;
|
||||
p_size += 3 * sizeof(uint32);
|
||||
}
|
||||
}
|
||||
p_size += 3 * sizeof(uint32);
|
||||
}
|
||||
|
||||
BuyerBuyLines_Struct bl{};
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, p_size);
|
||||
auto eq = (char *) outapp->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 1);
|
||||
VARSTRUCT_ENCODE_STRING(eq, bls.search_string.c_str());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bls.transaction_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, bls.no_items);
|
||||
for (auto const &b: bls.buy_line) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.slot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_id);
|
||||
VARSTRUCT_ENCODE_STRING(eq, b.item_name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_icon);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_cost);
|
||||
auto no_sub_items = b.trade_items.size();
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_sub_items);
|
||||
for (auto const &i: b.trade_items) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||
}
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.buyer_entity_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.buyer_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_id);
|
||||
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id);
|
||||
VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str());
|
||||
}
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
case Barter_RemoveFromMerchantWindow: {
|
||||
auto emu = (BuyerRemoveItemFromMerchantWindow_Struct *) inapp->pBuffer;
|
||||
|
||||
emu->action = structs::RoF2BuyerActions::BuyerSendBuyLine;
|
||||
dest->FastQueuePacket(&inapp);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerTransactionComplete:
|
||||
case Barter_SellerTransactionComplete: {
|
||||
BuyerLineSellItem_Struct blsi{};
|
||||
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||
EQ::Util::MemoryStreamReader ss(
|
||||
reinterpret_cast<char *>(emu->payload),
|
||||
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||
);
|
||||
cereal::BinaryInputArchive ar(ss);
|
||||
ar(blsi);
|
||||
|
||||
//packet size
|
||||
auto packet_size = strlen(blsi.item_name) * 2 + 2 + 48 + 30 + blsi.seller_name.length() + 1 +
|
||||
blsi.buyer_name.length() + 1;
|
||||
for (auto const &b: blsi.trade_items) {
|
||||
packet_size += b.item_name.length() + 1;
|
||||
packet_size += 12;
|
||||
}
|
||||
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||
auto eq = (char *) outapp->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case Barter_BuyerTransactionComplete: {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerBuyItem);
|
||||
break;
|
||||
}
|
||||
case Barter_SellerTransactionComplete: {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSellItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.sub_action);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.error_code);
|
||||
eq += 16;
|
||||
VARSTRUCT_ENCODE_STRING(eq, blsi.buyer_name.c_str());
|
||||
VARSTRUCT_ENCODE_STRING(eq, blsi.item_name);
|
||||
VARSTRUCT_ENCODE_STRING(eq, blsi.seller_name.c_str());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFFFF);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFFFF);
|
||||
eq += 1;
|
||||
VARSTRUCT_ENCODE_STRING(eq, blsi.item_name);
|
||||
eq += 9;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.item_cost);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.trade_items.size());
|
||||
|
||||
for (auto const &i: blsi.trade_items) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||
}
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFF);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity);
|
||||
|
||||
dest->QueuePacket(outapp.get());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dest->FastQueuePacket(&inapp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_CancelTrade)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(CancelTrade_Struct);
|
||||
@@ -1690,7 +1977,7 @@ namespace RoF2
|
||||
uchar *__emu_buffer = in->pBuffer;
|
||||
ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *) __emu_buffer;
|
||||
|
||||
switch(old_item_pkt->PacketType)
|
||||
switch(old_item_pkt->PacketType)
|
||||
{
|
||||
case ItemPacketParcel: {
|
||||
ParcelMessaging_Struct pms{};
|
||||
@@ -4348,6 +4635,9 @@ namespace RoF2
|
||||
if (emu->DestructibleObject) {
|
||||
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
||||
}
|
||||
if (emu->buyer) {
|
||||
OtherData = OtherData | 0x01;
|
||||
}
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||
// float EmitterScalingRadius
|
||||
@@ -4459,7 +4749,7 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->lastName);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // aatitle
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->guild_show);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->guild_show);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // TempPet
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
|
||||
@@ -4664,6 +4954,66 @@ namespace RoF2
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Barter)
|
||||
{
|
||||
auto action = *(uint32 *) __packet->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case structs::RoF2BuyerActions::BuyerRemoveItem: {
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
emu->action = Barter_BuyerItemRemove;
|
||||
LogTradingDetail("(RoF2) Buyer Remove Item");
|
||||
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BuyerActions::BuyerInspectBegin: {
|
||||
LogTradingDetail("(RoF2) Buyer Inspect Begin Item");
|
||||
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
emu->action = Barter_BuyerInspectBegin;
|
||||
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BuyerActions::BuyerInspectEnd: {
|
||||
LogTradingDetail("(RoF2) Buyer Inspect End Item ");
|
||||
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
emu->action = Barter_BuyerInspectEnd;
|
||||
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BuyerActions::BuyerWelcomeMessage: {
|
||||
LogTradingDetail("(RoF2) Buyer Welcome Message Update");
|
||||
SETUP_DIRECT_DECODE(BuyerWelcomeMessageUpdate_Struct, structs::BuyerWelcomeMessageUpdate_Struct);
|
||||
|
||||
emu->action = Barter_WelcomeMessageUpdate;
|
||||
strn0cpy(emu->welcome_message, eq->welcome_message, sizeof(emu->welcome_message));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BuyerActions::BuyerItemInspect: {
|
||||
SETUP_DIRECT_DECODE(BarterItemSearchLinkRequest_Struct, structs::BarterItemSearchLinkRequest_Struct);
|
||||
LogTradingDetail("(RoF2) Seller ID <green>[{}] Inspecting Item <green>[{}] from Buyer ID <green>[{}] ",
|
||||
eq->seller_id,
|
||||
eq->item_id,
|
||||
eq->buyer_id
|
||||
);
|
||||
|
||||
emu->action = Barter_BarterItemInspect;
|
||||
emu->item_id = eq->item_id;
|
||||
emu->searcher_id = eq->seller_id;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
LogTradingDetail("(RoF2) Pass thru OP_Barter packet action <red>[{}]", emu->action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_BazaarSearch)
|
||||
{
|
||||
char *Buffer = (char *)__packet->pBuffer;
|
||||
@@ -4742,6 +5092,147 @@ namespace RoF2
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_BuyerItems)
|
||||
{
|
||||
auto action = *(uint32 *) __packet->pBuffer;
|
||||
|
||||
switch (action) {
|
||||
case structs::RoF2BuyerActions::BuyerModifyBuyLine:
|
||||
case structs::RoF2BuyerActions::BuyerBuyLine: {
|
||||
BuyerBuyLines_Struct buyer_buy_lines{};
|
||||
auto buffer = (char *) __packet->pBuffer;
|
||||
|
||||
buyer_buy_lines.action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
|
||||
buyer_buy_lines.no_items = 1;
|
||||
if (action == structs::RoF2BuyerActions::BuyerBuyLine) {
|
||||
buyer_buy_lines.no_items = VARSTRUCT_DECODE_TYPE(uint16, buffer);
|
||||
}
|
||||
|
||||
buyer_buy_lines.buy_lines.reserve(buyer_buy_lines.no_items);
|
||||
for (int i = 0; i < buyer_buy_lines.no_items; i++) {
|
||||
BuyerLineItems_Struct b{};
|
||||
b.slot = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
b.enabled = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||
b.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
b.item_name = std::string(buffer, strlen(buffer));
|
||||
buffer += strlen(buffer) + 1;
|
||||
b.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
b.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
b.item_toggle = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||
b.item_cost = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
auto trade_items = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
buyer_buy_lines.buy_lines.push_back(b);
|
||||
|
||||
if (trade_items > 0) {
|
||||
buyer_buy_lines.buy_lines[i].trade_items.reserve(trade_items);
|
||||
for (int x = 0; x < trade_items; x++) {
|
||||
BuyerLineTradeItems_Struct blti{};
|
||||
blti.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_name = std::string(buffer, strlen(buffer));
|
||||
buffer += strlen(buffer) + 1;
|
||||
buyer_buy_lines.buy_lines[i].trade_items.push_back(blti);
|
||||
}
|
||||
}
|
||||
buffer += 13;
|
||||
}
|
||||
|
||||
buffer = nullptr;
|
||||
std::stringstream ss{};
|
||||
cereal::BinaryOutputArchive ar(ss);
|
||||
{
|
||||
ar(buyer_buy_lines);
|
||||
}
|
||||
|
||||
auto new_size = sizeof(BuyerGeneric_Struct) + ss.str().length();
|
||||
auto new_packet = new unsigned char[new_size];
|
||||
__packet->size = new_size;
|
||||
__packet->pBuffer = new_packet;
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
emu->action = Barter_BuyerItemUpdate;
|
||||
|
||||
if (action == structs::RoF2BuyerActions::BuyerBuyLine) {
|
||||
emu->action = Barter_BuyerItemStart;
|
||||
}
|
||||
|
||||
memcpy(emu->payload, ss.str().data(), ss.str().length());
|
||||
__packet->SetOpcode(OP_Barter);
|
||||
|
||||
break;
|
||||
}
|
||||
case structs::RoF2BuyerActions::BuyerSellItem: {
|
||||
BuyerLineSellItem_Struct sell_item{};
|
||||
|
||||
char *buffer = (char *) __packet->pBuffer;
|
||||
|
||||
sell_item.action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.purchase_method = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
buffer += 4;
|
||||
sell_item.buyer_entity_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.buyer_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
buffer += 11;
|
||||
sell_item.slot = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.enabled = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||
sell_item.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
VARSTRUCT_DECODE_STRING(sell_item.item_name, buffer);
|
||||
sell_item.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.item_toggle = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||
sell_item.item_cost = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.no_trade_items = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
|
||||
if (sell_item.no_trade_items > 0) {
|
||||
sell_item.trade_items.reserve(sell_item.no_trade_items);
|
||||
for (int x = 0; x < sell_item.no_trade_items; x++) {
|
||||
BuyerLineTradeItems_Struct blti{};
|
||||
blti.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
blti.item_name = std::string(buffer, strlen(buffer));
|
||||
buffer += strlen(buffer) + 1;
|
||||
sell_item.trade_items.push_back(blti);
|
||||
}
|
||||
}
|
||||
|
||||
if (sell_item.purchase_method) {
|
||||
sell_item.buyer_entity_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.buyer_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.zone_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
sell_item.buyer_name = std::string(buffer, strlen(buffer));
|
||||
buffer += sell_item.buyer_name.length() + 1;
|
||||
}
|
||||
else {
|
||||
buffer += 13;
|
||||
}
|
||||
|
||||
sell_item.seller_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||
|
||||
buffer += 4;
|
||||
|
||||
buffer = nullptr;
|
||||
std::stringstream ss{};
|
||||
cereal::BinaryOutputArchive ar(ss);
|
||||
{
|
||||
ar(sell_item);
|
||||
}
|
||||
|
||||
auto new_size = sizeof(BuyerGeneric_Struct) + ss.str().length();
|
||||
auto new_packet = new unsigned char[new_size];
|
||||
__packet->size = new_size;
|
||||
__packet->pBuffer = new_packet;
|
||||
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||
emu->action = Barter_SellItem;
|
||||
|
||||
memcpy(emu->payload, ss.str().data(), ss.str().length());
|
||||
__packet->SetOpcode(OP_Barter);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_CastSpell)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||
|
||||
@@ -48,6 +48,7 @@ E(OP_BeginCast)
|
||||
E(OP_BlockedBuffs)
|
||||
E(OP_Buff)
|
||||
E(OP_BuffCreate)
|
||||
E(OP_BuyerItems)
|
||||
E(OP_CancelTrade)
|
||||
E(OP_CastSpell)
|
||||
E(OP_ChannelMessage)
|
||||
@@ -149,11 +150,13 @@ D(OP_Animation)
|
||||
D(OP_ApplyPoison)
|
||||
D(OP_AugmentInfo)
|
||||
D(OP_AugmentItem)
|
||||
D(OP_Barter)
|
||||
D(OP_BazaarSearch)
|
||||
D(OP_BlockedBuffs)
|
||||
D(OP_BookButton)
|
||||
D(OP_Buff)
|
||||
D(OP_BuffRemoveRequest)
|
||||
D(OP_BuyerItems)
|
||||
D(OP_CastSpell)
|
||||
D(OP_ChannelMessage)
|
||||
D(OP_CharacterCreate)
|
||||
|
||||
+142
-22
@@ -354,15 +354,15 @@ struct Spawn_Struct_Bitfields
|
||||
/*29*/ unsigned showname:1;
|
||||
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
|
||||
/*31*/ unsigned untargetable:1; // bClickThrough
|
||||
/* do these later
|
||||
32 unsigned buyer:1;
|
||||
33 unsigned offline:1;
|
||||
34 unsigned interactiveobject:1;
|
||||
35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
|
||||
36 unsigned title:1;
|
||||
37 unsigned suffix:1;
|
||||
38 unsigned padding1:1;
|
||||
39 unsigned padding2:1;
|
||||
// byte 5
|
||||
/*32 unsigned buyer:1;
|
||||
/*33 unsigned offline:1;
|
||||
/*34 unsigned interactiveobject:1;
|
||||
/*35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
|
||||
/*36 unsigned title:1;
|
||||
/*37 unsigned suffix:1;
|
||||
/*38 unsigned padding1:1;
|
||||
/*39 unsigned padding2:1;
|
||||
40 unsinged padding3:1;
|
||||
*/
|
||||
/*
|
||||
@@ -3107,19 +3107,139 @@ 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
|
||||
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 RoF2BuyerActions {
|
||||
BuyerSearchResults = 0x00,
|
||||
BuyerBuyLine = 0x06,
|
||||
BuyerModifyBuyLine = 0x07,
|
||||
BuyerRemoveItem = 0x08,
|
||||
BuyerSellItem = 0x09,
|
||||
BuyerBuyItem = 0x0a,
|
||||
BuyerInspectBegin = 0x0b,
|
||||
BuyerInspectEnd = 0x0c,
|
||||
BuyerAppearance = 0x0d,
|
||||
BuyerSendBuyLine = 0x0e,
|
||||
BuyerItemInspect = 0x0f,
|
||||
BuyerBrowsingBuyLine = 0x10,
|
||||
BarterWelcomeMessage = 0x11,
|
||||
BuyerWelcomeMessage = 0x13,
|
||||
BuyerGreeting = 0x14,
|
||||
BuyerInventoryFull = 0x16
|
||||
};
|
||||
|
||||
struct BarterItemSearchLinkRequest_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown_004;
|
||||
uint32 seller_id;
|
||||
uint32 buyer_id;
|
||||
uint32 unknown_016;
|
||||
uint32 slot_id; // 0xffffffff main buy line 0x0 trade_item_1, 0x1 trade_item_2
|
||||
uint32 item_id;
|
||||
uint32 unknown_028;
|
||||
};
|
||||
|
||||
struct BuyerWelcomeMessageUpdate_Struct {
|
||||
uint32 action;
|
||||
char unknown_004[64];
|
||||
uint32 unknown_068;
|
||||
char welcome_message[256];
|
||||
};
|
||||
|
||||
struct Buyer_SetAppearance_Struct {
|
||||
uint32 action;
|
||||
uint32 entity_id;
|
||||
char unknown[64];
|
||||
uint32 enabled;
|
||||
};
|
||||
|
||||
struct BuyerRemoveItem_Struct {
|
||||
uint32 action;
|
||||
uint32 unknown004;
|
||||
uint32 slot_id;
|
||||
uint32 toggle;
|
||||
};
|
||||
|
||||
struct BuyerLineSellItem_Struct {
|
||||
uint32 action;
|
||||
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
|
||||
uint32 unknown008;
|
||||
uint32 buyer_entity_id;
|
||||
uint32 seller_entity_id;
|
||||
char unknown[15];
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
char item_name[64];
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 item_toggle;
|
||||
uint32 item_cost;
|
||||
uint32 no_trade_items;
|
||||
BuyerLineTradeItems_Struct trade_items[10];
|
||||
char unknown2[13];
|
||||
uint32 seller_quantity;
|
||||
};
|
||||
|
||||
struct BuyerLineItemsSearch_Struct {
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
char item_name[64];
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 item_toggle;
|
||||
uint32 item_cost;
|
||||
uint32 buyer_id;
|
||||
BuyerLineTradeItems_Struct trade_items[MAX_BUYER_COMPENSATION_ITEMS];
|
||||
};
|
||||
|
||||
struct BuyerLineSearch_Struct {
|
||||
uint32 action;
|
||||
uint32 no_items;
|
||||
std::vector<BuyerLineItemsSearch_Struct> buy_line;
|
||||
};
|
||||
|
||||
struct BuyerStart_Struct {
|
||||
uint32 action;
|
||||
uint16 no_buyer_lines;
|
||||
uint32 slot;
|
||||
uint8 enabled;
|
||||
uint32 item_id;
|
||||
char item_name[1]; // vary length
|
||||
uint32 item_icon;
|
||||
uint32 item_quantity;
|
||||
uint8 toggle;
|
||||
uint32 item_cost;
|
||||
uint32 no_trade_items;
|
||||
BuyerLineTradeItems_Struct trade_items[1]; // size is actually no_trade_items. If 0, then this is not in packet
|
||||
char unknown[13];
|
||||
};
|
||||
|
||||
struct BuyerItemSearchResultEntry_Struct {
|
||||
char item_name[64];
|
||||
uint32 item_id;
|
||||
uint32 item_icon;
|
||||
uint32 unknown_072;
|
||||
};
|
||||
|
||||
struct BuyerItemSearchResults_Struct {
|
||||
uint32 action;
|
||||
uint32 result_count;
|
||||
BuyerItemSearchResultEntry_Struct results[];
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -806,7 +806,7 @@ namespace Titanium
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case AppearanceType::GuildShow: {
|
||||
FAIL_ENCODE();
|
||||
@@ -2567,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();
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
struct BotSpellsEntries {
|
||||
uint32_t id;
|
||||
int32_t npc_spells_id;
|
||||
int16_t spellid;
|
||||
uint16_t spell_id;
|
||||
uint32_t type;
|
||||
uint8_t minlevel;
|
||||
uint8_t maxlevel;
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
return {
|
||||
"id",
|
||||
"npc_spells_id",
|
||||
"spellid",
|
||||
"spell_id",
|
||||
"type",
|
||||
"minlevel",
|
||||
"maxlevel",
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
return {
|
||||
"id",
|
||||
"npc_spells_id",
|
||||
"spellid",
|
||||
"spell_id",
|
||||
"type",
|
||||
"minlevel",
|
||||
"maxlevel",
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
|
||||
e.id = 0;
|
||||
e.npc_spells_id = 0;
|
||||
e.spellid = 0;
|
||||
e.spell_id = 0;
|
||||
e.type = 0;
|
||||
e.minlevel = 0;
|
||||
e.maxlevel = 255;
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
|
||||
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<int16_t>(atoi(row[2])) : 0;
|
||||
e.spell_id = 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;
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.npc_spells_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.spellid));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.spell_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.type));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.minlevel));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.maxlevel));
|
||||
@@ -256,7 +256,7 @@ public:
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.minlevel));
|
||||
v.push_back(std::to_string(e.maxlevel));
|
||||
@@ -300,7 +300,7 @@ public:
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.minlevel));
|
||||
v.push_back(std::to_string(e.maxlevel));
|
||||
@@ -348,7 +348,7 @@ public:
|
||||
|
||||
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<int16_t>(atoi(row[2])) : 0;
|
||||
e.spell_id = 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;
|
||||
@@ -387,7 +387,7 @@ public:
|
||||
|
||||
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<int16_t>(atoi(row[2])) : 0;
|
||||
e.spell_id = 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;
|
||||
@@ -476,7 +476,7 @@ public:
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.minlevel));
|
||||
v.push_back(std::to_string(e.maxlevel));
|
||||
@@ -513,7 +513,7 @@ public:
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.npc_spells_id));
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.minlevel));
|
||||
v.push_back(std::to_string(e.maxlevel));
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This repository was automatically generated and is NOT to be modified directly.
|
||||
* Any repository modifications are meant to be made to the repository extending the base.
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
|
||||
#define EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseBuyerBuyLinesRepository {
|
||||
public:
|
||||
struct BuyerBuyLines {
|
||||
uint64_t id;
|
||||
uint64_t buyer_id;
|
||||
uint32_t char_id;
|
||||
int32_t buy_slot_id;
|
||||
int32_t item_id;
|
||||
int32_t item_qty;
|
||||
int32_t item_price;
|
||||
uint32_t item_icon;
|
||||
std::string item_name;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"buyer_id",
|
||||
"char_id",
|
||||
"buy_slot_id",
|
||||
"item_id",
|
||||
"item_qty",
|
||||
"item_price",
|
||||
"item_icon",
|
||||
"item_name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"buyer_id",
|
||||
"char_id",
|
||||
"buy_slot_id",
|
||||
"item_id",
|
||||
"item_qty",
|
||||
"item_price",
|
||||
"item_icon",
|
||||
"item_name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("buyer_buy_lines");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static BuyerBuyLines NewEntity()
|
||||
{
|
||||
BuyerBuyLines e{};
|
||||
|
||||
e.id = 0;
|
||||
e.buyer_id = 0;
|
||||
e.char_id = 0;
|
||||
e.buy_slot_id = 0;
|
||||
e.item_id = 0;
|
||||
e.item_qty = 0;
|
||||
e.item_price = 0;
|
||||
e.item_icon = 0;
|
||||
e.item_name = "";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static BuyerBuyLines GetBuyerBuyLines(
|
||||
const std::vector<BuyerBuyLines> &buyer_buy_liness,
|
||||
int buyer_buy_lines_id
|
||||
)
|
||||
{
|
||||
for (auto &buyer_buy_lines : buyer_buy_liness) {
|
||||
if (buyer_buy_lines.id == buyer_buy_lines_id) {
|
||||
return buyer_buy_lines;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static BuyerBuyLines FindOne(
|
||||
Database& db,
|
||||
int buyer_buy_lines_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
buyer_buy_lines_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
BuyerBuyLines e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.item_name = row[8] ? row[8] : "";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int buyer_buy_lines_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
buyer_buy_lines_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const BuyerBuyLines &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.buyer_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.char_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.buy_slot_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.item_qty));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.item_price));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.item_icon));
|
||||
v.push_back(columns[8] + " = '" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static BuyerBuyLines InsertOne(
|
||||
Database& db,
|
||||
BuyerBuyLines e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.buyer_id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.buy_slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_price));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
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<BuyerBuyLines> &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.buyer_id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.buy_slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_price));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<BuyerBuyLines> All(Database& db)
|
||||
{
|
||||
std::vector<BuyerBuyLines> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
BuyerBuyLines e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.item_name = row[8] ? row[8] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<BuyerBuyLines> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<BuyerBuyLines> 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) {
|
||||
BuyerBuyLines e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||
e.item_name = row[8] ? row[8] : "";
|
||||
|
||||
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 BuyerBuyLines &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.buyer_id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.buy_slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_price));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int ReplaceMany(
|
||||
Database& db,
|
||||
const std::vector<BuyerBuyLines> &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.buyer_id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.buy_slot_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_price));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
|
||||
@@ -19,40 +19,46 @@
|
||||
class BaseBuyerRepository {
|
||||
public:
|
||||
struct Buyer {
|
||||
int32_t charid;
|
||||
int32_t buyslot;
|
||||
int32_t itemid;
|
||||
std::string itemname;
|
||||
int32_t quantity;
|
||||
int32_t price;
|
||||
uint64_t id;
|
||||
uint32_t char_id;
|
||||
uint32_t char_entity_id;
|
||||
std::string char_name;
|
||||
uint32_t char_zone_id;
|
||||
uint32_t char_zone_instance_id;
|
||||
time_t transaction_date;
|
||||
std::string welcome_message;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("charid");
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"charid",
|
||||
"buyslot",
|
||||
"itemid",
|
||||
"itemname",
|
||||
"quantity",
|
||||
"price",
|
||||
"id",
|
||||
"char_id",
|
||||
"char_entity_id",
|
||||
"char_name",
|
||||
"char_zone_id",
|
||||
"char_zone_instance_id",
|
||||
"transaction_date",
|
||||
"welcome_message",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"charid",
|
||||
"buyslot",
|
||||
"itemid",
|
||||
"itemname",
|
||||
"quantity",
|
||||
"price",
|
||||
"id",
|
||||
"char_id",
|
||||
"char_entity_id",
|
||||
"char_name",
|
||||
"char_zone_id",
|
||||
"char_zone_instance_id",
|
||||
"UNIX_TIMESTAMP(transaction_date)",
|
||||
"welcome_message",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,12 +99,14 @@ public:
|
||||
{
|
||||
Buyer e{};
|
||||
|
||||
e.charid = 0;
|
||||
e.buyslot = 0;
|
||||
e.itemid = 0;
|
||||
e.itemname = "";
|
||||
e.quantity = 0;
|
||||
e.price = 0;
|
||||
e.id = 0;
|
||||
e.char_id = 0;
|
||||
e.char_entity_id = 0;
|
||||
e.char_name = "";
|
||||
e.char_zone_id = 0;
|
||||
e.char_zone_instance_id = 0;
|
||||
e.transaction_date = 0;
|
||||
e.welcome_message = "";
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -109,7 +117,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &buyer : buyers) {
|
||||
if (buyer.charid == buyer_id) {
|
||||
if (buyer.id == buyer_id) {
|
||||
return buyer;
|
||||
}
|
||||
}
|
||||
@@ -135,12 +143,14 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
Buyer e{};
|
||||
|
||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.itemname = row[3] ? row[3] : "";
|
||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 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.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.char_name = row[3] ? row[3] : "";
|
||||
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||
e.welcome_message = row[7] ? row[7] : "";
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -174,12 +184,13 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.charid));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.buyslot));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.itemid));
|
||||
v.push_back(columns[3] + " = '" + Strings::Escape(e.itemname) + "'");
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.quantity));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.price));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.char_entity_id));
|
||||
v.push_back(columns[3] + " = '" + Strings::Escape(e.char_name) + "'");
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.char_zone_id));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.char_zone_instance_id));
|
||||
v.push_back(columns[6] + " = FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||
v.push_back(columns[7] + " = '" + Strings::Escape(e.welcome_message) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -187,7 +198,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.charid
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -201,12 +212,14 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.buyslot));
|
||||
v.push_back(std::to_string(e.itemid));
|
||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
||||
v.push_back(std::to_string(e.quantity));
|
||||
v.push_back(std::to_string(e.price));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -217,7 +230,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.charid = results.LastInsertedID();
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -236,12 +249,14 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.buyslot));
|
||||
v.push_back(std::to_string(e.itemid));
|
||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
||||
v.push_back(std::to_string(e.quantity));
|
||||
v.push_back(std::to_string(e.price));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -275,12 +290,14 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Buyer e{};
|
||||
|
||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.itemname = row[3] ? row[3] : "";
|
||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 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.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.char_name = row[3] ? row[3] : "";
|
||||
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||
e.welcome_message = row[7] ? row[7] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -305,12 +322,14 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Buyer e{};
|
||||
|
||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.itemname = row[3] ? row[3] : "";
|
||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 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.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.char_name = row[3] ? row[3] : "";
|
||||
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||
e.welcome_message = row[7] ? row[7] : "";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -385,12 +404,14 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.buyslot));
|
||||
v.push_back(std::to_string(e.itemid));
|
||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
||||
v.push_back(std::to_string(e.quantity));
|
||||
v.push_back(std::to_string(e.price));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -413,12 +434,14 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.buyslot));
|
||||
v.push_back(std::to_string(e.itemid));
|
||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
||||
v.push_back(std::to_string(e.quantity));
|
||||
v.push_back(std::to_string(e.price));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.char_entity_id));
|
||||
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||
v.push_back(std::to_string(e.char_zone_id));
|
||||
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,439 @@
|
||||
/**
|
||||
* 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_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||
#define EQEMU_BASE_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseBuyerTradeItemsRepository {
|
||||
public:
|
||||
struct BuyerTradeItems {
|
||||
uint64_t id;
|
||||
uint64_t buyer_buy_lines_id;
|
||||
int32_t item_id;
|
||||
int32_t item_qty;
|
||||
int32_t item_icon;
|
||||
std::string item_name;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"buyer_buy_lines_id",
|
||||
"item_id",
|
||||
"item_qty",
|
||||
"item_icon",
|
||||
"item_name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"buyer_buy_lines_id",
|
||||
"item_id",
|
||||
"item_qty",
|
||||
"item_icon",
|
||||
"item_name",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("buyer_trade_items");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static BuyerTradeItems NewEntity()
|
||||
{
|
||||
BuyerTradeItems e{};
|
||||
|
||||
e.id = 0;
|
||||
e.buyer_buy_lines_id = 0;
|
||||
e.item_id = 0;
|
||||
e.item_qty = 0;
|
||||
e.item_icon = 0;
|
||||
e.item_name = "0";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static BuyerTradeItems GetBuyerTradeItems(
|
||||
const std::vector<BuyerTradeItems> &buyer_trade_itemss,
|
||||
int buyer_trade_items_id
|
||||
)
|
||||
{
|
||||
for (auto &buyer_trade_items : buyer_trade_itemss) {
|
||||
if (buyer_trade_items.id == buyer_trade_items_id) {
|
||||
return buyer_trade_items;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static BuyerTradeItems FindOne(
|
||||
Database& db,
|
||||
int buyer_trade_items_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
buyer_trade_items_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
BuyerTradeItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_name = row[5] ? row[5] : "0";
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int buyer_trade_items_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
buyer_trade_items_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
const BuyerTradeItems &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.buyer_buy_lines_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.item_qty));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.item_icon));
|
||||
v.push_back(columns[5] + " = '" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static BuyerTradeItems InsertOne(
|
||||
Database& db,
|
||||
BuyerTradeItems e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.buyer_buy_lines_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
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<BuyerTradeItems> &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.buyer_buy_lines_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<BuyerTradeItems> All(Database& db)
|
||||
{
|
||||
std::vector<BuyerTradeItems> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
BuyerTradeItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_name = row[5] ? row[5] : "0";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<BuyerTradeItems> GetWhere(Database& db, const std::string &where_filter)
|
||||
{
|
||||
std::vector<BuyerTradeItems> 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) {
|
||||
BuyerTradeItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_name = row[5] ? row[5] : "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 BuyerTradeItems &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.buyer_buy_lines_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int ReplaceMany(
|
||||
Database& db,
|
||||
const std::vector<BuyerTradeItems> &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.buyer_buy_lines_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.item_qty));
|
||||
v.push_back(std::to_string(e.item_icon));
|
||||
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
uint32_t ornamenticon;
|
||||
uint32_t ornamentidfile;
|
||||
int32_t ornament_hero_model;
|
||||
uint64_t guid;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
"ornamenticon",
|
||||
"ornamentidfile",
|
||||
"ornament_hero_model",
|
||||
"guid",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -83,6 +85,7 @@ public:
|
||||
"ornamenticon",
|
||||
"ornamentidfile",
|
||||
"ornament_hero_model",
|
||||
"guid",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,6 +142,7 @@ public:
|
||||
e.ornamenticon = 0;
|
||||
e.ornamentidfile = 0;
|
||||
e.ornament_hero_model = 0;
|
||||
e.guid = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -191,6 +195,7 @@ public:
|
||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -240,6 +245,7 @@ public:
|
||||
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
|
||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
|
||||
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
|
||||
v.push_back(columns[16] + " = " + std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -277,6 +283,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -322,6 +329,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -371,6 +379,7 @@ public:
|
||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -411,6 +420,7 @@ public:
|
||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -501,6 +511,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -539,6 +550,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
uint32_t ornamenticon;
|
||||
uint32_t ornamentidfile;
|
||||
int32_t ornament_hero_model;
|
||||
uint64_t guid;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -63,6 +64,7 @@ public:
|
||||
"ornamenticon",
|
||||
"ornamentidfile",
|
||||
"ornament_hero_model",
|
||||
"guid",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -86,6 +88,7 @@ public:
|
||||
"ornamenticon",
|
||||
"ornamentidfile",
|
||||
"ornament_hero_model",
|
||||
"guid",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,6 +146,7 @@ public:
|
||||
e.ornamenticon = 0;
|
||||
e.ornamentidfile = 0;
|
||||
e.ornament_hero_model = 0;
|
||||
e.guid = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -196,6 +200,7 @@ public:
|
||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -246,6 +251,7 @@ public:
|
||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
||||
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
||||
v.push_back(columns[16] + " = " + std::to_string(e.ornament_hero_model));
|
||||
v.push_back(columns[17] + " = " + std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -284,6 +290,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -330,6 +337,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -380,6 +388,7 @@ public:
|
||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -421,6 +430,7 @@ public:
|
||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -512,6 +522,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -551,6 +562,7 @@ public:
|
||||
v.push_back(std::to_string(e.ornamenticon));
|
||||
v.push_back(std::to_string(e.ornamentidfile));
|
||||
v.push_back(std::to_string(e.ornament_hero_model));
|
||||
v.push_back(std::to_string(e.guid));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -19,31 +19,34 @@
|
||||
class BaseSpellBucketsRepository {
|
||||
public:
|
||||
struct SpellBuckets {
|
||||
uint64_t spellid;
|
||||
std::string key_;
|
||||
std::string value;
|
||||
uint32_t spell_id;
|
||||
std::string bucket_name;
|
||||
std::string bucket_value;
|
||||
uint8_t bucket_comparison;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("spellid");
|
||||
return std::string("spell_id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"spellid",
|
||||
"`key`",
|
||||
"value",
|
||||
"spell_id",
|
||||
"bucket_name",
|
||||
"bucket_value",
|
||||
"bucket_comparison",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"spellid",
|
||||
"`key`",
|
||||
"value",
|
||||
"spell_id",
|
||||
"bucket_name",
|
||||
"bucket_value",
|
||||
"bucket_comparison",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -84,9 +87,10 @@ public:
|
||||
{
|
||||
SpellBuckets e{};
|
||||
|
||||
e.spellid = 0;
|
||||
e.key_ = "";
|
||||
e.value = "";
|
||||
e.spell_id = 0;
|
||||
e.bucket_name = "";
|
||||
e.bucket_value = "";
|
||||
e.bucket_comparison = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -97,7 +101,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &spell_buckets : spell_bucketss) {
|
||||
if (spell_buckets.spellid == spell_buckets_id) {
|
||||
if (spell_buckets.spell_id == spell_buckets_id) {
|
||||
return spell_buckets;
|
||||
}
|
||||
}
|
||||
@@ -123,9 +127,10 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
SpellBuckets e{};
|
||||
|
||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.bucket_name = row[1] ? row[1] : "";
|
||||
e.bucket_value = row[2] ? row[2] : "";
|
||||
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -159,9 +164,10 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.spellid));
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.spell_id));
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.bucket_name) + "'");
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.bucket_value) + "'");
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.bucket_comparison));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -169,7 +175,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.spellid
|
||||
e.spell_id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -183,9 +189,10 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||
v.push_back(std::to_string(e.bucket_comparison));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -196,7 +203,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.spellid = results.LastInsertedID();
|
||||
e.spell_id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -215,9 +222,10 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||
v.push_back(std::to_string(e.bucket_comparison));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -251,9 +259,10 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpellBuckets e{};
|
||||
|
||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.bucket_name = row[1] ? row[1] : "";
|
||||
e.bucket_value = row[2] ? row[2] : "";
|
||||
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -278,9 +287,10 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpellBuckets e{};
|
||||
|
||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.bucket_name = row[1] ? row[1] : "";
|
||||
e.bucket_value = row[2] ? row[2] : "";
|
||||
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -355,9 +365,10 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||
v.push_back(std::to_string(e.bucket_comparison));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -380,9 +391,10 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.spellid));
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||
v.push_back(std::to_string(e.bucket_comparison));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -44,7 +44,24 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static std::vector<std::string> GetBaseDataFileLines(Database& db)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY `level`, `class` ASC",
|
||||
ColumnsRaw(),
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
for (auto row : results) {
|
||||
lines.emplace_back(row[0]);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_DATA_REPOSITORY_H
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
#ifndef EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||
#define EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_buyer_buy_lines_repository.h"
|
||||
#include "buyer_trade_items_repository.h"
|
||||
#include "character_data_repository.h"
|
||||
#include "buyer_repository.h"
|
||||
|
||||
#include "../eq_packet_structs.h"
|
||||
|
||||
class BuyerBuyLinesRepository: public BaseBuyerBuyLinesRepository {
|
||||
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
|
||||
*
|
||||
* BuyerBuyLinesRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* BuyerBuyLinesRepository::GetWhereNeverExpires()
|
||||
* BuyerBuyLinesRepository::GetWhereXAndY()
|
||||
* BuyerBuyLinesRepository::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
|
||||
|
||||
struct WelcomeData_Struct {
|
||||
uint32 count_of_buyers;
|
||||
uint32 count_of_items;
|
||||
};
|
||||
|
||||
static int CreateBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
|
||||
{
|
||||
auto buyer = BuyerRepository::GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1", char_id));
|
||||
if (buyer.empty()){
|
||||
return 0;
|
||||
}
|
||||
|
||||
BuyerBuyLinesRepository::BuyerBuyLines buy_lines{};
|
||||
buy_lines.id = 0;
|
||||
buy_lines.buyer_id = buyer.front().id;
|
||||
buy_lines.char_id = char_id;
|
||||
buy_lines.buy_slot_id = b.slot;
|
||||
buy_lines.item_id = b.item_id;
|
||||
buy_lines.item_name = b.item_name;
|
||||
buy_lines.item_icon = b.item_icon;
|
||||
buy_lines.item_qty = b.item_quantity;
|
||||
buy_lines.item_price = b.item_cost;
|
||||
auto e = InsertOne(db, buy_lines);
|
||||
|
||||
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
|
||||
|
||||
for (auto const &r: b.trade_items) {
|
||||
BuyerTradeItemsRepository::BuyerTradeItems bti{};
|
||||
bti.id = 0;
|
||||
bti.buyer_buy_lines_id = e.id;
|
||||
bti.item_id = r.item_id;
|
||||
bti.item_qty = r.item_quantity;
|
||||
bti.item_icon = r.item_icon;
|
||||
bti.item_name = r.item_name;
|
||||
|
||||
if (bti.item_id) {
|
||||
queue.push_back(bti);
|
||||
}
|
||||
}
|
||||
|
||||
if (!queue.empty()) {
|
||||
BuyerTradeItemsRepository::InsertMany(db, queue);
|
||||
}
|
||||
|
||||
return e.id;
|
||||
}
|
||||
|
||||
static int ModifyBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
|
||||
{
|
||||
auto b_lines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}';", char_id, b.slot));
|
||||
if (b_lines.empty() || b_lines.size() > 1){
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto b_line = b_lines.front();
|
||||
|
||||
b_line.item_qty = b.item_quantity;
|
||||
b_line.item_price = b.item_cost;
|
||||
b_line.item_icon = b.item_icon;
|
||||
auto e = UpdateOne(db, b_line);
|
||||
|
||||
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
|
||||
|
||||
BuyerTradeItemsRepository::DeleteWhere(db, fmt::format("`buyer_buy_lines_id` = '{}';", b_line.id));
|
||||
for (auto const &r: b.trade_items) {
|
||||
BuyerTradeItemsRepository::BuyerTradeItems bti{};
|
||||
bti.id = 0;
|
||||
bti.buyer_buy_lines_id = b_line.id;
|
||||
bti.item_id = r.item_id;
|
||||
bti.item_qty = r.item_quantity;
|
||||
bti.item_icon = r.item_icon;
|
||||
bti.item_name = r.item_name;
|
||||
|
||||
if (bti.item_id) {
|
||||
queue.push_back(bti);
|
||||
}
|
||||
}
|
||||
|
||||
if (!queue.empty()) {
|
||||
BuyerTradeItemsRepository::InsertMany(db, queue);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool DeleteBuyLine(Database &db, uint32 char_id, int32 slot_id = 0xffffffff)
|
||||
{
|
||||
std::vector<BuyerBuyLines> buylines{};
|
||||
if (slot_id == 0xffffffff) {
|
||||
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}'", char_id));
|
||||
DeleteWhere(db, fmt::format("`char_id` = '{}'", char_id));
|
||||
}
|
||||
else {
|
||||
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
|
||||
DeleteWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
|
||||
}
|
||||
|
||||
if (buylines.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> buyline_ids{};
|
||||
for (auto const &bl: buylines) {
|
||||
buyline_ids.push_back((std::to_string(bl.id)));
|
||||
}
|
||||
|
||||
if (!buyline_ids.empty()) {
|
||||
BuyerTradeItemsRepository::DeleteWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`buyer_buy_lines_id` IN({})",
|
||||
Strings::Implode(", ", buyline_ids)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::vector<BuyerLineItems_Struct> GetBuyLines(Database &db, uint32 char_id)
|
||||
{
|
||||
std::vector<BuyerLineItems_Struct> all_entries{};
|
||||
|
||||
auto buy_line = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||
if (buy_line.empty()){
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`buyer_buy_lines_id` IN (SELECT b.id FROM buyer_buy_lines AS b WHERE b.char_id = '{}')",
|
||||
char_id
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(buy_line.size());
|
||||
|
||||
for (auto const &l: buy_line) {
|
||||
BuyerLineItems_Struct bli{};
|
||||
bli.item_id = l.item_id;
|
||||
bli.item_cost = l.item_price;
|
||||
bli.item_quantity = l.item_qty;
|
||||
bli.slot = l.buy_slot_id;
|
||||
bli.item_name = l.item_name;
|
||||
|
||||
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
|
||||
BuyerLineTradeItems_Struct blti{};
|
||||
blti.item_id = i.item_id;
|
||||
blti.item_icon = i.item_icon;
|
||||
blti.item_quantity = i.item_qty;
|
||||
blti.item_id = i.item_id;
|
||||
blti.item_name = i.item_name;
|
||||
bli.trade_items.push_back(blti);
|
||||
}
|
||||
all_entries.push_back(bli);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static BuyerLineSearch_Struct SearchBuyLines(
|
||||
Database &db,
|
||||
std::string &search_string,
|
||||
uint32 char_id = 0,
|
||||
uint32 zone_id = 0,
|
||||
uint32 zone_instance_id = 0
|
||||
)
|
||||
{
|
||||
BuyerLineSearch_Struct all_entries{};
|
||||
std::string where_clause(fmt::format("`item_name` LIKE \"%{}%\" ", search_string));
|
||||
|
||||
if (char_id) {
|
||||
where_clause += fmt::format("AND `char_id` = '{}' ", char_id);
|
||||
}
|
||||
|
||||
if (zone_id) {
|
||||
auto buyers = BuyerRepository::GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`char_zone_id` = '{}' AND char_zone_instance_id = '{}'",
|
||||
zone_id,
|
||||
zone_instance_id
|
||||
)
|
||||
);
|
||||
|
||||
if (buyers.empty()) {
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
std::vector<std::string> char_ids{};
|
||||
for (auto const &bl : buyers) {
|
||||
char_ids.push_back((std::to_string(bl.char_id)));
|
||||
}
|
||||
|
||||
where_clause += fmt::format("AND `char_id` IN ({}) ", Strings::Implode(", ", char_ids));
|
||||
}
|
||||
|
||||
auto buy_line = GetWhere(db, where_clause);
|
||||
if (buy_line.empty()){
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
std::vector<std::string> ids{};
|
||||
std::vector<std::string> char_ids{};
|
||||
for (auto const &bl : buy_line) {
|
||||
if (std::find(ids.begin(), ids.end(), std::to_string(bl.id)) == std::end(ids)) {
|
||||
ids.push_back(std::to_string(bl.id));
|
||||
}
|
||||
if (std::find(char_ids.begin(), char_ids.end(), std::to_string(bl.char_id)) == std::end(char_ids)) {
|
||||
char_ids.push_back((std::to_string(bl.char_id)));
|
||||
}
|
||||
}
|
||||
|
||||
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`buyer_buy_lines_id` IN ({});",
|
||||
Strings::Implode(", ", ids)
|
||||
)
|
||||
);
|
||||
|
||||
auto char_names = BuyerRepository::GetWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`char_id` IN ({});",
|
||||
Strings::Implode(", ", char_ids)
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.no_items = buy_line.size();
|
||||
for (auto const &l: buy_line) {
|
||||
BuyerLineItemsSearch_Struct blis{};
|
||||
blis.slot = l.buy_slot_id;
|
||||
blis.item_id = l.item_id;
|
||||
blis.item_cost = l.item_price;
|
||||
blis.item_icon = l.item_icon;
|
||||
blis.item_quantity = l.item_qty;
|
||||
blis.buyer_id = l.char_id;
|
||||
auto it = std::find_if(
|
||||
char_names.cbegin(),
|
||||
char_names.cend(),
|
||||
[&](BuyerRepository::Buyer e) { return e.char_id == l.char_id; }
|
||||
);
|
||||
blis.buyer_name = it != char_names.end() ? it->char_name : std::string("");
|
||||
blis.buyer_entity_id = it != char_names.end() ? it->char_entity_id : 0;
|
||||
blis.buyer_zone_id = it != char_names.end() ? it->char_zone_id : 0;
|
||||
blis.buyer_zone_instance_id = it != char_names.end() ? it->char_zone_instance_id : 0;
|
||||
strn0cpy(blis.item_name, l.item_name.c_str(), sizeof(blis.item_name));
|
||||
|
||||
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
|
||||
BuyerLineTradeItems_Struct e{};
|
||||
e.item_id = i.item_id;
|
||||
e.item_icon = i.item_icon;
|
||||
e.item_quantity = i.item_qty;
|
||||
e.item_id = i.item_id;
|
||||
e.item_name = i.item_name;
|
||||
|
||||
blis.trade_items.push_back(e);
|
||||
}
|
||||
all_entries.buy_line.push_back(blis);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<BuyerTradeItemsRepository::BuyerTradeItems>
|
||||
GetSubIDs(std::vector<BuyerTradeItemsRepository::BuyerTradeItems> &in, uint64 id)
|
||||
{
|
||||
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> results{};
|
||||
std::vector<uint64> indices{};
|
||||
|
||||
auto it = in.begin();
|
||||
while ((it = std::find_if(
|
||||
it,
|
||||
in.end(),
|
||||
[&](BuyerTradeItemsRepository::BuyerTradeItems const &e) {
|
||||
return e.buyer_buy_lines_id == id;
|
||||
}
|
||||
))
|
||||
!= in.end()
|
||||
) {
|
||||
indices.push_back(std::distance(in.begin(), it));
|
||||
results.push_back(*it);
|
||||
it++;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static WelcomeData_Struct GetWelcomeData(Database &db)
|
||||
{
|
||||
WelcomeData_Struct e{};
|
||||
|
||||
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), COUNT(char_id) FROM buyer;");
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return e;
|
||||
}
|
||||
|
||||
auto r = results.begin();
|
||||
e.count_of_buyers = Strings::ToInt(r[0]);
|
||||
e.count_of_items = Strings::ToInt(r[1]);
|
||||
return e;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_buyer_repository.h"
|
||||
#include "base/base_buyer_trade_items_repository.h"
|
||||
#include "base/base_buyer_buy_lines_repository.h"
|
||||
|
||||
class BuyerRepository: public BaseBuyerRepository {
|
||||
public:
|
||||
@@ -45,6 +47,97 @@ public:
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
static bool UpdateWelcomeMessage(Database& db, uint32 char_id, const char *message) {
|
||||
|
||||
auto const b = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||
|
||||
if (b.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto buyer = b.front();
|
||||
buyer.welcome_message = message;
|
||||
return UpdateOne(db, buyer);
|
||||
}
|
||||
|
||||
static std::string GetWelcomeMessage(Database& db, uint32 char_id) {
|
||||
|
||||
auto const b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||
if (b.empty()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return b.front().welcome_message;
|
||||
}
|
||||
|
||||
static int UpdateTransactionDate(Database& db, uint32 char_id, time_t transaction_date) {
|
||||
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||
if (b.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto e = b.front();
|
||||
e.transaction_date = transaction_date;
|
||||
|
||||
return UpdateOne(db, e);
|
||||
}
|
||||
|
||||
static time_t GetTransactionDate(Database& db, uint32 char_id) {
|
||||
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||
if (b.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto e = b.front();
|
||||
|
||||
return e.transaction_date;
|
||||
}
|
||||
|
||||
static bool DeleteBuyer(Database &db, uint32 char_id)
|
||||
{
|
||||
if (char_id == 0) {
|
||||
Truncate(db);
|
||||
BaseBuyerBuyLinesRepository::Truncate(db);
|
||||
BaseBuyerTradeItemsRepository::Truncate(db);
|
||||
}
|
||||
else {
|
||||
auto buyer = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||
if (buyer.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto buy_lines = BaseBuyerBuyLinesRepository::GetWhere(
|
||||
db,
|
||||
fmt::format("`buyer_id` = '{}'", buyer.front().id)
|
||||
);
|
||||
if (buy_lines.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> buy_line_ids{};
|
||||
for (auto const &bl: buy_lines) {
|
||||
buy_line_ids.push_back(std::to_string(bl.id));
|
||||
}
|
||||
|
||||
DeleteWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||
if (buy_line_ids.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseBuyerBuyLinesRepository::DeleteWhere(
|
||||
db,
|
||||
fmt::format("`id` IN({})", Strings::Implode(", ", buy_line_ids))
|
||||
);
|
||||
BaseBuyerTradeItemsRepository::DeleteWhere(
|
||||
db,
|
||||
fmt::format(
|
||||
"`buyer_buy_lines_id` IN({})",
|
||||
Strings::Implode(", ", buy_line_ids))
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BUYER_REPOSITORY_H
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||
#define EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
#include "base/base_buyer_trade_items_repository.h"
|
||||
|
||||
class BuyerTradeItemsRepository: public BaseBuyerTradeItemsRepository {
|
||||
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
|
||||
*
|
||||
* BuyerTradeItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* BuyerTradeItemsRepository::GetWhereNeverExpires()
|
||||
* BuyerTradeItemsRepository::GetWhereXAndY()
|
||||
* BuyerTradeItemsRepository::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<BuyerTradeItems> GetTradeItems(Database& db, const uint32 char_id)
|
||||
{
|
||||
std::vector<BuyerTradeItems> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT bti.* "
|
||||
"FROM buyer_trade_items AS bti "
|
||||
"INNER JOIN buyer_buy_lines AS bbl ON bti.buyer_buy_lines_id = bbl.id "
|
||||
"WHERE bbl.char_id = '{}';",
|
||||
char_id
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
BuyerTradeItems e{};
|
||||
|
||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||
e.item_name = row[5] ? row[5] : "0";
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BUYER_TRADE_ITEMS_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,12 @@ 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 = "stance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findstance"},
|
||||
{.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"},
|
||||
@@ -79,7 +85,6 @@ public:
|
||||
{.parent_command = "set", .sub_command = "endurance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setendurance"},
|
||||
{.parent_command = "set", .sub_command = "endurance_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "endurance"},
|
||||
{.parent_command = "set", .sub_command = "exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setxp|setexp"},
|
||||
{.parent_command = "set", .sub_command = "faction", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setfaction"},
|
||||
{.parent_command = "set", .sub_command = "flymode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flymode"},
|
||||
{.parent_command = "set", .sub_command = "freeze", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "freeze|unfreeze"},
|
||||
{.parent_command = "set", .sub_command = "gender", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gender"},
|
||||
|
||||
@@ -44,7 +44,24 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static std::vector<std::string> GetDBStrFileLines(Database& db)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT CONCAT(CONCAT_WS('^', {}), '^0') FROM {} ORDER BY `id`, `type` ASC",
|
||||
ColumnsRaw(),
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
for (auto row : results) {
|
||||
lines.emplace_back(row[0]);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_DB_STR_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,23 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static std::vector<std::string> GetSkillCapFileLines(Database& db)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT CONCAT_WS('^', `class_id`, `skill_id`, `level`, `cap`, `class_`) FROM {} ORDER BY `class_id`, `skill_id`, `level` ASC",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
for (auto row : results) {
|
||||
lines.emplace_back(row[0]);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_SKILL_CAPS_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,25 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static std::vector<std::string> GetSpellFileLines(Database& db)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY {} ASC",
|
||||
ColumnsRaw(),
|
||||
TableName(),
|
||||
PrimaryKey()
|
||||
)
|
||||
);
|
||||
|
||||
for (auto row : results) {
|
||||
lines.emplace_back(row[0]);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_SPELLS_NEW_REPOSITORY_H
|
||||
|
||||
@@ -217,6 +217,10 @@ public:
|
||||
delete_ids.push_back(std::to_string(e.id));
|
||||
}
|
||||
|
||||
if (delete_ids.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -189,6 +189,8 @@ void RuleManager::ResetRules(bool reload) {
|
||||
m_RuleRealValues[ Real__##rule_name ] = default_value;
|
||||
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
|
||||
m_RuleBoolValues[ Bool__##rule_name ] = default_value;
|
||||
#define RULE_STRING(category_name, rule_name, default_value, notes) \
|
||||
m_RuleStringValues[ String__##rule_name ] = default_value;
|
||||
#include "ruletypes.h"
|
||||
|
||||
// restore these rules to their pre-reset values
|
||||
|
||||
+41
-1
@@ -178,6 +178,7 @@ RULE_BOOL(Character, NoSkillsOnHorse, false, "Enabling this will prevent Bind Wo
|
||||
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
|
||||
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
|
||||
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
|
||||
RULE_INT(Character, DefaultGuildRank, 8, "Default guild rank when Character:DefaultGuild is a non-0 value, default is 8 (Recruit)")
|
||||
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
||||
RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-based experience modifiers.")
|
||||
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
|
||||
@@ -226,6 +227,9 @@ 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_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -240,6 +244,9 @@ RULE_INT(Mercs, AggroRadiusPuller, 25, "Determines the distance from which a mer
|
||||
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
|
||||
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
|
||||
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
|
||||
RULE_BOOL(Mercs, MercsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||
RULE_INT(Mercs, MercsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(Mercs, MercsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Guild)
|
||||
@@ -331,6 +338,7 @@ RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclu
|
||||
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
||||
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
|
||||
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
||||
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Zone)
|
||||
@@ -468,7 +476,6 @@ RULE_BOOL(Spells, OldRainTargets, false, "Use old incorrectly implemented maximu
|
||||
RULE_REAL(Spells, CallOfTheHeroAggroClearDist, 250.0, "Distance at which CoTH will wipe aggro. To disable and always enable aggro wipe on any distance of CoTH, set to 0.")
|
||||
RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
|
||||
RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002")
|
||||
RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
|
||||
RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch to swap targets from pet to pet owner if a pet is tanking.")
|
||||
RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.")
|
||||
RULE_BOOL(Spells, AllowDoubleInvis, true, "Allows you to cast invisibility spells on a player that is already invisible, live like behavior.")
|
||||
@@ -503,9 +510,14 @@ 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_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
|
||||
RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blank AOE spell can cast on. Set to 0 for no limit.")
|
||||
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
@@ -614,6 +626,21 @@ RULE_INT(Combat, PCAttackPowerScaling, 100, "Applies scaling to PC Attack Power
|
||||
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, SlayDamageMultiplier, 1.0, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 1.0")
|
||||
RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0")
|
||||
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)
|
||||
@@ -649,6 +676,9 @@ RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if e
|
||||
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
|
||||
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
|
||||
RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
|
||||
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Aggro)
|
||||
@@ -674,6 +704,7 @@ 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_STRING(Aggro, ExcludedFleeAllyFactionIDs, "0|5013|5014|5023|5032", "Common Faction IDs that are excluded from faction checks in EntityList::FleeAllyCount")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(TaskSystem)
|
||||
@@ -688,6 +719,7 @@ RULE_BOOL(TaskSystem, ExpRewardsIgnoreLevelBasedEXPMods, false, "Rewarding Level
|
||||
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
|
||||
RULE_INT(TaskSystem, SharedTasksTerminateTimerMS, 120000, "Delay (milliseconds) until a shared task is terminated if requirements are no longer met after member removal (default: 2 minutes)")
|
||||
RULE_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
|
||||
RULE_INT(TaskSystem, MaxUpdateMessages, 50, "Maximum update messages for non-GiveCash activity types in IncrementDoneCount")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Range)
|
||||
@@ -699,6 +731,7 @@ RULE_INT(Range, SpellParticles, 135, "The packet range in which spell particles
|
||||
RULE_INT(Range, DamageMessages, 50, "The packet range in which damage messages are sent (non-crit)")
|
||||
RULE_INT(Range, SpellMessages, 75, "The packet range in which spell damage messages are sent")
|
||||
RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are sent")
|
||||
RULE_INT(Range, StunMessages, 75, "The packet range in which stun messages are sent")
|
||||
RULE_INT(Range, ClientPositionUpdates, 300, "Distance in which the own changed position is communicated to other clients")
|
||||
RULE_INT(Range, CriticalDamage, 80, "The packet range in which critical hit messages are sent")
|
||||
RULE_INT(Range, MobCloseScanDistance, 600, "Close scan distance")
|
||||
@@ -740,6 +773,9 @@ RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hi
|
||||
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
||||
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_BOOL(Bots, BotsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||
RULE_INT(Bots, BotsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(Bots, BotsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Chat)
|
||||
@@ -786,6 +822,7 @@ RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in t
|
||||
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_INT(Bazaar, MaxBuyerInventorySearchResults, 200, "Maximum number of search results when a Buyer searches the global item list. Default is 200. RoF+ Only.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mail)
|
||||
@@ -877,6 +914,7 @@ RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any w
|
||||
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
|
||||
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
|
||||
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
|
||||
RULE_BOOL(Inventory, LazyLoadBank, true, "Don't load bank during zoning, only when in proximinity to a banker. May increase zone speed and stability")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Client)
|
||||
@@ -979,6 +1017,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)
|
||||
|
||||
@@ -140,6 +140,7 @@
|
||||
|
||||
#define ServerOP_TraderMessaging 0x0120
|
||||
#define ServerOP_BazaarPurchase 0x0121
|
||||
#define ServerOP_BuyerMessaging 0x0122
|
||||
|
||||
#define ServerOP_InstanceUpdateTime 0x014F
|
||||
#define ServerOP_AdventureRequest 0x0150
|
||||
|
||||
+116
-85
@@ -46,6 +46,8 @@
|
||||
#include "repositories/character_item_recast_repository.h"
|
||||
#include "repositories/character_corpses_repository.h"
|
||||
#include "repositories/skill_caps_repository.h"
|
||||
#include "repositories/inventory_repository.h"
|
||||
#include "repositories/books_repository.h"
|
||||
|
||||
namespace ItemField
|
||||
{
|
||||
@@ -300,15 +302,15 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance*
|
||||
// Update/Insert item
|
||||
const std::string query = StringFormat("REPLACE INTO inventory "
|
||||
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
|
||||
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model) "
|
||||
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model, guid) "
|
||||
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
|
||||
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
||||
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
||||
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
|
||||
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
|
||||
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
|
||||
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
|
||||
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
|
||||
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()));
|
||||
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()), inst->GetSerialNumber());
|
||||
const auto results = QueryDatabase(query);
|
||||
|
||||
// Save bag contents, if slot supports bag contents
|
||||
@@ -651,48 +653,67 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
return false;
|
||||
|
||||
// Retrieve character inventory
|
||||
const std::string query =
|
||||
StringFormat("SELECT slotid, itemid, charges, color, augslot1, augslot2, augslot3, augslot4, augslot5, "
|
||||
"augslot6, instnodrop, custom_data, ornamenticon, ornamentidfile, ornament_hero_model FROM "
|
||||
"inventory WHERE charid = %i ORDER BY slotid",
|
||||
char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogError("If you got an error related to the 'instnodrop' field, run the "
|
||||
"following SQL Queries:\nalter table inventory add instnodrop "
|
||||
"tinyint(1) unsigned default 0 not null;\n");
|
||||
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`;", char_id));
|
||||
if (results.empty()) {
|
||||
LogError("Error loading inventory for char_id {} from the database.", char_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto const &row: results) {
|
||||
if (row.guid != 0) {
|
||||
EQ::ItemInstance::AddGUIDToMap(row.guid);
|
||||
}
|
||||
}
|
||||
|
||||
const auto timestamps = GetItemRecastTimestamps(char_id);
|
||||
auto cv_conflict = false;
|
||||
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
||||
|
||||
auto cv_conflict = false;
|
||||
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
||||
std::vector<InventoryRepository::Inventory> queue{};
|
||||
for (auto &row: results) {
|
||||
const int16 slot_id = row.slotid;
|
||||
const uint32 item_id = row.itemid;
|
||||
const uint16 charges = row.charges;
|
||||
const uint32 color = row.color;
|
||||
const bool instnodrop = row.instnodrop;
|
||||
const uint32 ornament_icon = row.ornamenticon;
|
||||
const uint32 ornament_idfile = row.ornamentidfile;
|
||||
const uint32 ornament_hero_model = row.ornament_hero_model;
|
||||
|
||||
for (auto& row = results.begin(); row != results.end(); ++row) {
|
||||
int16 slot_id = Strings::ToInt(row[0]);
|
||||
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
||||
aug[0] = row.augslot1;
|
||||
aug[1] = row.augslot2;
|
||||
aug[2] = row.augslot3;
|
||||
aug[3] = row.augslot4;
|
||||
aug[4] = row.augslot5;
|
||||
aug[5] = row.augslot6;
|
||||
|
||||
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) { // Titanium thru UF check
|
||||
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
|
||||
// Titanium thru UF check
|
||||
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) { // Titanium thru UF check
|
||||
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + ((slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) {
|
||||
// Titanium thru UF check
|
||||
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + (
|
||||
(slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) { // Titanium check
|
||||
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) {
|
||||
// Titanium check
|
||||
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) { // Titanium check
|
||||
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) {
|
||||
// Titanium check
|
||||
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||
if (parent_index >= bank_size) {
|
||||
cv_conflict = true;
|
||||
@@ -700,64 +721,55 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 item_id = Strings::ToUnsignedInt(row[1]);
|
||||
const uint16 charges = Strings::ToUnsignedInt(row[2]);
|
||||
const uint32 color = Strings::ToUnsignedInt(row[3]);
|
||||
|
||||
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
||||
|
||||
aug[0] = Strings::ToUnsignedInt(row[4]);
|
||||
aug[1] = Strings::ToUnsignedInt(row[5]);
|
||||
aug[2] = Strings::ToUnsignedInt(row[6]);
|
||||
aug[3] = Strings::ToUnsignedInt(row[7]);
|
||||
aug[4] = Strings::ToUnsignedInt(row[8]);
|
||||
aug[5] = Strings::ToUnsignedInt(row[9]);
|
||||
|
||||
const bool instnodrop = (row[10] && static_cast<uint16>(Strings::ToUnsignedInt(row[10])));
|
||||
|
||||
const uint32 ornament_icon = Strings::ToUnsignedInt(row[12]);
|
||||
const uint32 ornament_idfile = Strings::ToUnsignedInt(row[13]);
|
||||
uint32 ornament_hero_model = Strings::ToUnsignedInt(row[14]);
|
||||
|
||||
const EQ::ItemData *item = GetItem(item_id);
|
||||
|
||||
auto *item = GetItem(item_id);
|
||||
if (!item) {
|
||||
LogError("Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]", char_id, item_id,
|
||||
slot_id);
|
||||
LogError(
|
||||
"Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]",
|
||||
char_id,
|
||||
item_id,
|
||||
slot_id
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr)
|
||||
auto *inst = CreateBaseItem(item, charges);
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (row[11]) {
|
||||
std::string data_str(row[11]);
|
||||
inst->SetCustomDataString(data_str);
|
||||
if (!row.custom_data.empty()) {
|
||||
inst->SetCustomDataString(row.custom_data);
|
||||
}
|
||||
|
||||
inst->SetOrnamentIcon(ornament_icon);
|
||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
||||
|
||||
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END))
|
||||
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <=
|
||||
EQ::invslot::EQUIPMENT_END)) {
|
||||
inst->SetAttuned(true);
|
||||
}
|
||||
|
||||
if (color > 0)
|
||||
if (color > 0) {
|
||||
inst->SetColor(color);
|
||||
}
|
||||
|
||||
if (charges == 0x7FFF)
|
||||
if (charges == 0x7FFF) {
|
||||
inst->SetCharges(-1);
|
||||
else if (charges == 0 && inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable.
|
||||
}
|
||||
else if (charges == 0 && inst->IsStackable()) {
|
||||
// Stackable items need a minimum charge of 1 remain moveable.
|
||||
inst->SetCharges(1);
|
||||
else
|
||||
}
|
||||
else {
|
||||
inst->SetCharges(charges);
|
||||
}
|
||||
|
||||
if (item->RecastDelay) {
|
||||
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
|
||||
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
||||
} else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
||||
}
|
||||
else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
||||
inst->SetRecastTimestamp(timestamps.at(item->ID));
|
||||
}
|
||||
else {
|
||||
@@ -767,35 +779,50 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
|
||||
if (item->IsClassCommon()) {
|
||||
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
||||
if (aug[i])
|
||||
if (aug[i]) {
|
||||
inst->PutAugment(this, i, aug[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16 put_slot_id;
|
||||
if (slot_id >= 8000 && slot_id <= 8999) {
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
} else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||
}
|
||||
else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||
// Admins: please report any occurrences of this error
|
||||
LogError("Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
||||
char_id, item_id, slot_id);
|
||||
LogError(
|
||||
"Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
||||
char_id,
|
||||
item_id,
|
||||
slot_id
|
||||
);
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||
}
|
||||
|
||||
row.guid = inst->GetSerialNumber();
|
||||
queue.push_back(row);
|
||||
|
||||
safe_delete(inst);
|
||||
|
||||
// Save ptr to item in inventory
|
||||
if (put_slot_id == INVALID_INDEX) {
|
||||
LogError("Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
||||
char_id, item_id, slot_id);
|
||||
LogError(
|
||||
"Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
||||
char_id,
|
||||
item_id,
|
||||
slot_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_conflict) {
|
||||
const std::string& char_name = GetCharName(char_id);
|
||||
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||
const std::string &char_name = GetCharName(char_id);
|
||||
LogError(
|
||||
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||
char_name,
|
||||
char_id,
|
||||
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
||||
@@ -803,6 +830,12 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
);
|
||||
}
|
||||
|
||||
if (!queue.empty()) {
|
||||
InventoryRepository::ReplaceMany(*this, queue);
|
||||
}
|
||||
|
||||
EQ::ItemInstance::ClearGUIDMap();
|
||||
|
||||
// Retrieve shared inventory
|
||||
return GetSharedBank(char_id, inv, true);
|
||||
}
|
||||
@@ -1359,30 +1392,28 @@ const EQ::ItemData* SharedDatabase::IterateItems(uint32* id) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string SharedDatabase::GetBook(const char *txtfile, int16 *language)
|
||||
Book_Struct SharedDatabase::GetBook(const std::string& text_file)
|
||||
{
|
||||
char txtfile2[20];
|
||||
std::string txtout;
|
||||
strcpy(txtfile2, txtfile);
|
||||
const auto& l = BooksRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`name` = '{}'",
|
||||
Strings::Escape(text_file)
|
||||
)
|
||||
);
|
||||
|
||||
const std::string query = StringFormat("SELECT txtfile, language FROM books WHERE name = '%s'", txtfile2);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
txtout.assign(" ",1);
|
||||
return txtout;
|
||||
Book_Struct b;
|
||||
|
||||
if (l.empty()) {
|
||||
return b;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
LogError("No book to send, ({})", txtfile);
|
||||
txtout.assign(" ",1);
|
||||
return txtout;
|
||||
}
|
||||
const auto& e = l.front();
|
||||
|
||||
auto& row = results.begin();
|
||||
txtout.assign(row[0],strlen(row[0]));
|
||||
*language = static_cast<int16>(Strings::ToInt(row[1]));
|
||||
b.language = e.language;
|
||||
b.text = e.txtfile;
|
||||
|
||||
return txtout;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Create appropriate EQ::ItemInstance class
|
||||
|
||||
+8
-3
@@ -41,8 +41,7 @@ struct NPCFactionList;
|
||||
struct FactionAssociations;
|
||||
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace EQ {
|
||||
|
||||
struct ItemData;
|
||||
class ItemInstance;
|
||||
@@ -50,6 +49,12 @@ namespace EQ
|
||||
class MemoryMappedFile;
|
||||
}
|
||||
|
||||
struct Book_Struct
|
||||
{
|
||||
uint8 language;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
/*
|
||||
This object is inherited by world and zone's DB object,
|
||||
and is mainly here to facilitate shared memory, and other
|
||||
@@ -114,7 +119,7 @@ public:
|
||||
int admin
|
||||
);
|
||||
|
||||
std::string GetBook(const char *txtfile, int16 *language);
|
||||
Book_Struct GetBook(const std::string& text_file);
|
||||
|
||||
/**
|
||||
* items
|
||||
|
||||
+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
-19
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +249,6 @@ const std::vector<EQ::skills::SkillType>& EQ::skills::GetExtraDamageSkills()
|
||||
EQ::skills::SkillFlyingKick,
|
||||
EQ::skills::SkillKick,
|
||||
EQ::skills::SkillRoundKick,
|
||||
EQ::skills::SkillRoundKick,
|
||||
EQ::skills::SkillTigerClaw,
|
||||
EQ::skills::SkillFrenzy
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
@@ -2315,3 +2325,108 @@ bool IsCastNotStandingSpell(uint16 spell_id) {
|
||||
*/
|
||||
return spells[spell_id].cast_not_standing;
|
||||
}
|
||||
|
||||
bool IsAegolismSpell(uint16 spell_id) {
|
||||
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool has_max_hp = false;
|
||||
bool has_current_hp = false;
|
||||
bool has_ac = false;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||
|
||||
if (i == 0 && spells[spell_id].effect_id[i] != SE_StackingCommand_Block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i == 1 && spells[spell_id].effect_id[i] == SE_TotalHP) {
|
||||
has_max_hp = true;
|
||||
}
|
||||
|
||||
if (i == 2 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
|
||||
has_current_hp = true;
|
||||
}
|
||||
|
||||
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
|
||||
has_ac = true;
|
||||
}
|
||||
|
||||
if (i == 4 && spells[spell_id].effect_id[i] != SE_StackingCommand_Overwrite) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_max_hp && has_current_hp && has_ac) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool AegolismStackingIsSymbolSpell(uint16 spell_id) {
|
||||
|
||||
/*
|
||||
This is hardcoded to be specific to the type of HP buffs that are removed if a mob has an Aegolism buff.
|
||||
*/
|
||||
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool has_max_hp = false;
|
||||
bool has_current_hp = false;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||
|
||||
if ((i < 2 && spells[spell_id].effect_id[i] != SE_CHA) ||
|
||||
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
|
||||
return 0;;
|
||||
}
|
||||
|
||||
if (i == 2 && spells[spell_id].effect_id[i] == SE_TotalHP) {
|
||||
has_max_hp = true;
|
||||
}
|
||||
|
||||
if (i == 3 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
|
||||
has_current_hp = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_max_hp && has_current_hp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AegolismStackingIsArmorClassSpell(uint16 spell_id) {
|
||||
/*
|
||||
This is hardcoded to be specific to the type of AC buffs that are removed if a mob has an Aegolism buff.
|
||||
*/
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool has_ac = false;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||
|
||||
if ((i < 3 && spells[spell_id].effect_id[i] != SE_CHA) ||
|
||||
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
|
||||
has_ac = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_ac) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -1624,5 +1625,8 @@ bool IsSpellUsableInThisZoneType(uint16 spell_id, uint8 zone_type);
|
||||
const char *GetSpellName(uint16 spell_id);
|
||||
int GetSpellStatValue(uint16 spell_id, const char* stat_identifier, uint8 slot = 0);
|
||||
bool IsCastRestrictedSpell(uint16 spell_id);
|
||||
bool IsAegolismSpell(uint16 spell_id);
|
||||
bool AegolismStackingIsSymbolSpell(uint16 spell_id);
|
||||
bool AegolismStackingIsArmorClassSpell(uint16 spell_id);
|
||||
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.51.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.57.0-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,8 +42,8 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9280
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9284
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -224,6 +224,23 @@ void Client::Handle_Login(const char *data, unsigned int size)
|
||||
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
|
||||
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
|
||||
|
||||
#ifdef LSPX
|
||||
// if user updated their password on the login server, update it here by validating their credentials with the login server
|
||||
if (!result && db_loginserver == "eqemu") {
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(user, cred);
|
||||
if (account_id > 0) {
|
||||
auto encryption_mode = server.options.GetEncryptionMode();
|
||||
server.db->UpdateLoginserverAccountPasswordHash(
|
||||
user,
|
||||
db_loginserver,
|
||||
eqcrypt_hash(user, cred, encryption_mode)
|
||||
);
|
||||
LogInfo("Updating eqemu account [{}] password hash", account_id);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LogDebug("Success [{0}]", (result ? "true" : "false"));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -138,6 +138,13 @@ public:
|
||||
*/
|
||||
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
|
||||
|
||||
/**
|
||||
* Gets the client version
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
LSClientVersion GetClientVersion() const { return m_client_version; }
|
||||
|
||||
/**
|
||||
* Gets the connection for this client
|
||||
*
|
||||
|
||||
@@ -88,6 +88,46 @@ ClientManager::ClientManager()
|
||||
clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
int larion_port = server.config.GetVariableInt("client_configuration", "larion_port", 15900);
|
||||
|
||||
EQStreamManagerInterfaceOptions larion_opts(larion_port, false, false);
|
||||
|
||||
larion_stream = new EQ::Net::EQStreamManager(larion_opts);
|
||||
larion_ops = new RegularOpcodeManager;
|
||||
|
||||
opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetServerPath(),
|
||||
server.config.GetVariableString(
|
||||
"client_configuration",
|
||||
"larion_opcodes",
|
||||
"login_opcodes.conf"
|
||||
)
|
||||
);
|
||||
|
||||
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
|
||||
server.config.GetVariableString("client_configuration", "larion_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
larion_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Larion client connection from [{0}:{1}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&larion_ops);
|
||||
Client* c = new Client(stream, cv_larion);
|
||||
clients.push_back(c);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ClientManager::~ClientManager()
|
||||
|
||||
@@ -55,6 +55,8 @@ private:
|
||||
EQ::Net::EQStreamManager *titanium_stream;
|
||||
OpcodeManager *sod_ops;
|
||||
EQ::Net::EQStreamManager *sod_stream;
|
||||
OpcodeManager *larion_ops;
|
||||
EQ::Net::EQStreamManager* larion_stream;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,7 +83,8 @@ struct PlayEverquestResponse_Struct {
|
||||
|
||||
enum LSClientVersion {
|
||||
cv_titanium,
|
||||
cv_sod
|
||||
cv_sod,
|
||||
cv_larion
|
||||
};
|
||||
|
||||
enum LSClientStatus {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#EQEmu Public Login Server OPCodes
|
||||
OP_SessionReady=0x0001
|
||||
OP_Login=0x0002
|
||||
OP_ServerListRequest=0x0004
|
||||
OP_PlayEverquestRequest=0x000d
|
||||
OP_PlayEverquestResponse=0x0022
|
||||
OP_ChatMessage=0x0017
|
||||
OP_LoginAccepted=0x0018
|
||||
OP_ServerListResponse=0x0019
|
||||
OP_Poll=0x0029
|
||||
OP_EnterChat=0x000f
|
||||
OP_PollResponse=0x0011
|
||||
OP_SystemFingerprint=0x0016
|
||||
OP_ExpansionList=0x0030
|
||||
@@ -137,7 +137,7 @@ std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Clien
|
||||
use_local_ip ? "Local" : "Remote"
|
||||
);
|
||||
|
||||
world_server->SerializeForClientServerList(buf, use_local_ip);
|
||||
world_server->SerializeForClientServerList(buf, use_local_ip, client->GetClientVersion());
|
||||
}
|
||||
|
||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
||||
|
||||
@@ -977,7 +977,7 @@ bool WorldServer::ValidateWorldServerAdminLogin(
|
||||
return false;
|
||||
}
|
||||
|
||||
void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_local_ip) const
|
||||
void WorldServer::SerializeForClientServerList(SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const
|
||||
{
|
||||
// see LoginClientServerData_Struct
|
||||
if (use_local_ip) {
|
||||
@@ -987,19 +987,31 @@ void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_lo
|
||||
out.WriteString(GetRemoteIP());
|
||||
}
|
||||
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
case LS::ServerType::Preferred:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Preferred);
|
||||
break;
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
if (version == cv_larion) {
|
||||
out.WriteUInt32(9000);
|
||||
}
|
||||
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
case LS::ServerType::Preferred:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Preferred);
|
||||
break;
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
}
|
||||
if (version == cv_larion) {
|
||||
auto server_id = GetServerId();
|
||||
//if this is 0, the client will not show the server in the list
|
||||
out.WriteUInt32(1);
|
||||
out.WriteUInt32(server_id);
|
||||
}
|
||||
else {
|
||||
out.WriteUInt32(GetServerId());
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetServerId());
|
||||
out.WriteString(GetServerLongName());
|
||||
out.WriteString("us"); // country code
|
||||
out.WriteString("en"); // language code
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "../common/packet_dump.h"
|
||||
#include "database.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include "login_types.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -149,7 +150,7 @@ public:
|
||||
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
|
||||
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
|
||||
|
||||
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip) const;
|
||||
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.51.0",
|
||||
"version": "22.57.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -433,6 +433,7 @@ OP_TraderShop=0x31df
|
||||
OP_TraderBulkSend=0x6a96
|
||||
OP_Trader=0x4ef5
|
||||
OP_Barter=0x243a
|
||||
OP_BuyerItems=0x1a6a
|
||||
OP_TraderBuy=0x0000
|
||||
OP_ShopItem=0x0000
|
||||
OP_BazaarInspect=0x0000
|
||||
|
||||
+25
-35
@@ -282,88 +282,78 @@ 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) {
|
||||
++iter;
|
||||
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;
|
||||
}
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+26
-8
@@ -315,6 +315,13 @@ void LoginServer::ProcessLSFatalError(uint16_t opcode, EQ::Net::Packet &p)
|
||||
error,
|
||||
reason
|
||||
);
|
||||
|
||||
if (m_legacy_client) {
|
||||
m_legacy_client.release();
|
||||
}
|
||||
else if (m_client) {
|
||||
m_client.release();
|
||||
}
|
||||
}
|
||||
|
||||
void LoginServer::ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p)
|
||||
@@ -598,6 +605,11 @@ bool LoginServer::Connect()
|
||||
|
||||
void LoginServer::SendInfo()
|
||||
{
|
||||
if (m_client == nullptr && m_legacy_client == nullptr) {
|
||||
LogDebug("No client to send info to loginserver");
|
||||
return;
|
||||
}
|
||||
|
||||
const WorldConfig *Config = WorldConfig::get();
|
||||
|
||||
auto pack = new ServerPacket;
|
||||
@@ -643,6 +655,11 @@ void LoginServer::SendInfo()
|
||||
|
||||
void LoginServer::SendStatus()
|
||||
{
|
||||
if (m_client == nullptr && m_legacy_client == nullptr) {
|
||||
LogDebug("No client to send status to loginserver");
|
||||
return;
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket;
|
||||
pack->opcode = ServerOP_LSStatus;
|
||||
pack->size = sizeof(ServerLSStatus_Struct);
|
||||
@@ -671,20 +688,21 @@ void LoginServer::SendStatus()
|
||||
*/
|
||||
void LoginServer::SendPacket(ServerPacket *pack)
|
||||
{
|
||||
if (m_is_legacy) {
|
||||
if (m_legacy_client) {
|
||||
m_legacy_client->SendPacket(pack);
|
||||
}
|
||||
if (m_legacy_client) {
|
||||
m_legacy_client->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
if (m_client) {
|
||||
m_client->SendPacket(pack);
|
||||
}
|
||||
else if (m_client) {
|
||||
m_client->SendPacket(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void LoginServer::SendAccountUpdate(ServerPacket *pack)
|
||||
{
|
||||
if (m_client == nullptr && m_legacy_client == nullptr) {
|
||||
LogDebug("No client to send account update to loginserver");
|
||||
return;
|
||||
}
|
||||
|
||||
auto *ls_account_update = (ServerLSAccountUpdate_Struct *) pack->pBuffer;
|
||||
if (CanUpdate()) {
|
||||
LogInfo(
|
||||
|
||||
@@ -289,6 +289,10 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
||||
LogInfo("Clearing inventory snapshots");
|
||||
database.ClearInvSnapshots();
|
||||
LogInfo("Loading items");
|
||||
LogInfo("Clearing trader table details");
|
||||
database.ClearTraderDetails();
|
||||
database.ClearBuyerDetails();
|
||||
LogInfo("Clearing buyer table details");
|
||||
|
||||
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;
|
||||
|
||||
+31
-1
@@ -1742,7 +1742,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacketToBootedZones(pack);
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_BazaarPurchase: {
|
||||
@@ -1753,9 +1752,40 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
"ServerOP_BazaarPurchase",
|
||||
in->trader_buy_struct.trader_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(Zones::BAZAAR, pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_BuyerMessaging: {
|
||||
auto in = (BuyerMessaging_Struct *)pack->pBuffer;
|
||||
switch (in->action) {
|
||||
case Barter_AddToBarterWindow:
|
||||
case Barter_RemoveFromBarterWindow: {
|
||||
if (in->buyer_id <= 0) {
|
||||
LogTrading("World Message <red>[{}] received with invalid buyer_id <red>[{}]",
|
||||
"ServerOP_BecomeBuyer",
|
||||
in->buyer_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacketToBootedZones(pack);
|
||||
break;
|
||||
}
|
||||
case Barter_SellItem: {
|
||||
zoneserver_list.SendPacket(Zones::BAZAAR, pack);
|
||||
break;
|
||||
}
|
||||
case Barter_FailedTransaction:
|
||||
case Barter_BuyerTransactionComplete: {
|
||||
zoneserver_list.SendPacket(in->zone_id, pack);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
||||
|
||||
@@ -65,6 +65,7 @@ SET(zone_sources
|
||||
lua_inventory.cpp
|
||||
lua_item.cpp
|
||||
lua_iteminst.cpp
|
||||
lua_merc.cpp
|
||||
lua_mob.cpp
|
||||
lua_mod.cpp
|
||||
lua_npc.cpp
|
||||
@@ -115,6 +116,7 @@ SET(zone_sources
|
||||
perl_groups.cpp
|
||||
perl_hateentry.cpp
|
||||
perl_inventory.cpp
|
||||
perl_merc.cpp
|
||||
perl_mob.cpp
|
||||
perl_npc.cpp
|
||||
perl_object.cpp
|
||||
@@ -224,6 +226,7 @@ SET(zone_headers
|
||||
lua_inventory.h
|
||||
lua_item.h
|
||||
lua_iteminst.h
|
||||
lua_merc.h
|
||||
lua_mob.h
|
||||
lua_mod.h
|
||||
lua_npc.h
|
||||
|
||||
+8
-4
@@ -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;
|
||||
@@ -2185,7 +2185,7 @@ void Client::AutoGrantAAPoints() {
|
||||
SendAlternateAdvancementStats();
|
||||
}
|
||||
|
||||
void Client::GrantAllAAPoints(uint8 unlock_level)
|
||||
void Client::GrantAllAAPoints(uint8 unlock_level, bool skip_grant_only)
|
||||
{
|
||||
//iterate through every AA
|
||||
for (auto& aa : zone->aa_abilities) {
|
||||
@@ -2195,6 +2195,10 @@ void Client::GrantAllAAPoints(uint8 unlock_level)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ability->grant_only && skip_grant_only) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8 level = unlock_level ? unlock_level : GetLevel();
|
||||
|
||||
AA::Rank* rank = ability->first;
|
||||
|
||||
+104
-16
@@ -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;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,25 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
}
|
||||
|
||||
// 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)))) {
|
||||
// Frustrated mobs (all rooted up with no one to kill)
|
||||
// will engage without PROX_AGGRO ability if someone new is close now.
|
||||
|
||||
const bool is_frustrated = IsRooted() && !CombatRange(target);
|
||||
|
||||
if (
|
||||
!is_frustrated &&
|
||||
IsEngaged() &&
|
||||
(
|
||||
(
|
||||
!GetSpecialAbility(SpecialAbility::ProximityAggro) &&
|
||||
GetBodyType() != BodyType::Undead
|
||||
) ||
|
||||
(
|
||||
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 +514,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
RuleB(Aggro, UseLevelAggro) &&
|
||||
(
|
||||
GetLevel() >= RuleI(Aggro, MinAggroLevel) ||
|
||||
GetBodyType() == BT_Undead ||
|
||||
GetBodyType() == BodyType::Undead ||
|
||||
AlwaysAggro() ||
|
||||
(
|
||||
mob->IsClient() &&
|
||||
@@ -524,7 +542,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() ||
|
||||
(
|
||||
@@ -564,6 +582,76 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int EntityList::FleeAllyCount(Mob* attacker, Mob* skipped)
|
||||
{
|
||||
// Return a list of how many NPCs of the same faction or race are within aggro range of the given exclude Mob.
|
||||
if (!attacker) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (const auto& e : npc_list) {
|
||||
NPC* n = e.second;
|
||||
if (!n || n == skipped) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float aggro_range = n->GetAggroRange();
|
||||
const float assist_range = n->GetAssistRange();
|
||||
|
||||
if (assist_range > aggro_range) {
|
||||
aggro_range = assist_range;
|
||||
}
|
||||
|
||||
// Square it because we will be using DistNoRoot
|
||||
aggro_range *= aggro_range;
|
||||
|
||||
if (DistanceSquared(n->GetPosition(), skipped->GetPosition()) > aggro_range) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& excluded = Strings::Split(RuleS(Aggro, ExcludedFleeAllyFactionIDs));
|
||||
|
||||
const auto& f = std::find_if(
|
||||
excluded.begin(),
|
||||
excluded.end(),
|
||||
[&](std::string x) {
|
||||
return Strings::ToUnsignedInt(x) == skipped->GetPrimaryFaction();
|
||||
}
|
||||
);
|
||||
|
||||
const bool is_excluded = f != excluded.end();
|
||||
|
||||
// If exclude doesn't have a faction, check for buddies based on race.
|
||||
// Also exclude common factions such as noob monsters, indifferent, kos, kos animal
|
||||
if (!is_excluded) {
|
||||
if (n->GetPrimaryFaction() != skipped->GetPrimaryFaction()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (n->GetBaseRace() != skipped->GetBaseRace() || n->IsCharmedPet()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LogFleeDetail(
|
||||
"[{}] on faction [{}] with aggro_range [{}] is at [{}], [{}], [{}] and will count as an ally for [{}]",
|
||||
n->GetName(),
|
||||
n->GetPrimaryFaction(),
|
||||
aggro_range,
|
||||
n->GetX(),
|
||||
n->GetY(),
|
||||
n->GetZ(),
|
||||
skipped->GetName()
|
||||
);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int EntityList::GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con)
|
||||
{
|
||||
// Return a list of how many non-feared, non-mezzed, non-green mobs, within aggro range, hate *attacker
|
||||
@@ -634,19 +722,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 +759,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 +1141,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
|
||||
}
|
||||
|
||||
|
||||
@@ -651,7 +651,6 @@ Json::Value ApiGetClientListDetail(EQ::Net::WebsocketServerConnection *connectio
|
||||
row["base_wis"] = client->GetBaseWIS();
|
||||
row["become_npc_level"] = client->GetBecomeNPCLevel();
|
||||
row["boat_id"] = client->GetBoatID();
|
||||
row["buyer_welcome_message"] = client->GetBuyerWelcomeMessage();
|
||||
row["calc_atk"] = client->CalcATK();
|
||||
row["calc_base_mana"] = client->CalcBaseMana();
|
||||
row["calc_current_weight"] = client->CalcCurrentWeight();
|
||||
|
||||
+394
-329
File diff suppressed because it is too large
Load Diff
+7
-12
@@ -72,7 +72,7 @@ Mob *Aura::GetOwner()
|
||||
// not 100% sure how this one should work and PVP affects ...
|
||||
void Aura::ProcessOnAllFriendlies(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this, distance);
|
||||
auto &mob_list = GetCloseMobList(distance);
|
||||
std::set<int> delayed_remove;
|
||||
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||
|
||||
@@ -127,7 +127,7 @@ void Aura::ProcessOnAllFriendlies(Mob *owner)
|
||||
|
||||
void Aura::ProcessOnAllGroupMembers(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this, distance);
|
||||
auto &mob_list = GetCloseMobList(distance);
|
||||
std::set<int> delayed_remove;
|
||||
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||
|
||||
@@ -369,7 +369,7 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner)
|
||||
|
||||
void Aura::ProcessOnGroupMembersPets(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this,distance);
|
||||
auto &mob_list = GetCloseMobList(distance);
|
||||
std::set<int> delayed_remove;
|
||||
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||
// This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura)
|
||||
@@ -576,7 +576,7 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner)
|
||||
|
||||
void Aura::ProcessTotem(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this, distance);
|
||||
auto &mob_list = GetCloseMobList(distance);
|
||||
std::set<int> delayed_remove;
|
||||
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||
|
||||
@@ -634,9 +634,7 @@ void Aura::ProcessTotem(Mob *owner)
|
||||
|
||||
void Aura::ProcessEnterTrap(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this, distance);
|
||||
|
||||
for (auto &e : mob_list) {
|
||||
for (auto &e : GetCloseMobList(distance)) {
|
||||
auto mob = e.second;
|
||||
if (!mob) {
|
||||
continue;
|
||||
@@ -656,9 +654,7 @@ void Aura::ProcessEnterTrap(Mob *owner)
|
||||
|
||||
void Aura::ProcessExitTrap(Mob *owner)
|
||||
{
|
||||
auto &mob_list = entity_list.GetCloseMobList(this, distance);
|
||||
|
||||
for (auto &e : mob_list) {
|
||||
for (auto &e : GetCloseMobList(distance)) {
|
||||
auto mob = e.second;
|
||||
if (!mob) {
|
||||
continue;
|
||||
@@ -689,8 +685,7 @@ void Aura::ProcessExitTrap(Mob *owner)
|
||||
// and hard to reason about
|
||||
void Aura::ProcessSpawns()
|
||||
{
|
||||
const auto &clients = entity_list.GetCloseMobList(this, distance);
|
||||
for (auto &e : clients) {
|
||||
for (auto &e: GetCloseMobList(distance)) {
|
||||
if (!e.second) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+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
-13
@@ -182,14 +182,20 @@ void Mob::CalcItemBonuses(StatBonuses* b) {
|
||||
SetDualWeaponsEquipped(true);
|
||||
}
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
for (i = EQ::invslot::TRIBUTE_BEGIN; i <= EQ::invslot::TRIBUTE_END; i++) {
|
||||
const EQ::ItemInstance* inst = m_inv[i];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->GetPP().tribute_active) {
|
||||
for (auto const &t: CastToClient()->GetPP().tributes) {
|
||||
auto item_id = CastToClient()->LookupTributeItemID(t.tribute, t.tier);
|
||||
if (item_id) {
|
||||
const EQ::ItemInstance *inst = database.CreateItem(item_id);
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItemBonuses(inst, b, false, true);
|
||||
AddItemBonuses(inst, b, false, true);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,8 +1445,8 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
|
||||
case SE_SlayUndead: {
|
||||
if (newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < base_value) {
|
||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = base_value; // Rate
|
||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = limit_value; // Damage Modifier
|
||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = base_value; // Rate
|
||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Damage Modifier
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2220,7 +2226,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)
|
||||
@@ -2438,6 +2444,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;
|
||||
}
|
||||
|
||||
@@ -3356,7 +3366,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
|
||||
case SE_Blind:
|
||||
if (RuleB(Combat, AllowRaidTargetBlind) && IsRaidTarget()) { // do not blind raid targets
|
||||
if (!RuleB(Combat, AllowRaidTargetBlind) && IsRaidTarget()) { // do not blind raid targets
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3585,8 +3595,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_SlayUndead: {
|
||||
if (new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < effect_value) {
|
||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = effect_value; // Rate
|
||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = limit_value; // Damage Modifier
|
||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Rate
|
||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value; // Damage Modifier
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+20
-34
@@ -204,7 +204,7 @@ Bot::Bot(
|
||||
);
|
||||
}
|
||||
|
||||
SetTaunting((GetClass() == Class::Warrior || GetClass() == Class::Paladin || GetClass() == Class::ShadowKnight) && (GetBotStance() == EQ::constants::stanceAggressive));
|
||||
SetTaunting((GetClass() == Class::Warrior || GetClass() == Class::Paladin || GetClass() == Class::ShadowKnight) && (GetBotStance() == Stance::Aggressive));
|
||||
SetPauseAI(false);
|
||||
|
||||
m_auto_defend_timer.Disable();
|
||||
@@ -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;
|
||||
@@ -1578,17 +1578,7 @@ bool Bot::Process()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mob_close_scan_timer.Check()) {
|
||||
LogAIScanCloseDetail(
|
||||
"is_moving [{}] bot [{}] timer [{}]",
|
||||
moving ? "true" : "false",
|
||||
GetCleanName(),
|
||||
mob_close_scan_timer.GetDuration()
|
||||
);
|
||||
|
||||
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
|
||||
}
|
||||
|
||||
ScanCloseMobProcess();
|
||||
SpellProcess();
|
||||
|
||||
if (tic_timer.Check()) {
|
||||
@@ -1899,8 +1889,8 @@ void Bot::AI_Process()
|
||||
#define NOT_GUARDING (!GetGuardFlag())
|
||||
#define HOLDING (GetHoldFlag())
|
||||
#define NOT_HOLDING (!GetHoldFlag())
|
||||
#define PASSIVE (GetBotStance() == EQ::constants::stancePassive)
|
||||
#define NOT_PASSIVE (GetBotStance() != EQ::constants::stancePassive)
|
||||
#define PASSIVE (GetBotStance() == Stance::Passive)
|
||||
#define NOT_PASSIVE (GetBotStance() != Stance::Passive)
|
||||
|
||||
Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr);
|
||||
|
||||
@@ -2418,14 +2408,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);
|
||||
}
|
||||
}
|
||||
@@ -2978,7 +2968,7 @@ void Bot::SetOwnerTarget(Client* bot_owner) {
|
||||
if (NOT_HOLDING && NOT_PASSIVE) {
|
||||
|
||||
auto attack_target = bot_owner->GetTarget();
|
||||
if (attack_target) {
|
||||
if (attack_target && HasBotAttackFlag(attack_target)) {
|
||||
|
||||
InterruptSpell();
|
||||
WipeHateList();
|
||||
@@ -5481,13 +5471,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 +5625,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) {
|
||||
@@ -6912,16 +6902,16 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
|
||||
if ((botCasterClass == Class::Paladin || botCasterClass == Class::Beastlord || botCasterClass == Class::Ranger) && (caster->HasGroup() || caster->IsRaidGrouped())) {
|
||||
float hpRatioToHeal = 25.0f;
|
||||
switch(caster->GetBotStance()) {
|
||||
case EQ::constants::stanceReactive:
|
||||
case EQ::constants::stanceBalanced:
|
||||
case Stance::Reactive:
|
||||
case Stance::Balanced:
|
||||
hpRatioToHeal = 50.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBurn:
|
||||
case EQ::constants::stanceBurnAE:
|
||||
case Stance::Burn:
|
||||
case Stance::AEBurn:
|
||||
hpRatioToHeal = 20.0f;
|
||||
break;
|
||||
case EQ::constants::stanceAggressive:
|
||||
case EQ::constants::stanceEfficient:
|
||||
case Stance::Aggressive:
|
||||
case Stance::Efficient:
|
||||
default:
|
||||
hpRatioToHeal = 25.0f;
|
||||
break;
|
||||
@@ -7655,11 +7645,7 @@ bool Bot::HasOrMayGetAggro() {
|
||||
}
|
||||
|
||||
void Bot::SetDefaultBotStance() {
|
||||
EQ::constants::StanceType defaultStance = EQ::constants::stanceBalanced;
|
||||
if (GetClass() == Class::Warrior)
|
||||
defaultStance = EQ::constants::stanceAggressive;
|
||||
|
||||
_botStance = defaultStance;
|
||||
_botStance = GetClass() == Class::Warrior ? Stance::Aggressive : Stance::Balanced;
|
||||
}
|
||||
|
||||
void Bot::BotGroupSay(Mob* speaker, const char* msg, ...) {
|
||||
@@ -9233,4 +9219,4 @@ void Bot::DoItemClick(const EQ::ItemData *item, uint16 slot_id)
|
||||
|
||||
}
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][Stance::AEBurn][cntHSND] = { 0 };
|
||||
|
||||
+4
-9
@@ -484,7 +484,7 @@ public:
|
||||
bool IsOfClientBotMerc() const override { return true; }
|
||||
|
||||
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
|
||||
EQ::constants::StanceType GetBotStance() { return _botStance; }
|
||||
uint8 GetBotStance() { return _botStance; }
|
||||
uint8 GetChanceToCastBySpellType(uint32 spellType);
|
||||
bool GetBotEnforceSpellSetting() { return m_enforce_spell_settings; }
|
||||
float GetBotCasterMaxRange(float melee_distance_max);
|
||||
@@ -605,12 +605,7 @@ public:
|
||||
void SetPetChooser(bool p) { _petChooser = p; }
|
||||
void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; }
|
||||
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == Class::Ranger ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
||||
void SetBotStance(EQ::constants::StanceType botStance) {
|
||||
if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE)
|
||||
_botStance = botStance;
|
||||
else
|
||||
_botStance = EQ::constants::stancePassive;
|
||||
}
|
||||
void SetBotStance(uint8 stance_id) { _botStance = Stance::IsValid(stance_id) ? stance_id : Stance::Passive; }
|
||||
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
|
||||
uint32 GetSpellRecastTimer(uint16 spell_id = 0);
|
||||
bool CheckSpellRecastTimer(uint16 spell_id = 0);
|
||||
@@ -753,7 +748,7 @@ public:
|
||||
//Raid additions
|
||||
Raid* p_raid_instance;
|
||||
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][Stance::AEBurn][cntHSND];
|
||||
|
||||
bool BotCastMez(Mob* tar, uint8 botLevel, bool checked_los, BotSpell& botSpell, Raid* raid);
|
||||
bool BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, Raid* raid);
|
||||
@@ -870,7 +865,7 @@ private:
|
||||
std::string _suffix;
|
||||
uint32 _lastZoneId;
|
||||
bool _rangerAutoWeaponSelect;
|
||||
EQ::constants::StanceType _botStance;
|
||||
uint8 _botStance;
|
||||
unsigned int RestRegenHP;
|
||||
unsigned int RestRegenMana;
|
||||
unsigned int RestRegenEndurance;
|
||||
|
||||
+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:
|
||||
|
||||
@@ -35,12 +35,17 @@ void bot_command_attack(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c->HasBotAttackFlag(target_mob)) {
|
||||
target_mob->SetBotAttackFlag(c->CharacterID());
|
||||
target_mob->bot_attack_flag_timer.Start(10000);
|
||||
}
|
||||
|
||||
size_t attacker_count = 0;
|
||||
Bot *first_attacker = nullptr;
|
||||
sbl.remove(nullptr);
|
||||
for (auto bot_iter : sbl) {
|
||||
|
||||
if (bot_iter->GetAppearance() != eaDead && bot_iter->GetBotStance() != EQ::constants::stancePassive) {
|
||||
if (bot_iter->GetAppearance() != eaDead && bot_iter->GetBotStance() != Stance::Passive) {
|
||||
|
||||
if (!first_attacker) {
|
||||
first_attacker = bot_iter;
|
||||
|
||||
+43
-21
@@ -198,7 +198,7 @@ void bot_command_clone(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
int clone_stance = EQ::constants::stancePassive;
|
||||
int clone_stance = Stance::Passive;
|
||||
if (!database.botdb.LoadStance(my_bot->GetBotID(), clone_stance)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
@@ -857,7 +857,7 @@ void bot_command_spawn(Client *c, const Seperator *sep)
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Usage: {} [bot_name]",
|
||||
"Usage: {} [bot_name] [optional: silent]",
|
||||
sep->arg[0]
|
||||
).c_str()
|
||||
);
|
||||
@@ -1045,9 +1045,17 @@ void bot_command_spawn(Client *c, const Seperator *sep)
|
||||
message_index = VALIDATECLASSID(my_bot->GetClass());
|
||||
}
|
||||
|
||||
if (c->GetBotOption(Client::booSpawnMessageSay)) {
|
||||
std::string silent_confirm = sep->arg[2];
|
||||
bool silentTell = false;
|
||||
|
||||
if (!silent_confirm.compare("silent")) {
|
||||
silentTell = true;
|
||||
}
|
||||
|
||||
if (!silentTell && c->GetBotOption(Client::booSpawnMessageSay)) {
|
||||
Bot::BotGroupSay(my_bot, bot_spawn_message[message_index].c_str());
|
||||
} else if (c->GetBotOption(Client::booSpawnMessageTell)) {
|
||||
}
|
||||
else if (!silentTell && c->GetBotOption(Client::booSpawnMessageTell)) {
|
||||
my_bot->OwnerMessage(bot_spawn_message[message_index]);
|
||||
}
|
||||
}
|
||||
@@ -1058,33 +1066,47 @@ void bot_command_stance(Client *c, const Seperator *sep)
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: %s [current | value: 1-9] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]);
|
||||
c->Message(Chat::White, "value: %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s)",
|
||||
EQ::constants::stancePassive, EQ::constants::GetStanceName(EQ::constants::stancePassive),
|
||||
EQ::constants::stanceBalanced, EQ::constants::GetStanceName(EQ::constants::stanceBalanced),
|
||||
EQ::constants::stanceEfficient, EQ::constants::GetStanceName(EQ::constants::stanceEfficient),
|
||||
EQ::constants::stanceReactive, EQ::constants::GetStanceName(EQ::constants::stanceReactive),
|
||||
EQ::constants::stanceAggressive, EQ::constants::GetStanceName(EQ::constants::stanceAggressive),
|
||||
EQ::constants::stanceAssist, EQ::constants::GetStanceName(EQ::constants::stanceAssist),
|
||||
EQ::constants::stanceBurn, EQ::constants::GetStanceName(EQ::constants::stanceBurn),
|
||||
EQ::constants::stanceEfficient2, EQ::constants::GetStanceName(EQ::constants::stanceEfficient2),
|
||||
EQ::constants::stanceBurnAE, EQ::constants::GetStanceName(EQ::constants::stanceBurnAE)
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Value: {} ({}), {} ({}), {} ({}), {} ({}), {} ({}), {} ({}), {} ({}), {} ({}), {} ({})",
|
||||
Stance::Passive,
|
||||
Stance::GetName(Stance::Passive),
|
||||
Stance::Balanced,
|
||||
Stance::GetName(Stance::Balanced),
|
||||
Stance::Efficient,
|
||||
Stance::GetName(Stance::Efficient),
|
||||
Stance::Reactive,
|
||||
Stance::GetName(Stance::Reactive),
|
||||
Stance::Aggressive,
|
||||
Stance::GetName(Stance::Aggressive),
|
||||
Stance::Assist,
|
||||
Stance::GetName(Stance::Assist),
|
||||
Stance::Burn,
|
||||
Stance::GetName(Stance::Burn),
|
||||
Stance::Efficient2,
|
||||
Stance::GetName(Stance::Efficient2),
|
||||
Stance::AEBurn,
|
||||
Stance::GetName(Stance::AEBurn)
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName);
|
||||
|
||||
bool current_flag = false;
|
||||
auto bst = EQ::constants::stanceUnknown;
|
||||
uint8 bst = Stance::Unknown;
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "current"))
|
||||
current_flag = true;
|
||||
else if (sep->IsNumber(1)) {
|
||||
bst = (EQ::constants::StanceType)Strings::ToInt(sep->arg[1]);
|
||||
if (bst < EQ::constants::stanceUnknown || bst > EQ::constants::stanceBurnAE)
|
||||
bst = EQ::constants::stanceUnknown;
|
||||
bst = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[1]));
|
||||
if (!Stance::IsValid(bst)) {
|
||||
bst = Stance::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current_flag && bst == EQ::constants::stanceUnknown) {
|
||||
if (!current_flag && bst == Stance::Unknown) {
|
||||
c->Message(Chat::White, "A [current] argument or valid numeric [value] is required to use this command");
|
||||
return;
|
||||
}
|
||||
@@ -1106,8 +1128,8 @@ void bot_command_stance(Client *c, const Seperator *sep)
|
||||
bot_iter,
|
||||
fmt::format(
|
||||
"My current stance is {} ({}).",
|
||||
EQ::constants::GetStanceName(bot_iter->GetBotStance()),
|
||||
static_cast<int>(bot_iter->GetBotStance())
|
||||
Stance::GetName(bot_iter->GetBotStance()),
|
||||
bot_iter->GetBotStance()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ void bot_command_pull(Client *c, const Seperator *sep)
|
||||
Bot* bot_puller = nullptr;
|
||||
for (auto bot_iter : sbl) {
|
||||
|
||||
if (bot_iter->GetAppearance() == eaDead || bot_iter->GetBotStance() == EQ::constants::stancePassive) {
|
||||
if (bot_iter->GetAppearance() == eaDead || bot_iter->GetBotStance() == Stance::Passive) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ bool BotDatabase::LoadBotSpellCastingChances()
|
||||
if (
|
||||
e.spell_type_index >= Bot::SPELL_TYPE_COUNT ||
|
||||
!IsPlayerClass(e.class_id) ||
|
||||
e.stance_index >= EQ::constants::STANCE_TYPE_COUNT
|
||||
e.stance_index >= Stance::AEBurn
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -761,7 +761,7 @@ bool BotDatabase::LoadStance(Bot* b, bool& stance_flag)
|
||||
|
||||
auto e = l.front();
|
||||
|
||||
b->SetBotStance(static_cast<EQ::constants::StanceType>(e.stance_id));
|
||||
b->SetBotStance(e.stance_id);
|
||||
|
||||
stance_flag = true;
|
||||
|
||||
@@ -793,7 +793,7 @@ bool BotDatabase::SaveStance(Bot* b)
|
||||
database,
|
||||
BotStancesRepository::BotStances{
|
||||
.bot_id = b->GetBotID(),
|
||||
.stance_id = static_cast<uint8_t>(b->GetBotStance())
|
||||
.stance_id = b->GetBotStance()
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -828,7 +828,7 @@ bool BotDatabase::LoadTimers(Bot* b)
|
||||
BotTimer_Struct t{ };
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (t.timer_value < (Timer::GetCurrentTime() + t.recast_time)) {
|
||||
if (e.timer_value < (Timer::GetCurrentTime() + e.recast_time)) {
|
||||
t.timer_id = e.timer_id;
|
||||
t.timer_value = e.timer_value;
|
||||
t.recast_time = e.recast_time;
|
||||
@@ -2208,7 +2208,7 @@ uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_ind
|
||||
if (
|
||||
spell_type_index >= Bot::SPELL_TYPE_COUNT ||
|
||||
class_index >= Class::PLAYER_CLASS_COUNT ||
|
||||
stance_index >= EQ::constants::STANCE_TYPE_COUNT ||
|
||||
stance_index >= Stance::AEBurn ||
|
||||
conditional_index >= cntHSND
|
||||
) {
|
||||
return 0;
|
||||
|
||||
+3
-1
@@ -312,10 +312,12 @@ void Client::SpawnRaidBotsOnConnect(Raid* raid) {
|
||||
for (const auto& m: r_members) {
|
||||
if (strlen(m.member_name) != 0) {
|
||||
|
||||
for (const auto& b: bots_list) {
|
||||
for (const auto& b : bots_list) {
|
||||
if (strcmp(m.member_name, b.bot_name) == 0) {
|
||||
std::string buffer = "^spawn ";
|
||||
buffer.append(m.member_name);
|
||||
std::string silent = " silent";
|
||||
buffer.append(silent);
|
||||
bot_command_real_dispatch(this, buffer.c_str());
|
||||
auto bot = entity_list.GetBotByBotName(m.member_name);
|
||||
|
||||
|
||||
+46
-44
@@ -629,16 +629,16 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
float manaRatioToCast = 75.0f;
|
||||
|
||||
switch(GetBotStance()) {
|
||||
case EQ::constants::stanceEfficient:
|
||||
case Stance::Efficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBalanced:
|
||||
case EQ::constants::stanceAggressive:
|
||||
case Stance::Balanced:
|
||||
case Stance::Aggressive:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case EQ::constants::stanceReactive:
|
||||
case EQ::constants::stanceBurn:
|
||||
case EQ::constants::stanceBurnAE:
|
||||
case Stance::Reactive:
|
||||
case Stance::Burn:
|
||||
case Stance::AEBurn:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
default:
|
||||
@@ -746,18 +746,18 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
float manaRatioToCast = 75.0f;
|
||||
|
||||
switch(GetBotStance()) {
|
||||
case EQ::constants::stanceEfficient:
|
||||
case Stance::Efficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBalanced:
|
||||
case Stance::Balanced:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case EQ::constants::stanceReactive:
|
||||
case EQ::constants::stanceAggressive:
|
||||
case Stance::Reactive:
|
||||
case Stance::Aggressive:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBurn:
|
||||
case EQ::constants::stanceBurnAE:
|
||||
case Stance::Burn:
|
||||
case Stance::AEBurn:
|
||||
manaRatioToCast = 25.0f;
|
||||
break;
|
||||
default:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -924,16 +924,16 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
float manaRatioToCast = 75.0f;
|
||||
|
||||
switch (GetBotStance()) {
|
||||
case EQ::constants::stanceEfficient:
|
||||
case Stance::Efficient:
|
||||
manaRatioToCast = 90.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBalanced:
|
||||
case EQ::constants::stanceAggressive:
|
||||
case Stance::Balanced:
|
||||
case Stance::Aggressive:
|
||||
manaRatioToCast = 75.0f;
|
||||
break;
|
||||
case EQ::constants::stanceReactive:
|
||||
case EQ::constants::stanceBurn:
|
||||
case EQ::constants::stanceBurnAE:
|
||||
case Stance::Reactive:
|
||||
case Stance::Burn:
|
||||
case Stance::AEBurn:
|
||||
manaRatioToCast = 50.0f;
|
||||
break;
|
||||
default:
|
||||
@@ -1088,18 +1088,18 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
float hpRatioToCast = 0.0f;
|
||||
|
||||
switch (GetBotStance()) {
|
||||
case EQ::constants::stanceEfficient:
|
||||
case EQ::constants::stanceAggressive:
|
||||
case Stance::Efficient:
|
||||
case Stance::Aggressive:
|
||||
hpRatioToCast = isPrimaryHealer ? 90.0f : 50.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBalanced:
|
||||
case Stance::Balanced:
|
||||
hpRatioToCast = isPrimaryHealer ? 95.0f : 75.0f;
|
||||
break;
|
||||
case EQ::constants::stanceReactive:
|
||||
case Stance::Reactive:
|
||||
hpRatioToCast = isPrimaryHealer ? 100.0f : 90.0f;
|
||||
break;
|
||||
case EQ::constants::stanceBurn:
|
||||
case EQ::constants::stanceBurnAE:
|
||||
case Stance::Burn:
|
||||
case Stance::AEBurn:
|
||||
hpRatioToCast = isPrimaryHealer ? 75.0f : 25.0f;
|
||||
break;
|
||||
default:
|
||||
@@ -2939,11 +2939,12 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||
return 0;
|
||||
--class_index;
|
||||
|
||||
EQ::constants::StanceType stance_type = GetBotStance();
|
||||
if (stance_type < EQ::constants::stancePassive || stance_type > EQ::constants::stanceBurnAE)
|
||||
uint32 stance_id = GetBotStance();
|
||||
if (!Stance::IsValid(stance_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 stance_index = EQ::constants::ConvertStanceTypeToIndex(stance_type);
|
||||
uint8 stance_index = Stance::GetIndex(stance_id);
|
||||
uint8 type_index = nHSND;
|
||||
|
||||
if (HasGroup()) {
|
||||
@@ -3323,18 +3324,19 @@ DBbotspells_Struct* ZoneDatabase::GetBotSpells(uint32 bot_spell_id)
|
||||
if (!bse.empty()) {
|
||||
for (const auto& e : bse) {
|
||||
DBbotspells_entries_Struct entry;
|
||||
entry.spellid = e.spellid;
|
||||
entry.type = e.type;
|
||||
entry.minlevel = e.minlevel;
|
||||
entry.maxlevel = e.maxlevel;
|
||||
entry.manacost = e.manacost;
|
||||
entry.recast_delay = e.recast_delay;
|
||||
entry.priority = e.priority;
|
||||
entry.min_hp = e.min_hp;
|
||||
entry.max_hp = e.max_hp;
|
||||
entry.resist_adjust = e.resist_adjust;
|
||||
entry.bucket_name = e.bucket_name;
|
||||
entry.bucket_value = e.bucket_value;
|
||||
|
||||
entry.spellid = e.spell_id;
|
||||
entry.type = e.type;
|
||||
entry.minlevel = e.minlevel;
|
||||
entry.maxlevel = e.maxlevel;
|
||||
entry.manacost = e.manacost;
|
||||
entry.recast_delay = e.recast_delay;
|
||||
entry.priority = e.priority;
|
||||
entry.min_hp = e.min_hp;
|
||||
entry.max_hp = e.max_hp;
|
||||
entry.resist_adjust = e.resist_adjust;
|
||||
entry.bucket_name = e.bucket_name;
|
||||
entry.bucket_value = e.bucket_value;
|
||||
entry.bucket_comparison = e.bucket_comparison;
|
||||
|
||||
// some spell types don't make much since to be priority 0, so fix that
|
||||
@@ -3344,8 +3346,8 @@ DBbotspells_Struct* ZoneDatabase::GetBotSpells(uint32 bot_spell_id)
|
||||
|
||||
if (e.resist_adjust) {
|
||||
entry.resist_adjust = e.resist_adjust;
|
||||
} else if (IsValidSpell(e.spellid)) {
|
||||
entry.resist_adjust = spells[e.spellid].resist_difficulty;
|
||||
} else if (IsValidSpell(e.spell_id)) {
|
||||
entry.resist_adjust = spells[e.spell_id].resist_difficulty;
|
||||
}
|
||||
|
||||
spell_set.entries.push_back(entry);
|
||||
|
||||
+684
-185
File diff suppressed because it is too large
Load Diff
+73
-25
@@ -70,6 +70,8 @@ namespace EQ
|
||||
#include "../common/data_verification.h"
|
||||
#include "../common/repositories/character_parcels_repository.h"
|
||||
#include "../common/repositories/trader_repository.h"
|
||||
#include "../common/guild_base.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
// since windows defines these within windef.h (which windows.h include)
|
||||
@@ -194,6 +196,7 @@ struct RespawnOption
|
||||
float heading;
|
||||
};
|
||||
|
||||
|
||||
// do not ask what all these mean because I have no idea!
|
||||
// named from the client's CEverQuest::GetInnateDesc, they're missing some
|
||||
enum eInnateSkill {
|
||||
@@ -258,7 +261,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);
|
||||
|
||||
@@ -276,6 +279,8 @@ public:
|
||||
|
||||
std::vector<Mob*> GetRaidOrGroupOrSelf(bool clients_only = false);
|
||||
|
||||
bool CheckIfAlreadyDead();
|
||||
|
||||
void AI_Init();
|
||||
void AI_Start(uint32 iMoveDelay = 0);
|
||||
void AI_Stop();
|
||||
@@ -288,6 +293,7 @@ public:
|
||||
void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||
void SendBazaarDone(uint32 trader_id);
|
||||
void SendBulkBazaarTraders();
|
||||
void SendBulkBazaarBuyers();
|
||||
void DoBazaarInspect(const BazaarInspect_Struct &in);
|
||||
void SendBazaarDeliveryCosts();
|
||||
static std::string DetermineMoneyString(uint64 copper);
|
||||
@@ -307,8 +313,10 @@ public:
|
||||
bool TryStacking(EQ::ItemInstance* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||
void SendBuyerPacket(Client* Buyer);
|
||||
void SendBuyerToBarterWindow(Client* buyer, uint32 action);
|
||||
GetItems_Struct* GetTraderItems();
|
||||
void SendBazaarWelcome();
|
||||
void SendBarterWelcome();
|
||||
void DyeArmor(EQ::TintProfile* dye);
|
||||
void DyeArmorBySlot(uint8 slot, uint8 red, uint8 green, uint8 blue, uint8 use_tint = 0x00);
|
||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
||||
@@ -375,14 +383,35 @@ public:
|
||||
uint32 GetCustomerID() { return customer_id; }
|
||||
void SetCustomerID(uint32 id) { customer_id = id; }
|
||||
|
||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||
void SetBuyerID(uint32 id) { m_buyer_id = id; }
|
||||
uint32 GetBuyerID() { return m_buyer_id; }
|
||||
bool IsBuyer() { return m_buyer_id != 0 ? true : false; }
|
||||
void SetBarterTime() { m_barter_time = time(nullptr); }
|
||||
uint32 GetBarterTime() { return m_barter_time; }
|
||||
void SetBuyerWelcomeMessage(const char* welcome_message);
|
||||
void SendBuyerGreeting(uint32 char_id);
|
||||
void SendSellerBrowsing(const std::string &browser);
|
||||
void SendBuyerMode(bool status);
|
||||
bool IsInBuyerSpace();
|
||||
void SendBuyLineUpdate(const BuyerLineItems_Struct &buy_line);
|
||||
void CheckIfMovedItemIsPartOfBuyLines(uint32 item_id);
|
||||
|
||||
void SendBuyerResults(BarterSearchRequest_Struct& bsr);
|
||||
void ShowBuyLines(const EQApplicationPacket *app);
|
||||
void SellToBuyer(const EQApplicationPacket *app);
|
||||
void ToggleBuyerMode(bool TurnOn);
|
||||
void UpdateBuyLine(const EQApplicationPacket *app);
|
||||
void ModifyBuyLine(const EQApplicationPacket *app);
|
||||
void CreateStartingBuyLines(const EQApplicationPacket *app);
|
||||
void BuyerItemSearch(const EQApplicationPacket *app);
|
||||
void SetBuyerWelcomeMessage(const char* WelcomeMessage) { BuyerWelcomeMessage = WelcomeMessage; }
|
||||
const char* GetBuyerWelcomeMessage() { return BuyerWelcomeMessage.c_str(); }
|
||||
void SendWindowUpdatesToSellerAndBuyer(BuyerLineSellItem_Struct& blsi);
|
||||
void SendBarterBuyerClientMessage(BuyerLineSellItem_Struct& blsi, BarterBuyerActions action, BarterBuyerSubActions sub_action, BarterBuyerSubActions error_code);
|
||||
bool BuildBuyLineMap(std::map<uint32, BuylineItemDetails_Struct>& item_map, BuyerBuyLines_Struct& bl);
|
||||
bool BuildBuyLineMapFromVector(std::map<uint32, BuylineItemDetails_Struct>& item_map, std::vector<BuyerLineItems_Struct>& bl);
|
||||
void RemoveItemFromBuyLineMap(std::map<uint32, BuylineItemDetails_Struct>& item_map, const BuyerLineItems_Struct& bl);
|
||||
bool ValidateBuyLineItems(std::map<uint32, BuylineItemDetails_Struct>& item_map);
|
||||
int64 ValidateBuyLineCost(std::map<uint32, BuylineItemDetails_Struct>& item_map);
|
||||
bool DoBarterBuyerChecks(BuyerLineSellItem_Struct& sell_line);
|
||||
bool DoBarterSellerChecks(BuyerLineSellItem_Struct& sell_line);
|
||||
|
||||
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
bool ShouldISpawnFor(Client *c) { return !GMHideMe(c) && !IsHoveringForRespawn(); }
|
||||
@@ -734,11 +763,12 @@ public:
|
||||
void GetRaidAAs(RaidLeadershipAA_Struct *into) const;
|
||||
void ClearGroupAAs();
|
||||
void UpdateGroupAAs(int32 points, uint32 type);
|
||||
void SacrificeConfirm(Client* caster);
|
||||
void Sacrifice(Client* caster);
|
||||
void SacrificeConfirm(Mob* caster);
|
||||
void Sacrifice(Mob* caster);
|
||||
void GoToDeath();
|
||||
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
|
||||
void SetZoning(bool in) { bZoning = in; }
|
||||
bool IsZoning() { return bZoning; }
|
||||
|
||||
void ShowSpells(Client* c, ShowSpellType show_spell_type);
|
||||
|
||||
@@ -825,9 +855,11 @@ public:
|
||||
void QuestReadBook(const char* text, uint8 type);
|
||||
void SendMoneyUpdate();
|
||||
bool TakeMoneyFromPP(uint64 copper, bool update_client = false);
|
||||
bool TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client);
|
||||
bool TakePlatinum(uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPP(uint64 copper, bool update_client = false);
|
||||
void AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPPWithOverflow(uint64 copper, bool update_client);
|
||||
void AddPlatinum(uint32 platinu, bool update_client = false);
|
||||
bool HasMoney(uint64 copper);
|
||||
uint64 GetCarriedMoney();
|
||||
@@ -866,7 +898,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);
|
||||
@@ -966,6 +998,8 @@ public:
|
||||
void ChangeTributeSettings(TributeInfo_Struct *t);
|
||||
void SendTributeTimer();
|
||||
void ToggleTribute(bool enabled);
|
||||
std::map<uint32, TributeData> GetTributeList();
|
||||
uint32 LookupTributeItemID(uint32 tribute_id, uint32 tier);
|
||||
void SendPathPacket(const std::vector<FindPerson_Point> &path);
|
||||
|
||||
inline PTimerList &GetPTimers() { return(p_timers); }
|
||||
@@ -992,7 +1026,7 @@ public:
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
uint32 GetRequiredAAExperience();
|
||||
void AutoGrantAAPoints();
|
||||
void GrantAllAAPoints(uint8 unlock_level = 0);
|
||||
void GrantAllAAPoints(uint8 unlock_level = 0, bool skip_grant_only = false);
|
||||
bool HasAlreadyPurchasedRank(AA::Rank* rank);
|
||||
void ListPurchasedAAs(Client *to, std::string search_criteria = std::string());
|
||||
|
||||
@@ -1054,6 +1088,8 @@ public:
|
||||
int32 GetItemIDAt(int16 slot_id);
|
||||
int32 GetAugmentIDAt(int16 slot_id, uint8 augslot);
|
||||
bool PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, bool client_update = false);
|
||||
bool PutItemInInventoryWithStacking(EQ::ItemInstance* inst);
|
||||
bool FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTradeItems_Struct> items);
|
||||
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
|
||||
void SendCursorBuffer();
|
||||
void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
|
||||
@@ -1092,7 +1128,6 @@ public:
|
||||
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; }
|
||||
|
||||
@@ -1129,7 +1164,7 @@ public:
|
||||
void RemoveNoRent(bool client_update = true);
|
||||
void RemoveDuplicateLore(bool client_update = true);
|
||||
void MoveSlotNotAllowed(bool client_update = true);
|
||||
virtual void RangedAttack(Mob* other, bool CanDoubleAttack = false);
|
||||
virtual bool RangedAttack(Mob* other, bool CanDoubleAttack = false);
|
||||
virtual void ThrowingAttack(Mob* other, bool CanDoubleAttack = false);
|
||||
void DoClassAttacks(Mob *ca_target, uint16 skill = -1, bool IsRiposte=false);
|
||||
|
||||
@@ -1211,7 +1246,7 @@ public:
|
||||
bool PendingTranslocate;
|
||||
time_t TranslocateTime;
|
||||
bool PendingSacrifice;
|
||||
std::string SacrificeCaster;
|
||||
uint16 sacrifice_caster_id;
|
||||
PendingTranslocate_Struct PendingTranslocateData;
|
||||
void SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID);
|
||||
|
||||
@@ -1386,7 +1421,11 @@ public:
|
||||
{
|
||||
return (task_state ? task_state->EnabledTaskCount(task_set_id) : -1);
|
||||
}
|
||||
inline int IsTaskCompleted(int task_id) { return (task_state ? task_state->IsTaskCompleted(task_id) : -1); }
|
||||
inline bool IsTaskCompleted(int task_id) { return (task_state ? task_state->IsTaskCompleted(task_id) : false); }
|
||||
inline bool AreTasksCompleted(std::vector<int> task_ids)
|
||||
{
|
||||
return (task_state ? task_state->AreTasksCompleted(task_ids) : false);
|
||||
}
|
||||
inline void ShowClientTasks(Client *client) { if (task_state) { task_state->ShowClientTasks(this, client); }}
|
||||
inline void CancelAllTasks() { if (task_state) { task_state->CancelAllTasks(this); }}
|
||||
inline int GetActiveTaskCount() { return (task_state ? task_state->GetActiveTaskCount() : 0); }
|
||||
@@ -1756,9 +1795,6 @@ public:
|
||||
|
||||
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
|
||||
|
||||
void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
|
||||
glm::vec4 &GetLastPositionBeforeBulkUpdate();
|
||||
|
||||
Raid *p_raid_instance;
|
||||
|
||||
void ShowDevToolsMenu();
|
||||
@@ -1909,8 +1945,8 @@ private:
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
uint8 mercSlot; // selected merc slot
|
||||
bool Buyer;
|
||||
std::string BuyerWelcomeMessage;
|
||||
uint32 m_buyer_id;
|
||||
uint32 m_barter_time;
|
||||
int32 m_parcel_platinum;
|
||||
int32 m_parcel_gold;
|
||||
int32 m_parcel_silver;
|
||||
@@ -1974,9 +2010,10 @@ private:
|
||||
void ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions, ZoneMode zm);
|
||||
void ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
|
||||
|
||||
void SendTopLevelInventory();
|
||||
|
||||
glm::vec4 m_ZoneSummonLocation;
|
||||
uint16 zonesummon_id;
|
||||
uint8 zonesummon_instance_id;
|
||||
uint8 zonesummon_ignorerestrictions;
|
||||
ZoneMode zone_mode;
|
||||
|
||||
@@ -1994,8 +2031,6 @@ private:
|
||||
Timer fishing_timer;
|
||||
Timer endupkeep_timer;
|
||||
Timer autosave_timer;
|
||||
Timer client_scan_npc_aggro_timer;
|
||||
Timer client_zone_wide_full_position_update_timer;
|
||||
Timer tribute_timer;
|
||||
|
||||
Timer proximity_timer;
|
||||
@@ -2012,16 +2047,29 @@ private:
|
||||
Timer afk_toggle_timer;
|
||||
Timer helm_toggle_timer;
|
||||
Timer aggro_meter_timer;
|
||||
Timer mob_close_scan_timer;
|
||||
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||
Timer consent_throttle_timer;
|
||||
Timer dynamiczone_removal_timer;
|
||||
Timer task_request_timer;
|
||||
Timer pick_lock_timer;
|
||||
Timer parcel_timer; //Used to limit the number of parcels to one every 30 seconds (default). Changable via rule.
|
||||
Timer lazy_load_bank_check_timer;
|
||||
Timer bandolier_throttle_timer;
|
||||
|
||||
bool m_lazy_load_bank = false;
|
||||
int m_lazy_load_sent_bank_slots = 0;
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
glm::vec4 last_position_before_bulk_update;
|
||||
|
||||
// client aggro
|
||||
Timer m_client_npc_aggro_scan_timer;
|
||||
void CheckClientToNpcAggroTimer();
|
||||
void ClientToNpcAggroProcess();
|
||||
|
||||
// bulk position updates
|
||||
glm::vec4 m_last_position_before_bulk_update;
|
||||
Timer m_client_zone_wide_full_position_update_timer;
|
||||
Timer m_position_update_timer;
|
||||
void CheckSendBulkClientPositionUpdate();
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
@@ -2138,7 +2186,6 @@ private:
|
||||
bool m_has_quest_compass = false;
|
||||
std::vector<uint32_t> m_dynamic_zone_ids;
|
||||
|
||||
|
||||
public:
|
||||
enum BotOwnerOption : size_t {
|
||||
booDeathMarquee,
|
||||
@@ -2180,6 +2227,7 @@ private:
|
||||
bool CanTradeFVNoDropItem();
|
||||
void SendMobPositions();
|
||||
void PlayerTradeEventLog(Trade *t, Trade *t2);
|
||||
void NPCHandinEventLog(Trade* t, NPC* n);
|
||||
|
||||
// full and partial mail key cache
|
||||
std::string m_mail_key_full;
|
||||
|
||||
+308
-266
@@ -65,6 +65,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/repositories/account_repository.h"
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/guild_tributes_repository.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/character_stats_record_repository.h"
|
||||
@@ -368,13 +369,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_Save] = &Client::Handle_OP_Save;
|
||||
ConnectedOpcodes[OP_SaveOnZoneReq] = &Client::Handle_OP_SaveOnZoneReq;
|
||||
ConnectedOpcodes[OP_SelectTribute] = &Client::Handle_OP_SelectTribute;
|
||||
|
||||
// Use or Ignore sense heading based on rule.
|
||||
bool train = RuleB(Skills, TrainSenseHeading);
|
||||
|
||||
ConnectedOpcodes[OP_SenseHeading] =
|
||||
(train) ? &Client::Handle_OP_SenseHeading : &Client::Handle_OP_Ignore;
|
||||
|
||||
ConnectedOpcodes[OP_SenseHeading] = &Client::Handle_OP_SenseHeading;
|
||||
ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps;
|
||||
ConnectedOpcodes[OP_SetGuildMOTD] = &Client::Handle_OP_SetGuildMOTD;
|
||||
ConnectedOpcodes[OP_SetRunMode] = &Client::Handle_OP_SetRunMode;
|
||||
@@ -764,8 +759,6 @@ void Client::CompleteConnect()
|
||||
|
||||
entity_list.SendIllusionWearChange(this);
|
||||
|
||||
entity_list.SendTraders(this);
|
||||
|
||||
SendWearChangeAndLighting(EQ::textures::LastTexture);
|
||||
Mob* pet = GetPet();
|
||||
if (pet) {
|
||||
@@ -793,13 +786,15 @@ void Client::CompleteConnect()
|
||||
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
|
||||
}
|
||||
|
||||
DeleteEntityVariable(SEE_BUFFS_FLAG);
|
||||
|
||||
// the way that the client deals with positions during the initial spawn struct
|
||||
// is subtly different from how it deals with getting a position update
|
||||
// if a mob is slightly in the wall or slightly clipping a floor they will be
|
||||
// sent to a succor point
|
||||
SendMobPositions();
|
||||
|
||||
SetLastPositionBeforeBulkUpdate(GetPosition());
|
||||
m_last_position_before_bulk_update = GetPosition();
|
||||
|
||||
/* This sub event is for if a player logs in for the first time since entering world. */
|
||||
if (firstlogon == 1) {
|
||||
@@ -939,12 +934,13 @@ void Client::CompleteConnect()
|
||||
}
|
||||
|
||||
database.LoadAuras(this); // this ends up spawning them so probably safer to load this later (here)
|
||||
database.LoadCharacterDisciplines(this);
|
||||
|
||||
entity_list.RefreshClientXTargets(this);
|
||||
|
||||
worldserver.RequestTellQueue(GetName());
|
||||
|
||||
entity_list.ScanCloseMobs(close_mobs, this, true);
|
||||
entity_list.ScanCloseMobs(this);
|
||||
|
||||
if (GetGM() && IsDevToolsEnabled()) {
|
||||
ShowDevToolsMenu();
|
||||
@@ -1323,7 +1319,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
database.LoadCharacterInspectMessage(cid, &m_inspect_message); /* Load Character Inspect Message */
|
||||
database.LoadCharacterSpellBook(cid, &m_pp); /* Load Character Spell Book */
|
||||
database.LoadCharacterMemmedSpells(cid, &m_pp); /* Load Character Memorized Spells */
|
||||
database.LoadCharacterDisciplines(cid, &m_pp); /* Load Character Disciplines */
|
||||
database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
|
||||
database.LoadCharacterLeadershipAbilities(cid, &m_pp); /* Load Character Leadership AA's */
|
||||
database.LoadCharacterTribute(this); /* Load CharacterTribute */
|
||||
@@ -3290,6 +3285,10 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
if (new_aug->GetItem()->Attuneable) {
|
||||
new_aug->SetAttuned(true);
|
||||
}
|
||||
|
||||
tobe_auged->PutAugment(in_augment->augment_index, *new_aug);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
|
||||
@@ -3643,29 +3642,39 @@ void Client::Handle_OP_AutoFire(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
||||
{
|
||||
// Although there are three different structs for OP_Bandolier, they are all the same size.
|
||||
//
|
||||
if (app->size != sizeof(BandolierCreate_Struct)) {
|
||||
LogDebug("Size mismatch in OP_Bandolier expected [{}] got [{}]", sizeof(BandolierCreate_Struct), app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
||||
auto bs = (BandolierCreate_Struct*) app->pBuffer;
|
||||
|
||||
switch (bs->Action)
|
||||
{
|
||||
case bandolierCreate:
|
||||
CreateBandolier(app);
|
||||
break;
|
||||
case bandolierRemove:
|
||||
RemoveBandolier(app);
|
||||
break;
|
||||
case bandolierSet:
|
||||
SetBandolier(app);
|
||||
break;
|
||||
default:
|
||||
LogDebug("Unknown Bandolier action [{}]", bs->Action);
|
||||
break;
|
||||
switch (bs->Action) {
|
||||
case bandolierCreate:
|
||||
CreateBandolier(app);
|
||||
break;
|
||||
case bandolierRemove:
|
||||
RemoveBandolier(app);
|
||||
break;
|
||||
case bandolierSet:
|
||||
if (bandolier_throttle_timer.GetDuration() && !bandolier_throttle_timer.Check()) {
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"You may only modify your bandolier once every {}.",
|
||||
Strings::ToLower(Strings::MillisecondsToTime(RuleI(Character, BandolierSwapDelay)))
|
||||
).c_str()
|
||||
);
|
||||
SendTopLevelInventory();
|
||||
break;
|
||||
}
|
||||
|
||||
SetBandolier(app);
|
||||
break;
|
||||
default:
|
||||
LogDebug("Unknown Bandolier action [{}]", bs->Action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3763,116 +3772,104 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
char* Buf = (char *)app->pBuffer;
|
||||
auto in = (BuyerGeneric_Struct *)app->pBuffer;
|
||||
|
||||
// The first 4 bytes of the packet determine the action. A lot of Barter packets require the
|
||||
// packet the client sent, sent back to it as an acknowledgement.
|
||||
//
|
||||
uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buf);
|
||||
//uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buf);
|
||||
|
||||
|
||||
switch (Action)
|
||||
{
|
||||
switch (in->action) {
|
||||
|
||||
case Barter_BuyerSearch:
|
||||
{
|
||||
BuyerItemSearch(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_SellerSearch:
|
||||
{
|
||||
BarterSearchRequest_Struct *bsr = (BarterSearchRequest_Struct*)app->pBuffer;
|
||||
SendBuyerResults(bsr->SearchString, bsr->SearchID);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerModeOn:
|
||||
{
|
||||
if (!IsTrader()) {
|
||||
ToggleBuyerMode(true);
|
||||
case Barter_BuyerSearch: {
|
||||
BuyerItemSearch(app);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
Buf = (char *)app->pBuffer;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerModeOff);
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
|
||||
case Barter_SellerSearch: {
|
||||
auto bsr = (BarterSearchRequest_Struct *) app->pBuffer;
|
||||
SendBuyerResults(*bsr);
|
||||
break;
|
||||
}
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerModeOff:
|
||||
{
|
||||
QueuePacket(app);
|
||||
ToggleBuyerMode(false);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerModeOn: {
|
||||
if (!IsTrader()) {
|
||||
ToggleBuyerMode(true);
|
||||
}
|
||||
else {
|
||||
ToggleBuyerMode(false);
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerItemUpdate:
|
||||
{
|
||||
UpdateBuyLine(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerModeOff: {
|
||||
ToggleBuyerMode(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerItemRemove:
|
||||
{
|
||||
BuyerRemoveItem_Struct* bris = (BuyerRemoveItem_Struct*)app->pBuffer;
|
||||
database.RemoveBuyLine(CharacterID(), bris->BuySlot);
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemUpdate: {
|
||||
ModifyBuyLine(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_SellItem:
|
||||
{
|
||||
SellToBuyer(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemStart: {
|
||||
CreateStartingBuyLines(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerInspectBegin:
|
||||
{
|
||||
ShowBuyLines(app);
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerItemRemove: {
|
||||
auto bris = (BuyerRemoveItem_Struct *) app->pBuffer;
|
||||
BuyerBuyLinesRepository::DeleteBuyLine(database, CharacterID(), bris->buy_slot_id);
|
||||
QueuePacket(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BuyerInspectEnd:
|
||||
{
|
||||
BuyerInspectRequest_Struct* bir = (BuyerInspectRequest_Struct*)app->pBuffer;
|
||||
Client *Buyer = entity_list.GetClientByID(bir->BuyerID);
|
||||
if (Buyer)
|
||||
Buyer->WithCustomer(0);
|
||||
case Barter_SellItem: {
|
||||
SellToBuyer(app);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Barter_BuyerInspectBegin: {
|
||||
ShowBuyLines(app);
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_BarterItemInspect:
|
||||
{
|
||||
BarterItemSearchLinkRequest_Struct* bislr = (BarterItemSearchLinkRequest_Struct*)app->pBuffer;
|
||||
case Barter_BuyerInspectEnd: {
|
||||
auto bir = (BuyerInspectRequest_Struct *) app->pBuffer;
|
||||
auto buyer = entity_list.GetClientByID(bir->buyer_id);
|
||||
if (buyer) {
|
||||
buyer->WithCustomer(0);
|
||||
}
|
||||
|
||||
const EQ::ItemData* item = database.GetItem(bislr->ItemID);
|
||||
break;
|
||||
}
|
||||
case Barter_BarterItemInspect: {
|
||||
auto bislr = (BarterItemSearchLinkRequest_Struct *) app->pBuffer;
|
||||
const EQ::ItemData *item = database.GetItem(bislr->item_id);
|
||||
|
||||
if (!item)
|
||||
Message(Chat::Red, "Error: This item does not exist!");
|
||||
else
|
||||
{
|
||||
EQ::ItemInstance* inst = database.CreateItem(item);
|
||||
if (inst)
|
||||
{
|
||||
if (!item) {
|
||||
Message(Chat::Red, "Error: This item does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *inst = database.CreateItem(item);
|
||||
if (inst) {
|
||||
SendItemPacket(0, inst, ItemPacketViewLink);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_Welcome:
|
||||
{
|
||||
//SendBazaarWelcome();
|
||||
SendBarterWelcome();
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_WelcomeMessageUpdate:
|
||||
{
|
||||
BuyerWelcomeMessageUpdate_Struct* bwmu = (BuyerWelcomeMessageUpdate_Struct*)app->pBuffer;
|
||||
SetBuyerWelcomeMessage(bwmu->WelcomeMessage);
|
||||
case Barter_WelcomeMessageUpdate: {
|
||||
auto bwmu = (BuyerWelcomeMessageUpdate_Struct *) app->pBuffer;
|
||||
SetBuyerWelcomeMessage(bwmu->welcome_message);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3896,15 +3893,20 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
|
||||
case Barter_Unknown23:
|
||||
case Barter_Greeting:
|
||||
{
|
||||
// Sent by SoD client for no discernible reason.
|
||||
auto data = (BuyerGreeting_Struct *)app->pBuffer;
|
||||
SendBuyerGreeting(data->buyer_id);
|
||||
}
|
||||
case Barter_OpenBarterWindow:
|
||||
{
|
||||
SendBulkBazaarBuyers();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Message(Chat::Red, "Unrecognised Barter action.");
|
||||
LogTrading("Unrecognised Barter Action [{}]", Action);
|
||||
LogTrading("Unrecognised Barter Action [{}]", in->action);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4986,6 +4988,10 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
TraderEndTrader();
|
||||
}
|
||||
|
||||
if (IsBuyer()) {
|
||||
ToggleBuyerMode(false);
|
||||
}
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
if ((hidden || improved_hidden) && !sneaking) {
|
||||
hidden = false;
|
||||
@@ -5006,103 +5012,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
|
||||
SetMoving(!(cy == m_Position.y && cx == m_Position.x));
|
||||
|
||||
/**
|
||||
* Client aggro scanning
|
||||
*/
|
||||
const uint16 client_scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||
const uint16 client_scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||
|
||||
LogAggroDetail(
|
||||
"ClientUpdate [{}] {}moving, scan timer [{}]",
|
||||
GetCleanName(),
|
||||
IsMoving() ? "" : "NOT ",
|
||||
client_scan_npc_aggro_timer.GetRemainingTime()
|
||||
);
|
||||
|
||||
if (IsMoving()) {
|
||||
if (client_scan_npc_aggro_timer.GetRemainingTime() > client_scan_npc_aggro_timer_moving) {
|
||||
LogAggroDetail("Client [{}] Restarting with moving timer", GetCleanName());
|
||||
client_scan_npc_aggro_timer.Disable();
|
||||
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_moving);
|
||||
client_scan_npc_aggro_timer.Trigger();
|
||||
}
|
||||
}
|
||||
else if (client_scan_npc_aggro_timer.GetDuration() == client_scan_npc_aggro_timer_moving) {
|
||||
LogAggroDetail("Client [{}] Restarting with idle timer", GetCleanName());
|
||||
client_scan_npc_aggro_timer.Disable();
|
||||
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client mob close list cache scan timer
|
||||
*/
|
||||
const uint16 client_mob_close_scan_timer_moving = 6000;
|
||||
const uint16 client_mob_close_scan_timer_idle = 60000;
|
||||
|
||||
LogAIScanCloseDetail(
|
||||
"Client [{}] {}moving, scan timer [{}]",
|
||||
GetCleanName(),
|
||||
IsMoving() ? "" : "NOT ",
|
||||
mob_close_scan_timer.GetRemainingTime()
|
||||
);
|
||||
|
||||
if (IsMoving()) {
|
||||
if (mob_close_scan_timer.GetRemainingTime() > client_mob_close_scan_timer_moving) {
|
||||
LogAIScanCloseDetail("Client [{}] Restarting with moving timer", GetCleanName());
|
||||
mob_close_scan_timer.Disable();
|
||||
mob_close_scan_timer.Start(client_mob_close_scan_timer_moving);
|
||||
mob_close_scan_timer.Trigger();
|
||||
}
|
||||
}
|
||||
else if (mob_close_scan_timer.GetDuration() == client_mob_close_scan_timer_moving) {
|
||||
LogAIScanCloseDetail("Client [{}] Restarting with idle timer", GetCleanName());
|
||||
mob_close_scan_timer.Disable();
|
||||
mob_close_scan_timer.Start(client_mob_close_scan_timer_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* On a normal basis we limit mob movement updates based on distance
|
||||
* This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
|
||||
*
|
||||
* For very large zones we will also force a full update based on distance
|
||||
*
|
||||
* We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
|
||||
* to full stop when they are actually still pathing
|
||||
*/
|
||||
|
||||
float distance_moved = DistanceNoZ(GetLastPositionBeforeBulkUpdate(), GetPosition());
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
|
||||
bool is_ready_to_update = (
|
||||
client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
);
|
||||
|
||||
if (IsMoving() && is_ready_to_update) {
|
||||
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
||||
|
||||
auto &mob_movement_manager = MobMovementManager::Get();
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
|
||||
for (auto &it : mob_list) {
|
||||
Mob *entity = it.second;
|
||||
if (!entity->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int animation_speed = 0;
|
||||
if (entity->IsMoving()) {
|
||||
if (entity->IsRunning()) {
|
||||
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
|
||||
}
|
||||
else {
|
||||
animation_speed = entity->GetWalkspeed();
|
||||
}
|
||||
}
|
||||
|
||||
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
|
||||
}
|
||||
|
||||
SetLastPositionBeforeBulkUpdate(GetPosition());
|
||||
}
|
||||
CheckClientToNpcAggroTimer();
|
||||
CheckScanCloseMobsMovingTimer();
|
||||
CheckSendBulkClientPositionUpdate();
|
||||
|
||||
int32 new_animation = ppu->animation;
|
||||
|
||||
@@ -5807,7 +5719,7 @@ void Client::Handle_OP_DeleteItem(const EQApplicationPacket *app)
|
||||
RecordPlayerEventLog(PlayerEvent::ITEM_DESTROY, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DeleteItemInInventory(alc->from_slot, 1);
|
||||
}
|
||||
|
||||
@@ -10434,7 +10346,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;
|
||||
|
||||
@@ -10514,7 +10426,7 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
|
||||
//check to see if selected option is a valid stance slot (option is the slot the stance is in, not the actual stance)
|
||||
if (option >= 0 && option < numStances)
|
||||
{
|
||||
merc->SetStance((EQ::constants::StanceType)mercTemplate->Stances[option]);
|
||||
merc->SetStance(mercTemplate->Stances[option]);
|
||||
GetMercInfo().Stance = mercTemplate->Stances[option];
|
||||
|
||||
Log(Logs::General, Logs::Mercenaries, "Set Stance: %u for %s (%s)", merc->GetStance(), merc->GetName(), GetName());
|
||||
@@ -10913,7 +10825,121 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
|
||||
{
|
||||
Kick("Unimplemented move multiple items"); // TODO: lets not desync though
|
||||
// This packet is only sent from the client if we ctrl click items in inventory
|
||||
if (m_ClientVersionBit & EQ::versions::maskRoF2AndLater) {
|
||||
if (!CharacterID()) {
|
||||
LinkDead();
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size < sizeof(MultiMoveItem_Struct)) {
|
||||
LinkDead();
|
||||
return; // Not enough data to be a valid packet
|
||||
}
|
||||
|
||||
const MultiMoveItem_Struct* multi_move = reinterpret_cast<const MultiMoveItem_Struct*>(app->pBuffer);
|
||||
if (app->size != sizeof(MultiMoveItem_Struct) + sizeof(MultiMoveItemSub_Struct) * multi_move->count) {
|
||||
LinkDead();
|
||||
return; // Packet size does not match expected size
|
||||
}
|
||||
|
||||
const int16 from_parent = multi_move->moves[0].from_slot.Slot;
|
||||
const int16 to_parent = multi_move->moves[0].to_slot.Slot;
|
||||
|
||||
// CTRL + left click drops an item into a bag without opening it.
|
||||
// This can be a bag, in which case it tries to fill the target bag with the contents of the bag on the cursor
|
||||
// CTRL + right click swaps the contents of two bags if a bag is on your cursor and you ctrl-right click on another bag.
|
||||
|
||||
// We need to check if this is a swap or just an addition (left click or right click)
|
||||
// Check if any component of this transaction is coming from anywhere other than the cursor
|
||||
bool left_click = true;
|
||||
for (int i = 0; i < multi_move->count; i++) {
|
||||
if (multi_move->moves[i].from_slot.Slot != EQ::invslot::slotCursor) {
|
||||
left_click = false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a left click which is purely additive. This should always be cursor object or cursor bag contents into general\bank\whatever bag
|
||||
if (left_click) {
|
||||
for (int i = 0; i < multi_move->count; i++) {
|
||||
MoveItem_Struct* mi = new MoveItem_Struct();
|
||||
mi->from_slot = multi_move->moves[i].from_slot.SubIndex == -1 ? multi_move->moves[i].from_slot.Slot : m_inv.CalcSlotId(multi_move->moves[i].from_slot.Slot, multi_move->moves[i].from_slot.SubIndex);
|
||||
mi->to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot, multi_move->moves[i].to_slot.SubIndex);
|
||||
|
||||
if (multi_move->moves[i].to_slot.Type == EQ::invtype::typeBank) { // Target is bank inventory
|
||||
mi->to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot + EQ::invslot::BANK_BEGIN, multi_move->moves[i].to_slot.SubIndex);
|
||||
} else if (multi_move->moves[i].to_slot.Type == EQ::invtype::typeSharedBank) { // Target is shared bank inventory
|
||||
mi->to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot + EQ::invslot::SHARED_BANK_BEGIN, multi_move->moves[i].to_slot.SubIndex);
|
||||
}
|
||||
|
||||
// This sends '1' as the stack count for unstackable items, which our titanium-era SwapItem blows up
|
||||
if (m_inv.GetItem(mi->from_slot)->IsStackable()) {
|
||||
mi->number_in_stack = multi_move->moves[i].number_in_stack;
|
||||
} else {
|
||||
mi->number_in_stack = 0;
|
||||
}
|
||||
|
||||
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
|
||||
bool error = false;
|
||||
SwapItemResync(mi);
|
||||
InterrogateInventory(this, false, true, false, error, false);
|
||||
if (error) {
|
||||
InterrogateInventory(this, true, false, true, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is the swap.
|
||||
// Client behavior is just to move stacks without combining them
|
||||
// Items get rearranged to fill the 'top' of the bag first
|
||||
} else {
|
||||
struct MoveInfo {
|
||||
EQ::ItemInstance* item;
|
||||
uint16 to_slot;
|
||||
};
|
||||
|
||||
std::vector<MoveInfo> items;
|
||||
items.reserve(multi_move->count);
|
||||
|
||||
for (int i = 0; i < multi_move->count; i++) {
|
||||
// These are always bags, so we don't need to worry about raw items in slotCursor
|
||||
uint16 from_slot = m_inv.CalcSlotId(multi_move->moves[i].from_slot.Slot, multi_move->moves[i].from_slot.SubIndex);
|
||||
if (multi_move->moves[i].from_slot.Type == EQ::invtype::typeBank) { // Target is bank inventory
|
||||
from_slot = m_inv.CalcSlotId(multi_move->moves[i].from_slot.Slot + EQ::invslot::BANK_BEGIN, multi_move->moves[i].from_slot.SubIndex);
|
||||
} else if (multi_move->moves[i].from_slot.Type == EQ::invtype::typeSharedBank) { // Target is shared bank inventory
|
||||
from_slot = m_inv.CalcSlotId(multi_move->moves[i].from_slot.Slot + EQ::invslot::SHARED_BANK_BEGIN, multi_move->moves[i].from_slot.SubIndex);
|
||||
}
|
||||
|
||||
uint16 to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot, multi_move->moves[i].to_slot.SubIndex);
|
||||
if (multi_move->moves[i].to_slot.Type == EQ::invtype::typeBank) { // Target is bank inventory
|
||||
to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot + EQ::invslot::BANK_BEGIN, multi_move->moves[i].to_slot.SubIndex);
|
||||
} else if (multi_move->moves[i].to_slot.Type == EQ::invtype::typeSharedBank) { // Target is shared bank inventory
|
||||
to_slot = m_inv.CalcSlotId(multi_move->moves[i].to_slot.Slot + EQ::invslot::SHARED_BANK_BEGIN, multi_move->moves[i].to_slot.SubIndex);
|
||||
}
|
||||
|
||||
// I wasn't able to produce any error states on purpose.
|
||||
MoveInfo move{
|
||||
.item = m_inv.PopItem(from_slot), // Don't delete the instance here
|
||||
.to_slot = to_slot
|
||||
};
|
||||
|
||||
if (move.item) {
|
||||
items.push_back(move);
|
||||
database.SaveInventory(CharacterID(), NULL, from_slot); // We have to manually save inventory here.
|
||||
} else {
|
||||
LinkDead();
|
||||
return; // Prevent inventory desync here. Forcing a resync would be better, but we don't have a MoveItem struct to work with.
|
||||
}
|
||||
}
|
||||
|
||||
for (const MoveInfo& move : items) {
|
||||
PutItemInInventory(move.to_slot, *move.item); // This saves inventory too
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
LinkDead(); // This packet should not be sent by an older client
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)
|
||||
@@ -11536,8 +11562,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);
|
||||
@@ -11549,8 +11575,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11882,8 +11908,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;
|
||||
}
|
||||
@@ -11958,15 +11984,7 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||
|
||||
auto t = GetTarget();
|
||||
if (t) {
|
||||
if (t->IsNPC()) {
|
||||
if (parse->HasQuestSub(t->GetNPCTypeID(), EVENT_POPUP_RESPONSE)) {
|
||||
parse->EventNPC(EVENT_POPUP_RESPONSE, t->CastToNPC(), this, std::to_string(popup_response->popupid), 0);
|
||||
}
|
||||
} else if (t->IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_POPUP_RESPONSE)) {
|
||||
parse->EventBot(EVENT_POPUP_RESPONSE, t->CastToBot(), this, std::to_string(popup_response->popupid), 0);
|
||||
}
|
||||
}
|
||||
parse->EventBotMercNPC(EVENT_POPUP_RESPONSE, t, this, [&]() { return std::to_string(popup_response->popupid); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13020,14 +13038,14 @@ void Client::Handle_OP_ReadBook(const EQApplicationPacket *app)
|
||||
LogError("Wrong size: OP_ReadBook, size=[{}], expected [{}]", app->size, sizeof(BookRequest_Struct));
|
||||
return;
|
||||
}
|
||||
BookRequest_Struct* book = (BookRequest_Struct*)app->pBuffer;
|
||||
ReadBook(book);
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF)
|
||||
{
|
||||
EQApplicationPacket EndOfBook(OP_FinishWindow, 0);
|
||||
QueuePacket(&EndOfBook);
|
||||
|
||||
auto b = (BookRequest_Struct*) app->pBuffer;
|
||||
ReadBook(b);
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
||||
EQApplicationPacket end_of_book(OP_FinishWindow, 0);
|
||||
QueuePacket(&end_of_book);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_RecipeAutoCombine(const EQApplicationPacket *app)
|
||||
@@ -13561,11 +13579,11 @@ void Client::Handle_OP_Sacrifice(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (ss->Confirm) {
|
||||
Client *Caster = entity_list.GetClientByName(SacrificeCaster.c_str());
|
||||
Mob *Caster = entity_list.GetMob(sacrifice_caster_id);
|
||||
if (Caster) Sacrifice(Caster);
|
||||
}
|
||||
PendingSacrifice = false;
|
||||
SacrificeCaster.clear();
|
||||
sacrifice_caster_id = 0;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_SafeFallSuccess(const EQApplicationPacket *app) // bit of a misnomer, sent whenever safe fall is used (success of fail)
|
||||
@@ -13608,14 +13626,24 @@ void Client::Handle_OP_SelectTribute(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!HasSkill(EQ::skills::SkillSenseHeading))
|
||||
if (!HasSkill(EQ::skills::SkillSenseHeading)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int chancemod = 0;
|
||||
if (RuleB(Skills, TrainSenseHeading)) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillSenseHeading, nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckIncreaseSkill(EQ::skills::SkillSenseHeading, nullptr, chancemod);
|
||||
if (parse->PlayerHasQuestSub(EVENT_USE_SKILL)) {
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {}",
|
||||
EQ::skills::SkillSenseHeading,
|
||||
GetRawSkill(EQ::skills::SkillSenseHeading)
|
||||
);
|
||||
|
||||
return;
|
||||
parse->EventPlayer(EVENT_USE_SKILL, this, export_string, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
|
||||
@@ -14644,12 +14672,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;
|
||||
}
|
||||
@@ -14862,14 +14896,15 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app)
|
||||
Group *group = nullptr;
|
||||
Raid *raid = nullptr;
|
||||
|
||||
if (IsRaidGrouped())
|
||||
if (IsRaidGrouped()) {
|
||||
raid = GetRaid();
|
||||
else if (IsGrouped())
|
||||
} else if (IsGrouped()) {
|
||||
group = GetGroup();
|
||||
}
|
||||
|
||||
// is there an actual error message for this?
|
||||
if (raid == nullptr && group == nullptr) {
|
||||
Message(Chat::Red, "You can not split money if you're not in a group.");
|
||||
MessageString(Chat::Red, SPLIT_NO_GROUP);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14877,14 +14912,15 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app)
|
||||
10 * static_cast<uint64>(split->silver) +
|
||||
100 * static_cast<uint64>(split->gold) +
|
||||
1000 * static_cast<uint64>(split->platinum))) {
|
||||
Message(Chat::Red, "You do not have enough money to do that split.");
|
||||
MessageString(Chat::Red, SPLIT_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (raid)
|
||||
if (raid) {
|
||||
raid->SplitMoney(raid->GetGroup(this), split->copper, split->silver, split->gold, split->platinum);
|
||||
else if (group)
|
||||
group->SplitMoney(split->copper, split->silver, split->gold, split->platinum, this);
|
||||
} else if (group) {
|
||||
group->SplitMoney(split->copper, split->silver, split->gold, split->platinum, this, true);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -14999,9 +15035,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 {
|
||||
@@ -15144,8 +15180,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 [{}]",
|
||||
@@ -15512,7 +15548,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
case TraderOn: {
|
||||
if (Buyer) {
|
||||
if (IsBuyer()) {
|
||||
TraderEndTrader();
|
||||
Message(Chat::Red, "You cannot be a Trader and Buyer at the same time.");
|
||||
return;
|
||||
@@ -15558,7 +15594,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
auto trader = entity_list.GetClientByID(in->trader_id);
|
||||
|
||||
switch (in->method) {
|
||||
case ByVendor: {
|
||||
case BazaarByVendor: {
|
||||
if (trader) {
|
||||
LogTrading("Buy item directly from vendor id <green>[{}] item_id <green>[{}] quantity <green>[{}] "
|
||||
"serial_number <green>[{}]",
|
||||
@@ -15571,7 +15607,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ByParcel: {
|
||||
case BazaarByParcel: {
|
||||
if (!RuleB(Parcel, EnableParcelMerchants) || !RuleB(Bazaar, EnableParcelDelivery)) {
|
||||
LogTrading(
|
||||
"Bazaar purchase attempt by parcel delivery though 'Parcel:EnableParcelMerchants' or "
|
||||
@@ -15581,7 +15617,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
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->method = BazaarByParcel;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
@@ -15596,7 +15632,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
BuyTraderItemOutsideBazaar(in, app);
|
||||
break;
|
||||
}
|
||||
case ByDirectToInventory: {
|
||||
case BazaarByDirectToInventory: {
|
||||
if (!RuleB(Parcel, EnableDirectToInventoryDelivery)) {
|
||||
LogTrading("Bazaar purchase attempt by direct inventory delivery though "
|
||||
"'Parcel:EnableDirectToInventoryDelivery' not enabled."
|
||||
@@ -15605,7 +15641,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not enabled on this server. Please visit the vendor directly."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->method = BazaarByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
@@ -15622,7 +15658,7 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
Chat::Yellow,
|
||||
"Direct inventory delivey is not yet implemented. Please visit the vendor directly or purchase via parcel delivery."
|
||||
);
|
||||
in->method = ByDirectToInventory;
|
||||
in->method = BazaarByDirectToInventory;
|
||||
in->sub_action = Failed;
|
||||
TradeRequestFailed(app);
|
||||
break;
|
||||
@@ -16021,7 +16057,8 @@ void Client::Handle_OP_WearChange(const EQApplicationPacket *app)
|
||||
wc->hero_forge_model = GetHerosForgeModel(wc->wear_slot_id);
|
||||
|
||||
// we could maybe ignore this and just send our own from moveitem
|
||||
entity_list.QueueClients(this, app, false);
|
||||
// We probably need to skip this entirely when it is send as an ack, but not sure how to ID that.
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_WhoAllRequest(const EQApplicationPacket *app)
|
||||
@@ -16768,9 +16805,14 @@ void Client::Handle_OP_RaidClearNPCMarks(const EQApplicationPacket* app)
|
||||
|
||||
void Client::RecordStats()
|
||||
{
|
||||
const uint32 character_id = CharacterID();
|
||||
if (!character_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto r = CharacterStatsRecordRepository::FindOne(
|
||||
database,
|
||||
CharacterID()
|
||||
character_id
|
||||
);
|
||||
|
||||
r.status = Admin();
|
||||
@@ -16848,8 +16890,8 @@ void Client::RecordStats()
|
||||
if (r.character_id > 0) {
|
||||
CharacterStatsRecordRepository::UpdateOne(database, r);
|
||||
} else {
|
||||
r.character_id = CharacterID();
|
||||
r.created_at = std::time(nullptr);
|
||||
r.character_id = character_id;
|
||||
r.created_at = std::time(nullptr);
|
||||
CharacterStatsRecordRepository::InsertOne(database, r);
|
||||
}
|
||||
}
|
||||
|
||||
+121
-89
@@ -121,7 +121,7 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||
if (!IsMoving() && position_update_timer.Check()) {
|
||||
if (!IsMoving() && m_position_update_timer.Check()) {
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
}
|
||||
|
||||
@@ -281,12 +281,37 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan close range mobs
|
||||
* Used in aggro checks
|
||||
*/
|
||||
if (mob_close_scan_timer.Check()) {
|
||||
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
|
||||
ScanCloseMobProcess();
|
||||
|
||||
if (RuleB(Inventory, LazyLoadBank)) {
|
||||
// poll once a second to see if we are close to a banker and we haven't loaded the bank yet
|
||||
if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) {
|
||||
if (m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END && IsCloseToBanker()) {
|
||||
m_lazy_load_bank = true;
|
||||
lazy_load_bank_check_timer.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_lazy_load_bank && m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END) {
|
||||
const EQ::ItemInstance *inst = nullptr;
|
||||
|
||||
// Jump the gaps
|
||||
if (m_lazy_load_sent_bank_slots < EQ::invslot::BANK_BEGIN) {
|
||||
m_lazy_load_sent_bank_slots = EQ::invslot::BANK_BEGIN;
|
||||
}
|
||||
else if (m_lazy_load_sent_bank_slots > EQ::invslot::BANK_END &&
|
||||
m_lazy_load_sent_bank_slots < EQ::invslot::SHARED_BANK_BEGIN) {
|
||||
m_lazy_load_sent_bank_slots = EQ::invslot::SHARED_BANK_BEGIN;
|
||||
}
|
||||
else {
|
||||
m_lazy_load_sent_bank_slots++;
|
||||
}
|
||||
|
||||
inst = m_inv[m_lazy_load_sent_bank_slots];
|
||||
if (inst) {
|
||||
SendItemPacket(m_lazy_load_sent_bank_slots, inst, ItemPacketType::ItemPacketTrade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool may_use_attacks = false;
|
||||
@@ -321,44 +346,42 @@ bool Client::Process() {
|
||||
auto_fire = false;
|
||||
}
|
||||
EQ::ItemInstance *ranged = GetInv().GetItem(EQ::invslot::slotRange);
|
||||
if (ranged)
|
||||
{
|
||||
if (ranged) {
|
||||
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQ::item::ItemTypeBow) {
|
||||
if (ranged_timer.Check(false)) {
|
||||
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
||||
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(GetTarget())) {
|
||||
//client has built in los check, but auto fire does not.. done last.
|
||||
RangedAttack(GetTarget());
|
||||
if (CheckDoubleRangedAttack())
|
||||
if (RangedAttack(GetTarget()) && CheckDoubleRangedAttack()) {
|
||||
RangedAttack(GetTarget(), true);
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQ::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQ::item::ItemTypeSmallThrowing)) {
|
||||
} else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQ::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQ::item::ItemTypeSmallThrowing)) {
|
||||
if (ranged_timer.Check(false)) {
|
||||
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
||||
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(GetTarget())) {
|
||||
//client has built in los check, but auto fire does not.. done last.
|
||||
ThrowingAttack(GetTarget());
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
ranged_timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -579,30 +602,7 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
//At this point, we are still connected, everything important has taken
|
||||
//place, now check to see if anybody wants to aggro us.
|
||||
// only if client is not feigned
|
||||
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
|
||||
int npc_scan_count = 0;
|
||||
for (auto & close_mob : close_mobs) {
|
||||
Mob *mob = close_mob.second;
|
||||
|
||||
if (!mob) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->IsClient()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
|
||||
mob->AddToHateList(this, 25);
|
||||
}
|
||||
|
||||
npc_scan_count++;
|
||||
}
|
||||
LogAggro("Checking Reverse Aggro (client->npc) scanned_npcs ([{}])", npc_scan_count);
|
||||
}
|
||||
ClientToNpcAggroProcess();
|
||||
|
||||
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
|
||||
{
|
||||
@@ -782,39 +782,41 @@ void Client::BulkSendInventoryItems()
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
// Bank items
|
||||
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
|
||||
const EQ::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
if (!RuleB(Inventory, LazyLoadBank)) {
|
||||
// Bank items
|
||||
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
|
||||
const EQ::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
inst->Serialize(ob, slot_id);
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
// SharedBank items
|
||||
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
|
||||
const EQ::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
// SharedBank items
|
||||
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
|
||||
const EQ::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
inst->Serialize(ob, slot_id);
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
@@ -1034,32 +1036,62 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I
|
||||
name, (uint16)spells[SpellID].base_value[0],
|
||||
SpellID, ZoneID, InstanceID);
|
||||
|
||||
if (RuleB(Spells, BuffsFadeOnDeath)) {
|
||||
BuffFadeNonPersistDeath();
|
||||
}
|
||||
const bool use_old_resurrection = (
|
||||
RuleB(Character, UseOldRaceRezEffects) &&
|
||||
(
|
||||
GetRace() == Race::Barbarian ||
|
||||
GetRace() == Race::Dwarf ||
|
||||
GetRace() == Race::Troll ||
|
||||
GetRace() == Race::Ogre
|
||||
)
|
||||
);
|
||||
|
||||
const uint16 resurrection_sickness_spell_id = (
|
||||
use_old_resurrection ?
|
||||
RuleI(Character, OldResurrectionSicknessSpellID) :
|
||||
RuleI(Character, ResurrectionSicknessSpellID)
|
||||
);
|
||||
|
||||
int SpellEffectDescNum = GetSpellEffectDescriptionNumber(SpellID);
|
||||
// Rez spells with Rez effects have this DescNum (first is Titanium, second is 6.2 Client)
|
||||
if(RuleB(Character, UseResurrectionSickness) && SpellEffectDescNum == 82 || SpellEffectDescNum == 39067) {
|
||||
SetHP(GetMaxHP() / 5);
|
||||
SetMana(0);
|
||||
int resurrection_sickness_spell_id = (
|
||||
RuleB(Character, UseOldRaceRezEffects) &&
|
||||
(
|
||||
GetRace() == BARBARIAN ||
|
||||
GetRace() == DWARF ||
|
||||
GetRace() == TROLL ||
|
||||
GetRace() == OGRE
|
||||
) ?
|
||||
RuleI(Character, OldResurrectionSicknessSpellID) :
|
||||
RuleI(Character, ResurrectionSicknessSpellID)
|
||||
);
|
||||
|
||||
if (RuleB(Spells, BuffsFadeOnDeath)) {
|
||||
BuffFadeNonPersistDeath();
|
||||
}
|
||||
|
||||
SpellOnTarget(resurrection_sickness_spell_id, this);
|
||||
} else if (SpellID == SPELL_DIVINE_REZ) {
|
||||
if (RuleB(Spells, BuffsFadeOnDeath)) {
|
||||
BuffFadeNonPersistDeath();
|
||||
}
|
||||
|
||||
RestoreHealth();
|
||||
RestoreMana();
|
||||
RestoreEndurance();
|
||||
} else {
|
||||
if (RuleB(Character, UseResurrectionSickness)) {
|
||||
bool has_resurrection_sickness = false;
|
||||
|
||||
for (int slot = 0; slot < GetMaxTotalSlots(); slot++) {
|
||||
if (IsValidSpell(buffs[slot].spellid) && IsResurrectionSicknessSpell(buffs[slot].spellid)){
|
||||
has_resurrection_sickness = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to wipe buffs after checking if client had rez effects.
|
||||
if (RuleB(Spells, BuffsFadeOnDeath)) {
|
||||
BuffFadeNonPersistDeath();
|
||||
}
|
||||
|
||||
if (has_resurrection_sickness) {
|
||||
SpellOnTarget(resurrection_sickness_spell_id, this);
|
||||
}
|
||||
}
|
||||
|
||||
SetHP(GetMaxHP() / 20);
|
||||
SetMana(GetMaxMana() / 20);
|
||||
SetEndurance(GetMaxEndurance() / 20);
|
||||
@@ -1718,7 +1750,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);
|
||||
|
||||
+3
-1
@@ -112,7 +112,7 @@ int command_init(void)
|
||||
command_add("delpetition", "[petition number] - Delete a petition", AccountStatus::ApprenticeGuide, command_delpetition) ||
|
||||
command_add("depop", "[Start Spawn Timer] - Depop your NPC target and optionally start their spawn timer (false by default)", AccountStatus::Guide, command_depop) ||
|
||||
command_add("depopzone", "[Start Spawn Timers] - Depop the zone and optionally start spawn timers (false by default)", AccountStatus::GMAdmin, command_depopzone) ||
|
||||
command_add("devtools", "[Enable|Disable] - Manages Developer Tools (send no parameter for menu)", AccountStatus::GMMgmt, command_devtools) ||
|
||||
command_add("devtools", "[menu|window] [enable|disable] - Manages Developer Tools (send no parameter for menu)", AccountStatus::GMMgmt, command_devtools) ||
|
||||
command_add("disablerecipe", "[Recipe ID] - Disables a Recipe", AccountStatus::QuestTroupe, command_disablerecipe) ||
|
||||
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", AccountStatus::QuestTroupe, command_disarmtrap) ||
|
||||
command_add("door", "Door editing command", AccountStatus::QuestTroupe, command_door) ||
|
||||
@@ -134,6 +134,7 @@ int command_init(void)
|
||||
command_add("fish", "Fish for an item", AccountStatus::QuestTroupe, command_fish) ||
|
||||
command_add("fixmob", "[race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev] - Manipulate appearance of your target", AccountStatus::QuestTroupe, command_fixmob) ||
|
||||
command_add("flagedit", "Edit zone flags on your target. Use #flagedit help for more info.", AccountStatus::GMAdmin, command_flagedit) ||
|
||||
command_add("fleeinfo", "- Gives info about whether a NPC will flee or not, using the command issuer as top hate.", AccountStatus::QuestTroupe, command_fleeinfo) ||
|
||||
command_add("forage", "Forage an item", AccountStatus::QuestTroupe, command_forage) ||
|
||||
command_add("gearup", "Developer tool to quickly equip yourself or your target", AccountStatus::GMMgmt, command_gearup) ||
|
||||
command_add("giveitem", "[itemid] [charges] - Summon an item onto your target's cursor. Charges are optional.", AccountStatus::GMMgmt, command_giveitem) ||
|
||||
@@ -829,6 +830,7 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/fish.cpp"
|
||||
#include "gm_commands/fixmob.cpp"
|
||||
#include "gm_commands/flagedit.cpp"
|
||||
#include "gm_commands/fleeinfo.cpp"
|
||||
#include "gm_commands/forage.cpp"
|
||||
#include "gm_commands/gearup.cpp"
|
||||
#include "gm_commands/giveitem.cpp"
|
||||
|
||||
+2
-1
@@ -87,6 +87,7 @@ void command_find(Client *c, const Seperator *sep);
|
||||
void command_fish(Client* c, const Seperator* sep);
|
||||
void command_fixmob(Client *c, const Seperator *sep);
|
||||
void command_flagedit(Client *c, const Seperator *sep);
|
||||
void command_fleeinfo(Client *c, const Seperator *sep);
|
||||
void command_forage(Client* c, const Seperator* sep);
|
||||
void command_gearup(Client *c, const Seperator *sep);
|
||||
void command_giveitem(Client *c, const Seperator *sep);
|
||||
@@ -136,7 +137,7 @@ void command_nukebuffs(Client *c, const Seperator *sep);
|
||||
void command_nukeitem(Client *c, const Seperator *sep);
|
||||
void command_object(Client *c, const Seperator *sep);
|
||||
void command_oocmute(Client *c, const Seperator *sep);
|
||||
void command_parcels(Client *c, const Seperator *sep);
|
||||
void command_parcels(Client *c, const Seperator *sep);
|
||||
void command_path(Client *c, const Seperator *sep);
|
||||
void command_peqzone(Client *c, const Seperator *sep);
|
||||
void command_petitems(Client *c, const Seperator *sep);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user