public BuildRoomAct(CreatureAI agent, BuildZoneOrder buildRoom) : base(agent) { Name = "Build BuildRoom " + buildRoom.ToString(); Resources = buildRoom.ListRequiredResources(); BuildRoom = buildRoom; if (BuildRoom.ResourcesReservedFor != null && BuildRoom.ResourcesReservedFor.IsDead) { BuildRoom.ResourcesReservedFor = null; } Tree = new Sequence(new Select(new Domain(buildRoom.MeetsBuildRequirements() || buildRoom.ResourcesReservedFor != null, true), new Domain(!buildRoom.MeetsBuildRequirements() && (buildRoom.ResourcesReservedFor == null || buildRoom.ResourcesReservedFor == Agent), new Sequence(new Wrap(Reserve), new GetResourcesAct(Agent, Resources))), new Domain(buildRoom.MeetsBuildRequirements() || buildRoom.ResourcesReservedFor != null, true)), new Domain(() => IsRoomBuildOrder(buildRoom) && !buildRoom.IsBuilt && !buildRoom.IsDestroyed && ValidResourceState(), new Sequence( SetTargetVoxelFromRoomAct(buildRoom, "ActionVoxel"), new GoToNamedVoxelAct("ActionVoxel", PlanAct.PlanType.Adjacent, Agent), new Wrap(PutResources), new Wrap(WaitForResources) { Name = "Wait for resources..." }, new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => buildRoom.BuildProgress, () => buildRoom.BuildProgress += agent.Stats.BuildSpeed / buildRoom.VoxelOrders.Count * 0.5f, () => MathFunctions.RandVector3Box(buildRoom.GetBoundingBox()), ContentPaths.Audio.Oscar.sfx_ic_dwarf_craft, () => !buildRoom.IsBuilt && !buildRoom.IsDestroyed)) { Name = "Build room.." }, new CreateRoomAct(Agent, buildRoom) , new Wrap(OnFailOrCancel))) | new Wrap(OnFailOrCancel) ); }
public override void Initialize() { var unreserveAct = new Wrap(UnReserve); var time = 3 * (ItemType.BaseCraftTime / Creature.AI.Stats.Intelligence); var getResources = new Select(new Domain(() => Des.HasResources || Des.ResourcesReservedFor != null, true), new Domain(() => !Des.HasResources && (Des.ResourcesReservedFor == Agent || Des.ResourcesReservedFor == null), new Sequence( new Wrap(ReserveResources), new GetResourcesOfApparentType(Agent, RawMaterials) { BlackboardEntry = "stashed-materials" }) | (new Wrap(UnReserve)) & false), new Domain(() => Des.HasResources || Des.ResourcesReservedFor != null, true)); if (!String.IsNullOrEmpty(ItemType.CraftLocation)) { Tree = new Sequence( new Wrap(() => Creature.FindAndReserve(ItemType.CraftLocation, "craft-location")), new ClearBlackboardData(Agent, "ResourcesStashed"), getResources, new Domain(ResourceStateValid, new Sequence( ActHelper.CreateEquipmentCheckAct(Agent, "Tool", ActHelper.EquipmentFallback.AllowDefault, "Hammer"), new GoToTaggedObjectAct(Agent) { Teleport = true, TeleportOffset = new Vector3(0.5f, 0.0f, 0), ObjectBlackboardName = "craft-location", CheckForOcclusion = true }, new Wrap(() => DestroyResources(() => Agent.Position + MathFunctions.RandVector3Cube() * 0.5f)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => Creature.HitAndWait(true, () => 1.0f, // Max Progress () => Des.Progress, // Current Progress () => { // Increment Progress var location = Creature.AI.Blackboard.GetData <GameComponent>(ItemType.CraftLocation); float workstationBuff = 1.0f; if (location != null) { Creature.Physics.Face(location.Position); if (location.GetComponent <SteamPipes.BuildBuff>().HasValue(out var buff)) { workstationBuff = buff.GetBuffMultiplier(); } } // Todo: Account for environment buff & 'anvil' buff. Des.Progress += (Creature.Stats.BuildSpeed * workstationBuff) / ItemType.BaseCraftTime; },
public override void Initialize() { Act unreserveAct = new Wrap(UnReserve); float time = 3 * (Item.ItemType.Placement_PlaceTime / Creature.AI.Stats.Intelligence); Act getResources = null; getResources = new Select( new Domain(() => Item.HasResources || Item.SelectedResource != null, new Always(Status.Success)), new Domain(() => !Item.HasResources && (Item.SelectedResource == null || Item.SelectedResource.ReservedFor == Agent || Item.SelectedResource.ReservedFor == null), new Sequence( new Select( new Sequence( new Wrap(LocateResources), new Wrap(AcquireResources)), new Wrap(UnReserve)), new Always(Status.Fail))), new Domain(() => Item.SelectedResource != null && (Item.HasResources || Item.SelectedResource.ReservedFor != null), new Always(Status.Success))); Act buildAct = null; buildAct = new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => Item.Progress, () => Item.Progress += (Creature.Stats.BuildSpeed * 8) / Item.ItemType.Placement_PlaceTime, // Todo: Account for creature debuffs, environment buffs () => Item.Location.WorldPosition + Vector3.One * 0.5f, "Craft")) { Name = "Construct object." }; Tree = new Select( new Domain(IsNotCancelled, new Sequence( new ClearBlackboardData(Agent, "ResourcesStashed"), getResources, new Sequence( new Domain(ResourceStateValid, new Sequence( new GoToVoxelAct(Voxel, PlanAct.PlanType.Adjacent, Agent), new Wrap(() => DestroyResources(() => Item.Location.WorldPosition)), new Wrap(WaitForResources) { Name = "Wait for resources." }, buildAct, new Wrap(FinallyPlaceObject) { Name = "Place the object." }))))), new Sequence( new Wrap(Creature.RestockAll), unreserveAct, new Always(Status.Fail))); base.Initialize(); }
public override IEnumerable <Status> Run() { if (!Creature.Faction.WallBuilder.IsDesignation(Voxel)) { yield return(Status.Fail); yield break; } foreach (Status status in Creature.HitAndWait(1.0f, true)) { if (status == Status.Running) { yield return(status); } } Body grabbed = Creature.Inventory.RemoveAndCreate(Resource).FirstOrDefault(); if (grabbed == null) { yield return(Status.Fail); yield break; } else { if (Creature.Faction.WallBuilder.IsDesignation(Voxel)) { TossMotion motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Voxel.Position + new Vector3(0.5f, 0.5f, 0.5f)); motion.OnComplete += grabbed.Die; grabbed.AnimationQueue.Add(motion); WallBuilder put = Creature.Faction.WallBuilder.GetDesignation(Voxel); put.Put(PlayState.ChunkManager); Creature.Faction.WallBuilder.Designations.Remove(put); Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); yield return(Status.Success); } else { Creature.Inventory.Resources.AddItem(grabbed); grabbed.Die(); yield return(Status.Fail); } } }
public BuildRoomAct(CreatureAI agent, BuildRoomOrder buildRoom) : base(agent) { Name = "Build BuildRoom " + buildRoom.ToString(); Resources = buildRoom.ListRequiredResources(); Tree = new Sequence(new GetResourcesAct(Agent, Resources), new Sequence( new Wrap(() => IsRoomBuildOrder(buildRoom)), SetTargetVoxelFromRoomAct(buildRoom, "TargetVoxel"), new Wrap(() => IsRoomBuildOrder(buildRoom)), new GoToVoxelAct("TargetVoxel", PlanAct.PlanType.Adjacent, Agent), new Wrap(() => IsRoomBuildOrder(buildRoom)), new Wrap(() => Creature.HitAndWait(buildRoom.VoxelOrders.Count * 0.5f / agent.Stats.BuildSpeed, true)), new Wrap(() => IsRoomBuildOrder(buildRoom)), new PlaceRoomResourcesAct(Agent, buildRoom, Resources) , new Wrap(Creature.RestockAll)) | new Wrap(Creature.RestockAll) ); }
public IEnumerable <Act.Status> DoMagicResearch() { var obj = Agent.Blackboard.GetData <Body>("Research"); if (obj == null) { yield return(Act.Status.Fail); yield break; } float timer = 0; foreach (var status in Creature.HitAndWait(false, () => { return(10.0f); }, () => { return(timer); }, () => { timer++; }, () => { return(obj.Position); }, ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research)) { yield return(Act.Status.Running); } Creature.AI.AddXP(10); yield return(Act.Status.Success); }
public IEnumerable <Act.Status> DoMagicResearch() { var obj = Agent.Blackboard.GetData <GameComponent>("training-object"); if (obj == null) { Agent.SetMessage("Failed to find magical object for research purposes."); yield return(Act.Status.Fail); yield break; } float timer = 0; foreach (var status in Creature.HitAndWait(false, () => { return(10.0f); }, () => { return(timer); }, () => { timer++; }, () => { return(obj.Position); }, ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research)) { yield return(Act.Status.Running); } Creature.AI.AddXP(5); yield return(Act.Status.Success); }
public override IEnumerable <Status> Run() { if (!Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { yield return(Status.Success); yield break; } if (!Creature.Inventory.HasResource(Resource)) { yield return(Status.Fail); } foreach (var status in Creature.HitAndWait(1.0f, true, () => Location.Coordinate.ToVector3() + Vector3.One * 0.5f)) { if (!Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { yield return(Status.Success); yield break; } if (status == Status.Running) { yield return(status); } } var grabbed = Creature.Inventory.RemoveAndCreate(Resource, Inventory.RestockType.Any).FirstOrDefault(); if (grabbed == null) { yield return(Status.Fail); yield break; } else { if (Creature.Faction.Designations.IsVoxelDesignation(Location, DesignationType.Put)) { // If the creature intersects the box, find a voxel adjacent to it that is free, and jump there to avoid getting crushed. if (Creature.Physics.BoundingBox.Intersects(Location.GetBoundingBox())) { var neighbors = VoxelHelpers.EnumerateAllNeighbors(Location.Coordinate) .Select(c => new VoxelHandle(Agent.Chunks.ChunkData, c)); var closest = VoxelHandle.InvalidHandle; float closestDist = float.MaxValue; foreach (var voxel in neighbors) { if (!voxel.IsValid) { continue; } float dist = (voxel.WorldPosition - Creature.Physics.Position).LengthSquared(); if (dist < closestDist && voxel.IsEmpty) { closestDist = dist; closest = voxel; } } if (closest.IsValid) { TossMotion teleport = new TossMotion(0.5f, 1.0f, Creature.Physics.GlobalTransform, closest.WorldPosition + Vector3.One * 0.5f); Creature.Physics.AnimationQueue.Add(teleport); } } TossMotion motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Location.Coordinate.ToVector3() + new Vector3(0.5f, 0.5f, 0.5f)); grabbed.GetRoot().GetComponent <Physics>().CollideMode = Physics.CollisionMode.None; grabbed.AnimationQueue.Add(motion); var put = Creature.Faction.Designations.GetVoxelDesignation(Location, DesignationType.Put) as short?; if (!put.HasValue) { yield return(Status.Fail); yield break; } var putType = VoxelLibrary.GetVoxelType(put.Value); motion.OnComplete += () => { grabbed.Die(); PlaceVoxel(Location, putType, Creature.Manager.World); Creature.Faction.Designations.RemoveVoxelDesignation(Location, DesignationType.Put); Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); }; yield return(Status.Success); yield break; } else { Creature.Inventory.Pickup(grabbed, Inventory.RestockType.RestockResource); grabbed.Die(); yield return(Status.Success); } } }
public override void Initialize() { Act unreserveAct = new Wrap(UnReserve); float time = 3 * (Item.ItemType.BaseCraftTime / Creature.AI.Stats.Intelligence); bool factionHasResources = Item.SelectedResources != null && Item.SelectedResources.Count > 0 && Creature.World.HasResources(Item.SelectedResources); Act getResources = null; if (Item.ExistingResource != null) { getResources = new Select(new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true), new Domain(() => !Item.HasResources && (Item.ResourcesReservedFor == Agent || Item.ResourcesReservedFor == null), new Select( new Sequence(new Wrap(ReserveResources), new GetResourcesAct(Agent, new List <ResourceAmount>() { new ResourceAmount(Item.ExistingResource) }), new Wrap(SetSelectedResources)), new Sequence(new Wrap(UnReserve), Act.Status.Fail) ) ), new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true)); } else if (!factionHasResources) { getResources = new Select(new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true), new Domain(() => !Item.HasResources && (Item.ResourcesReservedFor == Agent || Item.ResourcesReservedFor == null), new Select( new Sequence(new Wrap(ReserveResources), new GetResourcesAct(Agent, Item.ItemType.RequiredResources), new Wrap(SetSelectedResources)), new Sequence(new Wrap(UnReserve), Act.Status.Fail) ) ), new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true)); } else { getResources = new Select(new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true), new Domain(() => !Item.HasResources && (Item.ResourcesReservedFor == Agent || Item.ResourcesReservedFor == null), new Sequence(new Wrap(ReserveResources), new GetResourcesAct(Agent, Item.SelectedResources)) | (new Wrap(UnReserve)) & false), new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true)); } if (Item.ItemType.Type == CraftItem.CraftType.Object) { Act buildAct = null; if (Item.ExistingResource != null) { buildAct = new Always(Status.Success); } else { buildAct = new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => Item.Progress, () => Item.Progress += Creature.Stats.BuildSpeed / Item.ItemType.BaseCraftTime, // Todo: Account for creature debuffs, environment buffs () => Item.Location.WorldPosition + Vector3.One * 0.5f, "Craft")) { Name = "Construct object." }; } Tree = new Domain(IsNotCancelled, new Sequence( new ClearBlackboardData(Agent, "ResourcesStashed"), getResources, new Sequence(new Domain(ResourceStateValid, new Sequence( new GoToVoxelAct(Voxel, PlanAct.PlanType.Adjacent, Agent), new Wrap(() => DestroyResources(() => Item.Location.WorldPosition)), new Wrap(WaitForResources) { Name = "Wait for resources." }, buildAct, new CreateCraftItemAct(Voxel, Creature.AI, Item) ) )) )) | new Sequence(new Wrap(Creature.RestockAll), unreserveAct, false); } else if (Item.ItemType.Type == CraftItem.CraftType.Resource) { if (!String.IsNullOrEmpty(Item.ItemType.CraftLocation)) { Tree = new Sequence( new Wrap(() => Creature.FindAndReserve(Item.ItemType.CraftLocation, Item.ItemType.CraftLocation)), new ClearBlackboardData(Agent, "ResourcesStashed"), getResources, new Domain(ResourceStateValid, new Sequence( new GoToTaggedObjectAct(Agent) { Tag = Item.ItemType.CraftLocation, Teleport = true, TeleportOffset = new Vector3(0.5f, 0.0f, 0), ObjectName = Item.ItemType.CraftLocation, CheckForOcclusion = true }, new Wrap(() => DestroyResources(() => Agent.Position + MathFunctions.RandVector3Cube() * 0.5f)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => MaybeCreatePreviewBody(Item.SelectedResources)), new Wrap(() => Creature.HitAndWait(true, () => 1.0f, // Max Progress () => Item.Progress, // Current Progress () => { // Increment Progress var location = Creature.AI.Blackboard.GetData <GameComponent>(Item.ItemType.CraftLocation); float workstationBuff = 1.0f; if (location != null) { Creature.Physics.Face(location.Position); if (Item.PreviewResource != null) { Item.PreviewResource.LocalPosition = location.Position + Vector3.Up * 0.25f; } if (location.GetComponent <SteamPipes.BuildBuff>().HasValue(out var buff)) { workstationBuff = buff.GetBuffMultiplier(); } } // Todo: Account for environment buff & 'anvil' buff. Item.Progress += (Creature.Stats.BuildSpeed * workstationBuff) / Item.ItemType.BaseCraftTime; },
public override void Initialize() { Act unreserveAct = new Wrap(UnReserve); float time = 3 * (Item.ItemType.BaseCraftTime / Creature.AI.Stats.BuffedInt); Act getResources = null; if (Item.SelectedResources == null || Item.SelectedResources.Count == 0) { getResources = new Select(new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true), new Domain(() => !Item.HasResources && (Item.ResourcesReservedFor == Agent || Item.ResourcesReservedFor == null), new Sequence(new Wrap(ReserveResources), new GetResourcesAct(Agent, Item.ItemType.RequiredResources))), new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true)); } else { getResources = new Select(new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true), new Domain(() => !Item.HasResources && (Item.ResourcesReservedFor == Agent || Item.ResourcesReservedFor == null), new Sequence(new Wrap(ReserveResources), new GetResourcesAct(Agent, Item.SelectedResources))), new Domain(() => Item.HasResources || Item.ResourcesReservedFor != null, true)); } if (Item.ItemType.Type == CraftItem.CraftType.Object) { if (!String.IsNullOrEmpty(Item.ItemType.CraftLocation)) { Tree = new Domain(IsNotCancelled, new Sequence( new Wrap(() => Creature.FindAndReserve(Item.ItemType.CraftLocation, Item.ItemType.CraftLocation)), getResources, new Domain(ResourceStateValid, new Sequence ( new GoToTaggedObjectAct(Agent) { Tag = Item.ItemType.CraftLocation, Teleport = true, TeleportOffset = new Vector3(0.5f, 0.0f, 0), ObjectName = Item.ItemType.CraftLocation, CheckForOcclusion = true }, new Wrap(() => DestroyResources(Item.Location.WorldPosition)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => Item.Progress, () => Item.Progress += Creature.Stats.BuildSpeed / Item.ItemType.BaseCraftTime, () => Item.Location.WorldPosition + Vector3.One * 0.5f, "Craft", null, true)), new CreateCraftItemAct(Voxel, Creature.AI, Item))), unreserveAct ) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false) ) | new Sequence(unreserveAct, false); } else { Tree = new Domain(IsNotCancelled, new Sequence( getResources, new Sequence(new Domain(ResourceStateValid, new Sequence( new GoToVoxelAct(Voxel, PlanAct.PlanType.Adjacent, Agent), new Wrap(() => DestroyResources(Item.Location.WorldPosition)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => Item.Progress, () => Item.Progress += Creature.Stats.BuildSpeed / Item.ItemType.BaseCraftTime, () => Item.Location.WorldPosition + Vector3.One * 0.5f, "Craft")) { Name = "Construct object." }, new CreateCraftItemAct(Voxel, Creature.AI, Item) ) )) )) | new Sequence(new Wrap(Creature.RestockAll), unreserveAct, false); } } else { if (!String.IsNullOrEmpty(Item.ItemType.CraftLocation)) { Tree = new Sequence( new Wrap(() => Creature.FindAndReserve(Item.ItemType.CraftLocation, Item.ItemType.CraftLocation)), getResources, new Domain(ResourceStateValid, new Sequence ( new GoToTaggedObjectAct(Agent) { Tag = Item.ItemType.CraftLocation, Teleport = true, TeleportOffset = new Vector3(0.5f, 0.0f, 0), ObjectName = Item.ItemType.CraftLocation, CheckForOcclusion = true }, new Wrap(() => DestroyResources(Agent.Position + MathFunctions.RandVector3Cube() * 0.5f)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => Creature.HitAndWait(true, () => 1.0f, () => Item.Progress, () => Item.Progress += Creature.Stats.BuildSpeed / Item.ItemType.BaseCraftTime, () => Agent.Position, Noise)) { Name = "Construct object." }, unreserveAct, new Wrap(CreateResources), new Wrap(Creature.RestockAll) )) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false) ) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false); } else { Tree = new Sequence( getResources, new Domain(ResourceStateValid, new Sequence( new Wrap(() => DestroyResources(Creature.Physics.Position + MathFunctions.RandVector3Cube() * 0.5f)), new Wrap(WaitForResources) { Name = "Wait for resources." }, new Wrap(() => Creature.HitAndWait(time, true, () => Creature.Physics.Position)) { Name = "Construct object." }, new Wrap(CreateResources)) ) ) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false); } } base.Initialize(); }
public override void Initialize() { Act unreserveAct = new Wrap(() => Creature.Unreserve(ItemType.CraftLocation)); float time = ItemType.BaseCraftTime / Creature.AI.Stats.BuffedInt; Act getResources = null; if (ItemType.SelectedResources == null || ItemType.SelectedResources.Count == 0) { getResources = new GetResourcesAct(Agent, ItemType.RequiredResources); } else { getResources = new GetResourcesAct(Agent, ItemType.SelectedResources); } if (ItemType.Type == CraftItem.CraftType.Object) { Tree = new Sequence( new Wrap(() => Creature.FindAndReserve(ItemType.CraftLocation, ItemType.CraftLocation)), getResources, new Sequence ( new GoToTaggedObjectAct(Agent) { Tag = ItemType.CraftLocation, Teleport = false, TeleportOffset = new Vector3(1, 0, 0), ObjectName = ItemType.CraftLocation }, new Wrap(() => Creature.HitAndWait(time, true, Creature.AI.Position)), new Wrap(DestroyResources), unreserveAct, new GoToVoxelAct(Voxel, PlanAct.PlanType.Adjacent, Agent), new CreateCraftItemAct(Voxel, Creature.AI, ItemType.Name) ) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false) ) | new Sequence(unreserveAct, false); } else { Tree = new Sequence( new Wrap(() => Creature.FindAndReserve(ItemType.CraftLocation, ItemType.CraftLocation)), getResources, new Sequence ( new GoToTaggedObjectAct(Agent) { Tag = ItemType.CraftLocation, Teleport = false, TeleportOffset = new Vector3(1, 0, 0), ObjectName = ItemType.CraftLocation }, new Wrap(() => Creature.HitAndWait(time, true, Agent.Position)), new Wrap(DestroyResources), unreserveAct, new Wrap(CreateResources), new Wrap(Creature.RestockAll) ) | new Sequence(unreserveAct, new Wrap(Creature.RestockAll), false) ) | new Sequence(unreserveAct, false); } base.Initialize(); }
public override IEnumerable <Status> Run() { foreach (var res in Agent.Blackboard.GetData <List <Resource> >(ResourceBlackboardName)) { if (!Creature.Inventory.Contains(res)) { yield return(Status.Fail); } } foreach (var status in Creature.HitAndWait(1.0f, true, () => Location.Coordinate.ToVector3() + Vector3.One * 0.5f)) { if (status == Status.Running) { yield return(status); } } foreach (var res in Agent.Blackboard.GetData <List <Resource> >(ResourceBlackboardName)) { var grabbed = Creature.Inventory.RemoveAndCreate(res, Inventory.RestockType.Any); if (grabbed == null) { yield return(Status.Fail); yield break; } else { // If the creature intersects the box, find a voxel adjacent to it that is free, and jump there to avoid getting crushed. if (Creature.Physics.BoundingBox.Intersects(Location.GetBoundingBox())) { var neighbors = VoxelHelpers.EnumerateAllNeighbors(Location.Coordinate) .Select(c => new VoxelHandle(Agent.World.ChunkManager, c)); var closest = VoxelHandle.InvalidHandle; var closestDist = float.MaxValue; foreach (var voxel in neighbors) { if (!voxel.IsValid) { continue; } float dist = (voxel.WorldPosition - Creature.Physics.Position).LengthSquared(); if (dist < closestDist && voxel.IsEmpty) { closestDist = dist; closest = voxel; } } if (closest.IsValid) { TossMotion teleport = new TossMotion(0.5f, 1.0f, Creature.Physics.GlobalTransform, closest.WorldPosition + Vector3.One * 0.5f); Creature.Physics.AnimationQueue.Add(teleport); } } // Todo: Shitbox - what happens if the player saves while this animation is in progress?? How is the OnComplete restored? var motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Location.Coordinate.ToVector3() + new Vector3(0.5f, 0.5f, 0.5f)); if (grabbed.GetRoot().GetComponent <Physics>().HasValue(out var grabbedPhysics)) { grabbedPhysics.CollideMode = Physics.CollisionMode.None; } grabbed.AnimationQueue.Add(motion); motion.OnComplete += () => grabbed.Die(); } if (Library.GetVoxelType(VoxelType).HasValue(out var vType)) { PlaceVoxel(Location, vType, Creature.Manager.World); } Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); yield return(Status.Success); yield break; } }
public override IEnumerable <Status> Run() { if (!Creature.Faction.WallBuilder.IsDesignation(Voxel)) { yield return(Status.Fail); yield break; } foreach (Status status in Creature.HitAndWait(1.0f, true, Voxel.Position)) { if (status == Status.Running) { yield return(status); } } Body grabbed = Creature.Inventory.RemoveAndCreate(Resource).FirstOrDefault(); if (grabbed == null) { yield return(Status.Fail); yield break; } else { if (Creature.Faction.WallBuilder.IsDesignation(Voxel)) { // If the creature intersects the box, find a voxel adjacent to it that is free, and jump there to avoid getting crushed. if (Creature.Physics.BoundingBox.Intersects(Voxel.GetBoundingBox())) { List <Voxel> neighbors = Voxel.Chunk.GetNeighborsEuclidean(Voxel); Voxel closest = null; float closestDist = float.MaxValue; foreach (Voxel voxel in neighbors) { float dist = (voxel.Position - Creature.Physics.Position).LengthSquared(); if (dist < closestDist && voxel.IsEmpty) { closestDist = dist; closest = voxel; } } if (closest != null) { TossMotion teleport = new TossMotion(0.5f, 1.0f, Creature.Physics.GlobalTransform, closest.Position + Vector3.One * 0.5f); Creature.Physics.AnimationQueue.Add(teleport); } } TossMotion motion = new TossMotion(1.0f, 2.0f, grabbed.LocalTransform, Voxel.Position + new Vector3(0.5f, 0.5f, 0.5f)); motion.OnComplete += grabbed.Die; grabbed.GetComponent <Physics>().CollideMode = Physics.CollisionMode.None; grabbed.AnimationQueue.Add(motion); WallBuilder put = Creature.Faction.WallBuilder.GetDesignation(Voxel); put.Put(Creature.Manager.World.ChunkManager); Creature.Faction.WallBuilder.Designations.Remove(put); Creature.Stats.NumBlocksPlaced++; Creature.AI.AddXP(1); yield return(Status.Success); } else { Creature.Inventory.Resources.AddItem(grabbed); grabbed.Die(); yield return(Status.Fail); } } }