mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-23 13:12:28 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12eb838ee9 | |||
| 213fe6a9e9 | |||
| be6a5d5f50 | |||
| 1af29bd7b1 | |||
| ef945e6e99 | |||
| 9528c1e7fc | |||
| fd6e5f465d | |||
| d00125abe1 |
@@ -955,6 +955,29 @@ bool Database::UpdateName(const std::string& old_name, const std::string& new_na
|
||||
return CharacterDataRepository::UpdateOne(*this, e);
|
||||
}
|
||||
|
||||
bool Database::UpdateNameByID(const int character_id, const std::string& new_name)
|
||||
{
|
||||
LogInfo("Renaming [{}] to [{}]", character_id, new_name);
|
||||
|
||||
auto l = CharacterDataRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`id` = {}",
|
||||
character_id
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& e = l.front();
|
||||
|
||||
e.name = new_name;
|
||||
|
||||
return CharacterDataRepository::UpdateOne(*this, e);
|
||||
}
|
||||
|
||||
bool Database::IsNameUsed(const std::string& name)
|
||||
{
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
@@ -982,6 +1005,20 @@ bool Database::IsNameUsed(const std::string& name)
|
||||
return !character_data.empty();
|
||||
}
|
||||
|
||||
// Players cannot have the same name as a pet vanity name, or memory corruption occurs.
|
||||
bool Database::IsPetNameUsed(const std::string& name)
|
||||
{
|
||||
const auto& pet_name_data = CharacterPetNameRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`name` = '{}'",
|
||||
Strings::Escape(name)
|
||||
)
|
||||
);
|
||||
|
||||
return !pet_name_data.empty();
|
||||
}
|
||||
|
||||
uint32 Database::GetServerType()
|
||||
{
|
||||
const auto& l = VariablesRepository::GetWhere(*this, "`varname` = 'ServerType' LIMIT 1");
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
bool ReserveName(uint32 account_id, const std::string& name);
|
||||
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
|
||||
bool UpdateName(const std::string& old_name, const std::string& new_name);
|
||||
bool UpdateNameByID(const int character_id, const std::string& new_name);
|
||||
bool CopyCharacter(
|
||||
const std::string& source_character_name,
|
||||
const std::string& destination_character_name,
|
||||
@@ -116,6 +117,7 @@ public:
|
||||
bool CheckGMIPs(const std::string& login_ip, uint32 account_id);
|
||||
bool CheckNameFilter(const std::string& name, bool surname = false);
|
||||
bool IsNameUsed(const std::string& name);
|
||||
bool IsPetNameUsed(const std::string& name);
|
||||
|
||||
uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0);
|
||||
uint32 GetAccountIDByChar(uint32 character_id);
|
||||
|
||||
@@ -287,6 +287,8 @@ N(OP_InstillDoubt),
|
||||
N(OP_InterruptCast),
|
||||
N(OP_InvokeChangePetName),
|
||||
N(OP_InvokeChangePetNameImmediate),
|
||||
N(OP_InvokeNameChangeImmediate),
|
||||
N(OP_InvokeNameChangeLazy),
|
||||
N(OP_ItemLinkClick),
|
||||
N(OP_ItemLinkResponse),
|
||||
N(OP_ItemLinkText),
|
||||
|
||||
@@ -5832,21 +5832,28 @@ struct ChangeSize_Struct
|
||||
/*16*/
|
||||
};
|
||||
|
||||
enum ChangeNameResponse : int {
|
||||
Denied = 0, // 5167: "You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name."
|
||||
Accepted = 1, // 5976: "Your request for a name change was successful."
|
||||
Timeout = -1, // 5977: "Your request for a name change has timed out. Please try again later."
|
||||
ServerError = -2, // 5978: "The server had an error while processing your name request. Please try again later."
|
||||
RateLimited = -3, // 5979: "You must wait longer before submitting another name request. Please try again in a few minutes."
|
||||
Ineligible = -4, // 5980: "Your character is not eligible for a name change."
|
||||
Pending = -5 // 5193: "You already have a name change pending. Please wait until it is fully processed before attempting another name change."
|
||||
};
|
||||
|
||||
struct AltChangeName_Struct {
|
||||
/*00*/ char new_name[64];
|
||||
/*40*/ char old_name[64];
|
||||
/*80*/ int response_code;
|
||||
};
|
||||
|
||||
struct ChangePetName_Struct {
|
||||
/*00*/ char new_pet_name[64];
|
||||
/*40*/ char pet_owner_name[64];
|
||||
/*80*/ int response_code;
|
||||
};
|
||||
|
||||
enum ChangePetNameResponse : int {
|
||||
Denied = 0, // 5167 You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name.
|
||||
Accepted = 1, // 5976 Your request for a name change was successful.
|
||||
Timeout = -3, // 5979 You must wait longer before submitting another name request. Please try again in a few minutes.
|
||||
NotEligible = -4, // 5980 Your character is not eligible for a name change.
|
||||
Pending = -5, // 5193 You already have a name change pending. Please wait until it is fully processed before attempting another name change.
|
||||
Unhandled = -1
|
||||
};
|
||||
|
||||
// New OpCode/Struct for SoD+
|
||||
struct GroupMakeLeader_Struct
|
||||
{
|
||||
|
||||
+2
-1
@@ -231,6 +231,7 @@ RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will alway
|
||||
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
|
||||
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
|
||||
RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal")
|
||||
RULE_BOOL(Character, AlwaysAllowNameChange, false, "Enable this option to allow /changename to work without enabling a name change via scripts.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -835,7 +836,7 @@ RULE_INT(Bots, MinGroupCureTargets, 3, "Minimum number of targets in valid range
|
||||
RULE_INT(Bots, MinTargetsForAESpell, 3, "Minimum number of targets in valid range that are required for an AE spell to cast. Default 3.")
|
||||
RULE_INT(Bots, MinTargetsForGroupSpell, 3, "Minimum number of targets in valid range that are required for an group spell to cast. Default 3.")
|
||||
RULE_BOOL(Bots, AllowBuffingHealingFamiliars, false, "Determines if bots are allowed to buff and heal familiars. Default false.")
|
||||
RULE_BOOL(Bots, RunSpellTypeChecksOnSpawn, false, "This will run a serious of checks on spell types and output errors to LogBotSpellTypeChecks")
|
||||
RULE_BOOL(Bots, RunSpellTypeChecksOnBoot, false, "This will run a series of checks to find potential errors in your bot_spells_entries table on boot and output to LogBotSpellTypeChecks")
|
||||
RULE_BOOL(Bots, UseParentSpellTypeForChecks, true, "This will check only the parent instead of AE/Group/Pet types (ex: AENukes/AERains/PBAENukes fall under Nukes or PetBuffs fall under buffs) when RunSpellTypeChecksOnSpawn fires")
|
||||
RULE_BOOL(Bots, AllowForcedCastsBySpellID, true, "If enabled, players can use ^cast spellid # to cast a specific spell by ID that is in their spell list")
|
||||
RULE_BOOL(Bots, AllowCastAAs, true, "If enabled, players can use ^cast aa to cast a clickable AA")
|
||||
|
||||
+49
-37
@@ -1456,41 +1456,42 @@ bool IsCompleteHealSpell(uint16 spell_id)
|
||||
}
|
||||
|
||||
bool IsFastHealSpell(uint16 spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHP) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
|
||||
);
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHP) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
|
||||
);
|
||||
|
||||
if (!spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
|
||||
);
|
||||
}
|
||||
if (!spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id && IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (
|
||||
spells[spell_id].base_value[i] > 0 &&
|
||||
(
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHP ||
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spell_id != SPELL_MINOR_HEALING &&
|
||||
(spells[spell_id].cast_time > MAX_VERY_FAST_HEAL_CASTING_TIME && spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME) &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (
|
||||
spells[spell_id].base_value[i] > 0 &&
|
||||
(
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHP ||
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsVeryFastHealSpell(uint16 spell_id)
|
||||
@@ -1509,8 +1510,9 @@ bool IsVeryFastHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spell_id != SPELL_MINOR_HEALING &&
|
||||
spells[spell_id].cast_time <= MAX_VERY_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
@@ -1548,8 +1550,13 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (spell_id == SPELL_MINOR_HEALING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
spells[spell_id].cast_time > MAX_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].target_type == ST_Target &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
@@ -1589,9 +1596,14 @@ bool IsRegularPetHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id && IsValidSpell(spell_id)) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (spell_id == SPELL_MINOR_HEALING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
(spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_Undead) &&
|
||||
spells[spell_id].cast_time > MAX_FAST_HEAL_CASTING_TIME &&
|
||||
(spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_SummonedPet) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
!IsGroupSpell(spell_id)
|
||||
@@ -1630,7 +1642,7 @@ bool IsRegularGroupHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
IsGroupSpell(spell_id) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
#define SPELL_AMPLIFICATION 2603
|
||||
#define SPELL_DIVINE_REZ 2738
|
||||
#define SPELL_NATURES_RECOVERY 2520
|
||||
#define SPELL_MINOR_HEALING 200
|
||||
#define SPELL_ADRENALINE_SWELL 14445
|
||||
#define SPELL_ADRENALINE_SWELL_RK2 14446
|
||||
#define SPELL_ADRENALINE_SWELL_RK3 14447
|
||||
|
||||
+12
-252
@@ -1,4 +1,5 @@
|
||||
#include "spdat.h"
|
||||
#include "../zone/bot.h"
|
||||
|
||||
bool IsBotSpellTypeDetrimental(uint16 spell_type) {
|
||||
switch (spell_type) {
|
||||
@@ -417,264 +418,23 @@ uint16 GetCorrectBotSpellType(uint16 spell_type, uint16 spell_id) {
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
uint16 correct_type = UINT16_MAX;
|
||||
SPDat_Spell_Struct spell = spells[spell_id];
|
||||
std::string teleport_zone = spell.teleport_zone;
|
||||
uint16 correct_type = spell_type;
|
||||
|
||||
if (IsCharmSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Charm;
|
||||
}
|
||||
else if (IsFearSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Fear;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_Revive)) {
|
||||
correct_type = BotSpellTypes::Resurrect;
|
||||
}
|
||||
else if (IsHarmonySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Lull;
|
||||
}
|
||||
else if (
|
||||
teleport_zone.compare("") &&
|
||||
!IsEffectInSpell(spell_id, SE_GateToHomeCity) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Teleport;
|
||||
}
|
||||
else if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Succor)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Succor;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_BindAffinity)) {
|
||||
correct_type = BotSpellTypes::BindAffinity;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_Identify)) {
|
||||
correct_type = BotSpellTypes::Identify;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Levitate &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Levitate)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Levitate;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Rune &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Rune;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::WaterBreathing &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_WaterBreathing)
|
||||
) {
|
||||
correct_type = BotSpellTypes::WaterBreathing;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Size &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Size;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Invisibility &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Invisibility;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::MovementSpeed &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
correct_type = BotSpellTypes::MovementSpeed;
|
||||
}
|
||||
else if (
|
||||
!teleport_zone.compare("") &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_Translocate) || IsEffectInSpell(spell_id, SE_GateToHomeCity))
|
||||
) {
|
||||
correct_type = BotSpellTypes::SendHome;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_SummonCorpse)) {
|
||||
correct_type = BotSpellTypes::SummonCorpse;
|
||||
}
|
||||
if (!Bot::IsValidSpellTypeBySpellID(spell_type, spell_id)) {
|
||||
correct_type = UINT16_MAX;
|
||||
|
||||
if (correct_type == UINT16_MAX) {
|
||||
if (
|
||||
IsSummonPetSpell(spell_id) ||
|
||||
IsEffectInSpell(spell_id, SE_TemporaryPets)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Pet;
|
||||
}
|
||||
else if (IsMesmerizeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Mez;
|
||||
}
|
||||
else if (IsEscapeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Escape;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Root)
|
||||
) {
|
||||
if (IsAnyAESpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AERoot;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::Root;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsLifetapSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Lifetap;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Snare;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
(IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::DOT;
|
||||
}
|
||||
else if (IsDispelSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Dispel;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsSlowSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Slow;
|
||||
}
|
||||
else if (
|
||||
IsDebuffSpell(spell_id) &&
|
||||
!IsHateReduxSpell(spell_id) &&
|
||||
!IsHateSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Debuff;
|
||||
}
|
||||
else if (IsHateReduxSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::HateRedux;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsHateSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::HateLine;
|
||||
}
|
||||
else if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsBardSong(spell_id)
|
||||
) {
|
||||
if (
|
||||
spell_type == BotSpellTypes::InCombatBuffSong ||
|
||||
spell_type == BotSpellTypes::OutOfCombatBuffSong ||
|
||||
spell_type == BotSpellTypes::PreCombatBuffSong
|
||||
) {
|
||||
correct_type = spell_type;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::OutOfCombatBuffSong;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
!IsBardSong(spell_id) &&
|
||||
(
|
||||
(IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) ||
|
||||
(spell_type == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id))
|
||||
)
|
||||
) {
|
||||
correct_type = BotSpellTypes::InCombatBuff;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::PreCombatBuff &&
|
||||
IsAnyBuffSpell(spell_id) &&
|
||||
!IsBardSong(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::PreCombatBuff;
|
||||
}
|
||||
else if (
|
||||
(IsCureSpell(spell_id) && spell_type == BotSpellTypes::Cure) ||
|
||||
(IsCureSpell(spell_id) && !IsAnyHealSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Cure;
|
||||
}
|
||||
else if (IsAnyNukeOrStunSpell(spell_id)) {
|
||||
if (IsAnyAESpell(spell_id)) {
|
||||
if (IsAERainSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AERains;
|
||||
}
|
||||
else if (IsPBAENukeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::PBAENuke;
|
||||
}
|
||||
else if (IsStunSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AEStun;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::AENukes;
|
||||
}
|
||||
}
|
||||
else if (IsStunSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Stun;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::Nuke;
|
||||
}
|
||||
}
|
||||
else if (IsAnyHealSpell(spell_id)) {
|
||||
if (IsGroupSpell(spell_id)) {
|
||||
if (IsGroupCompleteHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupCompleteHeals;
|
||||
}
|
||||
else if (IsGroupHealOverTimeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupHoTHeals;
|
||||
}
|
||||
else if (IsRegularGroupHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupHeals;
|
||||
}
|
||||
auto start = std::min({ BotSpellTypes::START, BotSpellTypes::COMMANDED_START, BotSpellTypes::DISCIPLINE_START });
|
||||
auto end = std::max({ BotSpellTypes::END, BotSpellTypes::COMMANDED_END, BotSpellTypes::DISCIPLINE_END });
|
||||
|
||||
return correct_type;
|
||||
for (int i = end; i >= start; --i) {
|
||||
if (!Bot::IsValidBotSpellType(i) || i == BotSpellTypes::InCombatBuff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsVeryFastHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::VeryFastHeals;
|
||||
}
|
||||
else if (IsFastHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::FastHeals;
|
||||
}
|
||||
else if (IsCompleteHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::CompleteHeal;
|
||||
}
|
||||
else if (IsHealOverTimeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::HoTHeals;
|
||||
}
|
||||
else if (IsRegularSingleTargetHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::RegularHeal;
|
||||
}
|
||||
else if (IsRegularPetHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::RegularHeal;
|
||||
}
|
||||
}
|
||||
else if (IsAnyBuffSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Buff;
|
||||
if (Bot::IsValidSpellTypeBySpellID(i, spell_id)) {
|
||||
correct_type = i;
|
||||
|
||||
if (IsResistanceOnlySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::ResistBuffs;
|
||||
}
|
||||
else if (IsDamageShieldOnlySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::DamageShields;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,3 +746,6 @@ OP_TradeSkillRecipeInspect=0x4f7e
|
||||
OP_InvokeChangePetNameImmediate=0x046d
|
||||
OP_InvokeChangePetName=0x4506
|
||||
OP_ChangePetName=0x5dab
|
||||
|
||||
OP_InvokeNameChangeImmediate=0x4fe2
|
||||
OP_InvokeNameChangeLazy=0x2f2e
|
||||
|
||||
@@ -3041,9 +3041,15 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
if (!other)
|
||||
return;
|
||||
|
||||
if (other->IsDestroying())
|
||||
return;
|
||||
|
||||
if (other == this)
|
||||
return;
|
||||
|
||||
if (other->IsClient() && (other->CastToClient()->IsZoning() || other->CastToClient()->Connected() == false))
|
||||
return;
|
||||
|
||||
if (other->IsTrap())
|
||||
return;
|
||||
|
||||
|
||||
+293
-79
@@ -3578,8 +3578,16 @@ void Bot::Depop() {
|
||||
entity_list.RemoveFromHateLists(this);
|
||||
RemoveAllAuras();
|
||||
|
||||
if (HasPet())
|
||||
GetPet()->Depop();
|
||||
Mob* bot_pet = GetPet();
|
||||
|
||||
if (bot_pet) {
|
||||
if (bot_pet->Charmed()) {
|
||||
bot_pet->BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
else {
|
||||
bot_pet->Depop();
|
||||
}
|
||||
}
|
||||
|
||||
_botOwner = nullptr;
|
||||
_botOwnerCharacterID = 0;
|
||||
@@ -3702,11 +3710,6 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Bots, RunSpellTypeChecksOnSpawn)) {
|
||||
OwnerMessage("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline.");
|
||||
CheckBotSpells(); //This runs through a series of checks and outputs any spells that are set to the wrong spell type in the database
|
||||
}
|
||||
|
||||
if (IsBotRanged()) {
|
||||
ChangeBotRangedWeapons(true);
|
||||
}
|
||||
@@ -9790,6 +9793,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
}
|
||||
|
||||
uint8 bot_class = GetClass();
|
||||
auto spell = spells[spell_id];
|
||||
|
||||
switch (spell_type) {
|
||||
case BotSpellTypes::Buff:
|
||||
@@ -9813,7 +9817,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
case BotSpellTypes::SendHome:
|
||||
if (
|
||||
tar == this &&
|
||||
spells[spell_id].target_type == ST_TargetsTarget
|
||||
spell.target_type == ST_TargetsTarget
|
||||
) {
|
||||
LogBotSpellChecksDetail("{} says, 'Cancelling cast of {} on {} due to target_type checks. Using {}'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName(), GetSpellTargetType(spell_id));
|
||||
return false;
|
||||
@@ -9843,7 +9847,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
}
|
||||
|
||||
if (
|
||||
spells[spell_id].target_type == ST_Pet &&
|
||||
(spell.target_type == ST_Pet || spell.target_type == ST_SummonedPet) &&
|
||||
(
|
||||
!tar->IsPet() ||
|
||||
(
|
||||
@@ -11566,18 +11570,265 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBotSpellTypeDetrimental(spell_type) && !IsDetrimentalSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBotSpellTypeBeneficial(spell_type) && !IsBeneficialSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto spell = spells[spell_id];
|
||||
std::string teleport_zone = spell.teleport_zone;
|
||||
|
||||
switch (spell_type) {
|
||||
case BotSpellTypes::Buff:
|
||||
case BotSpellTypes::PetBuffs:
|
||||
if (
|
||||
IsResistanceOnlySpell(spell_id) ||
|
||||
IsDamageShieldOnlySpell(spell_id) ||
|
||||
IsDamageShieldAndResistSpell(spell_id)
|
||||
) {
|
||||
return false;
|
||||
case BotSpellTypes::Nuke:
|
||||
if (IsAnyNukeOrStunSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
case BotSpellTypes::RegularHeal:
|
||||
case BotSpellTypes::PetRegularHeals:
|
||||
if (
|
||||
IsAnyHealSpell(spell_id) &&
|
||||
!IsVeryFastHealSpell(spell_id) &&
|
||||
!IsFastHealSpell(spell_id) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
!IsBuffSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Root:
|
||||
case BotSpellTypes::AERoot:
|
||||
if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_Root)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Buff:
|
||||
case BotSpellTypes::PreCombatBuff:
|
||||
case BotSpellTypes::PetBuffs:
|
||||
if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
!IsBardSong(spell_id) &&
|
||||
!IsResistanceOnlySpell(spell_id) &&
|
||||
!IsDamageShieldOnlySpell(spell_id) &&
|
||||
!IsDamageShieldAndResistSpell(spell_id)
|
||||
) {
|
||||
if (
|
||||
spell_type != BotSpellTypes::PetBuffs &&
|
||||
(spell.target_type == ST_Pet || spell.target_type == ST_SummonedPet)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Escape:
|
||||
if (IsEscapeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Pet:
|
||||
if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lifetap:
|
||||
case BotSpellTypes::AELifetap:
|
||||
if (IsDetrimentalSpell(spell_id) && IsLifetapSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Snare:
|
||||
case BotSpellTypes::AESnare:
|
||||
if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::DOT:
|
||||
case BotSpellTypes::AEDoT:
|
||||
if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
(IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Dispel:
|
||||
case BotSpellTypes::AEDispel:
|
||||
if (IsDispelSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::InCombatBuff:
|
||||
if (
|
||||
!IsBardSong(spell_id) &&
|
||||
(
|
||||
(IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) ||
|
||||
(spell_type == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id))
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Mez:
|
||||
case BotSpellTypes::AEMez:
|
||||
if (IsMesmerizeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Charm:
|
||||
if (IsCharmSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Slow:
|
||||
case BotSpellTypes::AESlow:
|
||||
if (IsDetrimentalSpell(spell_id) && IsSlowSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Debuff:
|
||||
case BotSpellTypes::AEDebuff:
|
||||
if (
|
||||
IsDebuffSpell(spell_id) &&
|
||||
!IsHateReduxSpell(spell_id) &&
|
||||
!IsHateSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Cure:
|
||||
case BotSpellTypes::GroupCures:
|
||||
case BotSpellTypes::PetCures:
|
||||
if (IsCureSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Resurrect:
|
||||
if (IsEffectInSpell(spell_id, SE_Revive)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HateRedux:
|
||||
if (IsHateReduxSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::InCombatBuffSong:
|
||||
case BotSpellTypes::OutOfCombatBuffSong:
|
||||
case BotSpellTypes::PreCombatBuffSong:
|
||||
if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsBardSong(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Fear:
|
||||
case BotSpellTypes::AEFear:
|
||||
if (IsFearSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Stun:
|
||||
case BotSpellTypes::AEStun:
|
||||
if (IsDetrimentalSpell(spell_id) && IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HateLine:
|
||||
case BotSpellTypes::AEHateLine:
|
||||
if (IsDetrimentalSpell(spell_id) && IsHateSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::CompleteHeal:
|
||||
case BotSpellTypes::GroupCompleteHeals:
|
||||
case BotSpellTypes::PetCompleteHeals:
|
||||
if (IsCompleteHealSpell(spell_id) || IsGroupCompleteHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::FastHeals:
|
||||
case BotSpellTypes::PetFastHeals:
|
||||
if (IsFastHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::VeryFastHeals:
|
||||
case BotSpellTypes::PetVeryFastHeals:
|
||||
if (IsVeryFastHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::GroupHeals:
|
||||
if (IsRegularGroupHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HoTHeals:
|
||||
case BotSpellTypes::GroupHoTHeals:
|
||||
case BotSpellTypes::PetHoTHeals:
|
||||
if (IsHealOverTimeSpell(spell_id) || IsGroupHealOverTimeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AENukes:
|
||||
if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
!IsAERainSpell(spell_id) &&
|
||||
!IsPBAENukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AERains:
|
||||
if (IsAERainNukeSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::PBAENuke:
|
||||
if (IsPBAENukeSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::ResistBuffs:
|
||||
case BotSpellTypes::PetResistBuffs:
|
||||
if (IsResistanceBuffSpell(spell_id)) {
|
||||
@@ -11587,44 +11838,7 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
return false;
|
||||
case BotSpellTypes::DamageShields:
|
||||
case BotSpellTypes::PetDamageShields:
|
||||
if (IsEffectInSpell(spell_id, SE_DamageShield)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::PBAENuke:
|
||||
if (
|
||||
IsPBAENukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AERains:
|
||||
if (
|
||||
IsAERainNukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case BotSpellTypes::AEStun:
|
||||
case BotSpellTypes::Stun:
|
||||
if (IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AENukes:
|
||||
case BotSpellTypes::Nuke:
|
||||
if (!IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lull:
|
||||
if (IsHarmonySpell(spell_id)) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_DamageShield)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11632,13 +11846,18 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::Teleport:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate)
|
||||
)
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lull:
|
||||
case BotSpellTypes::AELull:
|
||||
if (IsHarmonySpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Succor:
|
||||
if (
|
||||
@@ -11662,25 +11881,21 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Levitate:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Levitate)
|
||||
) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Levitate)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Rune:
|
||||
if (
|
||||
IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) ||
|
||||
IsEffectInSpell(spell_id, SE_Rune)
|
||||
if (IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::WaterBreathing:
|
||||
if (IsEffectInSpell(spell_id, SE_WaterBreathing)) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_WaterBreathing)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11688,29 +11903,22 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::Size:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_ModelSize) ||
|
||||
IsEffectInSpell(spell_id, SE_ChangeHeight)
|
||||
)
|
||||
(IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Invisibility:
|
||||
if (
|
||||
IsEffectInSpell(spell_id, SE_SeeInvis) ||
|
||||
IsInvisibleSpell(spell_id)
|
||||
if (IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_SeeInvis) ||IsInvisibleSpell(spell_id))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::MovementSpeed:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11718,7 +11926,13 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::SendHome:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_GateToHomeCity)
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_GateToHomeCity) ||
|
||||
(
|
||||
teleport_zone.compare("") &&
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -683,7 +683,6 @@ public:
|
||||
void SetSitManaPct(uint8 value) { _SitManaPct = value; }
|
||||
|
||||
// Spell lists
|
||||
void CheckBotSpells();
|
||||
std::list<BotSpellTypeOrder> GetSpellTypesPrioritized(uint8 priority_type);
|
||||
static uint16 GetParentSpellType(uint16 spell_type);
|
||||
static bool IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id);
|
||||
|
||||
@@ -220,6 +220,11 @@ int bot_command_init(void)
|
||||
std::vector<std::pair<std::string, uint8>> injected_bot_command_settings;
|
||||
std::vector<std::string> orphaned_bot_command_settings;
|
||||
|
||||
if (RuleB(Bots, RunSpellTypeChecksOnBoot)) {
|
||||
LogBotSpellTypeChecks("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline.");
|
||||
database.botdb.CheckBotSpells();
|
||||
}
|
||||
|
||||
database.botdb.MapCommandedSpellTypeMinLevels();
|
||||
|
||||
for (auto bcs_iter : bot_command_settings) {
|
||||
@@ -813,7 +818,7 @@ void helper_send_usage_required_bots(Client *bot_owner, uint16 spell_type)
|
||||
auto spell_type_itr = spell_map.find(spell_type);
|
||||
auto class_itr = spell_type_itr->second.find(i);
|
||||
const auto& spell_info = class_itr->second;
|
||||
|
||||
|
||||
if (spell_info.min_level < UINT8_MAX) {
|
||||
found = true;
|
||||
|
||||
|
||||
@@ -2523,6 +2523,142 @@ bool BotDatabase::DeleteBotBlockedBuffs(const uint32 bot_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BotDatabase::CheckBotSpells() {
|
||||
auto spell_list = BotSpellsEntriesRepository::All(content_db);
|
||||
uint16 spell_id;
|
||||
SPDat_Spell_Struct spell;
|
||||
|
||||
for (const auto& s : spell_list) {
|
||||
if (!IsValidSpell(s.spell_id)) {
|
||||
LogBotSpellTypeChecks("{} is an invalid spell", s.spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
spell = spells[s.spell_id];
|
||||
spell_id = spell.id;
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] >= 255) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable by a {} [#{}].", GetSpellName(spell_id), spell_id, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX), s.npc_spells_id);
|
||||
}
|
||||
else {
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.minlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the min level is currently set to {}.",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX),
|
||||
s.npc_spells_id,
|
||||
s.minlevel
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]",
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
spell_id,
|
||||
s.npc_spells_id,
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
s.minlevel,
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX),
|
||||
s.npc_spells_id
|
||||
);
|
||||
}
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] < s.minlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] could be used starting at level {} for a {} [#{}] instead of the current min level of {}.",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX),
|
||||
s.npc_spells_id,
|
||||
s.minlevel
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]",
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
spell_id,
|
||||
s.npc_spells_id,
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
s.minlevel,
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX),
|
||||
s.npc_spells_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.maxlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the max level is currently set to {}.",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)],
|
||||
GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX),
|
||||
s.npc_spells_id,
|
||||
s.maxlevel
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 correct_type = GetCorrectBotSpellType(s.type, spell_id);
|
||||
|
||||
if (RuleB(Bots, UseParentSpellTypeForChecks)) {
|
||||
uint16 parent_type = Bot::GetParentSpellType(correct_type);
|
||||
|
||||
if (s.type == parent_type || s.type == correct_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type != parent_type) {
|
||||
correct_type = parent_type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsPetBotSpellType(s.type)) {
|
||||
correct_type = GetPetBotSpellType(correct_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPetBotSpellType(correct_type) && (spell.target_type != ST_Pet && spell.target_type != ST_SummonedPet)) {
|
||||
correct_type = Bot::GetParentSpellType(correct_type);
|
||||
}
|
||||
|
||||
if (correct_type == s.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type == UINT16_MAX) {
|
||||
LogBotSpellTypeChecks(
|
||||
"{} [#{}] is incorrect. It is currently set as {} [#{}] but the correct type is unknown.",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type,
|
||||
Bot::GetSpellTypeNameByID(correct_type),
|
||||
correct_type
|
||||
);
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spell_id` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]",
|
||||
correct_type,
|
||||
spell_id,
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type,
|
||||
Bot::GetSpellTypeNameByID(correct_type),
|
||||
correct_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BotDatabase::MapCommandedSpellTypeMinLevels() {
|
||||
commanded_spell_type_min_levels.clear();
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ public:
|
||||
bool SaveBotSettings(Mob* m);
|
||||
bool DeleteBotSettings(const uint32 bot_id);
|
||||
|
||||
void CheckBotSpells();
|
||||
void MapCommandedSpellTypeMinLevels();
|
||||
std::map<int32_t, std::map<int32_t, BotSpellTypesByClass>> GetCommandedSpellTypesMinLevels() { return commanded_spell_type_min_levels; }
|
||||
|
||||
|
||||
@@ -2865,132 +2865,3 @@ BotSpell Bot::GetBestBotSpellForCharm(Bot* caster, Mob* target, uint16 spell_typ
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Bot::CheckBotSpells() {
|
||||
auto spell_list = BotSpellsEntriesRepository::All(content_db);
|
||||
uint16 spell_id;
|
||||
SPDat_Spell_Struct spell;
|
||||
uint16 correct_type;
|
||||
uint16 parent_type;
|
||||
|
||||
for (const auto& s : spell_list) {
|
||||
if (!IsValidSpell(s.spell_id)) {
|
||||
LogBotSpellTypeChecks("{} is an invalid spell", s.spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
spell = spells[s.spell_id];
|
||||
spell_id = spell.id;
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] >= 255) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable by a {} [#{}].", GetSpellName(spell_id), spell_id, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX), s.npc_spells_id);
|
||||
}
|
||||
else {
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.minlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the min level is currently set to {}."
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX)
|
||||
, s.npc_spells_id
|
||||
, s.minlevel
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]"
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, spell_id
|
||||
, s.npc_spells_id
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, s.minlevel
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX)
|
||||
, s.npc_spells_id
|
||||
);
|
||||
}
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] < s.minlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] could be used starting at level {} for a {} [#{}] instead of the current min level of {}."
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX)
|
||||
, s.npc_spells_id
|
||||
, s.minlevel
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]"
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, spell_id
|
||||
, s.npc_spells_id
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, s.minlevel
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX)
|
||||
, s.npc_spells_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.maxlevel) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the max level is currently set to {}."
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)]
|
||||
, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX)
|
||||
, s.npc_spells_id
|
||||
, s.maxlevel
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
correct_type = GetCorrectBotSpellType(s.type, spell_id);
|
||||
parent_type = GetParentSpellType(correct_type);
|
||||
|
||||
if (RuleB(Bots, UseParentSpellTypeForChecks)) {
|
||||
if (s.type == parent_type || s.type == correct_type) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsPetBotSpellType(s.type)) {
|
||||
correct_type = GetPetBotSpellType(correct_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (correct_type == s.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type == UINT16_MAX) {
|
||||
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] but the correct type is unknown."
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, GetSpellTypeNameByID(s.type)
|
||||
, s.type
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]"
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, GetSpellTypeNameByID(s.type)
|
||||
, s.type
|
||||
, GetSpellTypeNameByID(correct_type)
|
||||
, correct_type
|
||||
);
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spell_id` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]"
|
||||
, correct_type
|
||||
, spell_id
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, GetSpellTypeNameByID(s.type)
|
||||
, s.type
|
||||
, GetSpellTypeNameByID(correct_type)
|
||||
, correct_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
-16
@@ -2549,40 +2549,59 @@ void Client::ChangeLastName(std::string last_name) {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
|
||||
// Deprecated, this packet does not actually work in ROF2
|
||||
bool Client::ChangeFirstName(const std::string in_firstname, const std::string gmname)
|
||||
{
|
||||
// check duplicate name
|
||||
bool used_name = database.IsNameUsed((const char*) in_firstname);
|
||||
if (used_name) {
|
||||
if (!ChangeFirstName(in_firstname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// update character_
|
||||
if(!database.UpdateName(GetName(), in_firstname))
|
||||
return false;
|
||||
|
||||
// update pp
|
||||
memset(m_pp.name, 0, sizeof(m_pp.name));
|
||||
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname);
|
||||
strcpy(name, m_pp.name);
|
||||
Save();
|
||||
|
||||
// send name update packet
|
||||
auto outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct));
|
||||
GMName_Struct* gmn=(GMName_Struct*)outapp->pBuffer;
|
||||
strn0cpy(gmn->gmname,gmname,64);
|
||||
strn0cpy(gmn->gmname,gmname.c_str(),64);
|
||||
strn0cpy(gmn->oldname,GetName(),64);
|
||||
strn0cpy(gmn->newname,in_firstname,64);
|
||||
strn0cpy(gmn->newname,in_firstname.c_str(),64);
|
||||
gmn->unknown[0] = 1;
|
||||
gmn->unknown[1] = 1;
|
||||
gmn->unknown[2] = 1;
|
||||
entity_list.QueueClients(this, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
// success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::ChangeFirstName(const std::string in_firstname)
|
||||
{
|
||||
// check duplicate name
|
||||
bool used_name = database.IsNameUsed(in_firstname) || database.IsPetNameUsed(in_firstname);
|
||||
if (used_name || !database.CheckNameFilter(in_firstname, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// update character_
|
||||
if(!database.UpdateNameByID(CharacterID(), in_firstname))
|
||||
return false;
|
||||
|
||||
// Send Name Update to Clients
|
||||
SendRename(this, GetName(), in_firstname.c_str());
|
||||
SetName(in_firstname.c_str());
|
||||
|
||||
// update pp
|
||||
memset(m_pp.name, 0, sizeof(m_pp.name));
|
||||
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname.c_str());
|
||||
strcpy(name, m_pp.name);
|
||||
Save();
|
||||
|
||||
// Update the active char in account table
|
||||
database.UpdateLiveChar(in_firstname, AccountID());
|
||||
|
||||
// finally, update the /who list
|
||||
UpdateWho();
|
||||
|
||||
// success
|
||||
ClearNameChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4737,6 +4756,57 @@ bool Client::KeyRingRemove(uint32 item_id)
|
||||
);
|
||||
}
|
||||
|
||||
bool Client::IsNameChangeAllowed() {
|
||||
if (RuleB(Character, AlwaysAllowNameChange)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto k = GetScopedBucketKeys();
|
||||
k.key = "name_change_allowed";
|
||||
|
||||
auto b = DataBucket::GetData(k);
|
||||
if (!b.value.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::ClearNameChange() {
|
||||
if (!IsNameChangeAllowed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto k = GetScopedBucketKeys();
|
||||
k.key = "name_change_allowed";
|
||||
|
||||
DataBucket::DeleteData(k);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::InvokeChangeNameWindow(bool immediate) {
|
||||
if (!IsNameChangeAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet_op = immediate ? OP_InvokeNameChangeImmediate : OP_InvokeNameChangeLazy;
|
||||
|
||||
auto outapp = new EQApplicationPacket(packet_op, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::GrantNameChange() {
|
||||
|
||||
auto k = GetScopedBucketKeys();
|
||||
k.key = "name_change_allowed";
|
||||
k.value = "allowed"; // potentially put a timestamp here
|
||||
DataBucket::SetData(k);
|
||||
|
||||
InvokeChangeNameWindow(true);
|
||||
}
|
||||
|
||||
bool Client::IsPetNameChangeAllowed() {
|
||||
if (RuleB(Pets, AlwaysAllowPetRename)) {
|
||||
return true;
|
||||
|
||||
+6
-1
@@ -332,6 +332,10 @@ public:
|
||||
bool KeyRingClear();
|
||||
bool KeyRingRemove(uint32 item_id);
|
||||
void KeyRingList();
|
||||
bool IsNameChangeAllowed();
|
||||
void InvokeChangeNameWindow(bool immediate = true);
|
||||
bool ClearNameChange();
|
||||
void GrantNameChange();
|
||||
bool IsPetNameChangeAllowed();
|
||||
void GrantPetNameChange();
|
||||
void ClearPetNameChange();
|
||||
@@ -511,7 +515,8 @@ public:
|
||||
bool AutoAttackEnabled() const { return auto_attack; }
|
||||
bool AutoFireEnabled() const { return auto_fire; }
|
||||
|
||||
bool ChangeFirstName(const char* in_firstname,const char* gmname);
|
||||
bool ChangeFirstName(const std::string in_firstname,const std::string gmname);
|
||||
bool ChangeFirstName(const std::string in_firstname);
|
||||
|
||||
void Duck();
|
||||
void Stand();
|
||||
|
||||
+23
-4
@@ -826,6 +826,10 @@ void Client::CompleteConnect()
|
||||
if (IsPetNameChangeAllowed() && !RuleB(Pets, AlwaysAllowPetRename)) {
|
||||
InvokeChangePetName(false);
|
||||
}
|
||||
|
||||
if (IsNameChangeAllowed() && !RuleB(Character, AlwaysAllowNameChange)) {
|
||||
InvokeChangeNameWindow(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
@@ -4256,7 +4260,7 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
|
||||
else {
|
||||
OnDisconnect(true);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4548,14 +4552,14 @@ void Client::Handle_OP_ChangePetName(const EQApplicationPacket *app) {
|
||||
|
||||
auto p = (ChangePetName_Struct *) app->pBuffer;
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
p->response_code = ChangePetNameResponse::NotEligible;
|
||||
p->response_code = ChangeNameResponse::Ineligible;
|
||||
QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
p->response_code = ChangePetNameResponse::Denied;
|
||||
p->response_code = ChangeNameResponse::Denied;
|
||||
if (ChangePetName(p->new_pet_name)) {
|
||||
p->response_code = ChangePetNameResponse::Accepted;
|
||||
p->response_code = ChangeNameResponse::Accepted;
|
||||
}
|
||||
|
||||
QueuePacket(app);
|
||||
@@ -6776,6 +6780,21 @@ void Client::Handle_OP_GMLastName(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size == sizeof(AltChangeName_Struct)) {
|
||||
auto p = (AltChangeName_Struct *) app->pBuffer;
|
||||
|
||||
if (!IsNameChangeAllowed()) {
|
||||
p->response_code = ChangeNameResponse::Ineligible;
|
||||
QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
p->response_code = ChangeFirstName(p->new_name) ? ChangeNameResponse::Accepted : ChangeNameResponse::Denied;
|
||||
QueuePacket(app);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size != sizeof(GMName_Struct)) {
|
||||
LogError("Wrong size: OP_GMNameChange, size=[{}], expected [{}]", app->size, sizeof(GMName_Struct));
|
||||
return;
|
||||
|
||||
@@ -14,7 +14,7 @@ void SetName(Client *c, const Seperator *sep)
|
||||
std::string new_name = sep->arg[2];
|
||||
std::string old_name = t->GetCleanName();
|
||||
|
||||
if (t->ChangeFirstName(new_name.c_str(), c->GetCleanName())) {
|
||||
if (t->ChangeFirstName(new_name, c->GetCleanName())) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -24,17 +24,13 @@ void SetName(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(Chat::White, "Sending player to char select.");
|
||||
|
||||
t->Kick("Name was changed");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Unable to rename {}. Check that the new name '{}' isn't already taken.",
|
||||
"Unable to rename {}. Check that the new name '{}' isn't already taken (Including Pet Names), or isn't invalid",
|
||||
old_name,
|
||||
new_name
|
||||
).c_str()
|
||||
|
||||
@@ -3496,6 +3496,24 @@ std::string Lua_Client::GetAccountBucketRemaining(std::string bucket_name)
|
||||
return self->GetAccountBucketRemaining(bucket_name);
|
||||
}
|
||||
|
||||
void Lua_Client::GrantNameChange()
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->GrantNameChange();
|
||||
}
|
||||
|
||||
bool Lua_Client::IsNameChangeAllowed()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsNameChangeAllowed();
|
||||
}
|
||||
|
||||
bool Lua_Client::ClearNameChange()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->ClearNameChange();
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetBandolierName(uint8 bandolier_slot)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
@@ -3635,6 +3653,7 @@ luabind::scope lua_register_client() {
|
||||
.def("CashReward", &Lua_Client::CashReward)
|
||||
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
|
||||
.def("GrantPetNameChange", &Lua_Client::GrantPetNameChange)
|
||||
.def("ClearNameChange", &Lua_Client::ClearNameChange)
|
||||
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill)
|
||||
@@ -3851,6 +3870,7 @@ luabind::scope lua_register_client() {
|
||||
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8,bool))&Lua_Client::GrantAllAAPoints)
|
||||
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
|
||||
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
|
||||
.def("GrantNameChange", &Lua_Client::GrantNameChange)
|
||||
.def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID)
|
||||
.def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank)
|
||||
.def("HasAugmentEquippedByID", (bool(Lua_Client::*)(uint32))&Lua_Client::HasAugmentEquippedByID)
|
||||
@@ -3881,6 +3901,7 @@ luabind::scope lua_register_client() {
|
||||
.def("IsInAGuild", (bool(Lua_Client::*)(void))&Lua_Client::IsInAGuild)
|
||||
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
|
||||
.def("IsMedding", (bool(Lua_Client::*)(void))&Lua_Client::IsMedding)
|
||||
.def("IsNameChangeAllowed", &Lua_Client::IsNameChangeAllowed)
|
||||
.def("IsRaidGrouped", (bool(Lua_Client::*)(void))&Lua_Client::IsRaidGrouped)
|
||||
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
|
||||
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)
|
||||
|
||||
@@ -609,6 +609,10 @@ public:
|
||||
void ShowZoneShardMenu();
|
||||
void GrantPetNameChange();
|
||||
|
||||
void GrantNameChange();
|
||||
bool IsNameChangeAllowed();
|
||||
bool ClearNameChange();
|
||||
|
||||
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages);
|
||||
|
||||
+4
-1
@@ -131,7 +131,8 @@ Mob::Mob(
|
||||
m_scan_close_mobs_timer(6000),
|
||||
m_see_close_mobs_timer(1000),
|
||||
m_mob_check_moving_timer(1000),
|
||||
bot_attack_flag_timer(10000)
|
||||
bot_attack_flag_timer(10000),
|
||||
m_destroying(false)
|
||||
{
|
||||
mMovementManager = &MobMovementManager::Get();
|
||||
mMovementManager->AddMob(this);
|
||||
@@ -531,6 +532,8 @@ Mob::Mob(
|
||||
|
||||
Mob::~Mob()
|
||||
{
|
||||
m_destroying = true;
|
||||
|
||||
entity_list.RemoveMobFromCloseLists(this);
|
||||
m_close_mobs.clear();
|
||||
|
||||
|
||||
@@ -1510,6 +1510,7 @@ public:
|
||||
|
||||
void ClearDataBucketCache();
|
||||
bool IsGuildmaster() const;
|
||||
bool IsDestroying() const { return m_destroying; }
|
||||
|
||||
protected:
|
||||
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
||||
@@ -1932,6 +1933,7 @@ private:
|
||||
EQ::InventoryProfile m_inv;
|
||||
std::shared_ptr<HealRotation> m_target_of_heal_rotation;
|
||||
bool m_manual_follow;
|
||||
bool m_destroying;
|
||||
|
||||
void SetHeroicStrBonuses(StatBonuses* n);
|
||||
void SetHeroicStaBonuses(StatBonuses* n);
|
||||
|
||||
@@ -3261,6 +3261,21 @@ std::string Perl_Client_GetAccountBucketRemaining(Client* self, std::string buck
|
||||
return self->GetAccountBucketRemaining(bucket_name);
|
||||
}
|
||||
|
||||
void Perl_Client_GrantNameChange(Client* self)
|
||||
{
|
||||
self->GrantNameChange();
|
||||
}
|
||||
|
||||
bool Perl_Client_IsNameChangeAllowed(Client* self)
|
||||
{
|
||||
return self->IsNameChangeAllowed();
|
||||
}
|
||||
|
||||
bool Perl_Client_ClearNameChange(Client* self)
|
||||
{
|
||||
return self->ClearNameChange();
|
||||
}
|
||||
|
||||
std::string Perl_Client_GetBandolierName(Client* self, uint8 bandolier_slot)
|
||||
{
|
||||
return self->GetBandolierName(bandolier_slot);
|
||||
@@ -3393,6 +3408,7 @@ void perl_register_client()
|
||||
package.add("CashReward", &Perl_Client_CashReward);
|
||||
package.add("ChangeLastName", &Perl_Client_ChangeLastName);
|
||||
package.add("GrantPetNameChange", &Perl_Client_GrantPetNameChange);
|
||||
package.add("ClearNameChange", (bool(*)(Client*))&Perl_Client_ClearNameChange);
|
||||
package.add("CharacterID", &Perl_Client_CharacterID);
|
||||
package.add("CheckIncreaseSkill", (bool(*)(Client*, int))&Perl_Client_CheckIncreaseSkill);
|
||||
package.add("CheckIncreaseSkill", (bool(*)(Client*, int, int))&Perl_Client_CheckIncreaseSkill);
|
||||
@@ -3607,6 +3623,7 @@ void perl_register_client()
|
||||
package.add("GrantAllAAPoints", (void(*)(Client*, uint8, bool))&Perl_Client_GrantAllAAPoints);
|
||||
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility);
|
||||
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility);
|
||||
package.add("GrantNameChange", (void(*)(Client*))&Perl_Client_GrantNameChange);
|
||||
package.add("GuildID", &Perl_Client_GuildID);
|
||||
package.add("GuildRank", &Perl_Client_GuildRank);
|
||||
package.add("HasAugmentEquippedByID", &Perl_Client_HasAugmentEquippedByID);
|
||||
@@ -3637,6 +3654,7 @@ void perl_register_client()
|
||||
package.add("IsInAGuild", &Perl_Client_IsInAGuild);
|
||||
package.add("IsLD", &Perl_Client_IsLD);
|
||||
package.add("IsMedding", &Perl_Client_IsMedding);
|
||||
package.add("IsNameChangeAllowed", (bool(*)(Client*))&Perl_Client_IsNameChangeAllowed);
|
||||
package.add("IsRaidGrouped", &Perl_Client_IsRaidGrouped);
|
||||
package.add("IsSitting", &Perl_Client_IsSitting);
|
||||
package.add("IsStanding", &Perl_Client_IsStanding);
|
||||
|
||||
@@ -939,6 +939,12 @@ QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::strin
|
||||
|
||||
Strings::FindReplace(npc_name, "`", "-");
|
||||
|
||||
const std::string& npc_id_and_name = fmt::format(
|
||||
"{}_{}",
|
||||
npc_name,
|
||||
npc_id
|
||||
);
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
@@ -959,13 +965,16 @@ QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::strin
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID ./quests/zone/v0/10.ext
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name ./quests/zone/v0/npc.ext
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext)
|
||||
fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID
|
||||
fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name
|
||||
fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name
|
||||
fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID
|
||||
fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID
|
||||
fmt::format("{}/default", zone_versioned_path), // Zone Default ./quests/zone/v0/default.ext
|
||||
fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name
|
||||
fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext)
|
||||
fmt::format("{}/default", zone_path), // Zone Default
|
||||
fmt::format("{}/default", global_path), // Global Default
|
||||
};
|
||||
|
||||
+2
-3
@@ -1310,15 +1310,14 @@ void QuestManager::rename(std::string name) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (initiator) {
|
||||
std::string current_name = initiator->GetName();
|
||||
if (initiator->ChangeFirstName(name.c_str(), current_name.c_str())) {
|
||||
if (initiator->ChangeFirstName(name)) {
|
||||
initiator->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Successfully renamed to {}, kicking to character select.",
|
||||
"Successfully renamed to {}.",
|
||||
name
|
||||
).c_str()
|
||||
);
|
||||
initiator->Kick("Name was changed.");
|
||||
} else {
|
||||
initiator->Message(
|
||||
Chat::Red,
|
||||
|
||||
@@ -277,6 +277,13 @@ bool Spawn2::Process() {
|
||||
|
||||
npcthis = npc;
|
||||
|
||||
if (!m_entity_variables.empty()) {
|
||||
for (auto &var : m_entity_variables) {
|
||||
npc->SetEntityVariable(var.first, var.second);
|
||||
}
|
||||
m_entity_variables = {};
|
||||
}
|
||||
|
||||
npc->SetResumedFromZoneSuspend(m_resumed_from_zone_suspend);
|
||||
m_resumed_from_zone_suspend = false;
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
inline NPC *GetNPC() const { return npcthis; }
|
||||
inline bool IsResumedFromZoneSuspend() const { return m_resumed_from_zone_suspend; }
|
||||
inline void SetResumedFromZoneSuspend(bool resumed) { m_resumed_from_zone_suspend = resumed; }
|
||||
inline void SetEntityVariables(std::map<std::string, std::string> vars) { m_entity_variables = vars; }
|
||||
|
||||
protected:
|
||||
friend class Zone;
|
||||
@@ -104,6 +105,7 @@ private:
|
||||
bool IsDespawned;
|
||||
uint32 killcount;
|
||||
bool m_resumed_from_zone_suspend = false;
|
||||
std::map<std::string, std::string> m_entity_variables = {};
|
||||
};
|
||||
|
||||
class SpawnCondition {
|
||||
|
||||
+41
-23
@@ -204,6 +204,33 @@ inline std::string GetLootSerialized(Corpse *c)
|
||||
return "";
|
||||
}
|
||||
|
||||
inline std::map<std::string, std::string> GetVariablesDeserialized(const std::string &entity_variables)
|
||||
{
|
||||
std::map<std::string, std::string> deserialized_map;
|
||||
|
||||
if (entity_variables.empty()) {
|
||||
return deserialized_map;
|
||||
}
|
||||
|
||||
if (!Strings::IsValidJson(entity_variables)) {
|
||||
LogZoneState("Invalid JSON data for entity variables");
|
||||
return deserialized_map;
|
||||
}
|
||||
|
||||
try {
|
||||
std::stringstream ss;
|
||||
{
|
||||
ss << entity_variables;
|
||||
cereal::JSONInputArchive ar(ss);
|
||||
ar(deserialized_map);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LogZoneState("Failed to load entity variables [{}]", e.what());
|
||||
}
|
||||
|
||||
return deserialized_map;
|
||||
}
|
||||
|
||||
inline void LoadNPCEntityVariables(NPC *n, const std::string &entity_variables)
|
||||
{
|
||||
if (!RuleB(Zone, StateSaveEntityVariables)) {
|
||||
@@ -214,25 +241,7 @@ inline void LoadNPCEntityVariables(NPC *n, const std::string &entity_variables)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Strings::IsValidJson(entity_variables)) {
|
||||
LogZoneState("Invalid JSON data for NPC [{}]", n->GetNPCTypeID());
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> deserialized_map;
|
||||
try {
|
||||
std::istringstream is(entity_variables);
|
||||
{
|
||||
cereal::JSONInputArchive archive(is);
|
||||
archive(deserialized_map);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
LogZoneState("Failed to load entity variables for NPC [{}] [{}]", n->GetNPCTypeID(), e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &[key, value]: deserialized_map) {
|
||||
for (const auto &[key, value]: GetVariablesDeserialized(entity_variables)) {
|
||||
n->SetEntityVariable(key, value);
|
||||
}
|
||||
}
|
||||
@@ -310,6 +319,11 @@ inline std::vector<uint32_t> GetLootdropIds(const std::vector<ZoneStateSpawnsRep
|
||||
return lootdrop_ids;
|
||||
}
|
||||
|
||||
inline void LoadNPCStatePreSpawn(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStateSpawns &s)
|
||||
{
|
||||
LoadNPCEntityVariables(n, s.entity_variables);
|
||||
}
|
||||
|
||||
inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStateSpawns &s)
|
||||
{
|
||||
if (s.hp > 0) {
|
||||
@@ -329,7 +343,6 @@ inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStat
|
||||
n->SetResumedFromZoneSuspend(false);
|
||||
LoadLootStateData(zone, n, s.loot_data);
|
||||
n->SetResumedFromZoneSuspend(true);
|
||||
LoadNPCEntityVariables(n, s.entity_variables);
|
||||
LoadNPCBuffs(n, s.buffs);
|
||||
|
||||
if (s.is_corpse) {
|
||||
@@ -342,7 +355,9 @@ inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStat
|
||||
n->Depop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
n->SetPosition(s.x, s.y, s.z);
|
||||
n->SetHeading(s.heading);
|
||||
n->SetResumedFromZoneSuspend(true);
|
||||
}
|
||||
|
||||
@@ -403,7 +418,7 @@ bool Zone::LoadZoneState(
|
||||
auto spawn_states = ZoneStateSpawnsRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"zone_id = {} AND instance_id = {} ORDER BY spawn2_id",
|
||||
"zone_id = {} AND instance_id = {} ORDER BY is_zone DESC, spawn2_id ASC",
|
||||
zoneid,
|
||||
zone->GetInstanceID()
|
||||
)
|
||||
@@ -475,6 +490,7 @@ bool Zone::LoadZoneState(
|
||||
if (spawn_time_left == 0) {
|
||||
new_spawn->SetCurrentNPCID(s.npc_id);
|
||||
new_spawn->SetResumedFromZoneSuspend(true);
|
||||
new_spawn->SetEntityVariables(GetVariablesDeserialized(s.entity_variables));
|
||||
}
|
||||
|
||||
spawn2_list.Insert(new_spawn);
|
||||
@@ -511,6 +527,8 @@ bool Zone::LoadZoneState(
|
||||
npc->SetQueuedToCorpse();
|
||||
}
|
||||
|
||||
LoadNPCStatePreSpawn(zone, npc, s);
|
||||
|
||||
entity_list.AddNPC(npc, true, true);
|
||||
|
||||
LoadNPCState(zone, npc, s);
|
||||
@@ -564,7 +582,7 @@ inline void SaveNPCState(NPC *n, ZoneStateSpawnsRepository::ZoneStateSpawns &s)
|
||||
auto buffs = n->GetBuffs();
|
||||
if (buffs) {
|
||||
std::vector<Buffs_Struct> valid_buffs;
|
||||
for (int index = 0; index < n->GetMaxBuffSlots(); index++) {
|
||||
for (int index = 0; index < n->GetMaxBuffSlots(); index++) {
|
||||
if (buffs[index].spellid != 0 && buffs[index].spellid != 65535) {
|
||||
valid_buffs.push_back(buffs[index]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user