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

New Infotypes and new display method #1287

Open
wants to merge 30 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0983bf8
Several new Infotypes and a new single frame display method
CrimRecya Jun 23, 2024
6ff1802
Little modify
CrimRecya Jun 25, 2024
662d872
Merge remote-tracking branch 'upstream/develop' into develop-newinfotype
CrimRecya Jun 25, 2024
2b79461
Initialize info
CrimRecya Jun 28, 2024
8502c8b
Merge remote-tracking branch 'upstream/develop' into develop-newinfotype
CrimRecya Jul 14, 2024
91cfb86
Fix reload timer not always stop when no ammo
CrimRecya Jul 14, 2024
5678e4b
Update Body.Visuals.cpp
CrimRecya Sep 3, 2024
518e6c3
Merge branch 'develop' into develop-newinfotype
CrimRecya Sep 3, 2024
68cf051
New function
CrimRecya Sep 3, 2024
28f7b4f
Update docs
CrimRecya Sep 3, 2024
fe88dec
Fix max value
CrimRecya Sep 3, 2024
27fc196
Leave these to customization
CrimRecya Sep 6, 2024
c738f2d
Merge branch 'develop' into develop-newinfotype
CrimRecya Sep 15, 2024
4cd6d5d
Merge branch 'develop' into develop-newinfotype
CrimRecya Sep 18, 2024
34f9d3d
Merge branch 'develop' into develop-newinfotype
CrimRecya Oct 14, 2024
23006a2
Change reload max value
CrimRecya Oct 23, 2024
29451a0
Merge branch 'develop' into develop-newinfotype
CrimRecya Nov 7, 2024
9d39b71
Const auto
CrimRecya Nov 7, 2024
f260915
Const auto
CrimRecya Nov 9, 2024
3285b76
Core
CrimRecya Feb 13, 2025
93b5f06
Check InLimbo
CrimRecya Feb 14, 2025
3b8e0e3
[Vanilla Fix] Fix impassable invisible barrier created by chronospher…
Coronia Feb 19, 2025
06664e9
[Minor] Fix Ammo features and tank bunkers. (#1420)
Fryone Feb 20, 2025
aa4e952
[Minor] Disallow other actions for building in planning mode (#1524)
TaranDahl Feb 20, 2025
83debb7
Merge remote-tracking branch 'upstream/develop' into develop-newinfotype
CrimRecya Feb 20, 2025
a954c83
Merge remote-tracking branch 'upstream/develop' into develop-newinfotype
CrimRecya Feb 24, 2025
886cd12
New `ValueAsTimer`
CrimRecya Feb 24, 2025
783bf21
Fix a typo
CrimRecya Feb 24, 2025
42857d0
Merge remote-tracking branch 'upstream/develop' into develop-newinfotype
CrimRecya Feb 26, 2025
29dcafe
Remove useless
CrimRecya Feb 26, 2025
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 @@ -390,6 +390,7 @@ This page lists all the individual contributions to the project by their author.
- Enhanced Bombard trajectory
- No turret unit turn to the target
- Damage multiplier for different houses
- Several new Infotypes, no display in specific status and a new single frame display method
- **Ollerus**
- Build limit group enhancement
- Customizable rocker amplitude
Expand Down
18 changes: 11 additions & 7 deletions docs/User-Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ IngameScore.LoseTheme= ; Soundtrack theme ID
- 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 and can be turned on or off via a [new hotkey](#toggle-digital-display).
- `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.
- By default, values are displayed in `current/maximum` format (i.e. 20/40). `HideMaxValue=true` will make the counter show only the current value (i.e. 20), the default value is whether the techno is infantry or not. `Percentage=true` changes the format to `percent%` (i.e. 50%). `ValueAsTimer` controls whether the value will be displayed in the form of a timer (i.e. 5:00, 25:00 or 1:00:00).
- `VisibleToHouses` and `VisibleToHouses.Observer` can limit visibility to specific players.
- `VisibleInSpecialState` controls whether this display type will show when the owner is in ironcurtain or is attacked by a temporal weapon.
- The digits can be either a custom shape (.shp) or text drawn using the game font. This depends on whether `Shape` is set.
- `Text.Color`, `Text.Color.ConditionYellow` and `Text.Color.ConditionRed` allow customization of the font color. `Text.Background=yes` will additionally draw a black rectangle background.
- When using shapes, a custom palette can be specified with `Palette`. `Shape.Spacing` controls pixel buffer between characters.
- Frames 0-9 will be used as digits when the owner's health bar is green, 10-19 when yellow, 20-29 when red. For `/` and `%` characters, frame numbers are 30-31, 32-33, 34-35, respectively.
- When using shapes, a custom palette can be specified with `Palette`. `Shape.Spacing` controls pixel buffer between characters. If `Shape.PercentageFrame` set to true, it will only draw one frame that corresponds to total frames by percentage.
- Frames 0-9 will be used as digits when the owner's health bar is green, 10-19 when yellow, 20-29 when red. For `/` and `%` (or `:` if set `ValueAsTimer` to true) characters, frame numbers are 30-31, 32-33, 34-35, respectively.
- Default `Offset.ShieldDelta` for `InfoType=Shield` is `0,-10`, `0,0` for others.
- 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.
- `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. Default to 1 (or 15 when set `ValueAsTimer` to true).

In `rulesmd.ini`:
```ini
Expand All @@ -60,7 +61,7 @@ Aircraft.DefaultDigitalDisplayTypes= ; List of DigitalDisplayTypes

[SOMEDIGITALDISPLAYTYPE] ; DigitalDisplayType
; Generic
InfoType=Health ; Displayed value enumeration (health|shield|ammo|mindcontrol|spawns|passengers|tiberium|experience|occupants|gattlingstage)
InfoType=Health ; Displayed value enumeration (health|shield|ammo|mindcontrol|spawns|passengers|tiberium|experience|occupants|gattlingstage|ROF|Reload|SpawnTimer|GattlingTimer|ProduceCash|PassengerKill|AutoDeath|SuperWeapon|IronCurtain|TemporalLife)
Offset=0,0 ; integers - horizontal, vertical
Offset.ShieldDelta= ; integers - horizontal, vertical
Align=right ; Text alignment enumeration (left|right|center/centre)
Expand All @@ -71,7 +72,9 @@ 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
VisibleInSpecialState=true ; boolean
ValueScaleDivisor= ; integer
ValueAsTimer=false ; boolean
; Text
Text.Color=0,255,0 ; integers - Red, Green, Blue
Text.Color.ConditionYellow=255,255,0 ; integers - Red, Green, Blue
Expand All @@ -81,6 +84,7 @@ Text.Background=false ; boolean
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.PercentageFrame=false ; boolean

[SOMETECHNO] ; TechnoType
DigitalDisplay.Disable=false ; boolean
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ New:
- No turret unit turn to the target (by CrimRecya & TaranDahl)
- Damage multiplier for different houses (by CrimRecya)
- Customizable duration for electric bolts (by Starkku)
- Several new Infotypes, no display in specific status and a new single frame display method (by CrimRecya)

Vanilla fixes:
- Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl)
Expand Down
12 changes: 12 additions & 0 deletions src/Ext/Techno/Body.Internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ CoordStruct TechnoExt::GetSimpleFLH(InfantryClass* pThis, int weaponIndex, bool&
return FLH;
}

void TechnoExt::ExtData::InitializeDisplayInfo()
{
const auto pThis = this->OwnerObject();
const auto pPrimary = pThis->GetWeapon(0)->WeaponType;
pThis->RearmTimer.Start(0);

if (pPrimary && pThis->GetTechnoType()->LandTargeting != LandTargetingType::Land_Not_OK)
pThis->RearmTimer.TimeLeft = pPrimary->ROF;
else if (const auto pSecondary = pThis->GetWeapon(1)->WeaponType)
pThis->RearmTimer.TimeLeft = pSecondary->ROF;
}

Comment on lines +147 to +158
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this for? Why are you explicitly setting RearmTimer on techno creation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Before the techno fires for the first time, RearmTimer is not set, which will not display anything.

void TechnoExt::ExtData::InitializeAttachEffects()
{
if (auto pTypeExt = this->TypeExtData)
Expand Down
217 changes: 190 additions & 27 deletions src/Ext/Techno/Body.Visuals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

#include <TacticalClass.h>
#include <SpawnManagerClass.h>

#include <FactoryClass.h>
#include <SuperClass.h>
#include <Ext/SWType/Body.h>
#include <Ext/House/Body.h>
#include <Utilities/EnumFunctions.h>

void TechnoExt::DrawSelfHealPips(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds)
Expand Down Expand Up @@ -331,18 +334,23 @@ void TechnoExt::ProcessDigitalDisplays(TechnoClass* pThis)
if (!HouseClass::IsCurrentPlayerObserver() && !EnumFunctions::CanTargetHouse(pDisplayType->VisibleToHouses, pThis->Owner, HouseClass::CurrentPlayer))
continue;

if (!pDisplayType->VisibleInSpecialState && (pThis->TemporalTargetingMe || pThis->IsIronCurtained()))
continue;

int value = -1;
int maxValue = -1;
int maxValue = 0;

GetValuesForDisplay(pThis, pDisplayType->InfoType, value, maxValue);

if (value == -1 || maxValue == -1)
if (value <= -1 || maxValue <= 0)
continue;

if (pDisplayType->ValueScaleDivisor > 1)
const auto divisor = pDisplayType->ValueScaleDivisor.Get(pDisplayType->ValueAsTimer ? 15 : 1);

if (divisor > 1)
{
value = Math::max(value / pDisplayType->ValueScaleDivisor, value != 0 ? 1 : 0);
maxValue = Math::max(maxValue / pDisplayType->ValueScaleDivisor, maxValue != 0 ? 1 : 0);
value = Math::max(value / divisor, value ? 1 : 0);
maxValue = Math::max(maxValue / divisor, 1);
}

const bool isBuilding = pThis->WhatAmI() == AbstractType::Building;
Expand Down Expand Up @@ -375,54 +383,51 @@ void TechnoExt::GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType
}
case DisplayInfoType::Shield:
{
if (pExt->Shield == nullptr || pExt->Shield->IsBrokenAndNonRespawning())
const auto pShield = pExt->Shield.get();

if (!pShield || pShield->IsBrokenAndNonRespawning())
return;

value = pExt->Shield->GetHP();
maxValue = pExt->Shield->GetType()->Strength.Get();
value = pShield->GetHP();
maxValue = pShield->GetType()->Strength.Get();
break;
}
case DisplayInfoType::Ammo:
{
if (pType->Ammo <= 0)
return;

value = pThis->Ammo;
maxValue = pType->Ammo;
break;
}
case DisplayInfoType::MindControl:
{
if (pThis->CaptureManager == nullptr)
const auto pCaptureManager = pThis->CaptureManager;

if (!pCaptureManager)
return;

value = pThis->CaptureManager->ControlNodes.Count;
maxValue = pThis->CaptureManager->MaxControlNodes;
value = pCaptureManager->ControlNodes.Count;
maxValue = pCaptureManager->MaxControlNodes;
break;
}
case DisplayInfoType::Spawns:
{
if (pThis->SpawnManager == nullptr || pType->Spawns == nullptr || pType->SpawnsNumber <= 0)
const auto pSpawnManager = pThis->SpawnManager;

if (!pSpawnManager || !pType->Spawns)
return;

value = pThis->SpawnManager->CountAliveSpawns();
value = pSpawnManager->CountAliveSpawns();
maxValue = pType->SpawnsNumber;
break;
}
case DisplayInfoType::Passengers:
{
if (pType->Passengers <= 0)
return;

value = pThis->Passengers.NumPassengers;
maxValue = pType->Passengers;
break;
}
case DisplayInfoType::Tiberium:
{
if (pType->Storage <= 0)
return;

value = static_cast<int>(pThis->Tiberium.GetTotalAmount());
maxValue = pType->Storage;
break;
Expand All @@ -438,13 +443,12 @@ void TechnoExt::GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType
if (pThis->WhatAmI() != AbstractType::Building)
return;

const auto pBuildingType = abstract_cast<BuildingTypeClass*>(pType);
const auto pBuilding = abstract_cast<BuildingClass*>(pThis);
const auto pBuildingType = static_cast<BuildingTypeClass*>(pType);

if (!pBuildingType->CanBeOccupied)
return;

value = pBuilding->Occupants.Count;
value = static_cast<BuildingClass*>(pThis)->Occupants.Count;
maxValue = pBuildingType->MaxNumberOccupants;
break;
}
Expand All @@ -453,10 +457,169 @@ void TechnoExt::GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType
if (!pType->IsGattling)
return;

value = pThis->CurrentGattlingStage;
value = pThis->GattlingValue ? pThis->CurrentGattlingStage + 1 : 0;
maxValue = pType->WeaponStages;
break;
}
case DisplayInfoType::ROF:
{
if (!pThis->IsArmed())
return;

const auto& timer = pThis->RearmTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
break;
}
case DisplayInfoType::Reload:
{
if (pType->Ammo <= 0)
return;

value = (pThis->Ammo >= pType->Ammo) ? 0 : pThis->ReloadTimer.GetTimeLeft();
maxValue = (pThis->Ammo || pType->EmptyReload <= 0) ? pType->Reload : pType->EmptyReload;
break;
}
case DisplayInfoType::SpawnTimer:
{
const auto pSpawnManager = pThis->SpawnManager;

if (!pSpawnManager || !pType->Spawns || pType->SpawnsNumber <= 0)
return;

value = 0;

for (int i = 0; i < pType->SpawnsNumber; i++)
{
const auto pSpawnNode = pSpawnManager->SpawnedNodes[i];

if (pSpawnNode->Status != SpawnNodeStatus::Dead)
continue;

const auto thisValue = pSpawnNode->SpawnTimer.GetTimeLeft();

if (thisValue < value || !value)
value = thisValue;
}

maxValue = pSpawnManager->RegenRate;
break;
}
case DisplayInfoType::GattlingTimer:
{
if (!pType->IsGattling)
return;

const auto thisStage = pThis->CurrentGattlingStage;
const auto& stage = pThis->Veterancy.IsElite() ? pType->EliteStage : pType->WeaponStage;

value = pThis->GattlingValue;
maxValue = stage[thisStage];

if (thisStage > 0)
{
value -= stage[thisStage - 1];
maxValue -= stage[thisStage - 1];
}

break;
}
case DisplayInfoType::ProduceCash:
{
if (pThis->WhatAmI() != AbstractType::Building || static_cast<BuildingTypeClass*>(pType)->ProduceCashAmount <= 0)
return;

const auto& timer = static_cast<BuildingClass*>(pThis)->CashProductionTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
break;
}
case DisplayInfoType::PassengerKill:
{
if (!pExt->TypeExtData->PassengerDeletionType)
return;

const auto& timer = pExt->PassengerDeletionTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
break;
}
case DisplayInfoType::AutoDeath:
{
const auto pTypeExt = pExt->TypeExtData;

if (!pTypeExt->AutoDeath_Behavior.isset())
return;

if (pTypeExt->AutoDeath_AfterDelay > 0)
{
const auto& timer = pExt->AutoDeathTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
}
else if (pTypeExt->AutoDeath_OnAmmoDepletion)
{
value = pThis->Ammo;
maxValue = pType->Ammo;
}

break;
}
case DisplayInfoType::SuperWeapon:
{
if (pThis->WhatAmI() != AbstractType::Building)
return;

const auto pHouse = pThis->Owner;
const auto pBuildingType = static_cast<BuildingTypeClass*>(pType);

if (pBuildingType->SuperWeapon != -1)
{
const auto& timer = pHouse->Supers.GetItem(pBuildingType->SuperWeapon)->RechargeTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
}
else if (pBuildingType->SuperWeapon2 != -1)
{
const auto& timer = pHouse->Supers.GetItem(pBuildingType->SuperWeapon2)->RechargeTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
}
else
{
const auto& superWeapons = BuildingTypeExt::ExtMap.Find(pBuildingType)->SuperWeapons;

if (superWeapons.size() > 0)
{
const auto& timer = pHouse->Supers.GetItem(superWeapons[0])->RechargeTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
}
}

break;
}
case DisplayInfoType::IronCurtain:
{
if (!pThis->IsIronCurtained())
return;

const auto& timer = pThis->IronCurtainTimer;
value = timer.GetTimeLeft();
maxValue = timer.TimeLeft;
break;
}
case DisplayInfoType::TemporalLife:
{
const auto pTemporal = pThis->TemporalTargetingMe;

if (!pTemporal)
return;

value = pTemporal->WarpRemaining;
maxValue = pType->Strength * 10;
break;
}
default:
{
value = pThis->Health;
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class TechnoExt
void UpdateSelfOwnedAttachEffects();
bool HasAttachedEffects(std::vector<AttachEffectTypeClass*> attachEffectTypes, bool requireAll, bool ignoreSameSource, TechnoClass* pInvoker, AbstractClass* pSource, std::vector<int> const* minCounts, std::vector<int> const* maxCounts) const;
int GetAttachedEffectCumulativeCount(AttachEffectTypeClass* pAttachEffectType, bool ignoreSameSource = false, TechnoClass* pInvoker = nullptr, AbstractClass* pSource = nullptr) const;
void InitializeDisplayInfo();

virtual ~ExtData() override;
virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ DEFINE_HOOK(0x6F42F7, TechnoClass_Init, 0x2)
pExt->CurrentShieldType = pExt->TypeExtData->ShieldType;
pExt->InitializeLaserTrails();
pExt->InitializeAttachEffects();
pExt->InitializeDisplayInfo();

if (pExt->TypeExtData->Harvester_Counted)
HouseExt::ExtMap.Find(pThis->Owner)->OwnedCountedHarvesters.push_back(pThis);
Expand Down
Loading