mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 07:18:37 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -226,12 +226,12 @@ std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
|
||||
const std::map<uint8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> flymode_map = {
|
||||
{ EQ::constants::GravityBehavior::Ground, "Ground" },
|
||||
{ EQ::constants::GravityBehavior::Flying, "Flying" },
|
||||
{ EQ::constants::GravityBehavior::Levitating, "Levitating" },
|
||||
{ EQ::constants::GravityBehavior::Water, "Water" },
|
||||
{ EQ::constants::GravityBehavior::Floating, "Floating" },
|
||||
{ EQ::constants::GravityBehavior::LevitateWhileRunning, "Levitating While Running" },
|
||||
{ GravityBehavior::Ground, "Ground" },
|
||||
{ GravityBehavior::Flying, "Flying" },
|
||||
{ GravityBehavior::Levitating, "Levitating" },
|
||||
{ GravityBehavior::Water, "Water" },
|
||||
{ GravityBehavior::Floating, "Floating" },
|
||||
{ GravityBehavior::LevitateWhileRunning, "Levitating While Running" },
|
||||
};
|
||||
return flymode_map;
|
||||
}
|
||||
@@ -337,3 +337,48 @@ std::string EQ::constants::GetAccountStatusName(uint8 account_status)
|
||||
|
||||
return status_name;
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> consider_level_map = {
|
||||
{ ConsiderLevel::Ally, "Ally" },
|
||||
{ ConsiderLevel::Warmly, "Warmly" },
|
||||
{ ConsiderLevel::Kindly, "Kindly" },
|
||||
{ ConsiderLevel::Amiably, "Amiably" },
|
||||
{ ConsiderLevel::Indifferently, "Indifferently" },
|
||||
{ ConsiderLevel::Apprehensively, "Apprehensively" },
|
||||
{ ConsiderLevel::Dubiously, "Dubiously" },
|
||||
{ ConsiderLevel::Threateningly, "Threateningly" },
|
||||
{ ConsiderLevel::Scowls, "Scowls" }
|
||||
};
|
||||
return consider_level_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
|
||||
{
|
||||
auto consider_levels = EQ::constants::GetConsiderLevelMap();
|
||||
if (!consider_levels[faction_consider_level].empty()) {
|
||||
return consider_levels[faction_consider_level];
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> damage_type_map = {
|
||||
{ EnvironmentalDamage::Lava, "Lava" },
|
||||
{ EnvironmentalDamage::Drowning, "Drowning" },
|
||||
{ EnvironmentalDamage::Falling, "Falling" },
|
||||
{ EnvironmentalDamage::Trap, "Trap" }
|
||||
};
|
||||
return damage_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
|
||||
{
|
||||
if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
|
||||
auto damage_types = EQ::constants::GetEnvironmentalDamageMap();
|
||||
return damage_types[damage_type];
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -230,6 +230,13 @@ namespace EQ
|
||||
LevitateWhileRunning
|
||||
};
|
||||
|
||||
enum EnvironmentalDamage : uint8 {
|
||||
Lava = 250,
|
||||
Drowning,
|
||||
Falling,
|
||||
Trap
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
@@ -248,6 +255,12 @@ namespace EQ
|
||||
extern const std::map<uint8, std::string>& GetAccountStatusMap();
|
||||
std::string GetAccountStatusName(uint8 account_status);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
|
||||
std::string GetConsiderLevelName(uint8 consider_level);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEnvironmentalDamageMap();
|
||||
std::string GetEnvironmentalDamageName(uint8 damage_type);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
@@ -391,4 +404,16 @@ enum AugmentActions : int {
|
||||
Destroy
|
||||
};
|
||||
|
||||
enum ConsiderLevel : uint8 {
|
||||
Ally = 1,
|
||||
Warmly,
|
||||
Kindly,
|
||||
Amiably,
|
||||
Indifferently,
|
||||
Apprehensively,
|
||||
Dubiously,
|
||||
Threateningly,
|
||||
Scowls
|
||||
};
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -2762,7 +2762,7 @@ struct EnvDamage2_Struct {
|
||||
/*0004*/ uint16 unknown4;
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ uint8 unknown10[12];
|
||||
/*0022*/ uint8 dmgtype; //FA = Lava; FC = Falling
|
||||
/*0022*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0023*/ uint8 unknown2[4];
|
||||
/*0027*/ uint16 constant; //Always FFFF
|
||||
/*0029*/ uint16 unknown29;
|
||||
|
||||
@@ -3061,7 +3061,7 @@ struct EnvDamage2_Struct {
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ float unknown10; // New to Underfoot - Seen 1
|
||||
/*0014*/ uint8 unknown14[12];
|
||||
/*0026*/ uint8 dmgtype; // FA = Lava; FC = Falling
|
||||
/*0026*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0027*/ uint8 unknown27[4];
|
||||
/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66
|
||||
/*0033*/ uint16 constant; // Always FFFF
|
||||
|
||||
@@ -3032,7 +3032,7 @@ struct EnvDamage2_Struct {
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ float unknown10; // New to Underfoot - Seen 1
|
||||
/*0014*/ uint8 unknown14[12];
|
||||
/*0026*/ uint8 dmgtype; // FA = Lava; FC = Falling
|
||||
/*0026*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0027*/ uint8 unknown27[4];
|
||||
/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66
|
||||
/*0033*/ uint16 constant; // Always FFFF
|
||||
|
||||
@@ -2539,7 +2539,7 @@ struct EnvDamage2_Struct {
|
||||
/*0004*/ uint16 unknown4;
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ uint8 unknown10[12];
|
||||
/*0022*/ uint8 dmgtype; //FA = Lava; FC = Falling
|
||||
/*0022*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0023*/ uint8 unknown2[4];
|
||||
/*0027*/ uint16 constant; //Always FFFF
|
||||
/*0029*/ uint16 unknown29;
|
||||
|
||||
@@ -2509,7 +2509,7 @@ struct EnvDamage2_Struct {
|
||||
/*0004*/ uint16 unknown4;
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ uint8 unknown10[12];
|
||||
/*0022*/ uint8 dmgtype; //FA = Lava; FC = Falling
|
||||
/*0022*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0023*/ uint8 unknown2[4];
|
||||
/*0027*/ uint16 constant; //Always FFFF
|
||||
/*0029*/ uint16 unknown29;
|
||||
|
||||
@@ -192,6 +192,7 @@ RULE_INT(Character, MagicianTrackingDistanceMultiplier, 0, "If you want magician
|
||||
RULE_INT(Character, EnchanterTrackingDistanceMultiplier, 0, "If you want enchanters to be able to track, increase this above 0. 0 disables tracking packets.")
|
||||
RULE_INT(Character, BeastlordTrackingDistanceMultiplier, 0, "If you want beastlords to be able to track, increase this above 0. 0 disables tracking packets.")
|
||||
RULE_INT(Character, BerserkerTrackingDistanceMultiplier, 0, "If you want berserkers to be able to track, increase this above 0. 0 disables tracking packets.")
|
||||
RULE_BOOL(Character, OnInviteReceiveAlreadyinGroupMessage, true, "If you want clients to receive a message when trying to invite a player into a group that is currently in another group.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
|
||||
+19
-36
@@ -1239,10 +1239,6 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
if (!IsValidSpell(rank->spell)) {
|
||||
return;
|
||||
}
|
||||
//do not allow AA to cast if your actively casting another AA.
|
||||
if (rank->spell == casting_spell_id && rank->id == casting_spell_aa_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanUseAlternateAdvancementRank(rank)) {
|
||||
return;
|
||||
@@ -1257,13 +1253,11 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
|
||||
uint32 charges = 0;
|
||||
// We don't have the AA
|
||||
if (!GetAA(rank_id, &charges)) {
|
||||
if (!GetAA(rank_id, &charges))
|
||||
return;
|
||||
}
|
||||
//if expendable make sure we have charges
|
||||
if (ability->charges > 0 && charges < 1) {
|
||||
if (ability->charges > 0 && charges < 1)
|
||||
return;
|
||||
}
|
||||
|
||||
//check cooldown
|
||||
if (!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
|
||||
@@ -1280,28 +1274,31 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
Message(Chat::Red, "You can use this ability again in %u minute(s) %u seconds",
|
||||
aaremain_min, aaremain_sec);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCastWhileInvis(rank->spell)) {
|
||||
CommonBreakInvisible();
|
||||
int timer_duration = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank);
|
||||
if (timer_duration < 0) {
|
||||
timer_duration = 0;
|
||||
}
|
||||
|
||||
if (!IsCastWhileInvis(rank->spell))
|
||||
CommonBreakInvisible();
|
||||
|
||||
if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) {
|
||||
MessageString(Chat::SpellFailure, SNEAK_RESTRICT);
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Modern clients don't require pet targeted for AA casts that are ST_Pet
|
||||
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet) {
|
||||
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet)
|
||||
target_id = GetPetID();
|
||||
}
|
||||
|
||||
// extra handling for cast_not_standing spells
|
||||
if (!IgnoreCastingRestriction(rank->spell)) {
|
||||
if (GetAppearance() == eaSitting) { // we need to stand!
|
||||
if (GetAppearance() == eaSitting) // we need to stand!
|
||||
SetAppearance(eaStanding, false);
|
||||
}
|
||||
|
||||
if (GetAppearance() != eaStanding) {
|
||||
MessageString(Chat::SpellFailure, STAND_TO_CAST);
|
||||
@@ -1318,33 +1315,20 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
if (!DoCastingChecksOnCaster(rank->spell)) {
|
||||
return;
|
||||
}
|
||||
SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false, -1, false, rank->id);
|
||||
|
||||
if (!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false, -1,
|
||||
rank->spell_type + pTimerAAStart, timer_duration, false, rank->id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
//Known issue: If you attempt to give a Bard an AA with a cast time, the cast timer will not display on the client (no live bard AA have cast time).
|
||||
else {
|
||||
CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, 0xFFFFFFFF, 0, nullptr, rank->id);
|
||||
if (!CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, timer_duration, nullptr, rank->id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetAARecastTimer(AA::Rank *rank_in, int32 spell_id) {
|
||||
|
||||
if (!rank_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
//calculate AA cooldown
|
||||
int timer_duration = rank_in->recast_time - GetAlternateAdvancementCooldownReduction(rank_in);
|
||||
|
||||
if (timer_duration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
CastToClient()->GetPTimers().Start(rank_in->spell_type + pTimerAAStart, timer_duration);
|
||||
CastToClient()->SendAlternateAdvancementTimer(rank_in->spell_type, 0, 0);
|
||||
LogSpells("Spell [{}]: Setting AA reuse timer [{}] to [{}]", spell_id, rank_in->spell_type + pTimerAAStart, timer_duration);
|
||||
}
|
||||
|
||||
int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
|
||||
if(!rank_in) {
|
||||
return 0;
|
||||
@@ -1376,7 +1360,6 @@ int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
|
||||
}
|
||||
|
||||
void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
|
||||
|
||||
for (auto &iter : aa_ranks) {
|
||||
AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first);
|
||||
if (ability && aa_id == ability->id) {
|
||||
|
||||
@@ -1495,8 +1495,6 @@ public:
|
||||
void SendItemRecastTimer(int32 recast_type, uint32 recast_delay = 0);
|
||||
void SetItemRecastTimer(int32 spell_id, uint32 inventory_slot);
|
||||
bool HasItemRecastTimer(int32 spell_id, uint32 inventory_slot);
|
||||
void SetDisciplineRecastTimer(int32 spell_id);
|
||||
void SetAARecastTimer(AA::Rank *rank_in, int32 spell_id);
|
||||
|
||||
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQ::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
|
||||
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
|
||||
|
||||
+35
-21
@@ -5784,8 +5784,7 @@ void Client::Handle_OP_EndLootRequest(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!ClientFinishedLoading())
|
||||
{
|
||||
if (!ClientFinishedLoading()) {
|
||||
SetHP(GetHP() - 1);
|
||||
return;
|
||||
}
|
||||
@@ -5795,38 +5794,46 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
EnvDamage2_Struct* ed = (EnvDamage2_Struct*)app->pBuffer;
|
||||
|
||||
int damage = ed->damage;
|
||||
|
||||
if (ed->dmgtype == 252) {
|
||||
|
||||
int mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage;
|
||||
|
||||
auto damage = ed->damage;
|
||||
if (ed->dmgtype == EQ::constants::EnvironmentalDamage::Falling) {
|
||||
uint32 mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage;
|
||||
damage -= damage * mod / 100;
|
||||
}
|
||||
|
||||
if (damage < 0)
|
||||
if (damage < 0) {
|
||||
damage = 31337;
|
||||
}
|
||||
|
||||
if (admin >= minStatusToAvoidFalling && GetGM()) {
|
||||
Message(Chat::Red, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
||||
Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"Your GM status protects you from {} points of {} (Type {}) damage.",
|
||||
ed->damage,
|
||||
EQ::constants::GetEnvironmentalDamageName(ed->dmgtype),
|
||||
ed->dmgtype
|
||||
).c_str()
|
||||
);
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
}
|
||||
else if (GetInvul()) {
|
||||
Message(Chat::Red, "Your invuln status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
||||
} else if (GetInvul()) {
|
||||
Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"Your invulnerability protects you from {} points of {} (Type {}) damage.",
|
||||
ed->damage,
|
||||
EQ::constants::GetEnvironmentalDamageName(ed->dmgtype),
|
||||
ed->dmgtype
|
||||
).c_str()
|
||||
);
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
}
|
||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) {
|
||||
// Hard coded tutorial and load zones for no fall damage
|
||||
} else if (zone->GetZoneID() == Zones::TUTORIAL || zone->GetZoneID() == Zones::LOAD) { // Hard coded tutorial and load zones for no fall damage
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
|
||||
|
||||
/* EVENT_ENVIRONMENTAL_DAMAGE */
|
||||
int final_damage = (damage * RuleR(Character, EnvironmentDamageMulipliter));
|
||||
std::string export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
@@ -6953,6 +6960,13 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
|
||||
Invitee->CastToClient()->QueuePacket(app);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (RuleB(Character, OnInviteReceiveAlreadyinGroupMessage)) {
|
||||
if (!Invitee->CastToClient()->MercOnlyOrNoGroup()) {
|
||||
Message(Chat::LightGray, "%s is already in another group.", Invitee->GetCleanName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef BOTS
|
||||
else if (Invitee->IsBot()) {
|
||||
|
||||
+5
-4
@@ -183,7 +183,7 @@ int command_init(void)
|
||||
command_add("findzone", "[search criteria] - Search database zones", AccountStatus::GMAdmin, command_findzone) ||
|
||||
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("flag", "[status] [acctname] - Refresh your admin status, or set an account's admin status if arguments provided", AccountStatus::Player, command_flag) ||
|
||||
command_add("flagedit", "- Edit zone flags on your target", AccountStatus::GMAdmin, command_flagedit) ||
|
||||
command_add("flagedit", "- Edit zone flags on your target. Use #flagedit help for more info.", AccountStatus::GMAdmin, command_flagedit) ||
|
||||
command_add("flags", "- displays the flags of you or your target", AccountStatus::Player, command_flags) ||
|
||||
command_add("flymode", "[0/1/2/3/4/5] - Set your or your player target's flymode to ground/flying/levitate/water/floating/levitate_running", AccountStatus::Guide, command_flymode) ||
|
||||
command_add("fov", "- Check wether you're behind or in your target's field of view", AccountStatus::QuestTroupe, command_fov) ||
|
||||
@@ -209,7 +209,7 @@ int command_init(void)
|
||||
command_add("hair", "- Change the hair style of your target", AccountStatus::QuestTroupe, command_hair) ||
|
||||
command_add("haircolor", "- Change the hair color of your target", AccountStatus::QuestTroupe, command_haircolor) ||
|
||||
command_add("haste", "[percentage] - Set your haste percentage", AccountStatus::GMAdmin, command_haste) ||
|
||||
command_add("hatelist", " - Display hate list for target.", AccountStatus::QuestTroupe, command_hatelist) ||
|
||||
command_add("hatelist", "- Display hate list for NPC.", AccountStatus::QuestTroupe, command_hatelist) ||
|
||||
command_add("heal", "- Completely heal your target", AccountStatus::Steward, command_heal) ||
|
||||
command_add("helm", "- Change the helm of your target", AccountStatus::QuestTroupe, command_helm) ||
|
||||
command_add("help", "[search term] - List available commands and their description, specify partial command as argument to search", AccountStatus::Player, command_help) ||
|
||||
@@ -252,14 +252,14 @@ int command_init(void)
|
||||
command_add("myskills", "- Show details about your current skill levels", AccountStatus::Player, command_myskills) ||
|
||||
command_add("mysql", "[Help|Query] [SQL Query] - Mysql CLI, see 'Help' for options.", AccountStatus::GMImpossible, command_mysql) ||
|
||||
command_add("mystats", "- Show details about you or your pet", AccountStatus::Guide, command_mystats) ||
|
||||
command_add("name", "[newname] - Rename your player target", AccountStatus::GMLeadAdmin, command_name) ||
|
||||
command_add("name", "[New Name] - Rename your player target", AccountStatus::GMLeadAdmin, command_name) ||
|
||||
command_add("netstats", "- Gets the network stats for a stream.", AccountStatus::GMMgmt, command_netstats) ||
|
||||
command_add("network", "- Admin commands for the udp network interface.", AccountStatus::GMImpossible, command_network) ||
|
||||
command_add("npccast", "[targetname/entityid] [spellid] - Causes NPC target to cast spellid on targetname/entityid", AccountStatus::QuestTroupe, command_npccast) ||
|
||||
command_add("npcedit", "[column] [value] - Mega NPC editing command", AccountStatus::GMAdmin, command_npcedit) ||
|
||||
command_add("npceditmass", "[name-search] [column] [value] - Mass (Zone wide) NPC data editing command", AccountStatus::GMAdmin, command_npceditmass) ||
|
||||
command_add("npcemote", "[message] - Make your NPC target emote a message.", AccountStatus::GMLeadAdmin, command_npcemote) ||
|
||||
command_add("npcloot", "[show/money/add/remove] [itemid/all/money: pp gp sp cp] - Manipulate the loot an NPC is carrying", AccountStatus::QuestTroupe, command_npcloot) ||
|
||||
command_add("npcloot", "- Manipulate the loot an NPC is carrying. Use #npcloot help for more information.", AccountStatus::QuestTroupe, command_npcloot) ||
|
||||
command_add("npcsay", "[message] - Make your NPC target say a message.", AccountStatus::GMLeadAdmin, command_npcsay) ||
|
||||
command_add("npcshout", "[message] - Make your NPC target shout a message.", AccountStatus::GMLeadAdmin, command_npcshout) ||
|
||||
command_add("npcspawn", "[create/add/update/remove/delete] - Manipulate spawn DB", AccountStatus::GMAreas, command_npcspawn) ||
|
||||
@@ -378,6 +378,7 @@ int command_init(void)
|
||||
command_add("trapinfo", "- Gets infomation about the traps currently spawned in the zone.", AccountStatus::QuestTroupe, command_trapinfo) ||
|
||||
command_add("tune", "Calculate statistical values related to combat.", AccountStatus::GMAdmin, command_tune) ||
|
||||
command_add("ucs", "- Attempts to reconnect to the UCS server", AccountStatus::Player, command_ucs) ||
|
||||
command_add("undye", "- Remove dye from all of your or your target's armor slots", AccountStatus::GMAdmin, command_undye) ||
|
||||
command_add("undyeme", "- Remove dye from all of your armor slots", AccountStatus::Player, command_undyeme) ||
|
||||
command_add("unfreeze", "- Unfreeze your target", AccountStatus::QuestTroupe, command_unfreeze) ||
|
||||
command_add("unlock", "- Unlock the worldserver", AccountStatus::GMLeadAdmin, command_unlock) ||
|
||||
|
||||
+41
-6
@@ -800,15 +800,50 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
||||
if (DoCastingChecksOnCaster(spell_id)) {
|
||||
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline);
|
||||
bool instant_recast = true;
|
||||
|
||||
if (spell.recast_time > 0) {
|
||||
uint32 reduced_recast = spell.recast_time / 1000;
|
||||
auto focus = GetFocusEffect(focusReduceRecastTime, spell_id);
|
||||
// do stupid stuff because custom servers.
|
||||
// we really should be able to just do the -= focus but since custom servers could have shorter reuse timers
|
||||
// we have to make sure we don't underflow the uint32 ...
|
||||
// and yes, the focus effect can be used to increase the durations (spell 38944)
|
||||
if (focus > reduced_recast) {
|
||||
reduced_recast = 0;
|
||||
if (GetPTimers().Enabled((uint32)DiscTimer))
|
||||
GetPTimers().Clear(&database, (uint32)DiscTimer);
|
||||
}
|
||||
else {
|
||||
reduced_recast -= focus;
|
||||
}
|
||||
|
||||
if (reduced_recast > 0) {
|
||||
instant_recast = false;
|
||||
|
||||
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
||||
if (DoCastingChecksOnCaster(spell_id)) {
|
||||
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
||||
}
|
||||
|
||||
SendDisciplineTimer(spells[spell_id].timer_id, reduced_recast);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
|
||||
}
|
||||
|
||||
if (instant_recast) {
|
||||
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
||||
if (DoCastingChecksOnCaster(spell_id)) {
|
||||
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, 0xFFFFFFFF, 0, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -8092,6 +8092,39 @@ XS(XS__getbodytypename) {
|
||||
}
|
||||
}
|
||||
|
||||
XS(XS__getconsiderlevelname);
|
||||
XS(XS__getconsiderlevelname) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: quest::getconsiderlevelname(uint8 consider_level)");
|
||||
{
|
||||
dXSTARG;
|
||||
uint8 consider_level = (uint8) SvUV(ST(0));
|
||||
std::string consider_level_name = quest_manager.getconsiderlevelname(consider_level);
|
||||
|
||||
sv_setpv(TARG, consider_level_name.c_str());
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
XSRETURN(1);
|
||||
}
|
||||
}
|
||||
|
||||
XS(XS__getenvironmentaldamagename);
|
||||
XS(XS__getenvironmentaldamagename) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: quest::getenvironmentaldamagename(uint8 damage_type)");
|
||||
|
||||
dXSTARG;
|
||||
uint8 damage_type = (uint8) SvIV(ST(0));
|
||||
std::string environmental_damage_name = quest_manager.getenvironmentaldamagename(damage_type);
|
||||
|
||||
sv_setpv(TARG, environmental_damage_name.c_str());
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
This is the callback perl will look for to setup the
|
||||
quest package's XSUBs
|
||||
@@ -8376,6 +8409,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file);
|
||||
newXS(strcpy(buf, "getclassname"), XS__getclassname, file);
|
||||
newXS(strcpy(buf, "getcleannpcnamebyid"), XS__getcleannpcnamebyid, file);
|
||||
newXS(strcpy(buf, "getconsiderlevelname"), XS__getconsiderlevelname, file);
|
||||
newXS(strcpy(buf, "gethexcolorcode"), XS__gethexcolorcode, file);
|
||||
newXS(strcpy(buf, "getcurrencyid"), XS__getcurrencyid, file);
|
||||
newXS(strcpy(buf, "getexpmodifierbycharid"), XS__getexpmodifierbycharid, file);
|
||||
@@ -8398,6 +8432,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "getcurrencyitemid"), XS__getcurrencyitemid, file);
|
||||
newXS(strcpy(buf, "getgendername"), XS__getgendername, file);
|
||||
newXS(strcpy(buf, "getdeityname"), XS__getdeityname, file);
|
||||
newXS(strcpy(buf, "getenvironmentaldamagename"), XS__getenvironmentaldamagename, file);
|
||||
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
|
||||
newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file);
|
||||
newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file);
|
||||
|
||||
+242
-118
@@ -2,138 +2,262 @@
|
||||
|
||||
void command_ai(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *target = c->GetTarget();
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
c->Message(Chat::White, "Usage: #ai consider [Mob Name] - Show how an NPC considers to a mob");
|
||||
c->Message(Chat::White, "Usage: #ai faction [Faction ID] - Set an NPC's Faction ID");
|
||||
c->Message(Chat::White, "Usage: #ai guard - Save an NPC's guard spot to their current location");
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Min X] [Max X] [Min Y] [Max Y] [Delay] [Minimum Delay] - Set an NPC's roambox using X and Y coordinates");
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Roam Distance] [Delay] [Minimum Delay] - Set an NPC's roambox using roam distance");
|
||||
c->Message(Chat::White, "Usage: #ai spells [Spell List ID] - Set an NPC's Spell List ID");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "factionid") == 0) {
|
||||
if (target && sep->IsNumber(2)) {
|
||||
if (target->IsNPC()) {
|
||||
target->CastToNPC()->SetNPCFactionID(atoi(sep->arg[2]));
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "%s is not an NPC.", target->GetName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: (targeted) #ai factionid [factionid]");
|
||||
}
|
||||
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
|
||||
c->Message(Chat::White, "You must target an NPC to use this command.");
|
||||
return;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "spellslist") == 0) {
|
||||
if (target && sep->IsNumber(2) && atoi(sep->arg[2]) >= 0) {
|
||||
if (target->IsNPC()) {
|
||||
target->CastToNPC()->AI_AddNPCSpells(atoi(sep->arg[2]));
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "%s is not an NPC.", target->GetName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: (targeted) #ai spellslist [npc_spells_id]");
|
||||
}
|
||||
|
||||
auto target = c->GetTarget()->CastToNPC();
|
||||
|
||||
bool is_consider = !strcasecmp(sep->arg[1], "consider");
|
||||
bool is_faction = !strcasecmp(sep->arg[1], "faction");
|
||||
bool is_guard = !strcasecmp(sep->arg[1], "guard");
|
||||
bool is_roambox = !strcasecmp(sep->arg[1], "roambox");
|
||||
bool is_spells = !strcasecmp(sep->arg[1], "spells");
|
||||
|
||||
if (
|
||||
!is_consider &&
|
||||
!is_faction &&
|
||||
!is_guard &&
|
||||
!is_roambox &&
|
||||
!is_spells
|
||||
) {
|
||||
c->Message(Chat::White, "Usage: #ai consider [Mob Name] - Show how an NPC considers to a mob");
|
||||
c->Message(Chat::White, "Usage: #ai faction [Faction ID] - Set an NPC's Faction ID");
|
||||
c->Message(Chat::White, "Usage: #ai guard - Save an NPC's guard spot to their current location");
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Min X] [Max X] [Min Y] [Max Y] [Delay] [Minimum Delay] - Set an NPC's roambox using X and Y coordinates");
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Roam Distance] [Delay] [Minimum Delay] - Set an NPC's roambox using roam distance");
|
||||
c->Message(Chat::White, "Usage: #ai spells [Spell List ID] - Set an NPC's Spell List ID");
|
||||
return;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "con") == 0) {
|
||||
if (target && sep->arg[2][0] != 0) {
|
||||
Mob *tar2 = entity_list.GetMob(sep->arg[2]);
|
||||
if (tar2) {
|
||||
|
||||
if (is_consider) {
|
||||
if (arguments == 2) {
|
||||
auto mob_name = sep->arg[2];
|
||||
auto mob_to_consider = entity_list.GetMob(mob_name);
|
||||
if (mob_to_consider) {
|
||||
auto consider_level = static_cast<uint8>(mob_to_consider->GetReverseFactionCon(target));
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"%s considering %s: %i",
|
||||
target->GetName(),
|
||||
tar2->GetName(),
|
||||
tar2->GetReverseFactionCon(target));
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: %s not found.", sep->arg[2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: (targeted) #ai con [mob name]");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "guard") == 0) {
|
||||
if (target && target->IsNPC()) {
|
||||
target->CastToNPC()->SaveGuardSpot(target->GetPosition());
|
||||
}
|
||||
else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: (targeted) #ai guard - sets npc to guard the current location (use #summon to move)"
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "roambox") == 0) {
|
||||
if (target && target->IsAIControlled() && target->IsNPC()) {
|
||||
if ((sep->argnum == 6 || sep->argnum == 7 || sep->argnum == 8) && sep->IsNumber(2) && sep->IsNumber(3) &&
|
||||
sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) {
|
||||
uint32 tmp = 2500;
|
||||
uint32 tmp2 = 2500;
|
||||
if (sep->IsNumber(7)) {
|
||||
tmp = atoi(sep->arg[7]);
|
||||
}
|
||||
if (sep->IsNumber(8)) {
|
||||
tmp2 = atoi(sep->arg[8]);
|
||||
}
|
||||
target->CastToNPC()->AI_SetRoambox(
|
||||
atof(sep->arg[2]),
|
||||
atof(sep->arg[3]),
|
||||
atof(sep->arg[4]),
|
||||
atof(sep->arg[5]),
|
||||
atof(sep->arg[6]),
|
||||
tmp,
|
||||
tmp2
|
||||
fmt::format(
|
||||
"{} ({}) considers {} ({}) as {} ({}).",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
mob_to_consider->GetCleanName(),
|
||||
mob_to_consider->GetID(),
|
||||
EQ::constants::GetConsiderLevelName(consider_level),
|
||||
consider_level
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
else if ((sep->argnum == 3 || sep->argnum == 4) && sep->IsNumber(2) && sep->IsNumber(3)) {
|
||||
uint32 tmp = 2500;
|
||||
uint32 tmp2 = 2500;
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #ai consider [Mob Name] - Show how an NPC considers a mob");
|
||||
}
|
||||
} else if (is_faction) {
|
||||
if (sep->IsNumber(2)) {
|
||||
auto faction_id = std::stoi(sep->arg[2]);
|
||||
auto faction_name = content_db.GetFactionName(faction_id);
|
||||
target->SetNPCFactionID(faction_id);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) is now on Faction {}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
(
|
||||
faction_name.empty() ?
|
||||
std::to_string(faction_id) :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
faction_name,
|
||||
faction_id
|
||||
)
|
||||
)
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #ai faction [Faction ID] - Set an NPC's Faction ID");
|
||||
}
|
||||
} else if (is_guard) {
|
||||
auto target_position = target->GetPosition();
|
||||
|
||||
target->SaveGuardSpot(target_position);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) now has a guard spot of {:.2f}, {:.2f}, {:.2f} with a heading of {:.2f}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
target_position.x,
|
||||
target_position.y,
|
||||
target_position.z,
|
||||
target_position.w
|
||||
).c_str()
|
||||
);
|
||||
} else if (is_roambox) {
|
||||
if (target->IsAIControlled()) {
|
||||
if (
|
||||
arguments >= 6 &&
|
||||
arguments <= 8 &&
|
||||
sep->IsNumber(2) &&
|
||||
sep->IsNumber(3) &&
|
||||
sep->IsNumber(4) &&
|
||||
sep->IsNumber(5) &&
|
||||
sep->IsNumber(6)
|
||||
) {
|
||||
auto distance = std::stof(sep->arg[2]);
|
||||
auto min_x = std::stof(sep->arg[3]);
|
||||
auto max_x = std::stof(sep->arg[4]);
|
||||
auto min_y = std::stof(sep->arg[5]);
|
||||
auto max_y = std::stof(sep->arg[6]);
|
||||
|
||||
uint32 delay = 2500;
|
||||
uint32 minimum_delay = 2500;
|
||||
|
||||
if (sep->IsNumber(7)) {
|
||||
delay = std::stoul(sep->arg[7]);
|
||||
}
|
||||
|
||||
if (sep->IsNumber(8)) {
|
||||
minimum_delay = std::stoul(sep->arg[8]);
|
||||
}
|
||||
|
||||
target->CastToNPC()->AI_SetRoambox(
|
||||
distance,
|
||||
max_x,
|
||||
min_x,
|
||||
max_y,
|
||||
min_y,
|
||||
delay,
|
||||
minimum_delay
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) now has a roambox from {}, {} to {}, {} with {} and {} and a distance of {}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
min_x,
|
||||
min_y,
|
||||
max_x,
|
||||
max_y,
|
||||
(
|
||||
delay ?
|
||||
fmt::format(
|
||||
"a delay of {} ({})",
|
||||
ConvertMillisecondsToTime(delay),
|
||||
delay
|
||||
):
|
||||
"no delay"
|
||||
),
|
||||
(
|
||||
minimum_delay ?
|
||||
fmt::format(
|
||||
"a minimum delay of {} ({})",
|
||||
ConvertMillisecondsToTime(minimum_delay),
|
||||
minimum_delay
|
||||
):
|
||||
"no minimum delay"
|
||||
),
|
||||
distance
|
||||
).c_str()
|
||||
);
|
||||
} else if (
|
||||
arguments >= 3 &&
|
||||
arguments <= 4 &&
|
||||
sep->IsNumber(2) &&
|
||||
sep->IsNumber(3)
|
||||
) {
|
||||
auto max_distance = std::stof(sep->arg[2]);
|
||||
auto roam_distance_variance = std::stof(sep->arg[3]);
|
||||
|
||||
uint32 delay = 2500;
|
||||
uint32 minimum_delay = 2500;
|
||||
|
||||
if (sep->IsNumber(4)) {
|
||||
tmp = atoi(sep->arg[4]);
|
||||
delay = std::stoul(sep->arg[4]);
|
||||
}
|
||||
|
||||
if (sep->IsNumber(5)) {
|
||||
tmp2 = atoi(sep->arg[5]);
|
||||
minimum_delay = std::stoul(sep->arg[5]);
|
||||
}
|
||||
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp, tmp2);
|
||||
|
||||
target->CastToNPC()->AI_SetRoambox(
|
||||
max_distance,
|
||||
roam_distance_variance,
|
||||
delay,
|
||||
minimum_delay
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) now has a roambox with a max distance of {} and a roam distance variance of {} with {} and {}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
max_distance,
|
||||
roam_distance_variance,
|
||||
(
|
||||
delay ?
|
||||
fmt::format(
|
||||
"a delay of {} ({})",
|
||||
delay,
|
||||
ConvertMillisecondsToTime(delay)
|
||||
):
|
||||
"no delay"
|
||||
),
|
||||
(
|
||||
minimum_delay ?
|
||||
fmt::format(
|
||||
"a minimum delay of {} ({})",
|
||||
minimum_delay,
|
||||
ConvertMillisecondsToTime(delay)
|
||||
):
|
||||
"no minimum delay"
|
||||
)
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Min X] [Max X] [Min Y] [Max Y] [Delay] [Minimum Delay] - Set an NPC's roambox using X and Y coordinates");
|
||||
c->Message(Chat::White, "Usage: #ai roambox [Distance] [Roam Distance] [Delay] [Minimum Delay] - Set an NPC's roambox using roam distance");
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: #ai roambox dist max_x min_x max_y min_y [delay] [mindelay]");
|
||||
c->Message(Chat::White, "Usage: #ai roambox dist roamdist [delay] [mindelay]");
|
||||
} else {
|
||||
c->Message(Chat::White, "You must target an NPC with AI.");
|
||||
}
|
||||
} else if (is_spells) {
|
||||
if (sep->IsNumber(2)) {
|
||||
auto spell_list_id = std::stoul(sep->arg[2]);
|
||||
if (spell_list_id >= 0) {
|
||||
target->CastToNPC()->AI_AddNPCSpells(spell_list_id);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) is now using Spell List {}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
spell_list_id
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(Chat::White, "Spell List ID must be greater than or equal to 0.");
|
||||
}
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #ai spells [Spell List ID] - Set an NPC's Spell List ID");
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "You need a AI NPC targeted");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "stop") == 0 && c->Admin() >= commandToggleAI) {
|
||||
if (target) {
|
||||
if (target->IsAIControlled()) {
|
||||
target->AI_Stop();
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: Target is not AI controlled");
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: Target a Mob with AI enabled and use this to turn off their AI.");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "start") == 0 && c->Admin() >= commandToggleAI) {
|
||||
if (target) {
|
||||
if (!target->IsAIControlled()) {
|
||||
target->AI_Start();
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: Target is already AI controlled");
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: Target a Mob with AI disabled and use this to turn on their AI.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "#AI Sub-commands");
|
||||
c->Message(Chat::White, " factionid");
|
||||
c->Message(Chat::White, " spellslist");
|
||||
c->Message(Chat::White, " con");
|
||||
c->Message(Chat::White, " guard");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+257
-124
@@ -2,156 +2,289 @@
|
||||
|
||||
void command_flagedit(Client *c, const Seperator *sep)
|
||||
{
|
||||
//super-command for editing zone flags
|
||||
if (sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) {
|
||||
c->Message(Chat::White, "Syntax: #flagedit [lockzone|unlockzone|listzones|give|take].");
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
auto flags_link = EQ::SayLinkEngine::GenerateQuestSaylink("#flags", false, "#flags");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"...lockzone [zone id/short] [flag name] - Set the specified flag name on the zone, locking the zone"
|
||||
"Usage: #flagedit lock [Zone ID|Zone Short Name] [Flag Name] - Set the specified flag name on the zone, locking the zone"
|
||||
);
|
||||
c->Message(Chat::White, "...unlockzone [zone id/short] - Removes the flag requirement from the specified zone");
|
||||
c->Message(Chat::White, "...listzones - List all zones which require a flag, and their flag's name");
|
||||
c->Message(Chat::White, "...give [zone id/short] - Give your target the zone flag for the specified zone.");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"...take [zone id/short] - Take the zone flag for the specified zone away from your target"
|
||||
"Usage: #flagedit unlock [Zone ID|Zone Short Name] - Removes the flag requirement from the specified zone"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit list - List all zones which require a flag, and their flag's name"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit give [Zone ID|Zone Short Name] - Give your target the zone flag for the specified zone."
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit take [Zone ID|Zone Short Name] - Take the zone flag for the specified zone away from your target"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Note: Use {} to view the flags a player has.",
|
||||
flags_link
|
||||
).c_str()
|
||||
);
|
||||
c->Message(Chat::White, "...Note: use #flags to view flags on a person");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "lockzone")) {
|
||||
uint32 zoneid = 0;
|
||||
if (sep->arg[2][0] != '\0') {
|
||||
zoneid = atoi(sep->arg[2]);
|
||||
if (zoneid < 1) {
|
||||
zoneid = ZoneID(sep->arg[2]);
|
||||
bool is_give = !strcasecmp(sep->arg[1], "give");
|
||||
bool is_list = !strcasecmp(sep->arg[1], "list");
|
||||
bool is_lock = !strcasecmp(sep->arg[1], "lock");
|
||||
bool is_take = !strcasecmp(sep->arg[1], "take");
|
||||
bool is_unlock = !strcasecmp(sep->arg[1], "unlock");
|
||||
|
||||
if (
|
||||
!is_give &&
|
||||
!is_list &&
|
||||
!is_lock &&
|
||||
!is_take &&
|
||||
!is_unlock
|
||||
) {
|
||||
auto flags_link = EQ::SayLinkEngine::GenerateQuestSaylink("#flags", false, "#flags");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit lock [Zone ID|Zone Short Name] [Flag Name] - Set the specified flag name on the zone, locking the zone"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit unlock [Zone ID|Zone Short Name] - Removes the flag requirement from the specified zone"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit list - List all zones which require a flag, and their flag's name"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit give [Zone ID|Zone Short Name] - Give your target the zone flag for the specified zone."
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit take [Zone ID|Zone Short Name] - Take the zone flag for the specified zone away from your target"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Note: Use {} to view the flags a player has.",
|
||||
flags_link
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_give) {
|
||||
uint32 zone_id = (
|
||||
sep->IsNumber(2) ?
|
||||
std::stoul(sep->arg[2]) :
|
||||
ZoneID(sep->arg[2])
|
||||
);
|
||||
std::string zone_short_name = str_tolower(ZoneName(zone_id, true));
|
||||
bool is_unknown_zone = zone_short_name.find("unknown") != std::string::npos;
|
||||
if (zone_id && !is_unknown_zone) {
|
||||
std::string zone_long_name = ZoneLongName(zone_id);
|
||||
auto target = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
target = c->GetTarget()->CastToClient();
|
||||
}
|
||||
}
|
||||
if (zoneid < 1) {
|
||||
c->Message(Chat::Red, "zone required. see help.");
|
||||
return;
|
||||
}
|
||||
|
||||
char flag_name[128];
|
||||
if (sep->argplus[3][0] == '\0') {
|
||||
c->Message(Chat::Red, "flag name required. see help.");
|
||||
return;
|
||||
}
|
||||
database.DoEscapeString(flag_name, sep->argplus[3], 64);
|
||||
flag_name[127] = '\0';
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE zone SET flag_needed = '%s' "
|
||||
"WHERE zoneidnumber = %d AND version = %d",
|
||||
flag_name, zoneid, zone->GetInstanceVersion());
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
c->Message(Chat::Red, "Error updating zone: %s", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::Yellow, "Success! Zone %s now requires a flag, named %s", ZoneName(zoneid), flag_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "unlockzone")) {
|
||||
uint32 zoneid = 0;
|
||||
if (sep->arg[2][0] != '\0') {
|
||||
zoneid = atoi(sep->arg[2]);
|
||||
if (zoneid < 1) {
|
||||
zoneid = ZoneID(sep->arg[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneid < 1) {
|
||||
c->Message(Chat::Red, "zone required. see help.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE zone SET flag_needed = '' "
|
||||
"WHERE zoneidnumber = %d AND version = %d",
|
||||
zoneid, zone->GetInstanceVersion());
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
c->Message(Chat::Yellow, "Error updating zone: %s", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::Yellow, "Success! Zone %s no longer requires a flag.", ZoneName(zoneid));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "listzones")) {
|
||||
std::string query = "SELECT zoneidnumber, short_name, long_name, version, flag_needed "
|
||||
"FROM zone WHERE flag_needed != ''";
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "Zones which require flags:");
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
target->SetZoneFlag(zone_id);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Zone %s (%s,%s) version %s requires key %s",
|
||||
row[2],
|
||||
fmt::format(
|
||||
"{} now {} the flag for {} ({}).",
|
||||
c == target ?
|
||||
"You" :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
),
|
||||
c == target ? "have" : "has",
|
||||
zone_long_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (is_list) {
|
||||
std::string query = SQL(
|
||||
SELECT long_name, zoneidnumber, version, flag_needed
|
||||
FROM zone
|
||||
WHERE flag_needed != ''
|
||||
ORDER BY long_name ASC
|
||||
);
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += "<tr><td>Zone</td><td>Flag Required</td></tr>";
|
||||
|
||||
for (auto row : results) {
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>{} ({}){}</td><td>{}</td></tr>",
|
||||
row[0],
|
||||
row[1],
|
||||
row[3],
|
||||
row[4]
|
||||
(
|
||||
std::stoi(row[2]) != 0 ?
|
||||
fmt::format(
|
||||
"[Version {}]",
|
||||
row[2]
|
||||
) :
|
||||
""
|
||||
),
|
||||
row[3]
|
||||
);
|
||||
}
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
c->SendPopupToClient(
|
||||
"Zone Flags",
|
||||
popup_text.c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
} else if (is_lock) {
|
||||
uint32 zone_id = (
|
||||
sep->IsNumber(2) ?
|
||||
std::stoul(sep->arg[2]) :
|
||||
ZoneID(sep->arg[2])
|
||||
);
|
||||
std::string zone_short_name = str_tolower(ZoneName(zone_id, true));
|
||||
bool is_unknown_zone = zone_short_name.find("unknown") != std::string::npos;
|
||||
if (zone_id && !is_unknown_zone) {
|
||||
if (arguments < 3) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Usage: #flagedit lock [Zone ID|Zone Short Name] [Flag Name] - Set the specified flag name on the zone, locking the zone"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string flag_name = EscapeString(sep->argplus[3]);
|
||||
std::string zone_long_name = ZoneLongName(zone_id);
|
||||
|
||||
auto query = fmt::format(
|
||||
SQL(
|
||||
UPDATE zone
|
||||
SET flag_needed = '{}'
|
||||
WHERE zoneidnumber = {} AND version = {}
|
||||
),
|
||||
flag_name,
|
||||
zone_id,
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "give")) {
|
||||
uint32 zoneid = 0;
|
||||
if (sep->arg[2][0] != '\0') {
|
||||
zoneid = atoi(sep->arg[2]);
|
||||
if (zoneid < 1) {
|
||||
zoneid = ZoneID(sep->arg[2]);
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Error updating zone flag for {} ({}).",
|
||||
zone_long_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (zoneid < 1) {
|
||||
c->Message(Chat::Red, "zone required. see help.");
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) now requires a flag, named {}.",
|
||||
zone_long_name,
|
||||
zone_id,
|
||||
flag_name
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Mob *t = c->GetTarget();
|
||||
if (t == nullptr || !t->IsClient()) {
|
||||
c->Message(Chat::Red, "client target required");
|
||||
return;
|
||||
}
|
||||
|
||||
t->CastToClient()->SetZoneFlag(zoneid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(sep->arg[1], "give")) {
|
||||
uint32 zoneid = 0;
|
||||
if (sep->arg[2][0] != '\0') {
|
||||
zoneid = atoi(sep->arg[2]);
|
||||
if (zoneid < 1) {
|
||||
zoneid = ZoneID(sep->arg[2]);
|
||||
} else if (is_take) {
|
||||
uint32 zone_id = (
|
||||
sep->IsNumber(2) ?
|
||||
std::stoul(sep->arg[2]) :
|
||||
ZoneID(sep->arg[2])
|
||||
);
|
||||
std::string zone_short_name = str_tolower(ZoneName(zone_id, true));
|
||||
bool is_unknown_zone = zone_short_name.find("unknown") != std::string::npos;
|
||||
if (zone_id && !is_unknown_zone) {
|
||||
std::string zone_long_name = ZoneLongName(zone_id);
|
||||
auto target = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
target = c->GetTarget()->CastToClient();
|
||||
}
|
||||
}
|
||||
if (zoneid < 1) {
|
||||
c->Message(Chat::Red, "zone required. see help.");
|
||||
|
||||
target->ClearZoneFlag(zone_id);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} no longer {} the flag for {} ({}).",
|
||||
c == target ?
|
||||
"You" :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
),
|
||||
c == target ? "have" : "has",
|
||||
zone_long_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (is_unlock) {
|
||||
uint32 zone_id = (
|
||||
sep->IsNumber(2) ?
|
||||
std::stoul(sep->arg[2]) :
|
||||
ZoneID(sep->arg[2])
|
||||
);
|
||||
std::string zone_short_name = str_tolower(ZoneName(zone_id, true));
|
||||
bool is_unknown_zone = zone_short_name.find("unknown") != std::string::npos;
|
||||
if (zone_id && !is_unknown_zone) {
|
||||
std::string zone_long_name = ZoneLongName(zone_id);
|
||||
auto query = fmt::format(
|
||||
SQL(
|
||||
UPDATE zone
|
||||
SET flag_needed = ''
|
||||
WHERE zoneidnumber = {} AND version = {}
|
||||
),
|
||||
zone_id,
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Error updating zone flag for {} ({}).",
|
||||
zone_long_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Mob *t = c->GetTarget();
|
||||
if (t == nullptr || !t->IsClient()) {
|
||||
c->Message(Chat::Red, "client target required");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) no longer requires a flag.",
|
||||
zone_long_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
t->CastToClient()->ClearZoneFlag(zoneid);
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::Yellow, "Invalid action specified. use '#flagedit help' for help");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
void command_hatelist(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *target = c->GetTarget();
|
||||
if (target == nullptr) {
|
||||
c->Message(Chat::White, "Error: you must have a target.");
|
||||
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
|
||||
c->Message(Chat::White, "You must target an NPC to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "Display hate list for %s..", target->GetName());
|
||||
auto target = c->GetTarget();
|
||||
|
||||
target->PrintHateListToClient(c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+182
-81
@@ -5,97 +5,198 @@ extern WorldServer worldserver;
|
||||
|
||||
void command_logs(Client *c, const Seperator *sep)
|
||||
{
|
||||
int logs_set = 0;
|
||||
if (sep->argnum > 0) {
|
||||
/* #logs reload_all */
|
||||
if (strcasecmp(sep->arg[1], "reload_all") == 0) {
|
||||
auto pack = new ServerPacket(ServerOP_ReloadLogs, 0);
|
||||
worldserver.SendPacket(pack);
|
||||
c->Message(
|
||||
Chat::Red,
|
||||
"Successfully sent the packet to world to reload log settings from the database for all zones"
|
||||
);
|
||||
safe_delete(pack);
|
||||
}
|
||||
/* #logs list_settings */
|
||||
if (strcasecmp(sep->arg[1], "list_settings") == 0 ||
|
||||
(strcasecmp(sep->arg[1], "set") == 0 && strcasecmp(sep->arg[3], "") == 0)) {
|
||||
c->Message(Chat::White, "[Category ID | console | file | gmsay | Category Description]");
|
||||
int redisplay_columns = 0;
|
||||
for (int i = 0; i < Logs::LogCategory::MaxCategoryID; i++) {
|
||||
if (redisplay_columns == 10) {
|
||||
c->Message(Chat::White, "[Category ID | console | file | gmsay | Category Description]");
|
||||
redisplay_columns = 0;
|
||||
}
|
||||
c->Message(
|
||||
0,
|
||||
StringFormat(
|
||||
"--- %i | %u | %u | %u | %s",
|
||||
i,
|
||||
LogSys.log_settings[i].log_to_console,
|
||||
LogSys.log_settings[i].log_to_file,
|
||||
LogSys.log_settings[i].log_to_gmsay,
|
||||
Logs::LogCategoryName[i]
|
||||
).c_str());
|
||||
redisplay_columns++;
|
||||
}
|
||||
}
|
||||
/* #logs set */
|
||||
if (strcasecmp(sep->arg[1], "set") == 0) {
|
||||
if (strcasecmp(sep->arg[2], "console") == 0) {
|
||||
LogSys.log_settings[atoi(sep->arg[3])].log_to_console = atoi(sep->arg[4]);
|
||||
logs_set = 1;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[2], "file") == 0) {
|
||||
LogSys.log_settings[atoi(sep->arg[3])].log_to_file = atoi(sep->arg[4]);
|
||||
logs_set = 1;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[2], "gmsay") == 0) {
|
||||
LogSys.log_settings[atoi(sep->arg[3])].log_to_gmsay = atoi(sep->arg[4]);
|
||||
logs_set = 1;
|
||||
}
|
||||
else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"--- #logs set [console|file|gmsay] <category_id> <debug_level (1-3)> - Sets log settings during the lifetime of the zone"
|
||||
);
|
||||
c->Message(Chat::White, "--- #logs set gmsay 20 1 - Would output Quest errors to gmsay");
|
||||
}
|
||||
if (logs_set == 1) {
|
||||
c->Message(Chat::Yellow, "Your Log Settings have been applied");
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
"Output Method: %s :: Debug Level: %i - Category: %s",
|
||||
sep->arg[2],
|
||||
atoi(sep->arg[4]),
|
||||
Logs::LogCategoryName[atoi(sep->arg[3])]
|
||||
);
|
||||
}
|
||||
/* We use a general 'is_category_enabled' now, let's update when we update any output settings
|
||||
This is used in hot places of code to check if its enabled in any way before triggering logs
|
||||
*/
|
||||
if (atoi(sep->arg[4]) > 0) {
|
||||
LogSys.log_settings[atoi(sep->arg[3])].is_category_enabled = 1;
|
||||
}
|
||||
else {
|
||||
LogSys.log_settings[atoi(sep->arg[3])].is_category_enabled = 0;
|
||||
}
|
||||
}
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs list - Shows current log settings and categories loaded into the current process' memory for the first 50 log categories"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs list [Start Category ID] - Shows current log settings and categories loaded into the current process' memory, only shows 50 at a time starting at specified Category ID"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs reload - Reload all settings in world and all zone processes with what is defined in the database"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs set [console|file|gmsay] [Category ID] [Debug Level (1-3)] - Sets log settings during the lifetime of the zone"
|
||||
);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "#logs usage:");
|
||||
|
||||
bool is_list = !strcasecmp(sep->arg[1], "list");
|
||||
bool is_reload = !strcasecmp(sep->arg[1], "reload");
|
||||
bool is_set = !strcasecmp(sep->arg[1], "set");
|
||||
|
||||
if (!is_list && !is_reload && !is_set) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"--- #logs reload_all - Reload all settings in world and all zone processes with what is defined in the database"
|
||||
"#logs list - Shows current log settings and categories loaded into the current process' memory for the first 50 log categories"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"--- #logs list_settings - Shows current log settings and categories loaded into the current process' memory"
|
||||
"#logs list [Start Category ID] - Shows current log settings and categories loaded into the current process' memory, only shows 50 at a time starting at specified Category ID"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"--- #logs set [console|file|gmsay] <category_id> <debug_level (1-3)> - Sets log settings during the lifetime of the zone"
|
||||
"#logs reload - Reload all settings in world and all zone processes with what is defined in the database"
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs set [console|file|gmsay] [Category ID] [Debug Level (1-3)] - Sets log settings during the lifetime of the zone"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_list) {
|
||||
uint32 start_category_id = 1;
|
||||
if (sep->IsNumber(2)) {
|
||||
start_category_id = std::stoul(sep->arg[2]);
|
||||
}
|
||||
|
||||
uint32 max_category_id = (start_category_id + 49);
|
||||
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += "<tr>";
|
||||
popup_text += "<td>ID</td>";
|
||||
popup_text += "<td>Name</td>";
|
||||
popup_text += "<td>Console</td>";
|
||||
popup_text += "<td>File</td>";
|
||||
popup_text += "<td>GM Say</td>";
|
||||
popup_text += "</tr>";
|
||||
|
||||
for (int index = start_category_id; index <= max_category_id; index++) {
|
||||
if (index >= Logs::LogCategory::MaxCategoryID) {
|
||||
max_category_id = (Logs::LogCategory::MaxCategoryID - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
|
||||
index,
|
||||
Logs::LogCategoryName[index],
|
||||
LogSys.log_settings[index].log_to_console,
|
||||
LogSys.log_settings[index].log_to_file,
|
||||
LogSys.log_settings[index].log_to_gmsay
|
||||
);
|
||||
}
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
std::string popup_title = fmt::format(
|
||||
"Log Settings [{} to {}]",
|
||||
start_category_id,
|
||||
max_category_id
|
||||
);
|
||||
|
||||
c->SendPopupToClient(
|
||||
popup_title.c_str(),
|
||||
popup_text.c_str()
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Viewing log category settings from {} ({}) to {} ({}).",
|
||||
Logs::LogCategoryName[start_category_id],
|
||||
start_category_id,
|
||||
Logs::LogCategoryName[max_category_id],
|
||||
max_category_id
|
||||
).c_str()
|
||||
);
|
||||
|
||||
int next_category_id = (max_category_id + 1);
|
||||
if (next_category_id < Logs::LogCategory::MaxCategoryID) {
|
||||
auto next_list_string = fmt::format(
|
||||
"#logs list {}",
|
||||
next_category_id
|
||||
);
|
||||
|
||||
auto next_list_link = EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
next_list_string,
|
||||
false,
|
||||
next_list_string
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"To view the next 50 log settings, you can use {}.",
|
||||
next_list_link
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else if (is_reload) {
|
||||
auto pack = new ServerPacket(ServerOP_ReloadLogs, 0);
|
||||
worldserver.SendPacket(pack);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Reloaded log settings worldwide."
|
||||
);
|
||||
safe_delete(pack);
|
||||
} else if (is_set) {
|
||||
auto logs_set = false;
|
||||
bool is_console = !strcasecmp(sep->arg[2], "console");
|
||||
bool is_file = !strcasecmp(sep->arg[2], "file");
|
||||
bool is_gmsay = !strcasecmp(sep->arg[2], "gmsay");
|
||||
|
||||
if (!is_console && !is_file && !is_gmsay) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#logs set [console|file|gmsay] [Category ID] [Debug Level (1-3)] - Sets log settings during the lifetime of the zone"
|
||||
);
|
||||
c->Message(Chat::White, "Example: #logs set gmsay 20 1 - Would output Quest errors to gmsay");
|
||||
return;
|
||||
}
|
||||
|
||||
logs_set = true;
|
||||
|
||||
auto category_id = std::stoul(sep->arg[3]);
|
||||
auto setting = std::stoul(sep->arg[4]);
|
||||
|
||||
if (is_console) {
|
||||
LogSys.log_settings[category_id].log_to_console = setting;
|
||||
} else if (is_file) {
|
||||
LogSys.log_settings[category_id].log_to_file = setting;
|
||||
} else if (is_gmsay) {
|
||||
LogSys.log_settings[category_id].log_to_gmsay = setting;
|
||||
}
|
||||
|
||||
if (logs_set) {
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>ID</td><td>{}</td><tr>",
|
||||
category_id
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Category</td><td>{}</td><tr>",
|
||||
Logs::LogCategoryName[category_id]
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Method</td><td>{}</td></tr>",
|
||||
sep->arg[2]
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Setting</td><td>{}</td></tr>",
|
||||
setting
|
||||
);
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
c->SendPopupToClient(
|
||||
"Log Settings Applied",
|
||||
popup_text.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
LogSys.log_settings[category_id].is_category_enabled = setting ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
-19
@@ -2,29 +2,41 @@
|
||||
|
||||
void command_name(Client *c, const Seperator *sep)
|
||||
{
|
||||
Client *target;
|
||||
|
||||
if ((strlen(sep->arg[1]) == 0) || (!(c->GetTarget() && c->GetTarget()->IsClient()))) {
|
||||
c->Message(Chat::White, "Usage: #name newname (requires player target)");
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
c->Message(Chat::White, "Usage: #name [New Name] - Rename your player target");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
target = c->GetTarget()->CastToClient();
|
||||
char *oldname = strdup(target->GetName());
|
||||
if (target->ChangeFirstName(sep->arg[1], c->GetName())) {
|
||||
c->Message(Chat::White, "Successfully renamed %s to %s", oldname, sep->arg[1]);
|
||||
// until we get the name packet working right this will work
|
||||
c->Message(Chat::White, "Sending player to char select.");
|
||||
target->Kick("Name was changed");
|
||||
}
|
||||
else {
|
||||
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
auto target = c->GetTarget()->CastToClient();
|
||||
|
||||
std::string new_name = sep->arg[1];
|
||||
std::string old_name = target->GetCleanName();
|
||||
|
||||
if (target->ChangeFirstName(new_name.c_str(), c->GetCleanName())) {
|
||||
c->Message(
|
||||
Chat::Red,
|
||||
"ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.",
|
||||
oldname,
|
||||
sep->arg[2]
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Successfully renamed {} to {}",
|
||||
old_name,
|
||||
new_name
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(Chat::White, "Sending player to char select.");
|
||||
|
||||
target->Kick("Name was changed");
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Unable to rename {}. Check that the new name '{}' isn't already taken.",
|
||||
old_name,
|
||||
new_name
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
free(oldname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+161
-133
@@ -2,140 +2,168 @@
|
||||
|
||||
void command_netstats(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c) {
|
||||
auto client = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
client = c->GetTarget()->CastToClient();
|
||||
}
|
||||
bool is_full = !strcasecmp(sep->arg[1], "full");
|
||||
bool is_reset = !strcasecmp(sep->arg[1], "reset");
|
||||
|
||||
if (strcasecmp(sep->arg[1], "reset") == 0) {
|
||||
auto connection = c->Connection();
|
||||
c->Message(Chat::White, "Resetting client stats (packet loss will not read correctly after reset).");
|
||||
connection->ResetStats();
|
||||
return;
|
||||
}
|
||||
|
||||
auto connection = c->Connection();
|
||||
auto opts = connection->GetManager()->GetOptions();
|
||||
auto eqs_stats = connection->GetStats();
|
||||
auto &stats = eqs_stats.DaybreakStats;
|
||||
auto now = EQ::Net::Clock::now();
|
||||
auto sec_since_stats_reset = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
now - stats.created
|
||||
).count();
|
||||
|
||||
c->Message(Chat::White, "Netstats:");
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Sent Bytes: %u (%.2f/sec)",
|
||||
stats.sent_bytes,
|
||||
stats.sent_bytes / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Recv Bytes: %u (%.2f/sec)",
|
||||
stats.recv_bytes,
|
||||
stats.recv_bytes / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White, "Bytes Before Encode (Sent): %u, Compression Rate: %.2f%%", stats.bytes_before_encode,
|
||||
static_cast<double>(stats.bytes_before_encode - stats.sent_bytes) /
|
||||
static_cast<double>(stats.bytes_before_encode) * 100.0
|
||||
);
|
||||
c->Message(
|
||||
Chat::White, "Bytes After Decode (Recv): %u, Compression Rate: %.2f%%", stats.bytes_after_decode,
|
||||
static_cast<double>(stats.bytes_after_decode - stats.recv_bytes) /
|
||||
static_cast<double>(stats.bytes_after_decode) * 100.0
|
||||
);
|
||||
c->Message(Chat::White, "Min Ping: %u", stats.min_ping);
|
||||
c->Message(Chat::White, "Max Ping: %u", stats.max_ping);
|
||||
c->Message(Chat::White, "Last Ping: %u", stats.last_ping);
|
||||
c->Message(Chat::White, "Average Ping: %u", stats.avg_ping);
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"(Realtime) Recv Packets: %u (%.2f/sec)",
|
||||
stats.recv_packets,
|
||||
stats.recv_packets / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"(Realtime) Sent Packets: %u (%.2f/sec)",
|
||||
stats.sent_packets,
|
||||
stats.sent_packets / sec_since_stats_reset
|
||||
);
|
||||
c->Message(Chat::White, "(Sync) Recv Packets: %u", stats.sync_recv_packets);
|
||||
c->Message(Chat::White, "(Sync) Sent Packets: %u", stats.sync_sent_packets);
|
||||
c->Message(Chat::White, "(Sync) Remote Recv Packets: %u", stats.sync_remote_recv_packets);
|
||||
c->Message(Chat::White, "(Sync) Remote Sent Packets: %u", stats.sync_remote_sent_packets);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Packet Loss In: %.2f%%",
|
||||
100.0 * (1.0 - static_cast<double>(stats.sync_recv_packets) /
|
||||
static_cast<double>(stats.sync_remote_sent_packets)));
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Packet Loss Out: %.2f%%",
|
||||
100.0 * (1.0 - static_cast<double>(stats.sync_remote_recv_packets) /
|
||||
static_cast<double>(stats.sync_sent_packets)));
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Resent Packets: %u (%.2f/sec)",
|
||||
stats.resent_packets,
|
||||
stats.resent_packets / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Resent Fragments: %u (%.2f/sec)",
|
||||
stats.resent_fragments,
|
||||
stats.resent_fragments / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Resent Non-Fragments: %u (%.2f/sec)",
|
||||
stats.resent_full,
|
||||
stats.resent_full / sec_since_stats_reset
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Dropped Datarate Packets: %u (%.2f/sec)",
|
||||
stats.dropped_datarate_packets,
|
||||
stats.dropped_datarate_packets / sec_since_stats_reset
|
||||
);
|
||||
|
||||
if (opts.daybreak_options.outgoing_data_rate > 0.0) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Outgoing Link Saturation %.2f%% (%.2fkb/sec)",
|
||||
100.0 * (1.0 - ((opts.daybreak_options.outgoing_data_rate - stats.datarate_remaining) /
|
||||
opts.daybreak_options.outgoing_data_rate)),
|
||||
opts.daybreak_options.outgoing_data_rate
|
||||
);
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "full") == 0) {
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
c->Message(Chat::White, "Sent Packet Types");
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto cnt = eqs_stats.SentCount[i];
|
||||
if (cnt > 0) {
|
||||
c->Message(Chat::White, "%s: %u (%.2f / sec)", OpcodeNames[i], cnt, cnt / sec_since_stats_reset);
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
c->Message(Chat::White, "Recv Packet Types");
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto cnt = eqs_stats.RecvCount[i];
|
||||
if (cnt > 0) {
|
||||
c->Message(Chat::White, "%s: %u (%.2f / sec)", OpcodeNames[i], cnt, cnt / sec_since_stats_reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "--------------------------------------------------------------------");
|
||||
if (is_reset) {
|
||||
auto connection = c->Connection();
|
||||
c->Message(Chat::White, "Resetting client stats (packet loss will not read correctly after reset).");
|
||||
connection->ResetStats();
|
||||
return;
|
||||
}
|
||||
|
||||
auto connection = c->Connection();
|
||||
auto opts = connection->GetManager()->GetOptions();
|
||||
auto eqs_stats = connection->GetStats();
|
||||
auto &stats = eqs_stats.DaybreakStats;
|
||||
auto now = EQ::Net::Clock::now();
|
||||
auto sec_since_stats_reset = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||
now - stats.created
|
||||
).count();
|
||||
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Sent Bytes</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.sent_bytes,
|
||||
stats.sent_bytes / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Received Bytes</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.recv_bytes,
|
||||
stats.recv_bytes / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Bytes Before Encode (Sent)</td><td>{}</td><td>Compression Rate</td><td>{:.2f}%%</td></tr>",
|
||||
stats.bytes_before_encode,
|
||||
static_cast<double>(stats.bytes_before_encode - stats.sent_bytes) /
|
||||
static_cast<double>(stats.bytes_before_encode) * 100.0
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Bytes After Decode (Received)</td><td>{}</td><td>Compression Rate</td><td>{:.2f}%%</td></tr>",
|
||||
stats.bytes_after_decode,
|
||||
static_cast<double>(stats.bytes_after_decode - stats.recv_bytes) /
|
||||
static_cast<double>(stats.bytes_after_decode) * 100.0
|
||||
);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format("<tr><td>Min Ping</td><td>{}</td></tr>", stats.min_ping);
|
||||
popup_text += fmt::format("<tr><td>Max Ping</td><td>{}</td></tr>", stats.max_ping);
|
||||
popup_text += fmt::format("<tr><td>Last Ping</td><td>{}</td></tr>", stats.last_ping);
|
||||
popup_text += fmt::format("<tr><td>Average Ping</td><td>{}</td></tr>", stats.avg_ping);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>(Realtime) Received Packets</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.recv_packets,
|
||||
stats.recv_packets / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>(Realtime) Sent Packets</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.sent_packets,
|
||||
stats.sent_packets / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format("<tr><td>(Sync) Received Packets</td><td>{}</td></tr>", stats.sync_recv_packets);
|
||||
popup_text += fmt::format("<tr><td>(Sync) Sent Packets</td><td>{}</td></tr>", stats.sync_sent_packets);
|
||||
popup_text += fmt::format("<tr><td>(Sync) Remote Received Packets</td><td>{}</td></tr>", stats.sync_remote_recv_packets);
|
||||
popup_text += fmt::format("<tr><td>(Sync) Remote Sent Packets</td><td>{}</td></tr>", stats.sync_remote_sent_packets);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Packet Loss In</td><td>{:.2f}%%</td></tr>",
|
||||
(100.0 * (1.0 - static_cast<double>(stats.sync_recv_packets) / static_cast<double>(stats.sync_remote_sent_packets)))
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Packet Loss Out</td><td>{:.2f}%%</td></tr>",
|
||||
(100.0 * (1.0 - static_cast<double>(stats.sync_remote_recv_packets) / static_cast<double>(stats.sync_sent_packets)))
|
||||
);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Resent Packets</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.resent_packets,
|
||||
stats.resent_packets / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Resent Fragments</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.resent_fragments,
|
||||
stats.resent_fragments / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Resent Non-Fragments</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.resent_full,
|
||||
stats.resent_full / sec_since_stats_reset
|
||||
);
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Dropped Datarate Packets</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
stats.dropped_datarate_packets,
|
||||
stats.dropped_datarate_packets / sec_since_stats_reset
|
||||
);
|
||||
|
||||
if (opts.daybreak_options.outgoing_data_rate > 0.0) {
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>Outgoing Link Saturation</td><td>{:.2f}%% ({:.2f}kb Per Second)</td></tr>",
|
||||
(100.0 * (1.0 - ((opts.daybreak_options.outgoing_data_rate - stats.datarate_remaining) / opts.daybreak_options.outgoing_data_rate))),
|
||||
opts.daybreak_options.outgoing_data_rate
|
||||
);
|
||||
}
|
||||
|
||||
if (is_full) {
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += "<tr><td>Sent Packet Types</td></tr>";
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto cnt = eqs_stats.SentCount[i];
|
||||
if (cnt > 0) {
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>{}</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
OpcodeNames[i],
|
||||
cnt,
|
||||
cnt / sec_since_stats_reset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
popup_text += "<br><br>";
|
||||
|
||||
popup_text += "<tr><td>Received Packet Types</td></tr>";
|
||||
for (auto i = 0; i < _maxEmuOpcode; ++i) {
|
||||
auto cnt = eqs_stats.RecvCount[i];
|
||||
if (cnt > 0) {
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>{}</td><td>{} ({:.2f} Per Second)</td></tr>",
|
||||
OpcodeNames[i],
|
||||
cnt,
|
||||
cnt / sec_since_stats_reset
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
c->SendPopupToClient(
|
||||
"Network Statistics",
|
||||
popup_text.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+227
-82
@@ -1,104 +1,249 @@
|
||||
#include "../client.h"
|
||||
#include "../corpse.h"
|
||||
#include "../../common/data_verification.h"
|
||||
|
||||
void command_npcloot(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c->GetTarget() == 0) {
|
||||
c->Message(Chat::White, "Error: No target");
|
||||
// #npcloot show
|
||||
if (!c->GetTarget() || (!c->GetTarget()->IsNPC() && !c->GetTarget()->IsCorpse())) {
|
||||
c->Message(Chat::White, "You must target an NPC or a Corpse to use this command.");
|
||||
return;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "show") == 0) {
|
||||
if (c->GetTarget()->IsNPC()) {
|
||||
c->GetTarget()->CastToNPC()->QueryLoot(c);
|
||||
}
|
||||
else if (c->GetTarget()->IsCorpse()) {
|
||||
c->GetTarget()->CastToCorpse()->QueryLoot(c);
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: Target's type doesnt have loot");
|
||||
}
|
||||
|
||||
int arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
c->Message(Chat::White, "Usage: #npcloot add [Item ID] [Charges] [Equip] [Augment 1 ID] [Augment 2 ID] [Augment 3 ID] [Augment 4 ID] [Augment 5 ID] [Augment 6 ID] - Adds the specified item to an NPC's loot");
|
||||
c->Message(Chat::White, "Usage: #npcloot money [Platinum] [Gold] [Silver] [Copper] - Set an NPC's current money");
|
||||
c->Message(Chat::White, "Usage: #npcloot remove [All|Item ID] - Remove loot from an NPC by ID or remove all loot");
|
||||
c->Message(Chat::White, "Usage: #npcloot show - Shows target NPC's or Corpse's current loot");
|
||||
return;
|
||||
}
|
||||
// These 2 types are *BAD* for the next few commands
|
||||
else if (c->GetTarget()->IsClient() || c->GetTarget()->IsCorpse()) {
|
||||
c->Message(Chat::White, "Error: Invalid target type, try a NPC =).");
|
||||
// #npcloot add
|
||||
|
||||
bool is_add = !strcasecmp(sep->arg[1], "add");
|
||||
bool is_money = !strcasecmp(sep->arg[1], "money");
|
||||
bool is_remove = !strcasecmp(sep->arg[1], "remove");
|
||||
bool is_show = !strcasecmp(sep->arg[1], "show");
|
||||
|
||||
if (
|
||||
!is_add &&
|
||||
!is_money &&
|
||||
!is_remove &&
|
||||
!is_show
|
||||
) {
|
||||
c->Message(Chat::White, "Usage: #npcloot add [Item ID] [Charges] [Equip] [Augment 1 ID] [Augment 2 ID] [Augment 3 ID] [Augment 4 ID] [Augment 5 ID] [Augment 6 ID] - Adds the specified item to an NPC's loot");
|
||||
c->Message(Chat::White, "Usage: #npcloot money [Platinum] [Gold] [Silver] [Copper] - Set an NPC's current money");
|
||||
c->Message(Chat::White, "Usage: #npcloot remove [All|Item ID] - Remove loot from an NPC by ID or remove all loot");
|
||||
c->Message(Chat::White, "Usage: #npcloot show - Shows target NPC's or Corpse's current loot");
|
||||
return;
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "add") == 0) {
|
||||
// #npcloot add item
|
||||
if (c->GetTarget()->IsNPC() && sep->IsNumber(2)) {
|
||||
uint32 item = atoi(sep->arg[2]);
|
||||
if (database.GetItem(item)) {
|
||||
if (sep->arg[3][0] != 0 && sep->IsNumber(3)) {
|
||||
c->GetTarget()->CastToNPC()->AddItem(item, atoi(sep->arg[3]), 0);
|
||||
}
|
||||
else {
|
||||
c->GetTarget()->CastToNPC()->AddItem(item, 1, 0);
|
||||
}
|
||||
c->Message(Chat::White, "Added item(%i) to the %s's loot.", item, c->GetTarget()->GetName());
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: #npcloot add: Item(%i) does not exist!", item);
|
||||
}
|
||||
|
||||
if (is_add) {
|
||||
if (!c->GetTarget()->IsNPC() || !sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #npcloot add [Item ID] [Charges] [Equip] [Augment 1 ID] [Augment 2 ID] [Augment 3 ID] [Augment 4 ID] [Augment 5 ID] [Augment 6 ID] - Adds the specified item to an NPC's loot");
|
||||
return;
|
||||
}
|
||||
else if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Error: #npcloot add: Itemid must be a number.");
|
||||
|
||||
auto item_id = std::stoul(sep->arg[2]);
|
||||
auto item_charges = sep->IsNumber(3) ? static_cast<uint16>(std::stoul(sep->arg[3])) : 1;
|
||||
bool equip_item = arguments >= 4 ? atobool(sep->arg[4]) : false;
|
||||
auto augment_one_id = sep->IsNumber(5) ? std::stoul(sep->arg[5]) : 0;
|
||||
auto augment_two_id = sep->IsNumber(6) ? std::stoul(sep->arg[6]) : 0;
|
||||
auto augment_three_id = sep->IsNumber(7) ? std::stoul(sep->arg[7]) : 0;
|
||||
auto augment_four_id = sep->IsNumber(8) ? std::stoul(sep->arg[8]) : 0;
|
||||
auto augment_five_id = sep->IsNumber(9) ? std::stoul(sep->arg[9]) : 0;
|
||||
auto augment_six_id = sep->IsNumber(10) ? std::stoul(sep->arg[10]) : 0;
|
||||
|
||||
auto item_data = database.GetItem(item_id);
|
||||
|
||||
if (!item_data) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Item ID {} could not be found",
|
||||
item_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: #npcloot add: This is not a valid target.");
|
||||
|
||||
c->GetTarget()->CastToNPC()->AddItem(
|
||||
item_id,
|
||||
item_charges,
|
||||
equip_item,
|
||||
augment_one_id,
|
||||
augment_two_id,
|
||||
augment_three_id,
|
||||
augment_four_id,
|
||||
augment_five_id,
|
||||
augment_six_id
|
||||
);
|
||||
|
||||
auto item = database.CreateItem(
|
||||
item_id,
|
||||
item_charges,
|
||||
augment_one_id,
|
||||
augment_two_id,
|
||||
augment_three_id,
|
||||
augment_four_id,
|
||||
augment_five_id,
|
||||
augment_six_id
|
||||
);
|
||||
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemInst);
|
||||
linker.SetItemInst(item);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Added {} ({}) to {} ({}).",
|
||||
item_link,
|
||||
item_id,
|
||||
c->GetTarget()->GetCleanName(),
|
||||
c->GetTarget()->GetID()
|
||||
).c_str()
|
||||
);
|
||||
} else if (is_money) {
|
||||
if (!c->GetTarget()->IsNPC()) {
|
||||
c->Message(Chat::White, "You must target an NPC to use this command.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// #npcloot remove
|
||||
else if (strcasecmp(sep->arg[1], "remove") == 0) {
|
||||
//#npcloot remove all
|
||||
if (strcasecmp(sep->arg[2], "all") == 0) {
|
||||
c->Message(Chat::White, "Error: #npcloot remove all: Not yet implemented.");
|
||||
//#npcloot remove itemid
|
||||
|
||||
auto target = c->GetTarget()->CastToNPC();
|
||||
|
||||
if (sep->IsNumber(2)) {
|
||||
uint16 platinum = EQ::Clamp(std::stoi(sep->arg[2]), 0, 65535);
|
||||
uint16 gold = sep->IsNumber(3) ? EQ::Clamp(std::stoi(sep->arg[3]), 0, 65535) : 0;
|
||||
uint16 silver = sep->IsNumber(4) ? EQ::Clamp(std::stoi(sep->arg[4]), 0, 65535) : 0;
|
||||
uint16 copper = sep->IsNumber(5) ? EQ::Clamp(std::stoi(sep->arg[5]), 0, 65535) : 0;
|
||||
target->AddCash(
|
||||
copper,
|
||||
silver,
|
||||
gold,
|
||||
platinum
|
||||
);
|
||||
|
||||
auto money_string = (
|
||||
(
|
||||
copper ||
|
||||
silver ||
|
||||
gold ||
|
||||
platinum
|
||||
) ?
|
||||
ConvertMoneyToString(
|
||||
platinum,
|
||||
gold,
|
||||
silver,
|
||||
copper
|
||||
) :
|
||||
"no money"
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) now has {}.",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
money_string
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #npcloot money [Platinum] [Gold] [Silver] [Copper] - Set an NPC's current money");
|
||||
}
|
||||
else {
|
||||
if (c->GetTarget()->IsNPC() && sep->IsNumber(2)) {
|
||||
uint32 item = atoi(sep->arg[2]);
|
||||
c->GetTarget()->CastToNPC()->RemoveItem(item);
|
||||
c->Message(Chat::White, "Removed item(%i) from the %s's loot.", item, c->GetTarget()->GetName());
|
||||
}
|
||||
else if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Error: #npcloot remove: Item must be a number.");
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: #npcloot remove: This is not a valid target.");
|
||||
}
|
||||
} else if (is_remove) {
|
||||
if (!c->GetTarget()->IsNPC()) {
|
||||
c->Message(Chat::White, "You must target an NPC to use this command.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// #npcloot money
|
||||
else if (strcasecmp(sep->arg[1], "money") == 0) {
|
||||
if (c->GetTarget()->IsNPC() && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4) && sep->IsNumber(5)) {
|
||||
if ((atoi(sep->arg[2]) < 34465 && atoi(sep->arg[2]) >= 0) &&
|
||||
(atoi(sep->arg[3]) < 34465 && atoi(sep->arg[3]) >= 0) &&
|
||||
(atoi(sep->arg[4]) < 34465 && atoi(sep->arg[4]) >= 0) &&
|
||||
(atoi(sep->arg[5]) < 34465 && atoi(sep->arg[5]) >= 0)) {
|
||||
c->GetTarget()->CastToNPC()->AddCash(
|
||||
atoi(sep->arg[5]),
|
||||
atoi(sep->arg[4]),
|
||||
atoi(sep->arg[3]),
|
||||
atoi(sep->arg[2]));
|
||||
|
||||
auto target = c->GetTarget()->CastToNPC();
|
||||
|
||||
bool is_remove_all = !strcasecmp(sep->arg[2], "all");
|
||||
if (is_remove_all) {
|
||||
auto loot_list = target->GetLootList();
|
||||
auto total_item_count = 0;
|
||||
for (const auto& item_id : loot_list) {
|
||||
auto item_count = target->CountItem(item_id);
|
||||
|
||||
target->RemoveItem(item_id);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Set %i Platinum, %i Gold, %i Silver, and %i Copper as %s's money.",
|
||||
atoi(sep->arg[2]),
|
||||
atoi(sep->arg[3]),
|
||||
atoi(sep->arg[4]),
|
||||
atoi(sep->arg[5]),
|
||||
c->GetTarget()->GetName());
|
||||
fmt::format(
|
||||
"Removed {} {} ({}) from {} ({}).",
|
||||
item_count,
|
||||
database.CreateItemLink(item_id),
|
||||
item_id,
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
total_item_count += item_count;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Error: #npcloot money: Values must be between 0-34465.");
|
||||
|
||||
if (!total_item_count) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) has no items to remove.",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} Item{} removed from {} ({}).",
|
||||
total_item_count,
|
||||
total_item_count != 1 ? "s" : "",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (sep->IsNumber(2)) {
|
||||
auto item_id = std::stoul(sep->arg[2]);
|
||||
auto item_count = target->CountItem(item_id);
|
||||
if (item_count) {
|
||||
target->RemoveItem(item_id);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Removed {} {} ({}) from {} ({}).",
|
||||
item_count,
|
||||
database.CreateItemLink(item_id),
|
||||
item_id,
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) does not have any {} ({}).",
|
||||
target->GetCleanName(),
|
||||
target->GetID(),
|
||||
database.CreateItemLink(item_id),
|
||||
item_id
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
c->Message(Chat::White, "Usage: #npcloot remove [All|Item ID] - Remove loot from an NPC by ID or remove all loot");
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: #npcloot money platinum gold silver copper");
|
||||
} else if (is_show) {
|
||||
if (c->GetTarget()->IsNPC()) {
|
||||
c->GetTarget()->CastToNPC()->QueryLoot(c);
|
||||
} else if (c->GetTarget()->IsCorpse()) {
|
||||
c->GetTarget()->CastToCorpse()->QueryLoot(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Usage: #npcloot [show/money/add/remove] [itemid/all/money: pp gp sp cp]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-11
@@ -2,21 +2,45 @@
|
||||
|
||||
void command_timers(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (!c->GetTarget() || !c->GetTarget()->IsClient()) {
|
||||
c->Message(Chat::White, "Need a player target for timers.");
|
||||
return;
|
||||
auto target = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
target = c->GetTarget()->CastToClient();
|
||||
}
|
||||
Client *them = c->GetTarget()->CastToClient();
|
||||
|
||||
std::vector<std::pair<pTimerType, PersistentTimer *> > res;
|
||||
them->GetPTimers().ToVector(res);
|
||||
std::vector<std::pair<pTimerType, PersistentTimer *>> timers;
|
||||
target->GetPTimers().ToVector(timers);
|
||||
|
||||
c->Message(Chat::White, "Timers for target:");
|
||||
std::string popup_title = fmt::format(
|
||||
"Recast Timers for {}",
|
||||
c == target ?
|
||||
"Yourself" :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
)
|
||||
);
|
||||
|
||||
int r;
|
||||
int l = res.size();
|
||||
for (r = 0; r < l; r++) {
|
||||
c->Message(Chat::White, "Timer %d: %d seconds remain.", res[r].first, res[r].second->GetRemainingTime());
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += "<tr><td>Timer ID</td><td>Remaining</td></tr>";
|
||||
|
||||
for (const auto& timer : timers) {
|
||||
auto remaining_time = timer.second->GetRemainingTime();
|
||||
if (remaining_time) {
|
||||
popup_text += fmt::format(
|
||||
"<tr><td>{}</td><td>{}</td></tr>",
|
||||
timer.first,
|
||||
ConvertSecondsToTime(remaining_time)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
c->SendPopupToClient(
|
||||
popup_title.c_str(),
|
||||
popup_text.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,23 @@
|
||||
|
||||
void command_undye(Client *c, const Seperator *sep)
|
||||
{
|
||||
auto target = c;
|
||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||
c->GetTarget()->CastToClient()->Undye();
|
||||
target = c->GetTarget()->CastToClient();
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "ERROR: Client target required");
|
||||
}
|
||||
}
|
||||
|
||||
target->Undye();
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Undyed armor for {}.",
|
||||
c == target ?
|
||||
"yourself" :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
target->GetCleanName(),
|
||||
target->GetID()
|
||||
)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
void command_undyeme(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c) {
|
||||
c->Undye();
|
||||
c->Message(Chat::Red, "Dye removed from all slots. Please zone for the process to complete.");
|
||||
}
|
||||
c->Undye();
|
||||
c->Message(Chat::White, "Undyed armor for yourself.");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
|
||||
void command_version(Client *c, const Seperator *sep)
|
||||
{
|
||||
c->Message(Chat::White, "Current version information.");
|
||||
c->Message(Chat::White, " %s", CURRENT_VERSION);
|
||||
c->Message(Chat::White, " Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME);
|
||||
c->Message(Chat::White, " Last modified on: %s", LAST_MODIFIED);
|
||||
std::string popup_text = "<table>";
|
||||
|
||||
popup_text += fmt::format("<tr><td>Version</td><td>{}</td></tr>", CURRENT_VERSION);
|
||||
popup_text += fmt::format("<tr><td>Compiled</td><td>{} {}</td></tr>", COMPILE_DATE, COMPILE_TIME);
|
||||
popup_text += fmt::format("<tr><td>Last Modified</td><td>{}</td></tr>", LAST_MODIFIED);
|
||||
|
||||
popup_text += "</table>";
|
||||
|
||||
c->SendPopupToClient(
|
||||
"Server Version Information",
|
||||
popup_text.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+46
-8
@@ -645,15 +645,53 @@ bool HateList::IsHateListEmpty() {
|
||||
|
||||
void HateList::PrintHateListToClient(Client *c)
|
||||
{
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
struct_HateList *e = (*iterator);
|
||||
c->Message(Chat::White, "- name: %s, damage: %d, hate: %d",
|
||||
(e->entity_on_hatelist && e->entity_on_hatelist->GetName()) ? e->entity_on_hatelist->GetName() : "(null)",
|
||||
e->hatelist_damage, e->stored_hate_amount);
|
||||
if (list.size()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Displaying hate list for {} ({}).",
|
||||
hate_owner->GetCleanName(),
|
||||
hate_owner->GetID()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
++iterator;
|
||||
auto entity_number = 1;
|
||||
for (const auto& hate_entity : list) {
|
||||
if (hate_entity->entity_on_hatelist) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Hate Entity {} | Name: {} ({}) Damage: {} Hate: {}",
|
||||
entity_number,
|
||||
hate_entity->entity_on_hatelist->GetName(),
|
||||
hate_entity->entity_on_hatelist->GetID(),
|
||||
hate_entity->hatelist_damage,
|
||||
hate_entity->stored_hate_amount
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Hate Entity {} | Damage: {} Hate: {}",
|
||||
entity_number,
|
||||
hate_entity->hatelist_damage,
|
||||
hate_entity->stored_hate_amount
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
entity_number++;
|
||||
}
|
||||
} else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) has nothing on its hatelist.",
|
||||
hate_owner->GetCleanName(),
|
||||
hate_owner->GetID()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3367,6 +3367,14 @@ std::string lua_get_body_type_name(uint32 bodytype_id) {
|
||||
return quest_manager.getbodytypename(bodytype_id);
|
||||
}
|
||||
|
||||
std::string lua_get_consider_level_name(uint8 consider_level) {
|
||||
return quest_manager.getconsiderlevelname(consider_level);
|
||||
}
|
||||
|
||||
std::string lua_get_environmental_damage_name(uint8 damage_type) {
|
||||
return quest_manager.getenvironmentaldamagename(damage_type);
|
||||
}
|
||||
|
||||
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
||||
cur = table[#name]; \
|
||||
if(luabind::type(cur) != LUA_TNIL) { \
|
||||
@@ -3814,6 +3822,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("get_faction_name", &lua_get_faction_name),
|
||||
luabind::def("get_language_name", &lua_get_language_name),
|
||||
luabind::def("get_body_type_name", &lua_get_body_type_name),
|
||||
luabind::def("get_consider_level_name", &lua_get_consider_level_name),
|
||||
luabind::def("get_environmental_damage_name", &lua_get_environmental_damage_name),
|
||||
|
||||
/*
|
||||
Cross Zone
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@ public:
|
||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQ::spells::CastingSlot slot, uint16 mana_used,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||
bool SpellFinished(uint16 spell_id, Mob *target, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, uint16 mana_used = 0,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, bool from_casted_spell = false, uint32 aa_id = 0);
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, bool from_casted_spell = false, uint32 aa_id = 0);
|
||||
void SendBeginCast(uint16 spell_id, uint32 casttime);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0,
|
||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0);
|
||||
|
||||
@@ -1052,6 +1052,10 @@ std::string QuestManager::getbodytypename(uint32 bodytype_id) {
|
||||
return EQ::constants::GetBodyTypeName(static_cast<bodyType>(bodytype_id));
|
||||
}
|
||||
|
||||
std::string QuestManager::getconsiderlevelname(uint8 consider_level) {
|
||||
return EQ::constants::GetConsiderLevelName(consider_level);
|
||||
}
|
||||
|
||||
void QuestManager::safemove() {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (initiator && initiator->IsClient())
|
||||
@@ -3698,3 +3702,8 @@ const SPDat_Spell_Struct* QuestManager::getspell(uint32 spell_id) {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string QuestManager::getenvironmentaldamagename(uint8 damage_type) {
|
||||
std::string environmental_damage_name = EQ::constants::GetEnvironmentalDamageName(damage_type);
|
||||
return environmental_damage_name;
|
||||
}
|
||||
|
||||
+3
-1
@@ -119,6 +119,7 @@ public:
|
||||
std::string getfactionname(int faction_id);
|
||||
std::string getlanguagename(int language_id);
|
||||
std::string getbodytypename(uint32 bodytype_id);
|
||||
std::string getconsiderlevelname(uint8 consider_level);
|
||||
void safemove();
|
||||
void rain(int weather);
|
||||
void snow(int weather);
|
||||
@@ -330,7 +331,8 @@ public:
|
||||
std::string getinventoryslotname(int16 slot_id);
|
||||
int getitemstat(uint32 item_id, std::string stat_identifier);
|
||||
int getspellstat(uint32 spell_id, std::string stat_identifier, uint8 slot = 0);
|
||||
const SPDat_Spell_Struct *getspell(uint32 spell_id);
|
||||
const SPDat_Spell_Struct *getspell(uint32 spell_id);
|
||||
std::string getenvironmentaldamagename(uint8 damage_type);
|
||||
|
||||
Client *GetInitiator() const;
|
||||
NPC *GetNPC() const;
|
||||
|
||||
@@ -8248,7 +8248,7 @@ void Mob::SendCastRestrictionMessage(int requirement_id, bool target_requirement
|
||||
|
||||
*/
|
||||
|
||||
std::string msg = "";
|
||||
const char *msg = "";
|
||||
|
||||
if (target_requirement) {
|
||||
msg = "Your target does not meet the spell requirements. ";
|
||||
|
||||
+87
-104
@@ -209,6 +209,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
if (item_slot && IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt))
|
||||
{
|
||||
if (!CheckItemRaceClassDietyRestrictionsOnCast(item_slot)) {
|
||||
StopCastSpell(spell_id, send_spellbar_enable);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -696,23 +697,30 @@ bool Mob::DoCastingChecksOnTarget(bool check_on_casting, int32 spell_id, Mob *sp
|
||||
Always check again on SpellOnTarget to account for AE checks.
|
||||
*/
|
||||
|
||||
|
||||
bool ignore_on_casting = false;
|
||||
bool ignore_if_npc_or_gm = false;
|
||||
if (!IsClient() || (IsClient() && CastToClient()->GetGM())) {
|
||||
ignore_if_npc_or_gm = true;
|
||||
}
|
||||
|
||||
if (check_on_casting && !spell_target){
|
||||
if (check_on_casting){
|
||||
|
||||
if (IsGroupSpell(spell_id) ||
|
||||
spells[spell_id].target_type == ST_AEClientV1 ||
|
||||
spells[spell_id].target_type == ST_AECaster ||
|
||||
spells[spell_id].target_type == ST_Ring ||
|
||||
spells[spell_id].target_type == ST_Beam){
|
||||
return true;
|
||||
if (!spell_target) {
|
||||
if (IsGroupSpell(spell_id) ||
|
||||
spells[spell_id].target_type == ST_AEClientV1 ||
|
||||
spells[spell_id].target_type == ST_AECaster ||
|
||||
spells[spell_id].target_type == ST_Ring ||
|
||||
spells[spell_id].target_type == ST_Beam) {
|
||||
return true;
|
||||
}
|
||||
else if (spells[spell_id].target_type == ST_Self) {
|
||||
spell_target = this;
|
||||
}
|
||||
}
|
||||
else if (spells[spell_id].target_type == ST_Self) {
|
||||
spell_target = this;
|
||||
else {
|
||||
if (IsGroupSpell(spell_id) && spell_target != this) {
|
||||
ignore_on_casting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,13 +780,20 @@ bool Mob::DoCastingChecksOnTarget(bool check_on_casting, int32 spell_id, Mob *sp
|
||||
Prevents buff from being cast based on tareget ing PC OR NPC (1 = PCs, 2 = NPCs)
|
||||
These target types skip pcnpc only check (according to dev quotes)
|
||||
*/
|
||||
if (spells[spell_id].pcnpc_only_flag && spells[spell_id].target_type != ST_AETargetHateList &&
|
||||
spells[spell_id].target_type != ST_HateList) {
|
||||
if (spells[spell_id].pcnpc_only_flag == 1 && !spell_target->IsClient() && !spell_target->IsMerc() && !spell_target->IsBot()) {
|
||||
return false;
|
||||
}
|
||||
else if (spells[spell_id].pcnpc_only_flag == 2 && (spell_target->IsClient() || spell_target->IsMerc() || spell_target->IsBot())) {
|
||||
return false;
|
||||
if (!ignore_on_casting) {
|
||||
if (spells[spell_id].pcnpc_only_flag && spells[spell_id].target_type != ST_AETargetHateList && spells[spell_id].target_type != ST_HateList) {
|
||||
if (spells[spell_id].pcnpc_only_flag == 1 && !spell_target->IsClient() && !spell_target->IsMerc() && !spell_target->IsBot()) {
|
||||
if (check_on_casting) {
|
||||
Message(Chat::SpellFailure, "This spell only works on other PCs");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (spells[spell_id].pcnpc_only_flag == 2 && (spell_target->IsClient() || spell_target->IsMerc() || spell_target->IsBot())) {
|
||||
if (check_on_casting) {
|
||||
Message(Chat::SpellFailure, "This spell only works on NPCs.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -1271,7 +1286,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
item = CastToClient()->GetInv().GetItem(inventory_slot); //checked for in reagents and charges.
|
||||
if (CastToClient()->HasItemRecastTimer(spell_id, inventory_slot)) {
|
||||
MessageString(Chat::Red, SPELL_RECAST);
|
||||
LogSpells("Casting of [{}] canceled: item spell reuse timer not expired", spell_id);
|
||||
LogSpells("Casting of [{}] canceled: item or augment spell reuse timer not expired", spell_id);
|
||||
StopCasting();
|
||||
return;
|
||||
}
|
||||
@@ -1586,7 +1601,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
}
|
||||
|
||||
// we're done casting, now try to apply the spell
|
||||
if(!SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust, false,-1, true))
|
||||
if(!SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust, false,-1, 0xFFFFFFFF, 0, true))
|
||||
{
|
||||
LogSpells("Casting of [{}] canceled: SpellFinished returned false", spell_id);
|
||||
// most of the cases we return false have a message already or are logic errors that shouldn't happen
|
||||
@@ -2206,7 +2221,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
// if you need to abort the casting, return false
|
||||
bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, uint16 mana_used,
|
||||
uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override,
|
||||
bool from_casted_spell, uint32 aa_id)
|
||||
uint32 timer, uint32 timer_duration, bool from_casted_spell, uint32 aa_id)
|
||||
{
|
||||
Mob *ae_center = nullptr;
|
||||
|
||||
@@ -2580,54 +2595,43 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
|
||||
if (mgb) {
|
||||
SetMGB(false);
|
||||
}
|
||||
|
||||
//all spell triggers use Item slot, but don't have an item associated. We don't need to check recast timers on these.
|
||||
bool is_triggered_spell = false;
|
||||
if (slot == CastingSlot::Item && inventory_slot == 0xFFFFFFFF) {
|
||||
is_triggered_spell = true;
|
||||
}
|
||||
|
||||
if (IsClient() && !isproc && !is_triggered_spell)
|
||||
/*
|
||||
Set Recast Timer on spells.
|
||||
*/
|
||||
if(IsClient() && !isproc)
|
||||
{
|
||||
//Set Item or Augment Click Recast Timer
|
||||
if (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt) {
|
||||
CastToClient()->SetItemRecastTimer(spell_id, inventory_slot);
|
||||
}
|
||||
//Set Discipline Recast Timer
|
||||
else if (slot == CastingSlot::Discipline) {
|
||||
if (spell_id == casting_spell_id || (GetClass() == BARD && spells[spell_id].cast_time == 0 && spell_id != casting_spell_id)) {
|
||||
CastToClient()->SetDisciplineRecastTimer(spell_id);
|
||||
if (slot == CastingSlot::AltAbility) {
|
||||
if (!aa_id) {
|
||||
aa_id = casting_spell_aa_id;
|
||||
}
|
||||
if (aa_id) {
|
||||
AA::Rank *rank = zone->GetAlternateAdvancementRank(aa_id);
|
||||
//handle expendable AA's
|
||||
if (rank && rank->base_ability) {
|
||||
ExpendAlternateAdvancementCharge(rank->base_ability->id);
|
||||
}
|
||||
//set AA recast timer
|
||||
CastToClient()->SendAlternateAdvancementTimer(rank->spell_type, 0, 0);
|
||||
}
|
||||
}
|
||||
//Set AA Recast Timer.
|
||||
else if (slot == CastingSlot::AltAbility){
|
||||
uint32 active_aa_id = 0;
|
||||
//aa_id is only passed directly into spellfinished when a bard is using AA while casting, this supports casting an AA while clicking an instant AA.
|
||||
if (GetClass() == BARD && spells[spell_id].cast_time == 0 && aa_id) {
|
||||
active_aa_id = aa_id;
|
||||
}
|
||||
else {
|
||||
active_aa_id = casting_spell_aa_id;
|
||||
}
|
||||
|
||||
AA::Rank *rank = zone->GetAlternateAdvancementRank(active_aa_id);
|
||||
|
||||
CastToClient()->SetAARecastTimer(rank, spell_id);
|
||||
|
||||
if (rank && rank->base_ability) {
|
||||
ExpendAlternateAdvancementCharge(rank->base_ability->id);
|
||||
}
|
||||
//handle bard AA and Discipline recast timers when singing
|
||||
if (GetClass() == BARD && spell_id != casting_spell_id && timer != 0xFFFFFFFF) {
|
||||
CastToClient()->GetPTimers().Start(timer, timer_duration);
|
||||
LogSpells("Spell [{}]: Setting BARD custom reuse timer [{}] to [{}]", spell_id, casting_spell_timer, casting_spell_timer_duration);
|
||||
}
|
||||
//Set Custom Recast Timer
|
||||
//handles AA and Discipline recast timers
|
||||
else if (spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF)
|
||||
{
|
||||
//aa new todo: aa expendable charges here
|
||||
CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration);
|
||||
LogSpells("Spell [{}]: Setting custom reuse timer [{}] to [{}]", spell_id, casting_spell_timer, casting_spell_timer_duration);
|
||||
}
|
||||
//Set Spell Recast Timer
|
||||
else if (spells[spell_id].recast_time > 1000 && !spells[spell_id].is_discipline) {
|
||||
int recast = spells[spell_id].recast_time / 1000;
|
||||
else if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF)
|
||||
{
|
||||
CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration);
|
||||
LogSpells("Spell [{}]: Setting custom reuse timer [{}] to [{}]", spell_id, casting_spell_timer, casting_spell_timer_duration);
|
||||
}
|
||||
else if(spells[spell_id].recast_time > 1000 && !spells[spell_id].is_discipline) {
|
||||
int recast = spells[spell_id].recast_time/1000;
|
||||
if (spell_id == SPELL_LAY_ON_HANDS) //lay on hands
|
||||
{
|
||||
recast -= GetAA(aaFervrentBlessing) * 420;
|
||||
@@ -2647,14 +2651,20 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
|
||||
}
|
||||
recast = std::max(recast, 0);
|
||||
}
|
||||
|
||||
|
||||
LogSpells("Spell [{}]: Setting long reuse timer to [{}] s (orig [{}])", spell_id, recast, spells[spell_id].recast_time);
|
||||
|
||||
|
||||
if (recast > 0) {
|
||||
CastToClient()->GetPTimers().Start(pTimerSpellStart + spell_id, recast);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Set Recast Timer on item clicks, including augmenets.
|
||||
*/
|
||||
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)){
|
||||
CastToClient()->SetItemRecastTimer(spell_id, inventory_slot);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
CastToNPC()->AI_Event_SpellCastFinished(true, static_cast<uint16>(slot));
|
||||
@@ -2715,8 +2725,6 @@ bool Mob::ApplyBardPulse(int32 spell_id, Mob *spell_target, CastingSlot slot) {
|
||||
if (!SpellFinished(spell_id, spell_target, slot, spells[spell_id].mana, 0xFFFFFFFF, spells[spell_id].resist_difficulty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -3479,10 +3487,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EQApplicationPacket *action_packet = nullptr, *message_packet = nullptr;
|
||||
float spell_effectiveness;
|
||||
|
||||
@@ -3576,6 +3580,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
|
||||
|
||||
mod_spell_cast(spell_id, spelltar, reflect_effectiveness, use_resist_adjust, resist_adjust, isproc);
|
||||
|
||||
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
// now check if the spell is allowed to land
|
||||
if (RuleB(Spells, EnableBlockedBuffs)) {
|
||||
// We return true here since the caster's client should act like normal
|
||||
@@ -6193,13 +6202,19 @@ bool Client::HasItemRecastTimer(int32 spell_id, uint32 inventory_slot)
|
||||
}
|
||||
|
||||
if (aug->Click.Effect == spell_id) {
|
||||
recast_delay = aug_i->GetItem()->RecastDelay;
|
||||
recast_type = aug_i->GetItem()->RecastType;
|
||||
if (aug_i->GetItem() && aug_i->GetItem()->RecastDelay > 0) {
|
||||
recast_delay = aug_i->GetItem()->RecastDelay;
|
||||
recast_type = aug_i->GetItem()->RecastType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//do not check if item has no recast delay.
|
||||
if (!recast_delay) {
|
||||
return false;
|
||||
}
|
||||
//if time is not expired, then it exists and therefore we have a recast on this item.
|
||||
if (!CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recast_type), false)) {
|
||||
return true;
|
||||
}
|
||||
@@ -6207,40 +6222,6 @@ bool Client::HasItemRecastTimer(int32 spell_id, uint32 inventory_slot)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::SetDisciplineRecastTimer(int32 spell_id) {
|
||||
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spells[spell_id].recast_time == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].timer_id;
|
||||
uint32 timer_duration = spells[spell_id].recast_time / 1000;
|
||||
auto focus = GetFocusEffect(focusReduceRecastTime, spell_id);
|
||||
|
||||
if (focus > timer_duration) {
|
||||
timer_duration = 0;
|
||||
if (GetPTimers().Enabled((uint32)DiscTimer)) {
|
||||
GetPTimers().Clear(&database, (uint32)DiscTimer);
|
||||
}
|
||||
else {
|
||||
timer_duration -= focus;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer_duration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
CastToClient()->GetPTimers().Start((uint32)DiscTimer, timer_duration);
|
||||
CastToClient()->SendDisciplineTimer(spells[spell_id].timer_id, timer_duration);
|
||||
LogSpells("Spell [{}]: Setting disciple reuse timer [{}] to [{}]", spell_id, spells[spell_id].timer_id, timer_duration);
|
||||
}
|
||||
|
||||
|
||||
void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ)
|
||||
{
|
||||
if (!distance) { return; }
|
||||
@@ -6668,4 +6649,6 @@ bool Mob::CheckItemRaceClassDietyRestrictionsOnCast(uint32 inventory_slot) {
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -469,6 +469,7 @@
|
||||
#define LEADER_OF_X_GUILD 12258
|
||||
#define NOT_IN_A_GUILD 12259
|
||||
#define TARGET_PLAYER_FOR_GUILD_STATUS 12260
|
||||
#define TARGET_ALREADY_IN_GROUP 12265 //% 1 is already in another group.
|
||||
#define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite <name> to invite someone to your group.
|
||||
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
|
||||
#define ALREADY_IN_PARTY 12272 //That person is already in your party.
|
||||
|
||||
Reference in New Issue
Block a user