Standalone ScenarioおよびCampaignで使用されているシナリオ作者以外誰にも使いこなせなさそうなLuaを解読してみるページ
Lua Script実用例集/LuaInitに改名する?
ここでは"LuaInit"(シナリオロード時に行われる各関数の読み込み)を見ていく
目次
- 目次
- 各パラメーターの設定・管理関連
- RunScript(fileName)
- LuaReset()
- ConfirmSpecialAction(actionDescription)
- ConvertStringToBoolean(stringName)
- IsBetaVersion(booleanValue)
- DebugModeIsOn(booleanValue)
- BugMessage(eventName,description)
- Round(num, numDecimalPlaces)
- ReturnTimeStringAsNumberOfMinutes
- ShuffleTable( t )
- ChangeScore(side,amt,reason)
- マップ関係
- メッセージ関連
- RadioSoundEffect()
- DTG(TimeVar)
- DTGPreEpoch(timeVar)
- GenerateRadioMessageBody(theMessage,callsign)
- RadioMessage(band,frequency,theMessage,location)
- ACP126(rec_station,snd_station,precedence,from,to,classification,body)
- TelexMessageToPlayer(rec_station, snd_station, precedence, from, to, classification, body, location)
- RegisterMessage(messageString)
- ReplayMessages()
- 天候関連
- ユニット関連
- 2陣営シナリオ用関数
- 敵対設定用関数
- SAR関連
- 通信攪乱関連
各パラメーターの設定・管理関連
- scenarioScriptFilePath = '/BrassDrum/'
シナリオ用Luaフォルダの場所
- IsBetaVersion(true)
IsBetaVersion関数の実行に影響
- scenarioZuluOffset = 0
シナリオが行われる場所の時差
- inDevelopment = true
2陣営シナリオ関連の関数実行に影響
RunScript(fileName)
Luaファイルを呼び出し実行する,シナリオLuaフォルダの場所名と拡張子.luaを書く必要のない工夫がされている
function RunScript(fileName)
local scriptFilePath = scenarioScriptFilePath..fileName..'.lua'
print ('Attempting to execute '..scriptFilePath)
if ScenEdit_RunScript(scriptFilePath) then
print ('Success!')
end
end
LuaReset()
Keyvalueをすべて削除+LuaInit.luaを再読み込みする
function LuaReset()
print ('Resetting...')
ScenEdit_ClearKeyValue("")
print ('KeyValues cleared.')
RunScript('LuaInit')
end
ConfirmSpecialAction(actionDescription)
特別アクションの実行確認らしいが使用例未確認
function ConfirmSpecialAction(actionDescription)
local choice = ScenEdit_MsgBox('Are you sure you want to execute the special action: \n \n'..actionDescription, 4)
if choice == 'Yes' then
return true
else
ScenEdit_MsgBox('Event Cancelled')
return false
end
end
ConvertStringToBoolean(stringName)
keyvalueにしたbooleanを再変換する
(keyvalueがbooleanの場合そのまま読み込まれるのでわざわざ再変換しなくていいんだけど)
function ConvertStringToBoolean(stringName)
local stringName = string.upper(stringName)
local result = false
if stringName == 'TRUE' then
result = true
end
return result
end
IsBetaVersion(booleanValue)
trueだと一部関数でで管理メッセージが出る
function IsBetaVersion(booleanValue)
if booleanValue == true then
ScenEdit_SetKeyValue('betaVersion','true')
return true
elseif booleanValue == false then
ScenEdit_SetKeyValue('betaVersion','false')
return false
else
local betaStatus = ScenEdit_GetKeyValue('betaVersion')
local result = ConvertStringToBoolean(betaStatus)
return result
end
end
DebugModeIsOn(booleanValue)
trueだと一部関数実行時に確認メッセージが表示される
function DebugModeIsOn(booleanValue)
if booleanValue == true then
ScenEdit_SetKeyValue('debugMode','true')
return true
elseif booleanValue == false then
ScenEdit_SetKeyValue('debugMode','false')
return false
else
local debugStatus = ScenEdit_GetKeyValue('debugMode')
local result = ConvertStringToBoolean(debugStatus)
return result
end
end
BugMessage(eventName,description)
function BugMessage(eventName,description)
if IsBetaVersion() then
ScenEdit_MsgBox('An issue occured with '..eventName..';\n'..description..'\n\nThis will not affect system stability but may affect scenario balance. \n\nPlease report this in the Beta Testing Forum. \n\nThanks!', 0)
else
ScenEdit_MsgBox('An issue occured with '..eventName..';\n'..description..'\n\nThis will not affect system stability but may affect scenario balance. \n\nPlease report this in the Tech Support subforum on the Matrix Games forum, including a screenshot of this message. \n\nhttp://www.matrixgames.com/forums/tt.asp?forumid=1279', 0)
end
end
Round(num, numDecimalPlaces)
四捨五入する(四捨五入する値,表示桁数)
function Round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
ReturnTimeStringAsNumberOfMinutes
Unitラッパーのairbornetimeは航空ユニットの飛行時間を"2 hr 15 min"のように表記するが,この" X hr X min"文字列を分単位の数値に変換する(ここに使用例がある)
airbornetimeが1時間以上かつ1日未満でないと機能しない(飛行時間を秒として返すairbornetime_vを使ったほうが楽だと思われるが…?)
- targetStringが「25」など長さが3未満である(=すでに分の数値)場合は,文字列を数値としてそのまま返す,長さが3以上だと" ** hr ~~ min"形式であるみなされる(もっとも長さが3以上でも「100」のような数値だけだと関数は結果を返さない)
- targetString内から" hr"の文字列がある個所を探し,targetStringの1文字目から" hr"がある個所の1文字前まで,すなわち時間をhourとして取得する
- targetString内から" min"の文字列がある個所を探し,targetStringの" hr"がある個所より("hr"の2文字を飛ばした)3文字目から" min"がある個所の1文字前まで,すなわち分をminとして取得する
- (hour*60)+minuteの計算をして飛行時間を分に変換
function ReturnTimeStringAsNumberOfMinutes(targetString)
if string.len(targetString) < 3 then --Is this already a number of minutes?
result = tonumber(targetString)
else --if not, parse the string to get the values
local hourDelimiter = string.find(targetString,' hr')
if hourDelimiter ~= nil then
hour = string.sub(targetString,1,hourDelimiter-1)
end
local minuteDelimiter = string.find(targetString,' min')
if minuteDelimiter ~= nil then
minute = string.sub(targetString,hourDelimiter+3,minuteDelimiter-1)
end
result = (hour*60)+minute
end
return result
end
ShuffleTable( t )
テーブルの入れ替え
function ShuffleTable( t )
local rand = math.random
assert( t, "ShuffleTable() expected a table, got nil" )
local iterations = #t
local j
for i = iterations, 2, -1 do
j = rand(i)
t[i], t[j] = t[j], t[i]
end
end
ChangeScore(side,amt,reason)
陣営現在の得点に加点・減点
function ChangeScore(side,amt,reason)
local newScore = ScenEdit_GetScore(side) + amt
ScenEdit_SetScore(side,newScore,reason)
print (side..' score changed to '..newScore)
return newScore
end
マップ関係
ConvertDecimalPositionToDegrees(latitude,longitude)
10進法座標から60進法座標への変換(緯度,経度)
10進数法座標=60進法度+(60進法分/60)+(60進法秒/60/60)であることを理解する(参考→軽~く軌道計算! 換算.すなわち
- 10進法1=60進法1度
- 10進法1/60=0.0167=60進法1分
- 10進法1/3600=0.000278=60進法1秒
であり,さらに
- 10進数法座標の整数部分が60進法度
- 1. の小数部分に60を乗算したもの「(10進数法座標-60進法度)*60」の整数部分が60進法分
- 2. の小数部分に60を乗算したもの「( (10進数法座標-60進法度)*60)-60進法分)*60」の整数部分が60進法秒
となる.
function ConvertDecimalPositionToDegrees(latitude,longitude)
local latitidePrefix, longitudePrefix
if latitude > 0 then
latitidePrefix = "N"
else
latitidePrefix = "S"
latitude = latitude*-1
end
local latitudeDegrees = math.floor(latitude)
local latitudeMinutes = math.floor((latitude - latitudeDegrees)*60)
local latitudeSeconds = (((latitude-latitudeDegrees)*60) - latitudeMinutes)*60
latitudeSeconds = Round(latitudeSeconds, 0)
if longitude > 0 then
longitudePrefix = "E"
else
longitudePrefix = "W"
longitude = longitude*-1
end
local longitudeDegrees = math.floor(longitude)
local longitudeMinutes = math.floor((longitude - longitudeDegrees)*60)
local longitudeSeconds = (((longitude-longitudeDegrees)*60) - longitudeMinutes)*60
longitudeSeconds = Round(longitudeSeconds, 0)
local result = (latitidePrefix..latitudeDegrees .. "°" .. latitudeMinutes .. "'" .. latitudeSeconds .. '", '..
longitudePrefix..longitudeDegrees .. "°" .. longitudeMinutes .. "'" .. longitudeSeconds .. '"')
return result
end
RandomPosition(latitudeMin,latitudeMax,longitudeMin,longitudeMax)
ランダムで地図上の座標を指定する(最小緯度,最大緯度,最小経度,最大経度)
- 最小緯経度,最大緯経度からランダムに度を決める
- 分と秒を決める
Commandにおいて10進数座標は13桁の数値によって表される(もっとも60進法1秒=0.000278なので7桁あれば十分)のだが,math.random(1,(10^13)/(10^13)の計算によって10^-13 (0.0000000000001)~1の小数点値が出る.これが座標の分と秒となる.
- 度と分・秒の値を合計して10進法座標完成
function RandomPosition(latitudeMin,latitudeMax,longitudeMin,longitudeMax)
local lat_var = math.random(1,(10^13)) --random number between 1 and 10^13
local lon_var = math.random(1,(10^13)) --random number between 1 and 10^13
local pos_lat = math.random(latitudeMin,latitudeMax) + (lat_var/(10^13)) --latitude;
local pos_lon = math.random(longitudeMin,longitudeMax) + (lon_var/(10^13)) --longitude;
return {latitude=pos_lat,longitude=pos_lon}
end
CircularRandomPosition(x_latitude, x_longitude, max_radius)
ランダム位置の取得
- 指定座標中心に72個の点からなる円を生成する(半径は0.1-max_radiusからランダム)
- 72ある点のうち1点をランダムに選択する
function CircularRandomPosition(x_latitude, x_longitude, max_radius)
local randomisationCircle = World_GetCircleFromPoint({
latitude=x_latitude,
longitude=x_longitude,
radius=math.random(0.1,max_radius),
numpoints = 72})
local randomisedPoint = randomisationCircle[math.random(1,#randomisationCircle)]
return randomisedPoint
end
OverWater (latitude, longitude)
指定位置が海上か判定=高度0m未満
function OverWater (latitude, longitude)
local pointElevation = World_GetElevation({
latitude = latitude,
longitude = longitude})
if pointElevation < 0 then
return true
else
return false
end
end
JitterPosition(guid,radius,overWater)
- ユニットの位置を起点にCircularRandomPosition()でランダム位置を取得する
- ランダム位置をOverWater ()によって判定する(true=海上,false=陸上)
- overWaterの値と同じならユニットをランダム位置に移動させる
function JitterPosition(guid,radius,overWater)
if overWater == nil then overWater = false end
local unit = ScenEdit_GetUnit({guid=guid})
local newPos = CircularRandomPosition(unit.latitude,unit.longitude,radius)
if OverWater(newPos.latitude,newPos.longitude) == overWater then
ScenEdit_SetUnit({
guid=unit.guid,
latitude=newPos.latitude,
longitude=newPos.longitude
})
end
end
CleanUpIdleCivilianShips()
Lua解読分析集/Game_Setup#水上ユニット生成(方法1)においてウェイポイントつきの水上ユニットが生成されるが,最終ウェイポイントに到着した=ウェイポイント未設定か速力0の水上ユニットを削除する
function CleanUpIdleCivilianShips()
local unitList = VP_GetSide({side='Civilian'}).units
local numberOfCivilianUnits = #unitList
local numberOfUnitsDeleted = 0
for k,v in ipairs (unitList) do
local unit = ScenEdit_GetUnit({guid=v.guid})
if (unit.course[1] == nil or unit.speed == 0) and
unit.type == 'Ship' then
ScenEdit_DeleteUnit({guid=v.guid})
numberOfUnitsDeleted = numberOfUnitsDeleted + 1
end
end
if DebugModeIsOn() and numberOfUnitsDeleted > 0 then
ScenEdit_SpecialMessage('playerside','Civ_Cleanup fired. <BR>Initial civilian Units: '..numberOfCivilianUnits..' <BR>Civilian units cleaned up: '..numberOfUnitsDeleted)
end
end
メッセージ関連
RadioSoundEffect()
Effectフォルダにある無線音声ファイル"radioChirp1.mp3"から"radioChirp8.mp3"のいずれかを再生する
function RadioSoundEffect()
local fileName = 'radioChirp'..math.random(1,8)..'.mp3'
ScenEdit_PlaySound(fileName)
end
DTG(TimeVar)
メッセージの時間テンプレート
DTGSoviet(),DTGNonAligned()なども文面がやや異なるだけで機能同じ
function DTG(TimeVar)
if TimeVar == nil then
TimeVar = ScenEdit_CurrentTime()
end
local msgtime = os.date("!%d%H%M" .. "Z" .. " " .. "%b %y", TimeVar)
local msgtime = string.upper(msgtime)
return msgtime
end
DTGPreEpoch(timeVar)
シナリオ日時がUNIXエポックである1970年より前の場合,そのままではos.date()関数が使えないのでこちらを使う
参考:https://www.matrixgames.com/forums/viewtopic.php?p=4097200#p4097200
- 現在のUNIX時間に4070908800(2099/1/1 00:00:00,1970年の129年後)を加算する
- 年が129年進んでいる以外は月・日・時間・分・秒が一致する(ただし閏年前後で日付ずれ発生,以下参照)
- タイムスタンプテーブルを取得しそこから日・時間・分・月を取得(string.format()をつかって二桁表記に直す)
- 最後に年-129の値を取得する(もっともここでは1966年なら「66」のように二桁表記にしたいので1900+129=2029を減算している
function DTGPreEpoch(timeVar)
if timeVar == nil then timeVar = ScenEdit_CurrentTime() end
local timeVar = timeVar + 4070908800 -- add seconds to bring year up to 2099 (+129 years)
local timeStampTable = os.date("!*t",timeVar) -- build timestamp table
local months = {'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'}
local messageTime = string.format('%02d',timeStampTable.day)..
string.format('%02d',timeStampTable.hour) ..
string.format('%02d',timeStampTable.min) ..
'Z ' ..
months[timeStampTable.month] ..
' ' ..
(timeStampTable.year-2029)
return messageTime
end
ただしこのスクリプトコードではもとの年と129年後の年とで閏年の来るタイミングが一致していないため,閏日が来たとき1年間にわたり日付がずれる欠陥がある.
| UNIX時間 | +4070908800 |
| 閏年でない | 閏年 |
| -89596800 | 3981312000 |
| 1967/3/1 00:00:00 | 2096/2/29 00:00:00 |
一年後
| UNIX時間 | +4070908800 |
| 閏年 | 閏年でない |
| -58060800 | 4012848000 |
| 1968/2/29 00:00:00 | 2097/2/28 00:00:00 |
次の日はどちらも3/1のため,次の閏日が来るまで日付が再一致する
1970年以降このコードを使うと68169600秒=閏年である1972/2/29 00:00:00を3/1と認識してしまい,しかも以降の日付で1日ずれた状態が続く.これは2100年が100で割り切れる数値でうるう年ではない(参考)のでUNIX時間+4070908800が4107542400 (2100/3/1 00:00:00)に到達したとき閏日が挿入されないため.
GenerateRadioMessageBody(theMessage,callsign)
(無線通信風メッセージの本文指定)
function GenerateRadioMessageBody(theMessage,callsign)
local result
if callsign == nil then callsign = 'unknown station' end
result = '<P>'..string.upper(callsign)..'<BR> <I>"'..theMessage..'"</I></P> '
return result
end
RadioMessage(band,frequency,theMessage,location)
無線通信メッセージのテンプレート
RadioMessageSoviet()とかRadioMessageNATO()とかも文言が若干違うだけでやってることは同じ
function RadioMessage(band,frequency,theMessage,location)
assert(theMessage,'RadioMessage(): No message passed!')
local DTG = DTG()
local theMessage = "<P>"..DTG..' <BR>'..band..' <BR>'..frequency..' </P>'..theMessage
if location ~= nil then
ScenEdit_SpecialMessage('playerside',theMessage,{latitude=location.latitude,longitude=location.longitude})
else
ScenEdit_SpecialMessage('playerside',theMessage)
end
RegisterMessage(theMessage)
RadioSoundEffect()
end
ACP126(rec_station,snd_station,precedence,from,to,classification,body)
テレックスメッセージのテンプレート
https://en.wikipedia.org/wiki/16-line_message_format
- rec_station --4 letter code (e.g. YDCX) 受信先のステーション名
- snd_station --4 letter code +/- NR 3 number (e.g. YBDN NR 270) 送信元のステーション名
- precedence --Flash (Z), Immediate (O), Priority (P), Routine (R), Flash Override (Y) 優先度
- dtg = DTG() 受信時刻
- from --e.g. MET FLT OPS 送信元
- to --e.g. SSN 21 SEAWOLF 受信先
- classification --Unclass +/- SBU / FOUO / NOFORN (Restricted), Confidential, Secret, Top Secret 機密度
- body 本文
function ACP126(rec_station,snd_station,precedence,from,to,classification,body)
_,gr = body:gsub("%S+","")
local sig_string = string.upper(
'<P><FONT face=Consolas>'..rec_station..' <BR>'..
'DE '..snd_station..' <BR>'..
precedence..' '..dtg..' <BR>'..
'fm '..from..' <BR>'..
'to '..to..' <BR>'..
'wd gr'..gr..' <BR>'..
'bt <BR>'..
classification..' <BR>'..
body..' <BR>'..
'bt <BR>'..
'nnnn </P>'
)
return sig_string
end
TelexMessageToPlayer(rec_station, snd_station, precedence, from, to, classification, body, location)
プレイヤー陣営にテレックスメッセージを表示する
function TelexMessageToPlayer(rec_station, snd_station, precedence, from, to, classification, body, location)
local theMessage = ACP126(rec_station, snd_station, precedence, from, to, classification, body)
if location ~= nil then
ScenEdit_SpecialMessage('playerside',theMessage,{latitude=location.latitude,longitude=location.longitude})
else
ScenEdit_SpecialMessage('playerside',theMessage)
end
ScenEdit_PlaySound('telex.mp3')
RegisterMessage(theMessage)
end
RegisterMessage(messageString)
メッセージの登録
function RegisterMessage(messageString)
local counter = 0
for int1 = 1, 10 do
local storedMessage = ScenEdit_GetKeyValue('storedMessage_'..int1)
if storedMessage ~= nil then
counter = counter + 1
end
end
if counter == 10 then
for int2 = 1, 10 do
local shiftedMessage = ScenEdit_GetKeyValue('storedMessage_'..int2)
local shiftedMessageSlot = int2 - 1
ScenEdit_SetKeyValue('storedMessage_'..shiftedMessageSlot,shiftedMessage)
end
messageNumber = 10
elseif counter <= 9 then
messageNumber = counter + 1
elseif counter == 0 then
messageNumber = 1
end
ScenEdit_SetKeyValue('storedMessage_'..messageNumber,messageString)
end
ReplayMessages()
最新のものからメッセージ表示
function ReplayMessages()
for i = 10,1,-1 do
local message = ScenEdit_GetKeyValue('storedMessage_'..i)
if message ~= nil and message ~= '' then
ScenEdit_SpecialMessage('playerside',message)
end
end
end
天候関連
Timeis(timeVar)
タイムテーブルから日付・時・分を抽出する
function TimeIs(timeVar)
if timeVar == nil then
timeVar = ScenEdit_CurrentTime()
end
local timeStampTable = os.date("!*t",timeVar)
local timeTable = {day = timeStampTable.day, hour = timeStampTable.hour, minute = timeStampTable.min}
return timeTable
end
WeatherReportIsDue()
現地時間が天候判定を行う0,6,12,18時かの判定
scenarioZuluOffset,TimeIs()と合わせて使う 現地時間を6で割った余りが0のとき=0,6,12,18時にtrueを返す
function WeatherReportIsDue()
local result = false
local hourZulu = TimeIs().hour
local hourLocal = hourZulu + scenarioZuluOffset
if hourLocal %6 == 0 then
result = true
end
return result
end
WeatherDrift(天候を変える)
function WeatherDrift()
local weatherBaseline = { seastate = 4, temp = 13, undercloud = 0.4, rainfall = 0 }
local seastateVariability = math.random(0,2)
local undercloudVariability = math.random(0,4)/10
local tempVariability = math.random(-1,4)
local rainfallVariability = math.random(0,10)
local newTemp = weatherBaseline.temp + tempVariability
local newRainfall = weatherBaseline.rainfall + rainfallVariability
local newUndercloud = weatherBaseline.undercloud + undercloudVariability
local newSeastate = weatherBaseline.seastate + seastateVariability
ScenEdit_SetWeather(
newTemp, --temp
newRainfall, --rainfall
newUndercloud, --undercloud
newSeastate --seastate
)
end
ConvertTempCtoF(C温度をF温度に変換)
function ConvertTempCtoF(temp)
local result = Round((temp*1.8) + 32,0)
return result
end
GenerateRainDescriptor(降雨の説明値)
function GenerateRainDescriptor(rain)
local result
if rain == 0 then result = 'nil'
elseif rain < 5 then result = 'very light'
elseif rain < 11 then result = 'light'
elseif rain < 20 then result = 'moderate'
elseif rain < 30 then result = 'heavy'
elseif rain < 40 then result = 'very heavy'
else result = 'extreme'
end
return result
end
GenerateCloudDescriptor(雲の説明値)
function GenerateCloudDescriptor(cloud)
local result
if cloud == 0 then result = 'clear skies'
elseif cloud < 0.2 then result = 'light low clouds'
elseif cloud < 0.3 then result = 'light middle clouds'
elseif cloud < 0.4 then result = 'light high clouds'
elseif cloud < 0.5 then result = 'moderate low clouds'
elseif cloud < 0.6 then result = 'moderate middle clouds'
elseif cloud < 0.7 then result = 'moderate high clouds'
elseif cloud < 0.8 then result = 'moderate middle clouds & light high clouds'
elseif cloud < 0.9 then result = 'solid middle clouds & moderate high clouds'
elseif cloud < 1.0 then result = 'thin fog & solid cloud cover'
else result = 'thick fog & solid cloud cover'
end
return result
end
WeatherReport(現在の天候をメッセージ表示)
function WeatherReport(outlook)
if outlook == nil then outlook = 'next forecast at '..DTG(ScenEdit_CurrentTime()+21600) end
local weather, DTG = ScenEdit_GetWeather(), DTG()
local tempC, tempF, cloud, rain, sea = weather.temp, ConvertTempCtoF(weather.temp), GenerateCloudDescriptor(weather.undercloud), GenerateRainDescriptor(weather.rainfall), weather.seastate
local theMessage = ACP126(
'ALL',
'HYDR',
'r',
'HYDROGRAPHIC OFFICE TAUNTON',
'ALL STATIONS',
'unclass',
'WX REPORT '..DTG..' - ENGLISH CHANNEL <BR>AVERAGE TEMP '..tempC..'°C / '..tempF..'°F <BR> SEA STATE '..sea..' <BR>'..rain..' PRECIPITATION <BR>'..cloud..' <BR>'..outlook
)
ScenEdit_SpecialMessage('playerside',theMessage)
if not ScenIsInDevelopment then
RegisterMessage(theMessage)
end
end
ユニット関連
RandomiseUnitTableProficiency(unitTable)
ユニットについて練度をランダム設定する グループでは所属ユニットの練度が一律設定されてしまうので除外する
0=Novice (5%)
1=Cadet (20%)
2=Regular (50%)
3="Veteran (20%)
4=Ace (5%)
function RandomiseUnitTableProficiency(unitTable)
for k,v in ipairs (unitTable) do
local unit = ScenEdit_GetUnit({guid=v.guid})
if unit.type ~= 'Group' then
local chance = math.random(1,100)
if chance <=50 then proficiency = 2
elseif chance <=70 then proficiency = 3
elseif chance <=90 then proficiency = 1
elseif chance <=95 then proficiency = 4
elseif chance <=100 then proficiency = 0
end
ScenEdit_SetUnit({guid=v.guid,proficiency=proficiency})
end
end
end
RandomiseSideUnitProficiency(sideName)
RandomiseUnitTableProficiency()と合わせて指定陣営の全ユニットについて練度をランダム設定する
function RandomiseSideUnitProficiency(sideName)
local sideUnits = VP_GetSide({side=sideName}).units
RandomiseUnitTableProficiency(sideUnits)
end
ReturnUnitProficiencyAsNumber
指定ユニットの練度を数値に変換する
function ReturnUnitProficiencyAsNumber (unitGUID)
local proficiencyList = {
{stringName = 'Novice', numberValue = 0},
{stringName = 'Cadet', numberValue = 1},
{stringName = 'Regular', numberValue = 2},
{stringName = 'Veteran', numberValue = 3},
{stringName = 'Ace', numberValue = 4},
}
local unitProficiencyString = ScenEdit_GetUnit({guid=unitGUID}).proficiency
for k,v in ipairs (proficiencyList) do
if unitProficiencyString == v.stringName then
matchedValue = v.numberValue
end
end
if matchedValue == nil then
return 'Error! No match found'
else
return matchedValue
end
end
2陣営シナリオ用関数
プレイ可能な陣営が2つあるシナリオで使用される関数(コードは"Duelist"から)
ThisIsFirstLoad(booleanValue)
Scenファイルからの初回ロードであればtrue(関数実行部の最後でfalseに設定される)
function ThisIsFirstLoad(booleanValue)
local result
if booleanValue == nil then
result = ScenEdit_GetKeyValue('firstLoad')
if result == '' or result == nil then result = true end
if result == 'false' then result = false end
else
if booleanValue == true then
ScenEdit_ClearKeyValue('firstLoad')
result = true
elseif booleanValue == false then
ScenEdit_SetKeyValue('firstLoad','false')
result = false
end
end
return result
end
ClearSideReferencePoints(sideName)
プレイ陣営のRPをすべて消す...がエディタモードで開いてもRPが消えるという無能関数
function ClearSideReferencePoints(sideName)
local sideRPs=VP_GetSide({side=sideName}).rps
for k,v in ipairs(sideRPs) do
ScenEdit_DeleteReferencePoint({side=sideName,guid=v.guid})
end
end
SetupSideAsAI(sideName)
AI陣営に対してCivilianとNature陣営を友軍に設定する(誤射の回避)
function SetupSideAsAI(sideName)
ScenEdit_SetSidePosture('Civilian', sideName, 'F')
ScenEdit_SetSidePosture('Nature', sideName, 'F')
ScenEdit_SetDoctrine({side=sideName}, {
weapon_control_status_air = 1,
weapon_control_status_surface = 1,
weapon_control_status_subsurface = 1,
weapon_control_status_land = 1,
})
end
関数実行部
- 初回ロード時プレイヤー陣営とAI陣営判定
- inDevelopment=trueならClearSideReferencePoints()とSetupSideAsAI()の実行,ThisIsFirstLoad()をfalseに設定する各確認,falseなら自動実行
if ThisIsFirstLoad() then math.randomseed(os.time()) local playerSide = ScenEdit_PlayerSide() local enemySide = 'USSR' if playerSide == 'USSR' then enemySide = 'United Kingdom' end
if inDevelopment then --ask to do stuff
local userInput = string.upper(ScenEdit_MsgBox('Clear RPs for '..playerSide..'?',1))
if userInput == 'OK' then
ClearSideReferencePoints(playerSide)
end
userInput = string.upper(ScenEdit_MsgBox('Setup '..enemySide..' as AI opponent?',1))
if userInput == 'OK' then
SetupSideAsAI(enemySide)
end
userInput = string.upper(ScenEdit_MsgBox('Set firstLoad key value to false?',1))
if userInput == 'OK' then
ThisIsFirstLoad(false)
end
else --don't give the option and just do it
ClearSideReferencePoints(playerSide)
SetupSideAsAI(enemySide)
ThisIsFirstLoad(false)
end
ClearCoursesForAllUnitsOnSide(sideName)
陣営の全ウェイポイントを削除する
Tiger and DragonのLuaInitにのみ存在し「なぜこの関数がここにあるか分からないが多分使ってないんで消してOK」の旨がコメントされている
function ClearCoursesForAllUnitsOnSide(sideName)
local sideUnits = VP_GetSide({side=sideName}).units
for k,v in ipairs (sideUnits) do
local unit = ScenEdit_SetUnit({guid=v.guid,course={}})
end
end
ClearCoursesForAllUnitsOnSide('India')
RandomiseReadyTime
local function RandomiseReadyTime(aircraftGUID,maxHours)
local unit = ScenEdit_GetUnit({guid=aircraftGUID})
ScenEdit_SetLoadout({unitName=unit.guid,
loadoutid=0,
TimeToReady_Minutes=math.random(0,(maxHours*60))})
end
local function GetListOfAircraftOnSide(sideName)
local aircraftTable = {}
local sideUnits = VP_GetSide({side=sideName}).units
for k,v in ipairs (sideUnits) do
local unit = ScenEdit_GetUnit({guid=v.guid})
if unit.type == 'Aircraft' then
table.insert(aircraftTable,unit)
end
end
return aircraftTable
end
local function RandomiseAircraftReadyTimesForSide(sideName,maxHours)
local aircraftTable = GetListOfAircraftOnSide(sideName) for k,v in ipairs (aircraftTable) do RandomiseReadyTime(v.guid,maxHours) end
end
敵対設定用関数
HostilitiesHaveCommenced(boolValue)
keyvalue"hostilities"を設定する(ユニット破壊イベントが起きるなどして戦闘が始まったらtrue)
…ただし実際には使われていない模様
function HostilitiesHaveCommenced(boolValue)
if boolValue == nil then
return ConvertStringToBoolean(ScenEdit_GetKeyValue('hostilities'))
elseif boolValue == true then
ScenEdit_SetKeyValue('hostilities','true')
return true
elseif boolValue == false then
ScenEdit_SetKeyValue('hostilities','false')
return false
else
return nil
end
end
SetSidesHostile()
陣営同士の関係を敵軍に設定する
function SetSidesHostile()
ScenEdit_SetSidePosture ('United States', 'Iran', 'H')
ScenEdit_SetSidePosture ('Iran', 'United States', 'H')
end
CommenceHostilities()
ActivateMissionsByList()と組み合わせてmissionListテーブルで指定した各ミッションをアクティブにする
この関数は"Iran_UnitDestroyed"など敵ユニットを破壊した際のイベントアクションに挿入されていて,この結果いずれかの敵ユニットを破壊すると敵軍の各ミッションがアクティブになる.
function CommenceHostilities()
if not HostilitiesHaveCommenced() then
SetSidesHostile()
local missionList = {
'Bandar Abbas Fishbed Intercept',
'Bandar Lengeh Intercept',
'Char Bahar Intercept',
'Jask Intercept',
'Maritime Strike A',
'Maritime Strike B'
}
local missionSide = 'Iran'
ActivateMissionsByList(missionSide, missionList)
end
end
ActivateMissionsByList(side, missionList)
missionListに入っているミッションをそれぞれアクティブ化する.
function ActivateMissionsByList(side, missionList)
for k,v in ipairs (missionList) do
ScenEdit_SetMission (side, v, {isactive=true})
end
end
SAR関連
GenerateSurvivors()関連
PilotSurvives()
パイロットが脱出に成功するか= survivorが生成されるかの判定(66%)
function PilotSurvives()
local chanceOfBailout = 66
local chance = math.random(1,100)
if chance <= chanceOfBailout then
return true
else
return false
end
end
GenerateSurvivors(latitude,longitude,name)
PilotSurvives()の判定に成功したらPlaceSurvivor()およびBailoutMessage()を実行する
function GenerateSurvivors(latitude,longitude,name)
math.randomseed(os.time())
if PilotSurvives() then
PlaceSurvivor(latitude,longitude)
BailoutMessage(name,latitude,longitude)
end
end
PlaceSurvivor()関連
DetermineTypeOfSurvivor(latitude,longitude)
survivorのユニットタイプを決定する
- CWDB
OverWater()がtrueなら:Ship #2286=Life Raft [5m]
falseなら:Facility #1791=Standed Personnel (1x, immobiile) - DB3K
OverWater()がtrueなら:Ship #2553=Life Raft [5m]
falseなら:Facility #2441=Standed Personnel (1x, immobiile)
function DetermineTypeOfSurvivor(latitude,longitude)
local liferaftDBID, strandedPersonDBID, survivorType = 2553, 2441, 'Facility'
local survivorDBID = strandedPersonDBID
if OverWater(latitude,longitude) then
survivorType, survivorDBID = 'Ship', liferaftDBID
end
return {type=survivorType,dbid=survivorDBID}
end
GenerateRank()
survivorユニット名に使う階級名を生成する
function GenerateRank()
local ranks = {"LTJG","LT","LCDR"}
local chance = math.random(1,100)
if chance < 40 then
return ranks[1]
elseif chance < 80 then
return ranks[2]
else
return ranks[3]
end
end
RandomLetter()
パイロットの名とミドルネームに使うアルファベットをランダム生成する
function RandomLetter()
local alphabet = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}
return string.upper(alphabet[math.random(1,#alphabet)])
end
GenerateSurvivorName()
survivorユニット名に使うパイロット名を生成する
function GenerateSurvivorName()
local rank = GenerateRank()
local initials = RandomLetter()..". "..RandomLetter()..". "
local surnames = {
--パイロット姓(テーブル長すぎるので省略)
}
return rank..' '..initials..surnames[math.random(1,#surnames)]
end
PlaceSurvivor(latitude,longitude)
元ユニット破壊位置から2nm以内のCircularRandomPosition()により指定される位置にsurvivorを生成する
function PlaceSurvivor(latitude,longitude)
local randomPosition = CircularRandomPosition(latitude,longitude,2)
local survivorData = DetermineTypeOfSurvivor(randomPosition.latitude,randomPosition.longitude)
local survivorName = GenerateSurvivorName()
local survivor = ScenEdit_AddUnit({
side='Downed Pilots',
type=survivorData.type,
dbid=survivorData.dbid,
name=survivorName,
latitude=randomPosition.latitude,
longitude=randomPosition.longitude
})
end
BailoutMessage()関連
RandomBailoutString()
damagePrefixesとbailoutSuffixesを組み合わせて" I've lost control! Eject, eject, eject!!!"のようなメッセージ本文を生成する
function RandomBailoutString()
local damagePrefixes = {
"I've lost control! ",
"They got me! ",
"Taking hits! ",
"I'm hit! ",
"Flight controls are gone! ",
"Taking heavy fire! "
}
local bailoutSuffixes = {
"Going in!",
"Going down!",
"Eject, eject, eject!!!",
"I can't hold it together!",
"Bailing out!"
}
local result = damagePrefixes[math.random(1,#damagePrefixes)]..bailoutSuffixes[math.random(1,#bailoutSuffixes)]
return result
end
BailoutMessage(name,latitude,longitude)
RandomBailoutString()とnameを組み合わせてRadioMessageとして表示されるメッセージを生成する
GenerateRadioMessageBody(theMessage,callsign)およびRadioMessage(band,frequency,theMessage,location)も参照
function BailoutMessage(name,latitude,longitude)
local theMessage = RandomBailoutString()
local theMessage = GenerateRadioMessageBody(theMessage,name)
RadioMessage('VHF','134.75 MHz',theMessage,{latitude=latitude, longitude=longitude})
end
survivorとrescuerのデータ取得関連
ValidUnitSelection(selectedUnits)
SAR機能ではマップ上で要救助ユニット=survivorと救助ユニット=rescuerを選択し,特別アクション"Perform Search and Rescue"を実行するようになっているが,ここでsurvivorとrescuerが正しく選択されているかを判定する.tooMany(選択しているユニットあるいはコンタクトが多すぎるとtrue)とnoneSelected(ユニットを選択していないとtrue)がいずれもfalseのときtrueを返す
やや長いが解説してみよう.ここでselectedUnits = ScenEdit_SelectedUnits()として考える(GetSelectedUnitInformation()ではそうなっている)
ユニットを選択した際,次の状況が考えられる
- survivorが自動発見不可=コンタクトであるときsurvivorとrescuerを1つずつ選択している
survivorとrescuerはそれぞれselectedUnits.contact,selectedUnits.unitテーブルとして返される:noneSelected=false
selectedUnits.contact,selectedUnits.unitの要素数はそれぞれ1:tooMany=false
結果:true - survivorが自動発見可=ユニットであるときにsurvivorとrescuerを1つずつ選択している
survivorとrescuerはいずれもselectedUnits.unitテーブルとして返される:noneSelected=false
selectedUnits.unitの要素数は2つ:tooMany=false
結果:true - survivorが自動発見不可=コンタクトであるときにsurvivorを1つ,rescuerを2つだけ選択している
survivorとrescuerはそれぞれselectedUnits.contact,selectedUnits.unitテーブルとして返される:noneSelected=false
selectedUnits.contactの要素数は1,selectedUnits.unitの要素数は2:tooMany=false
結果:true - survivorが自動発見可=ユニットであるときにsurvivorとrescuerの合計選択数が3つ以上(survivor,rescuer1,rescuer2…)
survivorとrescuerはいずれもselectedUnits.unitテーブルとして返される:noneSelected=false
selectedUnits.unitの要素数は2を超える(survivor,rescuer1,rescuer2…):tooMany=true
結果:false(rescuerがいすぎるのも良くないようだ) - survivorが自動発見不可=コンタクトであるときにrescuerの選択数が3つ以上(rescuer1,rescuer2,rescuer3…)
rescuerはいずれもselectedUnits.unitテーブルとして返される:noneSelected=false
selectedUnits.unitの要素数は2を超える(rescuer1,rescuer2,rescuer3…):tooMany=true
結果:false - survivorが自動発見不可=コンタクトであるときにsurvivorを2つ以上選択している
selectedUnits.contactの要素数は1を超える (survivor1, survivor2...):tooMany=true
結果:false - 'survivorが自動発見不可=コンタクトであるときにrescuerを選択していない
selectedUnits.unitテーブルが存在せずnilを返す:noneSelected=true
結果:false
なおsurvivorが自動発見可=ユニットであるときにsurvivorだけ選択してもtrueを返すが,rescuerがいないのでのちのReturnRescuer()で判定に失敗する
function ValidUnitSelection(selectedUnits)
local tooMany, noneSelected = false, false
if selectedUnits.units ~= nil then
if #selectedUnits.units > 2 then
tooMany = true
end
else
noneSelected = true
end
if selectedUnits.contacts ~= nil then
if #selectedUnits.contacts > 1 then
tooMany = true
end
end
if not tooMany and not noneSelected then
return true
else
return false
end
end
ReturnSurvivor(selectedUnits)
survivor(Downed Pilots陣営)のGUIDを取得する
function ReturnSurvivor(selectedUnits)
local survivorSide = 'Downed Pilots'
local rescuerSide = ScenEdit_PlayerSide()
if selectedUnits.units then
for k,v in ipairs(selectedUnits.units) do
local unit = ScenEdit_GetUnit({guid=v.guid})
if unit.side == survivorSide then
return unit
end
end
end
if selectedUnits.contacts then
for k,v in ipairs(selectedUnits.contacts) do
local contact = ScenEdit_GetContact({side=rescuerSide,guid=v.guid})
if contact.side == survivorSide then
local actualUnit = ScenEdit_GetUnit({guid=survivor.actualunitid})
return actualUnit
end
end
end
return nil
end
ReturnRescuer(selectedUnits)
rescuer(プレイヤー陣営)のGUIDを取得する
function ReturnRescuer(selectedUnits)
local rescuerSide = ScenEdit_PlayerSide()
for k,v in ipairs(selectedUnits.units) do
local unit = ScenEdit_GetUnit({guid=v.guid})
if unit.side == rescuerSide then
return unit
end
end
return nil
end
GetSelectedUnitInformation()
ReturnSurvivor()とReturnRescuer()でそれぞれ取得したsurvivorとrescuerのUnitテーブルをひとつのテーブルにおける入れ子としてまとめる
function GetSelectedUnitInformation()
local selectedUnits = ScenEdit_SelectedUnits()
if ValidUnitSelection(selectedUnits) then
local rescuer = ReturnRescuer(selectedUnits)
local survivor = ReturnSurvivor(selectedUnits)
if rescuer == nil or survivor == nil then
ScenEdit_MsgBox('Select both a downed pilot to rescue and a nearby friendly unit to perform this special action.',0)
return nil
else
return {rescuer=rescuer,survivor=survivor}
end
end
end
SAR可能判定関数
ContactIsValidRescueTarget()
survivorが実際に被救助可能か,すなわちユニットタイプ/GUIDがShip #2553あるいはFacilty #2441ならtrue
function ContactIsValidRescueTarget()
local selectedUnits = GetSelectedUnitInformation()
if selectedUnits.survivor.type == 'Ship' and selectedUnits.survivor.dbid == 2553 then
return true
elseif selectedUnits.survivor.type == 'Facility' and selectedUnits.survivor.dbid == 2441 then
return true
else
ScenEdit_MsgBox('The selected contact is not capable of being rescued!',0)
return false
end
end
ShipOrSubmarineIsWithinRescueParams()
rescuerが水上・潜水艦ユニットであるとき,
- 深度が20m/66ft以浅
- 速力が6kts以下
をいずれも満たす場合true
function ShipOrSubmarineIsWithinRescueParams()
local rescuer = GetSelectedUnitInformation().rescuer
if RescuerIsCloseEnoughToRescueSurvivor() then
if rescuer.altitude >= -20 and rescuer.speed <= 6 then
return true
else
local errorString = rescuer.name..' is moving too fast to perform a rescue.\n\nShips performing rescues must be moving at 5 knots or less.'
if rescuer.type == 'Submarine' then
errorString = rescuer.name..' is either moving too fast or is too deeply submerged to perform a rescue.\n\nSubmarines performing rescues must be moving at 5 knots or less and be on the surface.'
ScenEdit_MsgBox(errorString,0)
return false
end
end
else
return false
end
end
end
AircraftIsRescueCapable(dbid)
rescuer(航空ユニット)が実際に救助可能か
dbidListテーブルに登録したSAR可能航空ユニットのいずれかとdbidが一致するならtrue
function AircraftIsRescueCapable(dbid)
local dbidList = {
1986, --CH-53E Super Stallion
2006, --MH-60R Seahawk
2793, --MH-53E Sea Dragon
2794, --MH-60S Knighthawk
2844, --UH-1Y Venom [Huey]
297, --MV-22B Osprey
4356, --MH-60R Seahawk
4681, --MH-60S Knighthawk
571, --MH-60S Knighthawk
}
for k,v in ipairs (dbidList) do
if v == dbid then
return true
end
end
return false
end
ReturnRangeBetweenRescuerAndSurvivor()
survivor-rescuer間の距離をメートルおよびフィート単位で取得する
function ReturnRangeBetweenRescuerAndSurvivor()
local metresPerNMi, feetPerM = 1852, 3.28084
local selectedUnits = GetSelectedUnitInformation()
local rangeMetres = Round(Tool_Range(selectedUnits.rescuer.guid, selectedUnits.survivor.guid) * metresPerNMi)
local rangeFeet = Round(rangeMetres * feetPerM)
return {feet=rangeFeet,metres=rangeMetres}
end
RescuerIsCloseEnoughToRescueSurvivor()
survivor-rescuer間の距離がmaxRescueRange =1000m未満,すなわちReturnRangeBetweenRescuerAndSurvivor()のmetres値が1000未満ならtrueを返す
feet表記は単にメッセージでの表示目的らしい(いらない)
function RescuerIsCloseEnoughToRescueSurvivor()
local range = ReturnRangeBetweenRescuerAndSurvivor()
local maxRescueRange, feetPerM = 1000, 3.28084
local maxRescueRangeFeet = Round(maxRescueRange * feetPerM)
if range.metres < maxRescueRange then
return true
else
ScenEdit_MsgBox('Rescuer must be within '..maxRescueRange..'m / '..maxRescueRangeFeet..'ft.\n\nCurrent range is '..range.metres..'m / '..range.feet..'ft.\n\nMove closer to attempt a rescue.',0)
return false
end
end
ReturnUnitAltitudeAGL(guid)
ユニット (rescuer)の位置における地上高をもとにユニット対地高度を計算する
function ReturnUnitAltitudeAGL(guid)
local unit = ScenEdit_GetUnit({guid=guid})
local altitudeAboveSeaLevel, terrainElevation = unit.altitude, World_GetElevation({latitude=unit.latitude,longitude=unit.longitude})
if terrainElevation < 0 then terrainElevation = 0 end
local altitudeAboveGround = altitudeAboveSeaLevel - terrainElevation
return altitudeAboveGround
end
AirUnitIsWithinRescueParams()
rescuerが航空ユニットであるとき,
- ReturnUnitAltitudeAGL()で計算した対地高度が75m/246ft以下
- 速力が50kts以下
をいずれも満たす場合true
function AirUnitIsWithinRescueParams()
local rescuer = GetSelectedUnitInformation().rescuer
local altitudeAboveGround = ReturnUnitAltitudeAGL(rescuer.guid)
if RescuerIsCloseEnoughToRescueSurvivor() then
if altitudeAboveGround <= 75 and rescuer.speed <= 50 then
return true
else
ScenEdit_MsgBox(rescuer.name..' is flying too high or too fast to perform a rescue.\n\nAircraft performing rescues must be flying at less than 245ft/75m AGL and slower than 50 knots.',0)
return false
end
else
return false
end
end
PlayerUnitIsEligibleToRescue()
survivor,rescuerが前述の各条件を満たしSAR可能かを判定する
function PlayerUnitIsEligibleToRescue()
local selectedUnits, result = GetSelectedUnitInformation(), false
if ContactIsValidRescueTarget() then
if selectedUnits.rescuer.type == 'Ship' or selectedUnits.rescuer.type == 'Submarine' then
return ShipOrSubmarineIsWithinRescueParams()
elseif selectedUnits.rescuer.type == 'Aircraft' and AircraftIsRescueCapable(selectedUnits.rescuer.dbid) then
return AirUnitIsWithinRescueParams()
else
ScenEdit_MsgBox('Unit must be capable of rescue to attempt this special action.\n\nTry selecting a ship, submarine or helicopter.',0)
return result
end
end
SAR実行関連関数
PerformRescue()
survivorを削除する+メッセージ表示
function PerformRescue()
local selectedUnits = GetSelectedUnitInformation()
ScenEdit_DeleteUnit({guid=selectedUnits.survivor.guid})
local message = "We've rescued "..selectedUnits.survivor.name.."."
local theMessage = GenerateRadioMessageBody(message,selectedUnits.rescuer.name)
RadioMessage('VHF','134.25 MHz',theMessage,{latitude=selectedUnits.survivor.latitude, longitude=selectedUnits.survivor.longitude})
end
AttemptRescue()
特別アクション"Perform Search and Rescue"により実行
PlayerUnitIsEligibleToRescue()がtrueのときPerformRescue()を実行する+50点加点
function AttemptRescue()
local selectedUnits = GetSelectedUnitInformation()
if selectedUnits ~= nil then
if PlayerUnitIsEligibleToRescue() then
PerformRescue()
ChangeScore('playerside',50,selectedUnits.survivor.name..' was rescued.')
end
end
end
通信攪乱関連
コードはDrass Drumから
GetListOfIADSUnits()
陣営の全ユニットからaffectedDBIDsで定義した地上対空ユニットを抽出する
function GetListOfIADSUnits()
local sideUnits, result = VP_GetSide({side='Iran'}).units, {}
local affectedDBIDs = {
{type='Facility', dbid=1254, points=0, name='SAM Plt (SA-13 Gopher [9K35 Strela-10])', destroyedString='destroyed'},--SAM Plt (SA-13 Gopher [9K35 Strela-10])
{type='Facility', dbid=547, points=0, name='SAM Plt (SA-11 Gadfly [9K37 Buk-M1])', destroyedString='destroyed'},--SAM Plt (SA-11 Gadfly [9K37 Buk-M1])
{type='Facility', dbid=1815, points=0, name='AAA Bty (100mm KS-19 Auto [Sair] x 4, GFCR)', destroyedString='destroyed'},--AAA Bty (100mm KS-19 Auto [Sair] x 4, GFCR)
--以下省略
}
for each, entry in ipairs (sideUnits) do
local unit = ScenEdit_GetUnit({guid=entry.guid})
for k,v in ipairs(affectedDBIDs) do
if unit.dbid == v.dbid and unit.type == v.type then
table.insert(result,unit)
break
end
end
end
return result
end
Disrupt(陣営名)IADSComms()
GetListOfIADSUnits()で抽出した地上対空ユニットを各40%の確率で通信途絶状態にする
陣営のレーダーEMCONをアクティブにする
テレックスメッセージ表示
function DisruptIranIADSComms()
local unitsToBeDisrupted = GetListOfIADSUnits()
for k,v in ipairs (unitsToBeDisrupted) do
local chanceOfDisruption = 40
local chance = math.random(1,100)
if chance < chanceOfDisruption then
ScenEdit_SetUnit({guid=v.guid,outofcomms=true})
end
end
ScenEdit_SetDoctrine({side="Iran"}, {weapon_control_status_air=1})
ScenEdit_SetEMCON('Side', "Iran", 'Radar=Active')
TelexMessageToPlayer(
"CSG77",
'CENTCOM',
'i',
'US central command',
'carrier strike group 77',
'top secret',
'1. iranian AIR DEFENSE RADIO TRAFFIC ABRUPTLY CEASED MID TRANSMISSION <BR>2. SIMILAR DISRUPTION NOTED TO DATA TRAFFIC <BR>3. ASSESS THAT iranian AIR DEFENSE CONTROL COMMUNICATIONS ARE CURRENTLY INOPERABLE <BR>4. ANTICIPATE REDUCED COORDINATION OF iranian AIR DEFENSE ACTIVITIES UNTIL COMMUNICATIONS REESTABLISHED',
nil
)
end
GetListOfNavalUnits()
陣営の全ユニットからaffectedDBIDsで定義した地上対艦ミサイルユニット,水上ユニット,潜水艦ユニットを抽出する
function GetListOfNavalUnits()
local sideUnits, result = VP_GetSide({side='Iran'}).units, {}
local affectedDBIDs = {
{type='Facility', dbid=1813, points=0, name='SSM Bn (C-704 [Nasr])', destroyedString='destroyed'},--SSM Bn (C-704 [Nasr])
{type='Facility', dbid=904, points=0, name='SSM Bn (C-802)', destroyedString='destroyed'},--SSM Bn (C-802)
{type='Ship', dbid=1198, points=0, name='P 313-1 Fath [Thondor Type 021 Houdong]', destroyedString='sunk'},--P 313-1 Fath [Thondor Type 021 Houdong]
--以下省略
}
for each, entry in ipairs (sideUnits) do
local unit = ScenEdit_GetUnit({guid=entry.guid})
for k,v in ipairs(affectedDBIDs) do
if unit.dbid == v.dbid and unit.type == v.type then
table.insert(result,unit)
break
end
end
end
return result
end
DisruptIranNavalComms()
GetListOfNavalUnits()で抽出したユニットを各40%の確率で通信途絶状態にする
(陣営のレーダーEMCONをアクティブにする―DisruptIranIADSComms()と重複するためか未使用)
テレックスメッセージ表示
function DisruptIranNavalComms()
local unitsToBeDisrupted = GetListOfNavalUnits()
for k,v in ipairs (unitsToBeDisrupted) do
local chanceOfDisruption = 40
local chance = math.random(1,100)
if chance < chanceOfDisruption then
ScenEdit_SetUnit({guid=v.guid,outofcomms=true})
end
end
ScenEdit_SetDoctrine({side="Iran"}, {weapon_control_status_surface=1,weapon_control_status_subsurface=1})
--ScenEdit_SetEMCON('Side', "Iran", 'Radar=Active')
TelexMessageToPlayer(
"CSG77",
'CENTCOM',
'i',
'US central command',
'carrier strike group 77',
'top secret',
'1. iranian NAVAL COORDINATION RADIO TRAFFIC ABRUPTLY CEASED MID TRANSMISSION <BR>2. SIMILAR DISRUPTION NOTED TO DATA TRAFFIC <BR>3. ASSESS THAT iranian NAVAL COORDINATION COMMUNICATIONS ARE CURRENTLY INOPERABLE <BR>4. ANTICIPATE REDUCED COORDINATION OF iranian NAVAL ACTIVITIES UNTIL COMMUNICATIONS REESTABLISHED',
nil
)
end
IADSMessageHasPlayed(boolValue)
DisruptIranIADSComms()が実行されメッセージが表示された後trueになると思われるが実例未確認
function IADSMessageHasPlayed(boolValue)
if boolValue == nil then
return ConvertStringToBoolean(ScenEdit_GetKeyValue('IADSMessage'))
elseif boolValue == true then
ScenEdit_SetKeyValue('IADSMessage','true')
return true
elseif boolValue == false then
ScenEdit_SetKeyValue('IADSMessage','false')
return false
else
return nil
end
end
NavalHQMessageHasPlayed(boolValue)
DisruptIranNavalComms()が実行されメッセージが表示された後trueになると思われるが実例未確認
function NavalHQMessageHasPlayed(boolValue)
if boolValue == nil then
return ConvertStringToBoolean(ScenEdit_GetKeyValue('navalHQMessage'))
elseif boolValue == true then
ScenEdit_SetKeyValue('navalHQMessage','true')
return true
elseif boolValue == false then
ScenEdit_SetKeyValue('navalHQMessage','false')
return false
else
return nil
end
end