* Init * remove submodule * Init * Update docs * Fix tests * Update to use apcivvi * Update Readme and codeowners * Minor changes * Remove .value from options (except starting hint) * Minor updates * remove unnecessary property * Cleanup Rules and Region * Fix output file generation * Implement feedback * Remove 'AP' tag and fix issue with format strings and using same quotes * Update worlds/civ_6/__init__.py Co-authored-by: Scipio Wright <scipiowright@gmail.com> * Minor docs changes * minor updates * Small rework of create items * Minor updates * Remove unused variable * Move client to Launcher Components with rest of similar clients * Revert "Move client to Launcher Components with rest of similar clients" This reverts commit f9fd5df9fdf19eaf4f1de54e21e3c33a74f02364. * modify component * Fix generation issues * Fix tests * Minor change * Add improvement and test case * Minor options changes * . * Preliminary Review * Fix failing test due to slot data serialization * Format json * Remove exclude missable boosts * Update options (update goody hut text, make research multiplier a range) * Update docs punctuation and slot data init * Move priority/excluded locations into options * Implement docs PR feedback * PR Feedback for options * PR feedback misc * Update location classification and fix client type * Fix typings * Update research cost multiplier * Remove unnecessary location priority code * Remove extrenous use of items() * WIP PR Feedback * WIP PR Feedback * Add victory event * Add option set for death link effect * PR improvements * Update post fill hint to support items with multiple classifications * remove unnecessary len * Move location exclusion logic * Update test to use set instead of accidental dict * Update docs around progressive eras and boost locations * Update docs for options to be more readable * Fix issue with filler items and prehints * Update filler_data to be static * Update links in docs * Minor updates and PR feedback * Update boosts data * Update era required items * Update existing techs * Update existing techs * move boost data class * Update reward data * Update prereq data * Update new items and progressive districts * Remove unused code * Make filler item name func more efficient * Update death link text * Move Civ6 to the end of readme * Fix bug with hidden locations and location.name * Partial PR Feedback Implementation * Format changes * Minor review feedback * Modify access rules to use list created in generate_early * Modify boost rules to precalculate requirements * Remove option checks from access rules * Fix issue with pre initialized dicts * Add inno setup for civ6 client * Update inno_setup.iss --------- Co-authored-by: Scipio Wright <scipiowright@gmail.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
		
			
				
	
	
		
			354 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from enum import Enum
 | 
						|
from typing import Dict, Optional, TYPE_CHECKING, List
 | 
						|
from BaseClasses import Item, ItemClassification
 | 
						|
from .Data import (
 | 
						|
    GoodyHutRewardData,
 | 
						|
    get_era_required_items_data,
 | 
						|
    get_existing_civics_data,
 | 
						|
    get_existing_techs_data,
 | 
						|
    get_goody_hut_rewards_data,
 | 
						|
    get_progressive_districts_data,
 | 
						|
)
 | 
						|
from .Enum import CivVICheckType, EraType
 | 
						|
from .ProgressiveDistricts import get_flat_progressive_districts
 | 
						|
 | 
						|
if TYPE_CHECKING:
 | 
						|
    from . import CivVIWorld
 | 
						|
 | 
						|
 | 
						|
CIV_VI_AP_ITEM_ID_BASE = 5041000
 | 
						|
 | 
						|
NON_PROGRESSION_DISTRICTS = ["PROGRESSIVE_PRESERVE", "PROGRESSIVE_NEIGHBORHOOD"]
 | 
						|
 | 
						|
 | 
						|
# Items required as progression for boostsanity mode
 | 
						|
BOOSTSANITY_PROGRESSION_ITEMS = [
 | 
						|
    "TECH_THE_WHEEL",
 | 
						|
    "TECH_MASONRY",
 | 
						|
    "TECH_ARCHERY",
 | 
						|
    "TECH_ENGINEERING",
 | 
						|
    "TECH_CONSTRUCTION",
 | 
						|
    "TECH_GUNPOWDER",
 | 
						|
    "TECH_MACHINERY",
 | 
						|
    "TECH_SIEGE_TACTICS",
 | 
						|
    "TECH_STIRRUPS",
 | 
						|
    "TECH_ASTRONOMY",
 | 
						|
    "TECH_BALLISTICS",
 | 
						|
    "TECH_STEAM_POWER",
 | 
						|
    "TECH_SANITATION",
 | 
						|
    "TECH_COMPUTERS",
 | 
						|
    "TECH_COMBUSTION",
 | 
						|
    "TECH_TELECOMMUNICATIONS",
 | 
						|
    "TECH_ROBOTICS",
 | 
						|
    "CIVIC_FEUDALISM",
 | 
						|
    "CIVIC_GUILDS",
 | 
						|
    "CIVIC_THE_ENLIGHTENMENT",
 | 
						|
    "CIVIC_MERCANTILISM",
 | 
						|
    "CIVIC_CONSERVATION",
 | 
						|
    "CIVIC_CIVIL_SERVICE",
 | 
						|
    "CIVIC_GLOBALIZATION",
 | 
						|
    "CIVIC_COLD_WAR",
 | 
						|
    "CIVIC_URBANIZATION",
 | 
						|
    "CIVIC_NATIONALISM",
 | 
						|
    "CIVIC_MOBILIZATION",
 | 
						|
    "PROGRESSIVE_NEIGHBORHOOD",
 | 
						|
    "PROGRESSIVE_PRESERVE",
 | 
						|
]
 | 
						|
 | 
						|
 | 
						|
class FillerItemRarity(Enum):
 | 
						|
    COMMON = "COMMON"
 | 
						|
    UNCOMMON = "UNCOMMON"
 | 
						|
    RARE = "RARE"
 | 
						|
 | 
						|
 | 
						|
FILLER_DISTRIBUTION: Dict[FillerItemRarity, float] = {
 | 
						|
    FillerItemRarity.RARE: 0.025,
 | 
						|
    FillerItemRarity.UNCOMMON: 0.2,
 | 
						|
    FillerItemRarity.COMMON: 0.775,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class FillerItemData:
 | 
						|
    name: str
 | 
						|
    type: str
 | 
						|
    rarity: FillerItemRarity
 | 
						|
    civ_name: str
 | 
						|
 | 
						|
    def __init__(self, data: GoodyHutRewardData):
 | 
						|
        self.name = data["Name"]
 | 
						|
        self.rarity = FillerItemRarity(data["Rarity"])
 | 
						|
        self.civ_name = data["Type"]
 | 
						|
 | 
						|
 | 
						|
filler_data: Dict[str, FillerItemData] = {
 | 
						|
    item["Name"]: FillerItemData(item) for item in get_goody_hut_rewards_data()
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class CivVIItemData:
 | 
						|
    civ_vi_id: int
 | 
						|
    classification: ItemClassification
 | 
						|
    name: str
 | 
						|
    code: int
 | 
						|
    cost: int
 | 
						|
    item_type: CivVICheckType
 | 
						|
    progressive_name: Optional[str]
 | 
						|
    civ_name: Optional[str]
 | 
						|
    era: Optional[EraType]
 | 
						|
 | 
						|
    def __init__(
 | 
						|
        self,
 | 
						|
        name: str,
 | 
						|
        civ_vi_id: int,
 | 
						|
        cost: int,
 | 
						|
        item_type: CivVICheckType,
 | 
						|
        id_offset: int,
 | 
						|
        classification: ItemClassification,
 | 
						|
        progressive_name: Optional[str],
 | 
						|
        civ_name: Optional[str] = None,
 | 
						|
        era: Optional[EraType] = None,
 | 
						|
    ):
 | 
						|
        self.classification = classification
 | 
						|
        self.civ_vi_id = civ_vi_id
 | 
						|
        self.name = name
 | 
						|
        self.code = civ_vi_id + CIV_VI_AP_ITEM_ID_BASE + id_offset
 | 
						|
        self.cost = cost
 | 
						|
        self.item_type = item_type
 | 
						|
        self.progressive_name = progressive_name
 | 
						|
        self.civ_name = civ_name
 | 
						|
        self.era = era
 | 
						|
 | 
						|
 | 
						|
class CivVIEvent(Item):
 | 
						|
    game: str = "Civilization VI"
 | 
						|
 | 
						|
 | 
						|
class CivVIItem(Item):
 | 
						|
    game: str = "Civilization VI"
 | 
						|
    civ_vi_id: int
 | 
						|
    item_type: CivVICheckType
 | 
						|
 | 
						|
    def __init__(
 | 
						|
        self,
 | 
						|
        item: CivVIItemData,
 | 
						|
        player: int,
 | 
						|
        classification: Optional[ItemClassification] = None,
 | 
						|
    ):
 | 
						|
        super().__init__(
 | 
						|
            item.name, classification or item.classification, item.code, player
 | 
						|
        )
 | 
						|
        self.civ_vi_id = item.civ_vi_id
 | 
						|
        self.item_type = item.item_type
 | 
						|
 | 
						|
 | 
						|
def format_item_name(name: str) -> str:
 | 
						|
    name_parts = name.split("_")
 | 
						|
    return " ".join([part.capitalize() for part in name_parts])
 | 
						|
 | 
						|
 | 
						|
_items_by_civ_name: Dict[str, CivVIItemData] = {}
 | 
						|
 | 
						|
 | 
						|
def get_item_by_civ_name(
 | 
						|
    item_name: str, item_table: Dict[str, "CivVIItemData"]
 | 
						|
) -> "CivVIItemData":
 | 
						|
    """Gets the names of the items in the item_table"""
 | 
						|
    if not _items_by_civ_name:
 | 
						|
        for item in item_table.values():
 | 
						|
            if item.civ_name:
 | 
						|
                _items_by_civ_name[item.civ_name] = item
 | 
						|
 | 
						|
    try:
 | 
						|
        return _items_by_civ_name[item_name]
 | 
						|
    except KeyError as e:
 | 
						|
        raise KeyError(f"Item {item_name} not found in item_table") from e
 | 
						|
 | 
						|
 | 
						|
def _generate_tech_items(
 | 
						|
    id_base: int, required_items: List[str], progressive_items: Dict[str, str]
 | 
						|
) -> Dict[str, CivVIItemData]:
 | 
						|
    # Generate Techs
 | 
						|
    existing_techs = get_existing_techs_data()
 | 
						|
    tech_table: Dict[str, CivVIItemData] = {}
 | 
						|
 | 
						|
    tech_id = 0
 | 
						|
    for tech in existing_techs:
 | 
						|
        classification = ItemClassification.useful
 | 
						|
        name = tech["Name"]
 | 
						|
        civ_name = tech["Type"]
 | 
						|
        if civ_name in required_items:
 | 
						|
            classification = ItemClassification.progression
 | 
						|
        progressive_name = None
 | 
						|
        check_type = CivVICheckType.TECH
 | 
						|
        if civ_name in progressive_items.keys():
 | 
						|
            progressive_name = format_item_name(progressive_items[civ_name])
 | 
						|
 | 
						|
        tech_table[name] = CivVIItemData(
 | 
						|
            name=name,
 | 
						|
            civ_vi_id=tech_id,
 | 
						|
            cost=tech["Cost"],
 | 
						|
            item_type=check_type,
 | 
						|
            id_offset=id_base,
 | 
						|
            classification=classification,
 | 
						|
            progressive_name=progressive_name,
 | 
						|
            civ_name=civ_name,
 | 
						|
            era=EraType(tech["EraType"]),
 | 
						|
        )
 | 
						|
 | 
						|
        tech_id += 1
 | 
						|
 | 
						|
    return tech_table
 | 
						|
 | 
						|
 | 
						|
def _generate_civics_items(
 | 
						|
    id_base: int, required_items: List[str], progressive_items: Dict[str, str]
 | 
						|
) -> Dict[str, CivVIItemData]:
 | 
						|
    civic_id = 0
 | 
						|
    civic_table: Dict[str, CivVIItemData] = {}
 | 
						|
    existing_civics = get_existing_civics_data()
 | 
						|
 | 
						|
    for civic in existing_civics:
 | 
						|
        name = civic["Name"]
 | 
						|
        civ_name = civic["Type"]
 | 
						|
        progressive_name = None
 | 
						|
        check_type = CivVICheckType.CIVIC
 | 
						|
 | 
						|
        if civ_name in progressive_items.keys():
 | 
						|
            progressive_name = format_item_name(progressive_items[civ_name])
 | 
						|
 | 
						|
        classification = ItemClassification.useful
 | 
						|
        if civ_name in required_items:
 | 
						|
            classification = ItemClassification.progression
 | 
						|
 | 
						|
        civic_table[name] = CivVIItemData(
 | 
						|
            name=name,
 | 
						|
            civ_vi_id=civic_id,
 | 
						|
            cost=civic["Cost"],
 | 
						|
            item_type=check_type,
 | 
						|
            id_offset=id_base,
 | 
						|
            classification=classification,
 | 
						|
            progressive_name=progressive_name,
 | 
						|
            civ_name=civ_name,
 | 
						|
            era=EraType(civic["EraType"]),
 | 
						|
        )
 | 
						|
 | 
						|
        civic_id += 1
 | 
						|
 | 
						|
    return civic_table
 | 
						|
 | 
						|
 | 
						|
def _generate_progressive_district_items(id_base: int) -> Dict[str, CivVIItemData]:
 | 
						|
    progressive_table: Dict[str, CivVIItemData] = {}
 | 
						|
    progressive_id_base = 0
 | 
						|
    progressive_items = get_progressive_districts_data()
 | 
						|
    for item_name in progressive_items.keys():
 | 
						|
        classification = (
 | 
						|
            ItemClassification.useful
 | 
						|
            if item_name in NON_PROGRESSION_DISTRICTS
 | 
						|
            else ItemClassification.progression
 | 
						|
        )
 | 
						|
        name = format_item_name(item_name)
 | 
						|
        progressive_table[name] = CivVIItemData(
 | 
						|
            name=name,
 | 
						|
            civ_vi_id=progressive_id_base,
 | 
						|
            cost=0,
 | 
						|
            item_type=CivVICheckType.PROGRESSIVE_DISTRICT,
 | 
						|
            id_offset=id_base,
 | 
						|
            classification=classification,
 | 
						|
            progressive_name=None,
 | 
						|
            civ_name=item_name,
 | 
						|
        )
 | 
						|
        progressive_id_base += 1
 | 
						|
    return progressive_table
 | 
						|
 | 
						|
 | 
						|
def _generate_progressive_era_items(id_base: int) -> Dict[str, CivVIItemData]:
 | 
						|
    """Generates the single progressive district item"""
 | 
						|
    era_table: Dict[str, CivVIItemData] = {}
 | 
						|
    # Generate progressive eras
 | 
						|
    progressive_era_name = format_item_name("PROGRESSIVE_ERA")
 | 
						|
    era_table[progressive_era_name] = CivVIItemData(
 | 
						|
        name=progressive_era_name,
 | 
						|
        civ_vi_id=0,
 | 
						|
        cost=0,
 | 
						|
        item_type=CivVICheckType.ERA,
 | 
						|
        id_offset=id_base,
 | 
						|
        classification=ItemClassification.progression,
 | 
						|
        progressive_name=None,
 | 
						|
        civ_name="PROGRESSIVE_ERA",
 | 
						|
    )
 | 
						|
    return era_table
 | 
						|
 | 
						|
 | 
						|
def _generate_goody_hut_items(id_base: int) -> Dict[str, CivVIItemData]:
 | 
						|
    # Generate goody hut items
 | 
						|
    goody_huts = {
 | 
						|
        item["Name"]: FillerItemData(item) for item in get_goody_hut_rewards_data()
 | 
						|
    }
 | 
						|
    goody_table: Dict[str, CivVIItemData] = {}
 | 
						|
    goody_base = 0
 | 
						|
    for value in goody_huts.values():
 | 
						|
        goody_table[value.name] = CivVIItemData(
 | 
						|
            name=value.name,
 | 
						|
            civ_vi_id=goody_base,
 | 
						|
            cost=0,
 | 
						|
            item_type=CivVICheckType.GOODY,
 | 
						|
            id_offset=id_base,
 | 
						|
            classification=ItemClassification.filler,
 | 
						|
            progressive_name=None,
 | 
						|
            civ_name=value.civ_name,
 | 
						|
        )
 | 
						|
        goody_base += 1
 | 
						|
    return goody_table
 | 
						|
 | 
						|
 | 
						|
def generate_item_table() -> Dict[str, CivVIItemData]:
 | 
						|
    era_required_items = get_era_required_items_data()
 | 
						|
    required_items: List[str] = []
 | 
						|
    for value in era_required_items.values():
 | 
						|
        required_items += value
 | 
						|
 | 
						|
    progressive_items = get_flat_progressive_districts()
 | 
						|
 | 
						|
    item_table: Dict[str, CivVIItemData] = {}
 | 
						|
 | 
						|
    def get_id_base():
 | 
						|
        return len(item_table.keys())
 | 
						|
 | 
						|
    item_table.update(
 | 
						|
        **_generate_tech_items(get_id_base(), required_items, progressive_items)
 | 
						|
    )
 | 
						|
    item_table.update(
 | 
						|
        **_generate_civics_items(get_id_base(), required_items, progressive_items)
 | 
						|
    )
 | 
						|
    item_table.update(**_generate_progressive_district_items(get_id_base()))
 | 
						|
    item_table.update(**_generate_progressive_era_items(get_id_base()))
 | 
						|
    item_table.update(**_generate_goody_hut_items(get_id_base()))
 | 
						|
 | 
						|
    return item_table
 | 
						|
 | 
						|
 | 
						|
def get_items_by_type(
 | 
						|
    item_type: CivVICheckType, item_table: Dict[str, CivVIItemData]
 | 
						|
) -> List[CivVIItemData]:
 | 
						|
    """
 | 
						|
    Returns a list of items that match the given item type
 | 
						|
    """
 | 
						|
    return [item for item in item_table.values() if item.item_type == item_type]
 | 
						|
 | 
						|
 | 
						|
fillers_by_rarity: Dict[FillerItemRarity, List[FillerItemData]] = {
 | 
						|
    rarity: [item for item in filler_data.values() if item.rarity == rarity]
 | 
						|
    for rarity in FillerItemRarity
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
def get_random_filler_by_rarity(
 | 
						|
    world: "CivVIWorld", rarity: FillerItemRarity
 | 
						|
) -> FillerItemData:
 | 
						|
    """
 | 
						|
    Returns a random filler item by rarity
 | 
						|
    """
 | 
						|
    return world.random.choice(fillers_by_rarity[rarity])
 |