public void Update() { // TODO: timers & member boolean variables to reduce checks each frame if (!useAbilities) { return; } if (timer > Time.time) { return; } timer = Time.time + interval; // Use abilities if needed if (!ai.movement.targetIsInRange()) { if (ai.movement.DistanceToTarget > 5f) { bool allowSpeed = true; if (craft.faction == 0 && PlayerCore.Instance != null && !PlayerCore.Instance.GetIsDead() && ai.movement.GetTarget() != null) { // Don't run away or get behind when escorting a player float ownD = ((Vector2)ai.movement.GetTarget() - (Vector2)craft.transform.position).sqrMagnitude; float playerD = ((Vector2)ai.movement.GetTarget() - (Vector2)PlayerCore.Instance.transform.position).sqrMagnitude; allowSpeed = playerD < ownD; } if (allowSpeed) { var speeds = GetAbilities(1); int half = Mathf.CeilToInt(speeds.Count() / 2f); int count = 0; foreach (var booster in speeds) { booster.Activate(); if (booster.GetActiveTimeRemaining() > 0) { if (++count >= half) { break; } } } } } } if (craft.GetHealth()[0] < craft.GetMaxHealth()[0] * 0.8f) { var shellBoosts = GetAbilities(2, 17, 26, 29, 30, 31); // shell heal, shell regen, area restore foreach (var booster in shellBoosts) { if (craft.GetHealth()[0] > craft.GetMaxHealth()[0] * 0.9f) { break; } booster.Activate(); } } if (craft.GetHealth()[0] < craft.GetMaxHealth()[0] * 0.25f && Time.time > nextStealth) { var escapeAbilities = GetAbilities(24, 29, 27); // stealth, absorption, pin down foreach (var escapeAbility in escapeAbilities) { escapeAbility.Activate(); if (escapeAbility.GetActiveTimeRemaining() > 0f) { nextStealth = Time.time + escapeAbility.GetActiveTimeRemaining() + 1.0f; break; } } } if (craft.GetHealth()[0] < craft.GetMaxHealth()[0] * 0.2f) { var retreats = GetAbilities(28); // retreat foreach (var retreat in retreats) { bool CD = retreat.TimeUntilReady() > 0f; if (!CD) { retreat.Activate(); if (retreat.TimeUntilReady() > 0f) { break; } } } } if (craft.GetHealth()[1] < craft.GetMaxHealth()[1] * 0.5f) { var core = GetAbilities(11, 31); // core heal & regen foreach (var ability in core) { ability.Activate(); if (ability.GetActiveTimeRemaining() > 0) { break; } } } if (craft.GetHealth()[2] < craft.GetMaxHealth()[2] * 0.5f) { var energy = GetAbilities(12, 32); // energy add & regen foreach (var ability in energy) { ability.Activate(); if (ability.GetActiveTimeRemaining() > 0) { break; } } } var target = craft.GetTargetingSystem().GetTarget(); if (target != null && target) { Entity targetEntity = target.GetComponent <Entity>(); if (targetEntity != null && targetEntity && !targetEntity.GetIsDead()) { var damageBoosts = GetAbilities(25, 33); // damage boost, disrupt foreach (var damageBoost in damageBoosts) { damageBoost.Activate(); } // TODO: use only if the enemy is close enough! var pinDown = GetAbilities(27); // pin down if (Time.time > nextPin) { foreach (var pin in pinDown) { if (pin.GetActiveTimeRemaining() <= 0) { pin.Activate(); if (pin.GetActiveTimeRemaining() > 0f) { nextPin = Time.time + pin.GetActiveTimeRemaining() - 1.5f; // 2 sec activation time, leave 0.5 sec for fleeing break; } } } } } } if (craft is IOwner && target != null && target) { IOwner owner = craft as IOwner; if (owner.GetUnitsCommanding().Count < owner.GetTotalCommandLimit()) { var droneSpawns = GetAbilities(10); // drone spawn foreach (var droneSpawn in droneSpawns) { droneSpawn.Activate(); } } } }
private void Update() { if (!craft.GetIsDead()) { // find target Entity target = getNearestEntity <Entity>(craft.transform.position, craft.faction, true, craft.Terrain); craft.GetTargetingSystem().SetTarget(target ? target.transform : null); foreach (Ability a in craft.GetAbilities()) { if (a) { a.Tick(0); } } // shouldn't tick if dead or in cutscene, give control to the cutscene if (aggression != AIAggression.KeepMoving && aggroSearchTimer < Time.time && !DialogueSystem.isInCutscene) { // stop or follow target, give up if it's outside range if (target && (target.transform.position - craft.transform.position).sqrMagnitude < 800f) { aggroTarget = target; //Debug.Log("AggroTarget: " + aggroTarget.name + " Factions: " + aggroTarget.faction + " - " + craft.faction); } aggroSearchTimer = Time.time + 1f; } // shouldn't tick if dead or in cutscene, give control to the cutscene if (aggroTarget && !FactionManager.IsAllied(aggroTarget.faction, craft.faction) && !DialogueSystem.isInCutscene) { if (aggroTarget.GetIsDead() || aggroTarget.IsInvisible) { aggroTarget = null; aggroSearchTimer = 0f; } else { // if(craft as Drone && Input.GetKey(KeyCode.D)) Debug.Log(aggroTarget); switch (aggression) { case AIAggression.FollowInRange: var aggroPos = aggroTarget.transform.position; if (timer >= 0.3F) { timer = 0; movement.SetMoveTarget(aggroPos + new Vector3(Random.Range(-1F, 1F), Random.Range(-1F, 1F)), 9); } else { timer += Time.deltaTime; } float dist = movement.DistanceToTarget; if (dist > 1000f) { aggroTarget = null; } if (module is FollowAI && (module as FollowAI).followTarget) { if (((module as FollowAI).followTarget.position - craft.transform.position).sqrMagnitude > 150f) { aggroTarget = null; } } //// Stealth if module is not BattleAI to not interfere with it //if (!(module is BattleAI) && craft.GetHealth()[0] < craft.GetMaxHealth()[0] * 0.25f) //{ // var abilities = craft.GetAbilities(); // if(abilities != null) // { // var stealths = abilities.Where((x) => { return (x != null) && x.GetID() == 24; }); // foreach (var stealth in stealths) // { // stealth.Tick("activate"); // if (stealth.GetActiveTimeRemaining() > 0) // break; // } // } //} break; case AIAggression.StopToAttack: movement.SetMoveTarget(craft.transform.position); break; case AIAggression.KeepMoving: // Back to module's movement aggroTarget = null; break; default: break; } } } else { aggroTarget = null; aggroSearchTimer = 0f; } if (module != null) { if (state == AIState.Active) { module.StateTick(); if (aggroTarget == null) { module.ActionTick(); } if (allowRetreat) { // check if retreat necessary if (craft.GetHealth()[0] < retreatTreshold * craft.GetMaxHealth()[0]) { state = AIState.Retreating; //Debug.Log(craft.name + "[ " + craft.faction + " ] retreating!"); } } } else if (state == AIState.Retreating) { if ((!retreatTargetFound && retreatSearchTimer < Time.time) || retreatSearchTimer < Time.time) { Entity enemy = getNearestEntity <Entity>(craft.transform.position, craft.faction, true, Entity.TerrainType.All); if (enemy && (enemy.transform.position - craft.transform.position).sqrMagnitude < 1600f) { retreatTarget = craft.transform.position + (craft.transform.position - enemy.transform.position).normalized * 20f; //Debug.Log(craft.name + "[ " + craft.faction + " ] Initial retreat target : " + retreatTarget); IntRect bounds = SectorManager.instance.current.bounds; if (!bounds.contains(retreatTarget)) { retreatTarget = craft.spawnPoint; //Debug.Log(craft.name + "[ " + craft.faction + " ] Updated to Spawn point : " + retreatTarget); } // stay inside sector (just in case the spawn point is outside) if (retreatTarget.x > bounds.x + bounds.w) { retreatTarget = new Vector2(bounds.x + bounds.w, retreatTarget.y); } if (retreatTarget.x < bounds.x) { retreatTarget = new Vector2(bounds.x, retreatTarget.y); } if (retreatTarget.y < bounds.y - bounds.h) { retreatTarget = new Vector2(retreatTarget.x, bounds.y - bounds.h); } if (retreatTarget.y > bounds.y) { retreatTarget = new Vector2(retreatTarget.x, bounds.y); } retreatTargetFound = true; //Debug.Log(craft.name + "[ " + craft.faction + " ] Sector bounds: " + bounds.x + ", " + bounds.y + ", " + bounds.w + ", " + bounds.h); //Debug.Log(craft.name + "[ " + craft.faction + " ] Found a retreat target! : " + retreatTarget); } else { retreatTarget = craft.spawnPoint; retreatTargetFound = true; } retreatSearchTimer = Time.time + 3.0f; } else if (retreatTargetFound) { movement.SetMoveTarget(retreatTarget); if (movement.targetIsInRange() && retreatTarget != (Vector2)craft.spawnPoint) { retreatSearchTimer = 0f; } } else { movement.SetMoveTarget(craft.spawnPoint); } // check if retreating is still necessary if (craft.GetHealth()[0] > retreatTreshold * craft.GetMaxHealth()[0]) { state = AIState.Active; //Debug.Log(craft.name + "[ " + craft.faction + " ] stopped retreating!"); } } else { if (state == AIState.Inactive) { module.Init(); state = AIState.Active; } } } //else //{ // state = AIState.Inactive; //} movement.Update(); abilityControl.Update(); } }