/** ** Spell cast! ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target unit that spell is addressed to ** @param goalPos coord of target spot when/if target does not exist ** ** @return !=0 if spell should/can continue or 0 to stop */ int SpellCast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos) { Vec2i pos = goalPos; caster.Variable[INVISIBLE_INDEX].Value = 0;// unit is invisible until attacks // FIXME: Must be configurable if (target) { pos = target->tilePos; } // // For TargetSelf, you target.... YOURSELF // if (spell.Target == TargetSelf) { pos = caster.tilePos; target = &caster; } DebugPrint("Spell cast: (%s), %s -> %s (%d,%d)\n" _C_ spell.Ident.c_str() _C_ caster.Type->Name.c_str() _C_ target ? target->Type->Name.c_str() : "none" _C_ pos.x _C_ pos.y); if (CanCastSpell(caster, spell, target, pos)) { int cont = 1; // Should we recast the spell. bool mustSubtractMana = true; // false if action which have their own calculation is present. // // Ugly hack, CastAdjustVitals makes it's own mana calculation. // PlayGameSound(spell.SoundWhenCast.Sound, MaxSampleVolume); for (std::vector<SpellActionType *>::const_iterator act = spell.Action.begin(); act != spell.Action.end(); ++act) { if ((*act)->ModifyManaCaster) { mustSubtractMana = false; } cont = cont & (*act)->Cast(caster, spell, target, pos); } if (mustSubtractMana) { caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } caster.Player->SubCosts(spell.Costs); caster.SpellCoolDownTimers[spell.Slot] = spell.CoolDown; // // Spells like blizzard are casted again. // This is sort of confusing, we do the test again, to // check if it will be possible to cast again. Otherwise, // when you're out of mana the caster will try again ( do the // anim but fail in this proc. // if (spell.RepeatCast && cont) { return CanCastSpell(caster, spell, target, pos); } } // // Can't cast, STOP. // return 0; }
STATESTATUS CMagicState::CastSpell(CSpell* PSpell, CBattleEntity* PTarget, uint8 flags) { if(!CanCastSpell(PSpell, PTarget, flags)) { return STATESTATUS_ERROR; } Clear(); m_PSpell = PSpell; m_PTarget = PTarget; m_flags = flags; m_startPosition = m_PEntity->loc.p; m_castTime = CalculateCastTime(PSpell); apAction_t action; action.ActionTarget = m_PTarget; action.reaction = REACTION_NONE; action.speceffect = SPECEFFECT_NONE; action.animation = 0; action.param = m_PSpell->getID(); action.messageID = 327; // starts casting m_PEntity->m_ActionList.clear(); m_PEntity->m_ActionList.push_back(action); m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(m_PEntity)); return STATESTATUS_START; }
/** ** Cast Area Adjust Vital on all valid units in range. ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target unit that spell is addressed to ** @param goalPos TilePos of target spot when/if target does not exist ** ** @return =!0 if spell should be repeated, 0 if not */ /* virtual */ int Spell_AreaAdjustVital::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos) { const Vec2i range(this->Range, this->Range); const Vec2i typeSize(caster.Type->Width, caster.Type->Height); std::vector<CUnit *> units; // Get all the units around the unit Select(goalPos - range, goalPos + typeSize + range, units); int hp = this->HP; int mana = this->Mana; int shield = this->Shield; for (size_t j = 0; j != units.size(); ++j) { target = units[j]; // if (!PassCondition(caster, spell, target, goalPos) { if (!CanCastSpell(caster, spell, target, goalPos)) { continue; } if (hp < 0) { HitUnit(&caster, *target, -hp); } else { target->Variable[HP_INDEX].Value += hp; target->Variable[HP_INDEX].Value = std::min(target->Variable[HP_INDEX].Max, target->Variable[HP_INDEX].Value); } target->Variable[MANA_INDEX].Value += mana; clamp(&target->Variable[MANA_INDEX].Value, 0, target->Variable[MANA_INDEX].Max); target->Variable[SHIELD_INDEX].Value += shield; clamp(&target->Variable[SHIELD_INDEX].Value, 0, target->Variable[SHIELD_INDEX].Max); } if (UseMana) { caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } return 0; }
CMagicState::CMagicState(CBattleEntity* PEntity, uint16 targid, uint16 spellid, uint8 flags) : CState(PEntity, targid), m_PEntity(PEntity), m_PSpell(nullptr) { CSpell* PSpell = spell::GetSpell(spellid); m_PSpell = PSpell->clone(); if (!m_PSpell) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, m_PEntity, m_PSpell->getID(), 0, MSGBASIC_CANNOT_CAST_SPELL)); } auto PTarget = m_PEntity->IsValidTarget(m_targid, m_PSpell->getValidTarget(), m_errorMsg); if (!PTarget || m_errorMsg) { throw CStateInitException(std::move(m_errorMsg)); } if (!CanCastSpell(PTarget)) { throw CStateInitException(std::move(m_errorMsg)); } auto errorMsg = luautils::OnMagicCastingCheck(m_PEntity, PTarget, GetSpell()); if (errorMsg) { throw CStateInitException(std::make_unique<CMessageBasicPacket>(m_PEntity, PTarget, m_PSpell->getID(), 0, errorMsg == 1 ? MSGBASIC_CANNOT_CAST_SPELL : errorMsg)); } m_flags = flags; m_castTime = std::chrono::milliseconds(battleutils::CalculateSpellCastTime(m_PEntity, GetSpell())); m_startPos = m_PEntity->loc.p; action_t action; action.id = m_PEntity->id; action.spellgroup = m_PSpell->getSpellGroup(); action.actiontype = ACTION_MAGIC_START; actionList_t& actionList = action.getNewActionList(); actionList.ActionTargetID = PTarget->id; actionTarget_t& actionTarget = actionList.getNewActionTarget(); actionTarget.reaction = REACTION_NONE; actionTarget.speceffect = SPECEFFECT_NONE; actionTarget.animation = 0; actionTarget.param = m_PSpell->getID(); actionTarget.messageID = 327; // starts casting m_PEntity->PAI->EventHandler.triggerListener("MAGIC_START", m_PEntity, m_PSpell.get(), &action); //TODO: weaponskill lua object m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); }
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGUID) { // Target might be passed as NULL at script so better check it in core too for better safety. if(!pTarget) return CAST_FAIL_OTHER; Unit* pCaster = m_creature; if (uiCastFlags & CAST_FORCE_TARGET_SELF) pCaster = pTarget; if (!pTarget) return CAST_FAIL_OTHER; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (uiCastFlags & CAST_AURA_NOT_PRESENT) { if (pTarget->HasAura(uiSpell)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (uiCastFlags & CAST_INTERRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false)) pCaster->InterruptNonMeleeSpells(false); pCaster->CastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED, NULL, NULL, uiOriginalCasterGUID); return CAST_OK; } else { sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell); return CAST_FAIL_OTHER; } } else return CAST_FAIL_IS_CASTING; }
bool HeroBase::CanTranscribeScroll(const Artifact & art) const { Spell spell = art.GetSpell(); if(spell.isValid() && CanCastSpell(spell)) { int learning = GetLevelSkill(Skill::Secondary::LEARNING); return ((3 < spell.Level() && Skill::Level::EXPERT == learning) || (3 == spell.Level() && Skill::Level::ADVANCED <= learning) || (3 > spell.Level() && Skill::Level::BASIC <= learning)); } return false; }
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGUID) { Unit* pCaster = m_creature; if (uiCastFlags & CAST_FORCE_TARGET_SELF) pCaster = pTarget; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (uiCastFlags & CAST_AURA_NOT_PRESENT) { if (pTarget->HasAura(uiSpell)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(pTarget, pSpell, !!(uiCastFlags & CAST_TRIGGERED)); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (uiCastFlags & CAST_INTERRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false)) pCaster->InterruptNonMeleeSpells(false); // Creature should always stop before it will cast a new spell (logic applies to combat movement only) if (pCaster->isInCombat()) pCaster->StopMoving(); pCaster->CastSpell(pTarget, pSpell, !!(uiCastFlags & CAST_TRIGGERED), nullptr, nullptr, uiOriginalCasterGUID); return CAST_OK; } else { sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell); return CAST_FAIL_OTHER; } } else return CAST_FAIL_IS_CASTING; }
bool Heroes::ActionSpellCast(const Spell & spell) { std::string error; if(! CanMove()) { Dialog::Message("", _("Your hero is too tired to cast this spell today. Try again tomorrow."), Font::BIG, Dialog::OK); return false; } else if(spell == Spell::NONE || spell.isCombat() || ! CanCastSpell(spell, &error)) { if(error.size()) Dialog::Message("Error", error, Font::BIG, Dialog::OK); return false; } bool apply = false; switch(spell()) { case Spell::VIEWMINES: apply = ActionSpellViewMines(*this); break; case Spell::VIEWRESOURCES: apply = ActionSpellViewResources(*this); break; case Spell::VIEWARTIFACTS: apply = ActionSpellViewArtifacts(*this); break; case Spell::VIEWTOWNS: apply = ActionSpellViewTowns(*this); break; case Spell::VIEWHEROES: apply = ActionSpellViewHeroes(*this); break; case Spell::VIEWALL: apply = ActionSpellViewAll(*this); break; case Spell::IDENTIFYHERO: apply = ActionSpellIdentifyHero(*this); break; case Spell::SUMMONBOAT: apply = ActionSpellSummonBoat(*this); break; case Spell::DIMENSIONDOOR: apply = ActionSpellDimensionDoor(*this); break; case Spell::TOWNGATE: apply = isShipMaster() ? false : ActionSpellTownGate(*this); break; case Spell::TOWNPORTAL: apply = isShipMaster() ? false : ActionSpellTownPortal(*this); break; case Spell::VISIONS: apply = ActionSpellVisions(*this); break; case Spell::HAUNT: apply = ActionSpellSetGuardian(*this, spell, Monster::GHOST); break; case Spell::SETEGUARDIAN: apply = ActionSpellSetGuardian(*this, spell, Monster::EARTH_ELEMENT); break; case Spell::SETAGUARDIAN: apply = ActionSpellSetGuardian(*this, spell, Monster::AIR_ELEMENT); break; case Spell::SETFGUARDIAN: apply = ActionSpellSetGuardian(*this, spell, Monster::FIRE_ELEMENT); break; case Spell::SETWGUARDIAN: apply = ActionSpellSetGuardian(*this, spell, Monster::WATER_ELEMENT); break; default: break; } if(apply) { DEBUG(DBG_GAME, DBG_INFO, GetName() << " cast spell: " << spell.GetName()); SpellCasted(spell); return true; } return false; }
/** ** Cast Area Adjust Vital on all valid units in range. ** ** @param caster Unit that casts the spell ** @param spell Spell-type pointer ** @param target Target unit that spell is addressed to ** @param goalPos TilePos of target spot when/if target does not exist ** ** @return =!0 if spell should be repeated, 0 if not */ /* virtual */ int Spell_AreaAdjustVital::Cast(CUnit &caster, const CSpell &spell, CUnit *target, const Vec2i &goalPos, int z, int modifier) { const Vec2i range(this->Range, this->Range); const Vec2i typeSize(caster.Type->TileSize); std::vector<CUnit *> units; // Get all the units around the unit //Wyrmgus start // Select(goalPos - range, goalPos + typeSize + range, units); Select(goalPos - range, goalPos + typeSize + range, units, z); //Wyrmgus end int hp = this->HP * modifier / 100; int mana = this->Mana * modifier / 100; int shield = this->Shield * modifier / 100; for (size_t j = 0; j != units.size(); ++j) { target = units[j]; // if (!PassCondition(caster, spell, target, goalPos) { //Wyrmgus start // if (!CanCastSpell(caster, spell, target, goalPos)) { if (!CanCastSpell(caster, spell, target, goalPos, Map.MapLayers[z])) { //Wyrmgus end continue; } if (hp < 0) { HitUnit(&caster, *target, -hp); } else { target->Variable[HP_INDEX].Value += hp; //Wyrmgus start // target->Variable[HP_INDEX].Value = std::min(target->Variable[HP_INDEX].Max, target->Variable[HP_INDEX].Value); target->Variable[HP_INDEX].Value = std::min(target->GetModifiedVariable(HP_INDEX, VariableMax), target->Variable[HP_INDEX].Value); //Wyrmgus end } target->Variable[MANA_INDEX].Value += mana; //Wyrmgus start // clamp(&target->Variable[MANA_INDEX].Value, 0, target->Variable[MANA_INDEX].Max); clamp(&target->Variable[MANA_INDEX].Value, 0, target->GetModifiedVariable(MANA_INDEX, VariableMax)); //Wyrmgus end target->Variable[SHIELD_INDEX].Value += shield; clamp(&target->Variable[SHIELD_INDEX].Value, 0, target->Variable[SHIELD_INDEX].Max); } if (UseMana) { caster.Variable[MANA_INDEX].Value -= spell.ManaCost; } return 0; }
bool CMagicState::Update(time_point tick) { if (tick > GetEntryTime() + m_castTime && !IsCompleted()) { m_interrupted = false; auto PTarget = m_PEntity->IsValidTarget(m_targid, m_PSpell->getValidTarget(), m_errorMsg); MSGBASIC_ID msg = MSGBASIC_IS_INTERRUPTED; action_t action; if (HasMoved() || !CanCastSpell(PTarget)) { m_interrupted = true; } else if (battleutils::IsParalyzed(m_PEntity)) { msg = MSGBASIC_IS_PARALYZED; m_interrupted = true; } else if (battleutils::IsIntimidated(m_PEntity, static_cast<CBattleEntity*>(PTarget))) { msg = MSGBASIC_IS_INTIMIDATED; m_interrupted = true; } if (m_interrupted) { m_PEntity->OnCastInterrupted(*this, action, msg); } else { m_PEntity->OnCastFinished(*this,action); } m_PEntity->PAI->EventHandler.triggerListener("MAGIC_USE", m_PEntity, PTarget, m_PSpell.get(), &action); m_PEntity->loc.zone->PushPacket(m_PEntity, CHAR_INRANGE_SELF, new CActionPacket(action)); Complete(); } else if (IsCompleted() && tick > GetEntryTime() + m_castTime + std::chrono::milliseconds(m_PSpell->getAnimationTime())) { m_PEntity->PAI->EventHandler.triggerListener("MAGIC_STATE_EXIT", m_PEntity, m_PSpell.get()); return true; } return false; }
CanCastResult UnitAI::DoCastSpellIfCan(Unit* target, uint32 spellId, uint32 castFlags, ObjectGuid originalCasterGUID) const { Unit* caster = m_unit; if (target) { if (castFlags & CAST_SWITCH_CASTER_TARGET) std::swap(caster, target); if (castFlags & CAST_FORCE_TARGET_SELF) caster = target; } else if (castFlags & (CAST_FORCE_TARGET_SELF | CAST_SWITCH_CASTER_TARGET)) return CAST_FAIL_OTHER; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!caster->IsNonMeleeSpellCasted(false) || (castFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellId)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (castFlags & CAST_AURA_NOT_PRESENT) { if (!target) { if (caster->HasAura(spellId)) return CAST_FAIL_TARGET_AURA; } else if (target->HasAura(spellId)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(castFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(target, spellInfo, (castFlags & CAST_TRIGGERED) != 0); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (castFlags & CAST_INTERRUPT_PREVIOUS && caster->IsNonMeleeSpellCasted(false)) caster->InterruptNonMeleeSpells(false); // Creature should always stop before it will cast a non-instant spell if (GetSpellCastTime(spellInfo) || (IsChanneledSpell(spellInfo) && spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_MOVEMENT)) caster->StopMoving(); // Creature should interrupt any current melee spell caster->InterruptSpell(CURRENT_MELEE_SPELL); // Creature should stop wielding weapon while casting // caster->SetSheath(SHEATH_STATE_UNARMED); uint32 flags = (castFlags & CAST_TRIGGERED ? TRIGGERED_OLD_TRIGGERED : TRIGGERED_NONE) | (castFlags & CAST_IGNORE_UNSELECTABLE_TARGET ? TRIGGERED_IGNORE_UNSELECTABLE_FLAG : TRIGGERED_NONE); if (flags == TRIGGERED_NONE) flags |= TRIGGERED_NORMAL_COMBAT_CAST; caster->CastSpell(target, spellInfo, flags, nullptr, nullptr, originalCasterGUID); return CAST_OK; } sLog.outErrorDb("DoCastSpellIfCan by %s attempt to cast spell %u but spell does not exist.", m_unit->GetObjectGuid().GetString().c_str(), spellId); return CAST_FAIL_OTHER; } return CAST_FAIL_IS_CASTING; }
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGUID) const { Unit* pCaster = m_unit; if (!pTarget) return CAST_FAIL_OTHER; if (uiCastFlags & CAST_SWITCH_CASTER_TARGET) std::swap(pCaster, pTarget); if (uiCastFlags & CAST_FORCE_TARGET_SELF) pCaster = pTarget; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* pSpell = sSpellTemplate.LookupEntry<SpellEntry>(uiSpell)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (uiCastFlags & CAST_AURA_NOT_PRESENT) { if (pTarget->HasAura(uiSpell)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(pTarget, pSpell, !!(uiCastFlags & CAST_TRIGGERED)); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (uiCastFlags & CAST_INTERRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false)) pCaster->InterruptNonMeleeSpells(false); // Creature should always stop before it will cast a non-instant spell if (GetSpellCastTime(pSpell)) pCaster->StopMoving(); // Creature should interrupt any current melee spell pCaster->InterruptSpell(CURRENT_MELEE_SPELL); // Creature should stop wielding weapon while casting pCaster->SetSheath(SHEATH_STATE_UNARMED); uint32 flags = (uiCastFlags & CAST_TRIGGERED ? TRIGGERED_OLD_TRIGGERED : TRIGGERED_NONE) | (uiCastFlags & CAST_IGNORE_UNSELECTABLE_TARGET ? TRIGGERED_IGNORE_UNSELECTABLE_FLAG : TRIGGERED_NONE); pCaster->CastSpell(pTarget, pSpell, flags, nullptr, nullptr, uiOriginalCasterGUID); return CAST_OK; } else { sLog.outErrorDb("DoCastSpellIfCan by %s attempt to cast spell %u but spell does not exist.", m_unit->GetObjectGuid().GetString().c_str(), uiSpell); return CAST_FAIL_OTHER; } } else return CAST_FAIL_IS_CASTING; }
/* virtual */ void COrder_SpellCast::Execute(CUnit &unit) { COrder_SpellCast &order = *this; if (unit.Wait) { unit.Wait--; return ; } const SpellType &spell = order.GetSpell(); switch (this->State) { case 0: // Check if we can cast the spell. if (!CanCastSpell(unit, spell, order.GetGoal(), order.goalPos)) { // Notify player about this problem if (unit.Variable[MANA_INDEX].Value < spell.ManaCost) { unit.Player->Notify(NotifyYellow, unit.tilePos, _("%s: not enough mana for spell: %s"), unit.Type->Name.c_str(), spell.Name.c_str()); } else { unit.Player->Notify(NotifyYellow, unit.tilePos, _("%s: can't cast spell: %s"), unit.Type->Name.c_str(), spell.Name.c_str()); } if (unit.Player->AiEnabled) { DebugPrint("FIXME: do we need an AI callback?\n"); } this->Finished = true; return ; } if (CheckForDeadGoal(unit)) { return; } // FIXME FIXME FIXME: Check if already in range and skip straight to 2(casting) unit.ReCast = 0; // repeat spell on next pass? (defaults to `no') this->State = 1; // FALL THROUGH case 1: // Move to the target. if (spell.Range && spell.Range != INFINITE_RANGE) { if (SpellMoveToTarget(unit) == true) { this->Finished = true; return ; } return ; } else { this->State = 2; } // FALL THROUGH case 2: // Cast spell on the target. if (!spell.IsCasterOnly()) { AnimateActionSpellCast(unit, *this); if (unit.Anim.Unbreakable) { return ; } } else { // FIXME: what todo, if unit/goal is removed? CUnit *goal = order.GetGoal(); if (goal && goal != &unit && !goal->IsVisibleAsGoal(*unit.Player)) { unit.ReCast = 0; } else { unit.ReCast = SpellCast(unit, spell, goal, order.goalPos); } } // Target is dead ? Change order ? if (CheckForDeadGoal(unit)) { return; } // Check, if goal has moved (for ReCast) if (unit.ReCast && order.GetGoal() && unit.MapDistanceTo(*order.GetGoal()) > this->Range) { this->State = 0; return; } if (!unit.ReCast && unit.CurrentAction() != UnitActionDie) { this->Finished = true; return ; } break; default: this->State = 0; // Reset path, than move to target break; } }