Skip to content

Instantly share code, notes, and snippets.

@Shauren
Created December 30, 2018 17:56
Show Gist options
  • Save Shauren/8031b6b82283f0a409d760e8048cc861 to your computer and use it in GitHub Desktop.
Save Shauren/8031b6b82283f0a409d760e8048cc861 to your computer and use it in GitHub Desktop.
npc_trainer converter
namespace TrinityOld
{
struct TrainerRequirement
{
uint32 trainer_type;
uint32 trainer_spell;
uint32 trainer_class;
uint32 trainer_race;
};
struct TrainerSpell
{
int32 SpellId;
uint32 MoneyCost;
uint16 ReqSkillLine;
uint16 ReqSkillRank;
uint8 ReqLevel;
std::array<uint32, 3> ReqAbility;
friend bool operator<(TrainerSpell const& l, TrainerSpell const& r) { return l.SpellId < r.SpellId; }
friend bool operator==(TrainerSpell const& l, TrainerSpell const& r) { return l.SpellId == r.SpellId; }
};
using trainer_spell_set_key = std::pair<TrainerRequirement*, std::set<TrainerSpell>*>;
struct compare_set_ptrs
{
bool operator()(trainer_spell_set_key const& _Left, trainer_spell_set_key const& _Right) const
{ // apply operator< to operands
return std::tie(_Left.first->trainer_type, _Left.first->trainer_spell, _Left.first->trainer_class, _Left.first->trainer_race, *_Left.second) <
std::tie(_Right.first->trainer_type, _Right.first->trainer_spell, _Right.first->trainer_class, _Right.first->trainer_race, *_Right.second);
}
};
std::unordered_map<uint32, TrainerRequirement> trainerRequirements;
std::unordered_map<uint32, std::set<TrainerSpell>> trainerSpellsByTrainerIdInitial;
std::unordered_map<uint32, std::set<TrainerSpell>> trainerSpellsByTrainerIdExpanded;
std::map<trainer_spell_set_key, std::set<uint32>, compare_set_ptrs> trainersBySpellSet;
void load_old_requirements()
{
QueryResult creatureTemplate = WorldDatabase.Query("SELECT entry,trainer_type,trainer_spell,trainer_class,trainer_race FROM creature_template WHERE trainer_type!=0 OR trainer_spell!=0 OR trainer_class!=0 OR trainer_race!=0");
if (!creatureTemplate)
return;
do
{
Field* fields = creatureTemplate->Fetch();
TrainerRequirement& req = trainerRequirements[fields[0].GetUInt32()];
req.trainer_type = fields[1].GetUInt32();
req.trainer_spell = fields[2].GetUInt32();
req.trainer_class = fields[3].GetUInt32();
req.trainer_race = fields[4].GetUInt32();
} while (creatureTemplate->NextRow());
}
void load_old_trainers()
{
QueryResult npcTrainer = WorldDatabase.Query("SELECT ID,SpellID,MoneyCost,ReqSkillLine,ReqSkillRank,ReqLevel FROM npc_trainer");
if (!npcTrainer)
return;
do
{
Field* fields = npcTrainer->Fetch();
uint32 id = fields[0].GetUInt32();
TrainerSpell trainerSpell;
trainerSpell.SpellId = fields[1].GetInt32();
trainerSpell.MoneyCost = fields[2].GetUInt32();
trainerSpell.ReqSkillLine = fields[3].GetUInt16();
trainerSpell.ReqSkillRank = fields[4].GetUInt16();
trainerSpell.ReqLevel = fields[5].GetUInt8();
trainerSpell.ReqAbility.fill(0);
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(trainerSpell.SpellId))
{
std::vector<uint32> reqAbilities;
if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
{
for (std::size_t i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].IsEffect(SPELL_EFFECT_LEARN_SPELL))
{
if (uint32 prevRank = sSpellMgr->GetPrevSpellInChain(spellInfo->Effects[i].TriggerSpell))
reqAbilities.push_back(prevRank);
for (auto reqs : sSpellMgr->GetSpellsRequiredForSpellBounds(spellInfo->Effects[i].TriggerSpell))
reqAbilities.push_back(reqs.second);
}
}
}
else
{
if (uint32 prevRank = sSpellMgr->GetPrevSpellInChain(spellInfo->Id))
reqAbilities.push_back(prevRank);
for (auto reqs : sSpellMgr->GetSpellsRequiredForSpellBounds(spellInfo->Id))
reqAbilities.push_back(reqs.second);
}
for (std::size_t i = 0; i < std::min(reqAbilities.size(), size_t(3)); ++i)
trainerSpell.ReqAbility[i] = reqAbilities[i];
}
trainerSpellsByTrainerIdInitial[id].insert(trainerSpell);
} while (npcTrainer->NextRow());
}
void expand_trainer_reference(uint32 trainerId, std::set<TrainerSpell> const& oldSpells)
{
for (auto spellItr = oldSpells.begin(); spellItr != oldSpells.end(); ++spellItr)
{
if (spellItr->SpellId < 0)
expand_trainer_reference(trainerId, trainerSpellsByTrainerIdInitial[-spellItr->SpellId]);
else if (trainerId < 200000)
trainerSpellsByTrainerIdExpanded[trainerId].insert(*spellItr);
}
}
void expand_trainer_references()
{
for (auto&& p : trainerSpellsByTrainerIdInitial)
expand_trainer_reference(p.first, p.second);
}
void collect_trainer_spell_sets()
{
TrainerRequirement* const empty = new TrainerRequirement();
empty->trainer_type = 2;
empty->trainer_class = 0;
empty->trainer_race = 0;
empty->trainer_spell = 0;
for (auto itr = trainerSpellsByTrainerIdExpanded.begin(); itr != trainerSpellsByTrainerIdExpanded.end(); ++itr)
{
TrainerRequirement* requirement = Trinity::Containers::MapGetValuePtr(trainerRequirements, itr->first);
if (!requirement)
requirement = empty;
trainersBySpellSet[std::make_pair(requirement, &itr->second)].insert(itr->first);
}
}
void output_sql()
{
uint32 trainerIdGenerator = 1;
TC_LOG_ERROR("sql.sql", "INSERT INTO `trainer` (`Id`,`Type`,`Requirement`,`Greeting`,`VerifiedBuild`) VALUES");
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr)
{
uint32 requirement = 0;
switch (itr->first.first->trainer_type)
{
case 0:
requirement = itr->first.first->trainer_class;
break;
case 1:
requirement = itr->first.first->trainer_race;
break;
case 2:
requirement = itr->first.first->trainer_spell;
break;
case 3:
default:
break;
}
TC_LOG_ERROR("sql.sql", "(%u,%u,%u,NULL,0),", trainerIdGenerator, itr->first.first->trainer_type, requirement);
++trainerIdGenerator;
}
trainerIdGenerator = 1;
TC_LOG_ERROR("sql.sql", "INSERT INTO `trainer_spell` (`TrainerId`,`SpellId`,`MoneyCost`,`ReqSkillLine`,`ReqSkillRank`,`ReqAbility1`,`ReqAbility2`,`ReqAbility3`,`ReqLevel`,`VerifiedBuild`) VALUES");
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr)
{
for (TrainerSpell const& tSpell : *itr->first.second)
{
TC_LOG_ERROR("sql.sql", "(%u,%u,%u,%u,%u,%u,%u,%u,%u,0),",
trainerIdGenerator, tSpell.SpellId, tSpell.MoneyCost, tSpell.ReqSkillLine, tSpell.ReqSkillRank,
tSpell.ReqAbility[0], tSpell.ReqAbility[1], tSpell.ReqAbility[2], tSpell.ReqLevel);
}
++trainerIdGenerator;
}
trainerIdGenerator = 1;
TC_LOG_ERROR("sql.sql", "INSERT INTO `creature_default_trainer` (`CreatureId`,`TrainerId`) VALUES");
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr)
{
for (uint32 creatureId : itr->second)
{
TC_LOG_ERROR("sql.sql", "(%u,%u),", creatureId, trainerIdGenerator);
}
++trainerIdGenerator;
}
}
void convert_old_trainers()
{
load_old_requirements();
load_old_trainers();
expand_trainer_references();
collect_trainer_spell_sets();
output_sql();
exit(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment