Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
153 changes: 153 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,
HighestThreat = 65536,
Nearest = 131072,
Farthest = 196608
};

DEFINE_HOOK(0x6E9443, TeamClass_AI, 0x8)
{
GET(TeamClass*, pTeam, ESI);
Expand Down Expand Up @@ -103,3 +112,147 @@ 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'
&& val >= std::numeric_limits<int>::min()
&& val <= std::numeric_limits<int>::max())
{
// 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: // Note: PR 1900 needs to be merged into develop
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
*/

//strcpy_s(id, strtok_s(textArgument, ",", &context));
Copy link
Member

Choose a reason for hiding this comment

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

Those useless comments can be removed imo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Including the explanation or only the old code?

//_snprintf_s(bwp, sizeof(bwp), context);
//strcpy_s(bwp, context);
//context = nullptr;
//strcpy_s(bwp, strtok_s(textArgument, ",", &context));

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;
}