public async Task <UseAbilityResult> RunAbility() { UseAbilityResult result = UseAbilityResult.OK; try { //REMEMBER: This runs in the context of the SOURCE. //Any checks on the target will need to be awaited on the target's fiber. if (State == AbilityState.Casting) { await Task.Delay(EndTime - Environment.TickCount, m_cancellationTokenSource.Token); } if (Vector2.DistanceSquared(Target.Position, Source.Position) > Math.Pow(Ability.Range, 2)) { result = UseAbilityResult.OutOfRange; } else if (Source.Power < Ability.SourcePowerDelta) { result = UseAbilityResult.NotEnoughPower; } else if (Target.IsDead) { result = UseAbilityResult.InvalidTarget; } else { Target.ApplyHealthDelta(Ability.TargetHealthDelta, Source); Target.ApplyPowerDelta(Ability.TargetPowerDelta, Source); Source.ApplyHealthDelta(Ability.SourceHealthDelta, Source); Source.ApplyPowerDelta(Ability.SourcePowerDelta, Source); result = UseAbilityResult.OK; } State = AbilityState.Finished; } catch (TaskCanceledException) { State = AbilityState.Cancelled; result = UseAbilityResult.Cancelled; } return(result); }
private async void Handle_UseAbility(UseAbility_C2S ability) { IEntity target = default(IEntity); AbilityModel abilityModel = m_abilityRepository.GetAbilityByID(ability.AbilityID); UseAbilityResult result = UseAbilityResult.Failed; string targetName = "[No Target]"; if (abilityModel == null) { result = UseAbilityResult.Failed; } else if (m_lastAbility.State == AbilityState.Casting) { result = UseAbilityResult.AlreadyCasting; } else if (Environment.TickCount - m_lastAbilityAcceptTime <= GLOBAL_COOLDOWN_MS) { result = UseAbilityResult.OnCooldown; } else if (Power + abilityModel.SourcePowerDelta < 0) { result = UseAbilityResult.NotEnoughPower; } else { if (ability.TargetID != 0) { target = await CurrentZone.GetTarget(ability.TargetID); if (target != null) { targetName = target.Name; } } if (abilityModel.AbilityType != AbilityModel.ETargetType.AOE && target == null) { result = UseAbilityResult.InvalidTarget; } else if (target is NPCInstance && abilityModel.AbilityType == AbilityModel.EAbilityType.HELP) { result = UseAbilityResult.InvalidTarget; } else if (Vector2.DistanceSquared(target.Position, Position) > Math.Pow(abilityModel.Range, 2)) { result = UseAbilityResult.OutOfRange; } else { m_lastAbility.Dispose(); m_lastAbility = new AbilityInstance(this, target, abilityModel); if (m_lastAbility.State == AbilityState.Casting) { Send(new AbilityCastNotification() { StartTime = m_lastAbility.StartTime, EndTime = m_lastAbility.EndTime }); } result = await m_lastAbility.RunAbility(); } } if (result == UseAbilityResult.OK) { List <IEntity> nearPlayers = m_nearEntities; AbilityUsedNotification notification = new AbilityUsedNotification(); notification.AbilityID = abilityModel.AbilityID; notification.SourceID = ID; notification.TargetID = target != null ? target.ID : 0; notification.Timestamp = Environment.TickCount; for (int i = 0; i < nearPlayers.Count; i++) { PlayerPeer player = nearPlayers[i] as PlayerPeer; if (player != null) { player.EnqueueSend(notification); } } } string abilityName = abilityModel != null ? abilityModel.InternalName : string.Format("[INVALID ID {0}]", ability.AbilityID); Info("Used ability {0} on target {1} with result {2}", abilityName, targetName, result); Respond(ability, new UseAbility_S2C() { Result = (int)result }); }