アットウィキロゴ
(ダウンロードリンクをトップに移動しました。)

  • 20170411版(主人公のジョブ選択システム実装)

  • 20170401_2版(海水浴にイベント追加(現在3つ))

  • 20170326版(海水浴に悲しいエピソード追加)

  • 20170324版(バグ修正。野外活動できます)

  • 20170319_3版(全然嬉しくないオリジナル画像付き(野外活動開きません))

  • 20170319版(好感度チェックシステム実装(野外活動開きません))




  • 20170225版(ミニゲーム統合、アルバイト本屋ルート作りかけ)

  • 20170219版(ミニゲーム作成中(一応クリアできなくもない))



  • 20170212版(一通りプレイできる。ただしラストは一部キャラ分のみ。)

  • 20170211版(野外授業のシナリオを直してみた。ただし、次のシナリオは直してないので、死傷者が出ると変な挙動をする。)

  • 20170204_2版(人数を増やしてみた。ただし、放課後の教室まで(当然、これまでとの互換性なし。))

  • 20170204版(アルバイトシナリオにマップ差し替え実装)



  • 20170124版(アルバイトシナリオ実装、ただし今のところ皿洗いだけ)

  • 20170122_2版(お買い物イベント実装、ただし第3章さらルートのみ)

  • 20170122版(ヒロイン管理システム実装版、実際の操作はほとんど変更なし)


  • 20170114版(好感度システム実装)(前のバージョンとのセーブデータ互換性ないと思う。)





2017.04.11

ゲームの始めに主人公のユニットを選べるようにした。
お仕着せだけではなく、ユニット名を直接入力することができる自由度の高さ!
ということは、主人公をアンデッドにしてももんと名付けることも可能ですし、百合百合(あるいは男の娘)、フレンズ的楽しみ方もできるかもしれません。

(補足)
やったことは次のような比較的簡単なこと
       [message]
           speaker=narrator
           image="wesnoth-icon.png"
           message= _ "主人公のユニットを決めよう。次から選んでもいいし、ユニット名を直接入力してもいいぞ。"
 #1つ目のオプション(実質何もしない)
           [option]
               message= _ "エルフの戦士(デフォルト)"
           [/option]
 #2つ目のオプション
           [option]
               message= _ "悪漢"
               [command]
                   [set_variable]
                       name=unit_of_hero
                       value=Ruffian
                   [/set_variable]
               [/command]
           [/option]
 #3つ目のオプション(直接入力)
           [option]
               message= _ "直接入力する(『OK』を押して次へ)。"
               [command]
                   [message]
                       speaker=narrator
                       image="wesnoth-icon.png"
                       message= _ "ユニット名を英語で正しく入力してください。"
                      [text_input]
                          variable=unit_of_hero
                      [/text_input]
                   [/message]
               [/command]
           [/option]
       [/message]
 #変数 unit_of_hero に代入されたユニットに変化させる
       {TRANSFORM_UNIT (id=hero) ($unit_of_hero)}        
なお、「Elvish Shaman」と直接入力するとエルフの呪術師になるが、「femele^Mage」などとやっても女魔術師になったりはしない。


海水浴のイベントもちょこちょこ書いている最中。


2017.04.01

何やら最近、(非公式)ファンサイトのキャンペーン作成関係の記事が急激に充実している。敷居が下がるのはよいことだ。
これを機に、泥沼に足を踏み入れる人が増えることを期待している。泥沼といってもトカゲは出てこないが。

それはさておき、海水浴でのイベントの選択肢を増やしてみた。ただし、れべっかの水着姿とかは出てこない。期待する人はいないだろうが念のため。
あと、ありすルートも作る予定。


2017.03.26

海水浴で誰得?なエピソードを追加した。

一応、海水浴ではいくつかのイベントを用意して、どれが発生するかでその後の展開が微妙に変わるようにする構想がなくもない。
それがいつになるかはわからない。

ユニットのタイプを変えるのに TRANSFORM_UNIT というのを使うと簡単にできる。
Girl=unDead の「聖堂」のシナリオを書いた時には、知らなかったので、エルフのドルイドやシェードを步く死体に変えるのに苦労した。
使用例
       {TRANSFORM_UNIT (type=Elvish Druid)  (Walking Corpse)}        
       {TRANSFORM_UNIT (id=Meg)  (Walking Corpse)}        

2017.03.24

2ちゃんねるの wesnoth スレで野外活動がエラーでプレイできないとの書き込みがあった。
シナリオを見直してみたら、修正するときに変えてはいけないところまで書き換えていたことが判明した。
なお、海水浴イベントを発生させるにはは、野外活動で変に頑張らない方がよいです。




2017.03.19その2

下手を承知で、このキャンペーンのためのオリジナル画像を作成した。
別に必要性はないのだが、作成のモチベーション維持のために、ぜひ必要だったのだ。(笑)


それにしても、このゲームの世界観に全くそぐわない絵だなあ。

他にも追加したい絵があるので、本編の方の進行は停滞するかも。



2017.03.19

朝のあいさつで女子の好感度の大体の上がり具合がわかるシステムを実装した。
条件文が入れ子になっていて、少しややこしくなっているけど、要は、好感度の高さで反応が変わるようにしてあるだけ。
(なお、wesnoth 1.13 以降は、[elseif] が使えるようになるらしいので、そうなったらもう少しスッキリできると思う。)

好感度チェックマクロ
#define GREETING HEROINE MESSAGE_1 MESSAGE_2
    [if]
        [variable]
            name=favor_{HEROINE}
            greater_than=9
        [/variable]
        [then]
            [message]
                speaker={HEROINE}
                message={MESSAGE_1}
            [/message]
            [message]
                speaker=hero
                message= _ "ああ、おはよう。$full_name_{HEROINE}。"
            [/message]
        [/then]
        [else]
            [if]
                [variable]
                    name=favor_{HEROINE}
                    greater_than=0
                [/variable]
                [then]
                    [message]
                        speaker=hero
                        message= _ "おはよう、$full_name_{HEROINE}。"
                    [/message]
                    [message]
                        speaker={HEROINE}
                        message= {MESSAGE_2}
                    [/message]
                [/then]
                [else]
                    [if]
                        [variable]
                            name=favor_{HEROINE}
                            greater_than=-10
                        [/variable]
                        [then]
                            [message]
                                speaker=hero
                                message= _ "おはよう、$full_name_{HEROINE}。"
                            [/message]
                            [message]
                                speaker={HEROINE}
                                message= _ "フン。"
                            [/message]
                        [/then]
                        [else]
                            [message]
                                speaker=hero
                                message= _ "おはよう、$full_name_{HEROINE}。"
                            [/message]
                            [message]
                                speaker={HEROINE}
                                message= _ "・・・・"
                            [/message]
                            [message]
                                speaker=hero
                                message= _ "{HEROINE}ったら、あいさつもしてくれないなんて。"
                            [/message]
                        [/else]
                    [/if]
                [/else]
            [/if]
        [/else]
    [/if]
#enddef

実質同居と同じめぐとも学校であいさつしていたりとか、個別の修正は必要だけど。


2017.03.15

主人公が放課後の行動を選ぶときに、一度選んだ行動は非表示にしたいことがある。
そのような場合には、[option] 内で [show_if] を使うとよい。

例えば、さらとデートする前は変数「flag_afterschool_Sara」が0で、デート済みだと1になるようにしてあるような場合
よい例(大事なのは、どこでどういう風に [show_if] を使っているかだけなので、[command] の中身とかは飛ばしてください。)
       [message]
           speaker=narrator
           image="wesnoth-icon.png"
           message= _ "さあ、どうしよう?(試作品の都合で、放課後以外の選択肢もあります。)"
           [option]
               message= _ "さらに町を案内してもらおう。"
               [show_if]
                   [variable]
                       name=flag_afterschool_Sara
                       equals=0
                   [/variable]
               [/show_if]
               [command]
                   [set_variable]
                       name=1st_day_after_school
                       value=1st_day_Sara
                   [/set_variable]
                   [set_variable]
                       name=flag_afterschool_Sara
                       add=1
                   [/set_variable]
               [/command]
           [/option]
   [/message]
とやるのがよいようである。
[show_if] の間に挟むのは、[if] と同じように考えていいようである。

これがわかるまでは、どうやってもうまくいかなくて困った。
悪い例(普通に [if] を使ったが、期待通りに動かなかった。)
       [message]
           speaker=narrator
           image="wesnoth-icon.png"
           message= _ "さあ、どうしよう?(試作品の都合で、放課後以外の選択肢もあります。)"
           [if]
               [variable]
                   name=flag_afterschool_game_center
                   equals=0
               [/variable]
               [then]
                   [option]
                       message= _ "久しぶりにゲームセンターもいいな。"
                       [command]
                           [set_variable]
                               name=1st_day_after_school
                               value=game_center
                           [/set_variable]
                           [set_variable]
                               name=flag_afterschool_game_center
                               value=1
                           [/set_variable]
                       [/command]
                   [/option]
               [/then]
           [/if]
   [/message]


2017.03.08

いまだに変数の使い方でハマることが多い。今回もユニットの性別により、そのあとの展開が変わるようにしたかったのだが、上手くいかない。
上手くいかなかった記述
    [if]
        [variable]
            name=$unit.gender
            equals="female"
        [/variable]
        [then]
            (ユニットが女だった時の展開)
        [/then]
        [else]
            (ユニットが男だった時の展開)
        [/else]
    [/if]

よく考えてみたら、name=$unit.gender の「$」が余計だった。
$ がついていると、unit.gender が解釈されて、name=female あるいは、name=male ということになってしまう。

正しい記述
    [if]
        [variable]
            name=unit.gender
            equals="female"
        [/variable]
        [then]
            (ユニットが女だった時の展開)
        [/then]
        [else]
            (ユニットが男だった時の展開)
        [/else]
    [/if]



2017.03.05(続き)

野外授業で負傷者が出た時の後で、りさがクラスに復帰できない不具合を修正した。



2017.03.05

定番(?)の海水浴イベントを作成。例によって尻切れとんぼ。
と言うか、このキャンペーンで水着回をやる意味がわからない。

心の赴くままにシナリオを増やしているが、後で整合性を取るのに苦労しそうな予感がする。まあ、最初から場当たり的に作っているから。


2017.02.26

本屋のバイト一応完成。伏線らしきものを敷きながら、回収の見込みなし。
放課後の過ごし方にめぐルートを実装した。食いしん坊萌えの方はどうぞ。


2017.02.25

ミニゲームをキャンペーン本体に統合。
なぜか、一部挙動がおかしくなったので、修正したが、原因が不明のままなので何か気持ち悪い。

アルバイトシナリオの本屋ルートを作り始めた。



2017.02.22

ミニゲームが一応完成。
これをキャンペーン本編に組み込む予定。
なお、だいぶ易しめに作ってあるので、プレイ中に退屈になったら、さっさと敵にやられるのがオススメ。


シナリオ作成中に「Troll」を別の言葉に一括置換したら、キャンペーンを始めた途端にゲームオーバーになって焦った。
原因は、side の定義中の「controller」まで置換されてしまっているためと判明。
一括置換に関する不具合は、短い言葉だとよく発生するけど、まさか Troll でも発生するとは思わなかった。


2017.02.21

ゲームセンターシナリオがほぼゲームひとつ作ることと同じであることに気づいてしまったので、いったん独立したキャンペーン(といってもシナリオはひとつだけだけど)として作成中。
なんとなく、それっぽいものになりつつある。
もっとも、あくまでキャンペーンの中のミニゲームなので、それほど作り込むつもりはない(だんだん難易度が上がっていくとか)。



2017.02.19

ゲームセンターシナリオで一応クリアできるところまで作った。
作っていて気づいたのだが、今回のは、1シナリオを書くというより、ゲームひとつ作るのと同じだった(しかも、キャンペーン本編とはほとんど関係ない。)。
色々細かいところを考えていくと、まだまだやるべきところがたくさんある。


2017.02.18

当初実装していなかったてっぺいたちとゲームセンターに行くイベントを作成中。
見た目だけ何かに似ているゲームを楽しめますが、現在クリア不能です。


2017.02.12(続き)

ラストの放課後の教室での告白を全女性キャラ分を作成した。
めぐルートとか切なくなるかも。りさルートもなかなか。


2017.02.12

野外授業で死傷者が出た時の後日のシナリオが全員に対応するように修正した。
男女でだいぶ扱いに差があるが、これでまた一通りプレイできるようになったはず。

ネイティヴでない悲しさで、hero を hiro としてしまったり、variable を valiable としてしまうような綴りミスをしょっちゅうしてしまって、余計な手間がかかってしまって困る。



2017.02.11

調子に乗って登場人物増やしたら、野外授業のシナリオでクラスを2グループに分けるのがものすごく大変になってしまった。
とにかく条件文と変数を使いまくってなんとかしたが、えらく込み入ったものになってしまった。

変数の使い方の基本

例えば、チームAとチームBがあって
[if]
    <めぐがチームAのとき>
    [then]
        [set_variable]
            name=teamA
            value=1
        [/set_variable]
    [/then]
[/if]
[if]
    <さらがチームAのとき>
    [then]
        [set_variable]
            name=teamA
            add=1
        [/set_variable]
    [/then]
[/if]
と変数を設定し、次のような条件文でありすを振り分けようとしたとします。
[switch]
    variable=teamA
    [case]
        value=0
        <ありすはチームAに行く>
    [/case]
    [case]
        value=1
        <ありすは半々の確率でチームAかチームBに行く>
    [/case]
    [else]
        <ありすはチームBに行く>
    [/else]
[/switch]
これはうまく行きません。
なぜかというと、[switch]文の最初の value=0 成立しないからです。
具体的には、めぐもさらもBチームのときには、「teamA」なる変数そのものが存在しないので、「teamA」の値が0という状態も存在しません。

というわけで、
(最初に「teamA」という変数を宣言)
[set_variable]
    name=teamA
    value=0
[/set_variable]

[if]
    <めぐがチームAのとき>
    [then]
        [set_variable]
            name=teamA
            add=1
        [/set_variable]
    [/then]
[/if]
[if]
    <さらがチームAのとき>
    [then]
        [set_variable]
            name=teamA
            add=1
        [/set_variable]
    [/then]
[/if]

[switch]
    variable=teamA
    [case]
        value=0
        <ありすはチームAに行く>
    [/case]
    [case]
        value=1
        <ありすは半々の確率でチームAかチームBに行く>
    [/case]
    [else]
        <ありすはチームBに行く>
    [/else]
[/switch]
と書くとうまく行きます。たぶん。



2017.02.05

独自ユニットの追加(と言ってもほぼ既存ユニットの移植)を行った。
気をつけるのは、次の3点
  1. _main.cfg の #ifdef CAMPAIGN_WESNOTH_GAKUEN 内に {binary_path]を明示しないとユニット画像が表示されないらしい。
  2. 同じく #ifdef CAMPAIGN_WESNOTH_GAKUEN 内に [+units] でユニットの定義をしているファイルへのパスを追加する。
  3. 既存のユニット定義を少し変えるだけで、ユニットの「説明文」に変更を加えない場合は、定義ファイルの最初の行の textdomain を変える必要はない。(Girl_unDead のときには、textdomain を変えてしまったため、ユニットの説明が全部英語で表示されてしまっている。)
_main.cfg 設定例
#ifdef CAMPAIGN_WESNOTH_GAKUEN
    [binary_path]
        path=data/add-ons/Wesnoth_GAKUEN    
    [/binary_path]
    {~add-ons/Wesnoth_GAKUEN/utils}
    [+units]
        {~add-ons/Wesnoth_GAKUEN/units}
    [/units]
    {~add-ons/Wesnoth_GAKUEN/scenarios}
#endif

今回は、とりあえずやってみただけなので、ゲーム本体の添付はなし。


2017.02.04(続き)

あらたに妹系キャラを実装し、一層非モテの妄想に近づいた。
やはり、登場人物を増やすと、いろいろなところに影響があり、面倒さが格段に増す感じ。
さらに、もう一人は増やす予定。

ユニットを移動させるときに、素直に道の上を歩かずに、オバQのように他人の家に不法侵入して進んでしまうことがある。
そのようなことを防止するには、通過させたいポイントを次のように順番に書いてゆくとよい。
    [move_unit]
        id=hero
        to_x=4,7,6,12,19,19
        to_y=3,6,7,10,7,6
    [/move_unit]
当然ながら、xとyの数が違っているとエラーになってしまうので注意。


2017.02.04

アルバイトシナリオで、店内に入るとマップが変わるようにした。
[replace_map] を使用。
なお、元のマップと大きさが変わる場合には、expand=yes、shrink=yes にしておくのがよいみたい。
    [replace_map]
        map="{~add-ons/Wesnoth_GAKUEN/maps/restaurant.map}"
        expand=yes
        shrink=yes
    [/replace_map]



2017.01.22(続き)

野外授業で味方キャラが死んでしまったときのイベントを作成した。
大怪我をして、数日休んだということして、次のシナリオで復活する。

ゲームの仕掛けとして作ろうと思っていたものは、一応大体出来たので、今後は、ストーリーの充実やら、登場人物のキャラ付け(どこかで見たようなツンデレとか、どこかで見たような寡黙系とか、どこかで見たようなポンコツ系とか)やら、似たようなコードのマクロ化を進めていくことになると思う。
ただ、分岐が増えていくと、辻褄合わせが格段に面倒になっていくのが目に見えているので、ほどほどにしておこう。(黙々と人類の歴史の可能性をたどっているかがりちゃんは、実はゲームクリエイターの心理状態の反映なのではないかと思う。)


2017.01.29

野外授業シナリオを作ってみた。
今回の課題は
  1. ユニットをランダムに2グループに分けること
  2. 他のユニットが主人公について動くこと
の2点。

グループ分け

今回は3人ずつ2グループに分けるのだが、ゲームの特性上主人公グループに女子2人つけるので、逆にいえば女子を1人だけ別のグループに入れればいいだけなので、ランダムに女子1名を別グループ側に移動させるようにした。
    [set_variable]
        name=team_mate
        rand=Sara,Alice,Rebecca
    [/set_variable]
    [move_unit]
        id=$team_mate
        to_x=3
        to_y=9
    [/move_unit]

次に元の位置いるだけのユニットを主人公側に移動。
    [if]
        [have_unit]
            x,y=1,7
        [/have_unit]
        [then]
            [move_unit]
                id=Sara
                to_x=4
                to_y=5
            [/move_unit]
        [/then]
    [/if]
    [if]
        [have_unit]
            x,y=1,8
        [/have_unit]
        [then]
            [move_unit]
                id=Alice
                to_x=4
                to_y=6
            [/move_unit]
        [/then]
    [/if]
    [if]
        [have_unit]
            x,y=1,9
        [/have_unit]
        [then]
            [move_unit]
                id=Rebecca
                to_x=3
                to_y=5
            [/move_unit]            
        [/then]
    [/if]

追っかけシステム

偶数ターンごとに主人公の隣に
  1. 味方キャラ移動
  2. 敵キャラ登場
の順にイベントが発生するようにした。
(順番を間違えると味方の動きが不自然になる。)
見てみればわかるように、主人公のヘクスの真上に移動、登場するようになっているが、デフォルトでは、移動予定、登場予定のヘクスに既に別のユニットがいると近隣の別のヘクス移動、登場するようになっているので、主人公が消されることはない。
   [event]
       name=turn 6
       {STORE_UNIT	hero}
       [move_unit]
           id=Sara
           to_x=$hero_store.x
           to_y=$hero_store.y
       [/move_unit]
       [move_unit]
           id=Alice
           to_x=$hero_store.x
           to_y=$hero_store.y
       [/move_unit]
       [move_unit]
           id=Rebecca
           to_x=$hero_store.x
           to_y=$hero_store.y
       [/move_unit]
       {NAMED_UNIT 3 (Giant Rat) $hero_store.x $hero_store.y () () ()}
   [/event]
(味方キャラの動きが3人分書いてあるが、このうち1人は [kill] されている。)

味方キャラが殺されてしまったときの対策とか、シナリオ開始場面でユニットが話者の陰に隠れてしまうなどの不具合が残っている。


2017.01.24

アルバイトシナリオを作成。ただし、選べるバイトはまだひとつだけ。

お買い物イベントで、所持金がマイナスになっても際限なく買い物ができることが発覚。このままでは主人公が多重債務者になってしまうので、所持金以上に買い物ができないように修正した。
    [store_side]
        side=1
        variable=side_hero
    [/store_side]
    [if]
        [variable]    # <- ここで所持金判定
            name=side_hero.gold
            less_than=50
        [/variable]
        [then]
            [message]
                speaker=hero
                message= _ "いけね。小遣いが足りないや。"
            [/message]
        [/then]
        [else]
            [set_variable]
                name=side_hero.gold
                sub=50
            [/set_variable]
            [modify_side]
                side=1
                gold=$side_hero.gold
            [/modify_side]
            [message]
                speaker=narrator
                image="wesnoth-icon.png"
                message= _ "お買い物をして、所持金が $side_hero.gold ゴールドになった。"
            [/message]
            [clear_variable]
                name=side_hero
            [/clear_variable]
        [/else]
    [/if]



2017.01.23

お買い物イベントについて、本家の WML リファレンスページを見たら、そのまんま [gold] でお金を増やしたり減らしたりできることがわかった。
よって、昨日のコードは
    [gold]    <- 特にしていしなければ、side 1 のゴールド
        amount=-50
    [/gold]
    [store_side]
        side=1
        variable=side_hero
    [/store_side]
    [message]
        speaker=narrator
        image="wesnoth-icon.png"
        message= _ "所持金が $side_hero.gold ゴールドになった。"
    [/message]
    [clear_variable]
        name=side_hero
    [/clear_variable]
でもいける。


2017.01.22その2

お買い物イベントを追加してみた。
簡単に言えば、主人公サイドのゴールドを減らすだけ。
    [store_side]    <- まずはサイドの情報を一時保存
        side=1
        variable=side_hero
    [/store_side]
    [set_variable]    <- サイドのゴールドを50減らす
        name=side_hero.gold
        sub=50
    [/set_variable]
    [modify_side]    <- 減らしたあとのゴールドを適用
        side=1
        gold=$side_hero.gold
    [/modify_side]
    [message]
        speaker=narrator
        image="wesnoth-icon.png"
        message= _ "所持金が $side_hero.gold ゴールドになった。"
    [/message]
    [clear_variable]    <- 一時保存した情報を消去
        name=side_hero
    [/clear_variable]

あと、キャリーオーバーとか、ボーナスなどがないように [endlevel] を修正などなど。
村を占領した時も収入増えないようにするのはこれから。


2017.01.22

登場人物の管理を用意にするためのシステムをを作ってみた。
なぜ作ったかというと、今後登場人物を増やしたり、「好感度」以外のパラメーターを実装することになったとき楽をするため。

基本的には [set_valiables] を使っているのだが、これだと次の点で使いづらい。

  • 登場人物を数字で管理しなければならない。
実際にこうなっているわけではないが、たとえば
$heroines[0].full_name -> ありす
$hiroines_Alice.name -> ありす
では、後者の方が人間にとってはわかりやすい。
(その昔、某自動車メーカーで記号みたいな名前の車を乱発したら、ディーラーでさえ車名が混乱して、業績が悪化したというまことしやかな話もある。)

  • 途中で登場人物を追加したりすると、最初の順番がばらばらになってしまう。
はじめは、
$heroines[0].full_name -> ありす
だったのが、途中から
$heroines[0].full_name -> れべっか
になったりしたら、もうわけわからない。

で、実装

まず、マクロ
#define HEROINES NAME FULL_NAME
   [set_variables]
       name=heroines
       mode=insert   <- これ大事。「insert」にしないと、先にセットした heroines 変数がすべて消えてしまう。
       [value]
           name={NAME}
           full_name=_ "{FULL_NAME}"
           favor=0
       [/value]
   [/set_variables]
   [set_variable]    <- 好感度システム等で(数字ではなく)IDで指定できるようにしてる。
       name=ID_{NAME}
       value={NAME}
   [/set_variable]
   [set_variable]    <- メッセージ内で名前を表示できるようにしてる。
       name=full_name_{NAME}
       value=_ "{FULL_NAME}"
   [/set_variable]
   [set_variable]    <- 好感度を0にセット。
       name=favor_{NAME}
       value=0
   [/set_variable]
#enddef

最初のシナリオでは
       {HEROINES Sara (さら)}
       {HEROINES Alice (ありす)}
       {HEROINES Rebecca (れべっか)}

       {NAMED_GENERIC_UNIT 2 "Elvish Shaman" 7 8 ($ID_Sara) ($full_name_Sara)}
       {NAMED_UNIT 2 "Mage" 13 8 ($ID_Alice) ($full_name_Alice) gender=female}
       {NAMED_UNIT 2 "Thief" 13 5 ($ID_Rebecca) ($full_name_Rebecca) gender=female}
前半でキャラを登録、後半でユニット作成。


2017.01.14(続き)

一応、エンディングを作成した。
一応、相手により会話内容が変わってきます。

今後は、プレゼントを購入(主人公のゴールドが減る。)、3人以上のイベント、ランダムで相手が変わるイベントとかも実装してみたい。

作ってみてわかったことは、ゲームの性格上、やたら変数と条件文を多用するということ。
特に登場人物が増えると幾何級数的に条件の入れ子が激しくなる。
(そんなわけで、今回は手抜きした。)

やはりWMLは、この手のゲームは(作れなくはないけど)あまり向いてはいないように思う。
まあ、3つ以上の値の比較ができるマクロなどを作っていけば、多少は楽になるかも。
(たとえば、さら、ありす、れべっかを好感度が高い順にソートするとか、一定の好感度以上の子を全員を抽出するとか。)


2017.01.14

相手キャラの好感度変更システムを実装した。

1 第1章で、名前と好感度の変数セット。
####
#### キャラ名前登録(メッセージ内でキャラ名を表示させるため。)
####
       [set_variable]
           name=Sara_name
           value= _ "さら"
       [/set_variable]
       [set_variable]
           name=Alice_name
           value= _ "ありす"
       [/set_variable]
       [set_variable]
           name=Rebecca_name
           value= _ "れべっか"
       [/set_variable]
       [set_variable]
           name=Teacher_name
           value= _ "先生"
       [/set_variable]
       [set_variable]
           name=Teppei_name
           value= _ "てっぺい"
       [/set_variable]
       [set_variable]
           name=Sugisaku_name
           value= _ "すぎさく"
       [/set_variable]

####
#### 好感度変数
####
       [set_variable]
            name=favor_Sara
            value=0
       [/set_variable]
       [set_variable]
            name=favor_Alice
            value=0
       [/set_variable]
       [set_variable]
            name=favor_Rebecca
            value=0
       [/set_variable]
       [set_variable]
            name=favor_Teacher
            value=0
       [/set_variable]
       [set_variable]
            name=favor_Teppei
            value=0
       [/set_variable]
       [set_variable]
            name=favor_Sugisaku
            value=0
       [/set_variable]
2 次のようなマクロを用意し、イベントの結末に合わせて実行させる。
#define FAVOR ID VALUE
                   [set_variable]
                       name=add_favor_{ID}
                       value={VALUE}
                   [/set_variable]
                   [set_variable]
                       name=favor_{ID}
                       add={VALUE}
                   [/set_variable]
                   [message]
                       speaker=narrator
                       image=misc/laurel.png
                       message= _ "${ID}_nameの好感度が $add_favor_{ID} アップして $favor_{ID} になった。"
                   [/message]
#enddef

#define FAVOR_DOWN ID VALUE
                   [set_variable]
                       name=add_favor_{ID}
                       value={VALUE}
                   [/set_variable]
                   [set_variable]
                       name=favor_{ID}
                       sub={VALUE}
                   [/set_variable]
                   [message]
                       speaker=narrator
                       image=items/bones.png
                       message= _ "${ID}_nameの好感度が $add_favor_{ID} ダウンして $favor_{ID} になってしまった。"
                   [/message]
#enddef

特定のユニットの名前を表示させるのに、もっと頭のいい方法が絶対にあると思うのだけど・・・$unit_id.name みたいのないのかな?

あとは、蓄積ポイントに応じたエンディングを作れば、一応形になるかな。


2017.01.09

主人公の命名システムを実装した。

1 message に text_input タグを追加し、プレイヤーに名前をインプットさせて、変数に格納する。
       [message]
           speaker=narrator
           image=wesnoth-icon.png
           message= _ "君の分身に名前をつけよう。"
           [text_input]
               variable=herosname
           [/text_input]
       [/message]


2 modify_unit で主人公の名前を変更する。
       {MODIFY_UNIT (id=hero) name "$herosname"}

3 会話内でも変数を使って名前が表示されるようになる。
       [message]
           speaker=Teppei
           message= _ "おお、よろしくな、$herosname! おれはてっぺいっていうんだ。"
       [/message]


2017.01.08

Wesnoth学園を一部修正。
  1. よく使う store_unit と unstore_unit をマクロ化。
  2. 放課後の選択肢を充実。
  3. 仮のものであっても、ユニットIDを適当につけるとあとで苦労するので、適当だったユニットIDを名前と一致させた。

今後やりたいこと。
  1. 好感度システム実装
  2. 主人公の名前変更機能
  3. 登場人物のキャラは、そのうち大胆に変更するつもり。

2017.01.07

恋愛シュミレーション風キャンペーン「Wesnoth学園」を公開。
恋愛シュミレーションをやったことがないのだが、たぶんデートしたり贈り物をして相手の好感度を上げていって、最終的に誰を選ぶかでエンディングが変わってくると理解している。

主人公以外のユニットは、プレイヤーに操作させたくないので、別陣営としたため。シナリオごとに store_unit, unstore_unit を行うことで対応した。
マクロに MAKE_AI_SIDE_PERSISTENT, RECALL_AI_SIDE というAIの陣営をリコールできるっぽいのがあるのだが、使い方がわからない。
マクロの中身は一時的にAI陣営をプレイヤー操作陣営に変更しているらしい。
ここら辺に書いてある。http://svn.gna.org/svn/wesnoth/trunk/data/core/macros/side-utils.cfg

2016 09 19

_main.cfg ファイルをいじっていたら、キャンペーンが開かなくなってしまったが、Git で動いていた頃に戻すことができたので、事なきをえた。
やはり Git はおすすめです。まあ、今回のトラブルはこまめに保存と起動確認していれば、発生しなかったのだけど。

2016 05 21

Git お試しついでに、キャンペーンの続きを作成中。
今回は、特定のユニットの攻撃が当たると、特定ターンで味方に変わるマクロを作成してみた。

まずは攻撃が当たったことを登録する。とりあえず、role=poisoned にするようにしているが、多分手つきはよくないやり方と思われる。
自分から攻撃した時と攻撃を受けた時の2種類必要。
#define SET_SILENT_POISON
    [event]
        name=attacker hits
        [filter]
            type=Poison Bat
        [/filter]
        {MODIFY_UNIT (id=$second_unit.id) role poisoned}
    [/event]
    [event]
        name=defender hits
        [filter_second]
            type=Poison Bat
        [/filter_second]
        {MODIFY_UNIT (id=$unit.id) role poisoned}
    [/event]
#enddef

指定したターンで陣営が1に変わる。敵のリーダーの場合、この瞬間に勝利(笑)。
#define CHANGE_SIDE TURN
    [event]
        name=turn {TURN}
        {MODIFY_UNIT (role=poisoned) side 1}
    [/event]
#enddef
本当は、夜になると陣営が変わるようにしたいのだが、今のところ、いい方法がない。

2016 05 05

Git の試し用キャンペーンを作ってみたが、シナリオを読み込まず、3日間くらい悩んだ。
念のためマップファイルをテキストエディタで開いてみたら、わんさか余計がデータが書き込まれていて、それが悪さをしていた。
マップエディタで間違えて「シナリオとして」保存してしまったのがいけなかったようだ。
ところで、去年作り始めたキャンペーンはそのままお蔵入り状態。


2015 2 22(続き)

不死マクロをちょっと修正。
とりあえず負けたら消えてもらって、次のシナリオではちゃっかり復活するようにした。村で死んでも復活すると思う。
   #define IMMORTAL UNIT_ID SCENARIO_ID
   ### 戦闘前に生前の状態を保持
   ###
  [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id={UNIT_ID}
       [/filter_second]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
           [variable]        
               name=second_unit.hitpoints
               less_than=1
           [/variable]
           [then]
               [clear_variable]
                   name=store_{UNIT_ID}
               [/clear_variable]
               [store_unit]
                   [filter]
                       id={UNIT_ID}
                   [/filter]
                   variable=store_{UNIT_ID}
               [/store_unit]
               {SELECT_NEXT_SCENARIO {SCENARIO_ID}}
           [/then]
           [else]
           [/else]
       [/if]
   [/event]
 
   ### こちらからの攻撃
   ### [filter] と [variable] の name が違ってくる
   [event]
       name=attack end
       first_time_only=no
       [filter]
           id={UNIT_ID}
       [/filter]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
           [variable]        
               name=unit.hitpoints
               less_than=1
           [/variable]
           [then]
               [clear_variable]
                   name=store_XXX
               [/clear_variable]
               [store_unit]
                   [filter]
                       id={UNIT_ID}
                   [/filter]
                   variable=store_XXX
               [/store_unit]
               {SELECT_NEXT_SCENARIO {SCENARIO_ID}}
           [/then]
           [else]
           [/else]
       [/if]
   [/event]
   #enddef

そして次のシナリオでは、
   [event]
       name=prestart
       {RECALL AAA}
       {RECALL BBB}
       {RECALL CCC}
       [unstore_unit]
           variable=store_AAA
           x,y=24,15
       [/unstore_unit]
       [unstore_unit]
           variable=store_BBB
           x,y=23,17
       [/unstore_unit]
       [unstore_unit]
           variable=store_CCC
           x,y=25,17
       [/unstore_unit]        
   [/event]
で、生きていれば普通にリコール、死んでいれば [unstore_unit] で復活。ただし、ヒットポイントが限りなくゼロに近いので、フルヒールや毒抜きなどをする必要があると思われる。

2015 2 22

2月1日に {MODIFY_UNIT (side=2) max_moves 1} として、敵が1マスしか動かないように設定してもうまく行かないことの続き。
試してみるとスタート前に設定しても、なぜか第2ターンからしか有効にならない。
仕方がないのでズルいが第1ターンだけ別の方法で敵を動けないようにすることを考えた。

調べてみると、[side]タグで controller=null にするとこの陣営のユニットはまったく動かないことがわかった。
そこで、第1ターンまでは controller=null にして、第2ターンから controller=ai に変更するするようにしてみた。

まず、当初の [side] 設定(本当は第7陣営まであるが、やることは同じなので省略)
   [side]
       side=2
       controller=null
       team_name=ai
       no_leader=yes
       [ai]
           ai_special=guardian 
       [/ai]
   [/side]

第1ターンで1マスしか動けないようにする。(なぜか第2ターン以降で有効になる。)
   [event]
       name=turn 1
       {MODIFY_UNIT (side=2) max_moves 1}
   [/event]

第2ターンで、AI 操作に変更
   [event]
       name=turn 2
       [modify_side]
           side=2
           controller=ai
       [/modify_side]
   [/event]
なんだかあまりきれいなやり方ではないが、とりあえず意図した動きは実現したので、まあいいとする。

あとは、最初の方で作った不死マクロが、自ユニットが村にいるときには無効になってしまう(殺されてしまう)不具合の修正が残っている。


2015 2 11

レベルアップ用シナリオとして、敵を倒しても、次々と新手が現れるシナリオを作成。仕組みは簡単だが、敵味方双方の数や強さをうまく調整しないとレベルアップする前にやられてしまう。これは今後の課題。

まず、[scenario] タグに
victory_when_enemies_defeated=no
と一行入れておく。
次に、敵サイドの設定
   [side]
       side=2
       controller=ai
       team_name=ai
       no_leader=yes
       [goal]
           name=target
           [criteria]
               id=XXX
           [/criteria]
           value=5
       [/goal]
   [/side]
no_leader=yes としておくのが大事。これを忘れると、戦わずして勝利してしまう。

一体やられると次が現れる仕組み
(ゲーム開始時に aaa というユニットがいる前提で)

  [event]
       name=die
       [filter]
           id=aaa
       [/filter]
       {UNIT 2 (Goblin Impaler) 12 10 (id=bbb)}
   [/event]

あとは、同様に bbb や ccc がやられたらと同じことを続けてゆく。
   [event]
       name=die
       [filter]
           id=bbb
       [/filter]
       {UNIT 2 (Troll Whelp) 19 11 (id=ccc)}
       {UNIT 2 (Skeleton Archer) 6 9 (id=ddd)}
   [/event]

   [event]
       name=die
       [filter]
           id=ccc
       [/filter]
       {UNIT 2 (Troll) 20 1 (id=eee)}
       {UNIT 2 (Skeleton) 20 10 (id=fff)}
   [/event]

これを延々続けていくのは大変なので、fff がやられたら、bbb が再登場するというように、どこかでループするとよいと思う。


2015 2 1

昨日は [side] を配置するマクロで作成しはじめたが、具合が悪いので、[side] は普通に配置して、あとから {UNIT} マクロで敵を置くように方針転換した。
まず、普通に陣営を設置。ただし、リーダーなし設定なので、[scenario] タグ内に victory_when_enemies_defeated=no と1行入れておく。

   [side]
       side=2
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]
   [side]
       side=3
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]
   [side]
       side=4
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]
   [side]
       side=5
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]
   [side]
       side=6
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]
   [side]
       side=7
       controller=ai
       team_name=ai
       no_leader=yes
   [/side]

次にユニットを置くためのマクロを作成。
   #define SET_ENEMIES TYPE2 TYPE3 TYPE4 TYPE5 TYPE6 TYPE7
   {UNIT 2  {TYPE2} 24 11 ()}
   {UNIT 3  {TYPE3} 29 14 ()}
   {UNIT 4  {TYPE4} 29 19 ()}
   {UNIT 5  {TYPE5} 24 21 ()}
   {UNIT 6  {TYPE6} 19 19 ()}
   {UNIT 7  {TYPE7} 19 14 ()}
   #enddef

さらに自軍リーダーの ID とタイプに応じて敵ユニットを置くマクロに統合。(当初は、自軍リーダーのレベルに対応させるつもりだったが、ユニット固有の変数にレベルがなかったので、タイプに変更した。)
   #define SET_ENEMIES_4_SELF_TYPE ID SELFTYPE TYPE2 TYPE3 TYPE4 TYPE5 TYPE6 TYPE7
   [event]
       name=prestart
       [if]
            [have_unit]
                id={ID}
                type={SELFTYPE}
            [/have_unit]
           [then]
               {SET_ENEMIES {TYPE2} {TYPE3} {TYPE4} {TYPE5} {TYPE6} {TYPE7}}
           [/then]
           [else]
           [/else]
       [/if]
   [/event]
   #enddef

マクロの実行例(結果は、昨日の画像と同じ)
(マクロの中では、ユニットは ( ) で囲まないとエラーになる危険性高し。)
   {SET_ENEMIES_4_SELF_TYPE (XXX) (Sergeant) (Fugitive) (Elvish High Lord) (Dwarvish Lord) (Draug) (Orcish Sovereign) (Saurian Flanker)}

あとは、自軍リーダーのタイプの数(=レベルの数)だけこのマクロを設定すればよい。)
   {SET_ENEMIES_4_SELF_TYPE (XXX) (Sergeant) (Thug) (Elvish Fighter) (Dwarvish Fighter) (Skeleton) (Orcish Leader) (Saurian Skirmisher)}
   {SET_ENEMIES_4_SELF_TYPE (XXX) (Lieutenant) (Bandit) (Elvish Lord) (Dwarvish Steelclad) (Revenant) (Orcish Ruler) (Saurian Ambusher)}
   {SET_ENEMIES_4_SELF_TYPE (XXX) (General) (Highwayman) (Elvish High Lord) (Dwarvish Lord) (Draug) (Orcish Sovereign) (Saurian Flanker)}
   {SET_ENEMIES_4_SELF_TYPE (XXX) (Grand Marshal) (Highwayman) (Elvish High Lord) (Dwarvish Lord) (Draug) (Orcish Sovereign) (Saurian Flanker)}

敵ユニットには、うろちょろしてもらいたくないので、ガーディアン設定をする。
   [side]
       side=2
       controller=ai
       team_name=ai
       no_leader=yes
       [ai]
           ai_special=guardian 
       [/ai]
(以下、第6サイドまで同様)

さらに、移動能力を1マスに制限する。
   [event]
       name=prestart
       {MODIFY_UNIT (side=2) max_moves 1}
       {MODIFY_UNIT (side=3) max_moves 1}
       {MODIFY_UNIT (side=4) max_moves 1}
       {MODIFY_UNIT (side=5) max_moves 1}
       {MODIFY_UNIT (side=6) max_moves 1}
       {MODIFY_UNIT (side=7) max_moves 1}
   [/event]
あれ?うまくいかないな。

倒した敵に応じて、新規雇用ができるようにする。
   [event]
       name=die
       [filter]
           type=Thug
       [/filter]
       [allow_recruit]
           side=1
           type=Thug,Footpad,Thief,Poacher
       [/allow_recruit]
   [/event]
   [event]
       name=die
       [filter]
           type=Bandit
       [/filter]
       [allow_recruit]
           side=1
           type=Thug,Footpad,Thief,Poacher,Bandit,Outlaw,Rogue,Trapper
       [/allow_recruit]
   [/event]
   [event]
       name=die
       [filter]
           type=Highwayman
       [/filter]
       [allow_recruit]
           side=1
           type=Thug,Footpad,Thief,Poacher,Highwayman,Fugitive,Assassin,Huntsman,Ranger
       [/allow_recruit]
   [/event]
残りの敵(あと15ユニット!)も同じようにやってゆく。めんどくさ。


2015 1 31

今度は、自ユニットのリーダーのレベルに応じて、敵を変えるマクロに挑戦する。
まずは、敵ユニットのリーダーを配置するだけの簡単なマクロを作成。
   #define SET_ENEMIES TYPE2 TYPE3 TYPE4 TYPE5 TYPE6 TYPE7
   [side]
       side=2
       controller=ai
       team_name=ai
       type={TYPE2}
       id=MMM
       canrecruit=yes
   [/side]
   [side]
       side=3
       controller=ai
       team_name=ai
       type={TYPE3}
       id=NNN
       canrecruit=yes
   [/side]
   [side]
       side=4
       controller=ai
       team_name=ai
       type={TYPE4}
       id=OOO
       canrecruit=yes
   [/side]
   [side]
       side=5
       controller=ai
       team_name=ai
       type={TYPE5}
       id=PPP
       canrecruit=yes
   [/side]
   [side]
       side=6
       controller=ai
       team_name=ai
       type={TYPE6}
       id=QQQ
       canrecruit=yes
   [/side]
   [side]
       side=7
       controller=ai
       team_name=ai
       type={TYPE7}
       id=RRR
       canrecruit=yes
   [/side]
   #enddef

次のように実行してみる。
   {SET_ENEMIES (Fugitive) (Elvish High Lord) (Dwarvish Lord) (Draug) (Orcish Sovereign) (Saurian Flanker)}

するとこんな感じで指定したとおりの敵が配置される。


2015 1 27

不死マクロは一段落したので、次に特定のユニットから攻撃を受けた敵ユニットは次のターンから味方に変わるマクロを作成。
まず、攻撃を受けたことをなんらかの形で保存させる。
最初変数を使うことを考えたが、MODIFY_UNIT マクロを使ったら簡単にできた。格納するパラメーターはほかに影響のなさそうな role にした。
   #define SET_SIDE_CHANGE_FLAG
   ###
   ###特定の攻撃を受けるとフラグを立てる
   ###
   [event]
       name=attacker hits
       first_time_only=no        
       [filter]
           id=AAA
       [/filter]
       {MODIFY_UNIT (id=$second_unit.id) role kissed}
   [/event]
   #enddef

次のターンで味方に変わるマクロ。こっちも MODIFY_UNIT を利用。
   ###
   ###次のターンで味方になってしまう
   ###
   #define SIDE_CANGE
   [event]
       name=new turn
       first_time_only=no
       {MODIFY_UNIT (role=kissed) side 1}                
   [/event]
   #enddef

さらに夜になると味方になるマクロに修正。[filter_location] タグを使用。location とあるけれど地形だけではなく、時間でも使える。
   ###
   ###夜に味方になってしまう
   ###
   #define SIDE_CANGE
   [event]
       name=new turn
       first_time_only=no
       [filter_location]
           time_of_day=chaotic
       [/filter_location]
       {MODIFY_UNIT (role=kissed) side 1}                
   [/event]
   #enddef


2015 1 25

事実上全滅(石化)しても負けにもならず、戦闘続行もできない不具合を解消するため、不死マクロを元に倒されると問答無用で次のシナリオに行くマクロを作成。
   #define IMMORTAL_HERO UNIT_ID
   ### 戦闘前に生前の状態(位置)を保持
   ###
   [event]
       name=attack
       first_time_only=no
       [store_unit]
           [filter]
               id={UNIT_ID}
           [/filter]
           variable=store_{UNIT_ID}
           kill=no
       [/store_unit]
   [/event]

   ### name=attack end だと死ぬ前に発動するが
   ### name=die だと死んでゲームオーバーになってしまうのでだめ。
   ### まず攻撃されたとき
   [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id={UNIT_ID}
       [/filter_second]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
           [variable]        
               name=second_unit.hitpoints
               less_than=1
           [/variable]
           [then]
               [unstore_unit]
                   variable=store_{UNIT_ID}
               [/unstore_unit]
               [clear_variable]
                   name=store_{UNIT_ID}
               [/clear_variable]
               ###
               ###ファームへ
               [endlevel]
                   result=victory
                   next_scenario=00-training
                   bonus=no
               [/endlevel]
           [/then]
           [else]
           [/else]
       [/if]
   [/event]

   ### こちらからの攻撃
   ### [filter] と [variable] の name が違ってくる
   [event]
       name=attack end
       first_time_only=no
       [filter]
           id={UNIT_ID}
       [/filter]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
           [variable]        
               name=unit.hitpoints
               less_than=1
           [/variable]
           [then]
               [unstore_unit]
                   variable=store_XXX
               [/unstore_unit]
               [clear_variable]
                   name=store_XXX
               [/clear_variable]
               ###
               ###ファームへ
               [endlevel]
                   result=victory
                   next_scenario=00-training
                   bonus=no
               [/endlevel]
           [/then]
           [else]
           [/else]
       [/if]
   [/event]
   #enddef


2015 1 24

不死マクロで戦闘不能(石化)したときに、戦闘を続けるか離れるかを選択させるために、まず次のようなマクロを作成
#define SELECT_NEXT_SCENARIO
   [message]
       speaker=narrator
       image="wesnoth-icon.png"
       message= _ "The unit cann't fight. What shall we do ?"
       [option]
           message= _ "Continue the battle."
           [command]
           [/command]
       [/option]
       [option]
           message=_ "Lieve the field."
           [command]
               [endlevel]
                   result=victory
                   next_scenario=00-training
                   bonus=no
               [/endlevel]
           [/command]
       [/option]
   [/message]
#enddef

次に不死マクロの [/modify_unit]の後ろに上のマクロを追加する。
               [modify_unit]
                   [filter]
                       id={ID}
                   [/filter]
                   [status]
                       petrified=yes
                   [/status]
               [/modify_unit]
               {SELECT_NEXT_SCENARIO}
           [/then]
こんな感じ。
ただし、このままだと、自分のすべてのユニットが死んだり石化してもシナリオが終了しないという罠が残っている。


2015 1 19

不死マクロはこのままではどこかの魔法少女みたいにどんなに傷つけられても攻撃し放題となってしまうので、攻撃や反撃不能にする必要があるが、これが意外に面倒である。
ひとつ安易な手法として、石化させてしまうというのがある。
マクロの
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
       [modify_unit]
           [filter]
               id={ID}
           [/filter]
           [status]
               petrified=yes
           [/status]
       [/modify_unit]
に変えるだけでOK。
求めているのと違うが、当面これでやっていこうと思う。

なお、不死マクロはドレイン能力があるユニットでは、うまく機能しなくて死んでしまうことがあるが、そういうユニットには使わない予定なのでまあいいか。

2015 1 18

不死ギミックの続き
本当に死にそうなときのみ発動するように改良
   ### 戦闘前に生前の状態(位置)を保持
   ###
   [event]
       name=attack
       first_time_only=no
       [store_unit]
           [filter]
               id=XXX
           [/filter]
           variable=store_XXX
           kill=no
       [/store_unit]
   [/event]

   ### name=attack end だと死ぬ前に発動するが
   ### name=die だと死んでゲームオーバーになってしまうのでだめ。
   [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id=XXX
       [/filter_second]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
       [variable]        
           name=second_unit.hitpoints
           less_than=1
       [/variable]
       [then]
       [unstore_unit]
           variable=store_XXX
       [/unstore_unit]
       [clear_variable]
           name=store_XXX
       [/clear_variable]
       ### 死なない程度にHPを1にする。
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
       [/then]
       [else]
       [/else]
       [/if]
   [/event]

これだと敵から攻撃された時のみ有効なので、攻守反転バージョンも作成する必要があるので、次のように追加。
   ### 戦闘前に生前の状態(位置)を保持
   ###
   [event]
       name=attack
       first_time_only=no
       [store_unit]
           [filter]
               id=XXX
           [/filter]
           variable=store_XXX
           kill=no
       [/store_unit]
   [/event]

   ### name=attack end だと死ぬ前に発動するが
   ### name=die だと死んでゲームオーバーになってしまうのでだめ。
   ### まず攻撃されたとき
   [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id=XXX
       [/filter_second]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
       [variable]        
           name=second_unit.hitpoints
           less_than=1
       [/variable]
       [then]
       [unstore_unit]
           variable=store_XXX
       [/unstore_unit]
       [clear_variable]
           name=store_XXX
       [/clear_variable]
       ### 死なない程度にHPを1にする。
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
       [/then]
       [else]
       [/else]
       [/if]
   [/event]

   ### こちらからの攻撃
   ### [filter] と [variable] の name が違ってくる
   [event]
       name=attack end
       first_time_only=no
       [filter]
           id=XXX
       [/filter]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
       [variable]        
           name=unit.hitpoints
           less_than=1
       [/variable]
       [then]
       [unstore_unit]
           variable=store_XXX
       [/unstore_unit]
       [clear_variable]
           name=store_XXX
       [/clear_variable]
       ### 死なない程度にHPを1にする。
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
       [/then]
       [else]
       [/else]
       [/if]
   [/event]

マクロし、さらに引数をつけられるようにして、いくつものユニットでも使えるようにする。
   #define IMMORTAL ID
   ### 戦闘前に生前の状態(位置)を保持
   ###
   [event]
       name=attack
       first_time_only=no
       [store_unit]
           [filter]
               id={ID}
           [/filter]
           variable=store_{ID}
           kill=no
       [/store_unit]
   [/event]

   ### name=attack end だと死ぬ前に発動するが
   ### name=die だと死んでゲームオーバーになってしまうのでだめ。
   ### まず攻撃されたとき
   [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id={ID}
       [/filter_second]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
       [variable]        
           name=second_unit.hitpoints
           less_than=1
       [/variable]
       [then]
       [unstore_unit]
           variable=store_{ID}
       [/unstore_unit]
       [clear_variable]
           name=store_{ID}
       [/clear_variable]
       ### 死なない程度にHPを1にする。
       [modify_unit]
           [filter]
               id={ID}
           [/filter]
           hitpoints=1
       [/modify_unit]
       [/then]
       [else]
       [/else]
       [/if]
   [/event]

   ### こちらからの攻撃
   ### [filter] と [variable] の name が違ってくる
   [event]
       name=attack end
       first_time_only=no
       [filter]
           id=XXX
       [/filter]
       #### HPが1未満になった時に発動するようにする
       ### numerical_equals=0 や equals=0 だと死んじゃう
       [if]
       [variable]        
           name=unit.hitpoints
           less_than=1
       [/variable]
       [then]
       [unstore_unit]
           variable=store_XXX
       [/unstore_unit]
       [clear_variable]
           name=store_XXX
       [/clear_variable]
       ### 死なない程度にHPを1にする。
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
       [/then]
       [else]
       [/else]
       [/if]
   [/event]
   #enddef
(先頭と最後の #行はコメントではなく、定義なので、省略してはいけない。)

ほぼ、期待通りの動きをしたので、別ファイルにして、utils フォルダに保存し、_main.cfg にパスを追記
#ifdef 1_12_TEST
# add here custom code
      {~add-ons/1-12-test/utils}
{~add-ons/1-12-test/scenarios}
[+units]
	{~add-ons/1-12-test/units}
[/units]
#endif
(先頭と最後の #行はコメントではなく、定義なので、省略してはいけない。)

このとき、必ずシナリオへのパスより先に書くことに注意。そうしないと、キャンペーンを開始するときに「そんなマクロありません(意訳)」と怒られてしまう。そのことをすっかり失念していてだいぶ時間を無駄にしてしまった。


2015 1 17

無謀にもあらたなキャンペーン作りに着手した。
今回の目玉は、セーブ&ロードをする必要がない(主人公が絶対に死なない)という画期的というか、既にゲームとはいえないキャンペーンである。

とりあえず、殺されても死なないギミックのプロトタイプは次みたいなかんじ。
   [event]
       name=attack
       first_time_only=no
       [store_unit]
           [filter]
               id=XXX
           [/filter]
           variable=store_XXX
           kill=no
       [/store_unit]
   [/event]

   [event]
       name=attack end
       first_time_only=no
       [filter_second]
           id=XXX
       [/filter_second]
       [unstore_unit]
           variable=store_XXX
       [/unstore_unit]
       [clear_variable]
           name=store_XXX
       [/clear_variable]
       [modify_unit]
           [filter]
               id=XXX
           [/filter]
           hitpoints=1
       [/modify_unit]
   [/event]
これだと攻撃されると問答無用でHPが1になってしまうなど、いろいろ問題ありまくりだが、とりあえずどんなに攻撃されても死なないことだけは可能である。
それからいちいち攻撃前の状態を保持して、攻撃後に復旧するのはなんとなくスマートさに欠けるような気がする。
というか、(プログラミングできない分際で言うのも傲慢だけど)WML そのものがスマートさや統一感に欠けるところがあるように感じる。
最終更新:2017年04月13日 21:02