Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .vs/SAIN/v17/.suo
Binary file not shown.
2 changes: 1 addition & 1 deletion Components/SAIN Bot Component/Classes/AILimitClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public AILimitClass(BotOwner owner) : base(owner) { }

private float UpdateLimitFreqTimer = 0f;

public void UpdateAILimit()
public void Update()
{
if (UpdateLimitFreqTimer < Time.time)
{
Expand Down
52 changes: 32 additions & 20 deletions Components/SAIN Bot Component/Classes/BotSquadClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using static SAIN.UserSettings.DebugConfig;

namespace SAIN.Classes
{
Expand All @@ -16,11 +17,6 @@ public SquadClass(BotOwner bot) : base(bot)

public void Update()
{
if (!SAIN.BotActive || SAIN.GameIsEnding)
{
return;
}

if (BotInGroup)
{
if (UpdateMembersTimer < Time.time)
Expand All @@ -43,30 +39,42 @@ public void Update()

private void FindSquadLeader()
{
// If this bot is a boss type, they are the squad leader
if (SAIN.Info.IsBoss)
{
IsSquadLead = true;
Leader = BotOwner;
LeaderComponent = SAIN;
return;
}
// Assign current bot as leader to start
Leader = BotOwner;
BotOwner newSquadLead = BotOwner;
float power = SAIN.Info.PowerLevel;


// Iterate through each bot component in friendly group to see who has the highest power level
// Iterate through each bot component in friendly group to see who has the highest power level or if any are bosses
foreach (var bot in SquadMembers.Values)
{
// If this bot is a boss type, they are the squad leader
if (bot.Info.IsBoss)
{
newSquadLead = bot.BotOwner;
break;
}
// else If this bot has a higher power level than the last one we checked, they are the squad leader
if (bot.Info.PowerLevel > power)
{
power = bot.Info.PowerLevel;
Leader = bot.BotOwner;
newSquadLead = bot.BotOwner;
}
}

// If the current bot is the result, mark the IsSquadLead value as true
IsSquadLead = Leader == BotOwner;

if (!this.IsSquadLead)
{
LeaderComponent = Leader.GetComponent<SAINComponent>();
}
IsSquadLead = newSquadLead.ProfileId == BotOwner.ProfileId;
Leader = newSquadLead;
LeaderComponent = newSquadLead.GetComponent<SAINComponent>();

Console.WriteLine($"For Bot: [{BotOwner.Profile.Nickname}]: [{Leader.Profile.Nickname}] is Squad lead! Power Level = [{power}] Squad Power = [{SquadPowerLevel}] Members Count = [{SquadMembers.Count}]");
if (DebugBotInfo.Value)
Logger.LogDebug($"For Bot: [{BotOwner.Profile.Nickname}]: [{newSquadLead.Profile.Nickname}] is Squad lead! Power Level = [{power}] Squad Power = [{SquadPowerLevel}] Members Count = [{SquadMembers.Count}]");
}

public float SquadPowerLevel { get; private set; }
Expand All @@ -80,13 +88,15 @@ private void FindSquadLeader()

public Dictionary<BotOwner, SAINComponent> SquadMembers { get; private set; } = new Dictionary<BotOwner, SAINComponent>();

public SAINLogicDecision[] GroupDecisions { get; private set; }
public SAINSoloDecision[] SquadSoloDecisions { get; private set; }
public SAINSquadDecision[] SquadDecisions { get; private set; }

private void UpdateMembers()
{
var locations = new List<Vector3>();
var dictionary = new Dictionary<BotOwner, SAINComponent>();
var decisions = new List<SAINLogicDecision>();
var decisions = new List<SAINSoloDecision>();
var squadDecisions = new List<SAINSquadDecision>();

MemberIsFallingBack = false;

Expand All @@ -108,9 +118,10 @@ private void UpdateMembers()
{
dictionary.Add(member, component);
decisions.Add(component.CurrentDecision);
squadDecisions.Add(component.Decision.SquadDecision);
locations.Add(member.Position);

if (component.Decision.RetreatDecisions.Contains(component.CurrentDecision))
if (component.CurrentDecision == SAINSoloDecision.Retreat)
{
MemberIsFallingBack = true;
}
Expand All @@ -121,7 +132,8 @@ private void UpdateMembers()
}

SquadLocations = locations.ToArray();
GroupDecisions = decisions.ToArray();
SquadSoloDecisions = decisions.ToArray();
SquadDecisions = squadDecisions.ToArray();

SquadPowerLevel = BotOwner.BotsGroup.GroupPower;
SquadMembers = dictionary;
Expand Down
4 changes: 2 additions & 2 deletions Components/SAIN Bot Component/Classes/BotUnstuckClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ public void Update()

public bool BotIsStuck { get; private set; }

private bool CanBeStuckDecisions(SAINLogicDecision decision)
private bool CanBeStuckDecisions(SAINSoloDecision decision)
{
return decision == SAINLogicDecision.Search || decision == SAINLogicDecision.MoveToCover || decision == SAINLogicDecision.GroupSearch || decision == SAINLogicDecision.DogFight || decision == SAINLogicDecision.RunForCover || decision == SAINLogicDecision.RunAway || decision == SAINLogicDecision.RegroupSquad || decision == SAINLogicDecision.UnstuckSearch || decision == SAINLogicDecision.UnstuckDogFight || decision == SAINLogicDecision.UnstuckMoveToCover;
return decision == SAINSoloDecision.Search || decision == SAINSoloDecision.MoveToCover || decision == SAINSoloDecision.DogFight || decision == SAINSoloDecision.RunForCover || decision == SAINSoloDecision.RunAway || decision == SAINSoloDecision.UnstuckSearch || decision == SAINSoloDecision.UnstuckDogFight || decision == SAINSoloDecision.UnstuckMoveToCover;
}

public bool BotStuckOnPlayer()
Expand Down
48 changes: 24 additions & 24 deletions Components/SAIN Bot Component/Classes/CoverClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void Update()
CoverFinder.StopLooking();
return;
}
if ((SAIN.HasGoalEnemy || SAIN.HasGoalTarget) && SAIN.CurrentDecision != SAINLogicDecision.None && SAIN.CurrentDecision != SAINLogicDecision.Search)
if ((SAIN.HasGoalEnemy || SAIN.HasGoalTarget))
{
if (GetPointToHideFrom(out var target))
{
Expand Down Expand Up @@ -70,15 +70,7 @@ public CoverPoint ClosestPoint

private bool GetPointToHideFrom(out Vector3? target)
{
target = null;
if (CurrentDecision == SAINLogicDecision.RunAwayGrenade)
{
target = BotOwner.BewareGrenade.GrenadeDangerPoint?.DangerPoint;
}
if (target == null)
{
target = SAIN.CurrentTargetPosition;
}
target = SAIN.CurrentTargetPosition;
return target != null;
}

Expand All @@ -102,33 +94,41 @@ public bool DuckInCover()

public bool CheckLimbsForCover()
{
if (!SAIN.HasGoalEnemy)
{
return false;
}
if (SAIN.Enemy.IsVisible && SAIN.HasEnemyAndCanShoot)
if (SAIN.Enemy?.IsVisible == true)
{
var target = BotOwner.Memory.GoalEnemy.Person.WeaponRoot.position;
if (CheckLimbForCover(BodyPartType.leftLeg, target, 5f) && CheckLimbForCover(BodyPartType.leftArm, target, 5f))
if (CheckLimbTimer < Time.time)
{
return true;
}
if (CheckLimbForCover(BodyPartType.rightLeg, target, 5f) && CheckLimbForCover(BodyPartType.rightArm, target, 5f))
{
return true;
CheckLimbTimer = Time.time + 0.1f;
bool cover = false;
var target = BotOwner.Memory.GoalEnemy.Person.WeaponRoot.position;
if (CheckLimbForCover(BodyPartType.leftLeg, target, 5f) && CheckLimbForCover(BodyPartType.leftArm, target, 5f))
{
cover = true;
}
else if (CheckLimbForCover(BodyPartType.rightLeg, target, 5f) && CheckLimbForCover(BodyPartType.rightArm, target, 5f))
{
cover = true;
}
HasLimbCover = cover;
}
}
return false;
else
{
HasLimbCover = false;
}
return HasLimbCover;
}

private bool HasLimbCover;
private float CheckLimbTimer = 0f;

private bool CheckLimbForCover(BodyPartType bodyPartType, Vector3 target, float dist = 2f)
{
var position = BotOwner.MainParts[bodyPartType].Position;
Vector3 direction = target - position;
return Physics.Raycast(position, direction, dist, LayerMaskClass.HighPolyWithTerrainMask);
}

private SAINLogicDecision CurrentDecision => SAIN.CurrentDecision;
public CoverStatus FallBackPointStatus
{
get
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using BepInEx.Logging;
using EFT;
using UnityEngine;

namespace SAIN.Classes
{
public class EnemyDecisionClass : SAINBot
{
public EnemyDecisionClass(BotOwner bot) : base(bot) { }

protected ManualLogSource Logger => SAIN.Decision.Logger;

public bool GetDecision(out SAINSoloDecision Decision)
{
if (SAIN.Enemy == null || BotOwner.Memory.GoalEnemy == null)
{
Decision = SAINSoloDecision.None;
return false;
}

if (StartDogFightAction())
{
Decision = SAINSoloDecision.DogFight;
}
else if (StartStandAndShoot())
{
Decision = SAINSoloDecision.StandAndShoot;
}
else if (StartSearch())
{
Decision = SAINSoloDecision.Search;
}
else if (StartHoldInCover())
{
Decision = SAINSoloDecision.HoldInCover;
}
else if (StartMoveToCover())
{
Decision = SAINSoloDecision.MoveToCover;

if (StartRunForCover())
{
Decision = SAINSoloDecision.RunForCover;
}
}
else
{
Decision = SAINSoloDecision.Shoot;
}

if (Decision != SAINSoloDecision.MoveToCover && Decision != SAINSoloDecision.RunForCover)
{
StartRunCoverTimer = 0f;
}

return true;
}

private bool StartDogFightAction()
{
var pathStatus = SAIN.Enemy.CheckPathDistance();
return pathStatus == SAINEnemyPath.VeryClose && SAIN.Enemy.IsVisible;
}

private bool HideFromFlankShot()
{
if (BotOwner.Memory.IsUnderFire)
{
}
return false;
}

private bool StartRunForCover()
{
return StartRunCoverTimer < Time.time && SAIN.BotHasStamina && BotOwner.CanSprintPlayer;
}

private bool StartMoveToCover()
{
bool start = !SAIN.Cover.BotIsAtCoverPoint && (SAIN.Cover.CurrentCoverPoint != null || SAIN.Cover.CurrentFallBackPoint != null);

if (start)
{
if (CurrentDecision != SAINSoloDecision.MoveToCover && CurrentDecision != SAINSoloDecision.RunForCover)
{
StartRunCoverTimer = Time.time + 3f * Random.Range(0.66f, 1.33f);
}
return true;
}
else
{
return false;
}
}

private bool StartSearch()
{
if (SAIN.Enemy?.IsVisible == true)
{
return false;
}

if (SAIN.Enemy?.TimeSinceSeen >= SAIN.Info.TimeBeforeSearch)
{
return true;
}
return false;
}

private bool StartHoldInCover()
{
if (SAIN.Cover.BotIsAtCoverPoint)
{
return true;
}
return false;
}

private bool StartStandAndShoot()
{
if (SAIN.Enemy.IsVisible || SAIN.HasEnemyAndCanShoot)
{
float holdGround = SAIN.Info.HoldGroundDelay;

if (holdGround <= 0f)
{
return false;
}

float changeVis = Time.time - BotOwner.Memory.GoalEnemy.LastChangeVisionTime;
float lastShoot = Time.time - BotOwner.Memory.GoalEnemy.PersonalLastShootTime;

if (changeVis < holdGround && lastShoot < holdGround)
{
if (changeVis < holdGround / 2f && lastShoot < holdGround / 2f)
{
return true;
}
else
{
return SAIN.Cover.CheckLimbsForCover();
}
}
}
return false;
}

private float StartRunCoverTimer;
}
}
Loading