diff --git a/CREDITS.md b/CREDITS.md
index 96eed675df..22eddae60d 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -396,6 +396,8 @@ This page lists all the individual contributions to the project by their author.
- Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades
- Type select for buildings (doc)
- Enhanced Bombard trajectory
+ - Passenger-based insignias
+ - Use `InsigniaType` to set the properties of insignia in a batch
- **NaotoYuuki** - Vertical & meteor trajectory projectile prototypes
- **handama** - AI script action to jump back to previous script
- **TaranDahl (航味麻酱)**
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 2e0629bf7c..9abb5b8052 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -75,6 +75,7 @@
+
@@ -218,6 +219,7 @@
+
diff --git a/YRpp b/YRpp
index 63591f3115..20c05ab0ef 160000
--- a/YRpp
+++ b/YRpp
@@ -1 +1 @@
-Subproject commit 63591f3115a4041bacdafe1e327a7cfed905aa09
+Subproject commit 20c05ab0ef36284a679abe41b457422916b7d5cb
diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md
index 25b385930e..20ec1ceb23 100644
--- a/docs/Fixed-or-Improved-Logics.md
+++ b/docs/Fixed-or-Improved-Logics.md
@@ -674,9 +674,13 @@ Due to technical constraints, these settings do not apply to buildings teleporte
- You can now customize veterancy insignia of TechnoTypes.
- `Insignia.(Rookie|Veteran|Elite)` can be used to set a custom insignia file, optionally for each veterancy stage. Like the original / default file, `pips.shp`, they are drawn using `palette.pal` as palette.
- - `InsigniaFrame.(Rookie|Veteran|Elite)` can be used to set (zero-based) frame index of the insignia to display, optionally for each veterancy stage. Using -1 uses the default setting. Default settings are -1 (none) for rookie, 14 for veteran and 15 for elite.
- - A shorthand `InsigniaFrames` can be used to list them in order from rookie, veteran and elite instead as well. `InsigniaFrame.(Rookie|Veteran|Elite)` takes priority over this.
- - Normal insignia can be overridden for specific weapon modes of `Gunner=true` units by setting `Insignia.(Frame/Frames).WeaponN` where `N` stands for 1-based weapon mode index. If not set, defaults to non-mode specific insignia settings.
+ - `InsigniaFrame(.Rookie|Veteran|Elite)` can be used to set (zero-based) frame index of the insignia to display, optionally for each veterancy stage. Using -1 uses the default setting. Default settings are -1 (none) for rookie, 14 for veteran and 15 for elite.
+ - A shorthand `InsigniaFrames` can be used to list them in order from rookie, veteran and elite instead as well. `InsigniaFrame(.Rookie|Veteran|Elite)` takes priority over this.
+ - These settings will be overriden by the properties set in [InsigniaType](Miscellanous.md#insignia-type), if `InsigniaType` is set.
+ - Normal insignia can be overridden for specific weapon modes of `Gunner=true` units by setting `Insignia(.Frame/.Frames).WeaponN` where `N` stands for 1-based weapon mode index. If not set, defaults to non-mode specific insignia settings.
+ - These settings will be overriden by the properties set in [InsigniaType](Miscellanous.md#insignia-type), if `InsigniaType.WeaponN` is set.
+ - Normal insignia can be overridden when its current passenger size reaches a certain amount by setting `Insignia(.Frame/.Frames).PassengersN` where `N` stands for the current passenger size amount (from 0 to `Passengers` of the transport). If not set, defaults to non-passenger specific insignia settings. Will be overridden by weapon mode insignia settings, if set.
+ - These settings will be overriden by the properties set in [InsigniaType](Miscellanous.md#insignia-type), if `InsigniaType.PassengersN` is set.
- `Insignia.ShowEnemy` controls whether or not the insignia is shown to enemy players. Defaults to `[General] -> EnemyInsignia`, which in turn defaults to true.
- You can make insignias appear only on selected units using `DrawInsignia.OnlyOnSelected`.
- Position for insignias can be adjusted by setting `DrawInsignia.AdjustPos.Infantry` for infantry, `DrawInsignia.AdjustPos.Buildings` for buildings, and `DrawInsignia.AdjustPos.Units` for others.
@@ -704,6 +708,7 @@ InsigniaFrame.Rookie=-1 ; int, frame of insignia shp (zero-base
InsigniaFrame.Veteran=-1 ; int, frame of insignia shp (zero-based) or -1 for default
InsigniaFrame.Elite=-1 ; int, frame of insignia shp (zero-based) or -1 for default
InsigniaFrames=-1,-1,-1 ; int, frames of insignia shp (zero-based) or -1 for default
+InsigniaType= ; InsigniaType
Insignia.WeaponN= ; filename - excluding the .shp extension
Insignia.WeaponN.Rookie= ; filename - excluding the .shp extension
Insignia.WeaponN.Veteran= ; filename - excluding the .shp extension
@@ -713,6 +718,17 @@ InsigniaFrame.WeaponN.Rookie=-1 ; int, frame of insignia shp (zero-base
InsigniaFrame.WeaponN.Veteran=-1 ; int, frame of insignia shp (zero-based) or -1 for default
InsigniaFrame.WeaponN.Elite=-1 ; int, frame of insignia shp (zero-based) or -1 for default
InsigniaFrames.WeaponN=-1,-1,-1 ; int, frames of insignia shp (zero-based) or -1 for default
+InsigniaType.WeaponN= ; InsigniaType
+Insignia.PassengersN= ; filename - excluding the .shp extension
+Insignia.PassengersN.Rookie= ; filename - excluding the .shp extension
+Insignia.PassengersN.Veteran= ; filename - excluding the .shp extension
+Insignia.PassengersN.Elite= ; filename - excluding the .shp extension
+InsigniaFrame.PassengersN=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.PassengersN.Rookie=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.PassengersN.Veteran=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.PassengersN.Elite=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrames.PassengersN=-1,-1,-1 ; int, frames of insignia shp (zero-based) or -1 for default
+InsigniaType.PassengersN= ; InsigniaType
Insignia.ShowEnemy= ; boolean
```
diff --git a/docs/Miscellanous.md b/docs/Miscellanous.md
index 77006d8744..c0b96e8866 100644
--- a/docs/Miscellanous.md
+++ b/docs/Miscellanous.md
@@ -85,6 +85,25 @@ SaveVariablesOnScenarioEnd=false ; boolean
Correspondingly, if such a writing method causes any errors, it is also not within the scope of responsibility of this function.
```
+### Insignia Type
+
+- It is now possible to define the properties of insignia in an entity, so that all properties in it will be used once it's applied to a techno.
+
+In `rulesmd.ini`:
+```ini
+[InsigniaTypes]
+0=SOMEINSIGNIATYPE
+
+[SOMEINSIGNIATYPE] ; InsigniaType
+Insignia= ; filename - excluding the .shp extension
+Insignia.Rookie= ; filename - excluding the .shp extension
+Insignia.Veteran= ; filename - excluding the .shp extension
+Insignia.Elite= ; filename - excluding the .shp extension
+InsigniaFrame=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.Rookie=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.Veteran=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+InsigniaFrame.Elite=-1 ; int, frame of insignia shp (zero-based) or -1 for default
+
## Game Speed
### Single player game speed
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 9c194da618..99af44008b 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -502,6 +502,8 @@ New:
- Allow customizing charge turret delays per burst on a weapon (by Starkku)
- Unit `Speed` setting now accepts floating point values (by Starkku)
- Extending `Power` to all TechnoTypes (by Morton)
+- Passenger-based insignias (by Ollerus)
+- Use `InsigniaType` to set the properties of insignia in a batch (by Ollerus)
Vanilla fixes:
- Allow AI to repair structures built from base nodes/trigger action 125/SW delivery in single player missions (by Trsdy)
diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp
index b2f4efdddc..ea0118ce8a 100644
--- a/src/Ext/Rules/Body.cpp
+++ b/src/Ext/Rules/Body.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
std::unique_ptr RulesExt::Data = nullptr;
@@ -34,6 +35,7 @@ void RulesExt::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
ShieldTypeClass::LoadFromINIList(pINI);
LaserTrailTypeClass::LoadFromINIList(&CCINIClass::INI_Art);
AttachEffectTypeClass::LoadFromINIList(pINI);
+ InsigniaTypeClass::LoadFromINIList(pINI);
Data->LoadBeforeTypeData(pThis, pINI);
}
diff --git a/src/Ext/Techno/Body.Visuals.cpp b/src/Ext/Techno/Body.Visuals.cpp
index ad07a722a8..a7336ed82f 100644
--- a/src/Ext/Techno/Body.Visuals.cpp
+++ b/src/Ext/Techno/Body.Visuals.cpp
@@ -134,6 +134,28 @@ void TechnoExt::DrawInsignia(TechnoClass* pThis, Point2D* pLocation, RectangleSt
int insigniaFrame = insigniaFrames.X;
int frameIndex = pTechnoTypeExt->InsigniaFrame.Get(pThis);
+ if (pTechnoType->Passengers > 0)
+ {
+ int passengersIndex = pThis->Passengers.GetTotalSize();
+
+ if (auto const pCustomShapeFile = pTechnoTypeExt->Insignia_Passengers[passengersIndex].Get(pThis))
+ {
+ pShapeFile = pCustomShapeFile;
+ defaultFrameIndex = 0;
+ isCustomInsignia = true;
+ }
+
+ int frame = pTechnoTypeExt->InsigniaFrame_Passengers[passengersIndex].Get(pThis);
+
+ if (frame != -1)
+ frameIndex = frame;
+
+ auto& frames = pTechnoTypeExt->InsigniaFrames_Passengers[passengersIndex];
+
+ if (frames!= Vector3D(-1, -1, -1))
+ insigniaFrames = frames.Get();
+ }
+
if (pTechnoType->Gunner)
{
int weaponIndex = pThis->CurrentWeaponNumber;
@@ -153,7 +175,7 @@ void TechnoExt::DrawInsignia(TechnoClass* pThis, Point2D* pLocation, RectangleSt
auto& frames = pTechnoTypeExt->InsigniaFrames_Weapon[weaponIndex];
if (frames != Vector3D(-1, -1, -1))
- insigniaFrames = frames;
+ insigniaFrames = frames.Get();
}
if (pVeterancy->IsVeteran())
diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp
index 63b5651ddb..2ffd65bb3c 100644
--- a/src/Ext/TechnoType/Body.cpp
+++ b/src/Ext/TechnoType/Body.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
@@ -410,9 +411,23 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->DeployFireWeapon.Read(exINI, pSection, "DeployFireWeapon");
this->TargetZoneScanType.Read(exINI, pSection, "TargetZoneScanType");
- this->Insignia.Read(exINI, pSection, "Insignia.%s");
- this->InsigniaFrames.Read(exINI, pSection, "InsigniaFrames");
- this->InsigniaFrame.Read(exINI, pSection, "InsigniaFrame.%s");
+ // insignia type
+ Nullable InsigniaType;
+ InsigniaType.Read(exINI, pSection, "InsigniaType");
+
+ if (InsigniaType.isset())
+ {
+ this->Insignia = InsigniaType.Get()->Insignia;
+ this->InsigniaFrame = InsigniaType.Get()->InsigniaFrame;
+ this->InsigniaFrames = Vector3D(-1, -1, -1); // override it so only InsigniaFrame will be used
+ }
+ else
+ {
+ this->Insignia.Read(exINI, pSection, "Insignia.%s");
+ this->InsigniaFrames.Read(exINI, pSection, "InsigniaFrames");
+ this->InsigniaFrame.Read(exINI, pSection, "InsigniaFrame.%s");
+ }
+
this->Insignia_ShowEnemy.Read(exINI, pSection, "Insignia.ShowEnemy");
this->TiltsWhenCrushes_Vehicles.Read(exINI, pSection, "TiltsWhenCrushes.Vehicles");
@@ -505,14 +520,66 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
for (size_t i = 0; i < weaponCount; i++)
{
- _snprintf_s(tempBuffer, sizeof(tempBuffer), "Insignia.Weapon%d.%s", i + 1, "%s");
- this->Insignia_Weapon[i].Read(exINI, pSection, tempBuffer);
+ Nullable InsigniaType_Weapon;
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaType.Weapon%d", i + 1);
+ InsigniaType_Weapon.Read(exINI, pSection, tempBuffer);
+
+ if (InsigniaType_Weapon.isset())
+ {
+ this->Insignia_Weapon[i] = InsigniaType_Weapon.Get()->Insignia;
+ this->InsigniaFrame_Weapon[i] = InsigniaType_Weapon.Get()->InsigniaFrame;
+ this->InsigniaFrames_Weapon[i] = Vector3D(-1, -1, -1); // override it so only InsigniaFrame will be used
+ }
+ else
+ {
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "Insignia.Weapon%d.%s", i + 1, "%s");
+ this->Insignia_Weapon[i].Read(exINI, pSection, tempBuffer);
+
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrame.Weapon%d.%s", i + 1, "%s");
+ this->InsigniaFrame_Weapon[i].Read(exINI, pSection, tempBuffer);
+
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrames.Weapon%d", i + 1);
+ this->InsigniaFrames_Weapon[i].Read(exINI, pSection, tempBuffer);
+ }
+ }
+ }
+
+ if (this->OwnerObject()->Passengers > 0)
+ {
+ size_t passengers = this->OwnerObject()->Passengers + 1;
+
+ if (this->Insignia_Passengers.empty() || this->Insignia_Passengers.size() != passengers)
+ {
+ this->Insignia_Passengers.resize(passengers);
+ this->InsigniaFrame_Passengers.resize(passengers, Promotable(-1));
+ Valueable> frames;
+ frames = Vector3D(-1, -1, -1);
+ this->InsigniaFrames_Passengers.resize(passengers, frames);
+ }
+
+ for (size_t i = 0; i < passengers; i++)
+ {
+ Nullable InsigniaType_Passengers;
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaType.Passengers%d", i);
+ InsigniaType_Passengers.Read(exINI, pSection, tempBuffer);
+
+ if (InsigniaType_Passengers.isset())
+ {
+ this->Insignia_Passengers[i] = InsigniaType_Passengers.Get()->Insignia;
+ this->InsigniaFrame_Passengers[i] = InsigniaType_Passengers.Get()->InsigniaFrame;
+ this->InsigniaFrames_Passengers[i] = Vector3D(-1, -1, -1); // override it so only InsigniaFrame will be used
+ }
+ else
+ {
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "Insignia.Passengers%d.%s", i, "%s");
+ this->Insignia_Passengers[i].Read(exINI, pSection, tempBuffer);
- _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrame.Weapon%d.%s", i + 1, "%s");
- this->InsigniaFrame_Weapon[i].Read(exINI, pSection, tempBuffer);
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrame.Passengers%d.%s", i, "%s");
+ this->InsigniaFrame_Passengers[i].Read(exINI, pSection, tempBuffer);
- _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrames.Weapon%d", i + 1);
- this->InsigniaFrames_Weapon[i].Read(exINI, pSection, tempBuffer);
+ _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrames.Passengers%d", i);
+ this->InsigniaFrames_Passengers[i].Read(exINI, pSection, tempBuffer);
+ }
}
}
@@ -796,6 +863,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->Insignia_Weapon)
.Process(this->InsigniaFrame_Weapon)
.Process(this->InsigniaFrames_Weapon)
+ .Process(this->Insignia_Passengers)
+ .Process(this->InsigniaFrame_Passengers)
+ .Process(this->InsigniaFrames_Passengers)
.Process(this->TiltsWhenCrushes_Vehicles)
.Process(this->TiltsWhenCrushes_Overlays)
diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h
index cf325654c8..b0aec0c255 100644
--- a/src/Ext/TechnoType/Body.h
+++ b/src/Ext/TechnoType/Body.h
@@ -183,6 +183,9 @@ class TechnoTypeExt
std::vector> Insignia_Weapon;
std::vector> InsigniaFrame_Weapon;
std::vector>> InsigniaFrames_Weapon;
+ std::vector> Insignia_Passengers;
+ std::vector> InsigniaFrame_Passengers;
+ std::vector>> InsigniaFrames_Passengers;
Nullable TiltsWhenCrushes_Vehicles;
Nullable TiltsWhenCrushes_Overlays;
@@ -420,6 +423,9 @@ class TechnoTypeExt
, Insignia_Weapon {}
, InsigniaFrame_Weapon {}
, InsigniaFrames_Weapon {}
+ , Insignia_Passengers {}
+ , InsigniaFrame_Passengers {}
+ , InsigniaFrames_Passengers {}
, TiltsWhenCrushes_Vehicles {}
, TiltsWhenCrushes_Overlays {}
diff --git a/src/New/Type/InsigniaTypeClass.cpp b/src/New/Type/InsigniaTypeClass.cpp
new file mode 100644
index 0000000000..87e3e90cb3
--- /dev/null
+++ b/src/New/Type/InsigniaTypeClass.cpp
@@ -0,0 +1,17 @@
+#include "InsigniaTypeClass.h"
+
+template<>
+const char* Enumerable::GetMainSection()
+{
+ return "InsigniaTypes";
+}
+
+void InsigniaTypeClass::LoadFromINI(CCINIClass* pINI)
+{
+ const char* section = this->Name;
+
+ INI_EX exINI(pINI);
+
+ this->Insignia.Read(exINI, section, "Insignia.%s");
+ this->InsigniaFrame.Read(exINI, section, "InsigniaFrame.%s");
+}
diff --git a/src/New/Type/InsigniaTypeClass.h b/src/New/Type/InsigniaTypeClass.h
new file mode 100644
index 0000000000..d5c46c3e00
--- /dev/null
+++ b/src/New/Type/InsigniaTypeClass.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include
+
+class InsigniaTypeClass final : public Enumerable
+{
+public:
+ Promotable Insignia;
+ Promotable InsigniaFrame;
+
+ InsigniaTypeClass(const char* const pTitle) : Enumerable(pTitle)
+ , Insignia { }
+ , InsigniaFrame { -1 }
+ { }
+
+ void LoadFromINI(CCINIClass* pINI);
+ // No need to save and load as it's only for parsing
+};