API guide
Use the unified GCSApi to start battles, submit player actions, read live state, modify battle state safely, and subscribe to events
Import TinyGiants.GCS.Runtime to start a battle, submit actions, or subscribe to updates through GCSApi.
using TinyGiants.GCS.Runtime;
Check state before calling
Check GCSApi.IsReady before starting a battle. It becomes true when a GameCardManager is present. Check IsBattleActive before offering actions that need an active battle.
if (!GCSApi.IsReady)
{
return;
}
if (!GCSApi.IsBattleActive)
{
GCSApi.StartBattle(encounter);
}
Start a battle
Pass a GameEncounter to StartBattle to replace the current battle and deal the opening hand. GCS raises OnBattleStarted after drawing the opening hand, then resolves enemy Intents.
public GameEncounter Encounter;
public void Begin()
{
GCSApi.StartBattle(Encounter);
}
Subscribe to OnBattleStarted before starting the battle to populate the hand and unit views. Use OnEnemyUnitIntentChanged to refresh the Intent display as each plan is resolved.
private IDisposable _battleStarted;
void OnEnable()
{
_battleStarted = GCSApi.OnBattleStarted(RefreshAll);
}
void OnDisable()
{
_battleStarted?.Dispose();
}
Play a card
Read the hand, test playability, then call TryPlayCard
public void TryPlayFirstCard(UnitState target)
{
foreach (var card in GCSApi.Hand())
{
if (!GCSApi.CanPlayCard(card)) continue;
GCSApi.TryPlayCard(card, target);
return;
}
}
RequiresTarget returns true for Single Enemy, Single Ally, Other Ally, and Any Unit. Open the target picker for these modes. GCS resolves self, group, random, and untargeted cards when you submit them.
var activeCard = GCSApi.GetActiveCard(card);
if (GCSApi.RequiresTarget(activeCard))
{
ShowTargetPicker(card);
}
else
{
GCSApi.TryPlayCard(card);
}
TryPlayCard returns false when there is no active battle, the card is not in hand, energy is insufficient, the card has the Unplayable keyword, or a play Hook cancels the action
End the player turn
public void EndTurnButton()
{
if (GCSApi.Phase == BattlePhase.PlayerPhase)
{
GCSApi.EndPlayerTurn();
}
}
EndPlayerTurn advances to the enemy phase and does nothing outside PlayerPhase, so a stray click on a stale button cannot break the turn order
Read state required by UI
Common UI data has corresponding named query methods
turnLabel.text = GCSApi.TurnNumber.ToString();
energyLabel.text = $"{GCSApi.PlayerEnergy}/{GCSApi.MaxEnergy}";
var player = GCSApi.Player();
hpLabel.text = $"{GCSApi.Hp(player)}/{GCSApi.MaxHp(player)}";
foreach (var enemy in GCSApi.AliveEnemies())
{
RenderEnemy(enemy, GCSApi.CurrentIntentTag(enemy), GCSApi.CurrentIntentValue(enemy));
}
After an event fires, refresh from current API state. A cached copy may already be stale; runtime state is the source that UI should present
Mutate battle state safely
External systems modify state through named GCSApi methods. These calls enter the runtime Controller, so Hooks still run and events are published normally
var player = GCSApi.Player();
GCSApi.GainArmor(player, 5);
GCSApi.DrawCards(1);
GCSApi.ApplyStatus(player, shieldedStatus, 2, player);
Writing to UnitState.CurrentHp, UnitState.Statuses, or pile lists directly skips Hooks and events, so status reactions and UI refreshes do not receive the change. Use GCSApi mutation methods or the Controller
Win and loss are evaluated on phase transitions and after card plays, not on every HP write; dropping an enemy to zero HP through a mutation helper registers at the next check rather than ending the battle on the spot
Subscribe to events
Built-in events provide shortcut subscription methods that return an IDisposable used to release the listener
private readonly List<IDisposable> _subs = new();
void OnEnable()
{
_subs.Add(GCSApi.OnEnergyChanged(_ => RefreshEnergy()));
_subs.Add(GCSApi.OnUnitHpChanged(_ => RefreshUnits()));
_subs.Add(GCSApi.OnCardDrawn(_ => RefreshHand()));
}
void OnDisable()
{
foreach (var sub in _subs) sub.Dispose();
_subs.Clear();
}
Use Subscribe<TArgs> for custom event names or direct access to the event channel
_subs.Add(GCSApi.Subscribe<DamageEventArgs>(
GCSEventNames.OnDamageDealt,
args => LogDamage(args.SourceUnitId, args.TargetUnitId, args.Amount)));
Parameterless events use Subscribe(string, Action); every built-in name is a constant on GCSEventNames, and the payload classes live in GCSEventArgs; custom events raised through RaiseGameEvent deliver their payload as IReadOnlyDictionary<string, object>, so subscribe with that as TArgs
Discover content
GCSApi enumerates the active databases and their entities
foreach (var card in GCSApi.Cards())
{
AddCardToBrowser(card);
}
var poison = GCSApi.FindStatus(poisonGuid);
Enumeration methods build fresh lists and can allocate; cache the result for menus that refresh every frame
Maintain the Master Deck
The Master Deck is the Run-level deck used to create card instances for later battles. StartBattle fills the draw pile from those instances
GCSApi.ClearMasterDeck();
GCSApi.AddCardToMasterDeck(strike);
GCSApi.AddCardToMasterDeck(defend, isUpgraded: true);
GCSApi.StartBattle(encounter);
Changing the Master Deck does not rewrite the piles of a battle that has already started
Save and continue
Call GCSApi.BeginSaveAsync to capture a checkpoint while battle input is locked. Write session.Checkpoint through WriteLocalSaveAsync or your save provider, then dispose the session after committing or leaving the scene.
Use GCSSaveController to wire Save, Save and Quit, or Continue. To drive a custom flow, call RestoreCheckpointAsync and rebuild the view from OnCheckpointRestored. Save and restore covers scene mappings, custom state, and errors.
Extension registries
Tools and debug panels can read the four extension registries through these methods
var nodes = GCSApi.NodeTypes();
var cardTypes = GCSApi.CardTypes();
var tags = GCSApi.CardTags();
var tokens = GCSApi.DescriptionTokens();
The results include custom nodes, card types, tags, and description tokens discovered in every loaded assembly that references TinyGiants.GCS.Runtime. See the API reference for the full signatures and return types.