protected virtual Activity InnerTick(Actor self, AttackBase attack) { if (IsCanceled) return NextActivity; var type = Target.Type; if (!Target.IsValidFor(self) || type == TargetType.FrozenActor) return NextActivity; if (attack.Info.AttackRequiresEnteringCell && !positionable.CanEnterCell(Target.Actor.Location, null, false)) return NextActivity; // Drop the target if it moves under the shroud / fog. // HACK: This would otherwise break targeting frozen actors // The problem is that Shroud.IsTargetable returns false (as it should) for // frozen actors, but we do want to explicitly target the underlying actor here. if (!attack.Info.IgnoresVisibility && type == TargetType.Actor && !Target.Actor.HasTrait<FrozenUnderFog>() && !self.Owner.CanTargetActor(Target.Actor)) return NextActivity; // Try to move within range if (move != null && (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange))) return Util.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this); var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0); if (facing.Facing != desiredFacing) return Util.SequenceActivities(new Turn(self, desiredFacing), this); attack.DoAttack(self, Target); return this; }
protected virtual Activity InnerTick( Actor self, AttackBase attack ) { if (IsCanceled) return NextActivity; var facing = self.Trait<IFacing>(); if (!Target.IsValid) return NextActivity; if (targetable != null && !targetable.TargetableBy(Target.Actor, self)) return NextActivity; if (!Combat.IsInRange(self.CenterLocation, Range, Target)) { if (--nextPathTime > 0) return this; nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, delayBetweenPathingAttempts + delaySpread); return (AllowMovement) ? Util.SequenceActivities(self.Trait<Mobile>().MoveWithinRange(Target, Range), this) : NextActivity; } var desiredFacing = Util.GetFacing(Target.CenterLocation - self.CenterLocation, 0); if (facing.Facing != desiredFacing) return Util.SequenceActivities( new Turn( desiredFacing ), this ); attack.DoAttack(self, Target); return this; }
protected virtual Activity InnerTick(Actor self, AttackBase attack) { if (IsCanceled) return NextActivity; var type = Target.Type; if (!Target.IsValidFor(self) || type == TargetType.FrozenActor) return NextActivity; // TODO: This is horrible, and probably wrong. Work out what it is trying to solve, then redo it properly. if (type == TargetType.Actor && !self.Owner.HasFogVisibility() && Target.Actor.HasTrait<Mobile>() && !self.Owner.Shroud.IsTargetable(Target.Actor)) return NextActivity; if (!Target.IsInRange(self.CenterPosition, Range)) { if (--nextPathTime > 0) return this; nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, delayBetweenPathingAttempts + delaySpread); return (AllowMovement) ? Util.SequenceActivities(self.Trait<IMove>().MoveWithinRange(Target, Range), this) : NextActivity; } var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0); var facing = self.Trait<IFacing>(); if (facing.Facing != desiredFacing) return Util.SequenceActivities(new Turn(desiredFacing), this); attack.DoAttack(self, Target); return this; }
public AreaBeam(AreaBeamInfo info, ProjectileArgs args, Color color) { this.info = info; this.args = args; this.color = color; actorAttackBase = args.SourceActor.Trait<AttackBase>(); var world = args.SourceActor.World; if (info.Speed.Length > 1) speed = new WDist(world.SharedRandom.Next(info.Speed[0].Length, info.Speed[1].Length)); else speed = info.Speed[0]; // Both the head and tail start at the source actor, but initially only the head is travelling. headPos = args.Source; tailPos = headPos; target = args.PassiveTarget; if (info.Inaccuracy.Length > 0) { var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); var maxOffset = inaccuracy * (target - headPos).Length / args.Weapon.Range.Length; target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024; } towardsTargetFacing = (target - headPos).Yaw.Facing; // Update the target position with the range we shoot beyond the target by // I.e. we can deliberately overshoot, so aim for that position var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(towardsTargetFacing)); target += dir * info.BeyondTargetRange.Length / 1024; length = Math.Max((target - headPos).Length / speed.Length, 1); }
protected override IActivity InnerTick( Actor self, AttackBase attack ) { if (Target.IsActor && Target.Actor.GetDamageState() == DamageState.Undamaged) return NextActivity; return base.InnerTick(self, attack); }
IActivity InnerTick( Actor self, AttackBase attack ) { if (IsCanceled) return NextActivity; var facing = self.Trait<IFacing>(); if (!Target.IsValid) return NextActivity; var targetCell = Util.CellContaining(Target.CenterLocation); if ((targetCell - self.Location).LengthSquared >= Range * Range) return Util.SequenceActivities( new Move( Target, Range ), this ); var desiredFacing = Util.GetFacing((targetCell - self.Location).ToFloat2(), 0); var renderUnit = self.TraitOrDefault<RenderUnit>(); var numDirs = (renderUnit != null) ? renderUnit.anim.CurrentSequence.Facings : 8; if (Util.QuantizeFacing(facing.Facing, numDirs) != Util.QuantizeFacing(desiredFacing, numDirs)) { return Util.SequenceActivities( new Turn( desiredFacing ), this ); } attack.target = Target; attack.DoAttack(self); return this; }
protected override Activity InnerTick(Actor self, AttackBase attack) { if (!Target.IsValidFor(self)) return NextActivity; if (Target.Type == TargetType.Actor && Target.Actor.GetDamageState() == DamageState.Undamaged) return NextActivity; return base.InnerTick(self, attack); }
public Attack(Actor self, Target target, WRange minRange, WRange maxRange, bool allowMovement) { Target = target; this.minRange = minRange; this.maxRange = maxRange; attack = self.Trait<AttackBase>(); facing = self.Trait<IFacing>(); move = allowMovement ? self.TraitOrDefault<IMove>() : null; }
public Attack(Actor self, Target target, bool allowMovement, bool forceAttack) { Target = target; this.forceAttack = forceAttack; attack = self.Trait<AttackBase>(); facing = self.Trait<IFacing>(); positionable = self.Trait<IPositionable>(); move = allowMovement ? self.TraitOrDefault<IMove>() : null; }
IActivity InnerTick( Actor self, AttackBase attack ) { if (IsCanceled) return NextActivity; var facing = self.Trait<IFacing>(); if (!Target.IsValid) return NextActivity; if (!Combat.IsInRange(self.CenterLocation, Range, Target)) return (AllowMovement) ? Util.SequenceActivities(self.Trait<Mobile>().MoveWithinRange(Target, Range), this) : NextActivity; var desiredFacing = Util.GetFacing(Target.CenterLocation - self.CenterLocation, 0); if (facing.Facing != desiredFacing) return Util.SequenceActivities( new Turn( desiredFacing ), this ); attack.DoAttack(self, Target); return this; }
void DrawArmaments(Actor self, AttackBase attack, WorldRenderer wr, RgbaColorRenderer wcr, float iz) { var c = Color.White; // Fire ports on garrisonable structures var garrison = attack as AttackGarrisoned; if (garrison != null) { var bodyOrientation = coords.Value.QuantizeOrientation(self, self.Orientation); foreach (var p in garrison.Info.Ports) { var pos = self.CenterPosition + coords.Value.LocalToWorld(p.Offset.Rotate(bodyOrientation)); var da = coords.Value.LocalToWorld(new WVec(224, 0, 0).Rotate(WRot.FromYaw(p.Yaw + p.Cone)).Rotate(bodyOrientation)); var db = coords.Value.LocalToWorld(new WVec(224, 0, 0).Rotate(WRot.FromYaw(p.Yaw - p.Cone)).Rotate(bodyOrientation)); var o = wr.ScreenPosition(pos); var a = wr.ScreenPosition(pos + da * 224 / da.Length); var b = wr.ScreenPosition(pos + db * 224 / db.Length); wcr.DrawLine(o, a, iz, c); wcr.DrawLine(o, b, iz, c); } return; } foreach (var a in attack.Armaments) { foreach (var b in a.Barrels) { var muzzle = self.CenterPosition + a.MuzzleOffset(self, b); var dirOffset = new WVec(0, -224, 0).Rotate(a.MuzzleOrientation(self, b)); var sm = wr.ScreenPosition(muzzle); var sd = wr.ScreenPosition(muzzle + dirOffset); wcr.DrawLine(sm, sd, iz, c); TargetLineRenderable.DrawTargetMarker(wr, c, sm); } } }
protected virtual Activity InnerTick(Actor self, AttackBase attack) { if (IsCanceled) return NextActivity; var type = Target.Type; if (!Target.IsValidFor(self) || type == TargetType.FrozenActor) return NextActivity; if (attack.Info.AttackRequiresEnteringCell && !positionable.CanEnterCell(Target.Actor.Location, null, false)) return NextActivity; // Drop the target if it moves under the shroud / fog. // HACK: This would otherwise break targeting frozen actors // The problem is that Shroud.IsTargetable returns false (as it should) for // frozen actors, but we do want to explicitly target the underlying actor here. if (!attack.Info.IgnoresVisibility && type == TargetType.Actor && !Target.Actor.Info.HasTraitInfo<FrozenUnderFogInfo>() && !self.Owner.CanTargetActor(Target.Actor)) return NextActivity; // Drop the target once none of the weapons are effective against it var armaments = attack.ChooseArmamentsForTarget(Target, forceAttack).ToList(); if (armaments.Count == 0) return NextActivity; // Update ranges minRange = armaments.Max(a => a.Weapon.MinRange); maxRange = armaments.Min(a => a.MaxRange()); if (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange)) { // Try to move within range, drop the target otherwise if (move == null) return NextActivity; attackStatus |= AttackStatus.NeedsToMove; moveActivity = ActivityUtils.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this); return NextActivity; } var desiredFacing = (Target.CenterPosition - self.CenterPosition).Yaw.Facing; if (facing.Facing != desiredFacing) { attackStatus |= AttackStatus.NeedsToTurn; turnActivity = ActivityUtils.SequenceActivities(new Turn(self, desiredFacing), this); return NextActivity; } attackStatus |= AttackStatus.Attacking; attack.DoAttack(self, Target, armaments); return this; }