mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-14 20:12:26 +00:00
Merge remote-tracking branch 'origin/master' into build
This commit is contained in:
commit
0e9fae3181
@ -492,6 +492,7 @@ RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random speci
|
|||||||
RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system")
|
RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system")
|
||||||
RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind")
|
RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind")
|
||||||
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager")
|
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager")
|
||||||
|
RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(NPC)
|
RULE_CATEGORY(NPC)
|
||||||
@ -595,6 +596,8 @@ RULE_INT(Bots, CasterStopMeleeLevel, 13, "Level at which caster bots stop melee
|
|||||||
RULE_INT(Bots, AllowedClasses, 0xFFFFFFFF, "Bitmask of allowed bot classes")
|
RULE_INT(Bots, AllowedClasses, 0xFFFFFFFF, "Bitmask of allowed bot classes")
|
||||||
RULE_INT(Bots, AllowedRaces, 0xFFFFFFFF, "Bitmask of allowed bot races")
|
RULE_INT(Bots, AllowedRaces, 0xFFFFFFFF, "Bitmask of allowed bot races")
|
||||||
RULE_INT(Bots, AllowedGenders, 0x3, "Bitmask of allowed bot genders")
|
RULE_INT(Bots, AllowedGenders, 0x3, "Bitmask of allowed bot genders")
|
||||||
|
RULE_BOOL(Bots, AllowOwnerAutoDefend, false, "When active, bots will defend their owner on enemy aggro")
|
||||||
|
RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel from leash owner before being pulled back (squared value)")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
#include "skills.h"
|
#include "skills.h"
|
||||||
|
|
||||||
#define SPELL_UNKNOWN 0xFFFF
|
#define SPELL_UNKNOWN 0xFFFF
|
||||||
|
#define POISON_PROC 0xFFFE
|
||||||
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
||||||
|
|
||||||
//some spell IDs which will prolly change, but are needed
|
//some spell IDs which will prolly change, but are needed
|
||||||
|
|||||||
@ -744,6 +744,46 @@ sub do_install_config_json {
|
|||||||
unlink("eqemu_config_template.json");
|
unlink("eqemu_config_template.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub do_install_config_login_json {
|
||||||
|
get_installation_variables();
|
||||||
|
|
||||||
|
#::: Fetch json template
|
||||||
|
get_remote_file($eqemu_repository_request_url . "loginserver/login_util/login.json", "login_template.json");
|
||||||
|
|
||||||
|
use JSON;
|
||||||
|
my $json = new JSON();
|
||||||
|
|
||||||
|
my $content;
|
||||||
|
open(my $fh, '<', "login_template.json") or die "cannot open file $filename"; {
|
||||||
|
local $/;
|
||||||
|
$content = <$fh>;
|
||||||
|
}
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
$config = $json->decode($content);
|
||||||
|
|
||||||
|
if ($installation_variables{"mysql_eqemu_db_name"}) {
|
||||||
|
$db_name = $installation_variables{"mysql_eqemu_db_name"};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$db_name = "peq";
|
||||||
|
}
|
||||||
|
|
||||||
|
$config->{"database"}{"host"} = "127.0.0.1";
|
||||||
|
$config->{"database"}{"user"} = $installation_variables{"mysql_eqemu_user"};
|
||||||
|
$config->{"database"}{"password"} = $installation_variables{"mysql_eqemu_password"};
|
||||||
|
$config->{"database"}{"db"} = $db_name;
|
||||||
|
|
||||||
|
$json->canonical(1);
|
||||||
|
$json->indent_length(5);
|
||||||
|
|
||||||
|
open(my $fh, '>', 'login.json');
|
||||||
|
print $fh $json->pretty->indent_length(5)->utf8->encode($config);
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
unlink("login_template.json");
|
||||||
|
}
|
||||||
|
|
||||||
sub fetch_utility_scripts {
|
sub fetch_utility_scripts {
|
||||||
if ($OS eq "Windows") {
|
if ($OS eq "Windows") {
|
||||||
get_remote_file($install_repository_request_url . "t_database_backup.bat", "t_database_backup.bat");
|
get_remote_file($install_repository_request_url . "t_database_backup.bat", "t_database_backup.bat");
|
||||||
@ -1494,6 +1534,10 @@ sub do_windows_login_server_setup {
|
|||||||
print get_mysql_result_from_file("db_update/login_schema.sql");
|
print get_mysql_result_from_file("db_update/login_schema.sql");
|
||||||
print "[Install] Done...\n";
|
print "[Install] Done...\n";
|
||||||
|
|
||||||
|
print "[Install] Pulling and initializing Loginserver configuration files...\n";
|
||||||
|
do_install_config_login_json();
|
||||||
|
print "[Install] Done...\n";
|
||||||
|
|
||||||
add_login_server_firewall_rules();
|
add_login_server_firewall_rules();
|
||||||
|
|
||||||
rmtree('updates_staged');
|
rmtree('updates_staged');
|
||||||
@ -1523,40 +1567,18 @@ sub do_linux_login_server_setup {
|
|||||||
print get_mysql_result_from_file("db_update/login_schema.sql");
|
print get_mysql_result_from_file("db_update/login_schema.sql");
|
||||||
print "[Install] Done...\n\n";
|
print "[Install] Done...\n\n";
|
||||||
|
|
||||||
|
print "[Install] Pulling and initializing Loginserver configuration files...\n";
|
||||||
|
do_install_config_login_json();
|
||||||
|
print "[Install] Done...\n";
|
||||||
|
|
||||||
rmtree('updates_staged');
|
rmtree('updates_staged');
|
||||||
rmtree('db_update');
|
rmtree('db_update');
|
||||||
|
|
||||||
get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini");
|
|
||||||
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
|
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
|
||||||
get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf");
|
get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf");
|
||||||
get_remote_file($install_repository_request_url . "linux/server_start_with_login.sh", "server_start_with_login.sh");
|
get_remote_file($install_repository_request_url . "linux/server_start_with_login.sh", "server_start_with_login.sh");
|
||||||
system("chmod 755 *.sh");
|
system("chmod 755 *.sh");
|
||||||
|
|
||||||
get_installation_variables();
|
|
||||||
my $db_name = $installation_variables{"mysql_eqemu_db_name"};
|
|
||||||
my $db_user = $installation_variables{"mysql_eqemu_user"};
|
|
||||||
my $db_password = $installation_variables{"mysql_eqemu_password"};
|
|
||||||
|
|
||||||
#::: Open new config file
|
|
||||||
open(NEW_CONFIG, '>', 'login.ini');
|
|
||||||
|
|
||||||
#::: Iterate through template and replace variables...
|
|
||||||
open(FILE_TEMPLATE, "login_template.ini");
|
|
||||||
while (<FILE_TEMPLATE>) {
|
|
||||||
chomp;
|
|
||||||
$o = $_;
|
|
||||||
#::: Find replace variables
|
|
||||||
if ($o =~ /db/i) { $o = "db = " . $db_name; }
|
|
||||||
if ($o =~ /user/i) { $o = "user = " . $db_user; }
|
|
||||||
if ($o =~ /password/i) { $o = "password = " . $db_password; }
|
|
||||||
|
|
||||||
print NEW_CONFIG $o . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
close(FILE_TEMPLATE);
|
|
||||||
close(NEW_CONFIG);
|
|
||||||
unlink("login_template.ini");
|
|
||||||
|
|
||||||
print "[Install] Press any key to continue...\n";
|
print "[Install] Press any key to continue...\n";
|
||||||
|
|
||||||
<>; #Read from STDIN
|
<>; #Read from STDIN
|
||||||
|
|||||||
@ -2692,18 +2692,22 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
// if other is a bot, add the bots client to the hate list
|
// if other is a bot, add the bots client to the hate list
|
||||||
while (other->IsBot()) {
|
while (other->IsBot()) {
|
||||||
|
|
||||||
auto other_ = other->CastToBot();
|
auto other_ = other->CastToBot();
|
||||||
if (!other_ || !other_->GetBotOwner())
|
if (!other_ || !other_->GetBotOwner()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto owner_ = other_->GetBotOwner()->CastToClient();
|
auto owner_ = other_->GetBotOwner()->CastToClient();
|
||||||
if (!owner_ || owner_->IsDead() || !owner_->InZone()) // added isdead and inzone checks to avoid issues in AddAutoXTarget(...) below
|
if (!owner_ || owner_->IsDead() || !owner_->InZone()) { // added isdead and inzone checks to avoid issues in AddAutoXTarget(...) below
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (owner_->GetFeigned()) {
|
if (owner_->GetFeigned()) {
|
||||||
AddFeignMemory(owner_);
|
AddFeignMemory(owner_);
|
||||||
}
|
}
|
||||||
else if (!hate_list.IsEntOnHateList(owner_)) {
|
else if (!hate_list.IsEntOnHateList(owner_)) {
|
||||||
|
|
||||||
hate_list.AddEntToHateList(owner_, 0, 0, false, true);
|
hate_list.AddEntToHateList(owner_, 0, 0, false, true);
|
||||||
owner_->AddAutoXTarget(this); // this was being called on dead/out-of-zone clients
|
owner_->AddAutoXTarget(this); // this was being called on dead/out-of-zone clients
|
||||||
}
|
}
|
||||||
@ -4064,11 +4068,16 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
|||||||
if (!weapon && hand == EQEmu::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
|
if (!weapon && hand == EQEmu::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||||
rangedattk = true;
|
rangedattk = true;
|
||||||
|
|
||||||
|
int16 poison_slot=-1;
|
||||||
|
|
||||||
for (uint32 i = 0; i < MAX_PROCS; i++) {
|
for (uint32 i = 0; i < MAX_PROCS; i++) {
|
||||||
if (IsPet() && hand != EQEmu::invslot::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
if (IsPet() && hand != EQEmu::invslot::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
||||||
continue; // If pets ever can proc from off hand, this will need to change
|
continue; // If pets ever can proc from off hand, this will need to change
|
||||||
|
|
||||||
// Not ranged
|
if (!weapon || (SpellProcs[i].base_spellID == POISON_PROC && weapon->ItemType != EQEmu::item::ItemType1HPiercing))
|
||||||
|
continue; // Old school poison will only proc with 1HP equipped.
|
||||||
|
|
||||||
|
// Not ranged
|
||||||
if (!rangedattk) {
|
if (!rangedattk) {
|
||||||
// Perma procs (AAs)
|
// Perma procs (AAs)
|
||||||
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
|
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
|
||||||
@ -4083,6 +4092,11 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
|||||||
|
|
||||||
// Spell procs (buffs)
|
// Spell procs (buffs)
|
||||||
if (SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
if (SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
||||||
|
if (SpellProcs[i].base_spellID == POISON_PROC) {
|
||||||
|
poison_slot=i;
|
||||||
|
continue; // Process the poison proc last per @mackal
|
||||||
|
}
|
||||||
|
|
||||||
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
|
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance)) {
|
if (zone->random.Roll(chance)) {
|
||||||
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
|
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
|
||||||
@ -4113,6 +4127,21 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (poison_slot > -1) {
|
||||||
|
bool one_shot = !RuleB(Combat, UseExtendedPoisonProcs);
|
||||||
|
float chance = (one_shot) ? 100.0f : ProcChance * (static_cast<float>(SpellProcs[poison_slot].chance) / 100.0f);
|
||||||
|
uint16 spell_id = SpellProcs[poison_slot].spellID;
|
||||||
|
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
|
LogCombat("Poison proc [{}] procing spell [{}] ([{}] percent chance)", poison_slot, spell_id, chance);
|
||||||
|
SendBeginCast(spell_id, 0);
|
||||||
|
ExecWeaponProc(nullptr, spell_id, on, SpellProcs[poison_slot].level_override);
|
||||||
|
if (one_shot) {
|
||||||
|
RemoveProcFromWeapon(spell_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (HasSkillProcs() && hand != EQEmu::invslot::slotRange) { //We check ranged skill procs within the attack functions.
|
if (HasSkillProcs() && hand != EQEmu::invslot::slotRange) { //We check ranged skill procs within the attack functions.
|
||||||
uint16 skillinuse = 28;
|
uint16 skillinuse = 28;
|
||||||
if (weapon)
|
if (weapon)
|
||||||
|
|||||||
1400
zone/bot.cpp
1400
zone/bot.cpp
File diff suppressed because it is too large
Load Diff
57
zone/bot.h
57
zone/bot.h
@ -37,21 +37,22 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#define BOT_FOLLOW_DISTANCE_DEFAULT 184 // as DSq value (~13.565 units)
|
constexpr float BOT_FOLLOW_DISTANCE_DEFAULT = 184.0f; // as DSq value (~13.565 units)
|
||||||
#define BOT_FOLLOW_DISTANCE_DEFAULT_MAX 2500 // as DSq value (50 units)
|
constexpr float BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500.0f; // as DSq value (50 units)
|
||||||
#define BOT_FOLLOW_DISTANCE_WALK 1000 // as DSq value (~31.623 units)
|
constexpr float BOT_FOLLOW_DISTANCE_WALK = 1000.0f; // as DSq value (~31.623 units)
|
||||||
|
|
||||||
#define BOT_LEASH_DISTANCE 250000 // as DSq value (500 units)
|
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
|
||||||
|
|
||||||
#define BOT_KEEP_ALIVE_INTERVAL 5000 // 5 seconds
|
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MIN = 5000; // 5 seconds
|
||||||
|
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MAX = 20000; // 20 seconds
|
||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
const int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
||||||
const int MaxSpellTimer = 15;
|
constexpr int MaxSpellTimer = 15;
|
||||||
const int MaxDisciplineTimer = 10;
|
constexpr int MaxDisciplineTimer = 10;
|
||||||
const int DisciplineReuseStart = MaxSpellTimer + 1;
|
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||||
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -260,10 +261,24 @@ public:
|
|||||||
void Stand();
|
void Stand();
|
||||||
bool IsSitting();
|
bool IsSitting();
|
||||||
bool IsStanding();
|
bool IsStanding();
|
||||||
virtual int GetWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.785714f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
virtual int GetWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.785714285f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
||||||
virtual int GetRunspeed() const { return (int)((float)_GetRunSpeed() * 1.785714f); }
|
virtual int GetRunspeed() const { return (int)((float)_GetRunSpeed() * 1.785714285f); }
|
||||||
virtual void WalkTo(float x, float y, float z);
|
virtual void WalkTo(float x, float y, float z);
|
||||||
virtual void RunTo(float x, float y, float z);
|
virtual void RunTo(float x, float y, float z);
|
||||||
|
virtual void StopMoving();
|
||||||
|
virtual void StopMoving(float new_heading);
|
||||||
|
//bool GetCombatJitterFlag() { return m_combat_jitter_flag; }
|
||||||
|
bool GetGuardFlag() { return m_guard_flag; }
|
||||||
|
void SetGuardFlag(bool flag = true) { m_guard_flag = flag; }
|
||||||
|
bool GetHoldFlag() { return m_hold_flag; }
|
||||||
|
void SetHoldFlag(bool flag = true) { m_hold_flag = flag; }
|
||||||
|
bool GetAttackFlag() { return m_attack_flag; }
|
||||||
|
void SetAttackFlag(bool flag = true) { m_attack_flag = flag; }
|
||||||
|
bool GetAttackingFlag() { return m_attacking_flag; }
|
||||||
|
bool GetPullFlag() { return m_pull_flag; }
|
||||||
|
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
||||||
|
bool GetPullingFlag() { return m_pulling_flag; }
|
||||||
|
bool GetReturningFlag() { return m_returning_flag; }
|
||||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
||||||
bool GetNeedsCured(Mob *tar);
|
bool GetNeedsCured(Mob *tar);
|
||||||
@ -338,6 +353,7 @@ public:
|
|||||||
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
|
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
|
||||||
void SetStopMeleeLevel(uint8 level);
|
void SetStopMeleeLevel(uint8 level);
|
||||||
void SetGuardMode();
|
void SetGuardMode();
|
||||||
|
void SetHoldMode();
|
||||||
|
|
||||||
// Mob AI Virtual Override Methods
|
// Mob AI Virtual Override Methods
|
||||||
virtual void AI_Process();
|
virtual void AI_Process();
|
||||||
@ -674,7 +690,18 @@ private:
|
|||||||
int32 end_regen;
|
int32 end_regen;
|
||||||
uint32 timers[MaxTimer];
|
uint32 timers[MaxTimer];
|
||||||
|
|
||||||
Timer evade_timer; // can be moved to pTimers at some point
|
Timer m_evade_timer; // can be moved to pTimers at some point
|
||||||
|
Timer m_alt_combat_hate_timer;
|
||||||
|
//Timer m_combat_jitter_timer;
|
||||||
|
//bool m_combat_jitter_flag;
|
||||||
|
bool m_guard_flag;
|
||||||
|
bool m_hold_flag;
|
||||||
|
bool m_attack_flag;
|
||||||
|
bool m_attacking_flag;
|
||||||
|
bool m_pull_flag;
|
||||||
|
bool m_pulling_flag;
|
||||||
|
bool m_returning_flag;
|
||||||
|
eStandingPetOrder m_previous_pet_order;
|
||||||
|
|
||||||
BotCastingRoles m_CastingRoles;
|
BotCastingRoles m_CastingRoles;
|
||||||
|
|
||||||
@ -716,6 +743,10 @@ private:
|
|||||||
int32 GenerateBaseManaPoints();
|
int32 GenerateBaseManaPoints();
|
||||||
void GenerateSpecialAttacks();
|
void GenerateSpecialAttacks();
|
||||||
void SetBotID(uint32 botID);
|
void SetBotID(uint32 botID);
|
||||||
|
//void SetCombatJitterFlag(bool flag = true) { m_combat_jitter_flag = flag; }
|
||||||
|
void SetAttackingFlag(bool flag = true) { m_attacking_flag = flag; }
|
||||||
|
void SetPullingFlag(bool flag = true) { m_pulling_flag = flag; }
|
||||||
|
void SetReturningFlag(bool flag = true) { m_returning_flag = flag; }
|
||||||
|
|
||||||
// Private "Inventory" Methods
|
// Private "Inventory" Methods
|
||||||
void GetBotItems(EQEmu::InventoryProfile &inv, std::string* errorMessage);
|
void GetBotItems(EQEmu::InventoryProfile &inv, std::string* errorMessage);
|
||||||
|
|||||||
@ -71,6 +71,8 @@
|
|||||||
#include "water_map.h"
|
#include "water_map.h"
|
||||||
#include "worldserver.h"
|
#include "worldserver.h"
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
extern QueryServ* QServ;
|
extern QueryServ* QServ;
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
extern TaskManager *taskmanager;
|
extern TaskManager *taskmanager;
|
||||||
@ -1391,7 +1393,7 @@ int bot_command_init(void)
|
|||||||
bot_command_add("healrotationstart", "Starts a heal rotation", 0, bot_subcommand_heal_rotation_start) ||
|
bot_command_add("healrotationstart", "Starts a heal rotation", 0, bot_subcommand_heal_rotation_start) ||
|
||||||
bot_command_add("healrotationstop", "Stops a heal rotation", 0, bot_subcommand_heal_rotation_stop) ||
|
bot_command_add("healrotationstop", "Stops a heal rotation", 0, bot_subcommand_heal_rotation_stop) ||
|
||||||
bot_command_add("help", "List available commands and their description - specify partial command as argument to search", 0, bot_command_help) ||
|
bot_command_add("help", "List available commands and their description - specify partial command as argument to search", 0, bot_command_help) ||
|
||||||
bot_command_add("hold", "Suspends a bot's AI processing until released", 0, bot_command_hold) ||
|
bot_command_add("hold", "Prevents a bot from attacking until released", 0, bot_command_hold) ||
|
||||||
bot_command_add("identify", "Orders a bot to cast an item identification spell", 0, bot_command_identify) ||
|
bot_command_add("identify", "Orders a bot to cast an item identification spell", 0, bot_command_identify) ||
|
||||||
bot_command_add("inventory", "Lists the available bot inventory [subcommands]", 0, bot_command_inventory) ||
|
bot_command_add("inventory", "Lists the available bot inventory [subcommands]", 0, bot_command_inventory) ||
|
||||||
bot_command_add("inventorygive", "Gives the item on your cursor to a bot", 0, bot_subcommand_inventory_give) ||
|
bot_command_add("inventorygive", "Gives the item on your cursor to a bot", 0, bot_subcommand_inventory_give) ||
|
||||||
@ -1418,6 +1420,7 @@ int bot_command_init(void)
|
|||||||
bot_command_add("sendhome", "Orders a bot to open a magical doorway home", 0, bot_command_send_home) ||
|
bot_command_add("sendhome", "Orders a bot to open a magical doorway home", 0, bot_command_send_home) ||
|
||||||
bot_command_add("size", "Orders a bot to change a player's size", 0, bot_command_size) ||
|
bot_command_add("size", "Orders a bot to change a player's size", 0, bot_command_size) ||
|
||||||
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", 0, bot_command_summon_corpse) ||
|
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", 0, bot_command_summon_corpse) ||
|
||||||
|
bot_command_add("suspend", "Suspends a bot's AI processing until released", 0, bot_command_suspend) ||
|
||||||
bot_command_add("taunt", "Toggles taunt use by a bot", 0, bot_command_taunt) ||
|
bot_command_add("taunt", "Toggles taunt use by a bot", 0, bot_command_taunt) ||
|
||||||
bot_command_add("track", "Orders a capable bot to track enemies", 0, bot_command_track) ||
|
bot_command_add("track", "Orders a capable bot to track enemies", 0, bot_command_track) ||
|
||||||
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", 0, bot_command_water_breathing)
|
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", 0, bot_command_water_breathing)
|
||||||
@ -2577,38 +2580,55 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void bot_command_attack(Client *c, const Seperator *sep)
|
void bot_command_attack(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_attack", sep->arg[0], "attack"))
|
if (helper_command_alias_fail(c, "bot_command_attack", sep->arg[0], "attack")) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
c->Message(m_usage, "usage: <enemy_target> %s [actionable: byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]);
|
|
||||||
|
c->Message(m_usage, "usage: <enemy_target> %s [actionable: byname | ownergroup | botgroup | namesgroup | healrotation | default: spawned] ([actionable_name])", sep->arg[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int ab_mask = ActionableBots::ABM_Type2;
|
const int ab_mask = ActionableBots::ABM_Type2;
|
||||||
|
|
||||||
Mob* target_mob = ActionableTarget::AsSingle_ByAttackable(c);
|
Mob* target_mob = ActionableTarget::AsSingle_ByAttackable(c);
|
||||||
if (!target_mob) {
|
if (!target_mob) {
|
||||||
|
|
||||||
c->Message(m_fail, "You must <target> an enemy to use this command");
|
c->Message(m_fail, "You must <target> an enemy to use this command");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ab_arg(sep->arg[1]);
|
||||||
|
if (ab_arg.empty()) {
|
||||||
|
ab_arg = "spawned";
|
||||||
|
}
|
||||||
|
|
||||||
std::list<Bot*> sbl;
|
std::list<Bot*> sbl;
|
||||||
if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None)
|
if (ActionableBots::PopulateSBL(c, ab_arg.c_str(), sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t attacker_count = 0;
|
||||||
|
Bot *first_attacker = nullptr;
|
||||||
sbl.remove(nullptr);
|
sbl.remove(nullptr);
|
||||||
for (auto bot_iter : sbl) {
|
for (auto bot_iter : sbl) {
|
||||||
bot_iter->WipeHateList();
|
|
||||||
bot_iter->AddToHateList(target_mob, 1);
|
|
||||||
if (!bot_iter->GetPet())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bot_iter->GetPet()->WipeHateList();
|
if (bot_iter->GetAppearance() != eaDead && bot_iter->GetBotStance() != EQEmu::constants::stancePassive) {
|
||||||
bot_iter->GetPet()->AddToHateList(target_mob, 1);
|
|
||||||
|
if (!first_attacker) {
|
||||||
|
first_attacker = bot_iter;
|
||||||
|
}
|
||||||
|
++attacker_count;
|
||||||
|
|
||||||
|
bot_iter->SetAttackFlag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attacker_count == 1 && first_attacker) {
|
||||||
|
Bot::BotGroupSay(first_attacker, "Attacking %s!", target_mob->GetCleanName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->Message(m_action, "%i of your bots are attacking %s!", sbl.size(), target_mob->GetCleanName());
|
||||||
}
|
}
|
||||||
if (sbl.size() == 1)
|
|
||||||
Bot::BotGroupSay(sbl.front(), "Attacking %s", target_mob->GetCleanName());
|
|
||||||
else
|
|
||||||
c->Message(m_action, "%i of your bots are attacking %s", sbl.size(), target_mob->GetCleanName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bot_command_bind_affinity(Client *c, const Seperator *sep)
|
void bot_command_bind_affinity(Client *c, const Seperator *sep)
|
||||||
@ -3098,26 +3118,50 @@ void bot_command_follow(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void bot_command_guard(Client *c, const Seperator *sep)
|
void bot_command_guard(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_guard", sep->arg[0], "guard"))
|
if (helper_command_alias_fail(c, "bot_command_guard", sep->arg[0], "guard")) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
c->Message(m_usage, "usage: %s [actionable: target | byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]);
|
|
||||||
|
c->Message(m_usage, "usage: %s ([option: clear]) [actionable: target | byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_Type2);
|
const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_Type2);
|
||||||
|
|
||||||
|
bool clear = false;
|
||||||
|
int ab_arg = 1;
|
||||||
|
int name_arg = 2;
|
||||||
|
|
||||||
|
std::string clear_arg = sep->arg[1];
|
||||||
|
if (!clear_arg.compare("clear")) {
|
||||||
|
|
||||||
|
clear = true;
|
||||||
|
ab_arg = 2;
|
||||||
|
name_arg = 3;
|
||||||
|
}
|
||||||
|
|
||||||
std::list<Bot*> sbl;
|
std::list<Bot*> sbl;
|
||||||
if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None)
|
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[name_arg]) == ActionableBots::ABT_None) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sbl.remove(nullptr);
|
sbl.remove(nullptr);
|
||||||
for (auto bot_iter : sbl) {
|
for (auto bot_iter : sbl) {
|
||||||
bot_iter->SetGuardMode();
|
|
||||||
|
if (clear) {
|
||||||
|
bot_iter->SetGuardFlag(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bot_iter->SetGuardMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbl.size() == 1) {
|
||||||
|
Bot::BotGroupSay(sbl.front(), "%suarding this position.", (clear ? "No longer g" : "G"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->Message(m_action, "%i of your bots are %sguarding their positions.", sbl.size(), (clear ? "no longer " : ""));
|
||||||
}
|
}
|
||||||
if (sbl.size() == 1)
|
|
||||||
Bot::BotGroupSay(sbl.front(), "Guarding this position");
|
|
||||||
else
|
|
||||||
c->Message(m_action, "%i of your bots are guarding their positions", sbl.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bot_command_heal_rotation(Client *c, const Seperator *sep)
|
void bot_command_heal_rotation(Client *c, const Seperator *sep)
|
||||||
@ -3199,23 +3243,50 @@ void bot_command_help(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void bot_command_hold(Client *c, const Seperator *sep)
|
void bot_command_hold(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_hold", sep->arg[0], "hold"))
|
if (helper_command_alias_fail(c, "bot_command_hold", sep->arg[0], "hold")) {
|
||||||
return;
|
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
|
||||||
c->Message(m_usage, "usage: %s ([actionable: <any>] ([actionable_name]))", sep->arg[0]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int ab_mask = ActionableBots::ABM_NoFilter;
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
|
|
||||||
|
c->Message(m_usage, "usage: %s ([option: clear]) [actionable: target | byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_Type2);
|
||||||
|
|
||||||
|
bool clear = false;
|
||||||
|
int ab_arg = 1;
|
||||||
|
int name_arg = 2;
|
||||||
|
|
||||||
|
std::string clear_arg = sep->arg[1];
|
||||||
|
if (!clear_arg.compare("clear")) {
|
||||||
|
|
||||||
|
clear = true;
|
||||||
|
ab_arg = 2;
|
||||||
|
name_arg = 3;
|
||||||
|
}
|
||||||
|
|
||||||
std::list<Bot*> sbl;
|
std::list<Bot*> sbl;
|
||||||
if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None)
|
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[name_arg]) == ActionableBots::ABT_None) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sbl.remove(nullptr);
|
sbl.remove(nullptr);
|
||||||
for (auto bot_iter : sbl)
|
for (auto bot_iter : sbl) {
|
||||||
bot_iter->SetPauseAI(true);
|
|
||||||
|
if (clear) {
|
||||||
c->Message(m_action, "%i of your bots %s suspended", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is")));
|
bot_iter->SetHoldFlag(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bot_iter->SetHoldMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbl.size() == 1) {
|
||||||
|
Bot::BotGroupSay(sbl.front(), "%solding my attacks.", (clear ? "No longer h" : "H"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->Message(m_action, "%i of your bots are %sholding their attacks.", sbl.size(), (clear ? "no longer " : ""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bot_command_identify(Client *c, const Seperator *sep)
|
void bot_command_identify(Client *c, const Seperator *sep)
|
||||||
@ -3505,70 +3576,70 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
|||||||
{
|
{
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
|
|
||||||
c->Message(m_usage, "usage: %s [option] [argument | null]", sep->arg[0]);
|
c->Message(m_usage, "usage: %s [option] [argument]", sep->arg[0]);
|
||||||
|
|
||||||
std::string window_title = "Bot Owner Options";
|
std::string window_title = "Bot Owner Options";
|
||||||
std::string window_text =
|
std::string window_text =
|
||||||
"<table>"
|
"<table>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td><c \"#FFFFFF\">Option</td>"
|
"<td><c \"#FFFFFF\">Option<br>------</td>"
|
||||||
"<td>Argument</td>"
|
"<td><c \"#00FF00\">Argument<br>-------</td>"
|
||||||
"<td>Notes</td>"
|
"<td><c \"#AAAAAA\">Notes<br>-----</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td><c \"#FFFFFF\">deathmarquee</td>"
|
"<td><c \"#CCCCCC\">deathmarquee</td>"
|
||||||
"<td><c \"#00FF00\">enable</td>"
|
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">marquee message on death</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FF00\">disable</td>"
|
"<td><c \"#00CCCC\">null</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">(toggles)</td>"
|
||||||
|
"</tr>"
|
||||||
|
"<tr>"
|
||||||
|
"<td><c \"#CCCCCC\">statsupdate</td>"
|
||||||
|
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||||
|
"<td><c \"#888888\">report stats on update</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FFFF\">null</td>"
|
"<td><c \"#00CCCC\">null</td>"
|
||||||
"<td><c \"#AAAAAA\">(toggles)</td>"
|
"<td><c \"#888888\">(toggles)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td><c \"#FFFFFF\">statsupdate</td>"
|
"<td><c \"#CCCCCC\">spawnmessage</td>"
|
||||||
"<td><c \"#00FF00\">enable</td>"
|
"<td><c \"#00CC00\">say <c \"#CCCCCC\">| <c \"#00CC00\">tell <c \"#CCCCCC\">| <c \"#00CC00\">silent</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">spawn message into channel</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FF00\">disable</td>"
|
"<td><c \"#00CC00\">class <c \"#CCCCCC\">| <c \"#00CC00\">default</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">spawn with class-based message</td>"
|
||||||
|
"</tr>"
|
||||||
|
"<tr>"
|
||||||
|
"<td><c \"#CCCCCC\">altcombat</td>"
|
||||||
|
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||||
|
"<td><c \"#888888\">use alternate ai combat behavior</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FFFF\">null</td>"
|
"<td><c \"#00CCCC\">null</td>"
|
||||||
"<td><c \"#AAAAAA\">(toggles)</td>"
|
"<td><c \"#888888\">(toggles)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td><c \"#FFFFFF\">spawnmessage</td>"
|
"<td><c \"#CCCCCC\">autodefend</td>"
|
||||||
"<td><c \"#00FF00\">say</td>"
|
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">bots defend owner when aggroed</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FF00\">tell</td>"
|
"<td><c \"#00CCCC\">null</td>"
|
||||||
"<td></td>"
|
"<td><c \"#888888\">(toggles)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
|
"<td><c \"#CCCCCC\">current</td>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td><c \"#00FF00\">silent</td>"
|
"<td><c \"#888888\">show current settings</td>"
|
||||||
"<td></td>"
|
|
||||||
"</tr>"
|
|
||||||
"<tr>"
|
|
||||||
"<td></td>"
|
|
||||||
"<td><c \"#00FF00\">class</td>"
|
|
||||||
"<td></td>"
|
|
||||||
"</tr>"
|
|
||||||
"<tr>"
|
|
||||||
"<td></td>"
|
|
||||||
"<td><c \"#00FF00\">default</td>"
|
|
||||||
"<td></td>"
|
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"</table>";
|
"</table>";
|
||||||
|
|
||||||
@ -3680,6 +3751,70 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
c->Message(m_action, "Bot 'spawn message' is now %s.", argument.c_str());
|
c->Message(m_action, "Bot 'spawn message' is now %s.", argument.c_str());
|
||||||
}
|
}
|
||||||
|
else if (!owner_option.compare("altcombat")) {
|
||||||
|
|
||||||
|
if (!argument.compare("enable")) {
|
||||||
|
c->SetBotOption(Client::booAltCombat, true);
|
||||||
|
}
|
||||||
|
else if (!argument.compare("disable")) {
|
||||||
|
c->SetBotOption(Client::booAltCombat, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->SetBotOption(Client::booAltCombat, !c->GetBotOption(Client::booAltCombat));
|
||||||
|
}
|
||||||
|
|
||||||
|
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAltCombat, c->GetBotOption(Client::booAltCombat));
|
||||||
|
|
||||||
|
c->Message(m_action, "Bot 'alt combat' is now %s.", (c->GetBotOption(Client::booAltCombat) == true ? "enabled" : "disabled"));
|
||||||
|
}
|
||||||
|
else if (!owner_option.compare("autodefend")) {
|
||||||
|
|
||||||
|
if (RuleB(Bots, AllowOwnerAutoDefend)) {
|
||||||
|
|
||||||
|
if (!argument.compare("enable")) {
|
||||||
|
c->SetBotOption(Client::booAutoDefend, true);
|
||||||
|
}
|
||||||
|
else if (!argument.compare("disable")) {
|
||||||
|
c->SetBotOption(Client::booAutoDefend, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->SetBotOption(Client::booAutoDefend, !c->GetBotOption(Client::booAutoDefend));
|
||||||
|
}
|
||||||
|
|
||||||
|
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAutoDefend, c->GetBotOption(Client::booAutoDefend));
|
||||||
|
|
||||||
|
c->Message(m_action, "Bot 'auto defend' is now %s.", (c->GetBotOption(Client::booAutoDefend) == true ? "enabled" : "disabled"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->Message(m_fail, "Bot owner option 'autodefend' is not allowed on this server.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!owner_option.compare("current")) {
|
||||||
|
|
||||||
|
std::string window_title = "Current Bot Owner Options Settings";
|
||||||
|
std::string window_text = fmt::format(
|
||||||
|
"<table>"
|
||||||
|
"<tr>"
|
||||||
|
"<td><c \"#FFFFFF\">Option<br>------</td>"
|
||||||
|
"<td><c \"#00FF00\">Argument<br>-------</td>"
|
||||||
|
"</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">deathmarquee</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">statsupdate</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">altcombat</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">autodefend</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"</table>",
|
||||||
|
(c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"),
|
||||||
|
(c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"),
|
||||||
|
(c->GetBotOption(Client::booSpawnMessageSay) ? "say" : (c->GetBotOption(Client::booSpawnMessageTell) ? "tell" : "silent")),
|
||||||
|
(c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"),
|
||||||
|
(c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled"),
|
||||||
|
(c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled")
|
||||||
|
);
|
||||||
|
|
||||||
|
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
c->Message(m_fail, "Owner option '%s' is not recognized.", owner_option.c_str());
|
c->Message(m_fail, "Owner option '%s' is not recognized.", owner_option.c_str());
|
||||||
}
|
}
|
||||||
@ -3761,38 +3896,113 @@ void bot_command_pick_lock(Client *c, const Seperator *sep)
|
|||||||
c->Message(m_action, "%i door%s attempted - %i door%s successful", door_count, ((door_count != 1) ? ("s") : ("")), open_count, ((open_count != 1) ? ("s") : ("")));
|
c->Message(m_action, "%i door%s attempted - %i door%s successful", door_count, ((door_count != 1) ? ("s") : ("")), open_count, ((open_count != 1) ? ("s") : ("")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Rework to allow owner specificed criteria for puller
|
||||||
void bot_command_pull(Client *c, const Seperator *sep)
|
void bot_command_pull(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_pull", sep->arg[0], "pull"))
|
if (helper_command_alias_fail(c, "bot_command_pull", sep->arg[0], "pull")) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
|
|
||||||
c->Message(m_usage, "usage: <enemy_target> %s", sep->arg[0]);
|
c->Message(m_usage, "usage: <enemy_target> %s", sep->arg[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int ab_mask = ActionableBots::ABM_OwnerGroup; // existing behavior - need to add c->IsGrouped() check and modify code if different behavior is desired
|
int ab_mask = ActionableBots::ABM_OwnerGroup; // existing behavior - need to add c->IsGrouped() check and modify code if different behavior is desired
|
||||||
|
|
||||||
std::list<Bot*> sbl;
|
std::list<Bot*> sbl;
|
||||||
if (ActionableBots::PopulateSBL(c, "ownergroup", sbl, ab_mask) == ActionableBots::ABT_None)
|
if (ActionableBots::PopulateSBL(c, "ownergroup", sbl, ab_mask) == ActionableBots::ABT_None) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
sbl.remove(nullptr);
|
sbl.remove(nullptr);
|
||||||
|
|
||||||
auto target_mob = ActionableTarget::VerifyEnemy(c, BCEnum::TT_Single);
|
auto target_mob = ActionableTarget::VerifyEnemy(c, BCEnum::TT_Single);
|
||||||
if (!target_mob) {
|
if (!target_mob) {
|
||||||
c->Message(m_fail, "Your current target is not attackable");
|
|
||||||
|
c->Message(m_fail, "Your current target is not attackable!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bot* bot_puller = nullptr;
|
Bot* bot_puller = nullptr;
|
||||||
for (auto bot_iter : sbl) {
|
for (auto bot_iter : sbl) {
|
||||||
if (!bot_iter->IsArcheryRange(target_mob))
|
|
||||||
|
if (bot_iter->GetAppearance() == eaDead || bot_iter->GetBotStance() == EQEmu::constants::stancePassive) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Bot::BotGroupSay(bot_iter, "Attempting to pull %s..", target_mob->GetCleanName());
|
switch (bot_iter->GetClass()) {
|
||||||
bot_iter->InterruptSpell();
|
case ROGUE:
|
||||||
bot_iter->BotRangedAttack(target_mob);
|
case MONK:
|
||||||
|
case BARD:
|
||||||
|
case RANGER:
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
break;
|
||||||
|
case WARRIOR:
|
||||||
|
case SHADOWKNIGHT:
|
||||||
|
case PALADIN:
|
||||||
|
case BERSERKER:
|
||||||
|
case BEASTLORD:
|
||||||
|
if (!bot_puller) {
|
||||||
|
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bot_puller->GetClass()) {
|
||||||
|
case DRUID:
|
||||||
|
case SHAMAN:
|
||||||
|
case CLERIC:
|
||||||
|
case WIZARD:
|
||||||
|
case NECROMANCER:
|
||||||
|
case MAGICIAN:
|
||||||
|
case ENCHANTER:
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
case DRUID:
|
||||||
|
case SHAMAN:
|
||||||
|
case CLERIC:
|
||||||
|
if (!bot_puller) {
|
||||||
|
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bot_puller->GetClass()) {
|
||||||
|
case WIZARD:
|
||||||
|
case NECROMANCER:
|
||||||
|
case MAGICIAN:
|
||||||
|
case ENCHANTER:
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
case WIZARD:
|
||||||
|
case NECROMANCER:
|
||||||
|
case MAGICIAN:
|
||||||
|
case ENCHANTER:
|
||||||
|
if (!bot_puller) {
|
||||||
|
bot_puller = bot_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bot_puller = bot_iter;
|
bot_puller = bot_iter;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bot_puller) {
|
||||||
|
bot_puller->SetPullFlag();
|
||||||
|
}
|
||||||
|
|
||||||
helper_no_available_bots(c, bot_puller);
|
helper_no_available_bots(c, bot_puller);
|
||||||
}
|
}
|
||||||
@ -3817,7 +4027,7 @@ void bot_command_release(Client *c, const Seperator *sep)
|
|||||||
bot_iter->SetPauseAI(false);
|
bot_iter->SetPauseAI(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->Message(m_action, "%i of your bots %s unsuspended", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is")));
|
c->Message(m_action, "%i of your bots %s released.", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bot_command_resistance(Client *c, const Seperator *sep)
|
void bot_command_resistance(Client *c, const Seperator *sep)
|
||||||
@ -4126,6 +4336,30 @@ void bot_command_summon_corpse(Client *c, const Seperator *sep)
|
|||||||
helper_no_available_bots(c, my_bot);
|
helper_no_available_bots(c, my_bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bot_command_suspend(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
if (helper_command_alias_fail(c, "bot_command_suspend", sep->arg[0], "suspend")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||||
|
c->Message(m_usage, "usage: %s ([actionable: <any>] ([actionable_name]))", sep->arg[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int ab_mask = ActionableBots::ABM_NoFilter;
|
||||||
|
|
||||||
|
std::list<Bot*> sbl;
|
||||||
|
if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbl.remove(nullptr);
|
||||||
|
for (auto bot_iter : sbl) {
|
||||||
|
bot_iter->SetPauseAI(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(m_action, "%i of your bots %s suspended.", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is")));
|
||||||
|
}
|
||||||
|
|
||||||
void bot_command_taunt(Client *c, const Seperator *sep)
|
void bot_command_taunt(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_taunt", sep->arg[0], "taunt"))
|
if (helper_command_alias_fail(c, "bot_command_taunt", sep->arg[0], "taunt"))
|
||||||
|
|||||||
@ -586,6 +586,7 @@ void bot_command_rune(Client *c, const Seperator *sep);
|
|||||||
void bot_command_send_home(Client *c, const Seperator *sep);
|
void bot_command_send_home(Client *c, const Seperator *sep);
|
||||||
void bot_command_size(Client *c, const Seperator *sep);
|
void bot_command_size(Client *c, const Seperator *sep);
|
||||||
void bot_command_summon_corpse(Client *c, const Seperator *sep);
|
void bot_command_summon_corpse(Client *c, const Seperator *sep);
|
||||||
|
void bot_command_suspend(Client *c, const Seperator *sep);
|
||||||
void bot_command_taunt(Client *c, const Seperator *sep);
|
void bot_command_taunt(Client *c, const Seperator *sep);
|
||||||
void bot_command_track(Client *c, const Seperator *sep);
|
void bot_command_track(Client *c, const Seperator *sep);
|
||||||
void bot_command_water_breathing(Client *c, const Seperator *sep);
|
void bot_command_water_breathing(Client *c, const Seperator *sep);
|
||||||
|
|||||||
@ -580,7 +580,7 @@ bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id)
|
|||||||
bot_inst->GetPR(),
|
bot_inst->GetPR(),
|
||||||
bot_inst->GetDR(),
|
bot_inst->GetDR(),
|
||||||
bot_inst->GetCorrup(),
|
bot_inst->GetCorrup(),
|
||||||
BOT_FOLLOW_DISTANCE_DEFAULT,
|
(uint32)BOT_FOLLOW_DISTANCE_DEFAULT,
|
||||||
(IsCasterClass(bot_inst->GetClass()) ? (uint8)RuleI(Bots, CasterStopMeleeLevel) : 255)
|
(IsCasterClass(bot_inst->GetClass()) ? (uint8)RuleI(Bots, CasterStopMeleeLevel) : 255)
|
||||||
);
|
);
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
@ -2253,8 +2253,10 @@ bool BotDatabase::SaveOwnerOption(const uint32 owner_id, size_t type, const bool
|
|||||||
switch (static_cast<Client::BotOwnerOption>(type)) {
|
switch (static_cast<Client::BotOwnerOption>(type)) {
|
||||||
case Client::booDeathMarquee:
|
case Client::booDeathMarquee:
|
||||||
case Client::booStatsUpdate:
|
case Client::booStatsUpdate:
|
||||||
case Client::booSpawnMessageClassSpecific: {
|
case Client::booSpawnMessageClassSpecific:
|
||||||
|
case Client::booAltCombat:
|
||||||
|
case Client::booAutoDefend:
|
||||||
|
{
|
||||||
query = fmt::format(
|
query = fmt::format(
|
||||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
||||||
owner_id,
|
owner_id,
|
||||||
@ -2282,11 +2284,12 @@ bool BotDatabase::SaveOwnerOption(const uint32 owner_id, const std::pair<size_t,
|
|||||||
|
|
||||||
switch (static_cast<Client::BotOwnerOption>(type.first)) {
|
switch (static_cast<Client::BotOwnerOption>(type.first)) {
|
||||||
case Client::booSpawnMessageSay:
|
case Client::booSpawnMessageSay:
|
||||||
case Client::booSpawnMessageTell: {
|
case Client::booSpawnMessageTell:
|
||||||
|
{
|
||||||
switch (static_cast<Client::BotOwnerOption>(type.second)) {
|
switch (static_cast<Client::BotOwnerOption>(type.second)) {
|
||||||
case Client::booSpawnMessageSay:
|
case Client::booSpawnMessageSay:
|
||||||
case Client::booSpawnMessageTell: {
|
case Client::booSpawnMessageTell:
|
||||||
|
{
|
||||||
query = fmt::format(
|
query = fmt::format(
|
||||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}'), ('{}', '{}', '{}')",
|
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}'), ('{}', '{}', '{}')",
|
||||||
owner_id,
|
owner_id,
|
||||||
|
|||||||
@ -353,6 +353,10 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
bot_owner_options[booSpawnMessageSay] = false;
|
bot_owner_options[booSpawnMessageSay] = false;
|
||||||
bot_owner_options[booSpawnMessageTell] = true;
|
bot_owner_options[booSpawnMessageTell] = true;
|
||||||
bot_owner_options[booSpawnMessageClassSpecific] = true;
|
bot_owner_options[booSpawnMessageClassSpecific] = true;
|
||||||
|
bot_owner_options[booAltCombat] = false;
|
||||||
|
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerAutoDefend);
|
||||||
|
|
||||||
|
SetBotPulling(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AI_Init();
|
AI_Init();
|
||||||
|
|||||||
@ -1628,9 +1628,6 @@ private:
|
|||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum BotOwnerOption : size_t {
|
enum BotOwnerOption : size_t {
|
||||||
booDeathMarquee,
|
booDeathMarquee,
|
||||||
@ -1638,14 +1635,20 @@ public:
|
|||||||
booSpawnMessageSay,
|
booSpawnMessageSay,
|
||||||
booSpawnMessageTell,
|
booSpawnMessageTell,
|
||||||
booSpawnMessageClassSpecific,
|
booSpawnMessageClassSpecific,
|
||||||
|
booAltCombat,
|
||||||
|
booAutoDefend,
|
||||||
_booCount
|
_booCount
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GetBotOption(BotOwnerOption boo) const;
|
bool GetBotOption(BotOwnerOption boo) const;
|
||||||
void SetBotOption(BotOwnerOption boo, bool flag = true);
|
void SetBotOption(BotOwnerOption boo, bool flag = true);
|
||||||
|
|
||||||
|
bool GetBotPulling() { return m_bot_pulling; }
|
||||||
|
void SetBotPulling(bool flag = true) { m_bot_pulling = flag; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool bot_owner_options[_booCount];
|
bool bot_owner_options[_booCount];
|
||||||
|
bool m_bot_pulling;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2809,12 +2809,8 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
uint32 ApplyPoisonSuccessResult = 0;
|
uint32 ApplyPoisonSuccessResult = 0;
|
||||||
|
|
||||||
const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::invslot::slotPrimary);
|
|
||||||
const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::invslot::slotSecondary);
|
|
||||||
const EQEmu::ItemInstance* PoisonItemInstance = GetInv().GetItem(ApplyPoisonData->inventorySlot);
|
const EQEmu::ItemInstance* PoisonItemInstance = GetInv().GetItem(ApplyPoisonData->inventorySlot);
|
||||||
|
|
||||||
const EQEmu::ItemData* primary = (PrimaryWeapon ? PrimaryWeapon->GetItem() : nullptr);
|
|
||||||
const EQEmu::ItemData* secondary = (SecondaryWeapon ? SecondaryWeapon->GetItem() : nullptr);
|
|
||||||
const EQEmu::ItemData* poison = (PoisonItemInstance ? PoisonItemInstance->GetItem() : nullptr);
|
const EQEmu::ItemData* poison = (PoisonItemInstance ? PoisonItemInstance->GetItem() : nullptr);
|
||||||
|
|
||||||
bool IsPoison = (poison && poison->ItemType == EQEmu::item::ItemTypePoison);
|
bool IsPoison = (poison && poison->ItemType == EQEmu::item::ItemTypePoison);
|
||||||
@ -2828,10 +2824,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
|
|||||||
// Poison is too high to apply.
|
// Poison is too high to apply.
|
||||||
MessageString(Chat::LightBlue, POISON_TOO_HIGH);
|
MessageString(Chat::LightBlue, POISON_TOO_HIGH);
|
||||||
}
|
}
|
||||||
else if ((primary &&
|
else {
|
||||||
primary->ItemType == EQEmu::item::ItemType1HPiercing) ||
|
|
||||||
(secondary &&
|
|
||||||
secondary->ItemType == EQEmu::item::ItemType1HPiercing)) {
|
|
||||||
|
|
||||||
double ChanceRoll = zone->random.Real(0, 1);
|
double ChanceRoll = zone->random.Real(0, 1);
|
||||||
|
|
||||||
@ -2848,12 +2841,9 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
if (ChanceRoll < (.75 + poison_skill / 1000)) {
|
if (ChanceRoll < (.75 + poison_skill / 1000)) {
|
||||||
ApplyPoisonSuccessResult = 1;
|
ApplyPoisonSuccessResult = 1;
|
||||||
AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103);
|
AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Message(Chat::Red, "A piercing weapon must be wielded to apply poison.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Live always deletes the item, success or failure. Even if too high.
|
// Live always deletes the item, success or failure. Even if too high.
|
||||||
DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true);
|
DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true);
|
||||||
|
|||||||
@ -7740,7 +7740,7 @@ void command_npceditmass(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
database.QueryDatabase(
|
database.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"UPDATE `npc_types` SET {} = {} WHERE id IN ({})",
|
"UPDATE `npc_types` SET {} = '{}' WHERE id IN ({})",
|
||||||
change_column,
|
change_column,
|
||||||
change_value,
|
change_value,
|
||||||
npc_ids_string
|
npc_ids_string
|
||||||
|
|||||||
@ -3580,6 +3580,25 @@ XS(XS__worldwidemarquee) {
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS__log);
|
||||||
|
XS(XS__log) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 1 && items != 2) {
|
||||||
|
Perl_croak(aTHX_ "Usage: quest::log(uint8 log_category, string message)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint8 log_category = (uint8)SvIV(ST(0));
|
||||||
|
std::string log_message = (std::string) SvPV_nolen(ST(1));
|
||||||
|
|
||||||
|
if (log_category >= Logs::MaxCategoryID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Logs::General, log_category, log_message.c_str());
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
XS(XS__debug);
|
XS(XS__debug);
|
||||||
XS(XS__debug) {
|
XS(XS__debug) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@ -3606,6 +3625,21 @@ XS(XS__debug) {
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS__log_combat);
|
||||||
|
XS(XS__log_combat) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 1) {
|
||||||
|
Perl_croak(aTHX_ "Usage: quest::log_combat(string message)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
std::string log_message = (std::string) SvPV_nolen(ST(0));
|
||||||
|
Log(Logs::General, Logs::Combat, log_message.c_str());
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
XS(XS__UpdateZoneHeader);
|
XS(XS__UpdateZoneHeader);
|
||||||
XS(XS__UpdateZoneHeader) {
|
XS(XS__UpdateZoneHeader) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@ -3862,6 +3896,8 @@ EXTERN_C XS(boot_quest) {
|
|||||||
newXS(strcpy(buf, "itemlink"), XS__itemlink, file);
|
newXS(strcpy(buf, "itemlink"), XS__itemlink, file);
|
||||||
newXS(strcpy(buf, "lasttaskinset"), XS__lasttaskinset, file);
|
newXS(strcpy(buf, "lasttaskinset"), XS__lasttaskinset, file);
|
||||||
newXS(strcpy(buf, "level"), XS__level, file);
|
newXS(strcpy(buf, "level"), XS__level, file);
|
||||||
|
newXS(strcpy(buf, "log"), XS__log, file);
|
||||||
|
newXS(strcpy(buf, "log_combat"), XS__log_combat, file);
|
||||||
newXS(strcpy(buf, "me"), XS__me, file);
|
newXS(strcpy(buf, "me"), XS__me, file);
|
||||||
newXS(strcpy(buf, "modifynpcstat"), XS__ModifyNPCStat, file);
|
newXS(strcpy(buf, "modifynpcstat"), XS__ModifyNPCStat, file);
|
||||||
newXS(strcpy(buf, "movegrp"), XS__movegrp, file);
|
newXS(strcpy(buf, "movegrp"), XS__movegrp, file);
|
||||||
|
|||||||
@ -1367,6 +1367,13 @@ double lua_clock() {
|
|||||||
return static_cast<double>(t) / 1000.0;
|
return static_cast<double>(t) / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_log(int category, std::string message) {
|
||||||
|
if (category < Logs::None || category >= Logs::MaxCategoryID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log(Logs::General, static_cast<Logs::LogCategory>(category), message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void lua_debug(std::string message) {
|
void lua_debug(std::string message) {
|
||||||
Log(Logs::General, Logs::QuestDebug, message.c_str());
|
Log(Logs::General, Logs::QuestDebug, message.c_str());
|
||||||
}
|
}
|
||||||
@ -1378,6 +1385,10 @@ void lua_debug(std::string message, int level) {
|
|||||||
Log(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message.c_str());
|
Log(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_log_combat(std::string message) {
|
||||||
|
Log(Logs::General, Logs::Combat, message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void lua_update_zone_header(std::string type, std::string value) {
|
void lua_update_zone_header(std::string type, std::string value) {
|
||||||
quest_manager.UpdateZoneHeader(type, value);
|
quest_manager.UpdateZoneHeader(type, value);
|
||||||
}
|
}
|
||||||
@ -1772,8 +1783,10 @@ luabind::scope lua_register_general() {
|
|||||||
luabind::def("reloadzonestaticdata", &lua_reloadzonestaticdata),
|
luabind::def("reloadzonestaticdata", &lua_reloadzonestaticdata),
|
||||||
luabind::def("clock", &lua_clock),
|
luabind::def("clock", &lua_clock),
|
||||||
luabind::def("create_npc", &lua_create_npc),
|
luabind::def("create_npc", &lua_create_npc),
|
||||||
|
luabind::def("log", (void(*)(int, std::string))&lua_log),
|
||||||
luabind::def("debug", (void(*)(std::string))&lua_debug),
|
luabind::def("debug", (void(*)(std::string))&lua_debug),
|
||||||
luabind::def("debug", (void(*)(std::string, int))&lua_debug)
|
luabind::def("debug", (void(*)(std::string, int))&lua_debug),
|
||||||
|
luabind::def("log_combat", (void(*)(std::string))&lua_log_combat)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
zone/mob.cpp
35
zone/mob.cpp
@ -1493,17 +1493,23 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::StopMoving() {
|
void Mob::StopMoving()
|
||||||
|
{
|
||||||
StopNavigation();
|
StopNavigation();
|
||||||
if (moved)
|
|
||||||
|
if (moved) {
|
||||||
moved = false;
|
moved = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::StopMoving(float new_heading) {
|
void Mob::StopMoving(float new_heading)
|
||||||
|
{
|
||||||
StopNavigation();
|
StopNavigation();
|
||||||
RotateTo(new_heading);
|
RotateTo(new_heading);
|
||||||
if (moved)
|
|
||||||
|
if (moved) {
|
||||||
moved = false;
|
moved = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self)
|
void Mob::SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self)
|
||||||
@ -2684,6 +2690,27 @@ bool Mob::PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, fl
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::PlotPositionOnArcInFrontOfTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float distance, float min_deg, float max_deg)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mob::PlotPositionOnArcBehindTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float distance)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mob::PlotPositionBehindMeFacingTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_dist, float max_dist)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Mob::HateSummon() {
|
bool Mob::HateSummon() {
|
||||||
// check if mob has ability to summon
|
// check if mob has ability to summon
|
||||||
// 97% is the offical % that summoning starts on live, not 94
|
// 97% is the offical % that summoning starts on live, not 94
|
||||||
|
|||||||
10
zone/mob.h
10
zone/mob.h
@ -593,8 +593,8 @@ public:
|
|||||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||||
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
||||||
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
|
void SentPositionPacket(float dx, float dy, float dz, float dh, int anim, bool send_to_self = false);
|
||||||
void StopMoving();
|
virtual void StopMoving();
|
||||||
void StopMoving(float new_heading);
|
virtual void StopMoving(float new_heading);
|
||||||
void SetSpawned() { spawned = true; };
|
void SetSpawned() { spawned = true; };
|
||||||
bool Spawned() { return spawned; };
|
bool Spawned() { return spawned; };
|
||||||
virtual bool ShouldISpawnFor(Client *c) { return true; }
|
virtual bool ShouldISpawnFor(Client *c) { return true; }
|
||||||
@ -676,8 +676,10 @@ public:
|
|||||||
void ShowStats(Client* client);
|
void ShowStats(Client* client);
|
||||||
void ShowBuffs(Client* client);
|
void ShowBuffs(Client* client);
|
||||||
void ShowBuffList(Client* client);
|
void ShowBuffList(Client* client);
|
||||||
bool PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, float &z_dest,
|
bool PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, float &z_dest, bool lookForAftArc = true);
|
||||||
bool lookForAftArc = true);
|
bool PlotPositionOnArcInFrontOfTarget(Mob *target, float &x_dest, float &y_dest, float &z_dest, float distance, float min_deg = 5.0f, float max_deg = 150.0f);
|
||||||
|
bool PlotPositionOnArcBehindTarget(Mob *target, float &x_dest, float &y_dest, float &z_dest, float distance);
|
||||||
|
bool PlotPositionBehindMeFacingTarget(Mob *target, float &x_dest, float &y_dest, float &z_dest, float min_dist = 1.0f, float max_dist = 5.0f);
|
||||||
|
|
||||||
// aura functions
|
// aura functions
|
||||||
void MakeAura(uint16 spell_id);
|
void MakeAura(uint16 spell_id);
|
||||||
|
|||||||
@ -5394,13 +5394,31 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
|||||||
}
|
}
|
||||||
LogSpells("Too many perma procs for [{}]", GetName());
|
LogSpells("Too many perma procs for [{}]", GetName());
|
||||||
} else {
|
} else {
|
||||||
|
// If its a poison proc, replace any existing one if present.
|
||||||
|
if (base_spell_id == POISON_PROC) {
|
||||||
|
for (i = 0; i < MAX_PROCS; i++) {
|
||||||
|
// If we already have a poison proc active replace it and return
|
||||||
|
if (SpellProcs[i].base_spellID == POISON_PROC) {
|
||||||
|
SpellProcs[i].spellID = spell_id;
|
||||||
|
SpellProcs[i].chance = iChance;
|
||||||
|
SpellProcs[i].level_override = level_override;
|
||||||
|
Log(Logs::Detail, Logs::Spells, "Replaced poison-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here it either wasn't poison (which can only use 1 slot)
|
||||||
|
// or it is poison and no poison procs are currently present.
|
||||||
|
// Find a slot and use it as normal.
|
||||||
|
|
||||||
for (i = 0; i < MAX_PROCS; i++) {
|
for (i = 0; i < MAX_PROCS; i++) {
|
||||||
if (SpellProcs[i].spellID == SPELL_UNKNOWN) {
|
if (SpellProcs[i].spellID == SPELL_UNKNOWN) {
|
||||||
SpellProcs[i].spellID = spell_id;
|
SpellProcs[i].spellID = spell_id;
|
||||||
SpellProcs[i].chance = iChance;
|
SpellProcs[i].chance = iChance;
|
||||||
SpellProcs[i].base_spellID = base_spell_id;;
|
SpellProcs[i].base_spellID = base_spell_id;;
|
||||||
SpellProcs[i].level_override = level_override;
|
SpellProcs[i].level_override = level_override;
|
||||||
LogSpells("Added spell-granted proc spell [{}] with chance [{}] to slot [{}]", spell_id, iChance, i);
|
LogSpells("Added [{}]-granted proc spell [{}] with chance [{}] to slot [{}]", (base_spell_id == POISON_PROC) ? "poison" : "spell", spell_id, iChance, i);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user