108 lines
3.5 KiB
C#
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;
|
|
}
|
|
}
|