Forum > Serverside Modding
[TRINITY] Spells Scale from Level
<< < (2/2)
Laniax:
--- Quote from: "schlumpf" ---You may as well have a look at Player::GetTrainerSpellState(trainer_spell). That will look somewhere in Player, where you already are, if a spell is available. Therefore, there needs to be information inside of Player, if a spell is learnable. You shouldn't need to have a virtual trainer for doing this, being only indirection from Player to Trainer to Player. --- End quote ---
Interesting, i didn't know that function existed, yet you still need a source of potential spells. It's unrealistic to do a class and level check of every spell known in the dbcs. A virtual trainer isn't the best solution either but im not sure there is a way to get a class-only spellmap without checking every spell in the dbc. Please correct me if im wrong.
schlumpf:
Well, as it seems after actually looking at trinity core, this is indeed the only way to do this. Sadly. They implement trainers as having a list of trainable stuff _each_, not per trainer type. (seems bad design to me). The checking if it's available to the player, is done by checking if the player knows that particular spell being learned and matching the parameters given in the trainer data.
Therefore, the way to go is inserting a dummy trainer per class, but never spawning it.
--- Code: --- QueryResult result = WorldDatabase.Query("SELECT b.entry, a.spell, a.spellcost, a.reqskill, a.reqskillvalue, a.reqlevel FROM npc_trainer AS a " "INNER JOIN npc_trainer AS b ON a.entry = -(b.spell) " "UNION SELECT * FROM npc_trainer WHERE spell > 0"); --- End code --- This query as well as
--- Code: --- if (entry >= TRINITY_TRAINER_START_REF) return;
CreatureInfo const* cInfo = GetCreatureTemplate(entry); if (!cInfo) { sLog->outErrorDb("Table `npc_trainer` contains an entry for a non-existing creature template (Entry: %u), ignoring", entry); return; }
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) { sLog->outErrorDb("Table `npc_trainer` contains an entry for a creature template (Entry: %u) without trainer flag, ignoring", entry); return; }
SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); if (!spellinfo) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u), ignoring", entry, spell); return; }
if (!SpellMgr::IsSpellValid(spellinfo)) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a broken spell (Spell: %u), ignoring", entry, spell); return; }
if (GetTalentSpellCost(spell)) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u) which is a talent, ignoring", entry, spell); return; } --- End code ---
needs to be fulfilled.
You sadly need to assemble lists of all learnable spells per class yourself. You may copy that together from all trainers having the same type.
You then _not_ create a unit for this but you only ask const TrainerSpellData* sObjectMgr->GetNpcTrainerSpells(dummy_trainer_id_for_class); There, you now iterate over the entries as Laniax said.
you should end up with something like
--- Code: ---void Player::updateSpellsOnLevelup() const { const uint32 dummy_trainer_id_for_class (something()); TrainerSpellData const* trainer_spells (sObjectMgr->GetNpcTrainerSpells(dummy_trainer_id_for_class));
for ( TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin() ; itr != trainer_spells->spellList.end() ; ++itr ) { uint32 spellId (itr->first); // was this spell id? not sure. else get from trainer_spell.
TrainerSpell const* trainer_spell = trainer_spells->Find (itr->first); if (!trainer_spell) continue;
if (GetTrainerSpellState (trainer_spell) != TRAINER_SPELL_GREEN) continue;
WorldPacket data (SMSG_PLAY_SPELL_VISUAL, 12); data << uint64 (GetGUID()); data << uint32 (0x016A); // index from SpellVisualKit.dbc SendPacket(&data);
// learn explicitly or cast explicitly if (trainer_spell->IsCastable()) CastSpell(this, trainer_spell->spell, true); else learnSpell(spellId, false); } }
--- End code ---
Laniax:
--- Quote from: "schlumpf" ---Well, as it seems after actually looking at trinity core, this is indeed the only way to do this. Sadly. They implement trainers as having a list of trainable stuff _each_, not per trainer type. (seems bad design to me). The checking if it's available to the player, is done by checking if the player knows that particular spell being learned and matching the parameters given in the trainer data.
Therefore, the way to go is inserting a dummy trainer per class, but never spawning it.
--- Code: --- QueryResult result = WorldDatabase.Query("SELECT b.entry, a.spell, a.spellcost, a.reqskill, a.reqskillvalue, a.reqlevel FROM npc_trainer AS a " "INNER JOIN npc_trainer AS b ON a.entry = -(b.spell) " "UNION SELECT * FROM npc_trainer WHERE spell > 0"); --- End code --- This query as well as
--- Code: --- if (entry >= TRINITY_TRAINER_START_REF) return;
CreatureInfo const* cInfo = GetCreatureTemplate(entry); if (!cInfo) { sLog->outErrorDb("Table `npc_trainer` contains an entry for a non-existing creature template (Entry: %u), ignoring", entry); return; }
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) { sLog->outErrorDb("Table `npc_trainer` contains an entry for a creature template (Entry: %u) without trainer flag, ignoring", entry); return; }
SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); if (!spellinfo) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u), ignoring", entry, spell); return; }
if (!SpellMgr::IsSpellValid(spellinfo)) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a broken spell (Spell: %u), ignoring", entry, spell); return; }
if (GetTalentSpellCost(spell)) { sLog->outErrorDb("Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u) which is a talent, ignoring", entry, spell); return; } --- End code ---
needs to be fulfilled.
You sadly need to assemble lists of all learnable spells per class yourself. You may copy that together from all trainers having the same type.
You then _not_ create a unit for this but you only ask const TrainerSpellData* sObjectMgr->GetNpcTrainerSpells(dummy_trainer_id_for_class); There, you now iterate over the entries as Laniax said.
you should end up with something like
--- Code: ---void Player::updateSpellsOnLevelup() const { const uint32 dummy_trainer_id_for_class (something()); TrainerSpellData const* trainer_spells (sObjectMgr->GetNpcTrainerSpells(dummy_trainer_id_for_class));
for ( TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin() ; itr != trainer_spells->spellList.end() ; ++itr ) { uint32 spellId (itr->first); // was this spell id? not sure. else get from trainer_spell.
TrainerSpell const* trainer_spell = trainer_spells->Find (itr->first); if (!trainer_spell) continue;
if (GetTrainerSpellState (trainer_spell) != TRAINER_SPELL_GREEN) continue;
WorldPacket data (SMSG_PLAY_SPELL_VISUAL, 12); data << uint64 (GetGUID()); data << uint32 (0x016A); // index from SpellVisualKit.dbc SendPacket(&data);
// learn explicitly or cast explicitly if (trainer_spell->IsCastable()) CastSpell(this, trainer_spell->spell, true); else learnSpell(spellId, false); } }
--- End code ---
--- End quote ---
Then you have to create a virtual trainer for every class ingame. (thats 10 classes). Trinity bad designed trainer system does give us the opportunity to put all these classes inside 1 trainer. Not only will you end up with only 1 virtual trainer (instead of 10) but it is also already made for you. If were doing it a hacky way, atleast hack it 'cleanly'.
A global trainer, which is a trainer that can be used by every class. Now im not sure how they check the class condition in the trainer (haven't really checked the source) but you might want to include a classcheck in the core.
I'm not linking to other forums that are full of trolls, but this link should help you: http://tinyurl.com/3k9hlqr
Navigation
[0] Message Index
[*] Previous page
|