diff --git a/config/gameConfig.json b/config/gameConfig.json index 92e869a0b..66ce8c8ed 100644 --- a/config/gameConfig.json +++ b/config/gameConfig.json @@ -440,7 +440,11 @@ // NOTE: on HotA maps, this setting has no effect. Value provided in map will be used instead. "allowRandomSpecialWeeks" : true, // if enabled, every creature can get double growth month, ignoring predefined list - "allowAllForDoubleMonth" : false + "allowAllForDoubleMonth" : false, + // if enabled creatures may join player for free, disabling it removes free joining globally unless creature is set to join in map editor + "allowJoiningForFree" : true, + // percent of stack amount that joins player per each successful join (does not decrease cost when joining for gold), if 0 or lower creatures never join for free or gold + "joiningPercentage" : 100 }, "dwellings" : diff --git a/config/schemas/gameSettings.json b/config/schemas/gameSettings.json index 7888037a2..b29bcf5d9 100644 --- a/config/schemas/gameSettings.json +++ b/config/schemas/gameSettings.json @@ -87,7 +87,9 @@ "weeklyGrowthCap" : { "type" : "number" }, "dailyStackExperience" : { "type" : "number" }, "allowRandomSpecialWeeks" : { "type" : "boolean" }, - "allowAllForDoubleMonth" : { "type" : "boolean" } + "allowAllForDoubleMonth" : { "type" : "boolean" }, + "allowJoiningForFree" : { "type" : "boolean" }, + "joiningPercentage" : { "type" : "number" } } }, "dwellings": { diff --git a/lib/GameSettings.cpp b/lib/GameSettings.cpp index c1e688490..a54cbc5bd 100644 --- a/lib/GameSettings.cpp +++ b/lib/GameSettings.cpp @@ -57,8 +57,10 @@ const std::vector GameSettings::settingProperties = {EGameSettings::COMBAT_LAYOUTS, "combat", "layouts" }, {EGameSettings::COMBAT_ONE_HEX_TRIGGERS_OBSTACLES, "combat", "oneHexTriggersObstacles" }, {EGameSettings::CREATURES_ALLOW_ALL_FOR_DOUBLE_MONTH, "creatures", "allowAllForDoubleMonth" }, + {EGameSettings::CREATURES_ALLOW_JOINING_FOR_FREE, "creatures", "allowJoiningForFree" }, {EGameSettings::CREATURES_ALLOW_RANDOM_SPECIAL_WEEKS, "creatures", "allowRandomSpecialWeeks" }, {EGameSettings::CREATURES_DAILY_STACK_EXPERIENCE, "creatures", "dailyStackExperience" }, + {EGameSettings::CREATURES_JOINING_PERCENTAGE, "creatures", "joiningPercentage" }, {EGameSettings::CREATURES_WEEKLY_GROWTH_CAP, "creatures", "weeklyGrowthCap" }, {EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT, "creatures", "weeklyGrowthPercent" }, {EGameSettings::DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE, "spells", "dimensionDoorExposesTerrainType" }, diff --git a/lib/IGameSettings.h b/lib/IGameSettings.h index b4a0f6f72..f0eda3f6d 100644 --- a/lib/IGameSettings.h +++ b/lib/IGameSettings.h @@ -32,6 +32,8 @@ enum class EGameSettings CREATURES_ALLOW_ALL_FOR_DOUBLE_MONTH, CREATURES_ALLOW_RANDOM_SPECIAL_WEEKS, CREATURES_DAILY_STACK_EXPERIENCE, + CREATURES_ALLOW_JOINING_FOR_FREE, + CREATURES_JOINING_PERCENTAGE, CREATURES_WEEKLY_GROWTH_CAP, CREATURES_WEEKLY_GROWTH_PERCENT, DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE, diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index f7b9fb7a2..049b07923 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -182,7 +182,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const BlockingDialog ynd(true,false); ynd.player = h->tempOwner; ynd.text.appendLocalString(EMetaText::ADVOB_TXT, 86); - ynd.text.replaceName(getCreatureID(), getStackCount(SlotID(0))); + ynd.text.replaceName(getCreatureID(), getJoiningAmount()); cb->showBlockingDialog(this, &ynd); break; } @@ -195,7 +195,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const ynd.player = h->tempOwner; ynd.components.emplace_back(ComponentType::RESOURCE, GameResID(GameResID::GOLD), action); std::string tmp = VLC->generaltexth->advobtxt[90]; - boost::algorithm::replace_first(tmp, "%d", std::to_string(getStackCount(SlotID(0)))); + boost::algorithm::replace_first(tmp, "%d", std::to_string(getJoiningAmount())); boost::algorithm::replace_first(tmp, "%d", std::to_string(action)); boost::algorithm::replace_first(tmp,"%s",getCreature()->getNamePluralTranslated()); ynd.text.appendRawString(tmp); @@ -215,6 +215,11 @@ const CCreature * CGCreature::getCreature() const return getCreatureID().toCreature(); } +TQuantity CGCreature::getJoiningAmount() const +{ + return std::max(static_cast(1), getStackCount(SlotID(0)) * cb->getSettings().getInteger(EGameSettings::CREATURES_JOINING_PERCENTAGE) / 100); +} + void CGCreature::pickRandomObject(vstd::RNG & rand) { switch(ID.toEnum()) @@ -378,9 +383,9 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const if(charisma < character) return FIGHT; - if (allowJoin) + if (allowJoin && cb->getSettings().getInteger(EGameSettings::CREATURES_JOINING_PERCENTAGE) > 0) { - if(diplomacy + sympathy + 1 >= character) + if((cb->getSettings().getBoolean(EGameSettings::CREATURES_ALLOW_JOINING_FOR_FREE) || character == Character::COMPLIANT) && diplomacy + sympathy + 1 >= character) return JOIN_FOR_FREE; if(diplomacy * 2 + sympathy + 1 >= character) @@ -448,6 +453,10 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co cb->giveResource(h->tempOwner,EGameResID::GOLD,-cost); giveReward(h); + + for(std::pair stack : this->stacks) + stack.second->count = getJoiningAmount(); + cb->tryJoiningArmy(this, h, true, true); } } diff --git a/lib/mapObjects/CGCreature.h b/lib/mapObjects/CGCreature.h index daa554a2e..b3fd43384 100644 --- a/lib/mapObjects/CGCreature.h +++ b/lib/mapObjects/CGCreature.h @@ -51,6 +51,7 @@ public: void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override; CreatureID getCreatureID() const; const CCreature * getCreature() const; + TQuantity getJoiningAmount() const; //stack formation depends on position, bool containsUpgradedStack() const;