mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
[Bots] [Quest API] Add ^clickitem, ^timer, fix GetBestBotSpellForCure (#3755)
* [Bots][Quest API] Add ^clickitem, ^timer, revamp bot timers, fix GetBestBotSpellForCure This adds the command **^clickitem** for bots. Bots can click items they are wearing with the provided slot ID, players can use **^invlist** on their bots to see items and slot IDs. This supports actionables. **^itemclick 13 byclass 11** would command all Necromancer bots to attempt to click their Primary item. This adds and supports charges for items to bots, when an item is used, it will lose a charge and cannot be clicked once no charges remain. This adds the following rules: **Bots, BotsClickItemsMinLvl** - Minimum level bots can use **^clickitem**. **Bots, BotsCanClickItems** - Whether or not **^clickitem** is allowed for bots. **Bots, CanClickMageEpicV1** - Whether or not players are allowed to command their bots to use the Magician Epic 1.0 This adds quest methods to Perl/Lua for: ClearDisciplineReuseTimer, ClearItemReuseTimer, ClearSpellRecastTimer GetDisciplineReuseTimer, GetItemReuseTimer, GetSpellRecastTimer SetDisciplineReuseTimer, SetItemReuseTimer, SetSpellRecastTimer Discipline and Spell methods use the spell_id to check, get and set. Item uses the item_id. Clear and Get support wildcards (no spell/item id) to clear all timers of the type or get the first timer of the type. Get will return the remaining time on the chosen timer, if any. Set supports a wildcard (no recast/reuse provided) to use the default of the provided type, you can also specify a recast/reuse timer to set that timer to the chosen value. **^timer** has been added as a bot command, defaulted for GM access. This can be used to set, get and clear timers of different types. Use **^timer help** for info. This revamps the way timers are set, stored, loaded for bots. **GetBestBotSpellForCure** was previously checking only the first spell found and not properly iterating through the checks. This requires modifications to the **bot_timers** table and is included in this commit. * Rebase Conflicts * Update queries to use repositories * Minor adjustment * Formatting * Handle delete as well * Cleanup. * Adjust primary keys to prevent conflicts --------- Co-authored-by: Akkadius <akkadius1@gmail.com> Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
parent
4ca6485398
commit
bdf5f8b4a3
@ -82,6 +82,28 @@ CREATE TABLE `bot_starting_items` (
|
||||
`content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci;
|
||||
)",
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9041,
|
||||
.description = "2023_12_04_bot_timers.sql",
|
||||
.check = "SHOW COLUMNS FROM `bot_timers` LIKE 'recast_time'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `bot_timers`
|
||||
ADD COLUMN `recast_time` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `timer_value`,
|
||||
ADD COLUMN `is_spell` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `recast_time`,
|
||||
ADD COLUMN `is_disc` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_spell`,
|
||||
ADD COLUMN `spell_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_disc`,
|
||||
ADD COLUMN `is_item` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `spell_id`,
|
||||
ADD COLUMN `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_item`;
|
||||
ALTER TABLE `bot_timers`
|
||||
DROP FOREIGN KEY `FK_bot_timers_1`;
|
||||
ALTER TABLE `bot_timers`
|
||||
DROP PRIMARY KEY;
|
||||
ALTER TABLE `bot_timers`
|
||||
ADD PRIMARY KEY (`bot_id`, `timer_id`, `spell_id`, `item_id`);
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@ -16,12 +16,19 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseBotTimersRepository {
|
||||
public:
|
||||
struct BotTimers {
|
||||
uint32_t bot_id;
|
||||
uint32_t timer_id;
|
||||
uint32_t timer_value;
|
||||
uint32_t recast_time;
|
||||
uint8_t is_spell;
|
||||
uint8_t is_disc;
|
||||
uint32_t spell_id;
|
||||
uint8_t is_item;
|
||||
uint32_t item_id;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@ -35,6 +42,12 @@ public:
|
||||
"bot_id",
|
||||
"timer_id",
|
||||
"timer_value",
|
||||
"recast_time",
|
||||
"is_spell",
|
||||
"is_disc",
|
||||
"spell_id",
|
||||
"is_item",
|
||||
"item_id",
|
||||
};
|
||||
}
|
||||
|
||||
@ -44,6 +57,12 @@ public:
|
||||
"bot_id",
|
||||
"timer_id",
|
||||
"timer_value",
|
||||
"recast_time",
|
||||
"is_spell",
|
||||
"is_disc",
|
||||
"spell_id",
|
||||
"is_item",
|
||||
"item_id",
|
||||
};
|
||||
}
|
||||
|
||||
@ -87,6 +106,12 @@ public:
|
||||
e.bot_id = 0;
|
||||
e.timer_id = 0;
|
||||
e.timer_value = 0;
|
||||
e.recast_time = 0;
|
||||
e.is_spell = 0;
|
||||
e.is_disc = 0;
|
||||
e.spell_id = 0;
|
||||
e.is_item = 0;
|
||||
e.item_id = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@ -112,8 +137,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
bot_timers_id
|
||||
)
|
||||
);
|
||||
@ -125,6 +151,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
return e;
|
||||
}
|
||||
@ -161,6 +193,12 @@ public:
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.timer_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.timer_value));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.recast_time));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.is_spell));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.is_disc));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.spell_id));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.is_item));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.item_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -185,6 +223,12 @@ public:
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.timer_id));
|
||||
v.push_back(std::to_string(e.timer_value));
|
||||
v.push_back(std::to_string(e.recast_time));
|
||||
v.push_back(std::to_string(e.is_spell));
|
||||
v.push_back(std::to_string(e.is_disc));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.is_item));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -217,6 +261,12 @@ public:
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.timer_id));
|
||||
v.push_back(std::to_string(e.timer_value));
|
||||
v.push_back(std::to_string(e.recast_time));
|
||||
v.push_back(std::to_string(e.is_spell));
|
||||
v.push_back(std::to_string(e.is_disc));
|
||||
v.push_back(std::to_string(e.spell_id));
|
||||
v.push_back(std::to_string(e.is_item));
|
||||
v.push_back(std::to_string(e.item_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@ -253,6 +303,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@ -280,6 +336,12 @@ public:
|
||||
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
|
||||
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
|
||||
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
|
||||
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
|
||||
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
|
||||
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
|
||||
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
@ -656,6 +656,9 @@ RULE_BOOL(Bots, AllowPickpocketCommand, true, "Allows the use of the bot command
|
||||
RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal completely when leveling. Default FALSE.")
|
||||
RULE_INT(Bots, AutosaveIntervalSeconds, 300, "Number of seconds after which a timer is triggered which stores the bot data. The value 0 means no periodic automatic saving.")
|
||||
RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hit bot owner rather than bot.")
|
||||
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
||||
RULE_BOOL(Bots, BotsCanClickItems, true, "Enabled the ability for bots to click items they have equipped. Default TRUE")
|
||||
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Chat)
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9247
|
||||
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
653
zone/bot.cpp
653
zone/bot.cpp
@ -94,6 +94,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
SetPullFlag(false);
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag(false);
|
||||
SetIsUsingItemClick(false);
|
||||
m_previous_pet_order = SPO_Guard;
|
||||
|
||||
rest_timer.Disable();
|
||||
@ -107,6 +108,8 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
// Do this once and only in this constructor
|
||||
GenerateAppearance();
|
||||
GenerateBaseStats();
|
||||
bot_timers.clear();
|
||||
|
||||
// Calculate HitPoints Last As It Uses Base Stats
|
||||
current_hp = GenerateBaseHitPoints();
|
||||
current_mana = GenerateBaseManaPoints();
|
||||
@ -114,8 +117,6 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
hp_regen = CalcHPRegen();
|
||||
mana_regen = CalcManaRegen();
|
||||
end_regen = CalcEnduranceRegen();
|
||||
for (int i = 0; i < MaxTimer; i++)
|
||||
timers[i] = 0;
|
||||
|
||||
strcpy(name, GetCleanName());
|
||||
memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct));
|
||||
@ -213,6 +214,7 @@ Bot::Bot(
|
||||
SetPullFlag(false);
|
||||
SetPullingFlag(false);
|
||||
SetReturningFlag(false);
|
||||
SetIsUsingItemClick(false);
|
||||
m_previous_pet_order = SPO_Guard;
|
||||
|
||||
rest_timer.Disable();
|
||||
@ -238,9 +240,6 @@ Bot::Bot(
|
||||
error_message.clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MaxTimer; i++)
|
||||
timers[i] = 0;
|
||||
|
||||
if (GetClass() == Class::Rogue) {
|
||||
m_evade_timer.Start();
|
||||
}
|
||||
@ -252,8 +251,10 @@ Bot::Bot(
|
||||
|
||||
GenerateBaseStats();
|
||||
|
||||
if (!database.botdb.LoadTimers(this) && bot_owner)
|
||||
bot_timers.clear();
|
||||
if (!database.botdb.LoadTimers(this) && bot_owner) {
|
||||
bot_owner->Message(Chat::White, "%s for '%s'", BotDatabase::fail::LoadTimers(), GetCleanName());
|
||||
}
|
||||
|
||||
LoadAAs();
|
||||
|
||||
@ -7916,18 +7917,17 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
return false;
|
||||
|
||||
if (spell.recast_time > 0) {
|
||||
if (CheckDisciplineRecastTimers(this, spells[spell_id].timer_id)) {
|
||||
if (spells[spell_id].timer_id > 0 && spells[spell_id].timer_id < MAX_DISCIPLINE_TIMERS)
|
||||
SetDisciplineRecastTimer(spells[spell_id].timer_id, spell.recast_time);
|
||||
if (CheckDisciplineReuseTimer(spell_id)) {
|
||||
if (spells[spell_id].timer_id > 0) {
|
||||
SetDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
} else {
|
||||
uint32 remaining_time = (GetDisciplineRemainingTime(this, spells[spell_id].timer_id) / 1000);
|
||||
GetOwner()->Message(
|
||||
Chat::White,
|
||||
uint32 remaining_time = (GetDisciplineReuseRemainingTime(spell_id) / 1000);
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} can use this discipline in {}.",
|
||||
GetCleanName(),
|
||||
"I can use this discipline in {}.",
|
||||
Strings::SecondsToTime(remaining_time)
|
||||
).c_str()
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@ -8810,4 +8810,627 @@ void Bot::AddBotStartingItems(uint16 race_id, uint8 class_id)
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::SetSpellRecastTimer(uint16 spell_id, int32 recast_delay) {
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to set spell recast timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!recast_delay) {
|
||||
recast_delay = CalcSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimer(spell_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = spells[ spell_id ].timer_id;
|
||||
t.timer_value = (Timer::GetCurrentTime() + recast_delay);
|
||||
t.recast_time = recast_delay;
|
||||
t.is_spell = true;
|
||||
t.is_disc = false;
|
||||
t.spell_id = spells[ spell_id ].id;
|
||||
t.is_item = false;
|
||||
t.item_id = 0;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
} else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_spell &&
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[ i ].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (Timer::GetCurrentTime() + recast_delay);
|
||||
bot_timers[i].recast_time = recast_delay;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to get spell recast timer.");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_spell &&
|
||||
(
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::GetSpellRecastRemainingTime(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetSpellRecastTimer(spell_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetSpellRecastTimer(spell_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to check spell recast timer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetSpellRecastTimer(spell_id) < Timer::GetCurrentTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer)
|
||||
{
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
OwnerMessage("Failed to set discipline reuse timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reuse_timer) {
|
||||
reuse_timer = CalcSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
if (CheckDisciplineReuseTimer(spell_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = spells[ spell_id ].timer_id;
|
||||
t.timer_value = (Timer::GetCurrentTime() + reuse_timer);
|
||||
t.recast_time = reuse_timer;
|
||||
t.is_spell = false;
|
||||
t.is_disc = true;
|
||||
t.spell_id = spells[ spell_id ].id;
|
||||
t.is_item = false;
|
||||
t.item_id = 0;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
} else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (Timer::GetCurrentTime() + reuse_timer);
|
||||
bot_timers[i].recast_time = reuse_timer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
(
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::GetDisciplineReuseRemainingTime(uint16 spell_id) {
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetDisciplineReuseTimer(spell_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetDisciplineReuseTimer(spell_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (GetDisciplineReuseTimer(spell_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
|
||||
return true; //can cast spell
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer)
|
||||
{
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage("Failed to set item reuse timer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->RecastDelay <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckItemReuseTimer(item_id)) {
|
||||
BotTimer_Struct t;
|
||||
|
||||
t.timer_id = (item->RecastType == NegativeItemReuse ? item->ID : item->RecastType);
|
||||
t.timer_value = (
|
||||
reuse_timer != 0 ?
|
||||
(Timer::GetCurrentTime() + reuse_timer) :
|
||||
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
|
||||
);
|
||||
t.recast_time = (reuse_timer != 0 ? reuse_timer : (item->RecastDelay * 1000));
|
||||
t.is_spell = false;
|
||||
t.is_disc = false;
|
||||
t.spell_id = 0;
|
||||
t.is_item = true;
|
||||
t.item_id = item->ID;
|
||||
|
||||
bot_timers.push_back(t);
|
||||
}
|
||||
else {
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_item &&
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = (
|
||||
reuse_timer != 0 ?
|
||||
(Timer::GetCurrentTime() + reuse_timer) :
|
||||
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
|
||||
);
|
||||
bot_timers[i].recast_time = (
|
||||
reuse_timer != 0 ?
|
||||
reuse_timer :
|
||||
(item->RecastDelay * 1000)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Bot::GetItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
const EQ::ItemData* item;
|
||||
|
||||
if (item_id) {
|
||||
item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage("Failed to get item reuse timer.");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_item &&
|
||||
(
|
||||
!item_id ||
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
result = bot_timers[i].timer_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
ClearExpiredTimers();
|
||||
|
||||
if (GetItemReuseTimer(item_id) < Timer::GetCurrentTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 Bot::GetItemReuseRemainingTime(uint32 item_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (GetItemReuseTimer(item_id) > Timer::GetCurrentTime()) {
|
||||
result = (GetItemReuseTimer(item_id) - Timer::GetCurrentTime());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::CalcSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
uint32 result = 0;
|
||||
|
||||
if (spells[spell_id].recast_time == 0 && spells[spell_id].recovery_time == 0) {
|
||||
return result;
|
||||
} else {
|
||||
if (spells[spell_id].recovery_time > spells[spell_id].recast_time) {
|
||||
result = spells[spell_id].recovery_time;
|
||||
} else {
|
||||
result = spells[spell_id].recast_time;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Bot::ClearDisciplineReuseTimer(uint16 spell_id)
|
||||
{
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid spell ID.'",
|
||||
spell_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (
|
||||
bot_timers[i].is_disc &&
|
||||
bot_timers[i].timer_value >= Timer::GetCurrentTime()
|
||||
) {
|
||||
if (
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
void Bot::ClearItemReuseTimer(uint32 item_id)
|
||||
{
|
||||
const EQ::ItemData* item;
|
||||
|
||||
if (item_id) {
|
||||
item = database.GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid item ID.",
|
||||
item_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (bot_timers[i].is_item && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
|
||||
if (
|
||||
!item_id ||
|
||||
(
|
||||
(
|
||||
item->RecastType != 0 &&
|
||||
item->RecastType == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].item_id == item_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
void Bot::ClearSpellRecastTimer(uint16 spell_id)
|
||||
{
|
||||
if (spell_id && !IsValidSpell(spell_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is not a valid spell ID.",
|
||||
spell_id
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (int i = 0; i < bot_timers.size(); i++) {
|
||||
if (bot_timers[i].is_spell && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
|
||||
if (
|
||||
!spell_id ||
|
||||
(
|
||||
(
|
||||
spells[spell_id].timer_id != 0 &&
|
||||
spells[spell_id].timer_id == bot_timers[i].timer_id
|
||||
) ||
|
||||
bot_timers[i].spell_id == spell_id
|
||||
)
|
||||
) {
|
||||
bot_timers[i].timer_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearExpiredTimers();
|
||||
}
|
||||
|
||||
|
||||
void Bot::ClearExpiredTimers()
|
||||
{
|
||||
if (!bot_timers.empty()) {
|
||||
int current = 0;
|
||||
int end = bot_timers.size();
|
||||
|
||||
while (current < end) {
|
||||
if (bot_timers[current].timer_value < Timer::GetCurrentTime()) {
|
||||
bot_timers.erase(bot_timers.begin() + current);
|
||||
} else {
|
||||
current++;
|
||||
}
|
||||
|
||||
end = bot_timers.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::TryItemClick(uint16 slot_id)
|
||||
{
|
||||
if (!GetOwner()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *inst = GetClickItem(slot_id);
|
||||
|
||||
if (!inst) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *item = inst->GetItem();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckItemReuseTimer(item->ID)) {
|
||||
uint32 remaining_time = (GetItemReuseRemainingTime(item->ID) / 1000);
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I can use this item in {}.",
|
||||
Strings::SecondsToTime(remaining_time)
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
DoItemClick(item, slot_id);
|
||||
}
|
||||
|
||||
EQ::ItemInstance *Bot::GetClickItem(uint16 slot_id)
|
||||
{
|
||||
EQ::ItemInstance* inst = nullptr;
|
||||
const EQ::ItemData* item = nullptr;
|
||||
|
||||
inst = GetBotItem(slot_id);
|
||||
|
||||
if (!inst || !inst->GetItem()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
item = inst->GetItem();
|
||||
|
||||
if (item->ID == MAG_EPIC_1_0 && !RuleB(Bots, CanClickMageEpicV1)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is currently disabled for bots to click.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->Click.Effect <= 0) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} does not have a clickable effect.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsValidSpell(item->Click.Effect)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} does not have a valid clickable effect.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->ReqLevel > GetLevel()) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I am below the level requirement of {} for {}.",
|
||||
item->ReqLevel,
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (item->Click.Level2 > GetLevel()) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"I must be level {} to use {}.",
|
||||
item->Click.Level2,
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"{} is out of charges.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
void Bot::DoItemClick(const EQ::ItemData *item, uint16 slot_id)
|
||||
{
|
||||
bool is_casting_bard_song = false;
|
||||
Mob* tar = (GetOwner()->GetTarget() ? GetOwner()->GetTarget() : this);
|
||||
|
||||
if (IsCasting()) {
|
||||
InterruptSpell();
|
||||
}
|
||||
|
||||
SetIsUsingItemClick(true);
|
||||
|
||||
BotGroupSay(
|
||||
this,
|
||||
fmt::format(
|
||||
"Attempting to cast [{}] on {}.",
|
||||
spells[item->Click.Effect].name,
|
||||
tar->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (!IsCastWhileInvisibleSpell(item->Click.Effect)) {
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
if (GetClass() == Class::Bard && IsCasting() && casting_spell_slot < EQ::spells::CastingSlot::MaxGems) {
|
||||
is_casting_bard_song = true;
|
||||
}
|
||||
|
||||
if (GetClass() == Class::Bard) {
|
||||
DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay);
|
||||
} else {
|
||||
if (!CastSpell(item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, item->CastTime, 0, 0, slot_id)) {
|
||||
OwnerMessage(
|
||||
fmt::format(
|
||||
"Casting failed for {}. This could be due to zone restrictions, target restrictions or other limiting factors.",
|
||||
item->Name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
|
||||
43
zone/bot.h
43
zone/bot.h
@ -42,13 +42,12 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500; // as DSq value (50 uni
|
||||
|
||||
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
|
||||
|
||||
constexpr uint32 MAG_EPIC_1_0 = 28034;
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
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
|
||||
constexpr int MaxSpellTimer = 15;
|
||||
constexpr int MaxDisciplineTimer = 10;
|
||||
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||
constexpr int NegativeItemReuse = -1; // Unlinked timer for items
|
||||
|
||||
// nHSND negative Healer/Slower/Nuker/Doter
|
||||
// pH positive Healer
|
||||
@ -222,6 +221,8 @@ public:
|
||||
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
||||
bool GetPullingFlag() const { return m_pulling_flag; }
|
||||
bool GetReturningFlag() const { return m_returning_flag; }
|
||||
bool GetIsUsingItemClick() { return is_using_item_click; }
|
||||
void SetIsUsingItemClick(bool flag = true) { is_using_item_click = flag; }
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
|
||||
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
|
||||
@ -286,6 +287,10 @@ public:
|
||||
void SetEndurance(int32 newEnd) override;
|
||||
void DoEnduranceUpkeep();
|
||||
|
||||
void TryItemClick(uint16 slot_id);
|
||||
EQ::ItemInstance* GetClickItem(uint16 slot_id);
|
||||
void DoItemClick(const EQ::ItemData* inst, uint16 slot_id);
|
||||
|
||||
bool AI_AddBotSpells(uint32 bot_spell_id);
|
||||
void AddSpellToBotList(
|
||||
int16 iPriority,
|
||||
@ -408,11 +413,6 @@ public:
|
||||
static Bot* GetFirstBotInGroup(Group* group);
|
||||
static void ProcessClientZoneChange(Client* botOwner);
|
||||
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
|
||||
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
|
||||
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
|
||||
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
|
||||
|
||||
//Raid methods
|
||||
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
|
||||
@ -612,8 +612,23 @@ public:
|
||||
_botStance = EQ::constants::stancePassive;
|
||||
}
|
||||
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
|
||||
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||
uint32 GetSpellRecastTimer(uint16 spell_id = 0);
|
||||
bool CheckSpellRecastTimer(uint16 spell_id = 0);
|
||||
uint32 GetSpellRecastRemainingTime(uint16 spell_id = 0);
|
||||
void SetSpellRecastTimer(uint16 spell_id, int32 recast_delay = 0);
|
||||
uint32 CalcSpellRecastTimer(uint16 spell_id);
|
||||
uint32 GetDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
bool CheckDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
uint32 GetDisciplineReuseRemainingTime(uint16 spell_id = 0);
|
||||
void SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer = 0);
|
||||
uint32 GetItemReuseTimer(uint32 item_id = 0);
|
||||
bool CheckItemReuseTimer(uint32 item_id = 0);
|
||||
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer = 0);
|
||||
void ClearDisciplineReuseTimer(uint16 spell_id = 0);
|
||||
void ClearItemReuseTimer(uint32 item_id = 0);
|
||||
void ClearSpellRecastTimer(uint16 spell_id = 0);
|
||||
uint32 GetItemReuseRemainingTime(uint32 item_id = 0);
|
||||
void ClearExpiredTimers();
|
||||
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
void SetBeardColor(uint8 value) { beardcolor = value; }
|
||||
@ -713,7 +728,8 @@ public:
|
||||
|
||||
// New accessors for BotDatabase access
|
||||
bool DeleteBot();
|
||||
uint32* GetTimers() { return timers; }
|
||||
std::vector<BotTimer_Struct> GetBotTimers() { return bot_timers; }
|
||||
void SetBotTimers(std::vector<BotTimer_Struct> timers) { bot_timers = timers; }
|
||||
uint32 GetLastZoneID() const { return _lastZoneId; }
|
||||
int32 GetBaseAC() const { return _baseAC; }
|
||||
int32 GetBaseATK() const { return _baseATK; }
|
||||
@ -828,6 +844,7 @@ protected:
|
||||
|
||||
std::vector<BotSpells_Struct> AIBot_spells;
|
||||
std::vector<BotSpells_Struct> AIBot_spells_enforced;
|
||||
std::vector<BotTimer_Struct> bot_timers;
|
||||
|
||||
private:
|
||||
// Class Members
|
||||
@ -861,7 +878,6 @@ private:
|
||||
int32 cur_end;
|
||||
int32 max_end;
|
||||
int32 end_regen;
|
||||
uint32 timers[MaxTimer];
|
||||
|
||||
Timer m_evade_timer; // can be moved to pTimers at some point
|
||||
Timer m_alt_combat_hate_timer;
|
||||
@ -875,6 +891,7 @@ private:
|
||||
bool m_pull_flag;
|
||||
bool m_pulling_flag;
|
||||
bool m_returning_flag;
|
||||
bool is_using_item_click;
|
||||
eStandingPetOrder m_previous_pet_order;
|
||||
uint32 m_bot_caster_range;
|
||||
BotCastingRoles m_CastingRoles;
|
||||
|
||||
@ -1375,6 +1375,7 @@ int bot_command_init(void)
|
||||
bot_command_add("casterrange", "Controls the range casters will try to stay away from a mob (if too far, they will skip spells that are out-of-range)", AccountStatus::Player, bot_command_caster_range) ||
|
||||
bot_command_add("charm", "Attempts to have a bot charm your target", AccountStatus::Player, bot_command_charm) ||
|
||||
bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_subcommand_circle) ||
|
||||
bot_command_add("clickitem", "Orders your targeted bot to click the item in the provided inventory slot.", AccountStatus::Player, bot_command_click_item) ||
|
||||
bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) ||
|
||||
bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) ||
|
||||
bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) ||
|
||||
@ -1444,6 +1445,7 @@ int bot_command_init(void)
|
||||
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) ||
|
||||
bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) ||
|
||||
bot_command_add("taunt", "Toggles taunt use by a bot", AccountStatus::Player, bot_command_taunt) ||
|
||||
bot_command_add("timer", "Checks or clears timers of the chosen type.", AccountStatus::GMMgmt, bot_command_timer) ||
|
||||
bot_command_add("track", "Orders a capable bot to track enemies", AccountStatus::Player, bot_command_track) ||
|
||||
bot_command_add("viewcombos", "Views bot race class combinations", AccountStatus::Player, bot_command_view_combos) ||
|
||||
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", AccountStatus::Player, bot_command_water_breathing)
|
||||
@ -2832,7 +2834,7 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "%i of %i bots have used aggressive disciplines", success_count, candidate_count);
|
||||
c->Message(Chat::White, "%i of %i bots have attempted to use aggressive disciplines", success_count, candidate_count);
|
||||
}
|
||||
|
||||
void bot_command_apply_poison(Client *c, const Seperator *sep)
|
||||
@ -3332,7 +3334,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "%i of %i bots have used defensive disciplines", success_count, candidate_count);
|
||||
c->Message(Chat::White, "%i of %i bots have attempted to use defensive disciplines", success_count, candidate_count);
|
||||
}
|
||||
|
||||
void bot_command_depart(Client *c, const Seperator *sep)
|
||||
@ -5286,6 +5288,194 @@ void bot_command_taunt(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_timer(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_command_timer", sep->arg[0], "timer"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: %s [clear | has | set] [disc | item | spell] [timer ID | item ID | spell ID | all] [optional ms for set] [actionable].", sep->arg[0]);
|
||||
c->Message(Chat::White, "When setting, you can leave the value blank to use the default for the item or specify a value in ms to set the timer to.");
|
||||
c->Message(Chat::White, "Returns or sets the provided timer(s) for the selected bot(s) or clears the selected timer(s) for the selected bot(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
const int ab_mask = ActionableBots::ABM_Type1;
|
||||
|
||||
std::string arg1 = sep->arg[1];
|
||||
std::string arg2 = sep->arg[2];
|
||||
std::string arg3 = sep->arg[3];
|
||||
int ab_arg = 4;
|
||||
bool clear = false;
|
||||
bool has = false;
|
||||
bool set = false;
|
||||
bool disc = false;
|
||||
bool item = false;
|
||||
bool spell = false;
|
||||
uint32 timer_id = 0;
|
||||
uint32 timer_value = 0;
|
||||
bool all = false;
|
||||
|
||||
if (!arg1.compare("clear")) {
|
||||
clear = true;
|
||||
}
|
||||
else if (!arg1.compare("has")) {
|
||||
has = true;
|
||||
}
|
||||
else if (!arg1.compare("set")) {
|
||||
set = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect argument, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg2.compare("disc")) {
|
||||
disc = true;
|
||||
}
|
||||
else if (!arg2.compare("item")) {
|
||||
item = true;
|
||||
}
|
||||
else if (!arg2.compare("spell")) {
|
||||
spell = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect timer type, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sep->IsNumber(3)) {
|
||||
timer_id = atoi(sep->arg[3]);
|
||||
if (timer_id < 0) {
|
||||
c->Message(Chat::White, "You cannot use negative numbers.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!arg3.compare("all")) {
|
||||
if (has || set) {
|
||||
c->Message(Chat::White, "You can only use 'all' for clearing timers.");
|
||||
return;
|
||||
}
|
||||
|
||||
all = true;
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Incorrect ID option, use %s help for a list of options.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
if (sep->IsNumber(4)) {
|
||||
ab_arg = 5;
|
||||
timer_value = atoi(sep->arg[4]);
|
||||
if (timer_value <= 0) {
|
||||
c->Message(Chat::White, "You cannot use 0 or negative numbers.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string class_race_arg = sep->arg[ab_arg];
|
||||
bool class_race_check = false;
|
||||
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
|
||||
class_race_check = true;
|
||||
}
|
||||
|
||||
std::list<Bot*> sbl;
|
||||
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
|
||||
return;
|
||||
}
|
||||
sbl.remove(nullptr);
|
||||
|
||||
for (auto my_bot : sbl) {
|
||||
bool found = false;
|
||||
|
||||
if (clear) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'Clearing {} timer{}'",
|
||||
my_bot->GetCleanName(),
|
||||
disc ? "Discipline" : item ? "Item" : "Spell",
|
||||
(all ? "s." : ".")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (disc) {
|
||||
my_bot->ClearDisciplineReuseTimer(timer_id);
|
||||
}
|
||||
else if (item) {
|
||||
my_bot->ClearItemReuseTimer(timer_id);
|
||||
}
|
||||
else if (spell) {
|
||||
my_bot->ClearSpellRecastTimer(timer_id);
|
||||
}
|
||||
}
|
||||
else if (has) {
|
||||
uint32 remaining_time;
|
||||
std::string time_string = "";
|
||||
|
||||
if (disc) {
|
||||
if (!my_bot->CheckDisciplineReuseTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetDisciplineReuseRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else if (item) {
|
||||
if (!my_bot->CheckItemReuseTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetItemReuseRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else if (spell) {
|
||||
if (!my_bot->CheckSpellRecastTimer(timer_id)) {
|
||||
remaining_time = my_bot->GetSpellRecastRemainingTime(timer_id) / 1000;
|
||||
time_string = Strings::SecondsToTime(remaining_time);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'I {}{}{}'",
|
||||
my_bot->GetCleanName(),
|
||||
(!found ? " do not have that timer currently" : " have "),
|
||||
(!found ? "" : time_string),
|
||||
(!found ? "." : " remaining.")
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
else if (set) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} says, 'Setting {} timer{} for {} to {}.'",
|
||||
my_bot->GetCleanName(),
|
||||
disc ? "Discipline" : item ? "Item" : "Spell",
|
||||
(all ? "s" : ""),
|
||||
timer_id,
|
||||
timer_value ? std::to_string(timer_value) : "the default value"
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (disc) {
|
||||
my_bot->ClearDisciplineReuseTimer(timer_id);
|
||||
my_bot->SetDisciplineReuseTimer(timer_id, timer_value);
|
||||
}
|
||||
else if (item) {
|
||||
my_bot->ClearItemReuseTimer(timer_id);
|
||||
my_bot->SetItemReuseTimer(timer_id, timer_value);
|
||||
}
|
||||
else if (spell) {
|
||||
my_bot->ClearSpellRecastTimer(timer_id);
|
||||
my_bot->SetSpellRecastTimer(timer_id, timer_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_track(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track"))
|
||||
@ -10530,6 +10720,61 @@ void bot_command_caster_range(Client* c, const Seperator* sep)
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_click_item(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (!RuleB(Bots, BotsCanClickItems)) {
|
||||
c->Message(Chat::White, "The ability for bots to click equipped items is currently disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(Chat::White, "usage: <slot id> %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
|
||||
c->Message(Chat::White, "This will cause the selected bots to click the item in the given slot ID.");
|
||||
c->Message(Chat::White, "Use ^invlist to see their items along with slot IDs.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sep->IsNumber(1)) {
|
||||
c->Message(Chat::Yellow, "You must specify a slot ID. Use %s help for more information.", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const int ab_mask = ActionableBots::ABM_Type1;
|
||||
|
||||
int ab_arg = 1;
|
||||
uint32 slot_id = 0;
|
||||
|
||||
if (sep->IsNumber(1)) {
|
||||
ab_arg = 2;
|
||||
slot_id = atoi(sep->arg[1]);
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
|
||||
c->Message(Chat::Yellow, "You must specify a valid inventory slot from 0 to 22. Use %s help for more information", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string class_race_arg = sep->arg[ab_arg];
|
||||
bool class_race_check = false;
|
||||
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
|
||||
class_race_check = true;
|
||||
}
|
||||
|
||||
std::list<Bot*> sbl;
|
||||
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
|
||||
return;
|
||||
}
|
||||
sbl.remove(nullptr);
|
||||
|
||||
for (auto my_bot : sbl) {
|
||||
if (RuleI(Bots, BotsClickItemsMinLvl) > my_bot->GetLevel()) {
|
||||
c->Message(Chat::White, "%s must be level %i to use clickable items.", my_bot->GetCleanName(), RuleI(Bots, BotsClickItemsMinLvl));
|
||||
continue;
|
||||
}
|
||||
|
||||
my_bot->TryItemClick(slot_id);
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_pickpocket(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) {
|
||||
|
||||
@ -554,6 +554,7 @@ void bot_command_bind_affinity(Client *c, const Seperator *sep);
|
||||
void bot_command_bot(Client *c, const Seperator *sep);
|
||||
void bot_command_caster_range(Client* c, const Seperator* sep);
|
||||
void bot_command_charm(Client *c, const Seperator *sep);
|
||||
void bot_command_click_item(Client* c, const Seperator* sep);
|
||||
void bot_command_cure(Client *c, const Seperator *sep);
|
||||
void bot_command_defensive(Client *c, const Seperator *sep);
|
||||
void bot_command_depart(Client *c, const Seperator *sep);
|
||||
@ -595,6 +596,7 @@ void bot_command_enforce_spell_list(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_timer(Client* c, const Seperator* sep);
|
||||
void bot_command_track(Client *c, const Seperator *sep);
|
||||
void bot_command_view_combos(Client *c, const Seperator *sep);
|
||||
void bot_command_water_breathing(Client *c, const Seperator *sep);
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "../common/repositories/bot_data_repository.h"
|
||||
#include "../common/repositories/bot_inventories_repository.h"
|
||||
#include "../common/repositories/bot_timers_repository.h"
|
||||
|
||||
#include "zonedb.h"
|
||||
#include "bot.h"
|
||||
@ -917,45 +918,39 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
|
||||
if (!bot_inst)
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"SELECT"
|
||||
" IfNull(bt.`timer_id`, '0') As timer_id,"
|
||||
" IfNull(bt.`timer_value`, '0') As timer_value,"
|
||||
" IfNull(MAX(sn.`recast_time`), '0') AS MaxTimer"
|
||||
" FROM `bot_timers` bt, `spells_new` sn"
|
||||
" WHERE bt.`bot_id` = '%u' AND sn.`EndurTimerIndex` = ("
|
||||
"SELECT case"
|
||||
" WHEN timer_id > '%i' THEN timer_id - '%i'"
|
||||
" ELSE timer_id END AS timer_id"
|
||||
" FROM `bot_timers` WHERE `timer_id` = bt.`timer_id` AND `bot_id` = bt.`bot_id`" // double-check validity
|
||||
")"
|
||||
" AND sn.`classes%i` <= '%i'",
|
||||
bot_inst->GetBotID(),
|
||||
(DisciplineReuseStart - 1),
|
||||
(DisciplineReuseStart - 1),
|
||||
bot_inst->GetClass(),
|
||||
bot_inst->GetLevel()
|
||||
auto timers = BotTimersRepository::GetWhere(
|
||||
database,
|
||||
fmt::format("bot_id = {}", bot_inst->GetBotID())
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
if (!results.RowCount())
|
||||
return true;
|
||||
|
||||
uint32* bot_timers = bot_inst->GetTimers();
|
||||
if (!bot_timers)
|
||||
return false;
|
||||
std::vector<BotTimer_Struct> bot_timers;
|
||||
|
||||
int timer_id = 0;
|
||||
uint32 timer_value = 0;
|
||||
uint32 max_value = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
timer_id = Strings::ToInt(row[0]) - 1;
|
||||
timer_value = Strings::ToInt(row[1]);
|
||||
max_value = Strings::ToInt(row[2]);
|
||||
BotTimer_Struct t{};
|
||||
t.timer_id = 0;
|
||||
t.timer_value = 0;
|
||||
t.recast_time = 0;
|
||||
t.is_spell = false;
|
||||
t.is_disc = false;
|
||||
t.spell_id = 0;
|
||||
t.is_item = false;
|
||||
t.item_id = 0;
|
||||
|
||||
if (timer_id >= 0 && timer_id < MaxTimer && timer_value < (Timer::GetCurrentTime() + max_value))
|
||||
bot_timers[timer_id] = timer_value;
|
||||
for (auto& timer : timers) {
|
||||
if (t.timer_value < (Timer::GetCurrentTime() + t.recast_time)) {
|
||||
t.timer_id = timer.timer_id;
|
||||
t.timer_value = timer.timer_value;
|
||||
t.recast_time = timer.recast_time;
|
||||
t.is_spell = timer.is_spell ? true : false;
|
||||
t.is_disc = timer.is_disc ? true : false;
|
||||
t.spell_id = timer.spell_id;
|
||||
t.is_item = timer.is_item ? true : false;
|
||||
t.item_id = timer.item_id;
|
||||
bot_timers.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
bot_inst->SetBotTimers(bot_timers);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -963,26 +958,56 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
|
||||
|
||||
bool BotDatabase::SaveTimers(Bot* bot_inst)
|
||||
{
|
||||
if (!bot_inst)
|
||||
if (!bot_inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DeleteTimers(bot_inst->GetBotID()))
|
||||
if (!DeleteTimers(bot_inst->GetBotID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32* bot_timers = bot_inst->GetTimers();
|
||||
if (!bot_timers)
|
||||
return false;
|
||||
std::vector<BotTimer_Struct> bot_timers = bot_inst->GetBotTimers();
|
||||
|
||||
for (int timer_index = 0; timer_index < MaxTimer; ++timer_index) {
|
||||
if (bot_timers[timer_index] <= Timer::GetCurrentTime())
|
||||
continue;
|
||||
if (bot_timers.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('{}', '{}', '{}')",
|
||||
bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]
|
||||
std::vector<BotTimersRepository::BotTimers> timers;
|
||||
|
||||
if (!bot_timers.empty()) {
|
||||
for (auto & bot_timer : bot_timers) {
|
||||
if (bot_timer.timer_value <= Timer::GetCurrentTime()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto t = BotTimersRepository::BotTimers{
|
||||
.bot_id = bot_inst->GetBotID(),
|
||||
.timer_id = bot_timer.timer_id,
|
||||
.timer_value = bot_timer.timer_value,
|
||||
.recast_time = bot_timer.recast_time,
|
||||
.is_spell = bot_timer.is_spell ? true : false,
|
||||
.is_disc = bot_timer.is_disc ? true : false,
|
||||
.spell_id = bot_timer.spell_id,
|
||||
.is_item = bot_timer.is_item ? true : false,
|
||||
.item_id = bot_timer.item_id
|
||||
};
|
||||
|
||||
timers.push_back(t);
|
||||
}
|
||||
|
||||
if (timers.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// delete existing
|
||||
BotTimersRepository::DeleteWhere(
|
||||
database,
|
||||
fmt::format("bot_id = {}", bot_inst->GetBotID())
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
|
||||
// bulk insert current
|
||||
auto success = BotTimersRepository::InsertMany(database, timers);
|
||||
if (!success) {
|
||||
DeleteTimers(bot_inst->GetBotID());
|
||||
return false;
|
||||
}
|
||||
@ -993,13 +1018,14 @@ bool BotDatabase::SaveTimers(Bot* bot_inst)
|
||||
|
||||
bool BotDatabase::DeleteTimers(const uint32 bot_id)
|
||||
{
|
||||
if (!bot_id)
|
||||
if (!bot_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query = StringFormat("DELETE FROM `bot_timers` WHERE `bot_id` = '%u'", bot_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
auto success = BotTimersRepository::DeleteWhere(database, fmt::format("bot_id = {}", bot_id));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -81,4 +81,15 @@ struct BotSpells_Struct {
|
||||
uint8 bucket_comparison;
|
||||
};
|
||||
|
||||
struct BotTimer_Struct {
|
||||
uint32 timer_id;
|
||||
uint32 timer_value;
|
||||
uint32 recast_time;
|
||||
bool is_spell;
|
||||
bool is_disc;
|
||||
uint16 spell_id;
|
||||
bool is_item;
|
||||
uint32 item_id;
|
||||
};
|
||||
|
||||
#endif // BOT_STRUCTS
|
||||
|
||||
@ -108,7 +108,7 @@ bool Bot::BotCastSong(Mob* tar, uint8 botLevel) {
|
||||
auto iter : botSongList) {
|
||||
if (!iter.SpellId)
|
||||
continue;
|
||||
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
|
||||
if (!CheckSpellRecastTimer(iter.SpellId))
|
||||
continue;
|
||||
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
|
||||
continue;
|
||||
@ -142,7 +142,7 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
|
||||
auto iter : botSongList) {
|
||||
if (!iter.SpellId)
|
||||
continue;
|
||||
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
|
||||
if (!CheckSpellRecastTimer(iter.SpellId))
|
||||
continue;
|
||||
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
|
||||
continue;
|
||||
@ -174,7 +174,7 @@ bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpel
|
||||
for (auto iter : botSongList) {
|
||||
if (!iter.SpellId)
|
||||
continue;
|
||||
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
|
||||
if (!CheckSpellRecastTimer(iter.SpellId))
|
||||
continue;
|
||||
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
|
||||
continue;
|
||||
@ -312,7 +312,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) {
|
||||
if (!CheckSpellRecastTimer(iter.SpellId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -403,7 +403,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimers(this, s.SpellIndex))
|
||||
if (CheckSpellRecastTimer(s.SpellId))
|
||||
{
|
||||
|
||||
if (!(!tar->IsImmuneToSpell(s.SpellId, this) && tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
|
||||
@ -438,7 +438,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimers(this, s.SpellIndex)) {
|
||||
if (CheckSpellRecastTimer(s.SpellId)) {
|
||||
|
||||
if (!(!tar->IsImmuneToSpell(s.SpellId, this) &&
|
||||
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
|
||||
@ -652,7 +652,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimers(this, s.SpellIndex)) {
|
||||
if (CheckSpellRecastTimer(s.SpellId)) {
|
||||
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
|
||||
casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontBuffMeBefore);
|
||||
if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) {
|
||||
@ -947,7 +947,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckSpellRecastTimers(this, s.SpellIndex))
|
||||
if (CheckSpellRecastTimer(s.SpellId))
|
||||
{
|
||||
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
|
||||
|
||||
@ -1306,10 +1306,8 @@ bool Bot::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
||||
SetMana(hasMana);
|
||||
}
|
||||
else {
|
||||
AIBot_spells[i].time_cancast = Timer::GetCurrentTime() + spells[AIBot_spells[i].spellid].recast_time;
|
||||
|
||||
if (spells[AIBot_spells[i].spellid].timer_id > 0) {
|
||||
SetSpellRecastTimer(spells[AIBot_spells[i].spellid].timer_id, spells[AIBot_spells[i].spellid].recast_time);
|
||||
if (CalcSpellRecastTimer(AIBot_spells[i].spellid) > 0) {
|
||||
SetSpellRecastTimer(AIBot_spells[i].spellid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2044,7 +2042,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((botSpellList[i].type & spellType) && CheckSpellRecastTimers(botCaster, i)) {
|
||||
if ((botSpellList[i].type & spellType) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
|
||||
result.SpellId = botSpellList[i].spellid;
|
||||
result.SpellIndex = i;
|
||||
result.ManaCost = botSpellList[i].manacost;
|
||||
@ -2069,7 +2067,7 @@ BotSpell Bot::GetBestBotSpellForFastHeal(Bot *botCaster) {
|
||||
|
||||
for (auto botSpellListItr : botSpellList) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (IsFastHealSpell(botSpellListItr.SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)) {
|
||||
if (IsFastHealSpell(botSpellListItr.SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)) {
|
||||
result.SpellId = botSpellListItr.SpellId;
|
||||
result.SpellIndex = botSpellListItr.SpellIndex;
|
||||
result.ManaCost = botSpellListItr.ManaCost;
|
||||
@ -2106,7 +2104,7 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) {
|
||||
if (
|
||||
botSpellList[i].spellid == botSpellListItr.SpellId &&
|
||||
(botSpellList[i].type & SpellType_Heal) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr.SpellId;
|
||||
result.SpellIndex = botSpellListItr.SpellIndex;
|
||||
@ -2139,7 +2137,7 @@ BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsCompleteHealSpell(botSpellList[i].spellid) && CheckSpellRecastTimers(botCaster, i)) {
|
||||
if (IsCompleteHealSpell(botSpellList[i].spellid) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
|
||||
result.SpellId = botSpellList[i].spellid;
|
||||
result.SpellIndex = i;
|
||||
result.ManaCost = botSpellList[i].manacost;
|
||||
@ -2163,7 +2161,7 @@ BotSpell Bot::GetBestBotSpellForRegularSingleTargetHeal(Bot* botCaster) {
|
||||
|
||||
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
|
||||
if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
result.ManaCost = botSpellListItr->ManaCost;
|
||||
@ -2192,7 +2190,7 @@ BotSpell Bot::GetFirstBotSpellForSingleTargetHeal(Bot* botCaster) {
|
||||
IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) ||
|
||||
IsFastHealSpell(botSpellListItr->SpellId)
|
||||
) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2219,7 +2217,7 @@ BotSpell Bot::GetBestBotSpellForGroupHeal(Bot* botCaster) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (
|
||||
IsRegularGroupHealSpell(botSpellListItr->SpellId) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2257,7 +2255,7 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) {
|
||||
if (
|
||||
botSpellList[i].spellid == botSpellListItr->SpellId &&
|
||||
(botSpellList[i].type & SpellType_Heal) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2287,7 +2285,7 @@ BotSpell Bot::GetBestBotSpellForGroupCompleteHeal(Bot* botCaster) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (
|
||||
IsGroupCompleteHealSpell(botSpellListItr->SpellId) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2314,7 +2312,7 @@ BotSpell Bot::GetBestBotSpellForMez(Bot* botCaster) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (
|
||||
IsMesmerizeSpell(botSpellListItr->SpellId) &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2343,7 +2341,7 @@ BotSpell Bot::GetBestBotSpellForMagicBasedSlow(Bot* botCaster) {
|
||||
if (
|
||||
IsSlowSpell(botSpellListItr->SpellId) &&
|
||||
spells[botSpellListItr->SpellId].resist_type == RESIST_MAGIC &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2371,7 +2369,7 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) {
|
||||
if (
|
||||
IsSlowSpell(botSpellListItr->SpellId) &&
|
||||
spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE &&
|
||||
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
|
||||
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
|
||||
) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2437,7 +2435,7 @@ BotSpell Bot::GetBestBotMagicianPetSpell(Bot *botCaster) {
|
||||
|
||||
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (IsSummonPetSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
|
||||
if (IsSummonPetSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
|
||||
if (!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2546,7 +2544,7 @@ BotSpell Bot::GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType
|
||||
|
||||
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
|
||||
if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
result.ManaCost = botSpellListItr->ManaCost;
|
||||
@ -2574,7 +2572,7 @@ BotSpell Bot::GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType
|
||||
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr)
|
||||
{
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
if (IsStunSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex))
|
||||
if (IsStunSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId))
|
||||
{
|
||||
result.SpellId = botSpellListItr->SpellId;
|
||||
result.SpellIndex = botSpellListItr->SpellIndex;
|
||||
@ -2614,7 +2612,7 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
bool spellSelected = false;
|
||||
|
||||
if (CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
|
||||
if (botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
|
||||
if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
@ -2682,7 +2680,7 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) {
|
||||
if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid))
|
||||
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
|
||||
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
|
||||
&& CheckSpellRecastTimers(botCaster, i)) {
|
||||
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
|
||||
result.SpellId = botSpellList[i].spellid;
|
||||
result.SpellIndex = i;
|
||||
result.ManaCost = botSpellList[i].manacost;
|
||||
@ -2735,7 +2733,7 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) {
|
||||
|| (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)))
|
||||
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
|
||||
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
|
||||
&& CheckSpellRecastTimers(botCaster, i)) {
|
||||
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
|
||||
result.SpellId = botSpellList[i].spellid;
|
||||
result.SpellIndex = i;
|
||||
result.ManaCost = botSpellList[i].manacost;
|
||||
@ -2786,31 +2784,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
|
||||
for (std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
|
||||
BotSpell selectedBotSpell = *itr;
|
||||
|
||||
if (IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
|
||||
if (IsGroupSpell(itr->SpellId) && botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
|
||||
if (selectedBotSpell.SpellId == 0)
|
||||
continue;
|
||||
|
||||
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
|
||||
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
|
||||
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
|
||||
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
|
||||
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
|
||||
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
|
||||
if (spellSelected)
|
||||
{
|
||||
result.SpellId = itr->SpellId;
|
||||
result.SpellIndex = itr->SpellIndex;
|
||||
result.ManaCost = itr->ManaCost;
|
||||
result.SpellId = selectedBotSpell.SpellId;
|
||||
result.SpellIndex = selectedBotSpell.SpellIndex;
|
||||
result.ManaCost = selectedBotSpell.ManaCost;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2823,31 +2821,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
|
||||
for(std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
|
||||
BotSpell selectedBotSpell = *itr;
|
||||
|
||||
if (CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
|
||||
if (botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
|
||||
if (selectedBotSpell.SpellId == 0)
|
||||
continue;
|
||||
|
||||
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
|
||||
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
|
||||
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
|
||||
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
|
||||
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
|
||||
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
|
||||
spellSelected = true;
|
||||
}
|
||||
|
||||
if (spellSelected)
|
||||
{
|
||||
result.SpellId = itr->SpellId;
|
||||
result.SpellIndex = itr->SpellIndex;
|
||||
result.ManaCost = itr->ManaCost;
|
||||
result.SpellId = selectedBotSpell.SpellId;
|
||||
result.SpellIndex = selectedBotSpell.SpellIndex;
|
||||
result.ManaCost = selectedBotSpell.ManaCost;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2859,69 +2857,6 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Bot::SetSpellRecastTimer(int timer_index, int32 recast_delay) {
|
||||
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
|
||||
timers[timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
|
||||
}
|
||||
}
|
||||
|
||||
int32 Bot::GetSpellRecastTimer(Bot *caster, int timer_index) {
|
||||
int32 result = 0;
|
||||
if (caster) {
|
||||
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
|
||||
result = caster->timers[timer_index - 1];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckSpellRecastTimers(Bot *caster, int SpellIndex) {
|
||||
if (caster) {
|
||||
if (caster->AIBot_spells[SpellIndex].time_cancast < Timer::GetCurrentTime()) { //checks spell recast
|
||||
if (GetSpellRecastTimer(caster, spells[caster->AIBot_spells[SpellIndex].spellid].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
|
||||
return true; //can cast spell
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::SetDisciplineRecastTimer(int timer_index, int32 recast_delay) {
|
||||
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
|
||||
timers[DisciplineReuseStart + timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
|
||||
}
|
||||
}
|
||||
|
||||
int32 Bot::GetDisciplineRecastTimer(Bot *caster, int timer_index) {
|
||||
int32 result = 0;
|
||||
if (caster) {
|
||||
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
|
||||
result = caster->timers[DisciplineReuseStart + timer_index - 1];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 Bot::GetDisciplineRemainingTime(Bot *caster, int timer_index) {
|
||||
int32 result = 0;
|
||||
if (caster) {
|
||||
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
|
||||
if (GetDisciplineRecastTimer(caster, timer_index) > Timer::GetCurrentTime())
|
||||
result = GetDisciplineRecastTimer(caster, timer_index) - Timer::GetCurrentTime();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) {
|
||||
if (caster) {
|
||||
if (GetDisciplineRecastTimer(caster, timer_index) < Timer::GetCurrentTime()) { //checks for spells on the same timer
|
||||
return true; //can cast spell
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
|
||||
{
|
||||
uint8 spell_type_index = SPELL_TYPE_COUNT;
|
||||
|
||||
110
zone/lua_bot.cpp
110
zone/lua_bot.cpp
@ -389,6 +389,96 @@ int Lua_Bot::GetRawItemAC() {
|
||||
return self->GetRawItemAC();
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearDisciplineReuseTimer() {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearDisciplineReuseTimer();
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearDisciplineReuseTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearItemReuseTimer() {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearItemReuseTimer();
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearItemReuseTimer(uint32 item_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearItemReuseTimer(item_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearSpellRecastTimer() {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearSpellRecastTimer();
|
||||
}
|
||||
|
||||
void Lua_Bot::ClearSpellRecastTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->ClearSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetDisciplineReuseTimer() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDisciplineReuseRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetDisciplineReuseTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDisciplineReuseRemainingTime(spell_id);
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetItemReuseTimer() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetItemReuseRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetItemReuseTimer(uint32 item_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetItemReuseRemainingTime(item_id);
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetSpellRecastTimer() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSpellRecastRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Lua_Bot::GetSpellRecastTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSpellRecastRemainingTime(spell_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id, uint32 reuse_timer) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetDisciplineReuseTimer(spell_id, reuse_timer);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetItemReuseTimer(uint32 item_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetItemReuseTimer(item_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetItemReuseTimer(item_id, reuse_timer);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id, uint32 recast_delay) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->SetSpellRecastTimer(spell_id, recast_delay);
|
||||
}
|
||||
|
||||
bool Lua_Bot::IsGrouped() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsGrouped();
|
||||
@ -600,6 +690,12 @@ luabind::scope lua_register_bot() {
|
||||
.def("ApplySpellRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::ApplySpellRaid)
|
||||
.def("Camp", (void(Lua_Bot::*)(void))&Lua_Bot::Camp)
|
||||
.def("Camp", (void(Lua_Bot::*)(bool))&Lua_Bot::Camp)
|
||||
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearDisciplineReuseTimer)
|
||||
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearDisciplineReuseTimer)
|
||||
.def("ClearItemReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearItemReuseTimer)
|
||||
.def("ClearItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::ClearItemReuseTimer)
|
||||
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearSpellRecastTimer)
|
||||
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearSpellRecastTimer)
|
||||
.def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem)
|
||||
.def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
|
||||
.def("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket)
|
||||
@ -623,6 +719,8 @@ luabind::scope lua_register_bot() {
|
||||
.def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID)
|
||||
.def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem)
|
||||
.def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot)
|
||||
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetDisciplineReuseTimer)
|
||||
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetDisciplineReuseTimer)
|
||||
.def("GetBucket", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucket)
|
||||
.def("GetBucketExpires", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketExpires)
|
||||
.def("GetBucketRemaining", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketRemaining)
|
||||
@ -633,13 +731,17 @@ luabind::scope lua_register_bot() {
|
||||
.def("GetInstrumentMod", (int(Lua_Bot::*)(int))&Lua_Bot::GetInstrumentMod)
|
||||
.def("GetItemAt", (Lua_ItemInst(Lua_Bot::*)(int16))&Lua_Bot::GetItemAt)
|
||||
.def("GetItemIDAt", (int(Lua_Bot::*)(int16))&Lua_Bot::GetItemIDAt)
|
||||
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetItemReuseTimer)
|
||||
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::GetItemReuseTimer)
|
||||
.def("GetOwner", (Lua_Mob(Lua_Bot::*)(void))&Lua_Bot::GetOwner)
|
||||
.def("GetRaceAbbreviation", (std::string(Lua_Bot::*)(void))&Lua_Bot::GetRaceAbbreviation)
|
||||
.def("GetRawItemAC", (int(Lua_Bot::*)(void))&Lua_Bot::GetRawItemAC)
|
||||
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
|
||||
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetSpellRecastTimer)
|
||||
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetSpellRecastTimer)
|
||||
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
|
||||
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
|
||||
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16)) & Lua_Bot::HasBotSpellEntry)
|
||||
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16))&Lua_Bot::HasBotSpellEntry)
|
||||
.def("HasItemEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasItemEquippedByID)
|
||||
.def("IsGrouped", (bool(Lua_Bot::*)(void))&Lua_Bot::IsGrouped)
|
||||
.def("IsSitting", (bool(Lua_Bot::*)(void))&Lua_Bot::IsSitting)
|
||||
@ -655,6 +757,10 @@ luabind::scope lua_register_bot() {
|
||||
.def("SetBucket", (void(Lua_Bot::*)(std::string,std::string,std::string))&Lua_Bot::SetBucket)
|
||||
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int))&Lua_Bot::SetExpansionBitmask)
|
||||
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int,bool))&Lua_Bot::SetExpansionBitmask)
|
||||
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetDisciplineReuseTimer)
|
||||
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetDisciplineReuseTimer)
|
||||
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::SetItemReuseTimer)
|
||||
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32, uint32))&Lua_Bot::SetItemReuseTimer)
|
||||
.def("SetSpellDuration", (void(Lua_Bot::*)(int))&Lua_Bot::SetSpellDuration)
|
||||
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int))&Lua_Bot::SetSpellDuration)
|
||||
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDuration)
|
||||
@ -668,6 +774,8 @@ luabind::scope lua_register_bot() {
|
||||
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDurationRaid)
|
||||
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool))&Lua_Bot::SetSpellDurationRaid)
|
||||
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid)
|
||||
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetSpellRecastTimer)
|
||||
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetSpellRecastTimer)
|
||||
.def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload)
|
||||
.def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload)
|
||||
.def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal)
|
||||
|
||||
@ -107,6 +107,25 @@ public:
|
||||
void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets);
|
||||
void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets, bool is_raid_group_only);
|
||||
|
||||
void ClearDisciplineReuseTimer();
|
||||
void ClearDisciplineReuseTimer(uint16 spell_id);
|
||||
void ClearItemReuseTimer();
|
||||
void ClearItemReuseTimer(uint32 item_id);
|
||||
void ClearSpellRecastTimer();
|
||||
void ClearSpellRecastTimer(uint16 spell_id);
|
||||
uint32 GetDisciplineReuseTimer();
|
||||
uint32 GetDisciplineReuseTimer(uint16 spell_id);
|
||||
uint32 GetItemReuseTimer();
|
||||
uint32 GetItemReuseTimer(uint32 item_id);
|
||||
uint32 GetSpellRecastTimer();
|
||||
uint32 GetSpellRecastTimer(uint16 spell_id);
|
||||
void SetDisciplineReuseTimer(uint16 spell_id);
|
||||
void SetDisciplineReuseTimer(uint16 spell_id, uint32 reuse_timer);
|
||||
void SetItemReuseTimer(uint32 item_id);
|
||||
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer);
|
||||
void SetSpellRecastTimer(uint16 spell_id);
|
||||
void SetSpellRecastTimer(uint16 spell_id, uint32 reuse_timer);
|
||||
|
||||
int CountAugmentEquippedByID(uint32 item_id);
|
||||
int CountItemEquippedByID(uint32 item_id);
|
||||
bool HasAugmentEquippedByID(uint32 item_id);
|
||||
|
||||
@ -255,11 +255,101 @@ void Perl_Bot_Stand(Bot* self) // @categories Script Utility
|
||||
self->Stand();
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetSpellRecastTimer(Bot* self)
|
||||
{
|
||||
return self->GetSpellRecastRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetSpellRecastTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->GetSpellRecastRemainingTime(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearSpellRecastTimer(Bot* self)
|
||||
{
|
||||
return self->ClearSpellRecastTimer();
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearSpellRecastTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->ClearSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetDisciplineReuseTimer(Bot* self)
|
||||
{
|
||||
return self->GetDisciplineReuseRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetDisciplineReuseTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->GetDisciplineReuseRemainingTime(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearDisciplineReuseTimer(Bot* self)
|
||||
{
|
||||
return self->ClearDisciplineReuseTimer();
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearDisciplineReuseTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->ClearDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetDisciplineReuseTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->SetDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetDisciplineReuseTimer(Bot* self, uint16 spell_id, uint32 recast_delay)
|
||||
{
|
||||
return self->SetDisciplineReuseTimer(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetItemReuseTimer(Bot* self, uint32 item_id)
|
||||
{
|
||||
return self->SetItemReuseTimer(item_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetItemReuseTimer(Bot* self, uint32 item_id, uint32 reuse_timer)
|
||||
{
|
||||
return self->SetItemReuseTimer(item_id, reuse_timer);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetSpellRecastTimer(Bot* self, uint16 spell_id)
|
||||
{
|
||||
return self->SetSpellRecastTimer(spell_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_SetSpellRecastTimer(Bot* self, uint16 spell_id, uint32 recast_delay)
|
||||
{
|
||||
return self->SetSpellRecastTimer(spell_id, recast_delay);
|
||||
}
|
||||
|
||||
int Perl_Bot_GetItemIDAt(Bot* self, int16 slot_id) // @categories Inventory and Items
|
||||
{
|
||||
return self->GetItemIDAt(slot_id);
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetItemReuseTimer(Bot* self)
|
||||
{
|
||||
return self->GetItemReuseRemainingTime();
|
||||
}
|
||||
|
||||
uint32 Perl_Bot_GetItemReuseTimer(Bot* self, uint32 item_id)
|
||||
{
|
||||
return self->GetItemReuseRemainingTime(item_id);
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearItemReuseTimer(Bot* self)
|
||||
{
|
||||
return self->ClearItemReuseTimer();
|
||||
}
|
||||
|
||||
void Perl_Bot_ClearItemReuseTimer(Bot* self, uint32 item_id)
|
||||
{
|
||||
return self->ClearItemReuseTimer(item_id);
|
||||
}
|
||||
|
||||
int Perl_Bot_GetAugmentIDAt(Bot* self, int16 slot_id, uint8 aug_slot) // @categories Inventory and Items
|
||||
{
|
||||
return self->GetAugmentIDAt(slot_id, aug_slot);
|
||||
@ -555,7 +645,13 @@ void perl_register_bot()
|
||||
package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool))&Perl_Bot_ApplySpellRaid);
|
||||
package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_ApplySpellRaid);
|
||||
package.add("Camp", (void(*)(Bot*))&Perl_Bot_Camp);
|
||||
package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp);
|
||||
package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp);
|
||||
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearDisciplineReuseTimer);
|
||||
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*, uint16))&Perl_Bot_ClearDisciplineReuseTimer);
|
||||
package.add("ClearItemReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearItemReuseTimer);
|
||||
package.add("ClearItemReuseTimer", (void(*)(Bot*, uint32))&Perl_Bot_ClearItemReuseTimer);
|
||||
package.add("ClearSpellRecastTimer", (void(*)(Bot*))&Perl_Bot_ClearSpellRecastTimer);
|
||||
package.add("ClearSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_ClearSpellRecastTimer);
|
||||
package.add("CountAugmentEquippedByID", &Perl_Bot_CountAugmentEquippedByID);
|
||||
package.add("CountBotItem", &Perl_Bot_CountBotItem);
|
||||
package.add("CountItemEquippedByID", &Perl_Bot_CountItemEquippedByID);
|
||||
@ -594,6 +690,13 @@ void perl_register_bot()
|
||||
package.add("HasBotItem", &Perl_Bot_HasBotItem);
|
||||
package.add("HasBotSpellEntry", &Perl_Bot_HasBotSpellEntry);
|
||||
package.add("HasItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
||||
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetDisciplineReuseTimer);
|
||||
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetDisciplineReuseTimer);
|
||||
package.add("GetItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
||||
package.add("GetItemReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetItemReuseTimer);
|
||||
package.add("GetItemReuseTimer", (uint32(*)(Bot*, uint32))&Perl_Bot_GetItemReuseTimer);
|
||||
package.add("GetSpellRecastTimer", (uint32(*)(Bot*))&Perl_Bot_GetSpellRecastTimer);
|
||||
package.add("GetSpellRecastTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetSpellRecastTimer);
|
||||
package.add("IsGrouped", &Perl_Bot_IsGrouped);
|
||||
package.add("IsSitting", &Perl_Bot_IsSitting);
|
||||
package.add("IsStanding", &Perl_Bot_IsStanding);
|
||||
@ -608,6 +711,10 @@ void perl_register_bot()
|
||||
package.add("SendSpellAnim", &Perl_Bot_SendSpellAnim);
|
||||
package.add("SetExpansionBitmask", (void(*)(Bot*, int))&Perl_Bot_SetExpansionBitmask);
|
||||
package.add("SetExpansionBitmask", (void(*)(Bot*, int, bool))&Perl_Bot_SetExpansionBitmask);
|
||||
package.add("SetDisciplineReuseTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetDisciplineReuseTimer);
|
||||
package.add("SetDisciplineReuseTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetDisciplineReuseTimer);
|
||||
package.add("SetItemReuseTimer", (void(*)(Bot*, uint32))&Perl_Bot_SetItemReuseTimer);
|
||||
package.add("SetItemReuseTimer", (void(*)(Bot*, uint32, uint32))&Perl_Bot_SetItemReuseTimer);
|
||||
package.add("SetSpellDuration", (void(*)(Bot*, int))&Perl_Bot_SetSpellDuration);
|
||||
package.add("SetSpellDuration", (void(*)(Bot*, int, int))&Perl_Bot_SetSpellDuration);
|
||||
package.add("SetSpellDuration", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDuration);
|
||||
@ -621,6 +728,8 @@ void perl_register_bot()
|
||||
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDurationRaid);
|
||||
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool))&Perl_Bot_SetSpellDurationRaid);
|
||||
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_SetSpellDurationRaid);
|
||||
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetSpellRecastTimer);
|
||||
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetSpellRecastTimer);
|
||||
package.add("Signal", &Perl_Bot_Signal);
|
||||
package.add("Sit", &Perl_Bot_Sit);
|
||||
package.add("Stand", &Perl_Bot_Stand);
|
||||
|
||||
@ -402,7 +402,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
}
|
||||
}
|
||||
//must use SPA 415 with focus (SPA 127/500/501) to reduce item recast
|
||||
else if (cast_time && IsClient() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) {
|
||||
else if (cast_time && IsOfClientBot() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) {
|
||||
orgcasttime = cast_time;
|
||||
if (cast_time) {
|
||||
cast_time = GetActSpellCasttime(spell_id, cast_time);
|
||||
@ -1643,6 +1643,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
{
|
||||
DeleteChargeFromSlot = GetItemSlotToConsumeCharge(spell_id, inventory_slot);
|
||||
}
|
||||
if (IsBot() && slot == CastingSlot::Item && inventory_slot != 0xFFFFFFFF) // 10 is an item
|
||||
{
|
||||
DeleteChargeFromSlot = GetItemSlotToConsumeCharge(spell_id, inventory_slot);
|
||||
}
|
||||
// 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, 0xFFFFFFFF, 0, true))
|
||||
{
|
||||
@ -1661,9 +1665,23 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
|
||||
TryTriggerOnCastFocusEffect(focusTriggerOnCast, spell_id);
|
||||
|
||||
if (DeleteChargeFromSlot >= 0) {
|
||||
if (IsClient() && DeleteChargeFromSlot >= 0) {
|
||||
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
|
||||
}
|
||||
else if (IsBot() && DeleteChargeFromSlot >= 0) {
|
||||
EQ::ItemInstance* inst = CastToBot()->GetBotItem(DeleteChargeFromSlot);
|
||||
if (inst) {
|
||||
inst->SetCharges((inst->GetCharges() - 1));
|
||||
if (!database.botdb.SaveItemBySlot(CastToBot(), DeleteChargeFromSlot, inst)) {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Failed to save item [%i] slot [%i] for [%s].", inst->GetID(), DeleteChargeFromSlot, GetCleanName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Failed to update item charges.", GetCleanName());
|
||||
LogError("Failed to update item charges for {}.", GetCleanName());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// at this point the spell has successfully been cast
|
||||
@ -2739,6 +2757,18 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
|
||||
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)){
|
||||
CastToClient()->SetItemRecastTimer(spell_id, inventory_slot);
|
||||
}
|
||||
else if (IsBot() && CastToBot()->GetIsUsingItemClick() && slot == CastingSlot::Item) {
|
||||
EQ::ItemInstance* inst = CastToBot()->GetBotItem(inventory_slot);
|
||||
const EQ::ItemData* item = nullptr;
|
||||
if (inst && inst->GetItem()) {
|
||||
item = inst->GetItem();
|
||||
CastToBot()->SetItemReuseTimer(item->ID);
|
||||
CastToBot()->SetIsUsingItemClick(false);
|
||||
}
|
||||
else {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Failed to set item reuse timer for %s.", GetCleanName());
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
CastToNPC()->AI_Event_SpellCastFinished(true, static_cast<uint16>(slot));
|
||||
@ -6971,7 +7001,11 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
|
||||
}
|
||||
|
||||
if (cast_time != 0) {
|
||||
CastSpell(spell_id, target_id, CastingSlot::Item, cast_time, 0, 0, item_slot);
|
||||
if (!CastSpell(spell_id, target_id, CastingSlot::Item, cast_time, 0, 0, item_slot)) {
|
||||
if (IsBot()) {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Casting failed for %s. This could be due to zone restrictions, target restrictions or other limiting factors.", GetCleanName(), CastToBot()->GetBotItem(item_slot)->GetItem()->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Instant cast items do not stop bard songs or interrupt casting.
|
||||
else if (CheckItemRaceClassDietyRestrictionsOnCast(item_slot) && DoCastingChecksOnCaster(spell_id, CastingSlot::Item)) {
|
||||
@ -6980,6 +7014,25 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
|
||||
if (IsClient() && DeleteChargeFromSlot >= 0) {
|
||||
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
|
||||
}
|
||||
else if (IsBot() && DeleteChargeFromSlot >= 0) {
|
||||
EQ::ItemInstance* inst = CastToBot()->GetBotItem(DeleteChargeFromSlot);
|
||||
if (inst) {
|
||||
inst->SetCharges((inst->GetCharges() - 1));
|
||||
if (!database.botdb.SaveItemBySlot(CastToBot(), DeleteChargeFromSlot, inst)) {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Failed to save item [%i] slot [%i] for [%s].", inst->GetID(), DeleteChargeFromSlot, GetCleanName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Failed to update item charges.", GetCleanName());
|
||||
LogError("Failed to update item charges for {}.", GetCleanName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsBot()) {
|
||||
GetOwner()->Message(Chat::Red, "%s says, 'Casting failed for %s. This could be due to zone restrictions, target restrictions or other limiting factors.", GetCleanName(), CastToBot()->GetBotItem(item_slot)->GetItem()->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6988,12 +7041,17 @@ int16 Mob::GetItemSlotToConsumeCharge(int32 spell_id, uint32 inventory_slot)
|
||||
{
|
||||
int16 DeleteChargeFromSlot = -1;
|
||||
|
||||
if (!IsClient() || inventory_slot == 0xFFFFFFFF) {
|
||||
if (!IsOfClientBot() || inventory_slot == 0xFFFFFFFF) {
|
||||
return DeleteChargeFromSlot;
|
||||
}
|
||||
|
||||
EQ::ItemInstance *item = nullptr;
|
||||
item = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||
if (IsClient()) {
|
||||
item = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||
}
|
||||
else if (IsBot()) {
|
||||
item = CastToBot()->GetBotItem(inventory_slot);
|
||||
}
|
||||
|
||||
bool fromaug = false;
|
||||
EQ::ItemData* augitem = nullptr;
|
||||
@ -7036,7 +7094,12 @@ int16 Mob::GetItemSlotToConsumeCharge(int32 spell_id, uint32 inventory_slot)
|
||||
}
|
||||
else{
|
||||
LogSpells("Item used to cast spell [{}] was missing from inventory slot [{}] after casting!", spell_id, inventory_slot);
|
||||
Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i", inventory_slot);
|
||||
if (IsClient()) {
|
||||
Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i", inventory_slot);
|
||||
}
|
||||
else if (IsBot()) {
|
||||
CastToBot()->GetOwner()->Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i for %s", inventory_slot, GetCleanName());
|
||||
}
|
||||
InterruptSpell();
|
||||
return DeleteChargeFromSlot;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user