mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-28 12:22:25 +00:00
Merge branch 'master' of https://github.com/EQEmu/Server
This commit is contained in:
commit
ae3052fbd1
@ -1,6 +1,35 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
== 2/7/2019 ==
|
||||||
|
Uleat: Put merc and bot classes on the same stance standard (mercs)
|
||||||
|
- Both classes will now use the same stance standard
|
||||||
|
- Pushed stance types up to EQEmu::constants
|
||||||
|
|
||||||
|
== 2/4/2019 ==
|
||||||
|
Uleat: Added command 'profanity' (aliased 'prof')
|
||||||
|
- This is a server-based tool for redacting any language that an admin deems as profanity (socially unacceptable within their community)
|
||||||
|
- Five options are available under this command..
|
||||||
|
-- 'list' - shows the current list of banned words
|
||||||
|
-- 'clear' - clears the current list of banned words
|
||||||
|
-- 'add <word>' - adds <word> to the banned word list
|
||||||
|
-- 'del <word>' - deletes <word> from the banned word list
|
||||||
|
-- 'reload' - forces a reload of the banned word list
|
||||||
|
- All actions are immediate and a world broadcast refreshes other active zones
|
||||||
|
- The system is in stand-by when the list is empty..just add a word to the list to begin censorship
|
||||||
|
- Redaction only occurs on genuine occurences of any banned word
|
||||||
|
-- Banned words are replaced with a series of '*' characters
|
||||||
|
-- Compounded words are ignored to avoid issues with allowed words containing a banned sub-string
|
||||||
|
-- If 'test' is banned, 'testing' will not be banned .. it must be added separately
|
||||||
|
- Extreme care should be exercised when adding words to the banned list..
|
||||||
|
-- Quest failures and limited social interactions may alienate players if they become inhibiting
|
||||||
|
-- System commands are allowed to be processed before redaction occurs in the 'say' channel
|
||||||
|
- A longer list requires more clock cycles to process - so, try to keep them to the most offensible occurrences
|
||||||
|
Uleat: Fix for bots ceasing combat when their 'follow me' mob dies
|
||||||
|
- Bots will revert to their client leash owner (bot owner or client group leader) when their FollowID() mob is no longer valid
|
||||||
|
- Combat will no longer be interrupted in these cases
|
||||||
|
- Does not apply to bot owner death...
|
||||||
|
|
||||||
== 1/26/2019 ==
|
== 1/26/2019 ==
|
||||||
Uleat: Fix for class Bot not honoring NPCType data reference
|
Uleat: Fix for class Bot not honoring NPCType data reference
|
||||||
- Fixes bots not moving on spawn/grouping issue
|
- Fixes bots not moving on spawn/grouping issue
|
||||||
|
|||||||
@ -55,6 +55,7 @@ SET(common_sources
|
|||||||
perl_eqdb.cpp
|
perl_eqdb.cpp
|
||||||
perl_eqdb_res.cpp
|
perl_eqdb_res.cpp
|
||||||
proc_launcher.cpp
|
proc_launcher.cpp
|
||||||
|
profanity_manager.cpp
|
||||||
ptimer.cpp
|
ptimer.cpp
|
||||||
races.cpp
|
races.cpp
|
||||||
rdtsc.cpp
|
rdtsc.cpp
|
||||||
@ -181,6 +182,7 @@ SET(common_headers
|
|||||||
packet_functions.h
|
packet_functions.h
|
||||||
platform.h
|
platform.h
|
||||||
proc_launcher.h
|
proc_launcher.h
|
||||||
|
profanity_manager.h
|
||||||
profiler.h
|
profiler.h
|
||||||
ptimer.h
|
ptimer.h
|
||||||
queue.h
|
queue.h
|
||||||
|
|||||||
@ -118,3 +118,37 @@ EQEmu::bug::CategoryID EQEmu::bug::CategoryNameToCategoryID(const char* category
|
|||||||
|
|
||||||
return catOther;
|
return catOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *EQEmu::constants::GetStanceName(StanceType stance_type) {
|
||||||
|
switch (stance_type) {
|
||||||
|
case stanceUnknown:
|
||||||
|
return "Unknown";
|
||||||
|
case stancePassive:
|
||||||
|
return "Passive";
|
||||||
|
case stanceBalanced:
|
||||||
|
return "Balanced";
|
||||||
|
case stanceEfficient:
|
||||||
|
return "Efficient";
|
||||||
|
case stanceReactive:
|
||||||
|
return "Reactive";
|
||||||
|
case stanceAggressive:
|
||||||
|
return "Aggressive";
|
||||||
|
case stanceAssist:
|
||||||
|
return "Assist";
|
||||||
|
case stanceBurn:
|
||||||
|
return "Burn";
|
||||||
|
case stanceEfficient2:
|
||||||
|
return "Efficient2";
|
||||||
|
case stanceBurnAE:
|
||||||
|
return "BurnAE";
|
||||||
|
default:
|
||||||
|
return "Invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int EQEmu::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
||||||
|
if (stance_type >= EQEmu::constants::stancePassive && stance_type <= EQEmu::constants::stanceBurnAE)
|
||||||
|
return (stance_type - EQEmu::constants::stancePassive);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -203,6 +203,26 @@ namespace EQEmu
|
|||||||
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
||||||
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
||||||
|
|
||||||
|
enum StanceType : int {
|
||||||
|
stanceUnknown = 0,
|
||||||
|
stancePassive,
|
||||||
|
stanceBalanced,
|
||||||
|
stanceEfficient,
|
||||||
|
stanceReactive,
|
||||||
|
stanceAggressive,
|
||||||
|
stanceAssist,
|
||||||
|
stanceBurn,
|
||||||
|
stanceEfficient2,
|
||||||
|
stanceBurnAE
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *GetStanceName(StanceType stance_type);
|
||||||
|
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||||
|
|
||||||
|
const int STANCE_TYPE_FIRST = stancePassive;
|
||||||
|
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||||
|
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||||
|
|
||||||
} /*constants*/
|
} /*constants*/
|
||||||
|
|
||||||
namespace profile {
|
namespace profile {
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "emu_versions.h"
|
#include "emu_versions.h"
|
||||||
|
#include "emu_constants.h"
|
||||||
|
|
||||||
|
|
||||||
bool EQEmu::versions::IsValidClientVersion(ClientVersion client_version)
|
bool EQEmu::versions::IsValidClientVersion(ClientVersion client_version)
|
||||||
@ -493,7 +494,7 @@ EQEmu::expansions::Expansion EQEmu::expansions::ConvertExpansionBitToExpansion(u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 EQEmu::expansions::ConvertExpansionToExpansionMask(Expansion expansion)
|
uint32 EQEmu::expansions::ConvertExpansionToExpansionsMask(Expansion expansion)
|
||||||
{
|
{
|
||||||
switch (expansion) {
|
switch (expansion) {
|
||||||
case Expansion::RoK:
|
case Expansion::RoK:
|
||||||
@ -543,57 +544,15 @@ uint32 EQEmu::expansions::ConvertExpansionToExpansionMask(Expansion expansion)
|
|||||||
|
|
||||||
EQEmu::expansions::Expansion EQEmu::expansions::ConvertClientVersionToExpansion(versions::ClientVersion client_version)
|
EQEmu::expansions::Expansion EQEmu::expansions::ConvertClientVersionToExpansion(versions::ClientVersion client_version)
|
||||||
{
|
{
|
||||||
switch (client_version) {
|
return EQEmu::constants::StaticLookup(client_version)->Expansion;
|
||||||
case versions::ClientVersion::Titanium:
|
|
||||||
return expansions::Expansion::PoR;
|
|
||||||
case versions::ClientVersion::SoF:
|
|
||||||
return expansions::Expansion::SoF;
|
|
||||||
case versions::ClientVersion::SoD:
|
|
||||||
return expansions::Expansion::SoD;
|
|
||||||
case versions::ClientVersion::UF:
|
|
||||||
return expansions::Expansion::UF;
|
|
||||||
case versions::ClientVersion::RoF:
|
|
||||||
case versions::ClientVersion::RoF2:
|
|
||||||
return expansions::Expansion::RoF;
|
|
||||||
default:
|
|
||||||
return expansions::Expansion::EverQuest;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 EQEmu::expansions::ConvertClientVersionToExpansionBit(versions::ClientVersion client_version)
|
uint32 EQEmu::expansions::ConvertClientVersionToExpansionBit(versions::ClientVersion client_version)
|
||||||
{
|
{
|
||||||
switch (client_version) {
|
return EQEmu::constants::StaticLookup(client_version)->ExpansionBit;
|
||||||
case versions::ClientVersion::Titanium:
|
|
||||||
return expansions::bitPoR;
|
|
||||||
case versions::ClientVersion::SoF:
|
|
||||||
return expansions::bitSoF;
|
|
||||||
case versions::ClientVersion::SoD:
|
|
||||||
return expansions::bitSoD;
|
|
||||||
case versions::ClientVersion::UF:
|
|
||||||
return expansions::bitUF;
|
|
||||||
case versions::ClientVersion::RoF:
|
|
||||||
case versions::ClientVersion::RoF2:
|
|
||||||
return expansions::bitRoF;
|
|
||||||
default:
|
|
||||||
return expansions::bitEverQuest;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 EQEmu::expansions::ConvertClientVersionToExpansionMask(versions::ClientVersion client_version)
|
uint32 EQEmu::expansions::ConvertClientVersionToExpansionsMask(versions::ClientVersion client_version)
|
||||||
{
|
{
|
||||||
switch (client_version) {
|
return EQEmu::constants::StaticLookup(client_version)->ExpansionsMask;
|
||||||
case versions::ClientVersion::Titanium:
|
|
||||||
return expansions::maskPoR;
|
|
||||||
case versions::ClientVersion::SoF:
|
|
||||||
return expansions::maskSoF;
|
|
||||||
case versions::ClientVersion::SoD:
|
|
||||||
return expansions::maskSoD;
|
|
||||||
case versions::ClientVersion::UF:
|
|
||||||
return expansions::maskUF;
|
|
||||||
case versions::ClientVersion::RoF:
|
|
||||||
case versions::ClientVersion::RoF2:
|
|
||||||
return expansions::maskRoF;
|
|
||||||
default:
|
|
||||||
return expansions::maskEverQuest;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -210,10 +210,10 @@ namespace EQEmu
|
|||||||
const char* ExpansionName(uint32 expansion_bit);
|
const char* ExpansionName(uint32 expansion_bit);
|
||||||
uint32 ConvertExpansionToExpansionBit(Expansion expansion);
|
uint32 ConvertExpansionToExpansionBit(Expansion expansion);
|
||||||
Expansion ConvertExpansionBitToExpansion(uint32 expansion_bit);
|
Expansion ConvertExpansionBitToExpansion(uint32 expansion_bit);
|
||||||
uint32 ConvertExpansionToExpansionMask(Expansion expansion);
|
uint32 ConvertExpansionToExpansionsMask(Expansion expansion);
|
||||||
Expansion ConvertClientVersionToExpansion(versions::ClientVersion client_version);
|
Expansion ConvertClientVersionToExpansion(versions::ClientVersion client_version);
|
||||||
uint32 ConvertClientVersionToExpansionBit(versions::ClientVersion client_version);
|
uint32 ConvertClientVersionToExpansionBit(versions::ClientVersion client_version);
|
||||||
uint32 ConvertClientVersionToExpansionMask(versions::ClientVersion client_version);
|
uint32 ConvertClientVersionToExpansionsMask(versions::ClientVersion client_version);
|
||||||
|
|
||||||
} /*expansions*/
|
} /*expansions*/
|
||||||
|
|
||||||
|
|||||||
@ -43,17 +43,17 @@ static const EQEmu::constants::LookupEntry constants_static_lookup_entries[EQEmu
|
|||||||
{
|
{
|
||||||
/*[ClientVersion::Unknown] =*/
|
/*[ClientVersion::Unknown] =*/
|
||||||
EQEmu::constants::LookupEntry(
|
EQEmu::constants::LookupEntry(
|
||||||
EQEmu::expansions::Expansion::EverQuest,
|
ClientUnknown::constants::EXPANSION,
|
||||||
ClientUnknown::INULL,
|
ClientUnknown::constants::EXPANSION_BIT,
|
||||||
ClientUnknown::INULL,
|
ClientUnknown::constants::EXPANSIONS_MASK,
|
||||||
ClientUnknown::INULL,
|
ClientUnknown::INULL,
|
||||||
ClientUnknown::INULL
|
ClientUnknown::INULL
|
||||||
),
|
),
|
||||||
/*[ClientVersion::Client62] =*/
|
/*[ClientVersion::Client62] =*/
|
||||||
EQEmu::constants::LookupEntry(
|
EQEmu::constants::LookupEntry(
|
||||||
EQEmu::expansions::Expansion::EverQuest,
|
Client62::constants::EXPANSION,
|
||||||
Client62::INULL,
|
Client62::constants::EXPANSION_BIT,
|
||||||
Client62::INULL,
|
Client62::constants::EXPANSIONS_MASK,
|
||||||
Client62::INULL,
|
Client62::INULL,
|
||||||
Client62::INULL
|
Client62::INULL
|
||||||
),
|
),
|
||||||
@ -1167,7 +1167,7 @@ static const EQEmu::spells::LookupEntry spells_static_lookup_entries[EQEmu::vers
|
|||||||
/*[ClientVersion::UF] =*/
|
/*[ClientVersion::UF] =*/
|
||||||
EQEmu::spells::LookupEntry(
|
EQEmu::spells::LookupEntry(
|
||||||
UF::spells::SPELL_ID_MAX,
|
UF::spells::SPELL_ID_MAX,
|
||||||
SoD::spells::SPELLBOOK_SIZE,
|
UF::spells::SPELLBOOK_SIZE,
|
||||||
UF::spells::SPELL_GEM_COUNT,
|
UF::spells::SPELL_GEM_COUNT,
|
||||||
UF::spells::LONG_BUFFS,
|
UF::spells::LONG_BUFFS,
|
||||||
UF::spells::SHORT_BUFFS,
|
UF::spells::SHORT_BUFFS,
|
||||||
@ -1180,7 +1180,7 @@ static const EQEmu::spells::LookupEntry spells_static_lookup_entries[EQEmu::vers
|
|||||||
/*[ClientVersion::RoF] =*/
|
/*[ClientVersion::RoF] =*/
|
||||||
EQEmu::spells::LookupEntry(
|
EQEmu::spells::LookupEntry(
|
||||||
RoF::spells::SPELL_ID_MAX,
|
RoF::spells::SPELL_ID_MAX,
|
||||||
SoD::spells::SPELLBOOK_SIZE,
|
RoF::spells::SPELLBOOK_SIZE,
|
||||||
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
|
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
|
||||||
RoF::spells::LONG_BUFFS,
|
RoF::spells::LONG_BUFFS,
|
||||||
RoF::spells::SHORT_BUFFS,
|
RoF::spells::SHORT_BUFFS,
|
||||||
@ -1193,7 +1193,7 @@ static const EQEmu::spells::LookupEntry spells_static_lookup_entries[EQEmu::vers
|
|||||||
/*[ClientVersion::RoF2] =*/
|
/*[ClientVersion::RoF2] =*/
|
||||||
EQEmu::spells::LookupEntry(
|
EQEmu::spells::LookupEntry(
|
||||||
RoF2::spells::SPELL_ID_MAX,
|
RoF2::spells::SPELL_ID_MAX,
|
||||||
SoD::spells::SPELLBOOK_SIZE,
|
RoF2::spells::SPELLBOOK_SIZE,
|
||||||
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
|
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
|
||||||
RoF2::spells::LONG_BUFFS,
|
RoF2::spells::LONG_BUFFS,
|
||||||
RoF2::spells::SHORT_BUFFS,
|
RoF2::spells::SHORT_BUFFS,
|
||||||
|
|||||||
@ -243,6 +243,13 @@ namespace ClientUnknown
|
|||||||
const int16 IINVALID = -1;
|
const int16 IINVALID = -1;
|
||||||
const int16 INULL = 0;
|
const int16 INULL = 0;
|
||||||
|
|
||||||
|
namespace constants {
|
||||||
|
const EQEmu::expansions::Expansion EXPANSION = EQEmu::expansions::Expansion::EverQuest;
|
||||||
|
const uint32 EXPANSION_BIT = EQEmu::expansions::bitEverQuest;
|
||||||
|
const uint32 EXPANSIONS_MASK = EQEmu::expansions::maskEverQuest;
|
||||||
|
|
||||||
|
} // namespace constants
|
||||||
|
|
||||||
} /*ClientUnknown*/
|
} /*ClientUnknown*/
|
||||||
|
|
||||||
namespace Client62
|
namespace Client62
|
||||||
@ -250,6 +257,13 @@ namespace Client62
|
|||||||
const int16 IINVALID = -1;
|
const int16 IINVALID = -1;
|
||||||
const int16 INULL = 0;
|
const int16 INULL = 0;
|
||||||
|
|
||||||
|
namespace constants {
|
||||||
|
const EQEmu::expansions::Expansion EXPANSION = EQEmu::expansions::Expansion::EverQuest;
|
||||||
|
const uint32 EXPANSION_BIT = EQEmu::expansions::bitEverQuest;
|
||||||
|
const uint32 EXPANSIONS_MASK = EQEmu::expansions::maskEverQuest;
|
||||||
|
|
||||||
|
} // namespace constants
|
||||||
|
|
||||||
} /*Client62*/
|
} /*Client62*/
|
||||||
|
|
||||||
#endif /*COMMON_EQ_LIMITS_H*/
|
#endif /*COMMON_EQ_LIMITS_H*/
|
||||||
|
|||||||
250
common/profanity_manager.cpp
Normal file
250
common/profanity_manager.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/* EQEMu: Everquest Server Emulator
|
||||||
|
|
||||||
|
Copyright (C) 2001-2019 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "profanity_manager.h"
|
||||||
|
#include "dbcore.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
static std::list<std::string> profanity_list;
|
||||||
|
static bool update_originator_flag = false;
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::LoadProfanityList(DBcore *db) {
|
||||||
|
if (update_originator_flag == true) {
|
||||||
|
update_originator_flag = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!load_database_entries(db))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::UpdateProfanityList(DBcore *db) {
|
||||||
|
if (!load_database_entries(db))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
update_originator_flag = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::DeleteProfanityList(DBcore *db) {
|
||||||
|
if (!clear_database_entries(db))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
update_originator_flag = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::AddProfanity(DBcore *db, const char *profanity) {
|
||||||
|
if (!db || !profanity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string entry(profanity);
|
||||||
|
|
||||||
|
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
|
if (check_for_existing_entry(entry.c_str()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (entry.length() < REDACTION_LENGTH_MIN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
profanity_list.push_back(entry);
|
||||||
|
|
||||||
|
std::string query = "REPLACE INTO `profanity_list` (`word`) VALUES ('";
|
||||||
|
query.append(entry);
|
||||||
|
query.append("')");
|
||||||
|
auto results = db->QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
update_originator_flag = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::RemoveProfanity(DBcore *db, const char *profanity) {
|
||||||
|
if (!db || !profanity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string entry(profanity);
|
||||||
|
|
||||||
|
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
|
if (!check_for_existing_entry(entry.c_str()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
profanity_list.remove(entry);
|
||||||
|
|
||||||
|
std::string query = "DELETE FROM `profanity_list` WHERE `word` LIKE '";
|
||||||
|
query.append(entry);
|
||||||
|
query.append("'");
|
||||||
|
auto results = db->QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
update_originator_flag = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQEmu::ProfanityManager::RedactMessage(char *message) {
|
||||||
|
if (!message)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string test_message(message);
|
||||||
|
// hard-coded max length based on channel message buffer size (4096 bytes)..
|
||||||
|
// ..will need to change or remove if other sources are used for redaction
|
||||||
|
if (test_message.length() < REDACTION_LENGTH_MIN || test_message.length() >= 4096)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
|
for (const auto &iter : profanity_list) { // consider adding textlink checks if it becomes an issue
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t start_pos = 0;
|
||||||
|
|
||||||
|
while (pos != std::string::npos) {
|
||||||
|
pos = test_message.find(iter, start_pos);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((pos + iter.length()) == test_message.length() || !isalpha(test_message.at(pos + iter.length()))) {
|
||||||
|
if (pos == 0 || !isalpha(test_message.at(pos - 1)))
|
||||||
|
memset((message + pos), REDACTION_CHARACTER, iter.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
start_pos = (pos + iter.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQEmu::ProfanityManager::RedactMessage(std::string &message) {
|
||||||
|
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string test_message(const_cast<const std::string&>(message));
|
||||||
|
|
||||||
|
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
|
for (const auto &iter : profanity_list) { // consider adding textlink checks if it becomes an issue
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t start_pos = 0;
|
||||||
|
|
||||||
|
while (pos != std::string::npos) {
|
||||||
|
pos = test_message.find(iter, start_pos);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((pos + iter.length()) == test_message.length() || !isalpha(test_message.at(pos + iter.length()))) {
|
||||||
|
if (pos == 0 || !isalpha(test_message.at(pos - 1)))
|
||||||
|
message.replace(pos, iter.length(), iter.length(), REDACTION_CHARACTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
start_pos = (pos + iter.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::ContainsCensoredLanguage(const char *message) {
|
||||||
|
if (!message)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ContainsCensoredLanguage(std::string(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::ContainsCensoredLanguage(const std::string &message) {
|
||||||
|
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string test_message(message);
|
||||||
|
|
||||||
|
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
|
||||||
|
for (const auto &iter : profanity_list) {
|
||||||
|
if (test_message.find(iter) != std::string::npos)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<std::string> &EQEmu::ProfanityManager::GetProfanityList() {
|
||||||
|
return profanity_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::IsCensorshipActive() {
|
||||||
|
return (profanity_list.size() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::load_database_entries(DBcore *db) {
|
||||||
|
if (!db)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
profanity_list.clear();
|
||||||
|
|
||||||
|
std::string query = "SELECT `word` FROM `profanity_list`";
|
||||||
|
auto results = db->QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
if (std::strlen(row[0]) >= REDACTION_LENGTH_MIN) {
|
||||||
|
std::string entry(row[0]);
|
||||||
|
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||||
|
if (!check_for_existing_entry(entry.c_str()))
|
||||||
|
profanity_list.push_back((std::string)entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::clear_database_entries(DBcore *db) {
|
||||||
|
if (!db)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
profanity_list.clear();
|
||||||
|
|
||||||
|
std::string query = "DELETE FROM `profanity_list`";
|
||||||
|
auto results = db->QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQEmu::ProfanityManager::check_for_existing_entry(const char *profanity) {
|
||||||
|
if (!profanity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto &iter : profanity_list) {
|
||||||
|
if (iter.compare(profanity) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
62
common/profanity_manager.h
Normal file
62
common/profanity_manager.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* EQEMu: Everquest Server Emulator
|
||||||
|
|
||||||
|
Copyright (C) 2001-2019 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
|
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 COMMON_PROFANITY_MANAGER_H
|
||||||
|
#define COMMON_PROFANITY_MANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
|
class DBcore;
|
||||||
|
|
||||||
|
namespace EQEmu
|
||||||
|
{
|
||||||
|
class ProfanityManager {
|
||||||
|
public:
|
||||||
|
static bool LoadProfanityList(DBcore *db);
|
||||||
|
static bool UpdateProfanityList(DBcore *db);
|
||||||
|
static bool DeleteProfanityList(DBcore *db);
|
||||||
|
|
||||||
|
static bool AddProfanity(DBcore *db, const char *profanity);
|
||||||
|
static bool RemoveProfanity(DBcore *db, const char *profanity);
|
||||||
|
|
||||||
|
static void RedactMessage(char *message);
|
||||||
|
static void RedactMessage(std::string &message);
|
||||||
|
|
||||||
|
static bool ContainsCensoredLanguage(const char *message);
|
||||||
|
static bool ContainsCensoredLanguage(const std::string &message);
|
||||||
|
|
||||||
|
static const std::list<std::string> &GetProfanityList();
|
||||||
|
|
||||||
|
static bool IsCensorshipActive();
|
||||||
|
|
||||||
|
static const char REDACTION_CHARACTER = '*';
|
||||||
|
static const int REDACTION_LENGTH_MIN = 3;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool load_database_entries(DBcore *db);
|
||||||
|
static bool clear_database_entries(DBcore *db);
|
||||||
|
static bool check_for_existing_entry(const char *profanity);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*EQEmu*/
|
||||||
|
|
||||||
|
#endif /*COMMON_PROFANITY_MANAGER_H*/
|
||||||
@ -159,6 +159,7 @@
|
|||||||
#define ServerOP_SetWorldTime 0x200B
|
#define ServerOP_SetWorldTime 0x200B
|
||||||
#define ServerOP_GetWorldTime 0x200C
|
#define ServerOP_GetWorldTime 0x200C
|
||||||
#define ServerOP_SyncWorldTime 0x200E
|
#define ServerOP_SyncWorldTime 0x200E
|
||||||
|
#define ServerOP_RefreshCensorship 0x200F
|
||||||
|
|
||||||
#define ServerOP_LSZoneInfo 0x3001
|
#define ServerOP_LSZoneInfo 0x3001
|
||||||
#define ServerOP_LSZoneStart 0x3002
|
#define ServerOP_LSZoneStart 0x3002
|
||||||
|
|||||||
@ -68,16 +68,16 @@ enum SpellTypes : uint32
|
|||||||
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
|
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
|
||||||
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
|
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
|
||||||
SpellType_PreCombatBuff = (1 << 20),
|
SpellType_PreCombatBuff = (1 << 20),
|
||||||
SpellType_PreCombatBuffSong = (1 << 21),
|
SpellType_PreCombatBuffSong = (1 << 21)
|
||||||
|
|
||||||
SpellTypes_Detrimental = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow),
|
|
||||||
SpellTypes_Beneficial = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong),
|
|
||||||
|
|
||||||
SpellTypes_Innate = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root),
|
|
||||||
|
|
||||||
SpellType_Any = 0xFFFFFFFF
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uint32 SPELL_TYPE_MIN = (SpellType_Nuke << 1) - 1;
|
||||||
|
const uint32 SPELL_TYPE_MAX = (SpellType_PreCombatBuffSong << 1) - 1;
|
||||||
|
const uint32 SPELL_TYPE_ANY = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
const uint32 SPELL_TYPES_DETRIMENTAL = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow);
|
||||||
|
const uint32 SPELL_TYPES_BENEFICIAL = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong);
|
||||||
|
const uint32 SPELL_TYPES_INNATE = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root);
|
||||||
|
|
||||||
// These should not be used to determine spell category..
|
// These should not be used to determine spell category..
|
||||||
// They are a graphical affects (effects?) index only
|
// They are a graphical affects (effects?) index only
|
||||||
|
|||||||
@ -30,9 +30,9 @@
|
|||||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9135
|
#define CURRENT_BINARY_DATABASE_VERSION 9136
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9021
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9022
|
||||||
#else
|
#else
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -389,6 +389,7 @@
|
|||||||
9133|2018_11_25_StuckBehavior.sql|SHOW COLUMNS FROM `npc_types` LIKE 'stuck_behavior'|empty|
|
9133|2018_11_25_StuckBehavior.sql|SHOW COLUMNS FROM `npc_types` LIKE 'stuck_behavior'|empty|
|
||||||
9134|2019_01_04_update_global_base_scaling.sql|SELECT * FROM db_version WHERE version >= 9134|empty|
|
9134|2019_01_04_update_global_base_scaling.sql|SELECT * FROM db_version WHERE version >= 9134|empty|
|
||||||
9135|2019_01_10_multi_version_spawns.sql|SHOW COLUMNS FROM `spawn2` LIKE 'version'|contains|unsigned|
|
9135|2019_01_10_multi_version_spawns.sql|SHOW COLUMNS FROM `spawn2` LIKE 'version'|contains|unsigned|
|
||||||
|
9136|2019_02_04_profanity_command.sql|SHOW TABLES LIKE 'profanity_list'|empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
9019|2018_04_12_bots_stop_melee_level.sql|SHOW COLUMNS FROM `bot_data` LIKE 'stop_melee_level'|empty|
|
9019|2018_04_12_bots_stop_melee_level.sql|SHOW COLUMNS FROM `bot_data` LIKE 'stop_melee_level'|empty|
|
||||||
9020|2018_08_13_bots_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `bot_step` = 0|not_empty|
|
9020|2018_08_13_bots_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `bot_step` = 0|not_empty|
|
||||||
9021|2018_10_09_bots_owner_options.sql|SHOW TABLES LIKE 'bot_owner_options'|empty|
|
9021|2018_10_09_bots_owner_options.sql|SHOW TABLES LIKE 'bot_owner_options'|empty|
|
||||||
|
9022|2019_02_07_bots_stance_type_update.sql|SELECT * FROM `bot_spell_casting_chances` WHERE `spell_type_index` = '255' AND `class_id` = '255' AND `stance_index` = '0'|not_empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
-- Update `bot_stances`.`stance_id` to new values
|
||||||
|
UPDATE `bot_stances` SET `stance_id` = '9' WHERE `stance_id` = '6';
|
||||||
|
UPDATE `bot_stances` SET `stance_id` = '7' WHERE `stance_id` = '5';
|
||||||
|
UPDATE `bot_stances` SET `stance_id` = (`stance_id` + 1) WHERE `stance_id` in (0,1,2,3,4);
|
||||||
|
|
||||||
|
-- Update `bot_spell_casting_chances`.`stance_index` to new values
|
||||||
|
UPDATE `bot_spell_casting_chances` SET `stance_index` = '8' WHERE `stance_index` = '6';
|
||||||
|
UPDATE `bot_spell_casting_chances` SET `stance_index` = '6' WHERE `stance_index` = '5';
|
||||||
|
|
||||||
|
-- Update `bot_spell_casting_chances` implicit versioning
|
||||||
|
UPDATE `bot_spell_casting_chances` SET `stance_index` = '1' WHERE `spell_type_index` = '255' AND `class_id` = '255';
|
||||||
10
utils/sql/git/required/2019_02_04_profanity_command.sql
Normal file
10
utils/sql/git/required/2019_02_04_profanity_command.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
DROP TABLE IF EXISTS `profanity_list`;
|
||||||
|
|
||||||
|
CREATE TABLE `profanity_list` (
|
||||||
|
`word` VARCHAR(16) NOT NULL
|
||||||
|
)
|
||||||
|
COLLATE='latin1_swedish_ci'
|
||||||
|
ENGINE=InnoDB
|
||||||
|
;
|
||||||
|
|
||||||
|
REPLACE INTO `command_settings` VALUES ('profanity', 150, 'prof');
|
||||||
@ -172,12 +172,11 @@ void Client::SendExpansionInfo() {
|
|||||||
auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
|
auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
|
||||||
ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
|
ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
// need to rework .. not until full scope of change is accounted for, though
|
|
||||||
if (RuleB(World, UseClientBasedExpansionSettings)) {
|
if (RuleB(World, UseClientBasedExpansionSettings)) {
|
||||||
eis->Expansions = EQEmu::expansions::ConvertClientVersionToExpansionMask(eqs->ClientVersion());
|
eis->Expansions = EQEmu::expansions::ConvertClientVersionToExpansionsMask(eqs->ClientVersion());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eis->Expansions = RuleI(World, ExpansionSettings);
|
eis->Expansions = (RuleI(World, ExpansionSettings) & EQEmu::expansions::ConvertClientVersionToExpansionsMask(eqs->ClientVersion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
|
|||||||
@ -981,6 +981,10 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_RefreshCensorship: {
|
||||||
|
zoneserver_list.SendPacket(pack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ServerOP_SetWorldTime: {
|
case ServerOP_SetWorldTime: {
|
||||||
Log(Logs::Detail, Logs::World_Server, "Received SetWorldTime");
|
Log(Logs::Detail, Logs::World_Server, "Received SetWorldTime");
|
||||||
eqTimeOfDay* newtime = (eqTimeOfDay*)pack->pBuffer;
|
eqTimeOfDay* newtime = (eqTimeOfDay*)pack->pBuffer;
|
||||||
|
|||||||
@ -4514,7 +4514,9 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int &damage, Mob *defender, ExtraAt
|
|||||||
if (defender->IsClient() && defender->GetClass() == WARRIOR)
|
if (defender->IsClient() && defender->GetClass() == WARRIOR)
|
||||||
dmgbonusmod -= 5;
|
dmgbonusmod -= 5;
|
||||||
// 168 defensive
|
// 168 defensive
|
||||||
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect + itembonuses.MeleeMitigationEffect + aabonuses.MeleeMitigationEffect);
|
dmgbonusmod += (defender->spellbonuses.MeleeMitigationEffect +
|
||||||
|
defender->itembonuses.MeleeMitigationEffect +
|
||||||
|
defender->aabonuses.MeleeMitigationEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
damage += damage * dmgbonusmod / 100;
|
damage += damage * dmgbonusmod / 100;
|
||||||
|
|||||||
88
zone/bot.cpp
88
zone/bot.cpp
@ -163,7 +163,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
|||||||
if (!stance_flag && bot_owner)
|
if (!stance_flag && bot_owner)
|
||||||
bot_owner->Message(13, "Could not locate stance for '%s'", GetCleanName());
|
bot_owner->Message(13, "Could not locate stance for '%s'", GetCleanName());
|
||||||
|
|
||||||
SetTaunting((GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) && (GetBotStance() == BotStanceAggressive));
|
SetTaunting((GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) && (GetBotStance() == EQEmu::constants::stanceAggressive));
|
||||||
SetPauseAI(false);
|
SetPauseAI(false);
|
||||||
|
|
||||||
rest_timer.Disable();
|
rest_timer.Disable();
|
||||||
@ -2013,12 +2013,20 @@ bool Bot::Process() {
|
|||||||
if(GetAppearance() == eaDead && GetHP() > 0)
|
if(GetAppearance() == eaDead && GetHP() > 0)
|
||||||
SetAppearance(eaStanding);
|
SetAppearance(eaStanding);
|
||||||
|
|
||||||
|
if (IsMoving()) {
|
||||||
|
ping_timer.Disable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!ping_timer.Enabled())
|
||||||
|
ping_timer.Start(BOT_KEEP_ALIVE_INTERVAL);
|
||||||
|
|
||||||
|
if (ping_timer.Check())
|
||||||
|
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (IsStunned() || IsMezzed())
|
if (IsStunned() || IsMezzed())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!IsMoving() && ping_timer.Check())
|
|
||||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
|
||||||
|
|
||||||
// Bot AI
|
// Bot AI
|
||||||
AI_Process();
|
AI_Process();
|
||||||
return true;
|
return true;
|
||||||
@ -2240,10 +2248,9 @@ void Bot::AI_Process() {
|
|||||||
|
|
||||||
Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr);
|
Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr);
|
||||||
Group* bot_group = GetGroup();
|
Group* bot_group = GetGroup();
|
||||||
Mob* follow_mob = entity_list.GetMob(GetFollowID());
|
|
||||||
|
|
||||||
// Primary reasons for not processing AI
|
// Primary reasons for not processing AI
|
||||||
if (!bot_owner || !bot_group || !follow_mob || !IsAIControlled())
|
if (!bot_owner || !bot_group || !IsAIControlled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (bot_owner->IsDead()) {
|
if (bot_owner->IsDead()) {
|
||||||
@ -2253,11 +2260,18 @@ void Bot::AI_Process() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also need a leash owner (subset of primary AI criteria)
|
// We also need a leash owner and follow mob (subset of primary AI criteria)
|
||||||
Client* leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner);
|
Client* leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner);
|
||||||
if (!leash_owner)
|
if (!leash_owner)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Mob* follow_mob = entity_list.GetMob(GetFollowID());
|
||||||
|
|
||||||
|
if (!follow_mob) {
|
||||||
|
follow_mob = leash_owner;
|
||||||
|
SetFollowID(leash_owner->GetID());
|
||||||
|
}
|
||||||
|
|
||||||
// Berserk updates should occur if primary AI criteria are met
|
// Berserk updates should occur if primary AI criteria are met
|
||||||
if (GetClass() == WARRIOR || GetClass() == BERSERKER) {
|
if (GetClass() == WARRIOR || GetClass() == BERSERKER) {
|
||||||
if (!berserk && GetHP() > 0 && GetHPRatio() < 30.0f) {
|
if (!berserk && GetHP() > 0 && GetHPRatio() < 30.0f) {
|
||||||
@ -2752,7 +2766,7 @@ void Bot::AI_Process() {
|
|||||||
// we can't fight if we don't have a target, are stun/mezzed or dead..
|
// we can't fight if we don't have a target, are stun/mezzed or dead..
|
||||||
// Stop attacking if the target is enraged
|
// Stop attacking if the target is enraged
|
||||||
TEST_TARGET();
|
TEST_TARGET();
|
||||||
if (GetBotStance() == BotStancePassive || (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY())))
|
if (GetBotStance() == EQEmu::constants::stancePassive || (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY())))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// First, special attack per class (kick, backstab etc..)
|
// First, special attack per class (kick, backstab etc..)
|
||||||
@ -2879,7 +2893,7 @@ void Bot::AI_Process() {
|
|||||||
FaceTarget(GetTarget());
|
FaceTarget(GetTarget());
|
||||||
|
|
||||||
// This is a mob that is fleeing either because it has been feared or is low on hitpoints
|
// This is a mob that is fleeing either because it has been feared or is low on hitpoints
|
||||||
if (GetBotStance() != BotStancePassive) {
|
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||||
AI_PursueCastCheck(); // This appears to always return true..can't trust for success/fail
|
AI_PursueCastCheck(); // This appears to always return true..can't trust for success/fail
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2887,7 +2901,7 @@ void Bot::AI_Process() {
|
|||||||
} // end not in combat range
|
} // end not in combat range
|
||||||
|
|
||||||
if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work...
|
if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work...
|
||||||
if (GetBotStance() == BotStancePassive)
|
if (GetBotStance() == EQEmu::constants::stancePassive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (GetTarget() && AI_EngagedCastCheck())
|
if (GetTarget() && AI_EngagedCastCheck())
|
||||||
@ -2945,7 +2959,7 @@ void Bot::AI_Process() {
|
|||||||
// Ok to idle
|
// Ok to idle
|
||||||
if (fm_dist <= GetFollowDistance()) {
|
if (fm_dist <= GetFollowDistance()) {
|
||||||
if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) {
|
if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) {
|
||||||
if (GetBotStance() != BotStancePassive) {
|
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||||
if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD)
|
if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD)
|
||||||
BotMeditate(true);
|
BotMeditate(true);
|
||||||
}
|
}
|
||||||
@ -2990,7 +3004,7 @@ void Bot::AI_Process() {
|
|||||||
|
|
||||||
// Basically, bard bots get a chance to cast idle spells while moving
|
// Basically, bard bots get a chance to cast idle spells while moving
|
||||||
if (IsMoving()) {
|
if (IsMoving()) {
|
||||||
if (GetBotStance() != BotStancePassive) {
|
if (GetBotStance() != EQEmu::constants::stancePassive) {
|
||||||
if (GetClass() == BARD && !spellend_timer.Enabled() && AI_think_timer->Check()) {
|
if (GetClass() == BARD && !spellend_timer.Enabled() && AI_think_timer->Check()) {
|
||||||
AI_IdleCastCheck();
|
AI_IdleCastCheck();
|
||||||
return;
|
return;
|
||||||
@ -8199,7 +8213,7 @@ bool Bot::CheckLoreConflict(const EQEmu::ItemData* item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
||||||
if((iSpellTypes&SpellTypes_Detrimental) != 0) {
|
if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) {
|
||||||
Log(Logs::General, Logs::Error, "Error: detrimental spells requested from AICheckCloseBeneficialSpells!!");
|
Log(Logs::General, Logs::Error, "Error: detrimental spells requested from AICheckCloseBeneficialSpells!!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -8254,19 +8268,19 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
|
|||||||
Group *g = caster->GetGroup();
|
Group *g = caster->GetGroup();
|
||||||
float hpRatioToHeal = 25.0f;
|
float hpRatioToHeal = 25.0f;
|
||||||
switch(caster->GetBotStance()) {
|
switch(caster->GetBotStance()) {
|
||||||
case BotStanceReactive:
|
case EQEmu::constants::stanceReactive:
|
||||||
case BotStanceBalanced:
|
case EQEmu::constants::stanceBalanced:
|
||||||
hpRatioToHeal = 50.0f;
|
hpRatioToHeal = 50.0f;
|
||||||
break;
|
break;
|
||||||
case BotStanceBurn:
|
case EQEmu::constants::stanceBurn:
|
||||||
case BotStanceBurnAE:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
hpRatioToHeal = 20.0f;
|
hpRatioToHeal = 20.0f;
|
||||||
break;
|
break;
|
||||||
case BotStanceAggressive:
|
case EQEmu::constants::stanceAggressive:
|
||||||
case BotStanceEfficient:
|
case EQEmu::constants::stanceEfficient:
|
||||||
default:
|
default:
|
||||||
hpRatioToHeal = 25.0f;
|
hpRatioToHeal = 25.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(g) {
|
if(g) {
|
||||||
@ -8805,11 +8819,11 @@ bool Bot::HasOrMayGetAggro() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Bot::SetDefaultBotStance() {
|
void Bot::SetDefaultBotStance() {
|
||||||
BotStanceType defaultStance = BotStanceBalanced;
|
EQEmu::constants::StanceType defaultStance = EQEmu::constants::stanceBalanced;
|
||||||
if (GetClass() == WARRIOR)
|
if (GetClass() == WARRIOR)
|
||||||
defaultStance = BotStanceAggressive;
|
defaultStance = EQEmu::constants::stanceAggressive;
|
||||||
|
|
||||||
_baseBotStance = BotStancePassive;
|
_baseBotStance = EQEmu::constants::stancePassive;
|
||||||
_botStance = defaultStance;
|
_botStance = defaultStance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9082,18 +9096,6 @@ std::string Bot::CreateSayLink(Client* c, const char* message, const char* name)
|
|||||||
return saylink;
|
return saylink;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::StopMoving() {
|
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQEmu::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||||
if (!ping_timer.Enabled())
|
|
||||||
ping_timer.Start(8000);
|
|
||||||
|
|
||||||
Mob::StopMoving();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bot::StopMoving(float new_heading) {
|
|
||||||
if (!ping_timer.Enabled())
|
|
||||||
ping_timer.Start(8000);
|
|
||||||
|
|
||||||
Mob::StopMoving(new_heading);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
152
zone/bot.h
152
zone/bot.h
@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
#define BOT_LEASH_DISTANCE 250000 // as DSq value (500 units)
|
#define BOT_LEASH_DISTANCE 250000 // as DSq value (500 units)
|
||||||
|
|
||||||
|
#define BOT_KEEP_ALIVE_INTERVAL 5000 // 5 seconds
|
||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
||||||
@ -52,91 +54,7 @@ const int MaxDisciplineTimer = 10;
|
|||||||
const int DisciplineReuseStart = MaxSpellTimer + 1;
|
const int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||||
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||||
|
|
||||||
enum BotStanceType {
|
|
||||||
BotStancePassive,
|
|
||||||
BotStanceBalanced,
|
|
||||||
BotStanceEfficient,
|
|
||||||
BotStanceReactive,
|
|
||||||
BotStanceAggressive,
|
|
||||||
BotStanceBurn,
|
|
||||||
BotStanceBurnAE,
|
|
||||||
BotStanceUnknown,
|
|
||||||
MaxStances = BotStanceUnknown
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BOT_STANCE_COUNT 8
|
|
||||||
#define VALIDBOTSTANCE(x) ((x >= (int)BotStancePassive && x <= (int)BotStanceBurnAE) ? ((BotStanceType)x) : (BotStanceUnknown))
|
|
||||||
|
|
||||||
static const std::string bot_stance_name[BOT_STANCE_COUNT] = {
|
|
||||||
"Passive", // 0
|
|
||||||
"Balanced", // 1
|
|
||||||
"Efficient", // 2
|
|
||||||
"Reactive", // 3
|
|
||||||
"Aggressive", // 4
|
|
||||||
"Burn", // 5
|
|
||||||
"BurnAE", // 6
|
|
||||||
"Unknown" // 7
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* GetBotStanceName(int stance_id) { return bot_stance_name[VALIDBOTSTANCE(stance_id)].c_str(); }
|
|
||||||
|
|
||||||
#define VALIDBOTEQUIPSLOT(x) ((x >= EQEmu::invslot::EQUIPMENT_BEGIN && x <= EQEmu::invslot::EQUIPMENT_END) ? (x) : (EQEmu::invslot::EQUIPMENT_COUNT))
|
|
||||||
|
|
||||||
static const std::string bot_equip_slot_name[EQEmu::invslot::EQUIPMENT_COUNT + 1] =
|
|
||||||
{
|
|
||||||
"Charm", // slotCharm
|
|
||||||
"Ear 1", // slotEar1
|
|
||||||
"Head", // slotHead
|
|
||||||
"Face", // slotFace
|
|
||||||
"Ear 2", // slotEar2
|
|
||||||
"Neck", // slotNeck
|
|
||||||
"Shoulders", // slotShoulders
|
|
||||||
"Arms", // slotArms
|
|
||||||
"Back", // slotBack
|
|
||||||
"Wrist 1", // slotWrist1
|
|
||||||
"Wrist 2", // slotWrist2
|
|
||||||
"Range", // slotRange
|
|
||||||
"Hands", // slotHands
|
|
||||||
"Primary", // slotPrimary
|
|
||||||
"Secondary", // slotSecondary
|
|
||||||
"Finger 1", // slotFinger1
|
|
||||||
"Finger 2", // slotFinger2
|
|
||||||
"Chest", // slotChest
|
|
||||||
"Legs", // slotLegs
|
|
||||||
"Feet", // slotFeet
|
|
||||||
"Waist", // slotWaist
|
|
||||||
"Power Source", // slotPowerSource
|
|
||||||
"Ammo", // slotAmmo
|
|
||||||
"Unknown"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* GetBotEquipSlotName(int slot_id) { return bot_equip_slot_name[VALIDBOTEQUIPSLOT(slot_id)].c_str(); }
|
|
||||||
|
|
||||||
enum SpellTypeIndex {
|
|
||||||
SpellType_NukeIndex,
|
|
||||||
SpellType_HealIndex,
|
|
||||||
SpellType_RootIndex,
|
|
||||||
SpellType_BuffIndex,
|
|
||||||
SpellType_EscapeIndex,
|
|
||||||
SpellType_PetIndex,
|
|
||||||
SpellType_LifetapIndex,
|
|
||||||
SpellType_SnareIndex,
|
|
||||||
SpellType_DOTIndex,
|
|
||||||
SpellType_DispelIndex,
|
|
||||||
SpellType_InCombatBuffIndex,
|
|
||||||
SpellType_MezIndex,
|
|
||||||
SpellType_CharmIndex,
|
|
||||||
SpellType_SlowIndex,
|
|
||||||
SpellType_DebuffIndex,
|
|
||||||
SpellType_CureIndex,
|
|
||||||
SpellType_ResurrectIndex,
|
|
||||||
SpellType_HateReduxIndex,
|
|
||||||
SpellType_InCombatBuffSongIndex,
|
|
||||||
SpellType_OutOfCombatBuffSongIndex,
|
|
||||||
SpellType_PreCombatBuffIndex,
|
|
||||||
SpellType_PreCombatBuffSongIndex,
|
|
||||||
MaxSpellTypes
|
|
||||||
};
|
|
||||||
|
|
||||||
// nHSND negative Healer/Slower/Nuker/Doter
|
// nHSND negative Healer/Slower/Nuker/Doter
|
||||||
// pH positive Healer
|
// pH positive Healer
|
||||||
@ -226,29 +144,35 @@ public:
|
|||||||
BotRoleRaidHealer
|
BotRoleRaidHealer
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EqExpansions { // expansions are off..EQ should be '0'
|
enum SpellTypeIndex : uint32 {
|
||||||
ExpansionNone,
|
spellTypeIndexNuke,
|
||||||
ExpansionEQ,
|
spellTypeIndexHeal,
|
||||||
ExpansionRoK,
|
spellTypeIndexRoot,
|
||||||
ExpansionSoV,
|
spellTypeIndexBuff,
|
||||||
ExpansionSoL,
|
spellTypeIndexEscape,
|
||||||
ExpansionPoP,
|
spellTypeIndexPet,
|
||||||
ExpansionLoY,
|
spellTypeIndexLifetap,
|
||||||
ExpansionLDoN,
|
spellTypeIndexSnare,
|
||||||
ExpansionGoD,
|
spellTypeIndexDot,
|
||||||
ExpansionOoW,
|
spellTypeIndexDispel,
|
||||||
ExpansionDoN,
|
spellTypeIndexInCombatBuff,
|
||||||
ExpansionDoDH,
|
spellTypeIndexMez,
|
||||||
ExpansionPoR,
|
spellTypeIndexCharm,
|
||||||
ExpansionTSS,
|
spellTypeIndexSlow,
|
||||||
ExpansionSoF,
|
spellTypeIndexDebuff,
|
||||||
ExpansionSoD,
|
spellTypeIndexCure,
|
||||||
ExpansionUF,
|
spellTypeIndexResurrect,
|
||||||
ExpansionHoT,
|
spellTypeIndexHateRedux,
|
||||||
ExpansionVoA,
|
spellTypeIndexInCombatBuffSong,
|
||||||
ExpansionRoF
|
spellTypeIndexOutOfCombatBuffSong,
|
||||||
|
spellTypeIndexPreCombatBuff,
|
||||||
|
spellTypeIndexPreCombatBuffSong
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32 SPELL_TYPE_FIRST = spellTypeIndexNuke;
|
||||||
|
static const uint32 SPELL_TYPE_LAST = spellTypeIndexPreCombatBuffSong;
|
||||||
|
static const uint32 SPELL_TYPE_COUNT = SPELL_TYPE_LAST + 1;
|
||||||
|
|
||||||
// Class Constructors
|
// Class Constructors
|
||||||
Bot(NPCType *npcTypeData, Client* botOwner);
|
Bot(NPCType *npcTypeData, Client* botOwner);
|
||||||
Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType *npcTypeData);
|
Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType *npcTypeData);
|
||||||
@ -341,8 +265,6 @@ public:
|
|||||||
virtual int GetRunspeed() const { return (int)((float)_GetRunSpeed() * 1.785714f); }
|
virtual int GetRunspeed() const { return (int)((float)_GetRunSpeed() * 1.785714f); }
|
||||||
virtual void WalkTo(float x, float y, float z);
|
virtual void WalkTo(float x, float y, float z);
|
||||||
virtual void RunTo(float x, float y, float z);
|
virtual void RunTo(float x, float y, float z);
|
||||||
virtual void StopMoving();
|
|
||||||
virtual void StopMoving(float new_heading);
|
|
||||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
||||||
bool GetNeedsCured(Mob *tar);
|
bool GetNeedsCured(Mob *tar);
|
||||||
@ -519,7 +441,7 @@ public:
|
|||||||
virtual bool IsBot() const { return true; }
|
virtual bool IsBot() const { return true; }
|
||||||
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
|
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
|
||||||
BotRoleType GetBotRole() { return _botRole; }
|
BotRoleType GetBotRole() { return _botRole; }
|
||||||
BotStanceType GetBotStance() { return _botStance; }
|
EQEmu::constants::StanceType GetBotStance() { return _botStance; }
|
||||||
uint8 GetChanceToCastBySpellType(uint32 spellType);
|
uint8 GetChanceToCastBySpellType(uint32 spellType);
|
||||||
|
|
||||||
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
|
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
|
||||||
@ -633,7 +555,12 @@ public:
|
|||||||
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
|
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
|
||||||
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
||||||
void SetBotRole(BotRoleType botRole) { _botRole = botRole; }
|
void SetBotRole(BotRoleType botRole) { _botRole = botRole; }
|
||||||
void SetBotStance(BotStanceType botStance) { _botStance = ((botStance != BotStanceUnknown) ? (botStance) : (BotStancePassive)); }
|
void SetBotStance(EQEmu::constants::StanceType botStance) {
|
||||||
|
if (botStance >= EQEmu::constants::stancePassive && botStance <= EQEmu::constants::stanceBurnAE)
|
||||||
|
_botStance = botStance;
|
||||||
|
else
|
||||||
|
_botStance = EQEmu::constants::stancePassive;
|
||||||
|
}
|
||||||
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
||||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||||
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
||||||
@ -727,8 +654,8 @@ private:
|
|||||||
uint32 _lastZoneId;
|
uint32 _lastZoneId;
|
||||||
bool _rangerAutoWeaponSelect;
|
bool _rangerAutoWeaponSelect;
|
||||||
BotRoleType _botRole;
|
BotRoleType _botRole;
|
||||||
BotStanceType _botStance;
|
EQEmu::constants::StanceType _botStance;
|
||||||
BotStanceType _baseBotStance;
|
EQEmu::constants::StanceType _baseBotStance;
|
||||||
unsigned int RestRegenHP;
|
unsigned int RestRegenHP;
|
||||||
unsigned int RestRegenMana;
|
unsigned int RestRegenMana;
|
||||||
unsigned int RestRegenEndurance;
|
unsigned int RestRegenEndurance;
|
||||||
@ -792,6 +719,9 @@ private:
|
|||||||
bool LoadPet(); // Load and spawn bot pet if there is one
|
bool LoadPet(); // Load and spawn bot pet if there is one
|
||||||
bool SavePet(); // Save and depop bot pet if there is one
|
bool SavePet(); // Save and depop bot pet if there is one
|
||||||
bool DeletePet();
|
bool DeletePet();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQEmu::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOTS
|
#endif // BOTS
|
||||||
|
|||||||
@ -4249,7 +4249,7 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clone_stance = BotStancePassive;
|
int clone_stance = EQEmu::constants::stancePassive;
|
||||||
if (!botdb.LoadStance(my_bot->GetBotID(), clone_stance))
|
if (!botdb.LoadStance(my_bot->GetBotID(), clone_stance))
|
||||||
c->Message(m_fail, "%s for bot '%s'", BotDatabase::fail::LoadStance(), my_bot->GetCleanName());
|
c->Message(m_fail, "%s for bot '%s'", BotDatabase::fail::LoadStance(), my_bot->GetCleanName());
|
||||||
if (!botdb.SaveStance(clone_id, clone_stance))
|
if (!botdb.SaveStance(clone_id, clone_stance))
|
||||||
@ -5160,29 +5160,34 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
|
|||||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_stance", sep->arg[0], "botstance"))
|
if (helper_command_alias_fail(c, "bot_subcommand_bot_stance", sep->arg[0], "botstance"))
|
||||||
return;
|
return;
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
c->Message(m_usage, "usage: %s [current | value: 0-6] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]);
|
c->Message(m_usage, "usage: %s [current | value: 1-9] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]);
|
||||||
c->Message(m_note, "value: %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s)",
|
c->Message(m_note, "value: %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s)",
|
||||||
BotStancePassive, GetBotStanceName(BotStancePassive),
|
EQEmu::constants::stancePassive, EQEmu::constants::GetStanceName(EQEmu::constants::stancePassive),
|
||||||
BotStanceBalanced, GetBotStanceName(BotStanceBalanced),
|
EQEmu::constants::stanceBalanced, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBalanced),
|
||||||
BotStanceEfficient, GetBotStanceName(BotStanceEfficient),
|
EQEmu::constants::stanceEfficient, EQEmu::constants::GetStanceName(EQEmu::constants::stanceEfficient),
|
||||||
BotStanceReactive, GetBotStanceName(BotStanceReactive),
|
EQEmu::constants::stanceReactive, EQEmu::constants::GetStanceName(EQEmu::constants::stanceReactive),
|
||||||
BotStanceAggressive, GetBotStanceName(BotStanceAggressive),
|
EQEmu::constants::stanceAggressive, EQEmu::constants::GetStanceName(EQEmu::constants::stanceAggressive),
|
||||||
BotStanceBurn, GetBotStanceName(BotStanceBurn),
|
EQEmu::constants::stanceAssist, EQEmu::constants::GetStanceName(EQEmu::constants::stanceAssist),
|
||||||
BotStanceBurnAE, GetBotStanceName(BotStanceBurnAE)
|
EQEmu::constants::stanceBurn, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBurn),
|
||||||
|
EQEmu::constants::stanceEfficient2, EQEmu::constants::GetStanceName(EQEmu::constants::stanceEfficient2),
|
||||||
|
EQEmu::constants::stanceBurnAE, EQEmu::constants::GetStanceName(EQEmu::constants::stanceBurnAE)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName);
|
int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName);
|
||||||
|
|
||||||
bool current_flag = false;
|
bool current_flag = false;
|
||||||
auto bst = BotStanceUnknown;
|
auto bst = EQEmu::constants::stanceUnknown;
|
||||||
|
|
||||||
if (!strcasecmp(sep->arg[1], "current"))
|
if (!strcasecmp(sep->arg[1], "current"))
|
||||||
current_flag = true;
|
current_flag = true;
|
||||||
else if (sep->IsNumber(1))
|
else if (sep->IsNumber(1)) {
|
||||||
bst = VALIDBOTSTANCE(atoi(sep->arg[1]));
|
bst = (EQEmu::constants::StanceType)atoi(sep->arg[1]);
|
||||||
|
if (bst < EQEmu::constants::stanceUnknown || bst > EQEmu::constants::stanceBurnAE)
|
||||||
|
bst = EQEmu::constants::stanceUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
if (!current_flag && bst == BotStanceUnknown) {
|
if (!current_flag && bst == EQEmu::constants::stanceUnknown) {
|
||||||
c->Message(m_fail, "A [current] argument or valid numeric [value] is required to use this command");
|
c->Message(m_fail, "A [current] argument or valid numeric [value] is required to use this command");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -5200,7 +5205,12 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
|
|||||||
bot_iter->Save();
|
bot_iter->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bot::BotGroupSay(bot_iter, "My current stance is '%s' (%u)", GetBotStanceName(bot_iter->GetBotStance()), bot_iter->GetBotStance());
|
Bot::BotGroupSay(
|
||||||
|
bot_iter,
|
||||||
|
"My current stance is '%s' (%i)",
|
||||||
|
EQEmu::constants::GetStanceName(bot_iter->GetBotStance()),
|
||||||
|
bot_iter->GetBotStance()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7220,7 +7230,7 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
inst = my_bot->CastToBot()->GetBotItem(i);
|
inst = my_bot->CastToBot()->GetBotItem(i);
|
||||||
if (!inst || !inst->GetItem()) {
|
if (!inst || !inst->GetItem()) {
|
||||||
c->Message(m_message, "I need something for my %s (slot %i)", GetBotEquipSlotName(i), i);
|
c->Message(m_message, "I need something for my %s (slot %i)", EQEmu::invslot::GetInvPossessionsSlotName(i), i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7230,7 +7240,7 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
linker.SetItemInst(inst);
|
linker.SetItemInst(inst);
|
||||||
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), GetBotEquipSlotName(i), i);
|
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), EQEmu::invslot::GetInvPossessionsSlotName(i), i);
|
||||||
|
|
||||||
++inventory_count;
|
++inventory_count;
|
||||||
}
|
}
|
||||||
@ -7333,14 +7343,14 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
|||||||
case EQEmu::invslot::slotWaist:
|
case EQEmu::invslot::slotWaist:
|
||||||
case EQEmu::invslot::slotPowerSource:
|
case EQEmu::invslot::slotPowerSource:
|
||||||
case EQEmu::invslot::slotAmmo:
|
case EQEmu::invslot::slotAmmo:
|
||||||
c->Message(m_message, "My %s is %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already")));
|
c->Message(m_message, "My %s is %s unequipped", EQEmu::invslot::GetInvPossessionsSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||||
break;
|
break;
|
||||||
case EQEmu::invslot::slotShoulders:
|
case EQEmu::invslot::slotShoulders:
|
||||||
case EQEmu::invslot::slotArms:
|
case EQEmu::invslot::slotArms:
|
||||||
case EQEmu::invslot::slotHands:
|
case EQEmu::invslot::slotHands:
|
||||||
case EQEmu::invslot::slotLegs:
|
case EQEmu::invslot::slotLegs:
|
||||||
case EQEmu::invslot::slotFeet:
|
case EQEmu::invslot::slotFeet:
|
||||||
c->Message(m_message, "My %s are %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already")));
|
c->Message(m_message, "My %s are %s unequipped", EQEmu::invslot::GetInvPossessionsSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
c->Message(m_fail, "I'm soo confused...");
|
c->Message(m_fail, "I'm soo confused...");
|
||||||
@ -7383,7 +7393,7 @@ void bot_subcommand_inventory_window(Client *c, const Seperator *sep)
|
|||||||
item = inst->GetItem();
|
item = inst->GetItem();
|
||||||
|
|
||||||
window_text.append("<c \"#FFFFFF\">");
|
window_text.append("<c \"#FFFFFF\">");
|
||||||
window_text.append(GetBotEquipSlotName(i));
|
window_text.append(EQEmu::invslot::GetInvPossessionsSlotName(i));
|
||||||
window_text.append(": ");
|
window_text.append(": ");
|
||||||
if (item) {
|
if (item) {
|
||||||
//window_text.append("</c>");
|
//window_text.append("</c>");
|
||||||
|
|||||||
@ -83,12 +83,8 @@ bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8 spell_casting_chances[MaxSpellTypes][PLAYER_CLASS_COUNT][MaxStances][cntHSND];
|
|
||||||
|
|
||||||
bool BotDatabase::LoadBotSpellCastingChances()
|
bool BotDatabase::LoadBotSpellCastingChances()
|
||||||
{
|
{
|
||||||
memset(spell_casting_chances, 0, sizeof(spell_casting_chances));
|
|
||||||
|
|
||||||
query =
|
query =
|
||||||
"SELECT"
|
"SELECT"
|
||||||
" `spell_type_index`,"
|
" `spell_type_index`,"
|
||||||
@ -119,14 +115,14 @@ bool BotDatabase::LoadBotSpellCastingChances()
|
|||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
uint8 spell_type_index = atoi(row[0]);
|
uint8 spell_type_index = atoi(row[0]);
|
||||||
if (spell_type_index >= MaxSpellTypes)
|
if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
|
||||||
continue;
|
continue;
|
||||||
uint8 class_index = atoi(row[1]);
|
uint8 class_index = atoi(row[1]);
|
||||||
if (class_index < WARRIOR || class_index > BERSERKER)
|
if (class_index < WARRIOR || class_index > BERSERKER)
|
||||||
continue;
|
continue;
|
||||||
--class_index;
|
--class_index;
|
||||||
uint8 stance_index = atoi(row[2]);
|
uint8 stance_index = atoi(row[2]);
|
||||||
if (stance_index >= MaxStances)
|
if (stance_index >= EQEmu::constants::STANCE_TYPE_COUNT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 conditional_index = nHSND; conditional_index < cntHSND; ++conditional_index) {
|
for (uint8 conditional_index = nHSND; conditional_index < cntHSND; ++conditional_index) {
|
||||||
@ -136,7 +132,7 @@ bool BotDatabase::LoadBotSpellCastingChances()
|
|||||||
if (value > 100)
|
if (value > 100)
|
||||||
value = 100;
|
value = 100;
|
||||||
|
|
||||||
spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index] = value;
|
Bot::spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,7 +873,7 @@ bool BotDatabase::LoadStance(Bot* bot_inst, bool& stance_flag)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
bot_inst->SetBotStance((BotStanceType)atoi(row[0]));
|
bot_inst->SetBotStance((EQEmu::constants::StanceType)atoi(row[0]));
|
||||||
stance_flag = true;
|
stance_flag = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2853,16 +2849,16 @@ bool BotDatabase::DeleteAllHealRotations(const uint32 owner_id)
|
|||||||
/* Bot miscellaneous functions */
|
/* Bot miscellaneous functions */
|
||||||
uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index) // class_index is 0-based
|
uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index) // class_index is 0-based
|
||||||
{
|
{
|
||||||
if (spell_type_index >= MaxSpellTypes)
|
if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
|
||||||
return 0;
|
return 0;
|
||||||
if (class_index >= PLAYER_CLASS_COUNT)
|
if (class_index >= PLAYER_CLASS_COUNT)
|
||||||
return 0;
|
return 0;
|
||||||
if (stance_index >= MaxStances)
|
if (stance_index >= EQEmu::constants::STANCE_TYPE_COUNT)
|
||||||
return 0;
|
return 0;
|
||||||
if (conditional_index >= cntHSND)
|
if (conditional_index >= cntHSND)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index];
|
return Bot::spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -192,25 +192,24 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
else {
|
else {
|
||||||
float hpRatioToCast = 0.0f;
|
float hpRatioToCast = 0.0f;
|
||||||
|
|
||||||
switch(this->GetBotStance())
|
switch(this->GetBotStance()) {
|
||||||
{
|
case EQEmu::constants::stanceEfficient:
|
||||||
case BotStanceEfficient:
|
case EQEmu::constants::stanceAggressive:
|
||||||
case BotStanceAggressive:
|
hpRatioToCast = isPrimaryHealer?90.0f:50.0f;
|
||||||
hpRatioToCast = isPrimaryHealer?90.0f:50.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceBalanced:
|
||||||
case BotStanceBalanced:
|
hpRatioToCast = isPrimaryHealer?95.0f:75.0f;
|
||||||
hpRatioToCast = isPrimaryHealer?95.0f:75.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceReactive:
|
||||||
case BotStanceReactive:
|
hpRatioToCast = isPrimaryHealer?100.0f:90.0f;
|
||||||
hpRatioToCast = isPrimaryHealer?100.0f:90.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceBurn:
|
||||||
case BotStanceBurn:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
case BotStanceBurnAE:
|
hpRatioToCast = isPrimaryHealer?75.0f:25.0f;
|
||||||
hpRatioToCast = isPrimaryHealer?75.0f:25.0f;
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
hpRatioToCast = isPrimaryHealer?100.0f:0.0f;
|
||||||
hpRatioToCast = isPrimaryHealer?100.0f:0.0f;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we're at specified mana % or below, don't heal as hybrid
|
//If we're at specified mana % or below, don't heal as hybrid
|
||||||
@ -381,23 +380,22 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
{
|
{
|
||||||
float manaRatioToCast = 75.0f;
|
float manaRatioToCast = 75.0f;
|
||||||
|
|
||||||
switch(this->GetBotStance())
|
switch(this->GetBotStance()) {
|
||||||
{
|
case EQEmu::constants::stanceEfficient:
|
||||||
case BotStanceEfficient:
|
manaRatioToCast = 90.0f;
|
||||||
manaRatioToCast = 90.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceBalanced:
|
||||||
case BotStanceBalanced:
|
case EQEmu::constants::stanceAggressive:
|
||||||
case BotStanceAggressive:
|
manaRatioToCast = 75.0f;
|
||||||
manaRatioToCast = 75.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceReactive:
|
||||||
case BotStanceReactive:
|
case EQEmu::constants::stanceBurn:
|
||||||
case BotStanceBurn:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
case BotStanceBurnAE:
|
manaRatioToCast = 50.0f;
|
||||||
manaRatioToCast = 50.0f;
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
manaRatioToCast = 75.0f;
|
||||||
manaRatioToCast = 75.0f;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we're at specified mana % or below, don't rune as enchanter
|
//If we're at specified mana % or below, don't rune as enchanter
|
||||||
@ -461,25 +459,24 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
{
|
{
|
||||||
float manaRatioToCast = 75.0f;
|
float manaRatioToCast = 75.0f;
|
||||||
|
|
||||||
switch(this->GetBotStance())
|
switch(this->GetBotStance()) {
|
||||||
{
|
case EQEmu::constants::stanceEfficient:
|
||||||
case BotStanceEfficient:
|
manaRatioToCast = 90.0f;
|
||||||
manaRatioToCast = 90.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceBalanced:
|
||||||
case BotStanceBalanced:
|
manaRatioToCast = 75.0f;
|
||||||
manaRatioToCast = 75.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceReactive:
|
||||||
case BotStanceReactive:
|
case EQEmu::constants::stanceAggressive:
|
||||||
case BotStanceAggressive:
|
manaRatioToCast = 50.0f;
|
||||||
manaRatioToCast = 50.0f;
|
break;
|
||||||
break;
|
case EQEmu::constants::stanceBurn:
|
||||||
case BotStanceBurn:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
case BotStanceBurnAE:
|
manaRatioToCast = 25.0f;
|
||||||
manaRatioToCast = 25.0f;
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
manaRatioToCast = 50.0f;
|
||||||
manaRatioToCast = 50.0f;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we're at specified mana % or below, don't nuke as cleric or enchanter
|
//If we're at specified mana % or below, don't nuke as cleric or enchanter
|
||||||
@ -1310,7 +1307,7 @@ bool Bot::AI_EngagedCastCheck() {
|
|||||||
AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting.
|
AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting.
|
||||||
|
|
||||||
uint8 botClass = GetClass();
|
uint8 botClass = GetClass();
|
||||||
BotStanceType botStance = GetBotStance();
|
EQEmu::constants::StanceType botStance = GetBotStance();
|
||||||
bool mayGetAggro = HasOrMayGetAggro();
|
bool mayGetAggro = HasOrMayGetAggro();
|
||||||
|
|
||||||
Log(Logs::Detail, Logs::AI, "Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells.");
|
Log(Logs::Detail, Logs::AI, "Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells.");
|
||||||
@ -2573,79 +2570,79 @@ bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) {
|
|||||||
|
|
||||||
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||||
{
|
{
|
||||||
uint8 spell_type_index = MaxSpellTypes;
|
uint8 spell_type_index = SPELL_TYPE_COUNT;
|
||||||
switch (spellType) {
|
switch (spellType) {
|
||||||
case SpellType_Nuke:
|
case SpellType_Nuke:
|
||||||
spell_type_index = SpellType_NukeIndex;
|
spell_type_index = spellTypeIndexNuke;
|
||||||
break;
|
break;
|
||||||
case SpellType_Heal:
|
case SpellType_Heal:
|
||||||
spell_type_index = SpellType_HealIndex;
|
spell_type_index = spellTypeIndexHeal;
|
||||||
break;
|
break;
|
||||||
case SpellType_Root:
|
case SpellType_Root:
|
||||||
spell_type_index = SpellType_RootIndex;
|
spell_type_index = spellTypeIndexRoot;
|
||||||
break;
|
break;
|
||||||
case SpellType_Buff:
|
case SpellType_Buff:
|
||||||
spell_type_index = SpellType_BuffIndex;
|
spell_type_index = spellTypeIndexBuff;
|
||||||
break;
|
break;
|
||||||
case SpellType_Escape:
|
case SpellType_Escape:
|
||||||
spell_type_index = SpellType_EscapeIndex;
|
spell_type_index = spellTypeIndexEscape;
|
||||||
break;
|
break;
|
||||||
case SpellType_Pet:
|
case SpellType_Pet:
|
||||||
spell_type_index = SpellType_PetIndex;
|
spell_type_index = spellTypeIndexPet;
|
||||||
break;
|
break;
|
||||||
case SpellType_Lifetap:
|
case SpellType_Lifetap:
|
||||||
spell_type_index = SpellType_LifetapIndex;
|
spell_type_index = spellTypeIndexLifetap;
|
||||||
break;
|
break;
|
||||||
case SpellType_Snare:
|
case SpellType_Snare:
|
||||||
spell_type_index = SpellType_SnareIndex;
|
spell_type_index = spellTypeIndexSnare;
|
||||||
break;
|
break;
|
||||||
case SpellType_DOT:
|
case SpellType_DOT:
|
||||||
spell_type_index = SpellType_DOTIndex;
|
spell_type_index = spellTypeIndexDot;
|
||||||
break;
|
break;
|
||||||
case SpellType_Dispel:
|
case SpellType_Dispel:
|
||||||
spell_type_index = SpellType_DispelIndex;
|
spell_type_index = spellTypeIndexDispel;
|
||||||
break;
|
break;
|
||||||
case SpellType_InCombatBuff:
|
case SpellType_InCombatBuff:
|
||||||
spell_type_index = SpellType_InCombatBuffIndex;
|
spell_type_index = spellTypeIndexInCombatBuff;
|
||||||
break;
|
break;
|
||||||
case SpellType_Mez:
|
case SpellType_Mez:
|
||||||
spell_type_index = SpellType_MezIndex;
|
spell_type_index = spellTypeIndexMez;
|
||||||
break;
|
break;
|
||||||
case SpellType_Charm:
|
case SpellType_Charm:
|
||||||
spell_type_index = SpellType_CharmIndex;
|
spell_type_index = spellTypeIndexCharm;
|
||||||
break;
|
break;
|
||||||
case SpellType_Slow:
|
case SpellType_Slow:
|
||||||
spell_type_index = SpellType_SlowIndex;
|
spell_type_index = spellTypeIndexSlow;
|
||||||
break;
|
break;
|
||||||
case SpellType_Debuff:
|
case SpellType_Debuff:
|
||||||
spell_type_index = SpellType_DebuffIndex;
|
spell_type_index = spellTypeIndexDebuff;
|
||||||
break;
|
break;
|
||||||
case SpellType_Cure:
|
case SpellType_Cure:
|
||||||
spell_type_index = SpellType_CureIndex;
|
spell_type_index = spellTypeIndexCure;
|
||||||
break;
|
break;
|
||||||
case SpellType_Resurrect:
|
case SpellType_Resurrect:
|
||||||
spell_type_index = SpellType_ResurrectIndex;
|
spell_type_index = spellTypeIndexResurrect;
|
||||||
break;
|
break;
|
||||||
case SpellType_HateRedux:
|
case SpellType_HateRedux:
|
||||||
spell_type_index = SpellType_HateReduxIndex;
|
spell_type_index = spellTypeIndexHateRedux;
|
||||||
break;
|
break;
|
||||||
case SpellType_InCombatBuffSong:
|
case SpellType_InCombatBuffSong:
|
||||||
spell_type_index = SpellType_InCombatBuffSongIndex;
|
spell_type_index = spellTypeIndexInCombatBuffSong;
|
||||||
break;
|
break;
|
||||||
case SpellType_OutOfCombatBuffSong:
|
case SpellType_OutOfCombatBuffSong:
|
||||||
spell_type_index = SpellType_OutOfCombatBuffSongIndex;
|
spell_type_index = spellTypeIndexOutOfCombatBuffSong;
|
||||||
break;
|
break;
|
||||||
case SpellType_PreCombatBuff:
|
case SpellType_PreCombatBuff:
|
||||||
spell_type_index = SpellType_PreCombatBuffIndex;
|
spell_type_index = spellTypeIndexPreCombatBuff;
|
||||||
break;
|
break;
|
||||||
case SpellType_PreCombatBuffSong:
|
case SpellType_PreCombatBuffSong:
|
||||||
spell_type_index = SpellType_PreCombatBuffSongIndex;
|
spell_type_index = spellTypeIndexPreCombatBuffSong;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spell_type_index = MaxSpellTypes;
|
spell_type_index = SPELL_TYPE_COUNT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (spell_type_index >= MaxSpellTypes)
|
if (spell_type_index >= SPELL_TYPE_COUNT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint8 class_index = GetClass();
|
uint8 class_index = GetClass();
|
||||||
@ -2653,11 +2650,13 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
|||||||
return 0;
|
return 0;
|
||||||
--class_index;
|
--class_index;
|
||||||
|
|
||||||
uint8 stance_index = (uint8)GetBotStance();
|
EQEmu::constants::StanceType stance_type = GetBotStance();
|
||||||
if (stance_index >= MaxStances)
|
if (stance_type < EQEmu::constants::stancePassive || stance_type > EQEmu::constants::stanceBurnAE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
uint8 stance_index = EQEmu::constants::ConvertStanceTypeToIndex(stance_type);
|
||||||
uint8 type_index = nHSND;
|
uint8 type_index = nHSND;
|
||||||
|
|
||||||
if (HasGroup()) {
|
if (HasGroup()) {
|
||||||
if (IsGroupHealer()/* || IsRaidHealer()*/)
|
if (IsGroupHealer()/* || IsRaidHealer()*/)
|
||||||
type_index |= pH;
|
type_index |= pH;
|
||||||
|
|||||||
@ -38,6 +38,7 @@ extern volatile bool RunLoops;
|
|||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/data_verification.h"
|
#include "../common/data_verification.h"
|
||||||
|
#include "../common/profanity_manager.h"
|
||||||
#include "data_bucket.h"
|
#include "data_bucket.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
@ -895,6 +896,10 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
|||||||
language = 0; // No need for language when drunk
|
language = 0; // No need for language when drunk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Censor the message
|
||||||
|
if (EQEmu::ProfanityManager::IsCensorshipActive() && (chan_num != 8))
|
||||||
|
EQEmu::ProfanityManager::RedactMessage(message);
|
||||||
|
|
||||||
switch(chan_num)
|
switch(chan_num)
|
||||||
{
|
{
|
||||||
case 0: { /* Guild Chat */
|
case 0: { /* Guild Chat */
|
||||||
@ -1092,6 +1097,9 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EQEmu::ProfanityManager::IsCensorshipActive())
|
||||||
|
EQEmu::ProfanityManager::RedactMessage(message);
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
if (message[0] == BOT_COMMAND_CHAR) {
|
if (message[0] == BOT_COMMAND_CHAR) {
|
||||||
if (bot_command_dispatch(this, message) == -2) {
|
if (bot_command_dispatch(this, message) == -2) {
|
||||||
|
|||||||
@ -1414,12 +1414,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000) { m_pp.ldon_points_tak = 0; }
|
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000) { m_pp.ldon_points_tak = 0; }
|
||||||
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000) { m_pp.ldon_points_available = 0; }
|
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000) { m_pp.ldon_points_available = 0; }
|
||||||
|
|
||||||
// need to rework .. not until full scope of change is accounted for, though
|
|
||||||
if (RuleB(World, UseClientBasedExpansionSettings)) {
|
if (RuleB(World, UseClientBasedExpansionSettings)) {
|
||||||
m_pp.expansions = EQEmu::expansions::ConvertClientVersionToExpansionMask(ClientVersion());
|
m_pp.expansions = EQEmu::expansions::ConvertClientVersionToExpansionsMask(ClientVersion());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_pp.expansions = RuleI(World, ExpansionSettings);
|
m_pp.expansions = (RuleI(World, ExpansionSettings) & EQEmu::expansions::ConvertClientVersionToExpansionsMask(ClientVersion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!database.LoadAlternateAdvancement(this)) {
|
if (!database.LoadAlternateAdvancement(this)) {
|
||||||
@ -2813,24 +2812,19 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ApplyPoisonSuccessResult = 0;
|
|
||||||
ApplyPoison_Struct* ApplyPoisonData = (ApplyPoison_Struct*)app->pBuffer;
|
ApplyPoison_Struct* ApplyPoisonData = (ApplyPoison_Struct*)app->pBuffer;
|
||||||
|
|
||||||
|
uint32 ApplyPoisonSuccessResult = 0;
|
||||||
|
|
||||||
const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::invslot::slotPrimary);
|
const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::invslot::slotPrimary);
|
||||||
const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
||||||
const EQEmu::ItemInstance* PoisonItemInstance = GetInv()[ApplyPoisonData->inventorySlot];
|
const EQEmu::ItemInstance* PoisonItemInstance = GetInv().GetItem(ApplyPoisonData->inventorySlot);
|
||||||
const EQEmu::ItemData* poison=PoisonItemInstance->GetItem();
|
|
||||||
const EQEmu::ItemData* primary=nullptr;
|
|
||||||
const EQEmu::ItemData* secondary=nullptr;
|
|
||||||
bool IsPoison = PoisonItemInstance &&
|
|
||||||
(poison->ItemType == EQEmu::item::ItemTypePoison);
|
|
||||||
|
|
||||||
if (PrimaryWeapon) {
|
const EQEmu::ItemData* primary = (PrimaryWeapon ? PrimaryWeapon->GetItem() : nullptr);
|
||||||
primary=PrimaryWeapon->GetItem();
|
const EQEmu::ItemData* secondary = (SecondaryWeapon ? SecondaryWeapon->GetItem() : nullptr);
|
||||||
}
|
const EQEmu::ItemData* poison = (PoisonItemInstance ? PoisonItemInstance->GetItem() : nullptr);
|
||||||
|
|
||||||
if (SecondaryWeapon) {
|
bool IsPoison = (poison && poison->ItemType == EQEmu::item::ItemTypePoison);
|
||||||
secondary=SecondaryWeapon->GetItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsPoison && GetClass() == ROGUE) {
|
if (IsPoison && GetClass() == ROGUE) {
|
||||||
|
|
||||||
@ -9400,7 +9394,7 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
|
|||||||
//check to see if selected option is a valid stance slot (option is the slot the stance is in, not the actual stance)
|
//check to see if selected option is a valid stance slot (option is the slot the stance is in, not the actual stance)
|
||||||
if (option >= 0 && option < numStances)
|
if (option >= 0 && option < numStances)
|
||||||
{
|
{
|
||||||
merc->SetStance(mercTemplate->Stances[option]);
|
merc->SetStance((EQEmu::constants::StanceType)mercTemplate->Stances[option]);
|
||||||
GetMercInfo().Stance = mercTemplate->Stances[option];
|
GetMercInfo().Stance = mercTemplate->Stances[option];
|
||||||
|
|
||||||
Log(Logs::General, Logs::Mercenaries, "Set Stance: %u for %s (%s)", merc->GetStance(), merc->GetName(), GetName());
|
Log(Logs::General, Logs::Mercenaries, "Set Stance: %u for %s (%s)", merc->GetStance(), merc->GetName(), GetName());
|
||||||
|
|||||||
285
zone/command.cpp
285
zone/command.cpp
@ -54,6 +54,7 @@
|
|||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../say_link.h"
|
#include "../say_link.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/profanity_manager.h"
|
||||||
|
|
||||||
#include "data_bucket.h"
|
#include "data_bucket.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
@ -307,6 +308,7 @@ int command_init(void)
|
|||||||
command_add("petitioninfo", "[petition number] - Get info about a petition", 20, command_petitioninfo) ||
|
command_add("petitioninfo", "[petition number] - Get info about a petition", 20, command_petitioninfo) ||
|
||||||
command_add("pf", "- Display additional mob coordinate and wandering data", 0, command_pf) ||
|
command_add("pf", "- Display additional mob coordinate and wandering data", 0, command_pf) ||
|
||||||
command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", 0, command_picklock) ||
|
command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", 0, command_picklock) ||
|
||||||
|
command_add("profanity", "Manage censored language.", 150, command_profanity) ||
|
||||||
|
|
||||||
#ifdef EQPROFILE
|
#ifdef EQPROFILE
|
||||||
command_add("profiledump", "- Dump profiling info to logs", 250, command_profiledump) ||
|
command_add("profiledump", "- Dump profiling info to logs", 250, command_profiledump) ||
|
||||||
@ -6405,34 +6407,29 @@ void command_beardcolor(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void command_scribespells(Client *c, const Seperator *sep)
|
void command_scribespells(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
uint8 max_level, min_level;
|
Client *t = c;
|
||||||
uint16 book_slot, curspell, count;
|
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM())
|
||||||
Client *t=c;
|
t = c->GetTarget()->CastToClient();
|
||||||
|
|
||||||
if(c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM())
|
if(sep->argnum < 1 || !sep->IsNumber(1)) {
|
||||||
t=c->GetTarget()->CastToClient();
|
|
||||||
|
|
||||||
if(!sep->arg[1][0])
|
|
||||||
{
|
|
||||||
c->Message(0, "FORMAT: #scribespells <max level> <min level>");
|
c->Message(0, "FORMAT: #scribespells <max level> <min level>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_level = (uint8)atoi(sep->arg[1]);
|
uint8 max_level = (uint8)atol(sep->arg[1]);
|
||||||
if (!c->GetGM() && max_level > RuleI(Character, MaxLevel))
|
if (!c->GetGM() && max_level > (uint8)RuleI(Character, MaxLevel))
|
||||||
max_level = RuleI(Character, MaxLevel); //default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
max_level = (uint8)RuleI(Character, MaxLevel); // default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
||||||
min_level = sep->arg[2][0] ? (uint8)atoi(sep->arg[2]) : 1; //default to 1 if there isn't a 2nd argument
|
|
||||||
if (!c->GetGM() && min_level > RuleI(Character, MaxLevel))
|
|
||||||
min_level = RuleI(Character, MaxLevel); //default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
|
||||||
|
|
||||||
|
uint8 min_level = (sep->IsNumber(2) ? (uint8)atol(sep->arg[2]) : 1); // default to 1 if there isn't a 2nd argument
|
||||||
|
if (!c->GetGM() && min_level > (uint8)RuleI(Character, MaxLevel))
|
||||||
|
min_level = (uint8)RuleI(Character, MaxLevel); // default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
||||||
|
|
||||||
if(max_level < 1 || min_level < 1)
|
if(max_level < 1 || min_level < 1) {
|
||||||
{
|
|
||||||
c->Message(0, "ERROR: Level must be greater than 1.");
|
c->Message(0, "ERROR: Level must be greater than 1.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (min_level > max_level) {
|
if (min_level > max_level) {
|
||||||
c->Message(0, "Error: Min Level must be less than or equal to Max Level.");
|
c->Message(0, "ERROR: Min Level must be less than or equal to Max Level.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6441,42 +6438,71 @@ void command_scribespells(Client *c, const Seperator *sep)
|
|||||||
c->Message(0, "Scribing spells for %s.", t->GetName());
|
c->Message(0, "Scribing spells for %s.", t->GetName());
|
||||||
Log(Logs::General, Logs::Normal, "Scribe spells request for %s from %s, levels: %u -> %u", t->GetName(), c->GetName(), min_level, max_level);
|
Log(Logs::General, Logs::Normal, "Scribe spells request for %s from %s, levels: %u -> %u", t->GetName(), c->GetName(), min_level, max_level);
|
||||||
|
|
||||||
for (
|
int book_slot = t->GetNextAvailableSpellBookSlot();
|
||||||
curspell = 0,
|
int spell_id = 0;
|
||||||
book_slot = t->GetNextAvailableSpellBookSlot(),
|
int count = 0;
|
||||||
count = 0; // ;
|
|
||||||
curspell < SPDAT_RECORDS &&
|
for ( ; spell_id < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; ++spell_id) {
|
||||||
book_slot < EQEmu::spells::SPELLBOOK_SIZE; // ;
|
if (book_slot == -1) {
|
||||||
curspell++,
|
t->Message(
|
||||||
book_slot = t->GetNextAvailableSpellBookSlot(book_slot)
|
13,
|
||||||
)
|
"Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.",
|
||||||
{
|
((spell_id >= 0 && spell_id < SPDAT_RECORDS) ? spells[spell_id].name : "Out-of-range"),
|
||||||
if
|
spell_id
|
||||||
(
|
);
|
||||||
spells[curspell].classes[WARRIOR] != 0 && // check if spell exists
|
if (t != c)
|
||||||
spells[curspell].classes[t->GetPP().class_-1] <= max_level && //maximum level
|
c->Message(
|
||||||
spells[curspell].classes[t->GetPP().class_-1] >= min_level && //minimum level
|
13,
|
||||||
spells[curspell].skill != 52
|
"Error scribing spells: %s ran out of spell book slots on spell %s (%i)",
|
||||||
)
|
t->GetName(),
|
||||||
{
|
((spell_id >= 0 && spell_id < SPDAT_RECORDS) ? spells[spell_id].name : "Out-of-range"),
|
||||||
if (book_slot == -1) { //no more book slots
|
spell_id
|
||||||
t->Message(13, "Unable to scribe spell %s (%u) to spellbook: no more spell book slots available.", spells[curspell].name, curspell);
|
);
|
||||||
if (t != c)
|
|
||||||
c->Message(13, "Error scribing spells: %s ran out of spell book slots on spell %s (%u)", t->GetName(), spells[curspell].name, curspell);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!IsDiscipline(curspell) && !t->HasSpellScribed(curspell)) { //isn't a discipline & we don't already have it scribed
|
|
||||||
t->ScribeSpell(curspell, book_slot);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (spell_id < 0 || spell_id >= SPDAT_RECORDS) {
|
||||||
|
c->Message(13, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (book_slot < 0 || book_slot >= EQEmu::spells::SPELLBOOK_SIZE) {
|
||||||
|
c->Message(13, "FATAL ERROR: Book slot out-of-range (slot: %i, min: 0, max: %i)", book_slot, EQEmu::spells::SPELLBOOK_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].classes[t->GetPP().class_ - 1] > max_level) // maximum level
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].classes[t->GetPP().class_ - 1] < min_level) // minimum level
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].skill == 52)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint16 spell_id_ = (uint16)spell_id;
|
||||||
|
if ((spell_id_ != spell_id) || (spell_id != spell_id_)) {
|
||||||
|
c->Message(13, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDiscipline(spell_id_) && !t->HasSpellScribed(spell_id)) { // isn't a discipline & we don't already have it scribed
|
||||||
|
t->ScribeSpell(spell_id_, book_slot);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
book_slot = t->GetNextAvailableSpellBookSlot(book_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
t->Message(0, "Successfully scribed %u spells.", count);
|
t->Message(0, "Successfully scribed %i spells.", count);
|
||||||
if (t != c)
|
if (t != c)
|
||||||
c->Message(0, "Successfully scribed %u spells for %s.", count, t->GetName());
|
c->Message(0, "Successfully scribed %i spells for %s.", count, t->GetName());
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
t->Message(0, "No spells scribed.");
|
t->Message(0, "No spells scribed.");
|
||||||
if (t != c)
|
if (t != c)
|
||||||
c->Message(0, "No spells scribed for %s.", t->GetName());
|
c->Message(0, "No spells scribed for %s.", t->GetName());
|
||||||
@ -8732,28 +8758,24 @@ void command_reloadtitles(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void command_traindisc(Client *c, const Seperator *sep)
|
void command_traindisc(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
uint8 max_level, min_level;
|
Client *t = c;
|
||||||
uint16 curspell, count;
|
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM())
|
||||||
Client *t=c;
|
t = c->GetTarget()->CastToClient();
|
||||||
|
|
||||||
if(c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM())
|
if (sep->argnum < 1 || !sep->IsNumber(1)) {
|
||||||
t=c->GetTarget()->CastToClient();
|
|
||||||
|
|
||||||
if(!sep->arg[1][0])
|
|
||||||
{
|
|
||||||
c->Message(0, "FORMAT: #traindisc <max level> <min level>");
|
c->Message(0, "FORMAT: #traindisc <max level> <min level>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_level = (uint8)atoi(sep->arg[1]);
|
uint8 max_level = (uint8)atol(sep->arg[1]);
|
||||||
if (!c->GetGM() && max_level > RuleI(Character, MaxLevel))
|
if (!c->GetGM() && max_level >(uint8)RuleI(Character, MaxLevel))
|
||||||
max_level = RuleI(Character, MaxLevel); //default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
max_level = (uint8)RuleI(Character, MaxLevel); // default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
||||||
min_level = sep->arg[2][0] ? (uint8)atoi(sep->arg[2]) : 1; //default to 1 if there isn't a 2nd argument
|
|
||||||
if (!c->GetGM() && min_level > RuleI(Character, MaxLevel))
|
|
||||||
min_level = RuleI(Character, MaxLevel); //default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
|
||||||
|
|
||||||
if(max_level < 1 || min_level < 1)
|
uint8 min_level = (sep->IsNumber(2) ? (uint8)atol(sep->arg[2]) : 1); // default to 1 if there isn't a 2nd argument
|
||||||
{
|
if (!c->GetGM() && min_level > (uint8)RuleI(Character, MaxLevel))
|
||||||
|
min_level = (uint8)RuleI(Character, MaxLevel); // default to Character:MaxLevel if we're not a GM & it's higher than the max level
|
||||||
|
|
||||||
|
if(max_level < 1 || min_level < 1) {
|
||||||
c->Message(0, "ERROR: Level must be greater than 1.");
|
c->Message(0, "ERROR: Level must be greater than 1.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -8767,35 +8789,58 @@ void command_traindisc(Client *c, const Seperator *sep)
|
|||||||
c->Message(0, "Training disciplines for %s.", t->GetName());
|
c->Message(0, "Training disciplines for %s.", t->GetName());
|
||||||
Log(Logs::General, Logs::Normal, "Train disciplines request for %s from %s, levels: %u -> %u", t->GetName(), c->GetName(), min_level, max_level);
|
Log(Logs::General, Logs::Normal, "Train disciplines request for %s from %s, levels: %u -> %u", t->GetName(), c->GetName(), min_level, max_level);
|
||||||
|
|
||||||
for(curspell = 0, count = 0; curspell < SPDAT_RECORDS; curspell++)
|
int spell_id = 0;
|
||||||
{
|
int count = 0;
|
||||||
if
|
|
||||||
(
|
bool change = false;
|
||||||
spells[curspell].classes[WARRIOR] != 0 && // check if spell exists
|
|
||||||
spells[curspell].classes[t->GetPP().class_-1] <= max_level && //maximum level
|
for( ; spell_id < SPDAT_RECORDS; ++spell_id) {
|
||||||
spells[curspell].classes[t->GetPP().class_-1] >= min_level && //minimum level
|
if (spell_id < 0 || spell_id >= SPDAT_RECORDS) {
|
||||||
spells[curspell].skill != 52
|
c->Message(13, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS);
|
||||||
)
|
return;
|
||||||
{
|
}
|
||||||
if(IsDiscipline(curspell)){
|
|
||||||
//we may want to come up with a function like Client::GetNextAvailableSpellBookSlot() to help speed this up a little
|
while (true) {
|
||||||
for(int r = 0; r < MAX_PP_DISCIPLINES; r++) {
|
if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists
|
||||||
if(t->GetPP().disciplines.values[r] == curspell) {
|
break;
|
||||||
t->Message(13, "You already know this discipline.");
|
if (spells[spell_id].classes[t->GetPP().class_ - 1] > max_level) // maximum level
|
||||||
break; //continue the 1st loop
|
break;
|
||||||
} else if(t->GetPP().disciplines.values[r] == 0) {
|
if (spells[spell_id].classes[t->GetPP().class_ - 1] < min_level) // minimum level
|
||||||
t->GetPP().disciplines.values[r] = curspell;
|
break;
|
||||||
database.SaveCharacterDisc(t->CharacterID(), r, curspell);
|
if (spells[spell_id].skill == 52)
|
||||||
t->SendDisciplineUpdate();
|
break;
|
||||||
t->Message(0, "You have learned a new discipline!");
|
|
||||||
count++; //success counter
|
uint16 spell_id_ = (uint16)spell_id;
|
||||||
break; //continue the 1st loop
|
if ((spell_id_ != spell_id) || (spell_id != spell_id_)) {
|
||||||
} //if we get to this point, there's already a discipline in this slot, so we continue onto the next slot
|
c->Message(13, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsDiscipline(spell_id_))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (uint32 r = 0; r < MAX_PP_DISCIPLINES; ++r) {
|
||||||
|
if (t->GetPP().disciplines.values[r] == spell_id_) {
|
||||||
|
t->Message(13, "You already know this discipline.");
|
||||||
|
break; // continue the 1st loop
|
||||||
|
}
|
||||||
|
else if (t->GetPP().disciplines.values[r] == 0) {
|
||||||
|
t->GetPP().disciplines.values[r] = spell_id_;
|
||||||
|
database.SaveCharacterDisc(t->CharacterID(), r, spell_id_);
|
||||||
|
change = true;
|
||||||
|
t->Message(0, "You have learned a new discipline!");
|
||||||
|
++count; // success counter
|
||||||
|
break; // continue the 1st loop
|
||||||
|
} // if we get to this point, there's already a discipline in this slot, so we continue onto the next slot
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (change)
|
||||||
|
t->SendDisciplineUpdate();
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
t->Message(0, "Successfully trained %u disciplines.", count);
|
t->Message(0, "Successfully trained %u disciplines.", count);
|
||||||
if (t != c)
|
if (t != c)
|
||||||
@ -11043,6 +11088,68 @@ void command_picklock(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_profanity(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
std::string arg1(sep->arg[1]);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (arg1.compare("list") == 0) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else if (arg1.compare("clear") == 0) {
|
||||||
|
EQEmu::ProfanityManager::DeleteProfanityList(&database);
|
||||||
|
auto pack = new ServerPacket(ServerOP_RefreshCensorship);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}
|
||||||
|
else if (arg1.compare("add") == 0) {
|
||||||
|
if (!EQEmu::ProfanityManager::AddProfanity(&database, sep->arg[2]))
|
||||||
|
c->Message(CC_Red, "Could not add '%s' to the profanity list.", sep->arg[2]);
|
||||||
|
auto pack = new ServerPacket(ServerOP_RefreshCensorship);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}
|
||||||
|
else if (arg1.compare("del") == 0) {
|
||||||
|
if (!EQEmu::ProfanityManager::RemoveProfanity(&database, sep->arg[2]))
|
||||||
|
c->Message(CC_Red, "Could not delete '%s' from the profanity list.", sep->arg[2]);
|
||||||
|
auto pack = new ServerPacket(ServerOP_RefreshCensorship);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}
|
||||||
|
else if (arg1.compare("reload") == 0) {
|
||||||
|
if (!EQEmu::ProfanityManager::UpdateProfanityList(&database))
|
||||||
|
c->Message(CC_Red, "Could not reload the profanity list.");
|
||||||
|
auto pack = new ServerPacket(ServerOP_RefreshCensorship);
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string popup;
|
||||||
|
const auto &list = EQEmu::ProfanityManager::GetProfanityList();
|
||||||
|
for (const auto &iter : list) {
|
||||||
|
popup.append(iter);
|
||||||
|
popup.append("<br>");
|
||||||
|
}
|
||||||
|
if (list.empty())
|
||||||
|
popup.append("** Censorship Inactive **<br>");
|
||||||
|
else
|
||||||
|
popup.append("** End of List **<br>");
|
||||||
|
|
||||||
|
c->SendPopupToClient("Profanity List", popup.c_str());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(0, "Usage: #profanity [list] - shows profanity list");
|
||||||
|
c->Message(0, "Usage: #profanity [clear] - deletes all entries");
|
||||||
|
c->Message(0, "Usage: #profanity [add] [<word>] - adds entry");
|
||||||
|
c->Message(0, "Usage: #profanity [del] [<word>] - deletes entry");
|
||||||
|
c->Message(0, "Usage: #profanity [reload] - reloads profanity list");
|
||||||
|
}
|
||||||
|
|
||||||
void command_mysql(Client *c, const Seperator *sep)
|
void command_mysql(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if(!sep->arg[1][0] || !sep->arg[2][0]) {
|
if(!sep->arg[1][0] || !sep->arg[2][0]) {
|
||||||
|
|||||||
@ -210,6 +210,7 @@ void command_permagender(Client *c, const Seperator *sep);
|
|||||||
void command_permarace(Client *c, const Seperator *sep);
|
void command_permarace(Client *c, const Seperator *sep);
|
||||||
void command_petitioninfo(Client *c, const Seperator *sep);
|
void command_petitioninfo(Client *c, const Seperator *sep);
|
||||||
void command_picklock(Client *c, const Seperator *sep);
|
void command_picklock(Client *c, const Seperator *sep);
|
||||||
|
void command_profanity(Client *c, const Seperator *sep);
|
||||||
|
|
||||||
#ifdef EQPROFILE
|
#ifdef EQPROFILE
|
||||||
void command_profiledump(Client *c, const Seperator *sep);
|
void command_profiledump(Client *c, const Seperator *sep);
|
||||||
|
|||||||
@ -4178,7 +4178,7 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
|
|||||||
WAPP2->RankMSGID = 12315;
|
WAPP2->RankMSGID = 12315;
|
||||||
else if (ClientEntry->IsBuyer())
|
else if (ClientEntry->IsBuyer())
|
||||||
WAPP2->RankMSGID = 6056;
|
WAPP2->RankMSGID = 6056;
|
||||||
else if (ClientEntry->Admin() >= 10)
|
else if (ClientEntry->Admin() >= 10 && ClientEntry->GetGM())
|
||||||
WAPP2->RankMSGID = 12312;
|
WAPP2->RankMSGID = 12312;
|
||||||
else
|
else
|
||||||
WAPP2->RankMSGID = 0xFFFFFFFF;
|
WAPP2->RankMSGID = 0xFFFFFFFF;
|
||||||
|
|||||||
@ -66,7 +66,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
|
|||||||
memset(equipment, 0, sizeof(equipment));
|
memset(equipment, 0, sizeof(equipment));
|
||||||
|
|
||||||
SetMercID(0);
|
SetMercID(0);
|
||||||
SetStance(MercStanceBalanced);
|
SetStance(EQEmu::constants::stanceBalanced);
|
||||||
rest_timer.Disable();
|
rest_timer.Disable();
|
||||||
|
|
||||||
if (GetClass() == ROGUE)
|
if (GetClass() == ROGUE)
|
||||||
@ -1908,7 +1908,7 @@ bool Merc::AI_IdleCastCheck() {
|
|||||||
|
|
||||||
bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
||||||
|
|
||||||
if((iSpellTypes&SpellTypes_Detrimental) != 0) {
|
if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) {
|
||||||
//according to live, you can buff and heal through walls...
|
//according to live, you can buff and heal through walls...
|
||||||
//now with PCs, this only applies if you can TARGET the target, but
|
//now with PCs, this only applies if you can TARGET the target, but
|
||||||
// according to Rogean, Live NPCs will just cast through walls/floors, no problem..
|
// according to Rogean, Live NPCs will just cast through walls/floors, no problem..
|
||||||
@ -3669,13 +3669,13 @@ MercSpell Merc::GetBestMercSpellForAENuke(Merc* caster, Mob* tar) {
|
|||||||
|
|
||||||
switch(caster->GetStance())
|
switch(caster->GetStance())
|
||||||
{
|
{
|
||||||
case MercStanceBurnAE:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
initialCastChance = 50;
|
initialCastChance = 50;
|
||||||
break;
|
break;
|
||||||
case MercStanceBalanced:
|
case EQEmu::constants::stanceBalanced:
|
||||||
initialCastChance = 25;
|
initialCastChance = 25;
|
||||||
break;
|
break;
|
||||||
case MercStanceBurn:
|
case EQEmu::constants::stanceBurn:
|
||||||
initialCastChance = 0;
|
initialCastChance = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3717,11 +3717,11 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) {
|
|||||||
|
|
||||||
switch(caster->GetStance())
|
switch(caster->GetStance())
|
||||||
{
|
{
|
||||||
case MercStanceBurnAE:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
numTargetsCheck = 1;
|
numTargetsCheck = 1;
|
||||||
break;
|
break;
|
||||||
case MercStanceBalanced:
|
case EQEmu::constants::stanceBalanced:
|
||||||
case MercStanceBurn:
|
case EQEmu::constants::stanceBurn:
|
||||||
numTargetsCheck = 2;
|
numTargetsCheck = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3769,11 +3769,11 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) {
|
|||||||
|
|
||||||
switch(caster->GetStance())
|
switch(caster->GetStance())
|
||||||
{
|
{
|
||||||
case MercStanceBurnAE:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
numTargetsCheck = 2;
|
numTargetsCheck = 2;
|
||||||
break;
|
break;
|
||||||
case MercStanceBalanced:
|
case EQEmu::constants::stanceBalanced:
|
||||||
case MercStanceBurn:
|
case EQEmu::constants::stanceBurn:
|
||||||
numTargetsCheck = 3;
|
numTargetsCheck = 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3820,11 +3820,11 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) {
|
|||||||
|
|
||||||
switch(caster->GetStance())
|
switch(caster->GetStance())
|
||||||
{
|
{
|
||||||
case MercStanceBurnAE:
|
case EQEmu::constants::stanceBurnAE:
|
||||||
numTargetsCheck = 1;
|
numTargetsCheck = 1;
|
||||||
break;
|
break;
|
||||||
case MercStanceBalanced:
|
case EQEmu::constants::stanceBalanced:
|
||||||
case MercStanceBurn:
|
case EQEmu::constants::stanceBurn:
|
||||||
numTargetsCheck = 2;
|
numTargetsCheck = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5649,7 +5649,7 @@ void Client::SpawnMerc(Merc* merc, bool setMaxStats) {
|
|||||||
merc->SetSuspended(false);
|
merc->SetSuspended(false);
|
||||||
SetMerc(merc);
|
SetMerc(merc);
|
||||||
merc->Unsuspend(setMaxStats);
|
merc->Unsuspend(setMaxStats);
|
||||||
merc->SetStance(GetMercInfo().Stance);
|
merc->SetStance((EQEmu::constants::StanceType)GetMercInfo().Stance);
|
||||||
|
|
||||||
Log(Logs::General, Logs::Mercenaries, "SpawnMerc Success for %s.", GetName());
|
Log(Logs::General, Logs::Mercenaries, "SpawnMerc Success for %s.", GetName());
|
||||||
|
|
||||||
|
|||||||
18
zone/merc.h
18
zone/merc.h
@ -30,18 +30,6 @@ namespace EQEmu
|
|||||||
|
|
||||||
const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this
|
const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this
|
||||||
|
|
||||||
enum MercStanceType {
|
|
||||||
MercStancePassive = 1,
|
|
||||||
MercStanceBalanced,
|
|
||||||
MercStanceEfficient,
|
|
||||||
MercStanceReactive,
|
|
||||||
MercStanceAggressive,
|
|
||||||
MercStanceAssist,
|
|
||||||
MercStanceBurn,
|
|
||||||
MercStanceEfficient2,
|
|
||||||
MercStanceBurnAE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MercSpell {
|
struct MercSpell {
|
||||||
uint16 spellid; // <= 0 = no spell
|
uint16 spellid; // <= 0 = no spell
|
||||||
uint32 type; // 0 = never, must be one (and only one) of the defined values
|
uint32 type; // 0 = never, must be one (and only one) of the defined values
|
||||||
@ -175,7 +163,7 @@ public:
|
|||||||
uint8 GetTierID() { return _TierID; }
|
uint8 GetTierID() { return _TierID; }
|
||||||
uint32 GetCostFormula() { return _CostFormula; }
|
uint32 GetCostFormula() { return _CostFormula; }
|
||||||
uint32 GetMercNameType() { return _NameType; }
|
uint32 GetMercNameType() { return _NameType; }
|
||||||
uint32 GetStance() { return _currentStance; }
|
EQEmu::constants::StanceType GetStance() { return _currentStance; }
|
||||||
int GetHatedCount() { return _hatedCount; }
|
int GetHatedCount() { return _hatedCount; }
|
||||||
|
|
||||||
inline const uint8 GetClientVersion() const { return _OwnerClientVersion; }
|
inline const uint8 GetClientVersion() const { return _OwnerClientVersion; }
|
||||||
@ -265,7 +253,7 @@ public:
|
|||||||
void SetMercNameType( uint8 nametype ) { _NameType = nametype; }
|
void SetMercNameType( uint8 nametype ) { _NameType = nametype; }
|
||||||
void SetClientVersion(uint8 clientVersion) { _OwnerClientVersion = clientVersion; }
|
void SetClientVersion(uint8 clientVersion) { _OwnerClientVersion = clientVersion; }
|
||||||
void SetSuspended(bool suspended) { _suspended = suspended; }
|
void SetSuspended(bool suspended) { _suspended = suspended; }
|
||||||
void SetStance( uint32 stance ) { _currentStance = stance; }
|
void SetStance( EQEmu::constants::StanceType stance ) { _currentStance = stance; }
|
||||||
void SetHatedCount( int count ) { _hatedCount = count; }
|
void SetHatedCount( int count ) { _hatedCount = count; }
|
||||||
|
|
||||||
void Sit();
|
void Sit();
|
||||||
@ -385,7 +373,7 @@ private:
|
|||||||
uint8 _CostFormula;
|
uint8 _CostFormula;
|
||||||
uint8 _NameType;
|
uint8 _NameType;
|
||||||
uint8 _OwnerClientVersion;
|
uint8 _OwnerClientVersion;
|
||||||
uint32 _currentStance;
|
EQEmu::constants::StanceType _currentStance;
|
||||||
|
|
||||||
EQEmu::InventoryProfile m_inv;
|
EQEmu::InventoryProfile m_inv;
|
||||||
int32 max_end;
|
int32 max_end;
|
||||||
|
|||||||
@ -589,8 +589,8 @@ public:
|
|||||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||||
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
||||||
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
|
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
|
||||||
virtual void StopMoving();
|
void StopMoving();
|
||||||
virtual void StopMoving(float new_heading);
|
void StopMoving(float new_heading);
|
||||||
void SetSpawned() { spawned = true; };
|
void SetSpawned() { spawned = true; };
|
||||||
bool Spawned() { return spawned; };
|
bool Spawned() { return spawned; };
|
||||||
virtual bool ShouldISpawnFor(Client *c) { return true; }
|
virtual bool ShouldISpawnFor(Client *c) { return true; }
|
||||||
|
|||||||
@ -379,7 +379,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes) {
|
||||||
if((iSpellTypes & SpellTypes_Detrimental) != 0) {
|
if((iSpellTypes & SPELL_TYPES_DETRIMENTAL) != 0) {
|
||||||
//according to live, you can buff and heal through walls...
|
//according to live, you can buff and heal through walls...
|
||||||
//now with PCs, this only applies if you can TARGET the target, but
|
//now with PCs, this only applies if you can TARGET the target, but
|
||||||
// according to Rogean, Live NPCs will just cast through walls/floors, no problem..
|
// according to Rogean, Live NPCs will just cast through walls/floors, no problem..
|
||||||
@ -2813,7 +2813,7 @@ DBnpcspells_Struct *ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID)
|
|||||||
entry.max_hp = atoi(row[8]);
|
entry.max_hp = atoi(row[8]);
|
||||||
|
|
||||||
// some spell types don't make much since to be priority 0, so fix that
|
// some spell types don't make much since to be priority 0, so fix that
|
||||||
if (!(entry.type & SpellTypes_Innate) && entry.priority == 0)
|
if (!(entry.type & SPELL_TYPES_INNATE) && entry.priority == 0)
|
||||||
entry.priority = 1;
|
entry.priority = 1;
|
||||||
|
|
||||||
if (row[9])
|
if (row[9])
|
||||||
|
|||||||
@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "../common/eq_stream_ident.h"
|
#include "../common/eq_stream_ident.h"
|
||||||
#include "../common/patches/patches.h"
|
#include "../common/patches/patches.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
|
#include "../common/profanity_manager.h"
|
||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/platform.h"
|
#include "../common/platform.h"
|
||||||
@ -350,6 +351,10 @@ int main(int argc, char** argv) {
|
|||||||
Log(Logs::General, Logs::Zone_Server, "Loading corpse timers");
|
Log(Logs::General, Logs::Zone_Server, "Loading corpse timers");
|
||||||
database.GetDecayTimes(npcCorpseDecayTimes);
|
database.GetDecayTimes(npcCorpseDecayTimes);
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Zone_Server, "Loading profanity list");
|
||||||
|
if (!EQEmu::ProfanityManager::LoadProfanityList(&database))
|
||||||
|
Log(Logs::General, Logs::Error, "Loading profanity list FAILED!");
|
||||||
|
|
||||||
Log(Logs::General, Logs::Zone_Server, "Loading commands");
|
Log(Logs::General, Logs::Zone_Server, "Loading commands");
|
||||||
int retval = command_init();
|
int retval = command_init();
|
||||||
if (retval<0)
|
if (retval<0)
|
||||||
|
|||||||
@ -975,133 +975,181 @@ void QuestManager::permagender(int gender_id) {
|
|||||||
|
|
||||||
uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
|
uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
uint16 book_slot, count;
|
int book_slot = initiator->GetNextAvailableSpellBookSlot();
|
||||||
uint16 spell_id;
|
int spell_id = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
uint32 char_id = initiator->CharacterID();
|
uint32 char_id = initiator->CharacterID();
|
||||||
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
||||||
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
||||||
bool SpellGlobalCheckResult = 0;
|
bool SpellGlobalCheckResult = false;
|
||||||
bool SpellBucketCheckResult = 0;
|
bool SpellBucketCheckResult = false;
|
||||||
|
|
||||||
for (
|
for ( ; spell_id < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; ++spell_id) {
|
||||||
spell_id = 0,
|
if (book_slot == -1) {
|
||||||
book_slot = initiator->GetNextAvailableSpellBookSlot(),
|
initiator->Message(
|
||||||
count = 0; // ;
|
13,
|
||||||
spell_id < SPDAT_RECORDS &&
|
"Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.",
|
||||||
book_slot < EQEmu::spells::SPELLBOOK_SIZE; // ;
|
((spell_id >= 0 && spell_id < SPDAT_RECORDS) ? spells[spell_id].name : "Out-of-range"),
|
||||||
spell_id++,
|
spell_id
|
||||||
book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot)
|
);
|
||||||
)
|
|
||||||
{
|
break;
|
||||||
if
|
}
|
||||||
(
|
if (spell_id < 0 || spell_id >= SPDAT_RECORDS) {
|
||||||
spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists
|
initiator->Message(13, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS);
|
||||||
spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
|
return count;
|
||||||
spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
|
}
|
||||||
spells[spell_id].skill != 52 &&
|
if (book_slot < 0 || book_slot >= EQEmu::spells::SPELLBOOK_SIZE) {
|
||||||
spells[spell_id].effectid[EFFECT_COUNT - 1] != 10
|
initiator->Message(13, "FATAL ERROR: Book slot out-of-range (slot: %i, min: 0, max: %i)", book_slot, EQEmu::spells::SPELLBOOK_SIZE);
|
||||||
)
|
return count;
|
||||||
{
|
}
|
||||||
if (book_slot == -1) //no more book slots
|
|
||||||
|
while (true) {
|
||||||
|
if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists
|
||||||
break;
|
break;
|
||||||
if(!IsDiscipline(spell_id) && !initiator->HasSpellScribed(spell_id)) { //isn't a discipline & we don't already have it scribed
|
if (spells[spell_id].classes[initiator->GetPP().class_ - 1] > max_level) // maximum level
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].classes[initiator->GetPP().class_ - 1] < min_level) // minimum level
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].skill == 52)
|
||||||
|
break;
|
||||||
|
if (spells[spell_id].effectid[EFFECT_COUNT - 1] == 10)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint16 spell_id_ = (uint16)spell_id;
|
||||||
|
if ((spell_id_ != spell_id) || (spell_id != spell_id_)) {
|
||||||
|
initiator->Message(13, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDiscipline(spell_id_) && !initiator->HasSpellScribed(spell_id)) { // isn't a discipline & we don't already have it scribed
|
||||||
if (SpellGlobalRule) {
|
if (SpellGlobalRule) {
|
||||||
// Bool to see if the character has the required QGlobal to scribe it if one exists in the Spell_Globals table
|
// bool to see if the character has the required QGlobal to scribe it if one exists in the Spell_Globals table
|
||||||
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id);
|
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id_, char_id);
|
||||||
if (SpellGlobalCheckResult) {
|
if (SpellGlobalCheckResult) {
|
||||||
initiator->ScribeSpell(spell_id, book_slot);
|
initiator->ScribeSpell(spell_id_, book_slot);
|
||||||
count++;
|
++count;
|
||||||
}
|
}
|
||||||
} else if (SpellBucketRule) {
|
}
|
||||||
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id);
|
else if (SpellBucketRule) {
|
||||||
|
// bool to see if the character has the required bucket to train it if one exists in the spell_buckets table
|
||||||
|
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id_, char_id);
|
||||||
if (SpellBucketCheckResult) {
|
if (SpellBucketCheckResult) {
|
||||||
initiator->ScribeSpell(spell_id, book_slot);
|
initiator->ScribeSpell(spell_id_, book_slot);
|
||||||
count++;
|
++count;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
initiator->ScribeSpell(spell_id, book_slot);
|
else {
|
||||||
count++;
|
initiator->ScribeSpell(spell_id_, book_slot);
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot);
|
||||||
}
|
}
|
||||||
return count; //how many spells were scribed successfully
|
|
||||||
|
return count; // how many spells were scribed successfully
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
uint16 count;
|
int spell_id = 0;
|
||||||
uint16 spell_id;
|
int count = 0;
|
||||||
|
|
||||||
uint32 char_id = initiator->CharacterID();
|
uint32 char_id = initiator->CharacterID();
|
||||||
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
||||||
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
||||||
bool SpellGlobalCheckResult = 0;
|
bool SpellGlobalCheckResult = false;
|
||||||
bool SpellBucketCheckResult = 0;
|
bool SpellBucketCheckResult = false;
|
||||||
|
|
||||||
for(spell_id = 0, count = 0; spell_id < SPDAT_RECORDS; spell_id++)
|
bool change = false;
|
||||||
{
|
|
||||||
if
|
for( ; spell_id < SPDAT_RECORDS; ++spell_id) {
|
||||||
(
|
if (spell_id < 0 || spell_id >= SPDAT_RECORDS) {
|
||||||
spells[spell_id].classes[WARRIOR] != 0 && //check if spell exists
|
initiator->Message(13, "FATAL ERROR: Spell id out-of-range (id: %i, min: 0, max: %i)", spell_id, SPDAT_RECORDS);
|
||||||
spells[spell_id].classes[initiator->GetPP().class_-1] <= max_level && //maximum level
|
return count;
|
||||||
spells[spell_id].classes[initiator->GetPP().class_-1] >= min_level && //minimum level
|
}
|
||||||
spells[spell_id].skill != 52 &&
|
|
||||||
( !RuleB(Spells, UseCHAScribeHack) || spells[spell_id].effectid[EFFECT_COUNT - 1] != 10 )
|
while (true) {
|
||||||
)
|
if (spells[spell_id].classes[WARRIOR] == 0) // check if spell exists
|
||||||
{
|
break;
|
||||||
if(IsDiscipline(spell_id)){
|
if (spells[spell_id].classes[initiator->GetPP().class_ - 1] > max_level) // maximum level
|
||||||
//we may want to come up with a function like Client::GetNextAvailableSpellBookSlot() to help speed this up a little
|
break;
|
||||||
for(uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) {
|
if (spells[spell_id].classes[initiator->GetPP().class_ - 1] < min_level) // minimum level
|
||||||
if(initiator->GetPP().disciplines.values[r] == spell_id) {
|
break;
|
||||||
initiator->Message(13, "You already know this discipline.");
|
if (spells[spell_id].skill == 52)
|
||||||
break; //continue the 1st loop
|
break;
|
||||||
}
|
if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10)
|
||||||
else if(initiator->GetPP().disciplines.values[r] == 0) {
|
break;
|
||||||
if (SpellGlobalRule) {
|
|
||||||
// Bool to see if the character has the required QGlobal to train it if one exists in the Spell_Globals table
|
uint16 spell_id_ = (uint16)spell_id;
|
||||||
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id, char_id);
|
if ((spell_id_ != spell_id) || (spell_id != spell_id_)) {
|
||||||
if (SpellGlobalCheckResult) {
|
initiator->Message(13, "FATAL ERROR: Type conversion data loss with spell_id (%i != %u)", spell_id, spell_id_);
|
||||||
initiator->GetPP().disciplines.values[r] = spell_id;
|
return count;
|
||||||
database.SaveCharacterDisc(char_id, r, spell_id);
|
}
|
||||||
initiator->SendDisciplineUpdate();
|
|
||||||
initiator->Message(0, "You have learned a new discipline!");
|
if (!IsDiscipline(spell_id_))
|
||||||
count++; //success counter
|
break;
|
||||||
}
|
|
||||||
break; //continue the 1st loop
|
for (uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) {
|
||||||
} else if (SpellBucketRule) {
|
if (initiator->GetPP().disciplines.values[r] == spell_id_) {
|
||||||
// Bool to see if the character has the required bucket to train it if one exists in the spell_buckets table
|
initiator->Message(13, "You already know this discipline.");
|
||||||
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id, char_id);
|
break; // continue the 1st loop
|
||||||
if (SpellBucketCheckResult) {
|
}
|
||||||
initiator->GetPP().disciplines.values[r] = spell_id;
|
else if (initiator->GetPP().disciplines.values[r] == 0) {
|
||||||
database.SaveCharacterDisc(char_id, r, spell_id);
|
if (SpellGlobalRule) {
|
||||||
initiator->SendDisciplineUpdate();
|
// bool to see if the character has the required QGlobal to train it if one exists in the Spell_Globals table
|
||||||
initiator->Message(0, "You have learned a new discipline!");
|
SpellGlobalCheckResult = initiator->SpellGlobalCheck(spell_id_, char_id);
|
||||||
count++;
|
if (SpellGlobalCheckResult) {
|
||||||
}
|
initiator->GetPP().disciplines.values[r] = spell_id_;
|
||||||
break;
|
database.SaveCharacterDisc(char_id, r, spell_id_);
|
||||||
}
|
change = true;
|
||||||
else {
|
|
||||||
initiator->GetPP().disciplines.values[r] = spell_id;
|
|
||||||
database.SaveCharacterDisc(char_id, r, spell_id);
|
|
||||||
initiator->SendDisciplineUpdate();
|
|
||||||
initiator->Message(0, "You have learned a new discipline!");
|
initiator->Message(0, "You have learned a new discipline!");
|
||||||
count++; //success counter
|
++count; // success counter
|
||||||
break; //continue the 1st loop
|
|
||||||
}
|
}
|
||||||
} //if we get to this point, there's already a discipline in this slot, so we skip it
|
break; // continue the 1st loop
|
||||||
|
}
|
||||||
|
else if (SpellBucketRule) {
|
||||||
|
// bool to see if the character has the required bucket to train it if one exists in the spell_buckets table
|
||||||
|
SpellBucketCheckResult = initiator->SpellBucketCheck(spell_id_, char_id);
|
||||||
|
if (SpellBucketCheckResult) {
|
||||||
|
initiator->GetPP().disciplines.values[r] = spell_id_;
|
||||||
|
database.SaveCharacterDisc(char_id, r, spell_id_);
|
||||||
|
change = true;
|
||||||
|
initiator->Message(0, "You have learned a new discipline!");
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initiator->GetPP().disciplines.values[r] = spell_id_;
|
||||||
|
database.SaveCharacterDisc(char_id, r, spell_id_);
|
||||||
|
change = true;;
|
||||||
|
initiator->Message(0, "You have learned a new discipline!");
|
||||||
|
++count; // success counter
|
||||||
|
break; // continue the 1st loop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count; //how many disciplines were learned successfully
|
|
||||||
|
if (change)
|
||||||
|
initiator->SendDisciplineUpdate();
|
||||||
|
|
||||||
|
return count; // how many disciplines were learned successfully
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::unscribespells() {
|
void QuestManager::unscribespells() {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
initiator->UnscribeSpellAll();
|
initiator->UnscribeSpellAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::untraindiscs() {
|
void QuestManager::untraindiscs() {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
|
|||||||
@ -1075,9 +1075,6 @@ void Bot::WalkTo(float x, float y, float z)
|
|||||||
if (IsSitting())
|
if (IsSitting())
|
||||||
Stand();
|
Stand();
|
||||||
|
|
||||||
if (ping_timer.Enabled())
|
|
||||||
ping_timer.Disable();
|
|
||||||
|
|
||||||
Mob::WalkTo(x, y, z);
|
Mob::WalkTo(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,9 +1083,6 @@ void Bot::RunTo(float x, float y, float z)
|
|||||||
if (IsSitting())
|
if (IsSitting())
|
||||||
Stand();
|
Stand();
|
||||||
|
|
||||||
if (ping_timer.Enabled())
|
|
||||||
ping_timer.Disable();
|
|
||||||
|
|
||||||
Mob::RunTo(x, y, z);
|
Mob::RunTo(x, y, z);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
|
#include "../common/profanity_manager.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "corpse.h"
|
#include "corpse.h"
|
||||||
@ -793,6 +794,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_RefreshCensorship: {
|
||||||
|
if (!EQEmu::ProfanityManager::LoadProfanityList(&database))
|
||||||
|
Log(Logs::General, Logs::Error, "Received request to refresh the profanity list..but, the action failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ServerOP_ChangeWID: {
|
case ServerOP_ChangeWID: {
|
||||||
if (pack->size != sizeof(ServerChangeWID_Struct)) {
|
if (pack->size != sizeof(ServerChangeWID_Struct)) {
|
||||||
std::cout << "Wrong size on ServerChangeWID_Struct. Got: " << pack->size << ", Expected: " << sizeof(ServerChangeWID_Struct) << std::endl;
|
std::cout << "Wrong size on ServerChangeWID_Struct. Got: " << pack->size << ", Expected: " << sizeof(ServerChangeWID_Struct) << std::endl;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user