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
5 changes: 4 additions & 1 deletion CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,13 +609,16 @@ This page lists all the individual contributions to the project by their author.
- Auto deploy for GI-like infantry
- Fix an issue that Ares' Type Conversion not resetting barrel's direction by `FireAngle`
- Fix an issue that jumpjets in air can not correctly spawn missiles
- Passive acquire mode
- **solar-III (凤九歌)**
- Target scanning delay customization (documentation)
- Skip target scanning function calling for unarmed technos (documentation)
- **tyuah8**:
- Drive/Jumpjet/Ship/Teleport locomotor did not power on when it is un-piggybacked bugfix
- Destroyed unit leaves sensors bugfix
- **Aephiex** - initial fix for Ares academy not working on the initial payloads of vehicles built from a war factory
- **Aephiex**
- initial fix for Ares academy not working on the initial payloads of vehicles built from a war factory
- Passive acquire mode (aggressive mode part)
- **Multfinite** - Allow to toggle main exception handler via command line argument `-ExceptionHandler=boolean`
- **hejiajun107, Xkein** - Fix a jumpjet crash related to voxel shadow drawing
- **Ares developers**:
Expand Down
4 changes: 4 additions & 0 deletions Phobos.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Commands\PassiveAcquireMode.cpp" />
<ClCompile Include="src\Ext\Event\Body.cpp" />
<ClCompile Include="src\Ext\Infantry\Hooks.cpp" />
<ClCompile Include="src\Ext\Infantry\Hooks.Firing.cpp" />
<ClCompile Include="src\Ext\TechnoType\Hooks.MultiWeapon.cpp" />
Expand Down Expand Up @@ -213,7 +215,9 @@
<ClCompile Include="YRpp\StaticInits.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Commands\PassiveAcquireMode.h" />
<ClInclude Include="src\Ext\EBolt\Body.h" />
<ClInclude Include="src\Ext\Event\Body.h" />
<ClInclude Include="src\New\Type\Affiliated\CreateUnitTypeClass.h" />
<ClInclude Include="src\Blowfish\blowfish.h" />
<ClInclude Include="src\Ext\Cell\Body.h" />
Expand Down
26 changes: 26 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1794,6 +1794,32 @@ In `rulesmd.ini`:
Promote.IncludeSpawns=false ; boolean
```

### Passive acquire mode

- Now you can order the units to enter "Ceasefire Mode" or "Aggressive Mode", just like in RA3.
- In ceasefire mode, units will only attack the targets specified by the player.
- In aggressive mode, units will automatically attack all enemies, including buildings without weapons.
- In normal mode, units will auto-target like usual.
- You can use [two](User-Interface#ceasefire-mode) [hotkeys](User-Interface#aggressive-mode) to switch between these two modes if `[General] -> EnablePassiveAcquireMode` is set to `true`. When you press one of these hotkeys:
- If all selected units are in that mode, they will switch to the normal mode. Otherwise, they will enter that mode. Units that cannot switch modes are not counted.
- If any unit successfully switches its mode, a sound effect will be emitted. This sound can be customized through `[TechnoType] -> Voice(Enter/Exit)(Aggressive/Ceasefire)Mode`.
- You can use `[TechnoType] -> PassiveAcquireMode.Togglable` to specify whether the unit can toggle its mode.
- You can use `[TechnoType] -> PassiveAcquireMode` to specify the unit's initial mode.

In `rulesmd.ini`:
```ini
[General]
EnablePassiveAcquireMode=false ; boolean

[SOMETECHNO] ; TechnoType
PassiveAcquireMode=Normal ; passive acquire mode, Normal / Aggressive / Ceasefire
PassiveAcquireMode.Togglable=true ; boolean
VoiceEnterAggressiveMode= ; Sound entry, default to VoiceAttack or VoiceMove
VoiceExitAggressiveMode= ; Sound entry, default to VoiceMove or VoiceSelect
VoiceEnterCeasefireMode= ; Sound entry, default to VoiceSelect or VoiceMove
VoiceExitCeasefireMode= ; Sound entry, default to VoiceAttack or VoiceMove
```

### Promotion animation

- You can now specify an animation on the unit or structure promotion.
Expand Down
10 changes: 10 additions & 0 deletions docs/User-Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,16 @@ For this command to work in multiplayer - you need to use a version of [YRpp spa
- These vanilla CSF entries will be used: `TXT_SAVING_GAME`, `TXT_GAME_WAS_SAVED` and `TXT_ERROR_SAVING_GAME`.
- The save should be looks like `Allied Mission 25: Esther's Money - QuickSaved`.

### `[ ]` Ceasefire Mode

- Order the selected units to enter or exit the ceasefire mode. See [this](New-or-Enhanced-Logics#passive-acquire-mode) for details.
- For localization add `TXT_CEASEFIRE_MODE`, `TXT_CEASEFIRE_MODE_DESC`, `MSG:CEASEFIRE_MODE_ON` and `MSG:CEASEFIRE_MODE_OFF` into your `.csf` file.

### `[ ]` Aggressive Mode

- Order the selected units to enter or exit the aggressive mode. See [this](New-or-Enhanced-Logics#passive-acquire-mode) for details.
- For localization add `TXT_AGGRESSIVE_MODE`, `TXT_AGGRESSIVE_MODE_DESC`, `MSG:AGGRESSIVE_MODE_ON` and `MSG:AGGRESSIVE_MODE_OFF` into your `.csf` file.

## Loading screen

- PCX files can now be used as loadscreen images.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ New:
- [Ammo-based deploy customizations for vehicles expanded to non-IsSimpleDeployer deploy functions](New-or-Enhanced-Logics.md#automatic-deploy-and-blocking-deploying-based-on-ammo) (by Starkku)
- Randomized anims for several behaviors (by Ollerus)
- Shield respawn animation and weapon (by Ollerus)
- Passive acquire mode (by TaranDahl & Aephiex)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
10 changes: 10 additions & 0 deletions src/Commands/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
#include "SaveVariablesToFile.h"
#include "ToggleSWSidebar.h"
#include "FireTacticalSW.h"
#include "PassiveAcquireMode.h"

#include <CCINIClass.h>
#include <InputManagerClass.h>
#include <MouseClass.h>
#include <WWMouseClass.h>

#include <Utilities/Macro.h>
#include <Ext/Sidebar/SWSidebar/SWSidebarClass.h>

DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
Expand All @@ -22,6 +30,8 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand<QuickSaveCommandClass>();
MakeCommand<ToggleDigitalDisplayCommandClass>();
MakeCommand<ToggleDesignatorRangeCommandClass>();
MakeCommand<AggressiveModeClass>();
MakeCommand<CeasefireModeClass>();
MakeCommand<ToggleSWSidebar>();

if (Phobos::Config::SuperWeaponSidebarCommands)
Expand Down
210 changes: 210 additions & 0 deletions src/Commands/PassiveAcquireMode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#include "PassiveAcquireMode.h"

#include "Ext/Techno/Body.h"
#include <Ext/Event/Body.h>

const char* AggressiveModeClass::GetName() const
{
return "AggressiveMode";
}

const wchar_t* AggressiveModeClass::GetUIName() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_AGGRESSIVE_MODE", L"Aggressive Mode");
}

const wchar_t* AggressiveModeClass::GetUICategory() const
{
return CATEGORY_CONTROL;
}

const wchar_t* AggressiveModeClass::GetUIDescription() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_AGGRESSIVE_MODE_DESC", L"Aggressive Mode");
}

void AggressiveModeClass::Execute(WWKey eInput) const
{
std::vector<TechnoClass*> TechnoVectorAggressive;
std::vector<TechnoClass*> TechnoVectorNonAggressive;

// Get current selected units.
// If all selected units are at Aggressive mode, we should cancel their Aggressive mode.
// Otherwise, we should turn them into Aggressive mode.
bool isAnySelectedUnitTogglable = false;
bool isAllSelectedUnitAggressiveMode = true;

auto processATechno = [&](TechnoClass* pTechno)
{
const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno);

// If not togglable then exclude it from the iteration.
if (!pTechnoExt->CanTogglePassiveAcquireMode())
return;

isAnySelectedUnitTogglable = true;

if (pTechnoExt->GetPassiveAcquireMode() == PassiveAcquireMode::Aggressive)
{
TechnoVectorAggressive.push_back(pTechno);
}
else
{
isAllSelectedUnitAggressiveMode = false;
TechnoVectorNonAggressive.push_back(pTechno);
}
return;
};

for (const auto& pUnit : ObjectClass::CurrentObjects)
{
// try to cast to TechnoClass
TechnoClass* pTechno = abstract_cast<TechnoClass*>(pUnit);

// if not a techno or is in berserk or is not controlled by the local player then ignore it
if (!pTechno || pTechno->Berzerk || !pTechno->Owner->IsControlledByCurrentPlayer())
continue;

processATechno(pTechno);

if (auto pPassenger = pTechno->Passengers.GetFirstPassenger())
{
for (; pPassenger; pPassenger = abstract_cast<FootClass*>(pPassenger->NextObject))
processATechno(pPassenger);
}

if (auto pBuilding = abstract_cast<BuildingClass*>(pTechno))
{
for (auto pOccupier : pBuilding->Occupants)
processATechno(pOccupier);
}
}

// If this boolean is false, then none of the selected units are togglable, meaning this hotket doesn't need to do anything.
if (isAnySelectedUnitTogglable)
{
// If all selected units are Aggressive mode, then cancel their Aggressive mode;
// otherwise, make all selected units Aggressive mode.
if (isAllSelectedUnitAggressiveMode)
{
for (const auto& pTechno : TechnoVectorAggressive)
EventExt::RaiseTogglePassiveAcquireMode(pTechno, PassiveAcquireMode::Normal);

wchar_t buffer[0x100];
swprintf_s(buffer, GeneralUtils::LoadStringUnlessMissing("MSG:AGGRESSIVE_MODE_OFF", L"%i unit(s) ceased Aggressive Mode."), TechnoVectorAggressive.size());
MessageListClass::Instance.PrintMessage(buffer);
}
else
{
for (const auto& pTechno : TechnoVectorNonAggressive)
EventExt::RaiseTogglePassiveAcquireMode(pTechno, PassiveAcquireMode::Aggressive);

wchar_t buffer[0x100];
swprintf_s(buffer, GeneralUtils::LoadStringUnlessMissing("MSG:AGGRESSIVE_MODE_ON", L"%i unit(s) entered Aggressive Mode."), TechnoVectorNonAggressive.size());
MessageListClass::Instance.PrintMessage(buffer);
}
}
}

const char* CeasefireModeClass::GetName() const
{
return "CeasefireMode";
}

const wchar_t* CeasefireModeClass::GetUIName() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_CEASEFIRE_MODE", L"Ceasefire Mode");
}

const wchar_t* CeasefireModeClass::GetUICategory() const
{
return CATEGORY_CONTROL;
}

const wchar_t* CeasefireModeClass::GetUIDescription() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_CEASEFIRE_MODE_DESC", L"Ceasefire Mode");
}

void CeasefireModeClass::Execute(WWKey eInput) const
{
std::vector<TechnoClass*> TechnoVectorCeasefire;
std::vector<TechnoClass*> TechnoVectorNonCeasefire;

// Get current selected units.
// If all selected units are at Ceasefire mode, we should cancel their Ceasefire mode.
// Otherwise, we should turn them into Ceasefire mode.
bool isAnySelectedUnitTogglable = false;
bool isAllSelectedUnitCeasefireMode = true;

auto processATechno = [&](TechnoClass* pTechno)
{
const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno);

// If not togglable then exclude it from the iteration.
if (!pTechnoExt->CanTogglePassiveAcquireMode())
return;

isAnySelectedUnitTogglable = true;

if (pTechnoExt->GetPassiveAcquireMode() == PassiveAcquireMode::Ceasefire)
{
TechnoVectorCeasefire.push_back(pTechno);
}
else
{
isAllSelectedUnitCeasefireMode = false;
TechnoVectorNonCeasefire.push_back(pTechno);
}
return;
};

for (const auto& pUnit : ObjectClass::CurrentObjects)
{
// try to cast to TechnoClass
TechnoClass* pTechno = abstract_cast<TechnoClass*>(pUnit);

// if not a techno or is in berserk or is not controlled by the local player then ignore it
if (!pTechno || pTechno->Berzerk || !pTechno->Owner->IsControlledByCurrentPlayer())
continue;

processATechno(pTechno);

if (auto pPassenger = pTechno->Passengers.GetFirstPassenger())
{
for (; pPassenger; pPassenger = abstract_cast<FootClass*>(pPassenger->NextObject))
processATechno(pPassenger);
}

if (auto pBuilding = abstract_cast<BuildingClass*>(pTechno))
{
for (auto pOccupier : pBuilding->Occupants)
processATechno(pOccupier);
}
}

// If this boolean is false, then none of the selected units are togglable, meaning this hotket doesn't need to do anything.
if (isAnySelectedUnitTogglable)
{
// If all selected units are Ceasefire mode, then cancel their Ceasefire mode;
// otherwise, make all selected units Ceasefire mode.
if (isAllSelectedUnitCeasefireMode)
{
for (const auto& pTechno : TechnoVectorCeasefire)
EventExt::RaiseTogglePassiveAcquireMode(pTechno, PassiveAcquireMode::Normal);

wchar_t buffer[0x100];
swprintf_s(buffer, GeneralUtils::LoadStringUnlessMissing("MSG:CEASEFIRE_MODE_OFF", L"%i unit(s) ceased Ceasefire Mode."), TechnoVectorCeasefire.size());
MessageListClass::Instance.PrintMessage(buffer);
}
else
{
for (const auto& pTechno : TechnoVectorNonCeasefire)
EventExt::RaiseTogglePassiveAcquireMode(pTechno, PassiveAcquireMode::Ceasefire);

wchar_t buffer[0x100];
swprintf_s(buffer, GeneralUtils::LoadStringUnlessMissing("MSG:CEASEFIRE_MODE_ON", L"%i unit(s) entered Ceasefire Mode."), TechnoVectorNonCeasefire.size());
MessageListClass::Instance.PrintMessage(buffer);
}
}
}
25 changes: 25 additions & 0 deletions src/Commands/PassiveAcquireMode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include "Commands.h"

class AggressiveModeClass : public CommandClass
{
public:
// CommandClass
virtual const char* GetName() const override;
virtual const wchar_t* GetUIName() const override;
virtual const wchar_t* GetUICategory() const override;
virtual const wchar_t* GetUIDescription() const override;
virtual void Execute(WWKey eInput) const override;
};

class CeasefireModeClass : public CommandClass
{
public:
// CommandClass
virtual const char* GetName() const override;
virtual const wchar_t* GetUIName() const override;
virtual const wchar_t* GetUICategory() const override;
virtual const wchar_t* GetUIDescription() const override;
virtual void Execute(WWKey eInput) const override;
};
3 changes: 3 additions & 0 deletions src/Ext/BuildingType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ void BuildingTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

this->Refinery_UseNormalActiveAnim.Read(exArtINI, pArtSection, "Refinery.UseNormalActiveAnim");

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

// Ares tag
this->SpyEffect_Custom.Read(exINI, pSection, "SpyEffect.Custom");
if (SuperWeaponTypeClass::Array.Count > 0)
Expand Down Expand Up @@ -334,6 +336,7 @@ void BuildingTypeExt::ExtData::Serialize(T& Stm)
.Process(this->BuildingRepairedSound)
.Process(this->Refinery_UseNormalActiveAnim)
.Process(this->HasPowerUpAnim)
.Process(this->AggressiveModeExempt)
;
}

Expand Down
3 changes: 3 additions & 0 deletions src/Ext/BuildingType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class BuildingTypeExt

ValueableVector<bool> HasPowerUpAnim;

Valueable<bool> AggressiveModeExempt;

ExtData(BuildingTypeClass* OwnerObject) : Extension<BuildingTypeClass>(OwnerObject)
, PowersUp_Owner { AffectedHouse::Owner }
, PowersUp_Buildings {}
Expand Down Expand Up @@ -161,6 +163,7 @@ class BuildingTypeExt
, BuildingRepairedSound {}
, Refinery_UseNormalActiveAnim { false }
, HasPowerUpAnim {}
, AggressiveModeExempt{}
{ }

// Ares 0.A functions
Expand Down
Loading