Skip to content

MultiWeapon #1630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b39fac3
update code.
a851903106 Apr 16, 2025
08718f8
Merge branch 'Multi' of https://github.com/a851903106/StarBos into Multi
a851903106 Apr 16, 2025
685a81d
what?
a851903106 Apr 16, 2025
ee96284
oh test
a851903106 Apr 16, 2025
6aaceab
update doc again.
a851903106 Apr 16, 2025
1644f42
supplement the code.
a851903106 Apr 16, 2025
b0d1c9d
Merge branch 'develop' into Multi
a851903106 Apr 20, 2025
e8bee47
I should have been more careful.
a851903106 Apr 20, 2025
a6b1c21
Merge branch 'develop' into Multi
a851903106 Apr 21, 2025
0ec4836
Merge branch 'develop' into Multi
a851903106 Apr 24, 2025
0e4f8ac
Merge branch 'develop' into Multi
a851903106 Apr 28, 2025
39f0870
Merge branch 'develop' into Multi
a851903106 May 2, 2025
212dabc
update code.
a851903106 May 2, 2025
89b7bc0
handle merger conflicts.
a851903106 May 2, 2025
b7e75f9
delete the incorrect text
a851903106 May 2, 2025
8e80a1c
why is yrpp lacking parameters?
a851903106 May 2, 2025
b3e7f98
oh.
a851903106 May 2, 2025
b9b8996
another
a851903106 May 2, 2025
662cfaf
why, bro
a851903106 May 2, 2025
ed0b88f
fix something.
a851903106 May 2, 2025
c8a3b0f
did it fail to be generated?
a851903106 May 3, 2025
5da05e2
Merge branch 'Phobos-developers:develop' into Multi
a851903106 May 3, 2025
f889341
disable unlimited spawn.
a851903106 May 3, 2025
d3fb89d
fix an error
a851903106 May 3, 2025
9a1c260
separate code
a851903106 May 3, 2025
be09114
delete
a851903106 May 3, 2025
11315a3
and add
a851903106 May 3, 2025
343c68a
what?
a851903106 May 3, 2025
b2e9113
It's settled then!
DeathFishAtEase May 4, 2025
534e2f4
Merge branch 'Phobos-developers:develop' into Multi
a851903106 May 5, 2025
fcd42df
Merge branch 'develop' into Multi
a851903106 May 8, 2025
3fd585a
Merge branch 'develop' into Multi
a851903106 May 9, 2025
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 @@ -357,6 +357,7 @@ This page lists all the individual contributions to the project by their author.
- Fix the issue where computer players did not search for new enemies after defeating them or forming alliances with them
- Customize the damage taken when falling from a bridge
- `600 The shield of the attached object is broken` bug fix for the triggered event
- Can use more weapons
- **NetsuNegi**:
- Forbidding parallel AI queues by type
- Jumpjet crash speed fix when crashing onto building
Expand Down
2 changes: 2 additions & 0 deletions Phobos.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<ClCompile Include="src\Ext\House\Hooks.ForceEnemy.cpp" />
<ClCompile Include="src\Ext\TechnoType\Hooks.MatrixOp.cpp" />
<ClCompile Include="src\Ext\Techno\Hooks.Airstrike.cpp" />
<ClCompile Include="src\Ext\Techno\Body.MultiWeapon.cpp" />
<ClCompile Include="src\Ext\TechnoType\Hooks.MultiWeapon.cpp" />
<ClCompile Include="src\Ext\Unit\Hooks.Harvester.cpp" />
<ClCompile Include="src\Ext\Unit\Hooks.Sinking.cpp" />
<ClCompile Include="src\Misc\Hooks.AlphaImage.cpp" />
Expand Down
18 changes: 18 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,24 @@ MindControlLink.VisibleToHouse=all ; Affected House Enumeration (none|owner/s
MultiMindControl.ReleaseVictim=false ; boolean
```

### Multi Weapon

![Multi Weapon](_static/images/multiweapons.gif)
*Multi Weapon used to release different weapons against different targets in **Zero Boundary** by @[Stormsulfur](https://space.bilibili.com/11638715/lists/5358986)*

- You are free to decide whether to use Weapon x or not, instead of passively using Primary/secondary.
- TechnoType reads `WeaponX` as their weapon when `MultiWeapon=yes`, be careful not to forget `WeaponCount`.
- `MultiWeapon.IsSecondary` can only be used for infantry and is responsible for determining which weapons should use `SecondaryFire` in the `Sequence`.
- `MultiWeapon.SelectWeapon` determines how many weapons can be selected. maximum value is 4, minimum value is 1, defaults to 2.

In `rulesmd.ini`:
```ini
[SOMETECHNO] ; TechnoType
MultiWeapon= ; boolean
MultiWeapon.IsSecondary= ; List of integers
MultiWeapon.SelectWeapon= ; integer
```

### No Manual Move

- You can now specify whether a TechnoType is unable to receive move command.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ New:
- [Use `InsigniaType` to set the properties of insignia in a batch](Miscellanous.md#insignia-type) (by Ollerus)
- [Tiberium eater logic](New-or-Enhanced-Logics.md#tiberium-eater) (by NetsuNegi)
- [Customize the damage taken when falling from a bridge](Fixed-or-Improved-Logics.md#customize-bridge-falling-down-damage) (by FlyStar)
- Can use more weapons (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
Binary file added docs/_static/images/multiweapons.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions src/Ext/Techno/Body.MultiWeapon.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include "Body.h"

#include <InfantryClass.h>
#include <HouseClass.h>
#include <OverlayTypeClass.h>
#include <TerrainClass.h>
#include <SpawnManagerClass.h>
#include <SlaveManagerClass.h>
#include <AirstrikeClass.h>
#include <Kamikaze.h>

#include <Ext/BulletType/Body.h>
#include <Ext/WeaponType/Body.h>
#include <Utilities/GeneralUtils.h>
#include <Utilities/EnumFunctions.h>

bool TechnoExt::CheckMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget, WeaponTypeClass* const pWeaponType)
{
if (!pThis || !pTarget)
return false;

if (!pWeaponType || pWeaponType->NeverUse)
return false;

if (pThis->InOpenToppedTransport && !pWeaponType->FireInTransport)
return false;

const auto pBulletType = pWeaponType->Projectile;
const auto pWhatAmI = pTarget->WhatAmI();
const bool isBuilding = pWhatAmI != AbstractType::Building;
const auto pWH = pWeaponType->Warhead;
const auto pOwner = pThis->Owner;

if (pTarget->IsInAir())
{
if (!pBulletType->AA)
return false;

if (pWH->Airstrike)
return false;
}
else
{
const auto pBulletTypeExt = BulletTypeExt::ExtMap.Find(pBulletType);

if (pBulletTypeExt->AAOnly.Get())
{
return false;
}
else if(pWH->ElectricAssault)
{
if (isBuilding)
return false;

const auto pBuilding = static_cast<BuildingClass*>(pTarget);

if (!pOwner->IsAlliedWith(pBuilding->Owner) ||
!pBuilding->Type || !pBuilding->Type->Overpowerable)
return false;
}
else if (pWH->IsLocomotor)
{
if (isBuilding)
return false;
}
}

if (pTarget->AbstractFlags & AbstractFlags::Techno)
{
TechnoClass* pTechno = static_cast<TechnoClass*>(pTarget);

if (pTechno->Health <= 0 || !pTechno->IsAlive)
return false;

if (pTechno->AttachedBomb)
{
if (pWH->IvanBomb)
return false;
}
else if (pWH->BombDisarm)
{
return false;
}

const auto pTechnoType = pTechno->GetTechnoType();

if (pWH->MindControl && (pTechnoType->ImmuneToPsionics ||
pTechno->IsMindControlled() || pOwner == pTechno->Owner))
return false;

if (pWH->Parasite && (isBuilding ||
static_cast<FootClass*>(pTechno)->ParasiteEatingMe))
return false;

if (!pWH->Temporal && pTechno->BeingWarpedOut)
return false;

if (pWeaponType->DrainWeapon && (!pTechnoType->Drainable ||
(pTechno->DrainingMe || pOwner->IsAlliedWith(pTechno->Owner))))
return false;

if (const auto pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeaponType))
{
if (!pWeaponExt->HasRequiredAttachedEffects(pTechno, pThis))
return false;
}

const auto pTargetExt = TechnoExt::ExtMap.Find(pTechno);
const auto pShield = pTargetExt->Shield.get();

if (pShield && pShield->IsActive() &&
!pShield->CanBeTargeted(pWeaponType))
{
return false;
}
else if (GeneralUtils::GetWarheadVersusArmor(pWH, pTechno->GetTechnoType()->Armor) == 0.0)
{
return false;
}
}
else
{
if (pWhatAmI == AbstractType::Terrain)
{
if (!pWH->Wood)
return false;
}
else if (pWhatAmI == AbstractType::Cell)
{
const auto pCell = static_cast<CellClass*>(pTarget);

if (pCell && pCell->OverlayTypeIndex >= 0)
{
auto overlayType = OverlayTypeClass::Array.GetItem(pCell->OverlayTypeIndex);

if (overlayType->Wall && !pWH->Wall)
return false;
}
}
}

return true;
}
2 changes: 2 additions & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,6 @@ class TechnoExt
static int GetWeaponIndexAgainstWall(TechnoClass* pThis, OverlayTypeClass* pWallOverlayType);
static void ApplyKillWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH);
static void ApplyRevengeWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH);

static bool CheckMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget, WeaponTypeClass* const pWeaponType);
};
21 changes: 21 additions & 0 deletions src/Ext/Techno/Hooks.Firing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ DEFINE_HOOK(0x6F3339, TechnoClass_WhatWeaponShouldIUse_Interceptor, 0x8)
return SkipGameCode;
}

DEFINE_HOOK(0x6F3360, TechnoClass_WhatWeaponShouldIUse_MultiWeapon, 0x6)
{
GET(TechnoClass*, pThis, ESI);
enum { SkipGameCode = 0x6F3379 };

auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());

if (pTypeExt->MultiWeapon.Get() &&
(pThis->WhatAmI() != AbstractType::Unit || !pThis->GetTechnoType()->Gunner))
return SkipGameCode;

return 0;
}

DEFINE_HOOK(0x6F33CD, TechnoClass_WhatWeaponShouldIUse_ForceFire, 0x6)
{
enum { ReturnWeaponIndex = 0x6F37AF };
Expand Down Expand Up @@ -124,6 +138,13 @@ DEFINE_HOOK(0x6F3428, TechnoClass_WhatWeaponShouldIUse_ForceWeapon, 0x6)
R->EAX(forceWeaponIndex);
return UseWeaponIndex;
}

int multiWeaponIndex = pTypeExt->SelectMultiWeapon(pThis, pTarget);
if (multiWeaponIndex >= 0)
{
R->EAX(multiWeaponIndex);
return UseWeaponIndex;
}
}

return 0;
Expand Down
112 changes: 111 additions & 1 deletion src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,111 @@ void TechnoTypeExt::ExtData::ApplyTurretOffset(Matrix3D* mtx, double factor)
mtx->Translate(x, y, z);
}

bool TechnoTypeExt::ExtData::IsSecondary(const int& nWeaponIndex)
{
const auto pThis = this->OwnerObject();

if (pThis->IsGattling)
return nWeaponIndex != 0 && nWeaponIndex % 2 != 0;

if (this->MultiWeapon.Get() &&
!this->MultiWeapon_IsSecondary.empty())
{
int index = nWeaponIndex + 1;
return this->MultiWeapon_IsSecondary.Contains(index);
}

return nWeaponIndex != 0;
}

int TechnoTypeExt::ExtData::SelectMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget)
{
if (!pThis || !pTarget)
return -1;

const auto pType = this->OwnerObject();
int WeaponCount = pType->WeaponCount;

if (WeaponCount > 0 && pType->HasMultipleTurrets() &&
(pType->IsGattling || pType->Gunner))
return -1;

if (!this->MultiWeapon.Get() || WeaponCount <= 2)
return -1;

// considering the issue of performance loss, it is sufficient to expand it to four.
int selectweaponCount = this->MultiWeapon_SelectWeapon.Get();
int weaponCount = WeaponCount;

if (weaponCount > selectweaponCount)
weaponCount = selectweaponCount;

if (weaponCount < 2)
return 0;
else if (weaponCount == 2)
return -1;
else if (weaponCount > 4)
weaponCount = 4;

bool isElite = pThis->Veterancy.IsElite();
const auto secondary = pType->GetWeapon(1, isElite).WeaponType;
const auto secondaryWH = secondary->Warhead;
bool secondaryCanTarget = TechnoExt::CheckMultiWeapon(pThis, pTarget, secondary);

if (const auto pTargetTechno = abstract_cast<TechnoClass*>(pTarget))
{
if (secondaryCanTarget)
{
bool isAllies = pThis->Owner->IsAlliedWith(pTargetTechno->Owner);

if (pTarget->IsInAir())
return 1;
else if (secondaryWH->Airstrike)
return 1;
else if (secondary->DrainWeapon &&
pTargetTechno->GetTechnoType()->Drainable &&
!pThis->DrainTarget && !isAllies)
return 1;
else if (secondaryWH->ElectricAssault && isAllies &&
pTargetTechno->WhatAmI() == AbstractType::Building &&
static_cast<BuildingClass*>(pTargetTechno)->Type->Overpowerable)
return 1;
}

if (const auto pCell = pTargetTechno->GetCell())
{
bool targetOnWater = pCell->LandType == LandType::Water || pCell->LandType == LandType::Beach;

if (!pTargetTechno->OnBridge && targetOnWater)
{
int result = pThis->SelectNavalTargeting(pTargetTechno);

if (result == -1)
return 1;
}
}
}

for (int i = 0; i < weaponCount; i++)
{
if (i == 1)
{
if (secondaryCanTarget)
return i;

continue;
}

const auto pWeaponType = pType->GetWeapon(i, isElite).WeaponType;
if (!TechnoExt::CheckMultiWeapon(pThis, pTarget, pWeaponType))
continue;

return i;
}

return 0;
}

// Ares 0.A source
const char* TechnoTypeExt::ExtData::GetSelectionGroupID() const
{
Expand Down Expand Up @@ -60,7 +165,7 @@ void TechnoTypeExt::ExtData::ParseBurstFLHs(INI_EX& exArtINI, const char* pArtSe
char tempBuffer[32];
char tempBufferFLH[48];
auto pThis = this->OwnerObject();
bool parseMultiWeapons = pThis->TurretCount > 0 && pThis->WeaponCount > 0;
bool parseMultiWeapons = this->MultiWeapon.Get() || (pThis->TurretCount > 0 && pThis->WeaponCount > 0);
auto weaponCount = parseMultiWeapons ? pThis->WeaponCount : 2;
nFLH.resize(weaponCount);
nEFlh.resize(weaponCount);
Expand Down Expand Up @@ -1114,6 +1219,11 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)

.Process(this->FallingDownDamage)
.Process(this->FallingDownDamage_Water)

.Process(this->MultiWeapon)
.Process(this->MultiWeapon_IsSecondary)
.Process(this->MultiWeapon_SelectWeapon)
.Process(this->LastMultiWeapon)
;
}
void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
Expand Down
Loading