def gather_stat_data( dcsc_props: PrimalDinoStatusComponent, meta_props: PrimalDinoStatusComponent, is_flyer: bool, statIndexes: Tuple[int, ...]) -> List[Optional[List[float]]]: statsArray = list() iw_values: List[float] = [0] * len(statIndexes) for _, ark_index in enumerate(statIndexes): can_level = (ark_index == 2) or meta_props.CanLevelUpValue[ark_index] dont_use = meta_props.DontUseValue[ark_index] # Creates a null value in the JSON for stats that are unused if dont_use and not can_level: stat_data: Optional[List[float]] = None else: add_one = 1 if IS_PERCENT_STAT[ark_index] else 0 # Zero-out stats that can't level wild_mult = 1 if can_level else 0 # Also zero-out domestic stats that can't level, adding exception for flyer speed :( dom_mult = 1 if ark_index == 9 and is_flyer else wild_mult ETHM = dcsc_props.ExtraTamedHealthMultiplier[ 0].rounded_value if ark_index == 0 else 1 # Overrides the IW value for Torpor. While this hasn't been seen before, a species may allow torpor # to be leveled in the wild. Unsure how Ark would handle this. if ark_index == 2: iw_values[ ark_index] = dcsc_props.TheMaxTorporIncreasePerBaseLevel[ 0].rounded_value else: iw_values[ ark_index] = dcsc_props.AmountMaxGainedPerLevelUpValue[ ark_index].rounded_value stat_data = [ cd(dcsc_props.MaxStatusValues[ark_index].rounded_value + add_one), cd(iw_values[ark_index] * wild_mult), cd(dcsc_props.AmountMaxGainedPerLevelUpValueTamed[ark_index]. rounded_value * ETHM * dom_mult), cf(dcsc_props.TamingMaxStatAdditions[ark_index].rounded_value), cf(dcsc_props.TamingMaxStatMultipliers[ark_index].rounded_value ), ] statsArray.append(stat_data) return statsArray
def gather_stat_data(props, statIndexes): statsArray = list() # Create a temporary set of Iw defaults, overriding torpor with TheMaxTorporIncreasePerBaseLevel or 0.06 iw_values = list(IW_VALUES) iw_values[2] = stat_value(props, 'TheMaxTorporIncreasePerBaseLevel', 0, 0.06) for _, ark_index in enumerate(statIndexes): can_level = (ark_index == 2) or stat_value( props, 'CanLevelUpValue', ark_index, CANLEVELUP_VALUES) add_one = 1 if IS_PERCENT_STAT[ark_index] else 0 zero_mult = 1 if can_level else 0 ETHM = stat_value(props, 'ExtraTamedHealthMultiplier', ark_index, EXTRA_MULTS_VALUES) stat_data = [ cd( stat_value(props, 'MaxStatusValues', ark_index, BASE_VALUES) + add_one), cd( stat_value(props, 'AmountMaxGainedPerLevelUpValue', ark_index, iw_values) * zero_mult), cd( stat_value(props, 'AmountMaxGainedPerLevelUpValueTamed', ark_index, 0.0) * ETHM * zero_mult), cf(stat_value(props, 'TamingMaxStatAdditions', ark_index, 0.0)), cf(stat_value(props, 'TamingMaxStatMultipliers', ark_index, 0.0)), ] # Creates a null value in the JSON for stats that are unused dont_use = stat_value(props, 'DontUseValue', ark_index, DONTUSESTAT_VALUES) if dont_use and not can_level: stat_data = None statsArray.append(stat_data) return statsArray
def gather_taming_data(char_props: PrimalDinoCharacter, dcsc_props: PrimalDinoStatusComponent, overrides: OverrideSettings) -> Dict[str, Any]: data: Dict[str, Any] = dict() # Currently unable to gather the foods list eats: Optional[List[str]] = None special_food_values: Optional[List[Dict[str, Dict[str, List[int]]]]] = None if overrides.taming_method: can_tame = overrides.taming_method != TamingMethod.none data['nonViolent'] = overrides.taming_method == TamingMethod.awake data['violent'] = overrides.taming_method == TamingMethod.knockout else: can_tame = bool(char_props.bCanBeTamed[0]) can_knockout = char_props.bCanBeTorpid[0] can_basket_tame = char_props.bAllowTrapping[0] and not char_props.bPreventWildTrapping[0] and char_props.bIsTrapTamed[0] data['nonViolent'] = (char_props.bSupportWakingTame[0] and can_tame) or can_basket_tame data['violent'] = not char_props.bPreventSleepingTame[0] and can_tame and can_knockout if can_tame or True: data['tamingIneffectiveness'] = cf(char_props.TameIneffectivenessByAffinity[0].rounded_value) data['affinityNeeded0'] = cf(char_props.RequiredTameAffinity[0].rounded_value) data['affinityIncreasePL'] = cf(char_props.RequiredTameAffinityPerBaseLevel[0].rounded_value) torpor_depletion = dcsc_props.KnockedOutTorpidityRecoveryRateMultiplier[0].rounded_value \ * dcsc_props.RecoveryRateStatusValue[2].rounded_value if data['violent']: data['torporDepletionPS0'] = cd(-torpor_depletion) if data['nonViolent']: data['wakeAffinityMult'] = cf(char_props.WakingTameFoodAffinityMultiplier[0].rounded_value) data['wakeFoodDeplMult'] = cf(dcsc_props.WakingTameFoodConsumptionRateMultiplier[0].rounded_value) data['foodConsumptionBase'] = cf(-dcsc_props.BaseFoodConsumptionRate[0].rounded_value) data['foodConsumptionMult'] = cf(dcsc_props.ProneWaterFoodConsumptionMultiplier[0].rounded_value) data['babyFoodConsumptionMult'] = cf(dcsc_props.BabyDinoConsumingFoodRateMultiplier[0].rounded_value * dcsc_props.ExtraBabyDinoConsumingFoodRateMultiplier[0].rounded_value) if eats is not None: data['eats'] = eats if special_food_values is not None: data['specialFoodValues'] = special_food_values return data
def gather_taming_data( char_props: PrimalDinoCharacter, dcsc_props: PrimalDinoStatusComponent) -> Dict[str, Any]: data: Dict[str, Any] = dict() # Currently unable to gather the foods list eats: Optional[List[str]] = None favorite_kibble: Optional[str] = None special_food_values: Optional[List[Dict[str, Dict[str, List[int]]]]] = None can_tame = char_props.bCanBeTamed[0] can_knockout = char_props.bCanBeTorpid[0] data['nonViolent'] = char_props.bSupportWakingTame[0] and can_tame data['violent'] = not char_props.bPreventSleepingTame[ 0] and can_tame and can_knockout if can_tame or True: data['tamingIneffectiveness'] = cf( char_props.TameIneffectivenessByAffinity[0].rounded_value) data['affinityNeeded0'] = cf( char_props.RequiredTameAffinity[0].rounded_value) data['affinityIncreasePL'] = cf( char_props.RequiredTameAffinityPerBaseLevel[0].rounded_value) torpor_depletion = dcsc_props.KnockedOutTorpidityRecoveryRateMultiplier[0].rounded_value \ * dcsc_props.RecoveryRateStatusValue[2].rounded_value if data['violent']: data['torporDepletionPS0'] = cd(-torpor_depletion) if data['nonViolent']: data['wakeAffinityMult'] = cf( char_props.WakingTameFoodAffinityMultiplier[0].rounded_value) data['wakeFoodDeplMult'] = cf( dcsc_props.WakingTameFoodConsumptionRateMultiplier[0]. rounded_value) data['foodConsumptionBase'] = cf( -dcsc_props.BaseFoodConsumptionRate[0].rounded_value) data['foodConsumptionMult'] = cf( dcsc_props.ProneWaterFoodConsumptionMultiplier[0].rounded_value) if eats is not None: data['eats'] = eats if favorite_kibble is not None: data['favoriteKibble'] = favorite_kibble if special_food_values is not None: data['specialFoodValues'] = special_food_values return data
def gather_taming_data(props) -> Dict[str, Any]: data: Dict[str, Any] = dict() # Currently unable to gather the foods list eats: Optional[List[str]] = None favorite_kibble: Optional[str] = None special_food_values: Optional[List[Dict[str, Dict[str, List[int]]]]] = None can_tame = stat_value(props, 'bCanBeTamed', 0, True) can_knockout = stat_value(props, 'bCanBeTorpid', 0, True) data['nonViolent'] = stat_value(props, 'bSupportWakingTame', 0, False) and can_tame data['violent'] = not stat_value(props, 'bPreventSleepingTame', 0, False) and can_tame and can_knockout if can_tame or True: data['tamingIneffectiveness'] = cf( stat_value(props, 'TameIneffectivenessByAffinity', 0, 20.0)) data['affinityNeeded0'] = cf( stat_value(props, 'RequiredTameAffinity', 0, 100)) data['affinityIncreasePL'] = cf( stat_value(props, 'RequiredTameAffinityPerBaseLevel', 0, 5.0)) torpor_depletion = stat_value(props, 'KnockedOutTorpidityRecoveryRateMultiplier', 0, 3.0) \ * stat_value(props, 'RecoveryRateStatusValue', 2, 0.00) if data['violent']: data['torporDepletionPS0'] = cd(-torpor_depletion) if data['nonViolent']: data['wakeAffinityMult'] = cf( stat_value(props, 'WakingTameFoodAffinityMultiplier', 0, 1.6)) data['wakeFoodDeplMult'] = cf( stat_value(props, 'WakingTameFoodConsumptionRateMultiplier', 0, 2.0)) data['foodConsumptionBase'] = cf( -stat_value(props, 'BaseFoodConsumptionRate', 0, -0.025000)) # pylint: disable=invalid-unary-operand-type data['foodConsumptionMult'] = cf( stat_value(props, 'ProneWaterFoodConsumptionMultiplier', 0, 1.00)) if eats is not None: data['eats'] = eats if favorite_kibble is not None: data['favoriteKibble'] = favorite_kibble if special_food_values is not None: data['specialFoodValues'] = special_food_values return data
def values_for_species(asset: UAsset, proxy: PrimalDinoCharacter) -> Optional[Dict[str, Any]]: assert asset.loader and asset.default_export and asset.default_class and asset.default_class.fullname char_props: PrimalDinoCharacter = ue.gathering.gather_properties( asset.default_export) dcsc_props: PrimalDinoStatusComponent = ark.gathering.gather_dcsc_properties( asset.default_export) dcsc_alt_props: PrimalDinoStatusComponent = ark.gathering.gather_dcsc_properties( asset.default_export, alt=True) # Having no name or tag is an indication that this is an intermediate class, not a spawnable species name = (str(char_props.DescriptiveName[0]) or str(char_props.DinoNameTag[0])).strip() if not name: logger.debug( f"Species {asset.assetname} has no DescriptiveName or DinoNameTag - skipping" ) return None # Also consider anything that doesn't override any base status value as non-spawnable if not any( dcsc_props.has_override('MaxStatusValues', n) for n in ARK_STAT_INDEXES): logger.debug( f"Species {asset.assetname} has no overridden stats - skipping") return None assert asset.assetname and asset.default_export and asset.default_class and asset.default_class.fullname modid: str = asset.loader.get_mod_id(asset.assetname) or '' overrides = get_overrides_for_species(asset.assetname, modid) if overrides.skip_export: return None bp: str = asset.default_class.fullname if bp.endswith('_C'): bp = bp[:-2] # Replace names to match ASB's hardcoding of specific species name = overrides.descriptive_name or name # Variant information variants = get_variants_from_assetname( asset.assetname, overrides) | get_variants_from_species( proxy, overrides) if variants: if should_skip_from_variants(variants, overrides): return None name = adjust_name_from_variants(name, variants, overrides) species: Dict[str, Any] = dict(name=name, blueprintPath=bp) if variants: species['variants'] = tuple(sorted(variants)) # Stat data is_flyer = bool(char_props.bIsFlyerDino[0]) if is_flyer: species['isFlyer'] = True normal_stats = gather_stat_data(dcsc_props, dcsc_props, is_flyer, ARK_STAT_INDEXES) alt_stats = gather_stat_data(dcsc_alt_props, dcsc_props, is_flyer, ARK_STAT_INDEXES) alt_stats = reduce_alt_stats(normal_stats, alt_stats) species['fullStatsRaw'] = normal_stats if alt_stats: species['altBaseStats'] = alt_stats # Set imprint multipliers stat_imprint_mults: List[float] = list() unique_mults = False for stat_index in ARK_STAT_INDEXES: imprint_mult = dcsc_props.DinoMaxStatAddMultiplierImprinting[ stat_index] stat_imprint_mults.append(imprint_mult.rounded_value) # TODO: Optimize: Too many property look ups if DCSC_DEFAULTS.DinoMaxStatAddMultiplierImprinting[ stat_index] != imprint_mult: unique_mults = True if unique_mults: species['statImprintMult'] = stat_imprint_mults # ImmobilizedBy format data immobilization_data = None try: immobilization_data = gather_immobilization_data( char_props, asset.loader) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering immobilization data for {asset.assetname}:\n\t{ex}' ) if immobilization_data is not None: species['immobilizedBy'] = immobilization_data if not char_props.bUsesGender[0]: species['noGender'] = True # Breeding data if char_props.bCanHaveBaby[0]: # TODO: Consider always including this data breeding_data = None try: breeding_data = gather_breeding_data(char_props, asset.loader) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering breeding data for {asset.assetname}:\n\t{ex}' ) if breeding_data: species['breeding'] = breeding_data # Color data if char_props.bUseColorization[0]: colors = None try: colors = gather_color_data(char_props, overrides) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering color data for {asset.assetname}:\n\t{ex}' ) if colors is not None: species['colors'] = colors # Taming data if char_props.bCanBeTamed[ 0] or True: # ASB currently requires all species to have taming data taming = None try: taming = gather_taming_data(char_props, dcsc_props, overrides) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering taming data for {asset.assetname}:\n\t{ex}' ) if taming: species['taming'] = taming # Bone damage multipliers dmg_mults = None try: dmg_mults = gather_damage_mults(char_props) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering bone damage data for {asset.assetname}:\n\t{ex}' ) if dmg_mults: species['boneDamageAdjusters'] = dmg_mults # Misc data usesOxyWild = dcsc_props.bCanSuffocate[0] usesOxyTamed = True if usesOxyWild else dcsc_props.bCanSuffocateIfTamed[0] forceOxy = dcsc_props.bForceGainOxygen[0] doesntUseOxygen = not (usesOxyTamed or forceOxy) ETBHM = char_props.ExtraTamedBaseHealthMultiplier[0] TBHM = dcsc_props.TamedBaseHealthMultiplier[0] * ETBHM displayed_stats: int = 0 for i in ARK_STAT_INDEXES: use_stat = not dcsc_props.DontUseValue[i] if use_stat and not (i == 3 and doesntUseOxygen): displayed_stats |= (1 << i) species['TamedBaseHealthMultiplier'] = cf(TBHM) species['displayedStats'] = displayed_stats stat_name_overrides = get_stat_name_overrides(dcsc_props) if stat_name_overrides: species['statNames'] = stat_name_overrides return species
def gather_breeding_data(props, loader: AssetLoader) -> Dict[str, Any]: data: Dict[str, Any] = dict(gestationTime=0, incubationTime=0) gestation_breeding = stat_value(props, 'bUseBabyGestation', 0, False) has_eggs = False if props['FertilizedEggItemsToSpawn'][0] and props[ 'FertilizedEggItemsToSpawn'][0][-1].values: # eggs = list(filter(lambda v: v and str(v) != 'None', props['FertilizedEggItemsToSpawn'][0][-1].values)) eggs = [ egg for egg in props['FertilizedEggItemsToSpawn'][0][-1].values if str(egg) != 'None' ] has_eggs = bool(eggs) if gestation_breeding: gestation_speed = stat_value(props, 'BabyGestationSpeed', 0, BABYGESTATIONSPEED_DEFAULT) extra_gestation_speed_m = stat_value( props, 'ExtraBabyGestationSpeedMultiplier', 0, 1.0) # TODO: Verify if these should really default to 1 - seems odd gestation_speed = gestation_speed or 1 extra_gestation_speed_m = extra_gestation_speed_m or 1 # 'gestationTime' = 1 / (Baby Gestation Speed × Extra Baby Gestation Speed Multiplier) data['gestationTime'] = cd(( 1 / gestation_speed / extra_gestation_speed_m ) if gestation_speed and extra_gestation_speed_m else None) elif has_eggs: fert_egg_asset = loader.load_related(eggs[0]) fert_egg_props = ark.mod.gather_properties(fert_egg_asset) egg_decay = stat_value(fert_egg_props, 'EggLoseDurabilityPerSecond', 0, 1) extra_egg_decay_m = stat_value( fert_egg_props, 'ExtraEggLoseDurabilityPerSecondMultiplier', 0, 1) # 'incubationTime' = 100 / (Egg Lose Durability Per Second × Extra Egg Lose Durability Per Second Multiplier) data['incubationTime'] = cd(( 100 / egg_decay / extra_egg_decay_m) if egg_decay and extra_egg_decay_m else None) data['eggTempMin'] = cf( stat_value(fert_egg_props, 'EggMinTemperature', 0)) data['eggTempMax'] = cf( stat_value(fert_egg_props, 'EggMaxTemperature', 0)) # 'maturationTime' = 1 / (Baby Age Speed × Extra Baby Age Speed Multiplier) baby_age_speed = stat_value(props, 'BabyAgeSpeed', 0, 1) extra_baby_age_speed_m = stat_value(props, 'ExtraBabyAgeSpeedMultiplier', 0, 1) data['maturationTime'] = cd(( 1 / baby_age_speed / extra_baby_age_speed_m ) if baby_age_speed and extra_baby_age_speed_m else None) data['matingCooldownMin'] = cf( stat_value(props, 'NewFemaleMinTimeBetweenMating', 0, FEMALE_MINTIMEBETWEENMATING_DEFAULT)) data['matingCooldownMax'] = cf( stat_value(props, 'NewFemaleMaxTimeBetweenMating', 0, FEMALE_MAXTIMEBETWEENMATING_DEFAULT)) return data