cards/Card.cs
using Microsoft.VisualBasic;
using Sandbox;
using Sandbox.UI;
using System.Runtime;
using System.Threading.Tasks;
public enum CardType { None, Apple, Bomb, Rocket, Telephone, Trumpet, Pawn, Balloon, Spider, Umbrella, UmbrellaClosed, Juggler, Coin, Vampire, Maracas, Microwave, Raccoon, Rock, Bear, Candle,
CrystalBall, Snake, Rose, RoseWilted, Bell, Ant, Twins, Compass, Antenna, Wizard, AncientScroll, JumpingSpider, Bento, Ninja, Flashlight, Bodybuilder, Helicopter, FlyingMoney,
Syringe, Cellphone, Crab, Magnet, Stethoscope, UFO, Teacher, Tractor, FortuneCookie, Dolphin, Detective, Genie, Potion, Mirror, FaxMachine, Dice, Coffee, Tree, Chipmunk,
Dancer, Wine, King, Police, Ogre, Clown, MoneyBag, Bank, Steak, MagicWand, Carrot, Caterpillar, Butterfly, Tornado, Map, Cockroach, Broccoli, Donut, Cheese, CheeseMoldy, GuideDog, Taco, Burrito,
Skunk, CarePackage, Cash, BirthdayCake, Gem, Pickaxe, Mountain, DiamondRing, Rabbit, RedEnvelope,
}
// StockMarket, StockMarketDown, Key, AlarmClock, ATM
public class Card : Component, IEventHandler
{
public GameObject Model { get; set; }
public ModelRenderer ModelRenderer { get; set; }
public GameObject IconObj { get; set; }
public GameObject IconBackObj { get; set; }
public bool IsFlagShown { get; set; }
public float CardIconScale { get; set; } = 1f;
public bool IsHovered { get; set; }
public bool IsRevealed { get; set; }
public bool IsSpawning { get; set; }
public int NumTimesRevealed { get; set; }
public int NumTimesChosen { get; set; }
public CardType CardType { get; private set; }
public CardType OriginalCardType { get; private set; }
public virtual bool IsFoodOrBeverage => false;
public virtual bool IsAlive => false;
public virtual bool CantBeMoved => false;
public IntVector2 GridPos { get; set; }
public bool IsShaking { get; private set; }
private TimeSince _timeSinceShakeStart; // todo: replace with timer? this can become negative somehow
private float _shakeTime;
private EasingType _shakeEasingType;
public Vector2 ShakeOffset { get; set; }
private float _shakeStrength;
public bool IsMovementControlled { get; set; }
private Vector3 _moveStartPos;
private Vector3 _moveTargetPos;
private float _moveTime;
private TimeSince _timeSinceMoveStart;
private EasingType _moveEasingType;
private bool _moveRemoveControlAfter;
public int HP { get; set; }
public bool IsLocked { get; set; }
public int LockTurnsRemaining { get; set; }
public bool WasJustLocked { get; set; }
public int CardTypeID { get; set; }
public float IconOpacity { get; set; }
public bool IsExploding;
private TimeSince _timeSinceStartExploding;
private float _explodeTime;
private EasingType _explodeEasingType;
private Vector3 _explodeStartPos;
private EasingType _explodeShakeEasingType;
public bool IsScaling;
private TimeSince _timeSinceScale;
private float _scaleTime;
private float _scaleAmount;
private EasingType _scaleEasingType;
public bool AreRevealMarksShown { get; set; }
protected override void OnAwake()
{
base.OnAwake();
}
public virtual void Init(CardType cardType)
{
CardType = OriginalCardType = cardType;
Model = GameObject.Children.Find( x => x.Name == "model" );
ModelRenderer = Model.Components.Get<ModelRenderer>();
IconOpacity = 1f;
IconObj = GameObject.Children.Find( x => x.Name == "icon" );
var cardIcon = IconObj.Components.Get<CardIcon>( includeDisabled: true );
cardIcon.Card = this;
IconBackObj = GameObject.Children.Find( x => x.Name == "icon_back" );
var cardIconBack = IconBackObj.Components.Get<CardIconBack>( includeDisabled: true );
cardIconBack.Card = this;
SetMaterial( cardType );
}
public void SetMaterial(CardType cardType)
{
var matFilename = GetMaterialFilename( cardType );
if ( !string.IsNullOrEmpty( matFilename ) )
ModelRenderer.MaterialOverride = Material.Load( matFilename );
}
public void SetCardType(CardType newType)
{
CardType = newType;
SetMaterial( newType );
}
protected override void OnUpdate()
{
//if ( Input.Down( "Duck" ) )
//{
// var emoji = Card.GetIconEmoji( CardType );
// if ( string.IsNullOrEmpty( emoji ) )
// {
// Gizmo.Draw.Color = Color.Black.WithAlpha( 1f );
// Gizmo.Draw.Text( $"{CardType}", new global::Transform( WorldPosition + new Vector3( -0.5f, -0.5f, -1f ) ), size: 24f );
// Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
// Gizmo.Draw.Text( $"{CardType}", new global::Transform( WorldPosition ), size: 24f );
// }
// else
// {
// Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
// Gizmo.Draw.Text( emoji, new global::Transform( WorldPosition ), size: 60f );
// }
// if ( IsMovementControlled )
// {
// Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
// Gizmo.Draw.Text( "➡️", new global::Transform( WorldPosition + new Vector3( -15.5f, -19f, -1f ) ), size: 30f );
// }
// if ( IsLocked )
// {
// Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
// Gizmo.Draw.Text( "🔒", new global::Transform( WorldPosition + new Vector3( 15.5f, -19f, -1f ) ), size: 30f );
// Gizmo.Draw.Color = Color.Red.WithAlpha( 1f );
// Gizmo.Draw.Text( $"{LockTurnsRemaining}", new global::Transform( WorldPosition + new Vector3( 15.5f, -21f, 1f ) ), size: 20f );
// }
// Gizmo.Draw.Color = Color.Black.WithAlpha( 1f );
// Gizmo.Draw.Text( $"ID: {CardTypeID}", new global::Transform( WorldPosition + new Vector3( -13.5f, 19f, -1f ) + new Vector3( -0.5f, -0.5f, -1f ) ), size: 16 );
// Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
// Gizmo.Draw.Text( $"ID: {CardTypeID}", new global::Transform( WorldPosition + new Vector3( -13.5f, 19f, -1f ) ), size: 16 );
//}
HandleMoving();
HandleShaking();
if(IsExploding)
{
HandleExploding();
return;
}
if ( IsScaling )
{
HandleScaling();
}
//if(!IsScaling && !IsExploding)
//{
// Transform.LocalScale = new Vector3( Utils.DynamicEaseTo( Transform.LocalScale.x, IsHovered ? 1.05f : 1f, 0.3f, Time.Delta ) );
//}
if( IsSpawning )
{
// do nothing
}
else if( IsMovementControlled )
{
LocalPosition += new Vector3( ShakeOffset.x, ShakeOffset.y, 0f ) * Time.Delta * 10f;
}
else
{
var targetPos = Manager.GetCardPos( GridPos );
if ( IsShaking )
targetPos += new Vector3( ShakeOffset.x, ShakeOffset.y, 0f );
var height = 10f + ((IsRevealed || IsHovered) ? Globals.CARD_ADD_HEIGHT_REVEALED_OR_HOVERED : 0f) + ((IsRevealed && IsHovered) ? Globals.CARD_ADD_HEIGHT_REVEALED_AND_HOVERED : 0f);
var zPos = MathX.Lerp( LocalPosition.z, height, Time.Delta * 20f );
LocalPosition = Vector3.Lerp( LocalPosition, targetPos, Time.Delta * 10f ).WithZ( zPos );
}
var targetRot = Rotation.FromPitch( IsRevealed ? 0f : 180f );
WorldRotation = Rotation.Lerp( WorldRotation, targetRot, Time.Delta * 15f );
}
public void MoveToPos( Vector3 pos, float time, EasingType easingType = EasingType.Linear, bool removeControlAfter = false)
{
//Log.Info( $"Card - MoveToPos: {pos}" );
IsMovementControlled = true;
_moveStartPos = LocalPosition;
_moveTargetPos = pos;
_moveTime = time;
_timeSinceMoveStart = 0f;
_moveEasingType = easingType;
_moveRemoveControlAfter = removeControlAfter;
}
void HandleMoving()
{
if ( !IsMovementControlled )
return;
if(_timeSinceMoveStart > _moveTime)
{
LocalPosition = _moveTargetPos;
if( _moveRemoveControlAfter )
IsMovementControlled = false;
}
else
{
LocalPosition = Vector3.Lerp( _moveStartPos, _moveTargetPos, Utils.Map( _timeSinceMoveStart, 0f, _moveTime, 0f, 1f, _moveEasingType ) );
}
}
protected void HandleShaking()
{
if ( IsShaking )
{
if ( _timeSinceShakeStart > _shakeTime )
IsShaking = false;
else
ShakeOffset = Utils.GetRandomVector() * _shakeStrength * Utils.Map( _timeSinceShakeStart, 0f, _shakeTime, 1f, 0f, _shakeEasingType );
}
}
void HandleExploding()
{
LocalScale = new Vector3( Utils.Map(_timeSinceStartExploding, 0f, _explodeTime, 1f, Globals.CARD_EXPLODE_SCALE, _explodeEasingType) );
IconOpacity = Utils.Map( _timeSinceStartExploding, 0f, _explodeTime, 1f, 0f, EasingType.SineIn );
LocalPosition = _explodeStartPos + Vector3.Random * Utils.Map( _timeSinceStartExploding, 0f, _explodeTime, 0f, 2f, _explodeShakeEasingType) * Utils.Map( _timeSinceStartExploding, _explodeTime * 0.9f, _explodeTime, 1f, 0f );
}
void HandleScaling()
{
if(_timeSinceScale > 0.25f)
{
IsScaling = false;
LocalScale = new Vector3( 1f );
}
else
{
LocalScale = Utils.MapReturn( _timeSinceScale, 0f, _scaleTime, 1f, _scaleAmount, _scaleEasingType);
}
}
public static string GetName( CardType cardType )
{
switch ( cardType )
{
case CardType.CrystalBall: return "Crystal Ball";
case CardType.AncientScroll: return "Ancient Scroll";
case CardType.JumpingSpider: return "Jumping Spider";
case CardType.Rock: return "Boulder";
case CardType.Syringe: return "Morphine";
case CardType.FlyingMoney: return "Flying Money";
case CardType.FortuneCookie: return "Fortune Cookie";
//case CardType.AlarmClock: return "Alarm Clock";
case CardType.FaxMachine: return "Fax Machine";
case CardType.MoneyBag: return "Money Bag";
case CardType.MagicWand: return "Magic Wand";
//case CardType.StockMarket: return "Stock Market";
case CardType.GuideDog: return "Guide Dog";
case CardType.CarePackage: return "Care Package";
case CardType.BirthdayCake: return "Birthday Cake";
case CardType.DiamondRing: return "Diamond Ring";
case CardType.RedEnvelope: return "Red Envelope";
}
return cardType.ToString();
}
public static string GetFilename( CardType cardType )
{
switch ( cardType )
{
case CardType.Apple: return "apple";
case CardType.Bomb: return "bomb";
case CardType.Rocket: return "rocket";
case CardType.Telephone: return "telephone";
case CardType.Trumpet: return "trumpet";
case CardType.Pawn: return "pawn";
case CardType.Balloon: return "balloon";
case CardType.Spider: return "spider";
case CardType.Umbrella: return "umbrella";
case CardType.UmbrellaClosed: return "umbrella_closed";
case CardType.Juggler: return "juggler";
case CardType.Coin: return "coin";
case CardType.Vampire: return "vampire";
case CardType.Maracas: return "maracas";
case CardType.Microwave: return "microwave";
case CardType.Raccoon: return "raccoon";
case CardType.Rock: return "rock";
case CardType.Bear: return "bear";
case CardType.Candle: return "candle";
case CardType.CrystalBall: return "crystal_ball";
case CardType.Snake: return "snake";
case CardType.Rose: return "rose";
case CardType.RoseWilted: return "rose_wilted";
case CardType.Bell: return "bell";
case CardType.Ant: return "ant";
case CardType.Twins: return "twins";
case CardType.Compass: return "compass";
case CardType.Antenna: return "antenna";
case CardType.Wizard: return "wizard";
case CardType.AncientScroll: return "scroll";
case CardType.JumpingSpider: return "spider_jumping";
case CardType.Bento: return "bento";
//case CardType.StockMarket: return "investment";
//case CardType.StockMarketDown: return "investment_down";
case CardType.Ninja: return "ninja";
case CardType.Flashlight: return "flashlight";
case CardType.Bodybuilder: return "bodybuilder";
case CardType.Helicopter: return "helicopter";
case CardType.FlyingMoney: return "flying_money";
case CardType.Syringe: return "syringe";
case CardType.Cellphone: return "cellphone";
case CardType.Crab: return "crab";
case CardType.Magnet: return "magnet";
case CardType.Stethoscope: return "stethoscope";
case CardType.UFO: return "ufo";
case CardType.Teacher: return "teacher";
case CardType.Tractor: return "tractor";
case CardType.FortuneCookie: return "fortune_cookie";
case CardType.Dolphin: return "dolphin";
case CardType.Detective: return "detective";
case CardType.Genie: return "genie";
case CardType.Potion: return "potion";
case CardType.Mirror: return "mirror";
//case CardType.AlarmClock: return "alarm_clock";
case CardType.FaxMachine: return "fax_machine";
case CardType.Dice: return "dice";
case CardType.Coffee: return "coffee";
case CardType.Tree: return "tree";
case CardType.Chipmunk: return "chipmunk";
case CardType.Dancer: return "dancer";
case CardType.Wine: return "wine";
case CardType.King: return "king";
case CardType.Police: return "police";
case CardType.Ogre: return "ogre";
case CardType.Clown: return "clown";
case CardType.MoneyBag: return "money_bag";
case CardType.Bank: return "bank";
case CardType.Steak: return "steak";
case CardType.MagicWand: return "magic_wand";
case CardType.Carrot: return "carrot";
case CardType.Caterpillar: return "caterpillar";
case CardType.Butterfly: return "butterfly";
case CardType.Tornado: return "tornado";
case CardType.Map: return "map";
case CardType.Cockroach: return "cockroach";
//case CardType.Key: return "key";
case CardType.Broccoli: return "broccoli";
//case CardType.ATM: return "atm";
case CardType.Donut: return "donut";
case CardType.Cheese: return "cheese";
case CardType.CheeseMoldy: return "cheese_moldy";
case CardType.GuideDog: return "guide_dog";
case CardType.Taco: return "taco";
case CardType.Burrito: return "burrito";
case CardType.Skunk: return "skunk";
case CardType.CarePackage: return "care_package";
case CardType.Cash: return "cash";
case CardType.BirthdayCake: return "birthday_cake";
case CardType.Gem: return "gem";
case CardType.Pickaxe: return "pickaxe";
case CardType.Mountain: return "mountain";
case CardType.DiamondRing: return "diamond_ring";
case CardType.Rabbit: return "rabbit";
case CardType.RedEnvelope: return "red_envelope";
}
return "";
}
public static string GetIconFilename( CardType cardType )
{
return $"textures/{GetFilename( cardType )}.png";
}
public static string GetMaterialFilename( CardType cardType )
{
return $"materials/cards/{GetFilename( cardType )}.vmat";
}
public static string GetIconEmoji( CardType cardType )
{
switch ( cardType )
{
case CardType.Apple: return "🍎";
case CardType.Bomb: return "💣";
case CardType.Rocket: return "🚀";
case CardType.Telephone: return "☎️";
case CardType.Trumpet: return "🎺";
case CardType.Pawn: return "♟️";
case CardType.Balloon: return "🎈";
case CardType.Spider: return "🕷️";
case CardType.Umbrella: return "☂️";
case CardType.UmbrellaClosed: return "🌂";
case CardType.Juggler: return "🤹";
case CardType.Coin: return "🟡";
case CardType.Vampire: return "🧛";
case CardType.Raccoon: return "🦝";
case CardType.Rock: return "🗿";
case CardType.Bear: return "🐻";
case CardType.Candle: return "🕯️";
case CardType.CrystalBall: return "🔮";
case CardType.Snake: return "🐍";
case CardType.Rose: return "🌹";
case CardType.RoseWilted: return "🥀";
case CardType.Bell: return "🔔";
case CardType.Ant: return "🐜";
case CardType.Twins: return "👯";
case CardType.Compass: return "🧭";
case CardType.Antenna: return "📡";
case CardType.Wizard: return "🧙";
case CardType.AncientScroll: return "📜";
case CardType.JumpingSpider: return "🕷️";
case CardType.Bento: return "🍱";
//case CardType.StockMarket: return "📈";
//case CardType.StockMarketDown: return "📉";
case CardType.Ninja: return "🐱👤";
case CardType.Flashlight: return "🔦";
case CardType.Bodybuilder: return "🏋️";
case CardType.Helicopter: return "🚁";
case CardType.FlyingMoney: return "💸";
case CardType.Syringe: return "💉";
case CardType.Cellphone: return "📱";
case CardType.Crab: return "🦀";
case CardType.Magnet: return "🧲";
case CardType.Stethoscope: return "🩺";
case CardType.UFO: return "🛸";
case CardType.Teacher: return "👩🏫";
case CardType.Tractor: return "🚜";
case CardType.FortuneCookie: return "🥠";
case CardType.Dolphin: return "🐬";
case CardType.Detective: return "🕵️";
case CardType.Genie: return "🧞";
case CardType.Potion: return "🧪";
case CardType.Mirror: return "🔘";
//case CardType.AlarmClock: return "⏰";
case CardType.FaxMachine: return "📠";
case CardType.Dice: return "🎲";
case CardType.Coffee: return "☕";
case CardType.Tree: return "🌳";
case CardType.Chipmunk: return "🐿️";
case CardType.Dancer: return "💃";
case CardType.Wine: return "🍷";
case CardType.King: return "🤴";
case CardType.Police: return "👮";
case CardType.Ogre: return "👹";
case CardType.Clown: return "🤡";
case CardType.MoneyBag: return "💰";
case CardType.Bank: return "🏦";
case CardType.Steak: return "🥩";
case CardType.MagicWand: return "✨";
case CardType.Carrot: return "🥕";
case CardType.Caterpillar: return "🐛";
case CardType.Butterfly: return "🦋";
case CardType.Tornado: return "🌪️";
case CardType.Map: return "🗺️";
case CardType.Cockroach: return "𓆣";
//case CardType.Key: return "🔑";
case CardType.Broccoli: return "🥦";
//case CardType.ATM: return "🏧";
case CardType.Donut: return "🍩";
case CardType.Cheese: return "🧀";
case CardType.CheeseMoldy: return "🤮";
case CardType.GuideDog: return "🦮";
case CardType.Taco: return "🌮";
case CardType.Burrito: return "🌯";
case CardType.Skunk: return "🦨";
case CardType.CarePackage: return "📦";
case CardType.Cash: return "💵";
case CardType.BirthdayCake: return "🎂";
case CardType.Gem: return "💎";
case CardType.Pickaxe: return "⛏️";
case CardType.Mountain: return "⛰️";
case CardType.DiamondRing: return "💍";
case CardType.Rabbit: return "🐇";
case CardType.RedEnvelope: return "🧧";
}
return "";
}
public static string GetCardDescription( CardType cardType )
{
switch ( cardType )
{
case CardType.Apple: return "✅Match: +1 HP";
case CardType.Bomb: return "✅Match: reveal nearby cards then shuffle them";
case CardType.Rocket: return "❌Mismatch: swap position";
case CardType.Telephone: return "✅Match: shake nearby pairs";
case CardType.Trumpet: return "Match other cards: 30% chance to reveal";
case CardType.Pawn: return "➡️Turn start: 50% to try to move upward";
case CardType.Balloon: return "Floats upward";
case CardType.Spider: return "Starts in a corner";
case CardType.Umbrella: return "👁️Revealed: toggle open/closed";
case CardType.Juggler: return "❌Mismatch: rearrange nearby cards";
case CardType.Coin: return "✅Match: +$2";
case CardType.Vampire: return "While hovered: shake if you lose HP";
case CardType.Maracas: return "Makes a distinctive sound when shook";
case CardType.Microwave: return "➡️Turn start: shake a nearby food/drink";
case CardType.Raccoon: return "➡️Turn start: shake an adjacent card";
case CardType.Rock: return "Falls downward, pushing other cards";
case CardType.Bear: return "Food/drink revealed: 20% chance to shake";
case CardType.Candle: return "✅Match: each reveal a nearby card";
case CardType.CrystalBall: return "❌Mismatch: shake cards, including other card's match";
case CardType.Snake: return "Shake when an adjacent card is matched";
case CardType.Rose: return "When moved: shake and wilt";
case CardType.Bell: return "Rings when moved or shook";
case CardType.Ant: return "➡️Turn start: move to nearby empty space";
case CardType.Twins: return "👁️Revealed: nudge toward match";
case CardType.Compass: return "❌Mismatch: nudge toward other card's match";
case CardType.Antenna: return "👁️Revealed: sound indicates distance to match";
case CardType.Wizard: return "⏩Every 3 turns: shuffle some cards\n💔Damage Wizard: respawn some cards and shuffle them";
case CardType.AncientScroll: return "✅Match: reveal all cards (after next turn, shuffle all cards)";
case CardType.JumpingSpider: return "Starts in a corner\n❌Mismatch: swaps with an unknown card";
case CardType.Bento: return "✅Match: +1 HP for each consecutive match";
//case CardType.StockMarket: return "✅Match: gain half your money if the market is up, lose half if the market is down";
case CardType.Ninja: return "➡️Turn start: 25% chance to swap position";
case CardType.Flashlight: return "👆Chosen: reveal a nearby card";
case CardType.Bodybuilder: return "➡️Turn start: move adjacent card upwards, pushing other cards";
case CardType.Helicopter: return "❌Mismatch: relocate along with an adjacent card";
case CardType.FlyingMoney: return "✅Match: +$3\n❌Mismatch: shuffle with some nearby cards";
case CardType.Syringe: return "✅Match: heal all HP, but time is halved until end of level";
case CardType.Cellphone: return "❌Mismatch: vibrate nearest cellphone";
case CardType.Crab: return "Moves sideways to empty spaces";
case CardType.Magnet: return "➡️Turn start: pull card toward it";
case CardType.Stethoscope: return "✅Match/❌Mismatch: shake nearby cards with a heartbeat";
case CardType.UFO: return "✅Match: abduct and shuffle nearby cards";
case CardType.Teacher: return "✅Match: arrange row alphabetically";
case CardType.Tractor: return "✅Match/❌Mismatch: shift row one space";
case CardType.FortuneCookie: return "✅Match: +1 HP, and reveal 5 cards that you haven't seen before";
case CardType.Dolphin: return "Revealed on 4 consecutive mismatches";
case CardType.Detective: return "➡️Turn start: 50% chance to reveal a nearby card";
case CardType.Genie: return "✅Match: next card chosen shakes its match";
case CardType.Potion: return "✅Match: your HP is set to half";
case CardType.Mirror: return "✅Match: flip the level horizontally";
//case CardType.AlarmClock: return "70% chance to shake when timer goes below 1s";
case CardType.FaxMachine: return "👆Chosen: shake 3 cards, including another fax machine";
case CardType.Dice: return "❌Mismatch: roll a 6 to get +$2 (rolling 1 loses $1)\n✅Match: Roll a 12 to get +$5 (rolling 2 loses $2)";
case CardType.Coffee: return "✅Match: +2 HP, and your next turn lasts 3 seconds";
case CardType.Tree: return "✅Match: reveal an apple";
case CardType.Chipmunk: return "➡️Turn start: move toward a tree";
case CardType.Dancer: return "❌Mismatch: dance with multiple partners";
case CardType.Wine: return "✅Match: +2 HP\nShake if an adjacent card shakes";
case CardType.King: return "💔Damage King: he decides your next choice";
case CardType.Police: return "❌Mismatch: Reveal and lock a nearby card for 2 turns\n💔Damage Police: Lock some nearby cards for 1 turn, then shuffle";
case CardType.Ogre: return "💔Damage Ogre: shuffle with nearby cards";
case CardType.Clown: return "💔Damage Clown: swap multiple times";
case CardType.MoneyBag: return "✅Match: +$5";
case CardType.Bank: return "✅Match: transform all coins into money bags";
case CardType.Steak: return "✅Match: -$1 and +4 HP";
case CardType.MagicWand: return "❌Mismatch: send other card adjacent to its match";
case CardType.Carrot: return "✅Match: +3 HP, and timer is doubled next turn";
case CardType.Caterpillar: return "➡️Turn start: 20% chance to shake and transform into a butterfly";
case CardType.Tornado: return "➡️Turn start: swap 2 adjacent cards";
case CardType.Map: return "✅Match: reveal all cards between";
case CardType.Cockroach: return "Can't be matched until no other cards remain";
//case CardType.Key: return "❌Mismatch: unlock other card\n✅Match: unlock all cards";
case CardType.Broccoli: return "✅Match: +3 HP";
//case CardType.ATM: return "✅Match: +$1 for every 2 matches you've made this level (max: $7)";
case CardType.Donut: return "✅Match: +1 HP for each adjacent empty space";
case CardType.Cheese: return "✅Match: +3 HP if not moldy\nGoes moldy after 7 turns";
case CardType.GuideDog: return "When you mismatch other cards, 50% chance to point toward one of their matches";
case CardType.Taco: return "✅Match: +1 Max HP";
case CardType.Burrito: return "✅Match: +2 Max HP";
case CardType.Skunk: return "Can't be matched while adjacent to any non-skunks";
case CardType.CarePackage: return "✅Match: +$1 for every 2 HP missing";
case CardType.Cash: return "✅Match: +$3 if both cash are nearby eachother, otherwise +$1";
case CardType.BirthdayCake: return "✅Match: +1 HP and +$2";
case CardType.Gem: return "✅Match: +$4";
case CardType.Pickaxe: return "✅Match: transform all boulders into gems";
case CardType.Mountain: return "Can't be moved";
case CardType.DiamondRing: return "✅Match: +$3 if no other cards remain, otherwise +$1";
case CardType.Rabbit: return "➡️Turn start: 50% chance to move towards its match";
case CardType.RedEnvelope: return "✅Match: if you have less than $5, set your money to $5";
}
return "";
}
public static string GetCardExplanation( CardType cardType )
{
switch ( cardType )
{
case CardType.Ant: return "\"nearby\" means 1 space away\n(including diagonal)";
case CardType.Snake: return "\"adjacent\" means 1 space away\n(NOT including diagonal)";
}
return "";
}
public static bool HasHP( CardType cardType )
{
switch ( cardType )
{
case CardType.Ogre: return true;
case CardType.Clown: return true;
case CardType.Police: return true;
case CardType.Wizard: return true;
case CardType.King: return true;
}
return false;
}
public static int GetMaxHP( CardType cardType )
{
switch ( cardType )
{
case CardType.Ogre: return 2;
case CardType.Clown: return 2;
case CardType.Police: return 2;
case CardType.Wizard: return 3;
case CardType.King: return 3;
}
return 0;
}
public void SetRevealedFromAsync(bool revealed)
{
IsRevealed = revealed;
if( Card.HasHP(CardType) || IsLocked )
IconObj.Enabled = revealed;
if ( revealed )
{
NumTimesRevealed++;
if(Manager.Instance.Stats[StatType.MaxCrayonMarks] > 0f && !AreRevealMarksShown)
ShowRevealMarks();
}
}
public void SetRevealedInstant()
{
IsRevealed = true;
if ( Card.HasHP( CardType ) || IsLocked )
IconObj.Enabled = true;
WorldRotation = Rotation.FromPitch( 0f );
NumTimesRevealed++;
if ( Manager.Instance.Stats[StatType.MaxCrayonMarks] > 0f && !AreRevealMarksShown )
ShowRevealMarks();
}
public void SetHiddenInstant()
{
IsRevealed = false;
if ( Card.HasHP( CardType ) )
IconObj.Enabled = false;
WorldRotation = Rotation.FromPitch( 180f );
}
public void Shake( float strength, float time = 0.6f, EasingType easingType = EasingType.QuadOut, bool playSfx = true )
{
IsShaking = true;
_timeSinceShakeStart = 0f;
_shakeTime = time;
_shakeEasingType = easingType;
_shakeStrength = strength;
if ( playSfx || ( OverrideShakeSfx && ( IsRevealed || !OnlyOverrideShakeSfxWhenRevealed ) ) )
PlayShakeSfx();
}
public virtual void PlayShakeSfx()
{
//Manager.Instance.PlayCardSfx( "shake_1", this, volume: 1.1f, pitch: Game.Random.Float( 1.4f, 1.6f ) );
Manager.Instance.PlayCardSfx( "shake_3", this, volume: 1.35f, pitch: Game.Random.Float( 0.94f, 1.06f ) );
}
public virtual bool OverrideShakeSfx => false;
public virtual bool OnlyOverrideShakeSfxWhenRevealed => false;
public virtual void PlayHurtSfx(Card card0, Card card1)
{
Manager.Instance.PlayCardSfxBetween( "shake_1", card0, card1, volume: 1.3f, pitch: Game.Random.Float( 1.4f, 1.6f ) );
}
// return false if needed to change start pos
public virtual bool ValidateStartingGridPos()
{
return true;
}
public virtual bool ShouldHandleEvent( EventType eventType )
{
return false;
}
public virtual async Task HandleEventAsync(EventType eventType)
{
await Task.Frame();
}
public virtual string GetEventText( EventType eventType )
{
return GetCardDescription( CardType );
}
public async Task Hurt()
{
if(!Card.HasHP(CardType))
{
Log.Error( $"Trying to hurt card {CardType} with no HP!" );
return;
}
HP--;
await Manager.Instance.ShakeCard(this, playSfx: false);
}
public void Lock(int numTurns)
{
IsLocked = true;
LockTurnsRemaining = numTurns;
WasJustLocked = true;
}
public void Unlock()
{
IsLocked = false;
}
public virtual bool CanBeMatched()
{
return true;
}
public void StartExploding(float explodeTime)
{
IsExploding = true;
_timeSinceStartExploding = 0f;
_explodeTime = explodeTime;
_explodeStartPos = LocalPosition;
int rand = Game.Random.Int( 0, 5 );
switch(rand)
{
case 0: _explodeEasingType = EasingType.SineIn; break;
case 1: _explodeEasingType = EasingType.SineIn; break;
case 2: _explodeEasingType = EasingType.QuadIn; break;
case 3: _explodeEasingType = EasingType.QuadIn; break;
case 4: _explodeEasingType = EasingType.QuartIn; break;
case 5: _explodeEasingType = EasingType.Linear; break;
}
rand = Game.Random.Int( 0, 7 );
switch ( rand )
{
case 0: _explodeShakeEasingType = EasingType.SineIn; break;
case 1: _explodeShakeEasingType = EasingType.QuadIn; break;
case 2: _explodeShakeEasingType = EasingType.QuartIn; break;
case 3: _explodeShakeEasingType = EasingType.ExpoIn; break;
case 4: _explodeShakeEasingType = EasingType.ExpoIn; break;
case 5: _explodeShakeEasingType = EasingType.ExpoIn; break;
case 6: _explodeShakeEasingType = EasingType.ExpoIn; break;
case 7: _explodeShakeEasingType = EasingType.Linear; break;
}
}
public void Explode( int breakNum )
{
var scale = LocalScale.x * Model.LocalScale.x;
Manager.Instance.SpawnCardBreak( WorldPosition, LocalRotation, scale, ModelRenderer.MaterialOverride, breakNum );
Manager.Instance.PlayCardSfx( "explosion", this, volume: Game.Random.Float( 0.4f, 0.55f ), pitch: Game.Random.Float( 0.4f, 2f ) );
Manager.Instance.CardBreakParticlesPrefab.Clone( WorldPosition.WithZ( 25f ) );
Manager.Instance.CardBreakShockwavePrefab.Clone( WorldPosition.WithZ( 55f ) );
GameObject.Destroy();
}
public void StartScaling(float time, float amount, EasingType easingType)
{
IsScaling = true;
_timeSinceScale = 0f;
_scaleTime = time;
_scaleAmount = amount;
_scaleEasingType = easingType;
}
public void ShowFlag()
{
IsFlagShown = true;
IconBackObj.Enabled = true;
}
public void HideFlag()
{
IsFlagShown = false;
if ( !AreRevealMarksShown )
IconBackObj.Enabled = false;
}
public void ShowRevealMarks()
{
AreRevealMarksShown = true;
IconBackObj.Enabled = true;
}
}