using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class AIFireWeaponsSystemBrain : MonoBehaviour { [Header ("Main Settings")] [Space] public bool weaponsSystemEnabled = true; public bool drawWeaponsWhenResumingAI; public bool drawWeaponWhenAttackModeSelected; public bool keepWeaponsIfNotTargetsToAttack; public bool canDropWeaponExternallyEnabled = true; [Space] [Header ("Attack Enabled Settings")] [Space] public bool attackEnabled; [Space] [Header ("Attack Settings")] [Space] public float fireWeaponAttackRate = 0.17f; public bool setWaitTimeOnFireWeaponBlast; public Vector2 waitTimeRangeOnFireWeaponBlast; public Vector2 fireTimeRangeBeforeWaitForNextWeaponBlast; [Space] public bool checkToForceAttackIfNotUsedLongTimeAgo; public float maxWaitTimeToForceAttackIfNotUsedLongTimeAgo = 10; [Space] [Header ("Weapons Settings")] [Space] public bool changeWeaponAfterTimeEnabled; public bool changeWeaponRandomly; public Vector2 randomChangeWeaponRate; [Space] [Header ("Weapon List")] [Space] public int currentWeaponIndex; [Space] public List AIWeaponInfoList = new List (); [Space] public bool useAIWeaponRangeInfo; public List AIWeaponRangeInfoList = new List (); [Space] [Space] [Space] [Header ("Roll/Dodge Settings")] [Space] public bool rollEnabled; public Vector2 randomRollWaitTime; public float minWaitTimeAfterRollActive = 1.3f; public List rollMovementDirectionList = new List (); [Space] [Header ("Random Walk Settings")] [Space] public bool randomWalkEnabled; public Vector2 randomWalkWaitTime; public Vector2 randomWalkDuration; public Vector2 randomWalkRadius; [Space] public bool pauseFireWeaponDuringWalkEnabled = true; public bool ignoreRandomWalkInFrontDirectionEnabled = true; [Space] [Header ("Jump To Target Settings")] [Space] public bool jumpToTargetOnRangeDistance; public Vector2 rangeDistanceToJumpToTarget; public bool avoidAttackOnAir = true; public float minTimeToJumpAgain = 4; public bool useJumpProbability; [Range (0, 100)] public float jumpProbability; [Space] public bool setNewJumpForce; public float newJumpForce; public bool setNewJumpForceMinDistance; public float newJumpForceMinDistance; [Space] [Header ("Other Settings")] [Space] public bool changeWaitToActivateAttackEnabled = true; public bool activateRandomWalkIfWaitToActivateAttackActive; public bool checkIfAttackInProcessBeforeCallingNextAttack = true; public bool checkInitialWeaponsOnCharacterSpawnEnabled = true; public bool useWaitToActivateAttackActiveCounter; [Space] [Header ("Search Weapons On Scene Settings")] [Space] public bool searchWeaponsPickupsOnLevelIfNoWeaponsAvailable; public bool useMaxDistanceToGetPickupWeapon; public float maxDistanceToGetPickupWeapon; public bool ignoreCheckIfUsableWeaponsPrefabListActive; [Space] public bool useEventOnNoWeaponToPickFromScene; public UnityEvent eventOnNoWeaponToPickFromScene; [Space] public bool useEventsOnNoWeaponsAvailable; public bool useEventsOnNoWeaponsAvailableAfterCheckWeaponsOnScene; public UnityEvent eventOnNoWeaponsAvailable; [Space] [Header ("Steal Weapons From Targets Settings")] [Space] public bool stealWeaponFromCurrentTarget; [Range (0, 100)] public float probabilityToStealWeapon = 0; public bool stealWeaponOnlyIfNotPickupsLocated; public bool useMaxDistanceToStealWeapon; public float maxDistanceToGetStealWeapon; [Space] public bool useEventOnSteal; public UnityEvent eventOnStealWeapon; [Space] [Header ("Debug")] [Space] public bool showDebugPrint; public bool weaponsSystemActive; public bool weaponEquiped; public bool aimingWeapon; public bool waitingForAttackActive; float currentRandomTimeToAttack; public bool shootingWeapon; public bool canUseAttackActive; [Space] public bool walkActive; public bool waitingWalkActive; public bool waitingRollActive; [Space] public bool attackStatePaused; public bool insideMinDistanceToAttack; public bool searchingWeapon; public bool characterHasWeapons; public bool behaviorStatesPaused; public bool checkingToChangeWeaponActive; public bool onSpotted; public bool changeWeaponCheckActive; public bool waitToActivateAttackActive; public int waitToActivateAttackActiveCounter = 0; public GameObject currentWeaponToGet; public bool turnBasedCombatActionActive; public bool ignoreOtherActionsToForceAttackActive; [Space] [Space] public float currentPathDistanceToTarget; public float minDistanceToAim; public float minDistanceToDraw; public float minDistanceToShoot; [Space] public bool checkCharacterToAttackRadiusActive; public float currentCharacterToAttackRadius; [Space] [Header ("Events Settings")] [Space] public bool useEventsOnCombatActive; public UnityEvent eventOnCombatActive; public UnityEvent eventOnCombatDeactivate; [Space] public eventParameters.eventToCallWithString eventToChangeAttackMode; [Space] [Header ("Components")] [Space] public playerWeaponsManager mainPlayerWeaponsManager; public dashSystem mainDashSystem; public findObjectivesSystem mainFindObjectivesSystem; public AINavMesh mainAINavmeshManager; float lastTimeAttack; int currentAttackTypeIndex; bool weaponInfoStored; int currentAttackIndex; int currentAttackTypeToAlternateIndex; float lastTimeRollActive; float lastTimeWaitRollActive; float currentRollWaitTime; float lastTimeWaitWalkActive; float currentWalkTime; float lastTimeWalkActive; float currentWalkDuration; float currentWalkRadius; bool rollCoolDownActive; float currentPauseAttackStateDuration; float lastTimeAttackPauseWithDuration; bool checkIfDrawWeaponActive; float randomWaitTime; float lastTimeFireWeaponAttackAtDistance; bool checkIfAICarryingWeapon; bool checkIfSearchWeapon; bool AIPaused; bool cancelCheckAttackState; float lastTimeChangeWeapon; float timeToChangeWeapon; AIWeaponInfo currentAIWeaponInfo; bool originalRandomWalkEnabled; float lastTimeWeaponPicked = 0; string currentWeaponNameToPick; float currentMinTimeToUseNewWeaponAfterChange; float lastTimeWeaponEquippedChecked; float lastTimeJump; bool waitingForNextFireWeaponBlastActive; float lastTimeWaitingForNextFireWeaponBlastActive; float currentWaitTimeRangeOnFireWeaponBlast; float currentFireTimeRangeBeforeWaitForNextWeaponBlast; float lastTimeSettingFireWeaponBlast; bool useAIWeaponRangeInfoActive; float customMinDistanceToDraw; float customMinDistanceToAim; float customMinDistanceToShoot; float customMinDistanceToEnemyUsingWeapons; void Start () { originalRandomWalkEnabled = randomWalkEnabled; lastTimeWeaponEquippedChecked = Time.time; } public void updateAI () { if (weaponsSystemActive) { AIPaused = mainFindObjectivesSystem.isAIPaused (); if (!AIPaused) { if (!checkIfAICarryingWeapon) { if (Time.time > lastTimeWeaponEquippedChecked + 0.4f) { if (mainPlayerWeaponsManager.isPlayerCarringWeapon ()) { weaponEquiped = true; } checkIfAICarryingWeapon = true; } } if (walkActive) { if (Time.time > lastTimeWalkActive + 1) { if (Time.time > lastTimeWalkActive + currentWalkDuration || mainFindObjectivesSystem.getRemainingPathDistanceToTarget () < 0.5f || mainFindObjectivesSystem.getCurrentDistanceToTarget () < 0.5f) { resetRandomWalkState (); } } } if (searchingWeapon) { bool weaponReached = false; if (currentWeaponToGet != null) { if (GKC_Utils.distance (mainAINavmeshManager.transform.position, currentWeaponToGet.transform.position) < 1) { weaponPickup currentWeaponPickup = currentWeaponToGet.GetComponent (); if (currentWeaponPickup != null) { if (showDebugPrint) { print ("picking weapon " + currentWeaponToGet.name); } simpleActionButton currentSimpleActionButton = currentWeaponToGet.GetComponentInChildren (); if (currentSimpleActionButton != null) { mainFindObjectivesSystem.takeObject (currentSimpleActionButton.gameObject); } weaponReached = true; } } } else { weaponReached = true; } if (weaponReached) { characterHasWeapons = mainPlayerWeaponsManager.checkIfWeaponsAvailable () || (!ignoreCheckIfUsableWeaponsPrefabListActive && mainPlayerWeaponsManager.checkIfUsableWeaponsPrefabListActive ()); mainFindObjectivesSystem.setSearchigWeaponState (false); searchingWeapon = false; checkIfSearchWeapon = false; currentWeaponToGet = null; mainFindObjectivesSystem.setIgnoreVisionRangeActiveState (true); mainFindObjectivesSystem.resetAITargets (); mainFindObjectivesSystem.setIgnoreVisionRangeActiveState (false); mainPlayerWeaponsManager.repairObjectFully (currentWeaponNameToPick); lastTimeWeaponPicked = Time.time; if (showDebugPrint) { print ("Weapon picked, resuming state on AI"); } } } if (jumpToTargetOnRangeDistance) { checkJumpState (); } } } } void checkJumpState () { if (mainFindObjectivesSystem.isActionActive ()) { return; } if (!insideMinDistanceToAttack && !searchingWeapon && mainFindObjectivesSystem.isAIOnGround () && mainFindObjectivesSystem.isOnSpotted () && (lastTimeJump == 0 || Time.time > minTimeToJumpAgain + lastTimeJump)) { float distanceToTarget = mainFindObjectivesSystem.getDistanceToTarget (); if (distanceToTarget > rangeDistanceToJumpToTarget.x && distanceToTarget < rangeDistanceToJumpToTarget.y) { bool activateJumpResult = true; if (useJumpProbability) { float currentProbability = Random.Range (0, 100); if (currentProbability > jumpProbability) { useJumpProbability = false; } } if (activateJumpResult) { bool setNewJumpForceResult = setNewJumpForce; if (setNewJumpForceMinDistance) { if (distanceToTarget < newJumpForceMinDistance) { setNewJumpForceResult = false; } } if (setNewJumpForceResult) { mainFindObjectivesSystem.setJumpPower (newJumpForce); mainFindObjectivesSystem.activateJumpExternally (0); } else { mainFindObjectivesSystem.setOriginalJumpPower (); mainFindObjectivesSystem.activateJumpExternally (distanceToTarget); } } lastTimeJump = Time.time; } } } public void resetRandomWalkState () { mainFindObjectivesSystem.setRandomWalkPositionState (0); waitingWalkActive = false; walkActive = false; lastTimeWalkActive = Time.time; } public void resetRollState () { waitingRollActive = false; lastTimeRollActive = Time.time; } public void resetStates () { resetRandomWalkState (); resetRollState (); } public void checkIfResetStatsOnRandomWalk () { if (walkActive) { resetStates (); } } public void checkRollState () { if (ignoreOtherActionsToForceAttackActive) { return; } if (rollEnabled) { if (walkActive) { return; } if (!insideMinDistanceToAttack) { resetRollState (); lastTimeRollActive = 0; return; } if (waitingRollActive) { if (Time.time > lastTimeWaitRollActive + currentRollWaitTime) { int randomRollMovementDirection = Random.Range (0, rollMovementDirectionList.Count); Vector3 dashDirection = rollMovementDirectionList [randomRollMovementDirection]; if (mainFindObjectivesSystem.isLocked2_5dModeActive ()) { randomRollMovementDirection = Random.Range (0, 2); if (randomRollMovementDirection == 0) { dashDirection = Vector3.forward; } else { dashDirection = -Vector3.forward; } } mainDashSystem.activateDashStateWithCustomDirection (dashDirection); resetRollState (); } } else { if (Time.time > lastTimeRollActive + randomWaitTime) { currentRollWaitTime = Random.Range (randomRollWaitTime.x, randomRollWaitTime.y); lastTimeWaitRollActive = Time.time; waitingRollActive = true; randomWaitTime = Random.Range (0.1f, 0.5f); } } } } public void checkWalkState () { if (ignoreOtherActionsToForceAttackActive) { return; } if (randomWalkEnabled) { if (rollEnabled) { if (lastTimeRollActive != 0) { rollCoolDownActive = Time.time < lastTimeRollActive + 0.7f; if (rollCoolDownActive) { return; } } } if (waitingWalkActive) { if (!walkActive) { if (Time.time > lastTimeWaitWalkActive + currentWalkTime) { mainFindObjectivesSystem.setignoreRandomWalkInFrontDirectionEnabledState (ignoreRandomWalkInFrontDirectionEnabled); mainFindObjectivesSystem.setRandomWalkPositionState (currentWalkRadius); lastTimeWalkActive = Time.time; walkActive = true; } } } else { currentWalkTime = Random.Range (randomWalkWaitTime.x, randomWalkWaitTime.y); lastTimeWaitWalkActive = Time.time; waitingWalkActive = true; currentWalkDuration = Random.Range (randomWalkDuration.x, randomWalkDuration.y); currentWalkRadius = Random.Range (randomWalkRadius.x, randomWalkRadius.y); walkActive = false; } } } public void updateInsideMinDistance (bool newInsideMinDistanceToAttack) { insideMinDistanceToAttack = newInsideMinDistanceToAttack; if (mainFindObjectivesSystem.isAttackAlwaysOnPlace ()) { insideMinDistanceToAttack = true; } if (insideMinDistanceToAttack) { if (checkIfDrawWeaponActive) { if (!mainPlayerWeaponsManager.isPlayerCarringWeapon ()) { setDrawOrHolsterWeaponState (true); } checkIfDrawWeaponActive = false; } } else { if (aimingWeapon && !mainFindObjectivesSystem.isAttackTargetDirectlyActive ()) { setAimWeaponState (false); } } } void updateLookAtTargetIfBehaviorPaused () { cancelCheckAttackState = false; if (mainFindObjectivesSystem.isAttackTargetDirectlyActive ()) { mainFindObjectivesSystem.setLookingAtTargetPositionState (true); mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); } else { currentPathDistanceToTarget = mainFindObjectivesSystem.currentPathDistanceToTarget; if (useAIWeaponRangeInfoActive) { minDistanceToAim = customMinDistanceToDraw; minDistanceToDraw = customMinDistanceToAim; minDistanceToShoot = customMinDistanceToShoot; } else { minDistanceToAim = mainFindObjectivesSystem.minDistanceToAim; minDistanceToDraw = mainFindObjectivesSystem.minDistanceToDraw; minDistanceToShoot = mainFindObjectivesSystem.minDistanceToShoot; } bool useHalfMinDistance = mainAINavmeshManager.isUseHalfMinDistanceActive (); if (useHalfMinDistance) { mainFindObjectivesSystem.setLookingAtTargetPositionState (false); cancelCheckAttackState = true; } else { if (checkCharacterToAttackRadiusActive) { if (currentCharacterToAttackRadius < currentPathDistanceToTarget) { currentPathDistanceToTarget -= currentCharacterToAttackRadius; } } if (currentPathDistanceToTarget <= minDistanceToAim) { mainFindObjectivesSystem.setLookingAtTargetPositionState (true); mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); } else { if (currentPathDistanceToTarget >= minDistanceToAim + 1.5f) { mainFindObjectivesSystem.setLookingAtTargetPositionState (false); cancelCheckAttackState = true; } else { if (mainFindObjectivesSystem.isLookingAtTargetPosition ()) { mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); } } } } } } public void updateMainFireWeaponsBehavior () { if (!weaponsSystemActive) { return; } if (AIPaused) { return; } if (behaviorStatesPaused) { updateLookAtTargetIfBehaviorPaused (); return; } if (checkToForceAttackIfNotUsedLongTimeAgo) { if (lastTimeAttack > 0 && !ignoreOtherActionsToForceAttackActive) { if (Time.time > maxWaitTimeToForceAttackIfNotUsedLongTimeAgo + lastTimeAttack) { ignoreOtherActionsToForceAttackActive = true; resetRandomWalkState (); resetRollState (); if (showDebugPrint) { print ("too much time since last attack active, reseting other states" + " to force an attack"); } } } } checkWalkState (); bool ignoreRollStateResult = false; if (walkActive) { if (pauseFireWeaponDuringWalkEnabled) { return; } else { ignoreRollStateResult = true; } } if (!ignoreRollStateResult) { checkRollState (); if (rollEnabled) { if (Time.time < lastTimeRollActive + minWaitTimeAfterRollActive) { return; } } } if (characterHasWeapons) { cancelCheckAttackState = false; if (mainFindObjectivesSystem.isAttackTargetDirectlyActive ()) { if (attackEnabled) { mainFindObjectivesSystem.setLookingAtTargetPositionState (true); mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); if (changeWeaponCheckActive) { if (Time.time < lastTimeChangeWeapon + currentMinTimeToUseNewWeaponAfterChange) { return; } else { changeWeaponCheckActive = false; } } if (!weaponEquiped) { setDrawOrHolsterWeaponState (true); } else { if (!aimingWeapon) { if (mainPlayerWeaponsManager.currentWeaponWithHandsInPosition () && mainPlayerWeaponsManager.isPlayerCarringWeapon () && !mainPlayerWeaponsManager.currentWeaponIsMoving ()) { setAimWeaponState (true); } } if (aimingWeapon) { if (!mainPlayerWeaponsManager.currentWeaponIsMoving () && mainPlayerWeaponsManager.reloadingActionNotActive () && mainPlayerWeaponsManager.isPlayerCarringWeapon () && mainFindObjectivesSystem.checkIfMinimumAngleToAttack () && !mainPlayerWeaponsManager.isActionActiveInPlayer () && mainPlayerWeaponsManager.canPlayerMove ()) { bool canShootResult = getCanShootResult (); if (canShootResult) { shootTarget (); } else { if (shootingWeapon) { setShootWeaponState (false); } } } } } } } else { currentPathDistanceToTarget = mainFindObjectivesSystem.currentPathDistanceToTarget; if (checkCharacterToAttackRadiusActive) { if (currentCharacterToAttackRadius < currentPathDistanceToTarget) { currentPathDistanceToTarget -= currentCharacterToAttackRadius; } } if (useAIWeaponRangeInfoActive) { minDistanceToAim = customMinDistanceToDraw; minDistanceToDraw = customMinDistanceToAim; minDistanceToShoot = customMinDistanceToShoot; } else { minDistanceToAim = mainFindObjectivesSystem.minDistanceToAim; minDistanceToDraw = mainFindObjectivesSystem.minDistanceToDraw; minDistanceToShoot = mainFindObjectivesSystem.minDistanceToShoot; } bool useHalfMinDistance = mainAINavmeshManager.isUseHalfMinDistanceActive (); bool checkTargetNotVisibleForObstacleResult = false; if (useHalfMinDistance) { if (lastTimeHalfMinDistanceActive == 0) { lastTimeHalfMinDistanceActive = Time.time; } else { if (Time.time > lastTimeHalfMinDistanceActive + 0.6f) { checkTargetNotVisibleForObstacleResult = true; } } } else { if (lastTimeHalfMinDistanceActive != 0) { lastTimeHalfMinDistanceActive = 0; } } if (checkTargetNotVisibleForObstacleResult) { if (!changeWeaponCheckActive) { if (aimingWeapon) { setAimWeaponState (false); } } mainFindObjectivesSystem.setLookingAtTargetPositionState (false); cancelCheckAttackState = true; } else { if (currentPathDistanceToTarget <= minDistanceToAim) { if (!changeWeaponCheckActive) { if (!aimingWeapon) { if (mainPlayerWeaponsManager.currentWeaponWithHandsInPosition () && mainPlayerWeaponsManager.isPlayerCarringWeapon () && !mainPlayerWeaponsManager.currentWeaponIsMoving ()) { setAimWeaponState (true); } } } mainFindObjectivesSystem.setLookingAtTargetPositionState (true); mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); } else { if (currentPathDistanceToTarget >= minDistanceToAim + 1.5f) { if (!changeWeaponCheckActive) { if (aimingWeapon) { setAimWeaponState (false); } } mainFindObjectivesSystem.setLookingAtTargetPositionState (false); cancelCheckAttackState = true; } else { if (mainFindObjectivesSystem.isLookingAtTargetPosition ()) { mainFindObjectivesSystem.lookAtCurrentPlaceToShoot (); } } } if (!changeWeaponCheckActive) { if (!weaponEquiped && currentPathDistanceToTarget <= minDistanceToDraw) { setDrawOrHolsterWeaponState (true); } } } if (changeWeaponCheckActive) { if (Time.time < lastTimeChangeWeapon + currentMinTimeToUseNewWeaponAfterChange) { return; } else { changeWeaponCheckActive = false; } } } checkAttackState (); if (waitToActivateAttackActive) { if (activateRandomWalkIfWaitToActivateAttackActive) { if (!walkActive) { currentWalkTime = Random.Range (randomWalkWaitTime.x, randomWalkWaitTime.y); currentWalkDuration = Random.Range (randomWalkDuration.x, randomWalkDuration.y); currentWalkRadius = Random.Range (randomWalkRadius.x, randomWalkRadius.y); mainFindObjectivesSystem.setignoreRandomWalkInFrontDirectionEnabledState (ignoreRandomWalkInFrontDirectionEnabled); mainFindObjectivesSystem.setRandomWalkPositionState (currentWalkRadius); lastTimeWalkActive = Time.time; walkActive = true; } } return; } } else { checkNoFireWeaponsAvailableState (); } } float lastTimeHalfMinDistanceActive = 0; public void checkNoFireWeaponsAvailableState () { if (!weaponsSystemActive) { return; } if (!searchingWeapon && !checkIfSearchWeapon) { if (lastTimeWeaponPicked > 0) { if (Time.time < lastTimeWeaponPicked + 0.75f) { if (showDebugPrint) { print ("NO; WAITING TO WEAPON PICKED\n\n"); } return; } else { lastTimeWeaponPicked = 0; } } characterHasWeapons = mainPlayerWeaponsManager.checkIfWeaponsAvailable () || (!ignoreCheckIfUsableWeaponsPrefabListActive && mainPlayerWeaponsManager.checkIfUsableWeaponsPrefabListActive ()); //seach for the closest weapon if (!characterHasWeapons) { if (!stealWeaponOnlyIfNotPickupsLocated) { if (checkIfStealWeaponFromCurrentTarget ()) { return; } } if (!useEventsOnNoWeaponsAvailableAfterCheckWeaponsOnScene) { checkEventOnNoWeaponsAvailable (); } bool weaponFound = false; if (searchWeaponsPickupsOnLevelIfNoWeaponsAvailable) { checkIfSearchWeapon = true; if (showDebugPrint) { print ("checking if weapons found on scene"); } weaponPickup [] weaponPickupList = FindObjectsOfType (typeof (weaponPickup)) as weaponPickup []; List weaponObjectsDetected = new List (); if (weaponPickupList.Length > 0) { for (int i = 0; i < weaponPickupList.Length; i++) { bool checkObjectResult = true; if (useMaxDistanceToGetPickupWeapon) { float distance = GKC_Utils.distance (weaponPickupList [i].transform.position, mainAINavmeshManager.transform.position); if (distance > maxDistanceToGetPickupWeapon) { checkObjectResult = false; } } if (checkObjectResult) { weaponObjectsDetected.Add (weaponPickupList [i].gameObject); } } } if (weaponObjectsDetected.Count == 0) { if (showDebugPrint) { print ("no pickups detected, searching for physical objects"); } } if (weaponObjectsDetected.Count > 0) { if (showDebugPrint) { print ("weapons found on scene"); } string currentWeaponName = ""; for (int i = 0; i < weaponObjectsDetected.Count; i++) { if (!weaponFound) { currentWeaponName = ""; weaponPickup currentWeaponPickup = weaponObjectsDetected [i].GetComponent (); if (currentWeaponPickup != null) { currentWeaponName = currentWeaponPickup.weaponName; } currentWeaponNameToPick = currentWeaponName; if (showDebugPrint) { print ("checking if weapon with name " + currentWeaponName + " can be used"); } if (mainPlayerWeaponsManager.checkIfWeaponCanBePicked (currentWeaponPickup.weaponName)) { if (mainAINavmeshManager.updateCurrentNavMeshPath (weaponObjectsDetected [i].transform.position)) { mainFindObjectivesSystem.setSearchigWeaponState (true); currentWeaponToGet = weaponObjectsDetected [i]; mainAINavmeshManager.setTarget (weaponObjectsDetected [i].transform); mainAINavmeshManager.setTargetType (false, true); weaponFound = true; mainAINavmeshManager.lookAtTaget (false); if (showDebugPrint) { print ("weapon to use located, setting searching weapon state on AI"); } searchingWeapon = true; } } else { if (showDebugPrint) { print ("weapon " + currentWeaponName + " can't be used"); } } } } } else { if (showDebugPrint) { print ("no pickups or physical objects found"); } } if (!weaponFound) { if (stealWeaponOnlyIfNotPickupsLocated) { if (checkIfStealWeaponFromCurrentTarget ()) { return; } } if (useEventOnNoWeaponToPickFromScene) { eventOnNoWeaponToPickFromScene.Invoke (); } } } if (!weaponFound) { if (stealWeaponOnlyIfNotPickupsLocated) { if (checkIfStealWeaponFromCurrentTarget ()) { return; } } if (showDebugPrint) { print ("no weapons located or out of range, activating no weapons detected mode"); } if (useEventsOnNoWeaponsAvailableAfterCheckWeaponsOnScene) { checkEventOnNoWeaponsAvailable (); } } //it will need to check if the weapon can be seen by the character and if it is can be reached by the navmesh } mainFindObjectivesSystem.setLookingAtTargetPositionState (false); } } void checkEventOnNoWeaponsAvailable () { if (useEventsOnNoWeaponsAvailable) { eventOnNoWeaponsAvailable.Invoke (); } } bool checkIfStealWeaponFromCurrentTarget () { if (stealWeaponFromCurrentTarget) { if (showDebugPrint) { print ("Checking probability to steal weapon"); } float currentProbability = Random.Range (0, 100); if (currentProbability < probabilityToStealWeapon) { if (showDebugPrint) { print ("AI can check if steal object, checking target state"); } GameObject currentTarget = mainFindObjectivesSystem.getCurrentTargetToAttack (); if (currentTarget != null) { if (useMaxDistanceToStealWeapon) { float distance = GKC_Utils.distance (currentTarget.transform.position, mainAINavmeshManager.transform.position); if (distance > maxDistanceToGetStealWeapon) { return false; } } playerComponentsManager currentPlayerComponentsManager = currentTarget.GetComponent (); if (currentPlayerComponentsManager != null) { playerController currentPlayerController = currentPlayerComponentsManager.getPlayerController (); if (currentPlayerController.isPlayerUsingWeapons ()) { if (showDebugPrint) { print ("target is using fire weapons, checking weapon it self"); } playerWeaponsManager currentPlayerWeaponsManager = currentPlayerComponentsManager.getPlayerWeaponsManager (); if (currentPlayerWeaponsManager.canWeaponsBeStolenFromCharacter ()) { string currentWeaponName = currentPlayerWeaponsManager.getCurrentWeaponName (); if (showDebugPrint) { print (currentWeaponName + " is the weapon detected, checking if can be picked"); } if (mainPlayerWeaponsManager.checkIfWeaponCanBePicked (currentWeaponName)) { if (currentPlayerController.isCharacterUsedByAI ()) { currentPlayerWeaponsManager.dropCurrentWeaponExternallyWithoutResultAndDestroyIt (); } else { inventoryManager currentInventoryManager = currentPlayerComponentsManager.getInventoryManager (); if (currentInventoryManager != null) { currentInventoryManager.removeObjectAmountFromInventoryByName (currentWeaponName, 1); } } mainPlayerWeaponsManager.equipWeapon (currentWeaponName, false, false, "", ""); mainPlayerWeaponsManager.repairObjectFully (currentWeaponName); currentPlayerWeaponsManager.checkEventOnWeaponStolen (); if (showDebugPrint) { print ("weapon stolen from target"); } if (useEventOnSteal) { eventOnStealWeapon.Invoke (); } return true; } else { if (showDebugPrint) { print ("AI can't use weapon from target"); } } } } else { if (showDebugPrint) { print ("target is not using fire weapons"); } } } } } } return false; } public void checkAttackState () { if (!attackEnabled) { return; } if (!insideMinDistanceToAttack) { return; } if (currentPauseAttackStateDuration > 0) { if (Time.time > currentPauseAttackStateDuration + lastTimeAttackPauseWithDuration) { attackStatePaused = false; currentPauseAttackStateDuration = 0; } else { return; } } if (!canUseAttackActive) { return; } if (!aimingWeapon && !cancelCheckAttackState) { setAimWeaponState (true); } // if (showDebugPrint) { // print ("check to fire"); // } if (mainFindObjectivesSystem.isOnSpotted ()) { if (!onSpotted) { onSpotted = true; } } else { if (onSpotted) { onSpotted = false; checkingToChangeWeaponActive = false; } } if (jumpToTargetOnRangeDistance && avoidAttackOnAir) { if (!mainFindObjectivesSystem.isAIOnGround ()) { return; } } if (onSpotted) { if (changeWeaponAfterTimeEnabled) { if (!checkingToChangeWeaponActive) { if (!changeWeaponCheckActive) { lastTimeChangeWeapon = Time.time; checkingToChangeWeaponActive = true; timeToChangeWeapon = Random.Range (randomChangeWeaponRate.x, randomChangeWeaponRate.y); } } else { if (Time.time > lastTimeChangeWeapon + timeToChangeWeapon) { if (!mainPlayerWeaponsManager.currentWeaponIsMoving () && mainPlayerWeaponsManager.reloadingActionNotActive () && mainPlayerWeaponsManager.isPlayerCarringWeapon () && mainFindObjectivesSystem.checkIfMinimumAngleToAttack () && !mainPlayerWeaponsManager.isActionActiveInPlayer () && mainPlayerWeaponsManager.canPlayerMove ()) { string previousWeaponName = ""; if (currentAIWeaponInfo != null) { previousWeaponName = currentAIWeaponInfo.Name; } setNextWeapon (); if (previousWeaponName != currentAIWeaponInfo.Name) { setShootWeaponState (false); aimingWeapon = false; currentMinTimeToUseNewWeaponAfterChange = currentAIWeaponInfo.minTimeToUseNewWeaponAfterChange; mainPlayerWeaponsManager.changeCurrentWeaponByName (currentAIWeaponInfo.Name); changeWeaponCheckActive = true; lastTimeChangeWeapon = Time.time; resetSetWaitTimeOnFireWeaponBlastValues (); } } } } } } if (changeWeaponCheckActive) { if (Time.time < lastTimeChangeWeapon + currentMinTimeToUseNewWeaponAfterChange) { return; } else { changeWeaponCheckActive = false; } } if (Time.time > fireWeaponAttackRate + lastTimeFireWeaponAttackAtDistance) { if (weaponEquiped && aimingWeapon && currentPathDistanceToTarget <= minDistanceToShoot && !mainPlayerWeaponsManager.currentWeaponIsMoving () && mainPlayerWeaponsManager.reloadingActionNotActive () && mainPlayerWeaponsManager.isPlayerCarringWeapon () && mainFindObjectivesSystem.checkIfMinimumAngleToAttack () && !mainPlayerWeaponsManager.isActionActiveInPlayer () && mainPlayerWeaponsManager.canPlayerMove ()) { bool canShootResult = getCanShootResult (); if (canShootResult) { shootTarget (); } else { if (shootingWeapon) { setShootWeaponState (false); } } } lastTimeFireWeaponAttackAtDistance = Time.time; } } bool getCanShootResult () { bool canShootResult = true; if (setWaitTimeOnFireWeaponBlast) { if (waitingForNextFireWeaponBlastActive) { if (Time.time > lastTimeWaitingForNextFireWeaponBlastActive + currentWaitTimeRangeOnFireWeaponBlast) { waitingForNextFireWeaponBlastActive = false; } else { canShootResult = false; } } else { if (currentFireTimeRangeBeforeWaitForNextWeaponBlast == 0) { currentFireTimeRangeBeforeWaitForNextWeaponBlast = Random.Range (fireTimeRangeBeforeWaitForNextWeaponBlast.x, fireTimeRangeBeforeWaitForNextWeaponBlast.y); lastTimeSettingFireWeaponBlast = Time.time; } else { if (Time.time > currentFireTimeRangeBeforeWaitForNextWeaponBlast + lastTimeSettingFireWeaponBlast) { lastTimeWaitingForNextFireWeaponBlastActive = Time.time; waitingForNextFireWeaponBlastActive = true; currentFireTimeRangeBeforeWaitForNextWeaponBlast = 0; currentWaitTimeRangeOnFireWeaponBlast = Random.Range (waitTimeRangeOnFireWeaponBlast.x, waitTimeRangeOnFireWeaponBlast.y); } } } } // print (canShootResult); return canShootResult; } void resetSetWaitTimeOnFireWeaponBlastValues () { currentFireTimeRangeBeforeWaitForNextWeaponBlast = 0; waitingForNextFireWeaponBlastActive = false; lastTimeSettingFireWeaponBlast = 0; } public void updateMainFireWeaponsAttack (bool newCanUseAttackActiveState) { canUseAttackActive = newCanUseAttackActiveState; } public void setNextWeapon () { bool newWeaponIndexFound = false; int newWeaponIndex = -1; if (changeWeaponRandomly) { int counter = 0; while (!newWeaponIndexFound) { newWeaponIndex = Random.Range (0, AIWeaponInfoList.Count); if (newWeaponIndex != currentWeaponIndex) { if (AIWeaponInfoList [newWeaponIndex].weaponEnabled) { newWeaponIndexFound = true; } } counter++; if (counter > 100) { if (showDebugPrint) { print ("COUNTER LOOP"); newWeaponIndexFound = true; } newWeaponIndex = 0; } } } else { newWeaponIndex = currentWeaponIndex; while (!newWeaponIndexFound) { newWeaponIndex++; if (newWeaponIndex >= AIWeaponInfoList.Count) { newWeaponIndex = 0; } if (AIWeaponInfoList [newWeaponIndex].weaponEnabled) { newWeaponIndexFound = true; } } } if (newWeaponIndex > -1) { setNewWeaponByName (AIWeaponInfoList [newWeaponIndex].Name); if (showDebugPrint) { print ("changing weapon to " + AIWeaponInfoList [newWeaponIndex].Name); } } checkingToChangeWeaponActive = false; } public void setNewWeaponByName (string weaponName) { if (!weaponsSystemEnabled) { return; } int newWeaponIndex = AIWeaponInfoList.FindIndex (s => s.Name.Equals (weaponName)); if (newWeaponIndex > -1) { if (currentAIWeaponInfo != null) { currentAIWeaponInfo.isCurrentWeapon = false; } currentAIWeaponInfo = AIWeaponInfoList [newWeaponIndex]; currentAIWeaponInfo.isCurrentWeapon = true; currentWeaponIndex = newWeaponIndex; } } public void setWeaponsSystemActiveState (bool state) { if (!weaponsSystemEnabled) { return; } weaponsSystemActive = state; checkEventsOnCombatStateChange (weaponsSystemActive); if (weaponsSystemActive && drawWeaponWhenAttackModeSelected && !mainPlayerWeaponsManager.isPlayerCarringWeapon ()) { setDrawOrHolsterWeaponState (true); } onSpotted = false; changeWeaponCheckActive = false; lastTimeAttack = 0; waitToActivateAttackActive = false; waitToActivateAttackActiveCounter = 0; checkCharacterToAttackRadiusActive = false; } void checkEventsOnCombatStateChange (bool state) { if (useEventsOnCombatActive) { if (state) { eventOnCombatActive.Invoke (); } else { eventOnCombatDeactivate.Invoke (); } } } public void pauseAttackDuringXTime (float newDuration) { currentPauseAttackStateDuration = newDuration; lastTimeAttackPauseWithDuration = Time.time; attackStatePaused = true; } public void setWaitToActivateAttackActiveState (bool state) { if (!changeWaitToActivateAttackEnabled) { return; } if (useWaitToActivateAttackActiveCounter) { if (state) { waitToActivateAttackActiveCounter++; } else { waitToActivateAttackActiveCounter--; if (waitToActivateAttackActiveCounter < 0) { waitToActivateAttackActiveCounter = 0; } } if (waitToActivateAttackActiveCounter > 0) { if (waitToActivateAttackActive) { return; } else { state = true; } } else { if (!waitToActivateAttackActive) { return; } else { state = false; } } } waitToActivateAttackActive = state; if (activateRandomWalkIfWaitToActivateAttackActive) { if (state) { currentWalkTime = Random.Range (randomWalkWaitTime.x, randomWalkWaitTime.y); currentWalkDuration = Random.Range (randomWalkDuration.x, randomWalkDuration.y); currentWalkRadius = Random.Range (randomWalkRadius.x, randomWalkRadius.y); mainFindObjectivesSystem.setignoreRandomWalkInFrontDirectionEnabledState (ignoreRandomWalkInFrontDirectionEnabled); mainFindObjectivesSystem.setRandomWalkPositionState (currentWalkRadius); lastTimeWalkActive = Time.time; walkActive = true; } else { if (walkActive) { resetRandomWalkState (); } } } } public void setUseRandomWalkEnabledState (bool state) { randomWalkEnabled = state; } public void setOriginalUseRandomWalkEnabledState () { setUseRandomWalkEnabledState (originalRandomWalkEnabled); } public void resetBehaviorStates () { resetStates (); waitingForAttackActive = false; checkIfDrawWeaponActive = true; if (keepWeaponsIfNotTargetsToAttack) { setDrawOrHolsterWeaponState (false); } else { setAimWeaponState (false); } insideMinDistanceToAttack = false; } public void setDrawOrHolsterWeaponState (bool state) { if (state) { mainPlayerWeaponsManager.drawCurrentWeaponWhenItIsReady (true); } else { mainPlayerWeaponsManager.drawOrKeepWeapon (false); } weaponEquiped = state; if (!weaponEquiped) { aimingWeapon = false; resetSetWaitTimeOnFireWeaponBlastValues (); } if (showDebugPrint) { print ("setting draw weapon state " + state); } //if (state) { // if (useAIWeaponRangeInfo) { // checkWeaponRangeInfo (); // } //} } public void setAimWeaponState (bool state) { if (showDebugPrint) { print ("setting aim active state " + state); } if (state) { if (!aimingWeapon) { mainPlayerWeaponsManager.aimCurrentWeaponWhenItIsReady (true); lastTimeFireWeaponAttackAtDistance = Time.time; } } else { if (aimingWeapon) { mainPlayerWeaponsManager.stopAimCurrentWeaponWhenItIsReady (true); } } aimingWeapon = state; if (!aimingWeapon) { resetSetWaitTimeOnFireWeaponBlastValues (); } } public void setShootWeaponState (bool state) { mainPlayerWeaponsManager.shootWeapon (state); shootingWeapon = state; if (state) { lastTimeAttack = Time.time; ignoreOtherActionsToForceAttackActive = false; } } public void dropWeapon () { if (!weaponsSystemActive) { return; } if (AIPaused) { return; } if (behaviorStatesPaused) { return; } if (!canDropWeaponExternallyEnabled) { return; } if (shootingWeapon) { setShootWeaponState (false); } if (mainPlayerWeaponsManager.dropWeaponCheckingMinDelay ()) { aimingWeapon = false; resetAttackState (); updateWeaponsAvailableState (); if (characterHasWeapons) { setDrawOrHolsterWeaponState (true); } resetSetWaitTimeOnFireWeaponBlastValues (); } } float lastTimeAimWeapon; public void shootTarget () { lastTimeAimWeapon = mainPlayerWeaponsManager.getLastTimeAimWeapon (); if (lastTimeAimWeapon == 0 || Time.time < lastTimeAimWeapon + 0.1f) { //print ("wait"); return; } //if (!mainPlayerWeaponsManager.isWeaponHandsOnPositionToAim ()) { // return; //} setShootWeaponState (true); } public void resetAttackState () { weaponEquiped = false; aimingWeapon = false; resetSetWaitTimeOnFireWeaponBlastValues (); } public void checkIfDrawWeaponsWhenResumingAI () { if (drawWeaponsWhenResumingAI && !weaponEquiped) { setDrawOrHolsterWeaponState (true); } } public void stopAim () { if (aimingWeapon) { setAimWeaponState (false); } } public void disableOnSpottedState () { } public void updateWeaponsAvailableState () { characterHasWeapons = mainPlayerWeaponsManager.checkIfWeaponsAvailable (); } public void setBehaviorStatesPausedState (bool state) { behaviorStatesPaused = state; if (behaviorStatesPaused) { resetAttackState (); } } public bool isWeaponEquiped () { return weaponEquiped; } public void updateIfCarryingWeapon () { weaponEquiped = mainPlayerWeaponsManager.isPlayerCarringWeapon (); } public void inputWeaponMeleeAttack () { if (weaponsSystemActive) { setShootWeaponState (false); mainPlayerWeaponsManager.inputWeaponMeleeAttack (); } } public void stopCurrentAttackInProcess () { if (shootingWeapon || aimingWeapon) { setShootWeaponState (false); stopAim (); } } public void setTurnBasedCombatActionActiveState (bool state) { turnBasedCombatActionActive = state; } public void checkAIBehaviorStateOnCharacterSpawn () { if (checkInitialWeaponsOnCharacterSpawnEnabled) { mainPlayerWeaponsManager.enableOrDisableWeaponsListInRuntime (true); mainPlayerWeaponsManager.resetInitialWeaponCheckedOnCharacterSpawn (); } } public void checkAIBehaviorStateOnCharacterDespawn () { } public void setMaxWaitTimeToForceAttackIfNotUsedLongTimeAgoValue (float newValue) { maxWaitTimeToForceAttackIfNotUsedLongTimeAgo = newValue; } public void setCheckToForceAttackIfNotUsedLongTimeAgoState (bool state) { checkToForceAttackIfNotUsedLongTimeAgo = state; } public void checkIfDisableCurrentWeaponToChangeAttackMode (string newModeName) { changeAttackMode (newModeName); } public void changeCurrentAttackMode (string newModeName) { changeAttackMode (newModeName); } void changeAttackMode (string newModeName) { if (!weaponsSystemActive) { return; } stopAttackState (); eventToChangeAttackMode.Invoke (newModeName); } public void stopAttackState () { if (!weaponsSystemActive) { return; } if (mainPlayerWeaponsManager.isPlayerCarringWeapon ()) { bool playerIsBusy = mainPlayerWeaponsManager.currentWeaponIsMoving () || mainPlayerWeaponsManager.reloadingActionNotActive () || mainPlayerWeaponsManager.isActionActiveInPlayer () || !mainPlayerWeaponsManager.canPlayerMove (); if (playerIsBusy) { //print ("player is busy"); resetBehaviorStates (); mainPlayerWeaponsManager.checkIfDisableCurrentWeapon (); } else { //print ("player is not busy"); } } } public void setAttackEnabledState (bool state) { attackEnabled = state; } public void updateCurrentTargetSelectedInfo () { if (useAIWeaponRangeInfo) { if (checkWeaponRangeInfo ()) { return; } } currentCharacterToAttackRadius = mainFindObjectivesSystem.getCurrentCharacterToAttackRadius (); checkCharacterToAttackRadiusActive = currentCharacterToAttackRadius > 0; if (checkCharacterToAttackRadiusActive) { customMinDistanceToEnemyUsingWeapons = currentCharacterToAttackRadius + mainFindObjectivesSystem.getOriginalMinDistanceToEnemyUsingWeapons (); mainFindObjectivesSystem.setNewMinDistanceToEnemyUsingWeapons (customMinDistanceToEnemyUsingWeapons); } else { mainFindObjectivesSystem.setOriginalMinDistanceToEnemyUsingWeapons (); } //print ("updateCurrentTargetRadius " + currentCharacterToAttackRadius + " " + checkCharacterToAttackRadiusActive); } bool checkWeaponRangeInfo () { if (useAIWeaponRangeInfo) { updateWeaponsAvailableState (); if (characterHasWeapons) { string currentWeaponName = mainPlayerWeaponsManager.getCurrentWeaponName (); int newWeaponIndex = AIWeaponRangeInfoList.FindIndex (s => s.Name.Equals (currentWeaponName)); if (newWeaponIndex > -1) { AIWeaponRangeInfo currentAIWeaponRangeInfo = AIWeaponRangeInfoList [newWeaponIndex]; if (!currentAIWeaponRangeInfo.weaponRangeInfoEnabled) { useAIWeaponRangeInfoActive = false; return false; } useAIWeaponRangeInfoActive = true; if (showDebugPrint) { print ("checkWeaponRangeInfo " + currentAIWeaponRangeInfo.Name); } customMinDistanceToDraw = currentAIWeaponRangeInfo.minDistanceToDraw; customMinDistanceToAim = currentAIWeaponRangeInfo.minDistanceToAim; customMinDistanceToShoot = currentAIWeaponRangeInfo.minDistanceToShoot; customMinDistanceToEnemyUsingWeapons = currentAIWeaponRangeInfo.minDistanceToEnemyUsingWeapons; currentCharacterToAttackRadius = mainFindObjectivesSystem.getCurrentCharacterToAttackRadius (); if (currentCharacterToAttackRadius > 0) { customMinDistanceToEnemyUsingWeapons += currentCharacterToAttackRadius; } checkCharacterToAttackRadiusActive = currentCharacterToAttackRadius > 0; mainFindObjectivesSystem.setNewFireWeaponMinDistanceValues (customMinDistanceToDraw, customMinDistanceToAim, customMinDistanceToShoot); if (showDebugPrint) { print ("customMinDistanceToEnemyUsingWeapons " + customMinDistanceToEnemyUsingWeapons); } mainFindObjectivesSystem.setNewMinDistanceToEnemyUsingWeapons (customMinDistanceToEnemyUsingWeapons); return true; } } } return false; } //EDITOR FUNCTIONS public void setAttackEnabledStateFromEditor (bool state) { setAttackEnabledState (state); updateComponent (); } public void updateComponent () { GKC_Utils.updateComponent (this); GKC_Utils.updateDirtyScene ("Update AI Brain " + gameObject.name, gameObject); } [System.Serializable] public class AIWeaponInfo { [Header ("Main Settings")] [Space] public string Name; public bool weaponEnabled; public bool isCurrentWeapon; public float minTimeToUseNewWeaponAfterChange = 1.8f; } [System.Serializable] public class AIWeaponRangeInfo { [Header ("Main Settings")] [Space] public string Name; public bool weaponRangeInfoEnabled = true; public float minDistanceToDraw = 20; public float minDistanceToAim = 16; public float minDistanceToShoot = 12; public float minDistanceToEnemyUsingWeapons = 8; } }