diff --git a/CREDITS.md b/CREDITS.md index ca78a874c7..2c22fe0a1d 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -469,6 +469,7 @@ This page lists all the individual contributions to the project by their author. - Fix a bug introduced by Ares where building types that have `UndeploysInto` cannot display `AltCameo` or `AltCameoPCX` even when you infiltrate enemy buildings with `Factory=UnitType` - Fix a bug where units can be promoted when created via trigger actions even if they have `Trainable=false` - Fix the bug that ai will try to product aircraft even the airport has no free dock for it + - Allow techno type considered as other type when recruiting techno for teams - **Apollo** - Translucent SHP drawing patches - **ststl**: - Customizable `ShowTimer` priority of superweapons diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 99838b773a..0502d7ab2a 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1840,6 +1840,17 @@ HeightShadowScaling.MinScale=0.0 ; floating point value ShadowSizeCharacteristicHeight= ; integer, height in leptons ``` +### Allow techno type considered as other type when recruiting techno for teams + +- It is now possible to make techno type considered as other type when recruiting techno for teams, both for AI team recruitment and `Create Team` action. + - Only affect techno that's presented on the map. Cannot make AI produce this type of techno if it doesn't have any. + +In `rulesmd.ini`: +```ini +[SOMETECHNO] ; TechnoType +TeamMember.ConsideredAs= ; list of technotypes +``` + ## Terrains ### Animated TerrainTypes diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 1cd23d2502..5679abfa39 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -473,7 +473,8 @@ New: - [Allow merging AOE damage to buildings into one](New-or-Enhanced-Logics.md#allow-merging-aoe-damage-to-buildings-into-one) (by CrimRecya) - [Allow customizing whether to synchronously change the owner of the RadioLink-linked units when the owner of a building changes](Fixed-or-Improved-Logics.md#custom-whether-to-synchronously-change-the-owner-of-the-radiolink-linked-units-when-the-owner-of-a-building-changes) (by TaranDahl) - [Toggle per-target warhead effects apply timing](New-or-Enhanced-Logics.md#toggle-per-target-warhead-effects-apply-timing) (by TaranDahl) -- [Extra range for chasing and pre-firing](New-or-Enhanced-Logics.md#extra-range-for-chasing-and-pre-firing) (by TaranDahl) +- [Extra range for chasing and pre-firing](New-or-Enhanced-Logics.md#extra-range) (by TaranDahl) +- Allow techno type considered as other type when recruiting techno for teams (by NetsuNegi) 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/Team/Hooks.cpp b/src/Ext/Team/Hooks.cpp index 64688d2f17..adee3b7416 100644 --- a/src/Ext/Team/Hooks.cpp +++ b/src/Ext/Team/Hooks.cpp @@ -1,5 +1,6 @@ #include "Body.h" #include +#include // Bugfix: TAction 7,80,107. DEFINE_HOOK(0x65DF67, TeamTypeClass_CreateMembers_LoadOntoTransport, 0x6) @@ -53,3 +54,95 @@ DEFINE_HOOK(0x65DF67, TeamTypeClass_CreateMembers_LoadOntoTransport, 0x6) return 0x65DF8D; } + +DEFINE_HOOK(0x6EA6BE, TeamClass_CanAddMember_Consideration, 0x6) +{ + enum { SkipGameCode = 0x6EA6F2 }; + + GET(TeamClass*, pTeam, EBP); + GET(FootClass*, pFoot, ESI); + GET(int*, idx, EBX); + const auto pFootTypeExt = TechnoExt::ExtMap.Find(pFoot)->TypeExtData; + const auto pFootType = pFootTypeExt->OwnerObject(); + const auto pTaskForce = pTeam->Type->TaskForce; + + do + { + const auto pType = pTaskForce->Entries[*idx].Type; + + if (pType == pFootType || pFootTypeExt->TeamMember_ConsideredAs.Contains(pType)) + break; + + *idx = *idx + 1; + } + while (pTaskForce->CountEntries > *idx); + + return SkipGameCode; +} + +DEFINE_HOOK(0x6EA8E7, TeamClass_LiberateMember_Consideration, 0x5) +{ + enum { SkipGameCode = 0x6EA91B }; + + GET(TeamClass*, pTeam, EDI); + GET(FootClass*, pMember, EBP); + int idx = 0; + const auto pMemberTypeExt = TechnoExt::ExtMap.Find(pMember)->TypeExtData; + const auto pMemberType = pMemberTypeExt->OwnerObject(); + const auto pTaskForce = pTeam->Type->TaskForce; + + do + { + const auto pSearchType = pTaskForce->Entries[idx].Type; + + if (pSearchType == pMemberType || pMemberTypeExt->TeamMember_ConsideredAs.Contains(pSearchType)) + break; + + ++idx; + } + while (pTaskForce->CountEntries > idx); + + R->Stack(STACK_OFFSET(0x14, 0x8), idx); + return SkipGameCode; +} + +DEFINE_HOOK(0x6EAD73, TeamClass_RecruitMember_Consideration, 0x7) +{ + enum { ContinueCheck = 0x6EAD8F, SkipThisMember = 0x6EADB3 }; + + GET(TeamClass*, pTeam, ECX); + GET(UnitClass*, pMember, ESI); + GET_STACK(const int, idx, STACK_OFFSET(0x3C, 0x4)); + const auto pMemberType = pMember->Type; + const auto pTaskForce = pTeam->Type->TaskForce; + const auto pSearchType = pTaskForce->Entries[idx].Type; + + return pSearchType == pMemberType || TechnoTypeExt::ExtMap.Find(pMemberType)->TeamMember_ConsideredAs.Contains(pSearchType) ? ContinueCheck : SkipThisMember; +} + +DEFINE_HOOK(0x6EF57F, TeamClass_GetTaskForceMissingMemberTypes_Consideration, 0x5) +{ + enum { ContinueIn = 0x6EF584, SkipThisMember = 0x6EF5A5 }; + + GET(int, idx, EAX); + + if (idx != -1) + return ContinueIn; + + GET(DynamicVectorClass*, vector, ESI); + GET(FootClass*, pMember, EDI); + const auto pMemberTypeExt = TechnoExt::ExtMap.Find(pMember)->TypeExtData; + + for (const auto pConsideType : pMemberTypeExt->TeamMember_ConsideredAs) + { + idx = vector->FindItemIndex(pConsideType); + + if (idx != -1) + { + R->EAX(idx); + return ContinueIn; + } + } + + return SkipThisMember; +} diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 4bb689d3a8..34846e8b06 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1112,6 +1112,8 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) Debug::Log("[Developer warning][%s] Ammo.AutoConvertMinimumAmount is greater than Ammo.AutoConvertMaximumAmount, resulting in no conversion.\n", pSection); this->InfantryAutoDeploy.Read(exINI, pSection, "InfantryAutoDeploy"); + + this->TeamMember_ConsideredAs.Read(exINI, pSection, "TeamMember.ConsideredAs"); // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); @@ -1785,6 +1787,8 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->InfantryAutoDeploy) + .Process(this->TeamMember_ConsideredAs) + .Process(this->TurretResponse) ; } diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 4de978975e..88a037a994 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -451,6 +451,8 @@ class TechnoTypeExt Nullable InfantryAutoDeploy; + ValueableVector TeamMember_ConsideredAs; + Nullable TurretResponse; ExtData(TechnoTypeClass* OwnerObject) : Extension(OwnerObject) @@ -855,6 +857,8 @@ class TechnoTypeExt , InfantryAutoDeploy {} + , TeamMember_ConsideredAs {} + , TurretResponse {} { }