diff --git a/CREDITS.md b/CREDITS.md index 1ddaaf1b51..ab533c3c3a 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -372,6 +372,7 @@ This page lists all the individual contributions to the project by their author. - **Ollerus** - Build limit group enhancement - Customizable rocker amplitude + - Use `InsigniaType` to set the properties of insignia in a batch - **handama** - AI script action to jump back to previous script - **TaranDahl (航味麻酱)** - Skirmish AI "sell all buildings and set all technos to hunt" behavior dehardcode diff --git a/Phobos.vcxproj b/Phobos.vcxproj index 32890abf5e..d013304f77 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -20,6 +20,7 @@ + @@ -185,6 +186,7 @@ + diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 66061b4fb3..c93799ab92 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -615,10 +615,10 @@ Due to technical constraints, these settings do not apply to buildings teleporte ### Customizable veterancy insignias - 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. + - `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. + - 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. - `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. @@ -646,6 +646,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 @@ -655,6 +656,7 @@ 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.ShowEnemy= ; boolean ``` diff --git a/docs/Miscellanous.md b/docs/Miscellanous.md index 82806776b0..bfb43a624d 100644 --- a/docs/Miscellanous.md +++ b/docs/Miscellanous.md @@ -79,6 +79,26 @@ Teleport | `{4A582747-9839-11d1-B709-00A024DDAFD1}` | Mech | `{55D141B8-DB94-11d1-AC98-006008055BB5}` | Ship | `{2BEA74E1-7CCA-11d3-BE14-00104B62A16C}` | +### 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 fa8d761a70..eb201d555d 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -468,6 +468,7 @@ New: - Allow infantry to use land sequences in water (by Starkku) - `` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku) - Allow customizing charge turret delays per burst on a weapon (by Starkku) +- 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 0c57e70790..d435b957ec 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.get()); 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..0413a38d72 100644 --- a/src/Ext/Techno/Body.Visuals.cpp +++ b/src/Ext/Techno/Body.Visuals.cpp @@ -152,8 +152,8 @@ void TechnoExt::DrawInsignia(TechnoClass* pThis, Point2D* pLocation, RectangleSt auto& frames = pTechnoTypeExt->InsigniaFrames_Weapon[weaponIndex]; - if (frames != Vector3D(-1, -1, -1)) - insigniaFrames = frames; + if (frames.isset() && frames.Get() != Vector3D(-1, -1, -1)) + insigniaFrames = frames.Get(); } if (pVeterancy->IsVeteran()) diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 94ada02927..36ed002d80 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -407,9 +408,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"); @@ -478,30 +493,40 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) char tempBuffer[32]; - if (this->OwnerObject()->Gunner && this->Insignia_Weapon.empty()) + if (this->OwnerObject()->Gunner) { - int weaponCount = this->OwnerObject()->WeaponCount; - this->Insignia_Weapon.resize(weaponCount); - this->InsigniaFrame_Weapon.resize(weaponCount); - this->InsigniaFrames_Weapon.resize(weaponCount); + size_t weaponCount = this->OwnerObject()->WeaponCount; + + if (this->Insignia_Weapon.empty() || this->Insignia_Weapon.size() != weaponCount) + { + this->Insignia_Weapon.resize(weaponCount); + this->InsigniaFrame_Weapon.resize(weaponCount); + this->InsigniaFrames_Weapon.resize(weaponCount); + } for (int i = 0; i < weaponCount; i++) { - Promotable insignia; - _snprintf_s(tempBuffer, sizeof(tempBuffer), "Insignia.Weapon%d.%s", i + 1, "%s"); - insignia.Read(exINI, pSection, tempBuffer); - this->Insignia_Weapon[i] = insignia; - - Promotable frame = Promotable(-1); - _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrame.Weapon%d.%s", i + 1, "%s"); - frame.Read(exINI, pSection, tempBuffer); - this->InsigniaFrame_Weapon[i] = frame; - - Valueable> frames; - frames = Vector3D(-1, -1, -1); - _snprintf_s(tempBuffer, sizeof(tempBuffer), "InsigniaFrames.Weapon%d", i + 1); - frames.Read(exINI, pSection, tempBuffer); - this->InsigniaFrames_Weapon[i] = frames; + 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); + } } } diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 2b06116e3d..6e831d1138 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -174,7 +174,7 @@ class TechnoTypeExt Nullable Insignia_ShowEnemy; std::vector> Insignia_Weapon; std::vector> InsigniaFrame_Weapon; - std::vector> InsigniaFrames_Weapon; + std::vector>> InsigniaFrames_Weapon; Nullable TiltsWhenCrushes_Vehicles; Nullable 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 +};