mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-30 03:25:44 +00:00
Compare commits
112 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 |
+208
@@ -1,3 +1,211 @@
|
||||
## [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
|
||||
|
||||
@@ -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
|
||||
|
||||
+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,8 @@ 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,
|
||||
@@ -5143,7 +5148,20 @@ CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_
|
||||
.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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -5134,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) {
|
||||
|
||||
@@ -801,7 +801,7 @@ 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)
|
||||
{
|
||||
const int16 last_bag_slot = RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
|
||||
const int16 last_bag_slot = (RuleI(World, ExpansionSettings) == -1 || RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT) ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
|
||||
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) { // Check basic inventory
|
||||
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+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
|
||||
|
||||
|
||||
+36
-36
@@ -1598,7 +1598,7 @@ float GetRaceGenderDefaultHeight(int race, int gender)
|
||||
return 6.0f;
|
||||
}
|
||||
|
||||
if (gender == FEMALE) {
|
||||
if (gender == Gender::Female) {
|
||||
return female_height[race];
|
||||
}
|
||||
|
||||
@@ -1606,38 +1606,38 @@ float GetRaceGenderDefaultHeight(int race, int gender)
|
||||
}
|
||||
|
||||
// PlayerAppearance prep
|
||||
#define HUMAN_MALE ((HUMAN << 8) | MALE)
|
||||
#define HUMAN_FEMALE ((HUMAN << 8) | FEMALE)
|
||||
#define BARBARIAN_MALE ((BARBARIAN << 8) | MALE)
|
||||
#define BARBARIAN_FEMALE ((BARBARIAN << 8) | FEMALE)
|
||||
#define ERUDITE_MALE ((ERUDITE << 8) | MALE)
|
||||
#define ERUDITE_FEMALE ((ERUDITE << 8) | FEMALE)
|
||||
#define WOOD_ELF_MALE ((WOOD_ELF << 8) | MALE)
|
||||
#define WOOD_ELF_FEMALE ((WOOD_ELF << 8) | FEMALE)
|
||||
#define HIGH_ELF_MALE ((HIGH_ELF << 8) | MALE)
|
||||
#define HIGH_ELF_FEMALE ((HIGH_ELF << 8) | FEMALE)
|
||||
#define DARK_ELF_MALE ((DARK_ELF << 8) | MALE)
|
||||
#define DARK_ELF_FEMALE ((DARK_ELF << 8) | FEMALE)
|
||||
#define HALF_ELF_MALE ((HALF_ELF << 8) | MALE)
|
||||
#define HALF_ELF_FEMALE ((HALF_ELF << 8) | FEMALE)
|
||||
#define DWARF_MALE ((DWARF << 8) | MALE)
|
||||
#define DWARF_FEMALE ((DWARF << 8) | FEMALE)
|
||||
#define TROLL_MALE ((TROLL << 8) | MALE)
|
||||
#define TROLL_FEMALE ((TROLL << 8) | FEMALE)
|
||||
#define OGRE_MALE ((OGRE << 8) | MALE)
|
||||
#define OGRE_FEMALE ((OGRE << 8) | FEMALE)
|
||||
#define HALFLING_MALE ((HALFLING << 8) | MALE)
|
||||
#define HALFLING_FEMALE ((HALFLING << 8) | FEMALE)
|
||||
#define GNOME_MALE ((GNOME << 8) | MALE)
|
||||
#define GNOME_FEMALE ((GNOME << 8) | FEMALE)
|
||||
#define IKSAR_MALE ((IKSAR << 8) | MALE)
|
||||
#define IKSAR_FEMALE ((IKSAR << 8) | FEMALE)
|
||||
#define VAHSHIR_MALE ((VAHSHIR << 8) | MALE)
|
||||
#define VAHSHIR_FEMALE ((VAHSHIR << 8) | FEMALE)
|
||||
#define FROGLOK_MALE ((FROGLOK << 8) | MALE)
|
||||
#define FROGLOK_FEMALE ((FROGLOK << 8) | FEMALE)
|
||||
#define DRAKKIN_MALE ((DRAKKIN << 8) | MALE)
|
||||
#define DRAKKIN_FEMALE ((DRAKKIN << 8) | FEMALE)
|
||||
#define HUMAN_MALE ((HUMAN << 8) | Gender::Male)
|
||||
#define HUMAN_FEMALE ((HUMAN << 8) | Gender::Female)
|
||||
#define BARBARIAN_MALE ((BARBARIAN << 8) | Gender::Male)
|
||||
#define BARBARIAN_FEMALE ((BARBARIAN << 8) | Gender::Female)
|
||||
#define ERUDITE_MALE ((ERUDITE << 8) | Gender::Male)
|
||||
#define ERUDITE_FEMALE ((ERUDITE << 8) | Gender::Female)
|
||||
#define WOOD_ELF_MALE ((WOOD_ELF << 8) | Gender::Male)
|
||||
#define WOOD_ELF_FEMALE ((WOOD_ELF << 8) | Gender::Female)
|
||||
#define HIGH_ELF_MALE ((HIGH_ELF << 8) | Gender::Male)
|
||||
#define HIGH_ELF_FEMALE ((HIGH_ELF << 8) | Gender::Female)
|
||||
#define DARK_ELF_MALE ((DARK_ELF << 8) | Gender::Male)
|
||||
#define DARK_ELF_FEMALE ((DARK_ELF << 8) | Gender::Female)
|
||||
#define HALF_ELF_MALE ((HALF_ELF << 8) | Gender::Male)
|
||||
#define HALF_ELF_FEMALE ((HALF_ELF << 8) | Gender::Female)
|
||||
#define DWARF_MALE ((DWARF << 8) | Gender::Male)
|
||||
#define DWARF_FEMALE ((DWARF << 8) | Gender::Female)
|
||||
#define TROLL_MALE ((TROLL << 8) | Gender::Male)
|
||||
#define TROLL_FEMALE ((TROLL << 8) | Gender::Female)
|
||||
#define OGRE_MALE ((OGRE << 8) | Gender::Male)
|
||||
#define OGRE_FEMALE ((OGRE << 8) | Gender::Female)
|
||||
#define HALFLING_MALE ((HALFLING << 8) | Gender::Male)
|
||||
#define HALFLING_FEMALE ((HALFLING << 8) | Gender::Female)
|
||||
#define GNOME_MALE ((GNOME << 8) | Gender::Male)
|
||||
#define GNOME_FEMALE ((GNOME << 8) | Gender::Female)
|
||||
#define IKSAR_MALE ((IKSAR << 8) | Gender::Male)
|
||||
#define IKSAR_FEMALE ((IKSAR << 8) | Gender::Female)
|
||||
#define VAHSHIR_MALE ((VAHSHIR << 8) | Gender::Male)
|
||||
#define VAHSHIR_FEMALE ((VAHSHIR << 8) | Gender::Female)
|
||||
#define FROGLOK_MALE ((FROGLOK << 8) | Gender::Male)
|
||||
#define FROGLOK_FEMALE ((FROGLOK << 8) | Gender::Female)
|
||||
#define DRAKKIN_MALE ((DRAKKIN << 8) | Gender::Male)
|
||||
#define DRAKKIN_FEMALE ((DRAKKIN << 8) | Gender::Female)
|
||||
|
||||
#define BINDRG(r, g) (((int)r << 8) | g)
|
||||
|
||||
@@ -2238,11 +2238,11 @@ bool PlayerAppearance::IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_v
|
||||
|
||||
const char* GetGenderName(uint32 gender_id) {
|
||||
const char* gender_name = "Unknown";
|
||||
if (gender_id == MALE) {
|
||||
if (gender_id == Gender::Male) {
|
||||
gender_name = "Male";
|
||||
} else if (gender_id == FEMALE) {
|
||||
} else if (gender_id == Gender::Female) {
|
||||
gender_name = "Female";
|
||||
} else if (gender_id == NEUTER) {
|
||||
} else if (gender_id == Gender::Neuter) {
|
||||
gender_name = "Neuter";
|
||||
}
|
||||
return gender_name;
|
||||
|
||||
+5
-3
@@ -21,9 +21,11 @@
|
||||
#include "../common/types.h"
|
||||
#include <string>
|
||||
|
||||
#define MALE 0
|
||||
#define FEMALE 1
|
||||
#define NEUTER 2
|
||||
namespace Gender {
|
||||
constexpr uint8 Male = 0;
|
||||
constexpr uint8 Female = 1;
|
||||
constexpr uint8 Neuter = 2;
|
||||
}
|
||||
|
||||
//theres a big list straight from the client below.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -216,6 +216,9 @@ RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the r
|
||||
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)
|
||||
@@ -251,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)
|
||||
@@ -430,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")
|
||||
@@ -462,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)
|
||||
@@ -499,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")
|
||||
@@ -508,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)")
|
||||
@@ -538,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)
|
||||
@@ -563,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")
|
||||
@@ -593,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)
|
||||
|
||||
+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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.38.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,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9248
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9249
|
||||
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.38.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();
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -191,7 +191,6 @@ SET(zone_headers
|
||||
embperl.h
|
||||
encounter.h
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
expedition.h
|
||||
expedition_database.h
|
||||
|
||||
+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 {
|
||||
|
||||
+2
-1
@@ -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() &&
|
||||
|
||||
+194
-119
@@ -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)) {
|
||||
@@ -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,68 +2708,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
Corpse* corpse = nullptr;
|
||||
|
||||
// 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, killer_mob);
|
||||
}
|
||||
}
|
||||
|
||||
if (oos->IsNPC()) {
|
||||
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
|
||||
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
|
||||
}
|
||||
|
||||
auto emote_id = oos->GetEmoteID();
|
||||
if (emote_id) {
|
||||
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
|
||||
}
|
||||
if (killer_mob) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (killer_mob && killer_mob->IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
|
||||
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
|
||||
}
|
||||
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse };
|
||||
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse, this };
|
||||
|
||||
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
|
||||
}
|
||||
const uint16 entity_id = GetID();
|
||||
|
||||
if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) &&
|
||||
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
|
||||
@@ -2877,6 +2819,39 @@ 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, killer_mob);
|
||||
}
|
||||
}
|
||||
|
||||
if (oos->IsNPC()) {
|
||||
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
|
||||
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
|
||||
}
|
||||
|
||||
auto emote_id = oos->GetEmoteID();
|
||||
if (emote_id) {
|
||||
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
|
||||
}
|
||||
if (killer_mob) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (killer_mob && killer_mob->IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
|
||||
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
|
||||
}
|
||||
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
|
||||
WipeHateList();
|
||||
p_depop = true;
|
||||
|
||||
@@ -2885,6 +2860,39 @@ 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),
|
||||
entity_id
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse };
|
||||
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
|
||||
}
|
||||
|
||||
// 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),
|
||||
entity_id
|
||||
);
|
||||
|
||||
std::vector<std::any> args = { corpse, this };
|
||||
|
||||
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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
|
||||
|
||||
+20
-40
@@ -281,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(
|
||||
@@ -325,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;
|
||||
@@ -372,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;
|
||||
}
|
||||
@@ -2783,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);
|
||||
@@ -3674,7 +3676,7 @@ void Bot::LevelBotWithClient(Client* c, uint8 new_level, bool send_appearance) {
|
||||
}
|
||||
|
||||
e->SendHPUpdate();
|
||||
e->SendAppearancePacket(AT_WhoLevel, new_level, true, true); // who level change
|
||||
e->SendAppearancePacket(AppearanceType::WhoLevel, new_level, true, true); // who level change
|
||||
e->AI_AddBotSpells(e->GetBotSpellID());
|
||||
}
|
||||
}
|
||||
@@ -3706,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3726,7 +3728,7 @@ void Bot::BotRemoveEquipItem(uint16 slot_id)
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) {
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
SendAppearancePacket(AppearanceType::Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7894,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);
|
||||
}
|
||||
@@ -8138,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)) {
|
||||
|
||||
@@ -659,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;
|
||||
|
||||
|
||||
+58
-71
@@ -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) {
|
||||
@@ -2870,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;
|
||||
}
|
||||
|
||||
@@ -4003,8 +4003,6 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
}
|
||||
}
|
||||
|
||||
std::string text_link;
|
||||
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||
|
||||
@@ -4050,15 +4048,6 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
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()) {
|
||||
@@ -4074,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(
|
||||
@@ -4096,7 +4091,13 @@ void bot_command_item_use(Client* c, const Seperator* sep)
|
||||
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(
|
||||
@@ -5633,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;
|
||||
@@ -5670,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;
|
||||
@@ -6171,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7594,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);
|
||||
@@ -7667,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 ***
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -7694,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;
|
||||
}
|
||||
|
||||
@@ -9542,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,
|
||||
@@ -9553,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()
|
||||
);
|
||||
@@ -9561,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;
|
||||
@@ -9871,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) {
|
||||
@@ -9891,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"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -9926,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"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
if (casted_spell && GetClass() != Class::Bard) {
|
||||
if (raid) {
|
||||
const auto msg = fmt::format("Attempting to slow {}.", tar->GetCleanName());
|
||||
raid->RaidSay(msg.c_str(), GetCleanName(), 0, 100);
|
||||
raid->RaidSay(msg.c_str(), GetCleanName(), Language::CommonTongue, Language::MaxValue);
|
||||
} else {
|
||||
BotGroupSay(
|
||||
this,
|
||||
@@ -1159,7 +1159,7 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
} else if (IsRaidGrouped()) {
|
||||
uint32 r_group = raid->GetGroup(GetName());
|
||||
const auto msg = fmt::format("Casting {}.", spells[botSpell.SpellId].name);
|
||||
raid->RaidGroupSay(msg.c_str(), GetCleanName(), 0, 100);
|
||||
raid->RaidGroupSay(msg.c_str(), GetCleanName(), Language::CommonTongue, Language::MaxValue);
|
||||
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(r_group);
|
||||
for (const auto& rgm : raid_group_members) {
|
||||
if (rgm.member && !rgm.member->qglobal) {
|
||||
|
||||
@@ -349,10 +349,10 @@ void CheatManager::ProcessMovementHistory(const EQApplicationPacket *app)
|
||||
|
||||
void CheatManager::ProcessSpawnApperance(uint16 spawn_id, uint16 type, uint32 parameter)
|
||||
{
|
||||
if (type == AT_Anim && parameter == ANIM_SIT) {
|
||||
if (type == AppearanceType::Animation && parameter == Animation::Sitting) {
|
||||
m_time_since_last_memorization = Timer::GetCurrentTime();
|
||||
}
|
||||
else if (spawn_id == 0 && type == AT_AntiCheat) {
|
||||
else if (spawn_id == 0 && type == AppearanceType::AntiCheat) {
|
||||
m_time_since_last_action = parameter;
|
||||
}
|
||||
}
|
||||
|
||||
+245
-174
@@ -58,6 +58,7 @@ extern volatile bool RunLoops;
|
||||
#include "mob_movement_manager.h"
|
||||
#include "cheat_manager.h"
|
||||
|
||||
#include "../common/repositories/character_alternate_abilities_repository.h"
|
||||
#include "../common/repositories/account_flags_repository.h"
|
||||
#include "../common/repositories/bug_reports_repository.h"
|
||||
#include "../common/repositories/char_recipe_list_repository.h"
|
||||
@@ -86,9 +87,9 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
"", // in_lastname
|
||||
0, // in_cur_hp
|
||||
0, // in_max_hp
|
||||
0, // in_gender
|
||||
0, // in_race
|
||||
0, // in_class
|
||||
Gender::Male, // in_gender
|
||||
Race::Doug, // in_race
|
||||
Class::None, // in_class
|
||||
BT_Humanoid, // in_bodytype
|
||||
0, // in_deity
|
||||
0, // in_level
|
||||
@@ -483,7 +484,7 @@ void Client::SendZoneInPackets()
|
||||
// Spawn Appearance Packet
|
||||
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->type = AppearanceType::SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
@@ -498,7 +499,7 @@ void Client::SendZoneInPackets()
|
||||
safe_delete(outapp);
|
||||
SetSpawned();
|
||||
if (GetPVP(false)) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(false), true, false);
|
||||
SendAppearancePacket(AppearanceType::PVP, GetPVP(false), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
@@ -586,45 +587,52 @@ void Client::ReportConnectingState() {
|
||||
};
|
||||
}
|
||||
|
||||
bool Client::SaveAA() {
|
||||
std::string iquery;
|
||||
int spentpoints = 0;
|
||||
int i = 0;
|
||||
for(auto &rank : aa_ranks) {
|
||||
AA::Ability *ability = zone->GetAlternateAdvancementAbility(rank.first);
|
||||
if(!ability)
|
||||
bool Client::SaveAA()
|
||||
{
|
||||
std::vector<CharacterAlternateAbilitiesRepository::CharacterAlternateAbilities> v;
|
||||
|
||||
uint32 aa_points_spent = 0;
|
||||
|
||||
auto e = CharacterAlternateAbilitiesRepository::NewEntity();
|
||||
|
||||
for (auto &rank : aa_ranks) {
|
||||
auto a = zone->GetAlternateAdvancementAbility(rank.first);
|
||||
if (!a) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rank.second.first > 0) {
|
||||
AA::Rank *r = ability->GetRankByPointsSpent(rank.second.first);
|
||||
|
||||
if(!r)
|
||||
if (rank.second.first > 0) {
|
||||
auto r = a->GetRankByPointsSpent(rank.second.first);
|
||||
if (!r) {
|
||||
continue;
|
||||
|
||||
spentpoints += r->total_cost;
|
||||
|
||||
if(i == 0) {
|
||||
iquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)"
|
||||
" VALUES (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
|
||||
} else {
|
||||
iquery += StringFormat(", (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
|
||||
}
|
||||
i++;
|
||||
|
||||
aa_points_spent += r->total_cost;
|
||||
|
||||
e.id = character_id;
|
||||
e.aa_id = a->first_rank_id;
|
||||
e.aa_value = rank.second.first;
|
||||
e.charges = rank.second.second;
|
||||
|
||||
v.emplace_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
|
||||
m_pp.aapoints_spent = aa_points_spent + m_epp.expended_aa;
|
||||
|
||||
if(iquery.length() > 0) {
|
||||
database.QueryDatabase(iquery);
|
||||
}
|
||||
|
||||
return true;
|
||||
return CharacterAlternateAbilitiesRepository::ReplaceMany(database, v);
|
||||
}
|
||||
|
||||
void Client::RemoveExpendedAA(int aa_id)
|
||||
{
|
||||
database.QueryDatabase(StringFormat("DELETE from `character_alternate_abilities` WHERE `id` = %d and `aa_id` = %d", character_id, aa_id));
|
||||
CharacterAlternateAbilitiesRepository::DeleteWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`id` = {} AND `aa_id` = {}",
|
||||
CharacterID(),
|
||||
aa_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bool Client::Save(uint8 iCommitNow) {
|
||||
@@ -915,15 +923,19 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
// Garble the message based on drunkness
|
||||
if (GetIntoxication() > 0 && !(RuleB(Chat, ServerWideOOC) && chan_num == ChatChannel_OOC) && !GetGM()) {
|
||||
GarbleMessage(message, (int)(GetIntoxication() / 3));
|
||||
language = 0; // No need for language when drunk
|
||||
lang_skill = 100;
|
||||
language = Language::CommonTongue; // No need for language when drunk
|
||||
lang_skill = Language::MaxValue;
|
||||
}
|
||||
|
||||
// some channels don't use languages
|
||||
if (chan_num == ChatChannel_OOC || chan_num == ChatChannel_GMSAY || chan_num == ChatChannel_Broadcast || chan_num == ChatChannel_Petition)
|
||||
{
|
||||
language = 0;
|
||||
lang_skill = 100;
|
||||
if (
|
||||
chan_num == ChatChannel_OOC ||
|
||||
chan_num == ChatChannel_GMSAY ||
|
||||
chan_num == ChatChannel_Broadcast ||
|
||||
chan_num == ChatChannel_Petition
|
||||
) {
|
||||
language = Language::CommonTongue;
|
||||
lang_skill = Language::MaxValue;
|
||||
}
|
||||
|
||||
// Censor the message
|
||||
@@ -1274,69 +1286,88 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...) {
|
||||
if ((chan_num==11 && !(GetGM())) || (chan_num==10 && Admin() < AccountStatus::QuestTroupe)) // dont need to send /pr & /petition to everybody
|
||||
void Client::ChannelMessageSend(
|
||||
const char *from,
|
||||
const char *to,
|
||||
uint8 channel_id,
|
||||
uint8 language_id,
|
||||
uint8 language_skill,
|
||||
const char *message,
|
||||
...
|
||||
)
|
||||
{
|
||||
if (
|
||||
(channel_id == ChatChannel_Petition && Admin() < AccountStatus::QuestTroupe) ||
|
||||
(channel_id == ChatChannel_GMSAY && !GetGM())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list argptr;
|
||||
char buffer[4096];
|
||||
char message_sender[64];
|
||||
char buffer[4096];
|
||||
char message_sender[64];
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, 4096, message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
EQApplicationPacket app(OP_ChannelMessage, sizeof(ChannelMessage_Struct)+strlen(buffer)+1);
|
||||
ChannelMessage_Struct* cm = (ChannelMessage_Struct*)app.pBuffer;
|
||||
EQApplicationPacket app(OP_ChannelMessage, sizeof(ChannelMessage_Struct) + strlen(buffer) + 1);
|
||||
|
||||
if (from == 0)
|
||||
auto* cm = (ChannelMessage_Struct *) app.pBuffer;
|
||||
|
||||
if (from == 0) {
|
||||
strcpy(cm->sender, "ZServer");
|
||||
else if (from[0] == 0)
|
||||
} else if (from[0] == 0) {
|
||||
strcpy(cm->sender, "ZServer");
|
||||
else {
|
||||
} else {
|
||||
CleanMobName(from, message_sender);
|
||||
strcpy(cm->sender, message_sender);
|
||||
}
|
||||
if (to != 0)
|
||||
|
||||
if (to != 0) {
|
||||
strcpy((char *) cm->targetname, to);
|
||||
else if (chan_num == ChatChannel_Tell)
|
||||
} else if (channel_id == ChatChannel_Tell) {
|
||||
strcpy(cm->targetname, m_pp.name);
|
||||
else
|
||||
} else {
|
||||
cm->targetname[0] = 0;
|
||||
|
||||
uint8 ListenerSkill;
|
||||
|
||||
if (language < MAX_PP_LANGUAGE) {
|
||||
ListenerSkill = m_pp.languages[language];
|
||||
if (ListenerSkill < 24) {
|
||||
cm->language = (MAX_PP_LANGUAGE - 1); // in an unknown tongue
|
||||
}
|
||||
else {
|
||||
cm->language = language;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ListenerSkill = m_pp.languages[0];
|
||||
cm->language = 0;
|
||||
|
||||
uint8 listener_skill;
|
||||
|
||||
const bool is_valid_language = EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27);
|
||||
|
||||
if (is_valid_language) {
|
||||
listener_skill = m_pp.languages[language_id];
|
||||
cm->language = listener_skill < 24 ? Language::Unknown27 : language_id;
|
||||
} else {
|
||||
listener_skill = m_pp.languages[Language::CommonTongue];
|
||||
cm->language = Language::CommonTongue;
|
||||
}
|
||||
|
||||
// set effective language skill = lower of sender and receiver skills
|
||||
int32 EffSkill = (lang_skill < ListenerSkill ? lang_skill : ListenerSkill);
|
||||
if (EffSkill > 100) // maximum language skill is 100
|
||||
EffSkill = 100;
|
||||
cm->skill_in_language = EffSkill;
|
||||
uint8 effective_skill = (language_skill < listener_skill ? language_skill : listener_skill);
|
||||
if (effective_skill > Language::MaxValue) {
|
||||
effective_skill = Language::MaxValue;
|
||||
}
|
||||
|
||||
cm->chan_num = chan_num;
|
||||
cm->skill_in_language = effective_skill;
|
||||
|
||||
cm->chan_num = channel_id;
|
||||
strcpy(&cm->message[0], buffer);
|
||||
|
||||
QueuePacket(&app);
|
||||
|
||||
bool senderCanTrainSelf = RuleB(Client, SelfLanguageLearning);
|
||||
bool weAreNotSender = strcmp(GetCleanName(), cm->sender);
|
||||
const bool can_train_self = RuleB(Client, SelfLanguageLearning);
|
||||
const bool is_not_sender = strcmp(GetCleanName(), cm->sender);
|
||||
|
||||
if (senderCanTrainSelf || weAreNotSender) {
|
||||
if ((chan_num == ChatChannel_Group) && (ListenerSkill < 100)) { // group message in unmastered language, check for skill up
|
||||
if (language < MAX_PP_LANGUAGE && m_pp.languages[language] <= lang_skill)
|
||||
CheckLanguageSkillIncrease(language, lang_skill);
|
||||
if (can_train_self || is_not_sender) {
|
||||
if (
|
||||
channel_id == ChatChannel_Group &&
|
||||
listener_skill < Language::MaxValue
|
||||
) { // group message in non-mastered language, check for skill up
|
||||
if (is_valid_language && m_pp.languages[language_id] <= language_skill) {
|
||||
CheckLanguageSkillIncrease(language_id, language_skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1637,26 +1668,30 @@ void Client::SetSkill(EQ::skills::SkillType skillid, uint16 value) {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::IncreaseLanguageSkill(int skill_id, int value) {
|
||||
void Client::IncreaseLanguageSkill(uint8 language_id, uint8 increase)
|
||||
{
|
||||
if (!EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (skill_id >= MAX_PP_LANGUAGE)
|
||||
return; //Invalid lang id
|
||||
m_pp.languages[language_id] += increase;
|
||||
|
||||
m_pp.languages[skill_id] += value;
|
||||
if (m_pp.languages[language_id] > Language::MaxValue) {
|
||||
m_pp.languages[language_id] = Language::MaxValue;
|
||||
}
|
||||
|
||||
if (m_pp.languages[skill_id] > 100) //Lang skill above max
|
||||
m_pp.languages[skill_id] = 100;
|
||||
|
||||
database.SaveCharacterLanguage(CharacterID(), skill_id, m_pp.languages[skill_id]);
|
||||
database.SaveCharacterLanguage(CharacterID(), language_id, m_pp.languages[language_id]);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct));
|
||||
SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer;
|
||||
skill->skillId = 100 + skill_id;
|
||||
skill->value = m_pp.languages[skill_id];
|
||||
auto* s = (SkillUpdate_Struct*) outapp->pBuffer;
|
||||
|
||||
s->skillId = 100 + language_id;
|
||||
s->value = m_pp.languages[language_id];
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
MessageString( Chat::Skills, LANG_SKILL_IMPROVED ); //Notify client
|
||||
MessageString(Chat::Skills, LANG_SKILL_IMPROVED);
|
||||
}
|
||||
|
||||
void Client::AddSkill(EQ::skills::SkillType skillid, uint16 value) {
|
||||
@@ -2221,7 +2256,7 @@ void Client::SetGM(bool toggle) {
|
||||
m_pp.gm ? "now" : "no longer"
|
||||
).c_str()
|
||||
);
|
||||
SendAppearancePacket(AT_GM, m_pp.gm);
|
||||
SendAppearancePacket(AppearanceType::GM, m_pp.gm);
|
||||
Save();
|
||||
UpdateWho();
|
||||
}
|
||||
@@ -2272,9 +2307,9 @@ void Client::ReadBook(BookRequest_Struct *book) {
|
||||
|
||||
memcpy(out->booktext, booktxt2.c_str(), length);
|
||||
|
||||
if (book_language > 0 && book_language < MAX_PP_LANGUAGE) {
|
||||
if (m_pp.languages[book_language] < 100) {
|
||||
GarbleMessage(out->booktext, (100 - m_pp.languages[book_language]));
|
||||
if (EQ::ValueWithin(book_language, Language::CommonTongue, Language::Unknown27)) {
|
||||
if (m_pp.languages[book_language] < Language::MaxValue) {
|
||||
GarbleMessage(out->booktext, (Language::MaxValue - m_pp.languages[book_language]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2673,38 +2708,43 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::CheckLanguageSkillIncrease(uint8 langid, uint8 TeacherSkill) {
|
||||
if (IsDead() || IsUnconscious())
|
||||
void Client::CheckLanguageSkillIncrease(uint8 language_id, uint8 teacher_skill) {
|
||||
if (IsDead() || IsUnconscious()) {
|
||||
return;
|
||||
if (IsAIControlled())
|
||||
}
|
||||
|
||||
if (IsAIControlled()) {
|
||||
return;
|
||||
if (langid >= MAX_PP_LANGUAGE)
|
||||
return; // do nothing if langid is an invalid language
|
||||
}
|
||||
|
||||
int LangSkill = m_pp.languages[langid]; // get current language skill
|
||||
if (!EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LangSkill < 100) { // if the language isn't already maxed
|
||||
int32 Chance = 5 + ((TeacherSkill - LangSkill)/10); // greater chance to learn if teacher's skill is much higher than yours
|
||||
Chance = (Chance * RuleI(Character, SkillUpModifier)/100);
|
||||
const uint8 language_skill = m_pp.languages[language_id]; // get current language skill
|
||||
|
||||
if(zone->random.Real(0,100) < Chance) { // if they make the roll
|
||||
IncreaseLanguageSkill(langid); // increase the language skill by 1
|
||||
if (language_skill < Language::MaxValue) { // if the language isn't already maxed
|
||||
int chance = 5 + ((teacher_skill - language_skill) / 10); // greater chance to learn if teacher's skill is much higher than yours
|
||||
chance = (chance * RuleI(Character, SkillUpModifier) / 100);
|
||||
|
||||
if (zone->random.Real(0, 100) < chance) { // if they make the roll
|
||||
IncreaseLanguageSkill(language_id);
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_LANGUAGE_SKILL_UP)) {
|
||||
const auto& export_string = fmt::format(
|
||||
const auto &export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
langid,
|
||||
LangSkill + 1,
|
||||
100
|
||||
language_id,
|
||||
language_skill + 1,
|
||||
Language::MaxValue
|
||||
);
|
||||
|
||||
parse->EventPlayer(EVENT_LANGUAGE_SKILL_UP, this, export_string, 0);
|
||||
}
|
||||
|
||||
LogSkills("Language [{}] at value [{}] successfully gain with [{}] % chance", langid, LangSkill, Chance);
|
||||
LogSkills("Language [{}] at value [{}] successfully gain with [{}] % chance", language_id, language_skill, chance);
|
||||
} else {
|
||||
LogSkills("Language [{}] at value [{}] failed to gain with [{}] % chance", language_id, language_skill, chance);
|
||||
}
|
||||
else
|
||||
LogSkills("Language [{}] at value [{}] failed to gain with [{}] % chance", langid, LangSkill, Chance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2839,7 +2879,7 @@ void Client::SetPVP(bool toggle, bool message) {
|
||||
}
|
||||
}
|
||||
|
||||
SendAppearancePacket(AT_PVP, GetPVP());
|
||||
SendAppearancePacket(AppearanceType::PVP, GetPVP());
|
||||
Save();
|
||||
}
|
||||
|
||||
@@ -3566,25 +3606,30 @@ void Client::SetHideMe(bool flag)
|
||||
UpdateWho();
|
||||
}
|
||||
|
||||
void Client::SetLanguageSkill(int langid, int value)
|
||||
void Client::SetLanguageSkill(uint8 language_id, uint8 language_skill)
|
||||
{
|
||||
if (langid >= MAX_PP_LANGUAGE)
|
||||
return; //Invalid Language
|
||||
if (!EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > 100)
|
||||
value = 100; //Max lang value
|
||||
if (language_skill > Language::MaxValue) {
|
||||
language_skill = Language::MaxValue;
|
||||
}
|
||||
|
||||
m_pp.languages[langid] = value;
|
||||
database.SaveCharacterLanguage(CharacterID(), langid, value);
|
||||
m_pp.languages[language_id] = language_skill;
|
||||
|
||||
database.SaveCharacterLanguage(CharacterID(), language_id, language_skill);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct));
|
||||
SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer;
|
||||
skill->skillId = 100 + langid;
|
||||
skill->value = m_pp.languages[langid];
|
||||
auto* s = (SkillUpdate_Struct*) outapp->pBuffer;
|
||||
|
||||
s->skillId = 100 + language_id;
|
||||
s->value = m_pp.languages[language_id];
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
MessageString( Chat::Skills, LANG_SKILL_IMPROVED ); //Notify the client
|
||||
MessageString(Chat::Skills, LANG_SKILL_IMPROVED);
|
||||
}
|
||||
|
||||
void Client::LinkDead()
|
||||
@@ -3607,7 +3652,7 @@ void Client::LinkDead()
|
||||
|
||||
// save_timer.Start(2500);
|
||||
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
||||
SendAppearancePacket(AT_Linkdead, 1);
|
||||
SendAppearancePacket(AppearanceType::Linkdead, 1);
|
||||
client_state = CLIENT_LINKDEAD;
|
||||
AI_Start(CLIENT_LD_TIMEOUT);
|
||||
}
|
||||
@@ -3750,7 +3795,7 @@ void Client::EnteringMessages(Client* client)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
client->SendAppearancePacket(AT_Anim, ANIM_FREEZE);
|
||||
client->SendAppearancePacket(AppearanceType::Animation, Animation::Freeze);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4599,7 +4644,7 @@ void Client::ClearGroupAAs() {
|
||||
m_pp.raid_leadership_exp = 0;
|
||||
|
||||
Save();
|
||||
database.SaveCharacterLeadershipAA(CharacterID(), &m_pp);
|
||||
database.SaveCharacterLeadershipAbilities(CharacterID(), &m_pp);
|
||||
}
|
||||
|
||||
void Client::UpdateGroupAAs(int32 points, uint32 type) {
|
||||
@@ -6519,27 +6564,33 @@ void Client::RemoveFromInstance(uint16 instance_id)
|
||||
|
||||
void Client::SendAltCurrencies() {
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
||||
uint32 count = zone->AlternateCurrencies.size();
|
||||
if(count == 0) {
|
||||
const uint32 currency_count = zone->AlternateCurrencies.size();
|
||||
if (!currency_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(
|
||||
OP_AltCurrency,
|
||||
sizeof(AltCurrencyPopulate_Struct) +
|
||||
sizeof(AltCurrencyPopulateEntry_Struct) * currency_count
|
||||
);
|
||||
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyPopulate_Struct) +
|
||||
sizeof(AltCurrencyPopulateEntry_Struct) * count);
|
||||
AltCurrencyPopulate_Struct *altc = (AltCurrencyPopulate_Struct*)outapp->pBuffer;
|
||||
altc->opcode = ALT_CURRENCY_OP_POPULATE;
|
||||
altc->count = count;
|
||||
auto a = (AltCurrencyPopulate_Struct*) outapp->pBuffer;
|
||||
|
||||
a->opcode = AlternateCurrencyMode::Populate;
|
||||
a->count = currency_count;
|
||||
|
||||
uint32 currency_id = 0;
|
||||
for (const auto& alternate_currency : zone->AlternateCurrencies) {
|
||||
const EQ::ItemData* item = database.GetItem(alternate_currency.item_id);
|
||||
altc->entries[currency_id].currency_number = alternate_currency.id;
|
||||
altc->entries[currency_id].unknown00 = 1;
|
||||
altc->entries[currency_id].currency_number2 = alternate_currency.id;
|
||||
altc->entries[currency_id].item_id = alternate_currency.item_id;
|
||||
altc->entries[currency_id].item_icon = item ? item->Icon : 1000;
|
||||
altc->entries[currency_id].stack_size = item ? item->StackSize : 1000;
|
||||
for (const auto& c : zone->AlternateCurrencies) {
|
||||
const auto* item = database.GetItem(c.item_id);
|
||||
|
||||
a->entries[currency_id].currency_number = c.id;
|
||||
a->entries[currency_id].unknown00 = 1;
|
||||
a->entries[currency_id].currency_number2 = c.id;
|
||||
a->entries[currency_id].item_id = c.item_id;
|
||||
a->entries[currency_id].item_icon = item ? item->Icon : 1000;
|
||||
a->entries[currency_id].stack_size = item ? item->StackSize : 1000;
|
||||
|
||||
currency_id++;
|
||||
}
|
||||
|
||||
@@ -6636,11 +6687,8 @@ void Client::SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null)
|
||||
uint32 Client::GetAlternateCurrencyValue(uint32 currency_id) const
|
||||
{
|
||||
auto iter = alternate_currency.find(currency_id);
|
||||
if(iter == alternate_currency.end()) {
|
||||
return 0;
|
||||
} else {
|
||||
return (*iter).second;
|
||||
}
|
||||
|
||||
return iter == alternate_currency.end() ? 0 : (*iter).second;
|
||||
}
|
||||
|
||||
void Client::ProcessAlternateCurrencyQueue() {
|
||||
@@ -8565,37 +8613,37 @@ bool Client::CanMedOnHorse()
|
||||
void Client::EnableAreaHPRegen(int value)
|
||||
{
|
||||
AreaHPRegen = value * 0.001f;
|
||||
SendAppearancePacket(AT_AreaHPRegen, value, false);
|
||||
SendAppearancePacket(AppearanceType::AreaHealthRegen, value, false);
|
||||
}
|
||||
|
||||
void Client::DisableAreaHPRegen()
|
||||
{
|
||||
AreaHPRegen = 1.0f;
|
||||
SendAppearancePacket(AT_AreaHPRegen, 1000, false);
|
||||
SendAppearancePacket(AppearanceType::AreaHealthRegen, 1000, false);
|
||||
}
|
||||
|
||||
void Client::EnableAreaManaRegen(int value)
|
||||
{
|
||||
AreaManaRegen = value * 0.001f;
|
||||
SendAppearancePacket(AT_AreaManaRegen, value, false);
|
||||
SendAppearancePacket(AppearanceType::AreaManaRegen, value, false);
|
||||
}
|
||||
|
||||
void Client::DisableAreaManaRegen()
|
||||
{
|
||||
AreaManaRegen = 1.0f;
|
||||
SendAppearancePacket(AT_AreaManaRegen, 1000, false);
|
||||
SendAppearancePacket(AppearanceType::AreaManaRegen, 1000, false);
|
||||
}
|
||||
|
||||
void Client::EnableAreaEndRegen(int value)
|
||||
{
|
||||
AreaEndRegen = value * 0.001f;
|
||||
SendAppearancePacket(AT_AreaEndRegen, value, false);
|
||||
SendAppearancePacket(AppearanceType::AreaEnduranceRegen, value, false);
|
||||
}
|
||||
|
||||
void Client::DisableAreaEndRegen()
|
||||
{
|
||||
AreaEndRegen = 1.0f;
|
||||
SendAppearancePacket(AT_AreaEndRegen, 1000, false);
|
||||
SendAppearancePacket(AppearanceType::AreaEnduranceRegen, 1000, false);
|
||||
}
|
||||
|
||||
void Client::EnableAreaRegens(int value)
|
||||
@@ -10011,7 +10059,7 @@ void Client::SetAnon(uint8 anon_flag) {
|
||||
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* spawn_appearance = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
spawn_appearance->spawn_id = GetID();
|
||||
spawn_appearance->type = AT_Anon;
|
||||
spawn_appearance->type = AppearanceType::Anonymous;
|
||||
spawn_appearance->parameter = anon_flag;
|
||||
entity_list.QueueClients(this, outapp);
|
||||
Save();
|
||||
@@ -10024,7 +10072,7 @@ void Client::SetAFK(uint8 afk_flag) {
|
||||
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* spawn_appearance = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
spawn_appearance->spawn_id = GetID();
|
||||
spawn_appearance->type = AT_AFK;
|
||||
spawn_appearance->type = AppearanceType::AFK;
|
||||
spawn_appearance->parameter = afk_flag;
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
@@ -10269,7 +10317,7 @@ void Client::RemoveItem(uint32 item_id, uint32 quantity)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetGMStatus(int16 new_status) {
|
||||
void Client::SetGMStatus(int new_status) {
|
||||
if (Admin() != new_status) {
|
||||
database.UpdateGMStatus(AccountID(), new_status);
|
||||
UpdateAdmin();
|
||||
@@ -10546,9 +10594,9 @@ void Client::ReadBookByName(std::string book_name, uint8 book_type)
|
||||
|
||||
memcpy(out->booktext, book_text.c_str(), length);
|
||||
|
||||
if (book_language > 0 && book_language < MAX_PP_LANGUAGE) {
|
||||
if (m_pp.languages[book_language] < 100) {
|
||||
GarbleMessage(out->booktext, (100 - m_pp.languages[book_language]));
|
||||
if (EQ::ValueWithin(book_language, Language::CommonTongue, Language::Unknown27)) {
|
||||
if (m_pp.languages[book_language] < Language::MaxValue) {
|
||||
GarbleMessage(out->booktext, (Language::MaxValue - m_pp.languages[book_language]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10697,22 +10745,22 @@ void Client::SaveSpells()
|
||||
|
||||
void Client::SaveDisciplines()
|
||||
{
|
||||
std::vector<CharacterDisciplinesRepository::CharacterDisciplines> character_discs = {};
|
||||
std::vector<CharacterDisciplinesRepository::CharacterDisciplines> v;
|
||||
|
||||
for (int index = 0; index < MAX_PP_DISCIPLINES; index++) {
|
||||
if (IsValidSpell(m_pp.disciplines.values[index])) {
|
||||
auto discipline = CharacterDisciplinesRepository::NewEntity();
|
||||
discipline.id = CharacterID();
|
||||
discipline.slot_id = index;
|
||||
discipline.disc_id = m_pp.disciplines.values[index];
|
||||
character_discs.emplace_back(discipline);
|
||||
for (int slot_id = 0; slot_id < MAX_PP_DISCIPLINES; slot_id++) {
|
||||
if (IsValidSpell(m_pp.disciplines.values[slot_id])) {
|
||||
auto e = CharacterDisciplinesRepository::NewEntity();
|
||||
|
||||
e.id = CharacterID();
|
||||
e.slot_id = slot_id;
|
||||
e.disc_id = m_pp.disciplines.values[slot_id];
|
||||
|
||||
v.emplace_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDisciplinesRepository::DeleteWhere(database, fmt::format("id = {}", CharacterID()));
|
||||
|
||||
if (!character_discs.empty()) {
|
||||
CharacterDisciplinesRepository::InsertMany(database, character_discs);
|
||||
if (!v.empty()) {
|
||||
CharacterDisciplinesRepository::ReplaceMany(database, v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10883,8 +10931,8 @@ void Client::ReconnectUCS()
|
||||
|
||||
buffer = StringFormat(
|
||||
"%s,%i,%s.%s,%c%s",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->GetUCSHost().c_str(),
|
||||
Config->GetUCSPort(),
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
connection_type,
|
||||
@@ -10910,8 +10958,8 @@ void Client::ReconnectUCS()
|
||||
|
||||
buffer = StringFormat(
|
||||
"%s,%i,%s.%s,%c%s",
|
||||
Config->MailHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->GetUCSHost().c_str(),
|
||||
Config->GetUCSPort(),
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
connection_type,
|
||||
@@ -11224,7 +11272,7 @@ void Client::Undye()
|
||||
SendWearChange(slot);
|
||||
}
|
||||
|
||||
database.DeleteCharacterDye(CharacterID());
|
||||
database.DeleteCharacterMaterialColor(CharacterID());
|
||||
}
|
||||
|
||||
void Client::SetTrackingID(uint32 entity_id)
|
||||
@@ -11944,3 +11992,26 @@ std::string GetZoneModeString(ZoneMode mode)
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ClearXTargets()
|
||||
{
|
||||
if (!XTargettingAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetMaxXTargets(); ++i) {
|
||||
if (XTargets[i].ID) {
|
||||
Mob* m = entity_list.GetMob(XTargets[i].ID);
|
||||
|
||||
if (m) {
|
||||
RemoveXTarget(m, false);
|
||||
}
|
||||
|
||||
XTargets[i].ID = 0;
|
||||
XTargets[i].Name[0] = 0;
|
||||
XTargets[i].dirty = false;
|
||||
|
||||
SendXTargetPacket(i, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-7
@@ -335,7 +335,7 @@ public:
|
||||
void QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone);
|
||||
void FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL);
|
||||
void ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_skill, const char* orig_message, const char* targetname = nullptr, bool is_silent = false);
|
||||
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
|
||||
void ChannelMessageSend(const char* from, const char* to, uint8 channel_id, uint8 language_id, uint8 language_skill, const char* message, ...);
|
||||
void Message(uint32 type, const char* message, ...);
|
||||
void FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...);
|
||||
void VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber);
|
||||
@@ -382,7 +382,7 @@ public:
|
||||
inline ExtendedProfile_Struct& GetEPP() { return m_epp; }
|
||||
inline EQ::InventoryProfile& GetInv() { return m_inv; }
|
||||
inline const EQ::InventoryProfile& GetInv() const { return m_inv; }
|
||||
inline PetInfo* GetPetInfo(uint16 pet) { return (pet==1)?&m_suspendedminion:&m_petinfo; }
|
||||
inline PetInfo* GetPetInfo(int pet_info_type) { return pet_info_type == PetInfoType::Suspended ? &m_suspendedminion : &m_petinfo; }
|
||||
inline InspectMessage_Struct& GetInspectMessage() { return m_inspect_message; }
|
||||
inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; }
|
||||
void ReloadExpansionProfileSetting();
|
||||
@@ -452,7 +452,7 @@ public:
|
||||
void SendSingleTraderItem(uint32 char_id, int uniqueid);
|
||||
void BulkSendMerchantInventory(int merchant_id, int npcid);
|
||||
|
||||
inline uint8 GetLanguageSkill(uint16 n) const { return m_pp.languages[n]; }
|
||||
inline uint8 GetLanguageSkill(uint8 language_id) const { return m_pp.languages[language_id]; }
|
||||
|
||||
void SendPickPocketResponse(Mob *from, uint32 amt, int type, const EQ::ItemData* item = nullptr);
|
||||
|
||||
@@ -767,7 +767,7 @@ public:
|
||||
void SetSkillPoints(int inp) { m_pp.points = inp;}
|
||||
|
||||
void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= EQ::skills::HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } }
|
||||
void IncreaseLanguageSkill(int skill_id, int value = 1);
|
||||
void IncreaseLanguageSkill(uint8 language_id, uint8 increase = 1);
|
||||
virtual uint16 GetSkill(EQ::skills::SkillType skill_id) const { if (skill_id <= EQ::skills::HIGHEST_SKILL) { return(itembonuses.skillmod[skill_id] > 0 ? (itembonuses.skillmodmax[skill_id] > 0 ? std::min(m_pp.skills[skill_id] + itembonuses.skillmodmax[skill_id], m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id]); } return 0; }
|
||||
uint32 GetRawSkill(EQ::skills::SkillType skill_id) const { if (skill_id <= EQ::skills::HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; }
|
||||
bool HasSkill(EQ::skills::SkillType skill_id) const;
|
||||
@@ -777,8 +777,8 @@ public:
|
||||
void CheckSpecializeIncrease(uint16 spell_id);
|
||||
void CheckSongSkillIncrease(uint16 spell_id);
|
||||
bool CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who, int chancemodi = 0);
|
||||
void CheckLanguageSkillIncrease(uint8 langid, uint8 TeacherSkill);
|
||||
void SetLanguageSkill(int langid, int value);
|
||||
void CheckLanguageSkillIncrease(uint8 language_id, uint8 teacher_skill);
|
||||
void SetLanguageSkill(uint8 language_id, uint8 language_skill);
|
||||
void SetHoTT(uint32 mobid);
|
||||
void ShowSkillsWindow();
|
||||
|
||||
@@ -988,6 +988,7 @@ public:
|
||||
void IncStats(uint8 type,int16 increase_val);
|
||||
void DropItem(int16 slot_id, bool recurse = true);
|
||||
void DropItemQS(EQ::ItemInstance* inst, bool pickup);
|
||||
bool HasItemOnCorpse(uint32 item_id);
|
||||
|
||||
bool IsAugmentRestricted(uint8 item_type, uint32 augment_restriction);
|
||||
|
||||
@@ -1527,6 +1528,7 @@ public:
|
||||
void JoinGroupXTargets(Group *g);
|
||||
void LeaveGroupXTargets(Group *g);
|
||||
void LeaveRaidXTargets(Raid *r);
|
||||
void ClearXTargets();
|
||||
bool GroupFollow(Client* inviter);
|
||||
inline bool GetRunMode() const { return runmode; }
|
||||
|
||||
@@ -1605,7 +1607,7 @@ public:
|
||||
void SetAccountFlag(const std::string& flag, const std::string& value);
|
||||
std::string GetAccountFlag(const std::string& flag);
|
||||
std::vector<std::string> GetAccountFlags();
|
||||
void SetGMStatus(int16 new_status);
|
||||
void SetGMStatus(int new_status);
|
||||
void Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto_consume);
|
||||
void PlayMP3(const char* fname);
|
||||
void ExpeditionSay(const char *str, int ExpID);
|
||||
|
||||
@@ -1455,7 +1455,7 @@ int32 Client::CalcATK()
|
||||
|
||||
uint32 Mob::GetInstrumentMod(uint16 spell_id)
|
||||
{
|
||||
if (GetClass() != Class::Bard) {
|
||||
if (GetClass() != Class::Bard || spells[spell_id].is_discipline || spell_id == SPELL_AMPLIFICATION) {
|
||||
//Other classes can get a base effects mod using SPA 413
|
||||
if (HasBaseEffectFocus()) {
|
||||
return (10 + (GetFocusEffect(focusFcBaseEffects, spell_id) / 10));//TODO: change action->instrument mod to float to support < 10% focus values
|
||||
|
||||
+170
-110
@@ -547,8 +547,8 @@ void Client::CompleteConnect()
|
||||
default: { break; } // GUILD_NONE
|
||||
}
|
||||
}
|
||||
SendAppearancePacket(AT_GuildID, GuildID(), false);
|
||||
SendAppearancePacket(AT_GuildRank, rank, false);
|
||||
SendAppearancePacket(AppearanceType::GuildID, GuildID(), false);
|
||||
SendAppearancePacket(AppearanceType::GuildRank, rank, false);
|
||||
}
|
||||
|
||||
// moved to dbload and translators since we iterate there also .. keep m_pp values whatever they are when they get here
|
||||
@@ -681,8 +681,11 @@ void Client::CompleteConnect()
|
||||
break;
|
||||
}
|
||||
case SE_SummonHorse: {
|
||||
SummonHorse(buffs[j1].spellid);
|
||||
//hasmount = true; //this was false, is that the correct thing?
|
||||
if (RuleB(Character, PreventMountsFromZoning)) {
|
||||
BuffFadeByEffect(SE_SummonHorse);
|
||||
} else {
|
||||
SummonHorse(buffs[j1].spellid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_Silence:
|
||||
@@ -703,7 +706,7 @@ void Client::CompleteConnect()
|
||||
case SE_Invisibility2:
|
||||
case SE_Invisibility:
|
||||
{
|
||||
SendAppearancePacket(AT_Invis, Invisibility::Invisible);
|
||||
SendAppearancePacket(AppearanceType::Invisibility, Invisibility::Invisible);
|
||||
break;
|
||||
}
|
||||
case SE_Levitate:
|
||||
@@ -712,17 +715,17 @@ void Client::CompleteConnect()
|
||||
{
|
||||
if (!GetGM())
|
||||
{
|
||||
SendAppearancePacket(AT_Levitate, 0);
|
||||
SendAppearancePacket(AppearanceType::FlyMode, 0);
|
||||
BuffFadeByEffect(SE_Levitate);
|
||||
Message(Chat::Red, "You can't levitate in this zone.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (spell.limit_value[x1] == 1) {
|
||||
SendAppearancePacket(AT_Levitate, EQ::constants::GravityBehavior::LevitateWhileRunning, true, true);
|
||||
SendAppearancePacket(AppearanceType::FlyMode, EQ::constants::GravityBehavior::LevitateWhileRunning, true, true);
|
||||
}
|
||||
else {
|
||||
SendAppearancePacket(AT_Levitate, EQ::constants::GravityBehavior::Levitating, true, true);
|
||||
SendAppearancePacket(AppearanceType::FlyMode, EQ::constants::GravityBehavior::Levitating, true, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -747,7 +750,7 @@ void Client::CompleteConnect()
|
||||
}
|
||||
}
|
||||
|
||||
/* Sends appearances for all mobs not doing anim_stand aka sitting, looting, playing dead */
|
||||
/* Sends appearances for all mobs not doing Animation::Standing aka sitting, looting, playing dead */
|
||||
entity_list.SendZoneAppearance(this);
|
||||
/* Sends the Nimbus particle effects (up to 3) for any mob using them */
|
||||
entity_list.SendNimbusEffects(this);
|
||||
@@ -1268,7 +1271,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
|
||||
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
|
||||
database.LoadCharacterMaterialColor(cid, &m_pp); /* Load Character Material */
|
||||
database.LoadCharacterPotions(cid, &m_pp); /* Load Character Potion Belt */
|
||||
database.LoadCharacterPotionBelt(cid, &m_pp); /* Load Character Potion Belt */
|
||||
database.LoadCharacterCurrency(cid, &m_pp); /* Load Character Currency into PP */
|
||||
database.LoadCharacterData(cid, &m_pp, &m_epp); /* Load Character Data from DB into PP as well as E_PP */
|
||||
database.LoadCharacterSkills(cid, &m_pp); /* Load Character Skills */
|
||||
@@ -1277,7 +1280,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
database.LoadCharacterMemmedSpells(cid, &m_pp); /* Load Character Memorized Spells */
|
||||
database.LoadCharacterDisciplines(cid, &m_pp); /* Load Character Disciplines */
|
||||
database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
|
||||
database.LoadCharacterLeadershipAA(cid, &m_pp); /* Load Character Leadership AA's */
|
||||
database.LoadCharacterLeadershipAbilities(cid, &m_pp); /* Load Character Leadership AA's */
|
||||
database.LoadCharacterTribute(this); /* Load CharacterTribute */
|
||||
|
||||
// this pattern is strange
|
||||
@@ -1316,7 +1319,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
/* If GM, not trackable */
|
||||
if (gm_hide_me) { trackable = false; }
|
||||
if (gminvul) { invulnerable = true; }
|
||||
if (flymode > 0) { SendAppearancePacket(AT_Levitate, flymode); }
|
||||
if (flymode > 0) { SendAppearancePacket(AppearanceType::FlyMode, flymode); }
|
||||
/* Set Con State for Reporting */
|
||||
conn_state = PlayerProfileLoaded;
|
||||
|
||||
@@ -2737,6 +2740,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (!RuleB(Merchant, EnableAltCurrencySell)) {
|
||||
Message(Chat::Red, "Selling alternate currency items is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4326,6 +4330,14 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
LogSpells("OP CastSpell: slot [{}] spell [{}] target [{}] inv [{}]", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot);
|
||||
CastingSlot slot = static_cast<CastingSlot>(castspell->slot);
|
||||
|
||||
if (RuleB(Spells, RequireMnemonicRetention)) {
|
||||
if (EQ::ValueWithin(castspell->slot, 8, 11) && GetAA(aaMnemonicRetention) < (castspell->slot - 7)) {
|
||||
InterruptSpell(castspell->spell_id);
|
||||
Message(Chat::Red, "You do not have the required AA to use this spell slot.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Memorized Spell */
|
||||
if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id) {
|
||||
uint16 spell_to_cast = 0;
|
||||
@@ -4505,23 +4517,24 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
|
||||
{
|
||||
ChannelMessage_Struct* cm = (ChannelMessage_Struct*)app->pBuffer;
|
||||
auto* cm = (ChannelMessage_Struct*) app->pBuffer;
|
||||
|
||||
if (app->size < sizeof(ChannelMessage_Struct)) {
|
||||
std::cout << "Wrong size " << app->size << ", should be " << sizeof(ChannelMessage_Struct) << "+ on 0x" << std::hex << std::setfill('0') << std::setw(4) << app->GetOpcode() << std::dec << std::endl;
|
||||
return;
|
||||
}
|
||||
if (IsAIControlled() && !GetGM()) {
|
||||
Message(Chat::Red, "You try to speak but cant move your mouth!");
|
||||
LogDebug("Size mismatch in OP_ChannelMessage expected [{}] got [{}]", sizeof(ChannelMessage_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 skill_in_language = 100;
|
||||
if (cm->language < MAX_PP_LANGUAGE)
|
||||
{
|
||||
skill_in_language = m_pp.languages[cm->language];
|
||||
if (IsAIControlled() && !GetGM()) {
|
||||
Message(Chat::Red, "You try to speak but can't move your mouth!");
|
||||
return;
|
||||
}
|
||||
ChannelMessageReceived(cm->chan_num, cm->language, skill_in_language, cm->message, cm->targetname);
|
||||
|
||||
uint8 language_skill = Language::MaxValue;
|
||||
if (EQ::ValueWithin(cm->language, Language::CommonTongue, Language::Unknown27)) {
|
||||
language_skill = m_pp.languages[cm->language];
|
||||
}
|
||||
|
||||
ChannelMessageReceived(cm->chan_num, cm->language, language_skill, cm->message, cm->targetname);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4887,8 +4900,13 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillTracking, nullptr, -20);
|
||||
}
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
if (cy != m_Position.y || cx != m_Position.x) {
|
||||
// End trader mode if we move
|
||||
if (Trader) {
|
||||
Trader_EndTrader();
|
||||
}
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
if ((hidden || improved_hidden) && !sneaking) {
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
@@ -5053,7 +5071,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
if (zone->watermap) {
|
||||
if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
|
||||
if (zone->watermap->InLiquid(glm::vec3(m_Position)) && IsMoving()) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillSwimming, nullptr, -17);
|
||||
|
||||
// Dismount horses when entering water
|
||||
@@ -5770,7 +5788,7 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app)
|
||||
|
||||
if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
|
||||
m_pp.spell_book[dss->spell_slot] = SPELLBOOK_UNKNOWN;
|
||||
database.DeleteCharacterSpell(CharacterID(), m_pp.spell_book[dss->spell_slot], dss->spell_slot);
|
||||
database.DeleteCharacterSpell(CharacterID(), dss->spell_slot);
|
||||
dss->success = 1;
|
||||
}
|
||||
else
|
||||
@@ -6233,6 +6251,13 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (ed->dmgtype == EQ::constants::EnvironmentalDamage::Falling) {
|
||||
if (zone->HasWaterMap()) {
|
||||
auto target_position = glm::vec3(GetX(), GetY(), GetZ());
|
||||
if (!zone->watermap->InLiquid(target_position)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage;
|
||||
damage -= damage * mod / 100;
|
||||
}
|
||||
@@ -6481,7 +6506,7 @@ void Client::Handle_OP_GMBecomeNPC(const EQApplicationPacket *app)
|
||||
t->SetGM(false);
|
||||
}
|
||||
|
||||
m->SendAppearancePacket(AT_NPCName, 1, true);
|
||||
m->SendAppearancePacket(AppearanceType::NPCName, 1, true);
|
||||
t->SetBecomeNPC(true);
|
||||
t->SetBecomeNPCLevel(b->maxlevel);
|
||||
m->MessageString(Chat::White, TOGGLE_OFF);
|
||||
@@ -6598,17 +6623,26 @@ void Client::Handle_OP_GMGoto(const EQApplicationPacket *app)
|
||||
|
||||
auto *gmg = (GMSummon_Struct *) app->pBuffer;
|
||||
Mob *gt = entity_list.GetMob(gmg->charname);
|
||||
if (!gt) {
|
||||
MovePC(zone->GetZoneID(), zone->GetInstanceID(), gt->GetX(), gt->GetY(), gt->GetZ(), gt->GetHeading());
|
||||
if (gt) {
|
||||
MovePC(
|
||||
zone->GetZoneID(),
|
||||
zone->GetInstanceID(),
|
||||
gt->GetX(),
|
||||
gt->GetY(),
|
||||
gt->GetZ(),
|
||||
gt->GetHeading()
|
||||
);
|
||||
} else if (!worldserver.Connected()) {
|
||||
Message(Chat::Red, "Error: World server disconnected.");
|
||||
} else {
|
||||
auto pack = new ServerPacket(ServerOP_GMGoto, sizeof(ServerGMGoto_Struct));
|
||||
memset(pack->pBuffer, 0, pack->size);
|
||||
ServerGMGoto_Struct *wsgmg = (ServerGMGoto_Struct *) pack->pBuffer;
|
||||
strcpy(wsgmg->myname, GetName());
|
||||
strcpy(wsgmg->gotoname, gmg->charname);
|
||||
wsgmg->admin = admin;
|
||||
|
||||
auto* g = (ServerGMGoto_Struct *) pack->pBuffer;
|
||||
strcpy(g->myname, GetName());
|
||||
strcpy(g->gotoname, gmg->charname);
|
||||
g->admin = admin;
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
@@ -7303,64 +7337,81 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
GroupInvite_Struct* gis = (GroupInvite_Struct*)app->pBuffer;
|
||||
|
||||
Mob* invitee = nullptr;
|
||||
|
||||
Mob *Invitee = entity_list.GetMob(gis->invitee_name);
|
||||
if (RuleB(Character, GroupInvitesRequireTarget)) {
|
||||
// We can only invite the current target.
|
||||
invitee = GetTarget();
|
||||
} else {
|
||||
invitee = entity_list.GetMob(gis->invitee_name);
|
||||
}
|
||||
|
||||
if (Invitee == this)
|
||||
{
|
||||
if (invitee == this) {
|
||||
MessageString(Chat::LightGray, GROUP_INVITEE_SELF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Invitee)
|
||||
{
|
||||
if (Invitee->IsClient())
|
||||
{
|
||||
if (Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped())
|
||||
{
|
||||
if (app->GetOpcode() == OP_GroupInvite2)
|
||||
{
|
||||
if (invitee) {
|
||||
if (invitee->IsClient()) {
|
||||
if (invitee->CastToClient()->MercOnlyOrNoGroup() && !invitee->IsRaidGrouped()) {
|
||||
if (app->GetOpcode() == OP_GroupInvite2) {
|
||||
//Make a new packet using all the same information but make sure it's a fixed GroupInvite opcode so we
|
||||
//Don't have to deal with GroupFollow2 crap.
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct));
|
||||
memcpy(outapp->pBuffer, app->pBuffer, outapp->size);
|
||||
Invitee->CastToClient()->QueuePacket(outapp);
|
||||
invitee->CastToClient()->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//The correct opcode, no reason to bother wasting time reconstructing the packet
|
||||
Invitee->CastToClient()->QueuePacket(app);
|
||||
invitee->CastToClient()->QueuePacket(app);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else if (invitee->IsRaidGrouped()) {
|
||||
Raid* inviter_raid = GetRaid();
|
||||
Raid* invitee_raid = invitee->CastToClient()->GetRaid();
|
||||
|
||||
bool leader = false;
|
||||
|
||||
if (invitee_raid) {
|
||||
leader = invitee_raid->IsGroupLeader(invitee->GetName());
|
||||
}
|
||||
|
||||
if (inviter_raid != invitee_raid || leader) {
|
||||
MessageString(Chat::Default, ALREADY_IN_GRP_RAID, invitee->GetCleanName());
|
||||
} else {
|
||||
MessageString(Chat::Default, TARGET_ALREADY_IN_GROUP, invitee->GetCleanName());
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
if (RuleB(Character, OnInviteReceiveAlreadyinGroupMessage)) {
|
||||
if (!Invitee->CastToClient()->MercOnlyOrNoGroup()) {
|
||||
Message(Chat::LightGray, "%s is already in another group.", Invitee->GetCleanName());
|
||||
if (!invitee->CastToClient()->MercOnlyOrNoGroup()) {
|
||||
MessageString(Chat::Default, TARGET_ALREADY_IN_GROUP, invitee->GetCleanName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Invitee->IsBot()) {
|
||||
} else if (invitee->IsBot()) {
|
||||
Client* inviter = entity_list.GetClientByName(gis->inviter_name);
|
||||
if (inviter && inviter->IsRaidGrouped() && !Invitee->HasRaid()) {
|
||||
Bot::ProcessRaidInvite(Invitee->CastToBot(), inviter, true);
|
||||
}
|
||||
else if (!Invitee->HasRaid()) {
|
||||
Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName()));
|
||||
if (inviter && inviter->IsRaidGrouped() && !invitee->HasRaid()) {
|
||||
Bot::ProcessRaidInvite(invitee->CastToBot(), inviter, true);
|
||||
} else if (!invitee->HasRaid()) {
|
||||
Bot::ProcessBotGroupInvite(this, std::string(invitee->GetName()));
|
||||
} else {
|
||||
MessageString(Chat::LightGray, ALREADY_IN_RAID, Invitee->GetCleanName());
|
||||
MessageString(Chat::LightGray, ALREADY_IN_RAID, invitee->GetCleanName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pack = new ServerPacket(ServerOP_GroupInvite, sizeof(GroupInvite_Struct));
|
||||
memcpy(pack->pBuffer, gis, sizeof(GroupInvite_Struct));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
} else {
|
||||
if (RuleB(Character, GroupInvitesRequireTarget)) {
|
||||
Message(Chat::White, "You must target a player first to invite to join your group.");
|
||||
} else {
|
||||
auto pack = new ServerPacket(ServerOP_GroupInvite, sizeof(GroupInvite_Struct));
|
||||
memcpy(pack->pBuffer, gis, sizeof(GroupInvite_Struct));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -8853,7 +8904,7 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
|
||||
Message(Chat::LightGray, "You say, '%s'", response.c_str());
|
||||
}
|
||||
|
||||
ChannelMessageReceived(ChatChannel_Say, 0, 100, response.c_str(), nullptr, true);
|
||||
ChannelMessageReceived(ChatChannel_Say, Language::CommonTongue, Language::MaxValue, response.c_str(), nullptr, true);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -10716,7 +10767,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||
if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||
if (target != this && DistanceSquared(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||
mypet->SetFeigned(false);
|
||||
if (mypet->IsPetStop()) {
|
||||
mypet->SetPetStop(false);
|
||||
@@ -10842,7 +10893,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
// Set Sit button to unpressed - send stand anim/end hpregen
|
||||
mypet->SetFeigned(false);
|
||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
|
||||
mypet->SayString(this, Chat::PetResponse, PET_GUARDINGLIFE);
|
||||
mypet->SetPetOrder(SPO_Guard);
|
||||
@@ -10867,7 +10918,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
|
||||
// fix GUI sit button to be unpressed - send stand anim/end hpregen
|
||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
|
||||
if (mypet->IsPetStop()) {
|
||||
mypet->SetPetStop(false);
|
||||
@@ -10915,7 +10966,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
|
||||
// Set Sit button to unpressed - send stand anim/end hpregen
|
||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
|
||||
if (mypet->IsPetStop()) {
|
||||
mypet->SetPetStop(false);
|
||||
@@ -10933,7 +10984,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetFeigned(false);
|
||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -10943,7 +10994,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
|
||||
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_SIT);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Sitting);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -10956,7 +11007,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -10971,7 +11022,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
|
||||
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_SIT);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Sitting);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -11176,7 +11227,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetPetOrder(SPO_FeignDeath);
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
mypet->StopNavigation();
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
|
||||
mypet->SendAppearancePacket(AppearanceType::Animation, Animation::Lying);
|
||||
mypet->SetFeigned(true);
|
||||
mypet->SetTarget(nullptr);
|
||||
if (!mypet->UseBardSpellLogic()) {
|
||||
@@ -11564,7 +11615,7 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||
if (EntityVariableExists(DIAWIND_RESPONSE_ONE_KEY)) {
|
||||
response = GetEntityVariable(DIAWIND_RESPONSE_ONE_KEY);
|
||||
if (!response.empty()) {
|
||||
ChannelMessageReceived(ChatChannel_Say, 0, 100, response.c_str(), nullptr, true);
|
||||
ChannelMessageReceived(ChatChannel_Say, Language::CommonTongue, Language::MaxValue, response.c_str(), nullptr, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -11573,7 +11624,7 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||
if (EntityVariableExists(DIAWIND_RESPONSE_TWO_KEY)) {
|
||||
response = GetEntityVariable(DIAWIND_RESPONSE_TWO_KEY);
|
||||
if (!response.empty()) {
|
||||
ChannelMessageReceived(ChatChannel_Say, 0, 100, response.c_str(), nullptr, true);
|
||||
ChannelMessageReceived(ChatChannel_Say, Language::CommonTongue, Language::MaxValue, response.c_str(), nullptr, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -11671,7 +11722,7 @@ void Client::Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app)
|
||||
m_pp.raid_leadership_points -= cost;
|
||||
m_pp.leader_abilities.ranks[aaid]++;
|
||||
|
||||
database.SaveCharacterLeadershipAA(CharacterID(), &m_pp);
|
||||
database.SaveCharacterLeadershipAbilities(CharacterID(), &m_pp);
|
||||
}
|
||||
else {
|
||||
//it is a group ability.
|
||||
@@ -11684,7 +11735,7 @@ void Client::Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app)
|
||||
m_pp.group_leadership_points -= cost;
|
||||
m_pp.leader_abilities.ranks[aaid]++;
|
||||
|
||||
database.SaveCharacterLeadershipAA(CharacterID(), &m_pp);
|
||||
database.SaveCharacterLeadershipAbilities(CharacterID(), &m_pp);
|
||||
}
|
||||
|
||||
//success, send them an update
|
||||
@@ -11808,8 +11859,8 @@ void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->GetUCSHost().c_str(),
|
||||
Config->GetUCSPort(),
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
ConnectionType,
|
||||
@@ -11834,8 +11885,8 @@ void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->MailHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->GetUCSHost().c_str(),
|
||||
Config->GetUCSPort(),
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
ConnectionType,
|
||||
@@ -12044,6 +12095,13 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app)
|
||||
{
|
||||
auto player_sending_invite_group = player_sending_invite->GetGroup();
|
||||
Group* group = GetGroup();
|
||||
|
||||
/* Prevent scenario where player had joined group with Raid invitor before accepting Raid invite */
|
||||
if (group && group == player_sending_invite_group) {
|
||||
player_sending_invite->MessageString(Chat::Red, INVITE_GROUP_LEADER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (group) //if our target has a group
|
||||
{
|
||||
raid = new Raid(player_sending_invite);
|
||||
@@ -14247,14 +14305,14 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
if (sa->spawn_id != GetID())
|
||||
return;
|
||||
|
||||
if (sa->type == AT_Invis) {
|
||||
if (sa->type == AppearanceType::Invisibility) {
|
||||
if (sa->parameter != 0)
|
||||
{
|
||||
if (!HasSkill(EQ::skills::SkillHide) && GetSkill(EQ::skills::SkillHide) == 0)
|
||||
{
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::SoF)
|
||||
{
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AT_Invis [{}]", sa->parameter);
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AppearanceType::Invisibility [{}]", sa->parameter);
|
||||
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
|
||||
}
|
||||
}
|
||||
@@ -14266,18 +14324,18 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
entity_list.QueueClients(this, app, true);
|
||||
return;
|
||||
}
|
||||
else if (sa->type == AT_Anim) {
|
||||
else if (sa->type == AppearanceType::Animation) {
|
||||
if (IsAIControlled())
|
||||
return;
|
||||
|
||||
if (sa->parameter == ANIM_STAND) {
|
||||
if (sa->parameter == Animation::Standing) {
|
||||
SetAppearance(eaStanding);
|
||||
playeraction = 0;
|
||||
SetFeigned(false);
|
||||
BindWound(this, false, true);
|
||||
camp_timer.Disable();
|
||||
}
|
||||
else if (sa->parameter == ANIM_SIT) {
|
||||
else if (sa->parameter == Animation::Sitting) {
|
||||
SetAppearance(eaSitting);
|
||||
playeraction = 1;
|
||||
if (!UseBardSpellLogic())
|
||||
@@ -14287,19 +14345,19 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
tmSitting = Timer::GetCurrentTime();
|
||||
BuffFadeBySitModifier();
|
||||
}
|
||||
else if (sa->parameter == ANIM_CROUCH) {
|
||||
else if (sa->parameter == Animation::Crouching) {
|
||||
if (!UseBardSpellLogic())
|
||||
InterruptSpell();
|
||||
SetAppearance(eaCrouching);
|
||||
playeraction = 2;
|
||||
SetFeigned(false);
|
||||
}
|
||||
else if (sa->parameter == ANIM_DEATH) { // feign death too
|
||||
else if (sa->parameter == Animation::Lying) { // feign death too
|
||||
SetAppearance(eaDead);
|
||||
playeraction = 3;
|
||||
InterruptSpell();
|
||||
}
|
||||
else if (sa->parameter == ANIM_LOOT) {
|
||||
else if (sa->parameter == Animation::Looting) {
|
||||
SetAppearance(eaLooting);
|
||||
playeraction = 4;
|
||||
SetFeigned(false);
|
||||
@@ -14312,7 +14370,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
else if (sa->type == AT_Anon) {
|
||||
else if (sa->type == AppearanceType::Anonymous) {
|
||||
if (!anon_toggle_timer.Check()) {
|
||||
return;
|
||||
}
|
||||
@@ -14334,19 +14392,19 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
entity_list.QueueClients(this, app, true);
|
||||
UpdateWho();
|
||||
}
|
||||
else if ((sa->type == AT_HP) && (dead == 0)) {
|
||||
else if ((sa->type == AppearanceType::Health) && (dead == 0)) {
|
||||
return;
|
||||
}
|
||||
else if (sa->type == AT_AFK) {
|
||||
else if (sa->type == AppearanceType::AFK) {
|
||||
if (afk_toggle_timer.Check()) {
|
||||
AFK = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
}
|
||||
else if (sa->type == AT_Split) {
|
||||
else if (sa->type == AppearanceType::Split) {
|
||||
m_pp.autosplit = (sa->parameter == 1);
|
||||
}
|
||||
else if (sa->type == AT_Sneak) {
|
||||
else if (sa->type == AppearanceType::Sneak) {
|
||||
if (sneaking == 0)
|
||||
return;
|
||||
|
||||
@@ -14354,7 +14412,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!HasSkill(EQ::skills::SkillSneak))
|
||||
{
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AT_Sneak [{}]", sa->parameter);
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AppearanceType::Sneak [{}]", sa->parameter);
|
||||
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
|
||||
}
|
||||
return;
|
||||
@@ -14362,38 +14420,38 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
sneaking = 0;
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
else if (sa->type == AT_Size)
|
||||
else if (sa->type == AppearanceType::Size)
|
||||
{
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AT_Size [{}]", sa->parameter);
|
||||
auto message = fmt::format("Player sent OP_SpawnAppearance with AppearanceType::Size [{}]", sa->parameter);
|
||||
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
|
||||
}
|
||||
else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield)
|
||||
else if (sa->type == AppearanceType::Light) // client emitting light (lightstone, shiny shield)
|
||||
{
|
||||
//don't do anything with this
|
||||
}
|
||||
else if (sa->type == AT_Levitate)
|
||||
else if (sa->type == AppearanceType::FlyMode)
|
||||
{
|
||||
// don't do anything with this, we tell the client when it's
|
||||
// levitating, not the other way around
|
||||
}
|
||||
else if (sa->type == AT_ShowHelm)
|
||||
else if (sa->type == AppearanceType::ShowHelm)
|
||||
{
|
||||
if (helm_toggle_timer.Check()) {
|
||||
m_pp.showhelm = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
}
|
||||
else if (sa->type == AT_GroupConsent)
|
||||
else if (sa->type == AppearanceType::GroupAutoConsent)
|
||||
{
|
||||
m_pp.groupAutoconsent = (sa->parameter == 1);
|
||||
ConsentCorpses("Group", (sa->parameter != 1));
|
||||
}
|
||||
else if (sa->type == AT_RaidConsent)
|
||||
else if (sa->type == AppearanceType::RaidAutoConsent)
|
||||
{
|
||||
m_pp.raidAutoconsent = (sa->parameter == 1);
|
||||
ConsentCorpses("Raid", (sa->parameter != 1));
|
||||
}
|
||||
else if (sa->type == AT_GuildConsent)
|
||||
else if (sa->type == AppearanceType::GuildAutoConsent)
|
||||
{
|
||||
m_pp.guildAutoconsent = (sa->parameter == 1);
|
||||
ConsentCorpses("Guild", (sa->parameter != 1));
|
||||
@@ -14533,10 +14591,10 @@ void Client::Handle_OP_SwapSpell(const EQApplicationPacket *app)
|
||||
|
||||
/* Save Spell Swaps */
|
||||
if (!database.SaveCharacterSpell(CharacterID(), m_pp.spell_book[swapspell->from_slot], swapspell->from_slot)) {
|
||||
database.DeleteCharacterSpell(CharacterID(), m_pp.spell_book[swapspell->from_slot], swapspell->from_slot);
|
||||
database.DeleteCharacterSpell(CharacterID(), swapspell->from_slot);
|
||||
}
|
||||
if (!database.SaveCharacterSpell(CharacterID(), swapspelltemp, swapspell->to_slot)) {
|
||||
database.DeleteCharacterSpell(CharacterID(), swapspelltemp, swapspell->to_slot);
|
||||
database.DeleteCharacterSpell(CharacterID(), swapspell->to_slot);
|
||||
}
|
||||
|
||||
QueuePacket(app);
|
||||
@@ -15504,6 +15562,8 @@ void Client::Handle_OP_Translocate(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
entity_list.ClearAggro(this);
|
||||
|
||||
////Was sending the packet back to initiate client zone...
|
||||
////but that could be abusable, so lets go through proper channels
|
||||
MovePC(
|
||||
|
||||
+26
-14
@@ -572,7 +572,7 @@ bool Client::Process() {
|
||||
linkdead_timer.Start(RuleI(Zone, ClientLinkdeadMS));
|
||||
client_state = CLIENT_LINKDEAD;
|
||||
AI_Start(CLIENT_LD_TIMEOUT);
|
||||
SendAppearancePacket(AT_Linkdead, 1);
|
||||
SendAppearancePacket(AppearanceType::Linkdead, 1);
|
||||
|
||||
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::LinkDead);
|
||||
}
|
||||
@@ -763,10 +763,12 @@ void Client::BulkSendInventoryItems()
|
||||
}
|
||||
}
|
||||
|
||||
bool deletenorent = database.NoRentExpired(GetName());
|
||||
if (deletenorent) { //client was offline for more than 30 minutes, delete no rent items
|
||||
if (RuleB(Inventory, TransformSummonedBags))
|
||||
const bool delete_no_rent = database.NoRentExpired(GetName());
|
||||
if (delete_no_rent) { //client was offline for more than 30 minutes, delete no rent items
|
||||
if (RuleB(Inventory, TransformSummonedBags)) {
|
||||
DisenchantSummonedBags(false);
|
||||
}
|
||||
|
||||
RemoveNoRent(false);
|
||||
}
|
||||
|
||||
@@ -1184,10 +1186,10 @@ void Client::CancelSneakHide()
|
||||
if (hidden || improved_hidden) {
|
||||
auto app = new EQApplicationPacket(OP_CancelSneakHide, 0);
|
||||
FastQueuePacket(&app);
|
||||
// SoF and Tit send back a OP_SpawnAppearance turning off AT_Invis
|
||||
// SoF and Tit send back a OP_SpawnAppearance turning off AppearanceType::Invisibility
|
||||
// so we need to handle our sneaking flag only
|
||||
// The later clients send back a OP_Hide (this has a size but data is 0)
|
||||
// as well as OP_SpawnAppearance with AT_Invis and one with AT_Sneak
|
||||
// as well as OP_SpawnAppearance with AppearanceType::Invisibility and one with AppearanceType::Sneak
|
||||
// So we don't have to handle any of those flags
|
||||
if (ClientVersionBit() & EQ::versions::maskSoFAndEarlier)
|
||||
sneaking = false;
|
||||
@@ -1552,19 +1554,24 @@ void Client::OPGMTraining(const EQApplicationPacket *app)
|
||||
|
||||
Mob* pTrainer = entity_list.GetMob(gmtrain->npcid);
|
||||
|
||||
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM)
|
||||
if (!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM) {
|
||||
return;
|
||||
}
|
||||
|
||||
//you can only use your own trainer, client enforces this, but why trust it
|
||||
if (!RuleB(Character, AllowCrossClassTrainers)) {
|
||||
int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
|
||||
if (GetClass() != trains_class)
|
||||
if (GetClass() != trains_class) {
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//you have to be somewhat close to a trainer to be properly using them
|
||||
if(DistanceSquared(m_Position,pTrainer->GetPosition()) > USE_NPC_RANGE2)
|
||||
if (DistanceSquared(m_Position,pTrainer->GetPosition()) > USE_NPC_RANGE2) {
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
// if this for-loop acts up again (crashes linux), try enabling the before and after #pragmas
|
||||
//#pragma GCC push_options
|
||||
@@ -1657,7 +1664,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
// languages go here
|
||||
if (gmskill->skill_id > 25)
|
||||
{
|
||||
std::cout << "Wrong Training Skill (languages)" << std::endl;
|
||||
LogSkills("Wrong Training Skill (languages)");
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
@@ -1672,7 +1679,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
// normal skills go here
|
||||
if (gmskill->skill_id > EQ::skills::HIGHEST_SKILL)
|
||||
{
|
||||
std::cout << "Wrong Training Skill (abilities)" << std::endl;
|
||||
LogSkills("Wrong Training Skill (abilities)");
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
@@ -1691,11 +1698,12 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
|
||||
uint16 skilllevel = GetRawSkill(skill);
|
||||
|
||||
if(skilllevel == 0) {
|
||||
if (skilllevel == 0) {
|
||||
//this is a new skill..
|
||||
uint16 t_level = SkillTrainLevel(skill, GetClass());
|
||||
if (t_level == 0)
|
||||
{
|
||||
|
||||
if (t_level == 0) {
|
||||
LogSkills("Tried to train a new skill [{}] which is invalid for this race/class.", skill);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1715,6 +1723,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
case EQ::skills::SkillPottery:
|
||||
if(skilllevel >= RuleI(Skills, MaxTrainTradeskills)) {
|
||||
MessageString(Chat::Red, MORE_SKILLED_THAN_I, pTrainer->GetCleanName());
|
||||
SetSkill(skill, skilllevel);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -1725,6 +1734,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
case EQ::skills::SkillSpecializeEvocation:
|
||||
if(skilllevel >= RuleI(Skills, MaxTrainSpecializations)) {
|
||||
MessageString(Chat::Red, MORE_SKILLED_THAN_I, pTrainer->GetCleanName());
|
||||
SetSkill(skill, skilllevel);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
@@ -1736,6 +1746,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
{
|
||||
// Don't allow training over max skill level
|
||||
MessageString(Chat::Red, MORE_SKILLED_THAN_I, pTrainer->GetCleanName());
|
||||
SetSkill(skill, skilllevel);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1746,6 +1757,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
{
|
||||
// Restrict specialization training to follow the rules
|
||||
MessageString(Chat::Red, MORE_SKILLED_THAN_I, pTrainer->GetCleanName());
|
||||
SetSkill(skill, skilllevel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -100,6 +100,7 @@ int command_init(void)
|
||||
command_add("camerashake", "[Duration (Milliseconds)] [Intensity (1-10)] - Shakes the camera on everyone's screen globally.", AccountStatus::QuestTroupe, command_camerashake) ||
|
||||
command_add("castspell", "[Spell ID] [Instant (0 = False, 1 = True, Default is 1 if Unused)] - Cast a spell", AccountStatus::Guide, command_castspell) ||
|
||||
command_add("chat", "[Channel ID] [Message] - Send a channel message to all zones", AccountStatus::GMMgmt, command_chat) ||
|
||||
command_add("clearxtargets", "Clears XTargets", AccountStatus::Player, command_clearxtargets) ||
|
||||
command_add("copycharacter", "[source_char_name] [dest_char_name] [dest_account_name] - Copies character to destination account", AccountStatus::GMImpossible, command_copycharacter) ||
|
||||
command_add("corpse", "Manipulate corpses, use with no arguments for help", AccountStatus::Guide, command_corpse) ||
|
||||
command_add("corpsefix", "Attempts to bring corpses from underneath the ground within close proximity of the player", AccountStatus::Player, command_corpsefix) ||
|
||||
@@ -238,7 +239,6 @@ int command_init(void)
|
||||
command_add("zonebootup", "[ZoneServerID] [shortname] - Make a zone server boot a specific zone", AccountStatus::GMLeadAdmin, command_zonebootup) ||
|
||||
command_add("zoneinstance", "[Instance ID] [X] [Y] [Z] - Teleport to specified Instance by ID (coordinates are optional)", AccountStatus::Guide, command_zone_instance) ||
|
||||
command_add("zoneshutdown", "[shortname] - Shut down a zone server", AccountStatus::GMLeadAdmin, command_zoneshutdown) ||
|
||||
command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", AccountStatus::GMImpossible, command_zopp) ||
|
||||
command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave)
|
||||
) {
|
||||
command_deinit();
|
||||
@@ -792,6 +792,7 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/camerashake.cpp"
|
||||
#include "gm_commands/castspell.cpp"
|
||||
#include "gm_commands/chat.cpp"
|
||||
#include "gm_commands/clearxtargets.cpp"
|
||||
#include "gm_commands/copycharacter.cpp"
|
||||
#include "gm_commands/corpse.cpp"
|
||||
#include "gm_commands/corpsefix.cpp"
|
||||
@@ -925,5 +926,4 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/zonebootup.cpp"
|
||||
#include "gm_commands/zoneshutdown.cpp"
|
||||
#include "gm_commands/zone_instance.cpp"
|
||||
#include "gm_commands/zopp.cpp"
|
||||
#include "gm_commands/zsave.cpp"
|
||||
|
||||
@@ -35,6 +35,8 @@ void SendNPCEditSubCommands(Client *c);
|
||||
void SendRuleSubCommands(Client *c);
|
||||
void SendGuildSubCommands(Client *c);
|
||||
void SendShowInventorySubCommands(Client *c);
|
||||
void SendFixMobSubCommands(Client *c);
|
||||
void SendDataBucketsSubCommands(Client *c);
|
||||
|
||||
// Commands
|
||||
void command_acceptrules(Client *c, const Seperator *sep);
|
||||
@@ -51,6 +53,7 @@ void command_bugs(Client *c, const Seperator *sep);
|
||||
void command_camerashake(Client *c, const Seperator *sep);
|
||||
void command_castspell(Client *c, const Seperator *sep);
|
||||
void command_chat(Client *c, const Seperator *sep);
|
||||
void command_clearxtargets(Client *c, const Seperator *sep);
|
||||
void command_copycharacter(Client *c, const Seperator *sep);
|
||||
void command_corpse(Client *c, const Seperator *sep);
|
||||
void command_corpsefix(Client *c, const Seperator *sep);
|
||||
|
||||
+1
-1
@@ -927,7 +927,7 @@ void Corpse::RemoveItem(ServerLootItem_Struct* item_data)
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
SendAppearancePacket(AppearanceType::Light, GetActiveLightType());
|
||||
|
||||
safe_delete(sitem);
|
||||
return;
|
||||
|
||||
+45
-12
@@ -60,15 +60,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
bool Critical = false;
|
||||
int64 base_value = value;
|
||||
int chance = 0;
|
||||
|
||||
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
|
||||
if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
|
||||
value -= (GetLevel() - 40) * 20;
|
||||
|
||||
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBot()) { //Improved Harm Touch
|
||||
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
|
||||
}
|
||||
int legacy_manaburn_cap = RuleI(Spells, LegacyManaburnCap);
|
||||
|
||||
chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level)
|
||||
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
|
||||
@@ -138,12 +130,30 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value) * ratio / 100;
|
||||
}
|
||||
|
||||
// legacy manaburn can crit, but is still held to the same cap
|
||||
if (RuleB(Spells, LegacyManaburn) && spell_id == SPELL_MANA_BURN) {
|
||||
if (value < -legacy_manaburn_cap) {
|
||||
value = -legacy_manaburn_cap;
|
||||
}
|
||||
}
|
||||
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, true, 100, Chat::SpellCrit, FilterSpellCrits,
|
||||
OTHER_CRIT_BLAST, nullptr, GetName(), itoa(-value));
|
||||
|
||||
if (IsClient())
|
||||
if (IsClient()) {
|
||||
MessageString(Chat::SpellCrit, YOU_CRIT_BLAST, itoa(-value));
|
||||
}
|
||||
|
||||
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
|
||||
if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH) && GetLevel() > 40) {
|
||||
value -= (GetLevel() - 40) * 20;
|
||||
}
|
||||
|
||||
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm Touch.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && IsOfClientBot()) { //Improved Harm Touch
|
||||
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -183,6 +193,13 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
value -= GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value);
|
||||
}
|
||||
|
||||
// Apply Manaburn Damage Cap
|
||||
if (RuleB(Spells, LegacyManaburn) && spell_id == SPELL_MANA_BURN) {
|
||||
if (value < -legacy_manaburn_cap) {
|
||||
value = -legacy_manaburn_cap;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -592,6 +609,22 @@ int32 Mob::GetActSpellCost(uint16 spell_id, int32 cost)
|
||||
|
||||
int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
{
|
||||
// focuses don't affect discipline duration (Except War Cries)
|
||||
if (
|
||||
IsDiscipline(spell_id) &&
|
||||
(
|
||||
spell_id != SPELL_BATTLE_CRY &&
|
||||
spell_id != SPELL_WAR_CRY &&
|
||||
spell_id != SPELL_BATTLE_CRY_OF_DRAVEL &&
|
||||
spell_id != SPELL_WAR_CRY_OF_DRAVEL &&
|
||||
spell_id != SPELL_BATTLE_CRY_OF_THE_MASTRUQ &&
|
||||
spell_id != SPELL_ANCIENT_CRY_OF_CHAOS &&
|
||||
spell_id != SPELL_BLOODTHIRST
|
||||
)
|
||||
) {
|
||||
return duration;
|
||||
}
|
||||
|
||||
int increase = 100;
|
||||
increase += GetFocusEffect(focusSpellDuration, spell_id);
|
||||
int tic_inc = 0;
|
||||
@@ -690,7 +723,7 @@ bool Client::TrainDiscipline(uint32 itemid) {
|
||||
return false;
|
||||
} else if (m_pp.disciplines.values[r] == 0) {
|
||||
m_pp.disciplines.values[r] = spell_id;
|
||||
database.SaveCharacterDisc(CharacterID(), r, spell_id);
|
||||
database.SaveCharacterDiscipline(CharacterID(), r, spell_id);
|
||||
SendDisciplineUpdate();
|
||||
Message(Chat::White, "You have learned a new discipline!");
|
||||
return true;
|
||||
@@ -789,7 +822,7 @@ void Client::TrainDiscBySpellID(int32 spell_id)
|
||||
for(i = 0; i < MAX_PP_DISCIPLINES; i++) {
|
||||
if(m_pp.disciplines.values[i] == 0) {
|
||||
m_pp.disciplines.values[i] = spell_id;
|
||||
database.SaveCharacterDisc(CharacterID(), i, spell_id);
|
||||
database.SaveCharacterDiscipline(CharacterID(), i, spell_id);
|
||||
SendDisciplineUpdate();
|
||||
Message(Chat::Yellow, "You have learned a new combat ability!");
|
||||
return;
|
||||
|
||||
+1
-1
@@ -1891,6 +1891,7 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
|
||||
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
ExportVar(package_name.c_str(), "killed_entity_id", sep.arg[4]);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() >= 1) {
|
||||
Corpse *corpse = std::any_cast<Corpse *>(extra_pointers->at(0));
|
||||
@@ -1902,7 +1903,6 @@ void PerlembParser::ExportEventVariables(
|
||||
if (extra_pointers && extra_pointers->size() >= 2) {
|
||||
NPC *killed = std::any_cast<NPC *>(extra_pointers->at(1));
|
||||
if (killed) {
|
||||
ExportVar(package_name.c_str(), "killed_entity_id", killed->GetID());
|
||||
ExportVar(package_name.c_str(), "killed_bot_id", killed->IsBot() ? killed->CastToBot()->GetBotID() : 0);
|
||||
ExportVar(package_name.c_str(), "killed_npc_id", killed->IsNPC() ? killed->GetNPCTypeID() : 0);
|
||||
ExportVar(package_name.c_str(), "killed_x", killed->GetX());
|
||||
|
||||
+12
-12
@@ -93,13 +93,13 @@ void Perl__say(const char* message)
|
||||
// we currently default to these
|
||||
opts.speak_mode = Journal::SpeakMode::Say;
|
||||
opts.journal_mode = Journal::Mode::Log2;
|
||||
opts.language = 0;
|
||||
opts.language = Language::CommonTongue;
|
||||
opts.message_type = Chat::NPCQuestSay;
|
||||
|
||||
quest_manager.say(message, opts);
|
||||
}
|
||||
|
||||
void Perl__say(const char* message, int language_id)
|
||||
void Perl__say(const char* message, uint8 language_id)
|
||||
{
|
||||
Journal::Options opts;
|
||||
opts.speak_mode = Journal::SpeakMode::Say;
|
||||
@@ -110,7 +110,7 @@ void Perl__say(const char* message, int language_id)
|
||||
quest_manager.say(message, opts);
|
||||
}
|
||||
|
||||
void Perl__say(const char* message, int language_id, int message_type)
|
||||
void Perl__say(const char* message, uint8 language_id, int message_type)
|
||||
{
|
||||
Journal::Options opts;
|
||||
opts.speak_mode = Journal::SpeakMode::Say;
|
||||
@@ -121,7 +121,7 @@ void Perl__say(const char* message, int language_id, int message_type)
|
||||
quest_manager.say(message, opts);
|
||||
}
|
||||
|
||||
void Perl__say(const char* message, int language_id, int message_type, int speak_mode)
|
||||
void Perl__say(const char* message, uint8 language_id, int message_type, int speak_mode)
|
||||
{
|
||||
Journal::Options opts;
|
||||
opts.speak_mode = static_cast<Journal::SpeakMode>(speak_mode);
|
||||
@@ -132,7 +132,7 @@ void Perl__say(const char* message, int language_id, int message_type, int speak
|
||||
quest_manager.say(message, opts);
|
||||
}
|
||||
|
||||
void Perl__say(const char* message, int language_id, int message_type, int speak_mode, int journal_mode)
|
||||
void Perl__say(const char* message, uint8 language_id, int message_type, int speak_mode, int journal_mode)
|
||||
{
|
||||
Journal::Options opts;
|
||||
opts.speak_mode = static_cast<Journal::SpeakMode>(speak_mode);
|
||||
@@ -674,9 +674,9 @@ void Perl__addskill(int skill_id, int value)
|
||||
quest_manager.addskill(skill_id, value);
|
||||
}
|
||||
|
||||
void Perl__setlanguage(int skill_id, int value)
|
||||
void Perl__setlanguage(uint8 language_id, uint8 language_skill)
|
||||
{
|
||||
quest_manager.setlanguage(skill_id, value);
|
||||
quest_manager.setlanguage(language_id, language_skill);
|
||||
}
|
||||
|
||||
void Perl__setskill(int skill_id, int value)
|
||||
@@ -4713,7 +4713,7 @@ std::string Perl__getfactionname(int faction_id)
|
||||
return quest_manager.getfactionname(faction_id);
|
||||
}
|
||||
|
||||
std::string Perl__getlanguagename(int language_id)
|
||||
std::string Perl__getlanguagename(uint8 language_id)
|
||||
{
|
||||
return quest_manager.getlanguagename(language_id);
|
||||
}
|
||||
@@ -6532,10 +6532,10 @@ void perl_register_quest()
|
||||
package.add("safemove", &Perl__safemove);
|
||||
package.add("save", &Perl__save);
|
||||
package.add("say", (void(*)(const char*))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, int, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, int, int, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, int, int, int, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8, int, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8, int, int, int))&Perl__say);
|
||||
package.add("saylink", (std::string(*)(const char*))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(const char*, bool))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(const char*, bool, const char*))&Perl__saylink);
|
||||
|
||||
+3
-3
@@ -37,9 +37,9 @@ Encounter::Encounter(const char *enc_name) : 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
|
||||
|
||||
+45
-21
@@ -1282,7 +1282,7 @@ uint16 EntityList::GetFreeID()
|
||||
// if no language skill is specified, sent with 100 skill
|
||||
void EntityList::ChannelMessage(Mob *from, uint8 chan_num, uint8 language, const char *message, ...)
|
||||
{
|
||||
ChannelMessage(from, chan_num, language, 100, message);
|
||||
ChannelMessage(from, chan_num, language, Language::MaxValue, message);
|
||||
}
|
||||
|
||||
void EntityList::ChannelMessage(Mob *from, uint8 chan_num, uint8 language,
|
||||
@@ -1411,7 +1411,7 @@ void EntityList::SendZonePVPUpdates(Client *to)
|
||||
while (it != client_list.end()) {
|
||||
Client *c = it->second;
|
||||
if(c->GetPVP())
|
||||
c->SendAppearancePacket(AT_PVP, c->GetPVP(), true, false, to);
|
||||
c->SendAppearancePacket(AppearanceType::PVP, c->GetPVP(), true, false, to);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -1491,18 +1491,21 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets)
|
||||
Mob *m = it->second;
|
||||
++it;
|
||||
|
||||
if (!m)
|
||||
if (!m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RemoveFromXTargets && mob) {
|
||||
if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m)))
|
||||
if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m))) {
|
||||
m->CastToClient()->RemoveXTarget(mob, false);
|
||||
// FadingMemories calls this function passing the client.
|
||||
else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob)))
|
||||
} else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob))) {
|
||||
mob->CastToClient()->RemoveXTarget(m, false);
|
||||
}
|
||||
}
|
||||
|
||||
m->RemoveFromHateList(mob);
|
||||
m->RemoveFromRampageList(mob);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1515,20 +1518,24 @@ void EntityList::RemoveFromTargetsFadingMemories(Mob *spell_target, bool RemoveF
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_level && mob->GetLevel() > max_level)
|
||||
if (max_level && mob->GetLevel() > max_level) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->GetSpecialAbility(IMMUNE_FADING_MEMORIES))
|
||||
if (mob->GetSpecialAbility(IMMUNE_FADING_MEMORIES)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RemoveFromXTargets && spell_target) {
|
||||
if (mob->IsClient() && (spell_target->CheckAggro(mob) || spell_target->IsOnFeignMemory(mob)))
|
||||
if (mob->IsClient() && (spell_target->CheckAggro(mob) || spell_target->IsOnFeignMemory(mob))) {
|
||||
mob->CastToClient()->RemoveXTarget(spell_target, false);
|
||||
else if (spell_target->IsClient() && (mob->CheckAggro(spell_target) || mob->IsOnFeignMemory(spell_target)))
|
||||
} else if (spell_target->IsClient() && (mob->CheckAggro(spell_target) || mob->IsOnFeignMemory(spell_target))) {
|
||||
spell_target->CastToClient()->RemoveXTarget(mob, false);
|
||||
}
|
||||
}
|
||||
|
||||
mob->RemoveFromHateList(spell_target);
|
||||
mob->RemoveFromRampageList(spell_target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1814,14 +1821,14 @@ void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee)
|
||||
}
|
||||
}
|
||||
|
||||
Client *EntityList::GetClientByName(const char *checkname)
|
||||
Client *EntityList::GetClientByName(const char* name)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
if (strcasecmp(it->second->GetName(), checkname) == 0)
|
||||
return it->second;
|
||||
++it;
|
||||
for (const auto& e : client_list) {
|
||||
if (e.second && Strings::EqualFold(e.second->GetName(), name)) {
|
||||
return e.second;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -3188,8 +3195,10 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
|
||||
if (it->second->CheckAggro(mob)) {
|
||||
if (!settoone) {
|
||||
it->second->RemoveFromHateList(mob);
|
||||
if (mob->IsClient())
|
||||
it->second->RemoveFromRampageList(mob);
|
||||
if (mob->IsClient()) {
|
||||
mob->CastToClient()->RemoveXTarget(it->second, false); // gotta do book keeping
|
||||
}
|
||||
} else {
|
||||
it->second->SetHateAmountOnEnt(mob, 1);
|
||||
}
|
||||
@@ -3536,20 +3545,29 @@ void EntityList::HalveAggro(Mob *who)
|
||||
}
|
||||
|
||||
//removes "targ" from all hate lists, including feigned, in the zone
|
||||
void EntityList::ClearAggro(Mob* targ)
|
||||
void EntityList::ClearAggro(Mob* targ, bool clear_caster_id)
|
||||
{
|
||||
Client *c = nullptr;
|
||||
|
||||
if (targ->IsClient()) {
|
||||
c = targ->CastToClient();
|
||||
}
|
||||
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
if (clear_caster_id) {
|
||||
it->second->BuffDetachCaster(targ);
|
||||
}
|
||||
|
||||
if (it->second->CheckAggro(targ)) {
|
||||
if (c) {
|
||||
c->RemoveXTarget(it->second, false);
|
||||
}
|
||||
|
||||
it->second->RemoveFromHateList(targ);
|
||||
it->second->RemoveFromRampageList(targ, true);
|
||||
}
|
||||
|
||||
if (c && it->second->IsOnFeignMemory(c)) {
|
||||
it->second->RemoveFromFeignMemory(c); //just in case we feigned
|
||||
c->RemoveXTarget(it->second, false);
|
||||
@@ -3573,6 +3591,7 @@ void EntityList::ClearWaterAggro(Mob* targ)
|
||||
c->RemoveXTarget(it->second, false);
|
||||
}
|
||||
it->second->RemoveFromHateList(targ);
|
||||
it->second->RemoveFromRampageList(targ);
|
||||
}
|
||||
if (c && it->second->IsOnFeignMemory(c)) {
|
||||
it->second->RemoveFromFeignMemory(c); //just in case we feigned
|
||||
@@ -3618,6 +3637,11 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
||||
}
|
||||
|
||||
it->second->RemoveFromHateList(targ);
|
||||
|
||||
if (it->second->GetSpecialAbility(SPECATK_RAMPAGE)) {
|
||||
it->second->RemoveFromRampageList(targ, true);
|
||||
}
|
||||
|
||||
if (targ->IsClient()) {
|
||||
if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) {
|
||||
it->second->AddFeignMemory(targ);
|
||||
@@ -4588,7 +4612,7 @@ void EntityList::GroupMessage(uint32 gid, const char *from, const char *message)
|
||||
g = it->second->GetGroup();
|
||||
if (g) {
|
||||
if (g->GetID() == gid)
|
||||
it->second->ChannelMessageSend(from, it->second->GetName(), ChatChannel_Group, 0, 100, message);
|
||||
it->second->ChannelMessageSend(from, it->second->GetName(), ChatChannel_Group, Language::CommonTongue, Language::MaxValue, message);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
@@ -4704,10 +4728,10 @@ void EntityList::SendZoneAppearance(Client *c)
|
||||
continue;
|
||||
}
|
||||
if (cur->GetAppearance() != eaStanding) {
|
||||
cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c);
|
||||
cur->SendAppearancePacket(AppearanceType::Animation, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c);
|
||||
}
|
||||
if (cur->GetSize() != cur->GetBaseSize()) {
|
||||
cur->SendAppearancePacket(AT_Size, (uint32) cur->GetSize(), false, true, c);
|
||||
cur->SendAppearancePacket(AppearanceType::Size, (uint32) cur->GetSize(), false, true, c);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
@@ -4781,7 +4805,7 @@ void EntityList::SendAppearanceEffects(Client *c)
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
cur->SendSavedAppearenceEffects(c);
|
||||
cur->SendSavedAppearanceEffects(c);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
+2
-2
@@ -171,7 +171,7 @@ public:
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
Client *GetClientByName(const char *name);
|
||||
Client *GetClientByName(const char* name);
|
||||
Client *GetClientByAccID(uint32 accid);
|
||||
inline Client *GetClientByID(uint16 id)
|
||||
{
|
||||
@@ -463,7 +463,7 @@ public:
|
||||
void UpdateHoTT(Mob* target);
|
||||
|
||||
void Process();
|
||||
void ClearAggro(Mob* targ);
|
||||
void ClearAggro(Mob* targ, bool clear_caster_id = false);
|
||||
void ClearWaterAggro(Mob* targ);
|
||||
void ClearFeignAggro(Mob* targ);
|
||||
void ClearZoneFeignAggro(Mob* targ);
|
||||
|
||||
@@ -1,60 +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
|
||||
|
||||
+1
-1
@@ -950,7 +950,7 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
SendAppearancePacket(AT_WhoLevel, set_level); // who level change
|
||||
SendAppearancePacket(AppearanceType::WhoLevel, set_level); // who level change
|
||||
|
||||
LogInfo("Setting Level for [{}] to [{}]", GetName(), set_level);
|
||||
|
||||
|
||||
+1
-1
@@ -1171,7 +1171,7 @@ bool Expedition::HasLockoutByCharacterID(
|
||||
{
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(character_id);
|
||||
return std::any_of(lockouts.begin(), lockouts.end(), [&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.IsSameLockout(expedition_name, event_name);
|
||||
return !lockout.IsExpired() && lockout.IsSameLockout(expedition_name, event_name);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ void command_acceptrules(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
database.SetAgreementFlag(c->AccountID());
|
||||
c->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
c->SendAppearancePacket(AppearanceType::Animation, Animation::Standing);
|
||||
c->Message(Chat::White, "It is recorded you have agreed to the rules.");
|
||||
}
|
||||
|
||||
@@ -2,25 +2,43 @@
|
||||
|
||||
void command_appearance(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *t = c->CastToMob();
|
||||
const int arguments = sep->argnum;
|
||||
if (!arguments || !sep->IsNumber(1) || !sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #appearance [Type] [Value]");
|
||||
c->Message(Chat::White, "Note: Types are as follows:");
|
||||
|
||||
// sends any appearance packet
|
||||
// Dev debug command, for appearance types
|
||||
if (sep->arg[2][0] == 0) {
|
||||
c->Message(Chat::White, "Usage: #appearance type value");
|
||||
}
|
||||
else {
|
||||
if ((c->GetTarget())) {
|
||||
t = c->GetTarget();
|
||||
for (const auto& a : EQ::constants::GetAppearanceTypeMap()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Appearance Type {} | {}",
|
||||
a.first,
|
||||
a.second
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
t->SendAppearancePacket(Strings::ToInt(sep->arg[1]), Strings::ToInt(sep->arg[2]));
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Sending appearance packet: target=%s, type=%s, value=%s",
|
||||
t->GetName(),
|
||||
sep->arg[1],
|
||||
sep->arg[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Mob *t = c;
|
||||
if (c->GetTarget()) {
|
||||
t = c->GetTarget();
|
||||
}
|
||||
|
||||
const uint32 type = Strings::ToUnsignedInt(sep->arg[1]);
|
||||
const uint32 value = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
|
||||
t->SendAppearancePacket(type, value);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Appearance Sent to {} | Type: {} ({}) Value: {}",
|
||||
c->GetTargetDescription(t, TargetDescriptionType::UCSelf),
|
||||
EQ::constants::GetAppearanceTypeName(type),
|
||||
type,
|
||||
value
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ void command_appearanceeffects(Client *c, const Seperator *sep)
|
||||
.texture = t->GetTexture(),
|
||||
}
|
||||
);
|
||||
t->ClearAppearenceEffects();
|
||||
t->ClearAppearanceEffects();
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user