private async void ProcessArea(Creature creature, Skill skill, Targeting targeting, TargetingArea area, Projectile projectile = null) { try { bool isProjectileSkill = skill.Type == SkillType.Projectile || skill.Type == SkillType.Userslug; int skillId = creature.Attack.Args.SkillId; if (isProjectileSkill) { skillId += 20; } if (targeting.Time > 0) { await Task.Delay((int)(targeting.Time / skill.TimeRate)); } int elapsed = targeting.Time; Player player = creature as Player; do { try { if (creature.LifeStats.IsDead()) { return; } if (area.DropItem != null) { creature.Instance.AddDrop(new Item { Owner = player, ItemId = (int)area.DropItem, Count = 1, Position = Geom.ForwardPosition(creature.Position, 40), Instance = player.Instance, }); } Point3D center = projectile != null ? projectile.Position.ToPoint3D() : Geom.GetNormal(creature.Position.Heading) .Multiple(area.OffsetDistance) .Add(creature.Position); int count = 0; List <Creature> targets = creature.Attack.Args.Targets.Count > 0 ? creature.Attack.Args.Targets : VisibleService.FindTargets(creature, center, projectile != null ? projectile.AttackDistance : area.MaxRadius, area.Type); foreach (Creature target in targets) { if (target != creature && //Ignore checks for self-target !isProjectileSkill && !creature.Attack.Args.IsItemSkill) { if (center.DistanceTo(target.Position) < area.MinRadius - 40) { continue; } if (center.DistanceTo(target.Position) > area.MaxRadius) { continue; } short diff = Geom.GetAngleDiff(creature.Attack.Args.StartPosition.Heading, Geom.GetHeading(center, target.Position)); //diff from 0 to 180 //area.RangeAngel from 0 to 360 if (diff * 2 > (creature.Attack.Args.IsTargetAttack ? 90 : Math.Abs(area.RangeAngle) + 10)) { continue; } } if (skill.TotalAtk > 0) { int damage = SeUtils.CalculateDamage(creature, target, skill.TotalAtk * area.Effect.Atk); AttackResult result = new AttackResult { AttackType = AttackType.Normal, AttackUid = creature.Attack.UID, Damage = damage, Target = target, }; result.AngleDif = Geom.GetAngleDiff(creature.Attack.Args.StartPosition.Heading, result.Target.Position.Heading); SeUtils.UpdateAttackResult(creature, result); if (result.AttackType == AttackType.Block) { VisibleService.Send(target, new SpAttackShowBlock(target, skillId)); } VisibleService.Send(target, new SpAttackResult(creature, skillId, result)); AiLogic.OnAttack(creature, target); AiLogic.OnAttacked(target, creature, result.Damage); if (target is Player && ((Player)target).Duel != null && player != null && ((Player)target).Duel.Equals(player.Duel) && target.LifeStats.GetHpDiffResult(damage) < 1) { DuelService.FinishDuel(player); } else { CreatureLogic.HpChanged(target, target.LifeStats.MinusHp(result.Damage)); } } if (area.Effect.HpDiff > 0) { AttackResult result = new AttackResult { HpDiff = area.Effect.HpDiff, Target = target }; PassivityProcessor.OnHeal(player, result); if (target is Player) { PassivityProcessor.OnHealed((Player)target, result); } CreatureLogic.HpChanged(target, target.LifeStats.PlusHp(result.HpDiff), creature); } if (area.Effect.MpDiff > 0) { CreatureLogic.MpChanged(target, target.LifeStats.PlusMp(area.Effect.MpDiff), creature); } if (area.Effect.AbnormalityOnCommon != null) { for (int i = 0; i < area.Effect.AbnormalityOnCommon.Count; i++) { AbnormalityProcessor.AddAbnormality(target, area.Effect.AbnormalityOnCommon[i], creature); } } if (player != null) { DuelService.ProcessDamage(player); //MP regen on combo skill if (skill.Id / 10000 == 1 && player.GameStats.CombatMpRegen > 0) { CreatureLogic.MpChanged(player, player.LifeStats.PlusMp( player.MaxMp * player.GameStats.CombatMpRegen / 200)); } } if (++count == area.MaxCount) { break; } } } catch (Exception ex) { Logger.WriteLine(LogState.Exception, "SkillEngine: ProcessAreaExc: " + ex); } if (targeting.Interval > 0) { await Task.Delay((int)(targeting.Interval / skill.TimeRate)); elapsed += targeting.Interval; } } while (targeting.Interval > 0 && elapsed < targeting.Until); } catch (Exception ex) { Logger.WriteLine(LogState.Exception, "SkillEngine: ProcessArea: " + ex); } }
private async void ProcessMove(Creature creature, Skill skill) { bool checkIntersections = creature is Player && skill.Type != SkillType.Evade; AnimSeq anim = null; skill.Actions.Map(action => action.StageList.Map(stage => stage.AnimationList.Map(animation => { if (anim != null) { return; } if (animation.With(a => a.Animation).With(a => a.Distance).Get(d => d[6], 0f) < 1) { return; } anim = animation; }))); if (anim == null) { return; } short heading = (short)(creature.Position.Heading + anim.Animation.Dir); int stepTime = (int)((anim.Animation.Duraction / skill.TimeRate) / 7); float movedDistance = 0f; for (int l = 0; l < 7; l++) { await Task.Delay(stepTime); if (creature.LifeStats.IsDead()) { return; } float stepDistance = anim.Animation.Distance[l] * anim.RootMotionXYRate - movedDistance; if (stepDistance <= 0.0) { continue; } movedDistance += stepDistance; Point3D moved = Geom.GetNormal(heading).Multiple(stepDistance); if (checkIntersections && anim.Animation.Dir != 32768) { float koef = SeUtils.CheckIntersections(creature, heading, moved, stepDistance); moved.X *= koef; moved.Y *= koef; } creature.Position.X += moved.X; creature.Position.Y += moved.Y; } }