Skip to content
Draft
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 @@ -536,6 +536,7 @@ This page lists all the individual contributions to the project by their author.
- Aux technos and TechLevel requirement of superweapon
- Allow `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades
- Fix the bug where passengers, when their transport unit is removed, would cause incorrect `LimboTracker` counts due to either having their destructor called directly (bypassing `UnInit`) or nested `UnInit` calls resetting the deletion flag too early, thereby breaking auto-death and superweapon auxiliary techno checks
- Improve occupants firing logic
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
Expand Down
2 changes: 1 addition & 1 deletion YRpp
13 changes: 13 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,19 @@ In `rulesmd.ini`:
Cloning.Powered=true ; boolean
```

### Improve occupants firing logic

- In vanilla, the range of all occupy weapons can only use the value specified by `[CombatDamage] -> OccupyWeaponRange` . Additionally, the original alternating-fire processing has many limitations; for example, if an occupying unit cannot attack the target due to issues such as `Versus` , `AA` , etc., the entire firing process will get stuck there and be unable to attack. Now you can use a new system.
- `FixOccupyFire` can be used to enable the new system, where all occupying infantry handle firing actions independently without affecting each other.
- `UseGlobalOccupyRange` can be used to determine whether occupy weapons use a unified range. If set to `false` , they will use their own `Range` to determine distance.

In `rulesmd.ini`:
```ini
[CombatDamage]
FixOccupyFire=false ; boolean
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ExtendedOccupyFire

UseGlobalOccupyRange=true ; boolean
```

## Infantry

### Auto deploy for GI-like infantry
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ New:
- [Electric bolt Z-adjust](Fixed-or-Improved-Logics.md#electric-bolt-z-adjust) (by Noble_Fish)
- Allow disabling the processing of the Z-depth of EBolt drawn by BuildingType being clamped to non-positive numbers (by Noble_Fish)
- Add the `Bolt.ZAdjust` setting item to the LaserTrailType with `DrawType=ebolt` (by Noble_Fish)
- [Improve occupants firing logic](Fixed-or-Improved-Logics.md#improve-occupants-firing-logic) (by NetsuNegi)
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 docs/locale/zh_CN/LC_MESSAGES/CREDITS.po
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,9 @@ msgstr ""
msgid "Fix the bug where passengers, when their transport unit is removed, would cause incorrect `LimboTracker` counts due to either having their destructor called directly (bypassing `UnInit`) or nested `UnInit` calls resetting the deletion flag too early, thereby breaking auto-death and superweapon auxiliary techno checks"
msgstr "修复了乘客在其所在的运输工具被移除时,因被直接调用析构函数(绕过 `UnInit` )或 `UnInit` 嵌套调用导致删除标志过早重置,从而使 `LimboTracker` 计数错误,进而影响自动死亡及超武辅助单位判定的 Bug"

msgid "Improve occupants firing logic"
msgstr "改进驻扎开火逻辑"

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

Expand Down
27 changes: 27 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po
Original file line number Diff line number Diff line change
Expand Up @@ -3261,6 +3261,33 @@ msgid ""
" 2.0, they need power to work. Now you can specific it."
msgstr "在原版中,克隆缸即便没电也可以工作。从 Ares 2.0 开始,它们需要电力运作。现在你可以指定。"

msgid "Improve occupants firing logic"
msgstr "改进的驻扎开火逻辑"

msgid ""
"In vanilla, the range of all occupy weapons can only use the value "
"specified by `[CombatDamage] -> OccupyWeaponRange` . Additionally, the "
"original alternating-fire processing has many limitations; for example, "
"if an occupying unit cannot attack the target due to issues such as "
"`Versus` , `AA` , etc., the entire firing process will get stuck there "
"and be unable to attack. Now you can use a new system."
msgstr ""
"在原版中, 所有驻军武器的射程都只能使用 `[CombatDamage] -> OccupyWeaponRange` 指定的值,并且原有的轮流开火式处理存在诸多限制,例如只要一名驻员由于 `Versus`、`AA` 等问题而无法攻击目标,整个开火流程就会卡在那里而无法攻击。现在你可以使用一套新的系统。"

msgid ""
"`FixOccupyFire` can be used to enable the new system, where all occupying"
" infantry handle firing actions independently without affecting each "
"other."
msgstr ""
"`FixOccupyFire` 可用于开启新的系统,所有驻军步兵独立处理开火动作,互不影响。"

msgid ""
"`UseGlobalOccupyRange` can be used to determine whether occupy weapons "
"use a unified range. If set to `false` , they will use their own `Range` "
"to determine distance."
msgstr ""
"`UseGlobalOccupyRange` 可用于决定驻军武器是否使用统一射程。若设为 `false`,它们将会使用自身的 `Range` 决定距离。"

msgid "Infantry"
msgstr "步兵"

Expand Down
7 changes: 7 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/Whats-New.po
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,13 @@ msgid ""
"`DrawType=ebolt` (by Noble_Fish)"
msgstr ""

msgid ""
"[Improve occupants firing logic](Fixed-or-Improved-Logics.md#improve-"
"occupants-firing-logic) (by NetsuNegi)"
msgstr ""
"[改进的驻扎开火逻辑](Fixed-or-Improved-Logics.md#improve-occupants-firing-"
"logic)(by NetsuNegi)"

msgid "Vanilla fixes:"
msgstr "原版问题修复:"

Expand Down
68 changes: 68 additions & 0 deletions src/Ext/Building/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

BuildingExt::ExtContainer BuildingExt::ExtMap;

bool BuildingExt::ConsideringSpecificOccupant = false;

void BuildingExt::ExtData::DisplayIncomeString()
{
if (this->AccumulatedIncome)
Expand Down Expand Up @@ -448,6 +450,72 @@ WeaponStruct* BuildingExt::GetLaserWeapon(BuildingClass* pThis)
return pThis->GetPrimaryWeapon();
}

bool BuildingExt::CanOccupantsFire(BuildingClass* pThis, AbstractClass* pTarget)
{
if (!pTarget)
return false;

if (RulesExt::Global()->UseGlobalOccupyRange && !pThis->IsCloseEnough(pTarget, 0))
return false;

int& firingIdx = pThis->FiringOccupantIndex;
const int originalFiringIdx = firingIdx;
const auto& occupants = pThis->Occupants;

for (firingIdx = 0; firingIdx < occupants.Count; ++firingIdx)
{
constexpr int weaponIdx = 0;

switch (pThis->TechnoClass::GetFireError(pTarget, weaponIdx, !RulesExt::Global()->UseGlobalOccupyRange))
{
case FireError::ILLEGAL:
case FireError::CANT:
case FireError::RANGE:
continue;

default:
break;
}

firingIdx = originalFiringIdx;
return true;
}

firingIdx = originalFiringIdx;
return false;
}

int BuildingExt::GetOccupantsRange(BuildingClass* pThis)
{
if (RulesExt::Global()->UseGlobalOccupyRange)
return (pThis->GetOccupyRangeBonus() + RulesClass::Instance->OccupyWeaponRange) << 8;

int maximumRange = 0;

for (const auto pOccupier : pThis->Occupants)
{
constexpr int weaponIdx = 0;
auto pWeapon = pOccupier->Veterancy.IsElite()
? pOccupier->Type->EliteOccupyWeapon.WeaponType
: pOccupier->Type->OccupyWeapon.WeaponType;

if (!pWeapon)
{
pWeapon = pOccupier->GetWeapon(weaponIdx)->WeaponType;

if (!pWeapon)
continue;
}

int range = pWeapon->Range;

if (maximumRange < range)
maximumRange = range;
}

return maximumRange;
}

void BuildingExt::KickOutClone(std::pair<TechnoTypeClass*, HouseClass*>& info, void*, BuildingClass* pFactory)
{
if (!pFactory->IsAlive || pFactory->InLimbo || (BuildingTypeExt::ExtMap.Find(pFactory->Type)->Cloning_Powered && !pFactory->IsPowerOnline()) || pFactory->IsBeingWarpedOut())
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Building/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class BuildingExt

static ExtContainer ExtMap;

static bool ConsideringSpecificOccupant;

static bool LoadGlobals(PhobosStreamReader& Stm);
static bool SaveGlobals(PhobosStreamWriter& Stm);

Expand All @@ -101,5 +103,7 @@ class BuildingExt
static void KickOutStuckUnits(BuildingClass* pThis);
static const std::vector<CellStruct> GetFoundationCells(BuildingClass* pThis, CellStruct baseCoords, bool includeOccupyHeight = false);
static WeaponStruct* GetLaserWeapon(BuildingClass* pThis);
static bool CanOccupantsFire(BuildingClass* pThis, AbstractClass* pTarget);
static int GetOccupantsRange(BuildingClass* pThis);
static void __fastcall KickOutClone(std::pair<TechnoTypeClass*, HouseClass*>& info, void*, BuildingClass* pFactory);
};
70 changes: 70 additions & 0 deletions src/Ext/Building/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,76 @@ DEFINE_HOOK(0x4555E4, BuildingClass_IsPowerOnline_Overpower, 0x6)
return overPower < keepOnline ? LowPower : (R->Origin() == 0x4555E4 ? Continue1 : Continue2);
}

DEFINE_HOOK(0x44AD07, BuildingClass_Mission_Attack_OccupyFire, 0x6)
{
enum { ReturnFromFunction = 0x44AFE0 };

if (!RulesExt::Global()->FixOccupyFire && RulesExt::Global()->UseGlobalOccupyRange)
return 0;

GET(BuildingTypeClass*, pType, EAX);

if (!pType->CanBeOccupied)
return 0;

GET(BuildingClass*, pThis, ESI);
const auto pTarget = pThis->Target;
bool canFire = false;
const auto& occupants = pThis->Occupants;

if (pType->CanOccupyFire && occupants.Count && (!RulesExt::Global()->UseGlobalOccupyRange || pThis->IsCloseEnough(pTarget, 0)))
{
int& firingIdx = pThis->FiringOccupantIndex;
const int originalFiringIdx = firingIdx;
BuildingExt::ConsideringSpecificOccupant = true;

for (firingIdx = 0; firingIdx < occupants.Count;)
{
const auto pOccupier = occupants[firingIdx];
constexpr int weaponIdx = 0;
const auto fireError = pThis->GetFireError(pTarget, weaponIdx, !RulesExt::Global()->UseGlobalOccupyRange);

if (fireError == FireError::ILLEGAL
|| fireError == FireError::CANT
|| fireError == FireError::RANGE)
{
++firingIdx;
continue;
}

canFire = true;

if (fireError != FireError::OK)
{
++firingIdx;
continue;
}

pThis->Fire(pTarget, weaponIdx);

if (pOccupier->IsAlive && pOccupier->Health)
++firingIdx;
}

BuildingExt::ConsideringSpecificOccupant = false;
firingIdx = originalFiringIdx;
}

if (!canFire)
{
pThis->SetTarget(nullptr);
pThis->SupportingPrisms = 0;

if (pThis->IsNotWarpingIn())
pThis->TryNextPlanningTokenNode();

if (pThis->GetCurrentMission() != Mission::Wait)
pThis->ForceMission(Mission::Guard);
}

return ReturnFromFunction;
}

#pragma region OwnerChangeBuildupFix

static void __fastcall BuildingClass_Place_Wrapper(BuildingClass* pThis, void*, bool captured)
Expand Down
5 changes: 5 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)

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

this->FixOccupyFire.Read(exINI, GameStrings::CombatDamage, "FixOccupyFire");
this->UseGlobalOccupyRange.Read(exINI, GameStrings::CombatDamage, "UseGlobalOccupyRange");

// Section AITargetTypes
int itemsCount = pINI->GetKeyCount("AITargetTypes");
for (int i = 0; i < itemsCount; ++i)
Expand Down Expand Up @@ -737,6 +740,8 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->FiringAnim_Update)
.Process(this->ExtendedPlayerRepair)
.Process(this->Shrapnel_IgnoreHitBuildings)
.Process(this->FixOccupyFire)
.Process(this->UseGlobalOccupyRange)
;
}

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

Valueable<bool> Shrapnel_IgnoreHitBuildings;

Valueable<bool> FixOccupyFire;
Valueable<bool> UseGlobalOccupyRange;

ExtData(RulesClass* OwnerObject) : Extension<RulesClass>(OwnerObject)
, Storage_TiberiumIndex { -1 }
Expand Down Expand Up @@ -643,6 +646,9 @@ class RulesExt
, FiringAnim_Update { false }
, ExtendedPlayerRepair { false }
, Shrapnel_IgnoreHitBuildings { false }

, FixOccupyFire { false }
, UseGlobalOccupyRange { true }
{ }

virtual ~ExtData() = default;
Expand Down
Loading
Loading