Civ 6: Add era requirements for boosts and update boost prereqs (#5296)

* Resolve #5136

* Resolves #5210
This commit is contained in:
Carter Hesterman
2025-10-17 08:35:44 -06:00
committed by GitHub
parent f5f554cb3d
commit 7ead8fdf49
4 changed files with 98 additions and 15 deletions

View File

@@ -20,6 +20,7 @@ class CivVIBoostData:
Prereq: List[str] Prereq: List[str]
PrereqRequiredCount: int PrereqRequiredCount: int
Classification: str Classification: str
EraRequired: bool = False
class GoodyHutRewardData(TypedDict): class GoodyHutRewardData(TypedDict):

View File

@@ -150,7 +150,10 @@ def generate_era_location_table() -> Dict[str, Dict[str, CivVILocationData]]:
location = CivVILocationData( location = CivVILocationData(
boost.Type, 0, 0, id_base, boost.EraType, CivVICheckType.BOOST boost.Type, 0, 0, id_base, boost.EraType, CivVICheckType.BOOST
) )
era_locations["ERA_ANCIENT"][boost.Type] = location # If EraRequired is True, place the boost in its actual era
# Otherwise, place it in ERA_ANCIENT for early access
target_era = boost.EraType if boost.EraRequired else "ERA_ANCIENT"
era_locations[target_era][boost.Type] = location
id_base += 1 id_base += 1
return era_locations return era_locations

View File

@@ -210,8 +210,8 @@ boosts: List[CivVIBoostData] = [
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_SQUARE_RIGGING", "BOOST_TECH_SQUARE_RIGGING",
"ERA_RENAISSANCE", "ERA_RENAISSANCE",
["TECH_GUNPOWDER"], ["TECH_GUNPOWDER", "TECH_MILITARY_ENGINEERING", "TECH_MINING"],
1, 3,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -252,15 +252,15 @@ boosts: List[CivVIBoostData] = [
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_BALLISTICS", "BOOST_TECH_BALLISTICS",
"ERA_INDUSTRIAL", "ERA_INDUSTRIAL",
["TECH_SIEGE_TACTICS", "TECH_MILITARY_ENGINEERING"], ["TECH_SIEGE_TACTICS", "TECH_MILITARY_ENGINEERING", "TECH_BRONZE_WORKING"],
2, 3,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_MILITARY_SCIENCE", "BOOST_TECH_MILITARY_SCIENCE",
"ERA_INDUSTRIAL", "ERA_INDUSTRIAL",
["TECH_STIRRUPS"], ["TECH_BRONZE_WORKING", "TECH_STIRRUPS", "TECH_MINING"],
1, 3,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -301,8 +301,8 @@ boosts: List[CivVIBoostData] = [
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_REPLACEABLE_PARTS", "BOOST_TECH_REPLACEABLE_PARTS",
"ERA_MODERN", "ERA_MODERN",
["TECH_MILITARY_SCIENCE"], ["TECH_MILITARY_SCIENCE", "TECH_MINING"],
1, 2,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -343,8 +343,8 @@ boosts: List[CivVIBoostData] = [
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_ADVANCED_FLIGHT", "BOOST_TECH_ADVANCED_FLIGHT",
"ERA_ATOMIC", "ERA_ATOMIC",
["TECH_FLIGHT"], ["TECH_FLIGHT", "TECH_REFINING", "TECH_MINING"],
1, 3,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -436,8 +436,8 @@ boosts: List[CivVIBoostData] = [
CivVIBoostData( CivVIBoostData(
"BOOST_TECH_COMPOSITES", "BOOST_TECH_COMPOSITES",
"ERA_INFORMATION", "ERA_INFORMATION",
["TECH_COMBUSTION"], ["TECH_COMBUSTION", "TECH_REFINING", "TECH_MINING"],
1, 3,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -470,7 +470,7 @@ boosts: List[CivVIBoostData] = [
"TECH_ELECTRICITY", "TECH_ELECTRICITY",
"TECH_NUCLEAR_FISSION", "TECH_NUCLEAR_FISSION",
], ],
1, 4,
"DEFAULT", "DEFAULT",
), ),
CivVIBoostData( CivVIBoostData(
@@ -651,10 +651,11 @@ boosts: List[CivVIBoostData] = [
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_CIVIC_FEUDALISM", "BOOST_CIVIC_FEUDALISM",
"ERA_MEDIEVAL", "ERA_CLASSICAL",
[], [],
0, 0,
"DEFAULT", "DEFAULT",
True,
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_CIVIC_CIVIL_SERVICE", "BOOST_CIVIC_CIVIL_SERVICE",
@@ -662,6 +663,7 @@ boosts: List[CivVIBoostData] = [
[], [],
0, 0,
"DEFAULT", "DEFAULT",
True,
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_CIVIC_MERCENARIES", "BOOST_CIVIC_MERCENARIES",
@@ -790,6 +792,7 @@ boosts: List[CivVIBoostData] = [
[], [],
0, 0,
"DEFAULT", "DEFAULT",
True
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_CIVIC_CONSERVATION", "BOOST_CIVIC_CONSERVATION",
@@ -885,6 +888,7 @@ boosts: List[CivVIBoostData] = [
["TECH_ROCKETRY"], ["TECH_ROCKETRY"],
1, 1,
"DEFAULT", "DEFAULT",
True
), ),
CivVIBoostData( CivVIBoostData(
"BOOST_CIVIC_GLOBALIZATION", "BOOST_CIVIC_GLOBALIZATION",

View File

@@ -105,3 +105,78 @@ class TestBoostsanityExcluded(CivVITestBase):
if "BOOST" in location.name: if "BOOST" in location.name:
found_locations += 1 found_locations += 1
self.assertEqual(found_locations, 0) self.assertEqual(found_locations, 0)
class TestBoostsanityEraRequired(CivVITestBase):
options = {
"boostsanity": "true",
"progression_style": "none",
"shuffle_goody_hut_rewards": "false",
}
def test_era_required_boosts_not_accessible_early(self) -> None:
# BOOST_CIVIC_FEUDALISM has EraRequired=True and ERA_CLASSICAL
# It should NOT be accessible in Ancient era
self.assertFalse(self.can_reach_location("BOOST_CIVIC_FEUDALISM"))
# BOOST_CIVIC_URBANIZATION has EraRequired=True and ERA_INDUSTRIAL
# It should NOT be accessible in Ancient era
self.assertFalse(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))
# BOOST_CIVIC_SPACE_RACE has EraRequired=True and ERA_ATOMIC
# It should NOT be accessible in Ancient era
self.assertFalse(self.can_reach_location("BOOST_CIVIC_SPACE_RACE"))
# Regular boosts without EraRequired should be accessible
self.assertTrue(self.can_reach_location("BOOST_TECH_SAILING"))
self.assertTrue(self.can_reach_location("BOOST_CIVIC_MILITARY_TRADITION"))
def test_era_required_boosts_accessible_in_correct_era(self) -> None:
# Collect items to reach Classical era
self.collect_by_name(["Mining", "Bronze Working", "Astrology", "Writing",
"Irrigation", "Sailing", "Animal Husbandry",
"State Workforce", "Foreign Trade"])
# BOOST_CIVIC_FEUDALISM should now be accessible in Classical era
self.assertTrue(self.can_reach_location("BOOST_CIVIC_FEUDALISM"))
# BOOST_CIVIC_URBANIZATION still not accessible (requires Industrial)
self.assertFalse(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))
# Collect more items to reach Industrial era
self.collect_all_but(["TECH_ROCKETRY"])
# Now BOOST_CIVIC_URBANIZATION should be accessible
self.assertTrue(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))
class TestBoostsanityEraRequiredWithProgression(CivVITestBase):
options = {
"boostsanity": "true",
"progression_style": "eras_and_districts",
"shuffle_goody_hut_rewards": "false",
}
def test_era_required_with_progressive_eras(self) -> None:
# Collect all items except Progressive Era
self.collect_all_but(["Progressive Era"])
# Even with all other items, era-required boosts should not be accessible
self.assertFalse(self.can_reach_location("BOOST_CIVIC_FEUDALISM"))
self.assertFalse(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))
# Collect enough Progressive Era items to reach Classical (needs 2)
self.collect(self.get_item_by_name("Progressive Era"))
self.collect(self.get_item_by_name("Progressive Era"))
# BOOST_CIVIC_FEUDALISM should now be accessible
self.assertTrue(self.can_reach_location("BOOST_CIVIC_FEUDALISM"))
# But BOOST_CIVIC_URBANIZATION still requires Industrial era (needs 5 total)
self.assertFalse(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))
# Collect 3 more Progressive Era items to reach Industrial
self.collect_by_name(["Progressive Era", "Progressive Era", "Progressive Era"])
# Now BOOST_CIVIC_URBANIZATION should be accessible
self.assertTrue(self.can_reach_location("BOOST_CIVIC_URBANIZATION"))