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) -> 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 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 values_for_species(asset: UAsset, props: PriorityPropDict, proxy: PrimalDinoCharacter, allFields=False, fullStats=True, includeColor=True, includeBreeding=True, includeImmobilize=True, includeDamageMults=True, includeTaming=True): assert asset.loader # Having no name or tag is an indication that this is an intermediate class, not a spawnable species name = stat_value(props, 'DescriptiveName', 0, None) or stat_value( props, 'DinoNameTag', 0, None) if not name: logger.debug( f"Species {asset.assetname} has no DescriptiveName or DinoNameTag - skipping" ) return # Also consider anything that doesn't override any base status value as non-spawnable if not any( stat_value(props, 'MaxStatusValues', n, None) is not None for n in ARK_STAT_INDEXES): logger.debug( f"Species {asset.assetname} has no overridden stats - skipping") return 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) overrides = get_overrides_for_species(asset.assetname, modid) if get_overrides_for_species(asset.assetname, modid).skip_export: return 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) if variants: if should_skip_from_variants(variants, overrides): return name = adjust_name_from_variants(name, variants, overrides) species = dict(name=name, blueprintPath=bp) if variants: species['variants'] = tuple(sorted(variants)) # Stat data statsField = 'fullStatsRaw' if fullStats else 'statsRaw' statIndexes = ARK_STAT_INDEXES if fullStats else ASB_STAT_INDEXES species[statsField] = gather_stat_data(props, statIndexes) # Set imprint multipliers stat_imprint_mults: List[float] = list() for ark_index in statIndexes: imprint_mult = stat_value(props, 'DinoMaxStatAddMultiplierImprinting', ark_index, IMPRINT_VALUES) stat_imprint_mults.append(imprint_mult) if stat_imprint_mults != list(IMPRINT_VALUES): species['statImprintMult'] = stat_imprint_mults if includeImmobilize: # ImmobilizedBy format data immobilization_data = None try: immobilization_data = gather_immobilization_data( 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 includeBreeding: # Breeding data if stat_value(props, 'bCanHaveBaby', 0, False): # TODO: Consider always including this data breeding_data = None try: breeding_data = gather_breeding_data(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 if includeColor: # Color data if stat_value(props, 'bUseColorization', False): colors = None try: colors = gather_color_data(asset, 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 if includeTaming: # Taming data if stat_value( props, 'bCanBeTamed', True ) or True: # ASB currently requires all species to have taming data taming = None try: taming = gather_taming_data(props) except (AssetNotFound, ModNotFound) as ex: logger.warning( f'Failure while gathering taming data for {asset.assetname}:\n\t{ex}' ) if taming: species['taming'] = taming if includeDamageMults: # Bone damage multipliers dmg_mults = None try: dmg_mults = gather_damage_mults(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 noSpeedImprint = (stat_value(props, 'DinoMaxStatAddMultiplierImprinting', 9, IMPRINT_VALUES) == 0) usesOxyWild = stat_value(props, 'bCanSuffocate', 0, True) usesOxyTamed = stat_value(props, 'bCanSuffocateIfTamed', 0, usesOxyWild) forceOxy = stat_value(props, 'bForceGainOxygen', 0, False) doesntUseOxygen = not (usesOxyTamed or forceOxy) ETBHM = stat_value(props, 'ExtraTamedBaseHealthMultiplier', 0, 1) TBHM = stat_value(props, 'TamedBaseHealthMultiplier', 0, 1) * ETBHM displayed_stats: int = 0 for i in statIndexes: use_stat = not stat_value(props, 'DontUseValue', i, DONTUSESTAT_VALUES) if use_stat and not (i == 3 and doesntUseOxygen): displayed_stats |= (1 << i) if allFields or TBHM != 1: species['TamedBaseHealthMultiplier'] = cd(TBHM) if allFields or noSpeedImprint: species['NoImprintingForSpeed'] = noSpeedImprint if allFields or doesntUseOxygen: species['doesNotUseOxygen'] = doesntUseOxygen if allFields or displayed_stats: species['displayedStats'] = displayed_stats return species
def gather_breeding_data(char_props: PrimalDinoCharacter, loader: AssetLoader) -> Dict[str, Any]: data: Dict[str, Any] = dict(gestationTime=0, incubationTime=0) gestation_breeding = char_props.bUseBabyGestation[0] fert_eggs = char_props.get('FertilizedEggItemsToSpawn', 0, None) fert_egg_weights = char_props.get('FertilizedEggWeightsToSpawn', 0, None) if gestation_breeding: gestation_speed = char_props.BabyGestationSpeed[0].rounded_value extra_gestation_speed_m = char_props.ExtraBabyGestationSpeedMultiplier[ 0].rounded_value try: data['gestationTime'] = cd(1 / gestation_speed / extra_gestation_speed_m) except ZeroDivisionError: logger.warning( f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its gestationTime" ) elif fert_eggs and fert_eggs.values: eggs: List[Tuple[ObjectProperty, float]] = [] for index, egg in enumerate(fert_eggs.values): weight = fert_egg_weights.values[index] if fert_egg_weights else 1 # Verify the egg is a valid Object and that weight isn't 0 if str(egg) == 'None' or weight == 0: continue eggs.append((egg, weight)) # Sort eggs by highest weighting eggs.sort(reverse=True, key=itemgetter(1)) if eggs: # We only provide the highest possibility egg to ASB fert_egg_asset = loader.load_related(eggs[0][0]) assert fert_egg_asset.default_export egg_props: PrimalItem = ue.gathering.gather_properties( fert_egg_asset.default_export) egg_decay = egg_props.EggLoseDurabilityPerSecond[0].rounded_value extra_egg_decay_m = egg_props.ExtraEggLoseDurabilityPerSecondMultiplier[ 0].rounded_value # 'incubationTime' = 100 / (Egg Lose Durability Per Second × Extra Egg Lose Durability Per Second Multiplier) try: data['incubationTime'] = cd(100 / egg_decay / extra_egg_decay_m) except ZeroDivisionError: logger.warning( f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its incubationTime" ) data['eggTempMin'] = egg_props.EggMinTemperature[0] data['eggTempMax'] = egg_props.EggMaxTemperature[0] # 'maturationTime' = 1 / (Baby Age Speed × Extra Baby Age Speed Multiplier) baby_age_speed = char_props.BabyAgeSpeed[0].rounded_value extra_baby_age_speed_m = char_props.ExtraBabyAgeSpeedMultiplier[ 0].rounded_value try: data['maturationTime'] = cd(1 / baby_age_speed / extra_baby_age_speed_m) except ZeroDivisionError: logger.warning( f"Species {char_props.get_source().asset.assetname} tried dividing by zero for its maturationTime" ) data['matingCooldownMin'] = char_props.NewFemaleMinTimeBetweenMating[0] data['matingCooldownMax'] = char_props.NewFemaleMaxTimeBetweenMating[0] return data
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