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 +};