예제 #1
0
    /// <summary>
    /// Causes the squad to move to hack the context indicator target.
    /// One squad member is randomly chosen to hack while the others occupy cover points
    /// near the target.
    /// </summary>
    /// <param name="_context"></param>
    void SquadHackCommand(CurrentContext _context)
    {
        HackableConsole console = _context.indicator_hit.GetComponent <HackableConsole>();

        if (console.hacked)
        {
            return;
        }

        order_target_bobber.SetTarget(console.transform);

        squad_sense.hacker_squaddie = squad_sense.squaddies[Random.Range(0, num_squaddies)];
        for (int i = 0; i < num_squaddies; ++i)
        {
            SquaddieAI squaddie = squad_sense.squaddies[i];
            squaddie.knowledge.order_console = console;

            if (squaddie == squad_sense.hacker_squaddie)
            {
                // Hacker squaddie moves to hack.
                squaddie.knowledge.current_order = OrderType.HACK;
                squaddie.nav.destination         = console.hack_point.position;
            }
            else
            {
                // The other squaddies move to defend.
                Vector3 pos = JHelper.PosToCirclePos(console.hack_point.position, num_squaddies, i, 5);

                squaddie.knowledge.current_order = OrderType.GUARD;
                squaddie.MoveToCoverNearPosition(pos);
            }
        }
    }
예제 #2
0
    public override bool Decide(SquaddieAI _squaddie)
    {
        bool enemies_nearby      = _squaddie.knowledge.nearby_targets.Count > 0;
        bool squad_target_exists = _squaddie.knowledge.squad_sense.squad_target != null;

        return(enemies_nearby || squad_target_exists);
    }
예제 #3
0
    public override bool Decide(SquaddieAI _squaddie)
    {
        bool order_obeyed = true;

        switch (_squaddie.knowledge.current_order)
        {
        case OrderType.MOVE:
        {
            order_obeyed &= (!_squaddie.nav.hasPath && !_squaddie.nav.pathPending);
        } break;

        case OrderType.FOLLOW:
        {
            order_obeyed = false;
        } break;

        case OrderType.ATTACK:
        {
            order_obeyed &= _squaddie.knowledge.order_target == null;
        } break;

        case OrderType.HACK:
        {
            order_obeyed &= _squaddie.knowledge.order_console.hacked;
        } break;

        case OrderType.GUARD:
        {
            order_obeyed &= _squaddie.knowledge.squad_sense.hacker_squaddie == null;
        } break;
        }

        return(order_obeyed);
    }
예제 #4
0
    bool FindNewFollowTarget(SquaddieAI _squaddie)
    {
        if (_squaddie.knowledge.follow_target == null)
        {
            foreach (SquaddieAI ally in _squaddie.knowledge.squad_sense.squaddies)
            {
                if (ally == _squaddie ||
                    ally.knowledge.follow_target == _squaddie.transform)
                {
                    continue;
                }

                _squaddie.knowledge.follow_target = ally.transform;
                break;
            }
        }

        if (_squaddie.knowledge.follow_target == null)
        {
            Transform follow_target = GameManager.scene.perspective_manager.FPSModeActive() ?
                                      GameManager.scene.player.transform : GameManager.scene.context_scanner.indicator_transform;

            _squaddie.knowledge.follow_target = follow_target;
        }

        return(_squaddie.knowledge.follow_target != null);
    }
예제 #5
0
    public override void Act(SquaddieAI _squaddie)
    {
        _squaddie.knowledge.crouched = _squaddie.knowledge.in_cover &&
                                       _squaddie.knowledge.current_target_visible;

        _squaddie.knowledge.crouched &= !_squaddie.nav.hasPath;
    }
예제 #6
0
 public override void Trigger(SquaddieAI _squaddie)
 {
     _squaddie.knowledge.current_order  = OrderType.NONE;
     _squaddie.knowledge.order_waypoint = Vector3.zero;
     _squaddie.knowledge.hacking        = false;
     _squaddie.knowledge.squad_sense.hacker_squaddie = null;
 }
예제 #7
0
    void CheckTransitions(SquaddieAI _squaddie)
    {
        foreach (Transition transition in transitions)
        {
            bool  decision_success = transition.decision.Decide(_squaddie);
            State target_state     = decision_success ? transition.true_state : transition.false_state;

            if (target_state == null)
            {
                continue;
            }

            if (decision_success)
            {
                foreach (TransitionTrigger trigger in transition.true_triggers)
                {
                    trigger.Trigger(_squaddie);
                }
            }
            else
            {
                foreach (TransitionTrigger trigger in transition.false_triggers)
                {
                    trigger.Trigger(_squaddie);
                }
            }

            _squaddie.TransitionToState(target_state);
        }
    }
예제 #8
0
    /// <summary>
    /// Constructs an individual squaddie with the passed faction settings.
    /// </summary>
    /// <param name="_faction">The faction of the squaddie.</param>
    /// <param name="_pos">The location the squaddie should be placed.</param>
    /// <returns>A reference to the instantiated squaddie.</returns>
    public SquaddieAI CreateSquaddie(FactionSettings _faction, Vector3 _pos)
    {
        GameObject clone    = Instantiate(squaddie_prefab, _pos, Quaternion.identity);
        SquaddieAI squaddie = clone.GetComponent <SquaddieAI>();

        squaddie.Init(_faction);

        return(squaddie);
    }
예제 #9
0
    public void Hack(SquaddieAI _squaddie)
    {
        if (hacked)
        {
            return;
        }

        hack_timer = time_to_reset;
    }
예제 #10
0
    public static bool SameFaction(SquaddieAI _a, FactionSettings _b)
    {
        if (_a == null || _b == null)
        {
            return(false);
        }

        return(SameFaction(_a.stats.faction_settings, _b));
    }
예제 #11
0
    public Color state_color = Color.grey;  // Debug gizmo colour.


    public void UpdateState(SquaddieAI _squaddie)
    {
        _squaddie.knowledge.state_time_elapsed += Time.deltaTime;

        DoActions(_squaddie);
        CheckTransitions(_squaddie);

        _squaddie.knowledge.prev_state_time_elapsed =
            _squaddie.knowledge.state_time_elapsed;
    }
예제 #12
0
    void ShootEnemy(SquaddieAI _squaddie)
    {
        Quaternion rot = Quaternion.LookRotation(_squaddie.knowledge.current_target.torso_transform.position -
                                                 _squaddie.torso_transform.position);

        _squaddie.torso_transform.rotation = Quaternion.RotateTowards(_squaddie.torso_transform.rotation,
                                                                      rot, (_squaddie.nav.angularSpeed * 2) * Time.deltaTime);

        _squaddie.knowledge.chain_gun.cycle = _squaddie.knowledge.current_target_visible;
    }
예제 #13
0
    void DoActions(SquaddieAI _squaddie)
    {
        foreach (Action action in actions)
        {
            if (!action.PreconditionsMet(_squaddie))
            {
                continue;
            }

            action.Act(_squaddie);
        }
    }
예제 #14
0
    public void AddSquaddie(SquaddieAI _squaddie_ai)
    {
        if (squad_sense.squaddies.Contains(_squaddie_ai))
        {
            return;
        }

        _squaddie_ai.Init(squad_faction);
        _squaddie_ai.LinkSquadSense(ref squad_sense);

        squad_sense.squaddies.Add(_squaddie_ai);
    }
예제 #15
0
    public override bool PreconditionsMet(SquaddieAI _squaddie)
    {
        bool ordered_to_hack       = _squaddie.knowledge.current_order == OrderType.HACK;
        bool nearby_console_exists = _squaddie.knowledge.nearby_console != null;

        if (!ordered_to_hack || !nearby_console_exists)
        {
            _squaddie.knowledge.hacking = false;
            return(false);
        }

        return(true);
    }
예제 #16
0
    public override void Act(SquaddieAI _squaddie)
    {
        if (_squaddie.knowledge.follow_target == null)
        {
            if (!FindNewFollowTarget(_squaddie))
            {
                return;
            }
        }

        _squaddie.nav.isStopped   = _squaddie.nav.remainingDistance <= _squaddie.nav.stoppingDistance;
        _squaddie.nav.destination = _squaddie.knowledge.follow_target.position;
    }
예제 #17
0
    /// <summary>
    /// Cause the agent to seek a position that allows it to safely engage the target.
    /// </summary>
    /// <param name="_target">The flank target.</param>
    public void MoveToFlankEnemy(SquaddieAI _target)
    {
        var cover_points = GameManager.scene.tactical_assessor.FindFlankingPositions(
            this, _target, settings.cover_search_radius);

        if (cover_points.Count == 0)
        {
            nav.destination = _target.transform.position;
        }
        else
        {
            nav.destination = EvaluateUniqueCoverPoint(cover_points);
        }
    }
예제 #18
0
    /// <summary>
    /// Creates a new squad with the passed faction settings.
    /// The squaddies are arranged in a circular pattern at the passed position, based on the squad size.
    /// </summary>
    /// <param name="_faction">The faction of the squad.</param>
    /// <param name="_num_squaddies">The size of the squad.</param>
    /// <param name="_pos">The where the squad should be arranged.</param>
    /// <returns>A reference to the instantiated squad.</returns>
    public SquadManager CreateSquad(FactionSettings _faction, int _num_squaddies, Vector3 _pos)
    {
        SquadManager squad_manager = new SquadManager(_faction);

        for (int i = 0; i < _num_squaddies; ++i)
        {
            SquaddieAI squaddie = CreateSquaddie(_faction, _pos);
            squaddie.transform.position = JHelper.PosToCirclePos(_pos, _num_squaddies, i, _num_squaddies * 0.5f);

            squad_manager.AddSquaddie(squaddie);
        }

        return(squad_manager);
    }
예제 #19
0
    void MoveToPosition(SquaddieAI _squaddie)
    {
        UpdateHackPosition(_squaddie);

        if (_squaddie.nav.hasPath && _squaddie.nav.remainingDistance <=
            _squaddie.nav.stoppingDistance)
        {
            _squaddie.nav.isStopped = true;
            _squaddie.nav.ResetPath();
        }
        else
        {
            _squaddie.nav.isStopped = false;
        }
    }
예제 #20
0
    void UpdateHackPosition(SquaddieAI _squaddie)
    {
        if (_squaddie.knowledge.current_order == OrderType.HACK)
        {
            HackableConsole console = _squaddie.knowledge.order_console;
            float           dist    = Vector3.Distance(_squaddie.transform.position,
                                                       console.transform.position);

            if (dist > _squaddie.nav.stoppingDistance)
            {
                _squaddie.nav.destination = console.hack_point.position;
                _squaddie.nav.isStopped   = false;
            }
        }
    }
예제 #21
0
    public override bool PreconditionsMet(SquaddieAI _squaddie)
    {
        bool target_exists   = _squaddie.knowledge.current_target != null;
        bool target_visible  = _squaddie.knowledge.current_target_visible;
        bool target_in_range = _squaddie.knowledge.current_target_in_range;
        bool hacking         = _squaddie.knowledge.hacking;

        if (!target_exists || !target_visible || !target_in_range || hacking)
        {
            _squaddie.knowledge.chain_gun.cycle = false;
            return(false);
        }

        return(true);
    }
예제 #22
0
    // CollisionEventForwarder event.
    public void TriggerEnter(Collider _other)
    {
        if (!_other.CompareTag("DamageableBody"))
        {
            return;
        }

        SquaddieAI squaddie = _other.GetComponentInParent <SquaddieAI>();

        if (squaddie == null || JHelper.SameFaction(squaddie, this))
        {
            return;
        }

        knowledge.nearby_targets.Add(squaddie);
    }
예제 #23
0
    public override bool PreconditionsMet(SquaddieAI _squaddie)
    {
        OrderType current_order      = _squaddie.knowledge.current_order;
        bool      eligible_to_engage = current_order == OrderType.NONE ||
                                       current_order == OrderType.ATTACK;

        if (!eligible_to_engage ||
            _squaddie.knowledge.current_target == null ||
            (_squaddie.knowledge.current_target_visible &&
             _squaddie.knowledge.current_target_in_range))
        {
            return(false);
        }

        return(true);
    }
예제 #24
0
    void DestroyMouseOverSquaddie()
    {
        RaycastHit hit;
        var        success = JHelper.RaycastMousePosToLayer("Damageable", out hit);

        if (!success)
        {
            return;
        }

        SquaddieAI squaddie = hit.collider.transform.root.GetComponent <SquaddieAI>();

        if (squaddie != null)
        {
            Destroy(squaddie.gameObject);
        }
    }
예제 #25
0
    /// <summary>
    /// Causes the squad to engage the context indicator target.
    /// </summary>
    /// <param name="_context">The current context.</param>
    void SquadAttackCommand(CurrentContext _context)
    {
        SquaddieAI attack_target = _context.indicator_hit.GetComponent <SquaddieAI>();

        order_target_bobber.SetTarget(attack_target.transform);

        foreach (SquaddieAI squaddie in squad_sense.squaddies)
        {
            if (JHelper.SameFaction(squaddie, attack_target))
            {
                continue;
            }

            squaddie.knowledge.order_target  = attack_target;
            squaddie.knowledge.current_order = OrderType.ATTACK;
        }
    }
예제 #26
0
    /// <summary>
    /// Evaluates advantageous engagement positions from the flanker to the flank target, within
    /// the passed radius.
    /// </summary>
    /// <param name="_flanker">The flanking squaddie.</param>
    /// <param name="_flank_target">The target of the flank.</param>
    /// <param name="_radius">The radius to search for cover points around the flanker and flank target.</param>
    /// <returns>A list of cover points in descending order based on their distance to the flank target.</returns>
    public List <CoverPoint> FindFlankingPositions(SquaddieAI _flanker, SquaddieAI _flank_target, float _radius)
    {
        // Consider nearby cover points, as well as those near the enemy.
        var cover_to_consider = ClosestCoverPoints(_flanker.transform.position, _radius);

        cover_to_consider.AddRange(ClosestCoverPoints(_flank_target.transform.position, _radius));

        // The actual points that will be returned.
        List <CoverPoint> flanking_positions = new List <CoverPoint>();

        foreach (CoverPoint cover_point in cover_to_consider)
        {
            float distance = Vector3.Distance(_flank_target.transform.position, cover_point.position);

            bool too_far   = distance > _flanker.settings.maximum_engage_distance;
            bool too_close = distance < _flanker.settings.minimum_engage_distance;

            if (too_far || too_close)
            {
                continue;
            }

            bool bad_flank = !_flanker.TestSightToPosition(cover_point.position,
                                                           _flank_target.torso_transform.position);
            bool enemy_los = _flank_target.TestSightToPosition(cover_point.position);

            if (bad_flank || enemy_los)
            {
                continue;
            }

            // The further from the flank target the better.
            cover_point.weighting -= distance;

            // Encourage squad cohesion.
            cover_point.weighting += (cover_point.position -
                                      _flanker.knowledge.squad_sense.squad_center).magnitude;

            flanking_positions.Add(cover_point);
        }

        // The furthest flanking positions should appear first in the list.
        flanking_positions = flanking_positions.OrderBy(elem => elem.weighting).ToList();
        return(flanking_positions);
    }
예제 #27
0
    // CollisionEventForwarder event.
    public void TriggerExit(Collider _other)
    {
        if (!_other.CompareTag("DamageableBody"))
        {
            return;
        }

        SquaddieAI squaddie = _other.GetComponentInParent <SquaddieAI>();

        if (squaddie == null)
        {
            return;
        }

        if (knowledge.nearby_targets.Contains(squaddie))
        {
            knowledge.nearby_targets.Remove(squaddie);
        }
    }
예제 #28
0
    void EvaluateClosestTarget()
    {
        SquaddieAI closest_target = null;
        float      closest        = Mathf.Infinity;

        knowledge.nearby_targets.RemoveAll(elem => elem == null);
        foreach (SquaddieAI enemy in knowledge.nearby_targets)
        {
            float distance = (enemy.transform.position - transform.position).sqrMagnitude;
            if (distance > closest)
            {
                continue;
            }

            closest        = distance;
            closest_target = enemy;
        }

        knowledge.closest_target = closest_target;
    }
예제 #29
0
    public override bool PreconditionsMet(SquaddieAI _squaddie)
    {
        OrderType current_order          = _squaddie.knowledge.current_order;
        bool      eligible_to_reposition = current_order == OrderType.NONE ||
                                           current_order == OrderType.ATTACK || current_order == OrderType.GUARD;

        if (!eligible_to_reposition || _squaddie.knowledge.current_target == null)
        {
            return(false);
        }

        bool moving = _squaddie.nav.hasPath;

        if (!moving && (!_squaddie.knowledge.in_cover ||
                        _squaddie.knowledge.position_compromised))
        {
            return(true);
        }

        return(false);
    }
예제 #30
0
 public override void Trigger(SquaddieAI _squaddie)
 {
     _squaddie.knowledge.chain_gun.cycle = false;
 }