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 @@ -532,6 +532,7 @@ This page lists all the individual contributions to the project by their author.
- Fix a bug where passengers created by the InitialPayload logic or TeamType with `Full=true` would fail to fire when the transport unit with `OpenTopped=yes` moved to an area that the passengers' `MovementZone` cannot move into
- Fix a bug where game will crash after loading if a techno with `AlphaImage` converts to a type without it, or an anim with `AlphaImage` changes to a type without it through `Next`
- Fix a bug where updating the `OpenTopped` attribute during convert did not update the coordinates of passengers
- Aux technos of superweapon
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
Expand Down
9 changes: 9 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,15 @@ In `rulesmd.ini`:
TabIndex=1 ; integer
```

### Aux technos of superweapon

In `rulesmd.ini`:
```ini
[SOMESW] ; SuperWeaponType
SW.AuxTechnos= ; List of TechnoTypes
SW.NegTechnos= ; List of TechnoTypes
```

### EMPulse settings

- It is possible to customize which weapon a building with `EMPulseCannon=true` fires when an associated `Type=EMPulse` superweapon (**only** if `EMPulse.TargetSelf=false` or omitted) is fired by setting `EMPulse.WeaponIndex`.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ Fixes / interactions with other extensions:
- Fixed the issue that `BombSight` not being updated correctly in techno conversion (by TaranDahl)
- `EVA.Tag` already supports being set for specific countries, and `EVAIndex` is no longer reset after load game (by FlyStar)
- `DisableWeapons.Duration` now makes `Gattling=yes` rate tick down and stops the sounds from playing, no longer interferes with target acquisition and works together with Phobos' `OpenTopped.CheckTransportDisableWeapons` (by Starkku)
- Aux technos of superweapon (by NetsuNegi)
```

### 0.4.0.3
Expand Down
4 changes: 4 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/CREDITS.po
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,10 @@ msgid ""
"not update the coordinates of passengers"
msgstr "修复了类型转换会更新 `OpenTopped` 属性却不更新乘客坐标的 Bug"

msgid ""
"Aux technos of superweapon"
msgstr "超级武器的辅助单位"

msgid "**Apollo** - Translucent SHP drawing patches"
msgstr "**Apollo** - 半透明 SHP 绘制补丁"

Expand Down
3 changes: 3 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po
Original file line number Diff line number Diff line change
Expand Up @@ -2870,6 +2870,9 @@ msgid ""
" (vehicle tab)."
msgstr "有效值为:0(建筑栏)、1(防御栏)、2(步兵栏)、3(载具栏)。"

msgid "Aux technos of superweapon"
msgstr "超级武器的辅助单位"

msgid "EMPulse settings"
msgstr "EMPulse 设置"

Expand Down
4 changes: 4 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/Whats-New.po
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,10 @@ msgstr ""
"现在 `DisableWeapons.Duration` 会使 `Gattling=yes` 的速率降低并停止播放音效,不再干扰目标获取并且可以和"
" Phobos 的 `OpenTopped.CheckTransportDisableWeapons` 共用(by Starkku)"

msgid ""
"Aux technos of superweapon (by NetsuNegi)"
msgstr "超级武器的辅助单位(by NetsuNegi)"

msgid "0.4.0.3"
msgstr "0.4.0.3"

Expand Down
8 changes: 8 additions & 0 deletions src/Ext/SWType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->SW_ManualFire)
.Process(this->SW_ShowCameo)
.Process(this->SW_Unstoppable)
.Process(this->SW_AllowPlayer)
.Process(this->SW_AllowAI)
.Process(this->SW_Inhibitors)
.Process(this->SW_AnyInhibitor)
.Process(this->SW_Designators)
Expand All @@ -39,6 +41,8 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->SW_ForbiddenHouses)
.Process(this->SW_AuxBuildings)
.Process(this->SW_NegBuildings)
.Process(this->SW_AuxTechnos)
.Process(this->SW_NegTechnos)
.Process(this->SW_InitialReady)
.Process(this->SW_PostDependent)
.Process(this->SW_MaxCount)
Expand Down Expand Up @@ -116,6 +120,8 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_ManualFire.Read(exINI, pSection, "SW.ManualFire");
this->SW_ShowCameo.Read(exINI, pSection, "SW.ShowCameo");
this->SW_Unstoppable.Read(exINI, pSection, "SW.Unstoppable");
this->SW_AllowPlayer.Read(exINI, pSection, "SW.AllowPlayer");
this->SW_AllowAI.Read(exINI, pSection, "SW.AllowAI");
this->SW_Inhibitors.Read(exINI, pSection, "SW.Inhibitors");
this->SW_AnyInhibitor.Read(exINI, pSection, "SW.AnyInhibitor");
this->SW_Designators.Read(exINI, pSection, "SW.Designators");
Expand All @@ -126,6 +132,8 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_ForbiddenHouses = pINI->ReadHouseTypesList(pSection, "SW.ForbiddenHouses", this->SW_ForbiddenHouses);
this->SW_AuxBuildings.Read(exINI, pSection, "SW.AuxBuildings");
this->SW_NegBuildings.Read(exINI, pSection, "SW.NegBuildings");
this->SW_AuxTechnos.Read(exINI, pSection, "SW.AuxTechnos");
this->SW_NegTechnos.Read(exINI, pSection, "SW.NegTechnos");
this->SW_InitialReady.Read(exINI, pSection, "SW.InitialReady");
this->SW_PostDependent.Read(exINI, pSection, "SW.PostDependent");
this->SW_MaxCount.Read(exINI, pSection, "SW.MaxCount");
Expand Down
10 changes: 9 additions & 1 deletion src/Ext/SWType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class SWTypeExt
Valueable<bool> SW_ManualFire;
Valueable<bool> SW_ShowCameo;
Valueable<bool> SW_Unstoppable;
Valueable<bool> SW_AllowPlayer;
Valueable<bool> SW_AllowAI;
ValueableVector<TechnoTypeClass*> SW_Inhibitors;
Valueable<bool> SW_AnyInhibitor;
ValueableVector<TechnoTypeClass*> SW_Designators;
Expand All @@ -40,6 +42,8 @@ class SWTypeExt
DWORD SW_ForbiddenHouses;
ValueableVector<BuildingTypeClass*> SW_AuxBuildings;
ValueableVector<BuildingTypeClass*> SW_NegBuildings;
ValueableVector<TechnoTypeClass*> SW_AuxTechnos;
ValueableVector<TechnoTypeClass*> SW_NegTechnos;
Valueable<bool> SW_InitialReady;
ValueableIdx<SuperWeaponTypeClass> SW_PostDependent;
Valueable<int> SW_MaxCount;
Expand Down Expand Up @@ -119,6 +123,8 @@ class SWTypeExt
, SW_ManualFire { true }
, SW_ShowCameo { true }
, SW_Unstoppable { false }
, SW_AllowPlayer { true }
, SW_AllowAI { true }
, SW_Inhibitors {}
, SW_AnyInhibitor { false }
, SW_Designators { }
Expand All @@ -129,6 +135,8 @@ class SWTypeExt
, SW_ForbiddenHouses { 0u }
, SW_AuxBuildings {}
, SW_NegBuildings {}
, SW_AuxTechnos {}
, SW_NegTechnos {}
, SW_InitialReady { false }
, SW_PostDependent {}
, SW_MaxCount { -1 }
Expand Down Expand Up @@ -242,5 +250,5 @@ class SWTypeExt
static bool SaveGlobals(PhobosStreamWriter& Stm);

static bool Activate(SuperClass* pSuper, CellStruct cell, bool isPlayer);

static SuperClass* __stdcall IsSuperAvailable(int swIdx, HouseClass* pHouse);
};
74 changes: 49 additions & 25 deletions src/Ext/SWType/SWHelpers.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "Body.h"
#include <MessageListClass.h>

#include <Ext/House/Body.h>

// Universal handler of the rolls-weights system
std::vector<int> SWTypeExt::ExtData::WeightedRollsHandler(ValueableVector<float>* rolls, std::vector<ValueableVector<int>>* weights, size_t size)
{
Expand Down Expand Up @@ -170,45 +172,54 @@ std::pair<double, double> SWTypeExt::ExtData::GetLaunchSiteRange(BuildingClass*
bool SWTypeExt::ExtData::IsAvailable(HouseClass* pHouse) const
{
const auto pThis = this->OwnerObject();
const int shots = this->SW_Shots;

if (shots >= 0 && HouseExt::ExtMap.Find(pHouse)->SuperExts[pThis->ArrayIndex].ShotCount >= shots)
return false;

if (pHouse->IsControlledByHuman() ? (!this->SW_AllowPlayer) : (!this->SW_AllowAI))
return false;

auto IsTechnoPresent = [pHouse](TechnoTypeClass* pType)
{
const auto pBuildingType = abstract_cast<BuildingTypeClass*, true>(pType);

if (pBuildingType && (!BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.empty() || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding)))
return BuildingTypeExt::GetUpgradesAmount(pBuildingType, pHouse) > 0;

return HouseExt::ExtMap.Find(pHouse)->CountOwnedPresentAndLimboed(pType) > 0;
};

// check whether the optional aux building exists
if (pThis->AuxBuilding)
{
if ((BuildingTypeExt::ExtMap.Find(pThis->AuxBuilding)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pThis->AuxBuilding->PowersUpBuilding))
&& BuildingTypeExt::GetUpgradesAmount(pThis->AuxBuilding, pHouse) <= 0)
return false;
else if (pHouse->CountOwnedAndPresent(pThis->AuxBuilding) <= 0)
return false;
}
if (pThis->AuxBuilding && !IsTechnoPresent(pThis->AuxBuilding))
return false;

// allow only certain houses, disallow forbidden houses
const auto OwnerBits = 1u << pHouse->Type->ArrayIndex;
const auto ownerBits = 1u << pHouse->Type->ArrayIndex;

if (!(this->SW_RequiredHouses & OwnerBits) || (this->SW_ForbiddenHouses & OwnerBits))
if (!(this->SW_RequiredHouses & ownerBits) || (this->SW_ForbiddenHouses & ownerBits))
return false;

// check that any aux building exist and no neg building
auto IsBuildingPresent = [pHouse](BuildingTypeClass* pType)
{
if (pType)
{
if (BuildingTypeExt::ExtMap.Find(pType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pType->PowersUpBuilding))
return BuildingTypeExt::GetUpgradesAmount(pType, pHouse) > 0;
else
return pHouse->CountOwnedAndPresent(pType) > 0;
}

return false;
};
const auto& auxBuildings = this->SW_AuxBuildings;

if (!auxBuildings.empty() && std::ranges::none_of(auxBuildings, IsTechnoPresent))
return false;

const auto& negBuildings = this->SW_NegBuildings;

if (std::ranges::any_of(negBuildings, IsTechnoPresent))
return false;

const auto& Aux = this->SW_AuxBuildings;
const auto& auxTechnos = this->SW_AuxTechnos;

if (!Aux.empty() && std::none_of(Aux.begin(), Aux.end(), IsBuildingPresent))
if (!auxTechnos.empty() && std::ranges::none_of(auxTechnos, IsTechnoPresent))
return false;

const auto& Neg = this->SW_NegBuildings;
const auto& negTechnos = this->SW_NegTechnos;

if (std::any_of(Neg.begin(), Neg.end(), IsBuildingPresent))
if (std::ranges::any_of(negTechnos, IsTechnoPresent))
return false;

return true;
Expand Down Expand Up @@ -309,3 +320,16 @@ void SWTypeExt::ExtData::PrintMessage(const CSFText& message, HouseClass* pFirer
// print the message
MessageListClass::Instance.PrintMessage(message, RulesClass::Instance->MessageDelay, color);
}

SuperClass* __stdcall SWTypeExt::IsSuperAvailable(int swIdx, HouseClass* pHouse)
{
if (const auto pSuper = pHouse->Supers.GetItemOrDefault(swIdx))
{
const auto pExt = SWTypeExt::ExtMap.Find(pSuper->Type);

if (pExt->IsAvailable(pHouse))
return pSuper;
}

return nullptr;
}
3 changes: 3 additions & 0 deletions src/Ext/Techno/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,9 @@ DEFINE_HOOK(0x6F4500, TechnoClass_DTOR, 0x5)
{
GET(TechnoClass*, pItem, ECX);

if (pItem->AbstractFlags & AbstractFlags::Foot)
pItem->Owner->RecheckTechTree = true; // for SW.AuxTechons and SW.NegTechnos

TechnoExt::ExtMap.Remove(pItem);

return 0;
Expand Down
3 changes: 3 additions & 0 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ DEFINE_HOOK(0x6F42F7, TechnoClass_Init, 0x2)
pThis->TargetingTimer.Start(ScenarioClass::Instance->Random.RandomRanged(0, 15));
}

if (pThis->AbstractFlags & AbstractFlags::Foot)
pThis->Owner->RecheckTechTree = true; // for SW.AuxTechons and SW.NegTechnos

return 0;
}

Expand Down
14 changes: 14 additions & 0 deletions src/Misc/Hooks.Ares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <Ext/Building/Body.h>
#include <Ext/Sidebar/Body.h>
#include <Ext/EBolt/Body.h>
#include <Ext/SWType/Body.h>

#include <New/Entity/Ares/RadarJammerClass.h>

Expand Down Expand Up @@ -68,6 +69,11 @@ static bool __fastcall CameoIsVeteran(TechnoTypeClass** pTypeExt_Ares, void*, Ho
return TechnoTypeExt::ExtMap.Find(*pTypeExt_Ares)->CameoIsVeteran(pHouse);
}

static bool __fastcall SW_IsAvailable(SuperWeaponTypeClass** pExt_Ares, void*, HouseClass* pHouse)
{
return SWTypeExt::ExtMap.Find(*pExt_Ares)->IsAvailable(pHouse);
}

namespace PermaMCTemp
{
bool Selected = false;
Expand Down Expand Up @@ -181,6 +187,10 @@ void Apply_Ares3_0_Patches()
// Redirect Ares's TechnoTypeExt::ExtData::CameoIsElite() to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x3D800, &CameoIsVeteran);

// Redirect Ares's SWTypeExt::ExtData::IsAvailable to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x32BE0, &SW_IsAvailable);
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x329E0, &SWTypeExt::IsSuperAvailable);

// Remove Ares check for houses for Psychedelic=yes Warheads.
Patch::Apply_RAW(AresHelper::AresBaseAddress + 0x4AAAA, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 });

Expand Down Expand Up @@ -263,6 +273,10 @@ void Apply_Ares3_0p1_Patches()
// Redirect Ares's TechnoTypeExt::ExtData::CameoIsElite() to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x3E210, &CameoIsVeteran);

// Redirect Ares's SWTypeExt::ExtData::IsAvailable to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x335E0, &SW_IsAvailable);
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x333E0, &SWTypeExt::IsSuperAvailable);

// Remove Ares check for houses for Psychedelic=yes Warheads.
Patch::Apply_RAW(AresHelper::AresBaseAddress + 0x4B70A, { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 });

Expand Down
Loading