Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
757f67c
Initial commit
FS-21 Oct 4, 2023
3d265ff
Merge remote-tracking branch 'origin/develop' into feature/ai-teams-d…
FS-21 Mar 10, 2024
f42b2eb
Merge remote-tracking branch 'origin/develop' into feature/ai-teams-d…
FS-21 Mar 10, 2024
fbc3035
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Mar 12, 2024
16042b9
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Apr 30, 2024
1b0a658
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Aug 30, 2024
1484010
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Aug 30, 2024
950823d
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Oct 27, 2024
d8b71d5
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Oct 28, 2024
e3e4d9a
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Feb 18, 2025
fd7214d
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 May 20, 2025
83f9438
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 May 24, 2025
e91581a
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 May 29, 2025
7106d22
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 May 30, 2025
af02668
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Jun 8, 2025
195d04b
Merge remote-tracking branch 'origin/develop' into feature/ai-teams-d…
FS-21 Jul 7, 2025
4dff9a5
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Aug 7, 2025
2b459fc
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Aug 7, 2025
54d45da
Merge branch 'develop' into feature/ai-teams-detect-disguises
FS-21 Sep 2, 2025
d981bb2
Merge remote-tracking branch 'origin/develop' into feature/ai-teams-d…
FS-21 Aug 24, 2026
90a2e4d
Address review feedback on DetectDisguise.Percent from PR #1169
FS-21 Aug 24, 2026
dcabce9
Merge remote-tracking branch 'origin/develop' into feature/ai-teams-d…
FS-21 Aug 28, 2026
617fa33
fixes
FS-21 Aug 28, 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 @@ -158,6 +158,7 @@ This page lists all the individual contributions to the project by their author.
- Warhead activation target health thresholds enhancements
- Event 606: AttachEffect is attaching to a Techno
- Linked superweapons
- Customizable disguised target evaluation behaviour in new ScriptType attack actions
- Unit & infantry auto-conversion on ammo change
- Restore the ScriptType action#24 `Play speech` from Tiberian Sun
- Modify ammo on impact
Expand Down
10 changes: 10 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,16 @@ ChronoRangeMinimum= ; integer, can be used to set a small range within which
ChronoDelay= ; integer, delay after teleport for chronosphere
```

### Customizable disguised target evaluation behaviour in new ScriptType attack actions

- By default, any unit with `DetectDisguise=yes` seeking targets via new [attack team missions introduced in Phobos](AI-Scripting-and-Mapping.md#10000-10049-attack-actions) always detects the disguised units. The probability to detect a disguised object now can be customized.
- `DetectDisguise.Percent` values represent the probabilities in hard, medium & easy difficulty, in that order.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why reinvent the wheel here? Doesn't vanilla have that logic?


In `rulesmd.ini`:
```ini
[SOMETECHNO] ; TechnoType
DetectDisguise.Percent=1.0, 1.0, 1.0 ; float, percents or absolute
```
### Customizable veterancy insignias

- You can now customize veterancy insignia of TechnoTypes.
Expand Down
2 changes: 2 additions & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ HideShakeEffects=false ; boolean
#### New:
- [Customized transport plane for teams](AI-Scripting-and-Mapping.md#customized-transport-plane-for-teams) (by FlyStar)
- [Modify ammo on impact](New-or-Enhanced-Logics.md#modify-ammo-on-impact) (by FS-21)
- [Customizable disguised target evaluation behaviour in new ScriptType attack actions](Fixed-or-Improved-Logics.md#customizable-disguised-target-evaluation-behaviour-in-new-scripttype-attack-actions) (by FS-21)
- [Customize whether mind-controlled Insignificant technos can be auto-targeted](Fixed-or-Improved-Logics.md#customize-whether-mind-controlled-Insignificant-technos-can-be-auto-targeted) (by Noble_Fish)
- [AutoDeath based on player power status and player credits](New-or-Enhanced-Logics.md#kill-object-automatically) (by Flactine)
- [Roof production anim](New-or-Enhanced-Logics.md#roof-production-anim) (by Noble_Fish)
Expand Down Expand Up @@ -1028,6 +1029,7 @@ HideShakeEffects=false ; boolean
- Airstrike & spy plane fixed spawn distance & height (by Starkku)
- Allow enabling application of `Verses` and `PercentAtMax` for negative damage (by Starkku)
- In addition to `PlacementGrid.Translucency`, allow to set the transparency of the grid when `PlacementPreview` is enabled, using the `PlacementGrid.TranslucencyWithPreview` tag (by Belonit)
- Customizable disguised target evaluation behaviour in new ScriptType attack actions (by FS-21)
- Show briefing screen on singleplayer mission start (by Starkku)
- Allow setting mission par times and related messages in `missionmd.ini` (by Starkku)
- Allow setting default singleplayer map loading screen and briefing offsets (by Starkku)
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/Script/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class ScriptExt final : public AbstractExt

// Mission.Attack.cpp
static void Mission_Attack(TeamClass* pTeam, int calcThreatMode = 0, bool repeatAction = true, int attackAITargetType = -1, int idxAITargetTypeItem = -1);
static TechnoClass* GreatestThreat(TechnoClass* pTechno, int method, int calcThreatMode = 0, HouseClass* onlyTargetThisHouseEnemy = nullptr, int attackAITargetType = -1, int idxAITargetTypeItem = -1, bool agentMode = false);
static TechnoClass* GreatestThreat(TechnoClass* pTechno, int method, int calcThreatMode = 0, HouseClass* onlyTargetThisHouseEnemy = nullptr, int attackAITargetType = -1, int idxAITargetTypeItem = -1, bool agentMode = false, const std::vector<double>& disguiseDetection = {});
static bool EvaluateObjectWithMask(TechnoClass* pTechno, int mask, int attackAITargetType = -1, int idxAITargetTypeItem = -1, TechnoClass* pTeamLeader = nullptr);
static void Mission_Attack_List(TeamClass* pTeam, int calcThreatMode = 0, bool repeatAction = true, int attackAITargetType = -1);
static void Mission_Attack_List1Random(TeamClass* pTeam, int calcThreatMode = 0, bool repeatAction = true, int attackAITargetType = -1);
Expand Down
53 changes: 51 additions & 2 deletions src/Ext/Script/Mission.Attack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void ScriptExt::Mission_Attack(TeamClass* pTeam, int calcThreatMode, bool repeat
auto& waitNoTargetCounter = pTeamData->WaitNoTargetCounter;
auto& waitNoTargetTimer = pTeamData->WaitNoTargetTimer;
auto& waitNoTargetAttempts = pTeamData->WaitNoTargetAttempts;
std::vector<double> disguiseDetection = {};

const auto pHouseExt = HouseExt::Fetch(pTeam->Owner);
// When the new target wasn't found it sleeps some few frames before the new attempt. This can save cycles and cycles of unnecessary executed lines.
Expand Down Expand Up @@ -139,6 +140,30 @@ void ScriptExt::Mission_Attack(TeamClass* pTeam, int calcThreatMode, bool repeat
}

pacifistTeam &= !ScriptExt::IsUnitArmed(pFoot, pTechnoType);

auto pTechnoData = TechnoTypeExt::Fetch(pTechnoType);
if (pTechnoType->DetectDisguise)
{
auto const AIDifficulty = pFoot->Owner->GetAIDifficultyIndex();
const auto& percent = pTechnoData->DetectDisguise_Percent.Get();
double detectionValue = 1.0;

switch (AIDifficulty)
{
case 0:
detectionValue = percent.X;
break;
case 1:
detectionValue = percent.Y;
break;
case 2:
default:
detectionValue = percent.Z;
break;
}

disguiseDetection.push_back(detectionValue);
}
}
}

Expand Down Expand Up @@ -195,7 +220,7 @@ void ScriptExt::Mission_Attack(TeamClass* pTeam, int calcThreatMode, bool repeat

const auto& node = scriptActions[currentMission];
const int targetMask = node.Argument; // This is the target type
const auto pSelectedTarget = ScriptExt::GreatestThreat(pLeaderUnit, targetMask, calcThreatMode, enemyHouse, attackAITargetType, idxAITargetTypeItem, agentMode);
const auto pSelectedTarget = GreatestThreat(pLeaderUnit, targetMask, calcThreatMode, enemyHouse, attackAITargetType, idxAITargetTypeItem, agentMode, disguiseDetection);

if (pSelectedTarget)
{
Expand Down Expand Up @@ -451,7 +476,7 @@ void ScriptExt::Mission_Attack(TeamClass* pTeam, int calcThreatMode, bool repeat
}
}

TechnoClass* ScriptExt::GreatestThreat(TechnoClass* pTechno, int method, int calcThreatMode, HouseClass* onlyTargetThisHouseEnemy, int attackAITargetType, int idxAITargetTypeItem, bool agentMode)
TechnoClass* ScriptExt::GreatestThreat(TechnoClass* pTechno, int method, int calcThreatMode, HouseClass* onlyTargetThisHouseEnemy, int attackAITargetType, int idxAITargetTypeItem, bool agentMode, const std::vector<double>& disguiseDetection)
{
TechnoClass* pBestObject = nullptr;
double bestVal = -1;
Expand Down Expand Up @@ -501,6 +526,30 @@ TechnoClass* ScriptExt::GreatestThreat(TechnoClass* pTechno, int method, int cal
if (!pTargetType->LegalTarget || (!skipImmune && pTargetType->Immune))
continue;

// Checking disguise logic, if the target isn't detected then it will be ignored
if (pTarget->IsDisguised())
{
if (disguiseDetection.empty())
continue;

bool detected = false;

for (double item : disguiseDetection)
{
int dice = ScenarioClass::Instance->Random.RandomRanged(0, 99);
int detectionValue = static_cast<int>(std::round(item * 100.0));

if (detectionValue > dice)
{
detected = true;
break;
}
}

if (!detected)
continue;
}

// Note: the TEAM LEADER is picked for this task, be careful with leadership values in your mod
const auto pWeaponType = pTechno->GetWeapon(pTechno->SelectWeapon(pTarget))->WeaponType;

Expand Down
22 changes: 22 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,26 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI)
this->DeployFireWeapon.Read(exINI, pSection, "DeployFireWeapon");
this->TargetZoneScanType.Read(exINI, pSection, "TargetZoneScanType");

this->DetectDisguise_Percent.Read(exINI, pSection, "DetectDisguise.Percent");
{
auto& percent = *this->DetectDisguise_Percent.GetEx();
if (percent.ValueCount == 1)
{
percent.Y = percent.X;
percent.Z = percent.X;
percent.ValueCount = 3;
}
else if (percent.ValueCount == 2)
{
percent.Z = percent.Y;
percent.ValueCount = 3;
}

percent.X = std::clamp(percent.X, 0.0, 1.0);
percent.Y = std::clamp(percent.Y, 0.0, 1.0);
percent.Z = std::clamp(percent.Z, 0.0, 1.0);
}

this->AreaGuardRange.Read(exINI, pSection, "AreaGuardRange");
this->MaxGuardRange.Read(exINI, pSection, "MaxGuardRange");

Expand Down Expand Up @@ -1647,6 +1667,8 @@ void TechnoTypeExt::Serialize(T& Stm)
.Process(this->SpawnsPipSize)
.Process(this->SpawnsPipOffset)

.Process(this->DetectDisguise_Percent)

.Process(this->DroppodType)

.Process(this->TiberiumEaterType)
Expand Down
3 changes: 3 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ class TechnoTypeExt : public ObjectTypeExt

Valueable<float> CrashSpin_Multiplier;

Valueable<PartialVector3D<double>> DetectDisguise_Percent;

Nullable<int> AINormalTargetingDelay;
Nullable<int> PlayerNormalTargetingDelay;
Nullable<int> AIGuardAreaTargetingDelay;
Expand Down Expand Up @@ -722,6 +724,7 @@ class TechnoTypeExt : public ObjectTypeExt
, MakesWake { }

, CrashSpin_Multiplier { 1.0f }
, DetectDisguise_Percent { { 1.0, 1.0, 1.0 } }

, AINormalTargetingDelay {}
, PlayerNormalTargetingDelay {}
Expand Down
Loading