Skip to content
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 @@ -152,6 +152,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
- New ScriptTypeActions `19017, 19018, 19020, 19024, 19025, 19026, 19027, 19046, 19047, 19051, 19056, 19058` that require ID as argument
- **Starkku**:
- Misc. minor bugfixes & improvements
- AI script actions:
Expand Down
126 changes: 125 additions & 1 deletion docs/AI-Scripting-and-Mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,131 @@ x=i,n ; where 18048 <= i <= 18071, n is made up of two parts, the lo

### `19000-19999` Miscellanous/Uncategorized

This category is empty for now.
#### `19017` Change Script

- Similar to action 17, but uses a string ID from the `[ScriptTypes]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19017,ID ; text
```

#### `19018` Change TeamType

- Similar to action 18, but uses a string ID from the `[TeamTypes]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19018,ID ; text
```

#### `19020` Change House

- Similar to action 20, but uses a string ID from the `[Countries]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19020,ID ; text
```

#### `19024` Play Speech

- Similar to action 24, but uses a string ID from the `[DialogList]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19024,ID ; text
```

#### `19025` Play Sound

- Similar to action 25, but uses a string ID from the `[SoundList]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19025,ID ; text
```

#### `19027` Play Theme

- Similar to action 27, but uses a string ID from the `[Themes]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19027,ID ; text
```

#### `19051` Play Animation

- Similar to action 51, but uses a string ID from the `[Animations]` list instead of an index.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19051,ID ; text
```

#### `19046` Attack Enemy Structure

- Similar to action 46, but uses a string ID from the `[BuildingTypes]` list instead of an index.
- The last parameter is the BwP. Check below the possible strings.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19046,ID,BwP ; text
```

| *BwP values* | *Description* |
|--------------:|:----------------------------------------------------------|
| LeastThreat | Index of the instance of the building with least threat |
| HighestThreat | Index of the instance of the building with highest threat |
| Nearest | Index of the instance of the building which is nearest |
| Farthest | Index of the instance of the building which is farthest |

```{note}
More BwP information in https://modenc.renegadeprojects.com/ScriptTypes/ScriptActions
For this action to work in multiplayer - you need to use a version of [Script Actions information at Modenc](https://modenc.renegadeprojects.com/ScriptTypes/ScriptActions).
```

#### `19047` Move To Enemy Structure

- Similar to action 47, but uses a string ID from the `[BuildingTypes]` list instead of an index.
- The last parameter is the BwP. Check the table of the action `19046`.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19047,ID,BwP ; text
```

#### `19056` Chronoshift TaskForce To Structure

- Similar to action 56, but uses a string ID from the `[BuildingTypes]` list instead of an index.
- The last parameter is the BwP. Check the table of the action `19046`.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19056,ID,BwP ; text
```

#### `19058` Move To Friendly Structure

- Similar to action 58, but uses a string ID from the `[BuildingTypes]` list instead of an index.
- The last parameter is the BwP. Check the table of the action `19046`.

In `aimd.ini`:
```ini
[SOMESCRIPTTYPE] ; ScriptType
x=19058,ID,BwP ; text
```

## Trigger Actions

Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ New:
- Allow the aircraft to enter area guard mission and not crash immediately without any airport (by CrimRecya)
- [Unlimbo Detonate warhead](New-or-Enhanced-Logics.md#unlimbo-detonate-warhead) (by FlyStar)
- Attack and damage technos underground (by TaranDahl)
- New ScriptTypeActions `19017, 19018, 19020, 19024, 19025, 19026, 19027, 19046, 19047, 19051, 19056, 19058` that require ID as argument (by FS-21)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
16 changes: 15 additions & 1 deletion src/Ext/Script/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

enum class PhobosScripts : unsigned int
{
PlaySpeech = 24, // Reserved! PR 1900 needs to be merged

// Range 10000-10999 are team (aka ingame) actions
// Sub-range 10000-10049 is for "attack" actions
RepeatAttackCloser = 10000,
Expand Down Expand Up @@ -150,9 +152,21 @@ enum class PhobosScripts : unsigned int
GlobalVariableReverseByGlobal = 18068,
GlobalVariableXorByGlobal = 18069,
GlobalVariableOrByGlobal = 18070,
GlobalVariableAndByGlobal = 18071
GlobalVariableAndByGlobal = 18071,

// Range 19000-19999 are miscellanous/uncategorized actions
ChangeToScriptByID = 19017,
ChangeToTeamTypeByID = 19018,
ChangeToHouseByID = 19020,
PlaySpeechByID = 19024,
PlaySoundByID = 19025,
PlayMovieByID = 19026, // Reserved! Now does nothing
PlayThemeByID = 19027,
AttackEnemyStructureByID = 19046,
MoveToEnemyStructureByID = 19047,
PlayAnimationByID = 19051,
ChronoshiftTaskForceToStructureByID = 19056,
MoveToFriendlyStructureByID = 19058
};

class ScriptExt
Expand Down
145 changes: 145 additions & 0 deletions src/Ext/Script/Hooks.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
#include "Body.h"

#include <MapClass.h>
#include <ThemeClass.h>

#include <Ext/House/Body.h>
#include <Helpers/Macro.h>

enum class BuildingWithProperty : unsigned int
{
LeastThreat = 0 << 16,
HighestThreat = 1 << 16,
Nearest = 2 << 16,
Farthest = 3 << 16
};

DEFINE_HOOK(0x6E9443, TeamClass_AI, 0x8)
{
GET(TeamClass*, pTeam, ESI);
Expand Down Expand Up @@ -103,3 +112,139 @@ DEFINE_HOOK(0x6F01B0, TMission_ChronoShiftToTarget_SuperWeapons, 0x6)

return SkipGameCode;
}

DEFINE_HOOK(0x723CA1, TeamMissionClass_FillIn_StringsSupport_and_id_masks, 0xB)
{
enum { SkipCode = 0x723CD2 };

GET(ScriptActionNode*, node, ECX);
GET_STACK(char*, scriptActionLine, 0x8);

int action = 0;
int argument = 0;
char* endptr;

if (sscanf(scriptActionLine, "%d,%[^\n]", &action, Phobos::readBuffer) != 2)
{
node->Action = action;
node->Argument = argument;
R->ECX(node);

return SkipCode;
}

long val = strtol(Phobos::readBuffer, &endptr, 10);

if (*endptr == '\0')
{
// Integer case (the classic).
argument = static_cast<int>(val);
}
else
{
// New strings case
char textArgument[sizeof(Phobos::readBuffer)] = { 0 };

action = action;
strcpy_s(textArgument, Phobos::readBuffer);

// Action masks: These actions translate IDs into indices while preserving the original action values.
// The reason for using these masks is that some ScriptType actions rely on fixed indices rather than ID labels.
// When these lists change, there's a high probability of breaking the original index of the pointed element
char id[sizeof(AbstractTypeClass::ID)] = { 0 };
char bwp[20] = { 0 };
char* context = nullptr;
int index = 0;
int prefixIndex = 0;

switch (static_cast<PhobosScripts>(action))
{
case PhobosScripts::ChangeToScriptByID:
action = 17;
index = ScriptTypeClass::FindIndex(textArgument);
break;
case PhobosScripts::ChangeToTeamTypeByID:
action = 18;
index = TeamTypeClass::FindIndex(textArgument);
break;
case PhobosScripts::ChangeToHouseByID:
action = 20;
index = HouseTypeClass::FindIndexOfName(textArgument);

if (index < 0)
ScriptExt::Log("AI Scripts - TeamMissionClass_FillIn_StringsSupport: Invalid Country string [%s]\n", textArgument);
break;
case PhobosScripts::PlaySpeechByID:
action = static_cast<int>(PhobosScripts::PlaySpeech);
index = VoxClass::FindIndex(textArgument);
break;
case PhobosScripts::PlaySoundByID:
action = 25;
index = VocClass::FindIndex(textArgument);
break;
case PhobosScripts::PlayMovieByID:
// Note: action "26" is currently impossible without an expert Phobos developer declaring the Movies class... in that case I could code the right FindIndex(textArgument) so sadly I'll skip "26" for now :-(
action = 26;
index = 0;
break;
case PhobosScripts::PlayThemeByID:
action = 27;
index = ThemeClass::Instance.FindIndex(textArgument);
break;
case PhobosScripts::PlayAnimationByID:
action = 51;
index = AnimTypeClass::FindIndex(textArgument);
break;
case PhobosScripts::AttackEnemyStructureByID:
case PhobosScripts::MoveToEnemyStructureByID:
case PhobosScripts::ChronoshiftTaskForceToStructureByID:
case PhobosScripts::MoveToFriendlyStructureByID:
if (PhobosScripts::AttackEnemyStructureByID == static_cast<PhobosScripts>(action))
action = 46;
else if (PhobosScripts::MoveToEnemyStructureByID == static_cast<PhobosScripts>(action))
action = 47;
else if (PhobosScripts::ChronoshiftTaskForceToStructureByID == static_cast<PhobosScripts>(action))
action = 56;
else if (PhobosScripts::MoveToFriendlyStructureByID == static_cast<PhobosScripts>(action))
action = 58;

/* BwP check:
Information from https://modenc.renegadeprojects.com/ScriptTypes/ScriptActions
Computed Value Description
------------------------------------- -------------------------------------------------------
0 (Hex 0x0) + Building Index -> Index of the instance of the building with least threat
65536 (Hex 0x10000) + Building Index -> Index of the instance of the building with highest threat
131072 (Hex 0x20000) + Building Index -> Index of the instance of the building which is nearest
196608 (Hex 0x30000) + Building Index -> Index of the instance of the building which is farthest
*/

if (sscanf(textArgument, "%[^,],%s", id, bwp) == 2)
{
index = BuildingTypeClass::FindIndex(id);

if (index >= 0)
{
if (_strcmpi(bwp, "highestthreat") == 0)
prefixIndex = static_cast<int>(BuildingWithProperty::HighestThreat);
else if (_strcmpi(bwp, "nearest") == 0)
prefixIndex = static_cast<int>(BuildingWithProperty::Nearest);
else if (_strcmpi(bwp, "farthest") == 0)
prefixIndex = static_cast<int>(BuildingWithProperty::Farthest);
}
}
break;
default:
index = 0;
break;
}

if (index >= 0)
argument = prefixIndex + index;
}

node->Action = action;
node->Argument = argument;
R->ECX(node);

return SkipCode;
}