Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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 @@ -401,6 +401,7 @@ This page lists all the individual contributions to the project by their author.
- Fast access structure
- Iron Curtain/Custom Tint Support for SHP Turreted Vehicles
- Reactivate unused trigger events 2, 53, and 54
- Map Action 511, 609, 610
- **NetsuNegi**:
- Forbidding parallel AI queues by type
- Jumpjet crash speed fix when crashing onto building
Expand Down
47 changes: 47 additions & 0 deletions docs/AI-Scripting-and-Mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,19 @@ ID=ActionCount,[Action1],510,0,0,[MCVRedeploy],0,0,0,A,[ActionX]
...
```

### `511` Undeploy Building to Waypoint

- Undeploy specific BuildingTypes into VehicleTypes and move them to a specific Waypoint.
- If `<All>` is entered for the Building Type here, then undeploy all BuildingTypes.

In `mycampaign.map`:
```ini
[Actions]
...
ID=ActionCount,[Action1],511,-10,[BuildingTypesID],[HouseIndex],0,0,0,[WaypointIndex],[ActionX]
...
```

### `606` Edit Hate-Value

- Edit the hate-value that trigger houses to other houses.
Expand Down Expand Up @@ -707,6 +720,40 @@ ID=ActionCount,[Action1],608,0,0,[HouseIndex],0,0,0,A,[ActionX]
...
```

### `609` Set Radar Mode

- Change the current radar mode of the trigger house.

In `mycampaign.map`:
```ini
[Actions]
...
ID=ActionCount,[Action1],609,0,0,[RadarMode],0,0,0,A,[ActionX]
...
```

- The possible argument values are:

| *Argument* | *Description* |
| :--------: | :-----------------------------------------------------------------------: |
| 0 | Normal mode, requires buildings that provide radar and sufficient power |
| 1 | Change to [FreeRadar](https://modenc.renegadeprojects.com/FreeRadar) mode |
| 2 | Force enable radar |
| 3 | Force disable radar |

### `610` Set house's `TeamDelays` value

- Set the `TeamDelays` value of the trigger's house.
- If this value is less than 0, then use the value of `[General] -> TeamDelays`.

In `mycampaign.map`:
```ini
[Actions]
...
ID=ActionCount,[Action1],610,0,0,[Number],0,0,0,A,[ActionX]
...
```

### `800-802` Display Banner

- Display a 'banner' at a fixed location that is relative to the screen.
Expand Down
20 changes: 12 additions & 8 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,17 +185,20 @@ HideShakeEffects=false ; boolean
[ActionsRA2]
41=Play animation at a waypoint...,0,25,69,0,0,0,1,0,0,[LONG DESC].,0,1,41
125=Build at...,-10,47,0,65,0,0,1,0,0,[LONG DESC],0,1,125
500=Save game,-4,13,0,0,0,0,0,0,0,[LONG DESC],0,1,500,1
501=Edit variable,0,56,55,6,54,0,0,0,0,[LONG DESC],0,1,501,1
502=Generate random number,0,56,57,58,54,0,0,0,0,[LONG DESC],0,1,502,1
503=Print variable value,0,56,54,0,0,0,0,0,0,[LONG DESC],0,1,503,0
504=Binary operation,0,56,55,60,54,59,0,0,0,[LONG DESC],0,1,504,1
500=Save game (Phobos),-4,13,0,0,0,0,0,0,0,[LONG DESC],0,1,500,1
501=Edit variable (Phobos),0,56,55,6,54,0,0,0,0,[LONG DESC],0,1,501,1
502=Generate random number (Phobos),0,56,57,58,54,0,0,0,0,[LONG DESC],0,1,502,1
503=Print variable value (Phobos),0,56,54,0,0,0,0,0,0,[LONG DESC],0,1,503,0
504=Binary operation (Phobos),0,56,55,60,54,59,0,0,0,[LONG DESC],0,1,504,1
505=Fire Super Weapon at specified location (Phobos),0,0,20,2,21,22,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified location. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random,0,1,505
506=Fire Super Weapon at specified waypoint (Phobos),0,0,20,2,30,0,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified waypoint. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random,0,1,506
510=Toggle MCV Redeployablility (Phobos),0,0,15,0,0,0,0,0,0, Set MCVRedeploys to the given value,0,1,510
606=Edit hate-value (Phobos),0,2,55,6,0,0,0,0,0, Edit the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,606
607=Clear hate-value (Phobos),0,2,0,0,0,0,0,0,0, Clear the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,607
608=Set force enemy (Phobos),0,0,2,0,0,0,0,0,0, Force an enemy, it will not change with the change of hate-value. -1 will remove the forced enemy, -2 will never have any enemies.,0,1,608
511=Building Type undeploy at... (Phobos),-10,47,2,0,0,0,1,0,0,Recycle the building type into a vehicle and move it to the specified waypoint. If the type is `<All>`, recycle all buildings.,0,1,511
606=Edit hate-value... (Phobos),0,2,55,6,0,0,0,0,0, Edit the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,606
607=Clear hate-value... (Phobos),0,2,0,0,0,0,0,0,0, Clear the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,607
608=Set force enemy... (Phobos),0,0,2,0,0,0,0,0,0, Force an enemy, it will not change with the change of hate-value. -1 will remove the forced enemy, -2 will never have any enemies.,0,1,608
609=Set radar mode... (Phobos),0,0,15,0,0,0,0,0,0, Trigger's house can modify the current radar mode. 0 for requires full-power and building, 1 for free radar, 2 for forced enable, 3 for forced disable.,0,1,609
610=Set team delay... (Phobos),0,0,6,0,0,0,0,0,0, Trigger's house can customize TeamDelay. When the value is less than 0 in `[General]>TeamDelays`.,0,1,610
800=Display banner and local variable (Phobos),-4,101,104,102,103,3,0,0,0,Draw banner on screen and replace banner with same ID,0,1,800
801=Display banner and global variable (Phobos),-4,101,104,102,103,35,0,0,0,Draw banner on screen and replace banner with same ID,0,1,801
802=Delete banner (Phobos),0,104,0,0,0,0,0,0,0,Delete banner with ID,0,1,802
Expand Down Expand Up @@ -475,6 +478,7 @@ New:
- [Toggle per-target warhead effects apply timing](New-or-Enhanced-Logics.md#toggle-per-target-warhead-effects-apply-timing) (by TaranDahl)
- [Extra range for chasing and pre-firing](New-or-Enhanced-Logics.md#extra-range) (by TaranDahl)
- Allow techno type considered as other type when recruiting techno for teams (by NetsuNegi)
- Map Action [`511` Undeploy Building to Waypoint](AI-Scripting-and-Mapping.md#undeploy-building-to-waypoint), [`609` Set Radar Mode](AI-Scripting-and-Mapping.md#set-radar-mode), [`610` Set house's `TeamDelays` value](AI-Scripting-and-Mapping.md#set-house-s-teamdelays-value) (by FlyStar)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
3 changes: 3 additions & 0 deletions src/Ext/House/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,9 @@ void HouseExt::ExtData::Serialize(T& Stm)
.Process(this->ForceEnemyIndex)
.Process(this->ForceOnlyTargetHouseEnemy)
.Process(this->ForceOnlyTargetHouseEnemyMode)
.Process(this->TeamDelay)
.Process(this->FreeRadar)
.Process(this->ForceRadar)
;
}

Expand Down
6 changes: 6 additions & 0 deletions src/Ext/House/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class HouseExt
std::vector<SWExt> SuperExts;

int ForceEnemyIndex;
int TeamDelay;
bool FreeRadar;
bool ForceRadar;

ExtData(HouseClass* OwnerObject) : Extension<HouseClass>(OwnerObject)
, PowerPlantEnhancers {}
Expand Down Expand Up @@ -99,6 +102,9 @@ class HouseExt
, ForceEnemyIndex(-1)
, ForceOnlyTargetHouseEnemy { false }
, ForceOnlyTargetHouseEnemyMode { -1 }
, TeamDelay(-1)
, FreeRadar(false)
, ForceRadar(false)
{ }

bool OwnsLimboDeliveredBuilding(BuildingClass* pBuilding) const;
Expand Down
45 changes: 45 additions & 0 deletions src/Ext/House/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,48 @@ DEFINE_HOOK(0x4FD8F7, HouseClass_UpdateAI_OnLastLegs, 0x10)

return ret;
}

DEFINE_HOOK(0x4F8ACC, HouseClass_Update_ResetTeamDelay, 0x6)
{
enum { ResetTeamDelay = 0x4F8AD5 };

GET(HouseClass*, pThis, ESI);

const int teamDelay = HouseExt::ExtMap.Find(pThis)->TeamDelay;

if (teamDelay >= 0)
{
R->ECX(teamDelay);
return ResetTeamDelay;
}

return 0;
}

DEFINE_HOOK(0x508E17, HouseClass_UpdateRadar_FreeRadar, 0x8)
{
enum { ForceRadar = 0x508F2F, Continue = 0x508E4A };

GET(HouseClass*, pThis, ECX);

auto const pExt = HouseExt::ExtMap.Find(pThis);
const bool freeRadar = pExt->FreeRadar;

if (pExt->ForceRadar)
{
R->Stack(STACK_OFFSET(0x1C, -0xC), freeRadar);
return ForceRadar;
}
else if (pThis->PowerBlackoutTimer.InProgress())
{
R->Stack(STACK_OFFSET(0x1C, -0xC), false);
return ForceRadar;
}
else if (freeRadar)
{
R->Stack(STACK_OFFSET(0x1C, -0xC), true);
return ForceRadar;
}

return Continue;
}
7 changes: 7 additions & 0 deletions src/Ext/Scenario/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <SessionClass.h>
#include <VeinholeMonsterClass.h>

#include <Ext/House/Body.h>

std::unique_ptr<ScenarioExt::ExtData> ScenarioExt::Data = nullptr;

bool ScenarioExt::CellParsed = false;
Expand Down Expand Up @@ -90,6 +92,11 @@ void ScenarioExt::Remove(ScenarioClass* pThis)
void ScenarioExt::LoadFromINIFile(ScenarioClass* pThis, CCINIClass* pINI)
{
Data->LoadFromINI(pINI);

for (auto const pHouse : HouseClass::Array)
{
HouseExt::ExtMap.Find(pHouse)->FreeRadar = ScenarioClass::Instance->FreeRadar;
}
}

void ScenarioExt::ExtData::UpdateAutoDeathObjectsInLimbo()
Expand Down
153 changes: 153 additions & 0 deletions src/Ext/TAction/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ bool TActionExt::Execute(TActionClass* pThis, HouseClass* pHouse, ObjectClass* p

case PhobosTriggerAction::ToggleMCVRedeploy:
return TActionExt::ToggleMCVRedeploy(pThis, pHouse, pObject, pTrigger, location);
case PhobosTriggerAction::UndeployToWaypoint:
return TActionExt::UndeployToWaypoint(pThis, pHouse, pObject, pTrigger, location);

case PhobosTriggerAction::EditAngerNode:
return TActionExt::EditAngerNode(pThis, pHouse, pObject, pTrigger, location);
case PhobosTriggerAction::ClearAngerNode:
return TActionExt::ClearAngerNode(pThis, pHouse, pObject, pTrigger, location);
case PhobosTriggerAction::SetForceEnemy:
return TActionExt::SetForceEnemy(pThis, pHouse, pObject, pTrigger, location);
case PhobosTriggerAction::SetFreeRadar:
return TActionExt::SetFreeRadar(pThis, pHouse, pObject, pTrigger, location);
case PhobosTriggerAction::SetTeamDelay:
return TActionExt::SetTeamDelay(pThis, pHouse, pObject, pTrigger, location);

case PhobosTriggerAction::CreateBannerLocal:
return TActionExt::CreateBannerLocal(pThis, pHouse, pObject, pTrigger, location);
Expand Down Expand Up @@ -384,6 +390,100 @@ bool TActionExt::ToggleMCVRedeploy(TActionClass* pThis, HouseClass* pHouse, Obje
return true;
}

bool TActionExt::UndeployToWaypoint(TActionClass* const pThis, HouseClass* const pHouse, ObjectClass* const pObject, TriggerClass* const pTrigger, const CellStruct& location)
{
const auto& nCell = ScenarioExt::Global()->Waypoints[pThis->Waypoint];
CellClass* const pCell = MapClass::Instance.TryGetCellAt(nCell);

if (!pCell)
return true;

HouseClass* vHouse = nullptr;
const int houseIndex = pThis->Param3;

if (houseIndex >= 0)
{
vHouse = HouseClass::Index_IsMP(houseIndex)
? HouseClass::FindByIndex(houseIndex) : HouseClass::FindByCountryIndex(houseIndex);
}

if (!vHouse)
return true;

const char* buildingName = pThis->TechnoID;
bool allBuilding = false;
BuildingTypeClass* pBuildingType = nullptr;

if (!strcmp(buildingName, "<All>"))
{
allBuilding = true;
}
else
{
pBuildingType = BuildingTypeClass::Find(buildingName);
}

if (!allBuilding && !pBuildingType)
return true;

const auto& limboDelivereds = HouseExt::ExtMap.Find(vHouse)->OwnedLimboDeliveredBuildings;
const bool existLimboBuilding = !limboDelivereds.empty();

// Thanks to chaserli for the relevant code!
// There should be a more perfect way to do this, but I don't know how.
auto canUndeploy = [&](BuildingClass* const pBuilding)
{
auto const pType = pBuilding->Type;

if (!pType->UndeploysInto
|| pBuilding->Owner != vHouse
|| (!allBuilding && pType != pBuildingType)
|| pBuilding->CurrentMission == Mission::Selling
|| !pBuilding->IsAlive || pBuilding->Health <= 0 || pBuilding->InLimbo)
{
return false;
}

// verify whether the building's source is LimboDelivery.
if (existLimboBuilding)
{
for (auto const pLimboBuilding : limboDelivereds)
{
if (pLimboBuilding == pBuilding)
return false;
}
}

if (pType->ConstructionYard)
{
// Conyards can't undeploy if MCVRedeploy=no
if (!GameModeOptionsClass::Instance.MCVRedeploy)
return false;
// or MindControlledBy YURIX (why? for balance?)
if (!RulesExt::Global()->AllowDeployControlledMCV && pBuilding->MindControlledBy)
return false;
}

return true;
};

for (const auto pBuilding : BuildingClass::Array)
{
if (!canUndeploy(pBuilding))
continue;

// Why does having this allow it to undeploy?
// Why don't vehicles move when waypoints are placed off the map?

const bool old = std::exchange(VocClass::VoicesEnabled, false);
pBuilding->SetArchiveTarget(pCell);
pBuilding->Sell(true);
VocClass::VoicesEnabled = old;
}

return true;
}

bool TActionExt::EditAngerNode(TActionClass* pThis, HouseClass* pHouse, ObjectClass* pObject, TriggerClass* pTrigger, CellStruct const& location)
{
if (pHouse->AngerNodes.Count <= 0)
Expand Down Expand Up @@ -519,6 +619,59 @@ bool TActionExt::SetForceEnemy(TActionClass* pThis, HouseClass* pHouse, ObjectCl
return true;
}

bool TActionExt::SetFreeRadar(TActionClass* const pThis, HouseClass* const pHouse, ObjectClass* const pObject, TriggerClass* const pTrigger, const CellStruct& location)
{
if (pHouse->IsControlledByHuman())
{
auto const pHouseExt = HouseExt::ExtMap.Find(pHouse);

switch (pThis->Param3)
{
case 1:
pHouseExt->FreeRadar = true;
pHouseExt->ForceRadar = false;
break;
case 2:
pHouseExt->FreeRadar = true;
pHouseExt->ForceRadar = true;
break;
case 3:
pHouseExt->FreeRadar = false;
pHouseExt->ForceRadar = true;
break;
default:
pHouseExt->FreeRadar = false;
pHouseExt->ForceRadar = false;
break;
}

pHouse->RecheckRadar = true;
}

return true;
}

bool TActionExt::SetTeamDelay(TActionClass* const pThis, HouseClass* const pHouse, ObjectClass* const pObject, TriggerClass* const pTrigger, const CellStruct& location)
{
const int value = pThis->Param3;
const int timer = value < 0 ? RulesClass::Instance->TeamDelays.Items[static_cast<int>(pHouse->AIDifficulty)] : value;
HouseExt::ExtMap.Find(pHouse)->TeamDelay = value;

auto& Timer = pHouse->TeamDelayTimer;
const int time = std::min(Timer.GetTimeLeft(), timer);

if (Timer.StartTime == -1 && Timer.TimeLeft != 0 && time > 0)
{
Timer.TimeLeft = time;
}
else if (Timer.InProgress())
{
Timer.Start(time);
}

return true;
}

static void CreateOrReplaceBanner(TActionClass* pTAction, bool isGlobal)
{
const auto pBannerType = BannerTypeClass::Find(pTAction->Text);
Expand Down
Loading