WoWS - 推力バーモント: 最速転舵、減速不要です

バーモント+推力UGについて、「減速→加速転舵すると通常より高い速力で旋回できる」という話を聞いたので
これ、減速いりません。

現象

推力UGバーモントで転舵を行うと、(推力なしと比較して)旋回中の速力が上下する。

どうやら元の話だと

  • 加速中に転舵すると速力増加
  • トップスピードから転舵すると速力低下
  • 減速してから転舵+加速することで速力を維持

という結論になっているようですが、これは正確ではありません

速力を維持したまま転舵する方法

  • 船が旋回し始めた時に、一瞬だけ速力設定を変化させる

実際の速力調整は一切不要です。一瞬3/4とFullを切り替えるだけでOK

動画

youtu.be

WoWS - 観測機でズームすると視点が飛んでしまうバグの対処法

対処法

ターゲットをロックオンした状態で空を見上げてズームイン(標準ではShiftキー)します

なぜ視点が"飛ぶ"のか

ズームイン時の照準点が、ロック補正の掛からない遠くの海面になっているのが原因です。
実際、この現象は観測機がないときも発生しています。ただし、カメラの俯角が小さくエイム修正も容易なため知覚されづらいです。
youtu.be

WoWS - UI Mod作成の基本 2: Modをゲームに認識させる

前回
kawaii-14.hatenablog.com

はじめに

UnboundまたはUnbound2で作成したModは、ゲームが自動的に認識してくれるわけではありません。
Modファイルのパスと表示したい要素をXMLに指定して読み込ませる必要があります。
ただし、Python+Unboundの場合は例外です。(PythonのメソッドからUnboundをロードする)
また、既存の要素を置き換える場合と、新規要素を増やす場合では若干操作が異なります。

Unbound/Unbound2共に

  • Modファイルを読み込むと、記述された各要素がUnbound系グローバルスコープにロードされる
  • グローバルスコープに存在するだけではUIとして機能しない
  • 表示する要素は別途指定する必要がある

といった大まかなイメージを持っておくとよいです。

これらの操作はゲームのアップデート毎(ゲームフォルダが変わる度)に必ず要求されますが、半自動的に管理するためのModも存在します。

Modをクライアントに読み込ませる方法

ファイルとフォルダ

省略のため、頻出するパスは以下のように表します。res_mods内で途中のディレクトリが欠けている場合は適宜作成してください

  • gui: (World_of_Warships)\bin\(最新バージョン)\res_mods\guiフォルダ
  • uss_settings: gui\uss_settings.xml Modのパスを指定するファイルです。存在しない場合はUnpackerから抽出してください
  • battle_elements: gui\battle_elements.xml 表示する要素を指定するファイルです。存在しない場合はUnpackerから抽出してください

編集するファイル

既存要素を置き換えるMod 新規要素を追加するMod
Unbound uss_settings uss_settings, battle_elements
Unbound2 なし battle_elements

新規要素を追加するModの場合、battle_elementsは必ず編集することになります。
また、UnboundではModファイルパスを必ず指定する必要があります。
Unbound2ではファイルが自動的に読み込まれるため、uss_settingsを改変する必要はありません。

uss_settingsの設定

uss_settings.xmlを開き、<mods>要素の下に作成したModのファイルパスを記述します。

<mods>
    <swffile>../unbound/mods/ModFileName.swf</swffile>
    <xmlfile>../unbound/mods/ModFileName.xml</xmlfile>
</mods>

例: gui\unbound\modsTestMod.xmlTestMod.swfがある場合

uss_settingsにパスを通す例

battle_elementsの設定

重要: 既存の要素を置き換えるModの場合、このファイルを編集する必要はありません。

パラメータ
  • hitTest: UIの当たり判定を制御します。クリックやD&Dを利用する場合はtrueに、それ以外はfalseを指定します
  • tempModName: 他のModと競合しない自由な名前を設定してください。慣例ではunboundModNameになっていることが多いです
  • rootElementName(Unbound)またはelementName(Unbound2): Modとして読み込む要素の名前です。
<element>要素

<elementList>の内側に追加します

  • Unboundの場合
<elementList forceHideAll="false">
    <element class="lesta.libs.unbound.UnboundElement" name="tempModName" url="battle_stats.swf">
        <properties hitTest="true|false" rootElementId="rootElementName"/>
    </element>
</elementList>
  • Unbound2の場合
<elementList forceHideAll="false">
    <element class="lesta.unbound2.UbElement" elementName="rootElementName" name="tempModName" url="battle_stats.swf">
        <properties hitTest="true|false"/>
    </element>
</elementList>
<controller>要素

<controllers>の内側に追加します
Unbound2では不要です。

<controllers>
    <controller class="lesta.dialogs.battle_window_controllers.UnboundElementController" clips="tempModName"/>
</controllers>

例: Hello Worldを表示するMod
下記画像だとrootElementId="TestModRoot"またはelementName="TestModRoot"になります

例: Unboundの場合
例: Unbound2の場合

半自動でModを登録する方法

ModsInstallerというPython Modによって、これらの作業を自動化することができます。
使い方の説明は配布元のマニュアルに譲りますが、編集するファイルや内容等、この記事の知識が前提として必要になります。作者: Monstrofil, Roslich
drive.google.com

WoWS - UI Mod作成の基本 1: UnboundとDataHub

はじめに

World of Warshipsは複数のプログラミング言語で構成されており、それぞれ以下のような役割を担っています

  1. ゲームの中核(オブジェクトのレンダリングやダメージ処理など): Python, C++
  2. UI(ダメージポップアップや艦艇名表示など): ActionScript3, Unbound, Unbound2, Gameface

ゲーム中核とUIの間でデータを橋渡しするのがDataHubというオブジェクトです。

詳細は公式ドキュメントにもありませんが、UI系Modの作成ではほぼ必須の知識になります。
今までのModderは公式のマークアップや他人のModを見て独学してます。この狂った連鎖を断ち切りたい
具体例なんかは次回以降(SoonTM)にします

必要なもの

  • やる気と時間: 作ったModが思い通りに動かないこと多数。公式ドキュメントに記載されている手法も特定条件では動かなかったり(しかも条件書いてない)。Modテストのためにクライアント複数回起動するだけで1時間失ったりします。これはマジです
  • FlashDevelop: .swcファイルを読み込めるFlash IDEなら他のものでもOKです
  • SWCファイル: 下記リンクから最新バージョンのフォルダを選択、as3_library.zipをダウンロードしてください

drive.google.com

ダウンロードした.swcファイルのパスをIDEに通してください。
FlashDevelopであれば、画面上部のProject→Properties...→Compiler Options→SWC Librariesから設定できます

SWC Libraries

この手順が完了すると、FlashDevelopのProjectカラムにあるRefences→Classesより、各Component(後述)の持つプロパティやイベントが確認できるようになります。

例: AccountNameコンポーネントの持つ要素

DataHubのデータ構造

全体図(要拡大)

定数について

Unbound系に共通する定数としてCC(ComponentClass)が存在し、Component(後述)のクラスIDが保存されています。
例として、AccountNameコンポーネント(プレイヤーの名前が保持されている)のクラスIDはCC.accountNameのようにアクセスできます。

Collectionsについて

Collectionを格納するオブジェクトです。クラスID(CC.something)を使用して特定のCollectionを取得できます。

Collectionについて

特定のComponentを持ったEntityへの参照を格納する配列です。
配列インデックスを指定して任意のEntityを取り出せます。
また、コレクションから要素を選択し、新たなコレクションを作成することも可能です。
例えばAccountNameコレクションには、AccountNameコンポーネントを含むEntityが全て保存されています。

Entityについて

Componentを格納するコンテナです。
全てのEntityはユニークなIDを持ち、これを用いて直接参照することができます。

Componentについて

数値、文字列、イベントなど、実態のあるデータを保持するオブジェクトです。
前出のAccountNameコンポーネントであれば

  • name: プレイヤー名(IGN)
  • nickName: ニックネーム(クランタグを含むIGN)
  • evChanged: 上記どちらか変更された際トリガーされるイベント

が保存されています。
また、primaryKeyメソッドが存在する場合はユニークIDを持ちます。
ユニークIDは1つまたは複数の要素で構成されており、前者の場合は数値や文字列、後者の場合は'element1_element2'のようにアンダーバーで各要素を結合した文字列がキーとなります。

オブジェクトの取得方法

Collection

variableNameCC.somethingのコレクションを代入します。
variableName[index]で任意のインデックスにあるEntityを取り出すことができます

Unbound <bind name="collectionDH" value="CC.something; 'variableName'"/>
Unbound2 (var variableName:gfx = "$datahub.getCollection(CC.something)")

Entity

variableNameに任意のEntityを代入します。

EntityのユニークID(entity.id)から
Unbound <bind name="entityDH" value="'variableName'; entityId"/>
Unbound2 (var variableName:gfx = "$datahub.getEntity(entityId)")
ComponentのユニークIDから

複数の要素からなるIDの場合、自分で文字列を作成してgetPrimaryEntityを使用するか、getPrimaryCompositeEntityの引数に結合前の要素を与えることでEntityを得ることができます。
例1: ownSquadronのユニークIDは、飛行中隊のインデックス(ロケット:0, 雷撃機:1, 爆撃機:2等)です。getPrimaryEntity(CC.ownSquadron, index)
例2: battleConsumableのユニークIDは、消耗品タイプと飛行中隊インデックス(艦消耗品の場合-1)の結合文字列type_squadronIdです。
getPrimaryCompositeEntity(CC.battleConsumable, consumableType, squadronId)getPrimaryEntity(CC.battleConsumable, 'consumableType_squadronId')と等価です。

Unbound <bind name="primaryEntityDH" value="'variableName'; CC.something; index"/>
Unbound2 (var variableName:gfx = "$datahub.getPrimaryEntity(CC.something, index)")
(var variableName:gfx = "$datahub.getPrimaryCompositeEntity(CC.something, *args)")
コレクションの最初のEntity

collections[CC.something][0]と等価です。

Unbound <bind name="firstEntityDH" value="'variableName'; CC.something"/>
Unbound2 (var variableName:gfx = "$datahub.getSingleEntity(CC.something)")

Component

コレクション最初のEntityにあるComponent

collections[CC.something][0].somethingまたはgetSingleEntity(CC.something).somethingと等価です。

Unbound2 (var variableName:gfx = "$datahub.getSingleComponent(CC.something)")

WoWS - 艦載機の飛行速度と照準の拡大

TLDR

ロケットと爆弾の照準は、艦載機の飛行速度から影響を受けて進行方向に延伸します。
ほぼ戦闘に影響しませんが、減速するほどレティクルが縮み命中精度が向上します。

仕組み

関連するGameParams
  • attackInterval[s]: 弾体の発射間隔
  • attackCount: 弾体の発射回数
  • outerSalvoSize[BW]: 最大散布界(詳細は以下記事を参照)
  • minSpread, maxSpread: 拡散率(詳細は以下記事を参照)

kawaii-14.hatenablog.com

計算式

レティクルが伸びる長さ[BW] = v × (attackInterval × (attackCount - 1 ))
ただしv[BW/s]は艦載機の速度です
一応単位換算を載せておくと

  • 1[knots] = 2.6854[m/s]
  • 1[m/s] = 1/30[BW/s]

になります

これは軸長全体の増加量なので、実際の散布界半径に加算するときは0.5倍してください。
半軸の長さ[BW] = outerSalvoSize * minSpread + レティクルが伸びる長さ * 0.5

WoWS - 抗堪スキルが区画HPへ与える影響

割と最近実装された仕様。何か検証するときに役立つかもしれない。フランス駆逐で抗堪を取ると被ダメージが増えたバグの元凶(現在は修正済み)

概要

艦艇の最大HP変更(抗堪、軍拡のバフ等)は、各区画のHPおよび最大HPを同時に変化させる。
恐らく、軍拡競争などで区画飽和が異常に強くなることを防ぐための仕様。

例: Marceau (青: 通常, 赤: 抗堪+4000)

区画HPの計算

対象となる区画

影響を受けるのはモジュールでない区画のみ。GameParamsで言うとHitLocation.hlTypeが以下に該当するもの

hlType 具体例
simple_hitlocation 艦首, 艦尾, 船体(砲殻), 補助区画
citadel_hitlocation バイタル
casemate_hitlocation ケースメイト(駆逐艦の中央部等)
hull_hitlocation 艦全体
supersctructure_hitlocation 上部構造物
パラメータ

アンダーバー以降の単語は説明のために追加したもの。値を検索するときは無視すること。
currentHPを除く全パラメーターはGameParams内に存在する

  • health_base: デフォルトの艦艇最大HP
  • health: スキルやアップグレードにより変化した後の艦艇の最大HP
  • healthHullCoeff: 軍拡のバフなどで得られる、艦艇の最大HPに対する係数
  • maxHP_base: デフォルトの区画最大HP
  • maxHP: 変化後の区画最大HP
  • currentHP: 現在の区画HP
最大区画HP(maxHP)の計算式

ceil(maxHP_base * healthHullCoeff * (health / health_base) / 50) * 50

簡単に言うと、HPの増加割合とおよそ同じだけ区画最大HPを増加させる。
問題にはならないものの、ceil(切り上げ)を使っているため区画HPは本来より若干多く配分される。

区画HP(currentHP)の計算式

min(currentHP * max((maxHP / maxHP_base), 1.0), maxHP)

最大区画HPの増加に応じて現在の区画HPも増加する。現在値が最大区画HPを超えた場合はキャップが入るものの、基本的に減少することはない。(min、max関数部分が該当)

WoWS - 潜水艦のダメージモデルと爆雷の仕様

まとめ

  • 潜望鏡深度以下にいる潜水艦は、実質的に区画が飽和したフランス駆逐と同じ耐久性を発揮する
  • 空爆雷を避けるときは最大震度へ、通常爆雷を避けるときは海面近くへ逃げる
  • 対潜水艦はAPよりHE/SAPを優先して使う
  • 砲弾の爆風は爆発地点からの距離でダメージが変化しない。爆雷は変化する。
  • 通常爆雷の爆風は半径450m、着水から起爆まで約7秒。距離によるダメージ変化が小さいのでばらまくのが良い
  • 空爆雷の爆風は半径300m、着水から起爆まで約4秒。距離によるダメージ変化が大きいので可能な限り狙いは正確に

これ以降は詳しい話が好きな人向け

単位について

BW(BW)とメートル(m)、艦艇メートル(ship_m)の三種類がある。記事中で使われるのは前者2つだが、ゲーム内の潜水艦深度は艦艇メートルで表示されている
そのまま普通のメートルに当てはめると一致しないので注意
換算は次の通り
1[BW] = 30[m] = 15[ship_m]
また
1[ノット] = 2.6854[m/s]

潜水艦のダメージモデル(被ダメージ)

潜水艦の受けるダメージは3種類存在する。

直撃ダメージ

砲弾が貫通した際発生する。
ルールは水上艦(駆逐艦)と同じで

  • 区画ごとに受けるダメージが決まっており、貫通弾ではアルファダメージ x 0.165のHPが失われる*1
  • 船体中央は事実上無限(165500)のHPを持ち、区画HPが尽きることはない
  • 280mm以上のAP、SAPからは貫通種別を問わず0.1倍のダメージしか受けない

といった特徴がある。

火災・浸水ダメージ

爆雷や砲弾、魚雷の命中で発生する。基本的には駆逐艦と同じだが、一部相違点がある。

火災
  • 同時発生数; 1箇所
  • 1Tickあたりのダメージ: 最大HPの1%
  • 1火災から受けるダメージ: 最大HPの30%
浸水
  • 同時発生数: 1箇所
  • 1Tickあたりのダメージ: 最大HPの0.33%
  • 持続時間: 30秒
  • 1浸水から受けるダメージ: 最大HPの9.9%

浸水は理論上10回耐えられるが、火災は4回目で死ぬ。

爆風ダメージ

本題。潜水艦向けの新しい仕様で、爆雷や砲弾の爆発によって発生する。対空砲や舵といったモジュールに対する爆風とは別のもの

爆風半径(球体)内にいる潜水艦に対してアルファダメージ x 爆風ダメージ係数のダメージが発生する

爆風半径

砲弾は主に口径によって、爆雷は種類によって統一された爆風半径が決まっている。

主要な砲弾の爆風半径

口径[mm] HE爆風半径[BW] AP爆風半径[BW] SAP爆風半径[BW]
127 2.78 1.39 2.71
135 2.71 不明 3.02
152 3.02 1.51 3.02
203 3.39 1.69 3.39
305 3.92 1.96 4.21
356 4.13 2.06 不明
406 4.3 2.15 4.21
457 4.46 2.23 不明

爆雷の爆風半径

種類 爆風半径[BW]
空爆 10
通常爆雷 15

興味深い点

  • HEの爆風半径はAPの2倍、SAPはまちまち
  • イタリア駆逐(135mm)のSAPは152mmクラスの異常に大きい爆風半径を持つが、HEの加害範囲は127mmより小さい
  • 通常爆雷は航空爆雷の1.5倍の加害範囲(450m)を誇る
爆風ダメージ係数

爆風ダメージ係数は弾体側に設定されており、発生するダメージに船体の被ダメージ係数は関与しない。過貫通保護も起きないため、大口径SAPが刺さる。
爆雷の場合、爆発地点から最大爆発半径にかけて徐々に減衰するが、砲弾では固定されている(距離によらず一定のダメージ)。

砲弾の爆風ダメージ係数

弾体種類 ダメージ係数
HE弾/SAP弾/APロケット/AP爆弾 0.165
AP弾 0.1

爆雷の爆風ダメージ係数

空爆 爆発中心点からの距離(割合) 0.0~0.32 0.321~0.56 0.561~0.8 0.801~1.0
爆風ダメージ係数(倍) 1.0 0.35 0.25 0.0
通常爆雷 爆発中心点からの距離(割合) 0.0~0.15 0.151~1.0
爆風ダメージ係数(倍) 1.0 0.33

図にするとこのようになる。円内の比率は正確

空襲爆雷
通常爆雷

その他の爆雷仕様

ダメージ係数の他にも爆雷特有の設定が存在する。

発射直後の爆雷は信管が作動しておらず、ダメージのある当たり判定は存在しない。(至近距離の魚雷と同じ)
海中に入り信管が有効になった爆雷はランダムな一定速度で落下し、さらにランダムなタイマーを基準に爆発する。
また、爆雷爆発物専門家による爆風半径増加の影響を受けない

種類 落下速度[ノット] 落下速度のランダム幅[倍] 起爆タイマー[秒] 起爆タイマーのランダム幅[秒]
空爆 3.5 x0.8~1.2 4.0 -0.5~+0.5
通常爆雷 10 x0.8~1.2 7.0 -0.5~+0.5

海面からの平均起爆距離を計算すると

T10の潜水艦は最大120m(=60ship_m)潜れるので、航空爆雷を避ける際は最大深度、通常爆雷相手は海面近くに逃げるのがよい
あるいは、25ノットで7秒間に470m進むことができるため、動き続けていれば直上からの爆雷からも逃げ切れる可能性は高い

GameParams内の関連パラメータ

弾体に設定されているもの

  • pointsOfDamage: 爆発中心点からの距離(割合)とダメージ倍率
  • depthSplashRadius: 爆発半径[BW]
  • alphaDamage: アルファダメージ

爆雷の設定

  • speed: 落下速度[ノット]
  • speedDeltaRelative: 落下速度のランダム幅[(1±speedDeltaRelative)倍]
  • timer: 着水から起爆までの時間[秒]
  • timerDeltaAbsolute: 起爆時間のランダム幅[±秒]

*1:アルファダメージ=砲弾最大ダメージ