#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(); }