mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-28 09:45:45 +00:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d194083aa | |||
| dd41fc5fcd | |||
| 6bf36f3e77 | |||
| dfb06db17b | |||
| 3e958c575b | |||
| e5db19965f | |||
| ce73f6bfe1 | |||
| 700f4645e2 | |||
| 5a7d544c5b | |||
| 0f7f71334a | |||
| c731f3f560 | |||
| b30fbc70a3 | |||
| 195cb80d56 | |||
| b2d5007466 | |||
| 47e2eb0acf | |||
| c36b3f030b | |||
| 2b821e50ff | |||
| 0aa07e9529 | |||
| 7ddafd9ed8 | |||
| 5488e9bf22 | |||
| 6db6d7dca9 | |||
| 066b762e73 | |||
| cd85a8524a | |||
| 4490a53ba0 | |||
| 00eb462d47 | |||
| 2df7d19f97 | |||
| 48c6db3a9c | |||
| cce368d94c | |||
| 84b8bdd2b4 | |||
| fc8ace91cb | |||
| 2d6c9f881a | |||
| 9b72c07a54 | |||
| 9d5d13fbd0 | |||
| bc3e9e8fba | |||
| d9cfc3a858 | |||
| 51dc62dfb1 | |||
| e52e4d5b3f | |||
| 0c3149a6e5 | |||
| 611122833d | |||
| b83373491e | |||
| dfa349492c | |||
| c08200188f | |||
| 41d9a15c74 | |||
| 2ed4effbe3 | |||
| 6ec09f300a | |||
| 079f612730 | |||
| 2c971fb2de | |||
| 20e9a8b2d2 | |||
| 8fa6a0b496 | |||
| d6e1c3f187 | |||
| 70a4b6a2b1 | |||
| 7923d7bc6c | |||
| 6007ba454c | |||
| d4a78f4799 | |||
| 0ada53aa96 | |||
| 7803170d6b | |||
| 20778ad7d9 | |||
| 44d63c47d9 | |||
| b288202c96 | |||
| a724e92638 | |||
| 0ea825e9a4 | |||
| 2ca50b339d | |||
| 164fe31fa8 | |||
| f3de3e8c31 | |||
| 1227f35382 | |||
| c0769a9c29 | |||
| 2dd0e51936 | |||
| fd787af53a | |||
| aa39ac8023 | |||
| 397096996c | |||
| f8de9b9167 | |||
| 9d48cbcd29 | |||
| eb5eb0ca30 | |||
| bc4bebb4a9 | |||
| 05f09b56e6 | |||
| 411fe3d95d | |||
| c1e984dfc1 | |||
| a5d9a8596a | |||
| 7e23d798d5 | |||
| 47ab8910a3 | |||
| 259add68f5 | |||
| d2f5dc43a6 | |||
| 99d2e3a8b1 | |||
| 122fe398b4 | |||
| 43c4b13978 | |||
| a3a707adae | |||
| c4da9766a4 | |||
| a8eb2832ce | |||
| 076aab50e8 | |||
| 1e8889a9fc | |||
| 7c3481daf9 | |||
| b93dec357f | |||
| 2f4af4f0c2 | |||
| a0f2a8a743 | |||
| 4c7016bd7b | |||
| 6c18cd0bee | |||
| 87e63e1e36 | |||
| a771882cff | |||
| b3f6a8c55f | |||
| 605502cd9d | |||
| 4712ca471b | |||
| 836c3d6596 | |||
| 53169ae217 | |||
| fd31915fae | |||
| 52763b6dd2 | |||
| 51cd43b4ea | |||
| 2db84f5a4f | |||
| 79cc2d5351 | |||
| d31cb09214 | |||
| 8bedcd8751 | |||
| 473c5096f6 | |||
| 0b181d5048 | |||
| a7e9af2d27 | |||
| 7a72d5d67e | |||
| 25872203ff | |||
| 6396a6fbef | |||
| 6db0a5c3f0 | |||
| 4fa9e1d66f | |||
| 556af8c5e9 | |||
| f3ef8a0993 | |||
| 267c280db8 | |||
| e06c7d7735 | |||
| 028ebc3a0c | |||
| b3bd44cd76 | |||
| 75a627a3a2 | |||
| 0194aedc92 | |||
| 5cc87cbda7 | |||
| 703862d977 | |||
| 6e325c1ee3 | |||
| 933b83add6 | |||
| b3cd4e63f1 | |||
| 3c894cb533 | |||
| b19ad64800 | |||
| 2cd3d27c67 | |||
| d3b46becd0 | |||
| 286479198f | |||
| 21ec832ca6 | |||
| bdf5f8b4a3 | |||
| 4ca6485398 | |||
| 0c9c2e25c1 | |||
| 7e651877c7 | |||
| 9739c1c8ef | |||
| 8aae59eebe | |||
| c1b07afae9 | |||
| 9c238cd08d | |||
| 33adb9bcc1 | |||
| 2e8bf82861 | |||
| 4d118ab978 |
+1
-1
@@ -15,7 +15,7 @@ volumes:
|
||||
|
||||
steps:
|
||||
- name: Build Linux X64
|
||||
image: akkadius/eqemu-server:v13
|
||||
image: akkadius/eqemu-server:v14
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
|
||||
+284
@@ -1,3 +1,287 @@
|
||||
## [22.41.0] - 1/8/2024
|
||||
|
||||
### Bug
|
||||
|
||||
* DI Buff Fade ([#3919](https://github.com/EQEmu/Server/pull/3919)) @fryguy503 2024-01-08
|
||||
* NPCs will now only proc on hit ([#3913](https://github.com/EQEmu/Server/pull/3913)) @fryguy503 2024-01-08
|
||||
* Pets should not ignore Z axis ([#3912](https://github.com/EQEmu/Server/pull/3912)) @fryguy503 2024-01-08
|
||||
|
||||
### Fixes
|
||||
|
||||
* Disciplines should show when someone casts them. ([#3901](https://github.com/EQEmu/Server/pull/3901)) @fryguy503 2024-01-08
|
||||
* Fix Typo in Character Skills loading ([#3937](https://github.com/EQEmu/Server/pull/3937)) @Kinglykrab 2024-01-09
|
||||
* Fix for HasLockoutByCharacterID ([#3927](https://github.com/EQEmu/Server/pull/3927)) @fryguy503 2024-01-08
|
||||
* Harm Touch, Improved Harm Touch, and Unholy Touch ([#3904](https://github.com/EQEmu/Server/pull/3904)) @fryguy503 2024-01-08
|
||||
* Legacy Manaburn should have hard cap. ([#3905](https://github.com/EQEmu/Server/pull/3905)) @fryguy503 2024-01-08
|
||||
* TGB - Added logic to stop bard errors on group songs. ([#3906](https://github.com/EQEmu/Server/pull/3906)) @fryguy503 2024-01-08
|
||||
* World Shutdown Filter ([#3930](https://github.com/EQEmu/Server/pull/3930)) @fryguy503 2024-01-08
|
||||
|
||||
### Info
|
||||
|
||||
* Adding textual feedback when trying to sell alt items back to … ([#3917](https://github.com/EQEmu/Server/pull/3917)) @fryguy503 2024-01-08
|
||||
|
||||
### Rules
|
||||
|
||||
* Backstab Damage Modifier ([#3908](https://github.com/EQEmu/Server/pull/3908)) @fryguy503 2024-01-08
|
||||
* Classic Tradeskill Skill Clamp ([#3914](https://github.com/EQEmu/Server/pull/3914)) @fryguy503 2024-01-08
|
||||
* Classic Triple Attack ([#3903](https://github.com/EQEmu/Server/pull/3903)) @fryguy503 2024-01-08
|
||||
* Ensure mana taps only effect NPC's that have mana. ([#3907](https://github.com/EQEmu/Server/pull/3907)) @fryguy503 2024-01-08
|
||||
* Over Taunt Hate ([#3900](https://github.com/EQEmu/Server/pull/3900)) @fryguy503 2024-01-08
|
||||
* Stun Chance Percent Rule ([#3922](https://github.com/EQEmu/Server/pull/3922)) @fryguy503 2024-01-08
|
||||
|
||||
## [22.40.0] - 1/7/2024
|
||||
|
||||
### Account
|
||||
|
||||
* Convert Get/Update Account Karma to Repositories ([#3858](https://github.com/EQEmu/Server/pull/3858)) @Kinglykrab 2024-01-07
|
||||
* Convert UpdateGMStatus to Repositories ([#3859](https://github.com/EQEmu/Server/pull/3859)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Bots
|
||||
|
||||
* Resist Spell Fix ([#3840](https://github.com/EQEmu/Server/pull/3840)) @dariusuknuis 2024-01-07
|
||||
|
||||
### Bugfix
|
||||
|
||||
* Negative Aggro Fix ([#3866](https://github.com/EQEmu/Server/pull/3866)) @fryguy503 2024-01-07
|
||||
|
||||
### Character
|
||||
|
||||
* Convert Clear/Delete/Get/Update of Character Item Recast to Repositories ([#3857](https://github.com/EQEmu/Server/pull/3857)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Remove/Save of Character AA to Repositories ([#3849](https://github.com/EQEmu/Server/pull/3849)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Save of Character Bandolier to Repositories ([#3845](https://github.com/EQEmu/Server/pull/3845)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Save of Character Disciplines to Repositories ([#3850](https://github.com/EQEmu/Server/pull/3850)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Save of Character Leadership Abilities to Repositories ([#3847](https://github.com/EQEmu/Server/pull/3847)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Save of Character Material to Repositories ([#3846](https://github.com/EQEmu/Server/pull/3846)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Load/Save of Character Spells to Repositories ([#3842](https://github.com/EQEmu/Server/pull/3842)) @Kinglykrab 2024-01-07
|
||||
* Convert Delete/Save of Character Memmed Spells to Repositories ([#3841](https://github.com/EQEmu/Server/pull/3841)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Bind to Repositories ([#3851](https://github.com/EQEmu/Server/pull/3851)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Buffs to Repositories ([#3855](https://github.com/EQEmu/Server/pull/3855)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Currency to Repositories ([#3848](https://github.com/EQEmu/Server/pull/3848)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Data to Repositories ([#3839](https://github.com/EQEmu/Server/pull/3839)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Potion Belt to Repositories ([#3844](https://github.com/EQEmu/Server/pull/3844)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Save of Character Skills to Repositories ([#3843](https://github.com/EQEmu/Server/pull/3843)) @Kinglykrab 2024-01-07
|
||||
* Convert Load/Update of Character Alternate Currencies to Repositories ([#3856](https://github.com/EQEmu/Server/pull/3856)) @Kinglykrab 2024-01-07
|
||||
* Convert NoRentExpired to Repositories ([#3860](https://github.com/EQEmu/Server/pull/3860)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Characters
|
||||
|
||||
* Convert Load/Save of Character Auras to Repositories ([#3854](https://github.com/EQEmu/Server/pull/3854)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Code
|
||||
|
||||
* Remove bot-based saylink method ([#3852](https://github.com/EQEmu/Server/pull/3852)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Commands
|
||||
|
||||
* Add #clearxtargets Command ([#3833](https://github.com/EQEmu/Server/pull/3833)) @Kinglykrab 2024-01-07
|
||||
* Add scoped buckets and editing to #databuckets ([#3826](https://github.com/EQEmu/Server/pull/3826)) @Kinglykrab 2024-01-07
|
||||
* Cleanup #appearance Command ([#3827](https://github.com/EQEmu/Server/pull/3827)) @Kinglykrab 2024-01-07
|
||||
* Cleanup #fixmob Command ([#3828](https://github.com/EQEmu/Server/pull/3828)) @Kinglykrab 2024-01-07
|
||||
* Cleanup #petname Command ([#3829](https://github.com/EQEmu/Server/pull/3829)) @Kinglykrab 2024-01-07
|
||||
* Cleanup #shutdown Command ([#3830](https://github.com/EQEmu/Server/pull/3830)) @Kinglykrab 2024-01-07
|
||||
* Remove #zopp Command ([#3831](https://github.com/EQEmu/Server/pull/3831)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Crash
|
||||
|
||||
* Fix crash where Raid invite could be accepted after forming group with the Raid invitor. ([#3837](https://github.com/EQEmu/Server/pull/3837)) @Aeadoin 2024-01-06
|
||||
|
||||
### Feature
|
||||
|
||||
* Break Trader if moved ([#3862](https://github.com/EQEmu/Server/pull/3862)) @fryguy503 2024-01-07
|
||||
* Formula Addition (40+ Harm Touch) ([#3870](https://github.com/EQEmu/Server/pull/3870)) @fryguy503 2024-01-07
|
||||
* Legacy Fizzle Code ([#3868](https://github.com/EQEmu/Server/pull/3868)) @fryguy503 2024-01-07
|
||||
* Legacy Manaburn Rule ([#3872](https://github.com/EQEmu/Server/pull/3872)) @fryguy503 2024-01-07
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add locations where melee can be bound outside of a city. ([#3887](https://github.com/EQEmu/Server/pull/3887)) @fryguy503 2024-01-07
|
||||
* Amplification should not benefit from instrument mods ([#3898](https://github.com/EQEmu/Server/pull/3898)) @fryguy503 2024-01-07
|
||||
* Bard Caster Level Fixes ([#3883](https://github.com/EQEmu/Server/pull/3883)) @fryguy503 2024-01-07
|
||||
* Buff Sync ([#3896](https://github.com/EQEmu/Server/pull/3896)) @fryguy503 2024-01-07
|
||||
* Cancel Magic SE fix ([#3890](https://github.com/EQEmu/Server/pull/3890)) @fryguy503 2024-01-07
|
||||
* Class Trainers dont steal your money! ([#3864](https://github.com/EQEmu/Server/pull/3864)) @fryguy503 2024-01-07
|
||||
* Clear Ramp when Clearing hate ([#3892](https://github.com/EQEmu/Server/pull/3892)) @fryguy503 2024-01-07
|
||||
* DI/Death Pact Fix ([#3867](https://github.com/EQEmu/Server/pull/3867)) @fryguy503 2024-01-07
|
||||
* Depop Charm Pet and Detach Debuffs on Evacuate ([#3888](https://github.com/EQEmu/Server/pull/3888)) @fryguy503 2024-01-07
|
||||
* Dire Charm Reset ([#3875](https://github.com/EQEmu/Server/pull/3875)) @fryguy503 2024-01-07
|
||||
* Disciplines Getting Focuses Fix ([#3884](https://github.com/EQEmu/Server/pull/3884)) @fryguy503 2024-01-07
|
||||
* Fix issue with 9th/10th inventory slot ([#3835](https://github.com/EQEmu/Server/pull/3835)) @Kinglykrab 2024-01-03
|
||||
* Fix typo on ZoneDatabase::LoadPetInfo ([#3871](https://github.com/EQEmu/Server/pull/3871)) @Kinglykrab 2024-01-07
|
||||
* Harm Touch Unholy Disc Type ([#3874](https://github.com/EQEmu/Server/pull/3874)) @fryguy503 2024-01-07
|
||||
* Prevent QS Crashes ([#3877](https://github.com/EQEmu/Server/pull/3877)) @fryguy503 2024-01-07
|
||||
* Rez Effects Stacking ([#3882](https://github.com/EQEmu/Server/pull/3882)) @fryguy503 2024-01-07
|
||||
* Rez in zone clear aggro ([#3895](https://github.com/EQEmu/Server/pull/3895)) @fryguy503 2024-01-07
|
||||
* Rune Invis Break ([#3893](https://github.com/EQEmu/Server/pull/3893)) @fryguy503 2024-01-07
|
||||
* Snare and DOT Stacking ([#3897](https://github.com/EQEmu/Server/pull/3897)) @fryguy503 2024-01-07
|
||||
* Swim Skillup and Underwater Fall Damage Fix ([#3885](https://github.com/EQEmu/Server/pull/3885)) @fryguy503 2024-01-07
|
||||
* Swimming Rules Adjustment and Racial ([#3889](https://github.com/EQEmu/Server/pull/3889)) @fryguy503 2024-01-07
|
||||
* Target Locked Pet Taunt ([#3894](https://github.com/EQEmu/Server/pull/3894)) @fryguy503 2024-01-07
|
||||
* Vampiric Embrace Fixes ([#3873](https://github.com/EQEmu/Server/pull/3873)) @fryguy503 2024-01-07
|
||||
|
||||
### Languages
|
||||
|
||||
* Cleanup language constants, use repositories ([#3838](https://github.com/EQEmu/Server/pull/3838)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Pets
|
||||
|
||||
* Convert Load/Save of Pet Info to Repositories ([#3853](https://github.com/EQEmu/Server/pull/3853)) @Kinglykrab 2024-01-07
|
||||
|
||||
### Rules
|
||||
|
||||
* Casting Charm on over level = Aggro ([#3886](https://github.com/EQEmu/Server/pull/3886)) @fryguy503 2024-01-07
|
||||
* Classic Invite Requires Target ([#3878](https://github.com/EQEmu/Server/pull/3878)) @fryguy503 2024-01-07
|
||||
* Evac Aggro Wipe ([#3880](https://github.com/EQEmu/Server/pull/3880)) @fryguy503 2024-01-07
|
||||
* Mounts will wear off on zone ([#3865](https://github.com/EQEmu/Server/pull/3865)) @fryguy503 2024-01-07
|
||||
* PC Push and NPCtoNPC Push ([#3879](https://github.com/EQEmu/Server/pull/3879)) @fryguy503 2024-01-07
|
||||
* RequireMnemonicRetention for Spells 9-12 Rule ([#3876](https://github.com/EQEmu/Server/pull/3876)) @fryguy503 2024-01-07
|
||||
* Resist Softcap rules ([#3863](https://github.com/EQEmu/Server/pull/3863)) @fryguy503 2024-01-07
|
||||
* Restrict Finishing Blow to only Fleeing NPC's. ([#3869](https://github.com/EQEmu/Server/pull/3869)) @fryguy503 2024-01-07
|
||||
* Undead Aggro ([#3881](https://github.com/EQEmu/Server/pull/3881)) @fryguy503 2024-01-07
|
||||
|
||||
### Tuning
|
||||
|
||||
* FD and Sneak break when cast on adjustments. ([#3861](https://github.com/EQEmu/Server/pull/3861)) @fryguy503 2024-01-07
|
||||
|
||||
### UCS
|
||||
|
||||
* Consolidate configuration block ([#3768](https://github.com/EQEmu/Server/pull/3768)) @Akkadius 2024-01-07
|
||||
|
||||
## [22.39.1] - 12/31/2023
|
||||
|
||||
### Code
|
||||
|
||||
* Appearance not appearence ([#3819](https://github.com/EQEmu/Server/pull/3819)) @Kinglykrab 2023-12-30
|
||||
* Delete errmsg.h in common and zone ([#3821](https://github.com/EQEmu/Server/pull/3821)) @Kinglykrab 2023-12-30
|
||||
* Gender constants cleanup ([#3817](https://github.com/EQEmu/Server/pull/3817)) @Kinglykrab 2023-12-30
|
||||
* Remove MakeSpawnUpdateNoDelta from mob.cpp/mob.h ([#3816](https://github.com/EQEmu/Server/pull/3816)) @Kinglykrab 2023-12-31
|
||||
* Remove SendStunAppearance from mob.cpp/mob.h ([#3818](https://github.com/EQEmu/Server/pull/3818)) @Kinglykrab 2023-12-31
|
||||
* Remove unused PlotPosition methods from mob.cpp/mob.h ([#3820](https://github.com/EQEmu/Server/pull/3820)) @Kinglykrab 2023-12-31
|
||||
|
||||
### Database
|
||||
|
||||
* Database update improvements, content db and terminal checks ([#3814](https://github.com/EQEmu/Server/pull/3814)) @Akkadius 2023-12-31
|
||||
|
||||
### Fixes
|
||||
|
||||
* Client:SetBucket Overload Incorrectly Named ([#3825](https://github.com/EQEmu/Server/pull/3825)) @fryguy503 2023-12-30
|
||||
* Fix crash in Client::Handle_OP_GMGoto ([#3832](https://github.com/EQEmu/Server/pull/3832)) @Kinglykrab 2023-12-31
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add HasItemOnCorpse() to Perl/Lua ([#3824](https://github.com/EQEmu/Server/pull/3824)) @Kinglykrab 2023-12-31
|
||||
* Fix issue with death events. ([#3823](https://github.com/EQEmu/Server/pull/3823)) @Kinglykrab 2023-12-31
|
||||
|
||||
### Repositories
|
||||
|
||||
* Protected extended repositories from being overwritten if exists ([#3815](https://github.com/EQEmu/Server/pull/3815)) @Akkadius 2023-12-31
|
||||
|
||||
## [22.39.0] - 12/27/2023
|
||||
|
||||
### Character
|
||||
|
||||
* Fix character copier due to schema change ([#3805](https://github.com/EQEmu/Server/pull/3805)) @Akkadius 2023-12-28
|
||||
|
||||
### Combat
|
||||
|
||||
* Disarm was not dropping item to ground due to bug ([#3811](https://github.com/EQEmu/Server/pull/3811)) @noudess 2023-12-27
|
||||
|
||||
### Logs
|
||||
|
||||
* Bulk insert new log settings ([#3810](https://github.com/EQEmu/Server/pull/3810)) @Akkadius 2023-12-28
|
||||
* Reclassify unhelpful Info message ([#3809](https://github.com/EQEmu/Server/pull/3809)) @Akkadius 2023-12-28
|
||||
|
||||
### MySQL
|
||||
|
||||
* Fix MySQL Query error formatting ([#3808](https://github.com/EQEmu/Server/pull/3808)) @Akkadius 2023-12-28
|
||||
|
||||
### Objects
|
||||
|
||||
* Remove "No objects to load for zone" error message ([#3807](https://github.com/EQEmu/Server/pull/3807)) @Akkadius 2023-12-28
|
||||
|
||||
### Player Events
|
||||
|
||||
* Bulk replace settings on boot ([#3806](https://github.com/EQEmu/Server/pull/3806)) @Akkadius 2023-12-28
|
||||
|
||||
### Tasks
|
||||
|
||||
* Add enabled column ([#3804](https://github.com/EQEmu/Server/pull/3804)) @Akkadius 2023-12-28
|
||||
|
||||
## [22.38.0] - 12/26/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Remove unnecessary error on SetItemReuse ([#3795](https://github.com/EQEmu/Server/pull/3795)) @nytmyr 2023-12-20
|
||||
|
||||
### Code
|
||||
|
||||
* Consolidate GetHateRandom(), GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() ([#3794](https://github.com/EQEmu/Server/pull/3794)) @Kinglykrab 2023-12-25
|
||||
* Race constants refactor ([#3782](https://github.com/EQEmu/Server/pull/3782)) @Akkadius 2023-12-23
|
||||
|
||||
### Database
|
||||
|
||||
* Fix issue with saylinks query in MySQL 8.0+ ([#3800](https://github.com/EQEmu/Server/pull/3800)) @Akkadius 2023-12-24
|
||||
* Update faction mods with Live data ([#3799](https://github.com/EQEmu/Server/pull/3799)) @joligario 2023-12-23
|
||||
|
||||
### Fixes
|
||||
|
||||
* Disable Hide/Improved Hide on Trap damage ([#3791](https://github.com/EQEmu/Server/pull/3791)) @Kinglykrab 2023-12-19
|
||||
* Fix Bard Invisibility Songs breaking every 4 ticks ([#3783](https://github.com/EQEmu/Server/pull/3783)) @Kinglykrab 2023-12-19
|
||||
* Fix can_riposte parameter in DoMeleeSkillAttackDmg ([#3792](https://github.com/EQEmu/Server/pull/3792)) @Kinglykrab 2023-12-19
|
||||
|
||||
### Forage
|
||||
|
||||
* Add a rule to disabled using common_food_ids from the list in forage.cpp. currently set to enabled. ([#3796](https://github.com/EQEmu/Server/pull/3796)) @regneq 2023-12-22
|
||||
|
||||
### NPC
|
||||
|
||||
* Support for multiple emotes per type, emote variables ([#3801](https://github.com/EQEmu/Server/pull/3801)) @regneq 2023-12-25
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add GetHateTopBot(), GetHateTopClient(), and GetHateTopNPC() to Perl/Lua ([#3793](https://github.com/EQEmu/Server/pull/3793)) @Kinglykrab 2023-12-22
|
||||
* Add SummonItemIntoInventory() to Perl/Lua ([#3797](https://github.com/EQEmu/Server/pull/3797)) @Kinglykrab 2023-12-22
|
||||
|
||||
### Repositories
|
||||
|
||||
* Add ReplaceOne and ReplaceMany ([#3802](https://github.com/EQEmu/Server/pull/3802)) @Akkadius 2023-12-26
|
||||
|
||||
## [22.37.0] - 12/18/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Add ScanCloseMobs support to fix AEs ([#3786](https://github.com/EQEmu/Server/pull/3786)) @nytmyr 2023-12-18
|
||||
* Expand ^itemuse options ([#3756](https://github.com/EQEmu/Server/pull/3756)) @nytmyr 2023-12-17
|
||||
* Fix ^defensive from checking aggressive disciplines. ([#3787](https://github.com/EQEmu/Server/pull/3787)) @nytmyr 2023-12-18
|
||||
* Fix ^oo autodefend from sending bots/pets to invalid haters ([#3772](https://github.com/EQEmu/Server/pull/3772)) @nytmyr 2023-12-16
|
||||
* Fix unnecessary failed to save timer error ([#3788](https://github.com/EQEmu/Server/pull/3788)) @nytmyr 2023-12-18
|
||||
* [Quest API] Add ^clickitem, ^timer, fix GetBestBotSpellForCure ([#3755](https://github.com/EQEmu/Server/pull/3755)) @nytmyr 2023-12-17
|
||||
|
||||
### CI
|
||||
|
||||
* Switch to use clang for Linux builds (speed) ([#3777](https://github.com/EQEmu/Server/pull/3777)) @Akkadius 2023-12-17
|
||||
|
||||
### Compilation
|
||||
|
||||
* Use pre-compiled headers for Windows (speed) ([#3778](https://github.com/EQEmu/Server/pull/3778)) @Akkadius 2023-12-18
|
||||
|
||||
### Fixes
|
||||
|
||||
* Drop Invisibility when hit by traps ([#3785](https://github.com/EQEmu/Server/pull/3785)) @Kinglykrab 2023-12-18
|
||||
* Fix NPCs routing to 0.0, 0.0 on #summon ([#3780](https://github.com/EQEmu/Server/pull/3780)) @Kinglykrab 2023-12-18
|
||||
* Fix bad merge @Akkadius 2023-12-17
|
||||
* Fix issue with HOTBonusHealingSplitOverDuration Rule ([#3776](https://github.com/EQEmu/Server/pull/3776)) @Kinglykrab 2023-12-17
|
||||
* Fixed the discrepacy with time using command #time and in quests. ([#3767](https://github.com/EQEmu/Server/pull/3767)) @regneq 2023-12-17
|
||||
* Send Entity ID in Death Events to resolve #3721 ([#3779](https://github.com/EQEmu/Server/pull/3779)) @Kinglykrab 2023-12-18
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add EVENT_ALT_CURRENCY_GAIN and EVENT_ALT_CURRENCY_LOSS to Perl/Lua ([#3734](https://github.com/EQEmu/Server/pull/3734)) @Kinglykrab 2023-12-17
|
||||
* Add EVENT_CRYSTAL_GAIN and EVENT_CRYSTAL_LOSS to Perl/Lua ([#3735](https://github.com/EQEmu/Server/pull/3735)) @Kinglykrab 2023-12-17
|
||||
* Add EVENT_LDON_POINTS_GAIN and EVENT_LDON_POINTS_LOSS to Perl/Lua ([#3742](https://github.com/EQEmu/Server/pull/3742)) @Kinglykrab 2023-12-17
|
||||
* Add EVENT_LEVEL_UP and EVENT_LEVEL_DOWN to Bots ([#3750](https://github.com/EQEmu/Server/pull/3750)) @Kinglykrab 2023-12-17
|
||||
* Add EVENT_LOOT_ADDED to Perl/Lua ([#3739](https://github.com/EQEmu/Server/pull/3739)) @Kinglykrab 2023-12-17
|
||||
* Add GetNPCAggro() and SetNPCAggro() to Perl/Lua ([#3781](https://github.com/EQEmu/Server/pull/3781)) @Kinglykrab 2023-12-18
|
||||
|
||||
## [22.36.0] - 12/16/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -17,6 +17,7 @@ SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
|
||||
OPTION(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
|
||||
|
||||
IF (EQEMU_BUILD_STATIC)
|
||||
SET(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
@@ -13,7 +13,6 @@ SET(common_sources
|
||||
crc32.cpp
|
||||
database/database_dump_service.cpp
|
||||
database.cpp
|
||||
database_conversions.cpp
|
||||
database_instances.cpp
|
||||
database/database_update_manifest.cpp
|
||||
database/database_update_manifest_bots.cpp
|
||||
@@ -541,7 +540,6 @@ SET(common_headers
|
||||
events/player_event_logs.h
|
||||
events/player_event_discord_formatter.h
|
||||
events/player_events.h
|
||||
errmsg.h
|
||||
event_sub.h
|
||||
expedition_lockout_timer.h
|
||||
extprofile.h
|
||||
@@ -563,7 +561,6 @@ SET(common_headers
|
||||
item_fieldlist.h
|
||||
item_instance.h
|
||||
json_config.h
|
||||
languages.h
|
||||
light_source.h
|
||||
linked_list.h
|
||||
loottable.h
|
||||
@@ -792,5 +789,8 @@ IF (UNIX)
|
||||
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
|
||||
ENDIF (UNIX)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
|
||||
ENDIF()
|
||||
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
+9
-1
@@ -2246,6 +2246,11 @@ bool Database::CopyCharacter(
|
||||
row = results.begin();
|
||||
std::string new_character_id = row[0];
|
||||
|
||||
std::vector<std::string> tables_to_zero_id = {
|
||||
"keyring",
|
||||
"data_buckets",
|
||||
};
|
||||
|
||||
TransactionBegin();
|
||||
for (const auto &iter : DatabaseSchema::GetCharacterTables()) {
|
||||
std::string table_name = iter.first;
|
||||
@@ -2279,6 +2284,10 @@ bool Database::CopyCharacter(
|
||||
std::string column = columns[column_index];
|
||||
std::string value = row[column_index] ? row[column_index] : "null";
|
||||
|
||||
if (column == "id" && Strings::Contains(tables_to_zero_id, table_name)) {
|
||||
value = "0";
|
||||
}
|
||||
|
||||
if (column == character_id_column_name) {
|
||||
value = new_character_id;
|
||||
}
|
||||
@@ -2326,7 +2335,6 @@ bool Database::CopyCharacter(
|
||||
if (!insert.ErrorMessage().empty()) {
|
||||
TransactionRollback();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +226,6 @@ public:
|
||||
|
||||
void PurgeAllDeletedDataBuckets();
|
||||
|
||||
/* Database Conversions 'database_conversions.cpp' */
|
||||
|
||||
bool CheckDatabaseConversions();
|
||||
bool CheckDatabaseConvertCorpseDeblob();
|
||||
bool CheckDatabaseConvertPPDeblob();
|
||||
|
||||
/* Database Variables */
|
||||
|
||||
|
||||
@@ -76,9 +76,9 @@ void DatabaseUpdate::CheckDbUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
std::string DatabaseUpdate::GetQueryResult(std::string query)
|
||||
std::string DatabaseUpdate::GetQueryResult(const ManifestEntry& e)
|
||||
{
|
||||
auto results = m_database->QueryDatabase(query);
|
||||
auto results = (e.content_schema_update ? m_content_database : m_database)->QueryDatabase(e.check);
|
||||
|
||||
std::vector<std::string> result_lines = {};
|
||||
|
||||
@@ -121,6 +121,16 @@ bool DatabaseUpdate::ShouldRunMigration(ManifestEntry &e, std::string query_resu
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if we are running in a terminal
|
||||
bool is_atty()
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
return ::_isatty(_fileno(stdin));
|
||||
#else
|
||||
return isatty(fileno(stdin));
|
||||
#endif
|
||||
}
|
||||
|
||||
// return true if we ran updates
|
||||
bool DatabaseUpdate::UpdateManifest(
|
||||
std::vector<ManifestEntry> entries,
|
||||
@@ -136,7 +146,7 @@ bool DatabaseUpdate::UpdateManifest(
|
||||
for (auto &e: entries) {
|
||||
if (e.version == version) {
|
||||
bool has_migration = true;
|
||||
std::string r = GetQueryResult(e.check);
|
||||
std::string r = GetQueryResult(e);
|
||||
if (ShouldRunMigration(e, r)) {
|
||||
has_migration = false;
|
||||
missing_migrations.emplace_back(e.version);
|
||||
@@ -179,7 +189,7 @@ bool DatabaseUpdate::UpdateManifest(
|
||||
if (e.version == m) {
|
||||
bool errored_migration = false;
|
||||
|
||||
auto r = m_database->QueryDatabaseMulti(e.sql);
|
||||
auto r = (e.content_schema_update ? m_content_database : m_database)->QueryDatabaseMulti(e.sql);
|
||||
|
||||
// ignore empty query result "errors"
|
||||
if (r.ErrorNumber() != 1065 && !r.ErrorMessage().empty()) {
|
||||
@@ -187,31 +197,38 @@ bool DatabaseUpdate::UpdateManifest(
|
||||
errored_migration = true;
|
||||
|
||||
LogInfo("Required database update failed. This could be a problem");
|
||||
LogInfo("Would you like to skip this update? [y/n] (Timeout 60s)");
|
||||
|
||||
// user input
|
||||
std::string input;
|
||||
bool gave_input = false;
|
||||
time_t start_time = time(nullptr);
|
||||
time_t wait_time_seconds = 60;
|
||||
// if terminal attached then prompt for skip
|
||||
if (is_atty()) {
|
||||
LogInfo("Would you like to skip this update? [y/n] (Timeout 60s)");
|
||||
|
||||
// spawn a concurrent thread that waits for input from std::cin
|
||||
std::thread t1(
|
||||
[&]() {
|
||||
std::cin >> input;
|
||||
gave_input = true;
|
||||
// user input
|
||||
std::string input;
|
||||
bool gave_input = false;
|
||||
time_t start_time = time(nullptr);
|
||||
time_t wait_time_seconds = 60;
|
||||
|
||||
// spawn a concurrent thread that waits for input from std::cin
|
||||
std::thread t1(
|
||||
[&]() {
|
||||
std::cin >> input;
|
||||
gave_input = true;
|
||||
}
|
||||
);
|
||||
t1.detach();
|
||||
|
||||
// check the inputReceived flag once every 50ms for 10 seconds
|
||||
while (time(nullptr) < start_time + wait_time_seconds && !gave_input) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
);
|
||||
t1.detach();
|
||||
|
||||
// check the inputReceived flag once every 50ms for 10 seconds
|
||||
while (time(nullptr) < start_time + wait_time_seconds && !gave_input) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
// prompt for user skip
|
||||
if (Strings::Trim(input) == "y") {
|
||||
errored_migration = false;
|
||||
// prompt for user skip
|
||||
if (Strings::Trim(input) == "y") {
|
||||
errored_migration = false;
|
||||
LogInfo("Skipping update [{}] [{}]", e.version, e.description);
|
||||
}
|
||||
} else {
|
||||
errored_migration = true;
|
||||
LogInfo("Skipping update [{}] [{}]", e.version, e.description);
|
||||
}
|
||||
}
|
||||
@@ -247,6 +264,13 @@ DatabaseUpdate *DatabaseUpdate::SetDatabase(Database *db)
|
||||
return this;
|
||||
}
|
||||
|
||||
DatabaseUpdate *DatabaseUpdate::SetContentDatabase(Database *db)
|
||||
{
|
||||
m_content_database = db;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
|
||||
{
|
||||
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
|
||||
|
||||
@@ -10,6 +10,7 @@ struct ManifestEntry {
|
||||
std::string condition{}; // condition or "match_type" - Possible values [contains|match|missing|empty|not_empty]
|
||||
std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
|
||||
std::string sql{}; // the SQL DDL that gets ran when the condition is true
|
||||
bool content_schema_update{}; // if true, this migration is a content schema update and should be ran against the content database
|
||||
};
|
||||
|
||||
struct DatabaseVersion {
|
||||
@@ -22,14 +23,16 @@ public:
|
||||
DatabaseVersion GetDatabaseVersions();
|
||||
DatabaseVersion GetBinaryDatabaseVersions();
|
||||
void CheckDbUpdates();
|
||||
std::string GetQueryResult(std::string query);
|
||||
std::string GetQueryResult(const ManifestEntry& e);
|
||||
static bool ShouldRunMigration(ManifestEntry &e, std::string query_result);
|
||||
bool UpdateManifest(std::vector<ManifestEntry> entries, int version_low, int version_high);
|
||||
|
||||
DatabaseUpdate *SetDatabase(Database *db);
|
||||
DatabaseUpdate *SetContentDatabase(Database *db);
|
||||
bool HasPendingUpdates();
|
||||
private:
|
||||
Database *m_database;
|
||||
Database *m_content_database;
|
||||
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
|
||||
void InjectBotsVersionColumn();
|
||||
};
|
||||
|
||||
@@ -5016,7 +5016,7 @@ CREATE TABLE `spawn2_disabled` (
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
INSERT INTO spawn2_disabled (spawn2_id, disabled) SELECT id, 1 FROM spawn2 WHERE enabled = 0;
|
||||
ALTER TABLE `spawn2` DROP COLUMN `enabled`;
|
||||
)"
|
||||
)",
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9242,
|
||||
@@ -5028,7 +5028,8 @@ ALTER TABLE `spawn2` DROP COLUMN `enabled`;
|
||||
ALTER TABLE `spawnentry`
|
||||
ADD COLUMN `min_time` smallint(4) NOT NULL DEFAULT 0 AFTER `condition_value_filter`,
|
||||
ADD COLUMN `max_time` smallint(4) NOT NULL DEFAULT 0 AFTER `min_time`;
|
||||
)"
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9243,
|
||||
@@ -5082,7 +5083,8 @@ INSERT INTO
|
||||
|
||||
DROP TABLE `starting_items`;
|
||||
RENAME TABLE `starting_items_new` TO `starting_items`;
|
||||
)"
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9244,
|
||||
@@ -5092,7 +5094,8 @@ RENAME TABLE `starting_items_new` TO `starting_items`;
|
||||
.match = "0000-00-00 00:00:00",
|
||||
.sql = R"(
|
||||
ALTER TABLE `items` MODIFY COLUMN `updated` datetime NULL DEFAULT NULL;
|
||||
)"
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9245,
|
||||
@@ -5104,7 +5107,8 @@ ALTER TABLE `items` MODIFY COLUMN `updated` datetime NULL DEFAULT NULL;
|
||||
ALTER TABLE `object` CHANGE COLUMN `unknown08` `size_percentage` float NOT NULL DEFAULT 0 AFTER `icon`;
|
||||
ALTER TABLE `object` CHANGE COLUMN `unknown10` `solid_type` mediumint(5) NOT NULL DEFAULT 0 AFTER `size`;
|
||||
ALTER TABLE `object` CHANGE COLUMN `unknown20` `incline` int(11) NOT NULL DEFAULT 0 AFTER `solid_type`;
|
||||
)"
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9246,
|
||||
@@ -5133,7 +5137,31 @@ CHANGE COLUMN `slot` `inventory_slot` mediumint(9) NOT NULL DEFAULT -1 AFTER `st
|
||||
|
||||
ALTER TABLE `starting_items`
|
||||
CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`;
|
||||
)"
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9248,
|
||||
.description = "2023_12_22_drop_npc_emotes_index.sql",
|
||||
.check = "show index from npc_emotes where key_name = 'emoteid'",
|
||||
.condition = "not_empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `npc_emotes` DROP INDEX `emoteid`;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9249,
|
||||
.description = "2023_12_26_add_tasks_enabled_column.sql",
|
||||
.check = "SHOW COLUMNS FROM `tasks` LIKE 'enabled'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `tasks`
|
||||
ADD COLUMN `enabled` smallint NULL DEFAULT 1 AFTER `faction_amount`
|
||||
)",
|
||||
.content_schema_update = true
|
||||
}
|
||||
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@@ -82,6 +82,28 @@ CREATE TABLE `bot_starting_items` (
|
||||
`content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci;
|
||||
)",
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9041,
|
||||
.description = "2023_12_04_bot_timers.sql",
|
||||
.check = "SHOW COLUMNS FROM `bot_timers` LIKE 'recast_time'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `bot_timers`
|
||||
ADD COLUMN `recast_time` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `timer_value`,
|
||||
ADD COLUMN `is_spell` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `recast_time`,
|
||||
ADD COLUMN `is_disc` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_spell`,
|
||||
ADD COLUMN `spell_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_disc`,
|
||||
ADD COLUMN `is_item` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `spell_id`,
|
||||
ADD COLUMN `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_item`;
|
||||
ALTER TABLE `bot_timers`
|
||||
DROP FOREIGN KEY `FK_bot_timers_1`;
|
||||
ALTER TABLE `bot_timers`
|
||||
DROP PRIMARY KEY;
|
||||
ALTER TABLE `bot_timers`
|
||||
ADD PRIMARY KEY (`bot_id`, `timer_id`, `spell_id`, `item_id`);
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/strings.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "database/database_update.h"
|
||||
|
||||
|
||||
// Disgrace: for windows compile
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
|
||||
#include "unix.h"
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
DatabaseUpdate database_update;
|
||||
|
||||
bool Database::CheckDatabaseConversions()
|
||||
{
|
||||
auto *r = RuleManager::Instance();
|
||||
r->LoadRules(this, "default", false);
|
||||
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
|
||||
LogInfo("Bot tables found but rule not enabled, enabling");
|
||||
r->SetRule("Bots:Enabled", "true", this, true, true);
|
||||
}
|
||||
|
||||
database_update.SetDatabase(this)->CheckDbUpdates();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace DatabaseSchema {
|
||||
{"character_tasks", "charid"},
|
||||
{"character_tribute", "character_id"},
|
||||
{"completed_tasks", "charid"},
|
||||
{"data_buckets", "id"},
|
||||
{"data_buckets", "character_id"},
|
||||
{"faction_values", "char_id"},
|
||||
{"friends", "charid"},
|
||||
{"guild_members", "char_id"},
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "dbcore.h"
|
||||
|
||||
#include <errmsg.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mysqld_error.h>
|
||||
@@ -138,7 +137,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
* Error logging
|
||||
*/
|
||||
if (mysql_errno(mysql) > 0 && query[0] != '\0') {
|
||||
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
|
||||
LogMySQLError("MySQL Error ({}) [{}] Query [{}]", mysql_errno(mysql), mysql_error(mysql), query);
|
||||
}
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <string.h>
|
||||
#include <mutex>
|
||||
|
||||
#define CR_SERVER_GONE_ERROR 2006
|
||||
#define CR_SERVER_LOST 2013
|
||||
|
||||
class DBcore {
|
||||
public:
|
||||
enum eStatus {
|
||||
|
||||
+92
-34
@@ -22,7 +22,6 @@
|
||||
#include "data_verification.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "eqemu_logsys_log_aliases.h"
|
||||
#include "languages.h"
|
||||
#include "rulesys.h"
|
||||
|
||||
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
|
||||
@@ -159,45 +158,45 @@ int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::map<int, std::string>& EQ::constants::GetLanguageMap()
|
||||
const std::map<uint8, std::string>& EQ::constants::GetLanguageMap()
|
||||
{
|
||||
static const std::map<int, std::string> language_map = {
|
||||
{ LANG_COMMON_TONGUE, "Common Tongue" },
|
||||
{ LANG_BARBARIAN, "Barbarian" },
|
||||
{ LANG_ERUDIAN, "Erudian" },
|
||||
{ LANG_ELVISH, "Elvish" },
|
||||
{ LANG_DARK_ELVISH, "Dark Elvish" },
|
||||
{ LANG_DWARVISH, "Dwarvish" },
|
||||
{ LANG_TROLL, "Troll" },
|
||||
{ LANG_OGRE, "Ogre" },
|
||||
{ LANG_GNOMISH, "Gnomish" },
|
||||
{ LANG_HALFLING, "Halfling" },
|
||||
{ LANG_THIEVES_CANT, "Thieves Cant" },
|
||||
{ LANG_OLD_ERUDIAN, "Old Erudian" },
|
||||
{ LANG_ELDER_ELVISH, "Elder Elvish" },
|
||||
{ LANG_FROGLOK, "Froglok" },
|
||||
{ LANG_GOBLIN, "Goblin" },
|
||||
{ LANG_GNOLL, "Gnoll" },
|
||||
{ LANG_COMBINE_TONGUE, "Combine Tongue" },
|
||||
{ LANG_ELDER_TEIRDAL, "Elder Teirdal" },
|
||||
{ LANG_LIZARDMAN, "Lizardman" },
|
||||
{ LANG_ORCISH, "Orcish" },
|
||||
{ LANG_FAERIE, "Faerie" },
|
||||
{ LANG_DRAGON, "Dragon" },
|
||||
{ LANG_ELDER_DRAGON, "Elder Dragon" },
|
||||
{ LANG_DARK_SPEECH, "Dark Speech" },
|
||||
{ LANG_VAH_SHIR, "Vah Shir" },
|
||||
{ LANG_ALARAN, "Alaran" },
|
||||
{ LANG_HADAL, "Hadal" },
|
||||
{ LANG_UNKNOWN, "Unknown" }
|
||||
static const std::map<uint8, std::string> language_map = {
|
||||
{ Language::CommonTongue, "Common Tongue" },
|
||||
{ Language::Barbarian, "Barbarian" },
|
||||
{ Language::Erudian, "Erudian" },
|
||||
{ Language::Elvish, "Elvish" },
|
||||
{ Language::DarkElvish, "Dark Elvish" },
|
||||
{ Language::Dwarvish, "Dwarvish" },
|
||||
{ Language::Troll, "Troll" },
|
||||
{ Language::Ogre, "Ogre" },
|
||||
{ Language::Gnomish, "Gnomish" },
|
||||
{ Language::Halfling, "Halfling" },
|
||||
{ Language::ThievesCant, "Thieves Cant" },
|
||||
{ Language::OldErudian, "Old Erudian" },
|
||||
{ Language::ElderElvish, "Elder Elvish" },
|
||||
{ Language::Froglok, "Froglok" },
|
||||
{ Language::Goblin, "Goblin" },
|
||||
{ Language::Gnoll, "Gnoll" },
|
||||
{ Language::CombineTongue, "Combine Tongue" },
|
||||
{ Language::ElderTeirDal, "Elder Teir'Dal" },
|
||||
{ Language::Lizardman, "Lizardman" },
|
||||
{ Language::Orcish, "Orcish" },
|
||||
{ Language::Faerie, "Faerie" },
|
||||
{ Language::Dragon, "Dragon" },
|
||||
{ Language::ElderDragon, "Elder Dragon" },
|
||||
{ Language::DarkSpeech, "Dark Speech" },
|
||||
{ Language::VahShir, "Vah Shir" },
|
||||
{ Language::Alaran, "Alaran" },
|
||||
{ Language::Hadal, "Hadal" },
|
||||
{ Language::Unknown27, "Unknown" }
|
||||
};
|
||||
|
||||
return language_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetLanguageName(int language_id)
|
||||
std::string EQ::constants::GetLanguageName(uint8 language_id)
|
||||
{
|
||||
if (!EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
if (!EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -509,7 +508,6 @@ 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;
|
||||
@@ -580,3 +578,63 @@ std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
|
||||
|
||||
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetAppearanceTypeMap()
|
||||
{
|
||||
static const std::map<uint32, std::string> appearance_type_map = {
|
||||
{ AppearanceType::Die, "Die" },
|
||||
{ AppearanceType::WhoLevel, "Who Level" },
|
||||
{ AppearanceType::MaxHealth, "Max Health" },
|
||||
{ AppearanceType::Invisibility, "Invisibility" },
|
||||
{ AppearanceType::PVP, "PVP" },
|
||||
{ AppearanceType::Light, "Light" },
|
||||
{ AppearanceType::Animation, "Animation" },
|
||||
{ AppearanceType::Sneak, "Sneak" },
|
||||
{ AppearanceType::SpawnID, "Spawn ID" },
|
||||
{ AppearanceType::Health, "Health" },
|
||||
{ AppearanceType::Linkdead, "Linkdead" },
|
||||
{ AppearanceType::FlyMode, "Fly Mode" },
|
||||
{ AppearanceType::GM, "GM" },
|
||||
{ AppearanceType::Anonymous, "Anonymous" },
|
||||
{ AppearanceType::GuildID, "Guild ID" },
|
||||
{ AppearanceType::GuildRank, "Guild Rank" },
|
||||
{ AppearanceType::AFK, "AFK" },
|
||||
{ AppearanceType::Pet, "Pet" },
|
||||
{ AppearanceType::Summoned, "Summoned" },
|
||||
{ AppearanceType::Split, "Split" },
|
||||
{ AppearanceType::Size, "Size" },
|
||||
{ AppearanceType::SetType, "Set Type" },
|
||||
{ AppearanceType::NPCName, "NPCName" },
|
||||
{ AppearanceType::AARank, "AARank" },
|
||||
{ AppearanceType::CancelSneakHide, "Cancel Sneak Hide" },
|
||||
{ AppearanceType::AreaHealthRegen, "Area Health Regeneration" },
|
||||
{ AppearanceType::AreaManaRegen, "Area Mana Regeneration" },
|
||||
{ AppearanceType::AreaEnduranceRegen, "Area Endurance Regeneration" },
|
||||
{ AppearanceType::FreezeBeneficialBuffs, "Freeze Beneficial Buffs" },
|
||||
{ AppearanceType::NPCTintIndex, "NPC Tint Index" },
|
||||
{ AppearanceType::GroupAutoConsent, "Group Auto Consent" },
|
||||
{ AppearanceType::RaidAutoConsent, "Raid Auto Consent" },
|
||||
{ AppearanceType::GuildAutoConsent, "Guild Auto Consent" },
|
||||
{ AppearanceType::ShowHelm, "Show Helm" },
|
||||
{ AppearanceType::DamageState, "Damage State" },
|
||||
{ AppearanceType::EQPlayers, "EQ Players" },
|
||||
{ AppearanceType::FindBits, "Find Bits" },
|
||||
{ AppearanceType::TextureType, "Texture Type" },
|
||||
{ AppearanceType::FacePick, "Face Pick" },
|
||||
{ AppearanceType::AntiCheat, "Anti Cheat" },
|
||||
{ AppearanceType::GuildShow, "Guild Show" },
|
||||
{ AppearanceType::OfflineMode, "Offline Mode" }
|
||||
};
|
||||
|
||||
return appearance_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetAppearanceTypeName(uint32 appearance_type)
|
||||
{
|
||||
const auto& a = EQ::constants::GetAppearanceTypeMap().find(appearance_type);
|
||||
if (a != EQ::constants::GetAppearanceTypeMap().end()) {
|
||||
return a->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -358,8 +358,8 @@ namespace EQ
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
extern const std::map<int, std::string>& GetLanguageMap();
|
||||
std::string GetLanguageName(int language_id);
|
||||
extern const std::map<uint8, std::string>& GetLanguageMap();
|
||||
std::string GetLanguageName(uint8 language_id);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
|
||||
std::string GetLDoNThemeName(uint32 theme_id);
|
||||
@@ -397,6 +397,9 @@ namespace EQ
|
||||
extern const std::map<uint8, std::string>& GetEmoteTypeMap();
|
||||
std::string GetEmoteTypeName(uint8 emote_type);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetAppearanceTypeMap();
|
||||
std::string GetAppearanceTypeName(uint32 animation_type);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
|
||||
+99
-54
@@ -23,61 +23,59 @@
|
||||
#include "skills.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace AppearanceType {
|
||||
constexpr uint32 Die = 0; // Causes the client to keel over and zone to bind point (default action)
|
||||
constexpr uint32 WhoLevel = 1; // Level that shows up on /who
|
||||
constexpr uint32 MaxHealth = 2;
|
||||
constexpr uint32 Invisibility = 3; // 0 = Visible, 1 = Invisible
|
||||
constexpr uint32 PVP = 4; // 0 = Non-PVP, 1 = PVP
|
||||
constexpr uint32 Light = 5; // Light type emitted by player (lightstone, shiny shield)
|
||||
constexpr uint32 Animation = 14; // 100 = Standing, 102 = Freeze, 105 = Looting, 110 = Sitting, 111 = Crouching, 115 = Lying
|
||||
constexpr uint32 Sneak = 15; // 0 = Normal, 1 = Sneaking
|
||||
constexpr uint32 SpawnID = 16; // Server -> Client, sets player spawn ID
|
||||
constexpr uint32 Health = 17; // Client->Server, my HP has changed (like regen tic)
|
||||
constexpr uint32 Linkdead = 18; // 0 = Normal, 1 = Linkdead
|
||||
constexpr uint32 FlyMode = 19; // 0 = Off, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating while Running
|
||||
constexpr uint32 GM = 20; // 0 = Non-GM, 1 = GM
|
||||
constexpr uint32 Anonymous = 21; // 0 = Non-Anonymous, 1 = Anonymous, 2 = Roleplaying
|
||||
constexpr uint32 GuildID = 22;
|
||||
constexpr uint32 GuildRank = 23;
|
||||
constexpr uint32 AFK = 24; // 0 = Non-AFK, 1 = AFK
|
||||
constexpr uint32 Pet = 25; // Parameter is Entity ID of owner, or 0 for when charm breaks
|
||||
constexpr uint32 Summoned = 27;
|
||||
constexpr uint32 Split = 28; // 0 = No Split, 1 = Auto Split
|
||||
constexpr uint32 Size = 29; // Spawn's Size
|
||||
constexpr uint32 SetType = 30; // 0 = PC, 1 = NPC, 2 = Corpse
|
||||
constexpr uint32 NPCName = 31; // Change PC name color to NPC name color
|
||||
constexpr uint32 AARank = 32; // AA Rank Title ID, title in /who?
|
||||
constexpr uint32 CancelSneakHide = 33; // Turns off Hide and Sneak
|
||||
constexpr uint32 AreaHealthRegen = 35; // Guild Hall Regeneration Pool sets to value * 0.001
|
||||
constexpr uint32 AreaManaRegen = 36; // Guild Hall Regeneration Pool sets to value * 0.001
|
||||
constexpr uint32 AreaEnduranceRegen = 37; // Guild Hall Regeneration Pool sets to value * 0.001
|
||||
constexpr uint32 FreezeBeneficialBuffs = 38; // Freezes beneficial buff timers for PCs
|
||||
constexpr uint32 NPCTintIndex = 39;
|
||||
constexpr uint32 GroupAutoConsent = 40; // Auto Consent Group
|
||||
constexpr uint32 RaidAutoConsent = 41; // Auto Consent Raid
|
||||
constexpr uint32 GuildAutoConsent = 42; // Auto Consent Guild
|
||||
constexpr uint32 ShowHelm = 43; // 0 = Hide, 1 = Show
|
||||
constexpr uint32 DamageState = 44; // The damage state of a destructible object (0 through 10) plays sound IDs, most only have 2 or 4 states though
|
||||
constexpr uint32 EQPlayers = 45; // EQ Players Update
|
||||
constexpr uint32 FindBits = 46; // Set Find Bits?
|
||||
constexpr uint32 TextureType = 48; // Texture Type?
|
||||
constexpr uint32 FacePick = 49; // Turns off face pick window?
|
||||
constexpr uint32 AntiCheat = 51; // Sent by the client randomly telling the server how long since last action has occurred
|
||||
constexpr uint32 GuildShow = 52;
|
||||
constexpr uint32 OfflineMode = 53; // Offline Mode
|
||||
}
|
||||
|
||||
//SpawnAppearance types: (compared two clients for server-originating types: SoF & RoF2)
|
||||
#define AT_Die 0 // this causes the client to keel over and zone to bind point (default action)
|
||||
#define AT_WhoLevel 1 // the level that shows up on /who
|
||||
#define AT_HPMax 2 // idk
|
||||
#define AT_Invis 3 // 0 = visible, 1 = invisible
|
||||
#define AT_PVP 4 // 0 = blue, 1 = pvp (red)
|
||||
#define AT_Light 5 // light type emitted by player (lightstone, shiny shield)
|
||||
#define AT_Anim 14 // 100=standing, 110=sitting, 111=ducking, 115=feigned, 105=looting
|
||||
#define AT_Sneak 15 // 0 = normal, 1 = sneaking
|
||||
#define AT_SpawnID 16 // server to client, sets player spawn id
|
||||
#define AT_HP 17 // Client->Server, my HP has changed (like regen tic)
|
||||
#define AT_Linkdead 18 // 0 = normal, 1 = linkdead
|
||||
#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate max 5, see GravityBehavior enum
|
||||
#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM
|
||||
#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
||||
#define AT_GuildID 22
|
||||
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
||||
#define AT_AFK 24 // 0 = normal, 1 = afk
|
||||
#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks
|
||||
#define AT_Summoned 27 // Unsure
|
||||
#define AT_Split 28 // 0 = normal, 1 = autosplit on (not showing in SoF+) (client-to-server only)
|
||||
#define AT_Size 29 // spawn's size (present: SoF, absent: RoF2)
|
||||
#define AT_SetType 30 // 0 = PC, 1 = NPC, 2 <= = corpse
|
||||
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name, Trader on RoF2?
|
||||
#define AT_AARank 32 // AA Rank Title ID thingy, does is this the title in /who?
|
||||
#define AT_CancelSneakHide 33 // Turns off Hide and Sneak
|
||||
//#define AT_34 34 // unknown (present: SoF, absent: RoF2)
|
||||
#define AT_AreaHPRegen 35 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_AreaManaRegen 36 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_AreaEndRegen 37 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_FreezeBuffs 38 // Freezes beneficial buff timers
|
||||
#define AT_NpcTintIndex 39 // not 100% sure
|
||||
#define AT_GroupConsent 40 // auto consent group
|
||||
#define AT_RaidConsent 41 // auto consent raid
|
||||
#define AT_GuildConsent 42 // auto consent guild
|
||||
#define AT_ShowHelm 43 // 0 = hide graphic, 1 = show graphic
|
||||
#define AT_DamageState 44 // The damage state of a destructible object (0 through 10) plays soundids most only have 2 or 4 states though
|
||||
#define AT_EQPlayers 45 // /eqplayersupdate
|
||||
#define AT_FindBits 46 // set FindBits, whatever those are!
|
||||
#define AT_TextureType 48 // TextureType
|
||||
#define AT_FacePick 49 // Turns off face pick window? maybe ...
|
||||
#define AT_AntiCheat 51 // sent by the client randomly telling the server how long since last action has occured
|
||||
#define AT_GuildShow 52 // this is what MQ2 call sit, not sure
|
||||
#define AT_Offline 53 // Offline mode
|
||||
|
||||
//#define AT_Trader 300 // Bazaar Trader Mode (not present in SoF or RoF2)
|
||||
|
||||
// animations for AT_Anim
|
||||
#define ANIM_FREEZE 102
|
||||
#define ANIM_STAND 0x64
|
||||
#define ANIM_SIT 0x6e
|
||||
#define ANIM_CROUCH 0x6f
|
||||
#define ANIM_DEATH 0x73
|
||||
#define ANIM_LOOT 0x69
|
||||
namespace Animation {
|
||||
constexpr uint32 Standing = 100;
|
||||
constexpr uint32 Freeze = 102;
|
||||
constexpr uint32 Looting = 105;
|
||||
constexpr uint32 Sitting = 110;
|
||||
constexpr uint32 Crouching = 111;
|
||||
constexpr uint32 Lying = 115;
|
||||
}
|
||||
|
||||
constexpr int16 RECAST_TYPE_UNLINKED_ITEM = -1;
|
||||
|
||||
@@ -686,6 +684,53 @@ namespace Zones {
|
||||
constexpr uint16 APPRENTICE = 999; // Designer Apprentice
|
||||
}
|
||||
|
||||
namespace Language {
|
||||
constexpr uint8 CommonTongue = 0;
|
||||
constexpr uint8 Barbarian = 1;
|
||||
constexpr uint8 Erudian = 2;
|
||||
constexpr uint8 Elvish = 3;
|
||||
constexpr uint8 DarkElvish = 4;
|
||||
constexpr uint8 Dwarvish = 5;
|
||||
constexpr uint8 Troll = 6;
|
||||
constexpr uint8 Ogre = 7;
|
||||
constexpr uint8 Gnomish = 8;
|
||||
constexpr uint8 Halfling = 9;
|
||||
constexpr uint8 ThievesCant = 10;
|
||||
constexpr uint8 OldErudian = 11;
|
||||
constexpr uint8 ElderElvish = 12;
|
||||
constexpr uint8 Froglok = 13;
|
||||
constexpr uint8 Goblin = 14;
|
||||
constexpr uint8 Gnoll = 15;
|
||||
constexpr uint8 CombineTongue = 16;
|
||||
constexpr uint8 ElderTeirDal = 17;
|
||||
constexpr uint8 Lizardman = 18;
|
||||
constexpr uint8 Orcish = 19;
|
||||
constexpr uint8 Faerie = 20;
|
||||
constexpr uint8 Dragon = 21;
|
||||
constexpr uint8 ElderDragon = 22;
|
||||
constexpr uint8 DarkSpeech = 23;
|
||||
constexpr uint8 VahShir = 24;
|
||||
constexpr uint8 Alaran = 25;
|
||||
constexpr uint8 Hadal = 26;
|
||||
constexpr uint8 Unknown27 = 27;
|
||||
|
||||
constexpr uint8 MaxValue = 100;
|
||||
}
|
||||
namespace PetInfoType {
|
||||
constexpr int Current = 0;
|
||||
constexpr int Suspended = 1;
|
||||
}
|
||||
|
||||
namespace BuffEffectType {
|
||||
constexpr uint8 None = 0;
|
||||
constexpr uint8 Buff = 2;
|
||||
constexpr uint8 InverseBuff = 4;
|
||||
}
|
||||
|
||||
namespace AlternateCurrencyMode {
|
||||
constexpr uint32 Update = 7;
|
||||
constexpr uint32 Populate = 8;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FilterNone = 0,
|
||||
|
||||
@@ -124,6 +124,12 @@ struct LDoNTrapTemplate
|
||||
uint8 locked;
|
||||
};
|
||||
|
||||
enum CrystalReclaimTypes
|
||||
{
|
||||
Ebon = 5,
|
||||
Radiant = 4,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -5128,8 +5134,6 @@ struct GroupMakeLeader_Struct
|
||||
//ex for a blank crowns window you would send:
|
||||
//999999|1|999999|0
|
||||
//any items come after in much the same way adventure merchant items do except there is no theme included
|
||||
#define ALT_CURRENCY_OP_POPULATE 8
|
||||
#define ALT_CURRENCY_OP_UPDATE 7
|
||||
|
||||
//Server -> Client
|
||||
//Populates the initial Alternate Currency Window
|
||||
|
||||
+110
-15
@@ -20,9 +20,12 @@
|
||||
#include "eqemu_config.h"
|
||||
#include "misc_functions.h"
|
||||
#include "strings.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "json/json.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
|
||||
std::string EQEmuConfig::ConfigFile = "eqemu_config.json";
|
||||
EQEmuConfig *EQEmuConfig::_config = nullptr;
|
||||
@@ -111,13 +114,12 @@ void EQEmuConfig::parse_config()
|
||||
DisableConfigChecks = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* UCS
|
||||
*/
|
||||
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
|
||||
ChatPort = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "7778").asString());
|
||||
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
|
||||
MailPort = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "7778").asString());
|
||||
|
||||
|
||||
CheckUcsConfigConversion();
|
||||
|
||||
m_ucs_host = _root["server"]["ucs"].get("host", "eqchat.eqemulator.net").asString();
|
||||
m_ucs_port = Strings::ToUnsignedInt(_root["server"]["ucs"].get("port", "7778").asString());
|
||||
|
||||
/**
|
||||
* Database
|
||||
@@ -246,16 +248,16 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
|
||||
return (WorldHTTPEnabled ? "true" : "false");
|
||||
}
|
||||
if (var_name == "ChatHost") {
|
||||
return (ChatHost);
|
||||
return (m_ucs_host);
|
||||
}
|
||||
if (var_name == "ChatPort") {
|
||||
return (itoa(ChatPort));
|
||||
return (itoa(m_ucs_port));
|
||||
}
|
||||
if (var_name == "MailHost") {
|
||||
return (MailHost);
|
||||
return (m_ucs_host);
|
||||
}
|
||||
if (var_name == "MailPort") {
|
||||
return (itoa(MailPort));
|
||||
return (itoa(m_ucs_port));
|
||||
}
|
||||
if (var_name == "DatabaseHost") {
|
||||
return (DatabaseHost);
|
||||
@@ -362,10 +364,8 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "WorldHTTPPort = " << WorldHTTPPort << std::endl;
|
||||
std::cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << std::endl;
|
||||
std::cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << std::endl;
|
||||
std::cout << "ChatHost = " << ChatHost << std::endl;
|
||||
std::cout << "ChatPort = " << ChatPort << std::endl;
|
||||
std::cout << "MailHost = " << MailHost << std::endl;
|
||||
std::cout << "MailPort = " << MailPort << std::endl;
|
||||
std::cout << "UCSHost = " << m_ucs_host << std::endl;
|
||||
std::cout << "UCSPort = " << m_ucs_port << std::endl;
|
||||
std::cout << "DatabaseHost = " << DatabaseHost << std::endl;
|
||||
std::cout << "DatabaseUsername = " << DatabaseUsername << std::endl;
|
||||
std::cout << "DatabasePassword = " << DatabasePassword << std::endl;
|
||||
@@ -392,3 +392,98 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "DefaultStatus = " << (int) DefaultStatus << std::endl;
|
||||
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
||||
}
|
||||
|
||||
const std::string &EQEmuConfig::GetUCSHost() const
|
||||
{
|
||||
return m_ucs_host;
|
||||
}
|
||||
|
||||
uint16 EQEmuConfig::GetUCSPort() const
|
||||
{
|
||||
return m_ucs_port;
|
||||
}
|
||||
|
||||
void EQEmuConfig::CheckUcsConfigConversion()
|
||||
{
|
||||
std::string chat_host = _root["server"]["chatserver"].get("host", "").asString();
|
||||
uint32 chat_port = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "0").asString());
|
||||
std::string mail_host = _root["server"]["mailserver"].get("host", "").asString();
|
||||
uint32 mail_port = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "0").asString());
|
||||
std::string ucs_host = _root["server"]["ucs"].get("host", "").asString();
|
||||
|
||||
// automatic ucs legacy configuration migration
|
||||
// if old configuration values are set, let's backup the existing configuration
|
||||
// and migrate to to use the new fields and write the new config
|
||||
if ((!chat_host.empty() || !mail_host.empty()) && ucs_host.empty()) {
|
||||
LogInfo("Migrating old [eqemu_config] UCS configuration to new configuration");
|
||||
|
||||
std::string config_file_path = std::filesystem::path{
|
||||
path.GetServerPath() + "/eqemu_config.json"
|
||||
}.string();
|
||||
|
||||
std::string config_file_bak_path = std::filesystem::path{
|
||||
path.GetServerPath() + "/eqemu_config.ucs-migrate-json.bak"
|
||||
}.string();
|
||||
|
||||
// copy eqemu_config.json to eqemu_config.json.bak
|
||||
std::ifstream src(config_file_path, std::ios::binary);
|
||||
std::ofstream dst(config_file_bak_path, std::ios::binary);
|
||||
dst << src.rdbuf();
|
||||
src.close();
|
||||
|
||||
LogInfo("Old configuration backed up to [{}]", config_file_bak_path);
|
||||
|
||||
// read eqemu_config.json, transplant new fields and write to eqemu_config.json
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
std::ifstream file(config_file_path);
|
||||
if (!reader.parse(file, root)) {
|
||||
LogError("Failed to parse configuration file");
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
|
||||
// get old fields
|
||||
std::string host = !chat_host.empty() ? chat_host : mail_host;
|
||||
if (host.empty()) {
|
||||
host = "eqchat.eqemulator.net";
|
||||
}
|
||||
std::string port = chat_port > 0 ? std::to_string(chat_port) : std::to_string(mail_port);
|
||||
if (port.empty()) {
|
||||
port = "7778";
|
||||
}
|
||||
|
||||
// set new fields
|
||||
root["server"]["ucs"]["host"] = host;
|
||||
root["server"]["ucs"]["port"] = port;
|
||||
|
||||
// unset old fields
|
||||
root["server"].removeMember("chatserver");
|
||||
root["server"].removeMember("mailserver");
|
||||
|
||||
// get Json::Value raw string
|
||||
std::string config = root.toStyledString();
|
||||
|
||||
// format using more modern json library
|
||||
nlohmann::json data = nlohmann::json::parse(config);
|
||||
|
||||
// write to file
|
||||
std::ofstream o(config_file_path);
|
||||
o << std::setw(1) << data << std::endl;
|
||||
o.close();
|
||||
|
||||
// write new config
|
||||
LogInfo("New configuration written to [{}]", config_file_path);
|
||||
LogInfo("Migration complete, please review the new configuration file");
|
||||
|
||||
// reload config internally
|
||||
try {
|
||||
std::ifstream fconfig(config_file_path, std::ifstream::binary);
|
||||
fconfig >> _config->_root;
|
||||
_config->parse_config();
|
||||
}
|
||||
catch (std::exception &) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,14 +62,6 @@ class EQEmuConfig
|
||||
std::string SharedKey;
|
||||
bool DisableConfigChecks;
|
||||
|
||||
// From <chatserver/>
|
||||
std::string ChatHost;
|
||||
uint16 ChatPort;
|
||||
|
||||
// From <mailserver/>
|
||||
std::string MailHost;
|
||||
uint16 MailPort;
|
||||
|
||||
// From <database/>
|
||||
std::string DatabaseHost;
|
||||
std::string DatabaseUsername;
|
||||
@@ -122,12 +114,18 @@ class EQEmuConfig
|
||||
|
||||
bool auto_database_updates;
|
||||
|
||||
const std::string &GetUCSHost() const;
|
||||
uint16 GetUCSPort() const;
|
||||
|
||||
// uint16 DynamicCount;
|
||||
|
||||
// map<string,uint16> StaticZones;
|
||||
|
||||
protected:
|
||||
|
||||
std::string m_ucs_host;
|
||||
uint16 m_ucs_port;
|
||||
|
||||
static EQEmuConfig *_config;
|
||||
Json::Value _root;
|
||||
static std::string ConfigFile;
|
||||
@@ -186,6 +184,7 @@ class EQEmuConfig
|
||||
}
|
||||
|
||||
void Dump() const;
|
||||
void CheckUcsConfigConversion();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+11
-7
@@ -651,6 +651,9 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
}
|
||||
|
||||
// Auto inject categories that don't exist in the database...
|
||||
|
||||
std::vector<LogsysCategoriesRepository::LogsysCategories> db_categories_to_add{};
|
||||
|
||||
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
|
||||
|
||||
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
|
||||
@@ -665,11 +668,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
}
|
||||
|
||||
if (is_missing_in_database && !is_deprecated_category) {
|
||||
LogInfo(
|
||||
"Automatically adding new log category [{}] ({})",
|
||||
Logs::LogCategoryName[i],
|
||||
i
|
||||
);
|
||||
LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i);
|
||||
|
||||
auto new_category = LogsysCategoriesRepository::NewEntity();
|
||||
new_category.log_category_id = i;
|
||||
@@ -678,11 +677,16 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
|
||||
new_category.log_to_file = log_settings[i].log_to_file;
|
||||
new_category.log_to_discord = log_settings[i].log_to_discord;
|
||||
|
||||
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
|
||||
db_categories_to_add.emplace_back(new_category);
|
||||
}
|
||||
}
|
||||
|
||||
if (!db_categories_to_add.empty()) {
|
||||
LogsysCategoriesRepository::ReplaceMany(*m_database, db_categories_to_add);
|
||||
LoadLogDatabaseSettings();
|
||||
return this;
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] log categories", categories.size());
|
||||
|
||||
auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID));
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
/* Error messages for mysql clients */
|
||||
/* error messages for the demon is in share/language/errmsg.sys */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void init_client_errs(void);
|
||||
extern const char *client_errors[]; /* Error messages */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CR_MIN_ERROR 2000 /* For easier client code */
|
||||
#define CR_MAX_ERROR 2999
|
||||
#if defined(OS2) && defined( MYSQL_SERVER)
|
||||
#define CER(X) client_errors[(X)-CR_MIN_ERROR]
|
||||
#else
|
||||
#define ER(X) client_errors[(X)-CR_MIN_ERROR]
|
||||
#endif
|
||||
#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */
|
||||
|
||||
#define CR_UNKNOWN_ERROR 2000
|
||||
#define CR_SOCKET_CREATE_ERROR 2001
|
||||
#define CR_CONNECTION_ERROR 2002
|
||||
#define CR_CONN_HOST_ERROR 2003
|
||||
#define CR_IPSOCK_ERROR 2004
|
||||
#define CR_UNKNOWN_HOST 2005
|
||||
#define CR_SERVER_GONE_ERROR 2006
|
||||
#define CR_VERSION_ERROR 2007
|
||||
#define CR_OUT_OF_MEMORY 2008
|
||||
#define CR_WRONG_HOST_INFO 2009
|
||||
#define CR_LOCALHOST_CONNECTION 2010
|
||||
#define CR_TCP_CONNECTION 2011
|
||||
#define CR_SERVER_HANDSHAKE_ERR 2012
|
||||
#define CR_SERVER_LOST 2013
|
||||
#define CR_COMMANDS_OUT_OF_SYNC 2014
|
||||
#define CR_NAMEDPIPE_CONNECTION 2015
|
||||
#define CR_NAMEDPIPEWAIT_ERROR 2016
|
||||
#define CR_NAMEDPIPEOPEN_ERROR 2017
|
||||
#define CR_NAMEDPIPESETSTATE_ERROR 2018
|
||||
#define CR_CANT_READ_CHARSET 2019
|
||||
#define CR_NET_PACKET_TOO_LARGE 2020
|
||||
@@ -37,6 +37,8 @@ void PlayerEventLogs::Init()
|
||||
db.emplace_back(e.id);
|
||||
}
|
||||
|
||||
std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings> settings_to_insert{};
|
||||
|
||||
// insert entries that don't exist in database
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
|
||||
@@ -56,21 +58,21 @@ void PlayerEventLogs::Init()
|
||||
|
||||
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
|
||||
if (is_missing_in_database && is_implemented && !is_deprecated) {
|
||||
LogInfo(
|
||||
"[New] PlayerEvent [{}] ({})",
|
||||
PlayerEvent::EventName[i],
|
||||
i
|
||||
);
|
||||
LogInfo("[New] PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
|
||||
|
||||
auto c = PlayerEventLogSettingsRepository::NewEntity();
|
||||
c.id = i;
|
||||
c.event_name = PlayerEvent::EventName[i];
|
||||
c.event_enabled = m_settings[i].event_enabled;
|
||||
c.retention_days = m_settings[i].retention_days;
|
||||
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
|
||||
settings_to_insert.emplace_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings_to_insert.empty()) {
|
||||
PlayerEventLogSettingsRepository::ReplaceMany(*m_database, settings_to_insert);
|
||||
}
|
||||
|
||||
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
|
||||
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
|
||||
|
||||
@@ -611,7 +613,7 @@ void PlayerEventLogs::Process()
|
||||
|
||||
void PlayerEventLogs::ProcessRetentionTruncation()
|
||||
{
|
||||
LogInfo("Running truncation");
|
||||
LogPlayerEvents("Running truncation");
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
if (m_settings[i].retention_days > 0) {
|
||||
|
||||
+2
-2
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
|
||||
// TODO: add more values
|
||||
switch (r1) {
|
||||
case DARK_ELF:
|
||||
if (r2 == RACE_NERIAK_CITIZEN_77) {
|
||||
if (r2 == Race::NeriakCitizen) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case BARBARIAN:
|
||||
if (r2 == RACE_HALAS_CITIZEN_90) {
|
||||
if (r2 == Race::HalasCitizen) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,34 +801,35 @@ int16 EQ::InventoryProfile::HasItemByLoreGroup(uint32 loregroup, uint8 where)
|
||||
// Returns slot_id when there's one available, else SLOT_INVALID
|
||||
int16 EQ::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, bool is_arrow)
|
||||
{
|
||||
// Check basic inventory
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
const int16 last_bag_slot = (RuleI(World, ExpansionSettings) == -1 || RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT) ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
|
||||
|
||||
if (!GetItem(i))
|
||||
// Found available slot in personal inventory
|
||||
return i;
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) { // Check basic inventory
|
||||
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetItem(i)) {
|
||||
return i; // Found available slot in personal inventory
|
||||
}
|
||||
}
|
||||
|
||||
if (!for_bag) {
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) {
|
||||
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ItemInstance* inst = GetItem(i);
|
||||
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size)
|
||||
{
|
||||
if (inst->GetItem()->BagType == item::BagTypeQuiver && inst->GetItem()->ItemType != item::ItemTypeArrow)
|
||||
{
|
||||
const auto *inst = GetItem(i);
|
||||
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size) {
|
||||
if (inst->GetItem()->BagType == item::BagTypeQuiver &&
|
||||
inst->GetItem()->ItemType != item::ItemTypeArrow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
|
||||
const int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
|
||||
|
||||
uint8 slots = inst->GetItem()->BagSlots;
|
||||
uint8 j;
|
||||
for (j = invbag::SLOT_BEGIN; j<slots; j++) {
|
||||
const uint8 slots = inst->GetItem()->BagSlots;
|
||||
for (uint8 j = invbag::SLOT_BEGIN; j < slots; j++) {
|
||||
if (!GetItem(base_slot_id + j)) {
|
||||
// Found available slot within bag
|
||||
return (base_slot_id + j);
|
||||
|
||||
@@ -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_0, 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, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
|
||||
|
||||
// Remove item from inventory
|
||||
bool DeleteItem(int16 slot_id, int16 quantity = 0);
|
||||
|
||||
@@ -1273,7 +1273,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
{
|
||||
int race = RACE_DOUG_0;
|
||||
int race = Race::Doug;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
race = item->BaneDmgRace;
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef LANGUAGES_H
|
||||
#define LANGUAGES_H
|
||||
#include "../common/types.h"
|
||||
|
||||
#define LANG_COMMON_TONGUE 0
|
||||
#define LANG_BARBARIAN 1
|
||||
#define LANG_ERUDIAN 2
|
||||
#define LANG_ELVISH 3
|
||||
#define LANG_DARK_ELVISH 4
|
||||
#define LANG_DWARVISH 5
|
||||
#define LANG_TROLL 6
|
||||
#define LANG_OGRE 7
|
||||
#define LANG_GNOMISH 8
|
||||
#define LANG_HALFLING 9
|
||||
#define LANG_THIEVES_CANT 10
|
||||
#define LANG_OLD_ERUDIAN 11
|
||||
#define LANG_ELDER_ELVISH 12
|
||||
#define LANG_FROGLOK 13
|
||||
#define LANG_GOBLIN 14
|
||||
#define LANG_GNOLL 15
|
||||
#define LANG_COMBINE_TONGUE 16
|
||||
#define LANG_ELDER_TEIRDAL 17
|
||||
#define LANG_LIZARDMAN 18
|
||||
#define LANG_ORCISH 19
|
||||
#define LANG_FAERIE 20
|
||||
#define LANG_DRAGON 21
|
||||
#define LANG_ELDER_DRAGON 22
|
||||
#define LANG_DARK_SPEECH 23
|
||||
#define LANG_VAH_SHIR 24
|
||||
#define LANG_ALARAN 25
|
||||
#define LANG_HADAL 26
|
||||
#define LANG_UNKNOWN 27
|
||||
|
||||
#define MAX_LANGUAGE_SKILL 100
|
||||
|
||||
#endif
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace RoF
|
||||
unsigned char *emu_buffer = in->pBuffer;
|
||||
uint32 opcode = *((uint32*)emu_buffer);
|
||||
|
||||
if (opcode == 8) {
|
||||
if (opcode == AlternateCurrencyMode::Populate) {
|
||||
AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(
|
||||
@@ -2621,7 +2621,7 @@ namespace RoF
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
safe_delete(inapp);
|
||||
@@ -3165,7 +3165,7 @@ namespace RoF
|
||||
|
||||
SpawnAppearance_Struct *sas = (SpawnAppearance_Struct *)emu_buffer;
|
||||
|
||||
if (sas->type != AT_Size)
|
||||
if (sas->type != AppearanceType::Size)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
@@ -3868,8 +3868,8 @@ namespace RoF
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
|
||||
)
|
||||
{
|
||||
PacketSize += 60;
|
||||
@@ -4002,8 +4002,8 @@ namespace RoF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
|
||||
@@ -274,7 +274,7 @@ namespace RoF2
|
||||
unsigned char *emu_buffer = in->pBuffer;
|
||||
uint32 opcode = *((uint32*)emu_buffer);
|
||||
|
||||
if (opcode == 8) {
|
||||
if (opcode == AlternateCurrencyMode::Populate) {
|
||||
AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(
|
||||
@@ -3218,7 +3218,7 @@ namespace RoF2
|
||||
|
||||
SpawnAppearance_Struct *sas = (SpawnAppearance_Struct *)emu_buffer;
|
||||
|
||||
if (sas->type != AT_Size)
|
||||
if (sas->type != AppearanceType::Size)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
@@ -4007,8 +4007,8 @@ namespace RoF2
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
|
||||
)
|
||||
{
|
||||
PacketSize += 60;
|
||||
@@ -4212,8 +4212,8 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
|
||||
@@ -2507,8 +2507,8 @@ namespace SoD
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
|
||||
)
|
||||
{
|
||||
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
|
||||
@@ -2706,8 +2706,8 @@ namespace SoD
|
||||
|
||||
Buffer += sizeof(structs::Spawn_Struct_Position);
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
@@ -2733,8 +2733,8 @@ namespace SoD
|
||||
}
|
||||
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace UF
|
||||
unsigned char *emu_buffer = in->pBuffer;
|
||||
uint32 opcode = *((uint32*)emu_buffer);
|
||||
|
||||
if (opcode == 8) {
|
||||
if (opcode == AlternateCurrencyMode::Populate) {
|
||||
AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(
|
||||
@@ -2339,7 +2339,7 @@ namespace UF
|
||||
|
||||
SpawnAppearance_Struct *sas = (SpawnAppearance_Struct *)emu_buffer;
|
||||
|
||||
if (sas->type != AT_Size)
|
||||
if (sas->type != AppearanceType::Size)
|
||||
{
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
return;
|
||||
@@ -2779,8 +2779,8 @@ namespace UF
|
||||
}
|
||||
|
||||
float SpawnSize = emu->size;
|
||||
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
|
||||
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
|
||||
)
|
||||
{
|
||||
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
|
||||
@@ -2982,8 +2982,8 @@ namespace UF
|
||||
|
||||
Buffer += sizeof(structs::Spawn_Struct_Position);
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
||||
@@ -3018,8 +3018,8 @@ namespace UF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||
}
|
||||
|
||||
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
|
||||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
|
||||
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
||||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
||||
)
|
||||
{
|
||||
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// types
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
||||
// containers
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
// utilities
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
// fmt
|
||||
#include <fmt/format.h>
|
||||
|
||||
// lua
|
||||
#include "lua.hpp"
|
||||
#include <luabind/luabind.hpp>
|
||||
#include <luabind/object.hpp>
|
||||
+3
-2
@@ -44,9 +44,10 @@ enum : int { //values for pTimerType
|
||||
pTimerBeggingPickPocket = 27,
|
||||
pTimerLinkedSpellReuseStart = 28,
|
||||
pTimerLinkedSpellReuseEnd = 48,
|
||||
pTimerClearXTarget = 50,
|
||||
|
||||
pTimerShieldAbility = 86,
|
||||
|
||||
pTimerShieldAbility = 86,
|
||||
|
||||
pTimerLayHands = 87, //these IDs are used by client too
|
||||
pTimerHarmTouch = 89, //so dont change them
|
||||
|
||||
|
||||
+791
-791
File diff suppressed because it is too large
Load Diff
+744
-1474
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_ACCOUNT_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseAccountRepository {
|
||||
public:
|
||||
struct Account {
|
||||
@@ -196,8 +197,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
account_id
|
||||
)
|
||||
);
|
||||
@@ -547,6 +549,108 @@ public:
|
||||
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 Account &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.charname) + "'");
|
||||
v.push_back(std::to_string(e.sharedplat));
|
||||
v.push_back("'" + Strings::Escape(e.password) + "'");
|
||||
v.push_back(std::to_string(e.status));
|
||||
v.push_back("'" + Strings::Escape(e.ls_id) + "'");
|
||||
v.push_back(std::to_string(e.lsaccount_id));
|
||||
v.push_back(std::to_string(e.gmspeed));
|
||||
v.push_back(std::to_string(e.invulnerable));
|
||||
v.push_back(std::to_string(e.flymode));
|
||||
v.push_back(std::to_string(e.ignore_tells));
|
||||
v.push_back(std::to_string(e.revoked));
|
||||
v.push_back(std::to_string(e.karma));
|
||||
v.push_back("'" + Strings::Escape(e.minilogin_ip) + "'");
|
||||
v.push_back(std::to_string(e.hideme));
|
||||
v.push_back(std::to_string(e.rulesflag));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
|
||||
v.push_back(std::to_string(e.time_creation));
|
||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_skillcaps) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_basedata) + "'");
|
||||
|
||||
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<Account> &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("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.charname) + "'");
|
||||
v.push_back(std::to_string(e.sharedplat));
|
||||
v.push_back("'" + Strings::Escape(e.password) + "'");
|
||||
v.push_back(std::to_string(e.status));
|
||||
v.push_back("'" + Strings::Escape(e.ls_id) + "'");
|
||||
v.push_back(std::to_string(e.lsaccount_id));
|
||||
v.push_back(std::to_string(e.gmspeed));
|
||||
v.push_back(std::to_string(e.invulnerable));
|
||||
v.push_back(std::to_string(e.flymode));
|
||||
v.push_back(std::to_string(e.ignore_tells));
|
||||
v.push_back(std::to_string(e.revoked));
|
||||
v.push_back(std::to_string(e.karma));
|
||||
v.push_back("'" + Strings::Escape(e.minilogin_ip) + "'");
|
||||
v.push_back(std::to_string(e.hideme));
|
||||
v.push_back(std::to_string(e.rulesflag));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.suspendeduntil > 0 ? std::to_string(e.suspendeduntil) : "null") + ")");
|
||||
v.push_back(std::to_string(e.time_creation));
|
||||
v.push_back("'" + Strings::Escape(e.ban_reason) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.suspend_reason) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_eqgame) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_skillcaps) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.crc_basedata) + "'");
|
||||
|
||||
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_ACCOUNT_REPOSITORY_H
|
||||
|
||||
@@ -16,12 +16,19 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseBotTimersRepository {
|
||||
public:
|
||||
struct BotTimers {
|
||||
uint32_t bot_id;
|
||||
uint32_t timer_id;
|
||||
uint32_t timer_value;
|
||||
uint32_t recast_time;
|
||||
uint8_t is_spell;
|
||||
uint8_t is_disc;
|
||||
uint32_t spell_id;
|
||||
uint8_t is_item;
|
||||
uint32_t item_id;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -35,6 +42,12 @@ public:
|
||||
"bot_id",
|
||||
"timer_id",
|
||||
"timer_value",
|
||||
"recast_time",
|
||||
"is_spell",
|
||||
"is_disc",
|
||||
"spell_id",
|
||||
"is_item",
|
||||
"item_id",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,6 +57,12 @@ public:
|
||||
"bot_id",
|
||||
"timer_id",
|
||||
"timer_value",
|
||||
"recast_time",
|
||||
"is_spell",
|
||||
"is_disc",
|
||||
"spell_id",
|
||||
"is_item",
|
||||
"item_id",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,6 +106,12 @@ public:
|
||||
e.bot_id = 0;
|
||||
e.timer_id = 0;
|
||||
e.timer_value = 0;
|
||||
e.recast_time = 0;
|
||||
e.is_spell = 0;
|
||||
e.is_disc = 0;
|
||||
e.spell_id = 0;
|
||||
e.is_item = 0;
|
||||
e.item_id = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -112,8 +137,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
bot_timers_id
|
||||
)
|
||||
);
|
||||
@@ -125,6 +151,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -161,6 +193,12 @@ public:
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.timer_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.timer_value));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.recast_time));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.is_spell));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.is_disc));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.spell_id));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.is_item));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.item_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -185,6 +223,12 @@ public:
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.timer_id));
|
||||
v.push_back(std::to_string(e.timer_value));
|
||||
v.push_back(std::to_string(e.recast_time));
|
||||
v.push_back(std::to_string(e.is_spell));
|
||||
v.push_back(std::to_string(e.is_disc));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.is_item));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -217,6 +261,12 @@ public:
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.timer_id));
|
||||
v.push_back(std::to_string(e.timer_value));
|
||||
v.push_back(std::to_string(e.recast_time));
|
||||
v.push_back(std::to_string(e.is_spell));
|
||||
v.push_back(std::to_string(e.is_disc));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.is_item));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -253,6 +303,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -280,6 +336,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_ALT_CURRENCY_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterAltCurrencyRepository {
|
||||
public:
|
||||
struct CharacterAltCurrency {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_alt_currency_id
|
||||
)
|
||||
);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterAltCurrency &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.currency_id));
|
||||
v.push_back(std::to_string(e.amount));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int ReplaceMany(
|
||||
Database& db,
|
||||
const std::vector<CharacterAltCurrency> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.currency_id));
|
||||
v.push_back(std::to_string(e.amount));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_ALT_CURRENCY_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_ALTERNATE_ABILITIES_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterAlternateAbilitiesRepository {
|
||||
public:
|
||||
struct CharacterAlternateAbilities {
|
||||
@@ -116,8 +117,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_alternate_abilities_id
|
||||
)
|
||||
);
|
||||
@@ -348,6 +350,68 @@ public:
|
||||
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 CharacterAlternateAbilities &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.aa_id));
|
||||
v.push_back(std::to_string(e.aa_value));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
|
||||
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<CharacterAlternateAbilities> &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.aa_id));
|
||||
v.push_back(std::to_string(e.aa_value));
|
||||
v.push_back(std::to_string(e.charges));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_ALTERNATE_ABILITIES_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_AURAS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterAurasRepository {
|
||||
public:
|
||||
struct CharacterAuras {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_auras_id
|
||||
)
|
||||
);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterAuras &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
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<CharacterAuras> &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.slot));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_AURAS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_BANDOLIER_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterBandolierRepository {
|
||||
public:
|
||||
struct CharacterBandolier {
|
||||
@@ -124,8 +125,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_bandolier_id
|
||||
)
|
||||
);
|
||||
@@ -368,6 +370,72 @@ public:
|
||||
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 CharacterBandolier &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.bandolier_id));
|
||||
v.push_back(std::to_string(e.bandolier_slot));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.icon));
|
||||
v.push_back("'" + Strings::Escape(e.bandolier_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<CharacterBandolier> &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.bandolier_id));
|
||||
v.push_back(std::to_string(e.bandolier_slot));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.icon));
|
||||
v.push_back("'" + Strings::Escape(e.bandolier_name) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_BANDOLIER_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_BIND_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterBindRepository {
|
||||
public:
|
||||
struct CharacterBind {
|
||||
@@ -132,8 +133,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_bind_id
|
||||
)
|
||||
);
|
||||
@@ -387,6 +389,76 @@ public:
|
||||
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 CharacterBind &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.instance_id));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
|
||||
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<CharacterBind> &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.slot));
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.instance_id));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_BIND_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_BUFFS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterBuffsRepository {
|
||||
public:
|
||||
struct CharacterBuffs {
|
||||
@@ -168,8 +169,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_buffs_id
|
||||
)
|
||||
);
|
||||
@@ -478,6 +480,94 @@ public:
|
||||
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 CharacterBuffs &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.caster_level));
|
||||
v.push_back("'" + Strings::Escape(e.caster_name) + "'");
|
||||
v.push_back(std::to_string(e.ticsremaining));
|
||||
v.push_back(std::to_string(e.counters));
|
||||
v.push_back(std::to_string(e.numhits));
|
||||
v.push_back(std::to_string(e.melee_rune));
|
||||
v.push_back(std::to_string(e.magic_rune));
|
||||
v.push_back(std::to_string(e.persistent));
|
||||
v.push_back(std::to_string(e.dot_rune));
|
||||
v.push_back(std::to_string(e.caston_x));
|
||||
v.push_back(std::to_string(e.caston_y));
|
||||
v.push_back(std::to_string(e.caston_z));
|
||||
v.push_back(std::to_string(e.ExtraDIChance));
|
||||
v.push_back(std::to_string(e.instrument_mod));
|
||||
|
||||
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<CharacterBuffs> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.caster_level));
|
||||
v.push_back("'" + Strings::Escape(e.caster_name) + "'");
|
||||
v.push_back(std::to_string(e.ticsremaining));
|
||||
v.push_back(std::to_string(e.counters));
|
||||
v.push_back(std::to_string(e.numhits));
|
||||
v.push_back(std::to_string(e.melee_rune));
|
||||
v.push_back(std::to_string(e.magic_rune));
|
||||
v.push_back(std::to_string(e.persistent));
|
||||
v.push_back(std::to_string(e.dot_rune));
|
||||
v.push_back(std::to_string(e.caston_x));
|
||||
v.push_back(std::to_string(e.caston_y));
|
||||
v.push_back(std::to_string(e.caston_z));
|
||||
v.push_back(std::to_string(e.ExtraDIChance));
|
||||
v.push_back(std::to_string(e.instrument_mod));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_BUFFS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_CURRENCY_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterCurrencyRepository {
|
||||
public:
|
||||
struct CharacterCurrency {
|
||||
@@ -168,8 +169,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_currency_id
|
||||
)
|
||||
);
|
||||
@@ -478,6 +480,94 @@ public:
|
||||
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 CharacterCurrency &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.platinum));
|
||||
v.push_back(std::to_string(e.gold));
|
||||
v.push_back(std::to_string(e.silver));
|
||||
v.push_back(std::to_string(e.copper));
|
||||
v.push_back(std::to_string(e.platinum_bank));
|
||||
v.push_back(std::to_string(e.gold_bank));
|
||||
v.push_back(std::to_string(e.silver_bank));
|
||||
v.push_back(std::to_string(e.copper_bank));
|
||||
v.push_back(std::to_string(e.platinum_cursor));
|
||||
v.push_back(std::to_string(e.gold_cursor));
|
||||
v.push_back(std::to_string(e.silver_cursor));
|
||||
v.push_back(std::to_string(e.copper_cursor));
|
||||
v.push_back(std::to_string(e.radiant_crystals));
|
||||
v.push_back(std::to_string(e.career_radiant_crystals));
|
||||
v.push_back(std::to_string(e.ebon_crystals));
|
||||
v.push_back(std::to_string(e.career_ebon_crystals));
|
||||
|
||||
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<CharacterCurrency> &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.platinum));
|
||||
v.push_back(std::to_string(e.gold));
|
||||
v.push_back(std::to_string(e.silver));
|
||||
v.push_back(std::to_string(e.copper));
|
||||
v.push_back(std::to_string(e.platinum_bank));
|
||||
v.push_back(std::to_string(e.gold_bank));
|
||||
v.push_back(std::to_string(e.silver_bank));
|
||||
v.push_back(std::to_string(e.copper_bank));
|
||||
v.push_back(std::to_string(e.platinum_cursor));
|
||||
v.push_back(std::to_string(e.gold_cursor));
|
||||
v.push_back(std::to_string(e.silver_cursor));
|
||||
v.push_back(std::to_string(e.copper_cursor));
|
||||
v.push_back(std::to_string(e.radiant_crystals));
|
||||
v.push_back(std::to_string(e.career_radiant_crystals));
|
||||
v.push_back(std::to_string(e.ebon_crystals));
|
||||
v.push_back(std::to_string(e.career_ebon_crystals));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_CURRENCY_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_DATA_REPOSITORY_H
|
||||
@@ -1339,6 +1339,266 @@ public:
|
||||
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 CharacterData &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.last_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.title) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.suffix) + "'");
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.zone_instance));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.gender));
|
||||
v.push_back(std::to_string(e.race));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.deity));
|
||||
v.push_back(std::to_string(e.birthday));
|
||||
v.push_back(std::to_string(e.last_login));
|
||||
v.push_back(std::to_string(e.time_played));
|
||||
v.push_back(std::to_string(e.level2));
|
||||
v.push_back(std::to_string(e.anon));
|
||||
v.push_back(std::to_string(e.gm));
|
||||
v.push_back(std::to_string(e.face));
|
||||
v.push_back(std::to_string(e.hair_color));
|
||||
v.push_back(std::to_string(e.hair_style));
|
||||
v.push_back(std::to_string(e.beard));
|
||||
v.push_back(std::to_string(e.beard_color));
|
||||
v.push_back(std::to_string(e.eye_color_1));
|
||||
v.push_back(std::to_string(e.eye_color_2));
|
||||
v.push_back(std::to_string(e.drakkin_heritage));
|
||||
v.push_back(std::to_string(e.drakkin_tattoo));
|
||||
v.push_back(std::to_string(e.drakkin_details));
|
||||
v.push_back(std::to_string(e.ability_time_seconds));
|
||||
v.push_back(std::to_string(e.ability_number));
|
||||
v.push_back(std::to_string(e.ability_time_minutes));
|
||||
v.push_back(std::to_string(e.ability_time_hours));
|
||||
v.push_back(std::to_string(e.exp));
|
||||
v.push_back(std::to_string(e.exp_enabled));
|
||||
v.push_back(std::to_string(e.aa_points_spent));
|
||||
v.push_back(std::to_string(e.aa_exp));
|
||||
v.push_back(std::to_string(e.aa_points));
|
||||
v.push_back(std::to_string(e.group_leadership_exp));
|
||||
v.push_back(std::to_string(e.raid_leadership_exp));
|
||||
v.push_back(std::to_string(e.group_leadership_points));
|
||||
v.push_back(std::to_string(e.raid_leadership_points));
|
||||
v.push_back(std::to_string(e.points));
|
||||
v.push_back(std::to_string(e.cur_hp));
|
||||
v.push_back(std::to_string(e.mana));
|
||||
v.push_back(std::to_string(e.endurance));
|
||||
v.push_back(std::to_string(e.intoxication));
|
||||
v.push_back(std::to_string(e.str));
|
||||
v.push_back(std::to_string(e.sta));
|
||||
v.push_back(std::to_string(e.cha));
|
||||
v.push_back(std::to_string(e.dex));
|
||||
v.push_back(std::to_string(e.int_));
|
||||
v.push_back(std::to_string(e.agi));
|
||||
v.push_back(std::to_string(e.wis));
|
||||
v.push_back(std::to_string(e.zone_change_count));
|
||||
v.push_back(std::to_string(e.toxicity));
|
||||
v.push_back(std::to_string(e.hunger_level));
|
||||
v.push_back(std::to_string(e.thirst_level));
|
||||
v.push_back(std::to_string(e.ability_up));
|
||||
v.push_back(std::to_string(e.ldon_points_guk));
|
||||
v.push_back(std::to_string(e.ldon_points_mir));
|
||||
v.push_back(std::to_string(e.ldon_points_mmc));
|
||||
v.push_back(std::to_string(e.ldon_points_ruj));
|
||||
v.push_back(std::to_string(e.ldon_points_tak));
|
||||
v.push_back(std::to_string(e.ldon_points_available));
|
||||
v.push_back(std::to_string(e.tribute_time_remaining));
|
||||
v.push_back(std::to_string(e.career_tribute_points));
|
||||
v.push_back(std::to_string(e.tribute_points));
|
||||
v.push_back(std::to_string(e.tribute_active));
|
||||
v.push_back(std::to_string(e.pvp_status));
|
||||
v.push_back(std::to_string(e.pvp_kills));
|
||||
v.push_back(std::to_string(e.pvp_deaths));
|
||||
v.push_back(std::to_string(e.pvp_current_points));
|
||||
v.push_back(std::to_string(e.pvp_career_points));
|
||||
v.push_back(std::to_string(e.pvp_best_kill_streak));
|
||||
v.push_back(std::to_string(e.pvp_worst_death_streak));
|
||||
v.push_back(std::to_string(e.pvp_current_kill_streak));
|
||||
v.push_back(std::to_string(e.pvp2));
|
||||
v.push_back(std::to_string(e.pvp_type));
|
||||
v.push_back(std::to_string(e.show_helm));
|
||||
v.push_back(std::to_string(e.group_auto_consent));
|
||||
v.push_back(std::to_string(e.raid_auto_consent));
|
||||
v.push_back(std::to_string(e.guild_auto_consent));
|
||||
v.push_back(std::to_string(e.leadership_exp_on));
|
||||
v.push_back(std::to_string(e.RestTimer));
|
||||
v.push_back(std::to_string(e.air_remaining));
|
||||
v.push_back(std::to_string(e.autosplit_enabled));
|
||||
v.push_back(std::to_string(e.lfp));
|
||||
v.push_back(std::to_string(e.lfg));
|
||||
v.push_back("'" + Strings::Escape(e.mailkey) + "'");
|
||||
v.push_back(std::to_string(e.xtargets));
|
||||
v.push_back(std::to_string(e.firstlogon));
|
||||
v.push_back(std::to_string(e.e_aa_effects));
|
||||
v.push_back(std::to_string(e.e_percent_to_aa));
|
||||
v.push_back(std::to_string(e.e_expended_aa_spent));
|
||||
v.push_back(std::to_string(e.aa_points_spent_old));
|
||||
v.push_back(std::to_string(e.aa_points_old));
|
||||
v.push_back(std::to_string(e.e_last_invsnapshot));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int ReplaceMany(
|
||||
Database& db,
|
||||
const std::vector<CharacterData> &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.account_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.last_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.title) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.suffix) + "'");
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.zone_instance));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.gender));
|
||||
v.push_back(std::to_string(e.race));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.deity));
|
||||
v.push_back(std::to_string(e.birthday));
|
||||
v.push_back(std::to_string(e.last_login));
|
||||
v.push_back(std::to_string(e.time_played));
|
||||
v.push_back(std::to_string(e.level2));
|
||||
v.push_back(std::to_string(e.anon));
|
||||
v.push_back(std::to_string(e.gm));
|
||||
v.push_back(std::to_string(e.face));
|
||||
v.push_back(std::to_string(e.hair_color));
|
||||
v.push_back(std::to_string(e.hair_style));
|
||||
v.push_back(std::to_string(e.beard));
|
||||
v.push_back(std::to_string(e.beard_color));
|
||||
v.push_back(std::to_string(e.eye_color_1));
|
||||
v.push_back(std::to_string(e.eye_color_2));
|
||||
v.push_back(std::to_string(e.drakkin_heritage));
|
||||
v.push_back(std::to_string(e.drakkin_tattoo));
|
||||
v.push_back(std::to_string(e.drakkin_details));
|
||||
v.push_back(std::to_string(e.ability_time_seconds));
|
||||
v.push_back(std::to_string(e.ability_number));
|
||||
v.push_back(std::to_string(e.ability_time_minutes));
|
||||
v.push_back(std::to_string(e.ability_time_hours));
|
||||
v.push_back(std::to_string(e.exp));
|
||||
v.push_back(std::to_string(e.exp_enabled));
|
||||
v.push_back(std::to_string(e.aa_points_spent));
|
||||
v.push_back(std::to_string(e.aa_exp));
|
||||
v.push_back(std::to_string(e.aa_points));
|
||||
v.push_back(std::to_string(e.group_leadership_exp));
|
||||
v.push_back(std::to_string(e.raid_leadership_exp));
|
||||
v.push_back(std::to_string(e.group_leadership_points));
|
||||
v.push_back(std::to_string(e.raid_leadership_points));
|
||||
v.push_back(std::to_string(e.points));
|
||||
v.push_back(std::to_string(e.cur_hp));
|
||||
v.push_back(std::to_string(e.mana));
|
||||
v.push_back(std::to_string(e.endurance));
|
||||
v.push_back(std::to_string(e.intoxication));
|
||||
v.push_back(std::to_string(e.str));
|
||||
v.push_back(std::to_string(e.sta));
|
||||
v.push_back(std::to_string(e.cha));
|
||||
v.push_back(std::to_string(e.dex));
|
||||
v.push_back(std::to_string(e.int_));
|
||||
v.push_back(std::to_string(e.agi));
|
||||
v.push_back(std::to_string(e.wis));
|
||||
v.push_back(std::to_string(e.zone_change_count));
|
||||
v.push_back(std::to_string(e.toxicity));
|
||||
v.push_back(std::to_string(e.hunger_level));
|
||||
v.push_back(std::to_string(e.thirst_level));
|
||||
v.push_back(std::to_string(e.ability_up));
|
||||
v.push_back(std::to_string(e.ldon_points_guk));
|
||||
v.push_back(std::to_string(e.ldon_points_mir));
|
||||
v.push_back(std::to_string(e.ldon_points_mmc));
|
||||
v.push_back(std::to_string(e.ldon_points_ruj));
|
||||
v.push_back(std::to_string(e.ldon_points_tak));
|
||||
v.push_back(std::to_string(e.ldon_points_available));
|
||||
v.push_back(std::to_string(e.tribute_time_remaining));
|
||||
v.push_back(std::to_string(e.career_tribute_points));
|
||||
v.push_back(std::to_string(e.tribute_points));
|
||||
v.push_back(std::to_string(e.tribute_active));
|
||||
v.push_back(std::to_string(e.pvp_status));
|
||||
v.push_back(std::to_string(e.pvp_kills));
|
||||
v.push_back(std::to_string(e.pvp_deaths));
|
||||
v.push_back(std::to_string(e.pvp_current_points));
|
||||
v.push_back(std::to_string(e.pvp_career_points));
|
||||
v.push_back(std::to_string(e.pvp_best_kill_streak));
|
||||
v.push_back(std::to_string(e.pvp_worst_death_streak));
|
||||
v.push_back(std::to_string(e.pvp_current_kill_streak));
|
||||
v.push_back(std::to_string(e.pvp2));
|
||||
v.push_back(std::to_string(e.pvp_type));
|
||||
v.push_back(std::to_string(e.show_helm));
|
||||
v.push_back(std::to_string(e.group_auto_consent));
|
||||
v.push_back(std::to_string(e.raid_auto_consent));
|
||||
v.push_back(std::to_string(e.guild_auto_consent));
|
||||
v.push_back(std::to_string(e.leadership_exp_on));
|
||||
v.push_back(std::to_string(e.RestTimer));
|
||||
v.push_back(std::to_string(e.air_remaining));
|
||||
v.push_back(std::to_string(e.autosplit_enabled));
|
||||
v.push_back(std::to_string(e.lfp));
|
||||
v.push_back(std::to_string(e.lfg));
|
||||
v.push_back("'" + Strings::Escape(e.mailkey) + "'");
|
||||
v.push_back(std::to_string(e.xtargets));
|
||||
v.push_back(std::to_string(e.firstlogon));
|
||||
v.push_back(std::to_string(e.e_aa_effects));
|
||||
v.push_back(std::to_string(e.e_percent_to_aa));
|
||||
v.push_back(std::to_string(e.e_expended_aa_spent));
|
||||
v.push_back(std::to_string(e.aa_points_spent_old));
|
||||
v.push_back(std::to_string(e.aa_points_old));
|
||||
v.push_back(std::to_string(e.e_last_invsnapshot));
|
||||
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_DATA_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_DISCIPLINES_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterDisciplinesRepository {
|
||||
public:
|
||||
struct CharacterDisciplines {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_disciplines_id
|
||||
)
|
||||
);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterDisciplines &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.disc_id));
|
||||
|
||||
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<CharacterDisciplines> &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.slot_id));
|
||||
v.push_back(std::to_string(e.disc_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_DISCIPLINES_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_ITEM_RECAST_REPOSITORY_H
|
||||
@@ -16,11 +16,12 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterItemRecastRepository {
|
||||
public:
|
||||
struct CharacterItemRecast {
|
||||
uint32_t id;
|
||||
uint16_t recast_type;
|
||||
uint32_t recast_type;
|
||||
uint32_t timestamp;
|
||||
};
|
||||
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_item_recast_id
|
||||
)
|
||||
);
|
||||
@@ -123,7 +125,7 @@ public:
|
||||
CharacterItemRecast e{};
|
||||
|
||||
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.recast_type = static_cast<uint16_t>(strtoul(row[1], nullptr, 10));
|
||||
e.recast_type = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timestamp = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
|
||||
return e;
|
||||
@@ -251,7 +253,7 @@ public:
|
||||
CharacterItemRecast e{};
|
||||
|
||||
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.recast_type = static_cast<uint16_t>(strtoul(row[1], nullptr, 10));
|
||||
e.recast_type = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timestamp = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
@@ -278,7 +280,7 @@ public:
|
||||
CharacterItemRecast e{};
|
||||
|
||||
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.recast_type = static_cast<uint16_t>(strtoul(row[1], nullptr, 10));
|
||||
e.recast_type = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timestamp = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterItemRecast &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.recast_type));
|
||||
v.push_back(std::to_string(e.timestamp));
|
||||
|
||||
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<CharacterItemRecast> &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.recast_type));
|
||||
v.push_back(std::to_string(e.timestamp));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_ITEM_RECAST_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_LEADERSHIP_ABILITIES_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterLeadershipAbilitiesRepository {
|
||||
public:
|
||||
struct CharacterLeadershipAbilities {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_leadership_abilities_id
|
||||
)
|
||||
);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterLeadershipAbilities &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.rank));
|
||||
|
||||
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<CharacterLeadershipAbilities> &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.slot));
|
||||
v.push_back(std::to_string(e.rank));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_LEADERSHIP_ABILITIES_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_MATERIAL_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterMaterialRepository {
|
||||
public:
|
||||
struct CharacterMaterial {
|
||||
@@ -128,8 +129,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_material_id
|
||||
)
|
||||
);
|
||||
@@ -377,6 +379,74 @@ public:
|
||||
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 CharacterMaterial &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.blue));
|
||||
v.push_back(std::to_string(e.green));
|
||||
v.push_back(std::to_string(e.red));
|
||||
v.push_back(std::to_string(e.use_tint));
|
||||
v.push_back(std::to_string(e.color));
|
||||
|
||||
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<CharacterMaterial> &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.slot));
|
||||
v.push_back(std::to_string(e.blue));
|
||||
v.push_back(std::to_string(e.green));
|
||||
v.push_back(std::to_string(e.red));
|
||||
v.push_back(std::to_string(e.use_tint));
|
||||
v.push_back(std::to_string(e.color));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_MATERIAL_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_MEMMED_SPELLS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterMemmedSpellsRepository {
|
||||
public:
|
||||
struct CharacterMemmedSpells {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_memmed_spells_id
|
||||
)
|
||||
);
|
||||
@@ -338,6 +340,66 @@ public:
|
||||
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 CharacterMemmedSpells &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
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<CharacterMemmedSpells> &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.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_MEMMED_SPELLS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_PET_BUFFS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterPetBuffsRepository {
|
||||
public:
|
||||
struct CharacterPetBuffs {
|
||||
@@ -144,8 +145,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_pet_buffs_id
|
||||
)
|
||||
);
|
||||
@@ -418,6 +420,82 @@ public:
|
||||
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 CharacterPetBuffs &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.caster_level));
|
||||
v.push_back("'" + Strings::Escape(e.castername) + "'");
|
||||
v.push_back(std::to_string(e.ticsremaining));
|
||||
v.push_back(std::to_string(e.counters));
|
||||
v.push_back(std::to_string(e.numhits));
|
||||
v.push_back(std::to_string(e.rune));
|
||||
v.push_back(std::to_string(e.instrument_mod));
|
||||
|
||||
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<CharacterPetBuffs> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.caster_level));
|
||||
v.push_back("'" + Strings::Escape(e.castername) + "'");
|
||||
v.push_back(std::to_string(e.ticsremaining));
|
||||
v.push_back(std::to_string(e.counters));
|
||||
v.push_back(std::to_string(e.numhits));
|
||||
v.push_back(std::to_string(e.rune));
|
||||
v.push_back(std::to_string(e.instrument_mod));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_PET_BUFFS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_PET_INFO_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterPetInfoRepository {
|
||||
public:
|
||||
struct CharacterPetInfo {
|
||||
@@ -136,8 +137,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_pet_info_id
|
||||
)
|
||||
);
|
||||
@@ -398,6 +400,78 @@ public:
|
||||
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 CharacterPetInfo &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back("'" + Strings::Escape(e.petname) + "'");
|
||||
v.push_back(std::to_string(e.petpower));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.hp));
|
||||
v.push_back(std::to_string(e.mana));
|
||||
v.push_back(std::to_string(e.size));
|
||||
v.push_back(std::to_string(e.taunting));
|
||||
|
||||
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<CharacterPetInfo> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back("'" + Strings::Escape(e.petname) + "'");
|
||||
v.push_back(std::to_string(e.petpower));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.hp));
|
||||
v.push_back(std::to_string(e.mana));
|
||||
v.push_back(std::to_string(e.size));
|
||||
v.push_back(std::to_string(e.taunting));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_PET_INFO_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_PET_INVENTORY_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterPetInventoryRepository {
|
||||
public:
|
||||
struct CharacterPetInventory {
|
||||
@@ -116,8 +117,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_pet_inventory_id
|
||||
)
|
||||
);
|
||||
@@ -348,6 +350,68 @@ public:
|
||||
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 CharacterPetInventory &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
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<CharacterPetInventory> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.char_id));
|
||||
v.push_back(std::to_string(e.pet));
|
||||
v.push_back(std::to_string(e.slot));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_PET_INVENTORY_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_POTIONBELT_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterPotionbeltRepository {
|
||||
public:
|
||||
struct CharacterPotionbelt {
|
||||
@@ -116,8 +117,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_potionbelt_id
|
||||
)
|
||||
);
|
||||
@@ -348,6 +350,68 @@ public:
|
||||
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 CharacterPotionbelt &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.potion_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.icon));
|
||||
|
||||
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<CharacterPotionbelt> &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.potion_id));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
v.push_back(std::to_string(e.icon));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_POTIONBELT_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_SKILLS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterSkillsRepository {
|
||||
public:
|
||||
struct CharacterSkills {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_skills_id
|
||||
)
|
||||
);
|
||||
@@ -337,6 +339,66 @@ public:
|
||||
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 CharacterSkills &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.value));
|
||||
|
||||
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<CharacterSkills> &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.skill_id));
|
||||
v.push_back(std::to_string(e.value));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_SKILLS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_CHARACTER_SPELLS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseCharacterSpellsRepository {
|
||||
public:
|
||||
struct CharacterSpells {
|
||||
@@ -112,8 +113,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
character_spells_id
|
||||
)
|
||||
);
|
||||
@@ -337,6 +339,66 @@ public:
|
||||
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 CharacterSpells &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
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<CharacterSpells> &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.slot_id));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_CHARACTER_SPELLS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_LOGSYS_CATEGORIES_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseLogsysCategoriesRepository {
|
||||
public:
|
||||
struct LogsysCategories {
|
||||
@@ -128,8 +129,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
logsys_categories_id
|
||||
)
|
||||
);
|
||||
@@ -378,6 +380,74 @@ public:
|
||||
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 LogsysCategories &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.log_category_id));
|
||||
v.push_back("'" + Strings::Escape(e.log_category_description) + "'");
|
||||
v.push_back(std::to_string(e.log_to_console));
|
||||
v.push_back(std::to_string(e.log_to_file));
|
||||
v.push_back(std::to_string(e.log_to_gmsay));
|
||||
v.push_back(std::to_string(e.log_to_discord));
|
||||
v.push_back(std::to_string(e.discord_webhook_id));
|
||||
|
||||
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<LogsysCategories> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.log_category_id));
|
||||
v.push_back("'" + Strings::Escape(e.log_category_description) + "'");
|
||||
v.push_back(std::to_string(e.log_to_console));
|
||||
v.push_back(std::to_string(e.log_to_file));
|
||||
v.push_back(std::to_string(e.log_to_gmsay));
|
||||
v.push_back(std::to_string(e.log_to_discord));
|
||||
v.push_back(std::to_string(e.discord_webhook_id));
|
||||
|
||||
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_LOGSYS_CATEGORIES_REPOSITORY_H
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseNpcEmotesRepository {
|
||||
public:
|
||||
struct NpcEmotes {
|
||||
@@ -120,8 +121,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
npc_emotes_id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BasePlayerEventLogSettingsRepository {
|
||||
public:
|
||||
struct PlayerEventLogSettings {
|
||||
@@ -359,6 +360,70 @@ public:
|
||||
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 PlayerEventLogSettings &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back("'" + Strings::Escape(e.event_name) + "'");
|
||||
v.push_back(std::to_string(e.event_enabled));
|
||||
v.push_back(std::to_string(e.retention_days));
|
||||
v.push_back(std::to_string(e.discord_webhook_id));
|
||||
|
||||
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<PlayerEventLogSettings> &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("'" + Strings::Escape(e.event_name) + "'");
|
||||
v.push_back(std::to_string(e.event_enabled));
|
||||
v.push_back(std::to_string(e.retention_days));
|
||||
v.push_back(std::to_string(e.discord_webhook_id));
|
||||
|
||||
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_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
|
||||
@@ -240,8 +240,8 @@ public:
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.z));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.heading));
|
||||
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
|
||||
v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
|
||||
v.push_back(columns[10] + " = '" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back(columns[11] + " = '" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
@@ -274,8 +274,8 @@ public:
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_data) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
@@ -316,8 +316,8 @@ public:
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_data) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
@@ -460,6 +460,86 @@ public:
|
||||
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 PlayerEventLogs &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.instance_id));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", v)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int ReplaceMany(
|
||||
Database& db,
|
||||
const std::vector<PlayerEventLogs> &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.account_id));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.zone_id));
|
||||
v.push_back(std::to_string(e.instance_id));
|
||||
v.push_back(std::to_string(e.x));
|
||||
v.push_back(std::to_string(e.y));
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseReplace(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_TASKS_REPOSITORY_H
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseTasksRepository {
|
||||
public:
|
||||
struct Tasks {
|
||||
@@ -47,6 +48,7 @@ public:
|
||||
uint32_t dz_template_id;
|
||||
int32_t lock_activity_id;
|
||||
int32_t faction_amount;
|
||||
int16_t enabled;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -85,6 +87,7 @@ public:
|
||||
"dz_template_id",
|
||||
"lock_activity_id",
|
||||
"faction_amount",
|
||||
"enabled",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,6 +122,7 @@ public:
|
||||
"dz_template_id",
|
||||
"lock_activity_id",
|
||||
"faction_amount",
|
||||
"enabled",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -187,6 +191,7 @@ public:
|
||||
e.dz_template_id = 0;
|
||||
e.lock_activity_id = -1;
|
||||
e.faction_amount = 0;
|
||||
e.enabled = 1;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -212,8 +217,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
tasks_id
|
||||
)
|
||||
);
|
||||
@@ -250,6 +256,7 @@ public:
|
||||
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
|
||||
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
|
||||
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
|
||||
e.enabled = static_cast<int16_t>(atoi(row[28]));
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -311,6 +318,7 @@ public:
|
||||
v.push_back(columns[25] + " = " + std::to_string(e.dz_template_id));
|
||||
v.push_back(columns[26] + " = " + std::to_string(e.lock_activity_id));
|
||||
v.push_back(columns[27] + " = " + std::to_string(e.faction_amount));
|
||||
v.push_back(columns[28] + " = " + std::to_string(e.enabled));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -360,6 +368,7 @@ public:
|
||||
v.push_back(std::to_string(e.dz_template_id));
|
||||
v.push_back(std::to_string(e.lock_activity_id));
|
||||
v.push_back(std::to_string(e.faction_amount));
|
||||
v.push_back(std::to_string(e.enabled));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -417,6 +426,7 @@ public:
|
||||
v.push_back(std::to_string(e.dz_template_id));
|
||||
v.push_back(std::to_string(e.lock_activity_id));
|
||||
v.push_back(std::to_string(e.faction_amount));
|
||||
v.push_back(std::to_string(e.enabled));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -478,6 +488,7 @@ public:
|
||||
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
|
||||
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
|
||||
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
|
||||
e.enabled = static_cast<int16_t>(atoi(row[28]));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -530,6 +541,7 @@ public:
|
||||
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
|
||||
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
|
||||
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
|
||||
e.enabled = static_cast<int16_t>(atoi(row[28]));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -588,6 +600,118 @@ public:
|
||||
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 Tasks &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.type));
|
||||
v.push_back(std::to_string(e.duration));
|
||||
v.push_back(std::to_string(e.duration_code));
|
||||
v.push_back("'" + Strings::Escape(e.title) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.description) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.reward_text) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.reward_id_list) + "'");
|
||||
v.push_back(std::to_string(e.cash_reward));
|
||||
v.push_back(std::to_string(e.exp_reward));
|
||||
v.push_back(std::to_string(e.reward_method));
|
||||
v.push_back(std::to_string(e.reward_points));
|
||||
v.push_back(std::to_string(e.reward_point_type));
|
||||
v.push_back(std::to_string(e.min_level));
|
||||
v.push_back(std::to_string(e.max_level));
|
||||
v.push_back(std::to_string(e.level_spread));
|
||||
v.push_back(std::to_string(e.min_players));
|
||||
v.push_back(std::to_string(e.max_players));
|
||||
v.push_back(std::to_string(e.repeatable));
|
||||
v.push_back(std::to_string(e.faction_reward));
|
||||
v.push_back("'" + Strings::Escape(e.completion_emote) + "'");
|
||||
v.push_back(std::to_string(e.replay_timer_group));
|
||||
v.push_back(std::to_string(e.replay_timer_seconds));
|
||||
v.push_back(std::to_string(e.request_timer_group));
|
||||
v.push_back(std::to_string(e.request_timer_seconds));
|
||||
v.push_back(std::to_string(e.dz_template_id));
|
||||
v.push_back(std::to_string(e.lock_activity_id));
|
||||
v.push_back(std::to_string(e.faction_amount));
|
||||
v.push_back(std::to_string(e.enabled));
|
||||
|
||||
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<Tasks> &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.type));
|
||||
v.push_back(std::to_string(e.duration));
|
||||
v.push_back(std::to_string(e.duration_code));
|
||||
v.push_back("'" + Strings::Escape(e.title) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.description) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.reward_text) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.reward_id_list) + "'");
|
||||
v.push_back(std::to_string(e.cash_reward));
|
||||
v.push_back(std::to_string(e.exp_reward));
|
||||
v.push_back(std::to_string(e.reward_method));
|
||||
v.push_back(std::to_string(e.reward_points));
|
||||
v.push_back(std::to_string(e.reward_point_type));
|
||||
v.push_back(std::to_string(e.min_level));
|
||||
v.push_back(std::to_string(e.max_level));
|
||||
v.push_back(std::to_string(e.level_spread));
|
||||
v.push_back(std::to_string(e.min_players));
|
||||
v.push_back(std::to_string(e.max_players));
|
||||
v.push_back(std::to_string(e.repeatable));
|
||||
v.push_back(std::to_string(e.faction_reward));
|
||||
v.push_back("'" + Strings::Escape(e.completion_emote) + "'");
|
||||
v.push_back(std::to_string(e.replay_timer_group));
|
||||
v.push_back(std::to_string(e.replay_timer_seconds));
|
||||
v.push_back(std::to_string(e.request_timer_group));
|
||||
v.push_back(std::to_string(e.request_timer_seconds));
|
||||
v.push_back(std::to_string(e.dz_template_id));
|
||||
v.push_back(std::to_string(e.lock_activity_id));
|
||||
v.push_back(std::to_string(e.faction_amount));
|
||||
v.push_back(std::to_string(e.enabled));
|
||||
|
||||
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_TASKS_REPOSITORY_H
|
||||
|
||||
@@ -46,6 +46,24 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static uint32 GetSecondsSinceLastLogin(Database &db, const std::string& name)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT (UNIX_TIMESTAMP(NOW()) - last_login) FROM {} WHERE name = '{}'",
|
||||
TableName(),
|
||||
Strings::Escape(name)
|
||||
)
|
||||
);
|
||||
|
||||
if (!results.RowCount() || !results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
* @docs https://docs.eqemu.io/developer/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
|
||||
@@ -319,6 +319,62 @@ public:
|
||||
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 {{TABLE_NAME_STRUCT}} &e
|
||||
)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
{{INSERT_ONE_ENTRIES}}
|
||||
|
||||
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<{{TABLE_NAME_STRUCT}}> &entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
{{INSERT_MANY_ENTRIES}}
|
||||
|
||||
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_{{TABLE_NAME_UPPER}}_REPOSITORY_H
|
||||
|
||||
@@ -215,6 +215,10 @@ RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid ex
|
||||
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
|
||||
RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses")
|
||||
RULE_BOOL(Character, ItemExtraSkillDamageCalcAsPercent, false, "If enabled, apply Item Extra Skill Damage as Percentage-based modifiers")
|
||||
RULE_BOOL(Character, UseForageCommonFood, true, "If enabled, use the common foods specified in the code.")
|
||||
RULE_INT(Character, ClearXTargetDelay, 10, "Seconds between uses of the #clearxtargets command (Set to 0 to disable)")
|
||||
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_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -250,6 +254,7 @@ RULE_BOOL(Skills, TrainSenseHeading, false, "Switch whether SenseHeading is trai
|
||||
RULE_INT(Skills, SenseHeadingStartValue, 200, "Start value of sense heading skill")
|
||||
RULE_BOOL(Skills, SelfLanguageLearning, true, "Enabling self-learning of languages")
|
||||
RULE_BOOL(Skills, RequireTomeHandin, false, "Disable click-to-learn and force hand in to Guild Master")
|
||||
RULE_INT(Skills, TradeSkillClamp, 0, "Legacy tradeskills would clamp at 252 regardless of item modifiers and skill combination. DEFAULT: 0 will bypass clamp. Legacy value 252")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Pets)
|
||||
@@ -429,6 +434,10 @@ RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false, "Ignore Leadership Alternate Ab
|
||||
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false, "Allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc")
|
||||
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false, "Ignore the 5 level spread on applying SpellDmg")
|
||||
RULE_BOOL(Spells, ItemExtraSpellAmtCalcAsPercent, false, "Apply the Item stats Spell Dmg and Heal Amount as Percentage-based modifiers instead of flat additions")
|
||||
RULE_REAL(Spells, BreakFeignDeathWhenCastOn, 2.0, "Percentage that Feign Death will break when you resist a spell")
|
||||
RULE_REAL(Spells, BreakSneakWhenCastOn, 2.0, "Percentage that Sneak will break when you resist a spell")
|
||||
RULE_BOOL(Spells, EnableResistSoftCap, false, "Enabled resist softcap and can be adjusted by rule, SpellResistSoftCap")
|
||||
RULE_INT(Spells, SpellResistSoftCap, 255, "Softcap for spell resists.")
|
||||
RULE_BOOL(Spells, AllowItemTGB, false, "Target group buff (/tgb) doesn't work with items on live, custom servers want it though")
|
||||
RULE_BOOL(Spells, NPCInnateProcOverride, true, "NPC innate procs override the target type to single target")
|
||||
RULE_BOOL(Spells, OldRainTargets, false, "Use old incorrectly implemented maximum targets for rains")
|
||||
@@ -461,6 +470,14 @@ RULE_INT(Spells, DefensiveProcPenaltyLevelGap, 6, "Defensive Proc Penalty Level
|
||||
RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference")
|
||||
RULE_BOOL(Spells, DOTBonusDamageSplitOverDuration, true, "Disable to have Damage Over Time total bonus damage added to each tick instead of divided across duration")
|
||||
RULE_BOOL(Spells, HOTBonusHealingSplitOverDuration, true, "Disable to have Heal Over Time total bonus healing added to each tick instead of divided across duration")
|
||||
RULE_BOOL(Spells, UseLegacyFizzleCode, false, "Enable will turn on the legacy fizzle code which is far stricter and more accurate to 2001/2002 testing.")
|
||||
RULE_BOOL(Spells, LegacyManaburn, false, "Enable to have the legacy manaburn system from 2003 and earlier.")
|
||||
RULE_INT(Spells, LegacyManaburnCap, 9492, "Adjusted the hard cap (Normal or Crit) for the Legacy Manaburn system. DEFAULT: 9492")
|
||||
RULE_BOOL(Spells, EvacClearAggroInSameZone, false, "Enable to clear aggro on clients when evacing in same zone.")
|
||||
RULE_BOOL(Spells, CharmAggroOverLevel, false, "Enabling this rule will cause Charm casts over level to show resisted and cause aggro. Early EQ style.")
|
||||
RULE_BOOL(Spells, RequireMnemonicRetention, true, "Enabling will require spell slots 9-12 to have the appropriate Mnemonic Retention AA learned.")
|
||||
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_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
@@ -498,6 +515,7 @@ RULE_REAL(Combat, AvgDefProcsPerMinute, 2.0, "Average defense procs per minute")
|
||||
RULE_REAL(Combat, DefProcPerMinAgiContrib, 0.075, "How much agility contributes to defensive proc rate")
|
||||
RULE_INT(Combat, NPCFlurryChance, 20, "Chance for NPC to flurry")
|
||||
RULE_BOOL(Combat, TauntOverLevel, 1, "Allows you to taunt NPC's over warriors level")
|
||||
RULE_INT(Combat, TauntOverAggro, 0, "+ amount over hate_top it will add before any bonus hate.")
|
||||
RULE_REAL(Combat, TauntSkillFalloff, 0.33, "For every taunt skill point that's not maxed you lose this percentage chance to taunt")
|
||||
RULE_BOOL(Combat, EXPFromDmgShield, false, "Determine if damage from a damage shield counts for experience gain")
|
||||
RULE_INT(Combat, QuiverHasteCap, 1000, "Quiver haste cap 1000 on live for a while, currently 700 on live")
|
||||
@@ -507,6 +525,9 @@ RULE_BOOL(Combat, OneProcPerWeapon, true, "If enabled, One proc per weapon per r
|
||||
RULE_BOOL(Combat, ProjectileDmgOnImpact, true, "If enabled, projectiles (i.e. arrows) will hit on impact, instead of instantly")
|
||||
RULE_BOOL(Combat, MeleePush, true, "Enable melee push")
|
||||
RULE_INT(Combat, MeleePushChance, 50, "NPC chance the target will be pushed. Made up, 100 actually isn't that bad")
|
||||
RULE_REAL(Combat, MeleePushForceClientPercent, 0.00, "Percent to add or remove from push for players")
|
||||
RULE_REAL(Combat, MeleePushForcePetPercent, 0.00, "Percent to add or remove from push for pets")
|
||||
RULE_BOOL(Combat, NPCtoNPCPush, false, "Disabled prevents NPC to NPC pushing per the 2013+ patch.")
|
||||
RULE_BOOL(Combat, UseLiveCombatRounds, true, "Turn this false if you don't want to worry about fixing up combat rounds for NPCs")
|
||||
RULE_INT(Combat, NPCAssistCap, 5, "Maximum number of NPC that will assist another NPC at once")
|
||||
RULE_INT(Combat, NPCAssistCapTimer, 6000, "Time a NPC will take to clear assist aggro cap space (milliseconds)")
|
||||
@@ -537,6 +558,13 @@ RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a play
|
||||
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
|
||||
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
|
||||
RULE_INT(Combat, MaxProcs, 4, "Adjustable maximum number of procs per round, the hard cap is MAX_PROCS (11). Requires mob repop or client zone when changed")
|
||||
RULE_BOOL(Combat, FinishingBlowOnlyWhenFleeing, false, "Enable to only allow Finishing Blow when fleeing (Original Style Finishing Blow)")
|
||||
RULE_BOOL(Combat, ClassicTripleAttack, false, "enable to use non-skill based classic triple attack. Originally it was Warrior Only but was expanded, can use the TripleAttackChance to tune the classes out.")
|
||||
RULE_INT(Combat, ClassicTripleAttackChanceWarrior, 100, "Innate Chance for Warrior to Triple Attack after a Double Attack (125 = 12.5%). DEFAULT: 100")
|
||||
RULE_INT(Combat, ClassicTripleAttackChanceMonk, 100, "Innate Chance for Monk to Triple Attack after a Double Attack (200 = 20%). DEFAULT: 100")
|
||||
RULE_INT(Combat, ClassicTripleAttackChanceBerserker, 100, "Innate Chance for Berserker to Triple Attack after a Double Attack (200 = 20%). DEFAULT: 100")
|
||||
RULE_INT(Combat, ClassicTripleAttackChanceRanger, 100, "Innate Chance for Ranger to Triple Attack after a Double Attack (200 = 20%). DEFAULT: 100")
|
||||
RULE_INT(Combat, StunChance, 12, "Percent chance that client will be stunned when mob is behind player. DEFAULT: 12")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
@@ -562,6 +590,7 @@ RULE_INT(NPC, NPCToNPCAggroTimerMin, 500, "Minimum time span after which one NPC
|
||||
RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000, "Maximum time span after which one NPC aggro another NPC (milliseconds)")
|
||||
RULE_BOOL(NPC, UseClassAsLastName, true, "Uses class archetype as LastName for NPC with none")
|
||||
RULE_BOOL(NPC, NewLevelScaling, true, "Better level scaling, use old if new formulas would break your server")
|
||||
RULE_REAL(NPC,NPCBackstabMod, 1.9, "Multiplier for NPC Backstab, Higher = Lower backstab amount")
|
||||
RULE_INT(NPC, NPCGatePercent, 20, " Percentage at which the NPC Will attempt to gate at")
|
||||
RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?")
|
||||
RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate")
|
||||
@@ -592,6 +621,7 @@ RULE_INT(Aggro, ClientAggroCheckIdleInterval, 6000, "Interval in which clients a
|
||||
RULE_REAL(Aggro, PetAttackRange, 40000.0, "Maximum squared range /pet attack works at default is 200")
|
||||
RULE_BOOL(Aggro, NPCAggroMaxDistanceEnabled, true, "If enabled, NPC's will drop aggro beyond 600 units or what is defined at the zone level")
|
||||
RULE_BOOL(Aggro, AggroPlayerPets, false, "If enabled, NPCs will aggro player pets")
|
||||
RULE_BOOL(Aggro, UndeadAlwaysAggro, true, "should undead always aggro?")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(TaskSystem)
|
||||
@@ -656,6 +686,9 @@ RULE_BOOL(Bots, AllowPickpocketCommand, true, "Allows the use of the bot command
|
||||
RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal completely when leveling. Default FALSE.")
|
||||
RULE_INT(Bots, AutosaveIntervalSeconds, 300, "Number of seconds after which a timer is triggered which stores the bot data. The value 0 means no periodic automatic saving.")
|
||||
RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hit bot owner rather than bot.")
|
||||
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
||||
RULE_BOOL(Bots, BotsCanClickItems, true, "Enabled the ability for bots to click items they have equipped. Default TRUE")
|
||||
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Chat)
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
|
||||
|
||||
void EQ::SayLinkEngine::LoadCachedSaylinks()
|
||||
{
|
||||
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP BINARY '[A-Z]' and phrase not REGEXP '[0-9]'");
|
||||
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP '[A-Z]' and phrase not REGEXP '[0-9]'");
|
||||
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
|
||||
g_cached_saylinks = saylinks;
|
||||
}
|
||||
|
||||
+34
-18
@@ -44,6 +44,7 @@
|
||||
#include "repositories/starting_items_repository.h"
|
||||
#include "path_manager.h"
|
||||
#include "repositories/loottable_repository.h"
|
||||
#include "repositories/character_item_recast_repository.h"
|
||||
|
||||
namespace ItemField
|
||||
{
|
||||
@@ -882,34 +883,49 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQ::InventoryPr
|
||||
std::map<uint32, uint32> SharedDatabase::GetItemRecastTimestamps(uint32 char_id)
|
||||
{
|
||||
std::map<uint32, uint32> timers;
|
||||
const std::string query = StringFormat("SELECT recast_type,timestamp FROM character_item_recast WHERE id=%u", char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return timers;
|
||||
|
||||
for (auto& row = results.begin(); row != results.end(); ++row)
|
||||
timers[Strings::ToUnsignedInt(row[0])] = Strings::ToUnsignedInt(row[1]);
|
||||
return timers; // RVO or move assigned
|
||||
const auto& l = CharacterItemRecastRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`id` = {}",
|
||||
char_id
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return timers;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
timers[e.recast_type] = e.timestamp;
|
||||
}
|
||||
|
||||
return timers;
|
||||
}
|
||||
|
||||
uint32 SharedDatabase::GetItemRecastTimestamp(uint32 char_id, uint32 recast_type)
|
||||
{
|
||||
const std::string query = StringFormat("SELECT timestamp FROM character_item_recast WHERE id=%u AND recast_type=%u",
|
||||
char_id, recast_type);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return 0;
|
||||
const auto& l = CharacterItemRecastRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`id` = {} AND `recast_type` = {}",
|
||||
char_id,
|
||||
recast_type
|
||||
)
|
||||
);
|
||||
|
||||
auto& row = results.begin();
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
return l.empty() ? 0 : l[0].timestamp;
|
||||
}
|
||||
|
||||
void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id)
|
||||
{
|
||||
// This actually isn't strictly live-like. Live your recast timestamps are forever
|
||||
const std::string query =
|
||||
StringFormat("DELETE FROM character_item_recast WHERE id = %u and timestamp < UNIX_TIMESTAMP()", char_id);
|
||||
QueryDatabase(query);
|
||||
CharacterItemRecastRepository::DeleteWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`id` = {} AND `timestamp` < UNIX_TIMESTAMP()",
|
||||
char_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id)
|
||||
|
||||
@@ -202,6 +202,19 @@
|
||||
#define SPELL_GUIDE_LEVITATION 39852
|
||||
#define SPELL_GUIDE_SPELL_HASTE 39853
|
||||
#define SPELL_GUIDE_HASTE 39854
|
||||
#define SPELL_VAMPIRIC_EMBRACE 821
|
||||
#define SPELL_VAMPIRIC_EMBRACE_OF_SHADOW 822
|
||||
#define SPELL_BATTLE_CRY 5027
|
||||
#define SPELL_WAR_CRY 5028
|
||||
#define SPELL_BATTLE_CRY_OF_DRAVEL 5029
|
||||
#define SPELL_WAR_CRY_OF_DRAVEL 5030
|
||||
#define SPELL_BATTLE_CRY_OF_THE_MASTRUQ 5031
|
||||
#define SPELL_ANCIENT_CRY_OF_CHAOS 5032
|
||||
#define SPELL_BLOODTHIRST 8476
|
||||
#define SPELL_AMPLIFICATION 2603
|
||||
|
||||
// discipline IDs.
|
||||
#define DISC_UNHOLY_AURA 4520
|
||||
|
||||
//spellgroup ids
|
||||
#define SPELLGROUP_FRENZIED_BURNOUT 2754
|
||||
|
||||
+3
-1
@@ -359,9 +359,11 @@ namespace Tasks {
|
||||
if (activity_states[i].activity_state != ActivityCompleted)
|
||||
{
|
||||
completed_ids[i] = false;
|
||||
current_step = std::min(current_step, el.step);
|
||||
|
||||
// step system advances to next step if only optionals active
|
||||
if (!el.optional)
|
||||
{
|
||||
current_step = std::min(current_step, el.step);
|
||||
result.is_task_complete = false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.36.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.41.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,9 +42,9 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9247
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9249
|
||||
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.36.0",
|
||||
"version": "22.41.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errmsg.h>
|
||||
#include <mysqld_error.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
@@ -399,5 +398,6 @@ void QSDatabase::GeneralQueryReceive(ServerPacket *pack)
|
||||
LogInfo("[{}]", query.c_str());
|
||||
}
|
||||
|
||||
safe_delete(pack);
|
||||
safe_delete_array(queryBuffer);
|
||||
}
|
||||
|
||||
+12
-8
@@ -463,15 +463,17 @@ void TaskStateTest::TestOptionalSteps()
|
||||
// activity_id | step | state
|
||||
// 0 | 0 | complete
|
||||
// 1 | 1 | hidden | optional (active)
|
||||
// 2 | 2 | hidden | optional
|
||||
// 3 | 2 | hidden
|
||||
// 2 | 2 | hidden | optional (active)
|
||||
// 3 | 2 | hidden (active)
|
||||
|
||||
auto res = Tasks::GetActiveElements(data, state, activity_count);
|
||||
|
||||
// since optional is on its own step it's effectively non-optional to open next step
|
||||
// steps that only contain optionals should not need to be completed to open next step
|
||||
TEST_ASSERT(res.is_task_complete == false);
|
||||
TEST_ASSERT(res.active.size() == 1);
|
||||
TEST_ASSERT(res.active.size() == 3);
|
||||
TEST_ASSERT(std::find(res.active.begin(), res.active.end(), 1) != res.active.end());
|
||||
TEST_ASSERT(std::find(res.active.begin(), res.active.end(), 2) != res.active.end());
|
||||
TEST_ASSERT(std::find(res.active.begin(), res.active.end(), 3) != res.active.end());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -530,9 +532,9 @@ void TaskStateTest::TestOptionalLastSteps()
|
||||
auto state = GetMockWorldState(activity_count);
|
||||
data[0].step = 0;
|
||||
data[1].optional = true;
|
||||
data[1].step = 2;
|
||||
data[1].step = 1;
|
||||
data[2].optional = true;
|
||||
data[2].step = 3;
|
||||
data[2].step = 2;
|
||||
|
||||
{
|
||||
// activity_id | step | state
|
||||
@@ -553,13 +555,15 @@ void TaskStateTest::TestOptionalLastSteps()
|
||||
// activity_id | step | state
|
||||
// 0 | 0 | complete
|
||||
// 1 | 1 | hidden | optional (active)
|
||||
// 2 | 2 | hidden | optional
|
||||
// 2 | 2 | hidden | optional (active)
|
||||
|
||||
// step with only an optional should not prevent next step being active
|
||||
auto res = Tasks::GetActiveElements(data, state, activity_count);
|
||||
|
||||
TEST_ASSERT(res.is_task_complete == true);
|
||||
TEST_ASSERT(res.active.size() == 1);
|
||||
TEST_ASSERT(res.active.size() == 2);
|
||||
TEST_ASSERT(std::find(res.active.begin(), res.active.end(), 1) != res.active.end());
|
||||
TEST_ASSERT(std::find(res.active.begin(), res.active.end(), 2) != res.active.end());
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errmsg.h>
|
||||
#include <mysqld_error.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
@@ -160,7 +159,7 @@ bool UCSDatabase::VerifyMailKey(const std::string& characterName, int IPAddress,
|
||||
LogInfo("No mailkeys found for [{}].", characterName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
// The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated
|
||||
|
||||
+1
-7
@@ -164,13 +164,7 @@ int main() {
|
||||
|
||||
database.ExpireMail();
|
||||
|
||||
if(Config->ChatPort != Config->MailPort)
|
||||
{
|
||||
LogInfo("MailPort and CharPort must be the same in eqemu_config.json for UCS");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_Clientlist = new Clientlist(Config->ChatPort);
|
||||
g_Clientlist = new Clientlist(Config->GetUCSPort());
|
||||
|
||||
ChannelList = new ChatChannelList();
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module constantconvert
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gammazero/deque v0.2.0 // indirect
|
||||
github.com/gammazero/workerpool v1.1.3 // indirect
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
github.com/gammazero/deque v0.2.0 h1:SkieyNB4bg2/uZZLxvya0Pq6diUlwx7m2TeT7GAIWaA=
|
||||
github.com/gammazero/deque v0.2.0/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
|
||||
github.com/gammazero/workerpool v1.1.3 h1:WixN4xzukFoN0XSeXF6puqEqFTl2mECI9S6W44HWy9Q=
|
||||
github.com/gammazero/workerpool v1.1.3/go.mod h1:wPjyBLDbyKnUn2XwwyD3EEwo9dHutia9/fwNmSHWACc=
|
||||
@@ -0,0 +1,313 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gammazero/workerpool"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
loadDefinitions()
|
||||
|
||||
// get processor count
|
||||
wp := workerpool.New(runtime.NumCPU())
|
||||
|
||||
// loop through all files in current dir that are cpp files or h files
|
||||
err := filepath.WalkDir("../../", func(path string, d fs.DirEntry, err error) error {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !strings.Contains(path, ".cpp") && !strings.Contains(path, ".h") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if file ends with ".o" skip it
|
||||
if strings.HasSuffix(path, ".o") {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ignoreFiles = []string{
|
||||
"submodules", "/libs", "utils/", "races.h", "backward", "database_update_manifest.cpp", "zonedb.h",
|
||||
}
|
||||
|
||||
ignore := false
|
||||
for _, ignoreString := range ignoreFiles {
|
||||
if strings.Contains(path, ignoreString) {
|
||||
ignore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ignore {
|
||||
return nil
|
||||
}
|
||||
|
||||
wp.Submit(func() {
|
||||
|
||||
// open file for reading
|
||||
// get file contents
|
||||
contents, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatalf("impossible to read file: %s", err)
|
||||
}
|
||||
|
||||
content := string(contents)
|
||||
|
||||
wroteChanges := false
|
||||
|
||||
var newLines []string
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
newLine := line
|
||||
|
||||
// loop through oldDefs and see if any of them are in contents
|
||||
for key, value := range oldDefs {
|
||||
// combine all of the above contains into a slice
|
||||
// loop through slice and if any of them are in line, continue
|
||||
var ignoreMatches = []string{
|
||||
"#define ", "MALE", "FEMALE", "_BIT", "LANG_",
|
||||
}
|
||||
|
||||
ignore := false
|
||||
for _, ignoreString := range ignoreMatches {
|
||||
if strings.Contains(newLine, ignoreString) && !strings.Contains(newLine, "NPC_") {
|
||||
ignore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ignore {
|
||||
continue
|
||||
}
|
||||
|
||||
// below we hackishly use a series of specific string contains to avoid
|
||||
// making blind and wrong replacements
|
||||
// but hey - at least its 100% accurate :)
|
||||
if strings.Contains(line, "case "+key+":") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, " "+key+":", " "+key2+":")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "\t"+key) {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, "\t"+key, "\t"+key2)
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, key+",") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, key+",", key2+",")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, ", "+key) {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, ", "+key, ", "+key2)
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "= "+key+" ") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, "= "+key+" ", "= "+key2+" ")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "= "+key+")") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, "= "+key+")", "= "+key2+")")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "= "+key+";") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, "= "+key+";", "= "+key2+";")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, "= "+key+" ||") {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, "= "+key+" ||", "= "+key2+" ||")
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// match cases where our match is on the last line and last column
|
||||
// we need to be exact in the last column and not do a partial because we can
|
||||
// accidentally rename say OGRE to OGRE2 mistakenly
|
||||
if strings.Contains(line, key) {
|
||||
columns := strings.Split(line, " ")
|
||||
// get the last column
|
||||
lastColumn := strings.TrimSpace(columns[len(columns)-1])
|
||||
if lastColumn == key {
|
||||
for key2, value2 := range newDefs {
|
||||
if value == value2 {
|
||||
newLine = strings.ReplaceAll(newLine, lastColumn, key2)
|
||||
wroteChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if strings.Contains(line, "race == "+key) {
|
||||
// for key2, value2 := range newDefs {
|
||||
// if value == value2 {
|
||||
// newLine = strings.ReplaceAll(newLine, "race == "+key, "race == "+key2)
|
||||
// wroteChanges = true
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
newLines = append(newLines, newLine)
|
||||
}
|
||||
|
||||
// write contents back to file
|
||||
if wroteChanges {
|
||||
fmt.Printf("wrote changes to file [%v]\n", path)
|
||||
err = os.WriteFile(path, []byte(strings.Join(newLines, "\n")), 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("impossible to write file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("impossible to walk directories: %s", err)
|
||||
}
|
||||
|
||||
wp.StopWait()
|
||||
}
|
||||
|
||||
var newDefs = make(map[string]int)
|
||||
var oldDefs = make(map[string]int)
|
||||
|
||||
func loadDefinitions() {
|
||||
// git show master:common/races.h
|
||||
cmd := exec.Command("git", "show", "master:common/races.h")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// load into a string -> int map
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
if strings.Contains(line, "#define ") {
|
||||
if len(strings.Split(line, " ")) <= 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// ignore
|
||||
// #define MALE 0
|
||||
// #define FEMALE 1
|
||||
// #define NEUTER 2
|
||||
if strings.Contains(line, "#define MALE") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(line, "#define FEMALE") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(line, "#define NEUTER") {
|
||||
continue
|
||||
}
|
||||
|
||||
// load "#define RACE_FLYING_CARPET_720 720" into map
|
||||
|
||||
key := strings.Split(line, " ")[1]
|
||||
value := strings.Split(line, " ")[2]
|
||||
value = strings.ReplaceAll(value, "//", "")
|
||||
value = strings.TrimSpace(value)
|
||||
//fmt.Printf("key [%v] value [%v]\n", key, value)
|
||||
|
||||
if !strings.HasPrefix(key, "RACE_") && !strings.HasPrefix(key, "RT_") {
|
||||
continue
|
||||
}
|
||||
|
||||
// convert value to int
|
||||
intValue, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
oldDefs[key] = intValue
|
||||
|
||||
fmt.Printf("oldDefs key [%v] value [%v]\n", key, intValue)
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup/races_cpp_h
|
||||
cmd = exec.Command("git", "show", "cleanup/races_cpp_h:common/races.h")
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// load into a string -> int map
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
if strings.Contains(line, "constexpr uint16") {
|
||||
if len(strings.Split(line, " ")) <= 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// remove all extra spaces in between characters in line
|
||||
line = strings.Join(strings.Fields(line), " ")
|
||||
|
||||
// load " constexpr uint16 Doug = 0;" into map
|
||||
key := strings.Split(line, " ")[2]
|
||||
value := strings.Split(line, " ")[4]
|
||||
value = strings.ReplaceAll(value, "//", "")
|
||||
value = strings.ReplaceAll(value, ";", "")
|
||||
value = strings.TrimSpace(value)
|
||||
|
||||
// convert value to int
|
||||
intValue, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
mapKey := "Race::" + key
|
||||
|
||||
newDefs[mapKey] = intValue
|
||||
|
||||
fmt.Printf("newDefs key [%v] value [%v]\n", mapKey, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ mkdir -p build && cd build && \
|
||||
-DEQEMU_BUILD_LOGIN=ON \
|
||||
-DEQEMU_BUILD_LUA=ON \
|
||||
-DEQEMU_BUILD_PERL=ON \
|
||||
-DCMAKE_CXX_FLAGS:STRING="-O1 -g" \
|
||||
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g" \
|
||||
-DCMAKE_CXX_FLAGS:STRING="-O1 -g -Wno-everything" \
|
||||
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g -Wno-everything" \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-G 'Unix Makefiles' \
|
||||
.. && make -j$((`nproc`-4))
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
require (
|
||||
github.com/golang/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
)
|
||||
|
||||
@@ -10,8 +10,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
|
||||
@@ -513,6 +513,13 @@ foreach my $table_to_generate (@tables) {
|
||||
#############################################
|
||||
if ($repository_generation_option eq "all" || $repository_generation_option eq "extended") {
|
||||
my $generated_repository = './common/repositories/' . $table_to_generate . '_repository.h';
|
||||
|
||||
# check if file exists firsts
|
||||
if (-e $generated_repository) {
|
||||
print "File [$generated_repository] already exists! Can't overwrite extended once created!\n";
|
||||
next;
|
||||
}
|
||||
|
||||
my $cmake_generated_reference = $generated_repository;
|
||||
$cmake_generated_reference =~ s/.\/common\///g;
|
||||
$generated_repository_files .= $cmake_generated_reference . "\n";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,6 +78,10 @@ ADD_EXECUTABLE(world ${world_sources} ${world_headers})
|
||||
|
||||
INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(world PRIVATE ../common/pch/pch.h)
|
||||
ENDIF ()
|
||||
|
||||
ADD_DEFINITIONS(-DWORLD)
|
||||
|
||||
TARGET_LINK_LIBRARIES(world ${SERVER_LIBS})
|
||||
|
||||
@@ -9,5 +9,7 @@ void WorldserverCLI::DatabaseUpdates(int argc, char **argv, argh::parser &cmd, s
|
||||
}
|
||||
|
||||
DatabaseUpdate update;
|
||||
update.SetDatabase(&database)->CheckDbUpdates();
|
||||
update.SetDatabase(&database)
|
||||
->SetContentDatabase(&content_db)
|
||||
->CheckDbUpdates();
|
||||
}
|
||||
|
||||
+85
-95
@@ -28,7 +28,6 @@
|
||||
#include "../common/inventory_profile.h"
|
||||
#include "../common/races.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/languages.h"
|
||||
#include "../common/skills.h"
|
||||
#include "../common/extprofile.h"
|
||||
#include "../common/strings.h"
|
||||
@@ -945,8 +944,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
buffer = fmt::format("{},{},{}.{},{}{:08X}",
|
||||
config->ChatHost,
|
||||
config->ChatPort,
|
||||
config->GetUCSHost(),
|
||||
config->GetUCSPort(),
|
||||
config->ShortName,
|
||||
GetCharName(),
|
||||
static_cast<char>(connection_type),
|
||||
@@ -971,8 +970,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
buffer = fmt::format("{},{},{}.{},{}{:08X}",
|
||||
config->MailHost,
|
||||
config->MailPort,
|
||||
config->GetUCSHost(),
|
||||
config->GetUCSPort(),
|
||||
config->ShortName,
|
||||
GetCharName(),
|
||||
static_cast<char>(connection_type),
|
||||
@@ -1692,15 +1691,16 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
pp.hunger_level = 6000;
|
||||
pp.thirst_level = 6000;
|
||||
|
||||
/* Set default skills for everybody */
|
||||
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
|
||||
pp.skills[EQ::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
|
||||
|
||||
/* Set Racial and Class specific language and skills */
|
||||
SetRacialLanguages(&pp);
|
||||
SetRaceStartingSkills(&pp);
|
||||
SetClassStartingSkills(&pp);
|
||||
SetClassLanguages(&pp);
|
||||
|
||||
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
|
||||
pp.skills[EQ::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
|
||||
|
||||
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
|
||||
|
||||
memset(pp.spell_book, 0xFF, (sizeof(uint32) * EQ::spells::SPELLBOOK_SIZE));
|
||||
@@ -2144,7 +2144,9 @@ void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
|
||||
}
|
||||
case FROGLOK:
|
||||
{
|
||||
pp->skills[EQ::skills::SkillSwimming] = 125;
|
||||
if (RuleI(Skills, SwimmingStartValue) < 125) {
|
||||
pp->skills[EQ::skills::SkillSwimming] = 125;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GNOME:
|
||||
@@ -2161,7 +2163,9 @@ void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
|
||||
case IKSAR:
|
||||
{
|
||||
pp->skills[EQ::skills::SkillForage] = 50;
|
||||
pp->skills[EQ::skills::SkillSwimming] = 100;
|
||||
if (RuleI(Skills, SwimmingStartValue) < 100) {
|
||||
pp->skills[EQ::skills::SkillSwimming] = 100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WOOD_ELF:
|
||||
@@ -2181,115 +2185,101 @@ void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
|
||||
|
||||
void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
|
||||
{
|
||||
switch( pp->race )
|
||||
{
|
||||
case BARBARIAN:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_BARBARIAN] = 100;
|
||||
switch (pp->race) {
|
||||
case Race::Human: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case DARK_ELF:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_DARK_ELVISH] = 100;
|
||||
pp->languages[LANG_DARK_SPEECH] = 100;
|
||||
pp->languages[LANG_ELDER_ELVISH] = 100;
|
||||
pp->languages[LANG_ELVISH] = 25;
|
||||
case Race::Barbarian: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Barbarian] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case DWARF:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_DWARVISH] = 100;
|
||||
pp->languages[LANG_GNOMISH] = 25;
|
||||
case Race::Erudite: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Erudian] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case ERUDITE:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_ERUDIAN] = 100;
|
||||
case Race::WoodElf: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Elvish] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case FROGLOK:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_FROGLOK] = 100;
|
||||
pp->languages[LANG_TROLL] = 25;
|
||||
case Race::HighElf: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::DarkElvish] = 25;
|
||||
pp->languages[Language::ElderElvish] = 25;
|
||||
pp->languages[Language::Elvish] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case GNOME:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_DWARVISH] = 25;
|
||||
pp->languages[LANG_GNOMISH] = 100;
|
||||
case Race::DarkElf: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::DarkElvish] = Language::MaxValue;
|
||||
pp->languages[Language::DarkSpeech] = Language::MaxValue;
|
||||
pp->languages[Language::ElderElvish] = Language::MaxValue;
|
||||
pp->languages[Language::Elvish] = 25;
|
||||
break;
|
||||
}
|
||||
case HALF_ELF:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_ELVISH] = 100;
|
||||
case Race::HalfElf: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Elvish] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case HALFLING:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_HALFLING] = 100;
|
||||
case Race::Dwarf: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Dwarvish] = Language::MaxValue;
|
||||
pp->languages[Language::Gnomish] = 25;
|
||||
break;
|
||||
}
|
||||
case HIGH_ELF:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_DARK_ELVISH] = 25;
|
||||
pp->languages[LANG_ELDER_ELVISH] = 25;
|
||||
pp->languages[LANG_ELVISH] = 100;
|
||||
case Race::Troll: {
|
||||
pp->languages[Language::CommonTongue] = RuleI(Character, TrollCommonTongue);
|
||||
pp->languages[Language::DarkSpeech] = Language::MaxValue;
|
||||
pp->languages[Language::Troll] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case HUMAN:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
case Race::Ogre: {
|
||||
pp->languages[Language::CommonTongue] = RuleI(Character, OgreCommonTongue);
|
||||
pp->languages[Language::DarkSpeech] = Language::MaxValue;
|
||||
pp->languages[Language::Ogre] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case IKSAR:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, IksarCommonTongue);
|
||||
pp->languages[LANG_DARK_SPEECH] = 100;
|
||||
pp->languages[LANG_LIZARDMAN] = 100;
|
||||
case Race::Halfling: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Halfling] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case OGRE:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, OgreCommonTongue);
|
||||
pp->languages[LANG_DARK_SPEECH] = 100;
|
||||
pp->languages[LANG_OGRE] = 100;
|
||||
case Race::Gnome: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Dwarvish] = 25;
|
||||
pp->languages[Language::Gnomish] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case TROLL:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, TrollCommonTongue);
|
||||
pp->languages[LANG_DARK_SPEECH] = 100;
|
||||
pp->languages[LANG_TROLL] = 100;
|
||||
case Race::Iksar: {
|
||||
pp->languages[Language::CommonTongue] = RuleI(Character, IksarCommonTongue);
|
||||
pp->languages[Language::DarkSpeech] = Language::MaxValue;
|
||||
pp->languages[Language::Lizardman] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case WOOD_ELF:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_ELVISH] = 100;
|
||||
case Race::VahShir: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::CombineTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Erudian] = 25;
|
||||
pp->languages[Language::VahShir] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
case VAHSHIR:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_COMBINE_TONGUE] = 100;
|
||||
pp->languages[LANG_ERUDIAN] = 25;
|
||||
pp->languages[LANG_VAH_SHIR] = 100;
|
||||
case Race::Froglok: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::Froglok] = Language::MaxValue;
|
||||
pp->languages[Language::Troll] = 25;
|
||||
break;
|
||||
}
|
||||
case DRAKKIN:
|
||||
{
|
||||
pp->languages[LANG_COMMON_TONGUE] = 100;
|
||||
pp->languages[LANG_ELDER_DRAGON] = 100;
|
||||
pp->languages[LANG_DRAGON] = 100;
|
||||
case Race::Drakkin: {
|
||||
pp->languages[Language::CommonTongue] = Language::MaxValue;
|
||||
pp->languages[Language::ElderDragon] = Language::MaxValue;
|
||||
pp->languages[Language::Dragon] = Language::MaxValue;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2298,12 +2288,12 @@ void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
|
||||
void Client::SetClassLanguages(PlayerProfile_Struct *pp)
|
||||
{
|
||||
// we only need to handle one class, but custom server might want to do more
|
||||
switch(pp->class_) {
|
||||
case Class::Rogue:
|
||||
pp->languages[LANG_THIEVES_CANT] = 100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (pp->class_) {
|
||||
case Class::Rogue:
|
||||
pp->languages[Language::ThievesCant] = Language::MaxValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -434,7 +434,7 @@ int main(int argc, char **argv)
|
||||
tod.year,
|
||||
tod.month,
|
||||
tod.day,
|
||||
tod.hour,
|
||||
tod.hour - 1,
|
||||
tod.minute
|
||||
);
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ void SharedTaskManager::LoadSharedTaskState()
|
||||
|
||||
SharedTaskManager *SharedTaskManager::LoadTaskData()
|
||||
{
|
||||
m_task_data = TasksRepository::All(*m_content_database);
|
||||
m_task_data = TasksRepository::GetWhere(*m_content_database, "enabled = 1");
|
||||
m_task_activity_data = TaskActivitiesRepository::All(*m_content_database);
|
||||
|
||||
LogTasks("Loaded tasks [{}] activities [{}]", m_task_data.size(), m_task_activity_data.size());
|
||||
|
||||
+16
-10
@@ -26,6 +26,7 @@
|
||||
#include "../common/ip_util.h"
|
||||
#include "../common/zone_store.h"
|
||||
#include "../common/path_manager.h"
|
||||
#include "../common/database/database_update.h"
|
||||
|
||||
extern ZSList zoneserver_list;
|
||||
extern WorldConfig Config;
|
||||
@@ -293,7 +294,18 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
||||
const auto c = EQEmuConfig::get();
|
||||
if (c->auto_database_updates) {
|
||||
LogInfo("Checking Database Conversions");
|
||||
database.CheckDatabaseConversions();
|
||||
|
||||
auto *r = RuleManager::Instance();
|
||||
r->LoadRules(&database, "default", false);
|
||||
if (!RuleB(Bots, Enabled) && database.DoesTableExist("bot_data")) {
|
||||
LogInfo("Bot tables found but rule not enabled, enabling");
|
||||
r->SetRule("Bots:Enabled", "true", &database, true, true);
|
||||
}
|
||||
|
||||
DatabaseUpdate update{};
|
||||
update.SetDatabase(&database)
|
||||
->SetContentDatabase(&content_db)
|
||||
->CheckDbUpdates();
|
||||
}
|
||||
|
||||
if (RuleB(Logging, WorldGMSayLogging)) {
|
||||
@@ -622,8 +634,7 @@ void WorldBoot::CheckForPossibleConfigurationIssues()
|
||||
|
||||
// ucs (public)
|
||||
if (
|
||||
(!config_address.empty() && c->MailHost != config_address) ||
|
||||
(!config_address.empty() && c->ChatHost != config_address)
|
||||
(!config_address.empty() && c->GetUCSHost() != config_address)
|
||||
) {
|
||||
LogWarning("# UCS Address Mailhost (Configuration)");
|
||||
LogWarning("");
|
||||
@@ -635,14 +646,9 @@ void WorldBoot::CheckForPossibleConfigurationIssues()
|
||||
LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#mailserver]");
|
||||
LogWarning("");
|
||||
LogWarning(
|
||||
"[server.world.address] value [{}] [server.chatserver.host] [{}]",
|
||||
"[server.world.address] value [{}] [server.ucs.host] [{}]",
|
||||
config_address,
|
||||
c->ChatHost
|
||||
);
|
||||
LogWarning(
|
||||
"[server.world.address] value [{}] [server.mailserver.host] [{}]",
|
||||
config_address,
|
||||
c->MailHost
|
||||
c->GetUCSHost()
|
||||
);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
+2
-2
@@ -111,7 +111,7 @@ void ZSList::Process() {
|
||||
0,
|
||||
0,
|
||||
AccountStatus::Player,
|
||||
Chat::Yellow,
|
||||
Chat::System,
|
||||
fmt::format(
|
||||
"[SYSTEM] World will be shutting down in {} minutes.",
|
||||
((shutdowntimer->GetRemainingTime() / 1000) / 60)
|
||||
@@ -759,7 +759,7 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
|
||||
0,
|
||||
0,
|
||||
AccountStatus::Player,
|
||||
Chat::Yellow,
|
||||
Chat::System,
|
||||
fmt::format(
|
||||
"[SYSTEM] World will be shutting down in {} minutes.",
|
||||
(time / 60)
|
||||
|
||||
+6
-1
@@ -191,7 +191,6 @@ SET(zone_headers
|
||||
embperl.h
|
||||
encounter.h
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
expedition.h
|
||||
expedition_database.h
|
||||
@@ -284,6 +283,12 @@ ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
|
||||
|
||||
INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/pch.h)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/types.h ../common/eqemu_logsys.h ../common/eqemu_logsys_log_aliases.h ../common/features.h ../common/global_define.h)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE mob.h npc.h corpse.h doors.h bot.h entity.h client.h zone.h)
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DZONE)
|
||||
|
||||
TARGET_LINK_LIBRARIES(zone ${ZONE_LIBS})
|
||||
|
||||
+111
-99
@@ -39,6 +39,8 @@ Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
#include "bot.h"
|
||||
|
||||
#include "../common/repositories/character_alternate_abilities_repository.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
@@ -510,38 +512,41 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *tar, uint32 d
|
||||
delete made_npc;
|
||||
}
|
||||
|
||||
void Client::ResetAA() {
|
||||
void Client::ResetAA()
|
||||
{
|
||||
SendClearAA();
|
||||
RefundAA();
|
||||
|
||||
memset(&m_pp.aa_array[0], 0, sizeof(AA_Array) * MAX_PP_AA_ARRAY);
|
||||
|
||||
int i = 0;
|
||||
for(auto &rank_value : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value.first, rank_value.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
int slot_id = 0;
|
||||
|
||||
if(!rank) {
|
||||
for (auto& rank_value: aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value.first, rank_value.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if (!rank) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_pp.aa_array[i].AA = rank_value.first;
|
||||
m_pp.aa_array[i].value = rank_value.second.first;
|
||||
m_pp.aa_array[i].charges = rank_value.second.second;
|
||||
++i;
|
||||
m_pp.aa_array[slot_id].AA = rank_value.first;
|
||||
m_pp.aa_array[slot_id].value = rank_value.second.first;
|
||||
m_pp.aa_array[slot_id].charges = rank_value.second.second;
|
||||
++slot_id;
|
||||
}
|
||||
|
||||
for(int i = 0; i < _maxLeaderAA; ++i)
|
||||
m_pp.leader_abilities.ranks[i] = 0;
|
||||
for (int slot_id = 0; slot_id < _maxLeaderAA; ++slot_id) {
|
||||
m_pp.leader_abilities.ranks[slot_id] = 0;
|
||||
}
|
||||
|
||||
m_pp.group_leadership_points = 0;
|
||||
m_pp.raid_leadership_points = 0;
|
||||
m_pp.group_leadership_exp = 0;
|
||||
m_pp.raid_leadership_exp = 0;
|
||||
m_pp.raid_leadership_points = 0;
|
||||
m_pp.group_leadership_exp = 0;
|
||||
m_pp.raid_leadership_exp = 0;
|
||||
|
||||
database.DeleteCharacterAAs(CharacterID());
|
||||
database.DeleteCharacterLeadershipAAs(CharacterID());
|
||||
database.DeleteCharacterLeadershipAbilities(CharacterID());
|
||||
}
|
||||
|
||||
void Client::SendClearAA()
|
||||
@@ -833,31 +838,31 @@ void Client::RefundAA() {
|
||||
int refunded = 0;
|
||||
|
||||
auto rank_value = aa_ranks.begin();
|
||||
while(rank_value != aa_ranks.end()) {
|
||||
while (rank_value != aa_ranks.end()) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value->first, rank_value->second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if(!ability) {
|
||||
if (!ability) {
|
||||
++rank_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ability->charges > 0 && rank_value->second.second < 1) {
|
||||
if (ability->charges > 0 && rank_value->second.second < 1) {
|
||||
++rank_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ability->grant_only) {
|
||||
if (ability->grant_only) {
|
||||
++rank_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
refunded += rank->total_cost;
|
||||
rank_value = aa_ranks.erase(rank_value);
|
||||
rank_value = aa_ranks.erase(rank_value);
|
||||
}
|
||||
|
||||
if(refunded > 0) {
|
||||
if (refunded > 0) {
|
||||
m_pp.aapoints += refunded;
|
||||
SaveAA();
|
||||
Save();
|
||||
@@ -1438,40 +1443,42 @@ void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
|
||||
|
||||
bool ZoneDatabase::LoadAlternateAdvancement(Client *c) {
|
||||
c->ClearAAs();
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"aa_id, "
|
||||
"aa_value, "
|
||||
"charges "
|
||||
"FROM "
|
||||
"`character_alternate_abilities` "
|
||||
"WHERE `id` = %u", c->CharacterID());
|
||||
MySQLRequestResult results = database.QueryDatabase(query);
|
||||
|
||||
int i = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 aa = Strings::ToUnsignedInt(row[0]);
|
||||
uint32 value = Strings::ToUnsignedInt(row[1]);
|
||||
uint32 charges = Strings::ToUnsignedInt(row[2]);
|
||||
const auto& l = CharacterAlternateAbilitiesRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`id` = {}",
|
||||
c->CharacterID()
|
||||
)
|
||||
);
|
||||
|
||||
auto rank = zone->GetAlternateAdvancementRank(aa);
|
||||
if(!rank) {
|
||||
uint32 slot_id = 0;
|
||||
|
||||
for (const auto& e : l) {
|
||||
const uint16 aa_id = e.aa_id;
|
||||
const uint16 aa_value = e.aa_value;
|
||||
const uint16 charges = e.charges;
|
||||
|
||||
auto rank = zone->GetAlternateAdvancementRank(aa_id);
|
||||
if (!rank) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ability = rank->base_ability;
|
||||
if(!ability) {
|
||||
if (!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rank = ability->GetRankByPointsSpent(value);
|
||||
rank = ability->GetRankByPointsSpent(aa_value);
|
||||
|
||||
if(c->CanUseAlternateAdvancementRank(rank)) {
|
||||
c->GetPP().aa_array[i].AA = aa;
|
||||
c->GetPP().aa_array[i].value = value;
|
||||
c->GetPP().aa_array[i].charges = charges;
|
||||
c->SetAA(aa, value, charges);
|
||||
i++;
|
||||
if (c->CanUseAlternateAdvancementRank(rank)) {
|
||||
c->GetPP().aa_array[slot_id].AA = aa_id;
|
||||
c->GetPP().aa_array[slot_id].value = aa_value;
|
||||
c->GetPP().aa_array[slot_id].charges = charges;
|
||||
|
||||
c->SetAA(aa_id, aa_value, charges);
|
||||
|
||||
slot_id++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1556,56 +1563,61 @@ uint32 Mob::GetAAByAAID(uint32 aa_id, uint32 *charges) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges) {
|
||||
if(zone) {
|
||||
AA::Ability *ability = zone->GetAlternateAdvancementAbilityByRank(rank_id);
|
||||
bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges)
|
||||
{
|
||||
if (zone) {
|
||||
auto a = zone->GetAlternateAdvancementAbilityByRank(rank_id);
|
||||
|
||||
if(!ability) {
|
||||
if (!a) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(new_value > ability->GetMaxLevel(this)) {
|
||||
if(new_value > a->GetMaxLevel(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aa_ranks[ability->id] = std::make_pair(new_value, charges);
|
||||
aa_ranks[a->id] = std::make_pair(new_value, charges);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank)
|
||||
{
|
||||
if (!rank) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AA::Ability *ability = rank->base_ability;
|
||||
const auto a = rank->base_ability;
|
||||
|
||||
if(!ability)
|
||||
return false;
|
||||
|
||||
if(!(ability->classes & (1 << GetClass()))) {
|
||||
if (!a) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passive and Active Shroud AAs
|
||||
// For now we skip them
|
||||
if(ability->category == 3 || ability->category == 4) {
|
||||
if (!(a->classes & (1 << GetClass()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passive and Active Shroud AAs, skip for now
|
||||
if (
|
||||
a->category == AACategory::ShroudPassive ||
|
||||
a->category == AACategory::ShroudActive
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//the one titanium hack i will allow
|
||||
//just to make sure we dont crash the client with newer aas
|
||||
//we'll exclude any expendable ones
|
||||
if(IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskTitaniumAndEarlier) {
|
||||
if(ability->charges > 0) {
|
||||
if (IsClient() && CastToClient()->ClientVersionBit() & EQ::versions::maskTitaniumAndEarlier) {
|
||||
if (a->charges > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int expansion = RuleI(Expansion, CurrentExpansion);
|
||||
bool use_expansion_aa = RuleB(Expansion, UseCurrentExpansionAAOnly);
|
||||
const int expansion = RuleI(Expansion, CurrentExpansion);
|
||||
const bool use_expansion_aa = RuleB(Expansion, UseCurrentExpansionAAOnly);
|
||||
if (use_expansion_aa && expansion >= 0) {
|
||||
if (rank->expansion > expansion) {
|
||||
return false;
|
||||
@@ -1617,36 +1629,35 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
if (rank->expansion && !(CastToClient()->GetPP().expansions & (1 << (rank->expansion - 1)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (IsBot()) {
|
||||
} else if (IsBot()) {
|
||||
if (rank->expansion && !(CastToBot()->GetExpansionBitmask() & (1 << (rank->expansion - 1)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (rank->expansion && !(RuleI(World, ExpansionSettings) & (1 << (rank->expansion - 1)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto race = GetPlayerRaceValue(GetBaseRace());
|
||||
race = race > 16 ? 1 : race;
|
||||
if(!(ability->races & (1 << (race - 1)))) {
|
||||
|
||||
race = race > PLAYER_RACE_COUNT ? Race::Human : race;
|
||||
|
||||
if (!(a->races & (1 << (race - 1)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto deity = GetDeityBit();
|
||||
if(!(ability->deities & deity)) {
|
||||
const auto deity = GetDeityBit();
|
||||
if (!(a->deities & deity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(IsClient() && CastToClient()->Admin() < ability->status) {
|
||||
if (IsClient() && CastToClient()->Admin() < a->status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(GetBaseRace() == 522) {
|
||||
//drakkin_heritage
|
||||
if(!(ability->drakkin_heritage & (1 << GetDrakkinHeritage()))) {
|
||||
if (GetBaseRace() == Race::Drakkin) {
|
||||
if (!(a->drakkin_heritage & (1 << GetDrakkinHeritage()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1654,13 +1665,15 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant) {
|
||||
AA::Ability *ability = rank->base_ability;
|
||||
bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant)
|
||||
{
|
||||
auto a = rank->base_ability;
|
||||
|
||||
if(!ability)
|
||||
if (!a) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!CanUseAlternateAdvancementRank(rank)) {
|
||||
if (!CanUseAlternateAdvancementRank(rank)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1668,54 +1681,53 @@ bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price,
|
||||
return false;
|
||||
}
|
||||
|
||||
//You can't purchase grant only AAs they can only be assigned
|
||||
if(check_grant && ability->grant_only) {
|
||||
// You cannot purchase grant only AAs they can only be assigned
|
||||
if (check_grant && a->grant_only) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check level req
|
||||
if(rank->level_req > GetLevel()) {
|
||||
if (rank->level_req > GetLevel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 current_charges = 0;
|
||||
auto points = GetAA(rank->id, ¤t_charges);
|
||||
uint32 current_charges = 0;
|
||||
const uint32 points = GetAA(rank->id, ¤t_charges);
|
||||
|
||||
//check that we are on previous rank already (if exists)
|
||||
//grant ignores the req to own the previous rank.
|
||||
if(check_grant && rank->prev) {
|
||||
if(points != rank->prev->current_value) {
|
||||
if (check_grant && rank->prev) {
|
||||
if (points != rank->prev->current_value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check that we aren't already on this rank or one ahead of us
|
||||
if(points >= rank->current_value) {
|
||||
if (points >= rank->current_value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if expendable only let us purchase if we have no charges already
|
||||
//not quite sure on how this functions client side atm
|
||||
//I intend to look into it later to make sure the behavior is right
|
||||
if(ability->charges > 0 && current_charges > 0) {
|
||||
if (a->charges > 0 && current_charges > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check prereqs
|
||||
for(auto &prereq : rank->prereqs) {
|
||||
for (auto &prereq: rank->prereqs) {
|
||||
AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.first);
|
||||
|
||||
if(prereq_ability) {
|
||||
if (prereq_ability) {
|
||||
auto ranks = GetAA(prereq_ability->first_rank_id);
|
||||
if(ranks < prereq.second) {
|
||||
if (ranks < prereq.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check price, if client
|
||||
if(check_price && IsClient()) {
|
||||
if(rank->cost > CastToClient()->GetAAPoints()) {
|
||||
if (check_price && IsClient()) {
|
||||
if (rank->cost > CastToClient()->GetAAPoints()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1525,6 +1525,19 @@ enum { //values of AA_Action.action
|
||||
aaActionBuy = 3
|
||||
};
|
||||
|
||||
namespace AACategory {
|
||||
constexpr int None = -1;
|
||||
constexpr int Passive = 1;
|
||||
constexpr int Progression = 2;
|
||||
constexpr int ShroudPassive = 3;
|
||||
constexpr int ShroudActive = 4;
|
||||
constexpr int VeteranReward = 5;
|
||||
constexpr int Tradeskill = 6;
|
||||
constexpr int Expendable = 7;
|
||||
constexpr int RacialInnate = 8;
|
||||
constexpr int EverQuest = 9;
|
||||
}
|
||||
|
||||
class Timer;
|
||||
class Mob;
|
||||
class SwarmPet {
|
||||
|
||||
+7
-6
@@ -46,7 +46,7 @@ void EntityList::DescribeAggro(Client *to_who, NPC *from_who, float d, bool verb
|
||||
);
|
||||
|
||||
bool is_engaged = from_who->IsEngaged();
|
||||
bool will_aggro_npcs = from_who->WillAggroNPCs();
|
||||
bool will_aggro_npcs = from_who->GetNPCAggro();
|
||||
if (is_engaged) {
|
||||
Mob *top = from_who->GetHateTop();
|
||||
to_who->Message(
|
||||
@@ -524,7 +524,8 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
} else {
|
||||
if (
|
||||
(
|
||||
GetINT() <= RuleI(Aggro, IntAggroThreshold) ||
|
||||
(RuleB(Aggro, UndeadAlwaysAggro) && GetBodyType() == BT_Undead) ||
|
||||
(GetINT() <= RuleI(Aggro, IntAggroThreshold)) ||
|
||||
AlwaysAggro() ||
|
||||
(
|
||||
mob->IsClient() &&
|
||||
@@ -983,14 +984,14 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
|
||||
float size_mod = GetSize();
|
||||
float other_size_mod = other->GetSize();
|
||||
|
||||
if (GetRace() == RACE_LAVA_DRAGON_49 || GetRace() == RACE_WURM_158 || GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
|
||||
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) { //For races with a fixed size
|
||||
size_mod = 60.0f;
|
||||
}
|
||||
else if (size_mod < 6.0) {
|
||||
size_mod = 8.0f;
|
||||
}
|
||||
|
||||
if (other->GetRace() == RACE_LAVA_DRAGON_49 || other->GetRace() == RACE_WURM_158 || other->GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
|
||||
if (other->GetRace() == Race::LavaDragon || other->GetRace() == Race::Wurm || other->GetRace() == Race::GhostDragon) { //For races with a fixed size
|
||||
other_size_mod = 60.0f;
|
||||
}
|
||||
else if (other_size_mod < 6.0) {
|
||||
@@ -1011,11 +1012,11 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
|
||||
size_mod *= size_mod * 4;
|
||||
}
|
||||
|
||||
if (other->GetRace() == RACE_VELIOUS_DRAGON_184) // Lord Vyemm and other velious dragons
|
||||
if (other->GetRace() == Race::VeliousDragon) // Lord Vyemm and other velious dragons
|
||||
{
|
||||
size_mod *= 1.75;
|
||||
}
|
||||
if (other->GetRace() == RACE_DRAGON_SKELETON_122) // Dracoliche in Fear. Skeletal Dragon
|
||||
if (other->GetRace() == Race::DragonSkeleton) // Dracoliche in Fear. Skeletal Dragon
|
||||
{
|
||||
size_mod *= 2.25;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection,
|
||||
row["swarm_owner"] = npc->GetSwarmOwner();
|
||||
row["swarm_target"] = npc->GetSwarmTarget();
|
||||
row["waypoint_max"] = npc->GetWaypointMax();
|
||||
row["will_aggro_npcs"] = npc->WillAggroNPCs();
|
||||
row["npc_aggro"] = npc->GetNPCAggro();
|
||||
|
||||
response.append(row);
|
||||
}
|
||||
|
||||
+144
-69
@@ -1419,7 +1419,7 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo
|
||||
if (other->CheckHitChance(this, hit)) {
|
||||
if (IsNPC() && other->IsClient() && other->animation > 0 && GetLevel() >= 5 && BehindMob(other, GetX(), GetY())) {
|
||||
// ~ 12% chance
|
||||
if (zone->random.Roll(12)) {
|
||||
if (zone->random.Roll(RuleI(Combat, StunChance))) {
|
||||
int stun_resist2 = other->spellbonuses.FrontalStunResist + other->itembonuses.FrontalStunResist + other->aabonuses.FrontalStunResist;
|
||||
int stun_resist = other->spellbonuses.StunResist + other->itembonuses.StunResist + other->aabonuses.StunResist;
|
||||
if (zone->random.Roll(stun_resist2)) {
|
||||
@@ -1820,7 +1820,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
|
||||
auto emote_id = killerMob->GetEmoteID();
|
||||
if (emote_id) {
|
||||
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid);
|
||||
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
|
||||
}
|
||||
|
||||
killerMob->TrySpellOnKill(killed_level, spell);
|
||||
@@ -2119,6 +2119,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
}
|
||||
|
||||
RemoveFromHateList(other);
|
||||
RemoveFromRampageList(other);
|
||||
LogCombat("I am not allowed to attack [{}]", other->GetName());
|
||||
return false;
|
||||
}
|
||||
@@ -2280,49 +2281,51 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
if (other->IsClient() && IsPet() && GetOwner()->IsClient()) {
|
||||
//pets do half damage to clients in pvp
|
||||
my_hit.damage_done /= 2;
|
||||
if (my_hit.damage_done < 1)
|
||||
if (my_hit.damage_done < 1) {
|
||||
my_hit.damage_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
my_hit.damage_done = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
if (GetHP() > 0 && !other->HasDied()) {
|
||||
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks); // Not avoidable client already had thier chance to Avoid
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if (HasDied()) //killed by damage shield ect
|
||||
if (HasDied()) { //killed by damage shield ect
|
||||
return false;
|
||||
}
|
||||
|
||||
MeleeLifeTap(my_hit.damage_done);
|
||||
|
||||
CommonBreakInvisibleFromCombat();
|
||||
|
||||
//I doubt this works...
|
||||
if (!GetTarget())
|
||||
if (!GetTarget()) {
|
||||
return true; //We killed them
|
||||
|
||||
if (!bRiposte && !other->HasDied()) {
|
||||
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
|
||||
|
||||
if (!other->HasDied())
|
||||
TrySpellProc(nullptr, weapon, other, Hand);
|
||||
|
||||
if (my_hit.damage_done > 0 && HasSkillProcSuccess() && !other->HasDied())
|
||||
TrySkillProc(other, my_hit.skill, 0, true, Hand);
|
||||
}
|
||||
|
||||
if (GetHP() > 0 && !other->HasDied())
|
||||
bool has_hit = my_hit.damage_done > 0;
|
||||
if (has_hit && !bRiposte && !other->HasDied()) {
|
||||
TryWeaponProc(nullptr, weapon, other, Hand);
|
||||
|
||||
if (!other->HasDied()) {
|
||||
TrySpellProc(nullptr, weapon, other, Hand);
|
||||
}
|
||||
|
||||
if (HasSkillProcSuccess() && !other->HasDied()) {
|
||||
TrySkillProc(other, my_hit.skill, 0, true, Hand);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetHP() > 0 && !other->HasDied()) {
|
||||
TriggerDefensiveProcs(other, Hand, true, my_hit.damage_done);
|
||||
}
|
||||
|
||||
if (my_hit.damage_done > 0)
|
||||
return true;
|
||||
|
||||
else
|
||||
return false;
|
||||
return has_hit;
|
||||
}
|
||||
|
||||
void NPC::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, eSpecialAttacks special) {
|
||||
@@ -2705,6 +2708,8 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
Corpse* corpse = nullptr;
|
||||
|
||||
const uint16 entity_id = GetID();
|
||||
|
||||
if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) &&
|
||||
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
|
||||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
|
||||
@@ -2736,7 +2741,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
ApplyIllusionToCorpse(illusion_spell_id, corpse);
|
||||
|
||||
if (killer != 0 && emoteid != 0)
|
||||
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid);
|
||||
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
|
||||
if (killer != 0 && killer->IsClient()) {
|
||||
corpse->AllowPlayerLoot(killer, 0);
|
||||
if (killer->IsGrouped()) {
|
||||
@@ -2814,12 +2819,13 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
entity_list.RemoveFromXTargets(this);
|
||||
}
|
||||
|
||||
|
||||
// Parse quests even if we're killed by an NPC
|
||||
if (oos) {
|
||||
if (IsNPC()) {
|
||||
auto emote_id = GetEmoteID();
|
||||
if (emote_id) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2830,7 +2836,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
auto emote_id = oos->GetEmoteID();
|
||||
if (emote_id) {
|
||||
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
|
||||
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
|
||||
}
|
||||
if (killer_mob) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
@@ -2855,13 +2861,15 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
entity_list.UpdateFindableNPCState(this, true);
|
||||
|
||||
m_combat_record.Stop();
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {}",
|
||||
"{} {} {} {} {}",
|
||||
killer_mob ? killer_mob->GetID() : 0,
|
||||
damage,
|
||||
spell,
|
||||
static_cast<int>(attack_skill)
|
||||
static_cast<int>(attack_skill),
|
||||
entity_id
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse };
|
||||
@@ -2869,15 +2877,15 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
|
||||
}
|
||||
|
||||
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
|
||||
|
||||
// Zone controller process EVENT_DEATH_ZONE (Death events)
|
||||
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {}",
|
||||
"{} {} {} {} {}",
|
||||
killer_mob ? killer_mob->GetID() : 0,
|
||||
damage,
|
||||
spell,
|
||||
static_cast<int>(attack_skill)
|
||||
static_cast<int>(attack_skill),
|
||||
entity_id
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse, this };
|
||||
@@ -3718,9 +3726,43 @@ bool Client::CheckDoubleAttack()
|
||||
// with varying triple attack skill (1-3% error at least)
|
||||
bool Client::CheckTripleAttack()
|
||||
{
|
||||
int chance = GetSkill(EQ::skills::SkillTripleAttack);
|
||||
if (chance < 1)
|
||||
int chance;
|
||||
|
||||
if (RuleB(Combat, ClassicTripleAttack)) {
|
||||
if (
|
||||
IsClient() &&
|
||||
GetLevel() >= 60 &&
|
||||
(
|
||||
GetClass() == Class::Warrior ||
|
||||
GetClass() == Class::Ranger ||
|
||||
GetClass() == Class::Monk ||
|
||||
GetClass() == Class::Berserker
|
||||
)
|
||||
) {
|
||||
switch (GetClass()) {
|
||||
case Class::Warrior:
|
||||
chance = RuleI(Combat, ClassicTripleAttackChanceWarrior);
|
||||
break;
|
||||
case Class::Ranger:
|
||||
chance = RuleI(Combat, ClassicTripleAttackChanceRanger);
|
||||
break;
|
||||
case Class::Monk:
|
||||
chance = RuleI(Combat, ClassicTripleAttackChanceMonk);
|
||||
break;
|
||||
case Class::Berserker:
|
||||
chance = RuleI(Combat, ClassicTripleAttackChanceBerserker);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chance = GetSkill(EQ::skills::SkillTripleAttack);
|
||||
}
|
||||
|
||||
if (chance < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int inc = aabonuses.TripleAttackChance + spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
|
||||
chance = static_cast<int>(chance * (1 + inc / 100.0f));
|
||||
@@ -3805,6 +3847,8 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
|
||||
if (damage > 0) {
|
||||
//if there is some damage being done and theres an attacker involved
|
||||
int previous_hp_ratio = GetHPRatio();
|
||||
|
||||
if (attacker) {
|
||||
// if spell is lifetap add hp to the caster
|
||||
if (IsValidSpell(spell_id) && IsLifetapSpell(spell_id)) {
|
||||
@@ -3909,13 +3953,13 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
|
||||
}
|
||||
|
||||
if (IsClient() && CastToClient()->sneaking) {
|
||||
CastToClient()->sneaking = false;
|
||||
SendAppearancePacket(AT_Sneak, 0);
|
||||
if (IsClient()) {
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
if (attacker && attacker->IsClient() && attacker->CastToClient()->sneaking) {
|
||||
attacker->CastToClient()->sneaking = false;
|
||||
attacker->SendAppearancePacket(AT_Sneak, 0);
|
||||
attacker->SendAppearancePacket(AppearanceType::Sneak, 0);
|
||||
}
|
||||
|
||||
//final damage has been determined.
|
||||
@@ -4030,8 +4074,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (GetHPRatio() < 16)
|
||||
if (GetHPRatio() < 16 && previous_hp_ratio >= 16) {
|
||||
TryDeathSave();
|
||||
}
|
||||
}
|
||||
|
||||
TryTriggerOnCastRequirement();
|
||||
@@ -4087,7 +4132,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
IsPlayerRace(GetBaseRace()) &&
|
||||
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
|
||||
) ||
|
||||
GetBaseRace() == RACE_OGGOK_CITIZEN_93
|
||||
GetBaseRace() == Race::OggokCitizen
|
||||
) {
|
||||
is_immune_to_frontal_stun = true;
|
||||
}
|
||||
@@ -4107,7 +4152,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
IsPlayerRace(GetBaseRace()) &&
|
||||
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
|
||||
) ||
|
||||
GetBaseRace() == RACE_OGGOK_CITIZEN_93
|
||||
GetBaseRace() == Race::OggokCitizen
|
||||
)
|
||||
) {
|
||||
is_immune_to_frontal_stun = true;
|
||||
@@ -4179,8 +4224,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
|
||||
//send an HP update if we are hurt
|
||||
if (GetHP() < GetMaxHP())
|
||||
if (GetHP() < GetMaxHP()) {
|
||||
SendHPUpdate(); // the OP_Damage actually updates the client in these cases, so we skip the HP update for them
|
||||
}
|
||||
} //end `if damage was done`
|
||||
|
||||
//send damage packet...
|
||||
@@ -4188,32 +4234,48 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer;
|
||||
a->target = GetID();
|
||||
if (attacker == nullptr)
|
||||
|
||||
if (!attacker) {
|
||||
a->source = 0;
|
||||
else if (attacker->IsClient() && attacker->CastToClient()->GMHideMe())
|
||||
} else if (attacker->IsClient() && attacker->CastToClient()->GMHideMe()) {
|
||||
a->source = 0;
|
||||
else
|
||||
} else {
|
||||
a->source = attacker->GetID();
|
||||
}
|
||||
|
||||
a->type = (EQ::ValueWithin(skill_used, EQ::skills::Skill1HBlunt, EQ::skills::Skill2HPiercing)) ?
|
||||
SkillDamageTypes[skill_used] : SkillDamageTypes[EQ::skills::SkillHandtoHand]; // was 0x1c
|
||||
a->damage = damage;
|
||||
a->spellid = spell_id;
|
||||
if (special == eSpecialAttacks::AERampage)
|
||||
|
||||
if (special == eSpecialAttacks::AERampage) {
|
||||
a->special = 1;
|
||||
else if (special == eSpecialAttacks::Rampage)
|
||||
} else if (special == eSpecialAttacks::Rampage) {
|
||||
a->special = 2;
|
||||
else
|
||||
} else {
|
||||
a->special = 0;
|
||||
}
|
||||
|
||||
a->hit_heading = attacker ? attacker->GetHeading() : 0.0f;
|
||||
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
||||
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
||||
a->force = EQ::skills::GetSkillMeleePushForce(skill_used);
|
||||
|
||||
if (RuleR(Combat, MeleePushForceClientPercent) && IsClient()) {
|
||||
a->force += a->force * RuleR(Combat, MeleePushForceClientPercent);
|
||||
}
|
||||
|
||||
if (RuleR(Combat, MeleePushForcePetPercent) && IsPet()) {
|
||||
a->force += a->force * RuleR(Combat, MeleePushForcePetPercent);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
if (attacker && attacker->IsNPC()) {
|
||||
if (!RuleB(Combat, NPCtoNPCPush) && attacker && attacker->IsNPC()) {
|
||||
a->force = 0.0f; // 2013 change that disabled NPC vs NPC push
|
||||
} else {
|
||||
a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC
|
||||
}
|
||||
|
||||
if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) {
|
||||
m_Delta.x += a->force * g_Math.FastSin(a->hit_heading);
|
||||
m_Delta.y += a->force * g_Math.FastCos(a->hit_heading);
|
||||
@@ -5015,7 +5077,7 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
||||
hit.damage_done = (hit.damage_done * SlayDmgBonus) / 100;
|
||||
|
||||
/* Female */
|
||||
if (GetGender() == 1) {
|
||||
if (GetGender() == Gender::Female) {
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
false, /* Skip Sender */
|
||||
@@ -5183,7 +5245,6 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
||||
bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||
{
|
||||
float hp_limit = 10.0f;
|
||||
|
||||
auto fb_hp_limit = std::max(
|
||||
{
|
||||
aabonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO],
|
||||
@@ -5195,28 +5256,36 @@ bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||
if (fb_hp_limit) {
|
||||
hp_limit = fb_hp_limit/10.0f;
|
||||
}
|
||||
if (defender && !defender->IsClient() && defender->GetHPRatio() < hp_limit) {
|
||||
|
||||
uint32 FB_Dmg =
|
||||
if (defender && !defender->IsClient() && defender->GetHPRatio() < hp_limit) {
|
||||
uint32 finishing_blow_damage =
|
||||
aabonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] + spellbonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] + itembonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG];
|
||||
|
||||
uint32 FB_Level = 0;
|
||||
FB_Level = aabonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
if (FB_Level < spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX])
|
||||
FB_Level = spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
else if (FB_Level < itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX])
|
||||
FB_Level = itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
uint32 finishing_blow_level = 0;
|
||||
finishing_blow_level = aabonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
if (finishing_blow_level < spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX]) {
|
||||
finishing_blow_level = spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
} else if (finishing_blow_level < itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX]) {
|
||||
finishing_blow_level = itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX];
|
||||
}
|
||||
|
||||
// modern AA description says rank 1 (500) is 50% chance
|
||||
int ProcChance = (
|
||||
int proc_chance = (
|
||||
aabonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] +
|
||||
itembonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE] +
|
||||
spellbonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_PROC_CHANCE]
|
||||
);
|
||||
|
||||
if (FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) &&
|
||||
(ProcChance >= zone->random.Int(1, 1000))) {
|
||||
|
||||
if (
|
||||
(
|
||||
(RuleB(Combat, FinishingBlowOnlyWhenFleeing) && !defender->currently_fleeing) ||
|
||||
!RuleB(Combat, FinishingBlowOnlyWhenFleeing)
|
||||
) &&
|
||||
finishing_blow_level &&
|
||||
finishing_blow_damage &&
|
||||
defender->GetLevel() <= finishing_blow_level &&
|
||||
proc_chance >= zone->random.Int(1, 1000)
|
||||
) {
|
||||
/* Finishing Blow Critical Message */
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, /* Sender */
|
||||
@@ -5229,7 +5298,7 @@ bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||
GetCleanName() /* Message1 */
|
||||
);
|
||||
|
||||
damage = FB_Dmg;
|
||||
damage = finishing_blow_damage;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6287,15 +6356,21 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
|
||||
// you can only triple from the main hand
|
||||
if (hand == EQ::invslot::slotPrimary && CanThisClassTripleAttack()) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillTripleAttack, target, -10);
|
||||
if (!RuleB(Combat, ClassicTripleAttack)) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillTripleAttack, target, -10);
|
||||
}
|
||||
|
||||
if (CheckTripleAttack()) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance +
|
||||
int flurry_chance = aabonuses.FlurryChance + spellbonuses.FlurryChance +
|
||||
itembonuses.FlurryChance;
|
||||
if (flurrychance && zone->random.Roll(flurrychance)) {
|
||||
|
||||
if (flurry_chance && zone->random.Roll(flurry_chance)) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
if (zone->random.Roll(flurrychance))
|
||||
|
||||
if (zone->random.Roll(flurry_chance)) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
}
|
||||
MessageString(Chat::NPCFlurry, YOU_FLURRY);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -49,9 +49,9 @@ Beacon::Beacon(const glm::vec4 &in_pos, int lifetime) : Mob(
|
||||
nullptr, // in_lastname
|
||||
0, // in_cur_hp
|
||||
0, // in_max_hp
|
||||
MALE, // in_gender
|
||||
INVISIBLE_MAN, // in_race
|
||||
0, // in_class
|
||||
Gender::Male, // in_gender
|
||||
Race::InvisibleMan, // in_race
|
||||
Class::None, // in_class
|
||||
BT_NoTarget, // in_bodytype
|
||||
0, // in_deity
|
||||
0, // in_level
|
||||
|
||||
+691
-84
@@ -94,6 +94,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
SetPullFlag(false);
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag(false);
|
||||
SetIsUsingItemClick(false);
|
||||
m_previous_pet_order = SPO_Guard;
|
||||
|
||||
rest_timer.Disable();
|
||||
@@ -107,6 +108,8 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
// Do this once and only in this constructor
|
||||
GenerateAppearance();
|
||||
GenerateBaseStats();
|
||||
bot_timers.clear();
|
||||
|
||||
// Calculate HitPoints Last As It Uses Base Stats
|
||||
current_hp = GenerateBaseHitPoints();
|
||||
current_mana = GenerateBaseManaPoints();
|
||||
@@ -114,8 +117,6 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
hp_regen = CalcHPRegen();
|
||||
mana_regen = CalcManaRegen();
|
||||
end_regen = CalcEnduranceRegen();
|
||||
for (int i = 0; i < MaxTimer; i++)
|
||||
timers[i] = 0;
|
||||
|
||||
strcpy(name, GetCleanName());
|
||||
memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct));
|
||||
@@ -213,6 +214,7 @@ Bot::Bot(
|
||||
SetPullFlag(false);
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag(false);
|
||||
SetIsUsingItemClick(false);
|
||||
m_previous_pet_order = SPO_Guard;
|
||||
|
||||
rest_timer.Disable();
|
||||
@@ -238,9 +240,6 @@ Bot::Bot(
|
||||
error_message.clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MaxTimer; i++)
|
||||
timers[i] = 0;
|
||||
|
||||
if (GetClass() == Class::Rogue) {
|
||||
m_evade_timer.Start();
|
||||
}
|
||||
@@ -252,8 +251,10 @@ Bot::Bot(
|
||||
|
||||
GenerateBaseStats();
|
||||
|
||||
if (!database.botdb.LoadTimers(this) && bot_owner)
|
||||
bot_timers.clear();
|
||||
if (!database.botdb.LoadTimers(this) && bot_owner) {
|
||||
bot_owner->Message(Chat::White, "%s for '%s'", BotDatabase::fail::LoadTimers(), GetCleanName());
|
||||
}
|
||||
|
||||
LoadAAs();
|
||||
|
||||
@@ -280,10 +281,10 @@ Bot::Bot(
|
||||
case SE_IllusionCopy:
|
||||
case SE_Illusion: {
|
||||
if (spell.base_value[x1] == -1) {
|
||||
if (gender == FEMALE) {
|
||||
gender = MALE;
|
||||
} else if (gender == MALE) {
|
||||
gender = FEMALE;
|
||||
if (gender == Gender::Female) {
|
||||
gender = Gender::Male;
|
||||
} else if (gender == Gender::Male) {
|
||||
gender = Gender::Female;
|
||||
}
|
||||
|
||||
SendIllusionPacket(
|
||||
@@ -324,30 +325,30 @@ Bot::Bot(
|
||||
|
||||
switch (spell.base_value[x1]) {
|
||||
case OGRE:
|
||||
SendAppearancePacket(AT_Size, 9);
|
||||
SendAppearancePacket(AppearanceType::Size, 9);
|
||||
break;
|
||||
case TROLL:
|
||||
SendAppearancePacket(AT_Size, 8);
|
||||
SendAppearancePacket(AppearanceType::Size, 8);
|
||||
break;
|
||||
case VAHSHIR:
|
||||
case BARBARIAN:
|
||||
SendAppearancePacket(AT_Size, 7);
|
||||
SendAppearancePacket(AppearanceType::Size, 7);
|
||||
break;
|
||||
case HALF_ELF:
|
||||
case WOOD_ELF:
|
||||
case DARK_ELF:
|
||||
case FROGLOK:
|
||||
SendAppearancePacket(AT_Size, 5);
|
||||
SendAppearancePacket(AppearanceType::Size, 5);
|
||||
break;
|
||||
case DWARF:
|
||||
SendAppearancePacket(AT_Size, 4);
|
||||
SendAppearancePacket(AppearanceType::Size, 4);
|
||||
break;
|
||||
case HALFLING:
|
||||
case GNOME:
|
||||
SendAppearancePacket(AT_Size, 3);
|
||||
SendAppearancePacket(AppearanceType::Size, 3);
|
||||
break;
|
||||
default:
|
||||
SendAppearancePacket(AT_Size, 6);
|
||||
SendAppearancePacket(AppearanceType::Size, 6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -371,18 +372,18 @@ Bot::Bot(
|
||||
case SE_Invisibility:
|
||||
{
|
||||
invisible = true;
|
||||
SendAppearancePacket(AT_Invis, 1);
|
||||
SendAppearancePacket(AppearanceType::Invisibility, 1);
|
||||
break;
|
||||
}
|
||||
case SE_Levitate:
|
||||
{
|
||||
if (!zone->CanLevitate())
|
||||
{
|
||||
SendAppearancePacket(AT_Levitate, 0);
|
||||
SendAppearancePacket(AppearanceType::FlyMode, 0);
|
||||
BuffFadeByEffect(SE_Levitate);
|
||||
}
|
||||
else {
|
||||
SendAppearancePacket(AT_Levitate, 2);
|
||||
SendAppearancePacket(AppearanceType::FlyMode, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1668,7 +1669,7 @@ bool Bot::Process()
|
||||
mob_close_scan_timer.GetDuration()
|
||||
);
|
||||
|
||||
entity_list.ScanCloseClientMobs(close_mobs, this);
|
||||
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
|
||||
}
|
||||
|
||||
SpellProcess();
|
||||
@@ -2357,7 +2358,7 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) {
|
||||
}
|
||||
|
||||
auto hater = entity_list.GetMob(hater_iter.spawn_id);
|
||||
if (hater && !hater->IsMezzed() && DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= leash_distance) {
|
||||
if (hater && hater->CastToNPC()->IsOnHatelist(bot_owner) && !hater->IsMezzed() && DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= leash_distance) {
|
||||
// This is roughly equivilent to npc attacking a client pet owner
|
||||
AddToHateList(hater, 1);
|
||||
SetTarget(hater);
|
||||
@@ -2680,7 +2681,7 @@ void Bot::CalcMeleeDistances(const Mob* tar, const EQ::ItemInstance* const& p_it
|
||||
float other_size_mod = tar->GetSize();
|
||||
|
||||
// For races with a fixed size
|
||||
if (GetRace() == RT_DRAGON || GetRace() == RT_WURM || GetRace() == RT_DRAGON_7) {
|
||||
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) {
|
||||
// size_mod = 60.0f;
|
||||
}
|
||||
|
||||
@@ -2689,7 +2690,7 @@ void Bot::CalcMeleeDistances(const Mob* tar, const EQ::ItemInstance* const& p_it
|
||||
}
|
||||
|
||||
// For races with a fixed size
|
||||
if (tar->GetRace() == RT_DRAGON || tar->GetRace() == RT_WURM || tar->GetRace() == RT_DRAGON_7) {
|
||||
if (tar->GetRace() == Race::LavaDragon || tar->GetRace() == Race::Wurm || tar->GetRace() == Race::GhostDragon) {
|
||||
other_size_mod = 60.0f;
|
||||
}
|
||||
|
||||
@@ -2782,10 +2783,12 @@ bool Bot::IsValidTarget(Client* bot_owner, Client* leash_owner, float lo_distanc
|
||||
// Normally, we wouldn't want to do this without class checks..but, too many issues can arise if we let enchanter animation pets run rampant
|
||||
if (HasPet()) {
|
||||
GetPet()->RemoveFromHateList(tar);
|
||||
GetPet()->RemoveFromRampageList(tar);
|
||||
GetPet()->SetTarget(nullptr);
|
||||
}
|
||||
|
||||
RemoveFromHateList(tar);
|
||||
RemoveFromRampageList(tar);
|
||||
SetTarget(nullptr);
|
||||
|
||||
SetAttackFlag(false);
|
||||
@@ -2901,12 +2904,12 @@ void Bot::AcquireBotTarget(Group* bot_group, Raid* raid, Client* leash_owner, fl
|
||||
}
|
||||
} else {
|
||||
// This will keep bots on target for now..but, future updates will allow for rooting/stunning
|
||||
if (auto escaping = hate_list.GetEscapingEntOnHateList(leash_owner, leash_distance)) {
|
||||
if (auto escaping = hate_list.GetEscapingMobOnHateList(leash_owner, leash_distance)) {
|
||||
SetTarget(escaping);
|
||||
}
|
||||
|
||||
if (!GetTarget()) {
|
||||
auto most_hate = hate_list.GetEntWithMostHateOnList(this, nullptr, true);
|
||||
auto most_hate = hate_list.GetMobWithMostHateOnList(this, nullptr, true);
|
||||
if (most_hate) {
|
||||
SetTarget(most_hate);
|
||||
}
|
||||
@@ -3638,41 +3641,45 @@ uint32 Bot::SpawnedBotCount(const uint32 owner_id, uint8 class_id) {
|
||||
return spawned_bot_count;
|
||||
}
|
||||
|
||||
void Bot::LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp) {
|
||||
void Bot::LevelBotWithClient(Client* c, uint8 new_level, bool send_appearance) {
|
||||
// This essentially performs a '#bot update,' with appearance packets, based on the current methods.
|
||||
// This should not be called outside of Client::SetEXP() due to it's lack of rule checks.
|
||||
if (client) {
|
||||
std::list<Bot*> blist = entity_list.GetBotsByBotOwnerCharacterID(client->CharacterID());
|
||||
// This should not be called outside of Client::SetEXP() due to its lack of rule checks.
|
||||
|
||||
for (auto biter = blist.begin(); biter != blist.end(); ++biter) {
|
||||
Bot* bot = *biter;
|
||||
if (c) {
|
||||
const auto &l = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID());
|
||||
|
||||
if (bot && (bot->GetLevel() != client->GetLevel())) {
|
||||
bot->SetPetChooser(false); // not sure what this does, but was in bot 'update' code
|
||||
bot->CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
|
||||
for (const auto &e : l) {
|
||||
if (e && (e->GetLevel() != c->GetLevel())) {
|
||||
int levels_change = (new_level - e->GetLevel());
|
||||
|
||||
if (sendlvlapp) {
|
||||
bot->SendLevelAppearance();
|
||||
if (levels_change < 0) {
|
||||
parse->EventBot(EVENT_LEVEL_DOWN, e, nullptr, std::to_string(std::abs(levels_change)), 0);
|
||||
} else {
|
||||
parse->EventBot(EVENT_LEVEL_UP, e, nullptr, std::to_string(levels_change), 0);
|
||||
}
|
||||
// modified from Client::SetLevel()
|
||||
|
||||
e->SetPetChooser(false); // not sure what this does, but was in bot 'update' code
|
||||
e->CalcBotStats(c->GetBotOption(Client::booStatsUpdate));
|
||||
|
||||
if (send_appearance) {
|
||||
e->SendLevelAppearance();
|
||||
}
|
||||
|
||||
if (!RuleB(Bots, BotHealOnLevel)) {
|
||||
int mhp = bot->CalcMaxHP();
|
||||
if (bot->GetHP() > mhp) {
|
||||
bot->SetHP(mhp);
|
||||
const int64 max_hp = e->CalcMaxHP();
|
||||
if (e->GetHP() > max_hp) {
|
||||
e->SetHP(max_hp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bot->SetHP(bot->CalcMaxHP());
|
||||
bot->SetMana(bot->CalcMaxMana());
|
||||
} else {
|
||||
e->SetHP(e->CalcMaxHP());
|
||||
e->SetMana(e->CalcMaxMana());
|
||||
}
|
||||
|
||||
bot->SendHPUpdate();
|
||||
bot->SendAppearancePacket(AT_WhoLevel, level, true, true); // who level change
|
||||
bot->AI_AddBotSpells(bot->GetBotSpellID());
|
||||
e->SendHPUpdate();
|
||||
e->SendAppearancePacket(AppearanceType::WhoLevel, new_level, true, true); // who level change
|
||||
e->AI_AddBotSpells(e->GetBotSpellID());
|
||||
}
|
||||
}
|
||||
|
||||
blist.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3701,7 +3708,7 @@ void Bot::BotAddEquipItem(uint16 slot_id, uint32 item_id) {
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight() && GetID()) { // temp hack fix
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
SendAppearancePacket(AppearanceType::Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3721,7 +3728,7 @@ void Bot::BotRemoveEquipItem(uint16 slot_id)
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) {
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
SendAppearancePacket(AppearanceType::Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7889,7 +7896,7 @@ void Bot::BotGroupSay(Mob *speaker, const char *msg, ...) {
|
||||
if (speaker->HasGroup()) {
|
||||
Group *g = speaker->GetGroup();
|
||||
if (g)
|
||||
g->GroupMessage(speaker->CastToMob(), 0, 100, buf);
|
||||
g->GroupMessage(speaker->CastToMob(), Language::CommonTongue, Language::MaxValue, buf);
|
||||
} else
|
||||
speaker->Say("%s", buf);
|
||||
}
|
||||
@@ -7912,18 +7919,17 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
return false;
|
||||
|
||||
if (spell.recast_time > 0) {
|
||||
if (CheckDisciplineRecastTimers(this, spells[spell_id].timer_id)) {
|
||||
if (spells[spell_id].timer_id > 0 && spells[spell_id].timer_id < MAX_DISCIPLINE_TIMERS)
|
||||
SetDisciplineRecastTimer(spells[spell_id].timer_id, spell.recast_time);
|
||||
if (CheckDisciplineReuseTimer(spell_id)) {
|
||||
if (spells[spell_id].timer_id > 0) {
|
||||
SetDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
} else {
|
||||
uint32 remaining_time = (GetDisciplineRemainingTime(this, spells[spell_id].timer_id) / 1000);
|
||||
GetOwner()->Message(
|
||||
Chat::White,
|
||||
uint32 remaining_time = (GetDisciplineReuseRemainingTime(spell_id) / 1000);
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} can use this discipline in {}.",
|
||||
GetCleanName(),
|
||||
"I can use this discipline in {}.",
|
||||
Strings::SecondsToTime(remaining_time)
|
||||
).c_str()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -8134,28 +8140,6 @@ bool Bot::DyeArmor(int16 slot_id, uint32 rgb, bool all_flag, bool save_flag)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Bot::CreateSayLink(Client* c, const char* message, const char* name)
|
||||
{
|
||||
// TODO: review
|
||||
|
||||
int saylink_size = strlen(message);
|
||||
char* escaped_string = new char[saylink_size * 2];
|
||||
|
||||
database.DoEscapeString(escaped_string, message, saylink_size);
|
||||
|
||||
uint32 saylink_id = database.LoadSaylinkID(escaped_string);
|
||||
safe_delete_array(escaped_string);
|
||||
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemData);
|
||||
linker.SetProxyItemID(SAYLINK_ITEM_ID);
|
||||
linker.SetProxyAugment1ID(saylink_id);
|
||||
linker.SetProxyText(name);
|
||||
|
||||
auto saylink = linker.GenerateLink();
|
||||
return saylink;
|
||||
}
|
||||
|
||||
void Bot::Signal(int signal_id)
|
||||
{
|
||||
if (parse->BotHasQuestSub(EVENT_SIGNAL)) {
|
||||
@@ -8806,4 +8790,627 @@ void Bot::AddBotStartingItems(uint16 race_id, uint8 class_id)
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::SetSpellRecastTimer(uint16 spell_id, int32 recast_delay) {
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to set spell recast timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!recast_delay) {
|
||||
recast_delay = CalcSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimer(spell_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = spells[ spell_id ].timer_id;
|
||||
t.timer_value = (Timer::GetCurrentTime() + recast_delay);
|
||||
t.recast_time = recast_delay;
|
||||
t.is_spell = true;
|
||||
t.is_disc = false;
|
||||
t.spell_id = spells[ spell_id ].id;
|
||||
t.is_item = false;
|
||||
t.item_id = 0;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
} else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_spell &&
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[ i ].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (Timer::GetCurrentTime() + recast_delay);
|
||||
bot_timers[i].recast_time = recast_delay;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to get spell recast timer.");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_spell &&
|
||||
(
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::GetSpellRecastRemainingTime(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetSpellRecastTimer(spell_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetSpellRecastTimer(spell_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to check spell recast timer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetSpellRecastTimer(spell_id) < Timer::GetCurrentTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer)
|
||||
{
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to set discipline reuse timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reuse_timer) {
|
||||
reuse_timer = CalcSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
if (CheckDisciplineReuseTimer(spell_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = spells[ spell_id ].timer_id;
|
||||
t.timer_value = (Timer::GetCurrentTime() + reuse_timer);
|
||||
t.recast_time = reuse_timer;
|
||||
t.is_spell = false;
|
||||
t.is_disc = true;
|
||||
t.spell_id = spells[ spell_id ].id;
|
||||
t.is_item = false;
|
||||
t.item_id = 0;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
} else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (Timer::GetCurrentTime() + reuse_timer);
|
||||
bot_timers[i].recast_time = reuse_timer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
(
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::GetDisciplineReuseRemainingTime(uint16 spell_id) {
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetDisciplineReuseTimer(spell_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetDisciplineReuseTimer(spell_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (GetDisciplineReuseTimer(spell_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
|
||||
return true; //can cast spell
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer)
|
||||
{
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage("Failed to set item reuse timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->RecastDelay <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckItemReuseTimer(item_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = (item->RecastType == NegativeItemReuse ? item->ID : item->RecastType);
|
||||
t.timer_value = (
|
||||
reuse_timer != 0 ?
|
||||
(Timer::GetCurrentTime() + reuse_timer) :
|
||||
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
|
||||
);
|
||||
t.recast_time = (reuse_timer != 0 ? reuse_timer : (item->RecastDelay * 1000));
|
||||
t.is_spell = false;
|
||||
t.is_disc = false;
|
||||
t.spell_id = 0;
|
||||
t.is_item = true;
|
||||
t.item_id = item->ID;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
}
|
||||
else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_item &&
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (
|
||||
reuse_timer != 0 ?
|
||||
(Timer::GetCurrentTime() + reuse_timer) :
|
||||
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
|
||||
);
|
||||
bot_timers[i].recast_time = (
|
||||
reuse_timer != 0 ?
|
||||
reuse_timer :
|
||||
(item->RecastDelay * 1000)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
const EQ::ItemData* item;
|
||||
|
||||
if (item_id) {
|
||||
item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage("Failed to get item reuse timer.");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_item &&
|
||||
(
|
||||
!item_id ||
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (GetItemReuseTimer(item_id) < Timer::GetCurrentTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 Bot::GetItemReuseRemainingTime(uint32 item_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetItemReuseTimer(item_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetItemReuseTimer(item_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::CalcSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (spells[spell_id].recast_time == 0 && spells[spell_id].recovery_time == 0) {
|
||||
return result;
|
||||
} else {
|
||||
if (spells[spell_id].recovery_time > spells[spell_id].recast_time) {
|
||||
result = spells[spell_id].recovery_time;
|
||||
} else {
|
||||
result = spells[spell_id].recast_time;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Bot::ClearDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid spell ID.'",
|
||||
spell_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
bot_timers[i].timer_value >= Timer::GetCurrentTime()
|
||||
) {
|
||||
if (
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
void Bot::ClearItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
const EQ::ItemData* item;
|
||||
|
||||
if (item_id) {
|
||||
item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid item ID.",
|
||||
item_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (bot_timers[i].is_item && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
|
||||
if (
|
||||
!item_id ||
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
void Bot::ClearSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid spell ID.",
|
||||
spell_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (bot_timers[i].is_spell && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
|
||||
if (
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
|
||||
void Bot::ClearExpiredTimers()
|
||||
{
|
||||
if (!bot_timers.empty()) {
|
||||
int current = 0;
|
||||
int end = bot_timers.size();
|
||||
|
||||
while (current < end) {
|
||||
if (bot_timers[current].timer_value < Timer::GetCurrentTime()) {
|
||||
bot_timers.erase(bot_timers.begin() + current);
|
||||
} else {
|
||||
current++;
|
||||
}
|
||||
|
||||
end = bot_timers.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::TryItemClick(uint16 slot_id)
|
||||
{
|
||||
if (!GetOwner()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *inst = GetClickItem(slot_id);
|
||||
|
||||
if (!inst) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *item = inst->GetItem();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckItemReuseTimer(item->ID)) {
|
||||
uint32 remaining_time = (GetItemReuseRemainingTime(item->ID) / 1000);
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I can use this item in {}.",
|
||||
Strings::SecondsToTime(remaining_time)
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
DoItemClick(item, slot_id);
|
||||
}
|
||||
|
||||
EQ::ItemInstance *Bot::GetClickItem(uint16 slot_id)
|
||||
{
|
||||
EQ::ItemInstance* inst = nullptr;
|
||||
const EQ::ItemData* item = nullptr;
|
||||
|
||||
inst = GetBotItem(slot_id);
|
||||
|
||||
if (!inst || !inst->GetItem()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
item = inst->GetItem();
|
||||
|
||||
if (item->ID == MAG_EPIC_1_0 && !RuleB(Bots, CanClickMageEpicV1)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is currently disabled for bots to click.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->Click.Effect <= 0) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} does not have a clickable effect.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsValidSpell(item->Click.Effect)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} does not have a valid clickable effect.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->ReqLevel > GetLevel()) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I am below the level requirement of {} for {}.",
|
||||
item->ReqLevel,
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->Click.Level2 > GetLevel()) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I must be level {} to use {}.",
|
||||
item->Click.Level2,
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is out of charges.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
void Bot::DoItemClick(const EQ::ItemData *item, uint16 slot_id)
|
||||
{
|
||||
bool is_casting_bard_song = false;
|
||||
Mob* tar = (GetOwner()->GetTarget() ? GetOwner()->GetTarget() : this);
|
||||
|
||||
if (IsCasting()) {
|
||||
InterruptSpell();
|
||||
}
|
||||
|
||||
SetIsUsingItemClick(true);
|
||||
|
||||
BotGroupSay(
|
||||
this,
|
||||
fmt::format(
|
||||
"Attempting to cast [{}] on {}.",
|
||||
spells[item->Click.Effect].name,
|
||||
tar->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (!IsCastWhileInvisibleSpell(item->Click.Effect)) {
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
if (GetClass() == Class::Bard && IsCasting() && casting_spell_slot < EQ::spells::CastingSlot::MaxGems) {
|
||||
is_casting_bard_song = true;
|
||||
}
|
||||
|
||||
if (GetClass() == Class::Bard) {
|
||||
DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay);
|
||||
} else {
|
||||
if (!CastSpell(item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, item->CastTime, 0, 0, slot_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"Casting failed for {}. This could be due to zone restrictions, target restrictions or other limiting factors.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
|
||||
+30
-15
@@ -42,13 +42,12 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500; // as DSq value (50 uni
|
||||
|
||||
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
|
||||
|
||||
constexpr uint32 MAG_EPIC_1_0 = 28034;
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
||||
constexpr int MaxSpellTimer = 15;
|
||||
constexpr int MaxDisciplineTimer = 10;
|
||||
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||
constexpr int NegativeItemReuse = -1; // Unlinked timer for items
|
||||
|
||||
// nHSND negative Healer/Slower/Nuker/Doter
|
||||
// pH positive Healer
|
||||
@@ -222,6 +221,8 @@ public:
|
||||
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
||||
bool GetPullingFlag() const { return m_pulling_flag; }
|
||||
bool GetReturningFlag() const { return m_returning_flag; }
|
||||
bool GetIsUsingItemClick() { return is_using_item_click; }
|
||||
void SetIsUsingItemClick(bool flag = true) { is_using_item_click = flag; }
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
|
||||
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
|
||||
@@ -286,6 +287,10 @@ public:
|
||||
void SetEndurance(int32 newEnd) override;
|
||||
void DoEnduranceUpkeep();
|
||||
|
||||
void TryItemClick(uint16 slot_id);
|
||||
EQ::ItemInstance* GetClickItem(uint16 slot_id);
|
||||
void DoItemClick(const EQ::ItemData* inst, uint16 slot_id);
|
||||
|
||||
bool AI_AddBotSpells(uint32 bot_spell_id);
|
||||
void AddSpellToBotList(
|
||||
int16 iPriority,
|
||||
@@ -408,11 +413,6 @@ public:
|
||||
static Bot* GetFirstBotInGroup(Group* group);
|
||||
static void ProcessClientZoneChange(Client* botOwner);
|
||||
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
|
||||
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
|
||||
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
|
||||
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
|
||||
|
||||
//Raid methods
|
||||
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
|
||||
@@ -612,8 +612,23 @@ public:
|
||||
_botStance = EQ::constants::stancePassive;
|
||||
}
|
||||
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
|
||||
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||
uint32 GetSpellRecastTimer(uint16 spell_id = 0);
|
||||
bool CheckSpellRecastTimer(uint16 spell_id = 0);
|
||||
uint32 GetSpellRecastRemainingTime(uint16 spell_id = 0);
|
||||
void SetSpellRecastTimer(uint16 spell_id, int32 recast_delay = 0);
|
||||
uint32 CalcSpellRecastTimer(uint16 spell_id);
|
||||
uint32 GetDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
bool CheckDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
uint32 GetDisciplineReuseRemainingTime(uint16 spell_id = 0);
|
||||
void SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer = 0);
|
||||
uint32 GetItemReuseTimer(uint32 item_id = 0);
|
||||
bool CheckItemReuseTimer(uint32 item_id = 0);
|
||||
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer = 0);
|
||||
void ClearDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
void ClearItemReuseTimer(uint32 item_id = 0);
|
||||
void ClearSpellRecastTimer(uint16 spell_id = 0);
|
||||
uint32 GetItemReuseRemainingTime(uint32 item_id = 0);
|
||||
void ClearExpiredTimers();
|
||||
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
void SetBeardColor(uint8 value) { beardcolor = value; }
|
||||
@@ -644,8 +659,6 @@ public:
|
||||
void SetBotEnforceSpellSetting(bool enforcespellsettings, bool save = false);
|
||||
bool GetBotEnforceSpellSetting() const { return m_enforce_spell_settings; }
|
||||
|
||||
std::string CreateSayLink(Client* botOwner, const char* message, const char* name);
|
||||
|
||||
// Class Destructors
|
||||
~Bot() override;
|
||||
|
||||
@@ -713,7 +726,8 @@ public:
|
||||
|
||||
// New accessors for BotDatabase access
|
||||
bool DeleteBot();
|
||||
uint32* GetTimers() { return timers; }
|
||||
std::vector<BotTimer_Struct> GetBotTimers() { return bot_timers; }
|
||||
void SetBotTimers(std::vector<BotTimer_Struct> timers) { bot_timers = timers; }
|
||||
uint32 GetLastZoneID() const { return _lastZoneId; }
|
||||
int32 GetBaseAC() const { return _baseAC; }
|
||||
int32 GetBaseATK() const { return _baseATK; }
|
||||
@@ -828,6 +842,7 @@ protected:
|
||||
|
||||
std::vector<BotSpells_Struct> AIBot_spells;
|
||||
std::vector<BotSpells_Struct> AIBot_spells_enforced;
|
||||
std::vector<BotTimer_Struct> bot_timers;
|
||||
|
||||
private:
|
||||
// Class Members
|
||||
@@ -861,7 +876,6 @@ private:
|
||||
int32 cur_end;
|
||||
int32 max_end;
|
||||
int32 end_regen;
|
||||
uint32 timers[MaxTimer];
|
||||
|
||||
Timer m_evade_timer; // can be moved to pTimers at some point
|
||||
Timer m_alt_combat_hate_timer;
|
||||
@@ -875,6 +889,7 @@ private:
|
||||
bool m_pull_flag;
|
||||
bool m_pulling_flag;
|
||||
bool m_returning_flag;
|
||||
bool is_using_item_click;
|
||||
eStandingPetOrder m_previous_pet_order;
|
||||
uint32 m_bot_caster_range;
|
||||
BotCastingRoles m_CastingRoles;
|
||||
|
||||
+412
-88
@@ -404,38 +404,38 @@ public:
|
||||
|
||||
for (int i = EffectIDFirst; i <= EffectIDLast; ++i) {
|
||||
int effect_index = EFFECTIDTOINDEX(i);
|
||||
if (spells[spell_id].base_value[effect_index] <= 0)
|
||||
if (spells[spell_id].max_value[effect_index] <= 0)
|
||||
continue;
|
||||
|
||||
switch (spells[spell_id].effect_id[effect_index]) {
|
||||
case SE_ResistFire:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Fire)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Fire)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
case SE_ResistCold:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Cold)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Cold)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
case SE_ResistPoison:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Poison)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Poison)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
case SE_ResistDisease:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Disease)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Disease)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
case SE_ResistMagic:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Magic)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Magic)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
case SE_ResistCorruption:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Corruption)] += spells[spell_id].base_value[effect_index];
|
||||
BCEnum::RT_Corruption)] += spells[spell_id].max_value[effect_index];
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
entry_prototype->SafeCastToResistance()->resist_total += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_total += spells[spell_id].max_value[effect_index];
|
||||
valid_spell = true;
|
||||
}
|
||||
if (!valid_spell) {
|
||||
@@ -1375,6 +1375,7 @@ int bot_command_init(void)
|
||||
bot_command_add("casterrange", "Controls the range casters will try to stay away from a mob (if too far, they will skip spells that are out-of-range)", AccountStatus::Player, bot_command_caster_range) ||
|
||||
bot_command_add("charm", "Attempts to have a bot charm your target", AccountStatus::Player, bot_command_charm) ||
|
||||
bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_subcommand_circle) ||
|
||||
bot_command_add("clickitem", "Orders your targeted bot to click the item in the provided inventory slot.", AccountStatus::Player, bot_command_click_item) ||
|
||||
bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) ||
|
||||
bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) ||
|
||||
bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) ||
|
||||
@@ -1444,6 +1445,7 @@ int bot_command_init(void)
|
||||
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) ||
|
||||
bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) ||
|
||||
bot_command_add("taunt", "Toggles taunt use by a bot", AccountStatus::Player, bot_command_taunt) ||
|
||||
bot_command_add("timer", "Checks or clears timers of the chosen type.", AccountStatus::GMMgmt, bot_command_timer) ||
|
||||
bot_command_add("track", "Orders a capable bot to track enemies", AccountStatus::Player, bot_command_track) ||
|
||||
bot_command_add("viewcombos", "Views bot race class combinations", AccountStatus::Player, bot_command_view_combos) ||
|
||||
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", AccountStatus::Player, bot_command_water_breathing)
|
||||
@@ -2832,7 +2834,7 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "%i of %i bots have used aggressive disciplines", success_count, candidate_count);
|
||||
c->Message(Chat::White, "%i of %i bots have attempted to use aggressive disciplines", success_count, candidate_count);
|
||||
}
|
||||
|
||||
void bot_command_apply_poison(Client *c, const Seperator *sep)
|
||||
@@ -2868,7 +2870,7 @@ void bot_command_apply_poison(Client *c, const Seperator *sep)
|
||||
}
|
||||
if (my_rogue_bot->GetLevel() < 18) {
|
||||
|
||||
c->Message(Chat::White, "Your rogue bot must be level 18 before %s can apply poison!", (my_rogue_bot->GetGender() == 1 ? "she" : "he"));
|
||||
c->Message(Chat::White, "Your rogue bot must be level 18 before %s can apply poison!", (my_rogue_bot->GetGender() == Gender::Female ? "she" : "he"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3300,7 +3302,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
|
||||
auto local_entry = list_iter->SafeCastToStance();
|
||||
if (helper_spell_check_fail(local_entry))
|
||||
continue;
|
||||
if (local_entry->stance_type != BCEnum::StT_Aggressive)
|
||||
if (local_entry->stance_type != BCEnum::StT_Defensive)
|
||||
continue;
|
||||
|
||||
for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) {
|
||||
@@ -3332,7 +3334,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "%i of %i bots have used defensive disciplines", success_count, candidate_count);
|
||||
c->Message(Chat::White, "%i of %i bots have attempted to use defensive disciplines", success_count, candidate_count);
|
||||
}
|
||||
|
||||
void bot_command_depart(Client *c, const Seperator *sep)
|
||||
@@ -3906,16 +3908,77 @@ void bot_command_invisibility(Client *c, const Seperator *sep)
|
||||
void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: %s ([empty])", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s empty] will display only bots that can use the item in an empty slot.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s byclass classID] - Example: [%s byclass 7] will display only bots that match the class that can use the item. Example is a Monk, use [^create help] for a list of class IDs.", sep->arg[0], sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s casteronly] will display only caster bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s hybridonly] will display only hybrid bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s meleeonly] will display only melee bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s wiscasteronly] will display only Wisdom-based Caster bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s intcasteronly] will display only Intelligence-based Caster bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s plateonly] will display only Plate-wearing bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s chainonly] will display only Chain-wearing bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s leatheronly] will display only Leather-wearing bots that can use the item.", sep->arg[0]);
|
||||
c->Message(Chat::White, "usage: [%s clothonly] will display only Cloth-wearing bots that can use the item.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
bool empty_only = false;
|
||||
int8 class_mask = 0;
|
||||
bool caster_only = false;
|
||||
bool hybrid_only = false;
|
||||
bool melee_only = false;
|
||||
bool wis_caster_only = false;
|
||||
bool int_caster_only = false;
|
||||
bool plate_only = false;
|
||||
bool chain_only = false;
|
||||
bool leather_only = false;
|
||||
bool cloth_only = false;
|
||||
|
||||
std::string arg1 = sep->arg[1];
|
||||
std::string arg2 = sep->arg[2];
|
||||
if (arg1.compare("empty") == 0) {
|
||||
empty_only = true;
|
||||
}
|
||||
|
||||
else if (arg1.compare("byclass") == 0) {
|
||||
if (Strings::IsNumber(sep->arg[2])) {
|
||||
class_mask = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
if (!(class_mask >= Class::Warrior && class_mask <= Class::Berserker)) {
|
||||
c->Message(Chat::White, "Invalid class range, you must choose between 1 (Warrior) and 15 (Beastlord)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arg1.compare("casteronly") == 0) {
|
||||
caster_only = true;
|
||||
}
|
||||
else if (arg1.compare("hybridonly") == 0) {
|
||||
hybrid_only = true;
|
||||
}
|
||||
else if (arg1.compare("meleeonly") == 0) {
|
||||
melee_only = true;
|
||||
}
|
||||
else if (arg1.compare("wiscasteronly") == 0) {
|
||||
wis_caster_only = true;
|
||||
}
|
||||
else if (arg1.compare("intcasteronly") == 0) {
|
||||
int_caster_only = true;
|
||||
}
|
||||
else if (arg1.compare("plateonly") == 0) {
|
||||
plate_only = true;
|
||||
}
|
||||
else if (arg1.compare("chainonly") == 0) {
|
||||
chain_only = true;
|
||||
}
|
||||
else if (arg1.compare("leatheronly") == 0) {
|
||||
leather_only = true;
|
||||
}
|
||||
else if (arg1.compare("clothonly") == 0) {
|
||||
cloth_only = true;
|
||||
}
|
||||
else if (!arg1.empty()) {
|
||||
c->Message(Chat::White, "Please choose the correct subtype. For help use %s help.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
const auto item_instance = c->GetInv().GetItem(EQ::invslot::slotCursor);
|
||||
if (!item_instance) {
|
||||
c->Message(Chat::White, "No item found on cursor!");
|
||||
@@ -3940,32 +4003,51 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
}
|
||||
}
|
||||
|
||||
std::string text_link;
|
||||
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||
|
||||
std::list<Bot*> sbl;
|
||||
MyBots::PopulateSBL_BySpawnedBots(c, sbl);
|
||||
|
||||
if (class_mask) {
|
||||
ActionableBots::Filter_ByClasses(c, sbl, GetPlayerClassBit(class_mask));
|
||||
}
|
||||
|
||||
for (const auto& bot_iter : sbl) {
|
||||
if (!bot_iter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (caster_only && !IsCasterClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (hybrid_only && !IsSpellFighterClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (melee_only && !IsNonSpellFighterClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (wis_caster_only && !IsWISCasterClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (int_caster_only && !IsINTCasterClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (plate_only && !IsPlateClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (chain_only && !IsChainClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (leather_only && !IsLeatherClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (cloth_only && !IsClothClass(bot_iter->GetClass())) {
|
||||
continue;
|
||||
}
|
||||
if (((~item_data->Races) & GetPlayerRaceBit(bot_iter->GetRace())) || ((~item_data->Classes) & GetPlayerClassBit(bot_iter->GetClass()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
text_link = bot_iter->CreateSayLink(
|
||||
c,
|
||||
fmt::format(
|
||||
"^inventorygive byname {}",
|
||||
bot_iter->GetCleanName()
|
||||
).c_str(),
|
||||
bot_iter->GetCleanName()
|
||||
);
|
||||
|
||||
for (const auto& slot_iter : equipable_slot_list) {
|
||||
// needs more failure criteria - this should cover the bulk for now
|
||||
if (slot_iter == EQ::invslot::slotSecondary && item_data->Damage && !bot_iter->CanThisClassDualWield()) {
|
||||
@@ -3981,7 +4063,13 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
Chat::Say,
|
||||
fmt::format(
|
||||
"{} says, 'I can use that for my {} instead of my {}! Would you like to {} my {}?'",
|
||||
text_link,
|
||||
Saylink::Silent(
|
||||
fmt::format(
|
||||
"^inventorygive byname {}",
|
||||
bot_iter->GetCleanName()
|
||||
),
|
||||
bot_iter->GetCleanName()
|
||||
),
|
||||
EQ::invslot::GetInvPossessionsSlotName(slot_iter),
|
||||
linker.GenerateLink(),
|
||||
Saylink::Silent(
|
||||
@@ -3997,12 +4085,19 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
);
|
||||
|
||||
bot_iter->DoAnim(29);
|
||||
} else if (!equipped_item) {
|
||||
}
|
||||
else if (!equipped_item) {
|
||||
c->Message(
|
||||
Chat::Say,
|
||||
fmt::format(
|
||||
"{} says, 'I can use that for my {}! Would you like to {} it to me?'",
|
||||
text_link,
|
||||
Saylink::Silent(
|
||||
fmt::format(
|
||||
"^inventorygive byname {}",
|
||||
bot_iter->GetCleanName()
|
||||
),
|
||||
bot_iter->GetCleanName()
|
||||
),
|
||||
EQ::invslot::GetInvPossessionsSlotName(slot_iter),
|
||||
Saylink::Silent(
|
||||
fmt::format(
|
||||
@@ -5194,6 +5289,194 @@ void bot_command_taunt(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_timer(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_command_timer", sep->arg[0], "timer"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: %s [clear | has | set] [disc | item | spell] [timer ID | item ID | spell ID | all] [optional ms for set] [actionable].", sep->arg[0]);
|
||||
c->Message(Chat::White, "When setting, you can leave the value blank to use the default for the item or specify a value in ms to set the timer to.");
|
||||
c->Message(Chat::White, "Returns or sets the provided timer(s) for the selected bot(s) or clears the selected timer(s) for the selected bot(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
const int ab_mask = ActionableBots::ABM_Type1;
|
||||
|
||||
std::string arg1 = sep->arg[1];
|
||||
std::string arg2 = sep->arg[2];
|
||||
std::string arg3 = sep->arg[3];
|
||||
int ab_arg = 4;
|
||||
bool clear = false;
|
||||
bool has = false;
|
||||
bool set = false;
|
||||
bool disc = false;
|
||||
bool item = false;
|
||||
bool spell = false;
|
||||
uint32 timer_id = 0;
|
||||
uint32 timer_value = 0;
|
||||
bool all = false;
|
||||
|
||||
if (!arg1.compare("clear")) {
|
||||
clear = true;
|
||||
}
|
||||
else if (!arg1.compare("has")) {
|
||||
has = true;
|
||||
}
|
||||
else if (!arg1.compare("set")) {
|
||||
set = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect argument, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg2.compare("disc")) {
|
||||
disc = true;
|
||||
}
|
||||
else if (!arg2.compare("item")) {
|
||||
item = true;
|
||||
}
|
||||
else if (!arg2.compare("spell")) {
|
||||
spell = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect timer type, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sep->IsNumber(3)) {
|
||||
timer_id = atoi(sep->arg[3]);
|
||||
if (timer_id < 0) {
|
||||
c->Message(Chat::White, "You cannot use negative numbers.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!arg3.compare("all")) {
|
||||
if (has || set) {
|
||||
c->Message(Chat::White, "You can only use 'all' for clearing timers.");
|
||||
return;
|
||||
}
|
||||
|
||||
all = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect ID option, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
if (sep->IsNumber(4)) {
|
||||
ab_arg = 5;
|
||||
timer_value = atoi(sep->arg[4]);
|
||||
if (timer_value <= 0) {
|
||||
c->Message(Chat::White, "You cannot use 0 or negative numbers.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string class_race_arg = sep->arg[ab_arg];
|
||||
bool class_race_check = false;
|
||||
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
|
||||
class_race_check = true;
|
||||
}
|
||||
|
||||
std::list<Bot*> sbl;
|
||||
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
|
||||
return;
|
||||
}
|
||||
sbl.remove(nullptr);
|
||||
|
||||
for (auto my_bot : sbl) {
|
||||
bool found = false;
|
||||
|
||||
if (clear) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'Clearing {} timer{}'",
|
||||
my_bot->GetCleanName(),
|
||||
disc ? "Discipline" : item ? "Item" : "Spell",
|
||||
(all ? "s." : ".")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (disc) {
|
||||
my_bot->ClearDisciplineReuseTimer(timer_id);
|
||||
}
|
||||
else if (item) {
|
||||
my_bot->ClearItemReuseTimer(timer_id);
|
||||
}
|
||||
else if (spell) {
|
||||
my_bot->ClearSpellRecastTimer(timer_id);
|
||||
}
|
||||
}
|
||||
else if (has) {
|
||||
uint32 remaining_time;
|
||||
std::string time_string = "";
|
||||
|
||||
if (disc) {
|
||||
if (!my_bot->CheckDisciplineReuseTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetDisciplineReuseRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else if (item) {
|
||||
if (!my_bot->CheckItemReuseTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetItemReuseRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else if (spell) {
|
||||
if (!my_bot->CheckSpellRecastTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetSpellRecastRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'I {}{}{}'",
|
||||
my_bot->GetCleanName(),
|
||||
(!found ? " do not have that timer currently" : " have "),
|
||||
(!found ? "" : time_string),
|
||||
(!found ? "." : " remaining.")
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
else if (set) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'Setting {} timer{} for {} to {}.'",
|
||||
my_bot->GetCleanName(),
|
||||
disc ? "Discipline" : item ? "Item" : "Spell",
|
||||
(all ? "s" : ""),
|
||||
timer_id,
|
||||
timer_value ? std::to_string(timer_value) : "the default value"
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (disc) {
|
||||
my_bot->ClearDisciplineReuseTimer(timer_id);
|
||||
my_bot->SetDisciplineReuseTimer(timer_id, timer_value);
|
||||
}
|
||||
else if (item) {
|
||||
my_bot->ClearItemReuseTimer(timer_id);
|
||||
my_bot->SetItemReuseTimer(timer_id, timer_value);
|
||||
}
|
||||
else if (spell) {
|
||||
my_bot->ClearSpellRecastTimer(timer_id);
|
||||
my_bot->SetSpellRecastTimer(timer_id, timer_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_track(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track"))
|
||||
@@ -5351,7 +5634,7 @@ void bot_subcommand_bot_beard_color(Client *c, const Seperator *sep)
|
||||
uint8 uvalue = Strings::ToInt(sep->arg[1]);
|
||||
|
||||
auto fail_type = BCEnum::AFT_None;
|
||||
if (my_bot->GetGender() != MALE && my_bot->GetRace() != DWARF)
|
||||
if (my_bot->GetGender() != Gender::Male && my_bot->GetRace() != DWARF)
|
||||
fail_type = BCEnum::AFT_GenderRace;
|
||||
else if (!PlayerAppearance::IsValidBeardColor(my_bot->GetRace(), my_bot->GetGender(), uvalue))
|
||||
fail_type = BCEnum::AFT_Value;
|
||||
@@ -5388,7 +5671,7 @@ void bot_subcommand_bot_beard_style(Client *c, const Seperator *sep)
|
||||
uint8 uvalue = Strings::ToInt(sep->arg[1]);
|
||||
|
||||
auto fail_type = BCEnum::AFT_None;
|
||||
if (my_bot->GetGender() != MALE && my_bot->GetRace() != DWARF)
|
||||
if (my_bot->GetGender() != Gender::Male && my_bot->GetRace() != DWARF)
|
||||
fail_type = BCEnum::AFT_GenderRace;
|
||||
else if (!PlayerAppearance::IsValidBeard(my_bot->GetRace(), my_bot->GetGender(), uvalue))
|
||||
fail_type = BCEnum::AFT_Value;
|
||||
@@ -5631,11 +5914,11 @@ void bot_command_view_combos(Client *c, const Seperator *sep)
|
||||
};
|
||||
|
||||
const uint16 race_values[17] = {
|
||||
RACE_DOUG_0,
|
||||
RACE_HUMAN_1, RACE_BARBARIAN_2, RACE_ERUDITE_3, RACE_WOOD_ELF_4,
|
||||
RACE_HIGH_ELF_5, RACE_DARK_ELF_6, RACE_HALF_ELF_7, RACE_DWARF_8,
|
||||
RACE_TROLL_9, RACE_OGRE_10, RACE_HALFLING_11, RACE_GNOME_12,
|
||||
RACE_IKSAR_128, RACE_VAH_SHIR_130, RACE_FROGLOK_330, RACE_DRAKKIN_522
|
||||
Race::Doug,
|
||||
Race::Human, Race::Barbarian, Race::Erudite, Race::WoodElf,
|
||||
Race::HighElf, Race::DarkElf, Race::HalfElf, Race::Dwarf,
|
||||
Race::Troll, Race::Ogre, Race::Halfling, Race::Gnome,
|
||||
Race::Iksar, Race::VahShir, Race::Froglok2, Race::Drakkin
|
||||
};
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_command_view_combos", sep->arg[0], "viewcombos")) {
|
||||
@@ -5746,11 +6029,11 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
|
||||
};
|
||||
|
||||
const uint16 race_values[17] = {
|
||||
RACE_DOUG_0,
|
||||
RACE_HUMAN_1, RACE_BARBARIAN_2, RACE_ERUDITE_3, RACE_WOOD_ELF_4,
|
||||
RACE_HIGH_ELF_5, RACE_DARK_ELF_6, RACE_HALF_ELF_7, RACE_DWARF_8,
|
||||
RACE_TROLL_9, RACE_OGRE_10, RACE_HALFLING_11, RACE_GNOME_12,
|
||||
RACE_IKSAR_128, RACE_VAH_SHIR_130, RACE_FROGLOK_330, RACE_DRAKKIN_522
|
||||
Race::Doug,
|
||||
Race::Human, Race::Barbarian, Race::Erudite, Race::WoodElf,
|
||||
Race::HighElf, Race::DarkElf, Race::HalfElf, Race::Dwarf,
|
||||
Race::Troll, Race::Ogre, Race::Halfling, Race::Gnome,
|
||||
Race::Iksar, Race::VahShir, Race::Froglok2, Race::Drakkin
|
||||
};
|
||||
|
||||
const std::string gender_substrs[2] = {
|
||||
@@ -5889,18 +6172,18 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
auto bot_gender = MALE;
|
||||
auto bot_gender = Gender::Male;
|
||||
|
||||
if (sep->IsNumber(4)) {
|
||||
bot_gender = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[4]));
|
||||
if (bot_gender == NEUTER) {
|
||||
bot_gender = MALE;
|
||||
if (bot_gender == Gender::Neuter) {
|
||||
bot_gender = Gender::Male;
|
||||
}
|
||||
} else {
|
||||
if (!strcasecmp(sep->arg[4], "m") || !strcasecmp(sep->arg[4], "male")) {
|
||||
bot_gender = MALE;
|
||||
bot_gender = Gender::Male;
|
||||
} else if (!strcasecmp(sep->arg[4], "f") || !strcasecmp(sep->arg[4], "female")) {
|
||||
bot_gender = FEMALE;
|
||||
bot_gender = Gender::Female;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7312,7 +7595,7 @@ void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep)
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* saptr = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
saptr->spawn_id = bot_iter->GetID();
|
||||
saptr->type = AT_ShowHelm;
|
||||
saptr->type = AppearanceType::ShowHelm;
|
||||
saptr->parameter = bot_iter->GetShowHelm();
|
||||
|
||||
entity_list.QueueClients(bot_iter, outapp);
|
||||
@@ -7385,7 +7668,7 @@ void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep)
|
||||
[10-16-2015 :: 22:15:40] [Packet :: Server -> Client (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10]
|
||||
0: A2 02 2B 00 00 00 00 00 - showhelm = false
|
||||
|
||||
*** Bot did not update using the OP_SpawnAppearance packet with AT_ShowHelm appearance type ***
|
||||
*** Bot did not update using the OP_SpawnAppearance packet with AppearanceType::ShowHelm appearance type ***
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -7412,7 +7695,7 @@ void bot_subcommand_bot_update(Client *c, const Seperator *sep)
|
||||
|
||||
bot_iter->SetPetChooser(false);
|
||||
bot_iter->CalcBotStats(c->GetBotOption(Client::booStatsUpdate));
|
||||
bot_iter->SendAppearancePacket(AT_WhoLevel, bot_iter->GetLevel(), true, true);
|
||||
bot_iter->SendAppearancePacket(AppearanceType::WhoLevel, bot_iter->GetLevel(), true, true);
|
||||
++bot_count;
|
||||
}
|
||||
|
||||
@@ -9260,10 +9543,6 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
if (!Bot::IsValidRaceClassCombo(bot_race, bot_class)) {
|
||||
const std::string bot_race_name = GetRaceIDName(bot_race);
|
||||
const std::string bot_class_name = GetClassIDName(bot_class);
|
||||
const auto view_saylink = Saylink::Silent(
|
||||
fmt::format("^viewcombos {}", bot_race),
|
||||
"view"
|
||||
);
|
||||
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
@@ -9271,7 +9550,10 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
"{} {} is an invalid race-class combination, would you like to {} proper combinations for {}?",
|
||||
bot_race_name,
|
||||
bot_class_name,
|
||||
view_saylink,
|
||||
Saylink::Silent(
|
||||
fmt::format("^viewcombos {}", bot_race),
|
||||
"view"
|
||||
),
|
||||
bot_race_name
|
||||
).c_str()
|
||||
);
|
||||
@@ -9279,15 +9561,15 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
if (!EQ::ValueWithin(bot_gender, MALE, FEMALE)) {
|
||||
if (!EQ::ValueWithin(bot_gender, Gender::Male, Gender::Female)) {
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Gender: {} ({}) or {} ({})",
|
||||
GetGenderName(MALE),
|
||||
MALE,
|
||||
GetGenderName(FEMALE),
|
||||
FEMALE
|
||||
GetGenderName(Gender::Male),
|
||||
Gender::Male,
|
||||
GetGenderName(Gender::Female),
|
||||
Gender::Female
|
||||
).c_str()
|
||||
);
|
||||
return bot_id;
|
||||
@@ -9589,9 +9871,6 @@ void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_b
|
||||
return;
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
std::string text_link;
|
||||
|
||||
auto destination_count = 0;
|
||||
auto destination_number = 1;
|
||||
for (auto list_iter : *local_list) {
|
||||
@@ -9609,24 +9888,19 @@ void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_b
|
||||
continue;
|
||||
}
|
||||
|
||||
msg = fmt::format(
|
||||
"^circle {}{}",
|
||||
spells[local_entry->spell_id].teleport_zone,
|
||||
single_flag ? " single" : ""
|
||||
);
|
||||
|
||||
text_link = druid_bot->CreateSayLink(
|
||||
bot_owner,
|
||||
msg.c_str(),
|
||||
"Goto"
|
||||
);
|
||||
|
||||
druid_bot->OwnerMessage(
|
||||
fmt::format(
|
||||
"Destination {} | {} | {}",
|
||||
destination_number,
|
||||
local_entry->long_name,
|
||||
text_link
|
||||
Saylink::Silent(
|
||||
fmt::format(
|
||||
"^circle {}{}",
|
||||
spells[local_entry->spell_id].teleport_zone,
|
||||
single_flag ? " single" : ""
|
||||
),
|
||||
"Goto"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -9644,24 +9918,19 @@ void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_b
|
||||
continue;
|
||||
}
|
||||
|
||||
msg = fmt::format(
|
||||
"^portal {}{}",
|
||||
spells[local_entry->spell_id].teleport_zone,
|
||||
single_flag ? " single" : ""
|
||||
);
|
||||
|
||||
text_link = wizard_bot->CreateSayLink(
|
||||
bot_owner,
|
||||
msg.c_str(),
|
||||
"Goto"
|
||||
);
|
||||
|
||||
wizard_bot->OwnerMessage(
|
||||
fmt::format(
|
||||
"Destination {} | {} | {}",
|
||||
destination_number,
|
||||
local_entry->long_name,
|
||||
text_link
|
||||
Saylink::Silent(
|
||||
fmt::format(
|
||||
"^portal {}{}",
|
||||
spells[local_entry->spell_id].teleport_zone,
|
||||
single_flag ? " single" : ""
|
||||
),
|
||||
"Goto"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -10438,6 +10707,61 @@ void bot_command_caster_range(Client* c, const Seperator* sep)
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_click_item(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (!RuleB(Bots, BotsCanClickItems)) {
|
||||
c->Message(Chat::White, "The ability for bots to click equipped items is currently disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: <slot id> %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
|
||||
c->Message(Chat::White, "This will cause the selected bots to click the item in the given slot ID.");
|
||||
c->Message(Chat::White, "Use ^invlist to see their items along with slot IDs.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sep->IsNumber(1)) {
|
||||
c->Message(Chat::Yellow, "You must specify a slot ID. Use %s help for more information.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const int ab_mask = ActionableBots::ABM_Type1;
|
||||
|
||||
int ab_arg = 1;
|
||||
uint32 slot_id = 0;
|
||||
|
||||
if (sep->IsNumber(1)) {
|
||||
ab_arg = 2;
|
||||
slot_id = atoi(sep->arg[1]);
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
|
||||
c->Message(Chat::Yellow, "You must specify a valid inventory slot from 0 to 22. Use %s help for more information", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string class_race_arg = sep->arg[ab_arg];
|
||||
bool class_race_check = false;
|
||||
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
|
||||
class_race_check = true;
|
||||
}
|
||||
|
||||
std::list<Bot*> sbl;
|
||||
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
|
||||
return;
|
||||
}
|
||||
sbl.remove(nullptr);
|
||||
|
||||
for (auto my_bot : sbl) {
|
||||
if (RuleI(Bots, BotsClickItemsMinLvl) > my_bot->GetLevel()) {
|
||||
c->Message(Chat::White, "%s must be level %i to use clickable items.", my_bot->GetCleanName(), RuleI(Bots, BotsClickItemsMinLvl));
|
||||
continue;
|
||||
}
|
||||
|
||||
my_bot->TryItemClick(slot_id);
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_pickpocket(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user