From 5507c64c0a996c9e205ea76b4b0fec91e9ddbde2 Mon Sep 17 00:00:00 2001
From: dh381-1 <2575903651@qq.com>
Date: Wed, 9 Sep 2026 15:17:49 +0800
Subject: [PATCH 1/5] initial
---
CREDITS.md | 2 +
Phobos.vcxproj | 1 +
docs/New-or-Enhanced-Logics.md | 20 +++
docs/Whats-New.md | 1 +
src/Ext/House/Body.cpp | 1 +
src/Ext/House/Body.h | 3 +
src/Ext/HouseType/Body.cpp | 8 ++
src/Ext/HouseType/Body.h | 7 ++
src/Ext/HouseType/Hooks.InitialElite.cpp | 150 +++++++++++++++++++++++
src/Ext/TechnoType/Body.cpp | 6 +
src/Ext/TechnoType/Body.h | 8 ++
11 files changed, 207 insertions(+)
create mode 100644 src/Ext/HouseType/Hooks.InitialElite.cpp
diff --git a/CREDITS.md b/CREDITS.md
index a01c6e0585..98e5d9d97a 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -956,3 +956,5 @@ This page lists all the individual contributions to the project by their author.
- **obsidianus** - Automatic conversion based on health
- **Nuke** - Reload speed adjustment on promotion
- **frg2089 (舰队的偶像-岛风酱!)** - Fix `Slaved.OwnerWhenMasterKilled` not being respected when the master is sold or self-destructed
+- **dh381-1(dh381)**
+ - Add country initial elite unit lists
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 67dc28e6ee..a172ae1b7b 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -108,6 +108,7 @@
+
diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md
index aae20369cb..3037acdcde 100644
--- a/docs/New-or-Enhanced-Logics.md
+++ b/docs/New-or-Enhanced-Logics.md
@@ -2639,6 +2639,26 @@ WarpInWeapon.UseDistanceAsDamage=false ; boolean
WarpOutWeapon= ; WeaponType
```
+### Set country initial elite
+
+- Now you can add `TechnoTypes` in the three lists. They will appear at an elite initial level when produced, and cloned infantry will also be affected by this effect.
+
+In `rulesmd.ini`:
+```ini
+[SOMECOUNTRYIES] ; Countries
+EliteInfantry= ; List of InfantryTypes
+EliteUnits= ; List of UnitTypes
+EliteAircraft= ; List of AircraftTypes
+```
+
+- For each `TechnoType`, you can define `SpareCameo` to specify the elite‑level icon. When a `TechnoType` is added to the initial elite list, it will preferentially use the SpareCameo as its icon. Supports `SHP`/`PCX` formats.
+
+In `artmd.ini`:
+```ini
+[SOMETECHNO] ; TechnoTypes
+SpareCameo= ; filename
+```
+
## Terrain
### Destroy animation & sound
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 54de7231a8..948abd34f6 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -720,6 +720,7 @@ HideShakeEffects=false ; boolean
- [Disable AlphaImage during Buildup](Fixed-or-Improved-Logics.md#disable-alphaimage-during-buildup) (by Noble_Fish)
- [Reload speed adjustment on promotion](New-or-Enhanced-Logics.md#reload-speed-adjustment-on-promotion) (by Nuke)
- Allowed `(Pre)ProductionAnim` animations to use `Powered` & `PoweredLight/Effect/Special` keys (by Noble_Fish)
+- [Set country initial elite](New-or-Enhanced-Logics.md#set-country-initial-elite) (by dh381)
#### Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp
index e53d1d2ad9..cc78b14fc9 100644
--- a/src/Ext/House/Body.cpp
+++ b/src/Ext/House/Body.cpp
@@ -713,6 +713,7 @@ void HouseExt::Serialize(T& Stm)
.Process(this->ForceRadar)
.Process(this->PlayerAutoRepair)
//.Process(this->BeaconsPlacedOrder) beacon is not saved, so this follows it.
+ .Process(this->TechnoPCX_IsLoad)
;
}
diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h
index df5ba629b6..ba6ac3737a 100644
--- a/src/Ext/House/Body.h
+++ b/src/Ext/House/Body.h
@@ -81,6 +81,8 @@ class HouseExt final : public AbstractExt, public Detach::Listener BeaconsPlacedOrder;
+ ValueableVector TechnoPCX_IsLoad;
+
HouseExt(HouseClass* OwnerObject) : AbstractExt(OwnerObject)
, PowerPlantEnhancers {}
, OwnedLimboDeliveredBuildings {}
@@ -116,6 +118,7 @@ class HouseExt final : public AbstractExt, public Detach::ListenerEVATag.Read(pINI, pSection, "EVA.Tag");
+
+ this->EliteInfantry.Read(exINI, pSection, "EliteInfantry");
+ this->EliteUnits.Read(exINI, pSection, "EliteUnits");
+ this->EliteAircraft.Read(exINI, pSection, "EliteAircraft");
}
template
@@ -25,6 +29,10 @@ void HouseTypeExt::Serialize(T& Stm)
{
Stm
.Process(this->EVATag)
+
+ .Process(this->EliteInfantry)
+ .Process(this->EliteUnits)
+ .Process(this->EliteAircraft)
;
}
diff --git a/src/Ext/HouseType/Body.h b/src/Ext/HouseType/Body.h
index c843286266..796963c3b4 100644
--- a/src/Ext/HouseType/Body.h
+++ b/src/Ext/HouseType/Body.h
@@ -27,8 +27,15 @@ class HouseTypeExt final : public AbstractTypeExt
EVAType EVATag;
+ ValueableVector EliteInfantry;
+ ValueableVector EliteUnits;
+ ValueableVector EliteAircraft;
+
HouseTypeExt(HouseTypeClass* OwnerObject) : AbstractTypeExt(OwnerObject)
, EVATag { -2 }
+ , EliteInfantry {}
+ , EliteUnits {}
+ , EliteAircraft {}
{ }
virtual ~HouseTypeExt() = default;
diff --git a/src/Ext/HouseType/Hooks.InitialElite.cpp b/src/Ext/HouseType/Hooks.InitialElite.cpp
new file mode 100644
index 0000000000..3ea970f4fe
--- /dev/null
+++ b/src/Ext/HouseType/Hooks.InitialElite.cpp
@@ -0,0 +1,150 @@
+#include "Body.h"
+
+#include
+#include
+
+static SHPStruct* LoadSHPCameo(TechnoTypeClass* pType)
+{
+ auto pTypeExt = TechnoTypeExt::Fetch(pType);
+
+ if(pTypeExt->SpareCameo_IsLoad)
+ return pTypeExt->SpareCameo;
+
+ char pFileName[0x20];
+
+ strcpy_s(pFileName, pTypeExt->SpareCameoFile.data());
+ _strlwr_s(pFileName);
+
+ if(!_stricmp(pFileName, pTypeExt->SpareCameoFile.data())
+ && strstr(pFileName, ".shp"))
+ {
+ SHPStruct* pSHP = FileSystem::LoadSHPFile(pFileName);
+ pTypeExt->SpareCameo_IsLoad = true;
+ pTypeExt->SpareCameo = pSHP;
+ return pSHP;
+ }
+ return nullptr;
+}
+
+static bool DrawPCXCameo(TechnoTypeClass* pType, const int destX, const int destY)
+{
+ auto pTypeExt = TechnoTypeExt::Fetch(pType);
+ char pFileName[0x20];
+
+ strcpy_s(pFileName, pTypeExt->SpareCameoFile.data());
+ _strlwr_s(pFileName);
+
+ if(!_stricmp(pFileName, pTypeExt->SpareCameoFile.data())
+ && strstr(pFileName, ".pcx"))
+ {
+ PCX::Instance.LoadFile(pFileName);
+ if (const auto pCameoPCX = PCX::Instance.GetSurface(pFileName))
+ {
+ RectangleStruct bounds = { destX, destY, 60, 48 };
+ return PCX::Instance.BlitToSurface(&bounds, DSurface::Sidebar, pCameoPCX);
+ }
+ }
+ return false;
+}
+
+DEFINE_HOOK(0x6A980A, StripClass_Draw_DrawSHPCameo, 0x8)
+{
+ GET(TechnoTypeClass*, pType, EBX);
+
+ auto pHouseExt = HouseExt::Fetch(HouseClass::CurrentPlayer);
+ auto pHouseTypeExt = HouseTypeExt::Fetch(HouseClass::CurrentPlayer->Type);
+
+ SHPStruct* pSHP = nullptr;
+
+ switch(pType->WhatAmI())
+ {
+ case AbstractType::InfantryType:
+ {
+ if(pHouseTypeExt->EliteInfantry.Contains(pType))
+ {
+ pHouseExt->TechnoPCX_IsLoad.push_back(pType);
+ pSHP = LoadSHPCameo(pType);
+ }
+ break;
+ }
+ case AbstractType::UnitType:
+ {
+ if(pHouseTypeExt->EliteUnits.Contains(pType))
+ {
+ pHouseExt->TechnoPCX_IsLoad.push_back(pType);
+ pSHP = LoadSHPCameo(pType);
+ }
+ break;
+ }
+ case AbstractType::AircraftType:
+ {
+ if(pHouseTypeExt->EliteAircraft.Contains(pType))
+ {
+ pHouseExt->TechnoPCX_IsLoad.push_back(pType);
+ pSHP = LoadSHPCameo(pType);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if(pSHP)
+ R->EAX(pSHP);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x6A99E7, StripClass_Draw_DrawPCXCameo, 0x6)
+{
+ enum { SkipDrawSHP = 0x6A9A43 };
+
+ GET(const int, destX, ESI);
+ GET(const int, destY, EBP);
+ GET_STACK(SHPStruct*, pSHP, STACK_OFFSET(0x48C, -0x444));
+
+ auto pHouseExt = HouseExt::Fetch(HouseClass::CurrentPlayer);
+
+ for(auto pType : pHouseExt->TechnoPCX_IsLoad)
+ {
+ if(pSHP == pType->Cameo || pSHP == pType->AltCameo)
+ {
+ if(DrawPCXCameo(pType, destX, destY))
+ return SkipDrawSHP;
+ }
+ }
+ return 0;
+}
+
+DEFINE_HOOK(0x443C71, BuildingClass_ExitObject_CountryInitialElite, 0x6)
+{
+ GET(TechnoClass*, pTechno, EDI);
+
+ const auto pHouseTypeExt = HouseTypeExt::Fetch(pTechno->Owner->Type);
+
+ switch(pTechno->WhatAmI())
+ {
+ case AbstractType::Infantry:
+ {
+ if(pHouseTypeExt->EliteInfantry.Contains(pTechno->GetTechnoType()))
+ pTechno->Veterancy.SetElite();
+ break;
+ }
+ case AbstractType::Unit:
+ {
+ if(pHouseTypeExt->EliteUnits.Contains(pTechno->GetTechnoType()))
+ pTechno->Veterancy.SetElite();
+ break;
+ }
+ case AbstractType::Aircraft:
+ {
+ if(pHouseTypeExt->EliteAircraft.Contains(pTechno->GetTechnoType()))
+ pTechno->Veterancy.SetElite();
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp
index ae05a36241..e5bfab881a 100644
--- a/src/Ext/TechnoType/Body.cpp
+++ b/src/Ext/TechnoType/Body.cpp
@@ -1436,6 +1436,8 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI)
// VoiceIFVRepair from Ares 0.2
this->VoiceIFVRepair.Read(exINI, pSection, "VoiceIFVRepair");
this->ParseVoiceWeaponAttacks(exINI, pSection, this->VoiceWeaponAttacks, this->VoiceEliteWeaponAttacks);
+
+ this->SpareCameoFile.Read(pArtINI, pArtSection, "SpareCameo");
}
template
@@ -1831,6 +1833,10 @@ void TechnoTypeExt::Serialize(T& Stm)
.Process(this->DecloakAnims)
.Process(this->Cloak_KickOutParasite)
+ .Process(this->SpareCameoFile)
+ .Process(this->SpareCameo)
+ .Process(this->SpareCameo_IsLoad)
+
// Ares 0.2
.Process(this->RadarJamRadius)
diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h
index c7c2ba9ed6..329be0a190 100644
--- a/src/Ext/TechnoType/Body.h
+++ b/src/Ext/TechnoType/Body.h
@@ -461,6 +461,10 @@ class TechnoTypeExt : public ObjectTypeExt
Nullable Unsellable;
Nullable KeepAlive;
+ PhobosFixedString<0x20> SpareCameoFile;
+ SHPStruct* SpareCameo;
+ bool SpareCameo_IsLoad;
+
TechnoTypeExt(TechnoTypeClass* OwnerObject) : ObjectTypeExt(OwnerObject)
, HealthBar_Hide { false }
, HealthBar_HidePips { false }
@@ -851,6 +855,10 @@ class TechnoTypeExt : public ObjectTypeExt
, DecloakAnims {}
, Cloak_KickOutParasite {}
+ , SpareCameoFile { NONE_STR }
+ , SpareCameo { nullptr }
+ , SpareCameo_IsLoad { false }
+
// Ares 0.2
, RadarJamRadius { 0 }
From dbc20deb580b0bf9085638ac6cdac24b6a9e7e24 Mon Sep 17 00:00:00 2001
From: Noble_Fish <1065703286@qq.com>
Date: Wed, 9 Sep 2026 15:37:29 +0800
Subject: [PATCH 2/5] fix docs & correct the order of variables
---
docs/New-or-Enhanced-Logics.md | 8 +++++---
docs/Whats-New.md | 2 +-
src/Ext/HouseType/Body.cpp | 14 ++++++++------
src/Ext/HouseType/Body.h | 6 +++---
4 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md
index 9ef39379cd..565a445fec 100644
--- a/docs/New-or-Enhanced-Logics.md
+++ b/docs/New-or-Enhanced-Logics.md
@@ -823,6 +823,8 @@ SpyEffect.VictimSuperWeapon= ; SuperWeaponType
SpyEffect.InfiltratorSuperWeapon= ; SuperWeaponType
```
+## Countries
+
## Infantry
### Allow infantry to perform type conversion when deploying and undeploying
@@ -2705,7 +2707,7 @@ WarpOutWeapon= ; WeaponType
In `rulesmd.ini`:
```ini
-[SOMECOUNTRYIES] ; Countries
+[SOMECOUNTRY] ; Country
EliteInfantry= ; List of InfantryTypes
EliteUnits= ; List of UnitTypes
EliteAircraft= ; List of AircraftTypes
@@ -2715,8 +2717,8 @@ EliteAircraft= ; List of AircraftTypes
In `artmd.ini`:
```ini
-[SOMETECHNO] ; TechnoTypes
-SpareCameo= ; filename
+[SOMETECHNO] ; TechnoType
+SpareCameo= ; filename - including the .shp/.pcx extension
```
## Terrain
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index de389e0e0f..942e2eccaa 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -443,6 +443,7 @@ HideShakeEffects=false ; boolean
- [Allowed customize that whether `Temporal=yes` warhead will cause target building animation poweroff](Fixed-or-Improved-Logics.md#allow-customize-that-whether-temporal-yes-warhead-will-cause-target-building-animation-poweroff) (by NetsuNegi)
- Country-based attached effects (by Ollerus)
- [Customizable crew type per country](Fixed-or-Improved-Logics.md#customizable-crew-type-per-country) (by Sovietianqi)
+- [Set country initial elite](New-or-Enhanced-Logics.md#set-country-initial-elite) (by dh381)
#### Vanilla fixes:
- Fixed the bug where a building with `Factory=BuildingType` owned by the AI did not play `ProductionAnim` when placing a produced building (by Noble_Fish)
@@ -730,7 +731,6 @@ HideShakeEffects=false ; boolean
- [Disable AlphaImage during Buildup](Fixed-or-Improved-Logics.md#disable-alphaimage-during-buildup) (by Noble_Fish)
- [Reload speed adjustment on promotion](New-or-Enhanced-Logics.md#reload-speed-adjustment-on-promotion) (by Nuke)
- Allowed `(Pre)ProductionAnim` animations to use `Powered` & `PoweredLight/Effect/Special` keys (by Noble_Fish)
-- [Set country initial elite](New-or-Enhanced-Logics.md#set-country-initial-elite) (by dh381)
#### Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
diff --git a/src/Ext/HouseType/Body.cpp b/src/Ext/HouseType/Body.cpp
index d27def6330..474cd5abec 100644
--- a/src/Ext/HouseType/Body.cpp
+++ b/src/Ext/HouseType/Body.cpp
@@ -19,13 +19,14 @@ void HouseTypeExt::LoadFromINIFile(CCINIClass* pINI)
this->EVATag.Read(pINI, pSection, "EVA.Tag");
- this->EliteInfantry.Read(exINI, pSection, "EliteInfantry");
- this->EliteUnits.Read(exINI, pSection, "EliteUnits");
- this->EliteAircraft.Read(exINI, pSection, "EliteAircraft");
this->AttachEffects.LoadFromINI(pINI, pSection);
this->AttachEffects_AttachOnOwnerChange.Read(exINI, pSection, "AttachEffect.AttachOnOwnerChange");
this->Crew.Read(exINI, pSection, "Crew");
+
+ this->EliteInfantry.Read(exINI, pSection, "EliteInfantry");
+ this->EliteUnits.Read(exINI, pSection, "EliteUnits");
+ this->EliteAircraft.Read(exINI, pSection, "EliteAircraft");
}
template
@@ -34,12 +35,13 @@ void HouseTypeExt::Serialize(T& Stm)
Stm
.Process(this->EVATag)
- .Process(this->EliteInfantry)
- .Process(this->EliteUnits)
- .Process(this->EliteAircraft)
.Process(this->AttachEffects)
.Process(this->AttachEffects_AttachOnOwnerChange)
.Process(this->Crew)
+
+ .Process(this->EliteInfantry)
+ .Process(this->EliteUnits)
+ .Process(this->EliteAircraft)
;
}
diff --git a/src/Ext/HouseType/Body.h b/src/Ext/HouseType/Body.h
index a9e8a842a4..d610091bd3 100644
--- a/src/Ext/HouseType/Body.h
+++ b/src/Ext/HouseType/Body.h
@@ -38,12 +38,12 @@ class HouseTypeExt final : public AbstractTypeExt
HouseTypeExt(HouseTypeClass* OwnerObject) : AbstractTypeExt(OwnerObject)
, EVATag { -2 }
- , EliteInfantry {}
- , EliteUnits {}
- , EliteAircraft {}
, AttachEffects {}
, AttachEffects_AttachOnOwnerChange {}
, Crew {}
+ , EliteInfantry {}
+ , EliteUnits {}
+ , EliteAircraft {}
{ }
virtual ~HouseTypeExt() = default;
From c72f7e596ce97a16b9c1a740010c1f0a55a6fdf0 Mon Sep 17 00:00:00 2001
From: Noble_Fish <1065703286@qq.com>
Date: Wed, 9 Sep 2026 15:43:48 +0800
Subject: [PATCH 3/5] [doc] Move to the countries section
---
docs/New-or-Enhanced-Logics.md | 40 +++++++++++++++++-----------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md
index 565a445fec..2ce01b5958 100644
--- a/docs/New-or-Enhanced-Logics.md
+++ b/docs/New-or-Enhanced-Logics.md
@@ -825,6 +825,26 @@ SpyEffect.InfiltratorSuperWeapon= ; SuperWeaponType
## Countries
+### Set country initial elite
+
+- Now you can add `TechnoTypes` in the three lists. They will appear at an elite initial level when produced, and cloned infantry will also be affected by this effect.
+
+In `rulesmd.ini`:
+```ini
+[SOMECOUNTRY] ; Country
+EliteInfantry= ; List of InfantryTypes
+EliteUnits= ; List of UnitTypes
+EliteAircraft= ; List of AircraftTypes
+```
+
+- For each `TechnoType`, you can define `SpareCameo` to specify the elite‑level icon. When a `TechnoType` is added to the initial elite list, it will preferentially use the SpareCameo as its icon. Supports `SHP`/`PCX` formats.
+
+In `artmd.ini`:
+```ini
+[SOMETECHNO] ; TechnoType
+SpareCameo= ; filename - including the .shp/.pcx extension
+```
+
## Infantry
### Allow infantry to perform type conversion when deploying and undeploying
@@ -2701,26 +2721,6 @@ WarpInWeapon.UseDistanceAsDamage=false ; boolean
WarpOutWeapon= ; WeaponType
```
-### Set country initial elite
-
-- Now you can add `TechnoTypes` in the three lists. They will appear at an elite initial level when produced, and cloned infantry will also be affected by this effect.
-
-In `rulesmd.ini`:
-```ini
-[SOMECOUNTRY] ; Country
-EliteInfantry= ; List of InfantryTypes
-EliteUnits= ; List of UnitTypes
-EliteAircraft= ; List of AircraftTypes
-```
-
-- For each `TechnoType`, you can define `SpareCameo` to specify the elite‑level icon. When a `TechnoType` is added to the initial elite list, it will preferentially use the SpareCameo as its icon. Supports `SHP`/`PCX` formats.
-
-In `artmd.ini`:
-```ini
-[SOMETECHNO] ; TechnoType
-SpareCameo= ; filename - including the .shp/.pcx extension
-```
-
## Terrain
### Destroy animation & sound
From 3fcb41c277e5e75e805c7f1f7dd3ae6167179a66 Mon Sep 17 00:00:00 2001
From: dh381-1 <2575903651@qq.com>
Date: Thu, 10 Sep 2026 12:11:40 +0800
Subject: [PATCH 4/5] add SpareCameoPCX to load pcx file
---
src/Ext/HouseType/Hooks.InitialElite.cpp | 14 ++++++++------
src/Ext/TechnoType/Body.cpp | 4 +++-
src/Ext/TechnoType/Body.h | 7 +++++--
3 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/Ext/HouseType/Hooks.InitialElite.cpp b/src/Ext/HouseType/Hooks.InitialElite.cpp
index 3ea970f4fe..107b55eda4 100644
--- a/src/Ext/HouseType/Hooks.InitialElite.cpp
+++ b/src/Ext/HouseType/Hooks.InitialElite.cpp
@@ -7,7 +7,7 @@ static SHPStruct* LoadSHPCameo(TechnoTypeClass* pType)
{
auto pTypeExt = TechnoTypeExt::Fetch(pType);
- if(pTypeExt->SpareCameo_IsLoad)
+ if(pTypeExt->SHPCameo_IsLoad)
return pTypeExt->SpareCameo;
char pFileName[0x20];
@@ -16,10 +16,12 @@ static SHPStruct* LoadSHPCameo(TechnoTypeClass* pType)
_strlwr_s(pFileName);
if(!_stricmp(pFileName, pTypeExt->SpareCameoFile.data())
- && strstr(pFileName, ".shp"))
+ && !strstr(pFileName, ".pcx"))
{
- SHPStruct* pSHP = FileSystem::LoadSHPFile(pFileName);
- pTypeExt->SpareCameo_IsLoad = true;
+ std::string Filename(pFileName);
+ Filename += ".shp";
+ SHPStruct* pSHP = FileSystem::LoadSHPFile(Filename.c_str());
+ pTypeExt->SHPCameo_IsLoad = true;
pTypeExt->SpareCameo = pSHP;
return pSHP;
}
@@ -31,10 +33,10 @@ static bool DrawPCXCameo(TechnoTypeClass* pType, const int destX, const int dest
auto pTypeExt = TechnoTypeExt::Fetch(pType);
char pFileName[0x20];
- strcpy_s(pFileName, pTypeExt->SpareCameoFile.data());
+ strcpy_s(pFileName, pTypeExt->SpareCameoPCX.GetFilename());
_strlwr_s(pFileName);
- if(!_stricmp(pFileName, pTypeExt->SpareCameoFile.data())
+ if(!_stricmp(pFileName, pTypeExt->SpareCameoPCX.GetFilename())
&& strstr(pFileName, ".pcx"))
{
PCX::Instance.LoadFile(pFileName);
diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp
index e5bfab881a..c52afd71a4 100644
--- a/src/Ext/TechnoType/Body.cpp
+++ b/src/Ext/TechnoType/Body.cpp
@@ -1438,6 +1438,7 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI)
this->ParseVoiceWeaponAttacks(exINI, pSection, this->VoiceWeaponAttacks, this->VoiceEliteWeaponAttacks);
this->SpareCameoFile.Read(pArtINI, pArtSection, "SpareCameo");
+ this->SpareCameoPCX.Read(pArtINI, pArtSection, "SpareCameoPCX");
}
template
@@ -1835,7 +1836,8 @@ void TechnoTypeExt::Serialize(T& Stm)
.Process(this->SpareCameoFile)
.Process(this->SpareCameo)
- .Process(this->SpareCameo_IsLoad)
+ .Process(this->SHPCameo_IsLoad)
+ .Process(this->SpareCameoPCX)
// Ares 0.2
.Process(this->RadarJamRadius)
diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h
index 329be0a190..b6e0a3fcd4 100644
--- a/src/Ext/TechnoType/Body.h
+++ b/src/Ext/TechnoType/Body.h
@@ -463,7 +463,9 @@ class TechnoTypeExt : public ObjectTypeExt
PhobosFixedString<0x20> SpareCameoFile;
SHPStruct* SpareCameo;
- bool SpareCameo_IsLoad;
+ bool SHPCameo_IsLoad;
+ PhobosPCXFile SpareCameoPCX;
+
TechnoTypeExt(TechnoTypeClass* OwnerObject) : ObjectTypeExt(OwnerObject)
, HealthBar_Hide { false }
@@ -857,7 +859,8 @@ class TechnoTypeExt : public ObjectTypeExt
, SpareCameoFile { NONE_STR }
, SpareCameo { nullptr }
- , SpareCameo_IsLoad { false }
+ , SHPCameo_IsLoad { false }
+ , SpareCameoPCX {}
// Ares 0.2
, RadarJamRadius { 0 }
From d0855265a6b6cac7f443f8383c2c798b03f59e5b Mon Sep 17 00:00:00 2001
From: dh381-1 <2575903651@qq.com>
Date: Thu, 10 Sep 2026 12:17:18 +0800
Subject: [PATCH 5/5] Merge branch 'new/CountryInitialElite' of
https://github.com/dh381-1/Phobos into new/CountryInitialElite
---
docs/New-or-Enhanced-Logics.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md
index 2ce01b5958..36de23268b 100644
--- a/docs/New-or-Enhanced-Logics.md
+++ b/docs/New-or-Enhanced-Logics.md
@@ -837,12 +837,13 @@ EliteUnits= ; List of UnitTypes
EliteAircraft= ; List of AircraftTypes
```
-- For each `TechnoType`, you can define `SpareCameo` to specify the elite‑level icon. When a `TechnoType` is added to the initial elite list, it will preferentially use the SpareCameo as its icon. Supports `SHP`/`PCX` formats.
+- For each `TechnoType`, you can define `SpareCameo` and `SpareCameoPCX` to specify the elite‑level icon. When a `TechnoType` is added to the initial elite list, it will preferentially use the SpareCameo as its icon.
In `artmd.ini`:
```ini
[SOMETECHNO] ; TechnoType
-SpareCameo= ; filename - including the .shp/.pcx extension
+SpareCameo= ; filename
+SpareCameoPCX= ; filename - include ".pcx" extension
```
## Infantry