-
-
Notifications
You must be signed in to change notification settings - Fork 111
[General Purpose] New trajectory system #1582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
[General Purpose] New trajectory system #1582
Conversation
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. |
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 e.g. in StraightTrajectory.cpp this->LeadTimeCalculate.Read(exINI, pSection, "Trajectory.Straight.LeadTimeCalculate"); |
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? 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). |
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. |
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. |
Perhaps compatibility issues could be addressed through the key-value pair reading process, similar to how Ares' |
Why won't migration tool work? |
I am considering the situation described by Starkku.
However, this effectively reduces the workload for users to perform batch text modifications as well as the need to train users in PowerShell scripting. |
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. |
Well, you're right. :P |
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. 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
♻️ Duplicate comments (1)
src/Ext/Bullet/Trajectories/TracingTrajectory.cpp (1)
61-66
: Avoid const_cast in Save methods.Same issue as in VirtualTrajectory - using
const_cast
violates const-correctness.Also applies to: 101-106
🧹 Nitpick comments (34)
src/Ext/Bullet/Hooks.cpp (1)
341-344
: Consider uncommenting the detailed trajectory checks.The commented-out code provides more explicit trajectory type checks which could be beneficial for maintainability and clarity. The current implementation with
flag != TrajectoryFlag::Invalid
works but is less specific about which trajectories support snap behavior.constexpr bool CheckTrajectoryCanNotAlwaysSnap(const TrajectoryFlag flag) { - return flag != TrajectoryFlag::Invalid; -/* return flag == TrajectoryFlag::Straight + return flag == TrajectoryFlag::Straight || flag == TrajectoryFlag::Bombard || flag == TrajectoryFlag::Missile || flag == TrajectoryFlag::Engrave || flag == TrajectoryFlag::Parabola - || flag == TrajectoryFlag::Tracing;*/ + || flag == TrajectoryFlag::Tracing; }src/Ext/BulletType/Body.cpp (1)
55-55
: Consider aligning property name with INI key.The property
SubjectToSolid
is loaded from INI key"SubjectToBuildings"
. While the implementation is correct, consider renaming the property toSubjectToBuildings
for consistency and clarity.- this->SubjectToSolid.Read(exINI, pSection, "SubjectToBuildings"); + this->SubjectToBuildings.Read(exINI, pSection, "SubjectToBuildings");And update the property declaration and serialization accordingly.
Also applies to: 171-171
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h (2)
19-21
: Remove or implement the commented Read method.The commented
Read
method should either be implemented or removed entirely. Keeping commented code creates confusion about the intended design.
43-43
: Consider using const parameter if techno is not modified.The
InvalidFireCondition
method takes a non-constTechnoClass*
parameter. If this method doesn't modify the techno, consider changing it toconst TechnoClass*
for better const-correctness.src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (2)
28-38
: Remove large block of commented code.This commented implementation should be removed from the codebase. If the functionality is needed later, it can be retrieved from version control.
89-97
: Extract magic number and simplify angle calculation.The magic number 4096 represents a 45-degree threshold and should be a named constant. Also, the multiple casts to
short
seem redundant.+ static constexpr short FACING_TOLERANCE = 4096; // 45 degrees in DirStruct units + const auto tgtDir = DirStruct(-PhobosTrajectory::Get2DOpRadian(pTechno->GetCoords(), this->Bullet->TargetCoords)); const auto& face = pTechno->HasTurret() && pTechno->WhatAmI() == AbstractType::Unit ? pTechno->SecondaryFacing : pTechno->PrimaryFacing; const auto curDir = face.Current(); // 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>(tgtDir.Raw - curDir.Raw)) >= FACING_TOLERANCE);src/Ext/Bullet/Trajectories/TracingTrajectory.cpp (2)
184-187
: Document or extract magic numbers in duration calculation.The calculation
pWeapon->ROF - 10
uses an unexplained magic number. Consider documenting why 10 frames are subtracted or extracting it as a named constant.- this->DurationTimer.Start((pWeapon->ROF > 10) ? pWeapon->ROF - 10 : 1); + constexpr int ROF_OFFSET = 10; // Frames to subtract from ROF for trajectory duration + this->DurationTimer.Start((pWeapon->ROF > ROF_OFFSET) ? pWeapon->ROF - ROF_OFFSET : 1);
190-331
: Consider refactoring this complex method.The
ChangeVelocity
method is over 140 lines with deeply nested logic. Consider extracting the trace mode handling into separate methods for better maintainability.src/Ext/Bullet/Trajectories/AdditionalWarheads.cpp (2)
77-299
: Consider refactoring this complex function into smaller, more manageable pieces.This function spans over 200 lines with deeply nested logic and multiple state variables (
leftNext
,rightNext
,leftSkip
,rightSkip
,leftContinue
,rightContinue
). Breaking it down into smaller helper functions would improve readability and maintainability.Consider extracting the following logical sections into separate methods:
- Straight line handling (lines 84-119)
- Left boundary traversal logic
- Right boundary traversal logic
- Center filling logic
This would make the algorithm easier to understand and test.
663-664
: Consider using a named constant for the first cell distance.The magic number
256.0
represents the first cell distance but this isn't immediately clear from the code.+constexpr double FIRST_CELL_DISTANCE = 256.0; // Leptons distance of one cell // Remove the first cell distance for calculation -if (distance > 256.0) - damageMult += (this->GetType()->DamageEdgeAttenuation - 1.0) * ((distance - 256.0) / (this->AttenuationRange - Unsorted::LeptonsPerCell)); +if (distance > FIRST_CELL_DISTANCE) + damageMult += (this->GetType()->DamageEdgeAttenuation - 1.0) * ((distance - FIRST_CELL_DISTANCE) / (this->AttenuationRange - Unsorted::LeptonsPerCell));src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (2)
34-34
: Remove or implement the commented Read method.The commented virtual
Read
method suggests incomplete implementation. Either implement it or remove the comment to avoid confusion.
51-51
: Track the TODO for future improvement.The TODO comment indicates a known issue with frame delay and turret orientation that should be addressed.
Would you like me to create an issue to track this TODO item for future implementation?
docs/New-or-Enhanced-Logics.md (6)
807-814
: Clarify “Trajectory.Speed” semantics per-typeThese bullets currently mix “refers to” and “is used for” jargon, and do not tell the reader which unit the value is in (cells / frame).
Consider rewriting to a tabular form and explicitly stating the unit once, e.g.| Trajectory | Meaning of `Trajectory.Speed` | Unit | | ---------- | ---------------------------- | ---- | | Straight | Constant horizontal speed | leptons / frame |The same re-structure will shrink eight verbose bullet items into one glanceable table.
815-818
: “Duration” default rules read ambiguouslyThe phrase “If it is a non positive number, there will be no timing” can be parsed two ways:
- duration ≤ 0 ➜ infinite lifetime
- duration < 0 ➜ infinite, 0 ➜ immediate detonation
Please disambiguate and adopt the same wording used later (“negative → infinite, zero → …”).
819-828
: Inconsistent casing and missing article in bullet-facing modes
- “Spin - Continuously rotating itself on a horizontal plane.” → “… around the horizontal plane.”
- “Stable - Static after launch …” → consider “Fixed” instead, to avoid conflating with aircraft stability.
Also, bullet names use mixed casing (
Velocity
,Spin
,Stable
,Target
) vs lower-case elsewhere (velocity
in INI snippets). Pick one style for docs and INI to avoid confusion.
834-838
: Default value sentence is hard to parseCurrent:
Trajectory.PeacefulVanish
… “The default value isTrajectory=Engrave
orTrajectory.ProximityImpact
not equal to 0 orTrajectory.DisperseCycle
not equal to 0.”Proposed:
If not set, it defaults to
true
when any of the following is true:
• the trajectory type isEngrave
•Trajectory.ProximityImpact
≠ 0
•Trajectory.DisperseCycle
≠ 0
845-846
: Typo: “projectile need to”Use third-person singular:
- controls whether the projectile need to calculate + controls whether the projectile needs to calculateSame typo occurs in bullet right below (“projectile to predict”).
846-853
: Straight trajectory sub-note duplicates earlier definitionLines 846-848 re-explain the sign semantics of
DetonationDistance
. This duplicates the earlier generic definition and risks drifting. Suggest linking back (“See general note above”) instead of repeating.src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (1)
120-139
: Consider using enum for WaitOneFrame statesThe
WaitOneFrame
member uses magic numbers (0, 1, 2) to track state. Consider using an enum for better readability and maintainability.+enum class BulletPrepareState : int +{ + Ready = 0, + WaitingForTargetUpdate = 1, + InitialFrame = 2 +};Then update the logic to use the enum values instead of magic numbers.
src/Ext/Bullet/Trajectories/MissileTrajectory.h (1)
5-5
: Remove unnecessary includeThe
#include <Ext/WeaponType/Body.h>
appears to be unused in this header file. If it's only needed in the implementation file, move it there to reduce compilation dependencies.src/Ext/Bullet/Trajectories/StraightTrajectory.cpp (1)
321-322
: Consider extracting the magic number.The cliff height threshold of 384 appears here without the explanatory comment present in ParabolaTrajectory.h. Consider defining a named constant or adding a comment for consistency.
- if (std::abs(checkDifference) >= 384 && pBullet->Type->SubjectToCliffs) + // 384 = 4 * Unsorted::LevelHeight - 32 (error range) + if (std::abs(checkDifference) >= 384 && pBullet->Type->SubjectToCliffs)src/Ext/Bullet/Trajectories/EngraveTrajectory.cpp (1)
269-270
: Magic number should be documented.Similar to other trajectories, the cliff height threshold of 384 should have an explanatory comment.
const auto checkDifference = this->GetFloorCoordHeight(futureCoords) - futureCoords.Z; - // When crossing the cliff, directly move the position of the bullet, otherwise change the vertical velocity (384 -> (4 * Unsorted::LevelHeight - 32(error range))) + // When crossing the cliff, directly move the position of the bullet, otherwise change the vertical velocity + // 384 = 4 * Unsorted::LevelHeight - 32 (error range)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (1)
287-287
: Minor formatting: Add space after comma-return Math::atan2(target.Y - source.Y , target.X - source.X); +return Math::atan2(target.Y - source.Y, target.X - source.X);src/Ext/Bullet/Trajectories/BombardTrajectory.cpp (2)
67-68
: Improve FallSpeed validationThe FallSpeed validation only occurs when
isset()
returns true. Consider always validating the value after reading to ensure it's never invalid.this->FallSpeed.Read(exINI, pSection, "Trajectory.Bombard.FallSpeed"); -if (this->FallSpeed.isset()) this->FallSpeed = Math::max(0.001, this->FallSpeed); +if (this->FallSpeed.isset() && this->FallSpeed.Get() <= 0) + this->FallSpeed = 0.001;
112-125
: Document special DetonationDistance behaviorThe code implements special behavior when
DetonationDistance <= -1e-10
, changing the target to the ground cell. This behavior should be documented in the trajectory documentation or as a comment here.Add a comment explaining this special case:
// Special case: Set the target to the ground +// When DetonationDistance is negative, the projectile targets the ground cell instead of the unit if (this->Type->DetonationDistance.Get() <= -1e-10)
src/Ext/Bullet/Trajectories/ParabolaTrajectory.cpp (6)
135-135
: Improve floating-point comparisonUsing
<= -1e-10
for checking negative values is unconventional. Consider using a more standard approach:- if (this->Type->DetonationDistance.Get() <= -1e-10) + if (this->Type->DetonationDistance.Get() < 0.0)
153-286
: Consider refactoring this complex methodThe
OnVelocityCheck
method is over 130 lines with deeply nested logic. Consider extracting the low-speed (lines 167-200) and high-speed (lines 202-272) checking logic into separate helper methods for better readability and maintainability.Example refactoring approach:
bool ParabolaTrajectory::OnVelocityCheck() { // ... gravity adjustment ... double ratio = 1.0; int velocityCheck = 0; if (velocity < Unsorted::LeptonsPerCell) { CheckLowSpeedCollisions(ratio, velocityCheck); } else { CheckHighSpeedCollisions(ratio, velocityCheck); } // ... final velocity adjustment ... }
308-326
: Add documentation for angle-based detonation logicThe angle-based detonation calculations involve complex trigonometry. Consider adding comments to explain the mathematical reasoning:
// Angle if (std::abs(pType->DetonationAngle) < 1e-10) { + // Zero angle means detonate when projectile starts falling if (this->MovingVelocity.Z < 1e-10) return TrajectoryCheckReturnType::Detonate; } else if (std::abs(pType->DetonationAngle) < 90.0) { const auto velocity = PhobosTrajectory::Get2DVelocity(this->MovingVelocity); if (velocity > 1e-10) { + // Check if current trajectory angle is less than detonation angle + // tan(angle) = vertical_velocity / horizontal_velocity if ((this->MovingVelocity.Z / velocity) < Math::tan(pType->DetonationAngle * Math::Pi / 180.0)) return TrajectoryCheckReturnType::Detonate; }
370-370
: Simplify complex ternary expressionThe rotation calculation uses a complex ternary that could be clearer:
- const auto rotateRadian = this->Get2DOpRadian(((target == source && pBullet->Owner) ? pBullet->Owner->GetCoords() : source), target); + const auto& referenceCoords = (target == source && pBullet->Owner) ? pBullet->Owner->GetCoords() : source; + const auto rotateRadian = this->Get2DOpRadian(referenceCoords, target);
411-572
: Extract mode-specific calculations for better organizationThe
CalculateBulletVelocityLeadTime
method is over 160 lines with a large switch statement. Consider extracting each firing mode calculation into a separate method:void ParabolaTrajectory::CalculateBulletVelocityLeadTime(const CoordStruct& source, const double gravity) { // ... setup code ... switch (pType->OpenFireMode) { case ParabolaFireMode::Height: CalculateHeightModeVelocity(source, gravity, meetTime); break; case ParabolaFireMode::Angle: CalculateAngleModeVelocity(source, gravity, meetTime); break; // ... other cases ... } }This would improve readability and make the physics calculations easier to maintain and test.
694-694
: Consider making iteration limit configurableThe Newton's method uses a fixed iteration limit of 10. For some edge cases, this might not be sufficient for convergence:
- for (int i = 0; i < 10; ++i) + constexpr int MAX_ITERATIONS = 10; + for (int i = 0; i < MAX_ITERATIONS; ++i)This makes it easier to adjust if convergence issues are encountered in practice.
src/Ext/Bullet/Trajectories/EngraveTrajectory.h (2)
23-34
: Add documentation for laser configuration parametersConsider adding documentation comments to explain the purpose and units of each parameter for better maintainability.
+ // Controls whether the projectile displays a laser beam Valueable<bool> IsLaser; + // Makes the laser beam more visually intense/bright Valueable<bool> IsIntense; + // Uses the firing house's color for the laser Valueable<bool> IsHouseColor; + // Uses a single color instead of gradient Valueable<bool> IsSingleColor; + // RGB color for the inner/core part of the laser beam Valueable<ColorStruct> LaserInnerColor; + // RGB color for the outer part of the laser beam Valueable<ColorStruct> LaserOuterColor; + // RGB spread/variance for the outer laser color Valueable<ColorStruct> LaserOuterSpread; + // Visual thickness of the laser beam in pixels Valueable<int> LaserThickness; + // Duration in frames that the laser remains visible Valueable<int> LaserDuration; + // Delay in frames between laser pulses Valueable<int> LaserDelay; + // Whether the laser beam follows/attaches to the target Valueable<bool> AttachToTarget; + // Whether the laser beam updates its direction during flight Valueable<bool> UpdateDirection;
47-81
: Add virtual destructor for consistencyAlthough this class is marked
final
, adding a virtual destructor is good practice for consistency with the polymorphic hierarchy.class EngraveTrajectory final : public VirtualTrajectory { public: EngraveTrajectory(noinit_t) { } EngraveTrajectory(EngraveTrajectoryType const* trajType, BulletClass* pBullet) : VirtualTrajectory(trajType, pBullet) , Type { trajType } , LaserTimer {} , RotateRadian { 0 } { } + + virtual ~EngraveTrajectory() = default;src/Ext/Bullet/Trajectories/StraightTrajectory.h (1)
27-59
: Add virtual destructor for consistencyEven though the class is
final
, adding a virtual destructor maintains consistency with the polymorphic hierarchy.class StraightTrajectory final : public ActualTrajectory { public: StraightTrajectory(noinit_t) { } StraightTrajectory(StraightTrajectoryType const* trajType, BulletClass* pBullet) : ActualTrajectory(trajType, pBullet) , Type { trajType } , DetonationDistance { trajType->DetonationDistance } { } + + virtual ~StraightTrajectory() = default;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
docs/_static/images/Trajectory-demo-A.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-B.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-C.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-D.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-E.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-F.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-G.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-I.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-M.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-N.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-O.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-P.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-R.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-S.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-T.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-U.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-V.gif
is excluded by!**/*.gif
docs/_static/images/Trajectory-demo-W.gif
is excluded by!**/*.gif
📒 Files selected for processing (38)
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/Body.cpp
(3 hunks)src/Ext/Bullet/Body.h
(2 hunks)src/Ext/Bullet/Hooks.DetonateLogics.cpp
(1 hunks)src/Ext/Bullet/Hooks.cpp
(3 hunks)src/Ext/Bullet/Trajectories/AdditionalWarheads.cpp
(1 hunks)src/Ext/Bullet/Trajectories/AdditionalWeapons.cpp
(1 hunks)src/Ext/Bullet/Trajectories/BombardTrajectory.cpp
(7 hunks)src/Ext/Bullet/Trajectories/BombardTrajectory.h
(1 hunks)src/Ext/Bullet/Trajectories/EngraveTrajectory.cpp
(1 hunks)src/Ext/Bullet/Trajectories/EngraveTrajectory.h
(1 hunks)src/Ext/Bullet/Trajectories/MissileTrajectory.cpp
(1 hunks)src/Ext/Bullet/Trajectories/MissileTrajectory.h
(1 hunks)src/Ext/Bullet/Trajectories/ParabolaTrajectory.cpp
(6 hunks)src/Ext/Bullet/Trajectories/ParabolaTrajectory.h
(2 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/SampleTrajectory.h
(2 hunks)src/Ext/Bullet/Trajectories/StraightTrajectory.cpp
(4 hunks)src/Ext/Bullet/Trajectories/StraightTrajectory.h
(1 hunks)src/Ext/Bullet/Trajectories/TracingTrajectory.cpp
(1 hunks)src/Ext/Bullet/Trajectories/TracingTrajectory.h
(1 hunks)src/Ext/BulletType/Body.cpp
(5 hunks)src/Ext/BulletType/Body.h
(2 hunks)src/Ext/Techno/Body.cpp
(1 hunks)src/Ext/Techno/Body.h
(3 hunks)src/Ext/Techno/Hooks.Firing.cpp
(4 hunks)src/Phobos.Ext.cpp
(1 hunks)src/Utilities/EnumFunctions.cpp
(1 hunks)src/Utilities/SavegameDef.h
(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/Phobos.Ext.cpp (1)
src/Utilities/SavegameDef.h (1)
ClearSharedRegistry
(27-27)
src/Ext/Bullet/Body.cpp (3)
src/Ext/Techno/Body.cpp (1)
ExtData
(17-53)src/Ext/Anim/Body.cpp (1)
ExtData
(13-22)src/Ext/Bullet/Body.h (1)
ExtData
(53-55)
src/Ext/Techno/Hooks.Firing.cpp (1)
src/Ext/Techno/Body.Internal.cpp (2)
GetFLHAbsoluteCoords
(38-72)GetFLHAbsoluteCoords
(38-38)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (3)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (14)
Serialize
(937-996)Serialize
(937-937)Serialize
(1011-1045)Serialize
(1011-1011)Serialize
(1058-1065)Serialize
(1058-1058)OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnEarlyUpdate
(280-314)OnEarlyUpdate
(280-280)OnPreDetonate
(473-497)OnPreDetonate
(473-473)RotateAboutTheAxis
(616-628)RotateAboutTheAxis
(616-616)src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (4)
OnEarlyUpdate
(80-83)OnEarlyUpdate
(80-80)OnPreDetonate
(118-131)OnPreDetonate
(118-118)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (1)
HorizontalRotate
(297-300)
src/Ext/Bullet/Trajectories/StraightTrajectory.h (5)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (38)
Load
(114-127)Load
(114-114)Load
(142-181)Load
(142-142)Load
(924-928)Load
(924-924)Load
(998-1002)Load
(998-998)Load
(1047-1050)Load
(1047-1047)Save
(129-140)Save
(129-129)Save
(183-194)Save
(183-183)Save
(930-934)Save
(930-930)Save
(1004-1008)Save
(1004-1004)Save
(1052-1055)Save
(1052-1052)Read
(858-922)Read
(858-858)Serialize
(937-996)Serialize
(937-937)Serialize
(1011-1045)Serialize
(1011-1011)Serialize
(1058-1065)Serialize
(1058-1058)OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnVelocityCheck
(317-450)OnVelocityCheck
(317-317)OnDetonateUpdate
(460-470)OnDetonateUpdate
(460-460)OnPreDetonate
(473-497)OnPreDetonate
(473-473)OpenFire
(500-531)OpenFire
(500-500)src/Ext/Bullet/Trajectories/StraightTrajectory.cpp (34)
Load
(20-25)Load
(20-20)Load
(60-65)Load
(60-60)Save
(27-32)Save
(27-27)Save
(67-72)Save
(67-67)CreateInstance
(6-9)CreateInstance
(6-6)Read
(34-49)Read
(34-34)Serialize
(12-18)Serialize
(12-12)Serialize
(52-58)Serialize
(52-52)OnUnlimbo
(74-97)OnUnlimbo
(74-74)OnVelocityCheck
(99-107)OnVelocityCheck
(99-99)OnDetonateUpdate
(109-129)OnDetonateUpdate
(109-109)OnPreDetonate
(131-143)OnPreDetonate
(131-131)OpenFire
(145-154)OpenFire
(145-145)FireTrajectory
(156-191)FireTrajectory
(156-156)CalculateBulletLeadTime
(193-251)CalculateBulletLeadTime
(193-193)GetVelocityZ
(253-298)GetVelocityZ
(253-253)PassAndConfineAtHeight
(300-342)PassAndConfineAtHeight
(300-300)src/Utilities/Stream.h (2)
PhobosStreamReader
(145-224)PhobosStreamWriter
(226-267)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (3)
TrajectoryFlag
(258-267)- `` (477-477)
- `` (492-492)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (2)
void
(57-72)ActualTrajectory
(41-88)
src/Ext/Bullet/Trajectories/ParabolaTrajectory.h (7)
src/Utilities/Template.h (1)
Valueable
(58-71)src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (40)
Load
(114-127)Load
(114-114)Load
(142-181)Load
(142-142)Load
(924-928)Load
(924-924)Load
(998-1002)Load
(998-998)Load
(1047-1050)Load
(1047-1047)Save
(129-140)Save
(129-129)Save
(183-194)Save
(183-183)Save
(930-934)Save
(930-930)Save
(1004-1008)Save
(1004-1004)Save
(1052-1055)Save
(1052-1052)Read
(858-922)Read
(858-858)Serialize
(937-996)Serialize
(937-937)Serialize
(1011-1045)Serialize
(1011-1011)Serialize
(1058-1065)Serialize
(1058-1058)OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnVelocityCheck
(317-450)OnVelocityCheck
(317-317)OnDetonateUpdate
(460-470)OnDetonateUpdate
(460-460)OnPreDetonate
(473-497)OnPreDetonate
(473-473)OpenFire
(500-531)OpenFire
(500-500)MultiplyBulletVelocity
(555-563)MultiplyBulletVelocity
(555-555)src/Ext/Bullet/Trajectories/ParabolaTrajectory.cpp (40)
Load
(61-66)Load
(61-61)Load
(114-119)Load
(114-114)Save
(68-73)Save
(68-68)Save
(121-126)Save
(121-121)CreateInstance
(39-42)CreateInstance
(39-39)Read
(75-100)Read
(75-75)Serialize
(45-59)Serialize
(45-45)Serialize
(103-112)Serialize
(103-103)OnUnlimbo
(128-151)OnUnlimbo
(128-128)OnVelocityCheck
(153-286)OnVelocityCheck
(153-153)OnDetonateUpdate
(288-334)OnDetonateUpdate
(288-288)OnPreDetonate
(336-346)OnPreDetonate
(336-336)OpenFire
(348-357)OpenFire
(348-348)FireTrajectory
(359-395)FireTrajectory
(359-359)MultiplyBulletVelocity
(397-409)MultiplyBulletVelocity
(397-397)CalculateBulletVelocityRightNow
(574-681)CalculateBulletVelocityRightNow
(574-574)CalculateBulletVelocityLeadTime
(411-572)CalculateBulletVelocityLeadTime
(411-411)SearchVelocity
(683-713)SearchVelocity
(683-683)CalculateBulletVelocityAfterBounce
(849-896)CalculateBulletVelocityAfterBounce
(849-849)GetGroundNormalVector
(898-998)GetGroundNormalVector
(898-898)src/Utilities/Stream.h (2)
PhobosStreamReader
(145-224)PhobosStreamWriter
(226-267)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (3)
std
(495-495)- `` (477-477)
- `` (492-492)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (2)
void
(57-72)ActualTrajectory
(41-88)src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (4)
OnUnlimbo
(75-84)OnUnlimbo
(75-75)OnPreDetonate
(99-118)OnPreDetonate
(99-99)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.h (4)
src/Utilities/Template.h (1)
Valueable
(58-71)src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (24)
Load
(114-127)Load
(114-114)Load
(142-181)Load
(142-142)Load
(924-928)Load
(924-924)Load
(998-1002)Load
(998-998)Load
(1047-1050)Load
(1047-1047)Save
(129-140)Save
(129-129)Save
(183-194)Save
(183-183)Save
(930-934)Save
(930-930)Save
(1004-1008)Save
(1004-1004)Save
(1052-1055)Save
(1052-1052)OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnEarlyUpdate
(280-314)OnEarlyUpdate
(280-280)src/Utilities/Stream.h (2)
PhobosStreamReader
(145-224)PhobosStreamWriter
(226-267)src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (6)
OnUnlimbo
(61-69)OnUnlimbo
(61-61)OnEarlyUpdate
(71-77)OnEarlyUpdate
(71-71)InvalidFireCondition
(79-97)InvalidFireCondition
(79-79)
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (3)
src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (4)
OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnEarlyUpdate
(280-314)OnEarlyUpdate
(280-280)src/Ext/Techno/Body.cpp (2)
IsActive
(66-72)IsActive
(66-66)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (1)
Get2DOpRadian
(285-288)
src/Ext/Bullet/Trajectories/MissileTrajectory.h (7)
src/Utilities/Template.h (1)
Valueable
(58-71)src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (42)
Load
(114-127)Load
(114-114)Load
(142-181)Load
(142-142)Load
(924-928)Load
(924-924)Load
(998-1002)Load
(998-998)Load
(1047-1050)Load
(1047-1047)Save
(129-140)Save
(129-129)Save
(183-194)Save
(183-183)Save
(930-934)Save
(930-930)Save
(1004-1008)Save
(1004-1004)Save
(1052-1055)Save
(1052-1052)Read
(858-922)Read
(858-858)Serialize
(937-996)Serialize
(937-937)Serialize
(1011-1045)Serialize
(1011-1011)Serialize
(1058-1065)Serialize
(1058-1058)OnUnlimbo
(199-277)OnUnlimbo
(199-199)OnEarlyUpdate
(280-314)OnEarlyUpdate
(280-280)OnVelocityCheck
(317-450)OnVelocityCheck
(317-317)OnDetonateUpdate
(460-470)OnDetonateUpdate
(460-460)OpenFire
(500-531)OpenFire
(500-500)SetBulletNewTarget
(534-539)SetBulletNewTarget
(534-534)CalculateBulletVelocity
(542-552)CalculateBulletVelocity
(542-542)src/Ext/Bullet/Trajectories/MissileTrajectory.cpp (42)
Load
(31-36)Load
(31-31)Load
(107-112)Load
(107-107)Save
(38-43)Save
(38-38)Save
(114-119)Save
(114-114)Read
(45-90)Read
(45-45)Serialize
(11-29)Serialize
(11-11)Serialize
(93-105)Serialize
(93-93)OnUnlimbo
(121-131)OnUnlimbo
(121-121)OnEarlyUpdate
(133-143)OnEarlyUpdate
(133-133)OnVelocityCheck
(145-161)OnVelocityCheck
(145-145)OnDetonateUpdate
(163-177)OnDetonateUpdate
(163-163)OpenFire
(179-211)OpenFire
(179-179)SetBulletNewTarget
(224-237)SetBulletNewTarget
(224-224)CalculateBulletVelocity
(239-248)CalculateBulletVelocity
(239-239)InitializeBulletNotCurve
(250-298)InitializeBulletNotCurve
(250-250)GetPreAimCoordsWithBurst
(300-309)GetPreAimCoordsWithBurst
(300-300)CalculateReducedVelocity
(311-329)CalculateReducedVelocity
(311-311)CurveVelocityChange
(331-404)CurveVelocityChange
(331-331)NotCurveVelocityChange
(406-416)NotCurveVelocityChange
(406-406)StandardVelocityChange
(418-473)StandardVelocityChange
(418-418)ChangeBulletVelocity
(475-527)ChangeBulletVelocity
(475-475)src/Utilities/Stream.h (2)
PhobosStreamReader
(145-224)PhobosStreamWriter
(226-267)src/Ext/Bullet/Trajectories/PhobosTrajectory.h (4)
std
(495-495)TrajectoryFlag
(258-267)- `` (477-477)
- `` (492-492)
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (2)
void
(57-72)ActualTrajectory
(41-88)src/Ext/Bullet/Trajectories/PhobosActualTrajectory.cpp (4)
OnUnlimbo
(75-84)OnUnlimbo
(75-75)OnEarlyUpdate
(86-97)OnEarlyUpdate
(86-86)
src/Ext/Bullet/Trajectories/PhobosTrajectory.h (1)
src/Ext/Bullet/Trajectories/AdditionalWarheads.cpp (4)
GetCellsInRectangle
(77-299)GetCellsInRectangle
(77-77)GetCellsInProximityRadius
(8-62)GetCellsInProximityRadius
(8-8)
🔇 Additional comments (53)
CREDITS.md (1)
528-531
: LGTM: Proper attribution for significant trajectory system contributions.The additions appropriately acknowledge the extensive new trajectory system implementation including the new trajectory types (Missile, Engrave, Tracing) and the general trajectory framework, which represents a major feature addition to the project.
src/Utilities/EnumFunctions.cpp (1)
21-21
: LGTM: Clean code simplification.The direct assignment using
abstract_cast<TechnoClass*>
simplifies the logic while maintaining the same functionality. The subsequent null check ensures proper handling of the result.src/Ext/Techno/Body.cpp (1)
761-762
: LGTM: Proper serialization of new trajectory system members.The addition of
LastWeaponFLH
andTrajectoryGroup
to the serialization process correctly supports the new trajectory grouping and firing location tracking features. The placement in the serialization sequence is appropriate.src/Ext/BulletType/Body.h (1)
74-76
: LGTM: Well-integrated new bullet interaction flag.The
SubjectToSolid
property follows the established pattern for boolean configuration flags in the class. The initialization tofalse
and positioning among related flags is appropriate. This extends the bullet's environmental interaction capabilities as part of the trajectory system enhancements.Also applies to: 105-105
src/Phobos.Ext.cpp (2)
283-283
: LGTM: Global shared pointer registry for enhanced serialization.The
GlobalSharedRegistry
properly supports the enhanced serialization framework by tracking shared pointers during save/load operations, preventing duplication and maintaining pointer integrity during deserialization.
285-289
: LGTM: Proper registry cleanup on game load.The
LoadGame_ClearShared
hook ensures the shared pointer registry is cleared during game load, which is essential for memory management and preventing stale references from previous sessions.src/Ext/Bullet/Hooks.DetonateLogics.cpp (3)
19-19
: Good variable naming improvement.Renaming
pBullet
topThis
enhances consistency and follows common naming conventions for hook implementations.
23-27
: Excellent integration with the new trajectory system.This addition properly integrates trajectory-based detonation control with the existing bullet logic. The early return when
ShouldDetonate
is false allows trajectory implementations to have fine-grained control over when bullets should detonate, which is essential for the new trajectory types likeMissile
,Engrave
, andTracing
.
31-31
: Consistent variable usage update.Properly updated to use the renamed
pThis
variable, maintaining consistency throughout the function.src/Ext/Bullet/Body.h (3)
35-35
: Good addition for dispersal weapon support.The
DispersedTrajectory
flag appropriately supports the new trajectory system's dispersal weapon functionality. The placement after theTrajectory
member and boolean type are both logical choices.
49-50
: Proper constructor initialization.The initializer list correctly orders members to match declaration order and appropriately initializes
DispersedTrajectory
tofalse
as the default state.
53-53
: Appropriate destructor change for trajectory cleanup.The change from a defaulted destructor to an explicit virtual destructor is necessary to support proper cleanup of trajectory group membership and other trajectory-related resources when bullets are destroyed.
src/Ext/Bullet/Body.cpp (3)
16-32
: LGTM! Proper cleanup for trajectory groups.The destructor correctly removes the bullet from its trajectory group when destroyed, ensuring no dangling references remain in the group's bullet list.
171-176
: Good adaptation to the new trajectory system.The velocity angle calculation now correctly uses the trajectory's
MovingVelocity
when available, falling back to the bullet's velocity for compatibility. This ensures firing animations are properly oriented based on the trajectory's actual movement direction.
434-436
: Correct serialization update for new member.The
DispersedTrajectory
member is properly added to the serialization chain, maintaining save/load compatibility for the new trajectory system.Phobos.vcxproj (1)
60-71
: LGTM! Well-organized trajectory system files.The project file changes properly integrate the new trajectory source and header files. The grouping of all trajectory-related files together in the
src\Ext\Bullet\Trajectories\
directory follows good organizational practices.Also applies to: 245-253
src/Ext/Techno/Body.h (1)
9-9
: Appropriate additions for trajectory system integration.The new include and member variables are properly declared and initialized. The
LastWeaponFLH
member for tracking firing locations andTrajectoryGroup
for managing bullet capacity constraints align well with the trajectory system enhancements described in the PR.Also applies to: 56-57, 124-125
src/Ext/Bullet/Hooks.cpp (1)
86-93
: Good separation of concerns for laser trail handling.The change properly delegates laser trail drawing to trajectories when present, avoiding duplicate rendering. The early return with
Detonate
whenOnEarlyUpdate()
returns true and no spawn animation exists correctly triggers detonation logic.src/Ext/Techno/Hooks.Firing.cpp (4)
349-358
: Well-implemented trajectory capacity management.The capacity check properly enforces bullet creation limits per trajectory type. The lazy initialization of
TrajectoryGroup
and the differentiation betweenTemporarilyCannotFire
vsCannotFire
based on weapon damage provides appropriate feedback to the game's targeting system.
812-816
: Correct implementation of burst fire FLH mirroring.Moving the Y-coordinate mirroring logic inside the positive weapon index branch ensures it only applies to actual weapon firing, not alternate FLHs. The parity check on
CurrentBurstIndex
for mirroring is the standard approach for alternating fire positions.
828-835
: Good passenger-aware FLH tracking.The logic correctly identifies the passenger at the specified index and stores its FLH for later use. This enables proper projectile origin tracking for passengers firing from transports.
839-839
: Important register correction.Changing from
R->EBX(pCoords)
toR->EAX(pCoords)
fixes the return value register, as the game expects the result in EAX at this hook location.src/Ext/BulletType/Body.cpp (1)
125-141
: Excellent trajectory flag management.The validation logic properly:
- Resets the
Arm
flag to prevent conflicts- Transfers
Ranged
behavior to trajectory while clearing it from bullet- Propagates
SubjectToGround
to appropriate trajectory typesThe comment explaining the
Ranged
behavior is helpful for understanding the design decision.src/Utilities/SavegameDef.h (1)
443-455
: LGTM!The pair serialization implementation is clean and correct, properly handling both members with short-circuit evaluation.
src/Ext/Bullet/Trajectories/PhobosVirtualTrajectory.cpp (1)
61-69
: LGTM!The
OnUnlimbo
initialization logic is clear and correct.src/Ext/Bullet/Trajectories/TracingTrajectory.cpp (2)
6-35
: LGTM!The INI parser specialization for
TraceTargetMode
is well-implemented with proper error handling.
108-126
: LGTM!The lifecycle methods correctly handle trajectory initialization and early termination conditions.
src/Ext/Bullet/Trajectories/AdditionalWeapons.cpp (1)
552-594
: LGTM!The
CreateDisperseBullets
method is well-structured with clear responsibilities.src/Ext/Bullet/Trajectories/AdditionalWarheads.cpp (3)
301-337
: LGTM!The obstacle checking logic is well-structured with appropriate handling for different techno types and special cases.
604-622
: LGTM!Clean implementation with clear separation of different damage application methods.
624-652
: LGTM!Well-implemented damage calculation with appropriate handling of attenuation and minimal damage retention.
src/Ext/Bullet/Trajectories/PhobosActualTrajectory.h (1)
62-72
: LGTM!The inline helper method
CheckProjectileRange
is appropriately placed in the header due to its small size and frequent usage.src/Ext/Bullet/Trajectories/TracingTrajectory.h (3)
5-13
: LGTM!Well-designed enum class with clear mode names and type safety.
15-41
: LGTM!Well-structured trajectory type class with proper initialization and virtual method overrides.
43-75
: LGTM!Clean trajectory implementation with appropriate virtual method overrides and const correctness.
docs/New-or-Enhanced-Logics.md (1)
839-844
: Rotation section mixes coordinate spaces
Trajectory.RotateCoord
andTrajectory.AxisOfRotation
are described in world space, butTrajectory.OffsetCoord
is relative-target space. Readers have to infer this. Add one sentence clarifying coordinate space for each key.src/Ext/Bullet/Trajectories/SampleTrajectory.h (1)
12-50
: LGTM! Sample trajectory properly updated to new architecture.The changes correctly adapt the sample trajectory to the new trajectory system architecture, including:
- Proper base class initialization with bullet context
- Consistent method signatures with other trajectory implementations
- Appropriate visibility for configuration parameters
src/Ext/Bullet/Trajectories/ParabolaTrajectory.h (2)
5-13
: Good use of enum for firing modes.The
ParabolaFireMode
enum improves code clarity by providing named constants for the different trajectory calculation modes.
98-109
: Cliff detection logic is well-implemented.The static
CheckBulletHitCliff
method correctly:
- Validates cell existence before accessing
- Uses appropriate height threshold (384 = 4 * LevelHeight - 32)
- Includes clear documentation of the magic number
src/Ext/Bullet/Trajectories/BombardTrajectory.h (2)
15-15
: Good use of Nullable for optional configuration.The change from
Valueable<double>
toNullable<double>
forFallSpeed
allows proper handling of unset values, distinguishing them from a speed of 0.Also applies to: 27-27
55-55
: Clear naming improvement for angle units.Renaming
RotateAngle
toRotateRadian
clarifies that the value is in radians, reducing potential for unit conversion errors.Also applies to: 64-64
src/Ext/Bullet/Trajectories/StraightTrajectory.cpp (2)
74-97
: Range modifier calculation properly handles edge cases.The implementation correctly:
- Applies range modifiers only when enabled
- Handles both positive and negative detonation distances
- Prevents premature firing for dispersed trajectories
193-251
: Lead time calculation is mathematically sound.The quadratic equation solving for target interception is well-implemented with proper handling of:
- Edge cases (vertical shots, no solution)
- Moving targets (extra frame compensation)
- Linear equation special case
src/Ext/Bullet/Trajectories/EngraveTrajectory.cpp (2)
52-52
: Speed limitation needs documentation.The speed is clamped to a maximum of 128.0 without explanation. Consider adding a comment explaining why this limitation exists for engrave trajectories.
// Limitation + // Engrave trajectories are limited to prevent visual artifacts at high speeds this->Speed = Math::min(128.0, this->Speed);
284-284
: Unexplained magic number in height check.The value 256 is used as a threshold without explanation. This appears different from the cliff height of 384. Please document what this value represents.
- // Less than 384 and greater than the maximum difference that can be achieved between two non cliffs + // Less than 384 and greater than the maximum difference that can be achieved between two non-cliffs + // 256 = maximum height difference between adjacent non-cliff cells if (nowDifference >= 256)src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp (1)
1122-1123
: Verify hook return behaviorThe hook returns 0 when trajectory doesn't exist, which continues to the next instruction. Ensure this is the intended behavior and doesn't skip necessary game code.
If the intention is to skip game code when no trajectory exists, consider returning the skip address instead:
-if (!BulletExt::ExtMap.Find(pThis)->Trajectory) - return 0; +if (!BulletExt::ExtMap.Find(pThis)->Trajectory) + return SkipGameCode;src/Ext/Bullet/Trajectories/ParabolaTrajectory.cpp (4)
8-37
: LGTM!The template specialization for reading
ParabolaFireMode
is well-implemented with proper error handling and clear string-to-enum mappings.
39-100
: Proper refactoring to new base classesThe instance creation and serialization methods are correctly updated to work with the new
ActualTrajectoryType
base class. The comprehensive parameter reading in theRead
method properly handles all trajectory configuration options.
849-896
: Well-implemented bounce physicsThe bounce calculation correctly handles:
- Surface eligibility checks
- Techno collision detection
- Realistic bounce physics using surface normals
- Damage attenuation on bounce
- Additional warhead detonation
The implementation is thorough and physically accurate.
898-998
: Comprehensive ground normal vector calculationThe
GetGroundNormalVector
method excellently handles:
- Various slope indices with pre-calculated normal vectors
- Cliff detection with directional analysis
- Edge case handling for different terrain configurations
The magic numbers are well-documented with their mathematical derivations, making the code maintainable.
docs/Whats-New.md (1)
430-433
: LGTM!The new trajectory system entries are well-formatted and consistent with the existing changelog structure.
src/Ext/Bullet/Trajectories/EngraveTrajectory.h (1)
5-45
: Add virtual destructor for polymorphic base classSince
EngraveTrajectoryType
is a polymorphic class (has virtual functions and is used through base class pointers), it should have a virtual destructor to ensure proper cleanup.class EngraveTrajectoryType final : public VirtualTrajectoryType { public: EngraveTrajectoryType() : VirtualTrajectoryType() , IsLaser { true } , IsIntense { false } , IsHouseColor { false } , IsSingleColor { false } , LaserInnerColor { { 0, 0, 0 } } , LaserOuterColor { { 0, 0, 0 } } , LaserOuterSpread { { 0, 0, 0 } } , LaserThickness { 3 } , LaserDuration { 1 } , LaserDelay { 1 } , AttachToTarget { false } , UpdateDirection { false } { } + + virtual ~EngraveTrajectoryType() = default;Likely an incorrect or invalid review comment.
src/Ext/Bullet/Trajectories/SampleTrajectory.cpp (1)
1-166
: Excellent refactoring with helpful documentation!The refactoring to use the new base classes is clean and well-executed. The added comments explaining each lifecycle method's purpose significantly improve code maintainability.
continue; | ||
|
||
const auto nextDistanceCrd = distanceCrd - velocityCrd; | ||
// Should be behind the bullet's next frame position | ||
if (nextDistanceCrd * velocityCrd > 0) | ||
{ | ||
// Otherwise, at least within the spherical range of future position | ||
if (nextDistanceCrd.Magnitude() > radius) | ||
continue; | ||
} | ||
// Calculate the distance between the point and the line | ||
const auto distance = (velocity > 1e-10) ? (distanceCrd.CrossProduct(nextDistanceCrd).Magnitude() / velocity) : distanceCrd.Magnitude(); | ||
// Should be in the center cylinder | ||
if (distance > radius) | ||
continue; | ||
// Manual expansion | ||
if (thisSize >= vectSize) | ||
{ | ||
vectSize += cellSize; | ||
validTechnos.reserve(vectSize); | ||
} | ||
|
||
validTechnos.push_back(pTechno); | ||
thisSize += 1; | ||
} | ||
} | ||
// Step 3: Record each target without repetition. | ||
std::vector<int> casualtyChecked; | ||
casualtyChecked.reserve(Math::max(validTechnos.size(), this->TheCasualty.size())); | ||
// No impact on firer | ||
if (pFirer) | ||
this->TheCasualty[pFirer->UniqueID] = 5; | ||
// Update Record | ||
for (const auto& [ID, remainTime] : this->TheCasualty) | ||
{ | ||
if (remainTime > 0) | ||
this->TheCasualty[ID] = remainTime - 1; | ||
else | ||
casualtyChecked.push_back(ID); | ||
} | ||
|
||
for (const auto& ID : casualtyChecked) | ||
this->TheCasualty.erase(ID); | ||
|
||
std::vector<TechnoClass*> validTargets; | ||
validTargets.reserve(validTechnos.size()); | ||
// checking for duplicate | ||
for (const auto& pTechno : validTechnos) | ||
{ | ||
if (!this->TheCasualty.contains(pTechno->UniqueID)) | ||
validTargets.push_back(pTechno); | ||
// Record 5 frames | ||
this->TheCasualty[pTechno->UniqueID] = 5; | ||
} | ||
// Step 4: Detonate warheads in sequence based on distance. | ||
const auto targetsSize = validTargets.size(); | ||
|
||
if (this->ProximityImpact > 0 && static_cast<int>(targetsSize) > this->ProximityImpact) | ||
{ | ||
std::sort(&validTargets[0], &validTargets[targetsSize],[pBullet](TechnoClass* pTechnoA, TechnoClass* pTechnoB) | ||
{ | ||
const auto distanceA = pTechnoA->GetCoords().DistanceFromSquared(pBullet->SourceCoords); | ||
const auto distanceB = pTechnoB->GetCoords().DistanceFromSquared(pBullet->SourceCoords); | ||
// Distance priority | ||
if (distanceA < distanceB) | ||
return true; | ||
|
||
if (distanceA > distanceB) | ||
return false; | ||
|
||
return pTechnoA->UniqueID < pTechnoB->UniqueID; | ||
}); | ||
} | ||
|
||
for (const auto& pTechno : validTargets) | ||
{ | ||
// Not effective for the technos following it. | ||
if (pTechno == this->ExtraCheck) | ||
break; | ||
// Last chance | ||
if (this->ProximityImpact == 1) | ||
{ | ||
this->ExtraCheck = pTechno; | ||
break; | ||
} | ||
// Skip technos that are within range but will not obstruct and cannot be passed through | ||
const auto absType = pTechno->WhatAmI(); | ||
|
||
if (!pType->ThroughVehicles && (absType == AbstractType::Unit || absType == AbstractType::Aircraft)) | ||
continue; | ||
|
||
if (absType == AbstractType::Building && (static_cast<BuildingClass*>(pTechno)->IsStrange() ? !pType->ThroughVehicles : !pType->ThroughBuilding)) | ||
continue; | ||
|
||
this->ProximityDetonateAt(pOwner, pTechno); | ||
// Record the number of times | ||
if (this->ProximityImpact > 0) | ||
--this->ProximityImpact; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Refactor this complex function for better maintainability.
This 200+ line function handles multiple responsibilities: target validation, distance calculations, deduplication, and detonation sequencing. The embedded lambda is also quite large.
Consider extracting:
- The
checkCellContent
lambda into a separate method - Target validation logic into a dedicated function
- Distance calculation and filtering into helper methods
Additionally, the manual vector capacity management (lines 464-468, 519-523) seems redundant since reserve
is already being used. The vector will automatically grow as needed.
🤖 Prompt for AI Agents
In src/Ext/Bullet/Trajectories/AdditionalWarheads.cpp from lines 389 to 602,
refactor the large PrepareForDetonateAt function by extracting the
checkCellContent lambda into its own method, isolating target validation logic
into a separate function, and moving distance calculation and filtering into
helper methods. Remove the manual vector capacity management code that attempts
to reserve additional capacity during push_back calls, as std::vector
automatically grows and the initial reserve calls are sufficient. This will
improve maintainability and readability by breaking down the complex function
into smaller, focused components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and this bot comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and this bot comment
There are buildings on the ground, so the distance calculation is very different. So I don't think it's necessary to package it
Why did the bot suddenly trigger at your code xD |
I don't know, it suddenly popped up after the last push |
All completed |
docs/New-or-Enhanced-Logics.md
Outdated
- The referenced images, weapons, and warheads should be supplemented by yourself. | ||
- SOMEWEAPON[] - SOMEPROJECTILE[] - SOMEIMAGE[] / SOMEWARHEAD[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does, for example, SOMEWEAPON[] mean? Did you mean to put a placeholder this way, (like SOMEWEAPONA1)? It's not very clear this way. Maybe we could omit that at all? Should be clear that those aren't public assets, it's the default case in Phobos docs anyways.
Also how about putting it also under {note}
block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get it
 | ||
- The assets of the case come from mod *Light Cone*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you want to make those as links? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked the person who provides GIFs for this, and he said that their mod currently does not have any particularly good web pages that can be used as links, So they haven't put the link for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went ahead and did at least a partial code review (hard to go over 7k+/3k- lines), mainly on clarity and code style. I think due to size this would need some more reviewing, especially on the higher level code organization
casualtyChecked.reserve(Math::max(validTechnos.size(), this->TheCasualty.size())); | ||
// No impact on firer | ||
if (pFirer) | ||
this->TheCasualty[pFirer->UniqueID] = 5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally no articles are used in code, could just remove them (a
or the
)
this->CalculateNewDamage(); | ||
} | ||
|
||
int PhobosTrajectory::GetTheTrueDamage(int damage, bool self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
} | ||
// It has not lost its target | ||
if (!check) | ||
return false; | ||
// Check whether need to detonate directly after the target was lost | ||
if (!pType->TolerantTime || pType->RetargetRadius < 0) | ||
return true; | ||
// Check the timer | ||
if (this->RetargetTimer.HasTimeLeft()) | ||
return false; | ||
// Next time wait for so long first | ||
this->RetargetTimer.Start(pType->RetargetInterval); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, there should be newlines here and in all other places to improve readability:
} | |
// It has not lost its target | |
if (!check) | |
return false; | |
// Check whether need to detonate directly after the target was lost | |
if (!pType->TolerantTime || pType->RetargetRadius < 0) | |
return true; | |
// Check the timer | |
if (this->RetargetTimer.HasTimeLeft()) | |
return false; | |
// Next time wait for so long first | |
this->RetargetTimer.Start(pType->RetargetInterval); | |
} | |
// It has not lost its target | |
if (!check) | |
return false; | |
// Check whether need to detonate directly after the target was lost | |
if (!pType->TolerantTime || pType->RetargetRadius < 0) | |
return true; | |
// Check the timer | |
if (this->RetargetTimer.HasTimeLeft()) | |
return false; | |
// Next time wait for so long first | |
this->RetargetTimer.Start(pType->RetargetInterval); |
const auto pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon); | ||
TechnoClass* pNewTechno = nullptr; | ||
// Find the first target | ||
if (!this->TargetInTheAir) // Only get same type (on ground / in air) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another The
if (!pTechnoType->LegalTarget) | ||
continue; | ||
else if (pTechno->IsBeingWarpedOut()) | ||
continue; | ||
else if (pTechno->WhatAmI() == AbstractType::Building && static_cast<BuildingClass*>(pTechno)->Type->InvisibleInGame) | ||
continue; | ||
else if (!PhobosTrajectory::CheckWeaponValidness(pOwner, pTechno, pCell, pType->RetargetHouses)) | ||
continue; | ||
else if (PhobosTrajectory::GetDistanceFrom(retargetCoords, pTechno) > retargetRange) | ||
continue; | ||
else if (MapClass::GetTotalDamage(100, pBullet->WH, pTechnoType->Armor, 0) == 0) | ||
continue; | ||
else if (pWeapon && PhobosTrajectory::GetDistanceFrom(pFirer ? pFirer->GetCoords() : pBullet->SourceCoords, pTechno) > range) | ||
continue; | ||
else if (!PhobosTrajectory::CheckWeaponCanTarget(pWeaponExt, pFirer, pTechno)) | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else
are not needed here, also not sure it will be better but could just make it a long multiline var like
bool skip = ...
|| ...
|| ...
if (skip)
continue;
if (pType->NoLaunch) | ||
return extraOffsetCoord * this->GetLeadTime(std::round((this->Height - target.Z) / pType->FallSpeed.Get(pType->Speed))); | ||
|
||
const auto theDistanceSquared = targetSourceCoord.MagnitudeSquared(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another the
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose and the difference between PhobosTrajectory, PhobosActualTrajectory and PhobosVirtualTrajectory? Those seem like new concepts and I think every one of them should have an explanation and relation documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's beneficial to make the specific implemeneted trajectories go into a subfolder.
src/Ext/Techno/Body.h
Outdated
@@ -52,6 +53,8 @@ class TechnoExt | |||
bool CanCloakDuringRearm; // Current rearm timer was started by DecloakToFire=no weapon. | |||
int WHAnimRemainingCreationInterval; | |||
WeaponTypeClass* LastWeaponType; | |||
CoordStruct LastWeaponFLH; | |||
std::shared_ptr<PhobosMap<DWORD, PhobosTrajectory::GroupData>> TrajectoryGroup; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this for?
struct GroupData | ||
{ | ||
std::vector<DWORD> Bullets {}; | ||
double Angle { 0.0 }; | ||
bool ShouldUpdate { true }; | ||
|
||
GroupData() = default; | ||
|
||
bool Load(PhobosStreamReader& stm, bool registerForChange); | ||
bool Save(PhobosStreamWriter& stm) const; | ||
|
||
private: | ||
template <typename T> | ||
bool Serialize(T& stm); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could leave a comment on what this is for too
src/Ext/Techno/Hooks.Firing.cpp
Outdated
{ | ||
const auto pFirerExt = TechnoExt::ExtMap.Find(pThis); | ||
|
||
if (!pFirerExt->TrajectoryGroup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TrajectoryGroup code snippet should be wrapped into a helper function as it has been used in multiple places
void PhobosTrajectory::UpdateGroupIndex() | ||
{ | ||
const auto pBullet = this->Bullet; | ||
auto& groupData = (*this->TrajectoryGroup)[pBullet->Type->UniqueID]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the key for map could simply be a pointer instead of using its ID, as the Type itself is unique
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is too long! I'll review this much today and look at the rest later.
this->InitialTargetCoord = pBullet->TargetCoords; | ||
|
||
// Special case: Set the target to the ground | ||
if (this->Type->DetonationDistance.Get() <= -1e-10) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this 1e-10
should be a constexpr int
// Target will update location after techno firing, which may result in inaccurate | ||
// target position recorded by the LastTargetCoord in Unlimbo(). Therefore, it's | ||
// necessary to record the position during the first Update(). - CrimRecya | ||
if (this->WaitOneFrame == 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WaitOneFrame
has only three avaliable values. They should be enum class to make their usage more clear to developer
if (horizonDistance > 0) | ||
{ | ||
// Slowly step up | ||
double horizonMult = std::abs(this->MovingVelocity.Z / 64.0) / horizonDistance; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there needs a comment to explain why 64.0 here and beneath
// Check for additional obstacles on the ground | ||
if (this->CheckThroughAndSubjectInCell(MapClass::Instance.GetCellAt(pBullet->Location), pOwner)) | ||
{ | ||
if (32.0 < velocity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
velocity > 32.0
is more readable?
return false; | ||
|
||
// Detonates itself in the next frame | ||
if (velocityCheck == 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, velocityCheck
has limited fixed value of 0
, 1
, 2
, I think it's better to have an enum for it
return BulletVelocity{ 0.4472135954999579392818347337463 * reverseSgnX, 0.8944271909999158785636694674925 * reverseSgnY, 0.0 }; | ||
|
||
// 0.7071067811865475244008443621049 -> 1 / sqrt(2) | ||
return BulletVelocity{ 0.7071067811865475244008443621049 * reverseSgnX, 0.7071067811865475244008443621049 * reverseSgnY, 0.0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function has very many immediate numbers. I suggest to give they aliases by using constexpr
and comments for reason. Otherwise, I'm afraid nobody would know why these numbers should be these values after months.
else if (cliffType == CliffType::Type_2_1) | ||
return BulletVelocity{ shortRightAngledEdge * reverseSgnX, longRightAngledEdge * reverseSgnY, 0.0 }; | ||
|
||
constexpr double hypotenuse = 0.7071067811865475244008443621049; // 1 / sqrt(2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you misunderstood a bit. If you write
constexpr double hypotenuse = 1 / sqrt(2)
-- it will be equal to what you did now, except more readable. constexpr
guarantees you that the result of what's on the right side of equals sign will be available at compile time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MSVC does not support constexpr sqrt
Projectile trajectories
Trajectory
should not be combined with original game's projectile trajectory logics (Arcing
,ROT
,Vertical
orInviso
). 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 unlikeSpeed
used byROT
> 0 projectiles is defined on projectile not weapon.Trajectory=Straight
, it refers to the whole distance speed of the projectile.Trajectory=Bombard
, it refers to the initial speed of the projectile.Trajectory=Missile
, it refers to the final speed of the projectile.Trajectory.Speed
will be fixed at 192 by settingTrajectory.Missile.UniqueCurve=true
.Trajectory=Engrave
, it refers to the horizontal engrave speed of the projectile and it cannot exceed 128. Recommend set as about 40.Trajectory=Parabola
, it refers to the horizontal velocity of the projectile and is only used for modesSpeed
,SpeedAndHeight
, orSpeedAndAngle
.Trajectory=Tracing
, it refers to the moving speed of the projectile.Trajectory.Duration
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.Trajectory=Engrave
, if it is a non positive number, automatically useTrajectory.Engrave.SourceCoord
andTrajectory.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.Trajectory=Tracing
, if set to zero, use weapon'sROF
-10 as the duration. At least 1 frame. If it is negative, do not time it.Trajectory.TolerantTime
controls how long the projectile will detonate after losing the target. If it is 0, it will detonate directly when switching targets.Trajectory.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.Trajectory.BulletROT
controls the rotational speed of the projectile's orientation (facing direction). When it is 0, it will always face the direction defined byTrajectory.BulletFacing
. Otherwise, it will rotate towards the direction defined byTrajectory.BulletFacing
according to this speed.Trajectory.BulletFacing
controls what direction the projectile should face. This has the following 7 modes.Trajectory.BulletROT
is negative, it will only rotate on the horizontal plane.Trajectory.BulletROT
can control the direction.Trajectory.BulletROT
is negative, only the direction on the horizontal plane exists.Trajectory.BulletROT
is negative, it will only rotate on the horizontal plane.Trajectory.BulletROT
is negative, it will only rotate on the horizontal plane.Trajectory.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.Trajectory=Missile
, if the projectile hasn't arrivedTrajectory.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.Trajectory=Tracing
, the projectile will search for new target at the current position of itself.Trajectory.RetargetInterval
controls the interval between each search for a new target again.Trajectory.RetargetHouses
controls the projectile can find new target from which houses.Trajectory.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.Trajectory.PeacefulVanish
controls whether the projectile disappears directly when it is about to detonate, without producing animation or causing damage. The default value isTrajectory=Engrave
orTrajectory.ProximityImpact
not equal to 0 orTrajectory.DisperseCycle
not equal to 0.Trajectory.ApplyRangeModifiers
controls whether any applicable weapon range modifiers from the firer are applied to the projectile. Effective options includeTrajectory.Duration
,Trajectory.DetonationDistance
andTrajectory.EdgeAttenuation
.Trajectory.UseDisperseCoord
controls whether the fire position need to replaced with the FLH of its superior's trajectory, which setTrajectory.RecordSourceCoord
to true. Only takes effect when it is fired from one of theTrajectory.DisperseWeapons
.Trajectory.RecordSourceCoord
controls whether the projectile needs to record the launch position, which will be used for the appropriate weapons inTrajectory.DisperseWeapons
. It can be nested and inherited, which need subordinates to enableTrajectory.UseDisperseCoord
. The default value isTrajectory=Engrave
or have setTrajectory.DisperseWeapons
.Trajectory=Engrave
, it will also be used as a starting point for laser drawing.Trajectory.OffsetCoord
controls the offsets of the target. Projectile will aim at the relative coordinates of the target to attack. It also supportsInaccurate
andTrajectory.LeadTimeCalculate
on this basis.Trajectory=Engrave
orTrajectory=Tracing
, these are invalid.Trajectory.RotateCoord
controls whether to rotate the projectile's firing direction within the angle bisector ofTrajectory.OffsetCoord
(orTrajectory.Missile.PreAimCoord
inTrajectory=Missile
) according to the most superior's weapon'sBurst
. Set to 0 to disable this function. Negative values will reverse the direction of rotation.Trajectory.MirrorCoord
controls whetherTrajectory.OffsetCoord
(andTrajectory.Missile.PreAimCoord
inTrajectory=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 byTrajectory.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 calculatingTrajectory.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.Trajectory=Straight
, ifTrajectory.ApplyRangeModifiers
is set to true, any applicable weapon range modifiers from the firer are applied here as well. By settingTrajectory.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.Trajectory=Bombard
andTrajectory=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 forTrajectory.DisperseWeapons
andAirburstWeapon
).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. IfTrajectory.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.Trajectory=Bombard
orTrajectory=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
:Trajectory.RetargetRadius
value unless necessary.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.Inaccurate
,BallisticScatter.Min
,BallisticScatter.Max
,Gravity
,SubjectToGround
.Straight
Bombard
Missile
Engrave
Parabola
Tracing
Inaccurate
BallisticScatter
Gravity
SubjectToGround
ProjectileRange(Weapon's)
Trajectory.Speed
Trajectory.Duration
Trajectory.TolerantTime
Trajectory.CreateCapacity
Trajectory.BulletROT
Trajectory.BulletFacing
Trajectory.RetargetRadius
Trajectory.Synchronize
Trajectory.PeacefulVanish
Trajectory.ApplyRangeModifiers
Trajectory.UseDisperseCoord
Trajectory.RecordSourceCoord
Trajectory.OffsetCoord
Trajectory.RotateCoord
Trajectory.MirrorCoord
Trajectory.AxisOfRotation
Trajectory.LeadTimeCalculate
Trajectory.LeadTimeMaximum
Trajectory.DetonationDistance
Trajectory.TargetSnapDistance
Trajectory.EarlyDetonation
Trajectory.DetonationHeight
Trajectory.AllowFirerTurning
SubjectToGround
can cause the projectile withTrajectory=Straight
during the entire process or the projectile withTrajectory=Bombard
during the ascent phase to detonate prematurely due to impact with the ground.Trajectory.Missile.UniqueCurve
will ignore all of these settings.Trajectory.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.)Trajectory.PassDetonateWarhead
defines the warhead detonated byTrajectory.PassDetonate
. If not set, use the original warhead of the projectile.Trajectory.PassDetonateDamage
defines the damage caused byTrajectory.PassDetonateWarhead
. If not set, use the original damage of the projectile.Trajectory.PassDetonateDelay
controls the delay for detonating the warhead defined byTrajectory.PassDetonateWarhead
.Trajectory.PassDetonateInitialDelay
controls the initial delay for detonating the warhead defined byTrajectory.PassDetonateWarhead
.Trajectory.PassDetonateLocal
controls whetherTrajectory.PassDetonateWarhead
and weapon'sWarhead
are always detonate at ground level.Trajectory.ProximityImpact
controls the initial proximity fuse times. When there are enough remaining times and the projectile approaches another valid target, it will detonate a warhead defined byTrajectory.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'sWarhead
with lowVersus
only to aim at the target, and use theTrajectory.ProximityWarhead
to causing actual harm. (You can use this to cause non repeated damage to all units encountered during the flight of the projectile.)Trajectory.ProximityWarhead
defines the warhead detonated byTrajectory.ProximityImpact
. If not set, use the original warhead of the projectile.Trajectory.ProximityDamage
defines the damage caused byTrajectory.ProximityWarhead
. If not set, use the original damage of the projectile.Trajectory.ProximityRadius
controls the range of proximity fuse. It can NOT be set as a negative value.Trajectory.ProximityDirect
controls whether let the target receive damage instead of detonating the warhead.Trajectory.ProximityMedial
controls whether to detonateTrajectory.ProximityWarhead
at the bullet's location rather than the proximity target's location. IfTrajectory.ProximityDirect
is set to true, this will only affect the calculation result ofTrajectory.DamageEdgeAttenuation
.Trajectory.ProximityAllies
controls whether allies will also trigger the proximity fuse.Trajectory.ProximityFlight
controls whether to count units in the air.Trajectory.ThroughVehicles
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 haveTrajectory.ProximityImpact
times, it will also detonate aTrajectory.ProximityWarhead
at the location of the obstacle. Before the projectile being blocked,Trajectory.ProximityImpact
will also not cause damage to vehicles or aircrafts.Trajectory.ThroughBuilding
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 haveTrajectory.ProximityImpact
times, it will also detonate aTrajectory.ProximityImpact
at the location of the obstacle. Before the projectile being blocked,Trajectory.ProximityImpact
will also not cause damage to buildings.Trajectory.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.Trajectory.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
:Trajectory.PassDetonateWarhead
andTrajectory.ProximityWarhead
must be listed in[Warheads]
for them to work.Trajectory.ProximityRadius
value unless necessary.SubjectToBuildings
andTrajectory.ThroughBuilding
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 ifTrajectory.ProximityImpact
is set.Trajectory.PassDetonate
is periodically effect andTrajectory.ProximityImpact
is once per person effect.Trajectory.ProximityImpact
is set to non-zero, the default value ofTrajectory.PeacefulVanish
will be changed.Trajectory.DisperseWeapons
defines the dispersal weapons of the projectile.Trajectory.DisperseBursts
defines how many corresponding weapons each time the projectile will fire. When the quantity is lower thanTrajectory.DisperseWeapons
, the last value in the list will be used.Trajectory.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.Trajectory.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.Trajectory.DisperseCycle
controls how many rounds of weapons the projectile can fire, zero will not fire weapons, and negative numbers are considered infinite.Trajectory.DisperseInitialDelay
controls the initial delay for dispersing the weapons defined byTrajectory.DisperseWeapons
.Trajectory.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.Trajectory.DisperseSeparate
controls whether the projectile no longer fire all the weapons inTrajectory.DisperseWeapons
at once and instead fire a group of weapons in the list order, followingTrajectory.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 inTrajectory.DisperseWeapons
order. Otherwise, fire all weapons simultaneously and fire sequentially inTrajectory.DisperseCounts
order.Trajectory.DisperseRetarget
controls whether the Disperse weapons will find new targets on their own. Using theRange
,CanTarget
,CanTargetHouses
, requiredAttachedEffects
of weapons to search new targets.Trajectory.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.Trajectory.DisperseTendency
controls whether the Disperse weapons will choose the original target as the first new target in each group of weapons.Trajectory.DisperseHolistic
controls whether the Disperse weapons will choose targets that are in different states from the original target (in air and on ground).Trajectory.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.Trajectory.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.)Trajectory.DisperseSuicide
controls whether the projectile will self destruct after the number of times it spreads the weapon has been exhausted.Trajectory.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. WhenTrajectory=Engrave
orTrajectory=Tracing
, the default is true, while others are false.Trajectory.DisperseFaceCheck
controls whether the projectile will check its orientation before firing the weapons. Ignore this ifTrajectory.BulletFacing=Velocity
orTrajectory.BulletFacing=Spin
.Trajectory.DisperseForceFire
controls whether still fire disperse weapon when the projectile itself has no target or whenTrajectory.Synchronize=true
and the target of the projectile is beyond the weapon's range.Trajectory.DisperseCoord
controls the FLH where the projectile fires the weapon when setTrajectory.DisperseFromFirer
to false.In
rulesmd.ini
:Trajectory.DisperseWeapons
must be listed in[WeaponTypes]
for them to work.Trajectory.DisperseRetarget=true
, also make sure you setTrajectory.DisperseWeapons
a lowRange
value unless necessary.Trajectory.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.Trajectory.DisperseRetarget
will not change the true target of the projectile itself.Trajectory.DisperseCycle
is set to non-zero, the default value ofTrajectory.PeacefulVanish
will be changed.Straight 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 byTrajectory.DetonationDistance
. Note that ifTrajectory.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 settingSubjectToCliffs
to true. It can be cancelled by setting as a non positive integer. It will be forcibly cancelled by settingTrajectory.Speed
above 256. IfTrajectory.PassDetonateLocal
is set to true at the same time, the vertical speed will not be limited.In
rulesmd.ini
:Bombard trajectory
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.Trajectory.Bombard.FallPercentShift
. If set to 0%, random shift will be disabled.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. IfTrajectory.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 useTrajectory.Speed
. Can't work whenTrajectory.Bombard.FreeFallOnTarget
set to true.Trajectory.Bombard.TurningPointAnims
, if set, will play an anim when the projectile reaches the turning point. IfTrajectory.Bombard.FreeFallOnTarget
is set to true, it'll be spawned above the target with the projectile together. IfTrajectory.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
:Missile trajectory
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 inTrajectory.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 whetherTrajectory.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 beTrajectory.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 reachingTrajectory.Missile.PreAimCoord
and completing the first turn, the projectile will lock the direction of motion without further adjustment.Trajectory.Missile.CruiseEnable
controls whether after reachingTrajectory.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 timeTrajectory.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 calculateTrajectory.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
:Gravity
. If you are sure that you do not need it to be affected by it, you can setGravity=0
separately.Trajectory.Missile.CruiseUnableRange
is too small, it may cause the projectile to be permanently stay in cruise mode.Engrave trajectory
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. IfTrajectory.Duration
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.IsLaser
controls whether laser drawing is required.Trajectory.Engrave.IsIntense
controls whether the engrave laser will be brighter and thicker.Trajectory.Engrave.IsHouseColor
controls whether set the engrave laser to draw using player's house color.Trajectory.Engrave.IsSingleColor
controls whether set the engrave laser to draw using onlyTrajectory.Engrave.LaserInnerColor
.Trajectory.Engrave.LaserInnerColor
controls the inner color of the engrave laser.Trajectory.Engrave.LaserOuterColor
controls the outer color of the engrave laser.Trajectory.Engrave.LaserOuterSpread
controls the spread color of the engrave laser.Trajectory.Engrave.LaserThickness
controls the thickness of the engrave laser.Trajectory.Engrave.LaserDuration
controls the duration of the engrave laser.Trajectory.Engrave.LaserDelay
controls how often to draw the engrave laser.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.IsIntense
andTrajectory.Engrave.LaserThickness
require setTrajectory.Engrave.IsHouseColor
orTrajectory.Engrave.IsSingleColor
to true to take effect.Trajectory=Engrave
withTrajectory.PassDetonateWarhead
is more cost-effective than usingTrajectory.DisperseWeapons
. If you need the laser to be blocked by the Fire Storm Wall, you can try using the latter.Trajectory.PeacefulVanish
will be changed when using this type of trajectory.Parabola trajectory
Arcing
with different enhanced functions.Trajectory.Parabola.OpenFireMode
controls how should the projectile be launched. This has the following 6 modes.Trajectory.Speed
and target coordinates as calculation conditions.Trajectory.Parabola.ThrowHeight
and target coordinates as calculation conditions, i.e. the detonation time of the projectile is relatively fixed.Trajectory.Parabola.LaunchAngle
and target coordinates as calculation conditions.Trajectory.Speed
andTrajectory.Parabola.ThrowHeight
as calculation conditions, i.e. the trajectory will only undergo altitude changes with the height of the target.Trajectory.Parabola.ThrowHeight
andTrajectory.Parabola.LaunchAngle
as calculation conditions, i.e. the trajectory will change horizontally with the height of the target.Trajectory.Speed
andTrajectory.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 modesHeight
,SpeedAndHeight
, orHeightAndAngle
. 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 modesAngle
,HeightAndAngle
, orSpeedAndAngle
. Only supports -90.0 ~ 90.0 (Cannot use boundary values) in ModeAngle
orSpeedAndAngle
, and 0.0 ~ 90.0 (Cannot use boundary values) in ModeHeightAndAngle
.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=Angle
, the performance consumption is high, and may have no solution. It is not recommended to enableSubjectToCliffs
or enableAA
with a smallerMinimumRange
when using this mode.Trajectory.DetonationDistance
do not conflict withTrajectory.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 setTrajectory.DetonationDistance
to a non positive value.Tracing trajectory
Trajectory.Tracing.TraceMode
controls how should the projectile trace the target. This is used to calculate coordinate axis ofTrajectory.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.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 whenTrajectory.Tracing.TraceMode
isRotateCW
orRotateCCW
.Trajectory.Tracing.CreateCoord
controls the generate position. Not related toTrajectory.Tracing.TraceMode
.Trajectory.Tracing.AttachCoord
controls the tracing position on its target, useTrajectory.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.StableRotation
need to cooperate withTrajectory.CreateCapacity
records to take effect.Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores