public IEnumerable <Status> PerformStep(MoveAction Step) { var actionSpeed = GetAgentSpeed(Step.MoveType); switch (Step.MoveType) { #region Ride Elevator case MoveType.RideElevator: CleanupMinecart(); var shafts = Step.DestinationState.Tag as Elevators.ElevatorMoveState; if (shafts == null || shafts.Entrance == null || shafts.Entrance.IsDead || shafts.Exit == null || shafts.Exit.IsDead) { yield return(Status.Fail); } var shaft = shafts.Entrance.Shaft; if (shaft == null || shaft.Invalid) { yield return(Status.Fail); } if (!shaft.EnqueuDwarf(Agent, shafts)) { yield return(Status.Fail); } while (!shaft.ReadyToBoard(Agent)) { if (DeltaTime > 30.0f) { yield return(Status.Fail); // We waited too long. } if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Position, GetPathPoint(shafts.Entrance.GetContainingVoxel()), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } shaft.StartMotion(Agent); var grav = Creature.Physics.Gravity; //Creature.Physics.Gravity = Vector3.Zero; while (!shaft.AtDestination(Agent)) { if (shaft.Invalid) { yield return(Status.Fail); } SetCharacterMode(CharacterMode.Idle); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Red, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Red, 0.1f, false); } yield return(Status.Running); } DeltaTime = 0; foreach (var bit in Translate(Agent.Physics.LocalPosition, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (shaft.Invalid) { yield return(Status.Fail); } shaft.WaitForMe(Agent); SetCharacterMode(CharacterMode.Walking); if (Debugger.Switches.DebugElevators) { Drawer3D.DrawBox(shafts.Entrance.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(shafts.Exit.GetBoundingBox(), Color.Green, 0.1f, false); Drawer3D.DrawBox(Step.DestinationVoxel.GetBoundingBox(), Color.Green, 0.1f, false); } yield return(Status.Running); } Creature.Physics.Gravity = grav; shaft.Done(Agent); break; #endregion case MoveType.EnterVehicle: Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); foreach (var bit in Jump(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), Step.DestinationVoxel.Center - Step.SourceVoxel.Center, actionSpeed, 1.5f)) { SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } DeltaTime = 0.0f; SetupMinecart(); break; case MoveType.ExitVehicle: CleanupMinecart(); SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); break; case MoveType.RideVehicle: SetupMinecart(); var rail = Step.SourceState.Rail; if (rail == null) { yield return(Status.Fail); } var rideTime = 1.0f / actionSpeed; while (DeltaTime < rideTime) { var pos = rail.InterpolateSpline(DeltaTime / rideTime, Step.SourceVoxel.WorldPosition, Step.DestinationVoxel.WorldPosition); var transform = Agent.Physics.LocalTransform; transform.Translation = pos + Vector3.Up * 0.5f; Agent.Physics.LocalTransform = transform; Agent.Physics.Velocity = GetPathPoint(Step.DestinationVoxel) - GetPathPoint(Step.SourceVoxel); SetCharacterMode(CharacterMode.Minecart); transform.Translation = pos + Vector3.Up * -0.1f; if (Minecart != null) { Minecart.LocalTransform = transform; } yield return(Status.Running); } DeltaTime -= rideTime; break; case MoveType.Walk: // Todo: Fail if distance is too great. CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Walking); yield return(Status.Running); } break; case MoveType.Swim: CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { Creature.NoiseMaker.MakeNoise("Swim", Agent.Position, true); SetCharacterMode(CharacterMode.Swimming); yield return(Status.Running); } break; case MoveType.Jump: { CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); var dest = GetPathPoint(Step.DestinationVoxel); var above = VoxelHelpers.GetVoxelAbove(Step.SourceVoxel); if (above.IsValid && !above.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f, 0.0f)) { Creature.Physics.CollisionType = CollisionType.None; Creature.OverrideCharacterMode = false; SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } SetAgentTranslation(dest); break; } case MoveType.HighJump: { CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); var dest = GetPathPoint(Step.DestinationVoxel); var above = VoxelHelpers.GetVoxelAbove(Step.SourceVoxel); if (above.IsValid && !above.IsEmpty) { yield return(Status.Fail); } foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f, 1.5f)) { Creature.Physics.CollisionType = CollisionType.None; Creature.OverrideCharacterMode = false; SetCharacterMode(Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling); yield return(Status.Running); } SetAgentTranslation(dest); break; } case MoveType.Fall: CleanupMinecart(); foreach (var bit in Translate(Agent.Position, GetPathPoint(Step.DestinationVoxel), actionSpeed)) { SetCharacterMode(CharacterMode.Falling); yield return(Status.Running); } break; case MoveType.Climb: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); yield return(Status.Running); } break; case MoveType.ClimbWalls: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if (DeltaTime - LastNoiseTime > 1.0f) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); LastNoiseTime = DeltaTime; } SetCharacterMode(CharacterMode.Climbing); if (Step.ActionVoxel.IsValid) { var voxelVector = new Vector3(Step.ActionVoxel.Coordinate.X + 0.5f, Agent.Physics.Position.Y, Step.ActionVoxel.Coordinate.Z + 0.5f); Agent.Physics.Velocity = Vector3.Normalize(voxelVector - Agent.Physics.Position) * actionSpeed; } yield return(Status.Running); } break; case MoveType.Fly: CleanupMinecart(); DeltaTime = 0.0f; foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) { if ((int)(DeltaTime * 100) % 2 == 0) { Creature.NoiseMaker.MakeNoise("Flap", Agent.Position, false); } SetCharacterMode(CharacterMode.Flying); yield return(Status.Running); } break; case MoveType.Dig: CleanupMinecart(); var destroy = new DigAct(Creature.AI, new KillVoxelTask(Step.DestinationVoxel)) { CheckOwnership = false }; destroy.Initialize(); foreach (var status in destroy.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop digging if a path has opened. break; case MoveType.DestroyObject: CleanupMinecart(); var melee = new AttackAct(Creature.AI, (GameComponent)Step.InteractObject); melee.Initialize(); foreach (var status in melee.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); // Abort the path so that they stop destroying things if a path has opened. break; case MoveType.Teleport: CleanupMinecart(); if (Step.InteractObject == null || Step.InteractObject.IsDead) { yield return(Status.Fail); } if (Step.InteractObject.GetComponent <MagicalObject>().HasValue(out var teleporter)) { teleporter.CurrentCharges--; } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, Agent.Position, true, 1.0f); Agent.World.ParticleManager.Trigger("green_flame", (Step.InteractObject as GameComponent).Position, Color.White, 1); //Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, false); { var source = GetPathPoint(Step.SourceVoxel); var dest = GetPathPoint(Step.DestinationVoxel); var delta = dest - source; var steps = delta.Length() * 2.0f; delta.Normalize(); delta *= 0.5f; for (var i = 0; i <= steps; ++i) { Agent.World.ParticleManager.Trigger("star_particle", source, Color.White, 1); source += delta; } } //foreach (var bit in Translate(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel), actionSpeed)) //{ // Agent.World.ParticleManager.Trigger("star_particle", Agent.Position, Color.White, 1); // yield return Status.Running; //} SetAgentTranslation(GetPathPoint(Step.DestinationVoxel)); //Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true); yield return(Status.Running); break; } }
public IEnumerable <Status> PerformCurrentAction() { MoveAction action = Path.First(); float t = 0; int currentIndex = 0; if (!GetCurrentAction(ref action, ref t, ref currentIndex)) { CleanupMinecart(); yield break; } //Trace.Assert(t >= 0); Trace.Assert(action.SourceVoxel.IsValid); int nextID = currentIndex + 1; bool hasNextAction = false; Vector3 half = GetBoundingBoxOffset(); Vector3 nextPosition = Vector3.Zero; Vector3 currPosition = action.SourceVoxel.WorldPosition + half; currPosition += RandomPositionOffsets[currentIndex]; if (nextID < Path.Count) { hasNextAction = true; nextPosition = Path[nextID].SourceVoxel.WorldPosition; nextPosition += RandomPositionOffsets[nextID] + half; } else { hasNextAction = true; nextPosition = action.DestinationVoxel.WorldPosition + half; } Matrix transform = Agent.Physics.LocalTransform; Vector3 diff = (nextPosition - currPosition); Agent.GetRoot().SetFlag(GameComponent.Flag.Visible, true); switch (action.MoveType) { case MoveType.EnterVehicle: if (t < 0.5f) { Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling; if (hasNextAction) { float z = Easing.Ballistic(t, 1.0f, 1.0f); Vector3 start = currPosition; Vector3 end = nextPosition + Vector3.Up * 0.5f; Vector3 dx = (end - start) * t + start; dx.Y = start.Y * (1 - t) + end.Y * (t) + z; transform.Translation = dx; Agent.Physics.Velocity = new Vector3(diff.X, (dx.Y - Agent.Physics.Position.Y), diff.Z); } else { transform.Translation = currPosition; } if (t > 0.9f) { SetupMinecart(); } break; case MoveType.ExitVehicle: CleanupMinecart(); transform.Translation = currPosition; break; case MoveType.RideVehicle: SetupMinecart(); Creature.CurrentCharacterMode = CharacterMode.Minecart; var rail = action.SourceState.VehicleState.Rail; if (rail == null) { if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } } else { //Drawer3D.DrawBox(rail.GetContainingVoxel().GetBoundingBox(), Color.Green, 0.1f, true); var pos = rail.InterpolateSpline(t, action.SourceVoxel.WorldPosition + Vector3.One * 0.5f, action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f); transform.Translation = pos + Vector3.Up * 0.5f; Agent.Physics.Velocity = diff; } break; case MoveType.Walk: CleanupMinecart(); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Walking; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Swim: CleanupMinecart(); Creature.NoiseMaker.MakeNoise("Swim", Agent.Position, true); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Swimming; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Jump: CleanupMinecart(); if (t < 0.5f) { Creature.NoiseMaker.MakeNoise("Jump", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = Creature.Physics.Velocity.Y > 0 ? CharacterMode.Jumping : CharacterMode.Falling; if (hasNextAction) { float z = Easing.Ballistic(t, 1.0f, 1.0f); Vector3 start = currPosition; Vector3 end = nextPosition; Vector3 dx = (end - start) * t + start; dx.Y = start.Y * (1 - t) + end.Y * (t) + z; transform.Translation = dx; Agent.Physics.Velocity = new Vector3(diff.X, (dx.Y - Agent.Physics.Position.Y), diff.Z); } else { transform.Translation = currPosition; } break; case MoveType.Fall: CleanupMinecart(); Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Falling; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Climb: case MoveType.ClimbWalls: CleanupMinecart(); if (((int)((t + 1) * 100)) % 50 == 0) { Creature.NoiseMaker.MakeNoise("Climb", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Climbing; Creature.OverrideCharacterMode = true; if (hasNextAction) { if (action.MoveType == MoveType.ClimbWalls && action.ActionVoxel.IsValid) { Agent.Physics.Velocity = (action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) - currPosition; transform.Translation = diff * t + currPosition; } else if (action.MoveType == MoveType.Climb && action.InteractObject != null) { var ladderPosition = action.InteractObject.GetRoot().GetComponent <Body>().Position; transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = ladderPosition - currPosition; } } else { transform.Translation = currPosition; } break; case MoveType.Fly: CleanupMinecart(); if (((int)((t + 1) * 100)) % 2 == 0) { Creature.NoiseMaker.MakeNoise("Flap", Agent.Position, false); } Creature.OverrideCharacterMode = false; Creature.CurrentCharacterMode = CharacterMode.Flying; Creature.OverrideCharacterMode = true; if (hasNextAction) { transform.Translation = diff * t + currPosition; Agent.Physics.Velocity = diff; } else { transform.Translation = currPosition; } break; case MoveType.Dig: CleanupMinecart(); var destroy = new DigAct(Creature.AI, new KillVoxelTask(action.DestinationVoxel)) { CheckOwnership = false }; destroy.Initialize(); foreach (var status in destroy.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Fail); yield break; case MoveType.DestroyObject: CleanupMinecart(); var melee = new MeleeAct(Creature.AI, (Body)action.InteractObject); melee.Initialize(); foreach (var status in melee.Run()) { if (status == Act.Status.Fail) { yield return(Act.Status.Fail); } yield return(Act.Status.Running); } yield return(Act.Status.Success); yield break; case MoveType.Teleport: if (lastMovement != MoveType.Teleport) { if (action.InteractObject != null) { var teleporter = action.InteractObject.GetComponent <MagicalObject>(); if (teleporter != null) { teleporter.CurrentCharges--; } } SoundManager.PlaySound(ContentPaths.Audio.Oscar.sfx_ic_dwarf_magic_research, currPosition, true, 1.0f); } Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, false); Agent.World.ParticleManager.Trigger("star_particle", diff * t + currPosition, Color.White, 1); if (action.InteractObject != null) { Agent.World.ParticleManager.Trigger("green_flame", (action.InteractObject as Body).Position, Color.White, 1); } transform.Translation = action.DestinationVoxel.WorldPosition + Vector3.One * 0.5f; break; } Agent.Physics.LocalTransform = transform; lastMovement = action.MoveType; }