public SpAttackResult(Creature creature, int skillId, AttackResult atk) { Creature = creature; Target = atk.Target; SkillId = skillId; AttackUid = atk.AttackUid; AttackType = atk.AttackType.GetHashCode(); Damage = atk.Damage; VisualEffect = atk.VisualEffect; if (VisualEffect != null) AttackType |= 1 << 24; }
private static void TrySetCrit(Creature attacker, AttackResult result) { int chance = (attacker is Player) ? 10 : 30; chance += attacker.GameStats.CritChanse - result.Target.GameStats.CritResist; if (chance < 0) chance = 2; if (RandomUtilities.Random().Next(0, 100) > chance) return; result.Damage *= attacker.GameStats.CritPower; result.AttackType = AttackType.Critical; }
public static void UpdateAttackResult(Creature attacker, AttackResult result) { if(attacker is Player) PassivityProcessor.OnAttack((Player)attacker, result); if(result.Target is Player) PassivityProcessor.OnAttacked((Player)result.Target, result); TrySetCrit(attacker, result); }
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 static void ApplyPassivity(Player player, Condition condition, Passivity passivity, AttackResult result) { if(!CheckCondition(condition, passivity)) return; if(passivity.Probability >= 0.001f && 1.0f - passivity.Probability > 0.001f) if(RandomUtilities.Random().Next(0, 100) > passivity.Probability*100) return; switch (passivity.Type) { // Damage block case 109: if (result.AttackType != AttackType.Normal || !result.Target.EffectsImpact.IsBlockFrontAttacks) return; if (result.AngleDif < 135 || passivity.Value < result.Damage) return; result.Damage = 0; result.AttackType = AttackType.Block; break; // Heal modifier case 168: case 169: switch (passivity.Method) { case 2: result.HpDiff += (int)passivity.Value; break; case 3: result.HpDiff = (int)passivity.Value * result.HpDiff; break; } break; // Do more damage when attack ... case 152: if (passivity.MobSize != NpcSize.All) { if (result.Target is Player && passivity.MobSize != NpcSize.Player) return; if (result.Target is Npc && ((Npc)result.Target).NpcTemplate.Size != passivity.MobSize) return; } switch (passivity.Method) { case 2: result.Damage += (int)passivity.Value; break; case 3: result.Damage = (int)(passivity.Value * result.Damage); break; } break; // Chance to regenerate MP when combat starts. case 207: Communication.Global.FeedbackService.MpChanged(player, (int)passivity.Value, player); break; } }
private static void Apply(Player player, Condition condition, AttackResult result = null) { foreach (var passivity in player.GameStats.Passivities) ApplyPassivity(player, condition, passivity, result); }
public static void OnHealed(Player player, AttackResult heal) { Apply(player, Condition.Healed, heal); }
public static void OnAttacked(Player player, AttackResult attack) { Apply(player, Condition.Attacked, attack); }
public static void OnAttack(Player player, AttackResult attack) { }