diff --git a/data/base/script/campaign/cam3-a.js b/data/base/script/campaign/cam3-a.js index a17d8d1b0f9..a7cf7436780 100644 --- a/data/base/script/campaign/cam3-a.js +++ b/data/base/script/campaign/cam3-a.js @@ -232,6 +232,8 @@ function eventStartLevel() setPower(PLAYER_POWER, CAM_HUMAN_PLAYER); cam3Setup(); + enableTemplate("ConstructionDroid"); + camSetEnemyBases({ "NEXUS-WBase": { cleanup: "westBaseCleanup", diff --git a/data/base/script/fastplay/fastdemo.js b/data/base/script/fastplay/fastdemo.js index 765074334aa..f558c15f976 100644 --- a/data/base/script/fastplay/fastdemo.js +++ b/data/base/script/fastplay/fastdemo.js @@ -198,6 +198,9 @@ function eventStartLevel() camPlayVideos("MBDEMO_MSG"); hackAddMessage("FAST_OBJ1", PROX_MSG, CAM_HUMAN_PLAYER, false); + enableTemplate("ConstructionDroid"); + enableTemplate("ViperLtMGWheels"); + queue("sendAttackGroup1", camSecondsToMilliseconds(10)); queue("sendAttackGroup2", camSecondsToMilliseconds(20)); queue("activateDefenders", camSecondsToMilliseconds(30)); diff --git a/data/base/script/rules.js b/data/base/script/rules.js index 9f17b25abd1..dfc7414222a 100644 --- a/data/base/script/rules.js +++ b/data/base/script/rules.js @@ -156,6 +156,7 @@ function reticuleDesignCheck() { setReticuleButton(4, _("Design - construct HQ first"), "", ""); setMiniMap(false); + // Will enable templates that are researched whenever the reticule buttons update. setDesign(false); } } diff --git a/data/mp/multiplay/skirmish/rules.js b/data/mp/multiplay/skirmish/rules.js index 0479fe154b9..c1ce6feb6bb 100644 --- a/data/mp/multiplay/skirmish/rules.js +++ b/data/mp/multiplay/skirmish/rules.js @@ -108,7 +108,6 @@ function reticuleDesignCheck() { setReticuleButton(4, _("Design - construct HQ first"), "", ""); setMiniMap(false); - setDesign(false); } } diff --git a/src/qtscriptfuncs.cpp b/src/qtscriptfuncs.cpp index ab74fd75a02..bdb92035ffb 100644 --- a/src/qtscriptfuncs.cpp +++ b/src/qtscriptfuncs.cpp @@ -3251,13 +3251,13 @@ static QScriptValue js_setDesign(QScriptContext *context, QScriptEngine *engine) // FIXME: This dual data structure for templates is just plain insane. for (auto &keyvaluepair : droidTemplates[selectedPlayer]) { - bool researched = researchedTemplate(keyvaluepair.second, selectedPlayer); + bool researched = researchedTemplate(keyvaluepair.second, selectedPlayer, true); keyvaluepair.second->enabled = (researched || allowDesign); } for (auto &localTemplate : localTemplates) { psCurr = &localTemplate; - bool researched = researchedTemplate(psCurr, selectedPlayer); + bool researched = researchedTemplate(psCurr, selectedPlayer, true); psCurr->enabled = (researched || allowDesign); } return QScriptValue(); diff --git a/src/structure.cpp b/src/structure.cpp index b6b46069f60..f8c5232f072 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -2424,21 +2424,22 @@ static bool IsFactoryCommanderGroupFull(const FACTORY *psFactory) return true; } -// Check if a player has built a command relay. -bool hasBuiltCommandRelay(bool isMission, int player) +// Check if a player has a certain structure. Optionally, checks if there is +// at least one that is built. +bool structureExists(int player, STRUCTURE_TYPE type, bool built, bool isMission) { - bool hasRelay = false; + bool found = false; for (STRUCTURE *psCurr = isMission ? mission.apsStructLists[player] : apsStructLists[player]; psCurr; psCurr = psCurr->psNext) { - if (psCurr->pStructureType->type == REF_COMMAND_CONTROL && psCurr->status == SS_BUILT) + if (psCurr->pStructureType->type == type && (!built || (built && psCurr->status == SS_BUILT))) { - hasRelay = true; + found = true; break; } } - return hasRelay; + return found; } // Disallow manufacture of units once these limits are reached, @@ -2502,7 +2503,7 @@ static bool checkHaltOnMaxUnitsReached(STRUCTURE *psStructure, bool isMission) else switch (droidTemplateType(templ)) { case DROID_COMMAND: - if (!hasBuiltCommandRelay(isMission, player)) + if (!structureExists(player, REF_COMMAND_CONTROL, true, isMission)) { isLimit = true; ssprintf(limitMsg, _("Can't build \"%s\" without a Command Relay Center — Production Halted"), templ->name.toUtf8().c_str()); diff --git a/src/structure.h b/src/structure.h index 56286cc4424..4aa10c38fc6 100644 --- a/src/structure.h +++ b/src/structure.h @@ -78,7 +78,7 @@ void setMaxDroids(int player, int value); void setMaxCommanders(int player, int value); void setMaxConstructors(int player, int value); -bool hasBuiltCommandRelay(bool isMission, int player); +bool structureExists(int player, STRUCTURE_TYPE type, bool built, bool isMission); bool IsPlayerDroidLimitReached(int player); diff --git a/src/template.cpp b/src/template.cpp index d5f048efb16..e0ffe9eacd1 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -44,6 +44,7 @@ std::map droidTemplates[MAX_PLAYERS]; bool allowDesign = true; bool includeRedundantDesigns = false; +bool playerBuiltHQ = false; static bool researchedItem(const DROID_TEMPLATE* /*psCurr*/, int player, COMPONENT_TYPE partIndex, int part, bool allowZero, bool allowRedundant) @@ -645,6 +646,11 @@ void fillTemplateList(std::vector &pList, STRUCTURE *psFactory BODY_SIZE iCapacity = (BODY_SIZE)psFactory->capacity; + if (!playerBuiltHQ) + { + playerBuiltHQ = structureExists(player, REF_HQ, true, false) || structureExists(player, REF_HQ, true, true); + } + /* Add the templates to the list*/ for (DROID_TEMPLATE &i : localTemplates) { @@ -661,8 +667,10 @@ void fillTemplateList(std::vector &pList, STRUCTURE *psFactory } } - if (!psCurr->enabled || !validTemplateForFactory(psCurr, psFactory, false) - || !researchedTemplate(psCurr, player, includeRedundantDesigns)) + if (!psCurr->enabled + || (bMultiPlayer && !playerBuiltHQ) + || !validTemplateForFactory(psCurr, psFactory, false) + || !researchedTemplate(psCurr, player, includeRedundantDesigns)) { continue; } diff --git a/src/template.h b/src/template.h index b97aac1bebd..c08d7b24d21 100644 --- a/src/template.h +++ b/src/template.h @@ -28,6 +28,7 @@ extern std::map droidTemplates[MAX_PLAYERS]; extern bool allowDesign; extern bool includeRedundantDesigns; +extern bool playerBuiltHQ; bool initTemplates();