Skip to content

Commit 913523a

Browse files
authored
2 new tags for hiding the shield bar or recharge shields (#1177)
- `Pips.HideIfNoStrength` can be used to hide the shield's pip frame if the `Strength` is 0. - `SelfHealing.EnabledBy` can be used to control the self-heal of the shield. If the owner has no structures from this list then the shield won't self-heal. [SOMESHIELDTYPE] ; ShieldType name SelfHealing.EnabledBy= ; List of BuildingType names Pips.HideIfNoStrength=false ; boolean <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Shields now have a self-healing feature, enabled by specific building types. - Shields' pip frame will now be hidden if the strength is zero. - **Bug Fixes** - Adjustments made for building weapons, info tip, and reveal production cameo positioning. - Added support for `TurretOffset` for SHP vehicles. - **Documentation** - Updated documentation to reflect new and enhanced logics for shields. - **Credits** - Acknowledged the contribution of an unspecified contributor for the new shield features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent d27a43a commit 913523a

File tree

7 files changed

+59
-3
lines changed

7 files changed

+59
-3
lines changed

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ This page lists all the individual contributions to the project by their author.
137137
- Initial strength for cloned infantry
138138
- Map Events 604 & 605 for checking if a specific Techno enters in a cell
139139
- Warhead that can not kill
140+
- `Pips.HideIfNoStrength` and `SelfHealing.EnabledBy` additions for shields
140141
- **Starkku**:
141142
- Misc. minor bugfixes & improvements
142143
- AI script actions:

docs/New-or-Enhanced-Logics.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,15 @@ SelfHealing=0.0 ; floating point value, percents or
300300
SelfHealing.Rate=0.0 ; floating point value, ingame minutes
301301
SelfHealing.RestartInCombat=true ; boolean
302302
SelfHealing.RestartInCombatDelay=0 ; integer, game frames
303+
SelfHealing.EnabledBy= ; List of BuildingType names
303304
Respawn=0.0 ; floating point value, percents or absolute
304305
Respawn.Rate=0.0 ; floating point value, ingame minutes
305306
BracketDelta=0 ; integer - pixels
306307
Pips=-1,-1,-1 ; integer, frames of pips.shp (zero-based) for Green, Yellow, Red
307308
Pips.Building=-1,-1,-1 ; integer, frames of pips.shp (zero-based) for Green, Yellow, Red
308309
Pips.Background= ; filename - including the .shp/.pcx extension
309310
Pips.Building.Empty= ; integer, frame of pips.shp (zero-based) for empty building pip
311+
Pips.HideIfNoStrength=false ; boolean
310312
IdleAnim= ; AnimationType
311313
IdleAnim.ConditionYellow= ; AnimationType
312314
IdleAnim.ConditionRed= ; AnimationType
@@ -395,6 +397,7 @@ Shield.InheritStateOnReplace=false ; boolean
395397
- If you want shield recovers/respawns 1 HP per time, currently you need to set tag value to any number between 1 and 2, like `1.1`.
396398
- If `SelfHealing.RestartInCombat` is set, self-healing timer pauses and then resumes after `SelfHealing.RestartInCombatDelay` frames have passed when the shield gets damaged.
397399
- `SelfHealing.Rate` and `Respawn.Rate` respect the following settings: 0.0 instantly recovers the shield, other values determine the frequency of shield recovers/respawns in ingame minutes.
400+
- `SelfHealing.EnabledBy` can be used to control the self-heal of the shield. If the owner has no structures from this list then the shield won't self-heal.
398401
- `IdleAnim`, if set, will be played while the shield is intact. This animation is automatically set to loop indefinitely.
399402
- `IdleAnim.ConditionYellow` and `IdleAnim.ConditionRed` can be used to set different animations for when shield health is at or below the percentage defined in `[AudioVisual] -> ConditionYellow/ConditionRed`, respectively. If `IdleAnim.ConditionRed` is not set it falls back to `IdleAnim.ConditionYellow`, which in turn falls back to `IdleAnim`.
400403
- `IdleAnimDamaged`, `IdleAnimDamaged.ConditionYellow` and `IdleAnimDamaged.ConditionRed` are used in an identical manner, but only when health of the object the shield is attached to is at or below `[AudioVisual] -> ConditionYellow`. Follows similar fallback sequence to regular `IdleAnim` variants and if none are set, falls back to the regular `IdleAnim` or variants thereof.
@@ -418,6 +421,7 @@ Shield.InheritStateOnReplace=false ; boolean
418421
- `Pips.Shield` can be used to specify which pip frame should be used as shield strength. If only 1 digit is set, then it will always display that frame, or if 3 digits are set, it will use those if shield's current strength is at or below `ConditionYellow` and `ConditionRed`, respectively. `Pips.Shield.Building` is used for BuildingTypes. -1 as value will use the default frame, whether it is fallback to first value or the aforementioned hardcoded defaults.
419422
- `Pips.Shield.Background` can be used to set the background or 'frame' for non-building pips, which defaults to `pipbrd.shp`. 4th frame is used to display an infantry's shield strength and the 3th frame for other units, or 2nd and 1st respectively if not enough frames are available.
420423
- `Pips.Shield.Building.Empty` can be used to set the frame of `pips.shp` displayed for empty building strength pips, defaults to 1st frame of `pips.shp`.
424+
- `Pips.HideIfNoStrength` can be used to hide the shield's pip frame if the `Strength` is 0.
421425
- The above customizations are also available on per ShieldType basis, e.g `[ShieldType] -> Pips` instead of `[AudioVisual] -> Pips.Shield` and so on. ShieldType settings take precedence over the global ones, but will fall back to them if not set.
422426
- `BracketDelta` can be used as additional vertical offset (negative shifts it up) for shield strength bar. Much like `PixelSelectionBracketDelta`, it is not applied on buildings.
423427
- Warheads have new options that interact with shields. Note that all of these that do not by their very nature require ability to target the shield (such as modifiers like `Shield.Break` or removing / attaching) still require Warhead `Verses` to affect the target unless `EffectsRequireVerses` is set to false on the Warhead.

docs/Whats-New.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ New:
361361
- [Warhead that can not kill](New-or-Enhanced-Logics.md#warhead-that-cannot-kill) (by FS-21)
362362
- [Customize parasite culling targets](Fixed-or-Improved-Logics.md#customizing-parasite-culling-targets) (by NetsuNegi)
363363
- [Overload characteristic dehardcoded](New-or-Enhanced-Logics.md#overload-characteristic-dehardcoded) (by Otamaa)
364-
- RadarInvisible for non-enemy house (By TaranDahl)
364+
- [RadarInvisible for non-enemy house](Fixed-or-Improved-Logics.md#radarinvisible-for-non-enemy-house) (By TaranDahl)
365+
- New `Pips.HideIfNoStrength` and `SelfHealing.EnabledBy` additions for shields (by FS-21)
365366
366367
Vanilla fixes:
367368
- Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl)

src/New/Entity/ShieldClass.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ ShieldClass::ShieldClass(TechnoClass* pTechno, bool isAttached)
3535
, Attached { isAttached }
3636
, SelfHealing_Rate_Warhead { -1 }
3737
, Respawn_Rate_Warhead { -1 }
38+
, IsSelfHealingEnabled { true }
3839
{
3940
this->UpdateType();
4041
this->SetHP(this->Type->InitialStrength.Get(this->Type->Strength));
@@ -97,6 +98,7 @@ bool ShieldClass::Serialize(T& Stm)
9798
.Process(this->Respawn_Rate_Warhead)
9899
.Process(this->LastBreakFrame)
99100
.Process(this->LastTechnoHealthRatio)
101+
.Process(this->IsSelfHealingEnabled)
100102
.Success();
101103
}
102104

@@ -431,8 +433,13 @@ void ShieldClass::AI()
431433
return;
432434

433435
this->OnlineCheck();
434-
this->RespawnShield();
435-
this->SelfHealing();
436+
this->EnabledByCheck();
437+
438+
if (this->IsSelfHealingEnabled)
439+
{
440+
this->RespawnShield();
441+
this->SelfHealing();
442+
}
436443

437444
double ratio = this->Techno->GetHealthPercentage();
438445

@@ -465,6 +472,33 @@ void ShieldClass::CloakCheck()
465472
this->KillAnim();
466473
}
467474

475+
void ShieldClass::EnabledByCheck()
476+
{
477+
if (this->Type->SelfHealing_EnabledBy.empty())
478+
return;
479+
480+
this->IsSelfHealingEnabled = false;
481+
auto const pOwner = this->Techno->Owner;
482+
483+
for (auto const pBuilding : pOwner->Buildings)
484+
{
485+
bool isActive = !(pBuilding->Deactivated || pBuilding->IsUnderEMP()) && pBuilding->IsPowerOnline();
486+
487+
if (this->Type->SelfHealing_EnabledBy.Contains(pBuilding->Type) && isActive)
488+
{
489+
this->IsSelfHealingEnabled = true;
490+
break;
491+
}
492+
}
493+
494+
const auto timer = (this->HP <= 0) ? &this->Timers.Respawn : &this->Timers.SelfHealing;
495+
496+
if (!this->IsSelfHealingEnabled)
497+
timer->Pause();
498+
else
499+
timer->Resume();
500+
}
501+
468502
void ShieldClass::OnlineCheck()
469503
{
470504
if (!this->Type->Powered)
@@ -842,6 +876,9 @@ bool ShieldClass::IsRedSP()
842876

843877
void ShieldClass::DrawShieldBar_Building(const int length, RectangleStruct* pBound)
844878
{
879+
if (this->HP <= 0 && this->Type->Pips_HideIfNoStrength)
880+
return;
881+
845882
Point2D position = { 0, 0 };
846883
const int totalLength = DrawShieldBar_PipAmount(length);
847884
int frame = this->DrawShieldBar_Pip(true);
@@ -881,6 +918,9 @@ void ShieldClass::DrawShieldBar_Building(const int length, RectangleStruct* pBou
881918

882919
void ShieldClass::DrawShieldBar_Other(const int length, RectangleStruct* pBound)
883920
{
921+
if (this->HP <= 0 && this->Type->Pips_HideIfNoStrength)
922+
return;
923+
884924
auto position = TechnoExt::GetFootSelectBracketPosition(Techno, Anchor(HorizontalPosition::Left, VerticalPosition::Top));
885925
const auto pipBoard = this->Type->Pips_Background.Get(RulesExt::Global()->Pips_Shield_Background.Get(FileSystem::PIPBRD_SHP));
886926
int frame;

src/New/Entity/ShieldClass.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class ShieldClass
9999
void OnlineCheck();
100100
void TemporalCheck();
101101
bool ConvertCheck();
102+
void EnabledByCheck();
102103

103104
int DrawShieldBar_Pip(const bool isBuilding) const;
104105
int DrawShieldBar_PipAmount(const int length) const;
@@ -116,6 +117,7 @@ class ShieldClass
116117
bool Available;
117118
bool Attached;
118119
bool AreAnimsHidden;
120+
bool IsSelfHealingEnabled;
119121

120122
double SelfHealing_Warhead;
121123
int SelfHealing_Rate_Warhead;

src/New/Type/ShieldTypeClass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void ShieldTypeClass::LoadFromINI(CCINIClass* pINI)
5858

5959
this->SelfHealing_RestartInCombat.Read(exINI, pSection, "SelfHealing.RestartInCombat");
6060
this->SelfHealing_RestartInCombatDelay.Read(exINI, pSection, "SelfHealing.RestartInCombatDelay");
61+
this->SelfHealing_EnabledBy.Read(exINI, pSection, "SelfHealing.EnabledBy");
6162

6263
this->AbsorbOverDamage.Read(exINI, pSection, "AbsorbOverDamage");
6364
this->BracketDelta.Read(exINI, pSection, "BracketDelta");
@@ -89,6 +90,7 @@ void ShieldTypeClass::LoadFromINI(CCINIClass* pINI)
8990
this->Pips_Background.Read(exINI, pSection, "Pips.Background");
9091
this->Pips_Building.Read(exINI, pSection, "Pips.Building");
9192
this->Pips_Building_Empty.Read(exINI, pSection, "Pips.Building.Empty");
93+
this->Pips_HideIfNoStrength.Read(exINI, pSection, "Pips.HideIfNoStrength");
9294

9395
this->ImmuneToBerserk.Read(exINI, pSection, "ImmuneToBerserk");
9496
this->ImmuneToCrit.Read(exINI, pSection, "ImmuneToCrit");
@@ -117,6 +119,7 @@ void ShieldTypeClass::Serialize(T& Stm)
117119
.Process(this->SelfHealing_Rate)
118120
.Process(this->SelfHealing_RestartInCombat)
119121
.Process(this->SelfHealing_RestartInCombatDelay)
122+
.Process(this->SelfHealing_EnabledBy)
120123
.Process(this->AbsorbOverDamage)
121124
.Process(this->BracketDelta)
122125
.Process(this->ReceivedDamage_Minimum)
@@ -140,6 +143,7 @@ void ShieldTypeClass::Serialize(T& Stm)
140143
.Process(this->Pips_Background)
141144
.Process(this->Pips_Building)
142145
.Process(this->Pips_Building_Empty)
146+
.Process(this->Pips_HideIfNoStrength)
143147
.Process(this->ImmuneToBerserk)
144148
.Process(this->ImmuneToCrit)
145149
.Process(this->Tint_Color)

src/New/Type/ShieldTypeClass.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
2424
Valueable<int> SelfHealing_Rate;
2525
Valueable<bool> SelfHealing_RestartInCombat;
2626
Valueable<int> SelfHealing_RestartInCombatDelay;
27+
ValueableVector<BuildingTypeClass*> SelfHealing_EnabledBy;
2728

2829
Valueable<bool> AbsorbOverDamage;
2930
Valueable<int> BracketDelta;
@@ -51,6 +52,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
5152
Nullable<SHPStruct*> Pips_Background;
5253
Valueable<Vector3D<int>> Pips_Building;
5354
Nullable<int> Pips_Building_Empty;
55+
Valueable<bool> Pips_HideIfNoStrength;
5456
Valueable<bool> ImmuneToCrit;
5557
Valueable<bool> ImmuneToBerserk;
5658

@@ -75,6 +77,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
7577
, SelfHealing_Rate { 0 }
7678
, SelfHealing_RestartInCombat { true }
7779
, SelfHealing_RestartInCombatDelay { 0 }
80+
, SelfHealing_EnabledBy { }
7881
, AbsorbOverDamage { false }
7982
, BracketDelta { 0 }
8083
, IdleAnim_OfflineAction { AttachedAnimFlag::Hides }
@@ -99,6 +102,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
99102
, Pips_Background { }
100103
, Pips_Building { { -1,-1,-1 } }
101104
, Pips_Building_Empty { }
105+
, Pips_HideIfNoStrength { false }
102106
, ImmuneToBerserk { false }
103107
, ImmuneToCrit { false }
104108
, Tint_Color {}

0 commit comments

Comments
 (0)