public void HandleReproduction() { if (CurrentTask.HasValue()) { return; } if (!Creature.Stats.Species.CanReproduce) { return; } if (Creature.IsPregnant) { return; } if (!MathFunctions.RandEvent(0.0002f)) { return; } CreatureAI closestMate = null; float closestDist = float.MaxValue; foreach (var ai in Faction.Minions.Where(minion => minion != this && Mating.CanMate(minion.Creature, this.Creature))) { var dist = (ai.Position - Position).LengthSquared(); if (!(dist < closestDist)) { continue; } closestDist = dist; closestMate = ai; } if (closestMate != null && closestDist < 30) { Tasks.Add(new MateTask(closestMate)); } }
public ResourceSet GenerateTradeItems(WorldManager world) { var toReturn = new ResourceSet(); String[] blacklistTags = { "Money", "Corpse" }; foreach (var tags in TradeGoods) { int num = MathFunctions.RandInt(tags.Value, tags.Value + 4); if (tags.Key == "Craft") { for (int i = 0; i < num; i++) { MaybeNull <Resource> randResource = null; if (tags.Key == "Craft") { var craftTag = Datastructures.SelectRandom(Crafts); var availableCrafts = Library.EnumerateResourceTypesWithTag(craftTag); if (Library.CreateMetaResource("Trinket", null, new Resource("Trinket"), new List <Resource> { new Resource(Datastructures.SelectRandom(availableCrafts)) }).HasValue(out var trinket)) { if (MathFunctions.RandEvent(0.3f) && Encrustings.Count > 0) { randResource = Library.CreateMetaResource("GemTrinket", null, new Resource("Gem-set Trinket"), new List <Resource> { trinket, new Resource(Datastructures.SelectRandom(Library.EnumerateResourceTypesWithTag(Datastructures.SelectRandom(Encrustings)))) }); } else { randResource = trinket; } } } if (randResource.HasValue(out var res)) { toReturn.Add(res); } } } else { var resources = Library.EnumerateResourceTypesWithTag(tags.Key).Select(r => new Resource(r)); if (resources.Count() <= 0) { continue; } for (int i = 0; i < num; i++) { MaybeNull <Resource> randResource = Datastructures.SelectRandom(resources); if (!randResource.HasValue(out var res) || !res.ResourceType.HasValue(out var resType) || resType.Tags.Any(blacklistTags.Contains)) { continue; } if (randResource.HasValue(out res)) { toReturn.Add(res); } } } } return(toReturn); }
override public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { base.Update(gameTime, chunks, camera); if (!Active) return; Creature.NoiseMaker.BasePitch = Stats.VoicePitch; // Non-dwarves are always at full energy. Stats.Energy.CurrentValue = 100.0f; AutoGatherTimer.Update(gameTime); if (AutoGatherTimer.HasTriggered) { if (!String.IsNullOrEmpty(Faction.Race.BecomeWhenEvil) && MathFunctions.RandEvent(0.01f)) { Faction.Minions.Remove(this); Faction = World.Factions.Factions[Faction.Race.BecomeWhenEvil]; Faction.AddMinion(this); } else if (!String.IsNullOrEmpty(Faction.Race.BecomeWhenNotEvil) && MathFunctions.RandEvent(0.01f)) { Faction.Minions.Remove(this); Faction = World.Factions.Factions[Faction.Race.BecomeWhenNotEvil]; Faction.AddMinion(this); } foreach (var body in World.EnumerateIntersectingObjects(Physics.BoundingBox.Expand(3.0f)).OfType<ResourceEntity>().Where(r => r.Active && r.AnimationQueue.Count == 0)) { var resource = Library.GetResourceType(body.Resource.Type); if (resource.Tags.Contains(Resource.ResourceTags.Edible)) { if ((Faction.Race.EatsMeat && resource.Tags.Contains(Resource.ResourceTags.AnimalProduct)) || (Faction.Race.EatsPlants && !resource.Tags.Contains(Resource.ResourceTags.AnimalProduct))) { Creature.GatherImmediately(body); AssignTask(new ActWrapperTask(new EatFoodAct(this, false))); } } } OrderEnemyAttack(); } DeleteBadTasks(); PreEmptTasks(); HandleReproduction(); // Try to find food if we are hungry. Wait - doesn't this rob the player? if (Stats.Hunger.IsDissatisfied() && World.CountResourcesWithTag(Resource.ResourceTags.Edible) > 0) { Task toReturn = new SatisfyHungerTask(); if (Stats.Hunger.IsCritical()) toReturn.Priority = TaskPriority.Urgent; if (!Tasks.Contains(toReturn) && CurrentTask != toReturn) AssignTask(toReturn); } if (CurrentTask == null) // We need something to do. { var goal = GetEasiestTask(Tasks); if (goal != null) ChangeTask(goal); else { var newTask = ActOnIdle(); if (newTask != null) ChangeTask(newTask); } } else { if (!CurrentAct.HasValue()) // Should be impossible to have a current task and no current act. { // Try and recover the correct act. // <blecki> I always run with a breakpoint set here... just in case. ChangeAct(CurrentTask.CreateScript(Creature)); // This is a bad situation! if (!CurrentAct.HasValue()) ChangeTask(null); } if (CurrentAct.HasValue(out Act currentAct)) { var status = currentAct.Tick(); bool retried = false; if (CurrentAct.HasValue(out Act newCurrentAct) && CurrentTask != null) { if (status == Act.Status.Fail) { LastFailedAct = newCurrentAct.Name; if (!FailedTasks.Any(task => task.TaskFailure.Equals(CurrentTask))) FailedTasks.Add(new FailedTask() { TaskFailure = CurrentTask, FailedTime = World.Time.CurrentDate }); if (CurrentTask.ShouldRetry(Creature)) if (!Tasks.Contains(CurrentTask)) { ReassignCurrentTask(); retried = true; } } } if (CurrentTask != null && CurrentTask.IsComplete(World)) ChangeTask(null); else if (status != Act.Status.Running && !retried) ChangeTask(null); } } // With a small probability, the creature will drown if its under water. if (MathFunctions.RandEvent(GameSettings.Default.DrownChance)) { var above = VoxelHelpers.GetVoxelAbove(Physics.CurrentVoxel); var below = VoxelHelpers.GetVoxelBelow(Physics.CurrentVoxel); bool shouldDrown = (above.IsValid && (!above.IsEmpty || above.LiquidLevel > 0)); if ((Physics.IsInLiquid || (!Movement.CanSwim && (below.IsValid && (below.LiquidLevel > 5)))) && (!Movement.CanSwim || shouldDrown)) Creature.Damage(Movement.CanSwim ? 1.0f : 30.0f, Health.DamageType.Normal); } if (PositionConstraint.Contains(Physics.LocalPosition) == ContainmentType.Disjoint) { Physics.LocalPosition = MathFunctions.Clamp(Physics.Position, PositionConstraint); Physics.PropogateTransforms(); } }