void CMobController::CastSpell(uint16 spellid) { CSpell* PSpell = spell::GetSpell(spellid); if (PSpell == nullptr) { ShowWarning(CL_YELLOW"ai_mob_dummy::CastSpell: SpellId <%i> is not found\n" CL_RESET, spellid); } else { CBattleEntity* PCastTarget = nullptr; // check valid targets if (PSpell->getValidTarget() & TARGET_SELF) { PCastTarget = PMob; // only buff other targets if i'm roaming if ((PSpell->getValidTarget() & TARGET_PLAYER_PARTY)) { // chance to target my master if (PMob->PMaster != nullptr && dsprand::GetRandomNumber(2) == 0) { // target my master PCastTarget = PMob->PMaster; } else if (dsprand::GetRandomNumber(2) == 0) { // chance to target party PMob->PAI->TargetFind->reset(); PMob->PAI->TargetFind->findWithinArea(PMob, AOERADIUS_ATTACKER, PSpell->getRange()); if (!PMob->PAI->TargetFind->m_targets.empty()) { // randomly select a target PCastTarget = PMob->PAI->TargetFind->m_targets[dsprand::GetRandomNumber(PMob->PAI->TargetFind->m_targets.size())]; // only target if are on same action if (PMob->PAI->IsEngaged() == PCastTarget->PAI->IsEngaged()) { PCastTarget = PMob; } } } } } else { PCastTarget = PTarget; } Cast(PCastTarget->targid, spellid); } }
void CMagicState::FinishSpell() { DSP_DEBUG_BREAK_IF(m_PSpell == NULL); DSP_DEBUG_BREAK_IF(m_PEntity->PBattleAI->GetCurrentAction() != ACTION_MAGIC_FINISH); CSpell* PSpellCopy = new CSpell(*m_PSpell); luautils::OnSpellPrecast(m_PEntity, PSpellCopy); SpendCost(PSpellCopy); SetRecast(m_PSpell); // remove effects based on spell cast first int16 effectFlags = EFFECTFLAG_INVISIBLE | EFFECTFLAG_MAGIC_BEGIN; if (PSpellCopy->canTargetEnemy()) { effectFlags |= EFFECTFLAG_DETECTABLE; } m_PEntity->StatusEffectContainer->DelStatusEffectsByFlag(effectFlags); m_PTargetFind->reset(); m_PEntity->m_ActionList.clear(); // setup special targeting flags // can this spell target the dead? uint8 flags = FINDFLAGS_NONE; if (PSpellCopy->getValidTarget() & TARGET_PLAYER_DEAD) { flags |= FINDFLAGS_DEAD; } if (PSpellCopy->getFlag() & SPELLFLAG_HIT_ALL) { flags |= FINDFLAGS_HIT_ALL; } uint8 aoeType = battleutils::GetSpellAoEType(m_PEntity, PSpellCopy); if (aoeType == SPELLAOE_RADIAL) { float distance = spell::GetSpellRadius(PSpellCopy, m_PEntity); m_PTargetFind->findWithinArea(m_PTarget, AOERADIUS_TARGET, distance, flags); } else if (aoeType == SPELLAOE_CONAL) { //TODO: actual radius calculation float radius = spell::GetSpellRadius(PSpellCopy, m_PEntity); m_PTargetFind->findWithinCone(m_PTarget, radius, 45, flags); } else { // only add target m_PTargetFind->findSingleTarget(m_PTarget, flags); } uint16 totalTargets = m_PTargetFind->m_targets.size(); PSpellCopy->setTotalTargets(totalTargets); apAction_t action; action.ActionTarget = m_PTarget; action.reaction = REACTION_NONE; action.speceffect = SPECEFFECT_NONE; action.animation = PSpellCopy->getAnimationID(); action.param = 0; action.messageID = 0; uint16 msg = 0; int16 ce = 0; int16 ve = 0; for (std::vector<CBattleEntity*>::iterator it = m_PTargetFind->m_targets.begin() ; it != m_PTargetFind->m_targets.end(); ++it) { CBattleEntity* PTarget = *it; action.ActionTarget = PTarget; ce = PSpellCopy->getCE(); ve = PSpellCopy->getVE(); // take all shadows if (PSpellCopy->canTargetEnemy() && aoeType > 0) { PTarget->StatusEffectContainer->DelStatusEffect(EFFECT_BLINK); PTarget->StatusEffectContainer->DelStatusEffect(EFFECT_COPY_IMAGE); } // TODO: this is really hacky and should eventually be moved into lua if (PSpellCopy->canHitShadow() && aoeType == SPELLAOE_NONE && battleutils::IsAbsorbByShadow(PTarget)) { // take shadow msg = 31; action.param = 1; ve = 0; ce = 0; } else { action.param = luautils::OnSpellCast(m_PEntity, PTarget, PSpellCopy); // remove effects from damage if (PSpellCopy->canTargetEnemy() && action.param > 0 && m_PSpell->dealsDamage()) { PTarget->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_DAMAGE); } if(msg == 0) { msg = PSpellCopy->getMessage(); } else { msg = PSpellCopy->getAoEMessage(); } } action.messageID = msg; if (PSpellCopy->getID() != 305) //I hate to do this, but there really is no other spell like Odin CharOnTarget(&action, ce, ve); m_PEntity->m_ActionList.push_back(action); } CharAfterFinish(); m_PEntity->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_MAGIC_END); DSP_DEBUG_BREAK_IF(m_PEntity->PBattleAI->GetCurrentAction() != ACTION_MAGIC_FINISH); m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(m_PEntity)); delete PSpellCopy; Clear(); }