Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions McpMod.Actions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public static partial class McpMod
{
if (!CombatManager.Instance.IsInProgress)
return Error("Not in combat");
if (!CombatManager.Instance.IsPlayPhase)
if (!IsCombatPlayPhase(player))
return Error("Not in play phase - cannot act during enemy turn");
if (CombatManager.Instance.PlayerActionsDisabled)
return Error("Player actions are currently disabled");
Expand Down Expand Up @@ -140,7 +140,7 @@ public static partial class McpMod
{
if (!CombatManager.Instance.IsInProgress)
return Error("Not in combat");
if (!CombatManager.Instance.IsPlayPhase)
if (!IsCombatPlayPhase(player))
return Error("Not in play phase - cannot act during enemy turn");
if (CombatManager.Instance.PlayerActionsDisabled)
return Error("Player actions are currently disabled (turn may already be ending)");
Expand Down Expand Up @@ -183,7 +183,7 @@ public static partial class McpMod
{
if (!inCombat)
return Error($"Potion '{SafeGetText(() => potion.Title)}' can only be used in combat");
if (!CombatManager.Instance.IsPlayPhase)
if (!IsCombatPlayPhase(player))
return Error("Cannot use potions outside of play phase");
}
else if (potion.Usage == PotionUsage.Automatic)
Expand Down Expand Up @@ -1030,7 +1030,7 @@ public static partial class McpMod
};
}

private static Creature? ResolveTarget(CombatState combatState, string entityId)
private static Creature? ResolveTarget(ICombatState combatState, string entityId)
{
// Try to match by entity_id pattern: "model_entry_N"
// First try matching by combat_id if it's a pure number
Expand Down
25 changes: 25 additions & 0 deletions McpMod.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,39 @@
using System.Text;
using System.Text.Json;
using Godot;
using MegaCrit.Sts2.Core.Combat;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Entities.Players;
using MegaCrit.Sts2.Core.HoverTips;
using MegaCrit.Sts2.Core.Models;

namespace STS2_MCP;

public static partial class McpMod
{
// STS2 v0.104.0 removed CombatManager.IsPlayPhase. Reconstruct the same
// action-safe window from the current combat side and turn-ending flags.
private static bool IsCombatPlayPhase(Player? player = null)
{
try
{
var combatState = CombatManager.Instance.DebugOnlyGetState();
bool playerTurn = player != null
? CombatManager.Instance.IsPartOfPlayerTurn(player)
: combatState?.CurrentSide.ToString().Equals("Player", StringComparison.OrdinalIgnoreCase) == true;

return CombatManager.Instance.IsInProgress
&& playerTurn
&& !CombatManager.Instance.EndingPlayerTurnPhaseOne
&& !CombatManager.Instance.EndingPlayerTurnPhaseTwo
&& !CombatManager.Instance.PlayerActionsDisabled;
}
catch
{
return false;
}
}

private static string? SafeGetCardDescription(CardModel card, PileType pile = PileType.Hand)
{
try { return StripRichTextTags(card.GetDescriptionForPile(pile)).Replace("\n", " "); }
Expand Down
4 changes: 2 additions & 2 deletions McpMod.MultiplayerActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static partial class McpMod
{
if (!CombatManager.Instance.IsInProgress)
return Error("Not in combat");
if (!CombatManager.Instance.IsPlayPhase)
if (!IsCombatPlayPhase(player))
return Error("Not in play phase - cannot act during enemy turn");
if (CombatManager.Instance.PlayerActionsDisabled)
return Error("Player actions are currently disabled");
Expand Down Expand Up @@ -101,7 +101,7 @@ public static partial class McpMod
{
if (!CombatManager.Instance.IsInProgress)
return Error("Not in combat");
if (!CombatManager.Instance.IsPlayPhase)
if (!IsCombatPlayPhase(player))
return Error("Not in play phase - cannot act during enemy turn");
if (CombatManager.Instance.PlayerActionsDisabled)
return Error("Player actions are currently disabled");
Expand Down
2 changes: 1 addition & 1 deletion McpMod.MultiplayerState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public static partial class McpMod

battle["round"] = combatState.RoundNumber;
battle["turn"] = combatState.CurrentSide.ToString().ToLower();
battle["is_play_phase"] = CombatManager.Instance.IsPlayPhase;
battle["is_play_phase"] = IsCombatPlayPhase();
battle["all_players_ready"] = CombatManager.Instance.AllPlayersReadyToEndTurn();

// Enemies
Expand Down
2 changes: 1 addition & 1 deletion McpMod.StateBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ public static partial class McpMod

battle["round"] = combatState.RoundNumber;
battle["turn"] = combatState.CurrentSide.ToString().ToLower();
battle["is_play_phase"] = CombatManager.Instance.IsPlayPhase;
battle["is_play_phase"] = IsCombatPlayPhase();

// Enemies
var enemies = new List<Dictionary<string, object?>>();
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

A mod for [**Slay the Spire 2**](https://store.steampowered.com/app/2868840/Slay_the_Spire_2/) that lets AI agents play the game. Exposes game state and actions via a localhost REST API, with an optional MCP server for Claude Desktop / Claude Code integration.

Singleplayer and multiplayer (co-op) supported. Tested against STS2 `v0.103.2`.
Singleplayer and multiplayer (co-op) supported. Tested against STS2 `v0.103.2` and `v0.104.0`.

> [!warning]
> This mod allows external programs to read and control your game via a localhost API. Use at your own risk with runs you care less about.
Expand Down