Implement Triple Attack as a skill

See change log for more details
Optional SQL will max toons triple attack skills
This commit is contained in:
Michael Cook (mackal) 2015-07-06 16:11:00 -04:00
parent 5a73d26d12
commit 1e75b4ba77
9 changed files with 157 additions and 107 deletions

View File

@ -1,5 +1,12 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 07/06/2015 ==
mackal: Implement Triple Attack Skill
Parses showed about rand(1000) for the chance, may need more investigating
Corrected Double Attack chances as well
Running optional 2015_07_06_TripleAttack.sql will set current toons to their max skill
This is optional because the admins might want to go a different route.
== 07/05/2015 == == 07/05/2015 ==
mackal: Rewrite NPC combat attack round logic mackal: Rewrite NPC combat attack round logic
An NPC "quading" is really just an NPC with innate dual wield that doubles on both hands An NPC "quading" is really just an NPC with innate dual wield that doubles on both hands

View File

@ -108,16 +108,17 @@ enum SkillUseTypes
/*13869*/ SkillBerserking, /*13869*/ SkillBerserking,
/*13902*/ SkillTaunt, /*13902*/ SkillTaunt,
/*05837*/ SkillFrenzy, // This appears to be the only listed one not grouped with the others /*05837*/ SkillFrenzy, // This appears to be the only listed one not grouped with the others
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
// SoF+ specific skills // SoF+ specific skills
// /*03670*/ SkillRemoveTraps, /*03670*/ SkillRemoveTraps,
// /*13049*/ SkillTripleAttack, /*13049*/ SkillTripleAttack,
// RoF2+ specific skills // RoF2+ specific skills
// /*00789*/ Skill2HPiercing, // /*00789*/ Skill2HPiercing,
// /*01216*/ SkillNone, // This needs to move down as new skills are added // /*01216*/ SkillNone, // This needs to move down as new skills are added
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
// Skill Counts // Skill Counts
// /*-----*/ _SkillCount_62 = 75, // use for Ti and earlier max skill checks // /*-----*/ _SkillCount_62 = 75, // use for Ti and earlier max skill checks
// /*-----*/ _SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks // /*-----*/ _SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks
@ -170,7 +171,7 @@ enum SkillUseTypes
}; };
// temporary until it can be sorted out... // temporary until it can be sorted out...
#define HIGHEST_SKILL SkillFrenzy #define HIGHEST_SKILL SkillTripleAttack
// Spell Effects use this value to determine if an effect applies to all skills. // Spell Effects use this value to determine if an effect applies to all skills.
#define ALL_SKILLS -1 #define ALL_SKILLS -1

View File

@ -0,0 +1,27 @@
DELIMITER $$
DROP PROCEDURE IF EXISTS GrantTripleAttack$$
CREATE PROCEDURE GrantTripleAttack()
BEGIN
DECLARE finished INT;
DECLARE char_id INT;
DECLARE skill_max INT;
DECLARE cur CURSOR FOR SELECT character_data.id, skill_caps.cap FROM `character_data` LEFT JOIN `skill_caps` ON character_data.`level` = skill_caps.`level` AND character_data.class = skill_caps.class AND skill_caps.skillID = 76;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN cur;
SET finished = 0;
REPEAT
FETCH cur INTO char_id, skill_max;
IF skill_max IS NOT NULL AND skill_max > 0 THEN
REPLACE INTO `character_skills` (`id`, `skill_id`, `value`) VALUES(char_id, 76, skill_max);
END IF;
UNTIL finished END REPEAT;
CLOSE cur;
END$$
DELIMITER ;
CALL GrantTripleAttack();
DROP PROCEDURE GrantTripleAttack;

View File

@ -3406,41 +3406,39 @@ bool Mob::HasRangedProcs() const
return false; return false;
} }
bool Client::CheckDoubleAttack(bool tripleAttack) { bool Client::CheckDoubleAttack()
{
int chance = 0;
int skill = GetSkill(SkillDoubleAttack);
//Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA) //Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA)
uint32 bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack; int bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack;
if (skill > 0)
if(!HasSkill(SkillDoubleAttack) && !bonusGiveDA) chance = skill + GetLevel();
else if (!bonusGiveDA)
return false; return false;
float chance = 0.0f; if (bonusGiveDA)
chance += bonusGiveDA / 100.0f * 500; // convert to skill value
int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
if (per_inc)
chance += chance * per_inc / 100;
uint16 skill = GetSkill(SkillDoubleAttack); return zone->random.Int(1, 500) <= chance;
}
int32 bonusDA = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance; // Admittedly these parses were short, but this check worked for 3 toons across multiple levels
// with varying triple attack skill (1-3% error at least)
bool Client::CheckTripleAttack()
{
int chance = GetSkill(SkillTripleAttack);
if (chance < 1)
return false;
//Use skill calculations otherwise, if you only have AA applied GiveDoubleAttack chance then use that value as the base. int per_inc = aabonuses.TripleAttackChance + spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
if (skill) if (per_inc)
chance = (float(skill+GetLevel()) * (float(100.0f+bonusDA+bonusGiveDA) /100.0f)) /500.0f; chance += chance * per_inc / 100;
else
chance = (float(bonusGiveDA) * (float(100.0f+bonusDA)/100.0f) ) /100.0f;
//Live now uses a static Triple Attack skill (lv 46 = 2% lv 60 = 20%) - We do not have this skill on EMU ATM. return zone->random.Int(1, 1000) <= chance;
//A reasonable forumla would then be TA = 20% * chance
//AA's can also give triple attack skill over cap. (ie Burst of Power) NOTE: Skill ID in spell data is 76 (Triple Attack)
//Kayen: Need to decide if we can implement triple attack skill before working in over the cap effect.
if(tripleAttack) {
// Only some Double Attack classes get Triple Attack [This is already checked in client_processes.cpp]
int32 triple_bonus = spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
chance *= 0.2f; //Baseline chance is 20% of your double attack chance.
chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers.
}
if(zone->random.Roll(chance))
return true;
return false;
} }
bool Client::CheckDoubleRangedAttack() { bool Client::CheckDoubleRangedAttack() {
@ -3452,7 +3450,7 @@ bool Client::CheckDoubleRangedAttack() {
return false; return false;
} }
bool Mob::CheckDoubleAttack(bool tripleAttack) bool Mob::CheckDoubleAttack()
{ {
// Not 100% certain pets follow this or if it's just from pets not always // Not 100% certain pets follow this or if it's just from pets not always
// having the same skills as most mobs // having the same skills as most mobs
@ -5054,21 +5052,28 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
if (candouble) { if (candouble) {
CheckIncreaseSkill(SkillDoubleAttack, target, -10); CheckIncreaseSkill(SkillDoubleAttack, target, -10);
if (CheckDoubleAttack()) if (CheckDoubleAttack()) {
Attack(target, hand, false, false, IsFromSpell);
if (hand == MainPrimary && GetLevel() >= 60 &&
(GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) &&
CheckDoubleAttack(true))
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);
// you can only triple from the main hand
if (hand == MainPrimary && CanThisClassTripleAttack()) {
CheckIncreaseSkill(SkillTripleAttack, target, -10);
if (CheckTripleAttack())
Attack(target, hand, false, false, IsFromSpell);
}
}
} }
if (hand == MainPrimary) { if (hand == MainPrimary) {
// According to http://www.monkly-business.net/forums/showpost.php?p=312095&postcount=168 a dev told them flurry isn't dependant on triple attack
// the parses kind of back that up and all of my parses seemed to be 4 or 5 attacks in the round which would work out to be
// doubles or triples with 2 from flurries or triple with 1 or 2 flurries ... Going with the "dev quote" I guess like we've always had it
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance; auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
if (flurrychance && zone->random.Roll(flurrychance)) { if (flurrychance && zone->random.Roll(flurrychance)) {
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);
Message_StringID(MT_NPCFlurry, YOU_FLURRY); Message_StringID(MT_NPCFlurry, YOU_FLURRY);
} }
// I haven't parsed where this guy happens, but it's not part of the normal chain above so this is fine
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance; auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance)) if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
Attack(target, hand, false, false, IsFromSpell); Attack(target, hand, false, false, IsFromSpell);

View File

@ -888,7 +888,8 @@ public:
bool CheckTradeLoreConflict(Client* other); bool CheckTradeLoreConflict(Client* other);
void LinkDead(); void LinkDead();
void Insight(uint32 t_id); void Insight(uint32 t_id);
bool CheckDoubleAttack(bool tripleAttack = false); bool CheckDoubleAttack();
bool CheckTripleAttack();
bool CheckDoubleRangedAttack(); bool CheckDoubleRangedAttack();
bool CheckDualWield(); bool CheckDualWield();

View File

@ -146,7 +146,7 @@ Access Levels:
*/ */
int command_init(void) { int command_init(void) {
if if
( (
@ -434,7 +434,7 @@ int command_init(void) {
command_add("zsave", " - Saves zheader to the database", 80, command_zsave) || command_add("zsave", " - Saves zheader to the database", 80, command_zsave) ||
command_add("zsky", "[skytype] - Change zone sky type", 80, command_zsky) || command_add("zsky", "[skytype] - Change zone sky type", 80, command_zsky) ||
command_add("zstats", "- Show info about zone header", 80, command_zstats) || command_add("zstats", "- Show info about zone header", 80, command_zstats) ||
command_add("zunderworld", "[zcoord] - Sets the underworld using zcoord", 80, command_zunderworld) || command_add("zunderworld", "[zcoord] - Sets the underworld using zcoord", 80, command_zunderworld) ||
command_add("zuwcoords", "[z coord] - Set underworld coord", 80, command_zuwcoords) command_add("zuwcoords", "[z coord] - Set underworld coord", 80, command_zuwcoords)
) )
{ {
@ -644,8 +644,8 @@ void command_logcommand(Client *c, const char *message)
c->AccountName(), c->AccountName(),
c->AccountID(), c->AccountID(),
admin,c->GetName(), admin,c->GetName(),
c->GetTarget()?c->GetTarget()->GetName():"None", c->GetTarget()?c->GetTarget()->GetName():"None",
"Command", "Command",
message, message,
1 1
); );
@ -731,7 +731,7 @@ void command_setfaction(Client *c, const Seperator *sep)
auto npcTypeID = c->GetTarget()->CastToNPC()->GetNPCTypeID(); auto npcTypeID = c->GetTarget()->CastToNPC()->GetNPCTypeID();
c->Message(15,"Setting NPC %u to faction %i", npcTypeID, atoi(sep->argplus[1])); c->Message(15,"Setting NPC %u to faction %i", npcTypeID, atoi(sep->argplus[1]));
std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i", std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i",
atoi(sep->argplus[1]), npcTypeID); atoi(sep->argplus[1]), npcTypeID);
database.QueryDatabase(query); database.QueryDatabase(query);
} }
@ -2302,7 +2302,7 @@ void command_setskill(Client *c, const Seperator *sep)
Log.Out(Logs::General, Logs::Normal, "Set skill request from %s, target:%s skill_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) ); Log.Out(Logs::General, Logs::Normal, "Set skill request from %s, target:%s skill_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) );
int skill_num = atoi(sep->arg[1]); int skill_num = atoi(sep->arg[1]);
uint16 skill_value = atoi(sep->arg[2]); uint16 skill_value = atoi(sep->arg[2]);
if(skill_num < HIGHEST_SKILL) if(skill_num <= HIGHEST_SKILL)
c->GetTarget()->CastToClient()->SetSkill((SkillUseTypes)skill_num, skill_value); c->GetTarget()->CastToClient()->SetSkill((SkillUseTypes)skill_num, skill_value);
} }
} }
@ -2573,7 +2573,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
} }
@ -2584,7 +2584,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i",
MainPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); MainPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
} }
@ -2596,7 +2596,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "InvSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "InvSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2606,7 +2606,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -2618,7 +2618,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i", c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i",
MainCursor, 0, item_link.c_str(), 0); MainCursor, 0, item_link.c_str(), 0);
} }
else { else {
@ -2630,7 +2630,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i",
MainCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); MainCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; (cursorDepth == 0) && inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; (cursorDepth == 0) && inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2640,7 +2640,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
Inventory::CalcSlotId(MainCursor, indexSub), MainCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); Inventory::CalcSlotId(MainCursor, indexSub), MainCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -2655,7 +2655,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "TributeSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "TributeSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
} }
@ -2667,7 +2667,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "BankSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "BankSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2677,7 +2677,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -2688,8 +2688,8 @@ void command_peekinv(Client *c, const Seperator *sep)
linker.SetItemInst(inst_main); linker.SetItemInst(inst_main);
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "SharedBankSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "SharedBankSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2699,7 +2699,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -2712,7 +2712,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "TradeSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "TradeSlot: %i, Item: %i (%s), Charges: %i",
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2722,7 +2722,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -2744,7 +2744,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), "WorldSlot: %i, Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), "WorldSlot: %i, Item: %i (%s), Charges: %i",
(EmuConstants::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); (EmuConstants::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { for (uint8 indexSub = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) {
@ -2754,7 +2754,7 @@ void command_peekinv(Client *c, const Seperator *sep)
item_link = linker.GenerateLink(); item_link = linker.GenerateLink();
c->Message((item_data == nullptr), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", c->Message((item_data == nullptr), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
} }
} }
@ -3752,7 +3752,7 @@ void command_spellinfo(Client *c, const Seperator *sep)
c->Message(0, " zonetype: %d", s->zonetype); c->Message(0, " zonetype: %d", s->zonetype);
c->Message(0, " EnvironmentType: %d", s->EnvironmentType); c->Message(0, " EnvironmentType: %d", s->EnvironmentType);
c->Message(0, " TimeOfDay: %d", s->TimeOfDay); c->Message(0, " TimeOfDay: %d", s->TimeOfDay);
c->Message(0, " classes[15]: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", c->Message(0, " classes[15]: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
s->classes[0], s->classes[1], s->classes[2], s->classes[3], s->classes[4], s->classes[0], s->classes[1], s->classes[2], s->classes[3], s->classes[4],
s->classes[5], s->classes[6], s->classes[7], s->classes[8], s->classes[9], s->classes[5], s->classes[6], s->classes[7], s->classes[8], s->classes[9],
s->classes[10], s->classes[11], s->classes[12], s->classes[13], s->classes[14]); s->classes[10], s->classes[11], s->classes[12], s->classes[13], s->classes[14]);
@ -3882,7 +3882,7 @@ void command_repop(Client *c, const Seperator *sep)
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list); LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset(); iterator.Reset();
while (iterator.MoreElements()) { while (iterator.MoreElements()) {
std::string query = StringFormat("DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", std::string query = StringFormat("DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu",
(unsigned long)iterator.GetData()->GetID(), (unsigned long)iterator.GetData()->GetID(),
(unsigned long)zone->GetInstanceID()); (unsigned long)zone->GetInstanceID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
@ -4256,7 +4256,7 @@ void command_spawnfix(Client *c, const Seperator *sep) {
return; return;
} }
std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' WHERE id = '%i'", std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' WHERE id = '%i'",
c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID()); c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -4399,11 +4399,11 @@ void command_time(Client *c, const Seperator *sep)
c->Message(13, "To set the Time: #time HH [MM]"); c->Message(13, "To set the Time: #time HH [MM]");
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime); zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)", sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)",
((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12), ((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12),
(eqTime.minute < 10) ? "0" : "", (eqTime.minute < 10) ? "0" : "",
eqTime.minute, eqTime.minute,
(eqTime.hour >= 13) ? "pm" : "am", (eqTime.hour >= 13) ? "pm" : "am",
zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr(),
zone->zone_time.getEQTimeZoneMin() zone->zone_time.getEQTimeZoneMin()
); );
@ -5734,7 +5734,7 @@ void command_suspend(Client *c, const Seperator *sep)
} }
std::string query = StringFormat("UPDATE `account` SET `suspendeduntil` = DATE_ADD(NOW(), INTERVAL %i DAY), " std::string query = StringFormat("UPDATE `account` SET `suspendeduntil` = DATE_ADD(NOW(), INTERVAL %i DAY), "
"suspend_reason = '%s' WHERE `id` = %i", "suspend_reason = '%s' WHERE `id` = %i",
duration, EscapeString(message).c_str(), accountID); duration, EscapeString(message).c_str(), accountID);
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
@ -6206,21 +6206,21 @@ void command_npcedit(Client *c, const Seperator *sep)
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "meleetype") == 0) { if (strcasecmp(sep->arg[1], "meleetype") == 0) {
c->Message(15,"NPCID %u now has a primary melee type of %i and a secondary melee type of %i.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3])); c->Message(15,"NPCID %u now has a primary melee type of %i and a secondary melee type of %i.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3]));
std::string query = StringFormat("UPDATE npc_types SET prim_melee_type = %i, sec_melee_type = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET prim_melee_type = %i, sec_melee_type = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID);
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "rangedtype") == 0) { if (strcasecmp(sep->arg[1], "rangedtype") == 0) {
c->Message(15,"NPCID %u now has a ranged type of %i.", npcTypeID, atoi(sep->argplus[2])); c->Message(15,"NPCID %u now has a ranged type of %i.", npcTypeID, atoi(sep->argplus[2]));
std::string query = StringFormat("UPDATE npc_types SET rangedtype = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET rangedtype = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID);
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "ammoidfile") == 0) { if (strcasecmp(sep->arg[1], "ammoidfile") == 0) {
c->Message(15,"NPCID %u's ammo id file is now %i", npcTypeID, atoi(sep->argplus[2])); c->Message(15,"NPCID %u's ammo id file is now %i", npcTypeID, atoi(sep->argplus[2]));
std::string query = StringFormat("UPDATE npc_types SET ammoidfile = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET ammoidfile = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID);
@ -6255,7 +6255,7 @@ void command_npcedit(Client *c, const Seperator *sep)
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "walkspeed") == 0) { if (strcasecmp(sep->arg[1], "walkspeed") == 0) {
c->Message(15,"NPCID %u now walks at %f", npcTypeID, atof(sep->argplus[2])); c->Message(15,"NPCID %u now walks at %f", npcTypeID, atof(sep->argplus[2]));
std::string query = StringFormat("UPDATE npc_types SET walkspeed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET walkspeed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID);
@ -6409,7 +6409,7 @@ void command_npcedit(Client *c, const Seperator *sep)
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "Avoidance") == 0) { if (strcasecmp(sep->arg[1], "Avoidance") == 0) {
c->Message(15,"NPCID %u now has %i Avoidance.", npcTypeID, atoi(sep->argplus[2])); c->Message(15,"NPCID %u now has %i Avoidance.", npcTypeID, atoi(sep->argplus[2]));
std::string query = StringFormat("UPDATE npc_types SET avoidance = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET avoidance = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID);
@ -6465,7 +6465,7 @@ void command_npcedit(Client *c, const Seperator *sep)
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "Attackcount") == 0) { if (strcasecmp(sep->arg[1], "Attackcount") == 0) {
c->Message(15,"NPCID %u now has attack_count set to %i", npcTypeID,atoi(sep->arg[2])); c->Message(15,"NPCID %u now has attack_count set to %i", npcTypeID,atoi(sep->arg[2]));
std::string query = StringFormat("UPDATE npc_types SET attack_count = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); std::string query = StringFormat("UPDATE npc_types SET attack_count = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID);
@ -6502,7 +6502,7 @@ void command_npcedit(Client *c, const Seperator *sep)
"luclin_hairstyle = %i, luclin_beard = %i, " "luclin_hairstyle = %i, luclin_beard = %i, "
"face = %i, drakkin_heritage = %i, " "face = %i, drakkin_heritage = %i, "
"drakkin_tattoo = %i, drakkin_details = %i " "drakkin_tattoo = %i, drakkin_details = %i "
"WHERE id = %i", "WHERE id = %i",
target->GetHairColor(), target->GetBeardColor(), target->GetHairColor(), target->GetBeardColor(),
target->GetHairStyle(), target->GetBeard(), target->GetHairStyle(), target->GetBeard(),
target->GetLuclinFace(), target->GetDrakkinHeritage(), target->GetLuclinFace(), target->GetDrakkinHeritage(),
@ -6588,7 +6588,7 @@ void command_npcedit(Client *c, const Seperator *sep)
database.QueryDatabase(query); database.QueryDatabase(query);
return; return;
} }
if (strcasecmp(sep->arg[1], "slow_mitigation") == 0) { if (strcasecmp(sep->arg[1], "slow_mitigation") == 0) {
c->Message(15, "NPCID %u's slow mitigation limit is now %i.", npcTypeID, atoi(sep->arg[2])); c->Message(15, "NPCID %u's slow mitigation limit is now %i.", npcTypeID, atoi(sep->arg[2]));
std::string query = StringFormat("UPDATE npc_types SET slow_mitigation = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); std::string query = StringFormat("UPDATE npc_types SET slow_mitigation = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID);
@ -6643,7 +6643,7 @@ void command_qglobal(Client *c, const Seperator *sep) {
} }
if(!strcasecmp(sep->arg[1], "on")) { if(!strcasecmp(sep->arg[1], "on")) {
std::string query = StringFormat("UPDATE npc_types SET qglobal = 1 WHERE id = '%i'", std::string query = StringFormat("UPDATE npc_types SET qglobal = 1 WHERE id = '%i'",
target->GetNPCTypeID()); target->GetNPCTypeID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if(!results.Success()) { if(!results.Success()) {
@ -6656,7 +6656,7 @@ void command_qglobal(Client *c, const Seperator *sep) {
} }
if(!strcasecmp(sep->arg[1], "off")) { if(!strcasecmp(sep->arg[1], "off")) {
std::string query = StringFormat("UPDATE npc_types SET qglobal = 0 WHERE id = '%i'", std::string query = StringFormat("UPDATE npc_types SET qglobal = 0 WHERE id = '%i'",
target->GetNPCTypeID()); target->GetNPCTypeID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if(!results.Success()) { if(!results.Success()) {
@ -7052,13 +7052,13 @@ void command_ginfo(Client *c, const Seperator *sep)
if(g->membername[r][0] == '\0') if(g->membername[r][0] == '\0')
continue; continue;
c->Message(0, "...Zoned Member: %s, Roles: %s %s %s", g->membername[r], c->Message(0, "...Zoned Member: %s, Roles: %s %s %s", g->membername[r],
(g->MemberRoles[r] & RoleAssist) ? "Assist" : "", (g->MemberRoles[r] & RoleAssist) ? "Assist" : "",
(g->MemberRoles[r] & RoleTank) ? "Tank" : "", (g->MemberRoles[r] & RoleTank) ? "Tank" : "",
(g->MemberRoles[r] & RolePuller) ? "Puller" : ""); (g->MemberRoles[r] & RolePuller) ? "Puller" : "");
} else { } else {
c->Message(0, "...In-Zone Member: %s (0x%x) Roles: %s %s %s", g->membername[r], g->members[r], c->Message(0, "...In-Zone Member: %s (0x%x) Roles: %s %s %s", g->membername[r], g->members[r],
(g->MemberRoles[r] & RoleAssist) ? "Assist" : "", (g->MemberRoles[r] & RoleAssist) ? "Assist" : "",
(g->MemberRoles[r] & RoleTank) ? "Tank" : "", (g->MemberRoles[r] & RoleTank) ? "Tank" : "",
(g->MemberRoles[r] & RolePuller) ? "Puller" : ""); (g->MemberRoles[r] & RolePuller) ? "Puller" : "");
} }
@ -7221,7 +7221,7 @@ void command_flagedit(Client *c, const Seperator *sep) {
flag_name[127] = '\0'; flag_name[127] = '\0';
std::string query = StringFormat("UPDATE zone SET flag_needed = '%s' " std::string query = StringFormat("UPDATE zone SET flag_needed = '%s' "
"WHERE zoneidnumber = %d AND version = %d", "WHERE zoneidnumber = %d AND version = %d",
flag_name, zoneid, zone->GetInstanceVersion()); flag_name, zoneid, zone->GetInstanceVersion());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if(!results.Success()) { if(!results.Success()) {
@ -7248,7 +7248,7 @@ void command_flagedit(Client *c, const Seperator *sep) {
} }
std::string query = StringFormat("UPDATE zone SET flag_needed = '' " std::string query = StringFormat("UPDATE zone SET flag_needed = '' "
"WHERE zoneidnumber = %d AND version = %d", "WHERE zoneidnumber = %d AND version = %d",
zoneid, zone->GetInstanceVersion()); zoneid, zone->GetInstanceVersion());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if(!results.Success()) { if(!results.Success()) {
@ -7880,7 +7880,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
std::string query = StringFormat("INSERT INTO spawngroup " std::string query = StringFormat("INSERT INTO spawngroup "
"(name, spawn_limit, dist, max_x, min_x, max_y, min_y, delay) " "(name, spawn_limit, dist, max_x, min_x, max_y, min_y, delay) "
"VALUES (\"%s\", %i, %f, %f, %f, %f, %f, %i)", "VALUES (\"%s\", %i, %f, %f, %f, %f, %f, %i)",
sep->arg[2], sep->arg[2],
(sep->arg[3]? atoi(sep->arg[3]): 0), (sep->arg[3]? atoi(sep->arg[3]): 0),
(sep->arg[4]? atof(sep->arg[4]): 0), (sep->arg[4]? atof(sep->arg[4]): 0),
@ -7907,7 +7907,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
} }
std::string query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) " std::string query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) "
"VALUES (%i, %i, %i)", "VALUES (%i, %i, %i)",
atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]));
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -7928,7 +7928,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
} }
std::string query = StringFormat("UPDATE spawngroup SET dist = '%f', max_x = '%f', min_x = '%f', " std::string query = StringFormat("UPDATE spawngroup SET dist = '%f', max_x = '%f', min_x = '%f', "
"max_y = '%f', min_y = '%f', delay = '%i' WHERE id = '%i'", "max_y = '%f', min_y = '%f', delay = '%i' WHERE id = '%i'",
atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]),
atof(sep->arg[6]), atof(sep->arg[7]), atoi(sep->arg[8]), atof(sep->arg[6]), atof(sep->arg[7]), atoi(sep->arg[8]),
atoi(sep->arg[2])); atoi(sep->arg[2]));
@ -8013,7 +8013,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
} }
std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' " std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' "
"WHERE id = '%i'", "WHERE id = '%i'",
c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID()); c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -8084,7 +8084,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep)
int16 version = atoi(sep->arg[2]); int16 version = atoi(sep->arg[2]);
std::string query = StringFormat("UPDATE spawn2 SET version = %i " std::string query = StringFormat("UPDATE spawn2 SET version = %i "
"WHERE spawngroupID = '%i'", "WHERE spawngroupID = '%i'",
version, c->GetTarget()->CastToNPC()->GetSp2()); version, c->GetTarget()->CastToNPC()->GetSp2());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -10135,7 +10135,7 @@ void command_zopp(Client *c, const Seperator *sep)
ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges); ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
c->SendItemPacket(slotid, FakeItemInst, packettype); c->SendItemPacket(slotid, FakeItemInst, packettype);
c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.",
packettype == ItemPacketTrade ? "Trade" : "Summon", FakeItem->Name, itemid, charges, packettype == ItemPacketTrade ? "Trade" : "Summon", FakeItem->Name, itemid, charges,
std::abs(charges == 1) ? "charge" : "charges", slotid); std::abs(charges == 1) ? "charge" : "charges", slotid);
safe_delete(FakeItemInst); safe_delete(FakeItemInst);
@ -10354,7 +10354,7 @@ void command_tune(Client *c, const Seperator *sep)
ac_override = 0; ac_override = 0;
if (!info_level) if (!info_level)
info_level = 1; info_level = 1;
if(!strcasecmp(sep->arg[2], "A")) if(!strcasecmp(sep->arg[2], "A"))
c->Tune_FindATKByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,ac_override,info_level); c->Tune_FindATKByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,ac_override,info_level);
else if(!strcasecmp(sep->arg[2], "B")) else if(!strcasecmp(sep->arg[2], "B"))
@ -10389,7 +10389,7 @@ void command_tune(Client *c, const Seperator *sep)
atk_override = 0; atk_override = 0;
if (!info_level) if (!info_level)
info_level = 1; info_level = 1;
if(!strcasecmp(sep->arg[2], "A")) if(!strcasecmp(sep->arg[2], "A"))
c->Tune_FindACByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,atk_override,info_level); c->Tune_FindACByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,atk_override,info_level);
else if(!strcasecmp(sep->arg[2], "B")) else if(!strcasecmp(sep->arg[2], "B"))
@ -10431,7 +10431,7 @@ void command_tune(Client *c, const Seperator *sep)
c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit));
return; return;
} }
if(!strcasecmp(sep->arg[2], "A")) if(!strcasecmp(sep->arg[2], "A"))
c->Tune_FindAccuaryByHitChance(defender, attacker, hit_chance, interval, max_loop,avoid_override,info_level); c->Tune_FindAccuaryByHitChance(defender, attacker, hit_chance, interval, max_loop,avoid_override,info_level);
else if(!strcasecmp(sep->arg[2], "B")) else if(!strcasecmp(sep->arg[2], "B"))
@ -10473,7 +10473,7 @@ void command_tune(Client *c, const Seperator *sep)
c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit));
return; return;
} }
if(!strcasecmp(sep->arg[2], "A")) if(!strcasecmp(sep->arg[2], "A"))
c->Tune_FindAvoidanceByHitChance(defender, attacker, hit_chance, interval, max_loop,acc_override, info_level); c->Tune_FindAvoidanceByHitChance(defender, attacker, hit_chance, interval, max_loop,acc_override, info_level);
else if(!strcasecmp(sep->arg[2], "B")) else if(!strcasecmp(sep->arg[2], "B"))
@ -10499,7 +10499,7 @@ void command_logtest(Client *c, const Seperator *sep){
for (i = 0; i < atoi(sep->arg[1]); i++){ for (i = 0; i < atoi(sep->arg[1]); i++){
Log.Out(Logs::General, Logs::Debug, "[%u] Test #2... Took %f seconds", i, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); Log.Out(Logs::General, Logs::Debug, "[%u] Test #2... Took %f seconds", i, ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
} }
} }
} }
@ -10555,7 +10555,7 @@ void command_logs(Client *c, const Seperator *sep){
c->Message(15, "Your Log Settings have been applied"); c->Message(15, "Your Log Settings have been applied");
c->Message(15, "Output Method: %s :: Debug Level: %i - Category: %s", sep->arg[2], atoi(sep->arg[4]), Logs::LogCategoryName[atoi(sep->arg[3])]); c->Message(15, "Output Method: %s :: Debug Level: %i - Category: %s", sep->arg[2], atoi(sep->arg[4]), Logs::LogCategoryName[atoi(sep->arg[3])]);
} }
/* We use a general 'is_category_enabled' now, let's update when we update any output settings /* We use a general 'is_category_enabled' now, let's update when we update any output settings
This is used in hot places of code to check if its enabled in any way before triggering logs This is used in hot places of code to check if its enabled in any way before triggering logs
*/ */
if (sep->arg[4] > 0){ if (sep->arg[4] > 0){
@ -10583,9 +10583,9 @@ void command_mysqltest(Client *c, const Seperator *sep)
for (i = 0; i < atoi(sep->arg[1]); i++){ for (i = 0; i < atoi(sep->arg[1]); i++){
std::string query = "SELECT * FROM `zone`"; std::string query = "SELECT * FROM `zone`";
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
} }
} }
Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
} }
void command_resetaa_timer(Client *c, const Seperator *sep) { void command_resetaa_timer(Client *c, const Seperator *sep) {
@ -10596,18 +10596,18 @@ void command_resetaa_timer(Client *c, const Seperator *sep) {
target = c->GetTarget()->CastToClient(); target = c->GetTarget()->CastToClient();
} }
if(sep->IsNumber(1)) if(sep->IsNumber(1))
{ {
int timer_id = atoi(sep->arg[1]); int timer_id = atoi(sep->arg[1]);
c->Message(0, "Reset of timer %i for %s", timer_id, c->GetName()); c->Message(0, "Reset of timer %i for %s", timer_id, c->GetName());
c->ResetAlternateAdvancementTimer(timer_id); c->ResetAlternateAdvancementTimer(timer_id);
} }
else if(!strcasecmp(sep->arg[1], "all")) else if(!strcasecmp(sep->arg[1], "all"))
{ {
c->Message(0, "Reset all timers for %s", c->GetName()); c->Message(0, "Reset all timers for %s", c->GetName());
c->ResetAlternateAdvancementTimers(); c->ResetAlternateAdvancementTimers();
} }
else else
{ {
c->Message(0, "usage: #resetaa_timer [all | timer_id]"); c->Message(0, "usage: #resetaa_timer [all | timer_id]");
} }

View File

@ -2409,6 +2409,14 @@ bool Mob::CanThisClassDoubleAttack(void) const
} }
} }
bool Mob::CanThisClassTripleAttack() const
{
if (!IsClient())
return false; // When they added the real triple attack skill, mobs lost the ability to triple
else
return CastToClient()->HasSkill(SkillTripleAttack);
}
bool Mob::IsWarriorClass(void) const bool Mob::IsWarriorClass(void) const
{ {
switch(GetClass()) switch(GetClass())

View File

@ -169,7 +169,7 @@ public:
virtual bool CheckDualWield(); virtual bool CheckDualWield();
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr); void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr); void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
virtual bool CheckDoubleAttack(bool tripleAttack = false); // mob version doesn't use this flag virtual bool CheckDoubleAttack();
// inline process for places where we need to do them outside of the AI_Process // inline process for places where we need to do them outside of the AI_Process
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr) void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr)
{ {
@ -750,6 +750,7 @@ public:
virtual int GetMonkHandToHandDamage(void); virtual int GetMonkHandToHandDamage(void);
bool CanThisClassDoubleAttack(void) const; bool CanThisClassDoubleAttack(void) const;
bool CanThisClassTripleAttack() const;
bool CanThisClassDualWield(void) const; bool CanThisClassDualWield(void) const;
bool CanThisClassRiposte(void) const; bool CanThisClassRiposte(void) const;
bool CanThisClassDodge(void) const; bool CanThisClassDodge(void) const;

View File

@ -536,7 +536,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
RogueBackstab(other,false,ReuseTime); RogueBackstab(other,false,ReuseTime);
if (level > 54) { if (level > 54) {
if(IsClient() && CastToClient()->CheckDoubleAttack(false)) if(IsClient() && CastToClient()->CheckDoubleAttack())
{ {
if(other->GetHP() > 0) if(other->GetHP() > 0)
RogueBackstab(other,false,ReuseTime); RogueBackstab(other,false,ReuseTime);
@ -558,7 +558,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
if (level > 54) { if (level > 54) {
// Check for double attack with main hand assuming maxed DA Skill (MS) // Check for double attack with main hand assuming maxed DA Skill (MS)
if(IsClient() && CastToClient()->CheckDoubleAttack(false)) if(IsClient() && CastToClient()->CheckDoubleAttack())
if(other->GetHP() > 0) if(other->GetHP() > 0)
RogueBackstab(other,true, ReuseTime); RogueBackstab(other,true, ReuseTime);