Exemplo n.º 1
0
    void assignViolentWork(Unit_local worker)
    {
        UnitRelativePositionSorter comparer = new UnitRelativePositionSorter(worker.transform.position);

        comparer.DistanceMode();
        remainingToPerish.Sort(comparer);
        List <Unit> inRange        = new List <Unit>();
        Unit        closestHoplite = null;
        Unit        closestDog     = null;
        Unit        closestCourier = null;

        for (int i = 0; i < remainingToPerish.Count && comparer.DistanceOf(remainingToPerish[i]) <= worker.stats.weapon_range; ++i)
        {
            inRange.Add(remainingToPerish[i]);
            if (closestHoplite == null && remainingToPerish[i].name.Contains("hoplite"))
            {
                closestHoplite = remainingToPerish[i];
            }
            else if (closestDog == null && remainingToPerish[i].name.Contains("dog"))
            {
                closestDog = remainingToPerish[i];
            }
            else if (closestCourier == null && remainingToPerish[i].name.Contains("courier"))
            {
                closestCourier = remainingToPerish[i];
            }
        }
        Unit targetUnit;

        if (closestHoplite != null)
        {
            targetUnit = closestHoplite;
        }
        else if (closestDog != null)
        {
            targetUnit = closestDog;
        }
        else if (closestCourier != null)
        {
            targetUnit = closestCourier;
        }
        else
        {
            targetUnit = remainingToPerish[0];
        }
        Task result = new Task(worker, Task.actions.attack, targetUnit.transform.position, targetUnit);

        worker.work(result);
        assignments.Add(result);
    }
Exemplo n.º 2
0
    public bool assignTransactionWork(Unit_local needsCounterparty, bool assignByTarget = false)
    {
        // Debug.Log("AssignTransactionWork");
        Hashtable  counterParties      = null;
        Unit_local closestCounterparty = null;
// We have to get a little weird with these, because closestCounterparty, which one of these two things will reference, can't be decided until we determine what the counterparties are,
// which is done in the same IF statement that determines what the provider is. I know it's weird.
        Func <Unit_local> provider;
        Func <Unit_local> reciever;

        if (masterTask.nature == Task.actions.give ^ assignByTarget == true)
        {
            counterParties = remainingToAccept;
            provider       = () => needsCounterparty;
            reciever       = () => closestCounterparty;
        }
        else
        {
            counterParties = remainingToProvide;
            provider       = () => closestCounterparty;
            reciever       = () => needsCounterparty;
        }
        float bestDistance = 999999;

        foreach (Unit_local recieverCandidate in counterParties.Keys)
        {
            float distanceTo = Vector2.Distance(recieverCandidate.transform.position, needsCounterparty.transform.position);
            if (distanceTo < bestDistance)
            {
                closestCounterparty = recieverCandidate;
                bestDistance        = distanceTo;
            }
        }
        Hashtable  leftoverFactor;
        Hashtable  exhaustedFactor;
        Unit_local unitWithLeftovers;
        Unit_local limitingUnit;
        int        quantityToPass = 0;

        if (reciever().roomForMeat() == provider().meat)
        {
            quantityToPass = provider().meat;
            remainingToAccept.Remove(reciever);
            remainingToProvide.Remove(provider());
        }
        else
        {
            if (reciever().roomForMeat() < provider().meat)
            {
                leftoverFactor    = remainingToProvide;
                exhaustedFactor   = remainingToAccept;
                limitingUnit      = reciever();
                unitWithLeftovers = provider();
                quantityToPass    = reciever().roomForMeat();
            }
            else
            {
                leftoverFactor    = remainingToAccept;
                exhaustedFactor   = remainingToProvide;
                limitingUnit      = provider();
                unitWithLeftovers = reciever();
                quantityToPass    = provider().meat;
            }
            leftoverFactor[unitWithLeftovers] = (int)leftoverFactor[unitWithLeftovers] - (int)exhaustedFactor[limitingUnit];
            exhaustedFactor.Remove(limitingUnit);
        }
        Task newTask;

        if (assignByTarget == false)
        {
            newTask = new Task(needsCounterparty, masterTask.nature, Vector2.zero, closestCounterparty, quantityToPass);
            needsCounterparty.work(newTask);
        }
        else
        {
            newTask = new Task(closestCounterparty, masterTask.nature, Vector2.zero, needsCounterparty, quantityToPass);
            closestCounterparty.work(newTask);
        }
        assignments.Add(newTask);
        return(true);
    }
Exemplo n.º 3
0
    public void MoveCohort(Vector2 goTo, Unit_local toFollow)
    {
        Stop();
        masterTask = new Task(null, Task.actions.move, goTo, toFollow);
        List <Unit_local> thisIsToSupressWarnings = new List <Unit_local>(members);
        float             weakLinkETA             = 0;

        foreach (Unit_local toMove in thisIsToSupressWarnings)
        {
            if (toMove.stats.isMobile == false)
            {
                throw new InvalidOperationException("Cannot move a cohort that includes immobile members. Units should be sorted out in Gamestate.CombineActiveCohorts.");
            }
            else
            {
                float thisMoversETA = Vector2.Distance(toMove.transform.position, goTo) / toMove.stats.speed;
                if (thisMoversETA > weakLinkETA)
                {
                    weakLinkETA = thisMoversETA;
                }
            }
        }
        UnitRelativePositionSorter vsGoTo = new UnitRelativePositionSorter(goTo);

        vsGoTo.DirectionMode();
        List <Unit_local> unitsByDirection = new List <Unit_local>(members);

// This is a list of units sorted by their compass-direction from the destination point.
        (unitsByDirection).Sort(vsGoTo);
        vsGoTo.DistanceMode();
        List <Unit_local> unitsByDistance = new List <Unit_local>(members);

        unitsByDistance.Sort(vsGoTo);
// Units are removed from unitsByDirection (and unitsByDistance) as they are assigned to groups, so this is a way of saying "while there are unassigned units."
        while (unitsByDirection.Count > 0)
        {
// We take the current closest unit to the distination... (previous cycles of grouping will have removed closer units)
            Unit_local        sliceLeader                   = unitsByDistance[0];
            int               leaderDirectionIndex          = unitsByDirection.IndexOf(sliceLeader);
            float             leaderDistanceFromDestination = vsGoTo.DistanceOf(sliceLeader);
            float             leaderRadius                  = sliceLeader.bodyCircle.radius;
            int               totalUnaccounted              = unitsByDirection.Count;
            List <Unit_local> slice = new List <Unit_local> {
                sliceLeader
            };
// That unit will be the group leader. We check the units clockwise and counter-clockwise from its' position on the imaginary circle of unit positions aronud the destination.
            for (int sign = -1; sign <= 1 && slice.Count < unitsByDirection.Count; sign = sign + 2)
            {
                // this is a loop-breaker variable
                for (int indexOffset = sign; indexOffset < 1000; indexOffset += sign)
                {
                    Unit_local inQuestion = unitsByDirection[(leaderDirectionIndex + indexOffset + totalUnaccounted) % totalUnaccounted];
// These are all in radians...
                    float directionOfLeader       = vsGoTo.DirectionOf(sliceLeader);
                    float directionInQuestion     = vsGoTo.DirectionOf(inQuestion);
                    float circumferencialDistance = Mathf.Abs(directionOfLeader - directionInQuestion);
                    circumferencialDistance = Mathf.Min(circumferencialDistance, 2 * Mathf.PI - circumferencialDistance);
// ...until here, when circumferentialDistance becomes a measure of real distance.
                    circumferencialDistance *= leaderDistanceFromDestination;
// In both directions, we stop checking when the next-closest (by direction) unit doesn't fall within the shadow cast by the leader, if you imagine the destination as a light source.
                    if (circumferencialDistance < leaderRadius && inQuestion != sliceLeader)
                    {
                        slice.Add(inQuestion);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            slice.Sort(vsGoTo);
// This line makes it so that all groups arive at the same time.
// PROBLEM: this will make fast units move slugishly for very short journeys.
            float leaderSpeed = Mathf.Clamp(Vector2.Distance(sliceLeader.transform.position, goTo) / weakLinkETA, 0, sliceLeader.stats.speed);
            sliceLeader.work(new Task(sliceLeader, Task.actions.move, goTo, toFollow, -1, leaderSpeed));
            for (int followerIndex = 1; followerIndex < slice.Count; ++followerIndex)
            {
                slice[followerIndex].work(new Task(slice[followerIndex], Task.actions.move, goTo, sliceLeader));
            }
            foreach (MobileUnit_local sliceMember in slice)
            {
                assignments.Add(sliceMember.task);
                unitsByDirection.Remove(sliceMember);
                unitsByDistance.Remove(sliceMember);
            }
        }
    }