void TryLearningSpells(CCharEntity* PChar, CMobEntity* PMob) { if (PMob->m_UsedSkillIds.size() == 0) { // minor optimisation. return; } // prune the learnable blue spells std::vector<CSpell*> PLearnableSpells; for (std::map<uint16, uint16>::iterator i=PMob->m_UsedSkillIds.begin(); i != PMob->m_UsedSkillIds.end(); ++i) { CSpell* PSpell = spell::GetSpellByMonsterSkillId(i->first); if (PSpell != nullptr) { PLearnableSpells.push_back(PSpell); } } if (PLearnableSpells.size() == 0) { return; } std::vector<CCharEntity*> PBlueMages; // populate PBlueMages if (PChar->PParty != nullptr) { for (uint8 i = 0; i < PChar->PParty->members.size(); i++) { if (PChar->PParty->members[i]->GetMJob() == JOB_BLU && PChar->PParty->members[i]->objtype == TYPE_PC) { PBlueMages.push_back((CCharEntity*)PChar->PParty->members[i]); } } } else if (PChar->GetMJob() == JOB_BLU) { PBlueMages.push_back(PChar); } // loop through the list of BLUs and see if they can learn. for (size_t i = 0; i < PBlueMages.size(); i++) { CCharEntity* PBlueMage = PBlueMages[i]; if (PBlueMage->isDead()) { // too dead to learn continue; } if (distance(PBlueMage->loc.p, PMob->loc.p) > 100) { // too far away to learn continue; } for (size_t spell = 0; spell < PLearnableSpells.size(); spell++) { CSpell* PSpell = PLearnableSpells[spell]; if (charutils::hasSpell(PBlueMage, static_cast<uint16>(PSpell->getID()))) { continue; } // get the skill cap for the spell level auto skillLvlForSpell = battleutils::GetMaxSkill(SKILL_BLUE_MAGIC, JOB_BLU, PSpell->getJob(JOB_BLU)); // get player skill level with bonus from gear auto playerSkillLvl = PBlueMage->GetSkill(SKILL_BLUE_MAGIC); // make sure the difference between spell skill and player is at most 31 points if (playerSkillLvl >= skillLvlForSpell - 31) { // TODO: check for blue learning bonus and adjust base percent if (dsprand::GetRandomNumber(100) < 33) { if (charutils::addSpell(PBlueMage, static_cast<uint16>(PSpell->getID()))) { PBlueMage->pushPacket(new CMessageBasicPacket(PBlueMage, PBlueMage, static_cast<uint16>(PSpell->getID()), 0, MSGBASIC_LEARNS_SPELL)); charutils::SaveSpell(PBlueMage, static_cast<uint16>(PSpell->getID())); PBlueMage->pushPacket(new CCharSpellsPacket(PBlueMage)); } } break; // only one attempt at learning a spell, regardless of learn or not. } } } }
void TryLearningSpells(CCharEntity* PChar, CMobEntity* PMob) { if (PMob->m_UsedSkillIds.size() == 0) { // minor optimisation. return; } // prune the learnable blue spells std::vector<CSpell*> PLearnableSpells; for (std::map<uint16, uint16>::iterator i=PMob->m_UsedSkillIds.begin(); i != PMob->m_UsedSkillIds.end(); ++i) { CSpell* PSpell = spell::GetSpellByMonsterSkillId(i->first); if (PSpell != NULL) { PLearnableSpells.push_back(PSpell); } } if (PLearnableSpells.size() == 0) { return; } std::vector<CCharEntity*> PBlueMages; // populate PBlueMages if (PChar->PParty != NULL) { for (uint8 i = 0; i < PChar->PParty->members.size(); i++) { if (PChar->PParty->members[i]->GetMJob() == JOB_BLU && PChar->PParty->members[i]->objtype == TYPE_PC) { PBlueMages.push_back((CCharEntity*)PChar->PParty->members[i]); } } } else if (PChar->GetMJob() == JOB_BLU) { PBlueMages.push_back(PChar); } // loop through the list of BLUs and see if they can learn. for (int i=0; i<PBlueMages.size(); i++) { CCharEntity* PBlueMage = PBlueMages[i]; if (PBlueMage->isDead()) { // too dead to learn continue; } if (distance(PBlueMage->loc.p, PMob->loc.p) > 100) { // too far away to learn continue; } for (int spell=0; spell<PLearnableSpells.size(); spell++) { CSpell* PSpell = PLearnableSpells[spell]; if (charutils::hasSpell(PBlueMage, PSpell->getID())) { continue; } uint8 learnableLevel = PSpell->getJob(JOB_BLU); if (learnableLevel > 0 && learnableLevel < PBlueMage->GetMLevel()+7) { // TODO: Use blue magic skill check rather than level if (rand()%100 < 33) { if (charutils::addSpell(PBlueMage, PSpell->getID())) { PBlueMage->pushPacket(new CMessageBasicPacket(PBlueMage, PBlueMage, PSpell->getID(), 0, MSGBASIC_LEARNS_SPELL)); charutils::SaveSpells(PBlueMage); PBlueMage->pushPacket(new CCharSpellsPacket(PBlueMage)); } } break; // only one attempt at learning a spell, regardless of learn or not. } } } }
bool CanUseSpell(CBattleEntity* PCaster, uint16 SpellID) { bool usable = false; CSpell* spell = GetSpell(SpellID); if (spell != NULL) { uint8 JobMLVL = spell->getJob(PCaster->GetMJob()); uint8 JobSLVL = spell->getJob(PCaster->GetSJob()); uint8 requirements = spell->getRequirements(); if(PCaster->GetMLevel() >= JobMLVL) { usable = true; if (requirements & SPELLREQ_TABULA_RASA) { if (!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_TABULA_RASA)) { usable = false; } } if (requirements & SPELLREQ_ADDENDUM_BLACK && PCaster->GetMJob() == JOB_SCH) { if(!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ADDENDUM_BLACK) && !PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ENLIGHTENMENT)) { usable = false; } } else if (requirements & SPELLREQ_ADDENDUM_WHITE && PCaster->GetMJob() == JOB_SCH) { if (!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ADDENDUM_WHITE) && !PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ENLIGHTENMENT)) { usable = false; } } else if (SpellID > 0x200) { if (PCaster->objtype == TYPE_PC) { if (!blueutils::IsSpellSet((CCharEntity*)PCaster, (CBlueSpell*)spell)) { usable = false; } } } if (usable) { return true; } } if(PCaster->GetSLevel() >= JobSLVL) { usable = true; if (requirements & SPELLREQ_TABULA_RASA) { if (!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_TABULA_RASA)) { usable = false; } } if (requirements & SPELLREQ_ADDENDUM_BLACK && PCaster->GetSJob() == JOB_SCH) { if (!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ADDENDUM_BLACK) && !PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ENLIGHTENMENT)) { usable = false; } } else if (requirements & SPELLREQ_ADDENDUM_WHITE && PCaster->GetSJob() == JOB_SCH) { if (!PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ADDENDUM_WHITE) && !PCaster->StatusEffectContainer->HasStatusEffect(EFFECT_ENLIGHTENMENT)) { usable = false; } } else if (SpellID > 0x200) { if (PCaster->objtype == TYPE_PC) { if (!blueutils::IsSpellSet((CCharEntity*)PCaster, (CBlueSpell*)spell)) { usable = false; } } } } } return usable; }