mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 20:55:44 +00:00
Combine castles and infrastructure for hero cap (#8766)
This commit is contained in:
@@ -235,7 +235,8 @@ minimumTrustToOfferTruce 0 Int
|
||||
minimumTrustToInvite 20 Int
|
||||
minimumTrustToOfferAlliance 30 Int
|
||||
requiredPowerMultiplierForDismiss 1.5 Double
|
||||
heroCapDivisor 3.0 Double
|
||||
heroCapDivisor 10.0 Double
|
||||
heroCapPerCastle 5 Int
|
||||
overHeroCapLoyaltyDelta -1 Double
|
||||
minimumAgilityForArchery 75 Double
|
||||
minimumAgilityForStartFire 70 Double
|
||||
|
||||
|
@@ -95,7 +95,7 @@ object ProvinceUpdateHelpers {
|
||||
agricultureDevastation =
|
||||
(p.agricultureDevastation + cp.agricultureDevastationDelta.getOrElse(0.0)).max(0.0).min(p.agriculture),
|
||||
infrastructureDevastation = newInfrastructureDevastation,
|
||||
heroCap = ProvinceUtils.heroCap(newInfrastructure - newInfrastructureDevastation),
|
||||
heroCap = ProvinceUtils.heroCap(p.castleCount, newInfrastructure - newInfrastructureDevastation),
|
||||
support = (p.support + cp.supportDelta.getOrElse(0.0)).max(0.0).min(100.0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3100,7 +3100,20 @@ scala_setting_library(
|
||||
name = "hero_cap_divisor",
|
||||
setting_name = "HeroCapDivisor",
|
||||
setting_type = "Double",
|
||||
setting_value = "3.0",
|
||||
setting_value = "10.0",
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/util:__subpackages__",
|
||||
"//src/test/resources/net/eagle0/shardok/maps:__pkg__",
|
||||
"//src/test/scala/net/eagle0/eagle:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
scala_setting_library(
|
||||
name = "hero_cap_per_castle",
|
||||
setting_name = "HeroCapPerCastle",
|
||||
setting_type = "Int",
|
||||
setting_value = "5",
|
||||
visibility = [
|
||||
"//src/main/scala/net/eagle0/eagle:__subpackages__",
|
||||
"//src/main/scala/net/eagle0/util:__subpackages__",
|
||||
|
||||
@@ -125,6 +125,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:gold_increase_per_economy",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:gold_per_hero_held_back",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_divisor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_per_castle",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:history_backend",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:improvement_per_stat",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:improvement_reduction_max",
|
||||
|
||||
@@ -18,6 +18,7 @@ scala_library(
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:food_increase_per_agriculture",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:gold_increase_per_economy",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_divisor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_per_castle",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:min_support_for_taxes",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:per_development_resource_limit",
|
||||
"//src/main/scala/net/eagle0/eagle/library/util:battalion_utils",
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.eagle0.eagle.library.settings.{
|
||||
FoodIncreasePerAgriculture,
|
||||
GoldIncreasePerEconomy,
|
||||
HeroCapDivisor,
|
||||
HeroCapPerCastle,
|
||||
MinSupportForTaxes,
|
||||
PerDevelopmentResourceLimit
|
||||
}
|
||||
@@ -69,12 +70,12 @@ object ProvinceUtils {
|
||||
(province.infrastructure - province.infrastructureDevastation).max(0.0)
|
||||
|
||||
def heroCap(province: ProvinceT): Int =
|
||||
heroCap(effectiveInfrastructure(province))
|
||||
heroCap(province.castleCount, effectiveInfrastructure(province))
|
||||
|
||||
def heroCap(effectiveInfrastructure: Double): Int = {
|
||||
def heroCap(castleCount: Int, effectiveInfrastructure: Double): Int = {
|
||||
val divisor = HeroCapDivisor.doubleValue
|
||||
if !(divisor > 0.0) then throw new EagleInternalException(s"HeroCapDivisor must be positive, but was $divisor")
|
||||
(effectiveInfrastructure.max(0.0) / divisor).floor.toInt.max(1)
|
||||
castleCount * HeroCapPerCastle.intValue + (effectiveInfrastructure.max(0.0) / divisor).floor.toInt
|
||||
}
|
||||
|
||||
def goldCap(province: ProvinceT, isFocusProvince: Boolean): Int =
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ object ProvinceConverter {
|
||||
pendingConquestInfo = pendingConquestInfo.map(PendingConquestInfoConverter.toProto),
|
||||
hexMapName = hexMapName,
|
||||
castleCount = castleCount,
|
||||
heroCap = ProvinceUtils.heroCap((infrastructure - infrastructureDevastation).max(0.0))
|
||||
heroCap = ProvinceUtils.heroCap(castleCount, (infrastructure - infrastructureDevastation).max(0.0))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ object ProvinceConverter {
|
||||
pendingConquestInfo = pendingConquestInfoProto.map(PendingConquestInfoConverter.fromProto),
|
||||
hexMapName = hexMapName,
|
||||
castleCount = castleCount,
|
||||
heroCap = ProvinceUtils.heroCap((infrastructure - infrastructureDevastation).max(0.0))
|
||||
heroCap = ProvinceUtils.heroCap(castleCount, (infrastructure - infrastructureDevastation).max(0.0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ object GameParametersUtils {
|
||||
_.economy := provinceOverrides.economy,
|
||||
_.agriculture := provinceOverrides.agriculture,
|
||||
_.infrastructure := provinceOverrides.infrastructure,
|
||||
_.heroCap := ProvinceUtils.heroCap(provinceOverrides.infrastructure),
|
||||
_.heroCap := ProvinceUtils.heroCap(province.castleCount, provinceOverrides.infrastructure),
|
||||
_.priceIndex := PriceIndexUtils.steadyState(
|
||||
provinceOverrides.economy,
|
||||
provinceOverrides.agriculture,
|
||||
@@ -208,7 +208,7 @@ object GameParametersUtils {
|
||||
economy = provinceOverrides.economy,
|
||||
agriculture = provinceOverrides.agriculture,
|
||||
infrastructure = provinceOverrides.infrastructure,
|
||||
heroCap = ProvinceUtils.heroCap(provinceOverrides.infrastructure),
|
||||
heroCap = ProvinceUtils.heroCap(province.castleCount, provinceOverrides.infrastructure),
|
||||
priceIndex = PriceIndexUtils.steadyState(
|
||||
provinceOverrides.economy,
|
||||
provinceOverrides.agriculture,
|
||||
@@ -249,7 +249,7 @@ object GameParametersUtils {
|
||||
economy = overrides.economy,
|
||||
agriculture = overrides.agriculture,
|
||||
infrastructure = overrides.infrastructure,
|
||||
heroCap = ProvinceUtils.heroCap(overrides.infrastructure),
|
||||
heroCap = ProvinceUtils.heroCap(p.castleCount, overrides.infrastructure),
|
||||
priceIndex = PriceIndexUtils.steadyState(
|
||||
overrides.economy,
|
||||
overrides.agriculture,
|
||||
|
||||
+1
-1
@@ -315,7 +315,7 @@ object TutorialGameCreation {
|
||||
economy = if po.economy > 0 then po.economy else baseProvince.economy,
|
||||
agriculture = if po.agriculture > 0 then po.agriculture else baseProvince.agriculture,
|
||||
infrastructure = infrastructure,
|
||||
heroCap = ProvinceUtils.heroCap(infrastructure)
|
||||
heroCap = ProvinceUtils.heroCap(baseProvince.castleCount, infrastructure)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
package net.eagle0.eagle.library.actions.applier
|
||||
|
||||
import net.eagle0.eagle.library.settings.{ExtraXpForStatBumpOver100, HeroCapDivisor, XpForStatBump}
|
||||
import net.eagle0.eagle.library.settings.{ExtraXpForStatBumpOver100, HeroCapDivisor, HeroCapPerCastle, XpForStatBump}
|
||||
import net.eagle0.eagle.model.action_result.{NotificationDetails, NotificationT}
|
||||
import net.eagle0.eagle.model.action_result.changed_province.concrete.ChangedProvinceC
|
||||
import net.eagle0.eagle.model.action_result.concrete.{
|
||||
@@ -43,7 +43,8 @@ class ActionResultApplierImplTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
override def beforeEach(): Unit = {
|
||||
XpForStatBump.setIntValue(100)
|
||||
ExtraXpForStatBumpOver100.setIntValue(50)
|
||||
HeroCapDivisor.setDoubleValue(3.0)
|
||||
HeroCapDivisor.setDoubleValue(10.0)
|
||||
HeroCapPerCastle.setIntValue(5)
|
||||
}
|
||||
|
||||
private val applier = ActionResultApplierImpl(None)
|
||||
@@ -126,6 +127,7 @@ class ActionResultApplierImplTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
provinces = Map(
|
||||
provinceId -> ProvinceC(
|
||||
id = provinceId,
|
||||
castleCount = 2,
|
||||
infrastructure = 45,
|
||||
infrastructureDevastation = 12,
|
||||
heroCap = 99
|
||||
@@ -144,7 +146,7 @@ class ActionResultApplierImplTest extends AnyFlatSpec with Matchers with BeforeA
|
||||
|
||||
val result = applier.applyActionResult(startingState, actionResult)
|
||||
|
||||
result.resultingState.provinces(provinceId).heroCap shouldBe 9
|
||||
result.resultingState.provinces(provinceId).heroCap shouldBe 12
|
||||
}
|
||||
|
||||
it should "not advance command tokens for automatic results with an acting faction" in {
|
||||
|
||||
@@ -8,6 +8,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/library/actions/applier:action_result_applier_impl",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:extra_xp_for_stat_bump_over100",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_divisor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_per_castle",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:xp_for_stat_bump",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result:notification_trait",
|
||||
"//src/main/scala/net/eagle0/eagle/model/action_result/changed_province/concrete",
|
||||
|
||||
@@ -122,6 +122,7 @@ scala_test(
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:focus_province_storage_multiplier",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:food_increase_per_agriculture",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_divisor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_per_castle",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:improvement_per_stat",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:improvement_reduction_max",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:improvement_support_gain",
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.eagle0.eagle.library.settings.{
|
||||
FocusProvinceStorageMultiplier,
|
||||
FoodIncreasePerAgriculture,
|
||||
HeroCapDivisor,
|
||||
HeroCapPerCastle,
|
||||
ImprovementPerStat,
|
||||
ImprovementReductionMax,
|
||||
ImprovementSupportGain,
|
||||
@@ -83,7 +84,8 @@ class ProvinceUtilsTest extends AnyFlatSpec with Matchers with BeforeAndAfterEac
|
||||
BaseResourceLimit.setIntValue(5000)
|
||||
PerDevelopmentResourceLimit.setIntValue(50)
|
||||
FocusProvinceStorageMultiplier.setDoubleValue(1.5)
|
||||
HeroCapDivisor.setDoubleValue(3.0)
|
||||
HeroCapDivisor.setDoubleValue(10.0)
|
||||
HeroCapPerCastle.setIntValue(5)
|
||||
}
|
||||
|
||||
"provinceLeader" should "return the faction head if present" in {
|
||||
@@ -376,20 +378,21 @@ class ProvinceUtilsTest extends AnyFlatSpec with Matchers with BeforeAndAfterEac
|
||||
ProvinceUtils.containsFactionLeader(province, Vector(actingFaction)) shouldBe false
|
||||
}
|
||||
|
||||
"heroCap" should "use effective infrastructure divided by the configured divisor" in {
|
||||
"heroCap" should "add castle and effective infrastructure capacity" in {
|
||||
val province = ProvinceC(
|
||||
id = 7,
|
||||
castleCount = 2,
|
||||
infrastructure = 45,
|
||||
infrastructureDevastation = 12
|
||||
)
|
||||
|
||||
ProvinceUtils.heroCap(province) shouldBe 11
|
||||
ProvinceUtils.heroCap(province) shouldBe 13
|
||||
}
|
||||
|
||||
it should "floor fractional values and enforce a minimum cap of one" in {
|
||||
ProvinceUtils.heroCap(effectiveInfrastructure = 100) shouldBe 33
|
||||
ProvinceUtils.heroCap(effectiveInfrastructure = 8.99) shouldBe 2
|
||||
ProvinceUtils.heroCap(effectiveInfrastructure = 0) shouldBe 1
|
||||
it should "floor the infrastructure contribution" in {
|
||||
ProvinceUtils.heroCap(castleCount = 2, effectiveInfrastructure = 39.99) shouldBe 13
|
||||
ProvinceUtils.heroCap(castleCount = 0, effectiveInfrastructure = 9.99) shouldBe 0
|
||||
ProvinceUtils.heroCap(castleCount = 0, effectiveInfrastructure = 10) shouldBe 1
|
||||
}
|
||||
|
||||
"foodCap / goldCap" should "use the base resource cap when the province is not a focus province" in {
|
||||
|
||||
@@ -1902,7 +1902,7 @@ class SqliteHistoryTest extends AnyFlatSpec with Matchers with BeforeAndAfterEac
|
||||
// ---------------- newProvinces "new entity" decomposition (v11 — RED until implemented) ----------------
|
||||
|
||||
private def province(id: Int, name: String): ProvinceC =
|
||||
ProvinceC(id = id, name = name, gold = 100, food = 50, heroCap = 1)
|
||||
ProvinceC(id = id, name = name, gold = 100, food = 50, heroCap = 0)
|
||||
|
||||
"newProvinces v11 live write + reader" should "round-trip a new province via withNewResults" in {
|
||||
// newProvinces holds full ProvinceT snapshots (no Changed* wrapper) — the deepest entity. Stored as one proto blob.
|
||||
|
||||
@@ -26,6 +26,7 @@ scala_test(
|
||||
deps = [
|
||||
"//src/main/scala/net/eagle0/eagle/library:engine",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_divisor",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:hero_cap_per_castle",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings:history_backend",
|
||||
"//src/main/scala/net/eagle0/eagle/library/settings/loaders:battalion_type_loader",
|
||||
"//src/main/scala/net/eagle0/eagle/service:in_memory_history",
|
||||
|
||||
+5
-4
@@ -2,7 +2,7 @@ package net.eagle0.eagle.service.new_game_creation
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
import net.eagle0.eagle.library.settings.{HeroCapDivisor, HistoryBackend}
|
||||
import net.eagle0.eagle.library.settings.{HeroCapDivisor, HeroCapPerCastle, HistoryBackend}
|
||||
import net.eagle0.eagle.library.settings.loaders.BattalionTypeLoader
|
||||
import net.eagle0.eagle.service.{GameHistoryFactory, InMemoryHistory}
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
@@ -104,13 +104,14 @@ class FixedNewGameCreationTest extends AnyFlatSpec with Matchers {
|
||||
}
|
||||
}
|
||||
|
||||
"GameParametersUtils.provincesWithoutPlayers" should "derive hero caps from generic province infrastructure" in {
|
||||
HeroCapDivisor.setDoubleValue(3.0)
|
||||
"GameParametersUtils.provincesWithoutPlayers" should "derive hero caps from castles and generic infrastructure" in {
|
||||
HeroCapDivisor.setDoubleValue(10.0)
|
||||
HeroCapPerCastle.setIntValue(5)
|
||||
val provinces =
|
||||
GameParametersUtils.provincesWithoutPlayers(GameParametersUtils.defaultExpandedGameParameters.gameParameters)
|
||||
|
||||
all(provinces.map(_.infrastructure)) shouldBe 20.0
|
||||
all(provinces.map(_.heroCap)) shouldBe 6
|
||||
all(provinces.map(province => province.heroCap == 5 * province.castleCount + 2)) shouldBe true
|
||||
}
|
||||
|
||||
"FixedNewGameCreation" should "create the warmup-sized default game" in {
|
||||
|
||||
Reference in New Issue
Block a user