Skip to content
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

Faking Digital Display of Health #1418

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
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
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ This page lists all the individual contributions to the project by their author.
- **Ollerus**
- Build limit group enhancement
- Customizable rocker amplitude
- Allow faking digital display for `InfoType=Health`
- **handama** - AI script action to jump back to previous script
- **TaranDahl (航味麻酱)**
- Skirmish AI "sell all buildings and set all technos to hunt" behavior dehardcode
Expand Down
62 changes: 34 additions & 28 deletions docs/User-Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ IngameScore.LoseTheme= ; Soundtrack theme ID
*Default configuration of digital display using example shapes from [Phobos supplementaries](https://github.com/Phobos-developers/PhobosSupplementaries).*

- You can now configure various types of numerical counters to be displayed over Techno to represent its attributes, such as health points or shield points.
- `Anchor.Horizontal` and `Anchor.Vertical` set the anchor point from which the display is drawn (depending on `Align`) relative to unit's center/selection box. For buildings, `Anchor.Building` is used instead.
- `Anchor.Horizontal` and `Anchor.Vertical` set the anchor point from which the display is drawn (depending on `Align`) relative to unit's center/selection box. For buildings, `Anchor.Building` is used instead.
- `Offset` and `Offset.ShieldDelta` (the latter applied when a shield is active) can be used to further modify the position.
- By default, values are displayed in `current/maximum` format (i.e. 20/40). `HideMaxValue=yes` will make the counter show only the current value (i.e. 20). `Percentage=yes` changes the format to `percent%` (i.e. 50%).
- `CanSee` and `CanSee.Observer` can limit visibility to specific players.
Expand All @@ -46,50 +46,56 @@ IngameScore.LoseTheme= ; Soundtrack theme ID
- Default `Shape.Spacing` for buildings is `4,-2`, `4,0` for others.
- `ValueScaleDivisor` can be used to adjust scale of displayed values. Both the current & maximum value will be divided by the integer number given, if higher than 1.

- If a TechnoType has a DigitalDisplayType with `InfoType=Health`, it's allowed to display fake values to enemy players.
- `DigitalDisplay.Health.FakeStrength`, if set, will be used as the maximum value of health display. The current value will be displayed as the percentage of its current health multiplies the new maximum value.
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure what is the use of this tag? IMO it makes sense to almost always have digital display to display the disguise target's strength.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This can be used in cases where you want to cheat your enemies. For example, there's a decoy type of units which only have half of the strength as the original one, so we can use this tag to fake it like the real ones.

Copy link
Member

Choose a reason for hiding this comment

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

Won't they just disguise as the main unit and automatically inherit it's display of strength?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if I explained clearly, but I meant something like Nod's Decoy Army in CnC3, which is unit with same appearance but weaker in order to confuse enemies and attract firepower. Disguise as main unit won't work for decoys of VehicleTypes, also using value instead of reading from another TechnoType allows more customization.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I understood that. IMO it's better to fix disguise logic to work with vehicles and ensure disguising can work for decoy purposes (I know for sure people already use it like this using Phobos logics). If that is done, I feel like there would be no use case for such tag.

Copy link
Member

Choose a reason for hiding this comment

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

If I recall correctly, @Otamaa has vehicle disguising fixed in his fork.

- `DigitalDisplay.Health.FakeAtDisguise`, if set to true on an InfantryType with Disguise, will use the disguised TechnoType's `Strength` value as the maximum value of health display. The current value will be displayed as the percentage of its current health multiplies the new maximum value. This will be applied before `DigitalDisplay.Health.FakeStrength`.

In `rulesmd.ini`:
```ini
[DigitalDisplayTypes]
0=SOMEDIGITALDISPLAYTYPE

[AudioVisual]
Buildings.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Infantry.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Vehicles.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Aircraft.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Buildings.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Infantry.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Vehicles.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes
Aircraft.DefaultDigitalDisplayTypes= ; list of DigitalDisplayTypes

[SOMEDIGITALDISPLAYTYPE] ; DigitalDisplayType
[SOMEDIGITALDISPLAYTYPE] ; DigitalDisplayType
; Generic
InfoType=Health ; Displayed value enumeration (health|shield|ammo|mindcontrol|spawns|passengers|tiberium|experience|occupants|gattlingstage)
Offset=0,0 ; integers - horizontal, vertical
Offset.ShieldDelta= ; integers - horizontal, vertical
Align=right ; Text alignment enumeration (left|right|center/centre)
Anchor.Horizontal=right ; Horizontal position enumeration (left|center/centre|right)
Anchor.Vertical=top ; Vertical position enumeration (top|center/centre|bottom)
Anchor.Building=top ; Hexagon vertex enumeration (top|lefttop|leftbottom|bottom|rightbottom|righttop)
Percentage=false ; boolean
HideMaxValue=false ; boolean
VisibleToHouses=owner ; Affected house enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
VisibleToHouses.Observer=true ; boolean
ValueScaleDivisor=1 ; integer
InfoType=Health ; Displayed value enumeration (health|shield|ammo|mindcontrol|spawns|passengers|tiberium|experience|occupants|gattlingstage)
Offset=0,0 ; integers - horizontal, vertical
Offset.ShieldDelta= ; integers - horizontal, vertical
Align=right ; Text alignment enumeration (left|right|center/centre)
Anchor.Horizontal=right ; Horizontal position enumeration (left|center/centre|right)
Anchor.Vertical=top ; Vertical position enumeration (top|center/centre|bottom)
Anchor.Building=top ; Hexagon vertex enumeration (top|lefttop|leftbottom|bottom|rightbottom|righttop)
Percentage=false ; boolean
HideMaxValue=false ; boolean
VisibleToHouses=owner ; Affected house enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
VisibleToHouses.Observer=true ; boolean
ValueScaleDivisor=1 ; integer
; Text
Text.Color=0,255,0 ; integers - Red, Green, Blue
Text.Color.ConditionYellow=255,255,0 ; integers - Red, Green, Blue
Text.Color.ConditionRed=255,0,0 ; integers - Red, Green, Blue
Text.Background=false ; boolean
Text.Color=0,255,0 ; integers - Red, Green, Blue
Text.Color.ConditionYellow=255,255,0 ; integers - Red, Green, Blue
Text.Color.ConditionRed=255,0,0 ; integers - Red, Green, Blue
Text.Background=false ; boolean
; Shape
Shape= ; filename with .shp extension, if not present, game-drawn text will be used instead
Palette=palette.pal ; filename with .pal extension
Shape.Spacing= ; integers - horizontal, vertical spacing between digits
Shape= ; filename with .shp extension, if not present, game-drawn text will be used instead
Palette=palette.pal ; filename with .pal extension
Shape.Spacing= ; integers - horizontal, vertical spacing between digits

[SOMETECHNOTYPE]
DigitalDisplay.Disable=false ; boolean
DigitalDisplayTypes= ; list of DigitalDisplayTypes
DigitalDisplay.Disable=false ; boolean
DigitalDisplayTypes= ; list of DigitalDisplayTypes
DigitalDisplay.Health.FakeStrength=-1 ; integer
DigitalDisplay.Health.FakeAtDisguise=true ; boolean
```

In `RA2MD.ini`:
```ini
[Phobos]
DigitalDisplay.Enable=false ; boolean
DigitalDisplay.Enable=false ; boolean
```

```{note}
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ New:
- Allow infantry to use land sequences in water (by Starkku)
- `<Player @ X>` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku)
- Allow customizing charge turret delays per burst on a weapon (by Starkku)
- Allow faking digital display for `InfoType=Health` (by Ollerus)

Vanilla fixes:
- Allow AI to repair structures built from base nodes/trigger action 125/SW delivery in single player missions (by Trsdy)
Expand Down
23 changes: 23 additions & 0 deletions src/Ext/Techno/Body.Visuals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ void TechnoExt::GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType
{
value = pThis->Health;
maxValue = pType->Strength;

if (!pThis->Owner->IsAlliedWith(HouseClass::CurrentPlayer))
GetDigitalDisplayFakeHealth(pThis, value, maxValue);

break;
}
case DisplayInfoType::Shield:
Expand Down Expand Up @@ -465,3 +469,22 @@ void TechnoExt::GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType
}
}
}

void TechnoExt::GetDigitalDisplayFakeHealth(TechnoClass* pThis, int& value, int& maxValue)
{
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());
int newMaxValue = pTypeExt->DigitalDisplay_Health_FakeStrength;

if (pThis->Disguised && pTypeExt->DigitalDisplay_Health_FakeAtDisguise)
{
if (const auto pType = TechnoTypeExt::GetTechnoType(pThis->Disguise))
newMaxValue = pType->Strength;
}

if (newMaxValue >= 0)
{
double ratio = static_cast<double>(value) / maxValue;
value = static_cast<int>(ratio * newMaxValue);
maxValue = newMaxValue;
}
}
1 change: 1 addition & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class TechnoExt
static Point2D GetBuildingSelectBracketPosition(TechnoClass* pThis, BuildingSelectBracketPosition bracketPosition);
static void ProcessDigitalDisplays(TechnoClass* pThis);
static void GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType, int& value, int& maxValue);
static void GetDigitalDisplayFakeHealth(TechnoClass* pThis, int& value, int& maxValue);

// WeaponHelpers.cpp
static int PickWeaponIndex(TechnoClass* pThis, TechnoClass* pTargetTechno, AbstractClass* pTarget, int weaponIndexOne, int weaponIndexTwo, bool allowFallback = true, bool allowAAFallback = true);
Expand Down
6 changes: 6 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,9 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->Wake_Grapple.Read(exINI, pSection, "Wake.Grapple");
this->Wake_Sinking.Read(exINI, pSection, "Wake.Sinking");

this->DigitalDisplay_Health_FakeStrength.Read(exINI, pSection, "DigitalDisplay.Health.FakeStrength");
this->DigitalDisplay_Health_FakeAtDisguise.Read(exINI, pSection, "DigitalDisplay.Health.FakeAtDisguise");

// Ares 0.2
this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius");

Expand Down Expand Up @@ -831,6 +834,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->Wake)
.Process(this->Wake_Grapple)
.Process(this->Wake_Sinking)

.Process(this->DigitalDisplay_Health_FakeStrength)
.Process(this->DigitalDisplay_Health_FakeAtDisguise)
;
}
void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
Expand Down
5 changes: 5 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ class TechnoTypeExt
std::vector<std::vector<CoordStruct>> DeployedWeaponBurstFLHs;
std::vector<std::vector<CoordStruct>> EliteDeployedWeaponBurstFLHs;

Valueable<int> DigitalDisplay_Health_FakeStrength;
Valueable<bool> DigitalDisplay_Health_FakeAtDisguise;

ExtData(TechnoTypeClass* OwnerObject) : Extension<TechnoTypeClass>(OwnerObject)
, HealthBar_Hide { false }
Expand Down Expand Up @@ -450,6 +452,9 @@ class TechnoTypeExt
, Wake { }
, Wake_Grapple { }
, Wake_Sinking { }

, DigitalDisplay_Health_FakeStrength { -1 }
, DigitalDisplay_Health_FakeAtDisguise { true }
{ }

virtual ~ExtData() = default;
Expand Down
Loading