Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1517b01
initial
DeathFishAtEase May 15, 2026
72e1b61
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase May 24, 2026
a16fdf6
fix `AlternateFLH`
DeathFishAtEase May 27, 2026
9b93471
note the occupied building
DeathFishAtEase May 27, 2026
219e3e3
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase May 27, 2026
15ec06d
FrozenBurstIndex
DeathFishAtEase May 27, 2026
5142205
Merge remote-tracking branch 'Phobos-developers/develop' into proj/La…
DeathFishAtEase May 30, 2026
5db54d9
occupied building fallback
DeathFishAtEase May 30, 2026
62fdeea
Revert "note the occupied building"
DeathFishAtEase May 30, 2026
95029f7
Simplify the `DiskLaser_Update_ActivateMainBeam_Tracking` function
DeathFishAtEase May 30, 2026
0d7f5c5
add `LaserPositionUpdate.StopOnFirerConvert`
DeathFishAtEase May 31, 2026
b86496d
Optimize code style
NetsuNegi May 31, 2026
1244a7a
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase Jun 2, 2026
04ccc0b
update docs - title level & add link
DeathFishAtEase Jun 2, 2026
7cde274
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase Jun 5, 2026
79d3d7c
Merge branch 'develop' into LaserPositionUpdate
Coronia Jun 6, 2026
eed7ecc
cleanup
Coronia Jun 6, 2026
28f032a
Update Hooks.LaserDraw.cpp
NetsuNegi Jun 7, 2026
b9e03ae
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase Jun 14, 2026
12dbdb7
Add CREDITS
DeathFishAtEase Jun 14, 2026
4ee35e7
Merge remote-tracking branch 'Phobos-developers/develop' into LaserPo…
DeathFishAtEase Jul 6, 2026
451fa2c
Try to return and erase at an earlier position
DeathFishAtEase Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ This page lists all the individual contributions to the project by their author.
- Customize the step limit of the credits indicator
- Disable the credits indicator smooth transition
- Add `selling`, `undeploying` and `harvesting` conditions to `DiscardOn`
- Allow Laser drawing position update
- **Ollerus**:
- Build limit group enhancement
- Customizable rocker amplitude
Expand Down
30 changes: 30 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -3081,6 +3081,36 @@ UnlimboDetonate.KeepSelected=true ; boolean

## Weapons

### Allow Laser drawing position update

- Now you can define via `LaserPositionUpdate` whether the endpoints of a laser drawing are updated during its duration.
- `None`: No update.
- `Firer`: The start point follows the firer's FLH; if the firer dies, the update stops.
- Since the FLH of `DiskLaser` actually determines the center of the ring, in this scenario, during the update process, the direction of the line connecting the beam's starting point to the center is fixed relative to the ground and the distance is constant - that is, the starting point will still remain on the ring.
- `Target`: The end point follows the target; if the target object dies, the update stops.
- `All`: Equivalent to specifying both `Firer` and `Target`.
- `LaserPositionUpdate.StopOnFirerConvert` determines whether the laser source stops updating when the firer transforms. If set to false (default), the laser will continue to update using the transformed unit's corresponding parameters.

```{note}
For a sub-weapon created by `ShrapnelWeapon` or `AirburstWeapon`, its start point is the position where the parent weapon detonates, not the firer's FLH.
- If `Firer` is set, it will be treated as `None`.
- If `All` is set, it will be treated as `Target`.
```

In `rulesmd.ini`:
```ini
[AudioVisual]
LaserPositionUpdate.StopOnFirerConvert=false ; boolean

[SOMEWEAPON] ; WeaponType with IsLaser=yes or DiskLaser=yes
LaserPositionUpdate=none ; Position Follow Enumeration (none|firer|target|all)
LaserPositionUpdate.StopOnFirerConvert=false ; boolean, default to [AudioVisual] -> LaserPositionUpdate.StopOnFirerConvert
```

```{warning}
If the weapon sets this logic to a non-`None` value while also using other logics that change the drawing position, such as `FlakScatter` and `VisualScatter`, then after initially drawing the laser according to those other logics, the drawing position will be forced to change due to the update rules.
```

### AreaFire target customization

- You can now specify how AreaFire weapon picks its target. By default it targets the base cell the firer is currently on, but this can now be changed to fire on the firer itself or at a random cell within the radius of the weapon's `Range` by setting `AreaFire.Target` to `self` or `random` respectively.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ HideShakeEffects=false ; boolean
- [Customize the step limit of the credits indicator](User-Interface.md#customize-the-step-limit-of-the-credits-indicator) (by Noble_Fish)
- [Disable the credits indicator smooth transition](User-Interface.md#disable-the-credits-indicator-smooth-transition) (by Noble_Fish)
- Add `selling`, `undeploying` and `harvesting` conditions to `DiscardOn` (by Noble_Fish)
- [Allow Laser drawing position update](New-or-Enhanced-Logics.md#allow-laser-drawing-position-update) (by Noble_Fish)

#### Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
32 changes: 30 additions & 2 deletions src/Ext/Bullet/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
#include <Ext/EBolt/Body.h>
#include <New/Entity/LaserTrailClass.h>

namespace LaserRT
{
void SetLaserTrackingData(LaserDrawClass* pLaser, TechnoClass* pShooter, AbstractClass* pTarget, int weaponIdx, PositionFollow mode, bool ignoreShooter);
}

BulletExt::ExtContainer BulletExt::ExtMap;

void BulletExt::ExtData::InterceptBullet(TechnoClass* pSource, BulletClass* pInterceptor)
Expand Down Expand Up @@ -204,10 +209,12 @@ inline void BulletExt::SimulatedFiringLaser(BulletClass* pBullet, HouseClass* pH

const auto pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon);

LaserDrawClass* pLaser = nullptr;

if (pWeapon->IsHouseColor || pWeaponExt->Laser_IsSingleColor)
{
const auto black = ColorStruct { 0, 0, 0 };
const auto pLaser = GameCreate<LaserDrawClass>(pBullet->SourceCoords, BulletExt::GetTargetCoordsForFiring(pBullet),
pLaser = GameCreate<LaserDrawClass>(pBullet->SourceCoords, BulletExt::GetTargetCoordsForFiring(pBullet),
((pWeapon->IsHouseColor && pHouse) ? pHouse->LaserColor : pWeapon->LaserInnerColor), black, black, pWeapon->LaserDuration);

pLaser->IsHouseColor = true;
Expand All @@ -216,13 +223,34 @@ inline void BulletExt::SimulatedFiringLaser(BulletClass* pBullet, HouseClass* pH
}
else
{
const auto pLaser = GameCreate<LaserDrawClass>(pBullet->SourceCoords, BulletExt::GetTargetCoordsForFiring(pBullet),
pLaser = GameCreate<LaserDrawClass>(pBullet->SourceCoords, BulletExt::GetTargetCoordsForFiring(pBullet),
pWeapon->LaserInnerColor, pWeapon->LaserOuterColor, pWeapon->LaserOuterSpread, pWeapon->LaserDuration);

pLaser->IsHouseColor = false;
pLaser->Thickness = 3;
pLaser->IsSupported = false;
}

// LaserPositionUpdate
if (pLaser)
{
auto mode = pWeaponExt->LaserPositionUpdate;
const bool isSplit = BulletExt::ExtMap.Find(pBullet)->IsSplitFromAirburst;

if (isSplit)
{
if (mode == PositionFollow::Firer)
mode = PositionFollow::None;
else if (mode == PositionFollow::All)
mode = PositionFollow::Target;
}

if (mode != PositionFollow::None)
{
auto const pTarget = abstract_cast<ObjectClass*>(pBullet->Target);
LaserRT::SetLaserTrackingData(pLaser, pBullet->Owner, pTarget, 0, mode, isSplit);
}
}
}

// Make sure pBullet and pBullet->WeaponType is not empty before call
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Bullet/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class BulletExt
int ParabombFallRate;
bool IsInstantDetonation;
double FirepowerMult;
bool IsSplitFromAirburst = false;

TrajectoryPointer Trajectory;

Expand Down
1 change: 1 addition & 0 deletions src/Ext/Bullet/Hooks.DetonateLogics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,7 @@ DEFINE_HOOK(0x469EC0, BulletClass_Logics_AirburstWeapon, 0x6)
}

BulletExt::ExtMap.Find(pBullet)->FirepowerMult = pBulletExt->FirepowerMult;
BulletExt::ExtMap.Find(pBullet)->IsSplitFromAirburst = true;
BulletExt::SimulatedFiringUnlimbo(pBullet, pOwner, pWeapon, coords, headToTarget, radialFire);
BulletExt::SimulatedFiringEffects(pBullet, pOwner, nullptr, useFiringEffects, true);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->AirstrikeLineColor.Read(exINI, GameStrings::AudioVisual, "AirstrikeLineColor");
this->AirstrikeLineZAdjust.Read(exINI, GameStrings::AudioVisual, "AirstrikeLineZAdjust");

this->LaserPositionUpdate_StopOnFirerConvert.Read(exINI, GameStrings::AudioVisual, "LaserPositionUpdate.StopOnFirerConvert");
this->LaserZAdjust.Read(exINI, GameStrings::AudioVisual, "LaserZAdjust");
this->EBoltZAdjust.Read(exINI, GameStrings::AudioVisual, "EBoltZAdjust");
this->EBoltZAdjust_ClampInitialDepthForBuilding.Read(exINI, GameStrings::AudioVisual, "EBoltZAdjust.ClampInitialDepthForBuilding");
Expand Down Expand Up @@ -617,6 +618,7 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->ColorAddUse8BitRGB)
.Process(this->AirstrikeLineColor)
.Process(this->AirstrikeLineZAdjust)
.Process(this->LaserPositionUpdate_StopOnFirerConvert)
.Process(this->LaserZAdjust)
.Process(this->EBoltZAdjust)
.Process(this->EBoltZAdjust_ClampInitialDepthForBuilding)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class RulesExt
Valueable<ColorStruct> AirstrikeLineColor;
Valueable<int> AirstrikeLineZAdjust;

Valueable<bool> LaserPositionUpdate_StopOnFirerConvert;
Valueable<int> LaserZAdjust;
Valueable<int> EBoltZAdjust;
Valueable<bool> EBoltZAdjust_ClampInitialDepthForBuilding;
Expand Down Expand Up @@ -486,6 +487,7 @@ class RulesExt
, ColorAddUse8BitRGB { false }
, AirstrikeLineColor { { 255, 0, 0 } }
, AirstrikeLineZAdjust { 0 }
, LaserPositionUpdate_StopOnFirerConvert { false }
, LaserZAdjust { 0 }
, EBoltZAdjust { 0 }
, EBoltZAdjust_ClampInitialDepthForBuilding { true }
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WeaponType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->AreaFire_Target.Read(exINI, pSection, "AreaFire.Target");
this->FeedbackWeapon.Read<true>(exINI, pSection, "FeedbackWeapon");
this->Laser_IsSingleColor.Read(exINI, pSection, "IsSingleColor");
this->LaserPositionUpdate.Read(exINI, pSection, "LaserPositionUpdate");
this->LaserPositionUpdate_StopOnFirerConvert.Read(exINI, pSection, "LaserPositionUpdate.StopOnFirerConvert");
this->LaserZAdjust.Read(exINI, pSection, "LaserZAdjust");
this->EBoltZAdjust.Read(exINI, pSection, "EBoltZAdjust");
this->EBoltZAdjust_ClampInitialDepthForBuilding.Read(exINI, pSection, "EBoltZAdjust.ClampInitialDepthForBuilding");
Expand Down Expand Up @@ -244,6 +246,8 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm)
.Process(this->AreaFire_Target)
.Process(this->FeedbackWeapon)
.Process(this->Laser_IsSingleColor)
.Process(this->LaserPositionUpdate)
.Process(this->LaserPositionUpdate_StopOnFirerConvert)
.Process(this->LaserZAdjust)
.Process(this->EBoltZAdjust)
.Process(this->EBoltZAdjust_ClampInitialDepthForBuilding)
Expand Down
7 changes: 7 additions & 0 deletions src/Ext/WeaponType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class WeaponTypeExt
Valueable<AreaFireTarget> AreaFire_Target;
Valueable<WeaponTypeClass*> FeedbackWeapon;
Valueable<bool> Laser_IsSingleColor;
Valueable<PositionFollow> LaserPositionUpdate;
Nullable<bool> LaserPositionUpdate_StopOnFirerConvert;
Nullable<int> LaserZAdjust;
Nullable<int> EBoltZAdjust;
Nullable<bool> EBoltZAdjust_ClampInitialDepthForBuilding;
Expand Down Expand Up @@ -136,6 +138,8 @@ class WeaponTypeExt
, AreaFire_Target { AreaFireTarget::Base }
, FeedbackWeapon {}
, Laser_IsSingleColor { false }
, LaserPositionUpdate { PositionFollow::None }
, LaserPositionUpdate_StopOnFirerConvert {}
, LaserZAdjust {}
, EBoltZAdjust {}
, EBoltZAdjust_ClampInitialDepthForBuilding {}
Expand Down Expand Up @@ -235,4 +239,7 @@ class WeaponTypeExt
static int GetRangeWithModifiers(WeaponTypeClass* pThis, TechnoClass* pFirer);
static int GetRangeWithModifiers(WeaponTypeClass* pThis, TechnoClass* pFirer, int range);
static int GetTechnoKeepRange(WeaponTypeClass* pThis, TechnoClass* pFirer, bool isMinimum);

// Misc/Hooks.LaserDraw.cpp
static void LaserTrackingPointerExpired(void* ptr, bool removed);
};
Loading
Loading