public void Update(long tick) { if (TCPManager.GetTimeStampMS() >= _channelStartTime + _channelInfo.CastTime) { SendChannelEnd(); _parent.NotifyChannelEnded(); _channelInfo = null; _channelBuff = null; } else if (TCPManager.GetTimeStampMS() >= _nextTickTime) { if (_channelInfo.ApCost > 0 && !_host.ConsumeActionPoints(_channelInfo.ApCost)) { _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_AP); } else if (_playerHost != null && _channelInfo.SpecialCost > 3 && !_playerHost.CrrInterface.ConsumeResource((byte)_channelInfo.SpecialCost, true)) { _parent.CancelCast(1); } else if (_target != _host && !_host.IsInCastRange(_target, Math.Max((uint)25, _channelInfo.Range))) { _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_OUTOFRANGE); } else if (_checkVisibility && !_host.LOSHit(_target)) { _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_NOT_VISIBLE); } else { _nextTickTime += 1000; } } }
protected void TryUseAbilities() { if (_unit.AbtInterface.NPCAbilities == null) { return; } if (Combat.IsFighting && Combat.CurrentTarget != null && _unit.AbtInterface.CanCastCooldown(0) && TCPManager.GetTimeStampMS() > _nextTryCastTime) { long curTimeMs = TCPManager.GetTimeStampMS(); float rangeFactor = _unit.StsInterface.GetStatPercentageModifier(Stats.Range); uint AllowPercentAbilityCycle = 0; if (CurTarget != null) { var prm = new List <object>() { CurTarget }; _unit.EvtInterface.AddEvent(SetOldTarget, 2000, 1, prm); CurTarget = null; } foreach (NPCAbility ability in _unit.AbtInterface.NPCAbilities) { // If ability is set to Active = 0 it will not be played if (ability.Active == 0) { continue; } // If target is below MinRange that is set in creature_abilities we don't want to run this particular skill if (ability.MinRange != 0 && _unit.GetDistanceToObject(_unit.CbtInterface.GetCurrentTarget()) < ability.MinRange) { continue; } // This disable Shockwave (punt) for Keep Lords that are inside room if (ability.Entry == 13528 && _unit.GetDistanceToWorldPoint(_unit.WorldSpawnPoint) < 49) { continue; } if (ability.DisableAtHealthPercent != 0) { if (_unit.Health + 1 < (_unit.TotalHealth * ability.DisableAtHealthPercent) / 100) { continue; } } if (ability.ActivateAtHealthPercent != 0) { // This checks if we can add new ability to ability cycle if (ability.AbilityCycle == 1 && _unit.Health < (_unit.TotalHealth * ability.ActivateAtHealthPercent) / 100) { AllowPercentAbilityCycle = 1; } // This checks if we can reset the ability if NPC healed - if it's still on cooldwon, we do not refresh it if (ability.AbilityCycle == 0 && ability.AbilityUsed == 1 && (_unit.Health > (_unit.TotalHealth * ability.ActivateAtHealthPercent) / 100) && _oneshotPercentCast < curTimeMs) { ability.AbilityUsed = 0; } // This will play ability after NPC is wounded below X % if (ability.AbilityCycle == 0 && ability.AbilityUsed == 0 && (_unit.Health < (_unit.TotalHealth * ability.ActivateAtHealthPercent) / 100) && _oneshotPercentCast < curTimeMs) { // This set random target if needed if (ability.RandomTarget == 1) { SetRandomTarget(); } // This list of parameters is passed to the function that delays the cast by 1000 ms var prms = new List <object>() { _unit, ability.Entry, ability.RandomTarget }; if (ability.Text != "") { _unit.Say(ability.Text.Replace("<character name>", _unit.CbtInterface.GetCurrentTarget().Name)); } _unit.EvtInterface.AddEvent(StartDelayedCast, 1000, 1, prms); _oneshotPercentCast = TCPManager.GetTimeStampMS() + ability.Cooldown * 1000; ability.AbilityUsed = 1; continue; } } if (ability.AutoUse && !_unit.AbtInterface.IsCasting() && ability.CooldownEnd < curTimeMs && _unit.AbtInterface.CanCastCooldown(ability.Entry) && curTimeMs > _combatStart + ability.TimeStart * 1000) { uint ExtraRange = 0; if (Combat != null && Combat.CurrentTarget != null && Combat.CurrentTarget.IsMoving) { ExtraRange = 5; } if ((ability.Range == 0 || _unit.IsInCastRange(Combat.CurrentTarget, Math.Max(5 + ExtraRange, (uint)(ability.Range * rangeFactor))))) { if (ability.ActivateAtHealthPercent == 0 || AllowPercentAbilityCycle == 1) { if (!_unit.LOSHit(Combat.CurrentTarget)) { _nextTryCastTime = TCPManager.GetTimeStampMS() + 1000; } else { // This set random target if needed if (ability.RandomTarget == 1) { SetRandomTarget(); } // This list of parameters is passed to the function that delays the cast by 1000 ms var prms = new List <object>() { _unit, ability.Entry, ability.RandomTarget }; if (ability.Text != "") { _unit.Say(ability.Text.Replace("<character name>", _unit.CbtInterface.GetCurrentTarget().Name), ChatLogFilters.CHATLOGFILTERS_MONSTER_SAY); } _unit.EvtInterface.AddEvent(StartDelayedCast, 1000, 1, prms); //_unit.AbtInterface.StartCast(_unit, ability.Entry, 1); ability.CooldownEnd = curTimeMs + ability.Cooldown * 1000; } break; } } else { //AbilityInfo abInfo = AbilityMgr.GetAbilityInfo(abilityID); Chase(_unit.CbtInterface.GetCurrentTarget(), true, true, ability.Range); } } } } }
private bool AllowCast() { AbilityResult myResult = AbilityResult.ABILITYRESULT_OK; if (AbInfo.Target != null) { if (AbInfo.Target.IsDead && !AbInfo.ConstantInfo.AffectsDead) { myResult = AbilityResult.ABILITYRESULT_ILLEGALTARGET_DEAD; } else if (!AbInfo.Target.IsDead && AbInfo.ConstantInfo.AffectsDead) { myResult = AbilityResult.ABILITYRESULT_ILLEGALTARGET_NOT_DEAD_ALLY; } else if (AbInfo.Target != _caster) { if (AbInfo.ConstantInfo.CastAngle != 0 && _caster.IsMoving && !_caster.IsObjectInFront(AbInfo.Target, AbInfo.ConstantInfo.CastAngle)) { myResult = AbilityResult.ABILITYRESULT_OUT_OF_ARC; } // Explicit LOS check for move-cast abilities if (AbInfo.CastTime > 0 && AbInfo.CanCastWhileMoving && AbInfo.Target != null && !_caster.LOSHit(AbInfo.Target)) { myResult = AbilityResult.ABILITYRESULT_NOT_VISIBLE; } } } if (myResult != AbilityResult.ABILITYRESULT_OK) { CancelCast((ushort)myResult); return(false); } if (myResult == AbilityResult.ABILITYRESULT_OK && _caster.ItmInterface != null) { myResult = _caster.ItmInterface.WeaponCheck(AbInfo.ConstantInfo.WeaponNeeded); } if (AbInfo.ApCost > 0 && _caster is Player && !_caster.ConsumeActionPoints(AbInfo.ApCost)) { myResult = AbilityResult.ABILITYRESULT_AP; } if (myResult != AbilityResult.ABILITYRESULT_OK) { CancelCast((ushort)myResult); return(false); } AbilityMgr.GetCommandsFor(_caster, AbInfo); return(true); }