1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

STS2MOD開発2 オリジナルカードを作ってみた

1
Posted at
  • これらは2026/8/31現在の情報です

    • 今後のアップデートによって破壊的変更がありえます
      • 実際、先日のpublic beta配布時にbaselibが未対応であり、STS2の起動すらできなくなった
      • 今は解消されており、今回利用させていただく
  • 前回の記事の知識が前提となっている

目次

  • 今回の内容
  • プロジェクト作成
  • 実装
  • ゲーム内で確認
  • まとめ

今回の内容

  • 前回作成したMOD開発環境をそのまま使用
  • Alchyr.Slay the Spire 2 Contentテンプレートから新しいMODを作る
  • シンプルな攻撃カードTestStrikeを1枚追加する
  • 最終的にゲーム内で実際に使用できるところまで確認する

プロジェクト作成

  • Riderを起動し、新しいソリューションを作成する

  • テンプレートからSlay the Spire 2 Contentを選択

    • 新規ソリューションウィンドウの左下
    • 前回の記事で導入したAlchyr.Sts2.Templatesに含まれている
    • 今回はカード追加が目的なのでEmpty ModではなくContentテンプレートを使用する
    • プロジェクト名は今回はMyFirstSts2ContentModとした
      • 既に作成済みでエラーが出ているが気にしないでください

    image.png

  • 作成後、以下のような構成でプロジェクトが生成される

    • MyFirstSts2ContentModCode/Cards
      • カード関連のC#コード
    • MyFirstSts2ContentMod/localization/eng/cards.json
      • カード名や説明文などのローカライズ
    • MyFirstSts2ContentMod/images/card_portraits
      • カード画像
    • etc
  • 今回触るのは主に以下の3箇所

    • Cards
    • localization/eng/cards.json
    • images/card_portraits
  • テンプレートには最初からカード用の基底クラスが用意されている

    • MyFirstSts2ContentModCard.cs
    • 今回作るカードはこのクラスを継承して実装する
      • Cardsフォルダを右クリック
        • 追加 → Custom Card
        • クラス名をTestStrikeとして作成

    image.png

  • TestStrike.csが生成される

  • 生成直後はまだカードの中身が未実装なので、次の「実装」で内容を書いていく

MyFirstSts2ContentModCard.csについて

  • テンプレートの基底クラス
    • これを継承してカードを作成する
  • 重要!!!
    • カードプールの指定をしないと(通常)ゲーム内で利用できない
      • 今回は無色カードにする
    • 16行目, クラス宣言部の上に[Pool(typeof(ColorlessCardPool))] を追記
      • これを継承したクラスは全て無色カードとなる
using BaseLib.Abstracts;
using BaseLib.Extensions;
using BaseLib.Utils;
using MyFirstSts2ContentMod.MyFirstSts2ContentModCode.Extensions;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.Models.CardPools;

namespace MyFirstSts2ContentMod.MyFirstSts2ContentModCode.Cards;

/// <summary>
/// This is the base class for your mod's cards, which is set up to load the card's images from your mod's resources.
/// When creating a card, right click the Cards folder and create a new file with the Custom Card template.
/// This will generate a class that extends this one.
/// You can also just create the class manually; just make sure to inherit from this class.
/// </summary>

[Pool(typeof(ColorlessCardPool))]/// add code, set card pool
public abstract class MyFirstSts2ContentModCard(int cost, CardType type, CardRarity rarity, TargetType target) :
    CustomCardModel(cost, type, rarity, target)
{
    //Image size:
    //Normal art: 1000x760 (Using 500x380 should also work, it will simply be scaled.)
    //Full art: 606x852
    public override string CustomPortraitPath => $"{Id.Entry.RemovePrefix().ToLowerInvariant()}.png".BigCardImagePath();

    //Smaller variants of card images for efficiency:
    //Smaller variant of fullart: 250x350
    //Smaller variant of normalart: 250x190

    //Uses card_portraits/card_name.png as image path. These should be smaller images.
    public override string PortraitPath => $"{Id.Entry.RemovePrefix().ToLowerInvariant()}.png".CardImagePath();
    public override string BetaPortraitPath => $"beta/{Id.Entry.RemovePrefix().ToLowerInvariant()}.png".CardImagePath();
}

カードIDの仕様

  • STS2ではカードごとにIDがあり、Alchyr.baselibでは自動的に生成される
    • ゲーム内でのデバッグや次の実装セクションにも必要な知識なのでここでついでに解説
  • STS2ではカードごとに固有のIDが使われる
    • localization
    • 画像ファイル
    • デバッグ時のカード呼び出し
    • などで参照される
  • Alchyr.BaseLibでは、カードクラスからIDが自動生成される
  • 今回作成したクラス名は以下
public class TestStrike()
  • TestStrikeからカード名部分のIDとしてTEST_STRIKEが生成される
    • PascalCaseから大文字のsnake_caseに変換されるイメージ
TestStrike
↓
TEST_STRIKE
  • さらにMODのprefixが付与され、今回のカードIDは以下になる
MYFIRSTSTS2CONTENTMOD-TEST_STRIKE
  • つまり今回の対応関係は以下
クラス名
TestStrike

↓

カードID
MYFIRSTSTS2CONTENTMOD-TEST_STRIKE
  • このIDは、この後設定するlocalizationや画像ファイル名でも利用される

画像ファイル名との関係

  • 基底クラスには以下の処理が用意されている
public override string PortraitPath =>
    $"{Id.Entry.RemovePrefix().ToLowerInvariant()}.png".CardImagePath();
  • 今回のカードIDからMODのprefixを取り除く
MYFIRSTSTS2CONTENTMOD-TEST_STRIKE
↓
TEST_STRIKE
  • さらに小文字へ変換して.pngを付ける
TEST_STRIKE
↓
test_strike.png
  • したがって、今回使用する通常カード画像のファイル名は以下になる
test_strike.png
  • teststrike.pngではないので注意
    • 実際に筆者も最初これを間違え、テンプレート標準のcard.pngが表示された

実装

コード

  • 作成されたTestStrike.cs に以下のコードを貼り付け
    • いくつか警告が出ますが無視して大丈夫です
using MegaCrit.Sts2.Core.Commands;
using MegaCrit.Sts2.Core.Entities.Cards;
using MegaCrit.Sts2.Core.GameActions.Multiplayer;
using MegaCrit.Sts2.Core.Localization.DynamicVars;
using MegaCrit.Sts2.Core.ValueProps;
using MegaCrit.Sts2.Core.GameActions;
using MyFirstSts2ContentMod.MyFirstSts2ContentModCode.Cards;

namespace MyFirstSts2ContentMod.MyFirstSts2ContentModCode.Cards;

public class TestStrike() : MyFirstSts2ContentModCard(
    1,
    CardType.Attack,
    CardRarity.Basic,
    TargetType.AnyEnemy)
{
    protected override IEnumerable<DynamicVar> CanonicalVars =>
    [
        new DamageVar(7, ValueProp.Move)
    ];

    protected override async Task OnPlay(
        PlayerChoiceContext choiceContext,
        CardPlay play)
    {
        await DamageCmd.Attack(DynamicVars.Damage.BaseValue)
            .FromCard(this, play)
            .Targeting(play.Target)
            .Execute(choiceContext);
    }

    protected override void OnUpgrade()
    {
        DynamicVars.Damage.UpgradeValueBy(3);
    }
}

cards.json

  • 次にカード名と説明文を設定する

  • 編集するファイルは以下

    • MyFirstSts2ContentMod/localization/eng/cards.json
    • 今回は以下の内容を追加する
    {
      "MYFIRSTSTS2CONTENTMOD-TEST_STRIKE.title": "Test Strike",
      "MYFIRSTSTS2CONTENTMOD-TEST_STRIKE.description": "Deal {Damage} damage."
    }
    
    • キーの先頭には先ほど確認したカードIDを使用する
      • MYFIRSTSTS2CONTENTMOD-TEST_STRIKE
    • .title
      • カード名
    • .description
      • カードの説明文
    • {Damage}には、カードクラス側で定義したダメージ値が自動で表示される
new DamageVar(7, ValueProp.Move)
  • 今回は初期値が7なので、ゲーム内では以下のような説明になる
Deal 7 damage.
  • localizationを設定していない場合、Rider上で以下のような警告が表示される
STS001: Localization ... not found
  • cards.jsonを追加すると警告は解消される

画像

  • 次にカード画像を設定する

  • 画像は以下のフォルダに配置する

    • MyFirstSts2ContentMod/images/card_portraits/
  • テンプレート内のコメントでは、通常カード画像の推奨サイズは1000 × 760

    • 500 × 380でも使用可能
      • その場合はゲーム側で拡大表示される
    • Full Art用の画像サイズは606 × 852
  • また、軽量版として以下のサイズも想定されている

    • 通常画像:250 × 190
    • Full Art:250 × 350
  • 今回は動作確認が目的なので、通常カード画像として1000 × 760のPNGを1枚用意する

    • AIに生成させたものを使う

      image.png

  • ファイル名はtest_strike.pngとする

MyFirstSts2ContentMod/
└─ images/
   └─ card_portraits/
      └─ test_strike.png
  • 画像ファイル名はカードIDから自動的に決まる
  • 基底クラスでは以下の処理で画像パスを生成している
public override string PortraitPath =>
    $"{Id.Entry.RemovePrefix().ToLowerInvariant()}.png".CardImagePath();
  • 今回は以下のように変換される
MYFIRSTSTS2CONTENTMOD-TEST_STRIKE
↓
TEST_STRIKE
↓
test_strike.png
  • そのため、teststrike.pngではなくtest_strike.pngにする必要がある

  • ファイル名が一致していない場合、今回の環境ではテンプレートに最初から入っていたcard.pngが表示された

    image.png

公開(publish)

  • Publishでは、ソースコードや画像・localizationなどから以下のようなMOD用ファイルが生成される

    • .dll
      • C#で書いた処理
    • .pck
      • 画像やlocalizationなどのGodot側リソース
    • .json
      • MOD情報
  • プロジェクトトップを右クリック→公開→ローカルフォルダ

    image.png

  • (前回の記事の通りに設定すれば)自動でSTS実行ファイル/mods配下に生成ファイル群が配置される

    • ゲームを起動すれば自動で読み込む
    Slay the Spire 2/
    └─ mods/
       └─ MyFirstSts2ContentMod/
          ├─ MyFirstSts2ContentMod.dll
          ├─ MyFirstSts2ContentMod.pck
          └─ MyFirstSts2ContentMod.json
    
  • 今回は画像やcards.jsonも変更しているため、単なるBuildではなくPublishしておく

ゲーム内で確認

  • コレクション→カードライブラリから今回作成したカードがあることを確認

    image.png

  • shift+8でコンソールを起動

    • help で各種コマンドを見れます
  • 今回はcardコマンドで自作のカードを手札に追加してプレイしてみる

    • card MYFIRSTSTS”CONTENTMOD-TEST_STRIKE hand を実行
      • card cardID option[hand or deck]
      • カードIDが分からない場合、tabの補完で候補を見れます
        • 他のMODのバグるカードを削除したいときなどに便利!
    • 手札に追加できた

    image.png

    • 当然プレイできる

    image.png

    • 7ダメージを与えた

    image.png

まとめ

  • 参考になれば幸いです
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?