TimeStopが解決に入る直前のシナリオスタックは↓のような感じ。

[SP]=5 //スタックポインタ
[SENA_STK] //シナリオスタック
LV, SENA_NM
-----------------------------------
5, ’MTG_SENA_PRIOT’
4, ’MTG_SENA_PH_BGN_UPK’
3, ’MTG_SENA_PH_BGN’
2, ’MTG_SENA_APP_PHASE’
1, ’MTG_SENA_APP_PHASE_LOOP’
------------------------------------

で、5解決に入ってクリンナップしてるとき。

[SP]=7 //スタックポインタ
[SENA_STK] //シナリオスタック
LV, SENA_NM
-----------------------------------
7, ’MTG_SENA_PH_END_CUP’
6, ’MTG_CARD_Time_Stop_Effect0’
5, ’MTG_SENA_PRIOT’
 :
(略)
------------------------------------

「残りのフェイズステップをすっとばして、フェイズ一式を終了させる」とき。

[SP]=6 //スタックポインタ
[SENA_STK] //シナリオスタック
LV, SENA_NM
-----------------------------------
6, ’MTG_CARD_Time_Stop_Effect0’
5, ’MTG_SENA_PRIOT’
4, ’MTG_SENA_PH_BGN_UPK’
3, ’MTG_SENA_PH_BGN’
2, ’MTG_SENA_APP_PHASE’
1, ’MTG_SENA_APP_PHASE_LOOP’
------------------------------------
DBのストアドでなにをしなきゃいけないかというと、
スタックを遡りながら
1.パラメタで示されたシナリオまでのシナリオスタックを全てDELETEする。
2.親シナリオで発生した一時的なスタックやヒープがあれば削除する。

T-SQLのストアドだと多分こんな感じ。
昔一回使ったきりだからよく覚えてないけど・・。
CREATE PROCEDURE MTG_APP_EXIT_TO (@argSNM VARCHAR(32))
AS
BEGIN
  -- 引数のチェック
  DECLARE @plv INT;
  SET @plv = SELECT LV FROM SENA_STK WHERE SNM = @argSNM;
  IF @plv IS NULL
  BEGIN
    RAISERROR(どいつが親じゃゴルア!)
  END;
  -- シナリオスタックのお掃除。
  -- スタックだけなら一挙に削ってしまえるがわざわざループにしてるのは
  -- シナリオごとに「スコープやオーナがそのシナリオである」
  -- スタックとヒープの掃除を正しくしてまわらなくちゃいけないと思ってるから。
  -- たとえばFinal Fortuneは遅延効果を特定のプレイヤーのターン終了時に
  -- 発生させるため、ターン終了時以外のトリガーに加え、"最終(Final)ターン"が
  -- 始まったことを記録するための情報をヒープに確保する。
  -- (DBでそんなところまで実装すべきじゃないが手抜きのためなら何でもする)
  -- シナリオスタックの関係で言えばストーム持ちのカードがデッキに入ってる場合
  --「フェイズ一式300.1」のシナリオを上書きした「ストーム入りフェイズ一式」の
  -- シナリオを作成する。しかしこれは永続的な上書きなので書き換えられちゃ困る。
  -- (ぱっと聞いただけだと意味不明だと思うけど)
  DECLARE @lv INT;
  DECLARE @snm VARCHAR(32);
  DECLARE c CURSOR LOCAL FORWARD_ONLY STATIC FOR
    SELECT LV,SENA_NM
    FROM SENA_STK
    WHERE LV >= @plv
    ORDER BY LV DESC;
  OPEN c;
  FETCH NEXT FROM c INTO @lv, @snm;
  WHILE @@FETCH_STATUS = 0
  BEGIN
    -- シナリオの変数スタックを削除。
    EXEC MTG_DELETE_SENA_HEAP, @snm;
    -- シナリオスタックを削除。
    EXEC MTG_DELETE_SENA_STAK, @snm;
    FETCH NEXT FROM c INTO @lv, @snm;
  END;
  CLOSE c;
  DEALLOCATE c;
END;

考えがまとまるまでもう少しかな・・・。
あちこち省略してるけど、一応6/11のシナリオ言語(手抜き仕様)の雰囲気をつかんでみる。
ついでにシナリオスタックの振る舞いも。

■事例6

こんたはネタのアップキープに時間停止を撃った。

------------------------------
下の1〜6がこんたのTimeStopを説明するのに必要になりそうなシナリオサンプル一式。
TimeStopを解決する瞬間はおおよそ↓のの1〜5のシナリオが入れ子で実行されている。

1.プレイヤのループ
[MTG_SENA_APP_PHASE_LOOP]
EXEC,NULL,"MTG_APP_STAT_SetActivePlayer" //次のプレイヤを得る。
CALL,NULL,"MTG_SENA_APP_PHASE_LOOP" //フェイズ一式のシナリオを呼び出す。
EXIT,"MTG_GET_GAME_END","MTG_APP_START_MATCH" //自己ループさせる。
(おしまい)

2.フェイズ一式(300.1)
[MTG_SENA_APP_PHASE]
 :
CALL,NULL,"MTG_SENA_PH_BGN" //開始フェイズ。
CALL,NULL,"MTG_SENA_PH_MN1"
CALL,NULL,"MTG_SENA_PH_CBT"
CALL,NULL,"MTG_SENA_PH_MN2"
CALL,NULL,"MTG_SENA_PH_END"
 :
(おしまい)

3.開始フェイズ(301)
[MTG_SENA_PH_BGN]
 :
CALL,NULL,"MTG_SENA_PH_BGN_PHA" //302.1
CALL,NULL,"MTG_SENA_PH_BGN_UNT" //302.2
CALL,NULL,"MTG_SENA_PH_BGN_UPK" //303
CALL,NULL,"MTG_SENA_PH_BGN_DRW" //304
 :
(おしまい)

4.アップキープステップ
[MTG_SENA_PH_BGN_UPK] (303)
:
EXEC,NULL,"MTG_APP_EFCT_CHK","(’At beginning upkeep’)" //効果的なパラメタ渡しの方法は考えてないw
CALL,NULL,"MTG_SENA_PH_BGN_UPK_PUSH_STK" //スタックに積むシナリオ
CALL,NULL,"MTG_SENA_PRIORITY" // 優先権シナリオ
(おしまい)

5.優先権シナリオ
[MTG_SENA_PRIORITY]
EXIT,"MTG_GET_PRIORITY_END",NULL //優先権の入れ子直後ならそのまま終了。
 :
 //スタック解決へ。
 :
EXIT,"MTG_GET_PRIORITY_END","MTG_SENA_PRIORITY"
  // スタックが空か両方のプレイヤーがパスするか
  // 状況起因効果と誘発型効果のスタック待ちがなくなるまで自己ループさせる。
(おしまい)

6.時間停止能力(509.1a〜c)
[MTG_CARD_Time_Stop_Effect0]
EXEC,NULL,"MTG_APP_RMV_OBJ" //スタックからオブジェクトを、戦闘から生物を取り除く
EXEC,NULL,"MTG_APP_EFCT_CHK","(’State-Based Effects’)" //※4.に同じ。
EXEC,NULL,"MTG_APP_PH_PH_END" //フェイズの終了処理。まだなんも考えてない。
CALL,NULL,"MTG_SENA_PH_END_CUP" //クリンナップステップを行なう。
EXEC,NULL,"MTG_APP_EXIT_TO’MTG_SENA_PH_BGN’"
//残りのフェイズステップをすっとばして、フェイズ一式を終了させる。"
(おしまい)

------------------------------

お気に入り日記の更新

最新のコメント

この日記について

日記内を検索