Merge branch 'master' into wp_master

This commit is contained in:
KimLS 2018-05-02 18:24:19 -07:00
commit 51a006654a
21 changed files with 317 additions and 33 deletions

View File

@ -1,5 +1,4 @@
#include "event_sub.h"
#include <string.h>
void EventSubscriptionWatcher::Subscribe(const std::string &event_name)
{

View File

@ -1,6 +1,7 @@
#pragma once
#include <unordered_map>
#include <string>
class EventSubscriptionWatcher
{

View File

@ -6,6 +6,7 @@
#include <windows.h>
#endif
#include <string>
#include <mysql.h>
#include "types.h"
#include "mysql_request_row.h"

View File

@ -514,7 +514,8 @@ RULE_INT(NPC, MinorNPCCorpseDecayTimeMS, 450000) //level<55
RULE_INT(NPC, MajorNPCCorpseDecayTimeMS, 1500000) //level>=55
RULE_INT(NPC, CorpseUnlockTimer, 150000)
RULE_INT(NPC, EmptyNPCCorpseDecayTimeMS, 0)
RULE_BOOL (NPC, UseItemBonusesForNonPets, true)
RULE_BOOL(NPC, UseItemBonusesForNonPets, true)
RULE_BOOL(NPC, UseBaneDamage, false)
RULE_INT(NPC, SayPauseTimeInSec, 5)
RULE_INT(NPC, OOCRegen, 0)
RULE_BOOL(NPC, BuffFriends, false)
@ -547,6 +548,7 @@ RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of l
RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live
RULE_BOOL(Aggro, UseLevelAggro, true) // Level 18+ and Undead will aggro regardless of level difference. (this will disabled Rule:IntAggroThreshold if set to true)
RULE_INT(Aggro, ClientAggroCheckInterval, 6) // Interval in which clients actually check for aggro - in seconds
RULE_REAL(Aggro, PetAttackRange, 40000.0) // max squared range /pet attack works at default is 200
RULE_CATEGORY_END()
RULE_CATEGORY(TaskSystem)

View File

@ -6,6 +6,10 @@
#include <EXTERN.h>
#define WIN32IO_IS_STDIO
// header to detect if libc++ is the std lib
// this doesn't do shit for C++ but libc++ and GCC 6.1+ use it to define some macros
#include <ciso646>
#ifndef WIN32
extern "C" { //the perl headers dont do this for us...
#endif
@ -47,7 +51,7 @@ extern "C" { //the perl headers dont do this for us...
#endif
//These need to be cleaned up on FreeBSD
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(_LIBCPP_VERSION)
#ifdef do_open
#undef do_open
#endif

View File

@ -32,7 +32,7 @@
#define CURRENT_BINARY_DATABASE_VERSION 9122
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9018
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9019
#else
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
#endif

View File

@ -17,6 +17,7 @@
9016|2017_02_26_bots_spell_casting_chances_update.sql|SHOW TABLES LIKE 'bot_spell_casting_chances'|empty|
9017|2017_03_26_bots_spells_id_fix_for_saved_shadowknight_bots.sql|SELECT * FROM `bot_data` WHERE `class` = '5' AND `spells_id` = '3004'|not_empty|
9018|2018_02_02_Bot_Spells_Min_Max_HP.sql|SHOW COLUMNS FROM `bot_spells_entries` LIKE 'min_hp'|empty|
9019|2018_04_12_bots_stop_melee_level.sql|SHOW COLUMNS FROM `bot_data` LIKE 'stop_melee_level'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,8 @@
ALTER TABLE `bot_data` ADD COLUMN `stop_melee_level` TINYINT(3) UNSIGNED NOT NULL DEFAULT '255' AFTER `follow_distance`;
INSERT INTO `bot_command_settings`(`bot_command`, `access`, `aliases`) VALUES ('botstopmeleelevel', '0', 'sml');
SELECT @csml_raw := (SELECT `rule_value` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CasterStopMeleeLevel' LIMIT 1);
SELECT @csml_value := IF((SELECT @csml_raw REGEXP '^[0-9]+$') = '1', @csml_raw, '13');
UPDATE `bot_data` SET `stop_melee_level` = @csml_value WHERE `class` IN ('2', '6', '10', '11', '12', '13', '14');

View File

@ -2000,14 +2000,17 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
//if NPCs can't inheriently hit the target we don't add bane/magic dmg which isn't exactly the same as PCs
int eleBane = 0;
if (weapon) {
if (weapon->BaneDmgBody == other->GetBodyType()) {
eleBane += weapon->BaneDmgAmt;
}
if (weapon->BaneDmgRace == other->GetRace()) {
eleBane += weapon->BaneDmgRaceAmt;
if (RuleB(NPC, UseBaneDamage)) {
if (weapon->BaneDmgBody == other->GetBodyType()) {
eleBane += weapon->BaneDmgAmt;
}
if (weapon->BaneDmgRace == other->GetRace()) {
eleBane += weapon->BaneDmgRaceAmt;
}
}
// I don't think NPCs use this either ....
if (weapon->ElemDmgAmt) {
eleBane += (weapon->ElemDmgAmt * other->ResistSpell(weapon->ElemDmgType, 0, this) / 100);
}

View File

@ -78,6 +78,11 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
SetPauseAI(false);
rest_timer.Disable();
SetFollowDistance(BOT_FOLLOW_DISTANCE_DEFAULT);
if (IsCasterClass(GetClass()))
SetStopMeleeLevel((uint8)RuleI(Bots, CasterStopMeleeLevel));
else
SetStopMeleeLevel(255);
// Do this once and only in this constructor
GenerateAppearance();
GenerateBaseStats();
@ -151,6 +156,11 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
rest_timer.Disable();
SetFollowDistance(BOT_FOLLOW_DISTANCE_DEFAULT);
if (IsCasterClass(GetClass()))
SetStopMeleeLevel((uint8)RuleI(Bots, CasterStopMeleeLevel));
else
SetStopMeleeLevel(255);
strcpy(this->name, this->GetCleanName());
memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct));
@ -2041,6 +2051,13 @@ void Bot::SetTarget(Mob* mob) {
}
}
void Bot::SetStopMeleeLevel(uint8 level) {
if (IsCasterClass(GetClass()) || IsSpellFighterClass(GetClass()))
_stopMeleeLevel = level;
else
_stopMeleeLevel = 255;
}
void Bot::SetGuardMode() {
WipeHateList();
SetTarget(nullptr);
@ -2386,11 +2403,20 @@ void Bot::AI_Process() {
// Calculate casting distance
float caster_distance_max = 0.0f;
{
if (GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)) {
if (GetLevel() >= GetStopMeleeLevel()) {
switch (GetClass()) {
case CLERIC:
caster_distance_max = 1156.0f; // as DSq value (34 units)
break;
case PALADIN:
caster_distance_max = 576.0f; // as DSq value (24 units)
break;
case RANGER:
caster_distance_max = 784.0f; // as DSq value (28 units)
break;
case SHADOWKNIGHT:
caster_distance_max = 676.0f; // as DSq value (26 units)
break;
case DRUID:
caster_distance_max = 1764.0f; // as DSq value (42 units)
break;
@ -2409,7 +2435,11 @@ void Bot::AI_Process() {
case ENCHANTER:
caster_distance_max = 2500.0f; // as DSq value (50 units)
break;
case BEASTLORD:
caster_distance_max = 900.0f; // as DSq value (30 units)
break;
default:
// pure melee classes (and BARD) do not get this option
break;
}
}

View File

@ -406,6 +406,8 @@ public:
bool AIHealRotation(Mob* tar, bool useFastHeals);
bool GetPauseAI() { return _pauseAI; }
void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; }
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
void SetStopMeleeLevel(uint8 level);
void SetGuardMode();
// Mob AI Virtual Override Methods
@ -742,6 +744,7 @@ private:
bool _altoutofcombatbehavior;
bool _showhelm;
bool _pauseAI;
uint8 _stopMeleeLevel;
// Private "base stats" Members
int32 _baseMR;

View File

@ -1349,6 +1349,7 @@ int bot_command_init(void)
bot_command_add("botreport", "Orders a bot to report its readiness", 0, bot_subcommand_bot_report) ||
bot_command_add("botspawn", "Spawns a created bot", 0, bot_subcommand_bot_spawn) ||
bot_command_add("botstance", "Changes the stance of a bot", 0, bot_subcommand_bot_stance) ||
bot_command_add("botstopmeleelevel", "Sets the level a caster or spell-casting fighter bot will stop melee combat", 0, bot_subcommand_bot_stop_melee_level) ||
bot_command_add("botsummon", "Summons bot(s) to your location", 0, bot_subcommand_bot_summon) ||
bot_command_add("bottattoo", "Changes the Drakkin tattoo of a bot", 0, bot_subcommand_bot_tattoo) ||
bot_command_add("bottogglearcher", "Toggles a archer bot between melee and ranged weapon use", 0, bot_subcommand_bot_toggle_archer) ||
@ -2604,6 +2605,7 @@ void bot_command_bot(Client *c, const Seperator *sep)
subcommand_list.push_back("botreport");
subcommand_list.push_back("botspawn");
subcommand_list.push_back("botstance");
subcommand_list.push_back("botstopmeleelevel");
subcommand_list.push_back("botsummon");
subcommand_list.push_back("bottogglearcher");
subcommand_list.push_back("bottogglehelm");
@ -4791,7 +4793,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
return;
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(m_usage, "usage: %s ([class] [value]) ([race] [value]) ([name] [partial-full])", sep->arg[0]);
c->Message(m_note, "Note: filter criteria is orderless and optional");
c->Message(m_note, "note: filter criteria is orderless and optional");
return;
}
@ -5125,6 +5127,53 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
}
}
void bot_subcommand_bot_stop_melee_level(Client *c, const Seperator *sep)
{
if (helper_command_alias_fail(c, "bot_subcommand_bot_stop_melee_level", sep->arg[0], "botstopmeleelevel"))
return;
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(m_usage, "usage: <target_bot> %s [current | reset | sync | value: 0-255]", sep->arg[0]);
c->Message(m_note, "note: Only caster and spell-casting fighter class bots may be modified");
c->Message(m_note, "note: Use [reset] to set stop melee level to server rule");
c->Message(m_note, "note: Use [sync] to set stop melee level to current bot level");
return;
}
auto my_bot = ActionableBots::AsTarget_ByBot(c);
if (!my_bot) {
c->Message(m_fail, "You must <target> a bot that you own to use this command");
return;
}
if (!IsCasterClass(my_bot->GetClass()) && !IsSpellFighterClass(my_bot->GetClass())) {
c->Message(m_fail, "You must <target> a caster or spell-casting fighter class bot to use this command");
return;
}
uint8 sml = RuleI(Bots, CasterStopMeleeLevel);
if (sep->IsNumber(1)) {
sml = atoi(sep->arg[1]);
}
else if (!strcasecmp(sep->arg[1], "sync")) {
sml = my_bot->GetLevel();
}
else if (!strcasecmp(sep->arg[1], "current")) {
c->Message(m_message, "My current melee stop level is %u", my_bot->GetStopMeleeLevel());
return;
}
else if (strcasecmp(sep->arg[1], "reset")) {
c->Message(m_fail, "A [current] or [reset] argument, or numeric [value] is required to use this command");
return;
}
// [reset] falls through with initialization value
my_bot->SetStopMeleeLevel(sml);
if (!botdb.SaveStopMeleeLevel(c->CharacterID(), my_bot->GetBotID(), sml))
c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveStopMeleeLevel(), my_bot->GetCleanName());
c->Message(m_action, "Successfully set stop melee level for %s to %u", my_bot->GetCleanName(), sml);
}
void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
{
if (helper_command_alias_fail(c, "bot_subcommand_bot_summon", sep->arg[0], "botsummon"))

View File

@ -612,6 +612,7 @@ void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep);
void bot_subcommand_bot_report(Client *c, const Seperator *sep);
void bot_subcommand_bot_spawn(Client *c, const Seperator *sep);
void bot_subcommand_bot_stance(Client *c, const Seperator *sep);
void bot_subcommand_bot_stop_melee_level(Client *c, const Seperator *sep);
void bot_subcommand_bot_summon(Client *c, const Seperator *sep);
void bot_subcommand_bot_tattoo(Client *c, const Seperator *sep);
void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep);

View File

@ -340,7 +340,8 @@ bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot)
" `disease`," /* not in-use[41] */
" `corruption`," /* not in-use[42] */
" `show_helm`," // 43
" `follow_distance`" // 44
" `follow_distance`," // 44
" `stop_melee_level`" // 45
" FROM `bot_data`"
" WHERE `bot_id` = '%u'"
" LIMIT 1",
@ -397,13 +398,16 @@ bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot)
loaded_bot = new Bot(bot_id, atoi(row[0]), atoi(row[1]), atof(row[14]), atoi(row[6]), tempNPCStruct);
if (loaded_bot) {
loaded_bot->SetShowHelm((atoi(row[43]) > 0 ? true : false));
uint32 bfd = atoi(row[44]);
if (bfd < 1)
bfd = 1;
if (bfd > BOT_FOLLOW_DISTANCE_DEFAULT_MAX)
bfd = BOT_FOLLOW_DISTANCE_DEFAULT_MAX;
loaded_bot->SetFollowDistance(bfd);
uint8 sml = atoi(row[45]);
loaded_bot->SetStopMeleeLevel(sml);
}
return true;
@ -457,7 +461,8 @@ bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id)
" `disease`,"
" `corruption`,"
" `show_helm`,"
" `follow_distance`"
" `follow_distance`,"
" `stop_melee_level`"
")"
" VALUES ("
"'%u'," /* owner_id */
@ -501,7 +506,8 @@ bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id)
" '%i'," /* disease */
" '%i'," /* corruption */
" '1'," /* show_helm */
" '%i'" /* follow_distance */
" '%i'," /* follow_distance */
" '%u'" /* stop_melee_level */
")",
bot_inst->GetBotOwnerCharacterID(),
bot_inst->GetBotSpellID(),
@ -540,7 +546,8 @@ bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id)
bot_inst->GetPR(),
bot_inst->GetDR(),
bot_inst->GetCorrup(),
BOT_FOLLOW_DISTANCE_DEFAULT
BOT_FOLLOW_DISTANCE_DEFAULT,
(IsCasterClass(bot_inst->GetClass()) ? (uint8)RuleI(Bots, CasterStopMeleeLevel) : 255)
);
auto results = QueryDatabase(query);
if (!results.Success())
@ -599,7 +606,8 @@ bool BotDatabase::SaveBot(Bot* bot_inst)
" `disease` = '%i',"
" `corruption` = '%i',"
" `show_helm` = '%i',"
" `follow_distance` = '%i'"
" `follow_distance` = '%i',"
" `stop_melee_level` = '%u'"
" WHERE `bot_id` = '%u'",
bot_inst->GetBotOwnerCharacterID(),
bot_inst->GetBotSpellID(),
@ -641,6 +649,7 @@ bool BotDatabase::SaveBot(Bot* bot_inst)
bot_inst->GetBaseCorrup(),
((bot_inst->GetShowHelm()) ? (1) : (0)),
bot_inst->GetFollowDistance(),
bot_inst->GetStopMeleeLevel(),
bot_inst->GetBotID()
);
auto results = QueryDatabase(query);
@ -2026,7 +2035,8 @@ bool BotDatabase::CreateCloneBot(const uint32 owner_id, const uint32 bot_id, con
" `disease`,"
" `corruption`,"
" `show_helm`,"
" `follow_distance`"
" `follow_distance`,"
" `stop_melee_level`"
")"
" SELECT"
" bd.`owner_id`,"
@ -2073,7 +2083,8 @@ bool BotDatabase::CreateCloneBot(const uint32 owner_id, const uint32 bot_id, con
" bd.`disease`,"
" bd.`corruption`,"
" bd.`show_helm`,"
" bd.`follow_distance`"
" bd.`follow_distance`,"
" bd.`stop_melee_level`"
" FROM `bot_data` bd"
" WHERE"
" bd.`owner_id` = '%u'"
@ -2153,6 +2164,27 @@ bool BotDatabase::CreateCloneBotInventory(const uint32 owner_id, const uint32 bo
return true;
}
bool BotDatabase::SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id, const uint8 sml_value)
{
if (!owner_id || !bot_id)
return false;
query = StringFormat(
"UPDATE `bot_data`"
" SET `stop_melee_level` = '%u'"
" WHERE `owner_id` = '%u'"
" AND `bot_id` = '%u'",
sml_value,
owner_id,
bot_id
);
auto results = QueryDatabase(query);
if (!results.Success())
return false;
return true;
}
/* Bot bot-group functions */
bool BotDatabase::QueryBotGroupExistence(const std::string& group_name, bool& extant_flag)
@ -2852,6 +2884,7 @@ const char* BotDatabase::fail::SaveFollowDistance() { return "Failed to save fol
const char* BotDatabase::fail::SaveAllFollowDistances() { return "Failed to save all follow distances"; }
const char* BotDatabase::fail::CreateCloneBot() { return "Failed to create clone bot"; }
const char* BotDatabase::fail::CreateCloneBotInventory() { return "Failed to create clone bot inventory"; }
const char* BotDatabase::fail::SaveStopMeleeLevel() { return "Failed to save stop melee level"; }
/* fail::Bot bot-group functions */
const char* BotDatabase::fail::QueryBotGroupExistence() { return "Failed to query bot-group existence"; }

View File

@ -143,6 +143,8 @@ public:
bool CreateCloneBot(const uint32 owner_id, const uint32 bot_id, const std::string& clone_name, uint32& clone_id);
bool CreateCloneBotInventory(const uint32 owner_id, const uint32 bot_id, const uint32 clone_id);
bool SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id, const uint8 sml_value);
/* Bot bot-group functions */
bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag);
@ -253,6 +255,7 @@ public:
static const char* SaveAllFollowDistances();
static const char* CreateCloneBot();
static const char* CreateCloneBotInventory();
static const char* SaveStopMeleeLevel();
/* fail::Bot bot-group functions */
static const char* QueryBotGroupExistence();

View File

@ -10030,6 +10030,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
}
// default range is 200, takes Z into account
// really they do something weird where they're added to the aggro list then remove them
// and will attack if they come in range -- too lazy, lets remove exploits for now
if (DistanceSquared(mypet->GetPosition(), target->GetPosition()) >= RuleR(Aggro, PetAttackRange)) {
// they say they're attacking then remove on live ... so they don't really say anything in this case ...
break;
}
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
if (mypet->IsPetStop()) {
@ -13688,6 +13696,11 @@ void Client::Handle_OP_Taunt(const EQApplicationPacket *app)
if (GetTarget() == nullptr || !GetTarget()->IsNPC())
return;
if (!zone->CanDoCombat()) {
Message(13, "You cannot taunt in a no combat zone.");
return;
}
Taunt(GetTarget()->CastToNPC(), false);
return;
}

View File

@ -279,21 +279,26 @@ void Client::GoFish()
//check for add NPC
if (npc_chance > 0 && npc_id) {
if (zone->random.Roll(npc_chance)) {
const NPCType *tmp = database.LoadNPCTypesData(npc_id);
if (tmp != nullptr) {
auto positionNPC = GetPosition();
positionNPC.x = positionNPC.x + 3;
auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
if (zone->CanDoCombat()) {
const NPCType *tmp = database.LoadNPCTypesData(npc_id);
if (tmp != nullptr) {
auto positionNPC = GetPosition();
positionNPC.x = positionNPC.x + 3;
auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3);
npc->AddLootTable();
if (npc->DropsGlobalLoot())
npc->CheckGlobalLootTables();
npc->AddToHateList(this, 1, 0, false); // no help yelling
npc->AddToHateList(this, 1, 0, false); // no help yelling
entity_list.AddNPC(npc);
entity_list.AddNPC(npc);
Message(MT_Emote,
"You fish up a little more than you bargained for...");
Message(MT_Emote,
"You fish up a little more than you bargained for...");
}
}
else {
Message(MT_Emote, "You notice something lurking just below the water's surface...");
}
}
}

View File

@ -341,6 +341,19 @@ void lua_stop_all_timers(Lua_Encounter enc) {
quest_manager.stopalltimers(enc);
}
void lua_pause_timer(const char *timer) {
quest_manager.pausetimer(timer);
}
void lua_resume_timer(const char *timer) {
quest_manager.resumetimer(timer);
}
bool lua_is_paused_timer(const char *timer) {
return quest_manager.ispausedtimer(timer);
}
void lua_depop() {
quest_manager.depop(0);
}
@ -1543,6 +1556,9 @@ luabind::scope lua_register_general() {
luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer),
luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer),
luabind::def("stop_timer", (void(*)(const char*, Lua_Encounter))&lua_stop_timer),
luabind::def("pause_timer", (void(*)(const char*))&lua_pause_timer),
luabind::def("resume_timer", (void(*)(const char*))&lua_resume_timer),
luabind::def("is_paused_timer", (bool(*)(const char*))&lua_is_paused_timer),
luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers),
luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers),
luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers),

View File

@ -1534,7 +1534,8 @@ void NPC::PickPocket(Client* thief)
}
if(zone->random.Roll(5)) {
AddToHateList(thief, 50);
if (zone->CanDoCombat())
AddToHateList(thief, 50);
Say("Stop thief!");
thief->Message(13, "You are noticed trying to steal!");
thief->SendPickPocketResponse(this, 0, PickPocketFailed);

View File

@ -555,6 +555,107 @@ void QuestManager::stopalltimers(Mob *mob) {
}
}
void QuestManager::pausetimer(const char *timer_name) {
QuestManagerCurrentQuestVars();
std::list<QuestTimer>::iterator cur = QTimerList.begin(), end;
std::list<PausedTimer>::iterator pcur = PTimerList.begin(), pend;
PausedTimer pt;
uint32 milliseconds = 0;
pend = PTimerList.end();
while (pcur != pend)
{
if (pcur->owner && pcur->owner == owner && pcur->name == timer_name)
{
Log(Logs::General, Logs::Quests, "Timer %s is already paused for %s. Returning...", timer_name, owner->GetName());
return;
}
++pcur;
}
end = QTimerList.end();
while (cur != end)
{
if (cur->mob && cur->mob == owner && cur->name == timer_name)
{
milliseconds = cur->Timer_.GetRemainingTime();
QTimerList.erase(cur);
break;
}
++cur;
}
std::string timername = timer_name;
pt.name = timername;
pt.owner = owner;
pt.time = milliseconds;
Log(Logs::General, Logs::Quests, "Pausing timer %s for %s with %d ms remaining.", timer_name, owner->GetName(), milliseconds);
PTimerList.push_back(pt);
}
void QuestManager::resumetimer(const char *timer_name) {
QuestManagerCurrentQuestVars();
std::list<QuestTimer>::iterator cur = QTimerList.begin(), end;
std::list<PausedTimer>::iterator pcur = PTimerList.begin(), pend;
PausedTimer pt;
uint32 milliseconds = 0;
pend = PTimerList.end();
while (pcur != pend)
{
if (pcur->owner && pcur->owner == owner && pcur->name == timer_name)
{
milliseconds = pcur->time;
PTimerList.erase(pcur);
break;
}
++pcur;
}
if (milliseconds == 0)
{
Log(Logs::General, Logs::Quests, "Paused timer %s not found or has expired. Returning...", timer_name);
return;
}
end = QTimerList.end();
while (cur != end)
{
if (cur->mob && cur->mob == owner && cur->name == timer_name)
{
cur->Timer_.Enable();
cur->Timer_.Start(milliseconds, false);
Log(Logs::General, Logs::Quests, "Resuming timer %s for %s with %d ms remaining.", timer_name, owner->GetName(), milliseconds);
return;
}
++cur;
}
QTimerList.push_back(QuestTimer(milliseconds, owner, timer_name));
Log(Logs::General, Logs::Quests, "Creating a new timer and resuming %s for %s with %d ms remaining.", timer_name, owner->GetName(), milliseconds);
}
bool QuestManager::ispausedtimer(const char *timer_name) {
QuestManagerCurrentQuestVars();
std::list<PausedTimer>::iterator pcur = PTimerList.begin(), pend;
pend = PTimerList.end();
while (pcur != pend)
{
if (pcur->owner && pcur->owner == owner && pcur->name == timer_name)
{
return true;
}
++pcur;
}
return false;
}
void QuestManager::emote(const char *str) {
QuestManagerCurrentQuestVars();
if (!owner) {

View File

@ -41,6 +41,12 @@ class QuestManager {
bool depop_npc;
std::string encounter;
};
struct PausedTimer {
Mob * owner;
std::string name;
uint32 time;
};
public:
QuestManager();
virtual ~QuestManager();
@ -82,6 +88,9 @@ public:
void stopalltimers();
void stopalltimers(EQEmu::ItemInstance *inst);
void stopalltimers(Mob *mob);
void pausetimer(const char *timer_name);
void resumetimer(const char *timer_name);
bool ispausedtimer(const char *timer_name);
void emote(const char *str);
void shout(const char *str);
void shout2(const char *str);
@ -302,6 +311,7 @@ private:
};
std::list<QuestTimer> QTimerList;
std::list<SignalTimer> STimerList;
std::list<PausedTimer> PTimerList;
size_t item_timers;
};