Skip to content

Conversation

@CrimRecya
Copy link
Contributor

@CrimRecya CrimRecya commented Mar 20, 2025

Projectile life cycle logic

  • Projectile now has more ways to define its lifecycle and end methods.
    • LifeDuration controls the duration the projectile can exist, and at the end of the time, the projectile will detonate. If it is a non positive number, there will be no timing. The following are exceptions.
      • In Trajectory=Engrave, if it is a non positive number, automatically use Trajectory.Engrave.SourceCoord and Trajectory.Engrave.TargetCoord to calculate the process duration. At this point, Trajectory.Engrave.TargetCoord can be regarded as the endpoint coordinates of the cutting line segment.
      • In Trajectory=Tracing, if set to zero, use weapon's ROF-10 as the duration. At least 1 frame. If it is negative, do not time it.
    • NoTargetLifeTime controls how long the projectile will live after losing the target. If it is 0, it will detonate instantly when switching targets.
    • CreateCapacity controls the capacity that this type of trajectory projectile can be fired. When it is set to a non negative number, the trajectory projectile can only be fired when number of this trajectory type fired by the firer on the map is less than this value, namely effective. That is, every firer can have this number of projectiles.
    • PeacefulVanish controls whether the projectile disappears directly when it is about to detonate, without producing animation or causing damage. Default to true if Trajectory=Engrave or ProximityImpact not equal to 0 or DisperseCycle not equal to 0.
    • ApplyRangeModifiers controls whether any applicable weapon range modifiers from the firer are applied to the projectile. Effective options include LifeDuration, DamageEdgeAttenuation and Trajectory.DetonationDistance.

In rulesmd.ini:

[SOMEPROJECTILE]           ; Projectile
LifeDuration=0             ; integer
NoTargetLifeTime=-1        ; integer
CreateCapacity=-1          ; integer
ApplyRangeModifiers=false  ; boolean
PeacefulVanish=            ; boolean
This feature has been tested against [Trajectory](#projectile-trajectories) system. The support for Arcing, ROT etc. is not guaranteed because of Trajectory system offering better and more bug-free replacements. Please use this feature specifically with Trajectory system.

Projectile release warheads

  • Projectile can now detonate warheads during the flight.
    • PassDetonate enables extra detonations when the projectile is traveling. (You can use this when you want the projectile to detonate warheads every other distance/time during the flight.)
      • PassDetonateWarhead defines the warhead detonated by PassDetonate. If not set, use the original warhead of the projectile.
      • PassDetonateDamage defines the damage caused by PassDetonateWarhead. If not set, use the original damage of the projectile.
      • PassDetonateDelay controls the delay for detonating the warhead defined by PassDetonateWarhead.
      • PassDetonateInitialDelay controls the initial delay for detonating the warhead defined by PassDetonateWarhead.
      • PassDetonateLocal controls whether PassDetonateWarhead and weapon's Warhead are always detonate at ground level.
    • ProximityImpact controls the initial proximity fuse times of detonations. When there are enough remaining times of detonations and the projectile approaches another valid target, it will detonate a warhead defined by ProximityWarhead on it. If the times is about to run out, it will also detonate itself at its location. This function can be cancelled by setting to 0. A negative integer means unlimited times. By the way, you can use the weapon's Warhead with low Versus only to aim at the target, and use the ProximityWarhead to causing actual harm. (You can use this to cause non repeated damage to all units encountered during the flight of the projectile.)
      • ProximityWarhead defines the warhead detonated by ProximityImpact. If not set, use the original warhead of the projectile.
      • ProximityDamage defines the damage caused by ProximityWarhead. If not set, use the original damage of the projectile.
      • ProximityRadius controls the range of proximity fuse. It can NOT be set as a negative value.
      • ProximityDirect controls whether let the target receive damage instead of detonating the warhead.
      • ProximityMedial controls whether to detonate ProximityWarhead at the bullet's location rather than the proximity target's location. If ProximityDirect is set to true, this will only affect the calculation result of DamageEdgeAttenuation.
      • ProximityAllies controls whether allies will also trigger the proximity fuse.
      • ProximityFlight controls whether to count units in the air.
    • PassThroughVehicles controls whether the projectile will not be obstructed by vehicles or aircrafts on the ground. When it is obstructed, it will be directly detonated at its location. If it still have ProximityImpact times, it will also detonate a ProximityWarhead at the location of the obstacle. Before the projectile being blocked, ProximityImpact will also not cause damage to vehicles or aircrafts.
    • PassThroughBuilding controls whether the projectile will not be obstructed by buildings. When it is obstructed, it will be directly detonated at its location. If it still have ProximityImpact times, it will also detonate a ProximityImpact at the location of the obstacle. Before the projectile being blocked, ProximityImpact will also not cause damage to buildings.
    • DamageEdgeAttenuation controls the edge attenuation ratio of projectile damage (includes all types of the trajectory's damage), that is, the actual damage caused will be this value multiplied by the ratio of the current distance to the weapon's range. Can NOT be set to a negative value.
    • DamageCountAttenuation controls the attenuation coefficient related to frequency of projectile damage (includes all types of the trajectory's damage), that is, how many times the next damage after each bounce is the damage just caused. Can NOT be set to a negative value.

In rulesmd.ini:

[SOMEPROJECTILE]            ; Projectile
PassDetonate=false          ; boolean
PassDetonateWarhead=        ; WarheadType
PassDetonateDamage=         ; integer
PassDetonateDelay=1         ; integer, game frames
PassDetonateInitialDelay=0  ; integer, game frames
PassDetonateLocal=false     ; boolean
ProximityImpact=0           ; integer
ProximityWarhead=           ; WarheadType
ProximityDamage=            ; integer
ProximityRadius=0.7         ; floating point value
ProximityDirect=false       ; boolean
ProximityMedial=false       ; boolean
ProximityAllies=false       ; boolean
ProximityFlight=false       ; boolean
PassThroughVehicles=true    ; boolean
PassThroughBuilding=true    ; boolean
DamageEdgeAttenuation=1.0   ; floating point value
DamageCountAttenuation=1.0  ; floating point value
- The listed Warheads in `PassDetonateWarhead` and `ProximityWarhead` must be listed in `[Warheads]` for them to work.
- Make sure you set a low `ProximityRadius` value unless necessary.
- `SubjectToBuildings` and `PassThroughBuilding` are different. But the two are not in conflict and can take effect simultaneously. The former can affect the search for enemies and ignore the main target, follows the settings of Ares and will only self destruct when conditions are met. While the latter will self destruct when touching only non-allies building (including main target) and trigger its effect if `ProximityImpact` is set.
- Simply put, `PassDetonate` is periodically effect and `ProximityImpact` is once per person effect.
- If `ProximityImpact` is set to non-zero, the default value of `PeacefulVanish` will be changed.
This feature has been tested against [Trajectory](#projectile-trajectories) system. The support for Arcing, ROT etc. is not guaranteed because of Trajectory system offering better and more bug-free replacements. Please use this feature specifically with Trajectory system.

Projectile release weapons

  • Projectile can now launching weapons during the flight.
    • UseDisperseCoord controls whether the fire position need to replaced with the FLH of its superior's trajectory. It can be nested and inherited. Only takes effect when it is fired from one of the DisperseWeapons.
      • In Trajectory=Engrave or Trajectory=Tracing, it will also be used as a starting point for laser drawing.
    • DisperseWeapons defines the dispersal weapons of the projectile.
    • DisperseBursts defines how many corresponding weapons each time the projectile will fire. When the quantity is lower than DisperseWeapons, the last value in the list will be used.
    • DisperseCounts controls how many times the projectile can fire the weapon. Set to a negative value means unlimited times. If set to zero, the cooling will be calculated directly without firing the weapon. If the quantity is less than the number of firing groups, the last value in the list will be used.
    • DisperseDelays controls the interval delays for dispersing the weapons, at least 1 frame. If the quantity is less than the number of firing groups, the last value in the list will be used.
    • DisperseCycle controls how many rounds of weapons the projectile can fire, zero will not fire weapons, and negative numbers are considered infinite.
    • DisperseInitialDelay controls the initial delay for dispersing the weapons defined by DisperseWeapons.
    • DisperseEffectiveRange controls the weapon dispersing timer to start counting only within this distance of reaching the target. Set to 0 to disable this function. Set to a negative value means it will only Disperse the weapon at most once before detonation.
    • DisperseSeparate controls whether the projectile no longer fire all the weapons in DisperseWeapons at once and instead fire a group of weapons in the list order, following DisperseBursts. And control how to calculate the number of firing groups. In short, if true, group the weapons and fire them the corresponding counts of times in DisperseWeapons order. Otherwise, fire all weapons simultaneously and fire sequentially in DisperseCounts order.
    • DisperseRetarget controls whether the Disperse weapons will find new targets on their own. Using the Range, CanTarget, CanTargetHouses, required AttachedEffects of weapons to search new targets.
    • DisperseLocation controls whether the Disperse weapons will search for new targets at the center of the spreading position, otherwise they will focus on the original target.
    • DisperseTendency controls whether the Disperse weapons will choose the original target as the first new target in each group of weapons.
    • DisperseHolistic controls whether the Disperse weapons will choose targets that are in different states from the original target (in air and on ground).
    • DisperseMarginal controls whether the Disperse weapons will choose unimportant items such as trees (regard as on ground), streetlights (regard as on ground) or bullets (regard as in air) as secondary targets.
    • DisperseDoRepeat controls whether the Disperse weapons will select duplicate targets when the number of targets is insufficient. If it is set to true, when the weapon can select both the technos and the ground as targets, the technos will be prioritized, then if all non-repeating technos have been selected and the weapon can still be launched at this time (in each round of salvo), it will start selecting duplicate technos. If it is set to false, when the weapon can select both the technos and the ground as targets, the technos will be prioritized, followed by the ground cells, then if all non-repeating targets have been selected and the weapon can still be launched at this time (in each round of salvo), it will stop firing remaining bursts. (The priority of secondary targets is between the technos and the ground.)
    • DisperseSuicide controls whether the projectile will self destruct after the number of times it spreads the weapon has been exhausted.
    • DisperseFromFirer controls whether the weapons will be fired by the firer towards the projectile. Otherwise, the tracing weapons will be fired from the projectile towards the target. When Trajectory=Engrave or Trajectory=Tracing, the default is true, while others are false.
    • DisperseFaceCheck controls whether the projectile will check its orientation before firing the weapons. Ignore this if there is no Trajectory setting or there is Trajectory.BulletFacing=Velocity or Trajectory.BulletFacing=Spin.
    • DisperseForceFire controls whether still fire disperse weapon when the projectile itself has no target or when Synchronize=true and the target of the projectile is beyond the weapon's range.
    • DisperseCoord controls the FLH where the projectile fires the weapon when set DisperseFromFirer to false.

In rulesmd.ini:

[SOMEPROJECTILE]          ; Projectile
UseDisperseCoord=false    ; boolean
DisperseWeapons=          ; list of WeaponTypes
DisperseBursts=           ; list of integers
DisperseCounts=           ; list of integers
DisperseDelays=           ; list of integers, game frames
DisperseCycle=0           ; integer
DisperseInitialDelay=0    ; integer, game frames
DisperseEffectiveRange=0  ; floating point value
DisperseSeparate=false    ; boolean
DisperseRetarget=false    ; boolean
DisperseLocation=false    ; boolean
DisperseTendency=false    ; boolean
DisperseHolistic=false    ; boolean
DisperseMarginal=false    ; boolean
DisperseDoRepeat=false    ; boolean
DisperseSuicide=true      ; boolean
DisperseFromFirer=        ; boolean
DisperseFaceCheck=false   ; boolean
DisperseForceFire=true    ; boolean
DisperseCoord=0,0,0       ; integer - Forward,Lateral,Height
- The listed Weapons in `DisperseWeapons` must be listed in `[WeaponTypes]` for them to work.
- If you set `DisperseRetarget=true`, also make sure you set `DisperseWeapons` a low `Range` value unless necessary.
- Although `DisperseDoRepeat=false` will disable duplicate target selection, if the weapon is able to attack the ground, it may still attack duplicate targets by locking onto the cell where the target is located.
- `DisperseRetarget` will not change the true target of the projectile itself.
- If `DisperseCycle` is set to non-zero, the default value of `PeacefulVanish` will be changed.
This feature has been tested against [Trajectory](#projectile-trajectories) system. The support for Arcing, ROT etc. is not guaranteed because of Trajectory system offering better and more bug-free replacements. Please use this feature specifically with Trajectory system.

Projectile retargeting logic

  • Projectile can now re-search an enemy after losing the original target.
    • RetargetRadius controls the radius of the projectile to search for a new target after losing its original target. The projectile will search for new target at the original target's location. The following have exceptions.
      • In Trajectory=Missile, if the projectile hasn't arrived Trajectory.Missile.PreAimCoord yet, the last coordinate of the original target is taken as the center of the searching circle. Otherwise, the coordinate of the distance in front of the projectile is taken as the center of the circle. Set to 0 indicates that this function is not enabled, and it will still attempt to attack the original target's location. If it is set to a negative value, it will self explode in place when it starts searching.
      • In Trajectory=Tracing, the projectile will search for new target at the current position of itself.
    • RetargetInterval controls the interval between each search for a new target again.
    • RetargetHouses controls the projectile can find new target from which houses.
    • Synchronize controls whether the target of the projectile is synchronized with the target of its firer. If not, the projectile will not update the target.

In rulesmd.ini:

[SOMEPROJECTILE]           ; Projectile
RetargetRadius=0           ; floating point value
RetargetInterval=1         ; integer
RetargetHouses=enemies     ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
Synchronize=false          ; boolean
- Make sure you set a low `RetargetRadius` value unless necessary.
This feature has been tested against [Trajectory](#projectile-trajectories) system. The support for Arcing, ROT etc. is not guaranteed because of Trajectory system offering better and more bug-free replacements. Please use this feature specifically with Trajectory system.

Projectile trajectories

  • Projectiles can now have customizable trajectories.
    • Trajectory should not be combined with original game's projectile trajectory logics (Arcing, ROT, Vertical or Inviso). Attempt to do so will result in the other logics being disabled and a warning being written to log file.
    • Trajectory.Speed defines the speed of the projectile, which unlike Speed used by ROT > 0 projectiles is defined on projectile not weapon.
      • In Trajectory=Straight, it refers to the whole distance speed of the projectile.
      • In Trajectory=Bombard, it refers to the initial speed of the projectile.
      • In Trajectory=Missile, it refers to the final speed of the projectile. Trajectory.Speed will be fixed at 192 by setting Trajectory.Missile.UniqueCurve=true.
      • In Trajectory=Engrave, it refers to the horizontal engrave speed of the projectile and it cannot exceed 128. Recommend set as about 40.
      • In Trajectory=Parabola, it refers to the horizontal velocity of the projectile and is only used for modes Speed, SpeedAndHeight, or SpeedAndAngle.
      • In Trajectory=Tracing, it refers to the moving speed of the projectile.
    • Trajectory.BulletROT controls the rotational speed of the projectile's orientation (facing direction).
    • Trajectory.BulletFacing controls what direction the projectile should face. This has the following 7 modes.
      • Velocity - Towards the direction of motion of the projectile. When Trajectory.BulletROT is a non-positive value, it will always face this direction. Trajectory.BulletFacingOnPlane controls whether it will only rotates on a horizontal plane.
      • Spin - Continuously rotating itself on a horizontal plane. When Trajectory.BulletROT is 0, it will be unable to rotate. The positive and negative of Trajectory.BulletROT can control the direction.
      • Stable - Static after launch and no longer rotates towards the direction. Trajectory.BulletFacingOnPlane controls whether its direction will only on a horizontal plane.
      • Target - Towards the target unit. When Trajectory.BulletROT is a non-positive value, it will always face this direction. Trajectory.BulletFacingOnPlane controls whether it will only rotates on a horizontal plane.
      • Destination - Towards the direction of the projectile's destination (Not necessarily to the target. For example, in Trajectory=Straight, it will be the initial position of the target, and with Trajectory.LeadTimeCalculate, it will be a position in front of the target). When Trajectory.BulletROT is a non-positive value, it will always face this direction. Trajectory.BulletFacingOnPlane controls whether it will only rotates on a horizontal plane.
      • FirerBody - Follow the orientation of the firer's body, and remain still after the launcher is killed. When Trajectory.BulletROT is a non-positive value, it will always face this direction. Only rotates on a horizontal plane.
      • FirerTurret - Follow the orientation of the firer's turret, and remain still after the launcher is killed. When Trajectory.BulletROT is a non-positive value, it will always face this direction. Only rotates on a horizontal plane.
    • Trajectory.OffsetCoord controls the offsets of the target. Projectile will aim at the relative coordinates of the target to attack. It also supports Inaccurate and Trajectory.LeadTimeCalculate on this basis.
      • In Trajectory=Engrave or Trajectory=Tracing, these are invalid.
      • Trajectory.RotateCoord controls whether to rotate the projectile's firing direction within the angle bisector of Trajectory.OffsetCoord (or Trajectory.Missile.PreAimCoord in Trajectory=Missile) according to the most superior's weapon's Burst. Set to 0 to disable this function. Negative values will reverse the direction of rotation.
      • Trajectory.MirrorCoord controls whether Trajectory.OffsetCoord (and Trajectory.Missile.PreAimCoord in Trajectory=Missile) need to automatically mirror the lateral value to adapt to the firer's current burst index. At the same time as mirroring, the rotation direction calculated by Trajectory.RotateCoord will also be reversed, and the rotation angle between each adjacent projectile on each side will not change as a result.
      • Trajectory.AxisOfRotation controls the rotation axis when calculating Trajectory.RotateCoord. The axis will rotates with the unit orientation or the vector that from target position to the source position. The length is not important, but the direction is important (the opposite vector will also reverse the rotation direction).
    • Trajectory.LeadTimeCalculate controls whether the projectile need to calculate the lead time of the target when firing.
      • Trajectory.LeadTimeMaximum controls the projectile to predict how long the target will continue to move (used to prevent the projectile from flying too far).
    • Trajectory.DetonationDistance controls the maximum distance in cells from intended target at which the projectile will be forced to detonate. Set to 0 to disable forced detonation. The following are exceptions.
      • In Trajectory=Straight, if ApplyRangeModifiers is set to true, any applicable weapon range modifiers from the firer are applied here as well. By setting Trajectory.Straight.PassThrough=true, it refers to the distance that projectile should travel from its firer when it above 0, and the distance that projectile should move behind the target when it below 0 (use the absolute value), and keep moving without distance restrictions when it is zero.
      • In Trajectory=Bombard and Trajectory=Parabola, when it is set to a negative value, if the target is movable, it will change its target to the cell where the target is located (This is a function expanded for DisperseWeapons and AirburstWeapon).
    • Trajectory.TargetSnapDistance controls the maximum distance in cells from intended target the projectile can be at moment of detonation to make the projectile 'snap' on the intended target. Set to 0 to disable snapping.
    • Trajectory.DetonationHeight controls when the projectile is in a descending state and below the height of the launch position plus this value, it will detonate prematurely. Taking effect when it is set to non negative value. If Trajectory.EarlyDetonation is set to true, it'll take effect during the ascending stage instead, which makes it detonate when its height is above the launch position plus this value.
      • Only in Trajectory=Bombard or Trajectory=Parabola, these are valid.
    • Trajectory.AllowFirerTurning controls whether the projectile allow for significant changes in the orientation of the firer, otherwise it will be immediately detonated.

In rulesmd.ini:

[SOMEPROJECTILE]                      ; Projectile
Trajectory=                           ; Trajectory type enumeration (Straight|Bombard|Missile|Engrave|Parabola|Tracing)
Trajectory.Speed=100.0                ; floating point value
Trajectory.BulletROT=0                ; integer
Trajectory.BulletFacing=velocity      ; Bullet facing enumeration (Velocity|Spin|Stable|Target|Destination|FirerBody|FirerTurret)
Trajectory.BulletFacingOnPlane=false  ; boolean
Trajectory.OffsetCoord=0,0,0          ; integer - Forward,Lateral,Height
Trajectory.RotateCoord=0              ; floating point value
Trajectory.MirrorCoord=true           ; boolean
Trajectory.AxisOfRotation=0,0,1       ; integer - Forward,Lateral,Height
Trajectory.LeadTimeCalculate=false    ; boolean
Trajectory.LeadTimeMaximum=0          ; integer, game frames
Trajectory.DetonationDistance=0.4     ; floating point value
Trajectory.TargetSnapDistance=0.5     ; floating point value
Trajectory.EarlyDetonation=false      ; boolean
Trajectory.DetonationHeight=-1        ; integer
Trajectory.AllowFirerTurning=true     ; boolean
- `Trajectory.LeadTimeCalculate` will not affect the facing of the turret.
- `Trajectory.LeadTimeCalculate` performs best when the projectile speed is 2 to 3 times the target speed.
  • It also has linkage functions with Inaccurate, BallisticScatter.Min, BallisticScatter.Max, Gravity, SubjectToGround.
  • The following table will briefly display the support of various types for various general functions. (✔️ - effective / ❌ - invalid)
Key Straight Bombard Missile Engrave Parabola Tracing
Trajectory.Speed ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Trajectory.BulletROT ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Trajectory.BulletFacing ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Trajectory.BulletFacingOnPlane ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Trajectory.OffsetCoord ✔️ ✔️ ✔️ ✔️
Trajectory.RotateCoord ✔️ ✔️ ✔️ ✔️
Trajectory.MirrorCoord ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Trajectory.AxisOfRotation ✔️ ✔️ ✔️ ✔️
Trajectory.LeadTimeCalculate ✔️ ✔️ ✔️ ✔️
Trajectory.LeadTimeMaximum ✔️ ✔️ ✔️
Trajectory.DetonationDistance ✔️ ✔️ ✔️ ✔️
Trajectory.TargetSnapDistance ✔️ ✔️ ✔️ ✔️
Trajectory.EarlyDetonation ✔️ ✔️
Trajectory.DetonationHeight ✔️ ✔️
Trajectory.AllowFirerTurning ✔️ ✔️
Inaccurate ✔️ ✔️ ✔️ ✔️
BallisticScatter ✔️ ✔️ ✔️ ✔️
Gravity ✔️ ✔️ ✔️
SubjectToGround ✔️ ✔️
ProjectileRange(Weapon's) ✔️ ✔️ ✔️ ✔️
LifeDuration ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NoTargetLifeTime ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
CreateCapacity ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
ApplyRangeModifiers ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
RetargetRadius ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Synchronize ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
PeacefulVanish ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
PassDetonate ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
ProximityImpact ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
PassThroughVehicles ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
PassThroughBuilding ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
DamageEdgeAttenuation ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
DamageCountAttenuation ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
UseDisperseCoord ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
DisperseWeapons ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
- `SubjectToGround` can cause the projectile with `Trajectory=Straight` during the entire process or the projectile with `Trajectory=Bombard` during the ascent phase to detonate prematurely due to impact with the ground. For other trajectory types, only its original function of checking the launch position is available.
- Setting `Trajectory.Missile.UniqueCurve` will ignore all of these settings except of `PassDetonate`, `ProximityImpact` and `DisperseWeapons`.

Straight trajectory

Straigh trajectory blasters
Straight trajectory used to make blasters in a private mod by @brsajo#9745

  • Self-explanatory, is a straight-shot trajectory.
    • Trajectory.Straight.PassThrough enables special case logic where the projectile does not detonate in contact with the target but instead travels up to a distance defined by Trajectory.DetonationDistance. Note that if Trajectory.DetonationDistance is a non negative value, the firing angle of the projectile is adjusted with this in mind, making it fire straight ahead if the target is on same elevation.
    • Trajectory.Straight.ConfineAtHeight controls the height above ground that projectile will try to travel as it can. It can not move down from the cliff by setting SubjectToCliffs to true. It can be cancelled by setting as a non positive integer. It will be forcibly cancelled by setting Trajectory.Speed above 256. If PassDetonateLocal is set to true at the same time, the vertical speed will not be limited.

In rulesmd.ini:

[SOMEPROJECTILE]                       ; Projectile
Trajectory.Straight.PassThrough=false  ; boolean
Trajectory.Straight.ConfineAtHeight=0  ; integer

Bombard trajectory

  • Similar trajectory to Straight, but targets a coordinate between the attacker and intended target first. When the projectile approaches that turning point, it'll turn to the intended target and explodes when it hits the target or ground.
    • Trajectory.Bombard.Height controls the height of the turning point.
    • Trajectory.Bombard.FallPercent controls the distance of the turning point by its percentage of the total distance between attacker and intended target. If set to 0%, then it'll fly up vertically. If set to 100%, then it'll travel to the top of the intended target.
      • For each launch the turning point percentage could add or minus a random value, which is not greater than Trajectory.Bombard.FallPercentShift. If set to 0%, random shift will be disabled.
      • You can also makes the turning point scatter randomly in a circle with Trajectory.Bombard.FallScatter.Max as its radius. If set to 0, random scatter will be disabled. Trajectory.Bombard.FallScatter.Min can be used to determine the minimum radius of the circle. If Trajectory.Bombard.FallScatter.Linear set to true, the random scatter will be limited to the line that is vertical to the original direction of the projectile.
    • Trajectory.Bombard.FreeFallOnTarget controls how it'll hit the intended target. If set to true, the projectile will be respawned above the intended target and free fall. If set to false, the projectile will travel to the intended target from the turning point.
    • Trajectory.Bombard.NoLaunch controls whether the attacker will fire the projectile by itself. If set to true, projectile will directly fall from the turning point.
    • Trajectory.Bombard.FallSpeed controls the initial speed of the projectile after it turns. If set to 0.0, then it'll use Trajectory.Speed. Can't work when Trajectory.Bombard.FreeFallOnTarget set to true.
    • Trajectory.Bombard.TurningPointAnims, if set, will play an anim when the projectile reaches the turning point. If Trajectory.Bombard.FreeFallOnTarget is set to true, it'll be spawned above the target with the projectile together. If Trajectory.Bombard.NoLaunch is set to true, it'll be played at where the projectile falls, no matter if it's free fall or not. If more than one animation is listed, a random one is selected.

In rulesmd.ini:

[SOMEPROJECTILE]                             ; Projectile
Trajectory.Bombard.Height=0.0                ; floating point value
Trajectory.Bombard.FallPercent=1.0           ; floating point value
Trajectory.Bombard.FallPercentShift=0.0      ; floating point value
Trajectory.Bombard.FallScatter.Max=0.0       ; floating point value
Trajectory.Bombard.FallScatter.Min=0.0       ; floating point value
Trajectory.Bombard.FallScatter.Linear=false  ; boolean
Trajectory.Bombard.FreeFallOnTarget=true     ; boolean
Trajectory.Bombard.NoLaunch=false            ; boolean
Trajectory.Bombard.FallSpeed=0.0             ; floating point value
Trajectory.Bombard.TurningPointAnims=        ; List of AnimationTypes

Missile trajectory

  • Its trajectory looks a bit like a ROT, but its settings are more flexible. It also has a unique trajectory.
    • Trajectory.Missile.UniqueCurve controls whether to enable simulated Qian Xuesen trajectory. After enabling this, it will NOT respect the other items.
    • Trajectory.Missile.PreAimCoord controls the initial flight direction of the projectile, and after reaching this coordinate, it will begin to turn towards the target direction. When it is set to 0,0,0 , it will directly face the target.
      • Trajectory.Missile.FacingCoord controls whether the forward direction in Trajectory.Missile.PreAimCoord is depending on the orientation of the firer. By default, it will depend on the vector between the firer and the target.
      • Trajectory.Missile.ReduceCoord controls whether Trajectory.Missile.PreAimCoord defines the initial movement coordinates when the attack distance is 10 cells, and the actual initial movement coordinates will change with the length of the attack distance. It can be simply understood as an optimization term aimed at ensuring hits at close range.
    • Trajectory.Missile.LaunchSpeed controls the initial flight speed of the projectile.
      • Trajectory.Missile.Acceleration controls the acceleration of the projectile's flight speed, increasing or decreasing the speed per frame according to this value, the final speed will be Trajectory.Speed. The velocity superposition with gravity will not be limited by this value.
      • Trajectory.Missile.TurningSpeed controls the turning speed of the projectile's locomotion (moving direction) which refers to the maximum angle that the projectile can rotate per frame in terms of direction.
    • Trajectory.Missile.LockDirection controls whether after reaching Trajectory.Missile.PreAimCoord and completing the first turn, the projectile will lock the direction of motion without further adjustment.
    • Trajectory.Missile.CruiseEnable controls whether after reaching Trajectory.Missile.PreAimCoord, the projectile will maintain altitude while moving towards the target.
      • Trajectory.Missile.CruiseUnableRange controls how far away it is from the target to end the cruise phase, no longer maintaining the cruise altitude, and begins to move directly towards the target. If the distance is already below this value by the time Trajectory.Missile.PreAimCoord is reached, the cruise phase will be skipped.
      • Trajectory.Missile.CruiseAltitude controls the altitude of the projectile in the cruise phase.
      • Trajectory.Missile.CruiseAlongLevel controls whether to calculate Trajectory.Missile.CruiseAltitude by the ground height of the current position, otherwise it will be calculated by the height of the launch position.
    • Trajectory.Missile.SuicideAboveRange controls the projectile to self destruct directly after reaching the flight distance. Set to 0 to disable suicide. When set to a negative number, its absolute value represents a multiple of the initial distance.
    • Trajectory.Missile.SuicideShortOfROT controls whether the projectile will explode when it detected its insufficient turning ability.

In rulesmd.ini:

Trajectory.Missile.UniqueCurve=false        ; boolean
Trajectory.Missile.PreAimCoord=0,0,0        ; integer - Forward,Lateral,Height
Trajectory.Missile.FacingCoord=false        ; boolean
Trajectory.Missile.ReduceCoord=true         ; boolean
Trajectory.Missile.LaunchSpeed=0            ; floating point value
Trajectory.Missile.Acceleration=10.0        ; floating point value
Trajectory.Missile.TurningSpeed=10.0        ; floating point value
Trajectory.Missile.LockDirection=false      ; boolean
Trajectory.Missile.CruiseEnable=false       ; boolean
Trajectory.Missile.CruiseUnableRange=5.0    ; floating point value
Trajectory.Missile.CruiseAltitude=800       ; integer
Trajectory.Missile.CruiseAlongLevel=false   ; boolean
Trajectory.Missile.SuicideAboveRange=-3.0   ; floating point value
Trajectory.Missile.SuicideShortOfROT=false  ; boolean
- The trajectory can be affected by `Gravity`, so if `Trajectory.Missile.TurningSpeed` is too low, the missile will crash to the ground. If you are sure that you do not need it to be affected by it, you can set `Gravity=0` separately.
- If the value of `Trajectory.Missile.CruiseUnableRange` is too small, it may cause the projectile to be permanently stay in cruise mode.

Engrave trajectory

  • Visually, like the thermal lance. Calling it 'trajectory' may not be appropriate. It does not read the settings on the weapon.
    • Trajectory.Engrave.SourceCoord controls the starting point of engraving line segment. Taking the target as the coordinate center. Specifically, it will start from the firing position when set to 0,0 . The height of the point will always at ground level, unless the target is in the air.
    • Trajectory.Engrave.TargetCoord controls the end point of engraving line segment. If LifeDuration is set to a positive number, it is only used for direction calculation. Taking the target as the coordinate center. The height of the point will always at ground level, unless the target is in the air.
    • Trajectory.Engrave.AttachToTarget controls whether the center position of the engrave laser will update with the target position.
    • Trajectory.Engrave.UpdateDirection controls whether the engrave laser updates the direction with the firer and target position.

In rulesmd.ini:

Trajectory.Engrave.SourceCoord=0,0         ; integer - Forward,Lateral
Trajectory.Engrave.TargetCoord=0,0         ; integer - Forward,Lateral
Trajectory.Engrave.AttachToTarget=false    ; boolean
Trajectory.Engrave.UpdateDirection=false   ; boolean
- It's best not to let it be intercepted.
- In this type, the `IsLaser` of the weapon will continuously connect the firing position of the firer and the position of the bullet. Similarly, the laser will be removed after the duration defined by `LaserDuration`.
- Directly using the laser drawing in `Trajectory=Engrave` with `PassDetonateWarhead` is more cost-effective than using `DisperseWeapons`. If you need the laser to be blocked by the Fire Storm Wall, you can try using the latter.
- The default value of `PeacefulVanish` will be changed when using this type of trajectory.

Parabola trajectory

  • As the name says, this is a completely reset Arcing with different enhanced functions.
    • Trajectory.Parabola.OpenFireMode controls how should the projectile be launched. This has the following 6 modes.
      • Speed - Automatic calculation mode with fixed horizontal velocity, using Trajectory.Speed and target coordinates as calculation conditions.
      • Height - Automatic calculation mode with fixed maximum height, useing Trajectory.Parabola.ThrowHeight and target coordinates as calculation conditions, i.e. the detonation time of the projectile is relatively fixed.
      • Angle - Automatic calculation mode with fixed fire angle, useing Trajectory.Parabola.LaunchAngle and target coordinates as calculation conditions.
      • SpeedAndHeight - Fixed horizontal velocity and maximum height mode, using Trajectory.Speed and Trajectory.Parabola.ThrowHeight as calculation conditions, i.e. the trajectory will only undergo altitude changes with the height of the target.
      • HeightAndAngle - Fixed maximum height and fire angle mode, using Trajectory.Parabola.ThrowHeight and Trajectory.Parabola.LaunchAngle as calculation conditions, i.e. the trajectory will change horizontally with the height of the target.
      • SpeedAndAngle - Fixed horizontal velocity and fire angle mode, using Trajectory.Speed and Trajectory.Parabola.LaunchAngle as calculation conditions, i.e. the trajectory will be permanently fixed.
    • Trajectory.Parabola.ThrowHeight controls the maximum height of the projectile and is only used for modes Height, SpeedAndHeight, or HeightAndAngle. The specific height will be determined by taking the larger of the launch height and the target height then increasing this value. Non positive numbers are not supported.
    • Trajectory.Parabola.LaunchAngle controls the fire angle of the projectile and is only used for modes Angle, HeightAndAngle, or SpeedAndAngle. Only supports -90.0 ~ 90.0 (Cannot use boundary values) in Mode Angle or SpeedAndAngle, and 0.0 ~ 90.0 (Cannot use boundary values) in Mode HeightAndAngle.
    • Trajectory.Parabola.DetonationAngle controls when the angle between the projectile in the current velocity direction and the horizontal plane is less than this value, it will detonate prematurely. Taking effect when the value is at -90.0 ~ 90.0 (Cannot use boundary values).
    • Trajectory.Parabola.BounceTimes controls how many times can it bounce back when the projectile hits the ground or cliff. Be aware that excessive projectile speed may cause abnormal operation.
      • Trajectory.Parabola.BounceOnTarget controls the projectile can bounce on which cells or technos.
      • Trajectory.Parabola.BounceOnHouses controls the projectile can bounce on whose technos.
      • Trajectory.Parabola.BounceDetonate controls whether it detonates the warhead once extra during each bounce.
      • Trajectory.Parabola.BounceAttenuation controls the attenuation coefficient of projectile bounce damage, that is, how many times the next damage after each bounce is the damage just caused. This will also affect the damage of the final detonation.
      • Trajectory.Parabola.BounceCoefficient controls the attenuation coefficient of projectile bounce elasticity, that is, how many times the speed after each bounce is the speed before bouncing.

In rulesmd.ini:

Trajectory.Parabola.OpenFireMode=Speed     ; ParabolaFireMode value enumeration (Speed|Height|Angle|SpeedAndHeight|HeightAndAngle|SpeedAndAngle)
Trajectory.Parabola.ThrowHeight=600        ; integer
Trajectory.Parabola.LaunchAngle=30         ; floating point value
Trajectory.Parabola.DetonationAngle=-90.0  ; floating point value
Trajectory.Parabola.BounceTimes=0          ; integer
Trajectory.Parabola.BounceOnTarget=land    ; List of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all)
Trajectory.Parabola.BounceOnHouses=all     ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
Trajectory.Parabola.BounceDetonate=false   ; boolean
Trajectory.Parabola.BounceAttenuation=0.8  ; floating point value
Trajectory.Parabola.BounceCoefficient=0.8  ; floating point value
- If `Trajectory.Parabola.OpenFireMode=Angle`, the performance consumption is high, and may have no solution. It is not recommended to enable `SubjectToCliffs` or enable `AA` with a smaller `MinimumRange` when using this mode.
- Be aware that `Trajectory.DetonationDistance` do not conflict with `Trajectory.Parabola.BounceTimes` and will take effect simultaneously. So if you want to explode the bullet only after the times of bounces is exhausted, you should set `Trajectory.DetonationDistance` to a non positive value.

Tracing trajectory

  • A trajectory that can keep following the target and only detonate when its survival time is exhausted.
    • Trajectory.Tracing.TraceMode controls how should the projectile trace the target. This is used to calculate coordinate axis of Trajectory.Tracing.AttachCoord located on the tracking target. The H axis is not affected by the tilt and deflection of the tracking target, and always faces directly above. This has the following 6 modes.
      • Connection - Line vector. Take the horizontal component of the vector between the launch position and the target position as the F axis.
      • Global - Map direction. Take the lower right side of the map as the F axis.
      • Body - Follow the body. The F axis is the body orientation of the tracking target.
      • Turret - Follow the turret. The F axis is the turret orientation of the tracking target.
      • RotateCW - Rotate clockwise. Rotate clockwise around the H axis with the resultant offset in the FL direction as the radius.
      • RotateCCW - Rotate counterclockwise. Rotate counterclockwise around the H axis with the resultant offset in the FL direction as the radius.
    • Trajectory.Tracing.TrackTarget controls whether the target tracked by the projectile is the target of the projectile. Otherwise, it will trace the firer, and at the same time, the projectile will detonate if the firer dies.
    • Trajectory.Tracing.CreateAtTarget controls whether the projectile is directly generated at the target position.
    • Trajectory.Tracing.StableRotation controls whether the projectile will automatically rotate at the same angle interval when Trajectory.Tracing.TraceMode is RotateCW or RotateCCW.
    • Trajectory.Tracing.CreateCoord controls the generate position. Not related to Trajectory.Tracing.TraceMode.
    • Trajectory.Tracing.AttachCoord controls the tracing position on its target, use Trajectory.Tracing.TraceMode determines the specific location.
    • Trajectory.Tracing.ChasableDistance controls the maximum distance between the target's center of the projectile pursuing and the firer's center, the distance will not exceed this value. When the firer dies, if it is a positive number, it will peacefully vanish. And if it is a negative number, the projectile will explode. When it is zero, the weapon's range will be used and considered a positive number.

In rulesmd.ini:

Trajectory.Tracing.TraceMode=Connection  ; TraceMode value enumeration (Connection|Global|Body|Turret|RotateCW|RotateCCW)
Trajectory.Tracing.TrackTarget=true      ; boolean
Trajectory.Tracing.CreateAtTarget=false  ; boolean
Trajectory.Tracing.StableRotation=false  ; boolean
Trajectory.Tracing.CreateCoord=0,0,0     ; integer - Forward,Lateral,Height
Trajectory.Tracing.AttachCoord=0,0,0     ; integer - Forward,Lateral,Height
Trajectory.Tracing.ChasableDistance=0    ; floating point value
- `Trajectory.Tracing.StableRotation` need to cooperate with `CreateCapacity` records to take effect.
- In this type, the `IsLaser` of the weapon will continuously connect the firing position of the firer and the position of the bullet. Similarly, the laser will be removed after the duration defined by `LaserDuration`.

Summary by CodeRabbit

  • New Features

    • Introduced a unified projectile trajectory system with new types: Straight, Bombard, Missile, Parabola, Engrave, and Tracing.
    • Added projectile lifecycle controls, retargeting, proximity/pass detonation, and multi-target weapon dispersal.
    • Capacity-aware firing prevents over-spawning and may temporarily block firing.
  • Improvements

    • Aircraft weapons using trajectories no longer default to Strafing.
    • Unified Trajectory.* configuration keys and enhanced lead-time, snapping, and height handling.
    • More reliable save/load behavior for trajectory state.
  • Documentation

    • Vastly expanded guides with parameters, compatibility tables, and practical examples for all trajectory types.

@github-actions
Copy link

github-actions bot commented Mar 20, 2025

Nightly build for this pull request:

This comment is automatic and is meant to allow guests to get latest nightly builds for this pull request without registering. It is updated on every successful build.

@Coronia
Copy link
Contributor

Coronia commented Mar 20, 2025

Again, I would concern its backward compatibility. Since Straight, Bombard and Parabola are released logic, there might be modders using it already. Requiring them to modify existing codes is one thing, and those released mods and maps might even not have the chance to modify. I think the 'interface protocol', which means tags in the context of Phobos, should still be compatible when modifying existing functions

For trajectory, we can simply allow these existing 3 projectiles to read previous tags and overwrite the new variables. For example, if Trajectory.Straight.LeadTimeCalculate is already set for a straight trajectory, it should be used to overwrite Trajectory.LeadTimeCalculate. This would be an easy adjustment as we only need to add a few more ini parsing lines

e.g. in StraightTrajectory.cpp

this->LeadTimeCalculate.Read(exINI, pSection, "Trajectory.Straight.LeadTimeCalculate");

@mevitar
Copy link

mevitar commented Mar 20, 2025

I don't think we need to worry about backwards compatibility with this. Like, are there really that many mods that released between changes to Straight and now that aren't developed anymore?
And if they aren't developed, people should not switch to a newer Phobos.dll in the first place!

Everyone else can just update their code to fit the new logic. Just remember to note it in the What's New section (and i guess in the Migration Ulitity? not sure how that one even works, i never used it tbh).

@Metadorius
Copy link
Member

For most renames Migration Utility exists and is a valid option. It searches and replaces en masse using regex. Basically it's automated search and replace tool.

As such any simple tag renames should be put into the migration tool.

@Starkku
Copy link
Contributor

Starkku commented Mar 20, 2025

This PR is pretty much aiming to remove the sort of redundancy that having same value be parsed from multiple keys would add back so that's just not a good idea.

Breaking backwards compatibility is never ideal but it is acceptable in some cases with appropriate migration notice and additions to migration scripts. There will be people who are confused by the changes regardless, whether because they do not read the migration notices or something else, but this one corrects an issue that has potential to snowball into something bigger if even more trajectory types are added in future. In future any new additions that cover or have potential to apply to multiple trajectory types should follow same precedent.

@DeathFishAtEase
Copy link
Collaborator

Perhaps compatibility issues could be addressed through the key-value pair reading process, similar to how Ares' Ripple.Radius and IonCannon.Ripple handle it.

@Metadorius
Copy link
Member

Perhaps compatibility issues could be addressed through the key-value pair reading process, similar to how Ares' Ripple.Radius and IonCannon.Ripple handle it.

Why won't migration tool work?

@DeathFishAtEase
Copy link
Collaborator

DeathFishAtEase commented Mar 20, 2025

Why won't migration tool work?

I am considering the situation described by Starkku.

There will be people who are confused by the changes regardless, whether because they do not read the migration notices or something else


Perhaps compatibility issues could be addressed through the key-value pair reading process, similar to how Ares' Ripple.Radius and IonCannon.Ripple handle it.

However, this effectively reduces the workload for users to perform batch text modifications as well as the need to train users in PowerShell scripting.

@Metadorius
Copy link
Member

I am considering the situation described by Starkku.

There will be people who are confused by the changes regardless, whether because they do not read the migration notices or something else

I think the point was that there will be people like that no matter what you do, so there's no point in inventing something like that and the situation is fine.

@DeathFishAtEase
Copy link
Collaborator

there will be people like that no matter what you do

Well, you're right. :P

@CrimRecya
Copy link
Contributor Author

I mainly integrated functions that can be generalized and also created some new universal functions. Meanwhile, I used inheritance relationships to distinguish between two major categories of trajectories, they also have their own relatively independent functional differences. I have added a large number of comments and also updated the sample for creating new type in the future.
But since I don't have my own mod, I'm not quite sure how to present vivid GIFs in the doc in the most appropriate way. This is quite frustrating.

Regarding the key names, I also thought that there would be no need to add an extra paragraph for the parts that can be shared. A short name indicates its universality while avoiding overly lengthy names.
Actually, I have received some feedback that told me that when the trajectory type increases, the key names become quite lengthy, seems unnecessary because they only change in the middle.
At present, there are only three types that have been merged, and they were all just done in the previous version. I think it is not so complicated even manually replacing them with regular expressions like (Trajectory)(\.).+\.(Proximity.+=) -> $1$2$3.

@TaranDahl TaranDahl added ❓New feature ⚙️T2 T2 maintainer review is sufficient labels Mar 22, 2025
@Coronia Coronia added Needs testing Major Big stuff to do labels Mar 22, 2025
@Coronia
Copy link
Contributor

Coronia commented Sep 12, 2025

According to previous discussion, this PR is too large and might have hidden risks if not being reviewed. However, it's impossible to separate it to smaller PRs now, now only because the functions here are highly coupling with each other a lot, but also because splitting will add more code changes and testing into it, which further increases the risk.

Hence, due to the request of @Metadorius , we should start a group discussion for reviewing this PR. Every maintainer could come and exchange opinions towards it, hopefully in a time when everyone can join together. Hope that we can at least review its basic structure by this way

@secsome @Starkku @Thrifinesma

@ZivDero
Copy link
Contributor

ZivDero commented Sep 15, 2025

According to previous discussion, this PR is too large and might have hidden risks if not being reviewed. However, it's impossible to separate it to smaller PRs now, now only because the functions here are highly coupling with each other a lot, but also because splitting will add more code changes and testing into it, which further increases the risk.

Hence, due to the request of @Metadorius , we should start a group discussion for reviewing this PR. Every maintainer could come and exchange opinions towards it, hopefully in a time when everyone can join together. Hope that we can at least review its basic structure by this way

@secsome @Starkku @Thrifinesma

Right, so here's my 2 cents on this.

It is not necessary to split this into PRs. 8k lines is not a death sentence for a PR.
What did need to happen is splitting the features in the PR in the ways that were suggested previously by both me, and nother maintainers. I can see that a good amount of work has already gone into doing that, and that is good. Assuming that everything not trajectory-related has been refactored into bullets, it will need a new review attempt.

Now, about trajectories. Something that I think could be helpful (or even necessary) is if you provided a class diagram and explanation for how the structure is set up and how it works. Because I cannot trace the relation between "ActualTrajectory" and "PhobosTrajectory" and their descendants, which is what and does what. That needs claification.

Overall, good progress here on getting this into acceptable form.

@CrimRecya
Copy link
Contributor Author

Out of 8800 lines, approximately 3800 lines are from folder changes.
Of the remaining 5000 lines, approximately one fourth to one third are blank lines and comments.

New trajectories is based on polymorphism and inheritance. For these seemingly identical functions, their respective processing methods are used (life duration, retargeting center, processing order of weapon/warhead firing, etc).

Comments from header files

Base class: Actual Trajectory
- The trajectory itself is an attacking object
- Used to share the properties/functions
- for:
	- Straight
	- Bombard
	- Missile
	- Parabola
Base class: Virtual Trajectory
- The trajectory itself is just a carrier for attacking objects
- Used to share the properties/functions
- for:
	- Engrave
	- Tracing

@mevitar
Copy link

mevitar commented Sep 20, 2025

ApplyRangeModifiers controls whether any applicable weapon range modifiers from the firer are applied to the projectile. Effective options include LifeDuration, Trajectory.DetonationDistance and Trajectory.EdgeAttenuation.

This line needs to be updated. Trajectory.DetonationDistance still exists under trajectories, but Trajectory.EdgeAttenuation does not, only a general DamageEdgeAttenuation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (26)
src/Ext/BulletType/Body.cpp (4)

111-112: Read both new and legacy keys for building collisions.

Currently only SubjectToBuildings is read into SubjectToSolid. Support the new key too to ease migration.

Apply:

-	this->SubjectToSolid.Read(exINI, pSection, "SubjectToBuildings");
+	// Legacy then new key so the new one, if present, overrides
+	this->SubjectToSolid.Read(exINI, pSection, "SubjectToBuildings");
+	this->SubjectToSolid.Read(exINI, pSection, "SubjectToSolid");

71-73: Also accept PassThroughBuildings (plural) for consistency.

Docs/discussions use Vehicles/Buildings plural. Accept both singular and plural to reduce config footguns.

-	this->ThroughBuilding.Read(exINI, pSection, "PassThroughBuilding");
+	this->ThroughBuilding.Read(exINI, pSection, "PassThroughBuilding");   // legacy
+	this->ThroughBuilding.Read(exINI, pSection, "PassThroughBuildings");  // alias

191-197: Guard the ActualTrajectoryType cast.

static_cast<ActualTrajectoryType*> assumes the type matches for Straight/Bombard. Add a debug check (or dynamic_cast in debug) to avoid UB if flags/types drift.

-		if (flag == TrajectoryFlag::Straight || flag == TrajectoryFlag::Bombard)
-		{
-			if (this->SubjectToGround)
-				static_cast<ActualTrajectoryType*>(pTrajType)->SubjectToGround = true;
-		}
+		if (flag == TrajectoryFlag::Straight || flag == TrajectoryFlag::Bombard) {
+			if (this->SubjectToGround) {
+#if defined(_DEBUG) || defined(DEBUG)
+				if (auto* actual = dynamic_cast<ActualTrajectoryType*>(pTrajType)) {
+					actual->SubjectToGround = true;
+				} else {
+					Debug::Log("[Developer warning] [%s] Trajectory flag/type mismatch for SubjectToGround.\n", pSection);
+				}
+#else
+				static_cast<ActualTrajectoryType*>(pTrajType)->SubjectToGround = true;
+#endif
+			}
+		}

214-304: Large serialization surface change — confirm savegame compatibility.

Adding many .Process(...) fields alters the stream layout. If backward compatibility is not guaranteed, call it out in release notes; otherwise, gate by a version marker.

src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.h (1)

15-41: Enum and type defaults look sane; add brief inline docs for TraceMode.

A one-line comment per enum value (what center/orientation it uses) will help INI authors and future maintainers.

I can add succinct comments if you want.

src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (2)

37-42: Maintain backward-compat key as a fallback.

You moved to Trajectory.TargetSnapDistance. Consider reading the old key too to avoid breaking existing INIs.

  // Sample
- this->TargetSnapDistance.Read(exINI, pSection, "Trajectory.TargetSnapDistance");
+ // Prefer new key; keep legacy as fallback
+ this->TargetSnapDistance.Read(exINI, pSection, "Trajectory.Sample.TargetSnapDistance"); // legacy
+ this->TargetSnapDistance.Read(exINI, pSection, "Trajectory.TargetSnapDistance");        // new

160-163: Drop trailing semicolon after function definition.

Minor style nit; avoid stray null statements after definitions.

 bool SampleTrajectory::CalculateBulletVelocity(const double speed)
 {
   return this->PhobosTrajectory::CalculateBulletVelocity(speed);
-};
+}
src/Ext/Bullet/Body.cpp (1)

833-851: Serialize/deserialize methods should be private or follow RAII patterns

The new BulletGroupData serialization methods (Load/Save/Serialize) are public but manually manage success/failure states. Consider making these private helper methods or using RAII patterns.

Apply this diff to make the serialize method private:

+private:
 	template <typename T>
 	bool Serialize(T& stm)
 	{
 		return stm
 			.Process(this->Bullets)
 			.Process(this->Angle)
 			.Process(this->ShouldUpdate)
 			.Success();
 	}
+
+public:
 	bool Load(PhobosStreamReader& stm, bool registerForChange)
 	{
 		return this->Serialize(stm);
 	}
 
 	bool Save(PhobosStreamWriter& stm) const
 	{
 		return const_cast<BulletGroupData*>(this)->Serialize(stm);
 	}
src/Ext/Bullet/Hooks.cpp (1)

345-354: Simplify trajectory snap check logic

The function currently checks all trajectory types except Invalid. The commented code suggests checking specific types. Either remove the commented code entirely or explain why the simplified approach was chosen.

Consider simplifying to just:

 constexpr bool CheckTrajectoryCanNotAlwaysSnap(const TrajectoryFlag flag)
 {
 	return flag != TrajectoryFlag::Invalid;
-/*	return flag == TrajectoryFlag::Straight
-		|| flag == TrajectoryFlag::Bombard
-		|| flag == TrajectoryFlag::Missile
-		|| flag == TrajectoryFlag::Engrave
-		|| flag == TrajectoryFlag::Parabola
-		|| flag == TrajectoryFlag::Tracing;*/
 }
src/Ext/Bullet/AdditionalWeapons.cpp (1)

212-510: Complex but well-structured disperse weapon firing logic

The implementation correctly handles multiple firing modes, target selection strategies, and special cases. The use of vector reservations for performance optimization is appreciated. Consider extracting the target collection logic (lines 341-426) into a separate helper function for better maintainability.

src/Ext/Techno/Hooks.Firing.cpp (1)

345-346: Extract trajectory capacity logic into a helper method

The trajectory capacity check could be extracted into a helper method for better readability and potential reuse.

Consider creating a helper method like:

static inline CanFireResult CheckTrajectoryCapacity(TechnoClass* pThis, BulletTypeClass* pBulletType, 
    WeaponTypeClass* pWeapon, TechnoClass* pTargetTechno) 
{
    const auto pBulletTypeExt = BulletTypeExt::ExtMap.Find(pBulletType);
    if (pBulletTypeExt->CreateCapacity >= 0 && BulletExt::CheckExceededCapacity(pThis, pBulletType))
    {
        return (pWeapon->Damage >= 0 || (pTargetTechno && pTargetTechno->GetHealthPercentage() < RulesClass::Instance->unknown_double_16F8)) 
            ? TemporarilyCannotFire : CannotFire;
    }
    return Continue;
}
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.h (1)

99-111: Replace magic number in cliff check with a derived constant.

Hard-coded 384 obscures intent and couples to Unsorted::LevelHeight implicitly.

Apply this diff:

 static inline bool CheckBulletHitCliff(short X, short Y, int bulletHeight, int lastCellHeight)
 {
   if (const auto pCell = MapClass::Instance.TryGetCellAt(CellStruct{ X, Y }))
   {
     const auto cellHeight = pCell->Level * Unsorted::LevelHeight;

-    // (384 -> (4 * Unsorted::LevelHeight - 32(error range)))
-    if (bulletHeight < cellHeight && (cellHeight - lastCellHeight) > 384)
+    constexpr int CliffDeltaMin = 4 * Unsorted::LevelHeight - 32; // error range 32
+    if (bulletHeight < cellHeight && (cellHeight - lastCellHeight) > CliffDeltaMin)
       return true;
   }
   return false;
 }
src/Ext/Bullet/Trajectories/ActualTrajectories/StraightTrajectory.cpp (1)

325-369: Cap vertical correction and re‑normalize only when needed.

Minor: after clamping Z, CalculateBulletVelocity() is called unconditionally; avoid recalculating if magnitude already matches speed within epsilon.

Apply this diff:

-  if (this->CalculateBulletVelocity(pType->Speed))
-    return true;
+  if (std::abs(this->MovingSpeed - pType->Speed) > BulletExt::Epsilon)
+    if (this->CalculateBulletVelocity(pType->Speed))
+      return true;
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (1)

82-83: Mark FireTrajectory as override for interface safety.

Helps catch signature drift.

Apply this diff:

-  virtual void FireTrajectory() { this->OpenFire(); } // New
+  virtual void FireTrajectory() override { this->OpenFire(); } // New
src/Ext/Bullet/AdditionalWarheads.cpp (1)

575-589: Prefer iterator form of std::sort.

Pointer arithmetic on empty vectors is brittle; iterators are clearer and safe.

Apply this diff:

-    std::sort(&validTargets[0], &validTargets[targetsSize],[pBullet](TechnoClass* pTechnoA, TechnoClass* pTechnoB)
+    std::sort(validTargets.begin(), validTargets.end(), [pBullet](TechnoClass* pTechnoA, TechnoClass* pTechnoB)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (1)

241-273: Magic numbers in cliff height calculation.

The cliff height values (384 and 256) appear to be magic numbers without clear explanation. Consider extracting them into named constants with documentation about why these specific values were chosen.

+	// Cliff height thresholds - based on game engine's internal height levels
+	constexpr int CLIFF_HEIGHT_MAJOR = 384; // 4 * Unsorted::LevelHeight - 32 (error range)
+	constexpr int CLIFF_HEIGHT_MINOR = 256;
+	
 	// Calculate where will be located in the next frame
 	const auto checkDifference = this->GetFloorCoordHeight(futureCoords) - futureCoords.Z;
 
 	// When crossing the cliff, directly move the position of the bullet, otherwise change the vertical velocity
-	if (std::abs(checkDifference) >= 384)
+	if (std::abs(checkDifference) >= CLIFF_HEIGHT_MAJOR)
 	{
 		if (pBullet->Type->SubjectToCliffs)
 			return true;
 
 		// Move from low altitude to high altitude
 		if (checkDifference > 0)
 		{
 			bulletCoords.Z += checkDifference;
 			pBullet->SetLocation(bulletCoords);
 		}
 		else
 		{
 			const int nowDifference = bulletCoords.Z - this->GetFloorCoordHeight(bulletCoords);
 
 			// Less than 384 and greater than the maximum difference that can be achieved between two non cliffs
-			if (nowDifference >= 256)
+			if (nowDifference >= CLIFF_HEIGHT_MINOR)
 			{
 				bulletCoords.Z -= nowDifference;
 				pBullet->SetLocation(bulletCoords);
 			}
 		}
 	}
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (1)

143-143: Magic number for turret facing check.

The value 4096 appears to be an angular threshold but lacks documentation. Consider defining a named constant to clarify its purpose.

+	// 45 degree turret facing tolerance threshold (in raw direction units)
+	constexpr short TURRET_FACING_TOLERANCE = 4096;
+	
 	// Similar to the vanilla 45 degree turret facing check design
-	return (std::abs(static_cast<short>(static_cast<short>(tgtDir.Raw) - static_cast<short>(curDir.Raw))) >= 4096);
+	return (std::abs(static_cast<short>(static_cast<short>(tgtDir.Raw) - static_cast<short>(curDir.Raw))) >= TURRET_FACING_TOLERANCE);
src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (6)

213-219: Document the hardcoded trajectory calculation formulas.

These distance-to-height conversion formulas use specific multipliers (0.75, 0.4, 2.0, 8.0) that appear to simulate different missile trajectory behaviors based on range, but lack explanation of their physical or gameplay rationale.

Add comments explaining the trajectory behavior being simulated:

 		// OriginalDistance is converted to record the maximum height
-		if (this->OriginalDistance < (Unsorted::LeptonsPerCell * 8)) // When the distance is very close, the trajectory tends to be parabolic
+		if (this->OriginalDistance < (Unsorted::LeptonsPerCell * 8)) // Short range: parabolic trajectory (0.75x distance + 2 cells height)
 			this->OriginalDistance = static_cast<int>(this->OriginalDistance * 0.75) + (Unsorted::LeptonsPerCell * 2);
-		else if (this->OriginalDistance > (Unsorted::LeptonsPerCell * 15)) // When the distance is far enough, it is the complete trajectory
+		else if (this->OriginalDistance > (Unsorted::LeptonsPerCell * 15)) // Long range: ballistic trajectory (0.4x distance + 2 cells height)
 			this->OriginalDistance = static_cast<int>(this->OriginalDistance * 0.4) + (Unsorted::LeptonsPerCell * 2);
-		else // The distance is neither long nor short, it is an adaptive trajectory
+		else // Medium range: fixed 8-cell height adaptive trajectory
 			this->OriginalDistance = (Unsorted::LeptonsPerCell * 8);

322-326: Consider extracting coordReducingBaseCells constant.

The value 10 is used to calculate coordinate reduction for close-range missiles but is embedded inline without explanation.

Extract as a named constant:

+		constexpr int coordReducingBaseCells = 10; // Base cell distance for coordinate reduction calculations
 		// When the distance is short, the initial moving distance will be reduced
-		if (pType->ReduceCoord && this->OriginalDistance < (Unsorted::LeptonsPerCell * coordReducingBaseCells))
-			this->PreAimDistance *= this->OriginalDistance / (Unsorted::LeptonsPerCell * coordReducingBaseCells);
+		if (pType->ReduceCoord && this->OriginalDistance < (Unsorted::LeptonsPerCell * coordReducingBaseCells))
+			this->PreAimDistance *= this->OriginalDistance / (Unsorted::LeptonsPerCell * coordReducingBaseCells);

360-361: Clarify hardcoded coefficient 90/2 in turning calculation.

The formula (Unsorted::LeptonsPerCell * 90 / 2) for coordinate multiplication lacks explanation of why 90/2 is used.

Add a comment or extract as a constant:

+		constexpr double turningAngleBaseDivisor = 45.0; // 90/2: base turning angle calculation factor
 		// Check if its steering ability is sufficient
-		const double coordMult = (this->OriginalDistance * pType->TurningSpeed / (Unsorted::LeptonsPerCell * 90 / 2));
+		const double coordMult = (this->OriginalDistance * pType->TurningSpeed / (Unsorted::LeptonsPerCell * turningAngleBaseDivisor));

431-431: Extract frame-based prediction constants.

The hardcoded values 8 (predictFrame) and 48 (uniqueCurveTimeHeightBaseOffset) are used for trajectory prediction but lack clear rationale.

Extract as named constants with explanatory comments:

+		constexpr int trajectoryPredictFrames = 8; // Number of frames ahead to predict trajectory
+		constexpr int timeHeightBaseOffset = 48; // Base height offset for time-based hit prediction
 		// Predict the lowest position
-		constexpr int predictFrame = 8;
-		const double futureHeight = pBullet->Location.Z + predictFrame * this->MovingVelocity.Z;
+		const double futureHeight = pBullet->Location.Z + trajectoryPredictFrames * this->MovingVelocity.Z;
 		
 		// Calculate the target lead time
 		if (checkValid)
 		{
-			constexpr int uniqueCurveTimeHeightBaseOffset = 48;
-			targetLocation.Z += static_cast<int>(timeMult * uniqueCurveTimeHeightBaseOffset);
+			targetLocation.Z += static_cast<int>(timeMult * timeHeightBaseOffset);

Also applies to: 449-450


502-502: Clarify minimum speed constants and their purpose.

The hardcoded values 64.0 (minLeadTimeAllowableSpeed) control when lead time calculations are enabled, but the choice of this threshold lacks explanation.

Add comments explaining the speed threshold rationale:

-		constexpr double minLeadTimeAllowableSpeed = 64.0;
+		constexpr double minLeadTimeAllowableSpeed = 64.0; // Minimum speed required for accurate lead time calculations
 
 		// If the speed is too low, it will cause the lead time calculation results to be too far away and unable to be used
 		if (pType->LeadTimeCalculate.Get(true) && checkValid && (pType->UniqueCurve || pType->Speed > minLeadTimeAllowableSpeed))
 		{
 			const auto pTargetFoot = abstract_cast<FootClass*, true>(pTarget);
 
 			// Only movable targets need to be calculated
 			if ((pTargetFoot && !BulletExt::CheckTechnoIsInvalid(pTargetFoot)) || pTarget->WhatAmI() == AbstractType::Bullet)
 			{
-				const double leadSpeed = (pType->Speed + this->MovingSpeed) / 2;
+				const double leadSpeed = (pType->Speed + this->MovingSpeed) / 2; // Average speed for lead time calculation
 				const double timeMult = targetLocation.DistanceFrom(pBullet->Location) / leadSpeed;
 				targetLocation += (pBullet->TargetCoords - this->LastTargetCoord) * timeMult;
 			}
 		}

Also applies to: 512-512


3200-3200: Extract hardcoded threshold distance.

The value 3200 is used as a threshold for missile trajectory calculations but appears as a magic number.

Extract as a named constant:

 		// Calculate the maximum height during the ascending phase
-		constexpr int thresholdDistance = 3200;
+		constexpr int thresholdDistance = 3200; // Distance threshold for trajectory height calculation (approx 12.5 cells)
src/Ext/Bullet/Body.h (1)

51-74: Consider organizing new trajectory-related fields with documentation.

The addition of 24 new public fields significantly expands the ExtData interface. While functionally correct, grouping related fields and adding brief inline documentation would improve maintainability.

Consider organizing fields by functionality:

-		bool DispersedTrajectory;
-		CDTimerClass LifeDurationTimer;
-		CDTimerClass NoTargetLifeTimer;
-		CDTimerClass RetargetTimer;
-		double FirepowerMult;
-		int AttenuationRange;
-		bool TargetIsInAir;
-		bool TargetIsTechno;
-		bool NotMainWeapon;
-		TrajectoryStatus Status;
-		CoordStruct FLHCoord;
-		std::shared_ptr<PhobosMap<BulletTypeClass*, BulletGroupData>> TrajectoryGroup;
-		int GroupIndex;
-		int PassDetonateDamage;
-		CDTimerClass PassDetonateTimer;
-		int ProximityImpact;
-		int ProximityDamage;
-		TechnoClass* ExtraCheck;
-		std::map<DWORD, int> Casualty;
-		int DisperseIndex;
-		int DisperseCount;
-		int DisperseCycle;
-		CDTimerClass DisperseTimer;
+		// Trajectory state
+		bool DispersedTrajectory; // Whether this bullet was created via dispersion
+		TrajectoryStatus Status; // Current trajectory status flags
+		CoordStruct FLHCoord; // Fire location coordinates
+		
+		// Lifetime management
+		CDTimerClass LifeDurationTimer; // Overall bullet lifespan
+		CDTimerClass NoTargetLifeTimer; // Time limit when no target
+		CDTimerClass RetargetTimer; // Retargeting interval
+		
+		// Target and damage state
+		double FirepowerMult; // Damage multiplier from firer
+		int AttenuationRange; // Range for damage attenuation
+		bool TargetIsInAir; // Whether target is airborne
+		bool TargetIsTechno; // Whether target is a techno object
+		bool NotMainWeapon; // Whether fired from non-main weapon
+		TechnoClass* ExtraCheck; // Obstacle collision target
+		
+		// Group management
+		std::shared_ptr<PhobosMap<BulletTypeClass*, BulletGroupData>> TrajectoryGroup;
+		int GroupIndex; // Index within trajectory group
+		
+		// Pass-through detonation
+		int PassDetonateDamage; // Damage for pass-through detonation
+		CDTimerClass PassDetonateTimer; // Timer for pass-through detonation
+		
+		// Proximity effects
+		int ProximityImpact; // Proximity impact counter
+		int ProximityDamage; // Damage for proximity detonation
+		std::map<DWORD, int> Casualty; // Casualty tracking by unit ID
+		
+		// Dispersion system
+		int DisperseIndex; // Current dispersion index
+		int DisperseCount; // Number of dispersion rounds
+		int DisperseCycle; // Dispersion cycle counter
+		CDTimerClass DisperseTimer; // Timer for dispersion firing
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (2)

1138-1139: Extract cliff detection constants for better maintainability.

The cliff collision detection uses hardcoded fractions 1/sqrt(5) and 1/sqrt(2) that could benefit from descriptive names.

+constexpr double shortRightAngledEdge = 1 / ParabolaTrajectory::SqrtConstexpr(5); // ~0.447: Short edge of right triangle normal
+constexpr double longRightAngledEdge = 2 / ParabolaTrajectory::SqrtConstexpr(5); // ~0.894: Long edge of right triangle normal  
+constexpr double hypotenuse = 1 / ParabolaTrajectory::SqrtConstexpr(2); // ~0.707: 45-degree diagonal normal
+
-		constexpr double shortRightAngledEdge = 1 / ParabolaTrajectory::SqrtConstexpr(5);
-		constexpr double longRightAngledEdge = 2 / ParabolaTrajectory::SqrtConstexpr(5);
-		constexpr double hypotenuse = 1 / ParabolaTrajectory::SqrtConstexpr(2);

Also applies to: 1146-1146


1093-1094: Extract cliff height threshold constant.

The value 384 (representing 4 * Unsorted::LevelHeight - 32) for cliff detection should be extracted as a named constant.

+constexpr int cliffHeightThreshold = 384; // Cliff detection threshold: 4 * LevelHeight - 32 (error range)
 	// Check if it has hit a cliff (384 -> (4 * Unsorted::LevelHeight - 32(error range)))
-	if (bulletHeight < cellHeight && (cellHeight - lastCellHeight) > 384)
+	if (bulletHeight < cellHeight && (cellHeight - lastCellHeight) > cliffHeightThreshold)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f5617f and d26c122.

📒 Files selected for processing (33)
  • CREDITS.md (1 hunks)
  • Phobos.vcxproj (2 hunks)
  • docs/New-or-Enhanced-Logics.md (3 hunks)
  • docs/Whats-New.md (2 hunks)
  • src/Ext/Bullet/AdditionalWarheads.cpp (1 hunks)
  • src/Ext/Bullet/AdditionalWeapons.cpp (1 hunks)
  • src/Ext/Bullet/Body.cpp (5 hunks)
  • src/Ext/Bullet/Body.h (6 hunks)
  • src/Ext/Bullet/Hooks.DetonateLogics.cpp (1 hunks)
  • src/Ext/Bullet/Hooks.cpp (3 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.h (1 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.h (1 hunks)
  • src/Ext/Bullet/Trajectories/ActualTrajectories/StraightTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (1 hunks)
  • src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (6 hunks)
  • src/Ext/Bullet/Trajectories/PhobosTrajectory.h (2 hunks)
  • src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h (1 hunks)
  • src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (3 hunks)
  • src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.h (1 hunks)
  • src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (1 hunks)
  • src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.h (1 hunks)
  • src/Ext/BulletType/Body.cpp (7 hunks)
  • src/Ext/BulletType/Body.h (4 hunks)
  • src/Ext/Techno/Body.cpp (1 hunks)
  • src/Ext/Techno/Body.h (3 hunks)
  • src/Ext/Techno/Hooks.Firing.cpp (4 hunks)
  • src/Utilities/SavegameDef.h (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/Ext/Bullet/Hooks.DetonateLogics.cpp
  • src/Ext/Techno/Body.cpp
  • CREDITS.md
  • src/Utilities/SavegameDef.h
  • docs/Whats-New.md
  • src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.h
  • src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h
🧰 Additional context used
🧬 Code graph analysis (22)
src/Ext/Bullet/AdditionalWeapons.cpp (2)
src/Ext/Bullet/Body.h (5)
  • CheckTechnoIsInvalid (229-232)
  • CheckCanRetarget (248-260)
  • GetSurfaceFirer (284-290)
  • HorizontalRotate (201-204)
  • CheckCanDisperse (261-273)
src/Ext/Bullet/Body.cpp (4)
  • SimulatedFiringUnlimbo (632-697)
  • SimulatedFiringUnlimbo (632-632)
  • SimulatedFiringEffects (700-715)
  • SimulatedFiringEffects (700-700)
src/Ext/Bullet/AdditionalWarheads.cpp (1)
src/Ext/Bullet/Body.h (2)
  • SetNewDamage (274-283)
  • CheckTechnoIsInvalid (229-232)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (3)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (28)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • OpenFire (479-513)
  • OpenFire (479-479)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (26)
  • Load (22-27)
  • Load (22-22)
  • Load (61-66)
  • Load (61-61)
  • Save (29-34)
  • Save (29-29)
  • Save (68-73)
  • Save (68-68)
  • Serialize (6-20)
  • Serialize (6-6)
  • Serialize (53-59)
  • Serialize (53-53)
  • OnUnlimbo (75-88)
  • OnUnlimbo (75-75)
  • OnEarlyUpdate (90-108)
  • OnEarlyUpdate (90-90)
  • OnPreDetonate (110-131)
  • OnPreDetonate (110-110)
  • BulletPrepareCheck (133-153)
  • BulletPrepareCheck (133-133)
  • GetOnlyStableOffsetCoords (155-166)
  • GetOnlyStableOffsetCoords (155-155)
  • GetInaccurateTargetCoords (168-182)
  • GetInaccurateTargetCoords (168-168)
  • DisperseBurstSubstitution (184-210)
  • DisperseBurstSubstitution (184-184)
src/Utilities/Stream.h (2)
  • PhobosStreamReader (145-224)
  • PhobosStreamWriter (226-267)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.h (3)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h (2)
  • VirtualTrajectoryType (18-23)
  • VirtualTrajectory (40-68)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (28)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Read (730-740)
  • Read (730-730)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • CalculateBulletVelocity (524-536)
  • CalculateBulletVelocity (524-524)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (28)
  • Load (21-26)
  • Load (21-21)
  • Load (62-67)
  • Load (62-62)
  • Save (28-33)
  • Save (28-28)
  • Save (69-74)
  • Save (69-69)
  • CreateInstance (7-10)
  • CreateInstance (7-7)
  • Read (35-51)
  • Read (35-35)
  • Serialize (13-19)
  • Serialize (13-13)
  • Serialize (54-60)
  • Serialize (54-54)
  • OnVelocityCheck (76-87)
  • OnVelocityCheck (76-76)
  • OpenFire (89-130)
  • OpenFire (89-89)
  • CalculateBulletVelocity (132-164)
  • CalculateBulletVelocity (132-132)
  • GetFloorCoordHeight (166-174)
  • GetFloorCoordHeight (166-166)
  • ChangeVelocity (176-231)
  • ChangeVelocity (176-176)
  • PlaceOnCorrectHeight (233-273)
  • PlaceOnCorrectHeight (233-233)
src/Ext/Techno/Hooks.Firing.cpp (2)
src/Ext/Bullet/Body.cpp (2)
  • CheckExceededCapacity (321-351)
  • CheckExceededCapacity (321-321)
src/Ext/Techno/Body.Internal.cpp (2)
  • GetSimpleFLH (116-149)
  • GetSimpleFLH (116-116)
src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (4)
src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (12)
  • CreateInstance (9-12)
  • CreateInstance (9-9)
  • OnUnlimbo (104-136)
  • OnUnlimbo (104-104)
  • OnVelocityCheck (138-141)
  • OnVelocityCheck (138-138)
  • OnDetonateUpdate (143-171)
  • OnDetonateUpdate (143-143)
  • OpenFire (173-184)
  • OpenFire (173-173)
  • SetBulletNewTarget (246-254)
  • SetBulletNewTarget (246-246)
src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (16)
  • CreateInstance (5-8)
  • CreateInstance (5-5)
  • OnUnlimbo (129-142)
  • OnUnlimbo (129-129)
  • OnEarlyUpdate (144-160)
  • OnEarlyUpdate (144-144)
  • OnVelocityCheck (162-179)
  • OnVelocityCheck (162-162)
  • OnDetonateUpdate (181-197)
  • OnDetonateUpdate (181-181)
  • OpenFire (199-236)
  • OpenFire (199-199)
  • CalculateBulletVelocity (269-278)
  • CalculateBulletVelocity (269-269)
  • SetBulletNewTarget (251-267)
  • SetBulletNewTarget (251-251)
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (12)
  • CreateInstance (39-42)
  • CreateInstance (39-39)
  • OnUnlimbo (129-155)
  • OnUnlimbo (129-129)
  • OnVelocityCheck (157-317)
  • OnVelocityCheck (157-157)
  • OnDetonateUpdate (319-369)
  • OnDetonateUpdate (319-319)
  • OnPreDetonate (371-382)
  • OnPreDetonate (371-371)
  • OpenFire (384-393)
  • OpenFire (384-384)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (18)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnVelocityUpdate (422-429)
  • OnVelocityUpdate (422-422)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • CalculateBulletVelocity (524-536)
  • CalculateBulletVelocity (524-524)
  • SetBulletNewTarget (516-521)
  • SetBulletNewTarget (516-516)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (2)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (16)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Read (730-740)
  • Read (730-730)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OpenFire (479-513)
  • OpenFire (479-479)
src/Ext/Bullet/Body.h (3)
  • Get2DOpRadian (189-192)
  • HorizontalRotate (201-204)
  • GetSurfaceFirer (284-290)
src/Ext/Bullet/Hooks.cpp (2)
src/Ext/Bullet/Body.cpp (2)
  • Detonate (744-773)
  • Detonate (744-744)
src/Ext/WarheadType/Detonate.cpp (2)
  • Detonate (35-189)
  • Detonate (35-35)
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.h (1)
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (52)
  • Load (61-66)
  • Load (61-61)
  • Load (115-120)
  • Load (115-115)
  • Save (68-73)
  • Save (68-68)
  • Save (122-127)
  • Save (122-122)
  • CreateInstance (39-42)
  • CreateInstance (39-39)
  • Read (75-102)
  • Read (75-75)
  • Serialize (45-59)
  • Serialize (45-45)
  • Serialize (105-113)
  • Serialize (105-105)
  • OnUnlimbo (129-155)
  • OnUnlimbo (129-129)
  • OnVelocityCheck (157-317)
  • OnVelocityCheck (157-157)
  • OnDetonateUpdate (319-369)
  • OnDetonateUpdate (319-319)
  • OnPreDetonate (371-382)
  • OnPreDetonate (371-371)
  • OpenFire (384-393)
  • OpenFire (384-384)
  • FireTrajectory (395-437)
  • FireTrajectory (395-395)
  • MultiplyBulletVelocity (439-449)
  • MultiplyBulletVelocity (439-439)
  • CalculateBulletVelocityRightNow (653-780)
  • CalculateBulletVelocityRightNow (653-653)
  • CalculateBulletVelocityLeadTime (451-651)
  • CalculateBulletVelocityLeadTime (451-451)
  • SearchVelocity (782-816)
  • SearchVelocity (782-782)
  • CheckVelocityEquation (818-838)
  • CheckVelocityEquation (818-818)
  • SolveFixedSpeedMeetTime (840-880)
  • SolveFixedSpeedMeetTime (840-840)
  • SearchFixedHeightMeetTime (882-905)
  • SearchFixedHeightMeetTime (882-882)
  • CheckFixedHeightEquation (907-917)
  • CheckFixedHeightEquation (907-907)
  • SearchFixedAngleMeetTime (919-942)
  • SearchFixedAngleMeetTime (919-919)
  • CheckFixedAngleEquation (944-969)
  • CheckFixedAngleEquation (944-944)
  • CalculateBulletVelocityAfterBounce (971-1028)
  • CalculateBulletVelocityAfterBounce (971-971)
  • GetGroundNormalVector (1030-1153)
  • GetGroundNormalVector (1030-1030)
src/Ext/Bullet/Trajectories/ActualTrajectories/StraightTrajectory.cpp (4)
src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (22)
  • Serialize (15-29)
  • Serialize (15-15)
  • Serialize (77-88)
  • Serialize (77-77)
  • Load (31-36)
  • Load (31-31)
  • Load (90-95)
  • Load (90-90)
  • Save (38-43)
  • Save (38-38)
  • Save (97-102)
  • Save (97-97)
  • OnUnlimbo (104-136)
  • OnUnlimbo (104-104)
  • OnVelocityCheck (138-141)
  • OnVelocityCheck (138-138)
  • OnDetonateUpdate (143-171)
  • OnDetonateUpdate (143-143)
  • OpenFire (173-184)
  • OpenFire (173-173)
  • CalculateBulletLeadTime (325-395)
  • CalculateBulletLeadTime (325-325)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (30)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • OpenFire (479-513)
  • OpenFire (479-479)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (4)
  • OnUnlimbo (75-88)
  • OnUnlimbo (75-75)
  • OnPreDetonate (110-131)
  • OnPreDetonate (110-110)
src/Ext/Bullet/Body.h (2)
  • Get2DVelocity (185-188)
  • Get2DOpRadian (189-192)
src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (3)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (26)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Read (730-740)
  • Read (730-730)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • SetBulletNewTarget (516-521)
  • SetBulletNewTarget (516-516)
  • MultiplyBulletVelocity (539-548)
  • MultiplyBulletVelocity (539-539)
src/Ext/BulletType/Body.cpp (2)
  • GetAdjustedGravity (7-12)
  • GetAdjustedGravity (7-7)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (2)
  • OnUnlimbo (75-88)
  • OnUnlimbo (75-75)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (6)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (6)
  • OnUnlimbo (65-84)
  • OnUnlimbo (65-65)
  • OnEarlyUpdate (86-109)
  • OnEarlyUpdate (86-86)
  • OnPreDetonate (111-121)
  • OnPreDetonate (111-111)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (10)
  • OnUnlimbo (75-88)
  • OnUnlimbo (75-75)
  • OnEarlyUpdate (90-108)
  • OnEarlyUpdate (90-90)
  • OnPreDetonate (110-131)
  • OnPreDetonate (110-110)
  • Serialize (6-20)
  • Serialize (6-6)
  • Serialize (53-59)
  • Serialize (53-53)
src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (20)
  • OnUnlimbo (68-79)
  • OnUnlimbo (68-68)
  • OnEarlyUpdate (83-86)
  • OnEarlyUpdate (83-83)
  • OnVelocityCheck (89-92)
  • OnVelocityCheck (89-89)
  • OnVelocityUpdate (98-101)
  • OnVelocityUpdate (98-98)
  • OnDetonateUpdate (106-117)
  • OnDetonateUpdate (106-106)
  • OnPreDetonate (121-135)
  • OnPreDetonate (121-121)
  • OpenFire (139-145)
  • OpenFire (139-139)
  • SetBulletNewTarget (166-169)
  • SetBulletNewTarget (166-166)
  • CalculateBulletVelocity (160-163)
  • CalculateBulletVelocity (160-160)
  • Read (35-42)
  • Read (35-35)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (10)
  • OnEarlyUpdate (109-120)
  • OnEarlyUpdate (109-109)
  • OnVelocityCheck (122-129)
  • OnVelocityCheck (122-122)
  • OpenFire (131-173)
  • OpenFire (131-131)
  • Read (68-84)
  • Read (68-68)
  • Serialize (43-52)
  • Serialize (43-43)
src/Ext/Bullet/Body.cpp (6)
  • Detonate (744-773)
  • Detonate (744-744)
  • Serialize (780-819)
  • Serialize (780-780)
  • Serialize (844-851)
  • Serialize (844-844)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (12)
  • OnVelocityCheck (76-87)
  • OnVelocityCheck (76-76)
  • OpenFire (89-130)
  • OpenFire (89-89)
  • CalculateBulletVelocity (132-164)
  • CalculateBulletVelocity (132-132)
  • Read (35-51)
  • Read (35-35)
  • Serialize (13-19)
  • Serialize (13-13)
  • Serialize (54-60)
  • Serialize (54-54)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (4)
src/Ext/Bullet/Body.cpp (8)
  • Serialize (780-819)
  • Serialize (780-780)
  • Serialize (844-851)
  • Serialize (844-844)
  • Load (833-836)
  • Load (833-833)
  • Save (838-841)
  • Save (838-838)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (26)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
src/Ext/Bullet/Body.h (2)
  • GetSurfaceFirer (284-290)
  • Get2DOpRadian (189-192)
src/Ext/Techno/Body.cpp (2)
  • IsActive (73-79)
  • IsActive (73-73)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (4)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (28)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • RotateAboutTheAxis (609-625)
  • RotateAboutTheAxis (609-609)
src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (16)
  • Serialize (11-29)
  • Serialize (11-11)
  • Serialize (101-113)
  • Serialize (101-101)
  • Load (31-36)
  • Load (31-31)
  • Load (115-120)
  • Load (115-115)
  • Save (38-43)
  • Save (38-38)
  • Save (122-127)
  • Save (122-122)
  • OnUnlimbo (129-142)
  • OnUnlimbo (129-129)
  • OnEarlyUpdate (144-160)
  • OnEarlyUpdate (144-144)
src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (6)
  • OnUnlimbo (68-79)
  • OnUnlimbo (68-68)
  • OnEarlyUpdate (83-86)
  • OnEarlyUpdate (83-83)
  • OnPreDetonate (121-135)
  • OnPreDetonate (121-121)
src/Ext/Bullet/Body.h (1)
  • HorizontalRotate (201-204)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.h (4)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h (2)
  • VirtualTrajectoryType (18-23)
  • VirtualTrajectory (40-68)
src/Utilities/Stream.h (2)
  • PhobosStreamReader (145-224)
  • PhobosStreamWriter (226-267)
src/Ext/Bullet/Trajectories/PhobosTrajectory.h (5)
  • std (233-233)
  • TrajectoryFlag (72-130)
  • TrajectoryFlag (106-115)
  • `` (215-215)
  • `` (230-230)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (16)
  • CreateInstance (37-40)
  • CreateInstance (37-37)
  • Read (68-84)
  • Read (68-68)
  • Serialize (43-52)
  • Serialize (43-43)
  • Serialize (87-93)
  • Serialize (87-87)
  • OnEarlyUpdate (109-120)
  • OnEarlyUpdate (109-109)
  • OnVelocityCheck (122-129)
  • OnVelocityCheck (122-122)
  • OpenFire (131-173)
  • OpenFire (131-131)
  • ChangeVelocity (175-339)
  • ChangeVelocity (175-175)
src/Ext/Bullet/Body.h (2)
src/Ext/Bullet/Body.cpp (27)
  • Load (833-836)
  • Load (833-833)
  • Save (838-841)
  • Save (838-838)
  • Serialize (780-819)
  • Serialize (780-780)
  • Serialize (844-851)
  • Serialize (844-844)
  • ExtData (17-29)
  • InitializeOnUnlimbo (31-97)
  • InitializeOnUnlimbo (31-31)
  • CheckOnEarlyUpdate (99-136)
  • CheckOnEarlyUpdate (99-99)
  • CheckOnPreDetonate (138-163)
  • CheckOnPreDetonate (138-138)
  • FireAdditionals (166-192)
  • FireAdditionals (166-166)
  • DetonateOnObstacle (195-230)
  • DetonateOnObstacle (195-195)
  • CheckSynchronize (233-259)
  • CheckSynchronize (233-233)
  • CheckNoTargetLifeTime (262-285)
  • CheckNoTargetLifeTime (262-262)
  • UpdateGroupIndex (288-318)
  • UpdateGroupIndex (288-288)
  • CheckExceededCapacity (321-351)
  • CheckExceededCapacity (321-321)
src/Ext/Bullet/AdditionalWarheads.cpp (18)
  • GetCellsInProximityRadius (8-66)
  • GetCellsInProximityRadius (8-8)
  • CheckThroughAndSubjectInCell (305-344)
  • CheckThroughAndSubjectInCell (305-305)
  • CalculateNewDamage (346-368)
  • CalculateNewDamage (346-346)
  • PassWithDetonateAt (370-394)
  • PassWithDetonateAt (370-370)
  • PrepareForDetonateAt (397-619)
  • PrepareForDetonateAt (397-397)
  • ProximityDetonateAt (621-640)
  • ProximityDetonateAt (621-621)
  • GetTrueDamage (642-673)
  • GetTrueDamage (642-642)
  • GetExtraDamageMultiplier (675-689)
  • GetExtraDamageMultiplier (675-675)
  • GetCellsInRectangle (81-303)
  • GetCellsInRectangle (81-81)
src/Ext/Bullet/Body.cpp (3)
src/Ext/Techno/Body.cpp (5)
  • ExtData (18-60)
  • GetCurrentFirepowerMultiplier (196-200)
  • GetCurrentFirepowerMultiplier (196-196)
  • Serialize (871-935)
  • Serialize (871-871)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (20)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
src/Ext/BulletType/Body.cpp (2)
  • Serialize (202-304)
  • Serialize (202-202)
src/Ext/Bullet/Trajectories/PhobosTrajectory.h (9)
src/Ext/Bullet/Trajectories/SampleTrajectory.h (2)
  • TrajectoryFlag (17-55)
  • TrajectoryFlag (38-45)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (50)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Read (730-740)
  • Read (730-730)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnEarlyUpdate (216-263)
  • OnEarlyUpdate (216-216)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnVelocityUpdate (422-429)
  • OnVelocityUpdate (422-422)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • SetBulletNewTarget (516-521)
  • SetBulletNewTarget (516-516)
  • CalculateBulletVelocity (524-536)
  • CalculateBulletVelocity (524-524)
  • MultiplyBulletVelocity (539-548)
  • MultiplyBulletVelocity (539-539)
  • RotateVector (561-596)
  • RotateVector (561-561)
  • RotateAboutTheAxis (609-625)
  • RotateAboutTheAxis (609-609)
  • OnFacingCheck (628-652)
  • OnFacingCheck (628-628)
  • OnFacingUpdate (655-725)
  • OnFacingUpdate (655-655)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (16)
  • Load (54-59)
  • Load (54-54)
  • Save (61-66)
  • Save (61-61)
  • Read (68-84)
  • Read (68-68)
  • CreateInstance (37-40)
  • CreateInstance (37-37)
  • Serialize (43-52)
  • Serialize (43-43)
  • OnEarlyUpdate (109-120)
  • OnEarlyUpdate (109-109)
  • OnVelocityCheck (122-129)
  • OnVelocityCheck (122-122)
  • OpenFire (131-173)
  • OpenFire (131-131)
src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (16)
  • Read (45-74)
  • Read (45-45)
  • CreateInstance (9-12)
  • CreateInstance (9-9)
  • OnUnlimbo (104-136)
  • OnUnlimbo (104-104)
  • OnVelocityCheck (138-141)
  • OnVelocityCheck (138-138)
  • OnDetonateUpdate (143-171)
  • OnDetonateUpdate (143-143)
  • OpenFire (173-184)
  • OpenFire (173-173)
  • SetBulletNewTarget (246-254)
  • SetBulletNewTarget (246-246)
  • MultiplyBulletVelocity (256-264)
  • MultiplyBulletVelocity (256-256)
src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (18)
  • Read (45-98)
  • Read (45-45)
  • CreateInstance (5-8)
  • CreateInstance (5-5)
  • OnUnlimbo (129-142)
  • OnUnlimbo (129-129)
  • OnEarlyUpdate (144-160)
  • OnEarlyUpdate (144-144)
  • OnVelocityCheck (162-179)
  • OnVelocityCheck (162-162)
  • OnDetonateUpdate (181-197)
  • OnDetonateUpdate (181-181)
  • OpenFire (199-236)
  • OpenFire (199-199)
  • SetBulletNewTarget (251-267)
  • SetBulletNewTarget (251-251)
  • CalculateBulletVelocity (269-278)
  • CalculateBulletVelocity (269-269)
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (16)
  • Read (75-102)
  • Read (75-75)
  • CreateInstance (39-42)
  • CreateInstance (39-39)
  • OnUnlimbo (129-155)
  • OnUnlimbo (129-129)
  • OnVelocityCheck (157-317)
  • OnVelocityCheck (157-157)
  • OnDetonateUpdate (319-369)
  • OnDetonateUpdate (319-319)
  • OnPreDetonate (371-382)
  • OnPreDetonate (371-371)
  • OpenFire (384-393)
  • OpenFire (384-384)
  • MultiplyBulletVelocity (439-449)
  • MultiplyBulletVelocity (439-439)
src/Ext/Bullet/Trajectories/ActualTrajectories/StraightTrajectory.cpp (14)
  • Read (34-51)
  • Read (34-34)
  • CreateInstance (6-9)
  • CreateInstance (6-6)
  • OnUnlimbo (76-103)
  • OnUnlimbo (76-76)
  • OnVelocityCheck (105-114)
  • OnVelocityCheck (105-105)
  • OnDetonateUpdate (116-138)
  • OnDetonateUpdate (116-116)
  • OnPreDetonate (140-153)
  • OnPreDetonate (140-140)
  • OpenFire (155-164)
  • OpenFire (155-155)
src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (24)
  • Read (35-42)
  • Read (35-35)
  • CreateInstance (6-9)
  • CreateInstance (6-6)
  • OnUnlimbo (68-79)
  • OnUnlimbo (68-68)
  • OnEarlyUpdate (83-86)
  • OnEarlyUpdate (83-83)
  • OnVelocityCheck (89-92)
  • OnVelocityCheck (89-89)
  • OnVelocityUpdate (98-101)
  • OnVelocityUpdate (98-98)
  • OnDetonateUpdate (106-117)
  • OnDetonateUpdate (106-106)
  • OnPreDetonate (121-135)
  • OnPreDetonate (121-121)
  • OpenFire (139-145)
  • OpenFire (139-139)
  • GetCanHitGround (148-151)
  • GetCanHitGround (148-148)
  • SetBulletNewTarget (166-169)
  • SetBulletNewTarget (166-166)
  • CalculateBulletVelocity (160-163)
  • CalculateBulletVelocity (160-160)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (10)
  • Read (35-51)
  • Read (35-35)
  • CreateInstance (7-10)
  • CreateInstance (7-7)
  • OnVelocityCheck (76-87)
  • OnVelocityCheck (76-76)
  • OpenFire (89-130)
  • OpenFire (89-89)
  • CalculateBulletVelocity (132-164)
  • CalculateBulletVelocity (132-132)
src/Ext/Bullet/Trajectories/ActualTrajectories/ParabolaTrajectory.cpp (5)
src/Ext/Bullet/Trajectories/ActualTrajectories/BombardTrajectory.cpp (27)
  • CreateInstance (9-12)
  • CreateInstance (9-9)
  • Serialize (15-29)
  • Serialize (15-15)
  • Serialize (77-88)
  • Serialize (77-77)
  • Load (31-36)
  • Load (31-31)
  • Load (90-95)
  • Load (90-90)
  • Save (38-43)
  • Save (38-38)
  • Save (97-102)
  • Save (97-97)
  • Read (45-74)
  • Read (45-45)
  • exINI (48-48)
  • OnUnlimbo (104-136)
  • OnUnlimbo (104-104)
  • OnVelocityCheck (138-141)
  • OnVelocityCheck (138-138)
  • OnDetonateUpdate (143-171)
  • OnDetonateUpdate (143-143)
  • OpenFire (173-184)
  • OpenFire (173-173)
  • MultiplyBulletVelocity (256-264)
  • MultiplyBulletVelocity (256-256)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (36)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Read (730-740)
  • Read (730-730)
  • exINI (102-102)
  • exINI (732-732)
  • OnUnlimbo (199-213)
  • OnUnlimbo (199-199)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OnPreDetonate (447-476)
  • OnPreDetonate (447-447)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • MultiplyBulletVelocity (539-548)
  • MultiplyBulletVelocity (539-539)
src/Ext/BulletType/Body.cpp (3)
  • exINI (31-31)
  • GetAdjustedGravity (7-12)
  • GetAdjustedGravity (7-7)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (4)
  • OnUnlimbo (75-88)
  • OnUnlimbo (75-75)
  • OnPreDetonate (110-131)
  • OnPreDetonate (110-110)
src/Ext/Bullet/Body.h (3)
  • Get2DVelocity (185-188)
  • Get2DOpRadian (189-192)
  • SetNewDamage (274-283)
src/Ext/Bullet/Trajectories/ActualTrajectories/MissileTrajectory.cpp (3)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (32)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Read (730-740)
  • Read (730-730)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OnDetonateUpdate (432-444)
  • OnDetonateUpdate (432-432)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • CalculateBulletVelocity (524-536)
  • CalculateBulletVelocity (524-524)
  • RotateAboutTheAxis (609-625)
  • RotateAboutTheAxis (609-609)
src/Ext/Bullet/Body.cpp (2)
  • Detonate (744-773)
  • Detonate (744-744)
src/Ext/Bullet/Body.h (3)
  • Get2DOpRadian (189-192)
  • HorizontalRotate (201-204)
  • Coord2Point (205-212)
src/Ext/Bullet/Trajectories/VirtualTrajectories/EngraveTrajectory.cpp (3)
src/Ext/Bullet/Trajectories/VirtualTrajectories/TracingTrajectory.cpp (21)
  • Serialize (43-52)
  • Serialize (43-43)
  • Serialize (87-93)
  • Serialize (87-87)
  • Load (54-59)
  • Load (54-54)
  • Load (95-100)
  • Load (95-95)
  • Save (61-66)
  • Save (61-61)
  • Save (102-107)
  • Save (102-102)
  • Read (68-84)
  • Read (68-68)
  • exINI (71-71)
  • OnVelocityCheck (122-129)
  • OnVelocityCheck (122-122)
  • OpenFire (131-173)
  • OpenFire (131-131)
  • ChangeVelocity (175-339)
  • ChangeVelocity (175-175)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (30)
  • Serialize (755-765)
  • Serialize (755-755)
  • Serialize (780-790)
  • Serialize (780-780)
  • Load (114-127)
  • Load (114-114)
  • Load (142-181)
  • Load (142-142)
  • Load (742-746)
  • Load (742-742)
  • Load (767-771)
  • Load (767-767)
  • Save (129-140)
  • Save (129-129)
  • Save (183-194)
  • Save (183-183)
  • Save (748-752)
  • Save (748-748)
  • Save (773-777)
  • Save (773-773)
  • Read (730-740)
  • Read (730-730)
  • exINI (102-102)
  • exINI (732-732)
  • OnVelocityCheck (266-419)
  • OnVelocityCheck (266-266)
  • OpenFire (479-513)
  • OpenFire (479-479)
  • CalculateBulletVelocity (524-536)
  • CalculateBulletVelocity (524-524)
src/Ext/Bullet/Body.h (3)
  • Coord2Point (205-212)
  • Get2DOpRadian (189-192)
  • PointRotate (213-293)
src/Ext/BulletType/Body.h (1)
src/Utilities/Template.h (2)
  • Valueable (58-71)
  • Nullable (176-189)

@mevitar
Copy link

mevitar commented Oct 1, 2025

Documentation probably needs to make it clear that IsLaser=yes weapon will track the Engrave trajectory no longer than its LaserDuration=.

I was wondering why the beam kept disappearing prematurely when i copied the values from my old projectile-based beam, until i realized that need to increase duration because the beam actually moves now (instead of being repeatedly recreated at new spots as it used to).

@ZivDero
Copy link
Contributor

ZivDero commented Oct 2, 2025

Right, I guess... Let's start trying to move this somewhere?
So right off the bat, I can see these 2

- Projectile life cycle logic and retargeting logic (by CrimRecya)
- Projectile release warheads and weapons (by CrimRecya)

Can we move these two into their own separate PRs? If trajectories specifically depend on them, then we can work on merging those two first, which should hopefully not take long if they're manageable, then come back to this, hopefully with a smaller scope and tackle the main dish.

@Metadorius proposes to chip off individual features and merge them one by one instead of all at once, this way it should be easier for you and with more immediate results.

@Metadorius
Copy link
Member

Just to clarify: those two features that @ZivDero mentioned are obvious from the get go, there's probably more individual things to separate. Think of it as going to the main chunk, identifying a piece, carving it off individually, reviewing and merging it, then returning back and repeating this until everything is split into nice chunks and worked on individually. I'll emphasize again that I think this would be the least problematic way to go for you.

The reason we insist on splitting is because the bigger the PR is...:

  1. ...the easier it is to introduce a mistake and to make it big;
  2. ...the harder it is to spot a mistake for the reviewer.

I and some other maintainers have been burned by merging such large combined PRs in the past, so we would rather try and work out some strategy which would fix the situation best. From what I asked -- @Starkku @Thrifinesma @secsome @ZivDero all seem to agree that some sort of a split is needed.

And generally, as per what we discussed earlier in #1458, we should strive for reusable building blocks of features. This means loose coupling as well. So if a PR is that big -- there is a risk that many of the features are tightly coupled with each other, which is rather bad and should be avoided, because it reduces reusability (extreme example from vanilla: garrison logic and passenger logic being entirely unrelated and not sharing anything in common, thus opentopped is not possible to be easily combined with garrisons). If not -- you'll just simplify the life of a reviewer (yes, separating each feature out of a big PR is a pretty big cognitive load when you're reviewing).

@Coronia
Copy link
Contributor

Coronia commented Oct 2, 2025

I would once again argue that this doesn't have to be splitted for a review, but can be done in the above said way (each people reviewing different parts and discussing). Another way is to make some Draft PRs that only for reviewing, while still use this one as the basis of merge.

The drawbacks of splitting it at this point is listed above, but I wouldn't mind organize them again here:

  • despite the scale of it, this PR has been made used in several mods and map series already, and goes through 'thousands of test' literally. There're also individual testing for each tag to prove their correctness as well. While I know that such testing might not be enough to cover all cases, I can tell that doing a split as of now will just add more holes to it. No one has the time and effort to re-test if every function works properly after the splitting, so if something wrong happens during the splitting, it's just extra mess to be dealt with. And such re-testing will happen again whenever you want to merge another splitted function in, so it's like an exponential growth of complexity for testing.
  • same also applied for coding and reviewing actually. If we split them into different pieces, we'll not only have to consider their original functions, but also need to consider their corelation with each other. Hence, there's likely to be extra mistakes during the splitting, and the reviewing process won't be easier either - even if each part is sorted out individually, the reviewers still need to have knowledge of the whole picture, and might easily miss things due to that.
  • these functions and designed in a way that only support Trajectory, and we've agreed that there's no need to extend them for other projectiles as of now, but just leaving rooms in the design level. So if we split some part out, they might not really work well by themselves but needs support of others. I know this is kinda coupling but again, things can be extended in the future once we make sure that the tag pattern is extendible. E.g. we've already moved some Engrave property to Weapon so we can extend it to support other weapons in the future.
  • not to mention that both the maintainers and the testers are tired of it. I myself is also kinda runing out of patience tbh, and I don't think I'll organize testers on such 'exponential growth' testing which has already been tested heavily for lots of time. People's time and enthusiasm should be devoted in things that's more valueable and not that repetitive I'd say

Besides these drawbacks, there're also these 2 extra coins for you to consider:

  • we're afraid of big PR mostly cuz it might interrupt already existing stuffs. But this one is wholy about an individual system that's not shared with any other projectile and such. Hence, there's no worry that it'll mess up existing stuffs other than those who's using Trajectory as it is. But this also brings up the next point-
  • this PR is supposed to replace some old tags of Trajectory. While we do need to care about if these cases are working correctly (which again has been tested by multiple sources), we shouldn't delay it for too long either. Cuz when more mods and such begin to use Trajectory, it'll be more of a price to ask them for a migration.

@mevitar
Copy link

mevitar commented Oct 3, 2025

I didn't realize that big PRs are such an issue, but I need to point out that it might be too late for splitting this. If it will happen now then testing and merging all the parts will take another few months (so at least until March next year?).

And don't know about others, but for me personally, that guarantees i won't get much of anything else tested for that time. My mod is now so depentent on trajectories that most things do not work properly (or at all) without them. I'm already waiting for this one to be merged so i can move on to test other things.

If it's the same for other people then that means less testing overall (especially true for multiplayer testing).

@STK0Cervanthes
Copy link

Holy PR Batman.

@CrimRecya
Copy link
Contributor Author

I will create a few sketches later for review purposes only. Afterwards, I don't want to waste my time anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Major Big stuff to do ❓New feature ⚙️T2 T2 maintainer review is sufficient Tested

Projects

None yet

Development

Successfully merging this pull request may close these issues.