Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2991,6 +2991,36 @@ UnlimboDetonate.KeepSelected=false ; 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 @@ -579,6 +579,7 @@ HideShakeEffects=false ; boolean
- [Allow customizing guard mission retry delay for buildings with weapons](Fixed-or-Improved-Logics.md#armed-building-guard-retry-delay) (by Starkku)
- [Allow `Temporal` warhead to apply ratio and bonus](Fixed-or-Improved-Logics.md#allow-temporal-warhead-to-apply-ratio-and-bonus) (by NetsuNegi)
- Allow enabling a looser movement state check for the `DiscardOn=move` condition of AE to support more usage scenarios (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
36 changes: 34 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 @@ -197,17 +202,22 @@ inline void BulletExt::SimulatedFiringReport(BulletClass* pBullet)
inline void BulletExt::SimulatedFiringLaser(BulletClass* pBullet, HouseClass* pHouse)
{
// Can not use 0x6FD210 because the firer may die
if (!pBullet || !pBullet->WeaponType)
return;

const auto pWeapon = pBullet->WeaponType;

if (!pWeapon->IsLaser)
return;

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 +226,35 @@ 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 && pWeaponExt)
{
auto mode = pWeaponExt->LaserPositionUpdate;
const auto pBulletExt = BulletExt::ExtMap.Find(pBullet);
const bool isSplit = (pBulletExt && pBulletExt->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 @@ -27,6 +27,7 @@
int DamageNumberOffset;
int ParabombFallRate;
bool IsInstantDetonation;
bool IsSplitFromAirburst = false;

TrajectoryPointer Trajectory;

Expand Down Expand Up @@ -72,7 +73,7 @@

static void Detonate(const CoordStruct& coords, TechnoClass* pOwner, int damage, HouseClass* pFiringHouse, AbstractClass* pTarget, bool isBright, WeaponTypeClass* pWeapon, WarheadTypeClass* pWarhead);
static void ApplyArcingFix(BulletClass* pThis, const CoordStruct& sourceCoords, const CoordStruct& targetCoords, BulletVelocity& velocity);
static inline CoordStruct GetTargetCoordsForFiring(BulletClass* pBullet);

Check warning on line 76 in src/Ext/Bullet/Body.h

View workflow job for this annotation

GitHub Actions / build

no definition for inline function 'CoordStruct BulletExt::GetTargetCoordsForFiring(BulletClass *)' [D:\a\Phobos\Phobos\Phobos.vcxproj]

static void SimulatedFiringUnlimbo(BulletClass* pBullet, HouseClass* pHouse, WeaponTypeClass* pWeapon, const CoordStruct& sourceCoords, bool randomVelocity);
static void SimulatedFiringEffects(BulletClass* pBullet, HouseClass* pHouse, ObjectClass* pAttach, bool firingEffect, bool visualEffect);
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 @@ -833,6 +833,7 @@ DEFINE_HOOK(0x469EC0, BulletClass_Logics_AirburstWeapon, 0x6)
coords = MapClass::GetRandomCoordsNear(coords, distance, false);
}

BulletExt::ExtMap.Find(pBullet)->IsSplitFromAirburst = true;
BulletExt::SimulatedFiringUnlimbo(pBullet, pOwner, pWeapon, coords, true);
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 @@ -580,6 +581,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 @@ -461,6 +462,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 @@ -216,6 +218,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 @@ -134,6 +136,8 @@ class WeaponTypeExt
, AreaFire_Target { AreaFireTarget::Base }
, FeedbackWeapon {}
, Laser_IsSingleColor { false }
, LaserPositionUpdate { PositionFollow::None }
, LaserPositionUpdate_StopOnFirerConvert {}
, LaserZAdjust {}
, EBoltZAdjust {}
, EBoltZAdjust_ClampInitialDepthForBuilding {}
Expand Down Expand Up @@ -231,4 +235,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