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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ out

# Python virtual environment for docs
.venv/

# Personal agent instructions
/AGENTS.md
2 changes: 2 additions & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,5 @@ This page lists all the individual contributions to the project by their author.
- Interop export interface for accessing scenario local/global variables
- Add `ClampToScreen` tag for `BannerType` to control whether banner position is clamped to the visible area
- **obsidianus** - Automatic conversion based on health
- **Nuke**:
- Switch Voxel Turret Depends on MultiWeapon
27 changes: 27 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,33 @@ BurstPerTurret=0 ; integer
This is essentially designed to restore multi-turrets in RA1, not to help you make a Zantos. Therefore, features like different turrets using different weapons/targeting separately/calculating cooldown separately/having separate health are not within the scope of this function. Please use techno attachment for such requirements.
```

### Switch Voxel Turret Depends on MultiWeapon

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If it does not require any new statements and is used in conjunction with MultiWeapon, then it is best to merge it into the paragraph where the MultiWeapon feature resides.


- Now you can make a VXL vehicle swap its turret and barrel VXL models based on the currently selected weapon by setting `MultiWeapon=yes` together with `TurretCount>0`.
- When the selected weapon changes, the turret switches to `<ImageFile>turN.vxl` and the barrel to `<ImageFile>barlN.vxl`, where `N` is the weapon index (weapon 1 -> `<ImageFile>tur.vxl`, weapon 2 -> `<ImageFile>tur1.vxl`, weapon 3 -> `<ImageFile>tur2.vxl`, and so on).
- The number of effective turrets is the smaller of `WeaponCount` and `TurretCount`. A weapon whose index is out of this range falls back to the default turret, e.g. with `WeaponCount=3` and `TurretCount=2`, weapon 3 uses `<ImageFile>tur.vxl`.
- Elite weapons follow the same rule: `EliteWeaponN` also uses `<ImageFile>turN.vxl`.
- No changes to `artmd.ini` are needed. Only place the extra `.vxl` / `.hva` files into the game directory following the naming convention.
- Turret and barrel shadows are drawn as usual when `UseTurretShadow=yes`.

In `rulesmd.ini`:
```ini
[SOMEVEHICLE] ; VehicleType
MultiWeapon=yes ; boolean
TurretCount=2 ; integer
```

Files to provide in the game directory (named after the unit's `ImageFile`):
- `<ImageFile>.vxl` / `<ImageFile>.hva` - the body
- `<ImageFile>tur.vxl` / `<ImageFile>tur.hva` - turret for weapon 1
- `<ImageFile>barl.vxl` / `<ImageFile>barl.hva` - barrel for weapon 1
- `<ImageFile>tur1.vxl` / `<ImageFile>tur1.hva` - turret for weapon 2
- `<ImageFile>barl1.vxl` / `<ImageFile>barl1.hva` - barrel for weapon 2

```{note}
This feature applies to regular VXL vehicles. It does not work together with `IsChargeTurret=yes`, `IsGattling=yes` or `Gunner=yes`.
```

### Turret Response

- When the vehicle loses its target, you can customize whether to align the turret direction with the vehicle body.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ This serves as a changelog for when you just need to drop the new version in wit
- `PassengerDeletion.SoylentMultiplier`: `0.0` -> `1.0`
- `PassengerDeletion.SoylentAllowedHouses`: `none` -> `enemies`
- `PassengerDeletion.DisplaySoylentOffset`: `none` -> `all`
- VXL vehicles can now swap their turret and barrel models per weapon index by using `MultiWeapon` together with `TurretCount`. (by Nuke)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changelog position is incorrect.


#### Changes compared to inter-version builds / pre-releases

Expand Down
6 changes: 6 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/CREDITS.po
Original file line number Diff line number Diff line change
Expand Up @@ -3183,3 +3183,9 @@ msgstr "为 `BannerType` 添加了 `ClampToScreen` 标签以控制横幅位置
msgid "**obsidianus** - Automatic conversion based on health"
msgstr "**obsidianus** - 自动根据血量变形"

msgid "**Nuke**:"
msgstr "**Nuke**:"

msgid "Switch Voxel Turret Depends on MultiWeapon"
msgstr "根据 MultiWeapon 切换体素炮塔"

66 changes: 66 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 @@ -5493,6 +5493,72 @@ msgstr ""
"的多炮塔,而不是帮你造一台赞托斯。因此,不同炮塔使用不同武器/独立瞄准/独立计算冷却/拥有独立生命值等功能均不在该功能范围内。如有此类需求请使用科技类型附件(techno"
" attachment)。"

msgid "Switch Voxel Turret Depends on MultiWeapon"
msgstr "根据 MultiWeapon 切换体素炮塔"

msgid ""
"Now you can make a VXL vehicle swap its turret and barrel VXL models "
"based on the currently selected weapon by setting `MultiWeapon=yes` "
"together with `TurretCount>0`."
msgstr "现在你可以通过同时设置 `MultiWeapon=yes` 和 `TurretCount>0`,让 VXL 载具根据当前选中的武器切换炮塔和炮管模型。"

msgid ""
"When the selected weapon changes, the turret switches to "
"`<ImageFile>turN.vxl` and the barrel to `<ImageFile>barlN.vxl`, where `N`"
" is the weapon index (weapon 1 -> `<ImageFile>tur.vxl`, weapon 2 -> "
"`<ImageFile>tur1.vxl`, weapon 3 -> `<ImageFile>tur2.vxl`, and so on)."
msgstr ""
"当选中的武器变化时,炮塔切换到 `<ImageFile>turN.vxl`,炮管切换到 `<ImageFile>barlN.vxl`,其中 "
"`N` 是武器索引(武器 1 -> `<ImageFile>tur.vxl`,武器 2 -> `<ImageFile>tur1.vxl`,武器 3 -> "
"`<ImageFile>tur2.vxl`,以此类推)。"

msgid ""
"The number of effective turrets is the smaller of `WeaponCount` and "
"`TurretCount`. A weapon whose index is out of this range falls back to "
"the default turret, e.g. with `WeaponCount=3` and `TurretCount=2`, weapon"
" 3 uses `<ImageFile>tur.vxl`."
msgstr ""
"有效炮塔数量取 `WeaponCount` 和 `TurretCount` 中较小的值。武器索引超出该范围的武器回退到默认炮塔,例如 "
"`WeaponCount=3` 且 `TurretCount=2` 时,武器 3 使用 `<ImageFile>tur.vxl`。"

msgid ""
"Elite weapons follow the same rule: `EliteWeaponN` also uses "
"`<ImageFile>turN.vxl`."
msgstr "精英武器遵循同样的规则:`EliteWeaponN` 同样使用 `<ImageFile>turN.vxl`。"

msgid ""
"No changes to `artmd.ini` are needed. Only place the extra `.vxl` / "
"`.hva` files into the game directory following the naming convention."
msgstr "无需修改 `artmd.ini`。只需按照命名约定把额外的 `.vxl` / `.hva` 文件放入游戏目录。"

msgid "Turret and barrel shadows are drawn as usual when `UseTurretShadow=yes`."
msgstr "当 `UseTurretShadow=yes` 时,炮塔和炮管阴影照常绘制。"

msgid ""
"Files to provide in the game directory (named after the unit's "
"`ImageFile`):"
msgstr "需要放入游戏目录的文件(以单位的 `ImageFile` 命名):"

msgid "`<ImageFile>.vxl` / `<ImageFile>.hva` - the body"
msgstr "`<ImageFile>.vxl` / `<ImageFile>.hva` - 车体"

msgid "`<ImageFile>tur.vxl` / `<ImageFile>tur.hva` - turret for weapon 1"
msgstr "`<ImageFile>tur.vxl` / `<ImageFile>tur.hva` - 武器 1 的炮塔"

msgid "`<ImageFile>barl.vxl` / `<ImageFile>barl.hva` - barrel for weapon 1"
msgstr "`<ImageFile>barl.vxl` / `<ImageFile>barl.hva` - 武器 1 的炮管"

msgid "`<ImageFile>tur1.vxl` / `<ImageFile>tur1.hva` - turret for weapon 2"
msgstr "`<ImageFile>tur1.vxl` / `<ImageFile>tur1.hva` - 武器 2 的炮塔"

msgid "`<ImageFile>barl1.vxl` / `<ImageFile>barl1.hva` - barrel for weapon 2"
msgstr "`<ImageFile>barl1.vxl` / `<ImageFile>barl1.hva` - 武器 2 的炮管"

msgid ""
"This feature applies to regular VXL vehicles. It does not work together "
"with `IsChargeTurret=yes`, `IsGattling=yes` or `Gunner=yes`."
msgstr "该功能适用于普通 VXL 载具。它不能与 `IsChargeTurret=yes`、`IsGattling=yes` 或 `Gunner=yes` 一起使用。"

msgid "Turret Response"
msgstr "炮塔响应"

Expand Down
5 changes: 5 additions & 0 deletions docs/locale/zh_CN/LC_MESSAGES/Whats-New.po
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,11 @@ msgstr "`PassengerDeletion.SoylentAllowedHouses`:`none`→`enemies`"
msgid "`PassengerDeletion.DisplaySoylentOffset`: `none` -> `all`"
msgstr "`PassengerDeletion.DisplaySoylentOffset`:`none`→`all`"

msgid ""
"VXL vehicles can now swap their turret and barrel models per weapon index "
"by using `MultiWeapon` together with `TurretCount`."
msgstr "VXL 载具现在可以通过同时使用 `MultiWeapon` 和 `TurretCount`,按武器索引切换炮塔和炮管模型。"

msgid "Changes compared to inter-version builds / pre-releases"
msgstr "相较于版本间构建/预发布版本的更改"

Expand Down
38 changes: 38 additions & 0 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <Utilities/Helpers.Alex.h>
#include <Utilities/AresHelper.h>
#include <Utilities/AresFunctions.h>
#include <Utilities/Debug.h>
#include <Misc/FlyingStrings.h>

#pragma region GetTechnoType
Expand Down Expand Up @@ -78,6 +79,35 @@ DEFINE_HOOK(0x736480, UnitClass_AI, 0x6)
pThis->CurrentFiringFrame = animCounter;
}

// Make the displayed VXL turret / barrel follow the currently selected
// weapon for MultiWeapon + TurretCount units. When the unit has no target
// (e.g. after issuing an order with a mouse click) the turret stays on the
// last used weapon instead of snapping back to the default turret.
if (pThis->IsAlive && pExt->GetTypeExtData()->IsMultiWeaponTurretEnabled())
{
if (pThis->Target)
{
const int weaponIndex = pThis->SelectWeapon(pThis->Target);
const auto pType = pThis->GetTechnoType();

// Keep the raw weapon index. Weapons beyond the loaded turret count
// (min(WeaponCount, TurretCount)) are handled by the drawing code and
// fall back to the default turret, so they must not be clamped onto the
// last valid turret here.
const int turret = Math::clamp(weaponIndex, 0, Math::max(pType->WeaponCount - 1, 0));

if (pThis->CurrentTurretNumber != turret)
{
Debug::Log("[MultiWeaponTurret] %s SelectWeapon=%d Target=%p -> CurrentTurretNumber=%d (WeaponCount=%d TurretCount=%d).\n",
pType->ID, weaponIndex, static_cast<void*>(pThis->Target), turret, pType->WeaponCount, pType->TurretCount);
}

pThis->CurrentTurretNumber = turret;
}
// No target: keep the last used weapon's turret (CurrentTurretNumber is
// left untouched so the displayed turret does not jump around).
}

return 0;
}

Expand Down Expand Up @@ -228,6 +258,14 @@ DEFINE_HOOK(0x6FA540, TechnoClass_AI_ChargeTurret, 0x6)

GET(TechnoClass*, pThis, ESI);

// Do not let the charge turret logic touch CurrentTurretNumber for units
// that use the MultiWeapon turret switching feature.
if (auto const pUnitType = abstract_cast<UnitTypeClass*>(pThis->GetTechnoType()))
{
if (UnitTypeExt::Fetch(pUnitType)->IsMultiWeaponTurretEnabled())
return SkipGameCode;
}

if (pThis->ChargeTurretDelay <= 0)
{
pThis->CurrentTurretNumber = 0;
Expand Down
Loading