示例#1
0
        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.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;
        }
示例#2
0
        public IEnumerable <Status> FindGreedyPath()
        {
            Vector3 target = Target.Position;

            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }
            List <MoveAction> path = new List <MoveAction>();
            var curr = Creature.Physics.CurrentVoxel;

            for (int i = 0; i < PathLength; i++)
            {
                IEnumerable <MoveAction> actions =
                    Creature.AI.Movement.GetMoveActions(curr);

                MoveAction?bestAction = null;
                float      bestDist   = float.MaxValue;

                foreach (MoveAction action in actions)
                {
                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared();

                    if (dist < bestDist)
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                Vector3 half = Vector3.One * 0.5f;
                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType))
                {
                    path.Add(bestAction.Value);
                    MoveAction action = bestAction.Value;
                    action.DestinationVoxel = curr;
                    curr       = bestAction.Value.DestinationVoxel;
                    bestAction = action;

                    if (((bestAction.Value.DestinationVoxel.WorldPosition + half) - target).Length() < Threshold)
                    {
                        break;
                    }
                }
            }

            if (path.Count > 0)
            {
                path.Insert(0,
                            new MoveAction()
                {
                    Diff             = Vector3.Zero,
                    DestinationVoxel = path[0].SourceVoxel,
                    SourceVoxel      = Creature.Physics.CurrentVoxel,
                    MoveType         = MoveType.Walk
                });
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
示例#3
0
        public IEnumerable <Status> PerformStep(MoveAction Step)
        {
            var actionSpeed = GetAgentSpeed(Step.MoveType);

            switch (Step.MoveType)
            {
                #region Ride Elevator
            case MoveType.RideElevator:

                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))
                {
                    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);
                }

                while (DeltaTime < 1.0f / actionSpeed)
                {
                    var pos       = rail.InterpolateSpline(DeltaTime, GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel));
                    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);
                    yield return(Status.Running);
                }
                DeltaTime -= (1.0f / actionSpeed);

                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(GetPathPoint(Step.SourceVoxel), GetPathPoint(Step.DestinationVoxel) + (0.5f * Vector3.Up * Agent.Physics.BoundingBox.Extents().Y), 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);
                foreach (var bit in Jump(Agent.Position, dest, dest - Agent.Position, actionSpeed / 2.0f))
                {
                    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 MeleeAct(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:

                if (Step.InteractObject == null || Step.InteractObject.IsDead)
                {
                    yield return(Status.Fail);
                }

                var teleporter = Step.InteractObject.GetComponent <MagicalObject>();
                if (teleporter != null)
                {
                    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);

                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);
                }

                Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true);
                break;
            }
        }
示例#4
0
        public IEnumerable <Act.Status> GreedyFallbackBehavior(Creature agent)
        {
            var edgeGoal = new EdgeGoalRegion();

            while (true)
            {
                DieTimer.Update(DwarfTime.LastTime);
                if (DieTimer.HasTriggered)
                {
                    foreach (var status in Die(agent))
                    {
                        continue;
                    }
                    yield break;
                }
                var creatureVoxel      = agent.Physics.CurrentVoxel;
                List <MoveAction> path = new List <MoveAction>();
                var storage            = new MoveActionTempStorage();
                for (int i = 0; i < 10; i++)
                {
                    if (edgeGoal.IsInGoalRegion(creatureVoxel))
                    {
                        foreach (var status in Die(agent))
                        {
                            continue;
                        }
                        yield return(Act.Status.Success);

                        yield break;
                    }

                    var actions = agent.AI.Movement.GetMoveActions(new MoveState {
                        Voxel = creatureVoxel
                    }, new List <GameComponent>(), storage);

                    float minCost      = float.MaxValue;
                    var   minAction    = new MoveAction();
                    bool  hasMinAction = false;
                    foreach (var action in actions)
                    {
                        var vox = action.DestinationVoxel;

                        float cost = edgeGoal.Heuristic(vox) * 10 + MathFunctions.Rand(0.0f, 0.1f) + agent.AI.Movement.Cost(action.MoveType);

                        if (cost < minCost)
                        {
                            minAction    = action;
                            minCost      = cost;
                            hasMinAction = true;
                        }
                    }

                    if (hasMinAction)
                    {
                        path.Add(minAction);
                        creatureVoxel = minAction.DestinationVoxel;
                    }
                    else
                    {
                        foreach (var status in Die(agent))
                        {
                            continue;
                        }
                        yield return(Act.Status.Success);

                        yield break;
                    }
                }
                if (path.Count == 0)
                {
                    foreach (var status in Die(agent))
                    {
                        continue;
                    }
                    yield return(Act.Status.Success);

                    yield break;
                }
                agent.AI.Blackboard.SetData("GreedyPath", path);
                var pathAct = new FollowPathAct(agent.AI, "GreedyPath");
                pathAct.Initialize();

                foreach (Act.Status status in pathAct.Run())
                {
                    yield return(Act.Status.Running);
                }
                yield return(Act.Status.Running);
            }
        }
示例#5
0
        public IEnumerable <Status> AvoidTarget(float range, float time)
        {
            if (Target == null)
            {
                yield return(Status.Fail);

                yield break;
            }
            Timer avoidTimer = new Timer(time, true, Timer.TimerMode.Game);

            while (true)
            {
                avoidTimer.Update(DwarfTime.LastTime);

                if (avoidTimer.HasTriggered)
                {
                    yield return(Status.Success);
                }

                float dist = (Target.Position - Agent.Position).Length();

                if (dist > range)
                {
                    yield return(Status.Success);

                    yield break;
                }

                List <MoveAction> neighbors = Agent.Movement.GetMoveActions(Agent.Position).ToList();
                neighbors.Sort((a, b) =>
                {
                    if (a.Equals(b))
                    {
                        return(0);
                    }

                    float da = (a.DestinationVoxel.WorldPosition - Target.Position).LengthSquared();
                    float db = (b.DestinationVoxel.WorldPosition - Target.Position).LengthSquared();

                    return(da.CompareTo(db));
                });

                neighbors.RemoveAll(
                    a => a.MoveType == MoveType.Jump || a.MoveType == MoveType.Climb);

                if (neighbors.Count == 0)
                {
                    yield return(Status.Fail);

                    yield break;
                }

                MoveAction furthest      = neighbors.Last();
                bool       reachedTarget = false;
                Timer      timeout       = new Timer(2.0f, true);
                while (!reachedTarget)
                {
                    Vector3 output = Creature.Controller.GetOutput(DwarfTime.Dt, furthest.DestinationVoxel.WorldPosition + Vector3.One * 0.5f,
                                                                   Agent.Position);
                    Creature.Physics.ApplyForce(output, DwarfTime.Dt);

                    if (Creature.AI.Movement.CanFly)
                    {
                        Creature.Physics.ApplyForce(Vector3.Up * 10, DwarfTime.Dt);
                    }

                    timeout.Update(DwarfTime.LastTime);

                    yield return(Status.Running);

                    if (timeout.HasTriggered || (furthest.DestinationVoxel.WorldPosition - Agent.Position).Length() < 1)
                    {
                        reachedTarget = true;
                    }
                    Agent.Creature.CurrentCharacterMode = CharacterMode.Walking;
                }
                yield return(Status.Success);

                yield break;
            }
        }
示例#6
0
        public List <MoveAction> ComputeGreedyFallback(int maxsteps = 10, List <VoxelHandle> exploredVoxels = null)
        {
            List <MoveAction> toReturn = new List <MoveAction>();
            GoalRegion        goal     = GetGoal();
            var creatureVoxel          = Agent.Physics.CurrentVoxel;

            if (goal.IsInGoalRegion(creatureVoxel))
            {
                return(toReturn);
            }
            var currentVoxel = creatureVoxel;

            while (toReturn.Count < maxsteps)
            {
                var actions = Agent.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = currentVoxel
                }, Creature.World.OctTree);

                float minCost      = float.MaxValue;
                var   minAction    = new MoveAction();
                bool  hasMinAction = false;

                foreach (var action in actions)
                {
                    if (toReturn.Any(a => a.DestinationVoxel == action.DestinationVoxel && a.MoveType == action.MoveType))
                    {
                        continue;
                    }

                    var vox = action.DestinationVoxel;

                    float cost = goal.Heuristic(vox) * MathFunctions.Rand(1.0f, 1.1f) + Agent.Movement.Cost(action.MoveType);
                    if (exploredVoxels != null && exploredVoxels.Contains(action.DestinationVoxel))
                    {
                        cost *= 10;
                    }

                    if (cost < minCost)
                    {
                        minAction    = action;
                        minCost      = cost;
                        hasMinAction = true;
                    }
                }

                if (hasMinAction)
                {
                    MoveAction action = minAction;
                    action.DestinationVoxel = currentVoxel;
                    toReturn.Add(action);
                    currentVoxel = minAction.DestinationVoxel;
                    if (goal.IsInGoalRegion(minAction.DestinationVoxel))
                    {
                        return(toReturn);
                    }
                }
                else
                {
                    return(toReturn);
                }
            }
            return(toReturn);
        }
示例#7
0
        /// <summary> gets the list of actions that the creature can take from a given voxel. </summary>
        public IEnumerable <MoveAction> GetMoveActions(MoveState state, OctTreeNode <Body> OctTree, List <Body> teleportObjects, MoveActionTempStorage Storage)
        {
            if (Parent == null)
            {
                yield break;
            }

            if (!state.Voxel.IsValid)
            {
                yield break;
            }

            if (Creature == null)
            {
                yield break;
            }

            if (Storage == null)
            {
                Storage = new MoveActionTempStorage();
            }

            GetNeighborhood(state.Voxel.Chunk.Manager.ChunkData, state.Voxel, Storage.Neighborhood);

            bool inWater          = (Storage.Neighborhood[1, 1, 1].IsValid && Storage.Neighborhood[1, 1, 1].LiquidLevel > WaterManager.inWaterThreshold);
            bool standingOnGround = (Storage.Neighborhood[1, 0, 1].IsValid && !Storage.Neighborhood[1, 0, 1].IsEmpty);
            bool topCovered       = (Storage.Neighborhood[1, 2, 1].IsValid && !Storage.Neighborhood[1, 2, 1].IsEmpty);
            bool hasNeighbors     = HasNeighbors(Storage.Neighborhood);
            bool isRiding         = state.VehicleState.IsRidingVehicle;

            var neighborHoodBounds = new BoundingBox(Storage.Neighborhood[0, 0, 0].GetBoundingBox().Min, Storage.Neighborhood[2, 2, 2].GetBoundingBox().Max);

            Storage.NeighborObjects.Clear();
            OctTree.EnumerateItems(neighborHoodBounds, Storage.NeighborObjects);

            if (Can(MoveType.Teleport))
            {
                foreach (var obj in teleportObjects)
                {
                    if ((obj.Position - state.Voxel.WorldPosition).LengthSquared() < TeleportDistanceSquared)
                    {
                        yield return new MoveAction()
                               {
                                   InteractObject   = obj,
                                   MoveType         = MoveType.Teleport,
                                   SourceVoxel      = state.Voxel,
                                   DestinationState = new MoveState()
                                   {
                                       Voxel = new VoxelHandle(state.Voxel.Chunk.Manager.ChunkData, GlobalVoxelCoordinate.FromVector3(obj.Position))
                                   }
                               }
                    }
                }
            }
            ;

            var successors = EnumerateSuccessors(state, state.Voxel, Storage, inWater, standingOnGround, topCovered, hasNeighbors, isRiding);

            // Now, validate each move action that the creature might take.
            foreach (MoveAction v in successors)
            {
                var n = v.DestinationVoxel.IsValid ? v.DestinationVoxel : Storage.Neighborhood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z];
                if (n.IsValid && (v.MoveType == MoveType.Dig || isRiding || n.IsEmpty || n.LiquidLevel > 0))
                {
                    // Do one final check to see if there is an object blocking the motion.
                    bool blockedByObject = false;
                    if (!isRiding)
                    {
                        var objectsAtNeighbor = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(n.GetBoundingBox()));

                        // If there is an object blocking the motion, determine if it can be passed through.

                        foreach (var body in objectsAtNeighbor)
                        {
                            var door = body as Door;
                            // ** Doors are in the octtree, pretty sure this was always pointless -- var door = body.GetRoot().EnumerateAll().OfType<Door>().FirstOrDefault();
                            // If there is an enemy door blocking movement, we can destroy it to get through.
                            if (door != null)
                            {
                                if (
                                    Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction)
                                    .GetCurrentRelationship() ==
                                    Relationship.Hateful)
                                {
                                    if (Can(MoveType.DestroyObject))
                                    {
                                        yield return(new MoveAction
                                        {
                                            Diff = v.Diff,
                                            MoveType = MoveType.DestroyObject,
                                            InteractObject = door,
                                            DestinationVoxel = n,
                                            SourceState = state
                                        });
                                    }
                                    blockedByObject = true;
                                }
                            }
                        }
                    }

                    // If no object blocked us, we can move freely as normal.
                    if (!blockedByObject && n.LiquidType != LiquidType.Lava)
                    {
                        MoveAction newAction = v;
                        newAction.SourceState      = state;
                        newAction.DestinationVoxel = n;
                        yield return(newAction);
                    }
                }
            }
        }
示例#8
0
        public IEnumerable <MoveAction> GetInverseMoveActions_Experimental(VoxelHandle voxel)
        {
            if (!voxel.IsValid || !voxel.IsEmpty)
            {
                yield break;
            }

            CollisionManager objectHash = Creature.Manager.World.CollisionManager;

            var  neighborHood     = GetNeighborhood(voxel);
            bool inWater          = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold);
            bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty);
            bool topCovered       = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty);
            bool hasNeighbors     = HasNeighbors(neighborHood);
            bool isClimbing       = false;

            var successors = new List <MoveAction>();

            if (CanClimb)
            {
                var ladderAt    = GetBodyAt(voxel, objectHash, "Climbable");
                var ladderAbove = GetBodyAt(VoxelHelpers.GetVoxelAbove(voxel), objectHash, "Climbable");
                var ladderBelow = GetBodyAt(VoxelHelpers.GetNeighbor(voxel, new GlobalVoxelOffset(0, -1, 0)), objectHash, "Climbable");
                // If there was a ladder above the creature, we could have climbed down it to get here.
                if (ladderAbove != null)
                {
                    successors.Add(new MoveAction
                    {
                        Diff           = new Vector3(1, 2, 1),
                        MoveType       = MoveType.Climb,
                        InteractObject = ladderAbove
                    });
                }

                // If there was a ladder below the creature, we could have climbed up to get here.
                if (ladderBelow != null)
                {
                    successors.Add(new MoveAction
                    {
                        Diff           = new Vector3(1, 0, 1),
                        MoveType       = MoveType.Climb,
                        InteractObject = ladderBelow
                    });
                }

                if (ladderAt != null)
                {
                    standingOnGround = true;
                    isClimbing       = true;
                }
            }

            // If the creature can climb walls, check to see if there are any walls nearby that we could have climbed here from.
            if (CanClimbWalls && !topCovered)
            {
                // First check the voxel above to see if it has any walls nearby.
                if (!topCovered)
                {
                    var wallsAbove = new VoxelHandle[]
                    {
                        neighborHood[2, 2, 1], neighborHood[0, 2, 1], neighborHood[1, 2, 2],
                        neighborHood[1, 2, 0]
                    };
                    var wallAbove = VoxelHandle.InvalidHandle;
                    foreach (var w in wallsAbove)
                    {
                        if (w.IsValid && !w.IsEmpty)
                        {
                            wallAbove = w;
                            break;
                        }
                    }


                    // If there was a wall above us, we could have climbed down to get here.
                    if (wallAbove.IsValid)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff        = new Vector3(1, 2, 1),
                            MoveType    = MoveType.ClimbWalls,
                            ActionVoxel = wallAbove
                        });
                    }
                }

                // Now check the walls below
                if (!standingOnGround)
                {
                    var wallsBelow = new VoxelHandle[]
                    {
                        neighborHood[2, 0, 1], neighborHood[0, 0, 1], neighborHood[1, 0, 2],
                        neighborHood[1, 0, 0]
                    };
                    var wallBelow = VoxelHandle.InvalidHandle;
                    foreach (var w in wallsBelow)
                    {
                        if (w.IsValid && !w.IsEmpty)
                        {
                            wallBelow = w;
                            break;
                        }
                    }


                    // If there was a wall below us, we could have climbed up to get here.
                    if (wallBelow.IsValid)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff        = new Vector3(1, 0, 1),
                            MoveType    = MoveType.ClimbWalls,
                            ActionVoxel = wallBelow
                        });
                    }
                }
            }

            // If the creature either can walk or is in water, add the
            // eight-connected free neighbors around the voxel.
            if (CanWalk || CanSwim)
            {
                // If the creature is in water, it can swim. Otherwise, it will walk.
                var moveType = inWater ? MoveType.Swim : MoveType.Walk;
                if (neighborHood[0, 1, 1].IsValid &&
                    neighborHood[0, 1, 1].IsEmpty)
                {
                    if (moveType == MoveType.Swim || (neighborHood[0, 0, 1].IsValid &&
                                                      !neighborHood[0, 0, 1].IsEmpty))
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(0, 1, 1),
                            MoveType = moveType
                        });
                    }
                }

                if (neighborHood[2, 1, 1].IsValid && neighborHood[2, 1, 1].IsEmpty)
                {
                    if (moveType == MoveType.Swim || (neighborHood[2, 0, 1].IsValid &&
                                                      !neighborHood[2, 0, 1].IsEmpty))
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(2, 1, 1),
                            MoveType = moveType
                        });
                    }
                }


                if (neighborHood[1, 1, 0].IsValid && neighborHood[1, 1, 0].IsEmpty)
                {
                    if (moveType == MoveType.Swim || (neighborHood[1, 0, 0].IsValid &&
                                                      !neighborHood[1, 0, 0].IsEmpty))
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(1, 1, 0),
                            MoveType = moveType
                        });
                    }
                }

                if (neighborHood[1, 1, 2].IsValid && neighborHood[1, 1, 2].IsEmpty)
                {
                    if (moveType == MoveType.Swim || (neighborHood[1, 0, 2].IsValid &&
                                                      !neighborHood[1, 0, 2].IsEmpty))
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(1, 1, 2),
                            MoveType = moveType
                        });
                    }
                }

                // Only bother worrying about 8-connected movement if there are
                // no full neighbors around the voxel.
                if (!hasNeighbors)
                {
                    if (neighborHood[2, 1, 2].IsValid && neighborHood[2, 1, 2].IsEmpty)
                    {
                        if (moveType == MoveType.Swim || (neighborHood[2, 0, 2].IsValid &&
                                                          !neighborHood[2, 0, 2].IsEmpty))
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(2, 1, 2),
                                MoveType = moveType
                            });
                        }
                    }

                    if (neighborHood[2, 1, 0].IsValid && neighborHood[2, 1, 0].IsEmpty)
                    {
                        if (moveType == MoveType.Swim || (neighborHood[2, 0, 0].IsValid &&
                                                          !neighborHood[2, 0, 0].IsEmpty))
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(2, 1, 0),
                                MoveType = moveType
                            });
                        }
                    }

                    if (neighborHood[0, 1, 2].IsValid && neighborHood[0, 1, 2].IsEmpty)
                    {
                        if (moveType == MoveType.Swim || (neighborHood[0, 0, 2].IsValid &&
                                                          !neighborHood[0, 0, 2].IsEmpty))
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(0, 1, 2),
                                MoveType = moveType
                            });
                        }
                    }

                    if (neighborHood[0, 1, 0].IsValid && neighborHood[0, 1, 0].IsEmpty)
                    {
                        if (moveType == MoveType.Swim || (neighborHood[0, 0, 0].IsValid &&
                                                          !neighborHood[0, 0, 0].IsEmpty))
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(0, 1, 0),
                                MoveType = moveType
                            });
                        }
                    }
                }
            }

            // Now a somewhat tricky part. We've got to figure out which cells can jump to this cell.
            // The rules for jumping are as follows:
            // 1) The voxel must be exactly 1 below this one.
            // 2) The voxel must be exactly 1 away in the other dimensions
            // 3) The voxel above the one we're jumping from must be free.
            // 4) The voxel below the one we're jumping from must be filled, or be in water, or
            //    must be part of a climb action.
            // Step 4 is really hard, so let's ignore it for now.

            // First, check the 3x3 neighborhood around the voxel.
            if (standingOnGround)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        // Ignore the current voxel (can't jump from there)
                        if (dx == 1 && dz == 1)
                        {
                            continue;
                        }
                        // Can't jump from neighbor because neighbor's head isn't clear.
                        if (!(neighborHood[dx, 1, dz].IsValid && neighborHood[dx, 1, dz].IsEmpty))
                        {
                            continue;
                        }

                        // Now just assume we can jump from the neighbor below us. TODO (step 4)
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(dx, 0, dz),
                            MoveType = MoveType.Jump
                        });
                    }
                }
            }


            // If the creature is not in water and is not standing on ground,
            // it can fall one voxel downward in free space. So check the voxel above,
            // if it is free and has no water, then we could have fallen from it.
            if (neighborHood[1, 2, 1].IsValid && neighborHood[1, 2, 1].IsEmpty && neighborHood[1, 2, 1].WaterCell.WaterLevel == 0)
            {
                successors.Add(new MoveAction
                {
                    Diff     = new Vector3(1, 2, 1),
                    MoveType = MoveType.Fall
                });
            }

            // If the creature can fly and is not underwater, it can fly
            // to any adjacent empty cell. Luckily this is reversible so we don't have to change
            // anything from GetMoveactions
            if (CanFly && !inWater)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        for (int dy = 0; dy <= 2; dy++)
                        {
                            if (dx == 1 && dz == 1 && dy == 1)
                            {
                                continue;
                            }

                            if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty)
                            {
                                successors.Add(new MoveAction
                                {
                                    Diff     = new Vector3(dx, dy, dz),
                                    MoveType = MoveType.Fly
                                });
                            }
                        }
                    }
                }
            }

            // Now, validate each move action that the creature might take.
            foreach (MoveAction v in successors)
            {
                var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z];
                if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0))
                {
                    // Do one final check to see if there is an object blocking the motion.
                    bool blockedByObject   = false;
                    var  objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects(
                        n.GetBoundingBox(), CollisionManager.CollisionType.Static);

                    // If there is an object blocking the motion, determine if it can be passed through.

                    foreach (var body in objectsAtNeighbor.OfType <GameComponent>())
                    {
                        var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault();
                        // If there is an enemy door blocking movement, we can destroy it to get through.
                        if (door != null)
                        {
                            if (
                                Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction)
                                .GetCurrentRelationship() !=
                                Relationship.Loving)
                            {
                                if (Can(MoveType.DestroyObject))
                                {
                                    yield return(new MoveAction
                                    {
                                        Diff = -(v.Diff - Vector3.One),
                                        MoveType = MoveType.DestroyObject,
                                        InteractObject = door,
                                        DestinationVoxel = voxel,
                                        SourceVoxel = n
                                    });
                                }
                                blockedByObject = true;
                            }
                        }
                    }

                    // If no object blocked us, we can move freely as normal.
                    if (!blockedByObject)
                    {
                        MoveAction newAction = v;
                        newAction.Diff             = -(v.Diff - Vector3.One);
                        newAction.DestinationVoxel = voxel;
                        newAction.SourceVoxel      = n;
                        yield return(newAction);
                    }
                }
            }
        }
示例#9
0
        public override IEnumerable <Status> Run()
        {
            InitializePath();
            if (Path == null || Path.Count == 0)
            {
                yield return(Act.Status.Success);
            }
            if (TrajectoryTimer == null)
            {
                yield break;
            }
            while (!TrajectoryTimer.HasTriggered)
            {
                Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true);
                TrajectoryTimer.Update(DwarfTime.LastTime);
                ValidPathTimer.Update(DwarfTime.LastTime);
                foreach (Status status in PerformCurrentAction())
                {
                    if (status == Status.Fail)
                    {
                        CleanupMinecart();
                        yield return(Status.Fail);
                    }
                    else if (status == Status.Success)
                    {
                        break;
                    }
                    Creature.Physics.AnimationQueue.Clear();
                    yield return(Status.Running);
                }

                if (Debugger.Switches.DrawPaths)
                {
                    List <Vector3> points =
                        Path.Select(
                            (v, i) => v.SourceVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f) + RandomPositionOffsets[i])
                        .ToList();
                    points.Add(Path[Path.Count - 1].DestinationVoxel.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f));

                    List <Color> colors =
                        Path.Select((v, i) =>
                    {
                        switch (v.MoveType)
                        {
                        case MoveType.Climb:
                            return(Color.Cyan);

                        case MoveType.ClimbWalls:
                            return(Color.DarkCyan);

                        case MoveType.DestroyObject:
                            return(Color.Orange);

                        case MoveType.Fall:
                            return(Color.LightBlue);

                        case MoveType.Fly:
                            return(Color.Green);

                        case MoveType.Jump:
                            return(Color.Yellow);

                        case MoveType.Swim:
                            return(Color.Blue);

                        case MoveType.Walk:
                            return(Color.Red);
                        }
                        return(Color.White);
                    })
                        .ToList();
                    colors.Add(Color.White);
                    Drawer3D.DrawLineList(points, colors, 0.1f);
                }

                float      t            = 0;
                int        currentIndex = 0;
                MoveAction action       = new MoveAction();
                if (GetCurrentAction(ref action, ref t, ref currentIndex))
                {
                    // Check if the path has been made invalid
                    if (ValidPathTimer.HasTriggered && !IsPathValid(Path, currentIndex))
                    {
                        Creature.OverrideCharacterMode = false;
                        Creature.DrawIndicator(IndicatorManager.StandardIndicators.Question);
                        CleanupMinecart();
                        Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true);
                        yield return(Status.Fail);
                    }
                }
                Creature.Physics.AnimationQueue.Clear();
                yield return(Status.Running);
            }
            Creature.OverrideCharacterMode = false;
            SetPath(null);
            Agent.GetRoot().SetFlagRecursive(GameComponent.Flag.Visible, true);
            CleanupMinecart();
            yield return(Status.Success);
        }
示例#10
0
        /// <summary> gets the list of actions that the creature can take from a given voxel. </summary>
        public IEnumerable <MoveAction> GetMoveActions(VoxelHandle voxel)
        {
            if (!voxel.IsValid || !voxel.IsEmpty)
            {
                yield break;
            }

            CollisionManager objectHash = Creature.Manager.World.CollisionManager;

            var  neighborHood     = GetNeighborhood(voxel);
            bool inWater          = (neighborHood[1, 1, 1].IsValid && neighborHood[1, 1, 1].WaterCell.WaterLevel > WaterManager.inWaterThreshold);
            bool standingOnGround = (neighborHood[1, 0, 1].IsValid && !neighborHood[1, 0, 1].IsEmpty);
            bool topCovered       = (neighborHood[1, 2, 1].IsValid && !neighborHood[1, 2, 1].IsEmpty);
            bool hasNeighbors     = HasNeighbors(neighborHood);
            bool isClimbing       = false;

            var successors = new List <MoveAction>();

            if (CanClimb)
            {
                //Climbing ladders.
                var bodies = objectHash.EnumerateIntersectingObjects(voxel.GetBoundingBox(), CollisionManager.CollisionType.Static).OfType <GameComponent>();

                var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable"));

                // if the creature can climb objects and a ladder is in this voxel,
                // then add a climb action.
                if (ladder != null)
                {
                    successors.Add(new MoveAction
                    {
                        Diff           = new Vector3(1, 2, 1),
                        MoveType       = MoveType.Climb,
                        InteractObject = ladder
                    });

                    isClimbing = true;

                    if (!standingOnGround)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff           = new Vector3(1, 0, 1),
                            MoveType       = MoveType.Climb,
                            InteractObject = ladder
                        });
                    }

                    standingOnGround = true;
                }
            }

            // If the creature can climb walls and is not blocked by a voxl above.
            if (CanClimbWalls && !topCovered)
            {
                var walls = new VoxelHandle[]
                {
                    neighborHood[2, 1, 1], neighborHood[0, 1, 1], neighborHood[1, 1, 2],
                    neighborHood[1, 1, 0]
                };

                var wall = VoxelHandle.InvalidHandle;
                foreach (var w in walls)
                {
                    if (w.IsValid && !w.IsEmpty)
                    {
                        wall = w;
                    }
                }

                if (wall.IsValid)
                {
                    isClimbing = true;
                    successors.Add(new MoveAction
                    {
                        Diff        = new Vector3(1, 2, 1),
                        MoveType    = MoveType.ClimbWalls,
                        ActionVoxel = wall
                    });

                    if (!standingOnGround)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff        = new Vector3(1, 0, 1),
                            MoveType    = MoveType.ClimbWalls,
                            ActionVoxel = wall
                        });
                    }
                }
            }

            // If the creature either can walk or is in water, add the
            // eight-connected free neighbors around the voxel.
            if ((CanWalk && standingOnGround) || (CanSwim && inWater))
            {
                // If the creature is in water, it can swim. Otherwise, it will walk.
                var moveType = inWater ? MoveType.Swim : MoveType.Walk;
                if (!neighborHood[0, 1, 1].IsValid || neighborHood[0, 1, 1].IsEmpty)
                {
                    // +- x
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(0, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[2, 1, 1].IsValid || neighborHood[2, 1, 1].IsEmpty)
                {
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(2, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[1, 1, 0].IsValid || neighborHood[1, 1, 0].IsEmpty)
                {
                    // +- z
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(1, 1, 0),
                        MoveType = moveType
                    });
                }

                if (!neighborHood[1, 1, 2].IsValid || neighborHood[1, 1, 2].IsEmpty)
                {
                    successors.Add(new MoveAction
                    {
                        Diff     = new Vector3(1, 1, 2),
                        MoveType = moveType
                    });
                }

                // Only bother worrying about 8-connected movement if there are
                // no full neighbors around the voxel.
                if (!hasNeighbors)
                {
                    if (!neighborHood[2, 1, 2].IsValid || neighborHood[2, 1, 2].IsEmpty)
                    {
                        // +x + z
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(2, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[2, 1, 0].IsValid || neighborHood[2, 1, 0].IsEmpty)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(2, 1, 0),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[0, 1, 2].IsValid || neighborHood[0, 1, 2].IsEmpty)
                    {
                        // -x -z
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(0, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!neighborHood[0, 1, 0].IsValid || neighborHood[0, 1, 0].IsEmpty)
                    {
                        successors.Add(new MoveAction
                        {
                            Diff     = new Vector3(0, 1, 0),
                            MoveType = moveType
                        });
                    }
                }
            }

            // If the creature's head is free, and it is standing on ground,
            // or if it is in water, or if it is climbing, it can also jump
            // to voxels that are 1 cell away and 1 cell up.
            if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing))
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        if (dx == 1 && dz == 1)
                        {
                            continue;
                        }

                        if (neighborHood[dx, 1, dz].IsValid && !neighborHood[dx, 1, dz].IsEmpty)
                        {
                            successors.Add(new MoveAction
                            {
                                Diff     = new Vector3(dx, 2, dz),
                                MoveType = MoveType.Jump
                            });
                        }
                    }
                }
            }


            // If the creature is not in water and is not standing on ground,
            // it can fall one voxel downward in free space.
            if (!inWater && !standingOnGround)
            {
                successors.Add(new MoveAction
                {
                    Diff     = new Vector3(1, 0, 1),
                    MoveType = MoveType.Fall
                });
            }

            // If the creature can fly and is not underwater, it can fly
            // to any adjacent empty cell.
            if (CanFly && !inWater)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        for (int dy = 0; dy <= 2; dy++)
                        {
                            if (dx == 1 && dz == 1 && dy == 1)
                            {
                                continue;
                            }

                            if (!neighborHood[dx, 1, dz].IsValid || neighborHood[dx, 1, dz].IsEmpty)
                            {
                                successors.Add(new MoveAction
                                {
                                    Diff     = new Vector3(dx, dy, dz),
                                    MoveType = MoveType.Fly
                                });
                            }
                        }
                    }
                }
            }

            // Now, validate each move action that the creature might take.
            foreach (MoveAction v in successors)
            {
                var n = neighborHood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z];
                if (n.IsValid && (n.IsEmpty || n.WaterCell.WaterLevel > 0))
                {
                    // Do one final check to see if there is an object blocking the motion.
                    bool blockedByObject   = false;
                    var  objectsAtNeighbor = Creature.Manager.World.CollisionManager.EnumerateIntersectingObjects(
                        n.GetBoundingBox(), CollisionManager.CollisionType.Static);

                    // If there is an object blocking the motion, determine if it can be passed through.

                    foreach (var body in objectsAtNeighbor.OfType <GameComponent>())
                    {
                        var door = body.GetRoot().EnumerateAll().OfType <Door>().FirstOrDefault();
                        // If there is an enemy door blocking movement, we can destroy it to get through.
                        if (door != null)
                        {
                            if (
                                Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction)
                                .GetCurrentRelationship() !=
                                Relationship.Loving)
                            {
                                if (Can(MoveType.DestroyObject))
                                {
                                    yield return(new MoveAction
                                    {
                                        Diff = v.Diff,
                                        MoveType = MoveType.DestroyObject,
                                        InteractObject = door,
                                        DestinationVoxel = n,
                                        SourceVoxel = voxel
                                    });
                                }
                                blockedByObject = true;
                            }
                        }
                    }

                    // If no object blocked us, we can move freely as normal.
                    if (!blockedByObject)
                    {
                        MoveAction newAction = v;
                        newAction.SourceVoxel      = voxel;
                        newAction.DestinationVoxel = n;
                        yield return(newAction);
                    }
                }
            }
        }
示例#11
0
        public IEnumerable <Status> FindGreedyPath()
        {
            Vector3 target = Target.Position;

            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }
            List <MoveAction> path = new List <MoveAction>();
            var curr    = Creature.Physics.CurrentVoxel;
            var bodies  = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();
            var storage = new MoveActionTempStorage();

            for (int i = 0; i < PathLength; i++)
            {
                IEnumerable <MoveAction> actions =
                    Creature.AI.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = curr
                }, bodies, storage);

                MoveAction?bestAction = null;
                float      bestDist   = float.MaxValue;

                foreach (MoveAction action in actions)
                {
                    // Prevents a stack overflow due to "DestroyObject" task creating a FollowPathAct!
                    if (action.MoveType == MoveType.DestroyObject)
                    {
                        continue;
                    }
                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared();

                    if (dist < bestDist)
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                Vector3 half = Vector3.One * 0.5f;
                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType))
                {
                    path.Add(bestAction.Value);
                    MoveAction action = bestAction.Value;
                    action.DestinationVoxel = curr;
                    curr       = bestAction.Value.DestinationVoxel;
                    bestAction = action;

                    if (((bestAction.Value.DestinationVoxel.WorldPosition + half) - target).Length() < Threshold)
                    {
                        break;
                    }
                }
            }

            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
示例#12
0
        public IEnumerable <Status> FindRandomPath()
        {
            var target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position;

            if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint)
            {
                target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint);
            }
            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }

            var path              = new List <MoveAction>();
            var curr              = Creature.Physics.CurrentVoxel;
            var bodies            = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();
            var storage           = new MoveActionTempStorage();
            var previousMoveState = new MoveState {
                Voxel = curr
            };

            for (int i = 0; i < PathLength; i++)
            {
                var actions = Creature.AI.Movement.GetMoveActions(previousMoveState, bodies, storage);

                MoveAction?bestAction = null;
                var        bestDist   = float.MaxValue;

                foreach (MoveAction action in actions)
                {
                    if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls || action.MoveType == MoveType.Fall))
                    {
                        continue;
                    }

                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType);

                    if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel))
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType &&
                              Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains))
                {
                    MoveAction action = bestAction.Value;
                    path.Add(action);
                    previousMoveState = action.DestinationState;
                }
                else
                {
                    break;
                }
            }

            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
示例#13
0
        public IEnumerable <Status> FindRandomPath()
        {
            Vector3 target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position;

            if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint)
            {
                target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint);
            }
            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }
            List <MoveAction> path = new List <MoveAction>();
            VoxelHandle       curr = Creature.Physics.CurrentVoxel;

            for (int i = 0; i < PathLength; i++)
            {
                var actions = Creature.AI.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = curr
                }, Creature.World.OctTree);

                MoveAction?bestAction = null;
                float      bestDist   = float.MaxValue;
                foreach (MoveAction action in actions)
                {
                    if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls))
                    {
                        continue;
                    }
                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType);

                    if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel))
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType &&
                              Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains))
                {
                    MoveAction action = bestAction.Value;
                    action.DestinationVoxel = curr;
                    path.Add(action);
                    curr = bestAction.Value.DestinationVoxel;
                }
                else
                {
                    break;
                }
            }
            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
示例#14
0
        public static List <MoveAction> ReconstructInversePath(GoalRegion goal,
                                                               Dictionary <MoveState, MoveAction> cameFrom, MoveAction currentNode)
        {
            var toReturn = new List <MoveAction>()
            {
                currentNode
            };

            while (true)
            {
                if (!cameFrom.ContainsKey(currentNode.DestinationState))
                {
                    break;
                }
                currentNode = cameFrom[currentNode.DestinationState];
                toReturn.Add(currentNode);

                /*
                 * for (int frames = 0; frames < 6; frames++)
                 * {
                 *  var sourceColor = goal.IsInGoalRegion(currentNode.SourceVoxel) ? Color.Green : Color.Red;
                 *  Drawer3D.DrawLine(currentNode.SourceVoxel.WorldPosition + Vector3.One * 0.5f,
                 *         currentNode.DestinationVoxel.WorldPosition + Vector3.One * 0.5f, Color.Red, 0.1f);
                 *  Drawer3D.DrawBox(currentNode.SourceVoxel.GetBoundingBox(), sourceColor, 0.1f, true);
                 *  Drawer3D.DrawBox(currentNode.DestinationVoxel.GetBoundingBox(), Color.Yellow, 0.1f, true);
                 *  foreach (var pair in cameFrom)
                 *  {
                 *      var color = Color.White;
                 *      if (goal.IsInGoalRegion(pair.Value.SourceVoxel))
                 *          color = Color.Green;
                 *      Drawer3D.DrawLine(pair.Value.SourceVoxel.WorldPosition + Vector3.One * 0.5f,
                 *          pair.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f, color, 0.05f);
                 *
                 *  }
                 *  System.Threading.Thread.Sleep(16);
                 * }
                 */
                if (goal.IsInGoalRegion(currentNode.DestinationState.Voxel))
                {
                    break;
                }
            }
            return(toReturn);
        }