mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-30 15:55:45 +00:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
+146
@@ -1,3 +1,149 @@
|
||||
## [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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,8 @@ 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,
|
||||
@@ -5154,7 +5160,8 @@ ALTER TABLE `npc_emotes` DROP INDEX `emoteid`;
|
||||
.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;
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "dbcore.h"
|
||||
|
||||
#include <errmsg.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mysqld_error.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -430,6 +433,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 +469,12 @@ 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_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_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
@@ -508,6 +521,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 +554,7 @@ 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_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
@@ -593,6 +610,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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.39.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.40.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__
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.39.0",
|
||||
"version": "22.40.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
+123
-90
@@ -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;
|
||||
}
|
||||
@@ -2705,68 +2706,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 +2817,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 +2858,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;
|
||||
}
|
||||
|
||||
@@ -3805,6 +3811,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 +3917,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 +4038,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 +4188,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 +4198,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 +5041,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 +5209,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 +5220,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 +5262,7 @@ bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||
GetCleanName() /* Message1 */
|
||||
);
|
||||
|
||||
damage = FB_Dmg;
|
||||
damage = finishing_blow_damage;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+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
|
||||
|
||||
+168
-109
@@ -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;
|
||||
|
||||
@@ -4326,6 +4329,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 +4516,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 +4899,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 +5070,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 +5787,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 +6250,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 +6505,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 +6622,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 +7336,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 +8903,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;
|
||||
}
|
||||
@@ -10842,7 +10892,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 +10917,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 +10965,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 +10983,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 +10993,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 +11006,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 +11021,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 +11226,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 +11614,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 +11623,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 +11721,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 +11734,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 +11858,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 +11884,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 +12094,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 +14304,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 +14323,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 +14344,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 +14369,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 +14391,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 +14411,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 +14419,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 +14590,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 +15561,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;
|
||||
|
||||
+18
-2
@@ -592,6 +592,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 +706,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 +805,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);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -13,7 +13,7 @@ void command_chat(Client *c, const Seperator *sep)
|
||||
|
||||
auto channel_id = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[1]));
|
||||
std::string message = sep->argplus[2];
|
||||
if (!worldserver.SendChannelMessage(0, 0, channel_id, 0, 0, 100, message.c_str())) {
|
||||
if (!worldserver.SendChannelMessage(0, 0, channel_id, 0, Language::CommonTongue, Language::MaxValue, message.c_str())) {
|
||||
c->Message(Chat::White, "World server is disconnected.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "../client.h"
|
||||
|
||||
void command_clearxtargets(Client *c, const Seperator *sep)
|
||||
{
|
||||
const int reuse_timer = RuleI(Character, ClearXTargetDelay);
|
||||
|
||||
const int arguments = sep->argnum;
|
||||
if (arguments) {
|
||||
const bool is_help = !strcasecmp(sep->arg[1], "help");
|
||||
|
||||
if (is_help) {
|
||||
c->Message(Chat::White, "Usage: #clearxtargets");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Note: Use this if your Extended Target window is bugged or has lingering targets that are invalid."
|
||||
);
|
||||
if (reuse_timer) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Note: This can only be used every {}.",
|
||||
Strings::SecondsToTime(reuse_timer)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (reuse_timer) {
|
||||
const uint32 time_left = c->GetPTimers().GetRemainingTime(pTimerClearXTarget);
|
||||
if (!c->GetPTimers().Expired(&database, pTimerClearXTarget, false)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"You must wait {} before using this command again.",
|
||||
Strings::SecondsToTime(time_left)
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
c->ClearXTargets();
|
||||
c->Message(Chat::White, "Extended Target window has been cleared.");
|
||||
|
||||
if (reuse_timer) {
|
||||
c->GetPTimers().Start(pTimerClearXTarget, reuse_timer);
|
||||
}
|
||||
}
|
||||
@@ -1,92 +1,262 @@
|
||||
#include "../client.h"
|
||||
#include "../data_bucket.h"
|
||||
#include "../dialogue_window.h"
|
||||
#include "../../common/repositories/data_buckets_repository.h"
|
||||
|
||||
void command_databuckets(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == 0) {
|
||||
c->Message(Chat::Yellow, "Usage: #databuckets view (partial key)|(limit) OR #databuckets delete (key)");
|
||||
const int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
SendDataBucketsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(sep->arg[1], "view") == 0) {
|
||||
|
||||
std::string key_filter;
|
||||
uint8 limit = 50;
|
||||
for (int i = 2; i < 4; i++) {
|
||||
if (sep->arg[i][0] == '\0') {
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(sep->arg[i], "limit") == 0) {
|
||||
limit = (uint8) Strings::ToInt(sep->arg[i + 1]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sep->arg[2]) {
|
||||
key_filter = Strings::ToLower(sep->arg[2]);
|
||||
}
|
||||
std::string query = "SELECT `id`, `key`, `value`, `expires` FROM data_buckets";
|
||||
if (!key_filter.empty()) { query += StringFormat(" WHERE `key` LIKE '%%%s%%'", key_filter.c_str()); }
|
||||
query += StringFormat(" LIMIT %u", limit);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
const bool is_delete = !strcasecmp(sep->arg[1], "delete");
|
||||
const bool is_edit = !strcasecmp(sep->arg[1], "edit");
|
||||
const bool is_view = !strcasecmp(sep->arg[1], "view");
|
||||
|
||||
if (
|
||||
!is_delete &&
|
||||
!is_edit &&
|
||||
!is_view
|
||||
) {
|
||||
SendDataBucketsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_delete) {
|
||||
if (arguments < 2) {
|
||||
SendDataBucketsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
if (results.RowCount() == 0) {
|
||||
c->Message(Chat::Yellow, "No data_buckets found");
|
||||
return;
|
||||
}
|
||||
int _ctr = 0;
|
||||
// put in window for easier readability in case want command line for something else
|
||||
std::string window_title = "Data Buckets";
|
||||
std::string window_text =
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td>ID</td>"
|
||||
"<td>Expires</td>"
|
||||
"<td>Key</td>"
|
||||
"<td>Value</td>"
|
||||
"</tr>";
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
auto id = static_cast<uint32>(Strings::ToInt(row[0]));
|
||||
std::string key = row[1];
|
||||
std::string value = row[2];
|
||||
std::string expires = row[3];
|
||||
window_text.append(
|
||||
StringFormat(
|
||||
"<tr>"
|
||||
"<td>%u</td>"
|
||||
"<td>%s</td>"
|
||||
"<td>%s</td>"
|
||||
"<td>%s</td>"
|
||||
"</tr>",
|
||||
id,
|
||||
expires.c_str(),
|
||||
key.c_str(),
|
||||
value.c_str()
|
||||
));
|
||||
_ctr++;
|
||||
std::string del_saylink = StringFormat("#databuckets delete %s", key.c_str());
|
||||
|
||||
const std::string& key_filter = sep->arg[2];
|
||||
|
||||
const uint32 character_id = sep->IsNumber(3) ? Strings::ToUnsignedInt(sep->arg[3]) : 0;
|
||||
const uint32 npc_id = sep->IsNumber(4) ? Strings::ToUnsignedInt(sep->arg[4]) : 0;
|
||||
const uint32 bot_id = sep->IsNumber(5) ? Strings::ToUnsignedInt(sep->arg[5]) : 0;
|
||||
|
||||
if (
|
||||
!character_id &&
|
||||
!npc_id &&
|
||||
!bot_id
|
||||
) {
|
||||
if (!DataBucket::DeleteData(key_filter)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"An error occurred deleting data bucket '{}'.",
|
||||
key_filter
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"%s : %s",
|
||||
Saylink::Silent(del_saylink, "Delete").c_str(),
|
||||
key.c_str(),
|
||||
" Value: ",
|
||||
value.c_str());
|
||||
fmt::format(
|
||||
"Data bucket '{}' deleted.",
|
||||
key_filter
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
DataBucketKey k = {};
|
||||
|
||||
k.key = key_filter;
|
||||
k.character_id = character_id;
|
||||
k.npc_id = npc_id;
|
||||
k.bot_id = bot_id;
|
||||
|
||||
if (!DataBucket::DeleteData(k)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"An error occurred deleting data bucket '{}'.",
|
||||
key_filter
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Data bucket '{}' deleted.",
|
||||
key_filter
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
window_text.append("</table>");
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
std::string response = _ctr > 0 ? StringFormat("Found %i matching data buckets", _ctr).c_str()
|
||||
: "No Databuckets found.";
|
||||
c->Message(Chat::Yellow, response.c_str());
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "delete") == 0) {
|
||||
if (DataBucket::DeleteData(sep->argplus[2])) {
|
||||
c->Message(Chat::Yellow, "data bucket %s deleted.", sep->argplus[2]);
|
||||
} else if (is_edit) {
|
||||
if (arguments < 6) {
|
||||
SendDataBucketsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::Red, "An error occurred deleting data bucket %s", sep->argplus[2]);
|
||||
|
||||
const std::string& key_filter = sep->arg[2];
|
||||
const std::string& value = sep->arg[6];
|
||||
|
||||
const uint32 character_id = sep->IsNumber(3) ? Strings::ToUnsignedInt(sep->arg[3]) : 0;
|
||||
const uint32 npc_id = sep->IsNumber(4) ? Strings::ToUnsignedInt(sep->arg[4]) : 0;
|
||||
const uint32 bot_id = sep->IsNumber(5) ? Strings::ToUnsignedInt(sep->arg[5]) : 0;
|
||||
const uint32 expires = arguments > 6 && sep->IsNumber(7) ? Strings::ToUnsignedInt(sep->arg[7]) : 0;
|
||||
|
||||
DataBucketKey k = {};
|
||||
|
||||
k.key = key_filter;
|
||||
k.character_id = character_id;
|
||||
k.npc_id = npc_id;
|
||||
k.bot_id = bot_id;
|
||||
k.value = value;
|
||||
|
||||
if (arguments > 6) {
|
||||
k.expires = expires;
|
||||
}
|
||||
return;
|
||||
|
||||
const std::string& expires_string = expires == 0 ? "Never" : std::to_string(expires);
|
||||
|
||||
DataBucket::SetData(k);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Bucket Edited | Key: {} Value: {} Expires: {} Character ID: {} NPC ID: {} Bot ID: {}",
|
||||
key_filter,
|
||||
value,
|
||||
expires_string,
|
||||
character_id,
|
||||
npc_id,
|
||||
bot_id
|
||||
).c_str()
|
||||
);
|
||||
} else if (is_view) {
|
||||
if (arguments < 2) {
|
||||
SendDataBucketsSubCommands(c);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& key_filter = sep->arg[2];
|
||||
|
||||
const uint32 character_id = sep->IsNumber(3) ? Strings::ToUnsignedInt(sep->arg[3]) : 0;
|
||||
const uint32 npc_id = sep->IsNumber(4) ? Strings::ToUnsignedInt(sep->arg[4]) : 0;
|
||||
const uint32 bot_id = sep->IsNumber(5) ? Strings::ToUnsignedInt(sep->arg[5]) : 0;
|
||||
|
||||
std::string where_filter = fmt::format(
|
||||
"`key` LIKE '%{}%'",
|
||||
Strings::Escape(key_filter)
|
||||
);
|
||||
|
||||
if (character_id) {
|
||||
where_filter += fmt::format(
|
||||
" AND `character_id` = {}",
|
||||
character_id
|
||||
);
|
||||
}
|
||||
|
||||
if (npc_id) {
|
||||
where_filter += fmt::format(
|
||||
" AND `npc_id` = {}",
|
||||
npc_id
|
||||
);
|
||||
}
|
||||
|
||||
if (bot_id) {
|
||||
where_filter += fmt::format(
|
||||
" AND `bot_id` = {}",
|
||||
bot_id
|
||||
);
|
||||
}
|
||||
|
||||
where_filter += " LIMIT 50";
|
||||
|
||||
const auto& l = DataBucketsRepository::GetWhere(database, where_filter);
|
||||
|
||||
if (l.empty()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"No data buckets found matching '{}'.",
|
||||
key_filter
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string window_text = DialogueWindow::TableRow(
|
||||
DialogueWindow::TableCell("ID") +
|
||||
DialogueWindow::TableCell("Key") +
|
||||
DialogueWindow::TableCell("Value") +
|
||||
DialogueWindow::TableCell("Expires") +
|
||||
DialogueWindow::TableCell("Character ID") +
|
||||
DialogueWindow::TableCell("NPC ID") +
|
||||
DialogueWindow::TableCell("Bot ID")
|
||||
);
|
||||
|
||||
uint16 bucket_count = 0;
|
||||
uint16 bucket_number = 1;
|
||||
|
||||
for (const auto& e : l) {
|
||||
const std::string& expires_string = e.expires == 0 ? "Never" : std::to_string(e.expires);
|
||||
|
||||
window_text += DialogueWindow::TableRow(
|
||||
DialogueWindow::TableCell(std::to_string(e.id)) +
|
||||
DialogueWindow::TableCell(e.key_) +
|
||||
DialogueWindow::TableCell(e.value) +
|
||||
DialogueWindow::TableCell(expires_string) +
|
||||
DialogueWindow::TableCell(std::to_string(e.character_id)) +
|
||||
DialogueWindow::TableCell(std::to_string(e.npc_id)) +
|
||||
DialogueWindow::TableCell(std::to_string(e.bot_id))
|
||||
);
|
||||
|
||||
const std::string& delete_link = Saylink::Silent(
|
||||
fmt::format(
|
||||
"#databuckets delete {} {} {} {}",
|
||||
e.key_,
|
||||
e.character_id,
|
||||
e.npc_id,
|
||||
e.bot_id
|
||||
),
|
||||
"Delete"
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Bucket {} | Key: {} | Value: {} | Character ID: {} NPC ID: {} Bot ID: {} | {}",
|
||||
bucket_number,
|
||||
e.key_,
|
||||
e.value,
|
||||
e.character_id,
|
||||
e.npc_id,
|
||||
e.bot_id,
|
||||
delete_link
|
||||
).c_str()
|
||||
);
|
||||
|
||||
bucket_count++;
|
||||
bucket_number++;
|
||||
}
|
||||
|
||||
window_text = DialogueWindow::Table(window_text);
|
||||
|
||||
c->SendPopupToClient("Data Buckets", window_text.c_str());
|
||||
|
||||
const std::string& response = fmt::format(
|
||||
"Found {} data bucket{} matching '{}'{}.",
|
||||
bucket_count,
|
||||
bucket_count != 1 ? "s" : "",
|
||||
key_filter,
|
||||
bucket_count == 50 ? ", max reached" : ""
|
||||
);
|
||||
|
||||
c->Message(Chat::White, response.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void SendDataBucketsSubCommands(Client *c)
|
||||
{
|
||||
c->Message(Chat::White, "Usage: #databuckets delete [Key] [Character ID] [NPC ID] [Bot ID]");
|
||||
c->Message(Chat::White, "Usage: #databuckets edit [Key] [Character ID] [NPC ID] [Bot ID] [Value] [Expires]");
|
||||
c->Message(Chat::White, "Usage: #databuckets view [Partial Key] [Character ID] [NPC ID] [Bot ID]");
|
||||
c->Message(Chat::White, "Note: Character ID, NPC ID, and Bot ID are optional if not needed, if needed they are required for specificity");
|
||||
c->Message(Chat::White, "Note: Edit requires Character ID, NPC ID, Bot ID, and Value, Expires is optional and does not modify the existing expiration time if not provided");
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "../../client.h"
|
||||
#include "../../common/languages.h"
|
||||
|
||||
void FindLanguage(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(2)) {
|
||||
const auto language_id = Strings::ToInt(sep->arg[2]);
|
||||
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
if (EQ::ValueWithin(language_id, Language::CommonTongue, Language::Unknown27)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
|
||||
+266
-243
@@ -2,262 +2,285 @@
|
||||
|
||||
void command_fixmob(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *target = c->GetTarget();
|
||||
const char *Usage = "Usage: #fixmob [race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev]";
|
||||
|
||||
if (!sep->arg[1]) {
|
||||
c->Message(Chat::White, Usage);
|
||||
const int arguments = sep->argnum;
|
||||
if (arguments < 2) {
|
||||
SendFixMobSubCommands(c);
|
||||
return;
|
||||
}
|
||||
else if (!target) {
|
||||
c->Message(Chat::White, "Error: this command requires a target");
|
||||
|
||||
Mob* t = c;
|
||||
if (c->GetTarget()) {
|
||||
t = c->GetTarget();
|
||||
}
|
||||
else {
|
||||
|
||||
uint32 Adjustment = 1; // Previous or Next
|
||||
char codeMove = 0;
|
||||
const std::string& type = sep->arg[1];
|
||||
const std::string& move_type = Strings::ToLower(sep->arg[2]);
|
||||
|
||||
if (sep->arg[2]) {
|
||||
char *command2 = sep->arg[2];
|
||||
codeMove = (command2[0] | 0x20); // First character, lower-cased
|
||||
if (codeMove == 'n') {
|
||||
Adjustment = 1;
|
||||
}
|
||||
else if (codeMove == 'p') {
|
||||
Adjustment = -1;
|
||||
}
|
||||
std::string change_type;
|
||||
std::string change_value;
|
||||
|
||||
const bool is_next = move_type[0] == 'n';
|
||||
const bool is_previous = move_type[0] == 'p';
|
||||
|
||||
const uint32 adjustment = is_next ? 1 : -1;
|
||||
|
||||
uint16 race_id = t->GetRace();
|
||||
uint8 gender_id = t->GetGender();
|
||||
uint8 texture = UINT8_MAX;
|
||||
uint8 helm_texture = UINT8_MAX;
|
||||
uint8 hair_color = t->GetHairColor();
|
||||
uint8 beard_color = t->GetBeardColor();
|
||||
uint8 eye_color_1 = t->GetEyeColor1();
|
||||
uint8 eye_color_2 = t->GetEyeColor2();
|
||||
uint8 hair_style = t->GetHairStyle();
|
||||
uint8 face = t->GetLuclinFace();
|
||||
uint8 beard_style = t->GetBeard();
|
||||
uint8 drakkin_heritage = t->GetDrakkinHeritage();
|
||||
uint8 drakkin_tattoo = t->GetDrakkinTattoo();
|
||||
uint8 drakkin_details = t->GetDrakkinDetails();
|
||||
|
||||
const bool is_beard = Strings::EqualFold(type, "beard");
|
||||
const bool is_beard_color = Strings::EqualFold(type, "beard_color");
|
||||
const bool is_drakkin_details = Strings::EqualFold(type, "drakkin_details");
|
||||
const bool is_drakkin_heritage = Strings::EqualFold(type, "drakkin_heritage");
|
||||
const bool is_drakkin_tattoo = Strings::EqualFold(type, "drakkin_tattoo");
|
||||
const bool is_face = Strings::EqualFold(type, "face");
|
||||
const bool is_gender = Strings::EqualFold(type, "gender");
|
||||
const bool is_hair = Strings::EqualFold(type, "hair");
|
||||
const bool is_hair_color = Strings::EqualFold(type, "hair_color");
|
||||
const bool is_helm = Strings::EqualFold(type, "helm");
|
||||
const bool is_race = Strings::EqualFold(type, "race");
|
||||
const bool is_texture = Strings::EqualFold(type, "texture");
|
||||
|
||||
if (
|
||||
!is_beard &&
|
||||
!is_beard_color &&
|
||||
!is_drakkin_details &&
|
||||
!is_drakkin_heritage &&
|
||||
!is_drakkin_tattoo &&
|
||||
!is_face &&
|
||||
!is_gender &&
|
||||
!is_hair &&
|
||||
!is_hair_color &&
|
||||
!is_helm &&
|
||||
!is_race &&
|
||||
!is_texture
|
||||
) {
|
||||
SendFixMobSubCommands(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_race) {
|
||||
if (race_id == Race::Human && is_previous) {
|
||||
race_id = RuleI(NPC, MaxRaceID);
|
||||
} else if (race_id >= RuleI(NPC, MaxRaceID) && is_next) {
|
||||
race_id = Race::Human;
|
||||
} else {
|
||||
race_id += adjustment;
|
||||
}
|
||||
|
||||
uint16 Race = target->GetRace();
|
||||
uint8 Gender = target->GetGender();
|
||||
uint8 Texture = 0xFF;
|
||||
uint8 HelmTexture = 0xFF;
|
||||
uint8 HairColor = target->GetHairColor();
|
||||
uint8 BeardColor = target->GetBeardColor();
|
||||
uint8 EyeColor1 = target->GetEyeColor1();
|
||||
uint8 EyeColor2 = target->GetEyeColor2();
|
||||
uint8 HairStyle = target->GetHairStyle();
|
||||
uint8 LuclinFace = target->GetLuclinFace();
|
||||
uint8 Beard = target->GetBeard();
|
||||
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
|
||||
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
|
||||
uint32 DrakkinDetails = target->GetDrakkinDetails();
|
||||
|
||||
const char *ChangeType = nullptr; // If it's still nullptr after processing, they didn't send a valid command
|
||||
uint32 ChangeSetting;
|
||||
char *command = sep->arg[1];
|
||||
|
||||
if (strcasecmp(command, "race") == 0) {
|
||||
if (Race == 1 && codeMove == 'p') {
|
||||
Race = RuleI(NPC, MaxRaceID);
|
||||
}
|
||||
else if (Race >= RuleI(NPC, MaxRaceID) && codeMove != 'p') {
|
||||
Race = 1;
|
||||
}
|
||||
else {
|
||||
Race += Adjustment;
|
||||
}
|
||||
ChangeType = "Race";
|
||||
ChangeSetting = Race;
|
||||
}
|
||||
else if (strcasecmp(command, "gender") == 0) {
|
||||
if (Gender == MALE && codeMove == 'p') {
|
||||
Gender = NEUTER;
|
||||
}
|
||||
else if (Gender >= NEUTER && codeMove != 'p') {
|
||||
Gender = MALE;
|
||||
}
|
||||
else {
|
||||
Gender += Adjustment;
|
||||
}
|
||||
ChangeType = "Gender";
|
||||
ChangeSetting = Gender;
|
||||
}
|
||||
else if (strcasecmp(command, "texture") == 0) {
|
||||
Texture = target->GetTexture();
|
||||
|
||||
if (Texture == 0 && codeMove == 'p') {
|
||||
Texture = 25;
|
||||
}
|
||||
else if (Texture >= 25 && codeMove != 'p') {
|
||||
Texture = 0;
|
||||
}
|
||||
else {
|
||||
Texture += Adjustment;
|
||||
}
|
||||
ChangeType = "Texture";
|
||||
ChangeSetting = Texture;
|
||||
}
|
||||
else if (strcasecmp(command, "helm") == 0) {
|
||||
HelmTexture = target->GetHelmTexture();
|
||||
if (HelmTexture == 0 && codeMove == 'p') {
|
||||
HelmTexture = 25;
|
||||
}
|
||||
else if (HelmTexture >= 25 && codeMove != 'p') {
|
||||
HelmTexture = 0;
|
||||
}
|
||||
else {
|
||||
HelmTexture += Adjustment;
|
||||
}
|
||||
ChangeType = "HelmTexture";
|
||||
ChangeSetting = HelmTexture;
|
||||
}
|
||||
else if (strcasecmp(command, "face") == 0) {
|
||||
if (LuclinFace == 0 && codeMove == 'p') {
|
||||
LuclinFace = 87;
|
||||
}
|
||||
else if (LuclinFace >= 87 && codeMove != 'p') {
|
||||
LuclinFace = 0;
|
||||
}
|
||||
else {
|
||||
LuclinFace += Adjustment;
|
||||
}
|
||||
ChangeType = "LuclinFace";
|
||||
ChangeSetting = LuclinFace;
|
||||
}
|
||||
else if (strcasecmp(command, "hair") == 0) {
|
||||
if (HairStyle == 0 && codeMove == 'p') {
|
||||
HairStyle = 8;
|
||||
}
|
||||
else if (HairStyle >= 8 && codeMove != 'p') {
|
||||
HairStyle = 0;
|
||||
}
|
||||
else {
|
||||
HairStyle += Adjustment;
|
||||
}
|
||||
ChangeType = "HairStyle";
|
||||
ChangeSetting = HairStyle;
|
||||
}
|
||||
else if (strcasecmp(command, "haircolor") == 0) {
|
||||
if (HairColor == 0 && codeMove == 'p') {
|
||||
HairColor = 24;
|
||||
}
|
||||
else if (HairColor >= 24 && codeMove != 'p') {
|
||||
HairColor = 0;
|
||||
}
|
||||
else {
|
||||
HairColor += Adjustment;
|
||||
}
|
||||
ChangeType = "HairColor";
|
||||
ChangeSetting = HairColor;
|
||||
}
|
||||
else if (strcasecmp(command, "beard") == 0) {
|
||||
if (Beard == 0 && codeMove == 'p') {
|
||||
Beard = 11;
|
||||
}
|
||||
else if (Beard >= 11 && codeMove != 'p') {
|
||||
Beard = 0;
|
||||
}
|
||||
else {
|
||||
Beard += Adjustment;
|
||||
}
|
||||
ChangeType = "Beard";
|
||||
ChangeSetting = Beard;
|
||||
}
|
||||
else if (strcasecmp(command, "beardcolor") == 0) {
|
||||
if (BeardColor == 0 && codeMove == 'p') {
|
||||
BeardColor = 24;
|
||||
}
|
||||
else if (BeardColor >= 24 && codeMove != 'p') {
|
||||
BeardColor = 0;
|
||||
}
|
||||
else {
|
||||
BeardColor += Adjustment;
|
||||
}
|
||||
ChangeType = "BeardColor";
|
||||
ChangeSetting = BeardColor;
|
||||
}
|
||||
else if (strcasecmp(command, "heritage") == 0) {
|
||||
if (DrakkinHeritage == 0 && codeMove == 'p') {
|
||||
DrakkinHeritage = 6;
|
||||
}
|
||||
else if (DrakkinHeritage >= 6 && codeMove != 'p') {
|
||||
DrakkinHeritage = 0;
|
||||
}
|
||||
else {
|
||||
DrakkinHeritage += Adjustment;
|
||||
}
|
||||
ChangeType = "DrakkinHeritage";
|
||||
ChangeSetting = DrakkinHeritage;
|
||||
}
|
||||
else if (strcasecmp(command, "tattoo") == 0) {
|
||||
if (DrakkinTattoo == 0 && codeMove == 'p') {
|
||||
DrakkinTattoo = 8;
|
||||
}
|
||||
else if (DrakkinTattoo >= 8 && codeMove != 'p') {
|
||||
DrakkinTattoo = 0;
|
||||
}
|
||||
else {
|
||||
DrakkinTattoo += Adjustment;
|
||||
}
|
||||
ChangeType = "DrakkinTattoo";
|
||||
ChangeSetting = DrakkinTattoo;
|
||||
}
|
||||
else if (strcasecmp(command, "detail") == 0) {
|
||||
if (DrakkinDetails == 0 && codeMove == 'p') {
|
||||
DrakkinDetails = 7;
|
||||
}
|
||||
else if (DrakkinDetails >= 7 && codeMove != 'p') {
|
||||
DrakkinDetails = 0;
|
||||
}
|
||||
else {
|
||||
DrakkinDetails += Adjustment;
|
||||
}
|
||||
ChangeType = "DrakkinDetails";
|
||||
ChangeSetting = DrakkinDetails;
|
||||
change_type = "Race";
|
||||
change_value = std::to_string(race_id);
|
||||
} else if (is_gender) {
|
||||
if (gender_id == Gender::Male && is_previous) {
|
||||
gender_id = Gender::Neuter;
|
||||
} else if (gender_id >= Gender::Neuter && is_next) {
|
||||
gender_id = Gender::Male;
|
||||
} else {
|
||||
gender_id += adjustment;
|
||||
}
|
||||
|
||||
// Hack to fix some races that base features from face
|
||||
switch (Race) {
|
||||
case 2: // Barbarian
|
||||
if (LuclinFace > 10) {
|
||||
LuclinFace -= ((DrakkinTattoo - 1) * 10);
|
||||
}
|
||||
LuclinFace += (DrakkinTattoo * 10);
|
||||
break;
|
||||
case 3: // Erudite
|
||||
if (LuclinFace > 10) {
|
||||
LuclinFace -= ((HairStyle - 1) * 10);
|
||||
}
|
||||
LuclinFace += (HairStyle * 10);
|
||||
break;
|
||||
case 5: // HighElf
|
||||
case 6: // DarkElf
|
||||
case 7: // HalfElf
|
||||
if (LuclinFace > 10) {
|
||||
LuclinFace -= ((Beard - 1) * 10);
|
||||
}
|
||||
LuclinFace += (Beard * 10);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
change_type = "Gender";
|
||||
change_value = std::to_string(gender_id);
|
||||
} else if (is_texture) {
|
||||
texture = t->GetTexture();
|
||||
|
||||
if (texture == 0 && is_previous) {
|
||||
texture = 25;
|
||||
} else if (texture >= 25 && is_next) {
|
||||
texture = 0;
|
||||
} else {
|
||||
texture += adjustment;
|
||||
}
|
||||
|
||||
|
||||
if (ChangeType == nullptr) {
|
||||
c->Message(Chat::White, Usage);
|
||||
change_type = "Texture";
|
||||
change_value = std::to_string(texture);
|
||||
} else if (is_helm) {
|
||||
helm_texture = t->GetHelmTexture();
|
||||
if (helm_texture == 0 && is_previous) {
|
||||
helm_texture = 25;
|
||||
} else if (helm_texture >= 25 && is_next) {
|
||||
helm_texture = 0;
|
||||
} else {
|
||||
helm_texture += adjustment;
|
||||
}
|
||||
else {
|
||||
target->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
.beard = Beard,
|
||||
.beard_color = BeardColor,
|
||||
.drakkin_details = DrakkinDetails,
|
||||
.drakkin_heritage = DrakkinHeritage,
|
||||
.drakkin_tattoo = DrakkinTattoo,
|
||||
.eye_color_one = EyeColor1,
|
||||
.eye_color_two = EyeColor2,
|
||||
.face = LuclinFace,
|
||||
.gender_id = Gender,
|
||||
.hair = HairStyle,
|
||||
.hair_color = HairColor,
|
||||
.helmet_texture = HelmTexture,
|
||||
.race_id = Race,
|
||||
.texture = Texture,
|
||||
}
|
||||
);
|
||||
|
||||
c->Message(Chat::White, "%s=%i", ChangeType, ChangeSetting);
|
||||
change_type = "Helm Texture";
|
||||
change_value = std::to_string(helm_texture);
|
||||
} else if (is_face) {
|
||||
if (face == 0 && is_previous) {
|
||||
face = 87;
|
||||
} else if (face >= 87 && is_next) {
|
||||
face = 0;
|
||||
} else {
|
||||
face += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Face";
|
||||
change_value = std::to_string(face);
|
||||
} else if (is_hair) {
|
||||
if (hair_style == 0 && is_previous) {
|
||||
hair_style = 8;
|
||||
} else if (hair_style >= 8 && is_next) {
|
||||
hair_style = 0;
|
||||
} else {
|
||||
hair_style += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Hair Style";
|
||||
change_value = std::to_string(hair_style);
|
||||
} else if (is_hair_color) {
|
||||
if (hair_color == 0 && is_previous) {
|
||||
hair_color = 24;
|
||||
} else if (hair_color >= 24 && is_next) {
|
||||
hair_color = 0;
|
||||
} else {
|
||||
hair_color += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Hair Color";
|
||||
change_value = std::to_string(hair_color);
|
||||
} else if (is_beard) {
|
||||
if (beard_style == 0 && is_previous) {
|
||||
beard_style = 11;
|
||||
} else if (beard_style >= 11 && is_next) {
|
||||
beard_style = 0;
|
||||
} else {
|
||||
beard_style += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Beard Style";
|
||||
change_value = std::to_string(beard_style);
|
||||
} else if (is_beard_color) {
|
||||
if (beard_color == 0 && is_previous) {
|
||||
beard_color = 24;
|
||||
} else if (beard_color >= 24 && is_next) {
|
||||
beard_color = 0;
|
||||
} else {
|
||||
beard_color += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Beard Color";
|
||||
change_value = std::to_string(beard_color);
|
||||
} else if (is_drakkin_heritage) {
|
||||
if (drakkin_heritage == 0 && is_previous) {
|
||||
drakkin_heritage = 6;
|
||||
} else if (drakkin_heritage >= 6 && is_next) {
|
||||
drakkin_heritage = 0;
|
||||
} else {
|
||||
drakkin_heritage += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Drakkin Heritage";
|
||||
change_value = std::to_string(drakkin_heritage);
|
||||
} else if (is_drakkin_tattoo) {
|
||||
if (drakkin_tattoo == 0 && is_previous) {
|
||||
drakkin_tattoo = 8;
|
||||
} else if (drakkin_tattoo >= 8 && is_next) {
|
||||
drakkin_tattoo = 0;
|
||||
} else {
|
||||
drakkin_tattoo += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Drakkin Tattoo";
|
||||
change_value = std::to_string(drakkin_tattoo);
|
||||
} else if (is_drakkin_details) {
|
||||
if (drakkin_details == 0 && is_previous) {
|
||||
drakkin_details = 7;
|
||||
} else if (drakkin_details >= 7 && is_next) {
|
||||
drakkin_details = 0;
|
||||
} else {
|
||||
drakkin_details += adjustment;
|
||||
}
|
||||
|
||||
change_type = "Drakkin Details";
|
||||
change_value = std::to_string(drakkin_details);
|
||||
}
|
||||
|
||||
switch (race_id) {
|
||||
case Race::Barbarian: {
|
||||
if (face > 10) {
|
||||
face -= ((drakkin_tattoo - 1) * 10);
|
||||
}
|
||||
|
||||
face += (drakkin_tattoo * 10);
|
||||
break;
|
||||
}
|
||||
case Race::Erudite: {
|
||||
if (face > 10) {
|
||||
face -= ((hair_style - 1) * 10);
|
||||
}
|
||||
|
||||
face += (hair_style * 10);
|
||||
break;
|
||||
}
|
||||
case Race::HighElf:
|
||||
case Race::DarkElf:
|
||||
case Race::HalfElf: {
|
||||
if (face > 10) {
|
||||
face -= ((beard_style - 1) * 10);
|
||||
}
|
||||
|
||||
face += (beard_style * 10);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
.beard = beard_style,
|
||||
.beard_color = beard_color,
|
||||
.drakkin_details = drakkin_details,
|
||||
.drakkin_heritage = drakkin_heritage,
|
||||
.drakkin_tattoo = drakkin_tattoo,
|
||||
.eye_color_one = eye_color_1,
|
||||
.eye_color_two = eye_color_2,
|
||||
.face = face,
|
||||
.gender_id = gender_id,
|
||||
.hair = hair_style,
|
||||
.hair_color = hair_color,
|
||||
.helmet_texture = helm_texture,
|
||||
.race_id = race_id,
|
||||
.texture = texture,
|
||||
}
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Appearance for {} | Type: {} Value: {}",
|
||||
c->GetTargetDescription(t, TargetDescriptionType::UCSelf),
|
||||
change_type,
|
||||
change_value
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
void SendFixMobSubCommands(Client *c)
|
||||
{
|
||||
c->Message(Chat::White, "Usage: #fixmob beard [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob beard_color [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob drakkin_details [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob drakkin_heritage [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob drakkin_tattoo [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob face [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob gender [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob hair [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob hair_color [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob helm [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob race [Next|Previous]");
|
||||
c->Message(Chat::White, "Usage: #fixmob texture [Next|Previous]");
|
||||
}
|
||||
|
||||
@@ -2,21 +2,44 @@
|
||||
|
||||
void command_petname(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *target;
|
||||
target = c->GetTarget();
|
||||
Mob *t = nullptr;
|
||||
if (c->GetTarget()) {
|
||||
t = c->GetTarget();
|
||||
}
|
||||
|
||||
if (!target || !target->IsPet()) {
|
||||
c->Message(Chat::White, "Usage: #petname newname (requires a pet target)");
|
||||
if (!t) {
|
||||
c->Message(Chat::White, "You must target your pet to use this command.");
|
||||
return;
|
||||
}
|
||||
else if (target->GetOwnerID() == c->GetID() && strlen(sep->arg[1]) > 0) {
|
||||
char *oldname = strdup(target->GetName());
|
||||
target->TempName(sep->arg[1]);
|
||||
c->Message(Chat::White, "Renamed %s to %s", oldname, sep->arg[1]);
|
||||
free(oldname);
|
||||
|
||||
if (!t->IsPet()) {
|
||||
c->Message(Chat::White, "You must target your pet to use this command.");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
target->TempName();
|
||||
c->Message(Chat::White, "Restored the original name");
|
||||
|
||||
if (t->GetOwnerID() != c->GetID()) {
|
||||
c->Message(Chat::White, "You must target your pet to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sep->arg[1]) {
|
||||
const std::string& old_name = t->GetCleanName();
|
||||
const std::string& new_name = sep->arg[1];
|
||||
|
||||
t->TempName(new_name.c_str());
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Renamed your pet from {} to {}.",
|
||||
old_name,
|
||||
new_name
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
t->TempName();
|
||||
c->Message(Chat::White, "Restored the original name.");
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void SetFlymode(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
t->SetFlyMode(static_cast<GravityBehavior>(flymode_id));
|
||||
t->SendAppearancePacket(AT_Levitate, flymode_id);
|
||||
t->SendAppearancePacket(AppearanceType::FlyMode, flymode_id);
|
||||
|
||||
const uint32 account = c->AccountID();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ void SetFrozen(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
t->SendAppearancePacket(AT_Anim, is_frozen ? ANIM_FREEZE : ANIM_STAND);
|
||||
t->SendAppearancePacket(AppearanceType::Animation, is_frozen ? Animation::Freeze : Animation::Standing);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
|
||||
@@ -15,7 +15,7 @@ void SetGender(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
const uint8 gender_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
if (!EQ::ValueWithin(gender_id, MALE, NEUTER)) {
|
||||
if (!EQ::ValueWithin(gender_id, Gender::Male, Gender::Neuter)) {
|
||||
c->Message(Chat::White, "Usage: #set gender [Gender ID]");
|
||||
c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter");
|
||||
return;
|
||||
|
||||
@@ -15,7 +15,7 @@ void SetGenderPermanent(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
const uint8 gender_id = Strings::ToInt(sep->arg[2]);
|
||||
if (!EQ::ValueWithin(gender_id, MALE, NEUTER)) {
|
||||
if (!EQ::ValueWithin(gender_id, Gender::Male, Gender::Neuter)) {
|
||||
c->Message(Chat::White, "Usage: #set gender_permanent [Gender ID]");
|
||||
c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter");
|
||||
return;
|
||||
|
||||
@@ -26,7 +26,7 @@ void SetGodMode(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
c->SetInvul(god_mode);
|
||||
c->SendAppearancePacket(AT_Levitate, god_mode);
|
||||
c->SendAppearancePacket(AppearanceType::FlyMode, god_mode);
|
||||
c->SetHideMe(god_mode);
|
||||
|
||||
c->Message(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user