ここでは便利なLua Scriptの実用例を載せていく
Luaを触ったことない人もここにあるコードを自由に使用・改造してLuaの使い方を覚えよう!!
そもそもLuaの使い方がわからん→Luaプログラミング入門 - densan-labs.net
CMOマニュアルpp.110-116 "5.3 LUA SCRIPTING"も参照
- はじめに
- ユニットやミッション,イベントのプロパティを表示する
- 陣営レベルの操作
- マップ操作
- ユニットレベルの操作
- グループ操作
- イベント等の操作
- いっそ生成AIに書かせればよくね???
はじめに
C:MOではLua Scriptを使ってゲームの操作が可能だ。これを通常のプレイヤーが直接使用することはないが、Scenario Editorを使って高度なシナリオを作りたい場合、これは必須技能となる。
ただコンピュータ言語をマスターするのは非常に難しい。そのため、このセクションでは簡単に使用できるLua Script実用例集を用意した。
もし詳しくC:MOでのLua ScriptのFunctionを知りたい場合、公式のCommand Lua API Documentation (V2) を参照されたい。
追加で資料室も参考にできる。
Lua Scriptの使い方
メインで使用する場所はLua Script Console、Special Actions、Event内のConditionとAction。
- Lua Script Consoleはメインメニュー>Editorの一番下、またはショートカットキーCtrl+Shift+C。
- Special Actionsはメインメニュー>Editor>Event>Special Actionsで開いてCreate New Special Actionsから作成。
- Event内のConditionとActionに関してはこっち。
Tips
DBIDはDB viewerでユニットを表示した際に左上に出る数字です。
GUIDはシナリオに存在するオブジェクト(陣営,ユニット,ミッション,イベントなど)について定められる固有ID番号で,たとえば以下のような感じ.
{name='JASDF Tsuiki Air Base', guid='588456b9-d277-4a6e-9aeb-249cdce5ad0e'}
{name='ROKAF Gimhae Air Base', guid='9f7c59ab-a123-4e56-bc3f-40c61c3300c5'}
{name='ROKAF 8355th Unit (Ullung-do)', guid='801b49bb-96d7-45bd-b085-8fcd5b4a0ced'}
GUIDはユニットを選択して、右クリック>Scenario Editor>copy unit ID to clipboardもしくはCtrl+Cキーで得られます。メモ帳にでもペーストすれば読める。
ユニットやミッション,イベントのプロパティを表示する
各ユニットやミッション,イベントがもつプロパティを表示させるもの.
各プロパティ項目の一覧はここを参照
プロパティ項目の変更
local unit=ScenEdit_GetUnit ()
等でプロパティを取得したあと,
unit.heading
のようにコロンをつけてプロパティの項目を指定し,
unit.heading=135
のようにするとプロパティ項目を変更できる(読み取り専用の項目は不可)
ScenEdit_Setxx()関数を使っても同じ結果が得られる
ScenEdit_SetUnit({name=unitname, heading=135})
陣営
local name ="陣営名"
local side = VP_GetSide ({side="陣営名"})
print(side)
ユニット
local side = "陣営名"
local name = "ユニットの名前"
local unit = ScenEdit_GetUnit({side=side, name=name})
print(unit)
local guid = "ユニットのguid"
local unit = ScenEdit_GetUnit({guid=guid})
print(unit)
実行結果の例
>> return ScenEdit_GetUnit({name="306 TFS #904"})
unit {
type = 'Aircraft',
subtype = '2001',
name = '306 TFS #904',
side = 'Japan',
guid = 'b237eecf-302f-449b-9951-818ff49f0af0',
class = 'F-15J Eagle',
proficiency = 'Regular',
latitude = '36.3938888888889',
longitude = '136.407777777778',
altitude = '6',
heading = '0',
speed = '350',
throttle = 'Loiter',
autodetectable = 'False',
base = 'JASDF Komatsu Air Base',
mission = 'JPN CAP',
mounts = '2',
magazines = '2',
unitstate = 'Tasked',
fuelstate = 'None',
weaponstate = 'None',
AllowMultiMission = 'False',
AssignedMissionsQueue = 'table',
}
グループ
ユニットと同じくScenEdit_GetUnit()関数が使えるが,ユニットはUnitラッパーを返すのに対しこちらはGrouptラッパーを返す
local group = "groupname"
return GetUnit ({name=group})
コンタクト
local guid = "コンタクトのguid"
local contact = VP_GetContact ({guid=guid})
print(contact)
ミッション
local side = "陣営名"
local mission = "ミッション名"
local mission = ScenEdit_GetMission (side,mission)
print(mission)
実行結果例
--対空パトロールミッション"JPN CAP"の情報
>> local side = "Japan"
local mission = "JPN CAP"
local mission = ScenEdit_GetMission (side,mission)
print(mission)
mission {
guid = '0a35715c-b8b7-443f-bf32-003d68a53cc4',
name = 'JPN CAP',
side = 'Japan',
type = 'Patrol',
subtype = 'AAW Patrol',
isactive = 'True',
starttime = '',
endtime = '',
SISH = 'False',
aar = 'table',
unitlist = 'table',
}
ミッション情報では,ScenEdit_GetMission ()の次に以下の文字列を加えることによって各タイプのミッションがもつより詳細な情報を表示する.
- .ferrymission
- .mineclearmission
- .minemission
- .supportmission
- .patrolmission
- .strikemission
- .cargomission
--対空パトロールミッション"JPN CAP"の情報
>> local side = "Japan"
local mission = "JPN CAP"
local mission = ScenEdit_GetMission (side,mission)
print(mission.patrolmission)
{ ProsecutionZone = {
[1] = { name = 'JADIZ #2' },
[2] = { name = 'JADIZ #3' },
[3] = { name = 'JADIZ #4' },
[4] = { name = 'JADIZ #5' },
[5] = { name = 'JADIZ #18' },
[6] = { name = 'JADIZ #19' }
},
TransitThrottleAircraft = Loiter,
GroupMemberEngageDistance = 5,
StationThrottleShip = Loiter,
BoatsToInvestigate = Group_x1,
UseFlightSize = 'Yes',
StationThrottleAircraft = Loiter,
CheckOPA = 'Yes',
StationThrottleSubmarine = Loiter,
GroupSize = 'Command_Core.Mission+_GroupSize',
FlightsToInvestigate = Flight_x1,
AttackDistanceAircraft = 80,
PatrolZone = {
[1] = { name = '0deg @10nm' },
[2] = { name = '60deg @10nm' },
[3] = { name = '120deg @10nm' },
[4] = { name = '180deg @10nm' },
[5] = { name = '240deg @10nm' },
[6] = { name = '300deg @10nm' }
},
AttackTerrainFollowingAircraft = 'No',
FlightSize = 'Command_Core.Mission+_FlightSize',
UseGroupSize = 'No',
LoopType = RandomWithinArea,
WingmanEngageDistance = 5,
OneThirdRule = 'Yes',
TransitTerrainFollowingAircraft = 'No',
OnStation = 0,
ActiveEMCON = 'No',
CheckWWR = 'Yes',
BoatsToEngage = All,
Type = AAW,
TransitThrottleSubmarine = Cruise,
FlightsToEngage = All,
MinAircraftReq = 'NoPreferences',
StationTerrainFollowingAircraft = 'No',
TransitThrottleShip = Cruise }
陣営レベルの操作
中立・味方の変更
陣営の敵味方を変更できます。
ScenEdit_SetSidePosture('A', 'B', 'H')
これでAとBをSide name(陣営の名前)として、
AはBをHostile(敵)とみなす。 (Bから見た敵味方は攻撃が実行されるまで変わらない)
- H でHostile
- U でUnfriendry
- N でNeutral
- F でFriendry
に変更できる
プレイヤー陣営を変更する
switchtoオプションを使用してプレイヤーが操作する陣営を強制的に切り替えできる
local side = side -- 陣営名
ScenEdit_SetSideOptions ({Side=side, switchto=true})
機雷原を設定する - ScenEdit_AddMinefield()とScenEdit_DeleteMinefield()
機雷のDBID(種類により最大敷設可能深度があるので注意),機雷数(全部は敷設されないことが多い),作動遅延時間,機雷原エリアの頂点となる各RPを設定する
2416 - Dummy
2463 - Bottom, Simple 150ftくらい
2462 - Bottom, Advanced
2464 - Bottom, Unsweepable, Shallow-only
2466 - Bottom, Unsweepable
2465 - Bottom, Unsweepable
632 - Bottom Magnetic
2461 - Bottom Total Field Magnetometer Fuze
2582 - Drifting - 敷設されない模様
634 - Floating
633 - Moored
2581 - Rising
876 - SLMM Mod.1
662 - SLMM Mod.2
2422 - CAPTOR(潜水艦専用)
3404 - PMK-2(潜水艦専用)
3465 - PMT-1
3398 - EM-52
2086 - Mk62 (Mk82
2088 - Mk83
2089 - Mk65 (2000lb)
local side= ScenEdit_PlayerSide()
local dbid = 633
local number = 20
local delay = 0
local area = {"Minefield #1", "Minefield #2", "Minefield #3", "Minefield #4"}
ScenEdit_AddMinefield ( {side=side, dbid=dbid, number=number, delay=delay, area=area } )
ScenEdit_DeleteMinefield()で指定したエリア内の機雷を削除する
local side= ScenEdit_PlayerSide()
local area = {"Minefield #1", "Minefield #2", "Minefield #3", "Minefield #4"}
ScenEdit_DeleteMinefield({side=side, area=area } )
マップ操作
指定座標に基準ポイントを生成する
lat='N40.00.00'
lon='W70.40.00'
ScenEdit_AddReferencePoint({side="playerside", lat=lat, lon=lon, locked=true})
基準ポイントその1をもとに基準ポイント2を生成する
local side = ScenEdit_PlayerSide() --陣営
local rpname = "RP-4" --基準ポイントその1
local bearing = 90 --基準ポイントその1からの角度
local distance = 10 --基準ポイントその1からの距離
基準ポイント2を生成
local rpfrom =ScenEdit_GetReferencePoint({side=side, name=rpname})
local newrp = World_GetPointFromBearing({latitude=rpfrom.latitude, longitude=rpfrom.longitude, bearing=bearing, distance=distance})
ScenEdit_AddReferencePoint({side=side, latitude=newrp.latitude, longitude=newrp.longitude, highlighted=false, locked=true})
選択したユニットのまわりに基準ポイントを生成する
local side= ScenEdit_PlayerSide()
local guid = ScenEdit_SelectedUnits().units[1].guid
local unit = ScenEdit_GetUnit({guid=guid})
local circle = World_GetCircleFromPoint({latitude=unit.latitude,
longitude=unit.longitude, numpoints=24,radius=150})
for k, v in ipairs(circle) do
ScenEdit_AddReferencePoint({side=side, latitude=v.latitude,
longitude=v.longitude, highlighted=true, locked=false})
end
ユニットレベルの操作
ユニットの設置
ユニットを新規生成する
ユニットを新しく生成するにはScenEdit_AddUnit()を使用する.想定されていない増援等を行いたい場合はこちら
ScenEdit_AddUnit({type = 'ユニットタイプ', unitname = 'ユニット名', dbid = DBID, side = '陣営', Lat="緯度",Lon="経度",guid = 'GUID設定'})
typeは'Facility', 'Ship', 'Submarine', 'Aircraft'のうち一つ DBIDはDB viewerでユニットを表示した際に左上に出る数字
実例-ユニットタイプは(陸上)施設、名前はKadena AFB、DBIDは430、陣営はJSDF、緯度が北緯21度21分12秒(南緯の場合マイナス、-nn.nn.nn)、経度が東経127度45分55秒(西経はマイナス)、GUID(シナリオ内でのユニットのID、後述の用途に使う)がKadena123
ScenEdit_AddUnit({type = 'Facility', unitname = 'Kadena AFB', dbid = 430, side = 'JSDF', Lat="26.21.12",Lon="127.45.55",guid = 'kadena123'})
--N36.10.50, E140.24.52に"Hyakuri Airbase"という名前の飛行場を追加する
local side = ScenEdit_PlayerSide()
local name = 'Hyakuri Airbase'
local unittype = 'Facility'
local dbid = 1714
local lat = '36.10.50'
local lon = '140.24.52'
local heading = 45 --飛行場の針路はゲーム中表示されないが着陸機の飛行方向に影響
local unit = ScenEdit_AddUnit({side=side, name=name, type=unittype, dbid=dbid, lat=lat, lon=lon, heading=heading})
既存ユニットの位置を変更する
すでにシナリオ内に存在するユニットの位置を変更するにはUnitテーブルのlatitudeおよびlongitude値に座標を入力して変更する
local guid = '87YZY5-0HMNQ0PA58NEB' --ユニットのGUID
local unit = ScenEdit_GetUnit({guid=guid})
unit.latitude = "N11.22.33"
unit.longitude ="E11.22.33"
事前にマガジンやマウント等をいじったユニットを増援として登場させたいなら地球の反対側などシナリオに関係のないところにユニットを待機させておき,こちらの方法でユニットを登場させたほうがいいかもしれない
衛星を追加する
https://www.matrixgames.com/forums/search.php?keywords=updateorbit&fid%5B0%5D=10201&sid=6eb5d5cca91c2622b552a091a8cd6890
https://www.matrixgames.com/forums/viewtopic.php?f=10236&t=343398
https://www.matrixgames.com/forums/viewtopic.php?f=10236&t=353040&p=4658867&hilit=updateorbit#p4658867
https://www.matrixgames.com/forums/viewtopic.php?f=10236&t=374128&p=4901845&hilit=updateorbit#p4901845
https://www.matrixgames.com/forums/viewtopic.php?f=10230&t=374189&p=4902431&hilit=updateorbit#p4902431
基地へのユニットの追加
ScenEdit_AddUnit()でbase値を指定すると生成ユニットがbaseで指定した基地ユニット内に収容される
一機だけの場合
ScenEdit_AddUnit({type = 'ユニットタイプ', unitname = 'ユニットの名前', dbid = DBID, side = '陣営', base = '基地のGUID', LoadoutID = 兵装ナンバー, ignoremagazines = 基地内の兵器ストックの確認})
実例-ユニットタイプは航空機、名前は67th Fighter Squadron、DBIDは4638、陣営はJSDF、基地のGUIDはkadena123、LoadoutIDは25580, 基地の武器ストックは無視。
ScenEdit_AddUnit({type = 'Air', unitname = '67th Fighter Squadron', dbid = 4638, side = 'JSDF', base = 'kadena123', LoadoutID = 25580, ignoremagazines = 1})
typeは'Facility', 'Ship', 'Submarine', 'Aircraft'のうち一つ
DBIDはDB viewerでユニットを表示した際に左上に出る数字
LoadoutIDはDBviewerで航空機を見た際にAircraft Loadouts欄の一番右に出てくるDB ID#の数字
ignoremagazines = 1でその基地に兵装用の武器のストックがなくても武装できる。
複数の場合
実例
for planes = 1, 12, 1 do
ScenEdit_AddUnit({type = 'Air', unitname = '67th Fighter Squadron #'..planes, dbid = 4638, side = 'JSDF', base = 'kadena123', LoadoutID = 25580, ignoremagazines = 1})
end
for planes = 1, 12, 1 で12機追加できる。真ん中の文字でユニットの数を変更できる。ユニット名の#の後に順に数字が1から追加されていく。
基地に武器をストックする
せっかくLuaで基地を追加しても武器ストックがなければ再武装できないので、武器を追加する。
ScenEdit_AddWeaponToUnitMagazine({guid = '基地のGUID', wpn_dbid= DBID, number=数})
実例 基地のguidがkadena123、武器のDBIDが51で、数を200追加する。
ScenEdit_AddWeaponToUnitMagazine({guid = 'kadena123', wpn_dbid= 51, number=200})
GUIDはこの場合兵装をストックするユニットのGUID、single unit Airfieldなら基地のGUIDだが、滑走路ユニット等の複数のユニットで編成されている場合はAmmo Revetment等のGUIDを指定すること。
DBIDはDB viewerでユニットを表示した際に左上に出る数字。
ロードアウトIDを指定して「ミサイルAが4発とミサイルBが2発のロードアウトを30回分追加する」という方法も可(ロードアウトIDはで航空機DB viewerのロードアウト一覧から確認する)
local unit = 'Moi Air Base'
local loadoutid = 627
local quantity = 30
ScenEdit_FillMagsForLoadout({unit= unit, loadoutid=loadoutid, quantity=quantity})
ユニットの陣営変更 - ScenEdit_SetUnitSide()
- ScenEdit_SetUnitSide()
間違えて間違った陣営にユニットを置いちゃって置き換えるのがめんどくさい場合は使える。(もし空母に戦闘機を置いている場合空母だけじゃなくて飛行機にもやらないといけないから注意。)
もちろんEventのActionでLua Scriptを使って同じことをゲーム中に再現できる。指揮下の部隊を変更する際に使える。
スクリプト
スクリプト自体は下のようになる。雛形を挿入できるようになっているので活用しよう。
ScenEdit_SetUnitSide({side="ユニットが存在する陣営の名前",name="ユニット名",newside="入れたい陣営"})
もしJAPAN陣営のPG 824 HayabusaをJAPAN (JMSDF)に変更させたい場合は以下のようになる。
ScenEdit_SetUnitSide({side="JAPAN",name="PG 824 Hayabusa",newside="JAPAN (JMSDF)"})
もしうまく作動しない場合は陣営名等をRename機能のところからコピー&ペーストでやるとうまくいくかも。二バイト文字は避けるべき。
元陣営のユニット全部を新陣営に所属変更
VP_GetSide()により得られるSideラッパーに陣営のユニット一覧 (units)が含まれているのでそれぞれにSetUnitSide()を実行していく
local oldside = "元陣営の陣営名およびGUID"
local newside = "新陣営の陣営名およびGUID"
local side = VP_GetSide ({side = oldside})
for k, v in pairs(side.units) do
ScenEdit_SetUnitSide({side = oldside, guid = v.guid, newside = newside})
end
ユニットの損傷/破壊
損傷 - ScenEdit_SetUnitDamage ()
https://commandlua.github.io/assets/Function_ScenEdit_SetUnitDamage.html
ユニットの強制損傷を実行します。自爆とかの再現等に使用できます。
ScenEdit_SetUnitDamage({side='陣営名', unitname='ユニットネーム', fire=(火災被害率),flood=(浸水率),dp=(ダメージpoint),components={{'破壊箇所','Heavy/Meidium/Smallの中から一つ'}}})
使用例
陣営North Koreaのスパイ船にエンジンルームに重度の損傷、火災2%、及び浸水3%を発生させ5dpダメージポイントを与える。
ScenEdit_SetUnitDamage({side='North Korea', unitname='Commercial Fishing Boat [35m, Spy Boat]', fires=2,flood=3,dp=5,components={{'Diesels','Heavy'}}})
スパイ船は35dp持っているので小破程度なる。
Componentsは部位破壊を行いたい場合のみ追加する。
ユニットを通信途絶させる - OutOfComms=true/false
ScenEdit_SetUnit()でOutOfComms=trueと設定すると,ユニット通信装備故障の有無にかかわらず強制的に通信途絶状態になる.通信途絶から復帰したければOutOfComms=falseと設定する.
local guid = guid
ScenEdit_SetUnit({guid =guid, OutOfComms=true})
ScenEdit_SetUnit({guid =guid, OutOfComms=false})
ユニットを削除する・破壊する - DeleteUnit()とKillUnit()
どちらも最終的にユニットが消滅するが,処理の仕方が異なる.
ScenEdit_DeleteUnit()ではユニットを削除するだけ.ユニット破壊がトリガーとなっているイベントが発生しない.
ScenEdit_KillUnit()ではユニットを破壊している.破壊トリガーイベントが発生する上,陣営の損失にもカウントされる.
ScenEdit_DeleteUnit({side = "United States", unitname = "USS Abcd" })
ScenEdit_KillUnit({side = "United States", unitname = "USS Abcd" })
ユニットの燃料ステータス表示・燃料残量変更
https://commandlua.github.io/assets/DataTypes.html#dataType_Fuel
https://www.matrixgames.com/forums/viewtopic.php?p=4067311#p4067311 も参照
燃料ステータス表示
以下の燃料タイプからなるFuelテーブルを表示させる
- 1001 = NoFuel
- 2001 = AviationFuel(航空燃料)
- 3001 = DieselFuel(艦艇ディーゼル燃料)
- 3002 = OilFuel
- 3003 = GasFuel
- 4001 = Battery(潜水艦バッテリー残量)
- 4002 = AirIndepedent(潜水艦AIP燃料)
- 5001 = RocketFuel
- 5002 = TorpedoFuel
- 5003 = WeaponCoast
local guid = '87YZY5-0HMNQ0PA58NEB' --ユニットのGUID
local unit = ScenEdit_GetUnit({guid=guid})
print(unit.fuel)
燃料残量変更
- 参考:Starting Diesel Submarine/Ship Fuel Level
RE: Script To Generate Random Merchant Location + Traffic
ScenEdit_SetUnitで「fuel = { {燃料ID, 数値} }」とすると燃料残量を変更できる(ここでは3001=ディーゼル燃料の残量を9000に変更する)
fuel値の波括弧と,燃料タイプごとの括弧が二重に必要であるので注意
local guid = '8558e224-d1e3-4040-a087-9283267b1d1c' --ユニットのGUID
ScenEdit_SetUnit({guid=guid, fuel= { {3001, 9000} } })
max値=最大容量に対する割合で変更したい場合 数値は整数である必要がある(小数点があるとエラー)のでmath.floor()を使う
local guid = '8558e224-d1e3-4040-a087-9283267b1d1c' --ユニットのGUID
local unit = ScenEdit_GetUnit({guid=guid})
ScenEdit_SetUnit({guid=guid, fuel= { {3001, math.floor(0.5+unit.fuel[3001].max*0.7)} } })
ユニットにWaypointの作成
ユニットにWaypointを追加する
ScenEdit_SetUnit({guid='ユニットのGUID',course={{latitude='緯度', longitude='経度'}}, manualAltitude = '高度'})
実例:GUIDがsubmarine1、緯度が北緯17.0565979083558で、経度が西経-89.2178220232281、高度0(潜水艦なら=浮上)に向かうウェイポイント作成する。
ScenEdit_SetUnit({guid='submarine1',course={{latitude='17.0565979083558', longitude='-89.2178220232281'}}, manualAltitude = '0'})
ウェイポイントが複数必要な場合はまず空のcourseテーブルを定義し,table.insertを使ってウェイポイントテーブルを追加していく
local unit = EcenEdit_GetUnit({guid=GUID})
local course = {}
table.insert (course, {TypeOf = 'ManualPlottedCourseWaypoint', latitude=wp1.latitude, longitude= wp1.longitude, presetAltitude=6, presetThrottle=2})
table.insert (course, {TypeOf = 'ManualPlottedCourseWaypoint', latitude=wp2.latitude, longitude= wp2.longitude, presetAltitude=6, presetThrottle=2})
table.insert (course, {TypeOf = 'LandingMarshal', latitude=wp3.latitude, longitude= wp3.longitude, presetAltitude=6, presetThrottle=2})
unit.course=course
ユニットのWaypointを削除する
local guid = '87YZY5-0HMNOB5T4SJ1U'
ScenEdit_SetUnit({guid=guid, course= {} })
ユニットをミッションに参加させる
ScenEdit_AssignUnitToMission("ユニットネームまたはGUID", "ミッションの名前")
ミッションに目標を追加する
Strike Missionにターゲットを追加する。
ScenEdit_AssignUnitToMission('目標の名前またはGUID', 'ミッションの名前')
killer 552という名前のミッションに「a1d75aac-d6b1-4e35-8ce4-34969f115cd3」のGUIDを持つターゲットを追加する
ScenEdit_AssignUnitToMission('a1d75aac-d6b1-4e35-8ce4-34969f115cd3', 'killer 552')
ユニットにBarkを表示する
CMO v1.05よりBarkと呼ばれるテキストをユニットの横に表示させることができるようになった.
local unit = "Senjou Taro" --Barkを表示するユニットの名前
local text = "敵の潜水艦を発見!" --Barkの内容
local R = 255 --テキストカラーの赤成分 (0-255)
local B = 255 --テキストカラーの青成分 (0-255)
local G = 127 --テキストカラーの緑成分 (0-255)
local moveUpward = true --falseにするとテキストが浮き上がらない
local fade = true --falseにするとテキストがフェードアウトしない
local lifeTime = 5 --テキストの表示秒数
local fontSize = 30 --テキストフォントの大きさ
ScenEdit_CreateBarkNotification_Unit(unit, text, R, B, G,
moveUpward,fade,lifeTime,fontSize)
ユニットGUIDをコンタクトguidに変換する
ユニットのGUIDとコンタクトGUIDが違うのでそれの変換を行う。
value.guidをvalue.nameに変えればコンタクトネーム(e.g. SKUNK #53)に変換し、返します。
もしも探知しない場合は何も返さないので、Target Is Detectedなどのトリガーと組み合わせるとよし。
function getContactGUID(detecterside_guid, originalunitguid)
local unitA = ScenEdit_GetUnit({guid=originalunitguid})
for key, value in pairs(unitA.ascontact)do
if value.side == detecterside_guid
then return value.guid
else return "none"
end
end
end
使用例
上記のfunctionを入れたうえで
local A1 = getContactGUID("NNQBOL-0HMLCELCRRE66","dd153-yugiri")
print(A1)
コンタクトGUIDからユニットGUIDへの変換
こちらは非常に簡単
local contact = VP_GetContact({guid=contactguid})
return contact.actualunitid
指定したユニットにマウント追加
https://commandlua.github.io/assets/Function_ScenEdit_UpdateUnit.html も参照
例として指定したユニットにコンテナ発射機のカリブルミサイルを追加する(マウント4個=16発分)
local guid= '87YZY5-0HMNQ0PA3EA88' --対象ユニットのGUID
local dbid = 2914 --兵装自体のDBIDではなく"Add Weapon Mount"画面に表示されるIDであることに注意
local arc_mount = {"SMF2", "SMF1", "SMA2", "SMA1", "PMF2", "PMF1", "PMA2", "PMA1"}
for i = 1, 4 do
ScenEdit_UpdateUnit({guid=guid, mode="add_mount", dbid=dbid, arc_mount=arc_mount})
i = i+1
end
ユニットを爆発させる
- ScenEdit_AddExplosion( table )
ScenEdit_AddExplosion()を使うと任意の地点で爆発を発生させることができる
ScenEdit_GetUnit() でユニットの座標を取得したあと,爆発させる弾頭のDBIDを指定(DBビューアでWeaponエントリを調べる).ついでにScenEdit_PlaySound()で爆発音を再生する
--[[
弾頭DBIDの例 (CWDB/DB3K)
-210 = 250lb Mk81
-549/288 = 500lb Mk82
-302 = 1000lb Mk83
-521/299 = 2000lb Mk84
-1033 = 1kT nuclear
]]
local guid = "87YZY5-0HMFCCN38FA5J" --ユニットのGUID(あるいはユニット名を指定する)
local warheadid = 157 --爆発させる弾頭のDBID
---
local target = ScenEdit_GetUnit({guid=guid})
ScenEdit_AddExplosion({warheadid=warheadid, latitude=target.latitude, longitude=target.longitude, alitude=target.altitude})
ScenEdit_PlaySound("Impact_directhit_large.mp3")
(DB3K) ユニットを自爆できるようにする(カミカゼ爆弾の追加)
local guid = " ユニットのGUID"
local arc = {"PMF2", "PB1", "PB2", "SB1", "SB2", "SMF1"}
ScenEdit_UpdateUnit({guid=v, mode="add_mount", dbid=2668, arc_mount=arc })
カミカゼ爆弾(DBID=2668)をもつユニットは攻撃時敵ユニットに向かって突入していき,最終的に自爆する(攻撃ミッションを使うことも可能).
今のところCWDBにはカミカゼ爆弾のデータがないので使えない.
ミッションに編入されているユニット全部にカミカゼ爆弾追加
local side = "陣営名"
local mission = "ミッション名"
local mission = ScenEdit_GetMission(side, mission)
local arc = {"PMF2", "PB1", "PB2", "SB1", "SB2", "SMF1"}
for k, v in pairs (mission.unitlist) do
ScenEdit_UpdateUnit({guid=v, mode="add_mount", dbid=2668, arc_mount=arc })
end
グループ操作
https://commandlua.github.io/assets/Wrappers.html#wrapper_Group および
https://commandlua.github.io/assets/Tables.html#table_Formation
https://www.matrixgames.com/forums/viewtopic.php?p=5086247#p5086247
も参照
グループを作成する・ユニットをグループに編入する
local unit1 = ScenEdit_GetUnit({name='unit1name', guid="unit1guid"})
local unit2 = ScenEdit_GetUnit({name='unit2name', guid="unit2guid"})
local group = "groupname" --ユニットを編入するグループ名(なければ新規作成)
unit1.group = group
unit2.group = group
指定したユニットをグループリーダーにする
local unit1 = ScenEdit_GetUnit({name='unit1name', guid="unit1guid"})
local group = ScenEdit_GetUnit({name='groupname', guid="groupguid"})
group.group.lead = unit1.guid
グループメンバーの位置変更
local unit1 = ScenEdit_GetUnit({name='unit1name', guid="unit1guid"}) --グループリーダー
local unit2 = ScenEdit_GetUnit({name='unit2name', guid="unit2guid"}) --グループメンバー
--bearingはグループリーダーからみたグループメンバーのいる方位
--値は0-360以内である必要がある(これ以外の数値だとメンバーの位置が正しく設定されない)
bearing2=unit1.heading+120 --bearing2=unit1の針路+120度とした
if bearing2 <0 then
bearing2 = bearing2+360
elseif bearing2 >360 then
bearing2 = bearing2 %360
end
unit2.formation = {type=1 , sprint=false, bearing=bearing2, distance =5}
指定したユニットをグループから外す
CMO内では艦艇グループの一隻が行動不能になるとそれにつられてグループ全体が減速、場合によっては停止してしまう。
新しいグループを作って編入したい場合はグループ名を指定する
ScenEdit_SetUnit({side="陣営", guid ="ユニットのGUID", group = "適当な名前"})
--実例
ScenEdit_SetUnit({side="Red", unitname="DD 154 Amagiri", group = "unitv"})
単にグループから解除したい場合はgroup="none"と指定する
local unit1 = ScenEdit_GetUnit({guid=unit1guid})
unit1.group="none"
イベント等の操作
イベントをアクティブ/インアクティブにする
EventのConditionの代わりに使えます。
一々Luaで記述する必要がない分この方が楽なときもあるかもしれません。
trueをflaseにすればイベントを停止できます。
ScenEdit_SetEvent('イベント名', {Isactive='true'})
Special Actionをアクティブ/インアクティブにする
ScenEdit_SetSpecialAction({ActionNameOrID='Special Actionの名前かID',Isactive=true})
trueをfalseに変えればインアクティブになる。
ゲーム内のUNIX時間を表示する
これはlua Consoleで使用できる。
実例
TimeA = ScenEdit_CurrentTime()
print(TimeA)
UNIX時間をDate型に変換する
Timeイベントトリガー等はDate型(2022-2-24 12:00:00)を使用している.さらにメッセージで日付を表示するときなどUNIX時間からの変換が必要となることがある
参考:http://noriko3.blog42.fc2.com/blog-entry-128.html
local currenttime=ScenEdit_CurrentTime()
return os.date("!%Y-%m-%d %X", currenttime)
1970年以前(UNIX時間が負の値をとるためos.time()が使えない)でも使えるバージョン
Lua解読分析集#yea69342をもとに,加算する値を3155760000(2070/1/1 00:00:00,1970年の100年後)にした.これなら1900/3/1-1980/2/28までは閏日が来ても日付のずれは起きない
local currenttime = ScenEdit_CurrentTime()
local time
if currenttime <0 then
time= os.date("!*t", ScenEdit_CurrentTime()+3155760000)
time = (time.year-100).. "-" ..string.format("%02d", time.month).. "-" ..string.format("%02d", time.day).. " "
..EpochToUTC_Time(currenttime)
else
time = os.date("!%Y-%m-%d %X", currenttime)
end
print(time)
指定時間でbooleanを返す
これはEvent内Conditionで使用できる。
実例
TimeA = ScenEdit_CurrentTime()
if (TimeA == 時間) then
return true
else
return false
end
時間はUNIX時間を使用する。変換サイトはこちら。
イベントが起動してから指定時間後に別のイベントを発動
これはイベントのluaアクションで使用できる。
作戦は、(1)まず現在時刻を取得してそれに指定時間を足す。(2)取得した時間はunix時間なので、トリガーが読み込む普通のフォーマットに変える。(3)一応ちゃんと使えるかデバッグするためにprint()で書き出す。(4)トリガーを作成。
その後はイベントを作ってその中にトリガーとアクションを追加する。
実例
- トリガーの作成
local timeEVENT1_unix = ScenEdit_CurrentTime() +20;まず現在時刻をゲット、それに今回の場合20秒足している
timeEVENT1_string = os.date("%Y/%b/%d %H:%M:%S",timeEVENT1_unix)
今得ている変数はunix時間なので、ストリング型に変更
print(timeEVENT1_string)
デバッグ目的 ここでEVENT1_stringの時間があっているか確認
ScenEdit_SetTrigger ({Description = "trigger1", Mode = "add", name = "Trigger1", type = "Time", Time = timeEVENT1_string})
EVENT1_stringの時間をもとに、trigger1という名前のトリガーを作成
最後の行、ScenEdit_SetTriggerの Description = "trigger1" はDescriptionの代わりにnameを使っても問題ないはず。
- イベントの作成
- ScenEdit_SetEvent ("event1", {Description = "Event1", Mode = "add"})
event1という名前のイベントを作成
- ScenEdit_SetEventTrigger ("event1",{mode = "add", name = "trigger1"})
event1にtrigger1(上記作成)という名前のトリガーを追加
- ScenEdit_SetEventAction('event1', {mode='add', name = "msg:temp"})
event1にmsg:tempという名前のアクションを追加
- ScenEdit_SetEvent ("event1", {Description = "Event1", Mode = "add"})
ScenEdit_SetEvent での Description = "Event1" の下りは表示 (description)と実際の名前(name)を変えたいときにのみ利用。多分あまりないと思う。
アクションについては事前にエディタで通常通り作成してもここに入れられる。アクションについては同じイベントでluaで作ってもいいと思うが、事前に作っておいた方がコードが少なくていいと思う。
で、上の文をまとめるとこんな感じ
local timeEVENT1_unix = ScenEdit_CurrentTime() +20;--get time, add 20second
timeEVENT1_string = os.date("%Y/%b/%d %H:%M:%S",timeEVENT1_unix) --convert unix time to string format
print(timeEVENT1_string) --debug purpose, check time_string
ScenEdit_SetTrigger ({Description = "trigger1", Mode = "add", name = "Trigger1", type = "Time", Time = timeEVENT1_string})--create time trigger, based on timeEvent1
ScenEdit_SetEvent ("event1", {Description = "Event1", Mode = "add"})--creating event called "event1", displayed as "Event1" (Description = "Event1", is optional; does not required to create the event)
ScenEdit_SetEventTrigger ("event1",{mode = "add", name = "trigger1"})--add Trigger to "event1"
ScenEdit_SetEventAction('event1', {mode='add', name = "msg:temp"})--add action to "event1"
ちなみに昔のKC45はluaがさっぱりわからなかったのでside pointをforループの変数にして1秒ごとに足させてた。疑似的にこれと似たようなものを作れるけど多分重くなる。
- 使い道
使い道としてはプレイヤーからのアクションがあった際に、タイムラグを発生させることに使えるはず。例えばプレイヤーが空中給油機の応援を要請してから一時間後に味方陣営から出撃するようにしたり、プイレイヤーが越境攻撃を始めてから3時間後に核弾頭搭載のミサイルが発射されるといった具合に使えるはず。時間をランダムにするトリガーでも、時間変数を二つにすれば似たようなものが作れるはず。
バンザーイ!(音声ファイル再生)
下準備:
- https://commons.nicovideo.jp/material/nc133845 から音源を入手する.
- ファイル名を適当な名前にする(ここでは"banzai.mp3"とする)
- "banzai.mp3"を"CMOゲームファイル/Sound/Effects/"に移動する.
- Effectsフォルダ内に新規作成したフォルダ(voicesとする)への移動も可.
Effectsフォルダにある場合は音声ファイル名をそのまま指定する.
>ScenEdit_PlaySound("banzai.mp3")
voicesフォルダにある場合,音声ファイル名の前にフォルダの位置を指定する,
>ScenEdit_PlaySound("voices/banzai.mp3")
これを使うとイベント発生時に好きな音源(「敵の潜水艦を発見!」)を再生させられる.
選択肢つきメッセージダイアログを表示する
UI_CallAdvancedDialog ()で選択肢のあるメッセージダイアログを表示させることができる.
ただしプレーンテキスト限定、選択肢がすぐ見切れるなど短所が多く後述のUI_CallAdvancedHTMLDialog()を使ったほうが良いと思われる
local title = "冬戦争"
local description = [[ 1939年8月にドイツとソ連が不可侵条約を締結したことで、戦いの
矛先はフィンランドへ向けられる。この条約においてドイツはソ連
に、フィンランドを含めたバルト諸国の併合も認めた。当然ながらこ
れはすべて秘密協定であった。しかし時間とともにその密約は
フィンランド政府の知るところとなる。ソ連との軍事的緊張の高ま
りを受け、フィンランドがドイツに援助を求めたとき、ドイツはこれ
に応じない姿勢を示したのだ。もしもソ連と戦争になった場合、フ
ィンランドは大国にたった一国で立ち向かわねばならないというこ
とだ。そうした状況の中、ソ連がフィンランド領内に軍事基地を建
設する許可を求めてきた。だがフィンランドはこれを拒絶した。そ
して1939年11月30日、ソ連は1932年に結ばれた不可侵条約を破
棄、フィンランドへの侵攻を開始する。こうして始まった"冬戦争"
は1940年3月13日のモスクワ講和条約をもって終結、フィンランド
はソヴィエト連邦に南東部を割譲することとなった。
(決定のもたらす影響については、ボタンにカーソルを重ねると表
示される説明をご覧ください。)]]
local interactions = {"かかってこい! 相手になってやる!","ソ連の圧力に屈する"}
local decision = UI_CallAdvancedDialog (title, description, interactions)
print(decision)
その2:
UI_CallAdvancedHTMLDialog()(スクリプト例のHTMLコードが変換されてしまっているのでページソースを直接参照すべし)
HTML形式のフォームを作成する方法。フォーム内のテキストボックス、セレクトボックス、ラジオボタンに変数名を付けられる。画面下選択肢を押したときに選択肢と各変数を返す。
::point1::
local text = [[
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<STYLE>
body {
background-color: #3c3f46;
color: #FFFFFF;
font-family: "MS Pゴシック" ;
}
</STYLE>
</head>
<body>
<P><i>Please select one of options at the end of message.</i></P>
<hr>
<h1>冬戦争</h1>
<p> 1939年8月にドイツとソ連が不可侵条約を締結したことで、戦いの<br>
矛先はフィンランドへ向けられる。この条約においてドイツはソ連<br>
に、フィンランドを含めたバルト諸国の併合も認めた。当然ながらこ<br>
れはすべて秘密協定であった。しかし時間とともにその密約は<br>
フィンランド政府の知るところとなる。ソ連との軍事的緊張の高ま<br>
りを受け、フィンランドがドイツに援助を求めたとき、ドイツはこれ<br>
に応じない姿勢を示したのだ。もしもソ連と戦争になった場合、フ<br>
ィンランドは大国にたった一国で立ち向かわねばならないというこ<br>
とだ。そうした状況の中、ソ連がフィンランド領内に軍事基地を建<br>
設する許可を求めてきた。だがフィンランドはこれを拒絶した。そ<br>
して1939年11月30日、ソ連は1932年に結ばれた不可侵条約を破<br>
棄、フィンランドへの侵攻を開始する。こうして始まった"冬戦争"<br>
は1940年3月13日のモスクワ講和条約をもって終結、フィンランド<br>
はソヴィエト連邦に南東部を割譲することとなった。</p>
<p><i>(決定のもたらす影響については、ボタンにカーソルを重ねると表<br>
示される説明をご覧ください。)</i></p>
<hr>
<table>
<caption>DECISIONS:</caption>
<tr>
<td>
<input type="radio" name="option" value="0" id="0">
<label for="0">かかってこい! 相手になってやる!</label>
</td>
</tr>
<tr>
<td>
<input type="radio" name="option" value="1" id="1">
<label for="1">ソ連の圧力に屈する</label>
</td>
</tr>
</table>
</body>
</html>
]]
local button = UI_CallAdvancedHTMLDialog("冬戦争", text, {"DECISION"})
print(button)
if not button.option then
print("選択なし")
goto point1
end
いっそ生成AIに書かせればよくね???
最近生成AIにスクリプトを書かせた報告がいくつか上がっているが、存在しないデタラメ関数を使うことが多いそうな。

