#include "mod_quick_boost.h"
#include "Chat.h"
#include "Config.h"
#include "Creature.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptedGossip.h"
#include "ScriptMgr.h"
#include "StringFormat.h"
namespace
{
constexpr uint32 GOSSIP_ACTION_BOOST = 1;
constexpr uint32 QUICK_BOOST_NPC_TEXT = 70100;
}
std::unordered_map> const QuickBoost::_classGear =
{
{ CLASS_WARRIOR, {
{ 3489, EQUIPMENT_SLOT_MAINHAND }, // Thick War Axe
{ 821, EQUIPMENT_SLOT_CHEST }, // Riverpaw Leather Vest
{ 38513, EQUIPMENT_SLOT_LEGS }, // Boarhide Leggings
{ 4789, EQUIPMENT_SLOT_FEET }, // Stable Boots
} },
{ CLASS_PALADIN, {
{ 4569, EQUIPMENT_SLOT_MAINHAND }, // Staunch Hammer
{ 1211, EQUIPMENT_SLOT_CHEST }, // Gnoll War Harness
{ 6553, EQUIPMENT_SLOT_LEGS }, // Bard's Trousers
{ 6557, EQUIPMENT_SLOT_FEET }, // Bard's Boots
} },
{ CLASS_HUNTER, {
{ 11304, EQUIPMENT_SLOT_RANGED }, // Fine Longbow
{ 6268, EQUIPMENT_SLOT_CHEST }, // Pioneer Tunic
{ 4242, EQUIPMENT_SLOT_LEGS }, // Embossed Leather Pants
{ 5968, EQUIPMENT_SLOT_FEET }, // Rugged Boots
} },
{ CLASS_ROGUE, {
{ 4571, EQUIPMENT_SLOT_MAINHAND }, // War Knife
{ 2311, EQUIPMENT_SLOT_CHEST }, // White Leather Jerkin
{ 9756, EQUIPMENT_SLOT_LEGS }, // Gypsy Trousers
{ 2309, EQUIPMENT_SLOT_FEET }, // Embossed Leather Boots
} },
{ CLASS_PRIEST, {
{ 4575, EQUIPMENT_SLOT_MAINHAND }, // Medicine Staff
{ 9748, EQUIPMENT_SLOT_CHEST }, // Simple Robe
{ 9747, EQUIPMENT_SLOT_LEGS }, // Simple Britches
{ 22991, EQUIPMENT_SLOT_FEET }, // Apprentice Boots
} },
{ CLASS_SHAMAN, {
{ 4570, EQUIPMENT_SLOT_MAINHAND }, // Birchwood Maul
{ 2973, EQUIPMENT_SLOT_CHEST }, // Hunting Tunic
{ 2974, EQUIPMENT_SLOT_LEGS }, // Hunting Pants
{ 2307, EQUIPMENT_SLOT_FEET }, // Fine Leather Boots
} },
{ CLASS_MAGE, {
{ 4566, EQUIPMENT_SLOT_MAINHAND }, // Sturdy Quarterstaff
{ 6242, EQUIPMENT_SLOT_CHEST }, // Blue Linen Robe
{ 14097, EQUIPMENT_SLOT_LEGS }, // Native Pants
{ 2569, EQUIPMENT_SLOT_FEET }, // Linen Boots
} },
{ CLASS_WARLOCK, {
{ 1933, EQUIPMENT_SLOT_MAINHAND }, // Staff of Conjuring
{ 6527, EQUIPMENT_SLOT_CHEST }, // Ancestral Robe
{ 3291, EQUIPMENT_SLOT_LEGS }, // Ancestral Woollies
{ 4312, EQUIPMENT_SLOT_FEET }, // Soft-soled Linen Boots
} },
{ CLASS_DRUID, {
{ 1539, EQUIPMENT_SLOT_MAINHAND }, // Gnarled Hermit's Staff
{ 3288, EQUIPMENT_SLOT_CHEST }, // Tribal Vest
{ 15303, EQUIPMENT_SLOT_LEGS }, // Grizzly Pants
{ 15012, EQUIPMENT_SLOT_FEET }, // Lupine Slippers
} },
};
std::unordered_map const QuickBoost::_racePet =
{
{ RACE_HUMAN, 118 }, // Prowler (Elwynn Forest)
{ RACE_DWARF, 1196 }, // Ice Claw Bear (Dun Morogh)
{ RACE_GNOME, 1196 }, // Ice Claw Bear (Dun Morogh)
{ RACE_NIGHTELF, 2031 }, // Young Nightsaber (Teldrassil)
{ RACE_DRAENEI, 17345 }, // Brown Bear (Azuremyst Isle)
{ RACE_ORC, 3098 }, // Mottled Boar (Durotar)
{ RACE_TROLL, 3098 }, // Mottled Boar (Durotar)
{ RACE_TAUREN, 2958 }, // Prairie Wolf (Mulgore)
{ RACE_UNDEAD_PLAYER, 1765 }, // Worg (Tirisfal Glades)
{ RACE_BLOODELF, 15649 }, // Feral Dragonhawk Hatchling (Eversong Woods)
};
std::unordered_map const QuickBoost::_raceCapital =
{
{ RACE_HUMAN, { 0, -8833.38f, 628.628f, 94.0066f, 1.06535f } }, // Stormwind City
{ RACE_DWARF, { 0, -4918.88f, -940.406f, 501.564f, 5.42347f } }, // Ironforge
{ RACE_GNOME, { 0, -4918.88f, -940.406f, 501.564f, 5.42347f } }, // Ironforge
{ RACE_NIGHTELF, { 1, 9949.56f, 2284.21f, 1341.4f, 1.59587f } }, // Darnassus
{ RACE_DRAENEI, { 530, -3965.7f, -11653.6f, -138.844f, 0.852154f} }, // The Exodar
{ RACE_ORC, { 1, 1629.85f, -4373.64f, 31.5573f, 3.69762f } }, // Orgrimmar
{ RACE_TROLL, { 1, 1629.85f, -4373.64f, 31.5573f, 3.69762f } }, // Orgrimmar
{ RACE_TAUREN, { 1, -1277.37f, 124.804f, 131.287f, 5.22274f } }, // Thunder Bluff
{ RACE_UNDEAD_PLAYER, { 0, 1584.14f, 240.308f, -52.1534f, 0.041793f} }, // Undercity
{ RACE_BLOODELF, { 530, 9487.69f, -7279.2f, 14.2866f, 6.16478f } }, // Silvermoon City
};
void QuickBoost::LoadConfig()
{
_enabled = sConfigMgr->GetOption("QuickBoost.Enable", true);
_boostLevel = static_cast(sConfigMgr->GetOption("QuickBoost.Level", 15));
_destroyStartingGear = sConfigMgr->GetOption("QuickBoost.DestroyStartingGear", true);
_startingMoney = sConfigMgr->GetOption("QuickBoost.StartingMoney", 5000);
_teleportToCapital = sConfigMgr->GetOption("QuickBoost.TeleportToCapital", true);
_grantHunterPet = sConfigMgr->GetOption("QuickBoost.GrantHunterPet", true);
_learnClassSpells = sConfigMgr->GetOption("QuickBoost.LearnClassSpells", true);
}
void QuickBoost::DestroyStartingGear(Player* player) const
{
if (!_destroyStartingGear)
return;
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
if (player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
player->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
}
void QuickBoost::EquipStarterGear(Player* player) const
{
auto it = _classGear.find(player->getClass());
if (it == _classGear.end())
return;
for (QuickBoostGearEntry const& gear : it->second)
{
uint16 dest = 0;
if (player->CanEquipNewItem(gear.equipmentSlot, dest, gear.itemEntry, false) == EQUIP_ERR_OK)
player->EquipNewItem(dest, gear.itemEntry, true);
}
}
void QuickBoost::GiveStartingMoney(Player* player) const
{
if (_startingMoney)
player->ModifyMoney(static_cast(_startingMoney));
}
void QuickBoost::TeleportToCapital(Player* player) const
{
if (!_teleportToCapital)
return;
auto it = _raceCapital.find(player->getRace());
if (it == _raceCapital.end())
return;
QuickBoostLocation const& loc = it->second;
player->TeleportTo(loc.mapId, loc.x, loc.y, loc.z, loc.o);
}
void QuickBoost::GrantHunterPet(Player* player) const
{
if (!_grantHunterPet || player->getClass() != CLASS_HUNTER || player->IsExistPet())
return;
auto it = _racePet.find(player->getRace());
if (it == _racePet.end())
return;
player->CreatePet(it->second);
}
void QuickBoost::LearnClassSpells(Player* player) const
{
if (!_learnClassSpells)
return;
std::vector const& trainers = sObjectMgr->GetClassTrainers(player->getClass());
// Repeat until a full pass teaches nothing new: learning a rank can unlock
// the next rank's prerequisite, so a single pass can miss later ranks.
bool hadNew;
do
{
hadNew = false;
for (Trainer::Trainer const* trainer : trainers)
{
if (!trainer->IsTrainerValidForPlayer(player))
continue;
for (Trainer::Spell const& trainerSpell : trainer->GetSpells())
{
if (!trainer->CanTeachSpell(player, &trainerSpell))
continue;
if (trainerSpell.IsCastable())
player->CastSpell(player, trainerSpell.SpellId, true);
else
player->learnSpell(trainerSpell.SpellId, false);
hadNew = true;
}
}
} while (hadNew);
}
void QuickBoost::ApplyBoost(Player* player) const
{
player->GiveLevel(_boostLevel);
DestroyStartingGear(player);
EquipStarterGear(player);
GiveStartingMoney(player);
GrantHunterPet(player);
LearnClassSpells(player);
if (player->getPowerType() == POWER_MANA)
player->SetPower(POWER_MANA, player->GetMaxPower(POWER_MANA));
player->SetHealth(player->GetMaxHealth());
player->SaveToDB(false, false);
TeleportToCapital(player);
}
class QuickBoost_NPC : public CreatureScript
{
public:
QuickBoost_NPC() : CreatureScript("QuickBoost_NPC") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
ClearGossipMenuFor(player);
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
if (sQuickBoost->IsEnabled() && player->GetLevel() == 1)
{
AddGossipItemFor(player, GOSSIP_ICON_CHAT,
Acore::StringFormat("Boost me to level {}!", sQuickBoost->GetBoostLevel()),
GOSSIP_SENDER_MAIN, GOSSIP_ACTION_BOOST);
}
SendGossipMenuFor(player, QUICK_BOOST_NPC_TEXT, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 sender, uint32 action) override
{
if (sender != GOSSIP_SENDER_MAIN)
return false;
CloseGossipMenuFor(player);
if (action == GOSSIP_ACTION_BOOST && sQuickBoost->IsEnabled() && player->GetLevel() == 1)
sQuickBoost->ApplyBoost(player);
return true;
}
};
class QuickBoost_World : public WorldScript
{
public:
QuickBoost_World() : WorldScript("QuickBoost_World") { }
void OnBeforeConfigLoad(bool /*reload*/) override
{
sQuickBoost->LoadConfig();
}
};
void AddSC_mod_quick_boost()
{
new QuickBoost_NPC();
new QuickBoost_World();
}