Example #1
0
    public bool FollowPath()
    {
        if (EntityPath == null)
        {
            return(false);
        }
        Vec2i nexti_ = EntityPath.CurrentIndex();

        if (nexti_ == null)
        {
            return(true);
        }
        Vector2 next = nexti_.AsVector2();

        if (PositionWithinDistance(Entity.GetLoadedEntity().transform.position, next + new Vector2(0.5f, 0.5f), 0.1f))
        {
            Vec2i nexti = EntityPath.NextIndex();
            if (nexti == null)
            {
                return(true);
            }
            next = nexti.AsVector2();
        }

        if (next != null && Entity.GetLoadedEntity() != null)
        {
            Entity.GetLoadedEntity().MoveTowards(next + new Vector2(0.5f, 0.5f));
            Entity.GetLoadedEntity().LookTowardsPoint(next + new Vector2(0.5f, 0.5f));
            return(false);
        }
        return(false);
    }
Example #2
0
    public static Vec2i Rotate(Vec2i initial, Vec2i rotate)
    {
        float   angle = Vector2.SignedAngle(Vector2.up, rotate.AsVector2());
        Vector2 final = Quaternion.Euler(0, 0, angle) * initial.AsVector2();

        return(Vec2i.FromVector2(final));
    }
Example #3
0
    /// <summary>
    /// Default RunFromCombat results in the entity moving in directly the
    /// opposite direction from the current target.
    /// </summary>
    protected virtual void RunFromCombat(Vec2i combatPosition = null)
    {
        currentCombatTask = "running from combat";

        //If we are currently running, we don't need to update
        if (IsRunningFromCombat)
        {
            return;
        }
        Entity.GetLoadedEntity()?.SpeechBubble.PushMessage(Entity + " is running from combat");
        WorldManager.Instance.StartCoroutine(RunFromCombatCoolDown(5));

        //We now define that we are running from combat
        IsRunningFromCombat = true;
        //If the combats position is not defined, then we set it to the entities position
        if (combatPosition == null)
        {
            combatPosition = Entity.TilePos;
        }

        Debug.Log("Running");

        if (Entity.GetSubworld() != null)
        {
            Subworld sub = Entity.GetSubworld();
            //TODO - sub if small?
            Debug.Log("In subworld, exit: " + (sub.Exit as WorldObjectData).Position);
            Entity.GetLoadedEntity().SpeechBubble.PushMessage("Running to subworld exit");
            //WorldObject obj = (sub.Exit as WorldObjectData).LoadedObject;
            Entity.GetLoadedEntity().LEPathFinder.SetTarget((sub.Exit as WorldObjectData).Position, ExitThroughDoor, callbackArgs: new object[] { sub.Entrance, 0.5f });
        }
        else
        {
            Debug.Log("not in subworld");
            Vector2 movementDirection = Entity.Position2 - combatPosition.AsVector2();


            //If our movement is 0, we define it to be in a random direction.
            if (movementDirection == Vector2.zero)
            {
                movementDirection = GameManager.RNG.RandomVector2(-1, 1).normalized;
            }
            //Define the target position as at least 2 chunks away
            Vector2 targetPosition = Entity.Position2 + movementDirection * 32;
            //Set the AI target
            Entity.GetLoadedEntity().LEPathFinder.SetTarget(targetPosition);
        }
    }
Example #4
0
 /// <summary>
 /// Creates a entity group that aims to travel from the start chunk to the end chunk
 /// </summary>
 /// <param name="startChunk"></param>
 /// <param name="endChunk"></param>
 /// <param name="entities"></param>
 public EntityGroup(Vec2i startChunk, List <Entity> entities = null, EconomicInventory inventory = null)
 {
     ShouldDestroy     = false;
     StartChunk        = startChunk;
     CurrentPosition   = startChunk.AsVector2();
     GroupEntityIDs    = new List <int>();
     GroupInventory    = new Inventory();
     EconomicInventory = inventory == null?new EconomicInventory(): inventory;
     if (entities != null)
     {
         foreach (Entity e in entities)
         {
             GroupEntityIDs.Add(e.ID);
             GroupInventory.AddAll(e.Inventory);
             CombatStrength += e.CombatManager.CalculateEntityCombatStrength();
         }
     }
 }
Example #5
0
    protected override void InternalTick()
    {
        if (Entity.EntityAI.CombatAI.AngleBetweenLookAndEntity(DamageSource) > Entity.fov * 0.7f)
        {
            Entity.GetLoadedEntity().LookTowardsPoint(DamageSource.Position2);
        }
        float timePassed = Time.time - StartTime;

        //if we have spent too long looking
        if (timePassed > LookTime)
        {
            //We check if we have already stopped looking
            if (CurrentTileTarget != StartPosition)
            {
                //if not, we set our target as the start position.
                CurrentTileTarget = StartPosition;
                Entity.GetLoadedEntity().LEPathFinder.SetTarget(CurrentTileTarget.AsVector2());
            }
            else
            {
                //If our current position is close to our original position, then we are done
                if (Entity.TilePos.QuickDistance(StartPosition) < 4)
                {
                    IsComplete = true;
                }
            }
        }
        else if (CurrentTileTarget == null || Entity.TilePos == CurrentTileTarget)
        {
            Vector2 direction = (DamageSource.Position2 - Entity.Position2).normalized;
            float   dist      = GameManager.RNG.RandomInt(2, 5);
            Vector2 target    = Entity.Position2 + direction * dist;
            CurrentTileTarget = Vec2i.FromVector2(target);
            Entity.GetLoadedEntity().LEPathFinder.SetTarget(target);
        }
    }
Example #6
0
    /// <summary>
    /// Finds the next point on this entity groups path by travelling a distance
    /// based on
    /// </summary>
    /// <param name="movement">The amount of movement the entity should do. If this is -1, we set it to their current movement speed</param>
    /// <returns>The position the entity group will be at after this tick.
    ///          Returns null if we are at the end of the path</returns>
    public Vec2i NextPathPoint(float movement = -1)
    {
        if (Path == null)
        {
            return(null);
        }

        Vec2i finalPoint = FinalPathPoint();

        /*
         * if (Vec2i.QuickDistance(finalPoint, CurrentChunk) < 4)
         * {
         *  CurrentPosition = finalPoint.AsVector2();
         *  return null;
         * }*/

        if (movement <= 0)
        {
            movement = CurrentMovementSpeed;
        }

        if (movement < 0.5f)
        {
            //If the current chunk is the last point, we return null to imply we have ended our travels
            if (CurrentChunk == finalPoint)
            {
                return(null);
            }
            return(CurrentChunk);
        }



        //If the next point is out of bounds, then that means we are at the final point
        if (CurrentPathIndex + 1 >= Path.Count)
        {
            //This means there is no next path point
            return(null);
        }
        //If the next path point exists, we find it, and the direction from our current position to it
        Vec2i   nextPoint = Path[CurrentPathIndex + 1];
        Vector2 direction = (nextPoint.AsVector2() - CurrentPosition);

        //We find the size, and then normalise the direction
        float mag = direction.magnitude;

        direction /= mag;

        //If the next position is within our current movement
        if (mag + 0.3f < movement)
        {
            float rem = movement - mag;

            //We incriment to the next path point
            CurrentPathIndex++;
            //And find the path accordingly
            return(NextPathPoint(rem));
        }
        //We find the new position
        CurrentPosition = CurrentPosition + direction * movement;
        return(CurrentChunk);
    }
Example #7
0
    protected override void InternalTick()
    {
        if (Entity.TilePos == TargetTile)
        {
            IsComplete = true;
            return;
        }

        int quickDist = QuickDistanceToPlayer(Entity);

        //If we are currently far from the player
        if (quickDist > (World.ChunkSize * 6) * (World.ChunkSize * 6))
        {
            Debug.Log(Entity + " is far from player, can tp?");
            //And the target position is far from the player
            if (Vec2i.QuickDistance(TargetTile, PlayerManager.Instance.Player.TilePos) > (World.ChunkSize * 6) * (World.ChunkSize * 6))
            {
                Debug.Log(Entity + " target from player, will tp");
                if (HasTaskLocation)
                {
                    if (Location.SubworldWorldID != Entity.CurrentSubworldID)
                    {
                        //Then we teleport to our target position and world
                        Entity.MoveEntity(TargetTile, Location.SubworldWorldID);
                    }
                    else
                    {
                        //Then we teleport to our target position.
                        Entity.MoveEntity(TargetTile);
                    }
                }
                else
                {
                    //Then we teleport to our target position.
                    Entity.MoveEntity(TargetTile);
                }
                IsComplete = true;
                return;
            }
        }

        if (HasTarget)
        {
            Debug.Log(Entity + " has GOTO target");
            return;
        }

        //if no task location is set, we simply go to the desired tile position
        if (!HasTaskLocation)
        {
            Debug.Log(Entity + " Target set: " + TargetTile);
            Entity.GetLoadedEntity().LEPathFinder.SetTarget(TargetTile.AsVector2());
            HasTarget = true;
        }
        else
        {
            Debug.Log("not far, with task loc");
            //if we do have a location, we check the subworldID
            //if it is the current world, we simply walk there
            if (Entity.CurrentSubworldID == Location.SubworldWorldID)
            {
                Entity.GetLoadedEntity().LEPathFinder.SetTarget(TargetTile.AsVector2());
                HasTarget = true;
                Debug.Log("In same world, going now");
            }
            else
            {
                //If we are not in the current target subworld, we have 3 possible cases:
                //1) We are in the main World (-1) travelling to a subworld
                //2) We are in a subworld, travelling to the main world (-1)
                //3) We are in a subworld, and wish to travel to another subworld via the main world
                //Case 3 and 2 can be ignored, as we already automatically take entities from their subworlds
                //And place them outside if their AI brings them to a a target outside their subworld
                if (Entity.CurrentSubworldID == -1 && Location.SubworldWorldID != -1)
                {
                    Subworld sub = WorldManager.Instance.World.GetSubworld(Location.SubworldWorldID);
                    Debug.Log(Entity + " travelling from world to subworld at : " + (sub.Entrance as WorldObjectData).Position);

                    Entity.GetLoadedEntity().LEPathFinder.SetTarget((sub.Entrance as WorldObjectData).Position, TravelThroughDoor, new object[] { sub.Entrance, 0.5f });
                    HasTarget = true;
                }
            }
        }


        if (!HasTaskLocation || Location.SubworldWorldID == Entity.CurrentSubworldID)
        {
            if (TargetTile.QuickDistance(Entity.TilePos) < 4)
            {
                Entity.GetLoadedEntity()?.SpeechBubble.PushMessage("At Pathfinding target");
                IsComplete = true;
            }
        }
    }
Example #8
0
    /*
     * private void FromRiverSource(Vec2i source, Vec2i mainDir)
     * {
     *
     *  int i = 0;
     *  Vec2i end = null;
     *  Vec2i current = source;
     *  //Ray cast from the source to find the ocean point at this rivers end
     *  while(end == null)
     *  {
     *      i++;
     *      current += mainDir;
     *      if(ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean)
     *      {
     *          end = current;
     *      }
     *      if (i > World.WorldSize)
     *          return;
     *
     *  }
     *  i = 0;
     *
     *  Vec2i last = source;
     *
     *  current = source + mainDir;
     *  bool isDone = false;
     *
     *  Vector2 lastDir = (end - current).AsVector2().normalized;
     *  Vector2 exactCurrent = current.AsVector2();
     *
     *  List<Vec2i> river = new List<Vec2i>();
     *
     *  while (!isDone)
     *  {
     *
     *
     *
     *      i++;
     *      // Vector2 currentFlow = FlowField[current.x, current.z];
     *
     *      float fx = PerlinNoise(current.x, current.z, 36)*2 - 1;
     *      float fz = PerlinNoise(current.x, current.z, 37)*2 - 1;
     *      Vector2 noiseFlow = new Vector2(fx, fz);
     *      Vector2 flowField = FlowField[current.x, current.z];
     *      Vector2 targetFlow = (end - current).AsVector2().normalized;
     *
     *      Vector2 flow = (noiseFlow + 4 * targetFlow + 3 * flowField).normalized;
     *      exactCurrent += flow;
     *      current = Vec2i.FromVector2(exactCurrent);
     *      int check = Mathf.Min(river.Count, 5);
     *      bool isValid = true;
     *      for(int j=0; j< check; j++)
     *      {
     *          if (river[river.Count - j - 1] == current)
     *              isValid = false;
     *      }
     *      if (!isValid)
     *      {
     *          current += mainDir;
     *          exactCurrent = current.AsVector2();
     *      }
     *
     *
     *      if (ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean)
     *          isDone = true;
     *      ChunkBases[current.x, current.z].SetChunkFeature(new ChunkRiverNode());
     *      river.Add(current);
     *      if (i > 2048)
     *          return;
     *
     *  }
     *
     *
     * }*/


    private void ReverseFlowRiver(Vec2i start, int length, int distSinceFork = 0)
    {
        //Give rivers a slight biase towards the middle of the map
        Vector2 bias = -(new Vector2(World.WorldSize / 2, World.WorldSize / 2) - start.AsVector2()).normalized;


        Vec2i            current         = start;
        Vector2          fullCurrent     = current.AsVector2();
        Vec2i            last            = Vec2i.FromVector2(fullCurrent + bias);
        List <FlowPoint> inputFlowPoints = new List <FlowPoint>(5);

        for (int i = 0; i < length; i++)
        {
            distSinceFork++;
            inputFlowPoints.Clear();
            //if this chunk is a river node already, we have reached the end of this river branch
            if (ChunkBases[current.x, current.z].ChunkFeature is ChunkRiverNode)
            {
                //return;
            }

            //Add a river node here
            ChunkBases[current.x, current.z].SetChunkFeature(new ChunkRiverNode(current));

            //We iterate each of the near chunks
            foreach (Vec2i v in Vec2i.OCT_DIRDIR)
            {
                //Coordinate of point of interest
                Vec2i p = v + current;
                //If this is the point we just came from, ignore it
                if (last == p)
                {
                    continue;
                }
                Vector2 vFlow = FlowField[p.x, p.z];
                //Find the coordinate that this point flows into
                Vec2i pointFlowPos = Vec2i.FromVector2(p.AsVector2() + vFlow);

                //Check if this point flows into our current point
                if (pointFlowPos == current)
                {
                    FlowPoint fp = new FlowPoint();
                    fp.Pos = p;
                    fp.Dir = vFlow;
                    inputFlowPoints.Add(fp);
                }
            }
            //If no points flow here, then the river has reached an end (add lakes?)
            if (inputFlowPoints.Count == 0)
            {
                Debug.Log("zero flow");
                Vector2 currentToLast = (current - last).AsVector2();
                fullCurrent = fullCurrent - currentToLast;
                //Debug.Log("zero error...");
                //return;
            }
            else if (inputFlowPoints.Count == 1)
            {
                Debug.Log("single flow");
                fullCurrent = fullCurrent - inputFlowPoints[0].Dir;
            }
            else
            {
                if (distSinceFork < 40)
                {
                    fullCurrent = fullCurrent - GenRan.RandomFromList(inputFlowPoints).Dir;
                    Debug.Log("No fork - dist");
                }
                else
                {
                    Debug.Log("fork");
                    //If we are over 40, then we can create a fork

                    //only 2 forks maximum
                    while (inputFlowPoints.Count > 2)
                    {
                        inputFlowPoints.RemoveAt(GenRan.RandomInt(0, inputFlowPoints.Count));
                    }
                    ReverseFlowRiver(inputFlowPoints[0].Pos, length - i, 0);
                    ReverseFlowRiver(inputFlowPoints[1].Pos, length - i, 0);
                    Debug.Log("forks");
                    return;
                }
            }
            last    = new Vec2i(current.x, current.z);
            current = Vec2i.FromVector2(fullCurrent);

            /*
             * //We iterate all directions
             * Vector2 grad = (FlowField[current.x, current.z] + 0.1f * bias).normalized;
             * fullCurrent = fullCurrent - grad;
             * current = Vec2i.FromVector2(fullCurrent);
             */
        }
    }
Example #9
0
    private void FromRiverSource(Vec2i source, Vec2i end, float startHeight = -1, int distSinceFork = 0, bool riverRaySearch = true)
    {
        int i = 0;

        if (startHeight < 0)
        {
            startHeight = ChunkBases[source.x, source.z].Height;
        }

        i = 0;

        Vec2i last    = source;
        Vec2i mainDir = CalcDir(source, end);



        Vec2i current = source + mainDir;
        bool  isDone  = false;

        Vector2 exactCurrent = current.AsVector2();

        List <RiverPoint> river        = new List <RiverPoint>();
        ChunkRiverNode    previousNode = null;

        while (!isDone)
        {
            int distToEnd = end.QuickDistance(current);

            i++;

            /*
             * if(i%16 == 0 && riverRaySearch)
             * {
             *  bool success = false;
             *  //search up to 16 chunks away
             *  for(int j=1; j<16; j++)
             *  {
             *      if (success)
             *          break;
             *      //search all 8 directions
             *      foreach(Vec2i v in Vec2i.OCT_DIRDIR)
             *      {
             *          Vec2i p = current + v * j;
             *
             *          if(ChunkBases[p.x,p.z].Biome == ChunkBiome.ocean || ChunkBases[p.x, p.z].ChunkFeature is ChunkRiverNode)
             *          {
             *              end = p;
             *              success = true;
             *              break;
             *          }
             *      }
             *  }
             * }*/


            // Vector2 currentFlow = FlowField[current.x, current.z];

            float   fx         = PerlinNoise(current.x, current.z, 36) * 2 - 1;
            float   fz         = PerlinNoise(current.x, current.z, 37) * 2 - 1;
            Vector2 noiseFlow  = new Vector2(fx, fz);
            Vector2 flowField  = FlowField[current.x, current.z];
            Vector2 targetFlow = (end - current).AsVector2().normalized;


            float targetFlowMult = distToEnd < 400 ? 4 * Mathf.Exp((400f - distToEnd) / 200f) : 4;

            Vector2 flow = (noiseFlow + targetFlowMult * targetFlow + 3.5f * flowField).normalized;
            exactCurrent += flow;
            current       = Vec2i.FromVector2(exactCurrent);
            int  check   = Mathf.Min(river.Count, 5);
            bool isValid = true;
            for (int j = 0; j < check; j++)
            {
                if (river[river.Count - j - 1].Pos == current)
                {
                    isValid = false;
                }
            }
            if (!isValid)
            {
                current     += mainDir;
                exactCurrent = current.AsVector2();
            }


            if (ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean)
            {
                isDone = true;
            }
            if (ChunkBases[current.x, current.z].ChunkFeature is ChunkRiverNode)
            {
                isDone = true;
                //Shouldn't be null, but lets do a check anyway
                if (previousNode != null)
                {
                    //Get the river node
                    ChunkRiverNode endNode = ChunkBases[current.x, current.z].ChunkFeature as ChunkRiverNode;
                    //Inform river nodes of flow
                    endNode.FlowIn.Add(previousNode);
                    previousNode.FlowOut.Add(endNode);
                    ModifyRiverHeight(endNode);
                }
                if (GenRan.Random() < 0.5f)
                {
                    PlaceLake(current, 8);
                }
            }
            if (current == end)
            {
                isDone = true;
            }
            ChunkRiverNode nextNode = new ChunkRiverNode(current);
            ChunkBases[current.x, current.z].SetChunkFeature(nextNode);
            if (previousNode != null)
            {
                nextNode.FlowIn.Add(previousNode);
                previousNode.FlowOut.Add(nextNode);
            }
            previousNode = nextNode;
            //If this chunk is too high, we modify it and the surrounding area
            if (ChunkBases[current.x, current.z].Height > startHeight)
            {
                ModifyRiverValleyHeight(current, startHeight);
            }
            else if (ChunkBases[current.x, current.z].Height < startHeight)
            {
                startHeight = ChunkBases[current.x, current.z].Height;
            }
            RiverPoint rp = new RiverPoint();
            rp.Pos  = current;
            rp.Flow = flow;

            river.Add(rp);
            if (i > 4096)
            {
                PlaceLake(current, 12);
                return;
            }


            /*
             * distSinceFork++;
             *
             * if(distSinceFork > 256)
             * {
             *
             *  float p = Mathf.Exp(-distSinceFork/200f);
             *  if(p < GenRan.Random())
             *  {
             *
             *      Vec2i delta = GenRan.RandomVec2i(-64, 64);
             *
             *      FromRiverSource(current + delta, current);
             *      distSinceFork = 0;
             *  }
             *
             * }*/
            mainDir = CalcDir(current, end);
        }
        return;

        if (river.Count > 128)
        {
            int forkCount = Mathf.CeilToInt(river.Count / 128f);
            int jump      = (int)(((float)river.Count) / forkCount);
            int index     = GenRan.RandomInt(0, jump);
            for (int j = 0; j < forkCount; j++)
            {
                if (index > river.Count - 30)
                {
                    return;
                }
                RiverPoint rp      = river[index];
                Vec2i      forkEnd = rp.Pos;
                Vec2i      delta   = GenRan.RandomVec2i(-32, 32);

                Vector2 endToForkDir = (forkEnd - end).AsVector2().normalized;

                Vec2i forkStart = Vec2i.FromVector2(forkEnd.AsVector2() + endToForkDir * GenRan.Random(64, 128)) + delta;


                FromRiverSource(forkStart, forkEnd);



                index += jump + GenRan.RandomInt(-32, 32);
            }
        }
    }
Example #10
0
    public bool GeneratePath(Vec2i target)
    {
        Entity.GetLoadedEntity().LEPathFinder?.SetTarget(target.AsVector2());
        Target = target;

        return(true);

        //if no target, null previous paths and return.
        if (target == null)
        {
            Debug.Log("Target is null - no path");
            EntityPathTarget = null;
            EntityPath       = null;
            return(false);
        }

        if (EPF == null)
        {
            //TODO - get free path finder from parent
            EPF = new EntityPathFinder(GameManager.PathFinder);
        }

        Vec2i tilePos = Vec2i.FromVector3(Entity.Position);


        /*if(GameManager.PathFinder.NodeValue(tilePos) > 100)
         * {
         *  tilePos = Vec2i.FromVector3(Entity.Position + new Vector3(0.5f, 0, 0.5f));
         *  if(GameManager.PathFinder.NodeValue(tilePos) > 100)
         *  {
         *      Debug.Log("hm");
         *  }
         * }*/
        //if we have no path
        if (EntityPath == null)
        {
            Debug.Log("[PathFinding] Attempting path from " + tilePos + " to " + target);
            //We check if one is being generated
            if (!EPF.IsRunning)
            {
                //If not, we start generating it
                EPF.FindPath(tilePos, target);
                return(false);
            }

            //Check if the path finder has completed its work
            if (EPF.IsComplete())
            {
                //If the path is found, we set it and return true
                if (EPF.FoundPath)
                {
                    EntityPathTarget = target;
                    EntityPath       = new EntityPath(EPF.GetPath());
                    return(true);
                }
                else
                {
                    Debug.Log("Path from " + tilePos + " to " + target + " not found");

                    return(false);
                }
            }
            return(false);

            /*
             * //If there is no path, Attempt to generate it
             * List<Vec2i> path = GameManager.PathFinder.GeneratePath(tilePos, target);
             * if (path==null || path.Count == 0)
             * {
             *  Debug.Log("Path from " + tilePos + " to " + target + " not found");
             *  return false;
             * }
             * EntityPathTarget = target;
             * EntityPath = new EntityPath(path);
             * return true;*/
        }
        else if (EntityPath.Target == target)
        {//If the current path has the same target, return true
            return(true);
        }
        else
        {
            Debug.Log("[PathFinding] Attempting updated path " + tilePos + " to " + target);
            if (Vec2i.QuickDistance(EntityPath.Target, target) < 5)
            {
                //If the path exists but doesn't have the same target, but targets are close, we attempt to re-calculate the path
                return(EntityPath.UpdateTarget(target, EPF));
            }
            else
            {
                EntityPath = null;
                //We check if one is being generated
                if (!EPF.IsRunning)
                {
                    //If not, we start generating it
                    EPF.FindPath(tilePos, target);
                    return(false);
                }/*
                  * List<Vec2i> newPath = GameManager.PathFinder.GeneratePath(tilePos, target);
                  * if(newPath==null || newPath.Count == 0)
                  * {
                  * Debug.Log("No path found from " + tilePos + " to " + target + " for entity " + Entity);
                  * return false;
                  * }
                  * EntityPath = new EntityPath(newPath);
                  * return true;*/
            }
        }
        return(false);
    }