Skip to content

Commit 420848e

Browse files
committed
Add additional AITriggerType conditions
1 parent 1f4dee3 commit 420848e

8 files changed

Lines changed: 221 additions & 1 deletion

File tree

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ This page lists all the individual contributions to the project by their author.
289289
- Guard range customizations
290290
- Wall overlay unit sell exploit fix
291291
- Fix vehicles disguised as trees incorrectly displaying veterancy insignia when they shouldn't
292+
- AI trigger condition type extension
292293
- **Morton (MortonPL)**:
293294
- `XDrawOffset` for animations
294295
- Shield passthrough & absorption

Phobos.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
</ProjectConfiguration>
1919
</ItemGroup>
2020
<ItemGroup>
21+
<ClCompile Include="src\Ext\AITriggerType\Body.cpp" />
22+
<ClCompile Include="src\Ext\AITriggerType\Hooks.cpp" />
2123
<ClCompile Include="src\Ext\Cell\Hooks.cpp" />
2224
<ClCompile Include="src\Ext\Event\Body.cpp" />
2325
<ClCompile Include="src\Ext\Infantry\Hooks.cpp" />
@@ -219,6 +221,7 @@
219221
<ClCompile Include="YRpp\StaticInits.cpp" />
220222
</ItemGroup>
221223
<ItemGroup>
224+
<ClInclude Include="src\Ext\AITriggerType\Body.h" />
222225
<ClInclude Include="src\Ext\EBolt\Body.h" />
223226
<ClInclude Include="src\Ext\Event\Body.h" />
224227
<ClInclude Include="src\New\Entity\Ares\RadarJammerClass.h" />

YRpp

docs/AI-Scripting-and-Mapping.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,25 @@ x=i,n ; where 18048 <= i <= 18071, n is made up of two parts, the lo
514514

515515
This category is empty for now.
516516

517+
## AI Trigger Condition Types
518+
519+
Phobos adds new AI trigger condition types. AI trigger's condition type is defined as the number in fifth comma-separated parameter in `AITriggerType` declaration.
520+
521+
F.ex
522+
```ini
523+
ID=Name,Team1,OwnerHouse,TechLevel,ConditionType,ConditionObject,Comparator,StartingWeight,MinimumWeight,MaximumWeight,IsForSkirmish,unused,Side,IsBaseDefense,Team2,EnabledInE,EnabledInM,EnabledInH
524+
```
525+
526+
Some condition types operate on or with `ConditionObject` and `Comperator` as well. More information on defining AITriggerTypes can be found on [ModEnc](https://modenc.renegadeprojects.com/AITriggerTypes).
527+
528+
### `8` Amount of Capturable Tech Buildings Exists
529+
530+
Trigger can spring if a number of `Capturable=true` + `NeedsEngineer=true` buildings owned in total by all houses the trigger owner is not allied with satisfies `Comparator`.
531+
532+
### `9` Amount of Bridge Repair Huts Exists
533+
534+
Trigger can spring if a number of `BridgeRepairHut=true` buildings linked to broken bridges owned by first house belonging to `Civilian` side satisfies `Comparator`.
535+
517536
## Trigger Actions
518537

519538
### `500` Save Game

docs/Whats-New.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ New:
542542
- Allow jumpjet climbing ignore building height (by TaranDahl)
543543
- [Allow draw SuperWeapon timer as percentage](User-Interface.md#allow-draw-superweapon-timer-as-percentage) (by NetsuNegi)
544544
- Customize particle system of parasite logic (by NetsuNegi)
545+
- [New AITriggerType conditions for tech buildings & bridge repair huts](AI-Scripting-and-Mapping.md#ai-trigger-condition-types) (by Starkku)
545546
546547
Vanilla fixes:
547548
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)

src/Ext/AITriggerType/Body.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#include "Body.h"
2+
3+
AITriggerTypeExt::ExtContainer AITriggerTypeExt::ExtMap;
4+
5+
// =============================
6+
// load / save
7+
8+
void AITriggerTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
9+
{
10+
// Nothing yet
11+
}
12+
13+
void AITriggerTypeExt::ExtData::SaveToStream(PhobosStreamWriter& Stm)
14+
{
15+
// Nothing yet
16+
}
17+
18+
// container
19+
20+
AITriggerTypeExt::ExtContainer::ExtContainer() : Container("AITriggerTypeClass")
21+
{ }
22+
23+
AITriggerTypeExt::ExtContainer::~ExtContainer() = default;
24+
25+
int AITriggerTypeExt::CheckConditions(AITriggerTypeClass* pThis, HouseClass* pOwner, HouseClass* pEnemy)
26+
{
27+
int condition = (int)pThis->ConditionType;
28+
29+
if (condition < -1) // Invalid, bail out early.
30+
return 0;
31+
else if (condition < (int)PhobosAITriggerConditions::NumberOfTechBuildingsExist) // Not Phobos condition
32+
return -1;
33+
34+
bool success = false;
35+
36+
switch ((PhobosAITriggerConditions)condition)
37+
{
38+
case PhobosAITriggerConditions::NumberOfTechBuildingsExist:
39+
success = AITriggerTypeExt::NumberOfTechBuildingsExist(pThis, pOwner);
40+
break;
41+
case PhobosAITriggerConditions::NumberOfBridgeRepairHutsExist:
42+
success = AITriggerTypeExt::NumberOfBridgeRepairHutsExist(pThis);
43+
break;
44+
}
45+
46+
return success;
47+
}
48+
49+
bool AITriggerTypeExt::GetComparatorResult(int operand1, AITriggerConditionComparatorType operatorType, int operand2)
50+
{
51+
switch (operatorType)
52+
{
53+
case AITriggerConditionComparatorType::Less:
54+
return operand1 < operand2;
55+
break;
56+
case AITriggerConditionComparatorType::LessOrEqual:
57+
return operand1 <= operand2;
58+
break;
59+
case AITriggerConditionComparatorType::Equal:
60+
return operand1 == operand2;
61+
break;
62+
case AITriggerConditionComparatorType::GreaterOrEqual:
63+
return operand1 >= operand2;
64+
break;
65+
case AITriggerConditionComparatorType::Greater:
66+
return operand1 > operand2;
67+
break;
68+
case AITriggerConditionComparatorType::NotEqual:
69+
return operand1 != operand2;
70+
break;
71+
default:
72+
return false;
73+
break;
74+
}
75+
}
76+
77+
bool AITriggerTypeExt::NumberOfTechBuildingsExist(AITriggerTypeClass* pThis, HouseClass* pOwner)
78+
{
79+
int count = 0;
80+
81+
for (auto const pHouse : HouseClass::Array)
82+
{
83+
if (pHouse->IsAlliedWith(pOwner))
84+
continue;
85+
86+
// Could possibly be optimized with bespoke tracking but
87+
// it didn't seem to make much of a difference in testing.
88+
for (auto const pBuilding : pHouse->Buildings)
89+
{
90+
if (!pBuilding->IsAlive || pBuilding->InLimbo)
91+
continue;
92+
93+
auto const pType = pBuilding->Type;
94+
95+
if (pType->NeedsEngineer && pType->Capturable)
96+
count++;
97+
}
98+
}
99+
100+
return AITriggerTypeExt::GetComparatorResult(count, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand);
101+
}
102+
103+
bool AITriggerTypeExt::NumberOfBridgeRepairHutsExist(AITriggerTypeClass* pThis)
104+
{
105+
int count = 0;
106+
auto const pHouse = HouseClass::FindCivilianSide();
107+
108+
for (auto const pBuilding : pHouse->Buildings)
109+
{
110+
if (!pBuilding->IsAlive || pBuilding->InLimbo)
111+
continue;
112+
113+
auto const pType = pBuilding->Type;
114+
115+
if (pType->BridgeRepairHut && MapClass::Instance.IsLinkedBridgeDestroyed(pBuilding->GetMapCoords()))
116+
count++;
117+
}
118+
119+
return AITriggerTypeExt::GetComparatorResult(count, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand);
120+
}

src/Ext/AITriggerType/Body.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
#include <AITriggerTypeClass.h>
3+
#include <Utilities/Container.h>
4+
5+
// Vanilla game ones range from -1 to 7, see AITriggerCondition in GeneralDefinitions.h in YRpp.
6+
enum class PhobosAITriggerConditions : unsigned int
7+
{
8+
NumberOfTechBuildingsExist = 8,
9+
NumberOfBridgeRepairHutsExist = 9,
10+
};
11+
12+
class AITriggerTypeExt
13+
{
14+
public:
15+
using base_type = AITriggerTypeClass;
16+
17+
static constexpr DWORD Canary = 0x9B9B9B9B;
18+
19+
class ExtData final : public Extension<AITriggerTypeClass>
20+
{
21+
public:
22+
// Nothing yet
23+
24+
ExtData(AITriggerTypeClass* OwnerObject) : Extension<AITriggerTypeClass>(OwnerObject)
25+
// Nothing yet
26+
{ }
27+
28+
virtual ~ExtData() = default;
29+
30+
virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
31+
32+
virtual void LoadFromStream(PhobosStreamReader& Stm) override;
33+
virtual void SaveToStream(PhobosStreamWriter& Stm) override;
34+
35+
};
36+
37+
class ExtContainer final : public Container<AITriggerTypeExt>
38+
{
39+
public:
40+
ExtContainer();
41+
~ExtContainer();
42+
};
43+
44+
static ExtContainer ExtMap;
45+
46+
static int CheckConditions(AITriggerTypeClass* pThis, HouseClass* pOwner, HouseClass* pEnemy);
47+
static bool GetComparatorResult(int operand1, AITriggerConditionComparatorType operatorType, int operand2);
48+
static bool NumberOfTechBuildingsExist(AITriggerTypeClass* pThis, HouseClass* pOwner);
49+
static bool NumberOfBridgeRepairHutsExist(AITriggerTypeClass* pThis);
50+
};

src/Ext/AITriggerType/Hooks.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <Ext/AITriggerType/Body.h>
2+
#include <Helpers/Macro.h>
3+
4+
DEFINE_HOOK(0x41E8FF, AITriggerTypeClass_NewTeam_CheckConditions, 0x9) // ConditionMet() in YRpp
5+
{
6+
enum { ContinueGameChecks = 0x41E908, ReturnFromFunction = 0x41E9E1, Success = 0x41E9EA };
7+
8+
GET(AITriggerTypeClass*, pThis, ESI);
9+
GET(HouseClass*, pOwner, EDI);
10+
GET(HouseClass*, pEnemy, EBX);
11+
12+
int result = AITriggerTypeExt::CheckConditions(pThis, pOwner, pEnemy);
13+
14+
switch (result)
15+
{
16+
case 0:
17+
return ReturnFromFunction;
18+
break;
19+
case 1:
20+
return Success;
21+
break;
22+
default:
23+
return ContinueGameChecks;
24+
break;
25+
}
26+
}

0 commit comments

Comments
 (0)