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 @@ -292,6 +292,7 @@ This page lists all the individual contributions to the project by their author.
- Fix vehicles disguised as trees incorrectly displaying veterancy insignia when they shouldn't
- GapGen + SpySat desync fix
- Frame CRC generation rewrite
- Berzerk duration stacking behaviour customization
- **Morton (MortonPL)**:
- `XDrawOffset` for animations
- Shield passthrough & absorption
Expand Down
13 changes: 13 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2446,6 +2446,19 @@ AllowBerzerkOnAllies=false ; boolean
No per-warhead setting because `AffectsAllies` etc. is respected.
```

### Berzerk (Psychedelic) duration stacking customization

- By default `Psychedelic` warheads override the current duration of the berzerk effect regardless of if the new duration is higher or lower than the current one. This can now be customized with `Psychedelic.StackingMode`, with both global setting under `[CombatDamage]` and per-Warhead customization.

In `rulesmd.ini`:
```ini
[CombatDamage]
Psychedelic.StackingMode=override ; Stacking mode enum (override|setifzero|min|max|add|subtract|multiply|divide)

[SOMEWARHEAD] ; WarheadType
Psychedelic.StackingMode= ; Stacking mode enum (override|setifzero|min|max|add|subtract|multiply|divide)
```

### Combat light customizations

- You can now set minimum detail level at which combat light effects are shown by setting `[AudioVisual] -> CombatLightDetailLevel` or `CombatLightDetailLevel` on Warhead.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ New:
- Customize `HarvesterLoadRate` (by Noble_Fish)
- [Toggle to prevent `ShrapnelWeapon` from targeting buildings multiple times](Fixed-or-Improved-Logics.md#shrapnel-enhancements) (by Starkku)
- [Laser drawing Z-adjust customization](Fixed-or-Improved-Logics.md#laser-z-adjust) (by Starkku)
- [Berzerk / `Psychedelic` duration stacking customization](Fixed-or-Improved-Logics.md#berzerk-psychedelic-duration-stacking-customization) (by Starkku)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->ExtendedPlayerRepair.Read(exINI, GameStrings::General, "ExtendedPlayerRepair");

this->Shrapnel_IgnoreHitBuildings.Read(exINI, GameStrings::CombatDamage, "Shrapnel.IgnoreHitBuildings");
this->Psychedelic_StackingMode.Read(exINI, GameStrings::CombatDamage, "Psychedelic.StackingMode");

// Section AITargetTypes
int itemsCount = pINI->GetKeyCount("AITargetTypes");
Expand Down Expand Up @@ -726,6 +727,7 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->FiringAnim_Update)
.Process(this->ExtendedPlayerRepair)
.Process(this->Shrapnel_IgnoreHitBuildings)
.Process(this->Psychedelic_StackingMode)
;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ class RulesExt
Valueable<bool> ShipLocomotorMakesWake;

Valueable<bool> Shrapnel_IgnoreHitBuildings;

Valueable<StackingMode> Psychedelic_StackingMode;

ExtData(RulesClass* OwnerObject) : Extension<RulesClass>(OwnerObject)
, Storage_TiberiumIndex { -1 }
Expand Down Expand Up @@ -636,7 +638,9 @@ class RulesExt
, ShipLocomotorMakesWake { true }
, FiringAnim_Update { false }
, ExtendedPlayerRepair { false }

, Shrapnel_IgnoreHitBuildings { false }
, Psychedelic_StackingMode { StackingMode::Override }
{ }

virtual ~ExtData() = default;
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

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

this->Psychedelic_StackingMode.Read(exINI, pSection, "Psychedelic.StackingMode");

// Convert.From & Convert.To
TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All);

Expand Down Expand Up @@ -742,6 +744,8 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)

.Process(this->Taunt)

.Process(this->Psychedelic_StackingMode)

// Ares tags
.Process(this->AffectsEnemies)
.Process(this->AffectsOwner)
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ class WarheadTypeExt

Valueable<bool> Taunt;

Nullable<StackingMode> Psychedelic_StackingMode;

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
Valueable<bool> AffectsEnemies;
Expand Down Expand Up @@ -522,6 +524,8 @@ class WarheadTypeExt
, ApplyPerTargetEffectsOnDetonate {}

, Taunt { false }

, Psychedelic_StackingMode {}
{ }

void ApplyConvert(HouseClass* pHouse, TechnoClass* pTarget);
Expand Down
14 changes: 14 additions & 0 deletions src/Ext/WarheadType/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,3 +665,17 @@ DEFINE_HOOK(0x48DC90, MapClass_UnselectAll_ClearLimboLaunchers, 0x5)
}

#pragma endregion

DEFINE_HOOK(0x701D6B, TechnoClass_ReceiveDamage_Psychedelic, 0x6)
{
enum { SkipGameCode = 0x701D71 };

GET(TechnoClass*, pThis, ESI);
GET(WarheadTypeClass*, pWH, EBP);
GET(int, damage, EAX);

auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWH);
EnumFunctions::CalcValueWithStackingMode(pThis->BerzerkDurationLeft, damage, pWHExt->Psychedelic_StackingMode);

return SkipGameCode;
}
12 changes: 12 additions & 0 deletions src/Utilities/Enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,18 @@ enum class DamageDisplayType
Intercept = 2
};

enum class StackingMode
{
Override = 0,
SetIfZero = 1,
Min = 2,
Max = 3,
Add = 4,
Subtract = 5,
Multiply = 6,
Divide = 7
};

enum class ChronoSparkleDisplayPosition : unsigned char
{
None = 0x0,
Expand Down
47 changes: 47 additions & 0 deletions src/Utilities/EnumFunctions.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "EnumFunctions.h"

#include <Utilities/GeneralUtils.h>

bool EnumFunctions::CanTargetHouse(AffectedHouse flags, HouseClass* ownerHouse, HouseClass* targetHouse)
{
if (flags == AffectedHouse::All)
Expand Down Expand Up @@ -111,3 +113,48 @@ bool EnumFunctions::AreCellAndObjectsEligible(CellClass* const pCell, AffectedTa

return true;
}

bool EnumFunctions::CalcValueWithStackingMode(int& oldValue, int newValue, StackingMode stackingMode)
{
bool valueChanged = true;
int oldValueTemp = oldValue;

switch (stackingMode)
{
case StackingMode::Override:
oldValue = newValue;
break;
case StackingMode::SetIfZero:
if (oldValue == 0)
oldValue = newValue;
else
valueChanged = false;
break;
case StackingMode::Min:
oldValue = Math::min(oldValue, newValue);
break;
case StackingMode::Max:
oldValue = Math::max(oldValue, newValue);
break;
case StackingMode::Add:
oldValue += newValue;
break;
case StackingMode::Subtract:
oldValue -= newValue;
break;
case StackingMode::Multiply:
oldValue = GeneralUtils::SafeMultiply(oldValue, newValue);
break;
case StackingMode::Divide:
if (newValue != 0)
oldValue /= newValue;
else
valueChanged = false;
break;
default:
valueChanged = false;
break;
}

return valueChanged && oldValueTemp != oldValue;
}
1 change: 1 addition & 0 deletions src/Utilities/EnumFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ class EnumFunctions
static bool IsCellEligible(CellClass* const pCell, AffectedTarget allowed, bool explicitEmptyCells = false, bool considerBridgesLand = false);
static bool IsTechnoEligible(TechnoClass* const pTechno, AffectedTarget allowed, bool considerAircraftSeparately = false);
static bool AreCellAndObjectsEligible(CellClass* const pCell, AffectedTarget allowed, AffectedHouse allowedHouses, HouseClass* owner, bool explicitEmptyCells = false, bool considerAircraftSeparately = false, bool allowBridges = false);
static bool CalcValueWithStackingMode(int& oldValue, int newValue, StackingMode stackingMode);
};
49 changes: 49 additions & 0 deletions src/Utilities/TemplateDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,55 @@ namespace detail
return false;
}

template <>
inline bool read<StackingMode>(StackingMode& value, INI_EX& parser, const char* pSection, const char* pKey)
{
if (parser.ReadString(pSection, pKey))
{
if (_strcmpi(parser.value(), "override") == 0)
{
value = StackingMode::Override;
}
if (_strcmpi(parser.value(), "setifzero") == 0)
{
value = StackingMode::SetIfZero;
}
else if (_strcmpi(parser.value(), "min") == 0)
{
value = StackingMode::Min;
}
else if (_strcmpi(parser.value(), "max") == 0)
{
value = StackingMode::Max;
}
else if (_strcmpi(parser.value(), "add") == 0)
{
value = StackingMode::Add;
}
else if (_strcmpi(parser.value(), "subtract") == 0)
{
value = StackingMode::Subtract;
}
else if (_strcmpi(parser.value(), "multiply") == 0)
{
value = StackingMode::Multiply;
}
else if (_strcmpi(parser.value(), "divide") == 0)
{
value = StackingMode::Divide;
}
else
{
Debug::INIParseFailed(pSection, pKey, parser.value(), "Expected a stacking mode type");
return false;
}

return true;
}

return false;
}

template <>
inline bool read<ChronoSparkleDisplayPosition>(ChronoSparkleDisplayPosition& value, INI_EX& parser, const char* pSection, const char* pKey)
{
Expand Down
Loading