仕様合せ: 使用カード選択後の対象選択で上の効果の適用可能者を優先して選択する

Issue #976 new
k4nagatsuki repo owner created an issue

pull request #89

Web(というかTwitter)を見て回っていたところ、たまたま「暴露解除を効果リストの先頭に置くと暴露されたキャラクターが優先して対象に選ばれるがCWPyはそうなっていない」という話題を見かけました。

そこでCardWirth 1.50の挙動を調べたところ、これは体力の減っている者を優先して回復しようとするといった優先行動とは異なるフェイズの処理のようでした。優先行動は、使用優先度の高いカードがあれば必ずそれが自動選択されますが、暴露者に対する暴露解除のようなケースでは他のカードが自動選択される場合があります。

傍証として、体力が減っている者と暴露されている者がいる時に、暴露解除と回復の両方の効果を持つカードを持たせておくと、必ず体力が減っている者が対象として選択されます。

そこで、暴露された者と睡眠状態の者に対して

  1. 暴露解除
  2. 精神正常化

の効果を持つカードと

  1. 精神正常化
  2. 暴露解除

の効果を持つカードを用意して対象選択の結果を見たところ、前者は暴露された者を、後者は睡眠状態の者を必ず対象として選択する事が確認できました。

この結果は、暴露解除や精神正常化よりも上に、両方の対象に対して効果を持たない(行動力±0などの)効果を置いても同じでしたし、暴露→暴露解除や睡眠→精神正常化だけでなく、麻痺→麻痺解除や中毒→中毒解除などでも同じでした。

つまり、使用するカードが決まった後で、以下のような処理が行われているようでした。

  1. 使用カードの選択対象となっているキャラクター群の中から、一番上の効果が適用可能なグループを抽出します。
  2. グループ内のメンバをランダムに選択します。
  3. もし効果が適用可能なキャラクターがいなければ、二番目の効果に対して同じ処理を行い、以降、三番目、四番目……と効果がある限り繰り返します。全ての効果に対して対象がいない場合は、そもそもそのカードが自動選択されないので、この繰り返しは必ずどこかの効果で停止するはずです。

上記の処理を実装してみたところ、CW 1.50と同じように動いているようです。

その後Issueを立ててからマージしようかと思って措いていたところ、それをすっかり忘れてissue #969の作業を行ってしまい、pull request #89に混ぜてマージしてしまいました。とはいえ上手く動いてはいるので問題無いとは思います。

これからChangeLog.txtも更新します。

Comments (21)

  1. Furea A

    はじめまして、CWPyを愛用している者ですが、CWPy5b3ではこれは実装されていますか?

    自作の召喚獣カード

    1. 神聖属性攻撃
    2. 全属性攻撃

    は不浄な存在を優先的に攻撃しませんし、

    1. 全属性眠り
    2. 全属性攻撃

    のカードは眠っていない敵がいるのに、眠っている敵を攻撃しました。よければ教えてください!よろしくお願いします。

  2. k4nagatsuki reporter

    pull request #295

    ありがとうございます。

    確認したところ、このルーチンが召喚獣カードに対して機能していませんでした。修正しました。

  3. tachi gigas

    お疲れ様です。

    気づくの遅くて大変申し訳ございませんが、一点確認をお願いします。この修正で、例えば戦闘中にPCが魔法の鎧を自動選択した時、既に防御力ボーナスを得ているPCが対象から除外されるようになりました(改めて魔法の鎧を選択すれば味方全体が対象になります)が、これは想定された仕様でしょうか。

  4. 暗黒 騎士

    回復の優先対象が複数いて片方が一番上のモーションの有効条件を同時に満たすときはどうなるんだろう? と不安になったので検証しましたが、この場合はおそらく前者しか見ないようです。テストケースを意識不明にしてしまったので、モーション側の有効判定で意識不明だから無効と見なされているだけでした。

    それと検証過程で気づいたのですが、精神状態・暴露・沈黙・魔法無効化状態・能力変化4種は初期状態で意識不明と両立(呪縛のみ消滅)するようです。 課題は思い出せないのですが、召喚獣の件では「CWXEditorで初期状態を操作できるようにしてしまったので合わせる」という判断だった気がしますので、PRさせて頂きました。

    Pull Request #307 度々心苦しいのですが、お手すきの時にでもご確認よろしくお願いします。

  5. k4nagatsuki reporter

    pull request #302

    前に付帯能力で確認されたやつですね。対応していただけて助かりました。ありがとうございます。

    コードを見る限り問題なさそうなので、マージさせていただきます。

  6. 暗黒 騎士

    def _get_targetingbonus_and_targetsについて、現状、先に優先ボーナスを処理し、優先ボーナスがある場合はターゲット絞り込み処理を行わない(bonus == -2147483647ではないので)というフローになっているように見えるのですが、合っていますか?

    上で添付したシナリオの通り、モーションの序列が1.神聖属性ヒール 2.全属性ヒールの場合、不浄な存在が優先選択されているため、たとえば以下のようにbonustargets2を返した方が合致する結果がでます。(回復を選択するヒーラーがCWでは左手順に4人、PyRebootではばらばらに4人以上なのはCWでは内部番号順に選択するカードを決定しているのに対して、Rebootでは行動順を確定して最速順に選択カードを決定しているため)

        # 最大ボーナスを取得
        motions = self._get_motions(header)
        for motion in motions:
            mtype = motion.get("type", "")
            if not self._is_bonusedmtype(mtype):
                continue
            for targ in targets:
                assert isinstance(targ, cw.character.Character)
                b = targ.get_targetingbonus(mtype)
                if bonus == b:
                    maxbonustargs.append(targ)
                elif bonus < b:
                    maxbonustargs = [targ]
                    bonus = b
                if targ.is_effective(header, motion):
                        targets2.append(targ)
           if targets2:
                 return bonus, targets2
                 # if header.allrange else maxbonustargsも必要
    

  7. k4nagatsuki reporter

    pull request #308

    問題は優先選択されたカードの時に効果順の対象選択が機能していない事でよいでしょうか?

    上記のコードだと効果に対して有効なターゲットがいたらボーナスを無視して返してしまっているように見えたので

    1. 最大ボーナスの効果を探す(その際最大ボーナスの効果の対象となる対象のリストを作る)
    2. 最大ボーナスがあれば作ったリストの対象に対して、そうでなければ全対象に対して効果ごとの絞り込みを行う

    という形にしました。これでうまく動けばよいのですが。

  8. 暗黒 騎士

    あ、確かに上記だと複数の異なる体力値をもった意識不明者がいる場合におかしくなりますね。失礼しました。

    添付したシナリオは意識不明のエネミー4体を瀕死に変えただけですが、1.50では(意識不明ではなくなったために)暴露解除が有効になったことでヒーラーは4体~最大で6体全員がヒール(+暴露解除)を選択する場合があります。 一方、CardWirthPy 5.0 Beta 4 (64-bit) Build: 2021-10-30 18:47:32ではヒーラーは4体しかヒールを選択していないようにみえます。

    こちらのフォークにpull request #308を移植してみたところ、先のヒーラーが回復を選んでいることで回復モーションが無効となるはずの5・6番目のヒーラーにも優先ボーナスが載っているようで、6体全員が必ず回復を選択するようになっていました。b = targ.get_targetingbonus(mtype)の前後でもif targ.is_effective(header, motion):することで1.50と同等になった感じです。

    Rebootではこの部分は「一度回復を選んだ場合は選択しにくくなる」という独自仕様で意図的に挙動を変えている部分だったはずなので、どこまでを問題とするかは長月さんがどこまで合わせたいかによるかと思います。

  9. k4nagatsuki reporter

    一度回復を選んだ場合は選択しにくくなる

    これはCWの方がそうなっていたと思うんですが(優先選択で回復の対象に選ばれたキャラクターは次以降に行動するキャラクターから回復の対象にされなくなる)、暴露解除効果がそれを無効化している感じですかね?

  10. 暗黒 騎士

    無効化というか、自分のフォークの方ではモーションの有効判定で

        def is_effective
    ~~~~~~~~~~
            if mtype == "Heal":
                # すでに回復ターゲットになっている場合
                if beast:#召喚獣は別のリストを持つ
                    selected = cw.cwpy.battle.heal_selectedlist_beast
                else:
                    selected = cw.cwpy.battle.heal_selectedlist
                for target in selected:
                    if isinstance(target, cw.character.Character):
                        if target == self:
                            return False
                    elif self in target:
                        return False
    

    という実装にしています。つまり、リストに入ったキャラがターゲットの場合はモーションは無効であると返ってきていると予想しています。

    上記シナリオでヒーラーが所持している回復カードは1.神聖属性の暴露解除 2.神聖属性のヒール 3.全属性のヒールモーションが付いています。5~6番目のヒーラーの自動選択ではヒールモーションが無効として返ってきてるので、「普通の選択率で選択される暴露解除カード」という扱いになっている、という感じです。

  11. 暗黒 騎士

    https://w.atwiki.jp/pylite/pages/14.html#id_7481994c 自分が認識しているCW1.28以降の挙動です。

    Rebootでは上記の通り、先に行動順を決めてからその順で戦闘行動の自動選択を行っており、「回復選択済みリスト」は実装しているのですが、「絶対に回復を選択しなくなるのはおかしい」というのが当時の長月さんの判断で優先値を下げるという独自仕様になっています。陣営についても指摘しましたが「実際そこまで戦術を詰めたシナリオが出たら対応を考えます」ということでした。

    この結果、他エンジン比較で以下の仕様差が生じています。

    • Rebootでは、たとえば最速行動者が双方全体の回復モーション付きアイテムカードを持っている場合、確実にそちらに優先度が持って行かれ、敵も味方も回復行動を取れなくなる/取りにくくなる(添付シナリオ3)
    • 召喚獣は有効なら絶対に発動するので負傷者が一人存在すると同一陣営内で召喚されているウンディーネがRebootに限って全て重複して発動してしまう

    添付シナリオでは敏捷大胆19の全体ヒールを持つヒーラーを一体追加しています。挙動を1.50とRebootで見比べて頂ければ、戦術を詰めるとか以前の問題とご理解頂けるかと思います。

  12. k4nagatsuki reporter

    挙動を見る限りCW 1.50では行動順が無視されて並び順で自動選択が行われているように見えますが、そういう話ではないのでしょうか?

    1.50では最速ヒーラーをエネミーリストのいちばん上に持ってくると他のヒーラーは回復を行わなくなります(暴露解除は行おうとする)。

  13. k4nagatsuki reporter

    話を理解できているとは言いがたいですが(最近ようやく分かりましたが、私は情報やコードを断片で示されると混乱するタイプのようです)、優先度を計算する時に優先度計算対象外の効果は優先度0として計算する事と、行動順ではなく並び順に行動を選択する事は対応しました。

  14. 暗黒 騎士

    挙動を見る限りCW 1.50では行動順が無視されて並び順で自動選択が行われているように見えますが、そういう話ではないのでしょうか?

    うーん? よくわかりません、そういう話でもあります。Rebootでは「行動順がなぜか考慮されている」「回復リストの陣営が区別されていない」「ターゲットが回復リストに入っていても低い優先度で有効判定が返ってくる」この三つが影響しているということです。
    長月さんはCWPYコードの全容を当然把握されているはずなので、その方が話が早い(多少不備があってもニュアンスは掴んでいただけるであろう)かと思ってやっていたのですが、混乱させてしまったようであればすいません。以後しないようにします。

    簡潔に言えば「これらの独自仕様は長月さん側に考えがあってそうしているのか」と確認していたのですが、少なくとも行動順を考慮していた点については修正されたということは違うようですね。

  15. k4nagatsuki reporter

    少なくとも現時点で私が把握している仕様の違いは「誰かに回復されそうな対象が絶対に回復対象として選ばれない」という部分だけです。

    他の二つは問題自体覚えがないのですが、他の話と同時に出されて目が滑ったか(これもよくある)、記憶が抜けているだけかもしれません。

  16. 暗黒 騎士

    https://bitbucket.org/k4nagatsuki/cardwirthpy-reboot/issues/20/-------------#comment-56602582

    陣営についてはこれです。影響についてはたとえば「ネルカ城砦跡」のような同行NPCを使った全体回復系フィールドギミックを誤作動させる可能性があります。ただしこのシナリオは敏捷度15のNPCの付帯能力で表現しているので並び順になったのであれば(処理系的に味方→敵→NPCとなるはずなので)おそらく正常に動作します。アイテムで表現した場合は依然として影響が出るでしょう。

  17. k4nagatsuki reporter

    なるほど仕様が妙なので対応する必要性を感じないなどと言っていますね。記憶から抜けていました。申し訳ありません。

    実際に問題になるシナリオが出るか、Pull Requestを出していただければ対応します。

  18. 暗黒 騎士

    実際に問題になるシナリオは「敵が回復手段を持つシナリオ」ほぼ全てです。
    正直バトル系シナリオ作者に取ってはかなり重大な問題と捉えていて長年心残りだった(現在のご時世で1.50用シナリオを公開している作者はPyRebootを事実上無視できない)ため、解決できるのであればかなり嬉しいです。のちほどPRさせていただきます。

  19. Log in to comment