mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 17:09:08 +00:00
319 lines
9.7 KiB
C++
319 lines
9.7 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
|
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "ListSpellsAction.h"
|
|
|
|
#include "Event.h"
|
|
#include "Playerbots.h"
|
|
|
|
std::map<uint32, SkillLineAbilityEntry const*> ListSpellsAction::skillSpells;
|
|
std::set<uint32> ListSpellsAction::vendorItems;
|
|
|
|
bool CompareSpells(const std::pair<uint32, std::string>& s1, const std::pair<uint32, std::string>& s2)
|
|
{
|
|
SpellInfo const* si1 = sSpellMgr->GetSpellInfo(s1.first);
|
|
SpellInfo const* si2 = sSpellMgr->GetSpellInfo(s2.first);
|
|
if (!si1 || !si2)
|
|
{
|
|
LOG_ERROR("playerbots", "SpellInfo missing. {} {}", s1.first, s2.first);
|
|
return false;
|
|
}
|
|
uint32 p1 = si1->SchoolMask * 20000;
|
|
uint32 p2 = si2->SchoolMask * 20000;
|
|
|
|
uint32 skill1 = 0, skill2 = 0;
|
|
uint32 skillValue1 = 0, skillValue2 = 0;
|
|
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
|
|
{
|
|
if (SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j))
|
|
{
|
|
if (skillLine->Spell == s1.first)
|
|
{
|
|
skill1 = skillLine->SkillLine;
|
|
skillValue1 = skillLine->TrivialSkillLineRankLow;
|
|
}
|
|
|
|
if (skillLine->Spell == s2.first)
|
|
{
|
|
skill2 = skillLine->SkillLine;
|
|
skillValue2 = skillLine->TrivialSkillLineRankLow;
|
|
}
|
|
}
|
|
|
|
if (skill1 && skill2)
|
|
break;
|
|
}
|
|
|
|
p1 += skill1 * 500;
|
|
p2 += skill2 * 500;
|
|
|
|
p1 += skillValue1;
|
|
p2 += skillValue2;
|
|
|
|
if (p1 == p2)
|
|
{
|
|
return strcmp(si1->SpellName[0], si2->SpellName[0]) > 0;
|
|
}
|
|
|
|
return p1 > p2;
|
|
}
|
|
|
|
std::vector<std::pair<uint32, std::string>> ListSpellsAction::GetSpellList(std::string filter)
|
|
{
|
|
if (skillSpells.empty())
|
|
{
|
|
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
|
|
{
|
|
if (SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j))
|
|
skillSpells[skillLine->Spell] = skillLine;
|
|
}
|
|
}
|
|
|
|
if (vendorItems.empty())
|
|
{
|
|
QueryResult results = WorldDatabase.Query("SELECT item FROM npc_vendor WHERE maxcount = 0");
|
|
if (results)
|
|
{
|
|
do
|
|
{
|
|
Field* fields = results->Fetch();
|
|
int32 entry = fields[0].Get<int32>();
|
|
if (entry <= 0)
|
|
continue;
|
|
|
|
vendorItems.insert(entry);
|
|
} while (results->NextRow());
|
|
}
|
|
}
|
|
|
|
std::ostringstream posOut;
|
|
std::ostringstream negOut;
|
|
|
|
uint32 skill = 0;
|
|
|
|
std::vector<std::string> ss = split(filter, ' ');
|
|
if (!ss.empty())
|
|
{
|
|
skill = chat->parseSkill(ss[0]);
|
|
if (skill != SKILL_NONE)
|
|
{
|
|
filter = ss.size() > 1 ? filter = ss[1] : "";
|
|
}
|
|
|
|
if (ss[0] == "first" && ss[1] == "aid")
|
|
{
|
|
skill = SKILL_FIRST_AID;
|
|
filter = ss.size() > 2 ? filter = ss[2] : "";
|
|
}
|
|
}
|
|
|
|
std::string const ignoreList =
|
|
",Opening,Closing,Stuck,Remove Insignia,Opening - No Text,Grovel,Duel,Honorless Target,";
|
|
std::string alreadySeenList = ",";
|
|
|
|
uint32 minLevel = 0;
|
|
uint32 maxLevel = 0;
|
|
if (filter.find("-") != std::string::npos)
|
|
{
|
|
std::vector<std::string> ff = split(filter, '-');
|
|
minLevel = atoi(ff[0].c_str());
|
|
maxLevel = atoi(ff[1].c_str());
|
|
filter = "";
|
|
}
|
|
|
|
bool craftableOnly = false;
|
|
if (filter.find("+") != std::string::npos)
|
|
{
|
|
craftableOnly = true;
|
|
filter.erase(remove(filter.begin(), filter.end(), '+'), filter.end());
|
|
}
|
|
|
|
uint32 slot = chat->parseSlot(filter);
|
|
if (slot != EQUIPMENT_SLOT_END)
|
|
filter = "";
|
|
|
|
std::vector<std::pair<uint32, std::string>> spells;
|
|
for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr)
|
|
{
|
|
if (itr->second->State == PLAYERSPELL_REMOVED || !itr->second->Active)
|
|
continue;
|
|
|
|
if (!(itr->second->specMask & bot->GetActiveSpecMask()))
|
|
continue;
|
|
|
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
|
if (!spellInfo)
|
|
continue;
|
|
|
|
if (spellInfo->IsPassive())
|
|
continue;
|
|
|
|
SkillLineAbilityEntry const* skillLine = skillSpells[itr->first];
|
|
if (skill != SKILL_NONE && (!skillLine || skillLine->SkillLine != skill))
|
|
continue;
|
|
|
|
std::string const comp = spellInfo->SpellName[0];
|
|
if (!(ignoreList.find(comp) == std::string::npos && alreadySeenList.find(comp) == std::string::npos))
|
|
continue;
|
|
|
|
if (!filter.empty() && !strstri(spellInfo->SpellName[0], filter.c_str()))
|
|
continue;
|
|
|
|
bool first = true;
|
|
int32 craftCount = -1;
|
|
std::ostringstream materials;
|
|
for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
|
|
{
|
|
if (spellInfo->Reagent[x] <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32 itemid = spellInfo->Reagent[x];
|
|
uint32 reagentsRequired = spellInfo->ReagentCount[x];
|
|
if (itemid)
|
|
{
|
|
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid))
|
|
{
|
|
if (first)
|
|
{
|
|
materials << ": ";
|
|
first = false;
|
|
}
|
|
else
|
|
materials << ", ";
|
|
|
|
materials << chat->FormatItem(proto, reagentsRequired);
|
|
|
|
FindItemByIdVisitor visitor(itemid);
|
|
uint32 reagentsInInventory = InventoryAction::GetItemCount(&visitor);
|
|
bool buyable = (vendorItems.find(itemid) != vendorItems.end());
|
|
if (!buyable)
|
|
{
|
|
uint32 craftable = reagentsInInventory / reagentsRequired;
|
|
if (craftCount < 0 || craftCount > craftable)
|
|
craftCount = craftable;
|
|
}
|
|
|
|
if (reagentsInInventory)
|
|
materials << "|cffffff00(x" << reagentsInInventory << ")|r ";
|
|
else if (buyable)
|
|
materials << "|cffffff00(buy)|r ";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (craftCount < 0)
|
|
craftCount = 0;
|
|
|
|
std::ostringstream out;
|
|
bool filtered = false;
|
|
if (skillLine)
|
|
{
|
|
for (uint8 i = 0; i < 3; ++i)
|
|
{
|
|
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_CREATE_ITEM)
|
|
{
|
|
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(spellInfo->Effects[i].ItemType))
|
|
{
|
|
if (craftCount)
|
|
out << "|cffffff00(x" << craftCount << ")|r ";
|
|
|
|
out << chat->FormatItem(proto);
|
|
|
|
if ((minLevel || maxLevel) && (!proto->RequiredLevel || proto->RequiredLevel < minLevel ||
|
|
proto->RequiredLevel > maxLevel))
|
|
{
|
|
filtered = true;
|
|
break;
|
|
}
|
|
|
|
if (slot != EQUIPMENT_SLOT_END && bot->FindEquipSlot(proto, slot, true) != slot)
|
|
{
|
|
filtered = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (out.str().empty())
|
|
out << chat->FormatSpell(spellInfo);
|
|
|
|
if (filtered)
|
|
continue;
|
|
|
|
if (craftableOnly && !craftCount)
|
|
continue;
|
|
|
|
out << materials.str();
|
|
|
|
if (skillLine && skillLine->SkillLine)
|
|
{
|
|
uint32 GrayLevel = skillLine->TrivialSkillLineRankHigh;
|
|
uint32 GreenLevel = (skillLine->TrivialSkillLineRankHigh + skillLine->MinSkillLineRank) / 2;
|
|
uint32 YellowLevel = skillLine->MinSkillLineRank;
|
|
uint32 SkillValue = bot->GetSkillValue(skillLine->SkillLine);
|
|
|
|
out << " - ";
|
|
if (SkillValue >= GrayLevel)
|
|
out << " |cff808080gray";
|
|
else if (SkillValue >= GreenLevel)
|
|
out << " |cff80be80green";
|
|
else if (SkillValue >= YellowLevel)
|
|
out << " |cffffff00yellow";
|
|
else
|
|
out << " |cffff8040orange";
|
|
|
|
out << "|r";
|
|
}
|
|
|
|
if (out.str().empty())
|
|
continue;
|
|
|
|
if (itr->first == 0)
|
|
{
|
|
LOG_ERROR("playerbots", "?! {}", itr->first);
|
|
}
|
|
spells.push_back(std::pair<uint32, std::string>(itr->first, out.str()));
|
|
alreadySeenList += spellInfo->SpellName[0];
|
|
alreadySeenList += ",";
|
|
}
|
|
|
|
return spells;
|
|
}
|
|
|
|
bool ListSpellsAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
std::string const filter = event.getParam();
|
|
|
|
std::vector<std::pair<uint32, std::string>> spells = GetSpellList(filter);
|
|
|
|
botAI->TellMaster("=== Spells ===");
|
|
|
|
std::sort(spells.begin(), spells.end(), CompareSpells);
|
|
|
|
uint32 count = 0;
|
|
for (std::vector<std::pair<uint32, std::string>>::iterator i = spells.begin(); i != spells.end(); ++i)
|
|
{
|
|
botAI->TellMasterNoFacing(i->second);
|
|
|
|
// if (++count >= 50)
|
|
// {
|
|
// std::ostringstream msg;
|
|
// msg << (spells.size() - 50) << " more...";
|
|
// botAI->TellMasterNoFacing(msg.str());
|
|
// break;
|
|
// }
|
|
}
|
|
|
|
return true;
|
|
}
|