Compare commits

..

2 Commits

Author SHA1 Message Date
Trust 2434bab697 Updated for bypass all rule 2024-02-25 16:00:44 -05:00
Trust 7a5a755033 [Bug Fix] Cleanup NPC Mana Tap Logic
Mana Tap rule logic was invalid - Cleaned up and simplified, either we care about npc mana or we dont.
2024-02-25 15:20:58 -05:00
44 changed files with 302 additions and 723 deletions
-64
View File
@@ -1,67 +1,3 @@
## [22.46.0] 3/2/2024
### Commands
* Add #fish Command ([#4136](https://github.com/EQEmu/Server/pull/4136)) @Kinglykrab 2024-03-01
### Crash Fix
* Raid::UpdateGroupAAs ([#4139](https://github.com/EQEmu/Server/pull/4139)) @neckkola 2024-03-02
* Update to location of qGlobals initialization ([#4144](https://github.com/EQEmu/Server/pull/4144)) @neckkola 2024-03-02
### Feature
* Exempt a zone from IP-limit checks. ([#4137](https://github.com/EQEmu/Server/pull/4137)) @catapultam-habeo 2024-03-02
### Fixes
* Cleanup NPC Mana Tap Logic ([#4134](https://github.com/EQEmu/Server/pull/4134)) @noudess 2024-03-02
* Fix Bots/Bot Pets ending up on XTargets ([#4132](https://github.com/EQEmu/Server/pull/4132)) @Kinglykrab 2024-03-02
* Fix issue with NPC Secondary Textures ([#4129](https://github.com/EQEmu/Server/pull/4129)) @Kinglykrab 2024-03-01
* GetBotNameByID Temporary Reference Warning ([#4145](https://github.com/EQEmu/Server/pull/4145)) @Kinglykrab 2024-03-02
* Update FreeGuildID Routine ([#4143](https://github.com/EQEmu/Server/pull/4143)) @neckkola 2024-03-02
* Use std::clamp for Mob::ChangeSize ([#4140](https://github.com/EQEmu/Server/pull/4140)) @joligario 2024-03-02
### Quest API
* Add Bot Special Attacks for Immune Aggro/Damage ([#4108](https://github.com/EQEmu/Server/pull/4108)) @Kinglykrab 2024-03-02
### Zone
* Zone Routing Improvements ([#4142](https://github.com/EQEmu/Server/pull/4142)) @Akkadius 2024-03-02
## [22.45.1] 2/29/2024
### Character Creation
* Improved Random Name Generator ([#4081](https://github.com/EQEmu/Server/pull/4081)) @catapultam-habeo 2024-02-27
### Code
* Fix Server Rules Documentation Generation ([#4125](https://github.com/EQEmu/Server/pull/4125)) @Kinglykrab 2024-02-26
* Remove unnecessary stoptimer logs ([#4128](https://github.com/EQEmu/Server/pull/4128)) @Kinglykrab 2024-02-28
### Commands
* Add `#forage` command ([#4133](https://github.com/EQEmu/Server/pull/4133)) @joligario 2024-02-29
### Crash
* Fix crash issue during database dump ([#4127](https://github.com/EQEmu/Server/pull/4127)) @Akkadius 2024-02-29
### Crash Fix
* D20 crash if mitigation average resulted in 0 ([#4131](https://github.com/EQEmu/Server/pull/4131)) @nytmyr 2024-02-29
### Fixes
* Fix forage returning first result from table ([#4130](https://github.com/EQEmu/Server/pull/4130)) @nytmyr 2024-02-29
* Who /all displays incorrect guild name ([#4123](https://github.com/EQEmu/Server/pull/4123)) @neckkola 2024-02-25
### Quest API
* Add Pet Owner Methods to Perl/Lua ([#4115](https://github.com/EQEmu/Server/pull/4115)) @Kinglykrab 2024-02-25
## [22.45.0] 2/24/2024
### Beacon
+42 -78
View File
@@ -178,13 +178,12 @@ void WorldContentService::ReloadContentFlags()
LogInfo(
"Loaded content flag [{}] [{}]",
f.flag_name,
(f.enabled ? "enabled" : "disabled")
(f.enabled ? "Enabled" : "Disabled")
);
}
SetContentFlags(set_content_flags);
LoadZones();
LoadStaticGlobalZoneInstances();
SetContentZones(ZoneRepository::All(*m_content_database));
}
Database *WorldContentService::GetDatabase() const
@@ -236,6 +235,19 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
ReloadContentFlags();
}
// SetZones sets the zones for the world content service
// this is used for zone routing middleware
// we pull the zone list from the zone repository and feed from the zone store for now
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
WorldContentService *WorldContentService::SetContentZones(const std::vector<BaseZoneRepository::Zone>& zones)
{
m_zones = zones;
LogInfo("Loaded [{}] zones", m_zones.size());
return this;
}
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
//
// example # 1
@@ -248,52 +260,16 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
// we decide to route the client to the correct version of the zone based on the current server side expansion
// example # 2
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
{
auto r = FindZone(zc->zoneID, zc->instanceID);
if (r.zone_id == 0) {
// if we're already in an instance, we don't want to route the player to another instance
if (zc->instanceID > 0) {
return;
}
zc->instanceID = r.instance.id;
}
// LoadStaticGlobalZoneInstances loads all static global zone instances
// these are zones that are never set to expire and are global
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
WorldContentService * WorldContentService::LoadStaticGlobalZoneInstances()
{
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
return this;
}
// LoadZones sets the zones for the world content service
// this is used for zone routing middleware
// we pull the zone list from the zone repository and feed from the zone store for now
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
WorldContentService * WorldContentService::LoadZones()
{
m_zones = ZoneRepository::All(*GetContentDatabase());
LogInfo("Loaded [{}] zones", m_zones.size());
return this;
}
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
// era contextual routing, multiple version of zones, etc
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
{
// if we're already in a regular instance, we don't want to route the player to another instance
if (instance_id > RuleI(Instances, ReservedInstances)) {
return WorldContentService::FindZoneResult{};
}
for (auto &z: m_zones) {
if (z.zoneidnumber == zone_id) {
if (z.zoneidnumber == zc->zoneID) {
auto f = ContentFlags{
.min_expansion = z.min_expansion,
.max_expansion = z.max_expansion,
@@ -310,45 +286,33 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
z.long_name
);
// first pass, explicit match on public static global zone instances
for (auto &i: m_zone_instances) {
if (i.zone == zone_id && i.version == z.version) {
LogInfo(
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
i.id,
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
i.notes
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = i,
.zone = z
};
}
}
LogInfo(
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
z.note
auto instances = InstanceListRepository::GetWhere(
*GetDatabase(),
fmt::format(
"zone = {} AND version = {} AND never_expires = 1 AND is_global = 1",
z.zoneidnumber,
z.version
)
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = InstanceListRepository::NewEntity(),
.zone = z
};
if (!instances.empty()) {
auto instance = instances.front();
zc->instanceID = instance.id;
LogInfo(
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
instance.id,
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
instance.notes
);
break;
}
}
}
}
return WorldContentService::FindZoneResult{};
}
+1 -12
View File
@@ -5,7 +5,6 @@
#include <vector>
#include "../repositories/content_flags_repository.h"
#include "../repositories/zone_repository.h"
#include "../repositories/instance_list_repository.h"
class Database;
@@ -170,14 +169,7 @@ public:
void SetContentFlag(const std::string &content_flag_name, bool enabled);
void HandleZoneRoutingMiddleware(ZoneChange_Struct *zc);
struct FindZoneResult {
uint32 zone_id = 0;
InstanceListRepository::InstanceList instance;
ZoneRepository::Zone zone;
};
FindZoneResult FindZone(uint32 zone_id, uint32 instance_id);
WorldContentService * SetContentZones(const std::vector<ZoneRepository::Zone>& zones);
private:
int current_expansion{};
std::vector<ContentFlagsRepository::ContentFlags> content_flags;
@@ -188,9 +180,6 @@ private:
// holds a record of the zone table from the database
std::vector<ZoneRepository::Zone> m_zones = {};
WorldContentService *LoadStaticGlobalZoneInstances();
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
WorldContentService * LoadZones();
};
extern WorldContentService content_service;
+1 -6
View File
@@ -575,12 +575,7 @@ void DatabaseDumpService::RemoveSqlBackup()
{
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
if (File::Exists(file)) {
try {
std::filesystem::remove(file);
}
catch (std::exception &e) {
LogError("std::filesystem::remove err [{}]", e.what());
}
std::filesystem::remove(file);
}
RemoveCredentialsFile();
-2
View File
@@ -698,8 +698,6 @@ const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
{ IMMUNE_OPEN, "Immune to Open" },
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
};
return special_ability_map;
+1 -3
View File
@@ -656,9 +656,7 @@ enum {
IMMUNE_OPEN = 53,
IMMUNE_ASSASSINATE = 54,
IMMUNE_HEADSHOT = 55,
IMMUNE_AGGRO_BOT = 56,
IMMUNE_DAMAGE_BOT = 57,
MAX_SPECIAL_ATTACK = 58
MAX_SPECIAL_ATTACK = 56
};
-2
View File
@@ -141,7 +141,6 @@ namespace Logs {
Zoning,
EqTime,
Corpses,
XTargets,
MaxCategoryID /* Don't Remove this */
};
@@ -242,7 +241,6 @@ namespace Logs {
"Zoning",
"EqTime",
"Corpses",
"XTargets"
};
}
-10
View File
@@ -834,16 +834,6 @@
OutF(LogSys, Logs::Detail, Logs::Corpses, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogXTargets(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::XTargets))\
OutF(LogSys, Logs::General, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogXTargetsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::XTargets))\
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+34 -7
View File
@@ -342,14 +342,41 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id)
return true;
}
uint32 BaseGuildManager::_GetFreeGuildID()
{
GuildsRepository::DeleteWhere(*m_db, "`name` = ''");
GuildsRepository::Guilds out;
out.id = 0;
out.leader = 0;
out.minstatus = 0;
out.tribute = 0;
out.name = "";
out.motd = "";
out.motd_setter = "";
out.url = "";
out.channel = "";
auto last_insert_id = GuildsRepository::InsertOne(*m_db, out);
if (last_insert_id.id > 0) {
LogGuilds("Located a free guild ID [{}] in the database", last_insert_id.id);
return last_insert_id.id;
}
LogGuilds("Unable to find a free guild ID in the database");
return GUILD_NONE;
}
uint32 BaseGuildManager::CreateGuild(std::string name, uint32 leader_char_id)
{
uint32 guild_id = UpdateDbCreateGuild(name, leader_char_id);
if (guild_id == GUILD_NONE) {
return (GUILD_NONE);
}
uint32 guild_id = UpdateDbCreateGuild(name, leader_char_id);
if (guild_id == GUILD_NONE) {
return (GUILD_NONE);
}
//RefreshGuild(guild_id);
//SendGuildRefresh(guild_id, true, false, false, false);
//SendCharRefresh(GUILD_NONE, guild_id, leader_char_id);
return guild_id;
return guild_id;
}
bool BaseGuildManager::DeleteGuild(uint32 guild_id)
@@ -512,8 +539,8 @@ bool BaseGuildManager::SetPublicNote(uint32 charid, std::string public_note)
uint32 BaseGuildManager::UpdateDbCreateGuild(std::string name, uint32 leader)
{
auto new_id = GuildsRepository::GetMaxId(*m_db) + 1;
if (!new_id) {
auto new_id = _GetFreeGuildID();
if (new_id == GUILD_NONE) {
return GUILD_NONE;
}
+1
View File
@@ -208,6 +208,7 @@ class BaseGuildManager
bool _StoreGuildDB(uint32 guild_id);
GuildInfo* _CreateGuild(uint32 guild_id, std::string guild_name, uint32 leader_char_id, uint8 minstatus, std::string guild_motd, std::string motd_setter, std::string Channel, std::string URL, uint32 favour);
uint32 _GetFreeGuildID();
GuildsRepository::Guilds CreateGuildRepoFromGuildInfo(uint32 guild_id, BaseGuildManager::GuildInfo& in);
};
#endif /*GUILD_BASE_H_*/
+5 -35
View File
@@ -34,8 +34,8 @@ const char *RuleManager::s_categoryNames[_CatCount + 1] = {
"InvalidCategory"
};
const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount + 1] = {
/* this is done in three steps, so we can reliably get to them by index*/
const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + 1] = {
/* this is done in three steps so we can reliably get to them by index*/
#define RULE_INT(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, IntRule, Int__##rule_name, notes },
#include "ruletypes.h"
@@ -45,9 +45,6 @@ const RuleManager::RuleInfo RuleManager::s_RuleInfo[IntRuleCount + RealRuleCount
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, BoolRule, Bool__##rule_name, notes },
#include "ruletypes.h"
#define RULE_STRING(category_name, rule_name, default_value, notes) \
{ #category_name ":" #rule_name, Category__##category_name, StringRule, String__##rule_name, notes },
#include "ruletypes.h"
{ "Invalid Rule", _CatCount, IntRule }
};
@@ -117,9 +114,6 @@ bool RuleManager::GetRule(const std::string &rule_name, std::string &rule_value)
case BoolRule:
rule_value = m_RuleBoolValues[index] ? "true" : "false";
break;
case StringRule:
rule_value = m_RuleStringValues[index];
break;
}
return true;
@@ -158,10 +152,6 @@ bool RuleManager::SetRule(const std::string &rule_name, const std::string &rule_
m_RuleBoolValues[index] = static_cast<uint32>(Strings::ToBool(rule_value));
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleBoolValues[index] == 1 ? "true" : "false");
break;
case StringRule:
m_RuleStringValues[index] = rule_value;
LogRules("Set rule [{}] to value [{}]", rule_name, rule_value);
break;
}
if (db_save) {
@@ -225,13 +215,11 @@ std::string RuleManager::_GetRuleName(RuleType type, uint16 index) {
return s_RuleInfo[index + IntRuleCount].name;
case BoolRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount].name;
case StringRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount + StringRuleCount].name;
default:
break;
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount].name;
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount].name;
}
//assumes index is valid!
@@ -243,13 +231,11 @@ const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
return s_RuleInfo[index + IntRuleCount].notes;
case BoolRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount].notes;
case StringRule:
return s_RuleInfo[index + IntRuleCount + RealRuleCount + StringRuleCount].notes;
default:
break;
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount].notes;
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount].notes;
}
bool RuleManager::LoadRules(Database *db, const std::string &rule_set_name, bool reload) {
@@ -357,10 +343,6 @@ void RuleManager::SaveRules(Database *db, const std::string &rule_set_name) {
for (i = 0; i < BoolRuleCount; i++) {
_SaveRule(db, BoolRule, i);
}
for (i = 0; i < StringRuleCount; i++) {
_SaveRule(db, StringRule, i);
}
}
void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
@@ -385,9 +367,6 @@ void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
case BoolRule:
rule_value = m_RuleBoolValues[index] ? "true" : "false";
break;
case StringRule:
rule_value = m_RuleStringValues[index];
break;
}
const auto& rule_notes = _GetRuleNotes(type, index);
@@ -467,10 +446,6 @@ bool RuleManager::UpdateInjectedRules(Database *db, const std::string &rule_set_
rule_data[r.name].first = fmt::format("{}", m_RuleBoolValues[r.rule_index] ? "true" : "false");
rule_data[r.name].second = &r.notes;
break;
case StringRule:
rule_data[r.name].first = m_RuleStringValues[r.rule_index];
rule_data[r.name].second = &r.notes;
break;
default:
break;
}
@@ -577,7 +552,7 @@ bool RuleManager::RestoreRuleNotes(Database *db)
}
}
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount];
return s_RuleInfo[IntRuleCount + RealRuleCount + BoolRuleCount];
}(e.rule_name);
if (Strings::Contains(rule.name, e.rule_name)) {
@@ -642,8 +617,3 @@ bool RuleManager::GetBoolRule(RuleManager::BoolType t) const
{
return m_RuleBoolValues[t] == 1;
}
std::string RuleManager::GetStringRule(RuleManager::StringType t) const
{
return m_RuleStringValues[t];
}
+25 -45
View File
@@ -23,7 +23,6 @@
* - RuleI(category, rule) -> fetch an integer rule's value
* - RuleR(category, rule) -> fetch a real (float) rule's value
* - RuleB(category, rule) -> fetch a boolean/flag rule's value
* - RuleS(category, rule) -> fetch a string rule's value
*
*/
@@ -36,8 +35,6 @@
RuleManager::Instance()->GetRealRule( RuleManager::Real__##rule_name )
#define RuleB(category_name, rule_name) \
RuleManager::Instance()->GetBoolRule( RuleManager::Bool__##rule_name )
#define RuleS(category_name, rule_name) \
RuleManager::Instance()->GetStringRule( RuleManager::String__##rule_name )
#include <vector>
@@ -84,17 +81,6 @@ public:
static const int BoolRuleCount = static_cast<int>(_BoolRuleCount);
typedef enum {
#define RULE_STRING(category_name, rule_name, default_value, notes) \
String__##rule_name,
#include "ruletypes.h"
_StringRuleCount
} StringType;
static const int StringRuleCount = static_cast<int>(_StringRuleCount);
typedef enum {
#define RULE_CATEGORY(category_name) \
Category__##category_name,
@@ -113,49 +99,45 @@ public:
static const IntType InvalidInt = _IntRuleCount;
static const RealType InvalidReal = _RealRuleCount;
static const BoolType InvalidBool = _BoolRuleCount;
static const StringType InvalidString = _StringRuleCount;
static const CategoryType InvalidCategory = _CatCount;
static const uint32 RulesCount = IntRuleCount + RealRuleCount + BoolRuleCount + StringRuleCount;
static const uint32 RulesCount = IntRuleCount + RealRuleCount + BoolRuleCount;
//fetch routines, you should generally use the Rule* macros instead of this
int GetIntRule(IntType t) const;
float GetRealRule(RealType t) const;
bool GetBoolRule(BoolType t) const;
std::string GetStringRule(StringType t) const;
//management routines
static std::string GetRuleName(IntType t) { return s_RuleInfo[static_cast<int>(t)].name; }
static std::string GetRuleName(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].name; }
static std::string GetRuleName(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].name; }
static std::string GetRuleName(StringType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount + StringRuleCount].name; }
static const std::string& GetRuleNotes(IntType t) { return s_RuleInfo[static_cast<int>(t)].notes; }
static const std::string& GetRuleNotes(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].notes; }
static const std::string& GetRuleNotes(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].notes; }
static const std::string& GetRuleNotes(StringType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount + StringRuleCount].notes; }
static const std::string &GetRuleNotes(IntType t) { return s_RuleInfo[static_cast<int>(t)].notes; }
static const std::string &GetRuleNotes(RealType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount].notes; }
static const std::string &GetRuleNotes(BoolType t) { return s_RuleInfo[static_cast<int>(t) + IntRuleCount + RealRuleCount].notes; }
static uint32 CountRules() { return RulesCount; }
static CategoryType FindCategory(const std::string& category_name);
bool ListRules(const std::string& category_name, std::vector<std::string>& l);
bool ListCategories(std::vector<std::string>& l);
bool GetRule(const std::string& rule_name, std::string& rule_value);
static CategoryType FindCategory(const std::string &category_name);
bool ListRules(const std::string &category_name, std::vector <std::string> &l);
bool ListCategories(std::vector <std::string> &l);
bool GetRule(const std::string &rule_name, std::string &rule_value);
bool SetRule(
const std::string& rule_name,
const std::string& rule_value,
Database* db = nullptr,
const std::string &rule_name,
const std::string &rule_value,
Database *db = nullptr,
bool db_save = false,
bool reload = false
);
int GetActiveRulesetID() const { return m_activeRuleset; }
std::string GetActiveRuleset() const { return m_activeName; }
static bool ListRulesets(Database* db, std::map<int, std::string>& l);
static bool ListRulesets(Database *db, std::map<int, std::string> &l);
void ResetRules(bool reload = false);
bool LoadRules(Database* db, const std::string& rule_set_name, bool reload = false);
void SaveRules(Database* db, const std::string& rule_set_name);
bool UpdateInjectedRules(Database* db, const std::string& rule_set_name, bool quiet_update = false);
bool UpdateOrphanedRules(Database* db, bool quiet_update = false);
bool RestoreRuleNotes(Database* db);
bool LoadRules(Database *db, const std::string &rule_set_name, bool reload = false);
void SaveRules(Database *db, const std::string &rule_set_name);
bool UpdateInjectedRules(Database *db, const std::string &rule_set_name, bool quiet_update = false);
bool UpdateOrphanedRules(Database *db, bool quiet_update = false);
bool RestoreRuleNotes(Database *db);
private:
RuleManager();
@@ -165,23 +147,21 @@ private:
int m_activeRuleset;
std::string m_activeName;
int m_RuleIntValues[IntRuleCount];
float m_RuleRealValues[RealRuleCount];
uint32 m_RuleBoolValues[BoolRuleCount];
std::string m_RuleStringValues[StringRuleCount];
int m_RuleIntValues[IntRuleCount];
float m_RuleRealValues[RealRuleCount];
uint32 m_RuleBoolValues[BoolRuleCount];
typedef enum {
IntRule,
RealRule,
BoolRule,
StringRule
BoolRule
} RuleType;
static bool _FindRule(const std::string& rule_name, RuleType& type_into, uint16& index_into);
static bool _FindRule(const std::string &rule_name, RuleType &type_into, uint16 &index_into);
static std::string _GetRuleName(RuleType type, uint16 index);
static const std::string& _GetRuleNotes(RuleType type, uint16 index);
static int _FindOrCreateRuleset(Database* db, const std::string& rule_set_name);
void _SaveRule(Database* db, RuleType type, uint16 index);
static const std::string &_GetRuleNotes(RuleType type, uint16 index);
static int _FindOrCreateRuleset(Database *db, const std::string &rule_set_name);
void _SaveRule(Database *db, RuleType type, uint16 index);
static const char* s_categoryNames[];
typedef struct {
+3 -9
View File
@@ -28,9 +28,6 @@
#ifndef RULE_BOOL
#define RULE_BOOL(cat, rule, default_value, notes)
#endif
#ifndef RULE_STRING
#define RULE_STRING(cat, rule, default_value, notes)
#endif
#ifndef RULE_CATEGORY_END
#define RULE_CATEGORY_END()
#endif
@@ -51,10 +48,10 @@ RULE_BOOL(Character, DeathKeepLevel, false, "Players can not drop below 0% exper
RULE_BOOL(Character, UseDeathExpLossMult, false, "Setting to control whether DeathExpLossMultiplier or the code default is used: (Level x Level / 18.0) x 12000")
RULE_BOOL(Character, UseOldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
RULE_INT(Character, CorpseDecayTime, 604800000, "Time after which the corpse decays (milliseconds) DEFAULT: 604800000 (7 Days)")
RULE_INT(Character, EmptyCorpseDecayTime, 10800000, "Time after which an empty corpse decays (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT( Character, EmptyCorpseDecayTime, 10800000, "Time after which an empty corpse decays (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT(Character, CorpseResTime, 10800000, "Time after which the corpse can no longer be resurrected (milliseconds) DEFAULT: 10800000 (3 Hours)")
RULE_INT(Character, DuelCorpseResTime, 600000, "Time before cant res corpse after a duel (milliseconds) DEFAULT: 600000 (10 Minutes)")
RULE_INT(Character, CorpseOwnerOnlineTime, 30000, "How often corpse will check if its owner is online DEFAULT: 30000 (30 Seconds)")
RULE_INT( Character, DuelCorpseResTime, 600000, "Time before cant res corpse after a duel (milliseconds) DEFAULT: 600000 (10 Minutes)")
RULE_INT( Character, CorpseOwnerOnlineTime, 30000, "How often corpse will check if its owner is online DEFAULT: 30000 (30 Seconds)")
RULE_BOOL(Character, LeaveCorpses, true, "Setting whether you leave a corpse behind")
RULE_BOOL(Character, LeaveNakedCorpses, false, "Setting whether you leave a corpse without items")
RULE_INT(Character, MaxDraggedCorpses, 2, "Maximum number of corpses you can drag at once")
@@ -327,8 +324,6 @@ RULE_INT(World, MaximumQuestErrors, 30, "Changes the maximum number of quest err
RULE_INT(World, BootHour, 0, "Sets the in-game hour world will set when it first boots. 0-24 are valid options, where 0 disables this rule")
RULE_BOOL(World, UseItemLinksForKeyRing, false, "Uses item links for Key Ring Listing instead of item name")
RULE_BOOL(World, UseOldShadowKnightClassExport, true, "Disable to have Shadowknight show as Shadow Knight (live-like)")
RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclude from IP-limit checks. Empty string to disable.")
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@@ -956,5 +951,4 @@ RULE_CATEGORY_END()
#undef RULE_INT
#undef RULE_REAL
#undef RULE_BOOL
#undef RULE_STRING
#undef RULE_CATEGORY_END
+1 -1
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.46.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.45.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.46.0",
"version": "22.45.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+70 -72
View File
@@ -52,7 +52,6 @@
#include "../common/repositories/player_event_logs_repository.h"
#include "../common/repositories/inventory_repository.h"
#include "../common/events/player_event_logs.h"
#include "../common/content/world_content_service.h"
#include <iostream>
#include <iomanip>
@@ -600,63 +599,79 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app)
}
bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) {
char newName[17] = {0};
bool unique = false;
while (!unique) {
std::string cons = "bcdfghjklmnpqrstvwxyz";
std::string vows = "aeou";
std::string allVows = "aeiou";
std::vector<std::string> endPhon = {"a", "e", "i", "o", "u", "os", "as", "us", "is", "y", "an", "en", "in", "on", "un"};
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> lenDist(5, 10);
std::uniform_int_distribution<int> firstCharDist(0, 1);
std::uniform_int_distribution<int> consDist(0, cons.size() - 1);
std::uniform_int_distribution<int> vowDist(0, vows.size() - 1);
std::uniform_int_distribution<int> allVowDist(0, allVows.size() - 1);
std::uniform_int_distribution<int> endPhonDist(0, endPhon.size() - 1);
int len = 0;
memset(newName, 0, sizeof(newName));
if (firstCharDist(gen) == 0) {
newName[len++] = vows[vowDist(gen)];
newName[len++] = cons[consDist(gen)];
} else {
newName[len++] = cons[consDist(gen)];
newName[len++] = allVows[allVowDist(gen)];
}
newName[0] = toupper(newName[0]);
while (len < lenDist(gen) - 1) {
if (len % 2 == 0) {
newName[len++] = cons[consDist(gen)];
} else {
newName[len++] = allVows[allVowDist(gen)];
// creates up to a 10 char name
char vowels[18]="aeiouyaeiouaeioe";
char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd";
char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr";
int rndnum=emu_random.Int(0, 75),n=1;
bool dlc=false;
bool vwl=false;
bool dbl=false;
if (rndnum>63)
{ // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk"
rndname[0]=paircons[rndnum];
rndname[1]=paircons[rndnum+1];
n=2;
}
else if (rndnum>16)
{
rndnum-=17;
rndname[0]=cons[rndnum];
}
else
{
rndname[0]=vowels[rndnum];
vwl=true;
}
int namlen=emu_random.Int(5, 10);
for (int i=n;i<namlen;i++)
{
dlc=false;
if (vwl) //last char was a vowel
{ // so pick a cons or cons pair
rndnum=emu_random.Int(0, 62);
if (rndnum>46)
{ // pick a cons pair
if (i>namlen-3) // last 2 chars in name?
{ // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
rndnum=emu_random.Int(0, 7)*2;
}
else
{ // pick any from the set
rndnum=(rndnum-47)*2;
}
rndname[i]=paircons[rndnum];
rndname[i+1]=paircons[rndnum+1];
dlc=true; // flag keeps second letter from being doubled below
i+=1;
}
else
{ // select a single cons
rndname[i]=cons[rndnum];
}
}
std::string end = endPhon[endPhonDist(gen)];
for (char c : end) {
if (len < 10) newName[len++] = c;
else
{ // select a vowel
rndname[i]=vowels[emu_random.Int(0, 16)];
}
if (database.CheckNameFilter(newName)) {
std::string query = StringFormat("SELECT `name` FROM `character_data` WHERE `name` = '%s'", newName);
auto res = database.QueryDatabase(query);
if (res.Success() && res.RowCount() == 0) {
unique = true;
vwl=!vwl;
if (!dbl && !dlc)
{ // one chance at double letters in name
if (!emu_random.Int(0, i+9)) // chances decrease towards end of name
{
rndname[i+1]=rndname[i];
dbl=true;
i+=1;
}
}
}
rndname[0]=toupper(rndname[0]);
NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
memset(ngs->name, 0, 64);
strcpy(ngs->name, newName);
memset(ngs->name,0,64);
strcpy(ngs->name,rndname);
QueuePacket(app);
return true;
@@ -772,18 +787,6 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
return true;
}
auto r = content_service.FindZone(zone_id, instance_id);
if (r.zone_id && r.instance.id != instance_id) {
LogInfo(
"Zone [{}] has been remapped to instance_id [{}] from instance_id [{}] for client [{}]",
r.zone.short_name,
r.instance.id,
instance_id,
char_name
);
instance_id = r.instance.id;
}
// Make sure this account owns this character
if (temporary_account_id != account_id) {
LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id);
@@ -900,19 +903,14 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
}
auto outapp = new EQApplicationPacket(OP_MOTD);
std::string motd = RuleS(World, MOTD);
if (!motd.empty()) {
outapp->size = motd.length() + 1;
std::string motd_message;
if (database.GetVariable("MOTD", motd_message)) {
outapp->size = motd_message.length() + 1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer, 0, outapp->size);
strcpy((char*) outapp->pBuffer, motd.c_str());
} else if (database.GetVariable("MOTD", motd)) {
outapp->size = motd.length() + 1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer, 0, outapp->size);
strcpy((char*) outapp->pBuffer, motd.c_str());
strcpy((char*)outapp->pBuffer, motd_message.c_str());
} else { // Null Message of the Day. :)
outapp->size = 1;
outapp->size = 1;
outapp->pBuffer = new uchar[outapp->size];
outapp->pBuffer[0] = 0;
}
-9
View File
@@ -96,15 +96,6 @@ void ClientList::GetCLEIP(uint32 in_ip) {
while (iterator.MoreElements()) {
cle = iterator.GetData();
const auto zones = Strings::Split(RuleS(World, IPExemptionZones), ",");
for (const auto &z : zones) {
if (Strings::ToUnsignedInt(z) == cle->zone()) {
iterator.Advance();
continue;
}
}
if (
cle->GetIP() == in_ip &&
(
-1
View File
@@ -142,7 +142,6 @@ std::vector<Reload> reload_types = {
Reload{.command = "base_data", .opcode = ServerOP_ReloadBaseData, .desc = "Base Data"},
Reload{.command = "blocked_spells", .opcode = ServerOP_ReloadBlockedSpells, .desc = "Blocked Spells"},
Reload{.command = "commands", .opcode = ServerOP_ReloadCommands, .desc = "Commands"},
Reload{.command = "content_flags", .opcode = ServerOP_ReloadContentFlags, .desc = "Content Flags"},
Reload{.command = "data_buckets_cache", .opcode = ServerOP_ReloadDataBucketsCache, .desc = "Data Buckets Cache"},
Reload{.command = "doors", .opcode = ServerOP_ReloadDoors, .desc = "Doors"},
Reload{.command = "dztemplates", .opcode = ServerOP_ReloadDzTemplates, .desc = "Dynamic Zone Templates"},
-5
View File
@@ -188,11 +188,6 @@ int main(int argc, char **argv)
RegisterConsoleFunctions(console);
}
content_service.SetDatabase(&database)
->SetContentDatabase(&content_db)
->SetExpansionContext()
->ReloadContentFlags();
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
server_connection = std::make_unique<EQ::Net::ServertalkServer>();
+1 -11
View File
@@ -230,23 +230,13 @@ void WorldGuildManager::ProcessZonePacket(ServerPacket *pack) {
case ServerOP_GuildChannel:
case ServerOP_GuildURL:
case ServerOP_GuildMemberRemove:
case ServerOP_GuildMemberAdd:
case ServerOP_GuildSendGuildList:
case ServerOP_GuildMembersList:
{
zoneserver_list.SendPacketToBootedZones(pack);
break;
}
case ServerOP_GuildMemberAdd:
{
auto in = (ServerOP_GuildMessage_Struct *)pack->pBuffer;
auto guild = GetGuildByGuildID(in->guild_id);
if (!guild) {
BaseGuildManager::RefreshGuild(in->guild_id);
}
zoneserver_list.SendPacketToBootedZones(pack);
break;
}
default:
LogGuilds("Unknown packet {:#04x} received from zone??", pack->opcode);
break;
+1 -1
View File
@@ -1100,7 +1100,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
auto smotd = (ServerMotd_Struct*) pack->pBuffer;
RuleManager::Instance()->SetRule("MOTD", smotd->motd, &database, true, true);
database.SetVariable("MOTD", smotd->motd);
zoneserver_list.SendPacket(pack);
break;
}
+7 -17
View File
@@ -621,38 +621,28 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
// NPC *npc1, *npc2;
int reverse;
if (!zone->CanDoCombat()) {
if(!zone->CanDoCombat())
return false;
}
// some special cases
if (!target) {
if(!target)
return false;
}
if (this == target) { // you can attack yourself
if(this == target) // you can attack yourself
return true;
}
if (target->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){
return false;
}
if (IsBot() && target->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
if (target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
return false;
}
if (IsClient() && target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
return false;
}
if (IsNPC() && target->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
if (target->IsHorse())
return false;
}
if (target->IsHorse()) {
return false;
}
// can't damage own pet (applies to everthing)
Mob *target_owner = target->GetOwner();
+16 -31
View File
@@ -1005,7 +1005,7 @@ double Mob::RollD20(int offense, int mitigation)
auto atk_roll = zone->random.Roll0(offense + 5);
auto def_roll = zone->random.Roll0(mitigation + 5);
int avg = std::max(1, (offense + mitigation + 10) / 2);
int avg = (offense + mitigation + 10) / 2;
int index = std::max(0, (atk_roll - def_roll) + (avg / 2));
index = EQ::Clamp((index * 20) / avg, 0, 19);
@@ -3091,37 +3091,26 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
TryTriggerOnCastRequirement();
}
if (IsClient() && !IsAIControlled()) {
if (IsClient() && !IsAIControlled())
return;
}
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) {
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
return;
}
if (other->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) {
if (GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
return;
}
if (other->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) {
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
return;
}
if (other->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC)) {
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id))
return;
}
if (IsValidSpell(spell_id) && IsNoDetrimentalSpellAggroSpell(spell_id)) {
if (other == myowner)
return;
}
if (other == myowner) {
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON))
return;
}
if (other->GetSpecialAbility(IMMUNE_AGGRO_ON)) {
return;
}
if (GetSpecialAbility(NPC_TUNNELVISION)) {
int tv_mod = GetSpecialAbilityParam(NPC_TUNNELVISION, 0);
@@ -3205,9 +3194,8 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
// owner must get on list, but he's not actually gained any hate yet
if (
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
!(owner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(owner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(owner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
) {
if (owner->IsClient() && !CheckAggro(owner)) {
owner->CastToClient()->AddAutoXTarget(this);
@@ -3221,9 +3209,8 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
if (
!mypet->IsFamiliar() &&
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
!(IsBot() && mypet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(IsClient() && mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(IsNPC() && mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC))
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && IsClient()) &&
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && IsNPC())
) {
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -3232,9 +3219,8 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
if (
myowner->IsAIControlled() &&
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
!(myowner->IsBot() && GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(myowner->IsClient() && GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(myowner->IsNPC() && GetSpecialAbility(IMMUNE_AGGRO_NPC))
!(GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && myowner->IsClient()) &&
!(GetSpecialAbility(IMMUNE_AGGRO_NPC) && myowner->IsNPC())
) {
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -4074,9 +4060,8 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
!pet->IsEngaged() &&
attacker &&
!(attacker->IsBot() && pet->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(attacker->IsClient() && pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(attacker->IsNPC() && pet->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
!(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
!(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
attacker != this &&
!attacker->IsCorpse() &&
!pet->IsGHeld() &&
+1 -1
View File
@@ -2367,7 +2367,7 @@ const uint8 BotDatabase::GetBotLevelByID(const uint32 bot_id)
return e.bot_id ? e.level : 0;
}
const std::string BotDatabase::GetBotNameByID(const uint32 bot_id)
const std::string& BotDatabase::GetBotNameByID(const uint32 bot_id)
{
const auto& e = BotDataRepository::FindOne(database, bot_id);
+1 -1
View File
@@ -164,7 +164,7 @@ public:
const uint8 GetBotGenderByID(const uint32 bot_id);
std::vector<uint32> GetBotIDsByCharacterID(const uint32 character_id, uint8 class_id = Class::None);
const uint8 GetBotLevelByID(const uint32 bot_id);
const std::string GetBotNameByID(const uint32 bot_id);
const std::string& GetBotNameByID(const uint32 bot_id);
const uint16 GetBotRaceByID(const uint32 bot_id);
class fail {
+11 -42
View File
@@ -284,7 +284,6 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
PendingSacrifice = false;
controlling_boat_id = 0;
controlled_mob_id = 0;
qGlobals = nullptr;
if (!RuleB(Character, PerCharacterQglobalMaxLevel) && !RuleB(Character, PerCharacterBucketMaxLevel)) {
SetClientMaxLevel(0);
@@ -312,6 +311,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
aa_los_them_mob = nullptr;
los_status = false;
los_status_facing = false;
qGlobals = nullptr;
HideCorpseMode = HideCorpseNone;
PendingGuildInvitation = false;
@@ -6285,17 +6285,7 @@ void Client::SendZonePoints()
zp->zpe[i].z = data->target_z;
zp->zpe[i].heading = data->target_heading;
zp->zpe[i].zoneid = data->target_zone_id;
// if the target zone is the same as the current zone, use the instance of the current zone
// if we don't use the same instance_id that the client was sent, the client will forcefully
// issue a zone change request when they should be simply moving to a different point in the same zone
// because the client will think the zone point target is different from the current instance
auto target_instance = data->target_zone_instance;
if (data->target_zone_id == zone->GetZoneID() && data->target_zone_instance == 0) {
target_instance = zone->GetInstanceID();
}
zp->zpe[i].zoneinstance = target_instance;
zp->zpe[i].zoneinstance = data->target_zone_instance;
i++;
}
iterator.Advance();
@@ -6775,36 +6765,23 @@ void Client::UpdateClientXTarget(Client *c)
// IT IS NOT SAFE TO CALL THIS IF IT'S NOT INITIAL AGGRO
void Client::AddAutoXTarget(Mob *m, bool send)
{
if (m->IsBot() || (m->IsPet() && m->IsPetOwnerBot())) {
return;
}
m_activeautohatermgr->increment_count(m);
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m)) {
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m))
return;
}
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type == Auto && XTargets[i].ID == 0) {
for(int i = 0; i < GetMaxXTargets(); ++i)
{
if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0))
{
XTargets[i].ID = m->GetID();
if (send) { // if we don't send we're bulk sending updates later on
if (send) // if we don't send we're bulk sending updates later on
SendXTargetPacket(i, m);
} else {
else
XTargets[i].dirty = true;
}
break;
}
}
LogXTargets(
"Adding [{}] to [{}] ({}) XTargets",
m->GetCleanName(),
GetCleanName(),
GetID()
);
}
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
@@ -6813,23 +6790,15 @@ void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
// now we may need to clean up our CurrentTargetNPC entries
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type == CurrentTargetNPC && XTargets[i].ID == m->GetID()) {
XTargets[i].Type = Auto;
XTargets[i].ID = 0;
XTargets[i].Type = Auto;
XTargets[i].ID = 0;
XTargets[i].dirty = true;
}
}
auto r = GetRaid();
if (r) {
r->UpdateRaidXTargets();
}
LogXTargets(
"Removing [{}] from [{}] ({}) XTargets",
m->GetCleanName(),
GetCleanName(),
GetID()
);
}
void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name)
+1 -1
View File
@@ -1090,7 +1090,7 @@ public:
void SetPEQZoneFlag(uint32 zone_id);
bool CanFish();
void GoFish(bool guarantee = false, bool use_bait = true);
void GoFish();
void ForageItem(bool guarantee = false);
//Calculate vendor price modifier based on CHA: (reverse==selling)
float CalcPriceMod(Mob* other = 0, bool reverse = false);
-4
View File
@@ -131,10 +131,8 @@ int command_init(void)
command_add("feature", "Change your or your target's feature's temporarily", AccountStatus::QuestTroupe, command_feature) ||
command_add("size", "Change your targets size (alias of #feature size)", AccountStatus::QuestTroupe, command_feature) ||
command_add("find", "Search command used to find various things", AccountStatus::Guide, command_find) ||
command_add("fish", "Fish for an item", AccountStatus::QuestTroupe, command_fish) ||
command_add("fixmob", "[race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev] - Manipulate appearance of your target", AccountStatus::QuestTroupe, command_fixmob) ||
command_add("flagedit", "Edit zone flags on your target. Use #flagedit help for more info.", AccountStatus::GMAdmin, command_flagedit) ||
command_add("forage", "Forage an item", AccountStatus::QuestTroupe, command_forage) ||
command_add("gearup", "Developer tool to quickly equip yourself or your target", AccountStatus::GMMgmt, command_gearup) ||
command_add("giveitem", "[itemid] [charges] - Summon an item onto your target's cursor. Charges are optional.", AccountStatus::GMMgmt, command_giveitem) ||
command_add("givemoney", "[Platinum] [Gold] [Silver] [Copper] - Gives specified amount of money to you or your player target", AccountStatus::GMMgmt, command_givemoney) ||
@@ -824,10 +822,8 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/faction.cpp"
#include "gm_commands/feature.cpp"
#include "gm_commands/find.cpp"
#include "gm_commands/fish.cpp"
#include "gm_commands/fixmob.cpp"
#include "gm_commands/flagedit.cpp"
#include "gm_commands/forage.cpp"
#include "gm_commands/gearup.cpp"
#include "gm_commands/giveitem.cpp"
#include "gm_commands/givemoney.cpp"
-2
View File
@@ -83,10 +83,8 @@ void command_faction(Client *c, const Seperator *sep);
void command_faction_association(Client *c, const Seperator *sep);
void command_feature(Client *c, const Seperator *sep);
void command_find(Client *c, const Seperator *sep);
void command_fish(Client* c, const Seperator* sep);
void command_fixmob(Client *c, const Seperator *sep);
void command_flagedit(Client *c, const Seperator *sep);
void command_forage(Client* c, const Seperator* sep);
void command_gearup(Client *c, const Seperator *sep);
void command_giveitem(Client *c, const Seperator *sep);
void command_givemoney(Client *c, const Seperator *sep);
-9
View File
@@ -73,15 +73,6 @@ Doors::Doors(const DoorsRepository::Doors &door) :
m_door_param = door.door_param;
m_size = door.size;
m_invert_state = door.invert_state;
// if the target zone is the same as the current zone, use the instance of the current zone
// if we don't use the same instance_id that the client was sent, the client will forcefully
// issue a zone change request when they should be simply moving to a different point in the same zone
// because the client will think the zone point target is different from the current instance
if (door.dest_zone == zone->GetShortName() && m_destination_instance_id == 0) {
m_destination_instance_id = zone->GetInstanceID();
}
m_destination_instance_id = door.dest_instance;
m_is_ldon_door = door.is_ldon_door;
m_dz_switch_id = door.dz_switch_id;
+4 -6
View File
@@ -4379,9 +4379,8 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
if (
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
!(other->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(other->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(other->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC))
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient()) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
) {
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@@ -4406,9 +4405,8 @@ void EntityList::AddTempPetsToHateListOnOwnerDamage(Mob *owner, Mob* attacker, i
attacker != n &&
!n->IsEngaged() &&
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
!(attacker->IsBot() && n->GetSpecialAbility(IMMUNE_AGGRO_BOT)) &&
!(attacker->IsClient() && n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT)) &&
!(attacker->IsNPC() && n->GetSpecialAbility(IMMUNE_AGGRO_NPC)) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
!attacker->IsTrap() &&
!attacker->IsCorpse()
) {
+5 -7
View File
@@ -89,7 +89,7 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
}
forage_items[count] = e.Itemid;
forage_chances[count] = e.chance + current_chance;
forage_chances[count] = e.chance;
current_chance = forage_chances[count];
@@ -257,7 +257,7 @@ bool Client::CanFish() {
return true;
}
void Client::GoFish(bool guarantee, bool use_bait)
void Client::GoFish()
{
//TODO: generate a message if we're already fishing
@@ -306,7 +306,7 @@ void Client::GoFish(bool guarantee, bool use_bait)
fishing_skill = 100+((fishing_skill-100)/2);
}
if (guarantee || zone->random.Int(0,175) < fishing_skill) {
if (zone->random.Int(0,175) < fishing_skill) {
uint32 food_id = 0;
//25% chance to fish an item.
@@ -343,10 +343,8 @@ void Client::GoFish(bool guarantee, bool use_bait)
}
}
if (use_bait) {
//consume bait, should we always consume bait on success?
DeleteItemInInventory(bslot, 1, true); //do we need client update?
}
//consume bait, should we always consume bait on success?
DeleteItemInInventory(bslot, 1, true); //do we need client update?
if(food_id == 0) {
int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1);
-6
View File
@@ -1,6 +0,0 @@
#include "../client.h"
void command_fish(Client *c, const Seperator *sep)
{
c->GoFish(true, false);
}
-6
View File
@@ -1,6 +0,0 @@
#include "../client.h"
void command_forage(Client *c, const Seperator *sep)
{
c->ForageItem(true);
}
+1 -18
View File
@@ -5653,10 +5653,6 @@ bool get_ruleb(int rule) {
return RuleManager::Instance()->GetBoolRule((RuleManager::BoolType)rule);
}
std::string get_rules(int rule) {
return RuleManager::Instance()->GetStringRule((RuleManager::StringType)rule);
}
luabind::scope lua_register_general() {
return luabind::namespace_("eq")
[(
@@ -7248,13 +7244,7 @@ luabind::scope lua_register_rules_const() {
#define RULE_BOOL(cat, rule, default_value, notes) \
luabind::value(#rule, RuleManager::Bool__##rule),
#include "../common/ruletypes.h"
luabind::value("_BoolRuleCount", RuleManager::_BoolRuleCount),
#undef RULE_BOOL
#define RULE_STRING(cat, rule, default_value, notes) \
luabind::value(#rule, RuleManager::String__##rule),
#include "../common/ruletypes.h"
luabind::value("_StringRuleCount", RuleManager::_StringRuleCount)
#undef RULE_STRING
luabind::value("_BoolRuleCount", RuleManager::_BoolRuleCount)
)];
}
@@ -7279,13 +7269,6 @@ luabind::scope lua_register_ruleb() {
];
}
luabind::scope lua_register_rules() {
return luabind::namespace_("RuleS")
[
luabind::def("Get", &get_rules)
];
}
luabind::scope lua_register_journal_speakmode() {
return luabind::class_<Journal_SpeakMode>("SpeakMode")
.enum_("constants")
+1 -3
View File
@@ -3866,9 +3866,7 @@ luabind::scope lua_register_special_abilities() {
luabind::value("modify_avoid_damage", static_cast<int>(MODIFY_AVOID_DAMAGE)),
luabind::value("immune_open", static_cast<int>(IMMUNE_OPEN)),
luabind::value("immune_assassinate", static_cast<int>(IMMUNE_ASSASSINATE)),
luabind::value("immune_headshot", static_cast<int>(IMMUNE_HEADSHOT)),
luabind::value("immune_aggro_bot", static_cast<int>(IMMUNE_AGGRO_BOT)),
luabind::value("immune_damage_bot", static_cast<int>(IMMUNE_DAMAGE_BOT))
luabind::value("immune_headshot", static_cast<int>(IMMUNE_HEADSHOT))
)];
}
+1
View File
@@ -403,6 +403,7 @@ int main(int argc, char **argv)
content_service.SetDatabase(&database)
->SetContentDatabase(&content_db)
->SetContentZones(zone_store.GetZones())
->SetExpansionContext()
->ReloadContentFlags();
+45 -128
View File
@@ -1220,7 +1220,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
UpdateActiveLight();
ns->spawn.light = m_Light.Type[EQ::lightsource::LightActive];
ns->spawn.showhelm = helmtexture != std::numeric_limits<uint8>::max() ? 1 : 0;
if (IsNPC() && race == ERUDITE)
ns->spawn.showhelm = 1;
else
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1;
@@ -1269,8 +1272,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
for (i = 0; i < EQ::textures::materialCount; i++) {
if (IsPlayerRace(race) || i > EQ::textures::armorFeet) {
//for (i = 0; i < _MaterialCount; i++)
for (i = 0; i < 9; i++) {
// Only Player Races Wear Armor
if (IsPlayerRace(race) || i > 6) {
ns->spawn.equipment.Slot[i].Material = GetEquipmentMaterial(i);
ns->spawn.equipment.Slot[i].EliteModel = IsEliteMaterialItem(i);
ns->spawn.equipment.Slot[i].HerosForgeModel = GetHerosForgeModel(i);
@@ -1278,42 +1283,13 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
}
}
for (i = 0; i < EQ::textures::weaponPrimary; i++) {
if (texture == std::numeric_limits<uint8>::max()) {
continue;
if (texture > 0) {
for (i = 0; i < 9; i++) {
if (i == EQ::textures::weaponPrimary || i == EQ::textures::weaponSecondary || texture == 255) {
continue;
}
ns->spawn.equipment.Slot[i].Material = texture;
}
if (i == EQ::textures::armorHead && helmtexture != texture) {
ns->spawn.equipment.Slot[i].Material = helmtexture;
continue;
}
if (i == EQ::textures::armorArms && armtexture != 0) {
ns->spawn.equipment.Slot[i].Material = armtexture;
continue;
}
if (i == EQ::textures::armorWrist && bracertexture != 0) {
ns->spawn.equipment.Slot[i].Material = bracertexture;
continue;
}
if (i == EQ::textures::armorHands && handtexture != 0) {
ns->spawn.equipment.Slot[i].Material = handtexture;
continue;
}
if (i == EQ::textures::armorLegs && legtexture != 0) {
ns->spawn.equipment.Slot[i].Material = legtexture;
continue;
}
if (i == EQ::textures::armorFeet && feettexture != 0) {
ns->spawn.equipment.Slot[i].Material = feettexture;
continue;
}
ns->spawn.equipment.Slot[i].Material = texture;
}
memset(ns->spawn.set_to_0xFF, 0xFF, sizeof(ns->spawn.set_to_0xFF));
@@ -4384,15 +4360,17 @@ void Mob::SendWearChangeAndLighting(int8 last_texture) {
void Mob::ChangeSize(float in_size = 0, bool unrestricted)
{
size = std::clamp(in_size, 1.0f, 255.0f);
if (!unrestricted) {
if (IsClient() || petid != 0) {
size = std::clamp(in_size, 3.0f, 15.0f);
EQ::Clamp(in_size, 3.0f, 15.0f);
}
}
SendAppearancePacket(AppearanceType::Size, static_cast<uint32>(size));
EQ::Clamp(in_size, 1.0f, 255.0f);
size = in_size;
SendAppearancePacket(AppearanceType::Size, static_cast<uint32>(in_size));
}
Mob* Mob::GetOwnerOrSelf()
@@ -5204,47 +5182,32 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime)
}
void Mob::ExecWeaponProc(const EQ::ItemInstance* inst, uint16 spell_id, Mob* on, int level_override)
{
void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on, int level_override) {
// Changed proc targets to look up based on the spells goodEffect flag.
// This should work for the majority of weapons.
if (!on) {
return;
}
if (!IsValidSpell(spell_id) || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
if(!IsValidSpell(spell_id) || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
//This is so 65535 doesn't get passed to the client message and to logs because it is not relavant information for debugging.
return;
}
if (IsBot() && on->GetSpecialAbility(IMMUNE_DAMAGE_BOT)) {
if (on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
return;
}
if (IsClient() && on->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT)) {
if (on->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
return;
}
if (IsNPC() && on->GetSpecialAbility(IMMUNE_DAMAGE_NPC)) {
if (IsNoCast())
return;
}
if (IsNoCast()) {
return;
}
if (!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
if (IsClient()) {
Message(
Chat::White,
fmt::format(
"Invalid spell ID for proc {}.",
spell_id
).c_str()
);
if(!IsValidSpell(spell_id)) { // Check for a valid spell otherwise it will crash through the function
if(IsClient()){
Message(0, "Invalid spell proc %u", spell_id);
LogSpells("Player [{}] Weapon Procced invalid spell [{}]", GetName(), spell_id);
}
return;
}
@@ -5258,7 +5221,7 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance* inst, uint16 spell_id, Mob* on,
return;
}
if (inst && IsClient()) {
if(inst && IsClient()) {
//const cast is dirty but it would require redoing a ton of interfaces at this point
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
//So we'll live with it for now
@@ -5278,76 +5241,30 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance* inst, uint16 spell_id, Mob* on,
}
}
bool twin_proc = false;
int32 twin_proc_chance = 0;
bool twinproc = false;
int32 twinproc_chance = 0;
if (IsClient() || IsBot()) {
twin_proc_chance = GetFocusEffect(focusTwincast, spell_id);
twinproc_chance = GetFocusEffect(focusTwincast, spell_id);
}
if (twin_proc_chance && zone->random.Roll(twin_proc_chance)) {
twin_proc = true;
if (twinproc_chance && zone->random.Roll(twinproc_chance)) {
twinproc = true;
}
if (
IsBeneficialSpell(spell_id) &&
(
!IsNPC() ||
(
IsNPC() &&
CastToNPC()->GetInnateProcSpellID() != spell_id
)
) &&
spells[spell_id].target_type != ST_TargetsTarget
) { // NPC innate procs don't take this path ever
SpellFinished(
spell_id,
this,
EQ::spells::CastingSlot::Item,
0,
-1,
spells[spell_id].resist_difficulty,
true,
level_override
);
if (twin_proc) {
SpellFinished(
spell_id,
this,
EQ::spells::CastingSlot::Item,
0,
-1,
spells[spell_id].resist_difficulty,
true,
level_override
);
}
} else if (!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
SpellFinished(
spell_id,
on,
EQ::spells::CastingSlot::Item,
0,
-1,
spells[spell_id].resist_difficulty,
true,
level_override
);
if (twin_proc && (!(on->IsClient() && on->CastToClient()->dead))) {
SpellFinished(
spell_id,
on,
EQ::spells::CastingSlot::Item,
0,
-1,
spells[spell_id].resist_difficulty,
true,
level_override
);
if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id)) && spells[spell_id].target_type != ST_TargetsTarget) { // NPC innate procs don't take this path ever
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
if (twinproc) {
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
}
}
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
if (twinproc && (!(on->IsClient() && on->CastToClient()->dead))) {
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
}
}
return;
}
uint32 Mob::GetZoneID() const {
-2
View File
@@ -3798,8 +3798,6 @@ void NPC::DescribeSpecialAbilities(Client* c)
IMMUNE_OPEN,
IMMUNE_ASSASSINATE,
IMMUNE_HEADSHOT,
IMMUNE_AGGRO_BOT,
IMMUNE_DAMAGE_BOT
};
// These abilities have parameters that need to be parsed out individually
+4
View File
@@ -752,7 +752,11 @@ void QuestManager::stoptimer(const std::string& timer_name)
);
for (auto e = QTimerList.begin(); e != QTimerList.end(); ++e) {
LogInfo("Current [{}] Timer [{}]", e->name, timer_name);
if (e->mob && e->mob == owner && e->name == timer_name) {
LogInfo("Matched [{}] Timer [{}]", e->name, timer_name);
if (has_stop_event) {
if (owner->IsClient()) {
parse->EventPlayer(EVENT_TIMER_STOP, owner->CastToClient(), timer_name, 0);
+6 -2
View File
@@ -40,6 +40,8 @@ extern WorldServer worldserver;
Raid::Raid(uint32 raidID)
: GroupIDConsumer(raidID)
{
memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct));
memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS);
for (auto& gm : group_mentor) {
gm.mentor_percent = 0;
gm.mentoree = nullptr;
@@ -63,6 +65,8 @@ Raid::Raid(uint32 raidID)
Raid::Raid(Client* nLeader)
: GroupIDConsumer()
{
memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct));
memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS);
for (auto& gm : group_mentor) {
gm.mentor_percent = 0;
gm.mentoree = nullptr;
@@ -447,13 +451,13 @@ void Raid::SaveRaidLeaderAA()
void Raid::UpdateGroupAAs(uint32 gid)
{
if (gid > MAX_RAID_GROUPS || gid == RAID_GROUPLESS || gid < 0) {
if (gid > MAX_RAID_GROUPS) {
return;
}
Client *gl = GetGroupLeader(gid);
if (gl && gl->IsClient()) {
if (gl) {
gl->GetGroupAAs(&group_aa[gid]);
} else {
memset(&group_aa[gid], 0, sizeof(GroupLeadershipAA_Struct));
+2 -2
View File
@@ -292,8 +292,8 @@ protected:
bool disbandCheck;
bool forceDisband;
std::string motd;
RaidLeadershipAA_Struct raid_aa{};
GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS]{};
RaidLeadershipAA_Struct raid_aa;
GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS];
GroupMentor group_mentor[MAX_RAID_GROUPS];
+2 -5
View File
@@ -221,12 +221,9 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
BuffFadeByEffect(SE_NegateIfCombat);
}
// check to see if target is a caster mob before performing a mana tap
if(GetTarget() && IsManaTapSpell(spell_id)) {
// If melee, block if ManaTapsOnAnyClass rule is false
// if caster, block if ManaTapsRequireNPCMana and no mana
bool melee_block = !RuleB(Spells, ManaTapsOnAnyClass);
bool caster_block = (GetTarget()->GetCasterClass() != 'N' && RuleB(Spells, ManaTapsRequireNPCMana) && GetTarget()->GetMana() == 0);
if (melee_block || caster_block) {
if (!RuleB(Spells, ManaTapsOnAnyClass) && GetTarget()->GetCasterClass() != 'N' && RuleB(Spells, ManaTapsRequireNPCMana) && GetTarget()->GetMana() == 0) {
InterruptSpell(TARGET_NO_MANA, 0x121, spell_id);
return false;
}
+7 -56
View File
@@ -405,23 +405,11 @@ void Client::SendZoneCancel(ZoneChange_Struct *zc) {
zc->success
);
strn0cpy(zc2->char_name, zc->char_name, 64);
strcpy(zc2->char_name, zc->char_name);
zc2->zoneID = zone->GetZoneID();
zc2->success = 1;
zc2->instanceID = zone->GetInstanceID();
// this fixes an issue where when we do a zone cancel what often ends up happening is we are sending
// the client the wrong coordinates to zone back to. Often times it is the x,y,z of the destination zone
// because we saved the destination x,y,z on the client profile before we rejected the zone request.
// we're using rewind location because it should be where the client relatively was before we rejected the zone request.
// it also prevents the client from getting caught up in a zone loop because if we sent them exactly back to where they
// originated the request we could end up in a situation where the client is caught in a zone loop.
m_Position.x = m_RewindLocation.x;
m_Position.y = m_RewindLocation.y;
m_Position.z = m_RewindLocation.z;
zc2->x = m_Position.x;
zc2->y = m_Position.y;
zc2->z = m_Position.z;
outapp->priority = 6;
FastQueuePacket(&outapp);
LogZoning(
"(zc2) Client [{}] char_name [{}] zoning to [{}] ({}) cancelled instance_id [{}] x [{}] y [{}] z [{}] zone_reason [{}] success [{}]",
@@ -437,9 +425,6 @@ void Client::SendZoneCancel(ZoneChange_Struct *zc) {
zc2->success
);
outapp->priority = 6;
FastQueuePacket(&outapp);
//reset to unsolicited.
zone_mode = ZoneUnsolicited;
// reset since we're not zoning anymore
@@ -755,34 +740,10 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
pZoneName = strcpy(new char[zd->long_name.length() + 1], zd->long_name.c_str());
}
// If we are zoning to the same zone, we need to use the current instance ID if it is not specified.
if (zoneID == zone->GetZoneID() && instance_id == 0) {
instance_id = zone->GetInstanceID();
}
auto r = content_service.FindZone(zoneID, instance_id);
if (r.zone_id) {
zoneID = r.zone_id;
instance_id = r.instance.id;
LogZoning(
"Client caught HandleZoneRoutingMiddleware [{}] zone_id [{}] instance_id [{}] x [{}] y [{}] z [{}] heading [{}] ignorerestrictions [{}] zone_mode [{}]",
GetCleanName(),
zoneID,
instance_id,
x,
y,
z,
heading,
ignorerestrictions,
static_cast<int>(zm)
);
}
LogInfo(
"Client [{}] zone_id [{}] instance_id [{}] x [{}] y [{}] z [{}] heading [{}] ignorerestrictions [{}] zone_mode [{}]",
"Client [{}] zone_id [{}] x [{}] y [{}] z [{}] heading [{}] ignorerestrictions [{}] zone_mode [{}]",
GetCleanName(),
zoneID,
instance_id,
x,
y,
z,
@@ -906,8 +867,9 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
outapp->priority = 6;
FastQueuePacket(&outapp);
}
else if (zm == ZoneSolicited || zm == ZoneToSafeCoords) {
auto outapp = new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct));
else if(zm == ZoneSolicited || zm == ZoneToSafeCoords) {
auto outapp =
new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct));
RequestClientZoneChange_Struct* gmg = (RequestClientZoneChange_Struct*) outapp->pBuffer;
gmg->zone_id = zoneID;
@@ -918,17 +880,6 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
gmg->instance_id = instance_id;
gmg->type = 0x01; //an observed value, not sure of meaning
LogZoning(
"Player [{}] has requested zoning to zone_id [{}] instance_id [{}] x [{}] y [{}] z [{}] heading [{}]",
GetCleanName(),
zoneID,
instance_id,
x,
y,
z,
heading
);
outapp->priority = 6;
FastQueuePacket(&outapp);
}