ほげほげー

C#メインにプログラミング周りから日常のあれこれとかを不定期に書いていきます。

Stone Story RPG Stonescript 実用編 その2

基礎はこちら

tyheeeee.hateblo.jp

実用編その1はこちら

tyheeeee.hateblo.jp

続きのその3書きました。

tyheeeee.hateblo.jp

それでは実用編その2です。

実用編

マップごとの実装

最適化して動かすことを考えると、当然のことながらマップ毎に実装を変える必要があります。しかしながら関数がグローバルに影響してしまう都合上非常に見通しが悪くなりがち&最大文字数制限が存在するので、面倒ではありますが各マップ毎に用意しておくのがベターです。

自分はPCとスマホ(Android と iPhone 両方)間のやり取りの容易さと、雑に履歴が取れる Google Keep を利用しています。iPhone と Mac しか使ってないなら AirDrop で適当にやればいいんじゃないかなと思います。

PC版の場合はファイルを分けて読み込む、というやり方がありそうですが、スマホでそれができるかは不明なのと試すのも面倒なので無いものとします。(誰か知ってたら教えてください)

スキル使用

このゲーム、手動でスキルを使うのであれば何も気にせずボタンを押すだけで良いのですが、スクリプトでやろうとすると一工夫必要になります。

とりあえず例としてバルディッシュのスキルの使い方を以下に記載します。

?foe = boss & foe.distance <= 10 &
^item.GetCooldown("bardiche") <= 0 |
^item.GetCooldown("bardiche") > 870
   equip bardiche
   activate R
  1. 射程内に入ったら使うように distance で絞り込む
  2. バルディッシュのクールダウンが0以下になっていることを確認する
  3. バルディッシュのスキルが 当たるまで ここを通るようにする
    1. 大体クールダウンが870になったあたりでヒットする
  4. バルディッシュを装備する
  5. バルディッシュのスキルを使用する(両手持ち装備のスキルは R で発動する)
    1. 発動から30フレーム程度は攻撃モーションで、それが終って敵に当たるまでに装備を変えると攻撃が当たらない

という感じで、単純にぶっ放して終わりにするとスキルのモーションに入った瞬間に装備が変わってキャンセルされて無駄打ちすることになるので一工夫必要です。

さらに、他の装備のスキルも発動したい場合、現在他のスキルを使用中であるといったフラグを立てておかないといけなくなるのでそこにも注意です。

var activatingSkill = "none"
?foe = boss & foe.distance <= 10 &
^(activatingSkill="none" |
^activatingSkill="bardiche")
^item.GetCooldown("bardiche") <= 0 |
^item.GetCooldown("bardiche") > 870
  equip bardiche
  activate R
  activatingSkill = "bardiche"
:
  activatingSkill = "none"

バルディッシュの発動中、もしくは他にスキルを使っていない状態なら発動、という感じです。 未発動時の activatingSkill"" にしたいところですが、例によって Stonescript の = はフィルタなのですべてに一致してしまいます。なので none としています。

これに関しては以下のように関数化するのもアリかもしれません。(これは適当に動作確認なしに書いているので動かなかったらすみません)

var activatingSkill = "none"
func ActivateSkill(name, range, timing)
  ?foe = boss & foe.distance <= range &
  ^(activatingSkill="none" |
  ^activatingSkill=name)
  ^item.GetCooldown(name) <= 0 |
  ^item.GetCooldown(name) > timing
    equip @name@
    activate R
    activatingSkill = name
  :
    activatingSkill = "none"

ActivateSkill("bardiche", 10, 870)
ActivateSkill("hammer"...

時間を短縮する

放置での効率を求めると時間を可能な限り短縮する必要が出てきます。

ここでは時間を短縮するためにスクリプトでできることをまとめます。

ダッシュの盾(dashing shield)で距離を詰める

ダッシュの盾は一気に敵との距離を詰められるので時間の短縮につながりそうです。

とりあえずスキルが発動する距離を確認します。

var cd = 0
var moved = false
var distList = []
var prevDist = 0

// dashing_shield のスキル発動までのクールダウンを取得
cd = item.GetCooldown("dash")

// クールダウンが増えている = スキルが発動した & 発動後1度だけ処理したいのでフラグを立てる
// クールダウンが 40 以上で moved フラグが立っていない時は発動した距離をリストに突っ込む
?cd > 40 & !moved
  moved = true
  distList.Add(prevDist) // 1フレーム前の敵との距離を入れる

// クールダウンが 10 未満になったらフラグを落とす
?cd < 10
  moved = false

// ダッシュの盾を装備する
equipR dashing

// 現在の距離を入れておく
prevDist = foe.distance

// 発動距離の一覧を出力する
var x = 6
x = 6
>`0,@x++@,-- outputs --
distList.Sort()
?distList.Count() > 0
  for i = (distList.Count() - 1) .. 0
    >`0,@x++@,@distList[i]@

すると、基本17、たまに18が出力されます。という事はおおむね16になったタイミングで発動していると言えそうです。

それでは17になったら装備してそれ以外の値になったら装備を変える、として1フレームで発動するか見てみます。

?foe.distance = 17
  equipR dashing_shield
:
  equipR sword
  equipL long sword

発動します。では18ではどうでしょう。

?foe.distance = 18
  equipR dashing_shield
:
  equipR sword
  equipL long sword

発動しません。つまり dashing_shield を装備するなら17以下になった段階であれば無駄が少なくなりそうです。

同様に、ロスト装備の bashing_shield も試してみると同じ挙動を示しているようです。

ではこれを元に記述してみます。

var mainShield = "ステージに合った属性 shield A"
var mainLongSword = "ステージに合った+値の多いロングソード"
var subLongSword = "ステージに合った+値の次に多いロングソード"
?foe.distance > 17
  equipL triskel
  equipR @mainShield@

:?foe.distance > 6
  // ロングソードの攻撃範囲が6なので、ロングソードを使う場合距離が6より遠い時はダッシュ OR バッシュ盾を装備したい
  ?item.GetCooldown("dash") <= 0
    equipR dash
  :?item.GetCooldown("bash") <= 0
    equipR bash
  :
    equipR @mainShield@
:
  equipL @mainLongSword@
  equipR @subLongSword@
  // もしくは equipR @mainShield@

これでダッシュの盾発動距離より遠いときは triskel stone で移動速度アップ。
ダッシュの盾発動距離かつクールダウンが終っている状態ではダッシュスキル、もしくはバッシュスキルが発動。
最接近したら攻撃用装備に切り替え。

といった挙動をとれるようになりました。ロングソードの強さ次第ですが、かなり高速化が見込めます。

スプラッシュ攻撃でまとめて倒す

高レベルのステージでは雑魚敵が非常に多く出現するため、スプラッシュによる範囲攻撃は必須となります。

前項で触れたように、ダッシュの盾で一気に近寄って範囲攻撃で片付けるのが好ましいと思います。

さらに言えばスプラッシュな武器を左右両方に持てば更に良さそうです。☆☆☆☆☆までなら正直それだけで事足りますが、☆☆☆☆☆ともなると敵が多すぎて敵の遠距離攻撃の弾幕に晒されてものすごい勢いでHPが溶けてしまいます。

HPを溶かさないためには属性付きの盾(A: 特定属性の相手に防御が上がるとなっているもの)を装備して、アーマーを増やす必要があります。

アーマーが十分あれば両手持ちに切り替えても良いので、それに合わせてスクリプトを工夫します。

ちなみに完全に同一の装備は2本装備することはできないのでエンチャントのレベルに差をつけるか、装備のレベルに差をつけるか、プリフィックス(dFだとかDだとか)を変えるか、有り余っているようであればネームタグで武器に固有の名前を付けてしまうかをしてください。

var mainShield = "ステージに合った属性 shield A"
var mainLongSword = "ステージに合った+値の多いロングソード"
var subLongSword = "ステージに合った+値の次に多いロングソード"
?foe.distance > 17
  equipL triskel
  equipR @mainShield@

:?foe.distance > 6
  // ロングソードの攻撃範囲が6なので、ロングソードを使う場合距離が6より遠い時はダッシュ OR バッシュ盾を装備したい
  ?item.GetCooldown("dash") <= 0
    equipR dash
  :?item.GetCooldown("bash") <= 0
    equipR bash
  :
    equipR @mainShield@
:
  equipL @mainLongSword@
  ?armor > 40
    equipR @subLongSword@
  :
    equipR @mainShield@

物理攻撃無効の敵がいるステージでは各種属性の魔法の杖を装備にします。

アーマー持ちの敵には属性ハンマーを使うといった工夫を入れても良いと思います。

?foe.armor > 0
  equipL @mainHammer@
  equipR @subHammer@
資源を回収する

一部のステージでは資源が落ちており、そのままだと回収にそれなりに時間がとられてしまいます。

そのため、star stone を使って回収の時間を短縮することでかなりの時間を節約できます。

最寄りの資源との距離は pickup.distance で取得できます。これを使って以下のように記述します。

?pickup.distance < 10
  equipR star

これだけです。これを適切な場所に配置することで資源の回収が高速化できます。

スキルを活用する

敵を一掃できるスキルがあればそれを活用します。

堕神の剣(blade_of_god)がそれにあたります。(というか他にまともに使えるものがない)

堕神の剣のスキルは敵が多い方がお得なので、敵の数を条件に入れて発動させるようにしましょう。

ボスでは時間の無駄なので発動しないようにしておきます。

var useBlade = false
?(item.GetCooldown("blade")<=0&foe.count>6
^&!isBoss)
  equip blade_of_god
  activate R

ちなみに堕神の剣のスキルは即時発動なので敵に当たるまで待つ、といった処理を書く必要はありません。便利ですね。

5000文字を超えてきたので今回はここまでにしておきます。

次回以降は以下の項目を順次載せる予定です。

  • 実践編
    • ボスの状態に合わせて装備を変える

      • 攻撃を避ける

      • 防御する

      • 最適な武器を装備する

      • 細かく最適化する

  • Stonescript ハック集

    • 装備持ち替えによるDPS向上

    • 堕神の剣のスキルを効率よく使う

    • オフラインでの周回に最適化する

    • 地獄の鉱山の中ボスに対処する