/// <inheritdoc /> public int RegisterRangeTarget(IRangeTarget rangeTarget) { int newID = GetNewID(rangeTargets); rangeTarget.InstanceID = newID; rangeTargets.Add(rangeTarget.InstanceID, rangeTarget); return(newID); }
public override bool ShootProjectile(IRangeTarget target) { if (target.Moving) { return(ShootMovingTarget(target)); } return(ShootStaticTarget(target)); }
void OnTargetDestroyed(Shooter shooter, IRangeTarget target) { if (explicitTarget != null) { Debug.Assert(target == explicitTarget); ResetExplicitTarget(); } }
public override bool IsInRange(Vector3 source, IRangeTarget target) { return(BallisticProjectile.GetTimesAndVectorsForStaticTarget(target.CurrentPosition, source, Speed, out var loweTime, out var lowVector, out var highTime, out var highVector)); }
void InvokeOnTargetDestroyed(IRangeTarget target) { try { TargetDestroyed?.Invoke(this, target); } catch (Exception e) { Urho.IO.Log.Write(LogLevel.Debug, $"There was an unexpected exception during the invocation of {nameof(TargetDestroyed)}: {e.Message}"); } }
/// <summary> /// Stops shooting at any current target and sets <paramref name="newTarget"/> as the target of this Shooter if the <paramref name="newTarget"/> is in range of this shooter. /// </summary> /// <param name="newTarget">New target to try shooting at.</param> /// <returns>True if <paramref name="newTarget"/> is in range, false otherwise.</returns> public bool ShootAt(IRangeTarget newTarget) { StopShooting(); if (!CanShootAt(newTarget)) { return(false); } Target = newTarget; newTarget.AddShooter(this); return(true); }
/// <summary> /// If the <paramref name="target"/> can be hit when shooting from <paramref name="source"/>. /// </summary> /// <param name="source">The shooting position.</param> /// <param name="target">Target to hit.</param> /// <returns>True if the target can be hit, false otherwise.</returns> public bool IsInRange(Vector3 source, IRangeTarget target) { if (target == null) { return(false); } try { return(Plugin.IsInRange(source, target)); } catch (Exception e) { Urho.IO.Log.Write(LogLevel.Error, $"Projectile type plugin call {nameof(Plugin.IsInRange)} failed with Exception: {e.Message}"); return(false); } }
bool ShootMovingTarget(IRangeTarget target) { int numSolutions = BallisticProjectile.GetVectorsForMovingTarget(target, Projectile.Position, myType.Speed, out Vector3 lowVector, out Vector3 highVector); if (numSolutions >= 1) { flier.StartFlight(lowVector); return(true); } return(false); }
public override bool ShootProjectile(IRangeTarget target) { if (BallisticProjectile.GetTimesAndVectorsForStaticTarget(target.CurrentPosition, Projectile.Position, myType.Speed, out var lowTime, out var lowVector, out var highTime, out var highVector)) { flier.StartFlight(lowVector); return(true); } return(false); }
IRangeTarget SetExplicitTarget(IEntity targetEntity) { IRangeTarget target = targetEntity.GetDefaultComponent <RangeTargetComponent>(); if (target == null) { return(null); } ResetExplicitTarget(); explicitTarget = target; target.TargetMoved += ExplicitTargetMoved; target.AddShooter(this); return(target); }
/// <summary> /// Creates projectile to shoot at the given target, or null if projectile of this type cannot be shot and hit the target. /// </summary> /// <param name="newID">The id to give the projectile.</param> /// <param name="level">Level in which to shoot the projectile.</param> /// <param name="player">Owner of the projectile.</param> /// <param name="position">Initial position of the projectile, from where the shooting is happening.</param> /// <param name="initRotation">Initial rotation of the projectile.</param> /// <param name="target">Target to shoot the projectile at.</param> /// <returns>Projectile that was shot at the target, or null if projectile cannot be shot and hit the target.</returns> internal IProjectile ShootProjectile(int newID, ILevelManager level, IPlayer player, Vector3 position, Quaternion initRotation, IRangeTarget target) { var projectile = GetProjectile(newID, level, player, position, initRotation); if (!projectile.Shoot(target)) { projectile.RemoveFromLevel(); projectile = null; } return(projectile); }
void Shoot(float timeStep) { if (shotDelay > 0) { shotDelay -= timeStep; return; } InvokeOnShotReloaded(); if (Target == null) { return; } InvokeOnBeforeShotFired(); //Check if shotDelay was not reset in the OnBeforeShotFired or OnShotReloaded handlers if (shotDelay > 0) { return; } //Rotate the SourceOffset according to Entity world rotation Vector3 worldOffset = Quaternion.FromRotationTo(Vector3.UnitZ, Entity.Forward) * SourceOffset; var projectile = Level.SpawnProjectile(projectileType, Entity.Position + worldOffset, Quaternion.Identity, Player, Target); //Could not fire on the target if (projectile == null) { var previousTarget = Target; Target.RemoveShooter(this); Target = null; InvokeOnTargetLost(previousTarget); } else { InvokeOnShotFired(projectile); } ResetShotDelay(); }
void SearchTarget(float timeStep) { if (!SearchForTarget) { return; } if (searchDelay >= 0) { searchDelay -= timeStep; return; } if (Target == null && searchDelay < 0) { searchDelay = TargetSearchDelay; //Check for target in range var possibleTargets = Player.GetEnemyPlayers() .SelectMany(enemy => enemy.GetAllUnits()) //.AsParallel() .Where(unit => projectileType.IsInRange(Entity.Position, unit.GetDefaultComponent <RangeTargetComponent>())) .OrderBy(unit => Vector3.Distance(Entity.Position, unit.Position)); foreach (var possibleTarget in possibleTargets) { var newTarget = possibleTarget.GetDefaultComponent <RangeTargetComponent>(); Target = newTarget; Target.AddShooter(this); InvokeOnTargetAcquired(); break; } } }
public static int GetVectorsForMovingTarget(IRangeTarget rangeTarget, Vector3 sourcePosition, float initialProjectileSpeed, out Vector3 lowVector, out Vector3 highVector) { if (!rangeTarget.Moving) { if (GetTimesAndVectorsForStaticTarget(rangeTarget.CurrentPosition, sourcePosition, initialProjectileSpeed, out var lowTime, out lowVector, out var highTime, out highVector)) { return(2); } return(0); } var waypoints = rangeTarget.GetFutureWaypoints().GetEnumerator(); if (!waypoints.MoveNext()) { lowVector = Vector3.Zero; highVector = Vector3.Zero; return(0); } Waypoint current = waypoints.Current; Waypoint?next = null; float timeToNextWaypoint = 0; while (waypoints.MoveNext()) { next = waypoints.Current; timeToNextWaypoint += next.Value.TimeToWaypoint; if (!GetTimesAndVectorsForStaticTarget( current.Position, next.Value.Position, initialProjectileSpeed, out float lowTime, out Vector3 dontCare1, out float dontCare2, out Vector3 dontCare3)) { //Out of range lowVector = Vector3.Zero; highVector = Vector3.Zero; return(0); } //Found the right two waypoints, that the projectile will hit if (timeToNextWaypoint > lowTime) { break; } } waypoints.Dispose(); //Target is stationary if (!next.HasValue) { if (GetTimesAndVectorsForStaticTarget(current.Position, sourcePosition, initialProjectileSpeed, out var lowTime, out lowVector, out var highTime, out highVector)) { return(2); } return(0); } Vector3 targetMovement = (next.Value.Position - current.Position) / next.Value.TimeToWaypoint; //A position simulating a linear movement of target, so it arrives at the proper time to the next waypoint Vector3 fakePosition = next.Value.Position - targetMovement * timeToNextWaypoint; return(GetVectorsForMovingTarget(fakePosition, targetMovement, sourcePosition, initialProjectileSpeed, out lowVector, out highVector)); }
void ResetExplicitTarget() { explicitTarget?.RemoveShooter(this); explicitTarget = null; targetMoved = false; }
/// <summary> /// Starts the projectiles movement from it's current position towards the <paramref name="target"/>. /// </summary> /// <param name="target">The target to move to.</param> /// <returns>True if projectile can reach the target, false otherwise.</returns> public abstract bool ShootProjectile(IRangeTarget target);
void RangeTargetComponent.IShooter.OnTargetDestroy(IRangeTarget target) { ResetExplicitTarget(); }
/// <summary> /// Loads range target that was stored and already has an ID. /// </summary> /// <param name="rangeTarget">The range target with ID.</param> internal void LoadRangeTarget(IRangeTarget rangeTarget) { rangeTargets.Add(rangeTarget.InstanceID, rangeTarget); }
/// <summary> /// Checks if <paramref name="target"/> can be shot at, mainly if the target is in range. /// </summary> /// <param name="target">The target to check.</param> /// <returns>True of target can be shot at, false otherwise.</returns> public bool CanShootAt(IRangeTarget target) { return(projectileType.IsInRange(Entity.Position, target)); }
/// <inheritdoc /> public IProjectile SpawnProjectile(ProjectileType projectileType, Vector3 position, Quaternion initRotation, IPlayer player, IRangeTarget target) { IProjectile newProjectile; try { newProjectile = projectileType.ShootProjectile(GetNewID(entities), this, player, position, initRotation, target); } catch (CreationException) { return(null); } //Could not spawn projectile, maybe out of range if (newProjectile == null) { return(null); } RegisterEntity(newProjectile); projectiles.Add(newProjectile.ID, newProjectile); return(newProjectile); }
/// <summary> /// Stops shooting at any current target. /// </summary> public void StopShooting() { Target?.RemoveShooter(this); Target = null; }
/// <summary> /// Informs the shooter that the target was destroyed. /// </summary> /// <param name="target">The destroyed target.</param> void RangeTargetComponent.IShooter.OnTargetDestroy(IRangeTarget target) { Debug.Assert(this.Target == target); this.Target = null; InvokeOnTargetDestroyed(target); }
void ExplicitTargetMoved(IRangeTarget target) { targetMoved = true; }
/// <summary> /// Decides if the <paramref name="target"/> is in range of this projectile when shot from the position <paramref name="source"/>. /// </summary> /// <param name="source">The source position of the projectile.</param> /// <param name="target">The target of the projectile.</param> /// <returns>True if projectile of this type can reach the target from the <paramref name="source"/> position, false otherwise.</returns> public abstract bool IsInRange(Vector3 source, IRangeTarget target);
public ShootOrder(IRangeTarget target) { this.Target = target; }