s&box Package Code Search
Search C# source code, UI razor templates, shaders, and configs across s&box packages.
link Raw Facepunch API Link: https://public.facepunch.com/sbox/code/search/1/?ident=facepunch.memory&take=20
Showing code results for query:
*
(212 total matches found)
Game
game
using Sandbox;
using System.Drawing;
public class FloaterLock : Component
{
public int NumTurns { get; set; }
private TimeSince _timeSinceSpawn;
public float Lifetime { get; set; }
public bool ShowLocked { get; set ; }
private float _startScale;
private float _endScale;
private Vector2 _velocity;
private float _deceleration;
public float Scale { get; set; }
public float Opacity { get; set; }
public void Init( int numTurns )
{
NumTurns = numTurns;
Lifetime = 1.25f;
_velocity = new Vector2( 0f, 12f );
_deceleration = 4f;
Scale = _startScale = 1f;
_endScale = 1f;
}
protected override void OnStart()
{
base.OnStart();
_timeSinceSpawn = 0f;
Manager.Instance.PlaySfx( "lock_start", new Vector3( WorldPosition.x, WorldPosition.y, Manager.Instance.Camera.WorldPosition.z - 100f ), volume: 0.9f, pitch: Game.Random.Float( 1.05f, 1.13f ) );
}
protected override void OnUpdate()
{
Opacity = Utils.Map( _timeSinceSpawn, 0f, 0.3f, 0f, 1f, EasingType.QuadOut ) * Utils.Map( _timeSinceSpawn, 0f, Lifetime - 0.1f, 1f, 0.1f, EasingType.ExpoIn ) * Utils.Map( _timeSinceSpawn, Lifetime - 0.3f, Lifetime - 0.05f, 1f, 0f, EasingType.Linear );
Scale = Utils.Map( _timeSinceSpawn, 0f, Lifetime, _startScale, _endScale, EasingType.SineOut );
WorldPosition += new Vector3( _velocity.x, _velocity.y, 0f ) * Time.Delta;
_velocity *= (1f - _deceleration * Time.Delta);
if( !ShowLocked && _timeSinceSpawn > 0.5f )
{
ShowLocked = true;
_velocity = new Vector2( 0f, -20f );
_deceleration = 7f;
Manager.Instance.PlaySfx( "lock", new Vector3( WorldPosition.x, WorldPosition.y, Manager.Instance.Camera.WorldPosition.z - 100f ), volume: 2f, pitch: Game.Random.Float( 0.97f, 1.03f ) );
}
if ( _timeSinceSpawn > Lifetime )
{
Manager.Instance.NumFloaters--;
GameObject.Destroy();
}
}
}
Game
game
using Microsoft.VisualBasic;
using Sandbox;
using Sandbox.UI;
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;
}
}
Game
game
using Sandbox;
using System.Net;
using System.Threading.Tasks;
public class CardBank : Card
{
public override bool ShouldHandleEvent( EventType eventType )
{
switch ( eventType )
{
case EventType.Match:
return Manager.Instance.ChosenCards[1] == this;
}
return false;
}
public override async Task HandleEventAsync( EventType eventType )
{
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 150 );
var coins = Manager.Instance.Cards.Where( x => x.CardType == CardType.Coin ).ToList();
if(coins.Count > 0)
{
Manager.Instance.PlayCardSfxBetween( "bank", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1f, pitch: Game.Random.Float( 0.9f, 1.1f ) );
await Task.DelayRealtime( 50 );
foreach ( var coin in coins )
coin.SetCardType( CardType.MoneyBag );
await Task.DelayRealtime( 300 );
}
await Task.DelayRealtime( 800 );
Manager.Instance.PopEventMessage();
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
public class CardCockroach : Card
{
public override bool IsAlive => true;
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Mismatch && Manager.Instance.ChosenCards[0].CardType == CardType.Cockroach && Manager.Instance.ChosenCards[1].CardType == CardType.Cockroach && !IsLocked;
}
public override async Task HandleEventAsync( EventType eventType )
{
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 850 );
Manager.Instance.PopEventMessage();
}
public override bool CanBeMatched()
{
foreach(var card in Manager.Instance.Cards)
{
if ( card.CardType != CardType.Cockroach )
return false;
}
return true;
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
public class CardDancer : Card
{
public override bool IsAlive => true;
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Mismatch && Manager.Instance.ChosenCards.Contains( this ) && !Manager.Instance.IsMismatchALockedMatch;
}
public override async Task HandleEventAsync( EventType eventType )
{
Manager.Instance.PushEventMessage( this, eventType );
List<Card> neighbourCards = new();
List<IntVector2> neighboursEmpty = new();
Card lastPartnerCard = null;
await Task.DelayRealtime( 300 );
Manager.Instance.PlayCardSfx( "dancer", this, volume: 1.1f, pitch: Game.Random.Float( 0.98f, 1.02f ) );
for (int i = 0; i < 4; i++)
{
neighbourCards.Clear();
neighboursEmpty.Clear();
EvaluateNeighbour( GridPos + new IntVector2( -1, 0 ), neighbourCards, neighboursEmpty );
EvaluateNeighbour( GridPos + new IntVector2( 1, 0 ), neighbourCards, neighboursEmpty );
EvaluateNeighbour( GridPos + new IntVector2( 0, -1 ), neighbourCards, neighboursEmpty );
EvaluateNeighbour( GridPos + new IntVector2( 0, 1 ), neighbourCards, neighboursEmpty );
IntVector2 targetGridPos;
Card targetCard = null;
var validNeighbourCards = neighbourCards.Where( x => x != lastPartnerCard ).ToList();
if ( validNeighbourCards.Count > 0 )
{
validNeighbourCards.Shuffle();
targetCard = validNeighbourCards.First();
targetGridPos = targetCard.GridPos;
}
else
{
neighboursEmpty.Shuffle();
targetGridPos = neighboursEmpty.First();
}
if ( targetCard != null )
{
await Manager.Instance.ShakeCard( this );
await Manager.Instance.ShakeCard( targetCard );
lastPartnerCard = targetCard;
await Task.DelayRealtime( 650 );
if(i < 3)
{
await Manager.Instance.SwapCardPositions( this, targetCard );
await Task.DelayRealtime( 250 );
}
}
else
{
lastPartnerCard = null;
if ( i < 3 )
{
Manager.Instance.RemoveCardGridPos( this );
await Manager.Instance.SetCardGridPos( this, targetGridPos );
await Task.DelayRealtime( 400 );
}
}
}
await Task.DelayRealtime( 100 );
Manager.Instance.PopEventMessage();
await Manager.Instance.EventHappened( EventType.AfterCardsMoved );
}
void EvaluateNeighbour(IntVector2 gridPos, List<Card> neighbourCards, List<IntVector2> empty)
{
if ( !Manager.Instance.IsGridPosInBounds( gridPos ) )
return;
var card = Manager.Instance.GetCardAtGridPos( gridPos );
if ( card != null )
neighbourCards.Add( card );
else
empty.Add( gridPos );
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
using System.Xml.Linq;
public class CardDolphin : Card
{
public override bool IsAlive => true;
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Mismatch && !Manager.Instance.ChosenCards.Contains(this) && Manager.Instance.Stats[StatType.ConsecutiveMismatches] == 3;
}
public override async Task HandleEventAsync( EventType eventType )
{
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 250 );
Manager.Instance.PlayCardSfx( "card_flip", this, volume: 0.8f, pitch: Game.Random.Float( 1.15f, 1.2f ) );
await Task.DelayRealtime( 100 );
Manager.Instance.PlayCardSfx( "dolphin", this, volume: 0.8f, pitch: Game.Random.Float( 1f, 1.15f ) );
await Manager.Instance.RevealCard( this );
await Task.DelayRealtime( Game.Random.Int(400, 700) );
Manager.Instance.HideCard( this );
Manager.Instance.PlayCardSfx( "card_flip", this, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );
Manager.Instance.PopEventMessage();
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
public class CardGenie : Card
{
public override bool IsAlive => true;
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Match && Manager.Instance.ChosenCards[0] == this;
}
public override async Task HandleEventAsync( EventType eventType )
{
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 250 );
Manager.Instance.PlayCardSfxBetween( "genie", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 0.6f, pitch: Game.Random.Float( 1.25f, 1.26f ) );
Manager.Instance.AddStatus( "StatusGenie" );
await Task.DelayRealtime( 1750 );
Manager.Instance.PopEventMessage();
}
}
public class StatusGenie : StatusEffect
{
public float TimerReductionAmount { get; set; }
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Choose;
}
public override async Task HandleEventAsync( EventType eventType )
{
var validCards = Manager.Instance.Cards.Where(x => x.CardType == Manager.Instance.ChosenCard.CardType && x != Manager.Instance.ChosenCard).ToList();
if ( validCards.Count == 0 )
return;
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 250 );
Manager.Instance.PlayCardSfx( "genie_choose", Manager.Instance.ChosenCard, volume: 0.9f, pitch: Game.Random.Float( 0.95f, 1.05f ) );
await Task.DelayRealtime( 750 );
validCards.Shuffle();
await Manager.Instance.ShakeCard( validCards.FirstOrDefault() );
await Task.DelayRealtime( 750 );
Manager.Instance.PopEventMessage();
Manager.Instance.RemoveStatus( this );
}
public override string GetEventIcon( EventType eventType )
{
return "textures/genie.png";
}
public override string GetEventText( EventType eventType )
{
return "Shake matching card";
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
public class CardKey : Card
{
//public override bool ShouldHandleEvent( EventType eventType )
//{
// return eventType == EventType.Mismatch && Manager.Instance.ChosenCards.Contains(this) || eventType == EventType.Match && Manager.Instance.ChosenCards[1] == this;
//}
//public override async Task HandleEventAsync( EventType eventType )
//{
// if ( eventType == EventType.Mismatch )
// {
// var key = Manager.Instance.ChosenCards[0].CardType == CardType.Key ? Manager.Instance.ChosenCards[0] : Manager.Instance.ChosenCards[1];
// var otherCard = Manager.Instance.ChosenCards[0].CardType == CardType.Key ? Manager.Instance.ChosenCards[1] : Manager.Instance.ChosenCards[0];
// if ( key.IsLocked || !otherCard.IsLocked )
// return;
// Manager.Instance.PushEventMessage( this, eventType );
// await Task.DelayRealtime( 50 );
// Manager.Instance.PlayCardSfxBetween( "key", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1.5f, pitch: Game.Random.Float( 0.9f, 1.1f ) );
// await Task.DelayRealtime( 50 );
// await Manager.Instance.UnlockCard( otherCard );
// await Task.DelayRealtime( 900 );
// Manager.Instance.PopEventMessage();
// }
// else if (eventType == EventType.Match)
// {
// Manager.Instance.PushEventMessage( this, eventType );
// await Task.DelayRealtime( 50 );
// var lockedCards = Manager.Instance.Cards.Where( x => x.IsLocked ).ToList();
// if ( lockedCards.Count == 0 )
// {
// await Task.DelayRealtime( 800 );
// Manager.Instance.PopEventMessage();
// return;
// }
// Manager.Instance.PlayCardSfxBetween( "key", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1.5f, pitch: Game.Random.Float( 0.9f, 1.1f ) );
// await Task.DelayRealtime( 50 );
// foreach ( var card in lockedCards )
// {
// await Manager.Instance.UnlockCard( card );
// }
// await Task.DelayRealtime( 1000 );
// Manager.Instance.PopEventMessage();
// }
//}
//public override string GetEventText( EventType eventType )
//{
// if ( eventType == EventType.Mismatch )
// {
// return "❌Mismatch: unlock other card";
// }
// else
// {
// return "✅Match: unlock all cards";
// }
//}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicGuideDog : Relic
{
public override void Init()
{
base.Init();
MaxLevel = 1;
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicMammothMeat : Relic
{
public override void LevelUp()
{
base.LevelUp();
var mouse = Mouse.Position;
var camera = Scene.Camera;
var ray = camera.ScreenPixelToRay( mouse );
var tr = Scene.Trace.Ray( ray, 10000f ).Run();
Manager.Instance.PlaySfxCenter( "mammoth_meat", volume: 0.75f, pitch: Game.Random.Float( 0.85f, 0.9f ) );
int maxHpAmount = 8;
Manager.Instance.SpawnMaxHPFloater( maxHpAmount, tr.EndPosition );// + new Vector3(0f, -30f, 0f) );
Manager.Instance.MaxHP += maxHpAmount;
//int hpAmount = 5;
//Manager.Instance.HP = Math.Min( Manager.Instance.HP + hpAmount, Manager.Instance.MaxHP );
Manager.Instance.TimeSinceHPChanged = 0f;
//Manager.Instance.SpawnHealHPFloater( hpAmount, tr.EndPosition );
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicMantlepieceClock : Relic
{
public override void LevelUp()
{
base.LevelUp();
Manager.Instance.Stats[StatType.NumExtraBountyTurns] += (Level == 1 ? 2f : 1f);
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicMedicalLicense : Relic
{
public override void Init()
{
base.Init();
MaxLevel = 1;
}
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.OverhealHP;
}
public override async Task HandleEventAsync( EventType eventType )
{
await Task.DelayRealtime( 1000 );
Manager.Instance.PushEventMessage( this, eventType );
var camera = Scene.Camera;
var ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );
var tr = Scene.Trace.Ray( ray, 10000f ).Run();
Manager.Instance.PlaySfx( "medical_license", tr.EndPosition.WithZ( Scene.Camera.WorldPosition.z - Globals.CARD_SFX_DEPTH_DIFF ), volume: 1.2f, pitch: Game.Random.Float( 0.95f, 1.05f ) );
await Task.DelayRealtime( 350 );
int moneyAmount = (int)Manager.Instance.Stats[StatType.LatestOverhealAmount] + (int)Manager.Instance.Stats[StatType.EarnExtraMoney];
Manager.Instance.SpawnGainMoneyFloater( moneyAmount, tr.EndPosition );
await Manager.Instance.GainMoney( moneyAmount );
await Task.DelayRealtime( 650 );
Manager.Instance.PopEventMessage();
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicMouseTrap : Relic
{
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.ClaimBounty;
}
public override async Task HandleEventAsync(EventType eventType)
{
Manager.Instance.PushEventMessage( this, eventType );
await Task.DelayRealtime( 100 );
Manager.Instance.PlaySfxCenter( "mouse_trap", volume: 0.8f, pitch: Game.Random.Float( 0.95f, 1.05f ) );
await Task.DelayRealtime( 400 );
var camera = Scene.Camera;
var ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );
var tr = Scene.Trace.Ray( ray, 10000f ).Run();
int maxHP = Level;
Manager.Instance.SpawnMaxHPFloater( maxHP, tr.EndPosition );
Manager.Instance.MaxHP += maxHP;
Manager.Instance.TimeSinceHPChanged = 0f;
await Task.DelayRealtime( 500 );
Manager.Instance.PopEventMessage();
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;
public class RelicSacrificialBlade : Relic
{
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.HurtCards;
}
public override async Task HandleEventAsync(EventType eventType)
{
Manager.Instance.PushEventMessage( this, eventType );
var camera = Scene.Camera;
var ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );
var tr = Scene.Trace.Ray( ray, 10000f ).Run();
Manager.Instance.PlaySfx( "sacrificial_blade", tr.EndPosition.WithZ( Scene.Camera.WorldPosition.z - Globals.CARD_SFX_DEPTH_DIFF ), volume: 0.75f, pitch: Game.Random.Float( 1.6f, 1.65f ) );
await Task.DelayRealtime( 450 );
int healAmount = Level;
Manager.Instance.SpawnHealHPFloater( healAmount, tr.EndPosition );
await Task.DelayRealtime( 350 );
await Manager.Instance.GainHP( healAmount );
await Task.DelayRealtime( 250 );
Manager.Instance.PopEventMessage();
}
}
Game
game
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
public class RelicSign : Relic
{
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.Mismatch && Game.Random.Float(0f, 1f) < Level * 0.25f;
}
public override async Task HandleEventAsync( EventType eventType )
{
List<Card> validCards = new();
foreach ( var card in Manager.Instance.Cards )
{
if ( card.NumTimesRevealed > 0 && !Manager.Instance.ChosenCards.Contains(card) && !card.IsRevealed )
validCards.Add( card );
}
if ( validCards.Count == 0 )
return;
Manager.Instance.PushEventMessage( this, eventType );
// todo: sfx
await Task.DelayRealtime( 250 );
validCards.Shuffle();
var cardToReveal = validCards.First();
Manager.Instance.PlayCardSfx( "card_flip", cardToReveal, volume: 0.8f, pitch: Game.Random.Float( 1.15f, 1.2f ) );
await Manager.Instance.RevealCard( cardToReveal );
await Task.DelayRealtime( 750 );
Manager.Instance.HideCard( cardToReveal );
Manager.Instance.PlayCardSfx( "card_flip", cardToReveal, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );
await Task.DelayRealtime( 300 );
Manager.Instance.PopEventMessage();
}
}
Game
game
MessagePanel {
position: absolute;
//min-width: 60%;
height: 60px;
bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
//background-color: #00000088;
flex-direction: row;
padding: 8px;
backdrop-filter: blur(5px);
//transition: bottom 0.25s ease-out, transform 0.25s ease-out, opacity 0.25s ease-out;
transition: all 0.25s ease-out;
.message {
font-size: 24px;
color: #ffffffee;
}
.icon {
width: 55px;
height: 55px;
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
}
&.depth-0 {
transform: scale(1);
bottom: 10px;
z-index: 0;
}
&.depth-1 {
transform: scale(0.8);
bottom: 50px;
z-index: -3;
}
&.depth-2 {
transform: scale(0.6);
bottom: 90px;
z-index: -6;
}
&.depth-3 {
transform: scale(0.5);
bottom: 110px;
z-index: -9;
}
&.depth-4 {
transform: scale(0.4);
bottom: 140px;
z-index: -12;
}
}
Game
game
CardTypePanelElement {
//border-radius: 10px;
height: 80px;
width: 80px;
justify-content: center;
//flex-shrink: 1;
//margin: 2px;
//background-color: blue;
//border: 2px solid #111111;
//overflow: visible;
position: relative;
.icon_container {
width: 100%;
height: 100%;
transform: scale(1);
transition: transform 0.075s ease-out;
pointer-events: all;
&:hover {
//background-color: #301B3F99;
//border: 2px solid #111111;
//opacity: 1;
transform: scale(1.2);
}
}
.icon {
position: absolute;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
pointer-events: none;
}
.normal {
filter: brightness(1);
opacity: 1;
}
.matched {
filter: brightness(0);
opacity: 0.4;
}
.bounty {
position: absolute;
width: 60px;
height: 60px;
background-color: #0000ff99;
}
}
Game
game
using Sandbox;
public sealed class CardBreaker : Component
{
protected override void OnStart()
{
}
public void Init(Material material, Rotation rot, float scale)
{
LocalRotation = rot;
LocalScale = new Vector3( scale );
for ( int i = GameObject.Children.Count - 1; i >= 0; i-- )
{
var child = GameObject.Children[i];
child.SetParent( null );
var modelRenderer = child.Components.Get<ModelRenderer>();
modelRenderer.Tint = Color.White;
modelRenderer.MaterialOverride = material;
var rigidBody = child.Components.Get<Rigidbody>();
rigidBody.ApplyImpulse( (child.WorldPosition - WorldPosition).Normal * Game.Random.Float( 10f, 100f ) * rigidBody.PhysicsBody.Mass );
rigidBody.ApplyImpulse( new Vector3( 0f, 0f, 1f ) * Game.Random.Float( 400f, 800f ) * rigidBody.PhysicsBody.Mass );
rigidBody.AngularVelocity = Vector3.Random * Game.Random.Float( -10f, 10f );
}
GameObject.Destroy();
}
}
Game
game
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
using System.Text.Json;
public enum EasingType
{
None = -1,
Linear = 0,
SineIn, SineOut, SineInOut,
QuadIn, QuadOut, QuadInOut,
CubicIn, CubicOut, CubicInOut,
QuartIn, QuartOut, QuartInOut,
QuintIn, QuintOut, QuintInOut,
ExpoIn, ExpoOut, ExpoInOut,
ExtremeIn, ExtremeOut, ExtremeInOut,
ElasticIn, ElasticOut, ElasticInOut,
ElasticSoftIn, ElasticSoftOut, ElasticSoftInOut,
BackIn, BackOut, BackInOut,
BounceIn, BounceOut, BounceInOut
};
public struct IntVector2 : IEquatable<IntVector2>
{
public static implicit operator Vector2( IntVector2 vec )
{
return new Vector2( vec.x, vec.y );
}
public static explicit operator IntVector2( Vector2 vec )
{
return new IntVector2( (int)vec.x, (int)vec.y );
}
/// <summary>
/// A vector with zero for all components.
/// </summary>
public static readonly IntVector2 Zero = new IntVector2( 0, 0 );
/// <summary>
/// A normalized vector along the positive X axis.
/// </summary>
public static readonly IntVector2 UnitX = new IntVector2( 1, 0 );
/// <summary>
/// A normalized vector along the positive Y axis.
/// </summary>
public static readonly IntVector2 UnitY = new IntVector2( 0, 1 );
#region Operators
/// <summary>
/// The identity operator.
/// </summary>
public static IntVector2 operator +( IntVector2 vec )
{
return vec;
}
/// <summary>
/// Component-wise addition of a vector to another.
/// </summary>
public static IntVector2 operator +( IntVector2 a, IntVector2 b )
{
return new IntVector2( a.x + b.x, a.y + b.y );
}
/// <summary>
/// Finds the negation of a vector.
/// </summary>
public static IntVector2 operator -( IntVector2 vec )
{
return new IntVector2( -vec.x, -vec.y );
}
/// <summary>
/// Component-wise subtraction of a vector from another.
/// </summary>
public static IntVector2 operator -( IntVector2 a, IntVector2 b )
{
return new IntVector2( a.x - b.x, a.y - b.y );
}
/// <summary>
/// Component-wise multiplication of a vector by another.
/// </summary>
public static IntVector2 operator *( IntVector2 a, IntVector2 b )
{
return new IntVector2( a.x * b.x, a.y * b.y );
}
/// <summary>
/// Multiplies a vector by a scalar.
/// </summary>
public static IntVector2 operator *( IntVector2 vec, int val )
{
return new IntVector2( vec.x * val, vec.y * val );
}
/// <summary>
/// Multiplies a vector by a scalar.
/// </summary>
public static Vector2 operator *( IntVector2 vec, float val )
{
return new Vector2( vec.x * val, vec.y * val );
}
/// <summary>
/// Multiplies a vector by a scalar.
/// </summary>
public static IntVector2 operator *( int val, IntVector2 vec )
{
return new IntVector2( vec.x * val, vec.y * val );
}
/// <summary>
/// Multiplies a vector by a scalar.
/// </summary>
public static Vector2 operator *( float val, IntVector2 vec )
{
return new Vector2( vec.x * val, vec.y * val );
}
/// <summary>
/// Component-wise division of a vector by another.
/// </summary>
public static IntVector2 operator /( IntVector2 a, IntVector2 b )
{
return new IntVector2( a.x / b.x, a.y / b.y );
}
/// <summary>
/// Component-wise division of a vector by another.
/// </summary>
public static Vector2 operator /( Vector2 a, IntVector2 b )
{
return new Vector2( a.x / b.x, a.y / b.y );
}
/// <summary>
/// Component-wise division of a vector by another.
/// </summary>
public static Vector2 operator /( IntVector2 a, Vector2 b )
{
return new Vector2( a.x / b.x, a.y / b.y );
}
/// <summary>
/// Division of this vector by a scalar.
/// </summary>
public static IntVector2 operator /( IntVector2 vec, int val )
{
return new IntVector2( vec.x / val, vec.y / val );
}
public static Vector2 operator /( IntVector2 vec, float val )
{
return new Vector2( vec.x / val, vec.y / val );
}
public static IntVector2 operator /( int val, IntVector2 vec )
{
return new IntVector2( val / vec.x, val / vec.y );
}
public static Vector2 operator /( float val, IntVector2 vec )
{
return new Vector2( val / vec.x, val / vec.y );
}
#endregion
/// <summary>
/// Horizontal component.
/// </summary>
public int x;
/// <summary>
/// Vertical component.
/// </summary>
public int y;
/// <summary>
/// Floating point magnitude of the vector.
/// </summary>
public float Length { get { return (float)MathF.Sqrt( x * x + y * y ); } }
/// <summary>
/// Magnitude of the vector in Taxicab geometry.
/// </summary>
public int ManhattanLength { get { return Math.Abs( x ) + Math.Abs( y ); } }
/// <summary>
/// Sum of each component squared.
/// </summary>
public int LengthSquared { get { return x * x + y * y; } }
/// <summary>
/// Gets a normalized vector in the same direction as this one.
/// </summary>
public Vector2 Normalized { get { return LengthSquared >= float.Epsilon ? this / Length : Zero; } }
/// <summary>
/// Gets a vector equal to this one rotated counter-clockwise by 90 degrees.
/// </summary>
public IntVector2 Left { get { return new IntVector2( -y, x ); } }
/// <summary>
/// Gets a vector equal to this one rotated clockwise 90 degrees.
/// </summary>
public IntVector2 Right { get { return new IntVector2( y, -x ); } }
/// <summary>
/// Gets a vector equal to this one rotated 180 degrees.
/// </summary>
public IntVector2 Back { get { return -this; } }
/// <summary>
/// Constructs a vector from the given X and Y components.
/// </summary>
public IntVector2( int x, int y )
{
this.x = x; this.y = y;
}
/// <summary>
/// Finds the scalar product of this vector and another.
/// </summary>
public int Dot( IntVector2 vec )
{
return x * vec.x + y * vec.y;
}
public override bool Equals( object obj )
{
return obj is IntVector2 && Equals( (IntVector2)obj );
}
/// <summary>
/// Tests for equality with another vector.
/// </summary>
public bool Equals( IntVector2 vec )
{
return x == vec.x && y == vec.y;
}
public override int GetHashCode()
{
return x ^ y;
}
/// <summary>
/// Gets a string representing this vector in (X, Y) format.
/// </summary>
public override string ToString()
{
return string.Format( "({0}, {1})", x, y );
}
}
public struct AStarEdge<T>
{
/// <summary>
/// The node this connection leads to.
/// </summary>
public readonly T Dest;
/// <summary>
/// The cost of using this connection.
/// </summary>
public readonly float Cost;
internal AStarEdge( T dest, float cost )
{
Dest = dest;
Cost = cost;
}
}
public static class Utils
{
// projects vector A onto B
public static Vector3 ProjectVector( Vector3 a, Vector3 b )
{
float dotProduct = Vector3.Dot( a, b );
float lengthSquared = Vector3.Dot( b, b );
return (dotProduct / lengthSquared) * b;
}
// returns vector B or C, whichever is in the closest direction compared to A
public static Vector3 FindCloserVector( Vector3 a, Vector3 b, Vector3 c )
{
// Normalize B and C
b = b.Normal;
c = c.Normal;
// Compute dot products
float dotProductB = Vector3.Dot( a, b );
float dotProductC = Vector3.Dot( a, c );
// Determine which dot product is larger
return dotProductB > dotProductC ? b : c;
}
public static GameObject FindChild( this Component component, string name )
{
return component.GameObject.Children.Where( x => x.Name == name ).FirstOrDefault();
}
public static Color GetRandomColor( float total = 1.5f )
{
float r = Game.Random.Float( 0f, 1f );
total = Math.Max( total - r, 0f );
float g = MathF.Min( Game.Random.Float( 0f, 1f ), total );
total = Math.Max( total - g, 0f );
float b = MathF.Min( Game.Random.Float( 0f, 1f ), total );
return new Color( r, g, b );
}
public static T ReadJsonCustom<T>( this BaseFileSystem fs, string filename, T defaultValue = default( T ) )
{
string text = fs.ReadAllText( filename );
if ( string.IsNullOrWhiteSpace( text ) )
{
return defaultValue;
}
JsonSerializerOptions options = new JsonSerializerOptions
{
ReadCommentHandling = JsonCommentHandling.Skip,
PropertyNameCaseInsensitive = true,
AllowTrailingCommas = true,
Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() },
};
return JsonSerializer.Deserialize<T>( text, options );
}
public const float Deg2Rad = MathF.PI / 180f;
public const float Rad2Deg = 360f / (MathF.PI * 2f);
public static Vector2 RotateVector( Vector2 v, float degrees )
{
var rads = Deg2Rad * degrees;
var ca = MathF.Cos( rads );
var sa = MathF.Sin( rads );
return new Vector2( ca * v.x - sa * v.y, sa * v.x + ca * v.y );
}
public static Vector2 RotatePointAround( Vector2 p, Vector2 anchor, float degrees )
{
var offset = p - anchor;
var newVec = RotateVector( offset, degrees );
return anchor + newVec;
}
public static Vector2 DegreesToVector( float degrees )
{
var rads = Deg2Rad * degrees;
return new Vector2( MathF.Cos( rads ), MathF.Sin( rads ) );
}
public static float VectorToDegrees( Vector2 vec )
{
float radians = (float)Math.Atan2( vec.y, vec.x );
float degrees = radians * (180f / (float)Math.PI);
return degrees;
}
public static Vector2 GetPerpendicularVector( Vector2 vec )
{
return new Vector2( -vec.y, vec.x );
}
public static int GetDistance( int x, int y )
{
return (int)Math.Round( Math.Sqrt( x * x + y * y ) );
}
public static Vector2 GetRandomVector()
{
return DegreesToVector( Game.Random.Float( 0f, 360f ) );
}
public static float FastSin( float input )
{
// wrap input angle to -PI..PI
while ( input < -3.14159265f )
input += 6.28318531f;
while ( input > 3.14159265f )
input -= 6.28318531f;
return 1.27323954f * input + 0.405284735f * (input < 0f ? 1f : -1f) * input * input;
}
public static float DynamicEaseTo( float current, float goal, float factorPercent, float dt, float referenceFrameRate = 60f )
{
if ( float.IsPositiveInfinity( dt ) )
return goal;
return current + (goal - current) * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));
}
public static Vector2 DynamicEaseTo( Vector2 current, Vector2 goal, float factorPercent, float dt, float referenceFrameRate = 60f )
{
if ( float.IsPositiveInfinity( dt ) )
return goal;
var diff = goal - current;
return current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));
}
public static Vector3 DynamicEaseTo( Vector3 current, Vector3 goal, float factorPercent, float dt, float referenceFrameRate = 60f )
{
if ( float.IsPositiveInfinity( dt ) )
return goal;
var diff = goal - current;
return current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));
}
public static Rotation DynamicEaseTo( Rotation currentRot, Rotation goalRot, float factorPercent, float dt, float referenceFrameRate = 60f )
{
if ( float.IsPositiveInfinity( dt ) )
return goalRot;
Vector3 current = currentRot.Angles().AsVector3();
Vector3 goal = goalRot.Angles().AsVector3();
var diff = goal - current;
var output = current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));
return Rotation.From( new Angles( output ) );
}
public static float EaseUnclamped( float value, EasingType easingType )
{
switch ( easingType )
{
case EasingType.SineIn: return SineIn( value );
case EasingType.SineOut: return SineOut( value );
case EasingType.SineInOut: return SineInOut( value );
case EasingType.QuadIn: return QuadIn( value );
case EasingType.QuadOut: return QuadOut( value );
case EasingType.QuadInOut: return QuadInOut( value );
case EasingType.CubicIn: return CubicIn( value );
case EasingType.CubicOut: return CubicOut( value );
case EasingType.CubicInOut: return CubicInOut( value );
case EasingType.QuartIn: return QuartIn( value );
case EasingType.QuartOut: return QuartOut( value );
case EasingType.QuartInOut: return QuartInOut( value );
case EasingType.QuintIn: return QuintIn( value );
case EasingType.QuintOut: return QuintOut( value );
case EasingType.QuintInOut: return QuintInOut( value );
case EasingType.ExpoIn: return ExpoIn( value );
case EasingType.ExpoOut: return ExpoOut( value );
case EasingType.ExpoInOut: return ExpoInOut( value );
case EasingType.ExtremeIn: return ExtremeIn( value );
case EasingType.ExtremeOut: return ExtremeOut( value );
case EasingType.ExtremeInOut: return ExtremeInOut( value );
case EasingType.ElasticIn: return ElasticIn( value );
case EasingType.ElasticOut: return ElasticOut( value );
case EasingType.ElasticInOut: return ElasticInOut( value );
case EasingType.ElasticSoftIn: return ElasticSoftIn( value );
case EasingType.ElasticSoftOut: return ElasticSoftOut( value );
case EasingType.ElasticSoftInOut: return ElasticSoftInOut( value );
case EasingType.BackIn: return BackIn( value );
case EasingType.BackOut: return BackOut( value );
case EasingType.BackInOut: return BackInOut( value );
case EasingType.BounceIn: return BounceIn( value );
case EasingType.BounceOut: return BounceOut( value );
case EasingType.BounceInOut: return BounceInOut( value );
default: return value;
}
}
public static float Map( float value, float inputMin, float inputMax, float outputMin, float outputMax, EasingType easingType = EasingType.Linear, bool clamp = true )
{
if ( inputMin.Equals( inputMax ) || outputMin.Equals( outputMax ) )
return outputMin;
// if(inputMin.Equals(inputMax) || outputMin.Equals(outputMax))
// return outputMax;
if ( clamp )
{
// clamp input
if ( inputMax > inputMin )
{
if ( value < inputMin ) value = inputMin;
else if ( value > inputMax ) value = inputMax;
}
else if ( inputMax < inputMin )
{
if ( value > inputMin ) value = inputMin;
else if ( value < inputMax ) value = inputMax;
}
}
var ratio = EaseUnclamped( (value - inputMin) / (inputMax - inputMin), easingType );
var outVal = outputMin + ratio * (outputMax - outputMin);
// // clamp output
// if(outputMax < outputMin) {
// if(outVal < outputMax) outVal = outputMax;
// else if(outVal > outputMin) outVal = outputMin;
// } else {
// if(outVal > outputMax) outVal = outputMax;
// else if(outVal < outputMin) outVal = outputMin;
// }
return outVal;
}
public static float MapReturn( float value, float inputMin, float inputMax, float outputMin, float outputMax, EasingType easingType = EasingType.Linear )
{
var halfway = inputMin + (inputMax - inputMin) * 0.5f;
if ( value < halfway ) return Map( value, inputMin, halfway, outputMin, outputMax, easingType );
else return Map( value, halfway, inputMax, outputMax, outputMin, GetOppositeEasingType( easingType ) );
}
public static float EasePercent( float percent, EasingType easingType )
{
return Map( percent, 0f, 1f, 0f, 1f, easingType );
}
public static EasingType GetOppositeEasingType( EasingType easingType )
{
var opposite = EasingType.Linear;
switch ( easingType )
{
case EasingType.SineIn: opposite = EasingType.SineOut; break;
case EasingType.SineOut: opposite = EasingType.SineIn; break;
case EasingType.SineInOut: opposite = EasingType.SineInOut; break;
case EasingType.QuadIn: opposite = EasingType.QuadOut; break;
case EasingType.QuadOut: opposite = EasingType.QuadIn; break;
case EasingType.QuadInOut: opposite = EasingType.QuadInOut; break;
case EasingType.CubicIn: opposite = EasingType.CubicOut; break;
case EasingType.CubicOut: opposite = EasingType.CubicIn; break;
case EasingType.CubicInOut: opposite = EasingType.CubicInOut; break;
case EasingType.QuartIn: opposite = EasingType.QuartOut; break;
case EasingType.QuartOut: opposite = EasingType.QuartIn; break;
case EasingType.QuartInOut: opposite = EasingType.QuartInOut; break;
case EasingType.QuintIn: opposite = EasingType.QuintOut; break;
case EasingType.QuintOut: opposite = EasingType.QuintIn; break;
case EasingType.QuintInOut: opposite = EasingType.QuintInOut; break;
case EasingType.ExpoIn: opposite = EasingType.ExpoOut; break;
case EasingType.ExpoOut: opposite = EasingType.ExpoIn; break;
case EasingType.ExpoInOut: opposite = EasingType.ExpoInOut; break;
case EasingType.ExtremeIn: opposite = EasingType.ExtremeOut; break;
case EasingType.ExtremeOut: opposite = EasingType.ExtremeIn; break;
case EasingType.ExtremeInOut: opposite = EasingType.ExtremeInOut; break;
case EasingType.ElasticIn: opposite = EasingType.ElasticOut; break;
case EasingType.ElasticOut: opposite = EasingType.ElasticIn; break;
case EasingType.ElasticInOut: opposite = EasingType.ElasticInOut; break;
case EasingType.ElasticSoftIn: opposite = EasingType.ElasticSoftOut; break;
case EasingType.ElasticSoftOut: opposite = EasingType.ElasticSoftIn; break;
case EasingType.ElasticSoftInOut: opposite = EasingType.ElasticSoftInOut; break;
case EasingType.BackIn: opposite = EasingType.BackOut; break;
case EasingType.BackOut: opposite = EasingType.BackIn; break;
case EasingType.BackInOut: opposite = EasingType.BackInOut; break;
case EasingType.BounceIn: opposite = EasingType.BounceOut; break;
case EasingType.BounceOut: opposite = EasingType.BounceIn; break;
case EasingType.BounceInOut: opposite = EasingType.BounceInOut; break;
}
return opposite;
}
public static float SineIn( float t ) { return 1f - MathF.Cos( t * MathF.PI * 0.5f ); }
public static float SineOut( float t ) { return MathF.Sin( t * (MathF.PI * 0.5f) ); }
public static float SineInOut( float t ) { return -0.5f * (MathF.Cos( MathF.PI * t ) - 1f); }
public static float QuadIn( float t ) { return t * t; }
public static float QuadOut( float t ) { return t * (2f - t); }
public static float QuadInOut( float t ) { return t < 0.5f ? 2f * t * t : -1f + (4f - 2f * t) * t; }
public static float CubicIn( float t ) { return t * t * t; }
public static float CubicOut( float t ) { var t1 = t - 1f; return t1 * t1 * t1 + 1f; }
public static float CubicInOut( float t ) { return t < 0.5f ? 4f * t * t * t : (t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f; }
public static float QuartIn( float t ) { return t * t * t * t; }
public static float QuartOut( float t ) { var t1 = t - 1f; return 1f - t1 * t1 * t1 * t1; }
public static float QuartInOut( float t ) { return t < 0.5f ? 4f * t * t * t : (t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f; }
public static float QuintIn( float t ) { return t * t * t * t * t; }
public static float QuintOut( float t ) { var t1 = t - 1f; return 1f + t1 * t1 * t1 * t1 * t1; }
public static float QuintInOut( float t ) { var t1 = t - 1f; return t < 0.5f ? 16f * t * t * t * t * t : 1f + 16f * t1 * t1 * t1 * t1 * t1; }
public static float ExpoIn( float t ) { return MathF.Pow( 2f, 10f * (t - 1f) ); }
public static float ExpoOut( float t ) { return 1f - MathF.Pow( 2f, -10f * t ); }
public static float ExpoInOut( float t ) { return t < 0.5f ? ExpoIn( t * 2f ) * 0.5f : 1f - ExpoIn( 2f - t * 2f ) * 0.5f; }
public static float ExtremeIn( float t ) { return MathF.Pow( 10f, 10f * (t - 1f) ); }
public static float ExtremeOut( float t ) { return 1f - MathF.Pow( 10f, -10f * t ); }
public static float ExtremeInOut( float t ) { return t < 0.5f ? ExtremeIn( t * 2f ) * 0.5f : 1f - ExtremeIn( 2f - t * 2f ) * 0.5f; }
public static float ElasticIn( float t ) { return 1f - ElasticOut( 1f - t ); }
public static float ElasticOut( float t ) { var p = 0.3f; return MathF.Pow( 2f, -10f * t ) * MathF.Sin( (t - p / 4f) * (2f * (float)Math.PI) / p ) + 1f; }
public static float ElasticInOut( float t ) { return t < 0.5f ? ElasticIn( t * 2f ) * 0.5f : 1f - ElasticIn( 2f - t * 2f ) * 0.5f; }
public static float ElasticSoftIn( float t ) { return 1f - ElasticSoftOut( 1f - t ); }
public static float ElasticSoftOut( float t ) { var p = 0.5f; return MathF.Pow( 2f, -10f * t ) * MathF.Sin( (t - p / 4f) * (2f * (float)Math.PI) / p ) + 1f; }
public static float ElasticSoftInOut( float t ) { return t < 0.5f ? ElasticSoftIn( t * 2f ) * 0.5f : 1f - ElasticSoftIn( 2f - t * 2f ) * 0.5f; }
public static float BackIn( float t ) { var p = 1f; return t * t * ((p + 1f) * t - p); }
public static float BackOut( float t ) { var p = 1f; var scaledTime = t / 1f - 1f; return scaledTime * scaledTime * ((p + 1f) * scaledTime + p) + 1f; }
public static float BackInOut( float t )
{
var p = 1f;
var scaledTime = t * 2f;
var scaledTime2 = scaledTime - 2f;
var s = p * 1.525f;
if ( scaledTime < 1f ) return 0.5f * scaledTime * scaledTime * ((s + 1f) * scaledTime - s);
else return 0.5f * (scaledTime2 * scaledTime2 * ((s + 1f) * scaledTime2 + s) + 2f);
}
public static float BounceIn( float t ) { return 1f - BounceOut( 1f - t ); }
public static float BounceOut( float t )
{
var scaledTime = t / 1f;
if ( scaledTime < 1 / 2.75f )
{
return 7.5625f * scaledTime * scaledTime;
}
else if ( scaledTime < 2 / 2.75 )
{
var scaledTime2 = scaledTime - 1.5f / 2.75f;
return 7.5625f * scaledTime2 * scaledTime2 + 0.75f;
}
else if ( scaledTime < 2.5 / 2.75 )
{
var scaledTime2 = scaledTime - 2.25f / 2.75f;
return 7.5625f * scaledTime2 * scaledTime2 + 0.9375f;
}
else
{
var scaledTime2 = scaledTime - 2.625f / 2.75f;
return 7.5625f * scaledTime2 * scaledTime2 + 0.984375f;
}
}
public static float BounceInOut( float t )
{
if ( t < 0.5 ) return BounceIn( t * 2f ) * 0.5f;
else return BounceOut( t * 2f - 1f ) * 0.5f + 0.5f;
}
public static void Shuffle<T>( this IList<T> list )
{
System.Random rng = new System.Random();
int n = list.Count;
while ( n > 1 )
{
n--;
int k = rng.Next( n + 1 );
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
public static string FirstCharToUpper( this string input ) =>
input switch
{
null => throw new ArgumentNullException( nameof( input ) ),
"" => throw new ArgumentException( $"{nameof( input )} cannot be empty", nameof( input ) ),
_ => string.Concat( input[0].ToString().ToUpper(), input.AsSpan( 1 ) )
};
public static string GetRandomIcon( string i0, string i1 ) { int rand = Game.Random.Int( 0, 1 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; } }
public static string GetRandomIcon( string i0, string i1, string i2 ) { int rand = Game.Random.Int( 0, 2 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; } }
public static string GetRandomIcon( string i0, string i1, string i2, string i3 ) { int rand = Game.Random.Int( 0, 3 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; } }
public static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4 ) { int rand = Game.Random.Int( 0, 4 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; } }
public static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5 ) { int rand = Game.Random.Int( 0, 5 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; } }
public static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5, string i6 ) { int rand = Game.Random.Int( 0, 6 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; case 6: return i6; } }
public static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5, string i6, string i7 ) { int rand = Game.Random.Int( 0, 7 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; case 6: return i6; case 7: return i7; } }
private class NodeInfo<T>
{
private const int MaxPoolSize = 8192;
private static List<NodeInfo<T>> _sPool;
internal static NodeInfo<T> Create( T node, NodeInfo<T> prev = null, float costAdd = 0f )
{
NodeInfo<T> nodeInfo;
if ( _sPool == null || _sPool.Count == 0 )
{
nodeInfo = new NodeInfo<T>();
}
else
{
nodeInfo = _sPool[_sPool.Count - 1];
_sPool.RemoveAt( _sPool.Count - 1 );
}
nodeInfo.Node = node;
nodeInfo.Prev = prev;
if ( prev == null )
{
nodeInfo.Depth = 0;
nodeInfo.Cost = 0f;
}
else
{
nodeInfo.Depth = prev.Depth + 1;
nodeInfo.Cost = prev.Cost + costAdd;
}
return nodeInfo;
}
internal static void Pool( NodeInfo<T> nodeInfo )
{
if ( _sPool == null ) _sPool = new List<NodeInfo<T>>( MaxPoolSize );
if ( _sPool.Count >= MaxPoolSize ) return;
_sPool.Add( nodeInfo );
}
private float _heuristic;
public T Node { get; private set; }
public NodeInfo<T> Prev { get; private set; }
public int Depth { get; private set; }
public float Cost { get; private set; }
public float Total { get; private set; }
public float Heuristic
{
get { return _heuristic; }
set
{
_heuristic = value;
Total = Cost + value;
}
}
}
/// <summary>
/// Convenience method to produce a graph connection for use when calling AStar().
/// </summary>
/// <typeparam name="T">Graph node type.</typeparam>
/// <param name="dest">Destination node of the connection.</param>
/// <param name="cost">Cost of taking the connection.</param>
public static AStarEdge<T> Edge<T>( T dest, float cost )
{
return new AStarEdge<T>( dest, cost );
}
private static class AStarWrapper<T>
where T : IEquatable<T>
{
public static NodeInfo<T> FirstMatchOrDefault( List<NodeInfo<T>> list, T toCompare )
{
var count = list.Count;
for ( var i = count - 1; i >= 0; --i )
{
var item = list[i];
if ( item.Node.Equals( toCompare ) )
return item;
}
return null;
}
private static List<NodeInfo<T>> _sOpen;
private static List<NodeInfo<T>> _sClosed;
public static bool AStar( T origin, T target, List<T> destList,
Func<T, IEnumerable<AStarEdge<T>>> adjFunc, Func<T, T, float> heuristicFunc )
{
var open = _sOpen ?? (_sOpen = new List<NodeInfo<T>>());
var clsd = _sClosed ?? (_sClosed = new List<NodeInfo<T>>());
open.Clear();
clsd.Clear();
var first = NodeInfo<T>.Create( origin );
first.Heuristic = heuristicFunc( origin, target );
open.Add( first );
try
{
while ( open.Count > 0 )
{
NodeInfo<T> cur = null;
foreach ( var node in open )
{
if ( cur == null || node.Total < cur.Total ) cur = node;
}
if ( cur.Node.Equals( target ) )
{
for ( var i = cur.Depth; i >= 0; --i )
{
destList.Add( cur.Node );
cur = cur.Prev;
}
destList.Reverse();
return true;
}
open.Remove( cur );
clsd.Add( cur );
foreach ( var adj in adjFunc( cur.Node ) )
{
var node = NodeInfo<T>.Create( adj.Dest, cur, adj.Cost );
var existing = FirstMatchOrDefault( clsd, adj.Dest );
if ( existing != null )
{
if ( existing.Cost <= node.Cost ) continue;
clsd.Remove( existing );
node.Heuristic = existing.Heuristic;
NodeInfo<T>.Pool( existing );
}
existing = FirstMatchOrDefault( open, adj.Dest );
if ( existing != null )
{
if ( existing.Cost <= node.Cost ) continue;
open.Remove( existing );
node.Heuristic = existing.Heuristic;
NodeInfo<T>.Pool( existing );
}
else
{
node.Heuristic = heuristicFunc( node.Node, target );
}
open.Add( node );
}
}
return false;
}
finally
{
foreach ( var nodeInfo in open )
{
NodeInfo<T>.Pool( nodeInfo );
}
foreach ( var nodeInfo in clsd )
{
NodeInfo<T>.Pool( nodeInfo );
}
}
}
}
/// <summary>
/// An implementation of the AStar path finding algorithm.
/// </summary>
/// <typeparam name="T">Graph node type.</typeparam>
/// <param name="origin">Node to start path finding from.</param>
/// <param name="target">The goal node to reach.</param>
/// <param name="adjFunc">Function returning the neighbouring connections for a node.</param>
/// <param name="heuristicFunc">Function returning the estimated cost of travelling between two nodes.</param>
/// <returns>A sequence of nodes representing a path if one is found, otherwise an empty array.</returns>
public static bool AStar<T>( T origin, T target, List<T> destPath,
Func<T, IEnumerable<AStarEdge<T>>> adjFunc, Func<T, T, float> heuristicFunc )
where T : IEquatable<T>
{
return AStarWrapper<T>.AStar( origin, target, destPath, adjFunc, heuristicFunc );
}
}
Game
game
using Sandbox;
using System.Threading.Tasks;
public class CardAnt : Card
{
public override bool IsAlive => true;
public override bool ShouldHandleEvent( EventType eventType )
{
return eventType == EventType.TurnStart && Manager.Instance.GetNumNearbyEmptyGridPositions( GridPos, adjacentOnly: false ) > 0;
}
public override async Task HandleEventAsync( EventType eventType )
{
var emptyGridPos = Manager.Instance.GetRandomNearbyGridPos( GridPos, empty: true, adjacentOnly: false );
await Task.DelayRealtime( 200 );
Manager.Instance.PlayCardSfx( "card_move", this, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );
await Task.DelayRealtime( 100 );
Manager.Instance.RemoveCardGridPos( this );
await Manager.Instance.SetCardGridPos( this, emptyGridPos );
await Task.DelayRealtime( 300 );
await Manager.Instance.EventHappened( EventType.AfterCardsMoved );
}
}
Debug: View Raw JSON Response
{
"TotalCount": 212,
"Files": [
{
"Ident": "facepunch.memory",
"Path": "FloaterLock.cs",
"FileName": "FloaterLock.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Drawing;\r\n\r\npublic class FloaterLock : Component\r\n{\r\n\tpublic int NumTurns { get; set; }\r\n\r\n\tprivate TimeSince _timeSinceSpawn;\r\n\r\n\tpublic float Lifetime { get; set; }\r\n\tpublic bool ShowLocked { get; set ; }\r\n\r\n\tprivate float _startScale;\r\n\tprivate float _endScale;\r\n\tprivate Vector2 _velocity;\r\n\tprivate float _deceleration;\r\n\r\n\tpublic float Scale { get; set; }\r\n\tpublic float Opacity { get; set; }\r\n\r\n\tpublic void Init( int numTurns )\r\n\t{\r\n\t\tNumTurns = numTurns;\r\n\r\n\t\tLifetime = 1.25f;\r\n\t\t_velocity = new Vector2( 0f, 12f );\r\n\t\t_deceleration = 4f;\r\n\t\tScale = _startScale = 1f;\r\n\t\t_endScale = 1f;\r\n\t}\r\n\r\n\tprotected override void OnStart()\r\n\t{\r\n\t\tbase.OnStart();\r\n\r\n\t\t_timeSinceSpawn = 0f;\r\n\r\n\t\tManager.Instance.PlaySfx( \"lock_start\", new Vector3( WorldPosition.x, WorldPosition.y, Manager.Instance.Camera.WorldPosition.z - 100f ), volume: 0.9f, pitch: Game.Random.Float( 1.05f, 1.13f ) );\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tOpacity = Utils.Map( _timeSinceSpawn, 0f, 0.3f, 0f, 1f, EasingType.QuadOut ) * Utils.Map( _timeSinceSpawn, 0f, Lifetime - 0.1f, 1f, 0.1f, EasingType.ExpoIn ) * Utils.Map( _timeSinceSpawn, Lifetime - 0.3f, Lifetime - 0.05f, 1f, 0f, EasingType.Linear );\r\n\t\tScale = Utils.Map( _timeSinceSpawn, 0f, Lifetime, _startScale, _endScale, EasingType.SineOut );\r\n\r\n\t\tWorldPosition += new Vector3( _velocity.x, _velocity.y, 0f ) * Time.Delta;\r\n\t\t_velocity *= (1f - _deceleration * Time.Delta);\r\n\r\n\t\tif( !ShowLocked && _timeSinceSpawn > 0.5f )\r\n\t\t{\r\n\t\t\tShowLocked = true;\r\n\t\t\t_velocity = new Vector2( 0f, -20f );\r\n\t\t\t_deceleration = 7f;\r\n\r\n\t\t\tManager.Instance.PlaySfx( \"lock\", new Vector3( WorldPosition.x, WorldPosition.y, Manager.Instance.Camera.WorldPosition.z - 100f ), volume: 2f, pitch: Game.Random.Float( 0.97f, 1.03f ) );\r\n\t\t}\r\n\r\n\t\tif ( _timeSinceSpawn > Lifetime )\r\n\t\t{\r\n\t\t\tManager.Instance.NumFloaters--;\r\n\t\t\tGameObject.Destroy();\r\n\t\t}\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/Card.cs",
"FileName": "Card.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Microsoft.VisualBasic;\r\nusing Sandbox;\r\nusing Sandbox.UI;\r\nusing Sandbox.ui;\r\nusing System.Runtime;\r\nusing System.Threading.Tasks;\r\n\r\npublic enum CardType { None, Apple, Bomb, Rocket, Telephone, Trumpet, Pawn, Balloon, Spider, Umbrella, UmbrellaClosed, Juggler, Coin, Vampire, Maracas, Microwave, Raccoon, Rock, Bear, Candle, \r\n\tCrystalBall, Snake, Rose, RoseWilted, Bell, Ant, Twins, Compass, Antenna, Wizard, AncientScroll, JumpingSpider, Bento, Ninja, Flashlight, Bodybuilder, Helicopter, FlyingMoney,\r\n\tSyringe, Cellphone, Crab, Magnet, Stethoscope, UFO, Teacher, Tractor, FortuneCookie, Dolphin, Detective, Genie, Potion, Mirror, FaxMachine, Dice, Coffee, Tree, Chipmunk,\r\n\tDancer, Wine, King, Police, Ogre, Clown, MoneyBag, Bank, Steak, MagicWand, Carrot, Caterpillar, Butterfly, Tornado, Map, Cockroach, Broccoli, Donut, Cheese, CheeseMoldy, GuideDog, Taco, Burrito,\r\n\tSkunk, CarePackage, Cash, BirthdayCake, Gem, Pickaxe, Mountain, DiamondRing, Rabbit, RedEnvelope,\r\n}\r\n\r\n// StockMarket, StockMarketDown, Key, AlarmClock, ATM\r\n\r\npublic class Card : Component, IEventHandler\r\n{\r\n\tpublic GameObject Model { get; set; }\r\n\tpublic ModelRenderer ModelRenderer { get; set; }\r\n\tpublic GameObject IconObj { get; set; }\r\n\tpublic GameObject IconBackObj { get; set; }\r\n\tpublic bool IsFlagShown { get; set; }\r\n\r\n\tpublic float CardIconScale { get; set; } = 1f;\r\n\r\n\tpublic bool IsHovered { get; set; }\r\n\tpublic bool IsRevealed { get; set; }\r\n\tpublic bool IsSpawning { get; set; }\r\n\r\n\tpublic int NumTimesRevealed { get; set; }\r\n\tpublic int NumTimesChosen { get; set; }\r\n\r\n\tpublic CardType CardType { get; private set; }\r\n\tpublic CardType OriginalCardType { get; private set; }\r\n\r\n\tpublic virtual bool IsFoodOrBeverage => false;\r\n\tpublic virtual bool IsAlive => false;\r\n\tpublic virtual bool CantBeMoved => false;\r\n\r\n\tpublic IntVector2 GridPos { get; set; }\r\n\r\n\tpublic bool IsShaking { get; private set; }\r\n\tprivate TimeSince _timeSinceShakeStart; // todo: replace with timer? this can become negative somehow\r\n\tprivate float _shakeTime;\r\n\tprivate EasingType _shakeEasingType;\r\n\tpublic Vector2 ShakeOffset { get; set; }\r\n\tprivate float _shakeStrength;\r\n\r\n\tpublic bool IsMovementControlled { get; set; }\r\n\tprivate Vector3 _moveStartPos;\r\n\tprivate Vector3 _moveTargetPos;\r\n\tprivate float _moveTime;\r\n\tprivate TimeSince _timeSinceMoveStart;\r\n\tprivate EasingType _moveEasingType;\r\n\tprivate bool _moveRemoveControlAfter;\r\n\r\n\tpublic int HP { get; set; }\r\n\r\n\tpublic bool IsLocked { get; set; }\r\n\tpublic int LockTurnsRemaining { get; set; }\r\n\tpublic bool WasJustLocked { get; set; }\r\n\r\n\tpublic int CardTypeID { get; set; }\r\n\r\n\tpublic float IconOpacity { get; set; }\r\n\tpublic bool IsExploding;\r\n\tprivate TimeSince _timeSinceStartExploding;\r\n\tprivate float _explodeTime;\r\n\tprivate EasingType _explodeEasingType;\r\n\tprivate Vector3 _explodeStartPos;\r\n\tprivate EasingType _explodeShakeEasingType;\r\n\r\n\tpublic bool IsScaling;\r\n\tprivate TimeSince _timeSinceScale;\r\n\tprivate float _scaleTime;\r\n\tprivate float _scaleAmount;\r\n\tprivate EasingType _scaleEasingType;\r\n\r\n\tpublic bool AreRevealMarksShown { get; set; }\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t}\r\n\r\n\tpublic virtual void Init(CardType cardType)\r\n\t{\r\n\t\tCardType = OriginalCardType = cardType;\r\n\r\n\t\tModel = GameObject.Children.Find( x => x.Name == \"model\" );\r\n\t\tModelRenderer = Model.Components.Get<ModelRenderer>();\r\n\r\n\t\tIconOpacity = 1f;\r\n\r\n\t\tIconObj = GameObject.Children.Find( x => x.Name == \"icon\" );\r\n\t\tvar cardIcon = IconObj.Components.Get<CardIcon>( includeDisabled: true );\r\n\t\tcardIcon.Card = this;\r\n\r\n\t\tIconBackObj = GameObject.Children.Find( x => x.Name == \"icon_back\" );\r\n\t\tvar cardIconBack = IconBackObj.Components.Get<CardIconBack>( includeDisabled: true );\r\n\t\tcardIconBack.Card = this;\r\n\r\n\t\tSetMaterial( cardType );\r\n\t}\r\n\r\n\tpublic void SetMaterial(CardType cardType)\r\n\t{\r\n\t\tvar matFilename = GetMaterialFilename( cardType );\r\n\t\tif ( !string.IsNullOrEmpty( matFilename ) )\r\n\t\t\tModelRenderer.MaterialOverride = Material.Load( matFilename );\r\n\t}\r\n\r\n\tpublic void SetCardType(CardType newType)\r\n\t{\r\n\t\tCardType = newType;\r\n\t\tSetMaterial( newType );\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\t//if ( Input.Down( \"Duck\" ) )\r\n\t\t//{\r\n\t\t//\tvar emoji = Card.GetIconEmoji( CardType );\r\n\t\t//\tif ( string.IsNullOrEmpty( emoji ) )\r\n\t\t//\t{\r\n\t\t//\t\tGizmo.Draw.Color = Color.Black.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( $\"{CardType}\", new global::Transform( WorldPosition + new Vector3( -0.5f, -0.5f, -1f ) ), size: 24f );\r\n\r\n\t\t//\t\tGizmo.Draw.Color = Color.White.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( $\"{CardType}\", new global::Transform( WorldPosition ), size: 24f );\r\n\t\t//\t}\r\n\t\t//\telse\r\n\t\t//\t{\r\n\t\t//\t\tGizmo.Draw.Color = Color.White.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( emoji, new global::Transform( WorldPosition ), size: 60f );\r\n\t\t//\t}\r\n\r\n\t\t//\tif ( IsMovementControlled )\r\n\t\t//\t{\r\n\t\t//\t\tGizmo.Draw.Color = Color.White.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( \"\u27a1\ufe0f\", new global::Transform( WorldPosition + new Vector3( -15.5f, -19f, -1f ) ), size: 30f );\r\n\t\t//\t}\r\n\r\n\t\t//\tif ( IsLocked )\r\n\t\t//\t{\r\n\t\t//\t\tGizmo.Draw.Color = Color.White.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( \"\ud83d\udd12\", new global::Transform( WorldPosition + new Vector3( 15.5f, -19f, -1f ) ), size: 30f );\r\n\r\n\t\t//\t\tGizmo.Draw.Color = Color.Red.WithAlpha( 1f );\r\n\t\t//\t\tGizmo.Draw.Text( $\"{LockTurnsRemaining}\", new global::Transform( WorldPosition + new Vector3( 15.5f, -21f, 1f ) ), size: 20f );\r\n\t\t//\t}\r\n\r\n\t\t//\tGizmo.Draw.Color = Color.Black.WithAlpha( 1f );\r\n\t\t//\tGizmo.Draw.Text( $\"ID: {CardTypeID}\", new global::Transform( WorldPosition + new Vector3( -13.5f, 19f, -1f ) + new Vector3( -0.5f, -0.5f, -1f ) ), size: 16 );\r\n\r\n\t\t//\tGizmo.Draw.Color = Color.White.WithAlpha( 1f );\r\n\t\t//\tGizmo.Draw.Text( $\"ID: {CardTypeID}\", new global::Transform( WorldPosition + new Vector3( -13.5f, 19f, -1f ) ), size: 16 );\r\n\t\t//}\r\n\r\n\t\tHandleMoving();\r\n\t\tHandleShaking();\r\n\r\n\t\tif(IsExploding)\r\n\t\t{\r\n\t\t\tHandleExploding();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif ( IsScaling )\r\n\t\t{\r\n\t\t\tHandleScaling();\r\n\t\t}\r\n\t\t\r\n\t\t//if(!IsScaling && !IsExploding)\r\n\t\t//{\r\n\t\t//\tTransform.LocalScale = new Vector3( Utils.DynamicEaseTo( Transform.LocalScale.x, IsHovered ? 1.05f : 1f, 0.3f, Time.Delta ) );\r\n\t\t//}\r\n\r\n\t\tif( IsSpawning )\r\n\t\t{\r\n\t\t\t// do nothing\r\n\t\t}\r\n\t\telse if( IsMovementControlled )\r\n\t\t{\r\n\t\t\tLocalPosition += new Vector3( ShakeOffset.x, ShakeOffset.y, 0f ) * Time.Delta * 10f;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tvar targetPos = Manager.GetCardPos( GridPos );\r\n\r\n\t\t\tif ( IsShaking )\r\n\t\t\t\ttargetPos += new Vector3( ShakeOffset.x, ShakeOffset.y, 0f );\r\n\r\n\t\t\tvar height = 10f + ((IsRevealed || IsHovered) ? Globals.CARD_ADD_HEIGHT_REVEALED_OR_HOVERED : 0f) + ((IsRevealed && IsHovered) ? Globals.CARD_ADD_HEIGHT_REVEALED_AND_HOVERED : 0f);\r\n\t\t\tvar zPos = MathX.Lerp( LocalPosition.z, height, Time.Delta * 20f );\r\n\r\n\t\t\tLocalPosition = Vector3.Lerp( LocalPosition, targetPos, Time.Delta * 10f ).WithZ( zPos );\r\n\t\t}\r\n\r\n\t\tvar targetRot = Rotation.FromPitch( IsRevealed ? 0f : 180f );\r\n\t\tWorldRotation = Rotation.Lerp( WorldRotation, targetRot, Time.Delta * 15f );\r\n\t}\r\n\r\n\tpublic void MoveToPos( Vector3 pos, float time, EasingType easingType = EasingType.Linear, bool removeControlAfter = false)\r\n\t{\r\n\t\t//Log.Info( $\"Card - MoveToPos: {pos}\" );\r\n\r\n\t\tIsMovementControlled = true;\r\n\t\t_moveStartPos = LocalPosition;\r\n\t\t_moveTargetPos = pos;\r\n\t\t_moveTime = time;\r\n\t\t_timeSinceMoveStart = 0f;\r\n\t\t_moveEasingType = easingType;\r\n\t\t_moveRemoveControlAfter = removeControlAfter;\r\n\t}\r\n\r\n\tvoid HandleMoving()\r\n\t{\r\n\t\tif ( !IsMovementControlled )\r\n\t\t\treturn;\r\n\r\n\t\tif(_timeSinceMoveStart > _moveTime)\r\n\t\t{\r\n\t\t\tLocalPosition = _moveTargetPos;\r\n\r\n\t\t\tif( _moveRemoveControlAfter )\r\n\t\t\t\tIsMovementControlled = false;\r\n\t\t}\r\n\t\telse \r\n\t\t{\r\n\t\t\tLocalPosition = Vector3.Lerp( _moveStartPos, _moveTargetPos, Utils.Map( _timeSinceMoveStart, 0f, _moveTime, 0f, 1f, _moveEasingType ) );\r\n\t\t}\r\n\t}\r\n\r\n\tprotected void HandleShaking()\r\n\t{\r\n\t\tif ( IsShaking )\r\n\t\t{\r\n\t\t\tif ( _timeSinceShakeStart > _shakeTime )\r\n\t\t\t\tIsShaking = false;\r\n\t\t\telse\r\n\t\t\t\tShakeOffset = Utils.GetRandomVector() * _shakeStrength * Utils.Map( _timeSinceShakeStart, 0f, _shakeTime, 1f, 0f, _shakeEasingType );\r\n\t\t}\r\n\t}\r\n\r\n\tvoid HandleExploding()\r\n\t{\r\n\t\tLocalScale = new Vector3( Utils.Map(_timeSinceStartExploding, 0f, _explodeTime, 1f, Globals.CARD_EXPLODE_SCALE, _explodeEasingType) );\r\n\t\tIconOpacity = Utils.Map( _timeSinceStartExploding, 0f, _explodeTime, 1f, 0f, EasingType.SineIn );\r\n\r\n\t\tLocalPosition = _explodeStartPos + Vector3.Random * Utils.Map( _timeSinceStartExploding, 0f, _explodeTime, 0f, 2f, _explodeShakeEasingType) * Utils.Map( _timeSinceStartExploding, _explodeTime * 0.9f, _explodeTime, 1f, 0f );\r\n\t}\r\n\r\n\tvoid HandleScaling()\r\n\t{\r\n\t\tif(_timeSinceScale > 0.25f)\r\n\t\t{\r\n\t\t\tIsScaling = false;\r\n\t\t\tLocalScale = new Vector3( 1f );\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tLocalScale = Utils.MapReturn( _timeSinceScale, 0f, _scaleTime, 1f, _scaleAmount, _scaleEasingType);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static string GetName( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.CrystalBall: return \"Crystal Ball\";\r\n\t\t\tcase CardType.AncientScroll: return \"Ancient Scroll\";\r\n\t\t\tcase CardType.JumpingSpider: return \"Jumping Spider\";\r\n\t\t\tcase CardType.Rock: return \"Boulder\";\r\n\t\t\tcase CardType.Syringe: return \"Morphine\";\r\n\t\t\tcase CardType.FlyingMoney: return \"Flying Money\";\r\n\t\t\tcase CardType.FortuneCookie: return \"Fortune Cookie\";\r\n\t\t\t//case CardType.AlarmClock: return \"Alarm Clock\";\r\n\t\t\tcase CardType.FaxMachine: return \"Fax Machine\";\r\n\t\t\tcase CardType.MoneyBag: return \"Money Bag\";\r\n\t\t\tcase CardType.MagicWand: return \"Magic Wand\";\r\n\t\t\t//case CardType.StockMarket: return \"Stock Market\";\r\n\t\t\tcase CardType.GuideDog: return \"Guide Dog\";\r\n\t\t\tcase CardType.CarePackage: return \"Care Package\";\r\n\t\t\tcase CardType.BirthdayCake: return \"Birthday Cake\";\r\n\t\t\tcase CardType.DiamondRing: return \"Diamond Ring\";\r\n\t\t\tcase CardType.RedEnvelope: return \"Red Envelope\";\r\n\t\t}\r\n\r\n\t\treturn cardType.ToString();\r\n\t}\r\n\r\n\tpublic static string GetFilename( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Apple: return \"apple\";\r\n\t\t\tcase CardType.Bomb: return \"bomb\";\r\n\t\t\tcase CardType.Rocket: return \"rocket\";\r\n\t\t\tcase CardType.Telephone: return \"telephone\";\r\n\t\t\tcase CardType.Trumpet: return \"trumpet\";\r\n\t\t\tcase CardType.Pawn: return \"pawn\";\r\n\t\t\tcase CardType.Balloon: return \"balloon\";\r\n\t\t\tcase CardType.Spider: return \"spider\";\r\n\t\t\tcase CardType.Umbrella: return \"umbrella\";\r\n\t\t\tcase CardType.UmbrellaClosed: return \"umbrella_closed\";\r\n\t\t\tcase CardType.Juggler: return \"juggler\";\r\n\t\t\tcase CardType.Coin: return \"coin\";\r\n\t\t\tcase CardType.Vampire: return \"vampire\";\r\n\t\t\tcase CardType.Maracas: return \"maracas\";\r\n\t\t\tcase CardType.Microwave: return \"microwave\";\r\n\t\t\tcase CardType.Raccoon: return \"raccoon\";\r\n\t\t\tcase CardType.Rock: return \"rock\";\r\n\t\t\tcase CardType.Bear: return \"bear\";\r\n\t\t\tcase CardType.Candle: return \"candle\";\r\n\t\t\tcase CardType.CrystalBall: return \"crystal_ball\";\r\n\t\t\tcase CardType.Snake: return \"snake\";\r\n\t\t\tcase CardType.Rose: return \"rose\";\r\n\t\t\tcase CardType.RoseWilted: return \"rose_wilted\";\r\n\t\t\tcase CardType.Bell: return \"bell\";\r\n\t\t\tcase CardType.Ant: return \"ant\";\r\n\t\t\tcase CardType.Twins: return \"twins\";\r\n\t\t\tcase CardType.Compass: return \"compass\";\r\n\t\t\tcase CardType.Antenna: return \"antenna\";\r\n\t\t\tcase CardType.Wizard: return \"wizard\";\r\n\t\t\tcase CardType.AncientScroll: return \"scroll\";\r\n\t\t\tcase CardType.JumpingSpider: return \"spider_jumping\";\r\n\t\t\tcase CardType.Bento: return \"bento\";\r\n\t\t\t//case CardType.StockMarket: return \"investment\";\r\n\t\t\t//case CardType.StockMarketDown: return \"investment_down\";\r\n\t\t\tcase CardType.Ninja: return \"ninja\";\r\n\t\t\tcase CardType.Flashlight: return \"flashlight\";\r\n\t\t\tcase CardType.Bodybuilder: return \"bodybuilder\";\r\n\t\t\tcase CardType.Helicopter: return \"helicopter\";\r\n\t\t\tcase CardType.FlyingMoney: return \"flying_money\";\r\n\t\t\tcase CardType.Syringe: return \"syringe\";\r\n\t\t\tcase CardType.Cellphone: return \"cellphone\";\r\n\t\t\tcase CardType.Crab: return \"crab\";\r\n\t\t\tcase CardType.Magnet: return \"magnet\";\r\n\t\t\tcase CardType.Stethoscope: return \"stethoscope\";\r\n\t\t\tcase CardType.UFO: return \"ufo\";\r\n\t\t\tcase CardType.Teacher: return \"teacher\";\r\n\t\t\tcase CardType.Tractor: return \"tractor\";\r\n\t\t\tcase CardType.FortuneCookie: return \"fortune_cookie\";\r\n\t\t\tcase CardType.Dolphin: return \"dolphin\";\r\n\t\t\tcase CardType.Detective: return \"detective\";\r\n\t\t\tcase CardType.Genie: return \"genie\";\r\n\t\t\tcase CardType.Potion: return \"potion\";\r\n\t\t\tcase CardType.Mirror: return \"mirror\";\r\n\t\t\t//case CardType.AlarmClock: return \"alarm_clock\";\r\n\t\t\tcase CardType.FaxMachine: return \"fax_machine\";\r\n\t\t\tcase CardType.Dice: return \"dice\";\r\n\t\t\tcase CardType.Coffee: return \"coffee\";\r\n\t\t\tcase CardType.Tree: return \"tree\";\r\n\t\t\tcase CardType.Chipmunk: return \"chipmunk\";\r\n\t\t\tcase CardType.Dancer: return \"dancer\";\r\n\t\t\tcase CardType.Wine: return \"wine\";\r\n\t\t\tcase CardType.King: return \"king\";\r\n\t\t\tcase CardType.Police: return \"police\";\r\n\t\t\tcase CardType.Ogre: return \"ogre\";\r\n\t\t\tcase CardType.Clown: return \"clown\";\r\n\t\t\tcase CardType.MoneyBag: return \"money_bag\";\r\n\t\t\tcase CardType.Bank: return \"bank\";\r\n\t\t\tcase CardType.Steak: return \"steak\";\r\n\t\t\tcase CardType.MagicWand: return \"magic_wand\";\r\n\t\t\tcase CardType.Carrot: return \"carrot\";\r\n\t\t\tcase CardType.Caterpillar: return \"caterpillar\";\r\n\t\t\tcase CardType.Butterfly: return \"butterfly\";\r\n\t\t\tcase CardType.Tornado: return \"tornado\";\r\n\t\t\tcase CardType.Map: return \"map\";\r\n\t\t\tcase CardType.Cockroach: return \"cockroach\";\r\n\t\t\t//case CardType.Key: return \"key\";\r\n\t\t\tcase CardType.Broccoli: return \"broccoli\";\r\n\t\t\t//case CardType.ATM: return \"atm\";\r\n\t\t\tcase CardType.Donut: return \"donut\";\r\n\t\t\tcase CardType.Cheese: return \"cheese\";\r\n\t\t\tcase CardType.CheeseMoldy: return \"cheese_moldy\";\r\n\t\t\tcase CardType.GuideDog: return \"guide_dog\";\r\n\t\t\tcase CardType.Taco: return \"taco\";\r\n\t\t\tcase CardType.Burrito: return \"burrito\";\r\n\t\t\tcase CardType.Skunk: return \"skunk\";\r\n\t\t\tcase CardType.CarePackage: return \"care_package\";\r\n\t\t\tcase CardType.Cash: return \"cash\";\r\n\t\t\tcase CardType.BirthdayCake: return \"birthday_cake\";\r\n\t\t\tcase CardType.Gem: return \"gem\";\r\n\t\t\tcase CardType.Pickaxe: return \"pickaxe\";\r\n\t\t\tcase CardType.Mountain: return \"mountain\";\r\n\t\t\tcase CardType.DiamondRing: return \"diamond_ring\";\r\n\t\t\tcase CardType.Rabbit: return \"rabbit\";\r\n\t\t\tcase CardType.RedEnvelope: return \"red_envelope\";\r\n\t\t}\r\n\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tpublic static string GetIconFilename( CardType cardType )\r\n\t{\r\n\t\treturn $\"textures/{GetFilename( cardType )}.png\";\r\n\t}\r\n\r\n\tpublic static string GetMaterialFilename( CardType cardType )\r\n\t{\r\n\t\treturn $\"materials/cards/{GetFilename( cardType )}.vmat\";\r\n\t}\r\n\r\n\tpublic static string GetIconEmoji( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Apple: return \"\ud83c\udf4e\";\r\n\t\t\tcase CardType.Bomb: return \"\ud83d\udca3\";\r\n\t\t\tcase CardType.Rocket: return \"\ud83d\ude80\";\r\n\t\t\tcase CardType.Telephone: return \"\u260e\ufe0f\";\r\n\t\t\tcase CardType.Trumpet: return \"\ud83c\udfba\";\r\n\t\t\tcase CardType.Pawn: return \"\u265f\ufe0f\";\r\n\t\t\tcase CardType.Balloon: return \"\ud83c\udf88\";\r\n\t\t\tcase CardType.Spider: return \"\ud83d\udd77\ufe0f\";\r\n\t\t\tcase CardType.Umbrella: return \"\u2602\ufe0f\";\r\n\t\t\tcase CardType.UmbrellaClosed: return \"\ud83c\udf02\";\r\n\t\t\tcase CardType.Juggler: return \"\ud83e\udd39\";\r\n\t\t\tcase CardType.Coin: return \"\ud83d\udfe1\";\r\n\t\t\tcase CardType.Vampire: return \"\ud83e\udddb\";\r\n\t\t\tcase CardType.Raccoon: return \"\ud83e\udd9d\";\r\n\t\t\tcase CardType.Rock: return \"\ud83d\uddff\";\r\n\t\t\tcase CardType.Bear: return \"\ud83d\udc3b\";\r\n\t\t\tcase CardType.Candle: return \"\ud83d\udd6f\ufe0f\";\r\n\t\t\tcase CardType.CrystalBall: return \"\ud83d\udd2e\";\r\n\t\t\tcase CardType.Snake: return \"\ud83d\udc0d\";\r\n\t\t\tcase CardType.Rose: return \"\ud83c\udf39\";\r\n\t\t\tcase CardType.RoseWilted: return \"\ud83e\udd40\";\r\n\t\t\tcase CardType.Bell: return \"\ud83d\udd14\";\r\n\t\t\tcase CardType.Ant: return \"\ud83d\udc1c\";\r\n\t\t\tcase CardType.Twins: return \"\ud83d\udc6f\";\r\n\t\t\tcase CardType.Compass: return \"\ud83e\udded\";\r\n\t\t\tcase CardType.Antenna: return \"\ud83d\udce1\";\r\n\t\t\tcase CardType.Wizard: return \"\ud83e\uddd9\";\r\n\t\t\tcase CardType.AncientScroll: return \"\ud83d\udcdc\";\r\n\t\t\tcase CardType.JumpingSpider: return \"\ud83d\udd77\ufe0f\";\r\n\t\t\tcase CardType.Bento: return \"\ud83c\udf71\";\r\n\t\t\t//case CardType.StockMarket: return \"\ud83d\udcc8\";\r\n\t\t\t//case CardType.StockMarketDown: return \"\ud83d\udcc9\";\r\n\t\t\tcase CardType.Ninja: return \"\ud83d\udc31\u200d\ud83d\udc64\";\r\n\t\t\tcase CardType.Flashlight: return \"\ud83d\udd26\";\r\n\t\t\tcase CardType.Bodybuilder: return \"\ud83c\udfcb\ufe0f\";\r\n\t\t\tcase CardType.Helicopter: return \"\ud83d\ude81\";\r\n\t\t\tcase CardType.FlyingMoney: return \"\ud83d\udcb8\";\r\n\t\t\tcase CardType.Syringe: return \"\ud83d\udc89\";\r\n\t\t\tcase CardType.Cellphone: return \"\ud83d\udcf1\";\r\n\t\t\tcase CardType.Crab: return \"\ud83e\udd80\";\r\n\t\t\tcase CardType.Magnet: return \"\ud83e\uddf2\";\r\n\t\t\tcase CardType.Stethoscope: return \"\ud83e\ude7a\";\r\n\t\t\tcase CardType.UFO: return \"\ud83d\udef8\";\r\n\t\t\tcase CardType.Teacher: return \"\ud83d\udc69\u200d\ud83c\udfeb\";\r\n\t\t\tcase CardType.Tractor: return \"\ud83d\ude9c\";\r\n\t\t\tcase CardType.FortuneCookie: return \"\ud83e\udd60\";\r\n\t\t\tcase CardType.Dolphin: return \"\ud83d\udc2c\";\r\n\t\t\tcase CardType.Detective: return \"\ud83d\udd75\ufe0f\";\r\n\t\t\tcase CardType.Genie: return \"\ud83e\uddde\";\r\n\t\t\tcase CardType.Potion: return \"\ud83e\uddea\";\r\n\t\t\tcase CardType.Mirror: return \"\ud83d\udd18\";\r\n\t\t\t//case CardType.AlarmClock: return \"\u23f0\";\r\n\t\t\tcase CardType.FaxMachine: return \"\ud83d\udce0\";\r\n\t\t\tcase CardType.Dice: return \"\ud83c\udfb2\";\r\n\t\t\tcase CardType.Coffee: return \"\u2615\";\r\n\t\t\tcase CardType.Tree: return \"\ud83c\udf33\";\r\n\t\t\tcase CardType.Chipmunk: return \"\ud83d\udc3f\ufe0f\";\r\n\t\t\tcase CardType.Dancer: return \"\ud83d\udc83\";\r\n\t\t\tcase CardType.Wine: return \"\ud83c\udf77\";\r\n\t\t\tcase CardType.King: return \"\ud83e\udd34\";\r\n\t\t\tcase CardType.Police: return \"\ud83d\udc6e\";\r\n\t\t\tcase CardType.Ogre: return \"\ud83d\udc79\";\r\n\t\t\tcase CardType.Clown: return \"\ud83e\udd21\";\r\n\t\t\tcase CardType.MoneyBag: return \"\ud83d\udcb0\";\r\n\t\t\tcase CardType.Bank: return \"\ud83c\udfe6\";\r\n\t\t\tcase CardType.Steak: return \"\ud83e\udd69\";\r\n\t\t\tcase CardType.MagicWand: return \"\u2728\";\r\n\t\t\tcase CardType.Carrot: return \"\ud83e\udd55\";\r\n\t\t\tcase CardType.Caterpillar: return \"\ud83d\udc1b\";\r\n\t\t\tcase CardType.Butterfly: return \"\ud83e\udd8b\";\r\n\t\t\tcase CardType.Tornado: return \"\ud83c\udf2a\ufe0f\";\r\n\t\t\tcase CardType.Map: return \"\ud83d\uddfa\ufe0f\";\r\n\t\t\tcase CardType.Cockroach: return \"\ud80c\udda3\";\r\n\t\t\t//case CardType.Key: return \"\ud83d\udd11\";\r\n\t\t\tcase CardType.Broccoli: return \"\ud83e\udd66\";\r\n\t\t\t//case CardType.ATM: return \"\ud83c\udfe7\";\r\n\t\t\tcase CardType.Donut: return \"\ud83c\udf69\";\r\n\t\t\tcase CardType.Cheese: return \"\ud83e\uddc0\";\r\n\t\t\tcase CardType.CheeseMoldy: return \"\ud83e\udd2e\";\r\n\t\t\tcase CardType.GuideDog: return \"\ud83e\uddae\";\r\n\t\t\tcase CardType.Taco: return \"\ud83c\udf2e\";\r\n\t\t\tcase CardType.Burrito: return \"\ud83c\udf2f\";\r\n\t\t\tcase CardType.Skunk: return \"\ud83e\udda8\";\r\n\t\t\tcase CardType.CarePackage: return \"\ud83d\udce6\";\r\n\t\t\tcase CardType.Cash: return \"\ud83d\udcb5\";\r\n\t\t\tcase CardType.BirthdayCake: return \"\ud83c\udf82\";\r\n\t\t\tcase CardType.Gem: return \"\ud83d\udc8e\";\r\n\t\t\tcase CardType.Pickaxe: return \"\u26cf\ufe0f\";\r\n\t\t\tcase CardType.Mountain: return \"\u26f0\ufe0f\";\r\n\t\t\tcase CardType.DiamondRing: return \"\ud83d\udc8d\";\r\n\t\t\tcase CardType.Rabbit: return \"\ud83d\udc07\";\r\n\t\t\tcase CardType.RedEnvelope: return \"\ud83e\udde7\";\r\n\t\t}\r\n\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tpublic static string GetCardDescription( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Apple: return \"\u2705Match: +1 HP\";\r\n\t\t\tcase CardType.Bomb: return \"\u2705Match: reveal nearby cards then shuffle them\";\r\n\t\t\tcase CardType.Rocket: return \"\u274cMismatch: swap position\";\r\n\t\t\tcase CardType.Telephone: return \"\u2705Match: shake nearby pairs\";\r\n\t\t\tcase CardType.Trumpet: return \"Match other cards: 30% chance to reveal\";\r\n\t\t\tcase CardType.Pawn: return \"\u27a1\ufe0fTurn start: 50% to try to move upward\";\r\n\t\t\tcase CardType.Balloon: return \"Floats upward\";\r\n\t\t\tcase CardType.Spider: return \"Starts in a corner\";\r\n\t\t\tcase CardType.Umbrella: return \"\ud83d\udc41\ufe0fRevealed: toggle open/closed\";\r\n\t\t\tcase CardType.Juggler: return \"\u274cMismatch: rearrange nearby cards\";\r\n\t\t\tcase CardType.Coin: return \"\u2705Match: +$2\";\r\n\t\t\tcase CardType.Vampire: return \"While hovered: shake if you lose HP\";\r\n\t\t\tcase CardType.Maracas: return \"Makes a distinctive sound when shook\";\r\n\t\t\tcase CardType.Microwave: return \"\u27a1\ufe0fTurn start: shake a nearby food/drink\";\r\n\t\t\tcase CardType.Raccoon: return \"\u27a1\ufe0fTurn start: shake an adjacent card\";\r\n\t\t\tcase CardType.Rock: return \"Falls downward, pushing other cards\";\r\n\t\t\tcase CardType.Bear: return \"Food/drink revealed: 20% chance to shake\";\r\n\t\t\tcase CardType.Candle: return \"\u2705Match: each reveal a nearby card\";\r\n\t\t\tcase CardType.CrystalBall: return \"\u274cMismatch: shake cards, including other card's match\";\r\n\t\t\tcase CardType.Snake: return \"Shake when an adjacent card is matched\";\r\n\t\t\tcase CardType.Rose: return \"When moved: shake and wilt\";\r\n\t\t\tcase CardType.Bell: return \"Rings when moved or shook\";\r\n\t\t\tcase CardType.Ant: return \"\u27a1\ufe0fTurn start: move to nearby empty space\";\r\n\t\t\tcase CardType.Twins: return \"\ud83d\udc41\ufe0fRevealed: nudge toward match\";\r\n\t\t\tcase CardType.Compass: return \"\u274cMismatch: nudge toward other card's match\";\r\n\t\t\tcase CardType.Antenna: return \"\ud83d\udc41\ufe0fRevealed: sound indicates distance to match\";\r\n\t\t\tcase CardType.Wizard: return \"\u23e9Every 3 turns: shuffle some cards\\n\ud83d\udc94Damage Wizard: respawn some cards and shuffle them\";\r\n\t\t\tcase CardType.AncientScroll: return \"\u2705Match: reveal all cards (after next turn, shuffle all cards)\";\r\n\t\t\tcase CardType.JumpingSpider: return \"Starts in a corner\\n\u274cMismatch: swaps with an unknown card\";\r\n\t\t\tcase CardType.Bento: return \"\u2705Match: +1 HP for each consecutive match\";\r\n\t\t\t//case CardType.StockMarket: return \"\u2705Match: gain half your money if the market is up, lose half if the market is down\";\r\n\t\t\tcase CardType.Ninja: return \"\u27a1\ufe0fTurn start: 25% chance to swap position\";\r\n\t\t\tcase CardType.Flashlight: return \"\ud83d\udc46Chosen: reveal a nearby card\";\r\n\t\t\tcase CardType.Bodybuilder: return \"\u27a1\ufe0fTurn start: move adjacent card upwards, pushing other cards\";\r\n\t\t\tcase CardType.Helicopter: return \"\u274cMismatch: relocate along with an adjacent card\";\r\n\t\t\tcase CardType.FlyingMoney: return \"\u2705Match: +$3\\n\u274cMismatch: shuffle with some nearby cards\";\r\n\t\t\tcase CardType.Syringe: return \"\u2705Match: heal all HP, but time is halved until end of level\";\r\n\t\t\tcase CardType.Cellphone: return \"\u274cMismatch: vibrate nearest cellphone\";\r\n\t\t\tcase CardType.Crab: return \"Moves sideways to empty spaces\";\r\n\t\t\tcase CardType.Magnet: return \"\u27a1\ufe0fTurn start: pull card toward it\";\r\n\t\t\tcase CardType.Stethoscope: return \"\u2705Match/\u274cMismatch: shake nearby cards with a heartbeat\";\r\n\t\t\tcase CardType.UFO: return \"\u2705Match: abduct and shuffle nearby cards\";\r\n\t\t\tcase CardType.Teacher: return \"\u2705Match: arrange row alphabetically\";\r\n\t\t\tcase CardType.Tractor: return \"\u2705Match/\u274cMismatch: shift row one space\";\r\n\t\t\tcase CardType.FortuneCookie: return \"\u2705Match: +1 HP, and reveal 5 cards that you haven't seen before\";\r\n\t\t\tcase CardType.Dolphin: return \"Revealed on 4 consecutive mismatches\";\r\n\t\t\tcase CardType.Detective: return \"\u27a1\ufe0fTurn start: 50% chance to reveal a nearby card\";\r\n\t\t\tcase CardType.Genie: return \"\u2705Match: next card chosen shakes its match\";\r\n\t\t\tcase CardType.Potion: return \"\u2705Match: your HP is set to half\";\r\n\t\t\tcase CardType.Mirror: return \"\u2705Match: flip the level horizontally\";\r\n\t\t\t//case CardType.AlarmClock: return \"70% chance to shake when timer goes below 1s\";\r\n\t\t\tcase CardType.FaxMachine: return \"\ud83d\udc46Chosen: shake 3 cards, including another fax machine\";\r\n\t\t\tcase CardType.Dice: return \"\u274cMismatch: roll a 6 to get +$2 (rolling 1 loses $1)\\n\u2705Match: Roll a 12 to get +$5 (rolling 2 loses $2)\";\r\n\t\t\tcase CardType.Coffee: return \"\u2705Match: +2 HP, and your next turn lasts 3 seconds\";\r\n\t\t\tcase CardType.Tree: return \"\u2705Match: reveal an apple\";\r\n\t\t\tcase CardType.Chipmunk: return \"\u27a1\ufe0fTurn start: move toward a tree\";\r\n\t\t\tcase CardType.Dancer: return \"\u274cMismatch: dance with multiple partners\";\r\n\t\t\tcase CardType.Wine: return \"\u2705Match: +2 HP\\nShake if an adjacent card shakes\";\r\n\t\t\tcase CardType.King: return \"\ud83d\udc94Damage King: he decides your next choice\";\r\n\t\t\tcase CardType.Police: return \"\u274cMismatch: Reveal and lock a nearby card for 2 turns\\n\ud83d\udc94Damage Police: Lock some nearby cards for 1 turn, then shuffle\";\r\n\t\t\tcase CardType.Ogre: return \"\ud83d\udc94Damage Ogre: shuffle with nearby cards\";\r\n\t\t\tcase CardType.Clown: return \"\ud83d\udc94Damage Clown: swap multiple times\";\r\n\t\t\tcase CardType.MoneyBag: return \"\u2705Match: +$5\";\r\n\t\t\tcase CardType.Bank: return \"\u2705Match: transform all coins into money bags\";\r\n\t\t\tcase CardType.Steak: return \"\u2705Match: -$1 and +4 HP\";\r\n\t\t\tcase CardType.MagicWand: return \"\u274cMismatch: send other card adjacent to its match\";\r\n\t\t\tcase CardType.Carrot: return \"\u2705Match: +3 HP, and timer is doubled next turn\";\r\n\t\t\tcase CardType.Caterpillar: return \"\u27a1\ufe0fTurn start: 20% chance to shake and transform into a butterfly\";\r\n\t\t\tcase CardType.Tornado: return \"\u27a1\ufe0fTurn start: swap 2 adjacent cards\";\r\n\t\t\tcase CardType.Map: return \"\u2705Match: reveal all cards between\";\r\n\t\t\tcase CardType.Cockroach: return \"Can't be matched until no other cards remain\";\r\n\t\t\t//case CardType.Key: return \"\u274cMismatch: unlock other card\\n\u2705Match: unlock all cards\";\r\n\t\t\tcase CardType.Broccoli: return \"\u2705Match: +3 HP\";\r\n\t\t\t//case CardType.ATM: return \"\u2705Match: +$1 for every 2 matches you've made this level (max: $7)\";\r\n\t\t\tcase CardType.Donut: return \"\u2705Match: +1 HP for each adjacent empty space\";\r\n\t\t\tcase CardType.Cheese: return \"\u2705Match: +3 HP if not moldy\\nGoes moldy after 7 turns\";\r\n\t\t\tcase CardType.GuideDog: return \"When you mismatch other cards, 50% chance to point toward one of their matches\";\r\n\t\t\tcase CardType.Taco: return \"\u2705Match: +1 Max HP\";\r\n\t\t\tcase CardType.Burrito: return \"\u2705Match: +2 Max HP\";\r\n\t\t\tcase CardType.Skunk: return \"Can't be matched while adjacent to any non-skunks\";\r\n\t\t\tcase CardType.CarePackage: return \"\u2705Match: +$1 for every 2 HP missing\";\r\n\t\t\tcase CardType.Cash: return \"\u2705Match: +$3 if both cash are nearby eachother, otherwise +$1\";\r\n\t\t\tcase CardType.BirthdayCake: return \"\u2705Match: +1 HP and +$2\";\r\n\t\t\tcase CardType.Gem: return \"\u2705Match: +$4\";\r\n\t\t\tcase CardType.Pickaxe: return \"\u2705Match: transform all boulders into gems\";\r\n\t\t\tcase CardType.Mountain: return \"Can't be moved\";\r\n\t\t\tcase CardType.DiamondRing: return \"\u2705Match: +$3 if no other cards remain, otherwise +$1\";\r\n\t\t\tcase CardType.Rabbit: return \"\u27a1\ufe0fTurn start: 50% chance to move towards its match\";\r\n\t\t\tcase CardType.RedEnvelope: return \"\u2705Match: if you have less than $5, set your money to $5\";\r\n\t\t}\r\n\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tpublic static string GetCardExplanation( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Ant: return \"\\\"nearby\\\" means 1 space away\\n(including diagonal)\";\r\n\t\t\tcase CardType.Snake: return \"\\\"adjacent\\\" means 1 space away\\n(NOT including diagonal)\";\r\n\t\t}\r\n\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tpublic static bool HasHP( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Ogre: return true;\r\n\t\t\tcase CardType.Clown: return true;\r\n\t\t\tcase CardType.Police: return true;\r\n\t\t\tcase CardType.Wizard: return true;\r\n\t\t\tcase CardType.King: return true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic static int GetMaxHP( CardType cardType )\r\n\t{\r\n\t\tswitch ( cardType )\r\n\t\t{\r\n\t\t\tcase CardType.Ogre: return 2;\r\n\t\t\tcase CardType.Clown: return 2;\r\n\t\t\tcase CardType.Police: return 2;\r\n\t\t\tcase CardType.Wizard: return 3;\r\n\t\t\tcase CardType.King: return 3;\r\n\t\t}\r\n\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic void SetRevealedFromAsync(bool revealed)\r\n\t{\r\n\t\tIsRevealed = revealed;\r\n\r\n\t\tif( Card.HasHP(CardType) || IsLocked )\r\n\t\t\tIconObj.Enabled = revealed;\r\n\r\n\t\tif ( revealed )\r\n\t\t{\r\n\t\t\tNumTimesRevealed++;\r\n\r\n\t\t\tif(Manager.Instance.Stats[StatType.MaxCrayonMarks] > 0f && !AreRevealMarksShown)\r\n\t\t\t\tShowRevealMarks();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void SetRevealedInstant()\r\n\t{\r\n\t\tIsRevealed = true;\r\n\r\n\t\tif ( Card.HasHP( CardType ) || IsLocked )\r\n\t\t\tIconObj.Enabled = true;\r\n\r\n\t\tWorldRotation = Rotation.FromPitch( 0f );\r\n\r\n\t\tNumTimesRevealed++;\r\n\r\n\t\tif ( Manager.Instance.Stats[StatType.MaxCrayonMarks] > 0f && !AreRevealMarksShown )\r\n\t\t\tShowRevealMarks();\r\n\t}\r\n\r\n\tpublic void SetHiddenInstant()\r\n\t{\r\n\t\tIsRevealed = false;\r\n\r\n\t\tif ( Card.HasHP( CardType ) )\r\n\t\t\tIconObj.Enabled = false;\r\n\r\n\t\tWorldRotation = Rotation.FromPitch( 180f );\r\n\t}\r\n\r\n\tpublic void Shake( float strength, float time = 0.6f, EasingType easingType = EasingType.QuadOut, bool playSfx = true )\r\n\t{\r\n\t\tIsShaking = true;\r\n\t\t_timeSinceShakeStart = 0f;\r\n\t\t_shakeTime = time;\r\n\t\t_shakeEasingType = easingType;\r\n\t\t_shakeStrength = strength;\r\n\r\n\t\tif ( playSfx || ( OverrideShakeSfx && ( IsRevealed || !OnlyOverrideShakeSfxWhenRevealed ) ) )\r\n\t\t\tPlayShakeSfx();\r\n\t}\r\n\r\n\tpublic virtual void PlayShakeSfx()\r\n\t{\r\n\t\t//Manager.Instance.PlayCardSfx( \"shake_1\", this, volume: 1.1f, pitch: Game.Random.Float( 1.4f, 1.6f ) );\r\n\t\tManager.Instance.PlayCardSfx( \"shake_3\", this, volume: 1.35f, pitch: Game.Random.Float( 0.94f, 1.06f ) );\r\n\t}\r\n\r\n\tpublic virtual bool OverrideShakeSfx => false;\r\n\tpublic virtual bool OnlyOverrideShakeSfxWhenRevealed => false;\r\n\r\n\tpublic virtual void PlayHurtSfx(Card card0, Card card1)\r\n\t{\r\n\t\tManager.Instance.PlayCardSfxBetween( \"shake_1\", card0, card1, volume: 1.3f, pitch: Game.Random.Float( 1.4f, 1.6f ) );\r\n\t}\r\n\r\n\t// return false if needed to change start pos\r\n\tpublic virtual bool ValidateStartingGridPos()\r\n\t{\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic virtual bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic virtual async Task HandleEventAsync(EventType eventType)\r\n\t{\r\n\t\tawait Task.Frame();\r\n\t}\r\n\r\n\tpublic virtual string GetEventText( EventType eventType )\r\n\t{\r\n\t\treturn GetCardDescription( CardType );\r\n\t}\r\n\r\n\tpublic async Task Hurt()\r\n\t{\r\n\t\tif(!Card.HasHP(CardType))\r\n\t\t{\r\n\t\t\tLog.Error( $\"Trying to hurt card {CardType} with no HP!\" );\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tHP--;\r\n\t\tawait Manager.Instance.ShakeCard(this, playSfx: false);\r\n\t}\r\n\r\n\tpublic void Lock(int numTurns)\r\n\t{\r\n\t\tIsLocked = true;\r\n\t\tLockTurnsRemaining = numTurns;\r\n\t\tWasJustLocked = true;\r\n\t}\r\n\r\n\tpublic void Unlock()\r\n\t{\r\n\t\tIsLocked = false;\r\n\t}\r\n\r\n\tpublic virtual bool CanBeMatched()\r\n\t{\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic void StartExploding(float explodeTime)\r\n\t{\r\n\t\tIsExploding = true;\r\n\t\t_timeSinceStartExploding = 0f;\r\n\t\t_explodeTime = explodeTime;\r\n\t\t_explodeStartPos = LocalPosition;\r\n\r\n\t\tint rand = Game.Random.Int( 0, 5 );\r\n\t\tswitch(rand)\r\n\t\t{\r\n\t\t\tcase 0: _explodeEasingType = EasingType.SineIn; break;\r\n\t\t\tcase 1: _explodeEasingType = EasingType.SineIn; break;\r\n\t\t\tcase 2: _explodeEasingType = EasingType.QuadIn; break;\r\n\t\t\tcase 3: _explodeEasingType = EasingType.QuadIn; break;\r\n\t\t\tcase 4: _explodeEasingType = EasingType.QuartIn; break;\r\n\t\t\tcase 5: _explodeEasingType = EasingType.Linear; break;\r\n\t\t}\r\n\r\n\t\trand = Game.Random.Int( 0, 7 );\r\n\t\tswitch ( rand )\r\n\t\t{\r\n\t\t\tcase 0: _explodeShakeEasingType = EasingType.SineIn; break;\r\n\t\t\tcase 1: _explodeShakeEasingType = EasingType.QuadIn; break;\r\n\t\t\tcase 2: _explodeShakeEasingType = EasingType.QuartIn; break;\r\n\t\t\tcase 3: _explodeShakeEasingType = EasingType.ExpoIn; break;\r\n\t\t\tcase 4: _explodeShakeEasingType = EasingType.ExpoIn; break;\r\n\t\t\tcase 5: _explodeShakeEasingType = EasingType.ExpoIn; break;\r\n\t\t\tcase 6: _explodeShakeEasingType = EasingType.ExpoIn; break;\r\n\t\t\tcase 7: _explodeShakeEasingType = EasingType.Linear; break;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Explode( int breakNum )\r\n\t{\r\n\t\tvar scale = LocalScale.x * Model.LocalScale.x;\r\n\t\tManager.Instance.SpawnCardBreak( WorldPosition, LocalRotation, scale, ModelRenderer.MaterialOverride, breakNum );\r\n\t\tManager.Instance.PlayCardSfx( \"explosion\", this, volume: Game.Random.Float( 0.4f, 0.55f ), pitch: Game.Random.Float( 0.4f, 2f ) );\r\n\r\n\t\tManager.Instance.CardBreakParticlesPrefab.Clone( WorldPosition.WithZ( 25f ) );\r\n\t\tManager.Instance.CardBreakShockwavePrefab.Clone( WorldPosition.WithZ( 55f ) );\r\n\r\n\t\tGameObject.Destroy();\r\n\t}\r\n\r\n\tpublic void StartScaling(float time, float amount, EasingType easingType)\r\n\t{\r\n\t\tIsScaling = true;\r\n\t\t_timeSinceScale = 0f;\r\n\t\t_scaleTime = time;\r\n\t\t_scaleAmount = amount;\r\n\t\t_scaleEasingType = easingType;\r\n\t}\r\n\r\n\tpublic void ShowFlag()\r\n\t{\r\n\t\tIsFlagShown = true;\r\n\t\tIconBackObj.Enabled = true;\r\n\t}\r\n\r\n\tpublic void HideFlag()\r\n\t{\r\n\t\tIsFlagShown = false;\r\n\r\n\t\tif ( !AreRevealMarksShown )\r\n\t\t\tIconBackObj.Enabled = false;\r\n\t}\r\n\r\n\tpublic void ShowRevealMarks()\r\n\t{\r\n\t\tAreRevealMarksShown = true;\r\n\t\tIconBackObj.Enabled = true;\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardBank.cs",
"FileName": "CardBank.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardBank : Card\r\n{\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\tswitch ( eventType )\r\n\t\t{\r\n\t\t\tcase EventType.Match:\r\n\t\t\t\treturn Manager.Instance.ChosenCards[1] == this;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 150 );\r\n\r\n\t\tvar coins = Manager.Instance.Cards.Where( x => x.CardType == CardType.Coin ).ToList();\r\n\t\tif(coins.Count > 0)\r\n\t\t{\r\n\t\t\tManager.Instance.PlayCardSfxBetween( \"bank\", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1f, pitch: Game.Random.Float( 0.9f, 1.1f ) );\r\n\r\n\t\t\tawait Task.DelayRealtime( 50 );\r\n\r\n\t\t\tforeach ( var coin in coins )\r\n\t\t\t\tcoin.SetCardType( CardType.MoneyBag );\r\n\r\n\t\t\tawait Task.DelayRealtime( 300 );\r\n\t\t}\r\n\r\n\t\tawait Task.DelayRealtime( 800 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardCockroach.cs",
"FileName": "CardCockroach.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardCockroach : Card\r\n{\r\n\tpublic override bool IsAlive => true;\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Mismatch && Manager.Instance.ChosenCards[0].CardType == CardType.Cockroach && Manager.Instance.ChosenCards[1].CardType == CardType.Cockroach && !IsLocked;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 850 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n\r\n\tpublic override bool CanBeMatched()\r\n\t{\r\n\t\tforeach(var card in Manager.Instance.Cards)\r\n\t\t{\r\n\t\t\tif ( card.CardType != CardType.Cockroach )\r\n\t\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardDancer.cs",
"FileName": "CardDancer.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardDancer : Card\r\n{\r\n\tpublic override bool IsAlive => true;\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Mismatch && Manager.Instance.ChosenCards.Contains( this ) && !Manager.Instance.IsMismatchALockedMatch;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tList<Card> neighbourCards = new();\r\n\t\tList<IntVector2> neighboursEmpty = new();\r\n\t\tCard lastPartnerCard = null;\r\n\r\n\t\tawait Task.DelayRealtime( 300 );\r\n\r\n\t\tManager.Instance.PlayCardSfx( \"dancer\", this, volume: 1.1f, pitch: Game.Random.Float( 0.98f, 1.02f ) );\r\n\r\n\t\tfor (int i = 0; i < 4; i++)\r\n\t\t{\r\n\t\t\tneighbourCards.Clear();\r\n\t\t\tneighboursEmpty.Clear();\r\n\r\n\t\t\tEvaluateNeighbour( GridPos + new IntVector2( -1, 0 ), neighbourCards, neighboursEmpty );\r\n\t\t\tEvaluateNeighbour( GridPos + new IntVector2( 1, 0 ), neighbourCards, neighboursEmpty );\r\n\t\t\tEvaluateNeighbour( GridPos + new IntVector2( 0, -1 ), neighbourCards, neighboursEmpty );\r\n\t\t\tEvaluateNeighbour( GridPos + new IntVector2( 0, 1 ), neighbourCards, neighboursEmpty );\r\n\r\n\t\t\tIntVector2 targetGridPos;\r\n\t\t\tCard targetCard = null;\r\n\r\n\t\t\tvar validNeighbourCards = neighbourCards.Where( x => x != lastPartnerCard ).ToList();\r\n\r\n\t\t\tif ( validNeighbourCards.Count > 0 )\r\n\t\t\t{\r\n\t\t\t\tvalidNeighbourCards.Shuffle();\r\n\t\t\t\ttargetCard = validNeighbourCards.First();\r\n\t\t\t\ttargetGridPos = targetCard.GridPos;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tneighboursEmpty.Shuffle();\r\n\t\t\t\ttargetGridPos = neighboursEmpty.First();\r\n\t\t\t}\r\n\r\n\t\t\tif ( targetCard != null )\r\n\t\t\t{\r\n\t\t\t\tawait Manager.Instance.ShakeCard( this );\r\n\t\t\t\tawait Manager.Instance.ShakeCard( targetCard );\r\n\r\n\t\t\t\tlastPartnerCard = targetCard;\r\n\r\n\t\t\t\tawait Task.DelayRealtime( 650 );\r\n\r\n\t\t\t\tif(i < 3)\r\n\t\t\t\t{\r\n\t\t\t\t\tawait Manager.Instance.SwapCardPositions( this, targetCard );\r\n\t\t\t\t\tawait Task.DelayRealtime( 250 );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tlastPartnerCard = null;\r\n\r\n\t\t\t\tif ( i < 3 )\r\n\t\t\t\t{\r\n\t\t\t\t\tManager.Instance.RemoveCardGridPos( this );\r\n\t\t\t\t\tawait Manager.Instance.SetCardGridPos( this, targetGridPos );\r\n\r\n\t\t\t\t\tawait Task.DelayRealtime( 400 );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tawait Task.DelayRealtime( 100 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\r\n\t\tawait Manager.Instance.EventHappened( EventType.AfterCardsMoved );\r\n\t}\r\n\r\n\tvoid EvaluateNeighbour(IntVector2 gridPos, List<Card> neighbourCards, List<IntVector2> empty)\r\n\t{\r\n\t\tif ( !Manager.Instance.IsGridPosInBounds( gridPos ) )\r\n\t\t\treturn;\r\n\r\n\t\tvar card = Manager.Instance.GetCardAtGridPos( gridPos );\r\n\t\tif ( card != null )\r\n\t\t\tneighbourCards.Add( card );\r\n\t\telse\r\n\t\t\tempty.Add( gridPos );\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardDolphin.cs",
"FileName": "CardDolphin.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\nusing System.Xml.Linq;\r\n\r\npublic class CardDolphin : Card\r\n{\r\n\tpublic override bool IsAlive => true;\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Mismatch && !Manager.Instance.ChosenCards.Contains(this) && Manager.Instance.Stats[StatType.ConsecutiveMismatches] == 3;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 250 );\r\n\r\n\t\tManager.Instance.PlayCardSfx( \"card_flip\", this, volume: 0.8f, pitch: Game.Random.Float( 1.15f, 1.2f ) );\r\n\t\tawait Task.DelayRealtime( 100 );\r\n\t\tManager.Instance.PlayCardSfx( \"dolphin\", this, volume: 0.8f, pitch: Game.Random.Float( 1f, 1.15f ) );\r\n\t\tawait Manager.Instance.RevealCard( this );\r\n\r\n\t\tawait Task.DelayRealtime( Game.Random.Int(400, 700) );\r\n\r\n\t\tManager.Instance.HideCard( this );\r\n\t\tManager.Instance.PlayCardSfx( \"card_flip\", this, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardGenie.cs",
"FileName": "CardGenie.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardGenie : Card\r\n{\r\n\tpublic override bool IsAlive => true;\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Match && Manager.Instance.ChosenCards[0] == this;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 250 );\r\n\r\n\t\tManager.Instance.PlayCardSfxBetween( \"genie\", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 0.6f, pitch: Game.Random.Float( 1.25f, 1.26f ) );\r\n\r\n\t\tManager.Instance.AddStatus( \"StatusGenie\" );\r\n\r\n\t\tawait Task.DelayRealtime( 1750 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n\r\npublic class StatusGenie : StatusEffect\r\n{\r\n\tpublic float TimerReductionAmount { get; set; }\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Choose;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tvar validCards = Manager.Instance.Cards.Where(x => x.CardType == Manager.Instance.ChosenCard.CardType && x != Manager.Instance.ChosenCard).ToList();\r\n\t\tif ( validCards.Count == 0 )\r\n\t\t\treturn;\r\n\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 250 );\r\n\r\n\t\tManager.Instance.PlayCardSfx( \"genie_choose\", Manager.Instance.ChosenCard, volume: 0.9f, pitch: Game.Random.Float( 0.95f, 1.05f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 750 );\r\n\r\n\t\tvalidCards.Shuffle();\r\n\r\n\t\tawait Manager.Instance.ShakeCard( validCards.FirstOrDefault() );\r\n\t\t\r\n\t\tawait Task.DelayRealtime( 750 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\r\n\t\tManager.Instance.RemoveStatus( this );\r\n\t}\r\n\r\n\tpublic override string GetEventIcon( EventType eventType )\r\n\t{\r\n\t\treturn \"textures/genie.png\";\r\n\t}\r\n\r\n\tpublic override string GetEventText( EventType eventType )\r\n\t{\r\n\t\treturn \"Shake matching card\";\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardKey.cs",
"FileName": "CardKey.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardKey : Card\r\n{\r\n\t//public override bool ShouldHandleEvent( EventType eventType )\r\n\t//{\r\n\t//\treturn eventType == EventType.Mismatch && Manager.Instance.ChosenCards.Contains(this) || eventType == EventType.Match && Manager.Instance.ChosenCards[1] == this;\r\n\t//}\r\n\r\n\t//public override async Task HandleEventAsync( EventType eventType )\r\n\t//{\r\n\t//\tif ( eventType == EventType.Mismatch )\r\n\t//\t{\r\n\t//\t\tvar key = Manager.Instance.ChosenCards[0].CardType == CardType.Key ? Manager.Instance.ChosenCards[0] : Manager.Instance.ChosenCards[1];\r\n\t//\t\tvar otherCard = Manager.Instance.ChosenCards[0].CardType == CardType.Key ? Manager.Instance.ChosenCards[1] : Manager.Instance.ChosenCards[0];\r\n\r\n\t//\t\tif ( key.IsLocked || !otherCard.IsLocked )\r\n\t//\t\t\treturn;\r\n\r\n\t//\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t//\t\tawait Task.DelayRealtime( 50 );\r\n\r\n\t//\t\tManager.Instance.PlayCardSfxBetween( \"key\", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1.5f, pitch: Game.Random.Float( 0.9f, 1.1f ) );\r\n\r\n\t//\t\tawait Task.DelayRealtime( 50 );\r\n\r\n\t//\t\tawait Manager.Instance.UnlockCard( otherCard );\r\n\r\n\t//\t\tawait Task.DelayRealtime( 900 );\r\n\r\n\t//\t\tManager.Instance.PopEventMessage();\r\n\t//\t}\r\n // else if (eventType == EventType.Match)\r\n\t//\t{\r\n\t//\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t//\t\tawait Task.DelayRealtime( 50 );\r\n\r\n\t//\t\tvar lockedCards = Manager.Instance.Cards.Where( x => x.IsLocked ).ToList();\r\n\r\n\t//\t\tif ( lockedCards.Count == 0 )\r\n\t//\t\t{\r\n\t//\t\t\tawait Task.DelayRealtime( 800 );\r\n\r\n\t//\t\t\tManager.Instance.PopEventMessage();\r\n\r\n\t//\t\t\treturn;\r\n\t//\t\t}\r\n\r\n\t//\t\tManager.Instance.PlayCardSfxBetween( \"key\", Manager.Instance.ChosenCards[0], Manager.Instance.ChosenCards[1], volume: 1.5f, pitch: Game.Random.Float( 0.9f, 1.1f ) );\r\n\r\n\t//\t\tawait Task.DelayRealtime( 50 );\r\n\r\n\t//\t\tforeach ( var card in lockedCards )\r\n\t//\t\t{\r\n\t//\t\t\tawait Manager.Instance.UnlockCard( card );\r\n\t//\t\t}\r\n\r\n\t//\t\tawait Task.DelayRealtime( 1000 );\r\n\r\n\t//\t\tManager.Instance.PopEventMessage();\r\n\t//\t}\r\n\t//}\r\n\r\n\t//public override string GetEventText( EventType eventType )\r\n\t//{\r\n\t//\tif ( eventType == EventType.Mismatch )\r\n\t//\t{\r\n\t//\t\treturn \"\u274cMismatch: unlock other card\";\r\n\t//\t}\r\n\t//\telse\r\n\t//\t{\r\n\t//\t\treturn \"\u2705Match: unlock all cards\";\r\n\t//\t}\r\n\t//}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicGuideDog.cs",
"FileName": "RelicGuideDog.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicGuideDog : Relic\r\n{\r\n\tpublic override void Init()\r\n\t{\r\n\t\tbase.Init();\r\n\r\n\t\tMaxLevel = 1;\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicMammothMeat.cs",
"FileName": "RelicMammothMeat.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicMammothMeat : Relic\r\n{\r\n\tpublic override void LevelUp()\r\n\t{\r\n\t\tbase.LevelUp();\r\n\r\n\t\tvar mouse = Mouse.Position;\r\n\t\tvar camera = Scene.Camera;\r\n\t\tvar ray = camera.ScreenPixelToRay( mouse );\r\n\r\n\t\tvar tr = Scene.Trace.Ray( ray, 10000f ).Run();\r\n\r\n\t\tManager.Instance.PlaySfxCenter( \"mammoth_meat\", volume: 0.75f, pitch: Game.Random.Float( 0.85f, 0.9f ) );\r\n\r\n\t\tint maxHpAmount = 8;\r\n\t\tManager.Instance.SpawnMaxHPFloater( maxHpAmount, tr.EndPosition );// + new Vector3(0f, -30f, 0f) );\r\n\t\tManager.Instance.MaxHP += maxHpAmount;\r\n\r\n\t\t//int hpAmount = 5;\r\n\t\t//Manager.Instance.HP = Math.Min( Manager.Instance.HP + hpAmount, Manager.Instance.MaxHP );\r\n\t\tManager.Instance.TimeSinceHPChanged = 0f;\r\n\r\n\t\t//Manager.Instance.SpawnHealHPFloater( hpAmount, tr.EndPosition );\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicMantlepieceClock.cs",
"FileName": "RelicMantlepieceClock.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicMantlepieceClock : Relic\r\n{\r\n\tpublic override void LevelUp()\r\n\t{\r\n\t\tbase.LevelUp();\r\n\r\n\t\tManager.Instance.Stats[StatType.NumExtraBountyTurns] += (Level == 1 ? 2f : 1f);\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicMedicalLicense.cs",
"FileName": "RelicMedicalLicense.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicMedicalLicense : Relic\r\n{\r\n\tpublic override void Init()\r\n\t{\r\n\t\tbase.Init();\r\n\r\n\t\tMaxLevel = 1;\r\n\t}\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.OverhealHP;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tawait Task.DelayRealtime( 1000 );\r\n\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tvar camera = Scene.Camera;\r\n\t\tvar ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );\r\n\r\n\t\tvar tr = Scene.Trace.Ray( ray, 10000f ).Run();\r\n\r\n\t\tManager.Instance.PlaySfx( \"medical_license\", tr.EndPosition.WithZ( Scene.Camera.WorldPosition.z - Globals.CARD_SFX_DEPTH_DIFF ), volume: 1.2f, pitch: Game.Random.Float( 0.95f, 1.05f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 350 );\r\n\r\n\t\tint moneyAmount = (int)Manager.Instance.Stats[StatType.LatestOverhealAmount] + (int)Manager.Instance.Stats[StatType.EarnExtraMoney];\r\n\r\n\t\tManager.Instance.SpawnGainMoneyFloater( moneyAmount, tr.EndPosition );\r\n\r\n\t\tawait Manager.Instance.GainMoney( moneyAmount );\r\n\r\n\t\tawait Task.DelayRealtime( 650 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicMouseTrap.cs",
"FileName": "RelicMouseTrap.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicMouseTrap : Relic\r\n{\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.ClaimBounty;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync(EventType eventType)\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tawait Task.DelayRealtime( 100 );\r\n\r\n\t\tManager.Instance.PlaySfxCenter( \"mouse_trap\", volume: 0.8f, pitch: Game.Random.Float( 0.95f, 1.05f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 400 );\r\n\r\n\t\tvar camera = Scene.Camera;\r\n\t\tvar ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );\r\n\t\tvar tr = Scene.Trace.Ray( ray, 10000f ).Run();\r\n\r\n\t\tint maxHP = Level;\r\n\t\tManager.Instance.SpawnMaxHPFloater( maxHP, tr.EndPosition );\r\n\t\tManager.Instance.MaxHP += maxHP;\r\n\r\n\t\tManager.Instance.TimeSinceHPChanged = 0f;\r\n\r\n\t\tawait Task.DelayRealtime( 500 );\r\n\t\t\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicSacrificialBlade.cs",
"FileName": "RelicSacrificialBlade.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicSacrificialBlade : Relic\r\n{\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.HurtCards;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync(EventType eventType)\r\n\t{\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\tvar camera = Scene.Camera;\r\n\t\tvar ray = camera.ScreenPixelToRay( new Vector3( Screen.Width / 2, Screen.Height / 2, 0f ) );\r\n\t\tvar tr = Scene.Trace.Ray( ray, 10000f ).Run();\r\n\r\n\t\tManager.Instance.PlaySfx( \"sacrificial_blade\", tr.EndPosition.WithZ( Scene.Camera.WorldPosition.z - Globals.CARD_SFX_DEPTH_DIFF ), volume: 0.75f, pitch: Game.Random.Float( 1.6f, 1.65f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 450 );\r\n\r\n\t\tint healAmount = Level;\r\n\r\n\t\tManager.Instance.SpawnHealHPFloater( healAmount, tr.EndPosition );\r\n\r\n\t\tawait Task.DelayRealtime( 350 );\r\n\r\n\t\tawait Manager.Instance.GainHP( healAmount );\r\n\r\n\t\tawait Task.DelayRealtime( 250 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "relics/RelicSign.cs",
"FileName": "RelicSign.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Reflection.PortableExecutable;\r\nusing System.Runtime.Versioning;\r\nusing System.Text.RegularExpressions;\r\nusing System.Threading.Tasks;\r\n\r\npublic class RelicSign : Relic\r\n{\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.Mismatch && Game.Random.Float(0f, 1f) < Level * 0.25f;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tList<Card> validCards = new();\r\n\t\tforeach ( var card in Manager.Instance.Cards )\r\n\t\t{\r\n\t\t\tif ( card.NumTimesRevealed > 0 && !Manager.Instance.ChosenCards.Contains(card) && !card.IsRevealed )\r\n\t\t\t\tvalidCards.Add( card );\r\n\t\t}\r\n\r\n\t\tif ( validCards.Count == 0 )\r\n\t\t\treturn;\r\n\r\n\t\tManager.Instance.PushEventMessage( this, eventType );\r\n\r\n\t\t// todo: sfx\r\n\r\n\t\tawait Task.DelayRealtime( 250 );\r\n\r\n\t\tvalidCards.Shuffle();\r\n\r\n\t\tvar cardToReveal = validCards.First();\r\n\r\n\t\tManager.Instance.PlayCardSfx( \"card_flip\", cardToReveal, volume: 0.8f, pitch: Game.Random.Float( 1.15f, 1.2f ) );\r\n\t\tawait Manager.Instance.RevealCard( cardToReveal );\r\n\r\n\t\tawait Task.DelayRealtime( 750 );\r\n\r\n\t\tManager.Instance.HideCard( cardToReveal );\r\n\t\tManager.Instance.PlayCardSfx( \"card_flip\", cardToReveal, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 300 );\r\n\r\n\t\tManager.Instance.PopEventMessage();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "ui/messagepanel.razor.scss",
"FileName": "messagepanel.razor.scss",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "MessagePanel {\r\n position: absolute;\r\n //min-width: 60%;\r\n height: 60px;\r\n bottom: 10px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n border-radius: 15px;\r\n //background-color: #00000088;\r\n flex-direction: row;\r\n padding: 8px;\r\n backdrop-filter: blur(5px);\r\n //transition: bottom 0.25s ease-out, transform 0.25s ease-out, opacity 0.25s ease-out;\r\n transition: all 0.25s ease-out;\r\n\r\n .message {\r\n font-size: 24px;\r\n color: #ffffffee;\r\n }\r\n\r\n .icon {\r\n width: 55px;\r\n height: 55px;\r\n background-repeat: no-repeat;\r\n background-size: contain;\r\n background-position: center center;\r\n }\r\n\r\n &.depth-0 {\r\n transform: scale(1);\r\n bottom: 10px;\r\n z-index: 0;\r\n }\r\n\r\n &.depth-1 {\r\n transform: scale(0.8);\r\n bottom: 50px;\r\n z-index: -3;\r\n }\r\n\r\n &.depth-2 {\r\n transform: scale(0.6);\r\n bottom: 90px;\r\n z-index: -6;\r\n }\r\n\r\n &.depth-3 {\r\n transform: scale(0.5);\r\n bottom: 110px;\r\n z-index: -9;\r\n }\r\n\r\n &.depth-4 {\r\n transform: scale(0.4);\r\n bottom: 140px;\r\n z-index: -12;\r\n }\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "ui/cardtypepanelelement.razor.scss",
"FileName": "cardtypepanelelement.razor.scss",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "CardTypePanelElement {\r\n\t//border-radius: 10px;\r\n\theight: 80px;\r\n\twidth: 80px;\r\n\tjustify-content: center;\r\n\t//flex-shrink: 1;\r\n\t//margin: 2px;\r\n\t//background-color: blue;\r\n\t//border: 2px solid #111111;\r\n\t//overflow: visible;\r\n\tposition: relative;\r\n\r\n\t.icon_container {\r\n\t\twidth: 100%;\r\n\t\theight: 100%;\r\n\t\ttransform: scale(1);\r\n\t\ttransition: transform 0.075s ease-out;\r\n\t\tpointer-events: all;\r\n\r\n\t\t&:hover {\r\n\t\t\t//background-color: #301B3F99;\r\n\t\t\t//border: 2px solid #111111;\r\n\t\t\t//opacity: 1;\r\n\t\t\ttransform: scale(1.2);\r\n\t\t}\r\n\t}\r\n\r\n\t.icon {\r\n\t\tposition: absolute;\r\n\t\twidth: 100%;\r\n\t\theight: 100%;\r\n\t\tbackground-repeat: no-repeat;\r\n\t\tbackground-size: contain;\r\n\t\tbackground-position: center center;\r\n\t\tpointer-events: none;\r\n\t}\r\n\r\n\t.normal {\r\n\t\tfilter: brightness(1);\r\n\t\topacity: 1;\r\n\t}\r\n\r\n\t.matched {\r\n\t\tfilter: brightness(0);\r\n\t\topacity: 0.4;\r\n\t}\r\n\r\n\t.bounty {\r\n\t\tposition: absolute;\r\n\t\twidth: 60px;\r\n\t\theight: 60px;\r\n\t\tbackground-color: #0000ff99;\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "CardBreaker.cs",
"FileName": "CardBreaker.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\n\r\npublic sealed class CardBreaker : Component\r\n{\r\n\tprotected override void OnStart()\r\n\t{\r\n\r\n\t}\r\n\r\n\tpublic void Init(Material material, Rotation rot, float scale)\r\n\t{\r\n\t\tLocalRotation = rot;\r\n\t\tLocalScale = new Vector3( scale );\r\n\r\n\t\tfor ( int i = GameObject.Children.Count - 1; i >= 0; i-- )\r\n\t\t{\r\n\t\t\tvar child = GameObject.Children[i];\r\n\t\t\tchild.SetParent( null );\r\n\r\n\t\t\tvar modelRenderer = child.Components.Get<ModelRenderer>();\r\n\t\t\tmodelRenderer.Tint = Color.White;\r\n\t\t\tmodelRenderer.MaterialOverride = material;\r\n\r\n\t\t\tvar rigidBody = child.Components.Get<Rigidbody>();\r\n\t\t\trigidBody.ApplyImpulse( (child.WorldPosition - WorldPosition).Normal * Game.Random.Float( 10f, 100f ) * rigidBody.PhysicsBody.Mass );\r\n\t\t\trigidBody.ApplyImpulse( new Vector3( 0f, 0f, 1f ) * Game.Random.Float( 400f, 800f ) * rigidBody.PhysicsBody.Mass );\r\n\t\t\trigidBody.AngularVelocity = Vector3.Random * Game.Random.Float( -10f, 10f );\r\n\t\t}\r\n\r\n\t\tGameObject.Destroy();\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "Utils.cs",
"FileName": "Utils.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\nusing System.Text.Json;\r\n\r\npublic enum EasingType\r\n{\r\n\tNone = -1,\r\n\tLinear = 0,\r\n\tSineIn, SineOut, SineInOut,\r\n\tQuadIn, QuadOut, QuadInOut,\r\n\tCubicIn, CubicOut, CubicInOut,\r\n\tQuartIn, QuartOut, QuartInOut,\r\n\tQuintIn, QuintOut, QuintInOut,\r\n\tExpoIn, ExpoOut, ExpoInOut,\r\n\tExtremeIn, ExtremeOut, ExtremeInOut,\r\n\tElasticIn, ElasticOut, ElasticInOut,\r\n\tElasticSoftIn, ElasticSoftOut, ElasticSoftInOut,\r\n\tBackIn, BackOut, BackInOut,\r\n\tBounceIn, BounceOut, BounceInOut\r\n};\r\n\r\npublic struct IntVector2 : IEquatable<IntVector2>\r\n{\r\n\tpublic static implicit operator Vector2( IntVector2 vec )\r\n\t{\r\n\t\treturn new Vector2( vec.x, vec.y );\r\n\t}\r\n\r\n\tpublic static explicit operator IntVector2( Vector2 vec )\r\n\t{\r\n\t\treturn new IntVector2( (int)vec.x, (int)vec.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// A vector with zero for all components.\r\n\t/// </summary>\r\n\tpublic static readonly IntVector2 Zero = new IntVector2( 0, 0 );\r\n\r\n\t/// <summary>\r\n\t/// A normalized vector along the positive X axis.\r\n\t/// </summary>\r\n\tpublic static readonly IntVector2 UnitX = new IntVector2( 1, 0 );\r\n\r\n\t/// <summary>\r\n\t/// A normalized vector along the positive Y axis.\r\n\t/// </summary>\r\n\tpublic static readonly IntVector2 UnitY = new IntVector2( 0, 1 );\r\n\r\n\t#region Operators\r\n\t/// <summary>\r\n\t/// The identity operator.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator +( IntVector2 vec )\r\n\t{\r\n\t\treturn vec;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise addition of a vector to another.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator +( IntVector2 a, IntVector2 b )\r\n\t{\r\n\t\treturn new IntVector2( a.x + b.x, a.y + b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Finds the negation of a vector.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator -( IntVector2 vec )\r\n\t{\r\n\t\treturn new IntVector2( -vec.x, -vec.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise subtraction of a vector from another.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator -( IntVector2 a, IntVector2 b )\r\n\t{\r\n\t\treturn new IntVector2( a.x - b.x, a.y - b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise multiplication of a vector by another.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator *( IntVector2 a, IntVector2 b )\r\n\t{\r\n\t\treturn new IntVector2( a.x * b.x, a.y * b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Multiplies a vector by a scalar.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator *( IntVector2 vec, int val )\r\n\t{\r\n\t\treturn new IntVector2( vec.x * val, vec.y * val );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Multiplies a vector by a scalar.\r\n\t/// </summary>\r\n\tpublic static Vector2 operator *( IntVector2 vec, float val )\r\n\t{\r\n\t\treturn new Vector2( vec.x * val, vec.y * val );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Multiplies a vector by a scalar.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator *( int val, IntVector2 vec )\r\n\t{\r\n\t\treturn new IntVector2( vec.x * val, vec.y * val );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Multiplies a vector by a scalar.\r\n\t/// </summary>\r\n\tpublic static Vector2 operator *( float val, IntVector2 vec )\r\n\t{\r\n\t\treturn new Vector2( vec.x * val, vec.y * val );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise division of a vector by another.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator /( IntVector2 a, IntVector2 b )\r\n\t{\r\n\t\treturn new IntVector2( a.x / b.x, a.y / b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise division of a vector by another.\r\n\t/// </summary>\r\n\tpublic static Vector2 operator /( Vector2 a, IntVector2 b )\r\n\t{\r\n\t\treturn new Vector2( a.x / b.x, a.y / b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Component-wise division of a vector by another.\r\n\t/// </summary>\r\n\tpublic static Vector2 operator /( IntVector2 a, Vector2 b )\r\n\t{\r\n\t\treturn new Vector2( a.x / b.x, a.y / b.y );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Division of this vector by a scalar.\r\n\t/// </summary>\r\n\tpublic static IntVector2 operator /( IntVector2 vec, int val )\r\n\t{\r\n\t\treturn new IntVector2( vec.x / val, vec.y / val );\r\n\t}\r\n\r\n\tpublic static Vector2 operator /( IntVector2 vec, float val )\r\n\t{\r\n\t\treturn new Vector2( vec.x / val, vec.y / val );\r\n\t}\r\n\r\n\tpublic static IntVector2 operator /( int val, IntVector2 vec )\r\n\t{\r\n\t\treturn new IntVector2( val / vec.x, val / vec.y );\r\n\t}\r\n\r\n\tpublic static Vector2 operator /( float val, IntVector2 vec )\r\n\t{\r\n\t\treturn new Vector2( val / vec.x, val / vec.y );\r\n\t}\r\n\t#endregion\r\n\r\n\t/// <summary>\r\n\t/// Horizontal component.\r\n\t/// </summary>\r\n\tpublic int x;\r\n\r\n\t/// <summary>\r\n\t/// Vertical component.\r\n\t/// </summary>\r\n\tpublic int y;\r\n\r\n\t/// <summary>\r\n\t/// Floating point magnitude of the vector.\r\n\t/// </summary>\r\n\tpublic float Length { get { return (float)MathF.Sqrt( x * x + y * y ); } }\r\n\r\n\t/// <summary>\r\n\t/// Magnitude of the vector in Taxicab geometry.\r\n\t/// </summary>\r\n\tpublic int ManhattanLength { get { return Math.Abs( x ) + Math.Abs( y ); } }\r\n\r\n\t/// <summary>\r\n\t/// Sum of each component squared.\r\n\t/// </summary>\r\n\tpublic int LengthSquared { get { return x * x + y * y; } }\r\n\r\n\t/// <summary>\r\n\t/// Gets a normalized vector in the same direction as this one.\r\n\t/// </summary>\r\n\tpublic Vector2 Normalized { get { return LengthSquared >= float.Epsilon ? this / Length : Zero; } }\r\n\r\n\t/// <summary>\r\n\t/// Gets a vector equal to this one rotated counter-clockwise by 90 degrees.\r\n\t/// </summary>\r\n\tpublic IntVector2 Left { get { return new IntVector2( -y, x ); } }\r\n\r\n\t/// <summary>\r\n\t/// Gets a vector equal to this one rotated clockwise 90 degrees.\r\n\t/// </summary>\r\n\tpublic IntVector2 Right { get { return new IntVector2( y, -x ); } }\r\n\r\n\t/// <summary>\r\n\t/// Gets a vector equal to this one rotated 180 degrees.\r\n\t/// </summary>\r\n\tpublic IntVector2 Back { get { return -this; } }\r\n\r\n\t/// <summary>\r\n\t/// Constructs a vector from the given X and Y components.\r\n\t/// </summary>\r\n\tpublic IntVector2( int x, int y )\r\n\t{\r\n\t\tthis.x = x; this.y = y;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Finds the scalar product of this vector and another.\r\n\t/// </summary>\r\n\tpublic int Dot( IntVector2 vec )\r\n\t{\r\n\t\treturn x * vec.x + y * vec.y;\r\n\t}\r\n\r\n\tpublic override bool Equals( object obj )\r\n\t{\r\n\t\treturn obj is IntVector2 && Equals( (IntVector2)obj );\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Tests for equality with another vector.\r\n\t/// </summary>\r\n\tpublic bool Equals( IntVector2 vec )\r\n\t{\r\n\t\treturn x == vec.x && y == vec.y;\r\n\t}\r\n\r\n\tpublic override int GetHashCode()\r\n\t{\r\n\t\treturn x ^ y;\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Gets a string representing this vector in (X, Y) format.\r\n\t/// </summary>\r\n\tpublic override string ToString()\r\n\t{\r\n\t\treturn string.Format( \"({0}, {1})\", x, y );\r\n\t}\r\n}\r\n\r\npublic struct AStarEdge<T>\r\n{\r\n\t/// <summary>\r\n\t/// The node this connection leads to.\r\n\t/// </summary>\r\n\tpublic readonly T Dest;\r\n\r\n\t/// <summary>\r\n\t/// The cost of using this connection.\r\n\t/// </summary>\r\n\tpublic readonly float Cost;\r\n\r\n\tinternal AStarEdge( T dest, float cost )\r\n\t{\r\n\t\tDest = dest;\r\n\t\tCost = cost;\r\n\t}\r\n}\r\n\r\npublic static class Utils\r\n{\r\n\t// projects vector A onto B\r\n\tpublic static Vector3 ProjectVector( Vector3 a, Vector3 b )\r\n\t{\r\n\t\tfloat dotProduct = Vector3.Dot( a, b );\r\n\t\tfloat lengthSquared = Vector3.Dot( b, b );\r\n\t\treturn (dotProduct / lengthSquared) * b;\r\n\t}\r\n\r\n\t// returns vector B or C, whichever is in the closest direction compared to A\r\n\tpublic static Vector3 FindCloserVector( Vector3 a, Vector3 b, Vector3 c )\r\n\t{\r\n\t\t// Normalize B and C\r\n\t\tb = b.Normal;\r\n\t\tc = c.Normal;\r\n\r\n\t\t// Compute dot products\r\n\t\tfloat dotProductB = Vector3.Dot( a, b );\r\n\t\tfloat dotProductC = Vector3.Dot( a, c );\r\n\r\n\t\t// Determine which dot product is larger\r\n\t\treturn dotProductB > dotProductC ? b : c;\r\n\t}\r\n\r\n\tpublic static GameObject FindChild( this Component component, string name )\r\n\t{\r\n\t\treturn component.GameObject.Children.Where( x => x.Name == name ).FirstOrDefault();\r\n\t}\r\n\r\n\tpublic static Color GetRandomColor( float total = 1.5f )\r\n\t{\r\n\t\tfloat r = Game.Random.Float( 0f, 1f );\r\n\t\ttotal = Math.Max( total - r, 0f );\r\n\t\tfloat g = MathF.Min( Game.Random.Float( 0f, 1f ), total );\r\n\t\ttotal = Math.Max( total - g, 0f );\r\n\t\tfloat b = MathF.Min( Game.Random.Float( 0f, 1f ), total );\r\n\r\n\t\treturn new Color( r, g, b );\r\n\t}\r\n\r\n\tpublic static T ReadJsonCustom<T>( this BaseFileSystem fs, string filename, T defaultValue = default( T ) )\r\n\t{\r\n\t\tstring text = fs.ReadAllText( filename );\r\n\t\tif ( string.IsNullOrWhiteSpace( text ) )\r\n\t\t{\r\n\t\t\treturn defaultValue;\r\n\t\t}\r\n\r\n\t\tJsonSerializerOptions options = new JsonSerializerOptions\r\n\t\t{\r\n\t\t\tReadCommentHandling = JsonCommentHandling.Skip,\r\n\t\t\tPropertyNameCaseInsensitive = true,\r\n\t\t\tAllowTrailingCommas = true,\r\n\t\t\tConverters = { new System.Text.Json.Serialization.JsonStringEnumConverter() },\r\n\t\t};\r\n\t\treturn JsonSerializer.Deserialize<T>( text, options );\r\n\t}\r\n\r\n\tpublic const float Deg2Rad = MathF.PI / 180f;\r\n\tpublic const float Rad2Deg = 360f / (MathF.PI * 2f);\r\n\r\n\tpublic static Vector2 RotateVector( Vector2 v, float degrees )\r\n\t{\r\n\t\tvar rads = Deg2Rad * degrees;\r\n\t\tvar ca = MathF.Cos( rads );\r\n\t\tvar sa = MathF.Sin( rads );\r\n\r\n\t\treturn new Vector2( ca * v.x - sa * v.y, sa * v.x + ca * v.y );\r\n\t}\r\n\r\n\tpublic static Vector2 RotatePointAround( Vector2 p, Vector2 anchor, float degrees )\r\n\t{\r\n\t\tvar offset = p - anchor;\r\n\t\tvar newVec = RotateVector( offset, degrees );\r\n\t\treturn anchor + newVec;\r\n\t}\r\n\r\n\tpublic static Vector2 DegreesToVector( float degrees )\r\n\t{\r\n\t\tvar rads = Deg2Rad * degrees;\r\n\t\treturn new Vector2( MathF.Cos( rads ), MathF.Sin( rads ) );\r\n\t}\r\n\r\n\tpublic static float VectorToDegrees( Vector2 vec )\r\n\t{\r\n\t\tfloat radians = (float)Math.Atan2( vec.y, vec.x );\r\n\t\tfloat degrees = radians * (180f / (float)Math.PI);\r\n\t\treturn degrees;\r\n\t}\r\n\r\n\tpublic static Vector2 GetPerpendicularVector( Vector2 vec )\r\n\t{\r\n\t\treturn new Vector2( -vec.y, vec.x );\r\n\t}\r\n\r\n\tpublic static int GetDistance( int x, int y )\r\n\t{\r\n\t\treturn (int)Math.Round( Math.Sqrt( x * x + y * y ) );\r\n\t}\r\n\r\n\tpublic static Vector2 GetRandomVector()\r\n\t{\r\n\t\treturn DegreesToVector( Game.Random.Float( 0f, 360f ) );\r\n\t}\r\n\r\n\tpublic static float FastSin( float input )\r\n\t{\r\n\t\t// wrap input angle to -PI..PI\r\n\t\twhile ( input < -3.14159265f )\r\n\t\t\tinput += 6.28318531f;\r\n\t\twhile ( input > 3.14159265f )\r\n\t\t\tinput -= 6.28318531f;\r\n\r\n\t\treturn 1.27323954f * input + 0.405284735f * (input < 0f ? 1f : -1f) * input * input;\r\n\t}\r\n\r\n\tpublic static float DynamicEaseTo( float current, float goal, float factorPercent, float dt, float referenceFrameRate = 60f )\r\n\t{\r\n\t\tif ( float.IsPositiveInfinity( dt ) )\r\n\t\t\treturn goal;\r\n\r\n\t\treturn current + (goal - current) * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));\r\n\t}\r\n\r\n\tpublic static Vector2 DynamicEaseTo( Vector2 current, Vector2 goal, float factorPercent, float dt, float referenceFrameRate = 60f )\r\n\t{\r\n\t\tif ( float.IsPositiveInfinity( dt ) )\r\n\t\t\treturn goal;\r\n\t\tvar diff = goal - current;\r\n\r\n\t\treturn current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));\r\n\t}\r\n\r\n\tpublic static Vector3 DynamicEaseTo( Vector3 current, Vector3 goal, float factorPercent, float dt, float referenceFrameRate = 60f )\r\n\t{\r\n\t\tif ( float.IsPositiveInfinity( dt ) )\r\n\t\t\treturn goal;\r\n\t\tvar diff = goal - current;\r\n\r\n\t\treturn current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));\r\n\t}\r\n\r\n\tpublic static Rotation DynamicEaseTo( Rotation currentRot, Rotation goalRot, float factorPercent, float dt, float referenceFrameRate = 60f )\r\n\t{\r\n\t\tif ( float.IsPositiveInfinity( dt ) )\r\n\t\t\treturn goalRot;\r\n\r\n\t\tVector3 current = currentRot.Angles().AsVector3();\r\n\t\tVector3 goal = goalRot.Angles().AsVector3();\r\n\r\n\t\tvar diff = goal - current;\r\n\r\n\t\tvar output = current + diff * (1f - MathF.Pow( 1f - MathX.Clamp( factorPercent, 0f, 1f ), dt * referenceFrameRate ));\r\n\t\treturn Rotation.From( new Angles( output ) );\r\n\t}\r\n\r\n\tpublic static float EaseUnclamped( float value, EasingType easingType )\r\n\t{\r\n\t\tswitch ( easingType )\r\n\t\t{\r\n\t\t\tcase EasingType.SineIn: return SineIn( value );\r\n\t\t\tcase EasingType.SineOut: return SineOut( value );\r\n\t\t\tcase EasingType.SineInOut: return SineInOut( value );\r\n\r\n\t\t\tcase EasingType.QuadIn: return QuadIn( value );\r\n\t\t\tcase EasingType.QuadOut: return QuadOut( value );\r\n\t\t\tcase EasingType.QuadInOut: return QuadInOut( value );\r\n\r\n\t\t\tcase EasingType.CubicIn: return CubicIn( value );\r\n\t\t\tcase EasingType.CubicOut: return CubicOut( value );\r\n\t\t\tcase EasingType.CubicInOut: return CubicInOut( value );\r\n\r\n\t\t\tcase EasingType.QuartIn: return QuartIn( value );\r\n\t\t\tcase EasingType.QuartOut: return QuartOut( value );\r\n\t\t\tcase EasingType.QuartInOut: return QuartInOut( value );\r\n\r\n\t\t\tcase EasingType.QuintIn: return QuintIn( value );\r\n\t\t\tcase EasingType.QuintOut: return QuintOut( value );\r\n\t\t\tcase EasingType.QuintInOut: return QuintInOut( value );\r\n\r\n\t\t\tcase EasingType.ExpoIn: return ExpoIn( value );\r\n\t\t\tcase EasingType.ExpoOut: return ExpoOut( value );\r\n\t\t\tcase EasingType.ExpoInOut: return ExpoInOut( value );\r\n\r\n\t\t\tcase EasingType.ExtremeIn: return ExtremeIn( value );\r\n\t\t\tcase EasingType.ExtremeOut: return ExtremeOut( value );\r\n\t\t\tcase EasingType.ExtremeInOut: return ExtremeInOut( value );\r\n\r\n\t\t\tcase EasingType.ElasticIn: return ElasticIn( value );\r\n\t\t\tcase EasingType.ElasticOut: return ElasticOut( value );\r\n\t\t\tcase EasingType.ElasticInOut: return ElasticInOut( value );\r\n\r\n\t\t\tcase EasingType.ElasticSoftIn: return ElasticSoftIn( value );\r\n\t\t\tcase EasingType.ElasticSoftOut: return ElasticSoftOut( value );\r\n\t\t\tcase EasingType.ElasticSoftInOut: return ElasticSoftInOut( value );\r\n\r\n\t\t\tcase EasingType.BackIn: return BackIn( value );\r\n\t\t\tcase EasingType.BackOut: return BackOut( value );\r\n\t\t\tcase EasingType.BackInOut: return BackInOut( value );\r\n\r\n\t\t\tcase EasingType.BounceIn: return BounceIn( value );\r\n\t\t\tcase EasingType.BounceOut: return BounceOut( value );\r\n\t\t\tcase EasingType.BounceInOut: return BounceInOut( value );\r\n\t\t\tdefault: return value;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static float Map( float value, float inputMin, float inputMax, float outputMin, float outputMax, EasingType easingType = EasingType.Linear, bool clamp = true )\r\n\t{\r\n\t\tif ( inputMin.Equals( inputMax ) || outputMin.Equals( outputMax ) )\r\n\t\t\treturn outputMin;\r\n\r\n\t\t// if(inputMin.Equals(inputMax) || outputMin.Equals(outputMax))\r\n\t\t// return outputMax;\r\n\r\n\t\tif ( clamp )\r\n\t\t{\r\n\t\t\t// clamp input\r\n\t\t\tif ( inputMax > inputMin )\r\n\t\t\t{\r\n\t\t\t\tif ( value < inputMin ) value = inputMin;\r\n\t\t\t\telse if ( value > inputMax ) value = inputMax;\r\n\t\t\t}\r\n\t\t\telse if ( inputMax < inputMin )\r\n\t\t\t{\r\n\t\t\t\tif ( value > inputMin ) value = inputMin;\r\n\t\t\t\telse if ( value < inputMax ) value = inputMax;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar ratio = EaseUnclamped( (value - inputMin) / (inputMax - inputMin), easingType );\r\n\r\n\t\tvar outVal = outputMin + ratio * (outputMax - outputMin);\r\n\r\n\t\t// // clamp output\r\n\t\t// if(outputMax < outputMin) {\r\n\t\t// if(outVal < outputMax) outVal = outputMax;\r\n\t\t// else if(outVal > outputMin) outVal = outputMin;\r\n\t\t// } else {\r\n\t\t// if(outVal > outputMax) outVal = outputMax;\r\n\t\t// else if(outVal < outputMin) outVal = outputMin;\r\n\t\t// }\r\n\r\n\t\treturn outVal;\r\n\t}\r\n\r\n\tpublic static float MapReturn( float value, float inputMin, float inputMax, float outputMin, float outputMax, EasingType easingType = EasingType.Linear )\r\n\t{\r\n\t\tvar halfway = inputMin + (inputMax - inputMin) * 0.5f;\r\n\t\tif ( value < halfway ) return Map( value, inputMin, halfway, outputMin, outputMax, easingType );\r\n\t\telse return Map( value, halfway, inputMax, outputMax, outputMin, GetOppositeEasingType( easingType ) );\r\n\t}\r\n\r\n\tpublic static float EasePercent( float percent, EasingType easingType )\r\n\t{\r\n\t\treturn Map( percent, 0f, 1f, 0f, 1f, easingType );\r\n\t}\r\n\r\n\tpublic static EasingType GetOppositeEasingType( EasingType easingType )\r\n\t{\r\n\t\tvar opposite = EasingType.Linear;\r\n\t\tswitch ( easingType )\r\n\t\t{\r\n\t\t\tcase EasingType.SineIn: opposite = EasingType.SineOut; break;\r\n\t\t\tcase EasingType.SineOut: opposite = EasingType.SineIn; break;\r\n\t\t\tcase EasingType.SineInOut: opposite = EasingType.SineInOut; break;\r\n\r\n\t\t\tcase EasingType.QuadIn: opposite = EasingType.QuadOut; break;\r\n\t\t\tcase EasingType.QuadOut: opposite = EasingType.QuadIn; break;\r\n\t\t\tcase EasingType.QuadInOut: opposite = EasingType.QuadInOut; break;\r\n\r\n\t\t\tcase EasingType.CubicIn: opposite = EasingType.CubicOut; break;\r\n\t\t\tcase EasingType.CubicOut: opposite = EasingType.CubicIn; break;\r\n\t\t\tcase EasingType.CubicInOut: opposite = EasingType.CubicInOut; break;\r\n\r\n\t\t\tcase EasingType.QuartIn: opposite = EasingType.QuartOut; break;\r\n\t\t\tcase EasingType.QuartOut: opposite = EasingType.QuartIn; break;\r\n\t\t\tcase EasingType.QuartInOut: opposite = EasingType.QuartInOut; break;\r\n\r\n\t\t\tcase EasingType.QuintIn: opposite = EasingType.QuintOut; break;\r\n\t\t\tcase EasingType.QuintOut: opposite = EasingType.QuintIn; break;\r\n\t\t\tcase EasingType.QuintInOut: opposite = EasingType.QuintInOut; break;\r\n\r\n\t\t\tcase EasingType.ExpoIn: opposite = EasingType.ExpoOut; break;\r\n\t\t\tcase EasingType.ExpoOut: opposite = EasingType.ExpoIn; break;\r\n\t\t\tcase EasingType.ExpoInOut: opposite = EasingType.ExpoInOut; break;\r\n\r\n\t\t\tcase EasingType.ExtremeIn: opposite = EasingType.ExtremeOut; break;\r\n\t\t\tcase EasingType.ExtremeOut: opposite = EasingType.ExtremeIn; break;\r\n\t\t\tcase EasingType.ExtremeInOut: opposite = EasingType.ExtremeInOut; break;\r\n\r\n\t\t\tcase EasingType.ElasticIn: opposite = EasingType.ElasticOut; break;\r\n\t\t\tcase EasingType.ElasticOut: opposite = EasingType.ElasticIn; break;\r\n\t\t\tcase EasingType.ElasticInOut: opposite = EasingType.ElasticInOut; break;\r\n\r\n\t\t\tcase EasingType.ElasticSoftIn: opposite = EasingType.ElasticSoftOut; break;\r\n\t\t\tcase EasingType.ElasticSoftOut: opposite = EasingType.ElasticSoftIn; break;\r\n\t\t\tcase EasingType.ElasticSoftInOut: opposite = EasingType.ElasticSoftInOut; break;\r\n\r\n\t\t\tcase EasingType.BackIn: opposite = EasingType.BackOut; break;\r\n\t\t\tcase EasingType.BackOut: opposite = EasingType.BackIn; break;\r\n\t\t\tcase EasingType.BackInOut: opposite = EasingType.BackInOut; break;\r\n\r\n\t\t\tcase EasingType.BounceIn: opposite = EasingType.BounceOut; break;\r\n\t\t\tcase EasingType.BounceOut: opposite = EasingType.BounceIn; break;\r\n\t\t\tcase EasingType.BounceInOut: opposite = EasingType.BounceInOut; break;\r\n\t\t}\r\n\r\n\t\treturn opposite;\r\n\t}\r\n\r\n\tpublic static float SineIn( float t ) { return 1f - MathF.Cos( t * MathF.PI * 0.5f ); }\r\n\tpublic static float SineOut( float t ) { return MathF.Sin( t * (MathF.PI * 0.5f) ); }\r\n\tpublic static float SineInOut( float t ) { return -0.5f * (MathF.Cos( MathF.PI * t ) - 1f); }\r\n\r\n\tpublic static float QuadIn( float t ) { return t * t; }\r\n\tpublic static float QuadOut( float t ) { return t * (2f - t); }\r\n\tpublic static float QuadInOut( float t ) { return t < 0.5f ? 2f * t * t : -1f + (4f - 2f * t) * t; }\r\n\r\n\tpublic static float CubicIn( float t ) { return t * t * t; }\r\n\tpublic static float CubicOut( float t ) { var t1 = t - 1f; return t1 * t1 * t1 + 1f; }\r\n\tpublic static float CubicInOut( float t ) { return t < 0.5f ? 4f * t * t * t : (t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f; }\r\n\r\n\tpublic static float QuartIn( float t ) { return t * t * t * t; }\r\n\tpublic static float QuartOut( float t ) { var t1 = t - 1f; return 1f - t1 * t1 * t1 * t1; }\r\n\tpublic static float QuartInOut( float t ) { return t < 0.5f ? 4f * t * t * t : (t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f; }\r\n\r\n\tpublic static float QuintIn( float t ) { return t * t * t * t * t; }\r\n\tpublic static float QuintOut( float t ) { var t1 = t - 1f; return 1f + t1 * t1 * t1 * t1 * t1; }\r\n\tpublic static float QuintInOut( float t ) { var t1 = t - 1f; return t < 0.5f ? 16f * t * t * t * t * t : 1f + 16f * t1 * t1 * t1 * t1 * t1; }\r\n\r\n\tpublic static float ExpoIn( float t ) { return MathF.Pow( 2f, 10f * (t - 1f) ); }\r\n\tpublic static float ExpoOut( float t ) { return 1f - MathF.Pow( 2f, -10f * t ); }\r\n\tpublic static float ExpoInOut( float t ) { return t < 0.5f ? ExpoIn( t * 2f ) * 0.5f : 1f - ExpoIn( 2f - t * 2f ) * 0.5f; }\r\n\r\n\tpublic static float ExtremeIn( float t ) { return MathF.Pow( 10f, 10f * (t - 1f) ); }\r\n\tpublic static float ExtremeOut( float t ) { return 1f - MathF.Pow( 10f, -10f * t ); }\r\n\tpublic static float ExtremeInOut( float t ) { return t < 0.5f ? ExtremeIn( t * 2f ) * 0.5f : 1f - ExtremeIn( 2f - t * 2f ) * 0.5f; }\r\n\r\n\tpublic static float ElasticIn( float t ) { return 1f - ElasticOut( 1f - t ); }\r\n\tpublic static float ElasticOut( float t ) { var p = 0.3f; return MathF.Pow( 2f, -10f * t ) * MathF.Sin( (t - p / 4f) * (2f * (float)Math.PI) / p ) + 1f; }\r\n\tpublic static float ElasticInOut( float t ) { return t < 0.5f ? ElasticIn( t * 2f ) * 0.5f : 1f - ElasticIn( 2f - t * 2f ) * 0.5f; }\r\n\r\n\tpublic static float ElasticSoftIn( float t ) { return 1f - ElasticSoftOut( 1f - t ); }\r\n\tpublic static float ElasticSoftOut( float t ) { var p = 0.5f; return MathF.Pow( 2f, -10f * t ) * MathF.Sin( (t - p / 4f) * (2f * (float)Math.PI) / p ) + 1f; }\r\n\tpublic static float ElasticSoftInOut( float t ) { return t < 0.5f ? ElasticSoftIn( t * 2f ) * 0.5f : 1f - ElasticSoftIn( 2f - t * 2f ) * 0.5f; }\r\n\r\n\tpublic static float BackIn( float t ) { var p = 1f; return t * t * ((p + 1f) * t - p); }\r\n\tpublic static float BackOut( float t ) { var p = 1f; var scaledTime = t / 1f - 1f; return scaledTime * scaledTime * ((p + 1f) * scaledTime + p) + 1f; }\r\n\tpublic static float BackInOut( float t )\r\n\t{\r\n\t\tvar p = 1f;\r\n\t\tvar scaledTime = t * 2f;\r\n\t\tvar scaledTime2 = scaledTime - 2f;\r\n\t\tvar s = p * 1.525f;\r\n\r\n\t\tif ( scaledTime < 1f ) return 0.5f * scaledTime * scaledTime * ((s + 1f) * scaledTime - s);\r\n\t\telse return 0.5f * (scaledTime2 * scaledTime2 * ((s + 1f) * scaledTime2 + s) + 2f);\r\n\t}\r\n\r\n\tpublic static float BounceIn( float t ) { return 1f - BounceOut( 1f - t ); }\r\n\tpublic static float BounceOut( float t )\r\n\t{\r\n\t\tvar scaledTime = t / 1f;\r\n\r\n\t\tif ( scaledTime < 1 / 2.75f )\r\n\t\t{\r\n\t\t\treturn 7.5625f * scaledTime * scaledTime;\r\n\t\t}\r\n\t\telse if ( scaledTime < 2 / 2.75 )\r\n\t\t{\r\n\t\t\tvar scaledTime2 = scaledTime - 1.5f / 2.75f;\r\n\t\t\treturn 7.5625f * scaledTime2 * scaledTime2 + 0.75f;\r\n\t\t}\r\n\t\telse if ( scaledTime < 2.5 / 2.75 )\r\n\t\t{\r\n\t\t\tvar scaledTime2 = scaledTime - 2.25f / 2.75f;\r\n\t\t\treturn 7.5625f * scaledTime2 * scaledTime2 + 0.9375f;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tvar scaledTime2 = scaledTime - 2.625f / 2.75f;\r\n\t\t\treturn 7.5625f * scaledTime2 * scaledTime2 + 0.984375f;\r\n\t\t}\r\n\t}\r\n\tpublic static float BounceInOut( float t )\r\n\t{\r\n\t\tif ( t < 0.5 ) return BounceIn( t * 2f ) * 0.5f;\r\n\t\telse return BounceOut( t * 2f - 1f ) * 0.5f + 0.5f;\r\n\t}\r\n\r\n\tpublic static void Shuffle<T>( this IList<T> list )\r\n\t{\r\n\t\tSystem.Random rng = new System.Random();\r\n\t\tint n = list.Count;\r\n\t\twhile ( n > 1 )\r\n\t\t{\r\n\t\t\tn--;\r\n\t\t\tint k = rng.Next( n + 1 );\r\n\t\t\tT value = list[k];\r\n\t\t\tlist[k] = list[n];\r\n\t\t\tlist[n] = value;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static string FirstCharToUpper( this string input ) =>\r\n\t\tinput switch\r\n\t\t{\r\n\t\t\tnull => throw new ArgumentNullException( nameof( input ) ),\r\n\t\t\t\"\" => throw new ArgumentException( $\"{nameof( input )} cannot be empty\", nameof( input ) ),\r\n\t\t\t_ => string.Concat( input[0].ToString().ToUpper(), input.AsSpan( 1 ) )\r\n\t\t};\r\n\r\n\tpublic static string GetRandomIcon( string i0, string i1 ) { int rand = Game.Random.Int( 0, 1 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2 ) { int rand = Game.Random.Int( 0, 2 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2, string i3 ) { int rand = Game.Random.Int( 0, 3 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4 ) { int rand = Game.Random.Int( 0, 4 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5 ) { int rand = Game.Random.Int( 0, 5 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5, string i6 ) { int rand = Game.Random.Int( 0, 6 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; case 6: return i6; } }\r\n\tpublic static string GetRandomIcon( string i0, string i1, string i2, string i3, string i4, string i5, string i6, string i7 ) { int rand = Game.Random.Int( 0, 7 ); switch ( rand ) { case 0: default: return i0; case 1: return i1; case 2: return i2; case 3: return i3; case 4: return i4; case 5: return i5; case 6: return i6; case 7: return i7; } }\r\n\r\n\r\n\tprivate class NodeInfo<T>\r\n\t{\r\n\t\tprivate const int MaxPoolSize = 8192;\r\n\r\n\t\tprivate static List<NodeInfo<T>> _sPool;\r\n\r\n\t\tinternal static NodeInfo<T> Create( T node, NodeInfo<T> prev = null, float costAdd = 0f )\r\n\t\t{\r\n\t\t\tNodeInfo<T> nodeInfo;\r\n\r\n\t\t\tif ( _sPool == null || _sPool.Count == 0 )\r\n\t\t\t{\r\n\t\t\t\tnodeInfo = new NodeInfo<T>();\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tnodeInfo = _sPool[_sPool.Count - 1];\r\n\t\t\t\t_sPool.RemoveAt( _sPool.Count - 1 );\r\n\t\t\t}\r\n\r\n\t\t\tnodeInfo.Node = node;\r\n\t\t\tnodeInfo.Prev = prev;\r\n\r\n\t\t\tif ( prev == null )\r\n\t\t\t{\r\n\t\t\t\tnodeInfo.Depth = 0;\r\n\t\t\t\tnodeInfo.Cost = 0f;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tnodeInfo.Depth = prev.Depth + 1;\r\n\t\t\t\tnodeInfo.Cost = prev.Cost + costAdd;\r\n\t\t\t}\r\n\r\n\t\t\treturn nodeInfo;\r\n\t\t}\r\n\r\n\t\tinternal static void Pool( NodeInfo<T> nodeInfo )\r\n\t\t{\r\n\t\t\tif ( _sPool == null ) _sPool = new List<NodeInfo<T>>( MaxPoolSize );\r\n\t\t\tif ( _sPool.Count >= MaxPoolSize ) return;\r\n\r\n\t\t\t_sPool.Add( nodeInfo );\r\n\t\t}\r\n\r\n\t\tprivate float _heuristic;\r\n\r\n\t\tpublic T Node { get; private set; }\r\n\t\tpublic NodeInfo<T> Prev { get; private set; }\r\n\t\tpublic int Depth { get; private set; }\r\n\t\tpublic float Cost { get; private set; }\r\n\t\tpublic float Total { get; private set; }\r\n\r\n\t\tpublic float Heuristic\r\n\t\t{\r\n\t\t\tget { return _heuristic; }\r\n\t\t\tset\r\n\t\t\t{\r\n\t\t\t\t_heuristic = value;\r\n\t\t\t\tTotal = Cost + value;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// Convenience method to produce a graph connection for use when calling AStar().\r\n\t/// </summary>\r\n\t/// <typeparam name=\"T\">Graph node type.</typeparam>\r\n\t/// <param name=\"dest\">Destination node of the connection.</param>\r\n\t/// <param name=\"cost\">Cost of taking the connection.</param>\r\n\tpublic static AStarEdge<T> Edge<T>( T dest, float cost )\r\n\t{\r\n\t\treturn new AStarEdge<T>( dest, cost );\r\n\t}\r\n\r\n\tprivate static class AStarWrapper<T>\r\n\t\twhere T : IEquatable<T>\r\n\t{\r\n\t\tpublic static NodeInfo<T> FirstMatchOrDefault( List<NodeInfo<T>> list, T toCompare )\r\n\t\t{\r\n\t\t\tvar count = list.Count;\r\n\r\n\t\t\tfor ( var i = count - 1; i >= 0; --i )\r\n\t\t\t{\r\n\t\t\t\tvar item = list[i];\r\n\t\t\t\tif ( item.Node.Equals( toCompare ) )\r\n\t\t\t\t\treturn item;\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tprivate static List<NodeInfo<T>> _sOpen;\r\n\t\tprivate static List<NodeInfo<T>> _sClosed;\r\n\r\n\t\tpublic static bool AStar( T origin, T target, List<T> destList,\r\n\t\t\tFunc<T, IEnumerable<AStarEdge<T>>> adjFunc, Func<T, T, float> heuristicFunc )\r\n\t\t{\r\n\t\t\tvar open = _sOpen ?? (_sOpen = new List<NodeInfo<T>>());\r\n\t\t\tvar clsd = _sClosed ?? (_sClosed = new List<NodeInfo<T>>());\r\n\r\n\t\t\topen.Clear();\r\n\t\t\tclsd.Clear();\r\n\r\n\t\t\tvar first = NodeInfo<T>.Create( origin );\r\n\t\t\tfirst.Heuristic = heuristicFunc( origin, target );\r\n\r\n\t\t\topen.Add( first );\r\n\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\twhile ( open.Count > 0 )\r\n\t\t\t\t{\r\n\t\t\t\t\tNodeInfo<T> cur = null;\r\n\t\t\t\t\tforeach ( var node in open )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif ( cur == null || node.Total < cur.Total ) cur = node;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( cur.Node.Equals( target ) )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor ( var i = cur.Depth; i >= 0; --i )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdestList.Add( cur.Node );\r\n\t\t\t\t\t\t\tcur = cur.Prev;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdestList.Reverse();\r\n\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\topen.Remove( cur );\r\n\t\t\t\t\tclsd.Add( cur );\r\n\r\n\t\t\t\t\tforeach ( var adj in adjFunc( cur.Node ) )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar node = NodeInfo<T>.Create( adj.Dest, cur, adj.Cost );\r\n\t\t\t\t\t\tvar existing = FirstMatchOrDefault( clsd, adj.Dest );\r\n\r\n\t\t\t\t\t\tif ( existing != null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif ( existing.Cost <= node.Cost ) continue;\r\n\r\n\t\t\t\t\t\t\tclsd.Remove( existing );\r\n\t\t\t\t\t\t\tnode.Heuristic = existing.Heuristic;\r\n\r\n\t\t\t\t\t\t\tNodeInfo<T>.Pool( existing );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\texisting = FirstMatchOrDefault( open, adj.Dest );\r\n\r\n\t\t\t\t\t\tif ( existing != null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif ( existing.Cost <= node.Cost ) continue;\r\n\r\n\t\t\t\t\t\t\topen.Remove( existing );\r\n\t\t\t\t\t\t\tnode.Heuristic = existing.Heuristic;\r\n\r\n\t\t\t\t\t\t\tNodeInfo<T>.Pool( existing );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tnode.Heuristic = heuristicFunc( node.Node, target );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\topen.Add( node );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn false;\r\n\r\n\t\t\t}\r\n\t\t\tfinally\r\n\t\t\t{\r\n\t\t\t\tforeach ( var nodeInfo in open )\r\n\t\t\t\t{\r\n\t\t\t\t\tNodeInfo<T>.Pool( nodeInfo );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tforeach ( var nodeInfo in clsd )\r\n\t\t\t\t{\r\n\t\t\t\t\tNodeInfo<T>.Pool( nodeInfo );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/// <summary>\r\n\t/// An implementation of the AStar path finding algorithm.\r\n\t/// </summary>\r\n\t/// <typeparam name=\"T\">Graph node type.</typeparam>\r\n\t/// <param name=\"origin\">Node to start path finding from.</param>\r\n\t/// <param name=\"target\">The goal node to reach.</param>\r\n\t/// <param name=\"adjFunc\">Function returning the neighbouring connections for a node.</param>\r\n\t/// <param name=\"heuristicFunc\">Function returning the estimated cost of travelling between two nodes.</param>\r\n\t/// <returns>A sequence of nodes representing a path if one is found, otherwise an empty array.</returns>\r\n\tpublic static bool AStar<T>( T origin, T target, List<T> destPath,\r\n\t\tFunc<T, IEnumerable<AStarEdge<T>>> adjFunc, Func<T, T, float> heuristicFunc )\r\n\t\twhere T : IEquatable<T>\r\n\t{\r\n\t\treturn AStarWrapper<T>.AStar( origin, target, destPath, adjFunc, heuristicFunc );\r\n\t}\r\n}\r\n"
},
{
"Ident": "facepunch.memory",
"Path": "cards/CardAnt.cs",
"FileName": "CardAnt.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 398889,
"IsPrivate": false,
"Code": "using Sandbox;\r\nusing System.Threading.Tasks;\r\n\r\npublic class CardAnt : Card\r\n{\r\n\tpublic override bool IsAlive => true;\r\n\r\n\tpublic override bool ShouldHandleEvent( EventType eventType )\r\n\t{\r\n\t\treturn eventType == EventType.TurnStart && Manager.Instance.GetNumNearbyEmptyGridPositions( GridPos, adjacentOnly: false ) > 0;\r\n\t}\r\n\r\n\tpublic override async Task HandleEventAsync( EventType eventType )\r\n\t{\r\n\t\tvar emptyGridPos = Manager.Instance.GetRandomNearbyGridPos( GridPos, empty: true, adjacentOnly: false );\r\n\r\n\t\tawait Task.DelayRealtime( 200 );\r\n\r\n\t\tManager.Instance.PlayCardSfx( \"card_move\", this, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );\r\n\r\n\t\tawait Task.DelayRealtime( 100 );\r\n\r\n\t\tManager.Instance.RemoveCardGridPos( this );\r\n\t\tawait Manager.Instance.SetCardGridPos( this, emptyGridPos );\r\n\r\n\t\tawait Task.DelayRealtime( 300 );\r\n\r\n\t\tawait Manager.Instance.EventHappened( EventType.AfterCardsMoved );\r\n\t}\r\n}\r\n"
}
]
}