Author Topic: What is the expected movement of sniper ships?  (Read 2629 times)

Offline WeaponMaster

  • Newbie Mark III
  • *
  • Posts: 46
What is the expected movement of sniper ships?
« on: February 24, 2019, 10:35:09 am »
I've been messing around a bit with snipers because I've noticed that their movement can be a bit... odd. Odd in the sense that it seems like its random whether they will stand in place in shoot, run to a random direction while shooting, or jitter back and forth while shooting.

I did a close inspection of what targetDest in MovementPlanning.cs was set to when snipers are deciding how to move:

  • targetDest is set to your previous command's destination
  • It does not get overwritten by the targetEnemyEntity position because setMoveToEnemy gets set to false for snipers
  • Then, no matter the distance between entity (the sniper) and the previous destination, the angle is calculated and the next destination is set as ~15000 units away from last frame's destination, along the angle previously calculated
  • Since the destination is 15000 units along the line projected from last frame's destination, if you were closer than 15000 units last frame then you are told to turn around 180° and move (15000 - last frame's distance from dest)
  • Once in the loop of turning around forever, the sniper will stay that way until it receives a direct move order (not an attack order)

If you target a unit that is immune from outside a certain range (tesla coil turret), then the distance the code tells the ship to move is smaller, but still ends up in the same chaotic loop.

If you were to change the code so that (setMoveToEnemy = true) for snipers, then the snipers act like a normal ship with their kite range being ~15000. This is large, but the snipers can still be hit by the longest of ranged weapons this way (I think most guard posts and eyes have ranges larger than 15000).

An interesting way to change the code would be to equate (setMoveToEnemy = false) as "move to the edge of gravwell directly opposite of your target", but this also sounds like it could lead your snipers to backing away from an enemy right through all of their defences.

What should be the proper reaction of snipers? Don't move at all, run to edge of gravwell based on angle from the center, run to edge of gravwell based on angle from enemy target, stay just outside of your target's range, stay at a fixed range from target, something else?
« Last Edit: February 24, 2019, 10:36:43 am by WeaponMaster »

Offline BadgerBadger

  • Arcen Volunteer
  • Hero Member Mark III
  • *****
  • Posts: 1,229
  • BadgerBadgerBadgerBadger
Re: What is the expected movement of sniper ships?
« Reply #1 on: February 24, 2019, 11:29:21 am »
Always running to the gravwell edge might not be desirable (if, for example, the Warden fleet shows up to compel a retreat, the snipers might be caught escaping). I'm not sure there's an obvious answer to this one. I think "Don't move at all" is likely to be the least likely to have unpleasant side effects.
« Last Edit: February 24, 2019, 11:36:33 am by BadgerBadger »

Offline WeaponMaster

  • Newbie Mark III
  • *
  • Posts: 46
Re: What is the expected movement of sniper ships?
« Reply #2 on: February 24, 2019, 12:26:17 pm »
I think that stopping in place might have been the intention when the setMoveToEnemy variable was created, but the way that it functions now is very odd. It seems like a lot of the time they do sit in place, but there are odd occurrences where snipers run to the edge of the gravwell.

I think it might be better if there was some way to explicitly tell snipers to not move when firing. An issue with that is you then need to also make sure that snipers can attack tesla coils by walking up to range when needed.

Offline WeaponMaster

  • Newbie Mark III
  • *
  • Posts: 46
Re: What is the expected movement of sniper ships?
« Reply #3 on: February 25, 2019, 03:28:07 pm »
I rewrote a portion of MovementPlanning.cs to match the movement I described last post. The source code change to the attack case is posted below: the simple rewrite makes it so targetDest is always overwritten with enemyPosition, then test if the targeted unit has an invulnerability distance. If the attacker is a sniper vs a non-invuln unit, the sniper stands in place (maybe, need testing); if the attacker is a sniper vs an invuln unit, the sniper will move into range like a normal ship.

Source code starting from line 133 of MovementPlanning.cs:
Code: [Select]
                if ( targetEnemyEntity != null )
                {
                    if ( entity.Systems.Count > 0 )
                    {
                        bool setMoveToEnemy = true;

                        int kiteDistance = -1;
                        for ( int i = 0; i < entity.Systems.Count; i++ )
                        {
                            EntitySystem system = entity.Systems[i];
                            if ( system.DataForMark.Range >= 999999 )
                            {
                                setMoveToEnemy = false;
                                kiteDistance = system.GetKitingDistance( targetEnemyEntity );
                                break;
                            }
                            if ( !system.GetCanHitAssumingItIsEnemy( targetEnemyEntity, true ) )
                                continue;
                            if ( kiteDistance < 0 )
                            {
                                kiteDistance = system.GetKitingDistance( targetEnemyEntity );
                            }
                            else
                                kiteDistance = Math.Min( kiteDistance, system.GetKitingDistance( targetEnemyEntity ) );
                        }
                        targetDest = targetEnemyEntity.WorldLocation;
                        bool enemyDistanceInvuln = false;

                        if (targetEnemyEntity.DataForMark.MaxDistanceICanBeDamagedAtAllFrom <= 999999) //Is the target invulnerable from outside a certain range? e.g. Tesla Turret
                            enemyDistanceInvuln = true;

                        if (!setMoveToEnemy && !enemyDistanceInvuln) //For snipers, don't move at all if the enemy is not invulnerable based on distance from you
                        {
                            entity.WorkingDestination_OnlyWriteFromMovementPlanning = ArcenPoint.ZeroZeroPoint;
                            return DelReturn.Continue;
                        }

                        int stopDistance = ( kiteDistance * 8 ) / 10;
                        int approachDistance = (kiteDistance * 9) / 10;
                        int currentDistance = Mat.ApproxDistanceBetweenPointsFast( entity.WorldLocation, targetDest, stopDistance );
                        if ( currentDistance  <= stopDistance )
                        {
                            if (!entity.PlanetFaction.Faction.UnitsAutoKite)
                            {
                                //Not kiting; once we are in range, stay in range
                                return DelReturn.Continue;
                            }
                            //try to stay at the highest range
                            AngleDegrees currentAngle = targetDest.GetAngleToDegrees( entity.WorldLocation );
                            targetDest = targetDest.GetPointAtAngleAndDistance( currentAngle, stopDistance );
                        }
                        if ( currentDistance > approachDistance)
                        {
                            //Instance.TempFastRandom.ReinitializeWithSeed( entity.PrimaryKeyID + targetEntity.PrimaryKeyID ); note from chris: not used?
                            AngleDegrees currentAngle = targetDest.GetAngleToDegrees( entity.WorldLocation );
                            targetDest = targetDest.GetPointAtAngleAndDistance( currentAngle, approachDistance );
                        }
                    }
                }

Seems to be working. I'm going to update my tweaks pack with this and rebuild it for 0.814. As a side note: is there any better way to keep a bunch of changes separate from the source code files that change with every patch? At some point it might be that I need to copy and paste 100 different lines every patch, and that will get tiring fast (especially since I build the dll for double defence and normal defence).
« Last Edit: February 25, 2019, 04:18:17 pm by WeaponMaster »