cards/CardChipmunk.cs
using Sandbox;
using System.Threading.Tasks;
public class CardChipmunk : Card
{
public override bool IsAlive => true;
public override bool ValidateStartingGridPos()
{
foreach(var card in Manager.Instance.GetNearbyCards(GridPos, adjacentOnly: true))
{
if ( card.CardType == CardType.Tree )
{
int NUM_TRIES = 100;
for ( int i = 0; i < NUM_TRIES; i++ )
{
var newGridPos = Manager.Instance.GetRandomGridPos( except: GridPos );
var otherCard = Manager.Instance.GetCardAtGridPos( newGridPos );
if ( otherCard.CardType != CardType.Chipmunk && otherCard.CardType != CardType.Spider )
{
Manager.Instance.SwapCardPositionsNonAsync( this, otherCard );
break;
}
}
return false;
}
}
return true;
}
public override bool ShouldHandleEvent( EventType eventType )
{
if( eventType == EventType.TurnStart )
{
var trees = Manager.Instance.Cards.Where( x => x.CardType == CardType.Tree ).ToList();
if ( trees.Count == 0 )
return false;
foreach(var tree in trees)
{
if ( Manager.IsAdjacent( GridPos, tree.GridPos ) )
return false;
}
return true;
}
return false;
}
public override async Task HandleEventAsync( EventType eventType )
{
var trees = Manager.Instance.Cards.Where( x => x.CardType == CardType.Tree ).ToList();
if ( trees.Count == 0 )
return;
foreach ( var tree in trees )
{
if ( Manager.IsAdjacent( GridPos, tree.GridPos ) )
return;
}
List<IntVector2> validGridPositions = new();
IntVector2 currGridPos;
foreach ( var tree in trees )
{
currGridPos = tree.GridPos + new IntVector2( -1, 0 );
if( IsGridPosValid(currGridPos) && !validGridPositions.Contains( currGridPos ) )
validGridPositions.Add( currGridPos );
currGridPos = tree.GridPos + new IntVector2( 1, 0 );
if ( IsGridPosValid( currGridPos ) && !validGridPositions.Contains( currGridPos ) )
validGridPositions.Add( currGridPos );
currGridPos = tree.GridPos + new IntVector2( 0, -1 );
if ( IsGridPosValid( currGridPos ) && !validGridPositions.Contains( currGridPos ) )
validGridPositions.Add( currGridPos );
currGridPos = tree.GridPos + new IntVector2( 0, 1 );
if ( IsGridPosValid( currGridPos ) && !validGridPositions.Contains( currGridPos ) )
validGridPositions.Add( currGridPos );
}
if ( validGridPositions.Count == 0 )
return;
validGridPositions.Shuffle();
validGridPositions = validGridPositions.OrderBy( x => (GridPos - x).ManhattanLength ).ToList();
var destination = validGridPositions.FirstOrDefault();
var path = GetPathTo( GridPos, destination );
if ( path == null || path.Count == 0 )
return;
IntVector2 targetGridPos = path.FirstOrDefault();
await Task.DelayRealtime( 150 );
var targetCard = Manager.Instance.GetCardAtGridPos( targetGridPos );
if(targetCard != null)
Manager.Instance.PlayCardSfxBetween( "card_move", this, targetCard, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );
else
Manager.Instance.PlayCardSfx( "card_move", this, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );
this.MoveToPos( this.LocalPosition.WithZ( Game.Random.Float( 70f, 90f ) ), 0.3f, EasingType.SineOut );
targetCard?.MoveToPos( targetCard.LocalPosition.WithZ( Game.Random.Float( 70f, 90f ) ), 0.25f, EasingType.SineOut );
await Task.DelayRealtime( 250 );
this.MoveToPos( Manager.GetCardPos( targetGridPos ).WithZ( this.LocalPosition.z ), 0.45f, EasingType.SineInOut );
targetCard?.MoveToPos( Manager.GetCardPos( this.GridPos ).WithZ( targetCard.LocalPosition.z ), 0.45f, EasingType.SineInOut );
await Task.DelayRealtime( 450 );
this.MoveToPos( this.LocalPosition.WithZ( Globals.CARD_DEFAULT_HEIGHT + Globals.CARD_ADD_HEIGHT_REVEALED_OR_HOVERED ), 0.2f, EasingType.SineOut );
targetCard?.MoveToPos( targetCard.LocalPosition.WithZ( Globals.CARD_DEFAULT_HEIGHT ), 0.2f, EasingType.SineOut );
await Task.DelayRealtime( 200 );
if ( targetCard != null )
{
await Manager.Instance.SwapCardPositions( this, targetCard );
}
else
{
Manager.Instance.RemoveCardGridPos( this );
await Manager.Instance.SetCardGridPos( this, targetGridPos );
}
this.IsMovementControlled = false;
if ( targetCard != null )
targetCard.IsMovementControlled = false;
await Task.DelayRealtime( 200 );
await Manager.Instance.EventHappened( EventType.AfterCardsMoved );
}
bool IsGridPosValid( IntVector2 gridPos )
{
if ( !Manager.Instance.IsGridPosInBounds( gridPos ) )
return false;
return !ContainsChipmunk( gridPos );
}
bool ContainsChipmunk( IntVector2 gridPos )
{
var card = Manager.Instance.GetCardAtGridPos( gridPos );
return card != null && card.CardType == CardType.Chipmunk;
}
bool ContainsTree( IntVector2 gridPos )
{
var card = Manager.Instance.GetCardAtGridPos( gridPos );
return card != null && card.CardType == CardType.Tree;
}
private List<IntVector2> _gridPath;
private List<IntVector2> _walkable;
public List<IntVector2> GetPathTo( IntVector2 a, IntVector2 b )
{
if ( _gridPath == null )
_gridPath = new List<IntVector2>();
else
_gridPath.Clear();
_gridPath.Clear();
if ( (a - b).ManhattanLength <= 1 )
{
_gridPath.Add( b );
return _gridPath;
}
List<IntVector2> tempPath = new List<IntVector2>();
if ( Utils.AStar<IntVector2>( a, b, tempPath, GetEdges, GetHScoreFromGridPosToGridPos ) )
{
_gridPath.AddRange( tempPath );
// remove start pos
_gridPath.RemoveAt( 0 );
}
return _gridPath;
}
public List<IntVector2> GetWalkableAdjacentGridPositions( IntVector2 start )
{
if ( _walkable == null )
_walkable = new List<IntVector2>();
else
_walkable.Clear();
IntVector2 left = start + new IntVector2( -1, 0 );
if ( Manager.Instance.IsGridPosInBounds( left ) && !ContainsChipmunk(left) && !ContainsTree(left) )
_walkable.Add( left );
IntVector2 right = start + new IntVector2( 1, 0 );
if ( Manager.Instance.IsGridPosInBounds( right ) && !ContainsChipmunk( right ) && !ContainsTree( right ) )
_walkable.Add( right );
IntVector2 down = start + new IntVector2( 0, -1 );
if ( Manager.Instance.IsGridPosInBounds( down ) && !ContainsChipmunk( down ) && !ContainsTree( down ) )
_walkable.Add( down );
IntVector2 up = start + new IntVector2( 0, 1 );
if ( Manager.Instance.IsGridPosInBounds( up ) && !ContainsChipmunk( up ) && !ContainsTree( up ) )
_walkable.Add( up );
return _walkable;
}
static float GetHScoreFromGridPosToGridPos( IntVector2 a, IntVector2 b )
{
return (b - a).ManhattanLength;
}
IEnumerable<AStarEdge<IntVector2>> GetEdges( IntVector2 start )
{
var walkable = GetWalkableAdjacentGridPositions( start );
return walkable.Select( gridPos => Utils.Edge( gridPos, GetCostToMoveFromGridPosToAdjacentGridPos( start, gridPos ) ) );
}
float GetCostToMoveFromGridPosToAdjacentGridPos( IntVector2 a, IntVector2 b )
{
return 1f;
}
}