public bool CreateCombatBehavior(MentalType mentalType) { Character mentalAttackTarget = Character.CharacterList.Where( possibleTarget => HumanAIController.IsActive(possibleTarget) && (possibleTarget.TeamID != character.TeamID || mentalType == MentalType.Berserk) && humanAIController.VisibleHulls.Contains(possibleTarget.CurrentHull) && possibleTarget != character).GetRandom(); if (mentalAttackTarget == null) { return(false); } var combatMode = AIObjectiveCombat.CombatMode.None; bool holdFire = mentalType == MentalType.Afraid && character.IsSecurity; switch (mentalType) { case MentalType.Afraid: combatMode = character.IsSecurity ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Retreat; break; case MentalType.Desperate: // might be unnecessary to explicitly declare as arrest against non-humans combatMode = character.IsSecurity && mentalAttackTarget.IsHuman ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Defensive; break; case MentalType.Berserk: combatMode = AIObjectiveCombat.CombatMode.Offensive; break; } // using this as an explicit time-out for the behavior. it's possible it will never run out because of the manager being disabled, but combat objective has failsafes for that mentalBehaviorTimer = MentalBehaviorInterval; humanAIController.AddCombatObjective(combatMode, mentalAttackTarget, allowHoldFire: holdFire, abortCondition: obj => mentalBehaviorTimer <= 0f); string textIdentifier = $"dialogmentalstatereaction{combatMode.ToString().ToLowerInvariant()}"; character.Speak(TextManager.Get(textIdentifier), delay: Rand.Range(0.5f, 1.0f), identifier: textIdentifier, minDurationBetweenSimilar: 25f); if (mentalType == MentalType.Berserk && !character.HasTeamChange(MentalTeamChange)) { // TODO: could this be handled in the switch block above? character.TryAddNewTeamChange(MentalTeamChange, new ActiveTeamChange(CharacterTeamType.None, ActiveTeamChange.TeamChangePriorities.Absolute, aggressiveBehavior: true)); } return(true); }