static LandPredatorBrain() { PredatorTreeRoot = BT.Selector( LandAnimalBrain.LyingDownTree, BT.If(x => x.Alertness > LandAnimalBrain.AlertThreshold && x.Alertness < LandAnimalBrain.FullyAlertThreshold && x.AnimationState != AnimalAnimationState.Flee && x.AnimationState != AnimalAnimationState.AlertIdle && x.OnFlatGround, // play an alert reaction before fleeing and intermittently while alert PlayFixedTimeAnimation(AnimalAnimationState.AlertIdle, LandAnimalBrain.AlertIdleTime)), MovementBehaviors.Flee, GroupBehaviors.SleepNearLeader, BT.If(x => x.Hunger > HungerThreshold, BT.Selector( TryEatNearbyCorpses, new HuntMemoryBehavior() { NoNearbyFoodBehavior = LandAnimalBrain.LandAnimalFindFood })), GroupBehaviors.StayNearLeader(10f), //TODO: show a failed chase if there are no corpses neary to eat BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.WanderHome), BT.If(x => x.Alertness < Animal.FleeThreshold && RandomUtil.Chance(LandAnimalBrain.ChanceToLieDown) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.LyingDown, LandAnimalBrain.LyingTickDuration)), BT.If(x => RandomUtil.Chance(LandAnimalBrain.ChanceToIdle) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.Idle, _ => RandomUtil.Range(LandAnimalBrain.MinIdleTime, LandAnimalBrain.MaxIdleTime))), MovementBehaviors.Wander); }
public void LayerTick() { if (this.rate != -1) { // TODO this should be implemented via pull/interact/push pattern foreach (var layer in this.targetLayers) { var layerPos = layer.WorldPosToLayerPos(this.Parent.Position.XZi); var layerValue = layer.SafeEntry(layerPos); // 8 times faster than fish traps if (RandomUtil.Chance(layerValue / (layer.MaxValue * (float)this.rate))) { var organisms = layer.SafePopMapEntry(layerPos); if (organisms == null) { return; } var animal = organisms.Random() as Animal; // give items var newItems = Item.Create(animal.Species.ResourceItem, (int)animal.Species.ResourceRange.Max); if (this.storage.Inventory.TryAddItems(animal.Species.ResourceItem, (int)animal.Species.ResourceRange.Max)) { animal.Kill(DeathType.Harvesting); } return; } } } else { return; } }
static FishBrain() { const float MinIdleTime = 1f; const float MaxIdleTime = 5f; const float ChanceToIdle = 0.3f; FishTreeRoot = BT.Selector( MovementBehaviors.SwimFlee, BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.SwimWanderHome), BT.If(x => RandomUtil.Chance(1 - ChanceToIdle), MovementBehaviors.SwimWander), PlayAnimation(AnimalAnimationState.Idle, _ => RandomUtil.Range(MinIdleTime, MaxIdleTime)) ); }
static FishBrain() { const float ChanceToWander = 0.7f; FishTreeRoot = BT.Selector("Fish Brain", BT.If("Try Swim", x => (!x.IsStunned, $"available for swimming"), BT.Selector("Swimming", MovementBehaviors.SwimFlee, BT.If("Try Return Home", MovementBehaviors.ShouldReturnHome, MovementBehaviors.SwimWanderHome), BT.If("Swim Wander", x => (RandomUtil.Chance(ChanceToWander), $"{ChanceToWander.ToString("P0")} chance"), MovementBehaviors.SwimWander) ) ), RelaxBehaviors.Idle ); }
public static (bool result, string msg) ConsiderFleeing(Animal agent, bool skipChance = false) { // Run immediately if just attacked player or randomly choose run or not // For immediate run remember that we need to run away for a long time var fleePosition = agent.Position + agent.FacingDir; var chanceToFlee = !skipChance && RandomUtil.Chance(ChanceToFleeFromEnemy); agent.TryGetMemory(Animal.IsPlayerAttackedMemory, out bool attackedPlayer); if (attackedPlayer) { chanceToFlee = true; } if (agent.Prey != null) { if (!chanceToFlee && agent.Prey is Player playerEnemy) { // Be aware of a player with fire var selectedItem = playerEnemy.User.Inventory?.Toolbar?.SelectedItem; var playerWithFire = selectedItem is TorchItem; if (playerWithFire) { chanceToFlee = true; } } fleePosition = agent.Prey.Position; } if (!chanceToFlee) { return(false, "no flee"); } agent.Prey = null; if (attackedPlayer) { agent.FleeFromImmediately(fleePosition); agent.SetMemory(Animal.ShouldFleeTillMemory, WorldTime.Seconds + RunTimeAfterAttackingPlayer); agent.SetMemory(Animal.IsPlayerAttackedMemory, false); } else { agent.FleeFrom(fleePosition); } return(true, "preparing to flee"); }
public void randomRule() { GameManagerOne.Instance.activeRule = GameManagerOne.Instance.partFaceList.RandomItem <string>(); switch (GameManagerOne.Instance.activeRule) { case "eye": GameManagerOne.Instance.activeColor = colorEyeN.RandomItem <string>(); GameManagerOne.Instance.noColor = RandomUtil.Chance(0.5f); break; case "hair": GameManagerOne.Instance.activeColor = colorHairN.RandomItem <string>(); GameManagerOne.Instance.noColor = RandomUtil.Chance(0.5f); break; case "skin": GameManagerOne.Instance.activeColor = colorSkinN.RandomItem <string>(); GameManagerOne.Instance.noColor = RandomUtil.Chance(0.5f); break; } GameManagerOne.Instance.ruleText(GameObject.FindGameObjectWithTag("ruleText").GetComponent <Text>()); }
// temporary solution for hunting without affecting the environment // spawn a corpse nearby when a hungry animal becomes visible public override void OnBecameVisible(IWorldObserver observer, Animal animal) { base.OnBecameVisible(observer, animal); if (animal.Dead || animal.Hunger < HungerThreshold || !RandomUtil.Chance(ChanceCaughtPreyWhileOffscreen)) { return; } var preyType = this.GetRegionalPrey(animal); if (preyType != null) { var preySpecies = EcoSim.GetSpecies(preyType.Name) as AnimalSpecies; var spawnPos = (Vector3)animal.Position.WorldPosition3i.SpiralOutXZIter(10).Skip(20) .Select(x => RouteManager.NearestWalkableY(x, 10)).Where(x => x.IsValid && RouteCacheData.IsFlatGround(x)).FirstOrDefault(); if (spawnPos != default(Vector3)) { EcoSim.AnimalSim.SpawnCorpse(preySpecies, spawnPos); } } }
public virtual void DoWork(Settlement.Settlement settlement) { //Can't work if (Workplace == null) { return; } var discipline = Traits[Trait.Discipline]; if (discipline == TraitLevel.BelowAverage && RandomUtil.Chance(1, 40) || discipline == TraitLevel.Low && RandomUtil.Chance(1, 20) || discipline == TraitLevel.VeryLow && RandomUtil.Chance(1, 10)) { //skipped work settlement.AddMessage(new SettlerSkippedWorkMessage(this)); } else { Workplace.HostWork(this, settlement); } }
public void randomLevelN() { bool previousLapsus = GameManagerOne.Instance.lapsus; switch (countLevel) { case 1: GameManagerOne.Instance.randomTender = Random.Range(5, 9); break; case 2: GameManagerOne.Instance.randomTender = Random.Range(4, 7); break; case 3: GameManagerOne.Instance.randomTender = Random.Range(3, 5); GameManagerOne.Instance.lapsus = RandomUtil.Chance(0.5f); if (!previousLapsus && GameManagerOne.Instance.lapsus) { AudioManager.Instance.PlaySoundEffect(effectLapsus); } break; default: GameManagerOne.Instance.randomTender = Random.Range(2, 4); GameManagerOne.Instance.lapsus = RandomUtil.Chance(0.5f); if (!previousLapsus && GameManagerOne.Instance.lapsus) { AudioManager.Instance.PlaySoundEffect(effectLapsus); } break; } if (previousLapsus != GameManagerOne.Instance.lapsus) { GameManagerOne.Instance.OnLapsusChanged(GameManagerOne.Instance.lapsus); } }
static HerdAnimalBrain() { HerdAnimalTreeRoot = BT.Selector( LandAnimalBrain.LyingDownTree, BT.If(x => x.Alertness > LandAnimalBrain.AlertThreshold && x.Alertness < LandAnimalBrain.FullyAlertThreshold && x.AnimationState != AnimalAnimationState.Flee && x.AnimationState != AnimalAnimationState.AlertIdle && x.OnFlatGround, // play an alert reaction before fleeing and intermittently while alert PlayFixedTimeAnimation(AnimalAnimationState.AlertIdle, LandAnimalBrain.AlertIdleTime)), MovementBehaviors.Flee, GroupBehaviors.SleepNearLeader, new FindAndEatPlantsMemoryBehavior() { NoNearbyFoodBehavior = LandAnimalBrain.LandAnimalFindFood }, GroupBehaviors.StayNearLeader(20f), BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.WanderHome), BT.If(x => x.Alertness < Animal.FleeThreshold && RandomUtil.Chance(LandAnimalBrain.ChanceToLieDown) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.LyingDown, LandAnimalBrain.LyingTickDuration)), BT.If(x => RandomUtil.Chance(LandAnimalBrain.ChanceToIdle) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.Idle, _ => RandomUtil.Range(LandAnimalBrain.MinIdleTime, LandAnimalBrain.MaxIdleTime))), MovementBehaviors.Wander); }
static LandAnimalBrain() { LyingDownTree = BT.If(animal => animal.LyingDown, BT.Selector( BT.If(x => x.AnimationState == AnimalAnimationState.Sleeping && x.Alertness > Animal.WakeUpAlertness, // waking up takes time, start the transition animation then decide what to do next tick PlayFixedTimeAnimation(AnimalAnimationState.LyingDown, x => x.Species.TimeWakeUp)), BT.If(x => x.Alertness > Animal.FleeThreshold, PlayFixedTimeAnimation(AnimalAnimationState.Flee, x => x.Species.TimeLayToStand)), BT.If(x => x.Hunger > HungerThreshold, PlayFixedTimeAnimation(AnimalAnimationState.Idle, x => x.Species.TimeLayToStand)), BT.If(x => x.ShouldSleep, PlayAnimation(AnimalAnimationState.Sleeping, LyingTickDuration)), BT.If(x => RandomUtil.Chance(ChanceToStopLyingDown), PlayAnimation(AnimalAnimationState.Idle, x => x.Species.TimeLayToStand + RandomUtil.Range(MinIdleTime, MaxIdleTime))), PlayAnimation(AnimalAnimationState.LyingDown, _ => RandomUtil.Range(MinLyingIdleTime, MaxLyingIdleTime)))); LandAnimalTreeRoot = BT.Selector( LyingDownTree, BT.If(x => x.Alertness > AlertThreshold && x.Alertness < FullyAlertThreshold && x.AnimationState != AnimalAnimationState.Flee && x.AnimationState != AnimalAnimationState.AlertIdle && x.OnFlatGround, // play an alert reaction before fleeing and intermittently while alert PlayFixedTimeAnimation(AnimalAnimationState.AlertIdle, AlertIdleTime)), MovementBehaviors.Flee, new FindAndEatPlantsMemoryBehavior() { NoNearbyFoodBehavior = LandAnimalFindFood }, BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.WanderHome), BT.If(x => x.Alertness < Animal.FleeThreshold && RandomUtil.Chance(ChanceToLieDown) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.LyingDown, LyingTickDuration)), BT.If(x => RandomUtil.Chance(ChanceToIdle) && x.OnFlatGround, PlayAnimation(AnimalAnimationState.Idle, _ => RandomUtil.Range(MinIdleTime, MaxIdleTime))), MovementBehaviors.Wander); }
public static void GenerateChildTraits(Human child) { List <Settler> parents = new List <Settler>(); foreach (var relationship in child.Relationships) { if (relationship is ParentChildRelationship pcr && pcr.Role(child) == ParentChildRelationship.Child) { parents.Add(pcr.Other(child)); } } var badRelationshipParents = parents.Where(parent => child.Relationships .FirstOrDefault(rel => rel is ParentChildRelationship pcr && pcr.Other(parent) == child)?.Level <= RelationshipLevel.Dislike).ToList(); foreach (var trait in Trait.Traits) { var parentsTraitsArray = parents.ToArray().Select(parent => parent.Traits[trait].Value).ToArray(); if (badRelationshipParents.Count > 0 && RandomUtil.Chance(1, 3)) { var parent = RandomUtil.Get(badRelationshipParents); var level = parent.Traits[trait]; if (level == TraitLevel.Average) //Reaction goes extreme { child.Traits[trait] = RandomUtil.Get(new[] { TraitLevel.VeryLow, TraitLevel.Low, TraitLevel.High, TraitLevel.VeryHigh }); } else if (level == TraitLevel.AboveAverage) // Reaction goes extreme, more down { child.Traits[trait] = RandomUtil.Get(new[] { TraitLevel.VeryLow, TraitLevel.Low, TraitLevel.VeryHigh }); } else if (level == TraitLevel.BelowAverage) { child.Traits[trait] = RandomUtil.Get(new[] { TraitLevel.VeryLow, TraitLevel.High, TraitLevel.VeryHigh }); } else if (level >= TraitLevel.High) { child.Traits[trait] = RandomUtil.Get(new[] { TraitLevel.VeryLow, TraitLevel.Low, TraitLevel.BelowAverage }); } else { child.Traits[trait] = RandomUtil.Get(new[] { TraitLevel.AboveAverage, TraitLevel.High, TraitLevel.VeryHigh }); } } else { var baseLevel = TraitLevel.Average.Get(MathUtil.RoundTowardsZero(MathUtil.UnroundedAverage(parentsTraitsArray))); if (RandomUtil.CoinFlip()) //Drift { if (baseLevel == TraitLevel.VeryLow || baseLevel <= TraitLevel.High && RandomUtil.CoinFlip()) { baseLevel = baseLevel.Get(baseLevel.Value + 1); } else { baseLevel = baseLevel.Get(baseLevel.Value - 1); } } child.Traits[trait] = baseLevel as TraitLevel; } } TraitGenerator.EnsureMajorTrait(child); }
// Alligators can spawn on land or water public override bool IsValidSpawnPathPos(Vector3i pos) => World.World.IsUnderwater(pos) || RandomUtil.Chance(.3f);
static Otter() { const float MinIdleTime = 3f; const float MaxIdleTime = 10f; const float MinFloatIdleTime = 10f; const float MaxFloatIdleTime = 20f; const float ChanceToIdle = 0.3f; const float ChanceToSurface = 0.3f; const float ChanceToDive = 0.1f; const float TimeToStopFloating = 2f; const float DiveAlertness = 200; const float MaxHeightAboveSeaLevel = 5; OtterLandTree = BT.If(x => !World.World.IsUnderwater(x.Position.WorldPosition3i), BT.Selector( MovementBehaviors.AmphibiousFlee, BT.If(x => RandomUtil.Chance(ChanceToIdle), Brain.PlayAnimation(AnimalAnimationState.Idle, _ => RandomUtil.Range(MinIdleTime, MaxIdleTime))), BT.If(x => x.Position.y > WorldLayerManager.ClimateSim.State.SeaLevel + MaxHeightAboveSeaLevel, x => MovementBehaviors.RouteToWater(x, x.Species.WanderingSpeed, AnimalAnimationState.Wander)), BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.AmphibiousWanderHome), MovementBehaviors.AmphibiousWander)); OtterFloatingTree = BT.If(x => x.floating, BT.Selector( BT.If(x => x.AnimationState == AnimalAnimationState.FloatingIdle, // floating otters need time to flip back over before doing other things Brain.PlayFixedTimeAnimation(AnimalAnimationState.SurfaceSwimming, TimeToStopFloating)), BT.If(x => x.Alertness > DiveAlertness, // dive when scared BT.Success(x => x.floating = false), BT.Selector(MovementBehaviors.SwimFlee, MovementBehaviors.SwimWander)), MovementBehaviors.AmphibiousFlee, BT.If(x => RandomUtil.Chance(ChanceToDive), BT.Success(x => x.floating = false), MovementBehaviors.SwimWander), BT.If(MovementBehaviors.ShouldReturnHome, MovementBehaviors.AmphibiousWanderHome), BT.If(x => RandomUtil.Chance(ChanceToIdle), Brain.PlayAnimation(AnimalAnimationState.FloatingIdle, _ => RandomUtil.Range(MinFloatIdleTime, MaxFloatIdleTime))), MovementBehaviors.AmphibiousWander)); OtterDivingTree = BT.Selector( MovementBehaviors.SwimFlee, BT.If(MovementBehaviors.ShouldReturnHome, BT.Success(x => x.floating = true), MovementBehaviors.SwimWanderHomeSurface), BT.If(x => x.Alertness < DiveAlertness && RandomUtil.Chance(ChanceToSurface), BT.Success(x => x.floating = true), MovementBehaviors.SwimWanderSurface), BT.If(x => RandomUtil.Chance(1 - ChanceToIdle), MovementBehaviors.SwimWander), Brain.PlayAnimation(AnimalAnimationState.SwimmingIdle, _ => RandomUtil.Range(MinIdleTime, MaxIdleTime))); OtterTreeRoot = BT.Selector( OtterLandTree, // TODO: dive for food & eat on surface (need tummy eating animation) OtterFloatingTree, OtterDivingTree ); Brain <Otter> .SharedBehavior = OtterTreeRoot; }
static AmphibiousBrain() { LandTree = BT.If("Land Tree", x => (!World.World.IsUnderwater(x.Position.WorldPosition3i), "on land"), BT.Selector("Amphibious On Land", MovementBehaviors.AmphibiousFlee, BT.If("Return Home", MovementBehaviors.ShouldReturnHome, MovementBehaviors.AmphibiousWanderHome), BT.If("Return to Water", x => (x.Position.y > WorldLayerManager.Obj.ClimateSim.State.SeaLevel + MaxHeightAboveSeaLevel, $"above sea-level {(x.Position.Y + WorldLayerManager.Obj.ClimateSim.State.SeaLevel).ToString("0.#")} not more than {MaxHeightAboveSeaLevel}"), MovementBehaviors.MoveToWater), BT.Random("Relax", RelaxBehaviors.TryIdle, MovementBehaviors.AmphibiousWander))); FloatingTree = BT.If("Floating", x => (x.Floating, "floating"), BT.Selector("Floating", BT.If("Surface swim", x => (x.State == AnimalState.FloatingIdle && !x.Species.IsPredator, "is idling and not predator"), // floating amphibious need time to flip back over before doing other things Anim(AnimalState.SurfaceSwimming, true, TimeToStopFloating)), BT.If("Flee Dive", x => (x.Alertness > DiveAlertness, $"alert {x.Alertness.ToString("0.#")} > {DiveAlertness.ToString("0.#")}"), stopFloating, BT.Selector("Flee or Wander", MovementBehaviors.SwimFlee, MovementBehaviors.SwimWander)), MovementBehaviors.AmphibiousFlee, BT.If("Random Dive", x => AIUtil.Chance(ChanceToDive), stopFloating, MovementBehaviors.SwimWander), BT.If("Return Home", MovementBehaviors.ShouldReturnHome, MovementBehaviors.AmphibiousWanderHome), BT.If("Idle", x => AIUtil.Chance(ChanceToIdle), Anim(AnimalState.FloatingIdle, true, _ => RandomUtil.Range(MinFloatIdleTime, MaxFloatIdleTime))), MovementBehaviors.AmphibiousWander)); DivingTree = BT.Selector("Diving", MovementBehaviors.SwimFlee, BT.If("Return Home", MovementBehaviors.ShouldReturnHome, startFloating, MovementBehaviors.SwimWanderHomeSurface), BT.If("Surface", x => (x.Alertness < DiveAlertness && RandomUtil.Chance(ChanceToSurface), $"alert {x.Alertness.ToString("0.#")} < {DiveAlertness.ToString("0.#")} and {ChanceToSurface.ToString("P0")} chance"), startFloating, MovementBehaviors.SwimWanderSurface), BT.If("Wander", x => AIUtil.Chance(1 - ChanceToIdle), MovementBehaviors.SwimWander), Anim(AnimalState.SwimmingIdle, true, _ => RandomUtil.Range(MinIdleTime, MaxIdleTime))); // TODO: dive for food & eat on surface (need tummy eating animation) AmphibiousTreeRoot = BT.Selector("Amphibious", BT.If("Animal On Land", x => (!World.World.IsUnderwater(x.Position.WorldPosition3i), "on land"), BT.Selector("Landing", MovementBehaviors.Flee, FindAndEatPlants, LandTree)), BT.If("Animal In Water", x => (World.World.IsUnderwater(x.Position.WorldPosition3i), "in water"), BT.Selector("Swimming", MovementBehaviors.SwimFlee, FloatingTree, DivingTree)), RelaxBehaviors.Idle); PredatorAmphibiousTreeRoot = BT.Selector("Amphibious Predator", BT.If("Predator On Land", x => (!World.World.IsUnderwater(x.Position.WorldPosition3i), "on land"), BT.Selector("Landing", MovementBehaviors.Flee, LandPredatorBrain.FindAndAttackEnemyTree, LandPredatorBrain.FindAndEatCorpse, LandTree) ), BT.If("Predator In Water", x => (World.World.IsUnderwater(x.Position.WorldPosition3i), "in water"), BT.Selector("Swimming", MovementBehaviors.SwimFlee, FloatingTree, DivingTree) ), RelaxBehaviors.Idle); }