Files
DeviantMobile-Rohan/Assets/Scripts/AI/Actions/CollectBagAction.cs
2026-06-26 22:41:39 +05:30

108 lines
3.5 KiB
C#

using UnityEngine;
/// <summary>
/// CollectBagAction — Navigate to nearest unclaimed available/dropped cash box.
/// Prioritizes hot-drop boxes (bonus value) and closer boxes.
/// Respects TeamBlackboard claims to prevent clustering.
/// </summary>
public class CollectBagAction : AIAction
{
public override string Name => "CollectBag";
public override float Score(AIBlackboard bb, TeamBlackboard tb)
{
// Can't collect if dead or already full
if (bb.isDead) return 0f;
if (bb.carriedBagCount >= 3) return 0f;
// No bags nearby
int totalNearby = bb.nearbyAvailableBags.Count + bb.nearbyDroppedBags.Count;
if (totalNearby == 0) return 0f;
float score = 0.5f; // Base desire to collect
// Bonus for hot-drop bags (time-sensitive)
for (int i = 0; i < bb.nearbyDroppedBags.Count; i++)
{
if (bb.nearbyDroppedBags[i].IsHotDrop)
{
score += 0.2f;
break;
}
}
// Distance factor — closer bags = higher score
float distanceFactor = InverseCurve(bb.nearestBagDistance, 25f);
score *= (0.5f + distanceFactor * 0.5f);
// Less desire to collect when already carrying (deposit instead)
if (bb.carriedBagCount >= 2)
score *= 0.3f;
else if (bb.carriedBagCount >= 1)
score *= 0.6f;
// Reduce if nearby enemies (risky to collect)
if (bb.nearbyEnemyCount > 0 && bb.nearestEnemyDistance < 8f)
score *= 0.6f;
// Low health = less collecting
score *= (0.3f + bb.healthPercent * 0.7f);
return Mathf.Clamp01(score);
}
public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
{
// Find best bag (prefer dropped hot-drops, then closest available)
CashMag bestBag = null;
float bestScore = float.MinValue;
// Check dropped bags first (higher priority)
for (int i = 0; i < bb.nearbyDroppedBags.Count; i++)
{
CashMag bag = bb.nearbyDroppedBags[i];
if (bag == null || bag.IsCarried) continue;
if (tb.IsBagClaimed(bag, brain)) continue;
float dist = Vector3.Distance(brain.transform.position, bag.transform.position);
float bagScore = bag.GetEffectiveValue() / Mathf.Max(dist, 1f);
if (bag.IsHotDrop) bagScore *= 2f; // Big bonus for hot drops
if (bagScore > bestScore) { bestScore = bagScore; bestBag = bag; }
}
// Then available bags
if (bestBag == null)
{
for (int i = 0; i < bb.nearbyAvailableBags.Count; i++)
{
CashMag bag = bb.nearbyAvailableBags[i];
if (bag == null || bag.IsCarried) continue;
if (tb.IsBagClaimed(bag, brain)) continue;
float dist = Vector3.Distance(brain.transform.position, bag.transform.position);
float bagScore = bag.Value / Mathf.Max(dist, 1f);
if (bagScore > bestScore) { bestScore = bagScore; bestBag = bag; }
}
}
if (bestBag == null)
{
// No unclaimed bags, go idle
return;
}
// Claim and navigate
tb.TryClaimBag(bestBag, brain);
bb.targetBag = bestBag;
brain.NavigateTo(bestBag.transform.position);
}
public override void OnExit(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
{
tb.ReleaseBagClaim(brain);
bb.targetBag = null;
}
}