@jtff/miztemplate-lib 3.1.7 → 3.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lua/lib/Moose_.lua +1807 -560
- package/lua/lib/{mist_4_5_107.lua → mist_4_5_122.lua} +773 -351
- package/lua/lib/skynet-iads-compiled.lua +106 -60
- package/lua/src/020-mission_functions.lua +5 -5
- package/lua/src/130-airboss.lua +35 -36
- package/package.json +1 -1
- package/resources/sounds/AIRBOSS/Airboss Soundfiles/GetYourButtsUptoVipersOffice.ogg +0 -0
- package/resources/sounds/AIRBOSS/Airboss Soundfiles/GreatBallsOfFire.ogg +0 -0
- package/resources/sounds/AIRBOSS/Airboss Soundfiles/ffyrtp.ogg +0 -0
- package/resources/sounds/AIRBOSS/Airboss Soundfiles/sureshot.ogg +0 -0
- package/scripts/inject-scripts.js +3 -3
- /package/resources/sounds/{CTLD → CTLD CSAR}/beacon.ogg +0 -0
- /package/resources/sounds/{CTLD → CTLD CSAR}/beaconsilent.ogg +0 -0
package/lua/lib/Moose_.lua
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
env.info('*** MOOSE GITHUB Commit Hash ID:
|
|
1
|
+
env.info('*** MOOSE GITHUB Commit Hash ID: 2024-01-01T00:38:59+01:00-8dcd22f18c9bf740c53b69c7ba3901a9ada0bb2d ***')
|
|
2
2
|
env.info('*** MOOSE STATIC INCLUDE START *** ')
|
|
3
3
|
ENUMS={}
|
|
4
4
|
env.setErrorMessageBoxEnabled(false)
|
|
@@ -379,6 +379,7 @@ Galaxy="C-5",
|
|
|
379
379
|
Hawkeye="E-2D",
|
|
380
380
|
Sentry="E-3A",
|
|
381
381
|
Stratotanker="KC-135",
|
|
382
|
+
Gasstation="KC-135MPRS",
|
|
382
383
|
Extender="KC-10",
|
|
383
384
|
Orion="P-3C",
|
|
384
385
|
Viking="S-3B",
|
|
@@ -416,6 +417,12 @@ Reaper="MQ-9",
|
|
|
416
417
|
Predator="MQ-1A",
|
|
417
418
|
}
|
|
418
419
|
}
|
|
420
|
+
ENUMS.Link16Power={
|
|
421
|
+
none=0,
|
|
422
|
+
low=1,
|
|
423
|
+
medium=2,
|
|
424
|
+
high=3,
|
|
425
|
+
}
|
|
419
426
|
ENUMS.Storage={
|
|
420
427
|
weapons={
|
|
421
428
|
missiles={},
|
|
@@ -1277,21 +1284,33 @@ end
|
|
|
1277
1284
|
end
|
|
1278
1285
|
end
|
|
1279
1286
|
function UTILS.PrintTableToLog(table,indent)
|
|
1287
|
+
local text="\n"
|
|
1280
1288
|
if not table then
|
|
1281
|
-
|
|
1282
|
-
return
|
|
1289
|
+
env.warning("No table passed!")
|
|
1290
|
+
return nil
|
|
1283
1291
|
end
|
|
1284
1292
|
if not indent then indent=0 end
|
|
1285
1293
|
for k,v in pairs(table)do
|
|
1294
|
+
if string.find(k," ")then k='"'..k..'"'end
|
|
1286
1295
|
if type(v)=="table"then
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1296
|
+
env.info(string.rep(" ",indent)..tostring(k).." = {")
|
|
1297
|
+
text=text..string.rep(" ",indent)..tostring(k).." = {\n"
|
|
1298
|
+
text=text..tostring(UTILS.PrintTableToLog(v,indent+1)).."\n"
|
|
1299
|
+
env.info(string.rep(" ",indent).."},")
|
|
1300
|
+
text=text..string.rep(" ",indent).."},\n"
|
|
1301
|
+
else
|
|
1302
|
+
local value
|
|
1303
|
+
if tostring(v)=="true"or tostring(v)=="false"or tonumber(v)~=nil then
|
|
1304
|
+
value=v
|
|
1290
1305
|
else
|
|
1291
|
-
|
|
1306
|
+
value='"'..tostring(v)..'"'
|
|
1292
1307
|
end
|
|
1308
|
+
env.info(string.rep(" ",indent)..tostring(k).." = "..tostring(value)..",\n")
|
|
1309
|
+
text=text..string.rep(" ",indent)..tostring(k).." = "..tostring(value)..",\n"
|
|
1293
1310
|
end
|
|
1294
1311
|
end
|
|
1312
|
+
return text
|
|
1313
|
+
end
|
|
1295
1314
|
function UTILS.TableShow(tbl,loc,indent,tableshow_tbls)
|
|
1296
1315
|
tableshow_tbls=tableshow_tbls or{}
|
|
1297
1316
|
loc=loc or""
|
|
@@ -1817,9 +1836,15 @@ end
|
|
|
1817
1836
|
function UTILS.VecSubstract(a,b)
|
|
1818
1837
|
return{x=a.x-b.x,y=a.y-b.y,z=a.z-b.z}
|
|
1819
1838
|
end
|
|
1839
|
+
function UTILS.VecSubtract(a,b)
|
|
1840
|
+
return UTILS.VecSubstract(a,b)
|
|
1841
|
+
end
|
|
1820
1842
|
function UTILS.Vec2Substract(a,b)
|
|
1821
1843
|
return{x=a.x-b.x,y=a.y-b.y}
|
|
1822
1844
|
end
|
|
1845
|
+
function UTILS.Vec2Subtract(a,b)
|
|
1846
|
+
return UTILS.Vec2Substract(a,b)
|
|
1847
|
+
end
|
|
1823
1848
|
function UTILS.VecAdd(a,b)
|
|
1824
1849
|
return{x=a.x+b.x,y=a.y+b.y,z=a.z+b.z}
|
|
1825
1850
|
end
|
|
@@ -2288,15 +2313,15 @@ if string.find(type_name,"Hercules")and(unit:getDrawArgumentValue(1217)==1)then
|
|
|
2288
2313
|
BASE:T(unit_name.." side door is open")
|
|
2289
2314
|
return true
|
|
2290
2315
|
end
|
|
2291
|
-
if
|
|
2316
|
+
if type_name=="Bell-47"then
|
|
2292
2317
|
BASE:T(unit_name.." door is open")
|
|
2293
2318
|
return true
|
|
2294
2319
|
end
|
|
2295
|
-
if
|
|
2320
|
+
if type_name=="UH-60L"and(unit:getDrawArgumentValue(401)==1 or unit:getDrawArgumentValue(402)==1)then
|
|
2296
2321
|
BASE:T(unit_name.." cargo door is open")
|
|
2297
2322
|
return true
|
|
2298
2323
|
end
|
|
2299
|
-
if
|
|
2324
|
+
if type_name=="UH-60L"and(unit:getDrawArgumentValue(38)>0 or unit:getDrawArgumentValue(400)==1)then
|
|
2300
2325
|
BASE:T(unit_name.." front door(s) are open")
|
|
2301
2326
|
return true
|
|
2302
2327
|
end
|
|
@@ -2479,7 +2504,7 @@ filename=path.."\\"..filename
|
|
|
2479
2504
|
end
|
|
2480
2505
|
local exists=UTILS.CheckFileExists(Path,Filename)
|
|
2481
2506
|
if not exists then
|
|
2482
|
-
BASE:
|
|
2507
|
+
BASE:I(string.format("ERROR: File %s does not exist!",filename))
|
|
2483
2508
|
return false
|
|
2484
2509
|
end
|
|
2485
2510
|
local file=assert(io.open(filename,"rb"))
|
|
@@ -2991,6 +3016,300 @@ point_four:LineToAll(point_three,coalition,color,alpha,lineType)
|
|
|
2991
3016
|
circle_center_fix_four:CircleToAll(UTILS.NMToMeters(turn_radius),coalition,color,alpha,nil,0,lineType)
|
|
2992
3017
|
circle_center_two_three:CircleToAll(UTILS.NMToMeters(turn_radius),coalition,color,alpha,nil,0,lineType)
|
|
2993
3018
|
end
|
|
3019
|
+
function UTILS.TimeNow()
|
|
3020
|
+
return UTILS.SecondsToClock(timer.getAbsTime(),false,false)
|
|
3021
|
+
end
|
|
3022
|
+
function UTILS.TimeDifferenceInSeconds(start_time,end_time)
|
|
3023
|
+
return UTILS.ClockToSeconds(end_time)-UTILS.ClockToSeconds(start_time)
|
|
3024
|
+
end
|
|
3025
|
+
function UTILS.TimeLaterThan(time_string)
|
|
3026
|
+
if timer.getAbsTime()>UTILS.ClockToSeconds(time_string)then
|
|
3027
|
+
return true
|
|
3028
|
+
end
|
|
3029
|
+
return false
|
|
3030
|
+
end
|
|
3031
|
+
function UTILS.TimeBefore(time_string)
|
|
3032
|
+
if timer.getAbsTime()<UTILS.ClockToSeconds(time_string)then
|
|
3033
|
+
return true
|
|
3034
|
+
end
|
|
3035
|
+
return false
|
|
3036
|
+
end
|
|
3037
|
+
function UTILS.CombineTimeStrings(time_string_01,time_string_02)
|
|
3038
|
+
local hours1,minutes1,seconds1=time_string_01:match("(%d+):(%d+):(%d+)")
|
|
3039
|
+
local hours2,minutes2,seconds2=time_string_02:match("(%d+):(%d+):(%d+)")
|
|
3040
|
+
local total_seconds=tonumber(seconds1)+tonumber(seconds2)+tonumber(minutes1)*60+tonumber(minutes2)*60+tonumber(hours1)*3600+tonumber(hours2)*3600
|
|
3041
|
+
total_seconds=total_seconds%(24*3600)
|
|
3042
|
+
if total_seconds<0 then
|
|
3043
|
+
total_seconds=total_seconds+24*3600
|
|
3044
|
+
end
|
|
3045
|
+
local hours=math.floor(total_seconds/3600)
|
|
3046
|
+
total_seconds=total_seconds-hours*3600
|
|
3047
|
+
local minutes=math.floor(total_seconds/60)
|
|
3048
|
+
local seconds=total_seconds%60
|
|
3049
|
+
return string.format("%02d:%02d:%02d",hours,minutes,seconds)
|
|
3050
|
+
end
|
|
3051
|
+
function UTILS.SubtractTimeStrings(time_string_01,time_string_02)
|
|
3052
|
+
local hours1,minutes1,seconds1=time_string_01:match("(%d+):(%d+):(%d+)")
|
|
3053
|
+
local hours2,minutes2,seconds2=time_string_02:match("(%d+):(%d+):(%d+)")
|
|
3054
|
+
local total_seconds=tonumber(seconds1)-tonumber(seconds2)+tonumber(minutes1)*60-tonumber(minutes2)*60+tonumber(hours1)*3600-tonumber(hours2)*3600
|
|
3055
|
+
total_seconds=total_seconds%(24*3600)
|
|
3056
|
+
if total_seconds<0 then
|
|
3057
|
+
total_seconds=total_seconds+24*3600
|
|
3058
|
+
end
|
|
3059
|
+
local hours=math.floor(total_seconds/3600)
|
|
3060
|
+
total_seconds=total_seconds-hours*3600
|
|
3061
|
+
local minutes=math.floor(total_seconds/60)
|
|
3062
|
+
local seconds=total_seconds%60
|
|
3063
|
+
return string.format("%02d:%02d:%02d",hours,minutes,seconds)
|
|
3064
|
+
end
|
|
3065
|
+
function UTILS.TimeBetween(start_time,end_time)
|
|
3066
|
+
return UTILS.TimeLaterThan(start_time)and UTILS.TimeBefore(end_time)
|
|
3067
|
+
end
|
|
3068
|
+
function UTILS.PercentageChance(chance)
|
|
3069
|
+
chance=chance or math.random(0,100)
|
|
3070
|
+
chance=UTILS.Clamp(chance,0,100)
|
|
3071
|
+
local percentage=math.random(0,100)
|
|
3072
|
+
if percentage<chance then
|
|
3073
|
+
return true
|
|
3074
|
+
end
|
|
3075
|
+
return false
|
|
3076
|
+
end
|
|
3077
|
+
function UTILS.Clamp(value,min,max)
|
|
3078
|
+
if value<min then value=min end
|
|
3079
|
+
if value>max then value=max end
|
|
3080
|
+
return value
|
|
3081
|
+
end
|
|
3082
|
+
function UTILS.ClampAngle(value)
|
|
3083
|
+
if value>360 then return value-360 end
|
|
3084
|
+
if value<0 then return value+360 end
|
|
3085
|
+
return value
|
|
3086
|
+
end
|
|
3087
|
+
function UTILS.RemapValue(value,old_min,old_max,new_min,new_max)
|
|
3088
|
+
new_min=new_min or 0
|
|
3089
|
+
new_max=new_max or 100
|
|
3090
|
+
local old_range=old_max-old_min
|
|
3091
|
+
local new_range=new_max-new_min
|
|
3092
|
+
local percentage=(value-old_min)/old_range
|
|
3093
|
+
return(new_range*percentage)+new_min
|
|
3094
|
+
end
|
|
3095
|
+
function UTILS.RandomPointInTriangle(pt1,pt2,pt3)
|
|
3096
|
+
local pt={math.random(),math.random()}
|
|
3097
|
+
table.sort(pt)
|
|
3098
|
+
local s=pt[1]
|
|
3099
|
+
local t=pt[2]-pt[1]
|
|
3100
|
+
local u=1-pt[2]
|
|
3101
|
+
return{x=s*pt1.x+t*pt2.x+u*pt3.x,
|
|
3102
|
+
y=s*pt1.y+t*pt2.y+u*pt3.y}
|
|
3103
|
+
end
|
|
3104
|
+
function UTILS.AngleBetween(angle,min,max)
|
|
3105
|
+
angle=(360+(angle%360))%360
|
|
3106
|
+
min=(360+min%360)%360
|
|
3107
|
+
max=(360+max%360)%360
|
|
3108
|
+
if min<max then return min<=angle and angle<=max end
|
|
3109
|
+
return min<=angle or angle<=max
|
|
3110
|
+
end
|
|
3111
|
+
function UTILS.WriteJSON(data,file_path)
|
|
3112
|
+
package.path=package.path..";.\\Scripts\\?.lua"
|
|
3113
|
+
local JSON=require("json")
|
|
3114
|
+
local pretty_json_text=JSON:encode_pretty(data)
|
|
3115
|
+
local write_file=io.open(file_path,"w")
|
|
3116
|
+
write_file:write(pretty_json_text)
|
|
3117
|
+
write_file:close()
|
|
3118
|
+
end
|
|
3119
|
+
function UTILS.ReadJSON(file_path)
|
|
3120
|
+
package.path=package.path..";.\\Scripts\\?.lua"
|
|
3121
|
+
local JSON=require("json")
|
|
3122
|
+
local read_file=io.open(file_path,"r")
|
|
3123
|
+
local contents=read_file:read("*a")
|
|
3124
|
+
io.close(read_file)
|
|
3125
|
+
return JSON:decode(contents)
|
|
3126
|
+
end
|
|
3127
|
+
function UTILS.GetZoneProperties(zone_name)
|
|
3128
|
+
local return_table={}
|
|
3129
|
+
for _,zone in pairs(env.mission.triggers.zones)do
|
|
3130
|
+
if zone["name"]==zone_name then
|
|
3131
|
+
if table.length(zone["properties"])>0 then
|
|
3132
|
+
for _,property in pairs(zone["properties"])do
|
|
3133
|
+
return_table[property["key"]]=property["value"]
|
|
3134
|
+
end
|
|
3135
|
+
return return_table
|
|
3136
|
+
else
|
|
3137
|
+
BASE:I(string.format("%s doesn't have any properties",zone_name))
|
|
3138
|
+
return{}
|
|
3139
|
+
end
|
|
3140
|
+
end
|
|
3141
|
+
end
|
|
3142
|
+
end
|
|
3143
|
+
function UTILS.RotatePointAroundPivot(point,pivot,angle)
|
|
3144
|
+
local radians=math.rad(angle)
|
|
3145
|
+
local x=point.x-pivot.x
|
|
3146
|
+
local y=point.y-pivot.y
|
|
3147
|
+
local rotated_x=x*math.cos(radians)-y*math.sin(radians)
|
|
3148
|
+
local rotatex_y=x*math.sin(radians)+y*math.cos(radians)
|
|
3149
|
+
local original_x=rotated_x+pivot.x
|
|
3150
|
+
local original_y=rotatex_y+pivot.y
|
|
3151
|
+
return{x=original_x,y=original_y}
|
|
3152
|
+
end
|
|
3153
|
+
function UTILS.UniqueName(base)
|
|
3154
|
+
base=base or""
|
|
3155
|
+
local ran=tostring(math.random(0,1000000))
|
|
3156
|
+
if base==""then
|
|
3157
|
+
return ran
|
|
3158
|
+
end
|
|
3159
|
+
return base.."_"..ran
|
|
3160
|
+
end
|
|
3161
|
+
function string.startswith(str,value)
|
|
3162
|
+
return string.sub(str,1,string.len(value))==value
|
|
3163
|
+
end
|
|
3164
|
+
function string.endswith(str,value)
|
|
3165
|
+
return value==""or str:sub(-#value)==value
|
|
3166
|
+
end
|
|
3167
|
+
function string.split(input,separator)
|
|
3168
|
+
local parts={}
|
|
3169
|
+
for part in input:gmatch("[^"..separator.."]+")do
|
|
3170
|
+
table.insert(parts,part)
|
|
3171
|
+
end
|
|
3172
|
+
return parts
|
|
3173
|
+
end
|
|
3174
|
+
function string.contains(str,value)
|
|
3175
|
+
return string.match(str,value)
|
|
3176
|
+
end
|
|
3177
|
+
function table.contains(tbl,element)
|
|
3178
|
+
if element==nil or tbl==nil then return false end
|
|
3179
|
+
local index=1
|
|
3180
|
+
while tbl[index]do
|
|
3181
|
+
if tbl[index]==element then
|
|
3182
|
+
return true
|
|
3183
|
+
end
|
|
3184
|
+
index=index+1
|
|
3185
|
+
end
|
|
3186
|
+
return false
|
|
3187
|
+
end
|
|
3188
|
+
function table.contains_key(tbl,key)
|
|
3189
|
+
if tbl[key]~=nil then return true else return false end
|
|
3190
|
+
end
|
|
3191
|
+
function table.insert_unique(tbl,element)
|
|
3192
|
+
if element==nil or tbl==nil then return end
|
|
3193
|
+
if not table.contains(tbl,element)then
|
|
3194
|
+
table.insert(tbl,element)
|
|
3195
|
+
end
|
|
3196
|
+
end
|
|
3197
|
+
function table.remove_by_value(tbl,element)
|
|
3198
|
+
local indices_to_remove={}
|
|
3199
|
+
local index=1
|
|
3200
|
+
for _,value in pairs(tbl)do
|
|
3201
|
+
if value==element then
|
|
3202
|
+
table.insert(indices_to_remove,index)
|
|
3203
|
+
end
|
|
3204
|
+
index=index+1
|
|
3205
|
+
end
|
|
3206
|
+
for _,idx in pairs(indices_to_remove)do
|
|
3207
|
+
table.remove(tbl,idx)
|
|
3208
|
+
end
|
|
3209
|
+
end
|
|
3210
|
+
function table.remove_key(table,key)
|
|
3211
|
+
local element=table[key]
|
|
3212
|
+
table[key]=nil
|
|
3213
|
+
return element
|
|
3214
|
+
end
|
|
3215
|
+
function table.index_of(table,element)
|
|
3216
|
+
for i,v in ipairs(table)do
|
|
3217
|
+
if v==element then
|
|
3218
|
+
return i
|
|
3219
|
+
end
|
|
3220
|
+
end
|
|
3221
|
+
return nil
|
|
3222
|
+
end
|
|
3223
|
+
function table.length(T)
|
|
3224
|
+
local count=0
|
|
3225
|
+
for _ in pairs(T)do count=count+1 end
|
|
3226
|
+
return count
|
|
3227
|
+
end
|
|
3228
|
+
function table.slice(tbl,first,last)
|
|
3229
|
+
local sliced={}
|
|
3230
|
+
local start=first or 1
|
|
3231
|
+
local stop=last or table.length(tbl)
|
|
3232
|
+
local count=1
|
|
3233
|
+
for key,value in pairs(tbl)do
|
|
3234
|
+
if count>=start and count<=stop then
|
|
3235
|
+
sliced[key]=value
|
|
3236
|
+
end
|
|
3237
|
+
count=count+1
|
|
3238
|
+
end
|
|
3239
|
+
return sliced
|
|
3240
|
+
end
|
|
3241
|
+
function table.count_value(tbl,value)
|
|
3242
|
+
local count=0
|
|
3243
|
+
for _,item in pairs(tbl)do
|
|
3244
|
+
if item==value then count=count+1 end
|
|
3245
|
+
end
|
|
3246
|
+
return count
|
|
3247
|
+
end
|
|
3248
|
+
function table.combine(t1,t2)
|
|
3249
|
+
if t1==nil and t2==nil then
|
|
3250
|
+
BASE:E("Both tables were empty!")
|
|
3251
|
+
end
|
|
3252
|
+
if t1==nil then return t2 end
|
|
3253
|
+
if t2==nil then return t1 end
|
|
3254
|
+
for i=1,#t2 do
|
|
3255
|
+
t1[#t1+1]=t2[i]
|
|
3256
|
+
end
|
|
3257
|
+
return t1
|
|
3258
|
+
end
|
|
3259
|
+
function table.merge(t1,t2)
|
|
3260
|
+
for k,v in pairs(t2)do
|
|
3261
|
+
if(type(v)=="table")and(type(t1[k]or false)=="table")then
|
|
3262
|
+
table.merge(t1[k],t2[k])
|
|
3263
|
+
else
|
|
3264
|
+
t1[k]=v
|
|
3265
|
+
end
|
|
3266
|
+
end
|
|
3267
|
+
return t1
|
|
3268
|
+
end
|
|
3269
|
+
function table.add(tbl,item)
|
|
3270
|
+
tbl[#tbl+1]=item
|
|
3271
|
+
end
|
|
3272
|
+
function table.shuffle(tbl)
|
|
3273
|
+
local new_table={}
|
|
3274
|
+
for _,value in ipairs(tbl)do
|
|
3275
|
+
local pos=math.random(1,#new_table+1)
|
|
3276
|
+
table.insert(new_table,pos,value)
|
|
3277
|
+
end
|
|
3278
|
+
return new_table
|
|
3279
|
+
end
|
|
3280
|
+
function table.find_key_value_pair(tbl,key,value)
|
|
3281
|
+
for k,v in pairs(tbl)do
|
|
3282
|
+
if type(v)=="table"then
|
|
3283
|
+
local result=table.find_key_value_pair(v,key,value)
|
|
3284
|
+
if result~=nil then
|
|
3285
|
+
return result
|
|
3286
|
+
end
|
|
3287
|
+
elseif k==key and v==value then
|
|
3288
|
+
return tbl
|
|
3289
|
+
end
|
|
3290
|
+
end
|
|
3291
|
+
return nil
|
|
3292
|
+
end
|
|
3293
|
+
function UTILS.DecimalToOctal(Number)
|
|
3294
|
+
if Number<8 then return Number end
|
|
3295
|
+
local number=tonumber(Number)
|
|
3296
|
+
local octal=""
|
|
3297
|
+
local n=1
|
|
3298
|
+
while number>7 do
|
|
3299
|
+
local number1=number%8
|
|
3300
|
+
octal=string.format("%d",number1)..octal
|
|
3301
|
+
local number2=math.abs(number/8)
|
|
3302
|
+
if number2<8 then
|
|
3303
|
+
octal=string.format("%d",number2)..octal
|
|
3304
|
+
end
|
|
3305
|
+
number=number2
|
|
3306
|
+
n=n+1
|
|
3307
|
+
end
|
|
3308
|
+
return tonumber(octal)
|
|
3309
|
+
end
|
|
3310
|
+
function UTILS.OctalToDecimal(Number)
|
|
3311
|
+
return tonumber(Number,8)
|
|
3312
|
+
end
|
|
2994
3313
|
PROFILER={
|
|
2995
3314
|
ClassName="PROFILER",
|
|
2996
3315
|
Counters={},
|
|
@@ -6618,7 +6937,7 @@ if Event.weapon then
|
|
|
6618
6937
|
Event.Weapon=Event.weapon
|
|
6619
6938
|
Event.WeaponName=Event.Weapon:getTypeName()
|
|
6620
6939
|
Event.WeaponUNIT=CLIENT:Find(Event.Weapon,'',true)
|
|
6621
|
-
Event.WeaponPlayerName=Event.WeaponUNIT and Event.Weapon:getPlayerName()
|
|
6940
|
+
Event.WeaponPlayerName=Event.WeaponUNIT and Event.Weapon.getPlayerName and Event.Weapon:getPlayerName()
|
|
6622
6941
|
Event.WeaponCoalition=Event.WeaponUNIT and Event.Weapon:getCoalition()
|
|
6623
6942
|
Event.WeaponCategory=Event.WeaponUNIT and Event.Weapon:getDesc().category
|
|
6624
6943
|
Event.WeaponTypeName=Event.WeaponUNIT and Event.Weapon:getTypeName()
|
|
@@ -8166,7 +8485,13 @@ if Delay and Delay>0 then
|
|
|
8166
8485
|
self:ScheduleOnce(Delay,ZONE_BASE.UndrawZone,self)
|
|
8167
8486
|
else
|
|
8168
8487
|
if self.DrawID then
|
|
8488
|
+
if type(self.DrawID)~="table"then
|
|
8169
8489
|
UTILS.RemoveMark(self.DrawID)
|
|
8490
|
+
else
|
|
8491
|
+
for _,mark_id in pairs(self.DrawID)do
|
|
8492
|
+
UTILS.RemoveMark(mark_id)
|
|
8493
|
+
end
|
|
8494
|
+
end
|
|
8170
8495
|
end
|
|
8171
8496
|
end
|
|
8172
8497
|
return self
|
|
@@ -8881,8 +9206,81 @@ local PointVec2=POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
|
|
8881
9206
|
self:T3({PointVec2})
|
|
8882
9207
|
return PointVec2
|
|
8883
9208
|
end
|
|
9209
|
+
_ZONE_TRIANGLE={
|
|
9210
|
+
ClassName="ZONE_TRIANGLE",
|
|
9211
|
+
Points={},
|
|
9212
|
+
Coords={},
|
|
9213
|
+
CenterVec2={x=0,y=0},
|
|
9214
|
+
SurfaceArea=0,
|
|
9215
|
+
DrawID={}
|
|
9216
|
+
}
|
|
9217
|
+
function _ZONE_TRIANGLE:New(p1,p2,p3)
|
|
9218
|
+
local self=BASE:Inherit(self,ZONE_BASE:New())
|
|
9219
|
+
self.Points={p1,p2,p3}
|
|
9220
|
+
local center_x=(p1.x+p2.x+p3.x)/3
|
|
9221
|
+
local center_y=(p1.y+p2.y+p3.y)/3
|
|
9222
|
+
self.CenterVec2={x=center_x,y=center_y}
|
|
9223
|
+
for _,pt in pairs({p1,p2,p3})do
|
|
9224
|
+
table.add(self.Coords,COORDINATE:NewFromVec2(pt))
|
|
9225
|
+
end
|
|
9226
|
+
self.SurfaceArea=math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))*0.5
|
|
9227
|
+
return self
|
|
9228
|
+
end
|
|
9229
|
+
function _ZONE_TRIANGLE:ContainsPoint(pt,points)
|
|
9230
|
+
points=points or self.Points
|
|
9231
|
+
local function sign(p1,p2,p3)
|
|
9232
|
+
return(p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y)
|
|
9233
|
+
end
|
|
9234
|
+
local d1=sign(pt,self.Points[1],self.Points[2])
|
|
9235
|
+
local d2=sign(pt,self.Points[2],self.Points[3])
|
|
9236
|
+
local d3=sign(pt,self.Points[3],self.Points[1])
|
|
9237
|
+
local has_neg=(d1<0)or(d2<0)or(d3<0)
|
|
9238
|
+
local has_pos=(d1>0)or(d2>0)or(d3>0)
|
|
9239
|
+
return not(has_neg and has_pos)
|
|
9240
|
+
end
|
|
9241
|
+
function _ZONE_TRIANGLE:GetRandomVec2(points)
|
|
9242
|
+
points=points or self.Points
|
|
9243
|
+
local pt={math.random(),math.random()}
|
|
9244
|
+
table.sort(pt)
|
|
9245
|
+
local s=pt[1]
|
|
9246
|
+
local t=pt[2]-pt[1]
|
|
9247
|
+
local u=1-pt[2]
|
|
9248
|
+
return{x=s*points[1].x+t*points[2].x+u*points[3].x,
|
|
9249
|
+
y=s*points[1].y+t*points[2].y+u*points[3].y}
|
|
9250
|
+
end
|
|
9251
|
+
function _ZONE_TRIANGLE:Draw(Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly)
|
|
9252
|
+
Coalition=Coalition or-1
|
|
9253
|
+
Color=Color or{1,0,0}
|
|
9254
|
+
Alpha=Alpha or 1
|
|
9255
|
+
FillColor=FillColor or Color
|
|
9256
|
+
if not FillColor then UTILS.DeepCopy(Color)end
|
|
9257
|
+
FillAlpha=FillAlpha or Alpha
|
|
9258
|
+
if not FillAlpha then FillAlpha=1 end
|
|
9259
|
+
for i=1,#self.Coords do
|
|
9260
|
+
local c1=self.Coords[i]
|
|
9261
|
+
local c2=self.Coords[i%#self.Coords+1]
|
|
9262
|
+
local id=c1:LineToAll(c2,Coalition,Color,Alpha,LineType,ReadOnly)
|
|
9263
|
+
self.DrawID[#self.DrawID+1]=id
|
|
9264
|
+
end
|
|
9265
|
+
local newID=self.Coords[1]:MarkupToAllFreeForm({self.Coords[2],self.Coords[3]},Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly)
|
|
9266
|
+
self.DrawID[#self.DrawID+1]=newID
|
|
9267
|
+
return self.DrawID
|
|
9268
|
+
end
|
|
9269
|
+
function _ZONE_TRIANGLE:Fill(Coalition,FillColor,FillAlpha,ReadOnly)
|
|
9270
|
+
Coalition=Coalition or-1
|
|
9271
|
+
FillColor=FillColor
|
|
9272
|
+
FillAlpha=FillAlpha
|
|
9273
|
+
local newID=self.Coords[1]:MarkupToAllFreeForm({self.Coords[2],self.Coords[3]},Coalition,nil,nil,FillColor,FillAlpha,0,nil)
|
|
9274
|
+
self.DrawID[#self.DrawID+1]=newID
|
|
9275
|
+
return self.DrawID
|
|
9276
|
+
end
|
|
8884
9277
|
ZONE_POLYGON_BASE={
|
|
8885
9278
|
ClassName="ZONE_POLYGON_BASE",
|
|
9279
|
+
_Triangles={},
|
|
9280
|
+
SurfaceArea=0,
|
|
9281
|
+
DrawID={},
|
|
9282
|
+
FillTriangles={},
|
|
9283
|
+
Borderlines={},
|
|
8886
9284
|
}
|
|
8887
9285
|
function ZONE_POLYGON_BASE:New(ZoneName,PointsArray)
|
|
8888
9286
|
local self=BASE:Inherit(self,ZONE_BASE:New(ZoneName))
|
|
@@ -8894,9 +9292,84 @@ self._.Polygon[i]={}
|
|
|
8894
9292
|
self._.Polygon[i].x=PointsArray[i].x
|
|
8895
9293
|
self._.Polygon[i].y=PointsArray[i].y
|
|
8896
9294
|
end
|
|
9295
|
+
self._Triangles=self:_Triangulate()
|
|
9296
|
+
self.SurfaceArea=self:_CalculateSurfaceArea()
|
|
8897
9297
|
end
|
|
8898
9298
|
return self
|
|
8899
9299
|
end
|
|
9300
|
+
function ZONE_POLYGON_BASE:_Triangulate()
|
|
9301
|
+
local points=self._.Polygon
|
|
9302
|
+
local triangles={}
|
|
9303
|
+
local function get_orientation(shape_points)
|
|
9304
|
+
local sum=0
|
|
9305
|
+
for i=1,#shape_points do
|
|
9306
|
+
local j=i%#shape_points+1
|
|
9307
|
+
sum=sum+(shape_points[j].x-shape_points[i].x)*(shape_points[j].y+shape_points[i].y)
|
|
9308
|
+
end
|
|
9309
|
+
return sum>=0 and"clockwise"or"counter-clockwise"
|
|
9310
|
+
end
|
|
9311
|
+
local function ensure_clockwise(shape_points)
|
|
9312
|
+
local orientation=get_orientation(shape_points)
|
|
9313
|
+
if orientation=="counter-clockwise"then
|
|
9314
|
+
local reversed={}
|
|
9315
|
+
for i=#shape_points,1,-1 do
|
|
9316
|
+
table.insert(reversed,shape_points[i])
|
|
9317
|
+
end
|
|
9318
|
+
return reversed
|
|
9319
|
+
end
|
|
9320
|
+
return shape_points
|
|
9321
|
+
end
|
|
9322
|
+
local function is_clockwise(p1,p2,p3)
|
|
9323
|
+
local cross_product=(p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x)
|
|
9324
|
+
return cross_product<0
|
|
9325
|
+
end
|
|
9326
|
+
local function divide_recursively(shape_points)
|
|
9327
|
+
if#shape_points==3 then
|
|
9328
|
+
table.insert(triangles,_ZONE_TRIANGLE:New(shape_points[1],shape_points[2],shape_points[3]))
|
|
9329
|
+
elseif#shape_points>3 then
|
|
9330
|
+
for i,p1 in ipairs(shape_points)do
|
|
9331
|
+
local p2=shape_points[(i%#shape_points)+1]
|
|
9332
|
+
local p3=shape_points[(i+1)%#shape_points+1]
|
|
9333
|
+
local triangle=_ZONE_TRIANGLE:New(p1,p2,p3)
|
|
9334
|
+
local is_ear=true
|
|
9335
|
+
if not is_clockwise(p1,p2,p3)then
|
|
9336
|
+
is_ear=false
|
|
9337
|
+
else
|
|
9338
|
+
for _,point in ipairs(shape_points)do
|
|
9339
|
+
if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
|
|
9340
|
+
is_ear=false
|
|
9341
|
+
break
|
|
9342
|
+
end
|
|
9343
|
+
end
|
|
9344
|
+
end
|
|
9345
|
+
if is_ear then
|
|
9346
|
+
local is_valid_triangle=true
|
|
9347
|
+
for _,point in ipairs(points)do
|
|
9348
|
+
if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
|
|
9349
|
+
is_valid_triangle=false
|
|
9350
|
+
break
|
|
9351
|
+
end
|
|
9352
|
+
end
|
|
9353
|
+
if is_valid_triangle then
|
|
9354
|
+
table.insert(triangles,triangle)
|
|
9355
|
+
local remaining_points={}
|
|
9356
|
+
for j,point in ipairs(shape_points)do
|
|
9357
|
+
if point~=p2 then
|
|
9358
|
+
table.insert(remaining_points,point)
|
|
9359
|
+
end
|
|
9360
|
+
end
|
|
9361
|
+
divide_recursively(remaining_points)
|
|
9362
|
+
break
|
|
9363
|
+
end
|
|
9364
|
+
else
|
|
9365
|
+
end
|
|
9366
|
+
end
|
|
9367
|
+
end
|
|
9368
|
+
end
|
|
9369
|
+
points=ensure_clockwise(points)
|
|
9370
|
+
divide_recursively(points)
|
|
9371
|
+
return triangles
|
|
9372
|
+
end
|
|
8900
9373
|
function ZONE_POLYGON_BASE:UpdateFromVec2(Vec2Array)
|
|
8901
9374
|
self._.Polygon={}
|
|
8902
9375
|
for i=1,#Vec2Array do
|
|
@@ -8904,6 +9377,8 @@ self._.Polygon[i]={}
|
|
|
8904
9377
|
self._.Polygon[i].x=Vec2Array[i].x
|
|
8905
9378
|
self._.Polygon[i].y=Vec2Array[i].y
|
|
8906
9379
|
end
|
|
9380
|
+
self._Triangles=self:_Triangulate()
|
|
9381
|
+
self.SurfaceArea=self:_CalculateSurfaceArea()
|
|
8907
9382
|
return self
|
|
8908
9383
|
end
|
|
8909
9384
|
function ZONE_POLYGON_BASE:UpdateFromVec3(Vec3Array)
|
|
@@ -8913,8 +9388,17 @@ self._.Polygon[i]={}
|
|
|
8913
9388
|
self._.Polygon[i].x=Vec3Array[i].x
|
|
8914
9389
|
self._.Polygon[i].y=Vec3Array[i].z
|
|
8915
9390
|
end
|
|
9391
|
+
self._Triangles=self:_Triangulate()
|
|
9392
|
+
self.SurfaceArea=self:_CalculateSurfaceArea()
|
|
8916
9393
|
return self
|
|
8917
9394
|
end
|
|
9395
|
+
function ZONE_POLYGON_BASE:_CalculateSurfaceArea()
|
|
9396
|
+
local area=0
|
|
9397
|
+
for _,triangle in pairs(self._Triangles)do
|
|
9398
|
+
area=area+triangle.SurfaceArea
|
|
9399
|
+
end
|
|
9400
|
+
return area
|
|
9401
|
+
end
|
|
8918
9402
|
function ZONE_POLYGON_BASE:GetVec2()
|
|
8919
9403
|
self:F(self.ZoneName)
|
|
8920
9404
|
local Bounds=self:GetBoundingSquare()
|
|
@@ -8997,32 +9481,81 @@ i=i+1
|
|
|
8997
9481
|
end
|
|
8998
9482
|
return self
|
|
8999
9483
|
end
|
|
9000
|
-
function ZONE_POLYGON_BASE:DrawZone(Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly)
|
|
9484
|
+
function ZONE_POLYGON_BASE:DrawZone(Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly,IncludeTriangles)
|
|
9001
9485
|
if self._.Polygon and#self._.Polygon>=3 then
|
|
9002
|
-
local coordinate=COORDINATE:NewFromVec2(self._.Polygon[1])
|
|
9003
9486
|
Coalition=Coalition or self:GetDrawCoalition()
|
|
9004
9487
|
self:SetDrawCoalition(Coalition)
|
|
9005
9488
|
Color=Color or self:GetColorRGB()
|
|
9006
|
-
Alpha=Alpha or
|
|
9007
|
-
self:SetColor(Color,Alpha)
|
|
9489
|
+
Alpha=Alpha or self:GetColorAlpha()
|
|
9008
9490
|
FillColor=FillColor or self:GetFillColorRGB()
|
|
9009
|
-
if not FillColor then UTILS.DeepCopy(Color)end
|
|
9010
9491
|
FillAlpha=FillAlpha or self:GetFillColorAlpha()
|
|
9011
|
-
if
|
|
9012
|
-
self:
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
local
|
|
9020
|
-
|
|
9021
|
-
|
|
9492
|
+
if FillColor then
|
|
9493
|
+
self:ReFill(FillColor,FillAlpha)
|
|
9494
|
+
end
|
|
9495
|
+
if Color then
|
|
9496
|
+
self:ReDrawBorderline(Color,Alpha,LineType)
|
|
9497
|
+
end
|
|
9498
|
+
end
|
|
9499
|
+
if false then
|
|
9500
|
+
local coords=self:GetVerticiesCoordinates()
|
|
9501
|
+
local coord=coords[1]
|
|
9502
|
+
table.remove(coords,1)
|
|
9503
|
+
coord:MarkupToAllFreeForm(coords,Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly,"Drew Polygon")
|
|
9504
|
+
if true then
|
|
9505
|
+
return
|
|
9506
|
+
end
|
|
9507
|
+
end
|
|
9508
|
+
return self
|
|
9509
|
+
end
|
|
9510
|
+
function ZONE_POLYGON_BASE:ReFill(Color,Alpha)
|
|
9511
|
+
local color=Color or self:GetFillColorRGB()or{1,0,0}
|
|
9512
|
+
local alpha=Alpha or self:GetFillColorAlpha()or 1
|
|
9513
|
+
local coalition=self:GetDrawCoalition()or-1
|
|
9514
|
+
if#self.FillTriangles>0 then
|
|
9515
|
+
for _,triangle in pairs(self._Triangles)do
|
|
9516
|
+
triangle:UndrawZone()
|
|
9517
|
+
end
|
|
9518
|
+
for _,_value in pairs(self.FillTriangles)do
|
|
9519
|
+
table.remove_by_value(self.DrawID,_value)
|
|
9520
|
+
end
|
|
9521
|
+
self.FillTriangles=nil
|
|
9522
|
+
self.FillTriangles={}
|
|
9523
|
+
end
|
|
9524
|
+
for _,triangle in pairs(self._Triangles)do
|
|
9525
|
+
local draw_ids=triangle:Fill(coalition,color,alpha,nil)
|
|
9526
|
+
self.FillTriangles=draw_ids
|
|
9527
|
+
table.combine(self.DrawID,draw_ids)
|
|
9528
|
+
end
|
|
9529
|
+
return self
|
|
9530
|
+
end
|
|
9531
|
+
function ZONE_POLYGON_BASE:ReDrawBorderline(Color,Alpha,LineType)
|
|
9532
|
+
local color=Color or self:GetFillColorRGB()or{1,0,0}
|
|
9533
|
+
local alpha=Alpha or self:GetFillColorAlpha()or 1
|
|
9534
|
+
local coalition=self:GetDrawCoalition()or-1
|
|
9535
|
+
local linetype=LineType or 1
|
|
9536
|
+
if#self.Borderlines>0 then
|
|
9537
|
+
for _,MarkID in pairs(self.Borderlines)do
|
|
9538
|
+
trigger.action.removeMark(MarkID)
|
|
9539
|
+
end
|
|
9540
|
+
for _,_value in pairs(self.Borderlines)do
|
|
9541
|
+
table.remove_by_value(self.DrawID,_value)
|
|
9022
9542
|
end
|
|
9543
|
+
self.Borderlines=nil
|
|
9544
|
+
self.Borderlines={}
|
|
9545
|
+
end
|
|
9546
|
+
local coords=self:GetVerticiesCoordinates()
|
|
9547
|
+
for i=1,#coords do
|
|
9548
|
+
local c1=coords[i]
|
|
9549
|
+
local c2=coords[i%#coords+1]
|
|
9550
|
+
local newID=c1:LineToAll(c2,coalition,color,alpha,linetype,nil)
|
|
9551
|
+
self.DrawID[#self.DrawID+1]=newID
|
|
9552
|
+
self.Borderlines[#self.Borderlines+1]=newID
|
|
9023
9553
|
end
|
|
9024
9554
|
return self
|
|
9025
9555
|
end
|
|
9556
|
+
function ZONE_POLYGON_BASE:GetSurfaceArea()
|
|
9557
|
+
return self.SurfaceArea
|
|
9558
|
+
end
|
|
9026
9559
|
function ZONE_POLYGON_BASE:GetRadius()
|
|
9027
9560
|
local center=self:GetVec2()
|
|
9028
9561
|
local radius=0
|
|
@@ -9131,17 +9664,18 @@ local InZone=self:IsVec2InZone({x=Vec3.x,y=Vec3.z})
|
|
|
9131
9664
|
return InZone
|
|
9132
9665
|
end
|
|
9133
9666
|
function ZONE_POLYGON_BASE:GetRandomVec2()
|
|
9134
|
-
local
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9667
|
+
local weights={}
|
|
9668
|
+
for _,triangle in pairs(self._Triangles)do
|
|
9669
|
+
weights[triangle]=triangle.SurfaceArea/self.SurfaceArea
|
|
9670
|
+
end
|
|
9671
|
+
local random_weight=math.random()
|
|
9672
|
+
local accumulated_weight=0
|
|
9673
|
+
for triangle,weight in pairs(weights)do
|
|
9674
|
+
accumulated_weight=accumulated_weight+weight
|
|
9675
|
+
if accumulated_weight>=random_weight then
|
|
9676
|
+
return triangle:GetRandomVec2()
|
|
9140
9677
|
end
|
|
9141
|
-
n=n+1
|
|
9142
9678
|
end
|
|
9143
|
-
self:E("Could not find a random point in the polygon zone!")
|
|
9144
|
-
return nil
|
|
9145
9679
|
end
|
|
9146
9680
|
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
|
9147
9681
|
self:F2()
|
|
@@ -9198,6 +9732,7 @@ Radius=Radius or 1000
|
|
|
9198
9732
|
Alpha=Alpha or 1
|
|
9199
9733
|
Segments=Segments or 10
|
|
9200
9734
|
Closed=Closed or false
|
|
9735
|
+
local Limit
|
|
9201
9736
|
local i=1
|
|
9202
9737
|
local j=#self._.Polygon
|
|
9203
9738
|
if(Closed)then
|
|
@@ -9220,6 +9755,7 @@ i=i+1
|
|
|
9220
9755
|
end
|
|
9221
9756
|
return self
|
|
9222
9757
|
end
|
|
9758
|
+
do
|
|
9223
9759
|
ZONE_POLYGON={
|
|
9224
9760
|
ClassName="ZONE_POLYGON",
|
|
9225
9761
|
}
|
|
@@ -9244,6 +9780,36 @@ self:F({GroupName,ZoneGroup,self._.Polygon})
|
|
|
9244
9780
|
_EVENTDISPATCHER:CreateEventNewZone(self)
|
|
9245
9781
|
return self
|
|
9246
9782
|
end
|
|
9783
|
+
function ZONE_POLYGON:NewFromDrawing(DrawingName)
|
|
9784
|
+
local points={}
|
|
9785
|
+
for _,layer in pairs(env.mission.drawings.layers)do
|
|
9786
|
+
for _,object in pairs(layer["objects"])do
|
|
9787
|
+
if object["name"]==DrawingName then
|
|
9788
|
+
if(object["primitiveType"]=="Line"and object["closed"]==true)or(object["polygonMode"]=="free")then
|
|
9789
|
+
for _,point in UTILS.spairs(object["points"])do
|
|
9790
|
+
local p={x=object["mapX"]+point["x"],
|
|
9791
|
+
y=object["mapY"]+point["y"]}
|
|
9792
|
+
table.add(points,p)
|
|
9793
|
+
end
|
|
9794
|
+
elseif object["polygonMode"]=="rect"then
|
|
9795
|
+
local angle=object["angle"]
|
|
9796
|
+
local half_width=object["width"]/2
|
|
9797
|
+
local half_height=object["height"]/2
|
|
9798
|
+
local center={x=object["mapX"],y=object["mapY"]}
|
|
9799
|
+
local p1=UTILS.RotatePointAroundPivot({x=center.x-half_height,y=center.y+half_width},center,angle)
|
|
9800
|
+
local p2=UTILS.RotatePointAroundPivot({x=center.x+half_height,y=center.y+half_width},center,angle)
|
|
9801
|
+
local p3=UTILS.RotatePointAroundPivot({x=center.x+half_height,y=center.y-half_width},center,angle)
|
|
9802
|
+
local p4=UTILS.RotatePointAroundPivot({x=center.x-half_height,y=center.y-half_width},center,angle)
|
|
9803
|
+
points={p1,p2,p3,p4}
|
|
9804
|
+
else
|
|
9805
|
+
end
|
|
9806
|
+
end
|
|
9807
|
+
end
|
|
9808
|
+
end
|
|
9809
|
+
local self=BASE:Inherit(self,ZONE_POLYGON_BASE:New(DrawingName,points))
|
|
9810
|
+
_EVENTDISPATCHER:CreateEventNewZone(self)
|
|
9811
|
+
return self
|
|
9812
|
+
end
|
|
9247
9813
|
function ZONE_POLYGON:FindByName(ZoneName)
|
|
9248
9814
|
local ZoneFound=_DATABASE:FindZone(ZoneName)
|
|
9249
9815
|
return ZoneFound
|
|
@@ -9430,6 +9996,7 @@ end
|
|
|
9430
9996
|
function ZONE_POLYGON:IsNoneInZone()
|
|
9431
9997
|
return self:CountScannedCoalitions()==0
|
|
9432
9998
|
end
|
|
9999
|
+
end
|
|
9433
10000
|
do
|
|
9434
10001
|
ZONE_ELASTIC={
|
|
9435
10002
|
ClassName="ZONE_ELASTIC",
|
|
@@ -9523,6 +10090,124 @@ table.remove(h,#h)
|
|
|
9523
10090
|
return h
|
|
9524
10091
|
end
|
|
9525
10092
|
end
|
|
10093
|
+
ZONE_OVAL={
|
|
10094
|
+
ClassName="OVAL",
|
|
10095
|
+
ZoneName="",
|
|
10096
|
+
MajorAxis=nil,
|
|
10097
|
+
MinorAxis=nil,
|
|
10098
|
+
Angle=0,
|
|
10099
|
+
DrawPoly=nil
|
|
10100
|
+
}
|
|
10101
|
+
function ZONE_OVAL:New(name,vec2,major_axis,minor_axis,angle)
|
|
10102
|
+
self=BASE:Inherit(self,ZONE_BASE:New())
|
|
10103
|
+
self.ZoneName=name
|
|
10104
|
+
self.CenterVec2=vec2
|
|
10105
|
+
self.MajorAxis=major_axis
|
|
10106
|
+
self.MinorAxis=minor_axis
|
|
10107
|
+
self.Angle=angle or 0
|
|
10108
|
+
_DATABASE:AddZone(name,self)
|
|
10109
|
+
return self
|
|
10110
|
+
end
|
|
10111
|
+
function ZONE_OVAL:NewFromDrawing(DrawingName)
|
|
10112
|
+
self=BASE:Inherit(self,ZONE_BASE:New(DrawingName))
|
|
10113
|
+
for _,layer in pairs(env.mission.drawings.layers)do
|
|
10114
|
+
for _,object in pairs(layer["objects"])do
|
|
10115
|
+
if string.find(object["name"],DrawingName,1,true)then
|
|
10116
|
+
if object["polygonMode"]=="oval"then
|
|
10117
|
+
self.CenterVec2={x=object["mapX"],y=object["mapY"]}
|
|
10118
|
+
self.MajorAxis=object["r1"]
|
|
10119
|
+
self.MinorAxis=object["r2"]
|
|
10120
|
+
self.Angle=object["angle"]
|
|
10121
|
+
end
|
|
10122
|
+
end
|
|
10123
|
+
end
|
|
10124
|
+
end
|
|
10125
|
+
_DATABASE:AddZone(DrawingName,self)
|
|
10126
|
+
return self
|
|
10127
|
+
end
|
|
10128
|
+
function ZONE_OVAL:GetMajorAxis()
|
|
10129
|
+
return self.MajorAxis
|
|
10130
|
+
end
|
|
10131
|
+
function ZONE_OVAL:GetMinorAxis()
|
|
10132
|
+
return self.MinorAxis
|
|
10133
|
+
end
|
|
10134
|
+
function ZONE_OVAL:GetAngle()
|
|
10135
|
+
return self.Angle
|
|
10136
|
+
end
|
|
10137
|
+
function ZONE_OVAL:GetVec2()
|
|
10138
|
+
return self.CenterVec2
|
|
10139
|
+
end
|
|
10140
|
+
function ZONE_OVAL:IsVec2InZone(vec2)
|
|
10141
|
+
local cos,sin=math.cos,math.sin
|
|
10142
|
+
local dx=vec2.x-self.CenterVec2.x
|
|
10143
|
+
local dy=vec2.y-self.CenterVec2.y
|
|
10144
|
+
local rx=dx*cos(self.Angle)+dy*sin(self.Angle)
|
|
10145
|
+
local ry=-dx*sin(self.Angle)+dy*cos(self.Angle)
|
|
10146
|
+
return rx*rx/(self.MajorAxis*self.MajorAxis)+ry*ry/(self.MinorAxis*self.MinorAxis)<=1
|
|
10147
|
+
end
|
|
10148
|
+
function ZONE_OVAL:GetBoundingSquare()
|
|
10149
|
+
local min_x=self.CenterVec2.x-self.MajorAxis
|
|
10150
|
+
local min_y=self.CenterVec2.y-self.MinorAxis
|
|
10151
|
+
local max_x=self.CenterVec2.x+self.MajorAxis
|
|
10152
|
+
local max_y=self.CenterVec2.y+self.MinorAxis
|
|
10153
|
+
return{
|
|
10154
|
+
{x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
|
|
10155
|
+
}
|
|
10156
|
+
end
|
|
10157
|
+
function ZONE_OVAL:PointsOnEdge(num_points)
|
|
10158
|
+
num_points=num_points or 40
|
|
10159
|
+
local points={}
|
|
10160
|
+
local dtheta=2*math.pi/num_points
|
|
10161
|
+
for i=0,num_points-1 do
|
|
10162
|
+
local theta=i*dtheta
|
|
10163
|
+
local x=self.CenterVec2.x+self.MajorAxis*math.cos(theta)*math.cos(self.Angle)-self.MinorAxis*math.sin(theta)*math.sin(self.Angle)
|
|
10164
|
+
local y=self.CenterVec2.y+self.MajorAxis*math.cos(theta)*math.sin(self.Angle)+self.MinorAxis*math.sin(theta)*math.cos(self.Angle)
|
|
10165
|
+
table.insert(points,{x=x,y=y})
|
|
10166
|
+
end
|
|
10167
|
+
return points
|
|
10168
|
+
end
|
|
10169
|
+
function ZONE_OVAL:GetRandomVec2()
|
|
10170
|
+
local theta=math.rad(self.Angle)
|
|
10171
|
+
local random_point=math.sqrt(math.random())
|
|
10172
|
+
local phi=math.random()*2*math.pi
|
|
10173
|
+
local x_c=random_point*math.cos(phi)
|
|
10174
|
+
local y_c=random_point*math.sin(phi)
|
|
10175
|
+
local x_e=x_c*self.MajorAxis
|
|
10176
|
+
local y_e=y_c*self.MinorAxis
|
|
10177
|
+
local rx=(x_e*math.cos(theta)-y_e*math.sin(theta))+self.CenterVec2.x
|
|
10178
|
+
local ry=(x_e*math.sin(theta)+y_e*math.cos(theta))+self.CenterVec2.y
|
|
10179
|
+
return{x=rx,y=ry}
|
|
10180
|
+
end
|
|
10181
|
+
function ZONE_OVAL:GetRandomPointVec2()
|
|
10182
|
+
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
|
10183
|
+
end
|
|
10184
|
+
function ZONE_OVAL:GetRandomPointVec3()
|
|
10185
|
+
return POINT_VEC2:NewFromVec3(self:GetRandomVec2())
|
|
10186
|
+
end
|
|
10187
|
+
function ZONE_OVAL:DrawZone(Coalition,Color,Alpha,FillColor,FillAlpha,LineType)
|
|
10188
|
+
Coalition=Coalition or self:GetDrawCoalition()
|
|
10189
|
+
self:SetDrawCoalition(Coalition)
|
|
10190
|
+
Color=Color or self:GetColorRGB()
|
|
10191
|
+
Alpha=Alpha or 1
|
|
10192
|
+
self:SetColor(Color,Alpha)
|
|
10193
|
+
FillColor=FillColor or self:GetFillColorRGB()
|
|
10194
|
+
if not FillColor then
|
|
10195
|
+
UTILS.DeepCopy(Color)
|
|
10196
|
+
end
|
|
10197
|
+
FillAlpha=FillAlpha or self:GetFillColorAlpha()
|
|
10198
|
+
if not FillAlpha then
|
|
10199
|
+
FillAlpha=0.15
|
|
10200
|
+
end
|
|
10201
|
+
LineType=LineType or 1
|
|
10202
|
+
self:SetFillColor(FillColor,FillAlpha)
|
|
10203
|
+
self.DrawPoly=ZONE_POLYGON:NewFromPointsArray(self.ZoneName,self:PointsOnEdge(80))
|
|
10204
|
+
self.DrawPoly:DrawZone(Coalition,Color,Alpha,FillColor,FillAlpha,LineType)
|
|
10205
|
+
end
|
|
10206
|
+
function ZONE_OVAL:UndrawZone()
|
|
10207
|
+
if self.DrawPoly then
|
|
10208
|
+
self.DrawPoly:UndrawZone()
|
|
10209
|
+
end
|
|
10210
|
+
end
|
|
9526
10211
|
do
|
|
9527
10212
|
ZONE_AIRBASE={
|
|
9528
10213
|
ClassName="ZONE_AIRBASE",
|
|
@@ -9877,6 +10562,23 @@ table.remove(points,#points)
|
|
|
9877
10562
|
self:I(string.format("Register ZONE: %s (Polygon (free) drawing with %d vertices)",ZoneName,#points))
|
|
9878
10563
|
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName,points)
|
|
9879
10564
|
Zone:SetColor({1,0,0},0.15)
|
|
10565
|
+
Zone:SetFillColor({1,0,0},0.15)
|
|
10566
|
+
if objectData.colorString then
|
|
10567
|
+
local color=string.gsub(objectData.colorString,"^0x","")
|
|
10568
|
+
local r=tonumber(string.sub(color,1,2),16)/255
|
|
10569
|
+
local g=tonumber(string.sub(color,3,4),16)/255
|
|
10570
|
+
local b=tonumber(string.sub(color,5,6),16)/255
|
|
10571
|
+
local a=tonumber(string.sub(color,7,8),16)/255
|
|
10572
|
+
Zone:SetColor({r,g,b},a)
|
|
10573
|
+
end
|
|
10574
|
+
if objectData.fillColorString then
|
|
10575
|
+
local color=string.gsub(objectData.colorString,"^0x","")
|
|
10576
|
+
local r=tonumber(string.sub(color,1,2),16)/255
|
|
10577
|
+
local g=tonumber(string.sub(color,3,4),16)/255
|
|
10578
|
+
local b=tonumber(string.sub(color,5,6),16)/255
|
|
10579
|
+
local a=tonumber(string.sub(color,7,8),16)/255
|
|
10580
|
+
Zone:SetFillColor({r,g,b},a)
|
|
10581
|
+
end
|
|
9880
10582
|
self.ZONENAMES[ZoneName]=ZoneName
|
|
9881
10583
|
self:AddZone(ZoneName,Zone)
|
|
9882
10584
|
elseif objectData.polygonMode and objectData.polygonMode=="rect"then
|
|
@@ -9892,6 +10594,22 @@ points[4]={x=vec2.x-h/2,y=vec2.y-w/2}
|
|
|
9892
10594
|
self:I(string.format("Register ZONE: %s (Polygon (rect) drawing with %d vertices)",ZoneName,#points))
|
|
9893
10595
|
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName,points)
|
|
9894
10596
|
Zone:SetColor({1,0,0},0.15)
|
|
10597
|
+
if objectData.colorString then
|
|
10598
|
+
local color=string.gsub(objectData.colorString,"^0x","")
|
|
10599
|
+
local r=tonumber(string.sub(color,1,2),16)/255
|
|
10600
|
+
local g=tonumber(string.sub(color,3,4),16)/255
|
|
10601
|
+
local b=tonumber(string.sub(color,5,6),16)/255
|
|
10602
|
+
local a=tonumber(string.sub(color,7,8),16)/255
|
|
10603
|
+
Zone:SetColor({r,g,b},a)
|
|
10604
|
+
end
|
|
10605
|
+
if objectData.fillColorString then
|
|
10606
|
+
local color=string.gsub(objectData.colorString,"^0x","")
|
|
10607
|
+
local r=tonumber(string.sub(color,1,2),16)/255
|
|
10608
|
+
local g=tonumber(string.sub(color,3,4),16)/255
|
|
10609
|
+
local b=tonumber(string.sub(color,5,6),16)/255
|
|
10610
|
+
local a=tonumber(string.sub(color,7,8),16)/255
|
|
10611
|
+
Zone:SetFillColor({r,g,b},a)
|
|
10612
|
+
end
|
|
9895
10613
|
self.ZONENAMES[ZoneName]=ZoneName
|
|
9896
10614
|
self:AddZone(ZoneName,Zone)
|
|
9897
10615
|
elseif objectData.lineMode and(objectData.lineMode=="segments"or objectData.lineMode=="segment"or objectData.lineMode=="free")and objectData.points and#objectData.points>=2 then
|
|
@@ -10697,6 +11415,26 @@ self.CallScheduler=SCHEDULER:New(self)
|
|
|
10697
11415
|
self:SetEventPriority(2)
|
|
10698
11416
|
return self
|
|
10699
11417
|
end
|
|
11418
|
+
function SET_BASE:FilterFunction(ConditionFunction,...)
|
|
11419
|
+
local condition={}
|
|
11420
|
+
condition.func=ConditionFunction
|
|
11421
|
+
condition.arg={}
|
|
11422
|
+
if arg then
|
|
11423
|
+
condition.arg=arg
|
|
11424
|
+
end
|
|
11425
|
+
if not self.Filter.Functions then self.Filter.Functions={}end
|
|
11426
|
+
table.insert(self.Filter.Functions,condition)
|
|
11427
|
+
return self
|
|
11428
|
+
end
|
|
11429
|
+
function SET_BASE:_EvalFilterFunctions(Object)
|
|
11430
|
+
for _,_condition in pairs(self.Filter.Functions or{})do
|
|
11431
|
+
local condition=_condition
|
|
11432
|
+
if condition.func(Object,unpack(condition.arg))==false then
|
|
11433
|
+
return false
|
|
11434
|
+
end
|
|
11435
|
+
end
|
|
11436
|
+
return true
|
|
11437
|
+
end
|
|
10700
11438
|
function SET_BASE:Clear(TriggerEvent)
|
|
10701
11439
|
for Name,Object in pairs(self.Set)do
|
|
10702
11440
|
self:Remove(Name,not TriggerEvent)
|
|
@@ -10834,7 +11572,10 @@ self:T3({LastObject})
|
|
|
10834
11572
|
return LastObject
|
|
10835
11573
|
end
|
|
10836
11574
|
function SET_BASE:GetRandom()
|
|
10837
|
-
local tablemax=
|
|
11575
|
+
local tablemax=0
|
|
11576
|
+
for _,_ind in pairs(self.Index)do
|
|
11577
|
+
tablemax=tablemax+1
|
|
11578
|
+
end
|
|
10838
11579
|
local RandomItem=self.Set[self.Index[math.random(1,tablemax)]]
|
|
10839
11580
|
self:T3({RandomItem})
|
|
10840
11581
|
return RandomItem
|
|
@@ -11057,6 +11798,7 @@ Categories=nil,
|
|
|
11057
11798
|
Countries=nil,
|
|
11058
11799
|
GroupPrefixes=nil,
|
|
11059
11800
|
Zones=nil,
|
|
11801
|
+
Functions=nil,
|
|
11060
11802
|
},
|
|
11061
11803
|
FilterMeta={
|
|
11062
11804
|
Coalitions={
|
|
@@ -11506,7 +12248,7 @@ MGroupActive=true
|
|
|
11506
12248
|
end
|
|
11507
12249
|
MGroupInclude=MGroupInclude and MGroupActive
|
|
11508
12250
|
end
|
|
11509
|
-
if self.Filter.Coalitions then
|
|
12251
|
+
if self.Filter.Coalitions and MGroupInclude then
|
|
11510
12252
|
local MGroupCoalition=false
|
|
11511
12253
|
for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
|
|
11512
12254
|
self:T3({"Coalition:",MGroup:GetCoalition(),self.FilterMeta.Coalitions[CoalitionName],CoalitionName})
|
|
@@ -11516,7 +12258,7 @@ end
|
|
|
11516
12258
|
end
|
|
11517
12259
|
MGroupInclude=MGroupInclude and MGroupCoalition
|
|
11518
12260
|
end
|
|
11519
|
-
if self.Filter.Categories then
|
|
12261
|
+
if self.Filter.Categories and MGroupInclude then
|
|
11520
12262
|
local MGroupCategory=false
|
|
11521
12263
|
for CategoryID,CategoryName in pairs(self.Filter.Categories)do
|
|
11522
12264
|
self:T3({"Category:",MGroup:GetCategory(),self.FilterMeta.Categories[CategoryName],CategoryName})
|
|
@@ -11526,7 +12268,7 @@ end
|
|
|
11526
12268
|
end
|
|
11527
12269
|
MGroupInclude=MGroupInclude and MGroupCategory
|
|
11528
12270
|
end
|
|
11529
|
-
if self.Filter.Countries then
|
|
12271
|
+
if self.Filter.Countries and MGroupInclude then
|
|
11530
12272
|
local MGroupCountry=false
|
|
11531
12273
|
for CountryID,CountryName in pairs(self.Filter.Countries)do
|
|
11532
12274
|
self:T3({"Country:",MGroup:GetCountry(),CountryName})
|
|
@@ -11536,7 +12278,7 @@ end
|
|
|
11536
12278
|
end
|
|
11537
12279
|
MGroupInclude=MGroupInclude and MGroupCountry
|
|
11538
12280
|
end
|
|
11539
|
-
if self.Filter.GroupPrefixes then
|
|
12281
|
+
if self.Filter.GroupPrefixes and MGroupInclude then
|
|
11540
12282
|
local MGroupPrefix=false
|
|
11541
12283
|
for GroupPrefixId,GroupPrefix in pairs(self.Filter.GroupPrefixes)do
|
|
11542
12284
|
self:T3({"Prefix:",string.find(MGroup:GetName(),GroupPrefix,1),GroupPrefix})
|
|
@@ -11546,7 +12288,7 @@ end
|
|
|
11546
12288
|
end
|
|
11547
12289
|
MGroupInclude=MGroupInclude and MGroupPrefix
|
|
11548
12290
|
end
|
|
11549
|
-
if self.Filter.Zones then
|
|
12291
|
+
if self.Filter.Zones and MGroupInclude then
|
|
11550
12292
|
local MGroupZone=false
|
|
11551
12293
|
for ZoneName,Zone in pairs(self.Filter.Zones)do
|
|
11552
12294
|
if MGroup:IsInZone(Zone)then
|
|
@@ -11555,6 +12297,11 @@ end
|
|
|
11555
12297
|
end
|
|
11556
12298
|
MGroupInclude=MGroupInclude and MGroupZone
|
|
11557
12299
|
end
|
|
12300
|
+
if self.Filter.Functions and MGroupInclude then
|
|
12301
|
+
local MGroupFunc=false
|
|
12302
|
+
MGroupFunc=self:_EvalFilterFunctions(MGroup)
|
|
12303
|
+
MGroupInclude=MGroupInclude and MGroupFunc
|
|
12304
|
+
end
|
|
11558
12305
|
self:T2(MGroupInclude)
|
|
11559
12306
|
return MGroupInclude
|
|
11560
12307
|
end
|
|
@@ -11595,6 +12342,7 @@ Types=nil,
|
|
|
11595
12342
|
Countries=nil,
|
|
11596
12343
|
UnitPrefixes=nil,
|
|
11597
12344
|
Zones=nil,
|
|
12345
|
+
Functions=nil,
|
|
11598
12346
|
},
|
|
11599
12347
|
FilterMeta={
|
|
11600
12348
|
Coalitions={
|
|
@@ -11983,46 +12731,40 @@ self:F({MaxThreatLevelA2G=MaxThreatLevelA2G,MaxThreatText=MaxThreatText})
|
|
|
11983
12731
|
return MaxThreatLevelA2G,MaxThreatText
|
|
11984
12732
|
end
|
|
11985
12733
|
function SET_UNIT:GetCoordinate()
|
|
11986
|
-
local
|
|
11987
|
-
local
|
|
11988
|
-
|
|
11989
|
-
|
|
12734
|
+
local function GetSetVec3(units)
|
|
12735
|
+
local x=0
|
|
12736
|
+
local y=0
|
|
12737
|
+
local z=0
|
|
12738
|
+
local n=0
|
|
12739
|
+
for _,unit in pairs(units)do
|
|
12740
|
+
local vec3=nil
|
|
12741
|
+
if unit and unit:IsAlive()then
|
|
12742
|
+
vec3=unit:GetVec3()
|
|
11990
12743
|
end
|
|
11991
|
-
if
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
local y2=Coordinate.y
|
|
11997
|
-
local z1=Coordinate.z
|
|
11998
|
-
local z2=Coordinate.z
|
|
11999
|
-
local MaxVelocity=0
|
|
12000
|
-
local AvgHeading=nil
|
|
12001
|
-
local MovingCount=0
|
|
12002
|
-
for UnitName,UnitData in pairs(self:GetAliveSet())do
|
|
12003
|
-
local Unit=UnitData
|
|
12004
|
-
local Coordinate=Unit:GetCoordinate()
|
|
12005
|
-
x1=(Coordinate.x<x1)and Coordinate.x or x1
|
|
12006
|
-
x2=(Coordinate.x>x2)and Coordinate.x or x2
|
|
12007
|
-
y1=(Coordinate.y<y1)and Coordinate.y or y1
|
|
12008
|
-
y2=(Coordinate.y>y2)and Coordinate.y or y2
|
|
12009
|
-
z1=(Coordinate.y<z1)and Coordinate.z or z1
|
|
12010
|
-
z2=(Coordinate.y>z2)and Coordinate.z or z2
|
|
12011
|
-
local Velocity=Coordinate:GetVelocity()
|
|
12012
|
-
if Velocity~=0 then
|
|
12013
|
-
MaxVelocity=(MaxVelocity<Velocity)and Velocity or MaxVelocity
|
|
12014
|
-
local Heading=Coordinate:GetHeading()
|
|
12015
|
-
AvgHeading=AvgHeading and(AvgHeading+Heading)or Heading
|
|
12016
|
-
MovingCount=MovingCount+1
|
|
12744
|
+
if vec3 then
|
|
12745
|
+
x=x+vec3.x
|
|
12746
|
+
y=y+vec3.y
|
|
12747
|
+
z=z+vec3.z
|
|
12748
|
+
n=n+1
|
|
12017
12749
|
end
|
|
12018
12750
|
end
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12751
|
+
if n>0 then
|
|
12752
|
+
local Vec3={x=x/n,y=y/n,z=z/n}
|
|
12753
|
+
return Vec3
|
|
12754
|
+
end
|
|
12755
|
+
return nil
|
|
12756
|
+
end
|
|
12757
|
+
local Coordinate=nil
|
|
12758
|
+
local Vec3=GetSetVec3(self.Set)
|
|
12759
|
+
if Vec3 then
|
|
12760
|
+
Coordinate=COORDINATE:NewFromVec3(Vec3)
|
|
12761
|
+
end
|
|
12762
|
+
if Coordinate then
|
|
12763
|
+
local heading=self:GetHeading()or 0
|
|
12764
|
+
local velocity=self:GetVelocity()or 0
|
|
12765
|
+
Coordinate:SetHeading(heading)
|
|
12766
|
+
Coordinate:SetVelocity(velocity)
|
|
12767
|
+
self:I(UTILS.PrintTableToLog(Coordinate))
|
|
12026
12768
|
end
|
|
12027
12769
|
return Coordinate
|
|
12028
12770
|
end
|
|
@@ -12142,7 +12884,7 @@ MUnitActive=true
|
|
|
12142
12884
|
end
|
|
12143
12885
|
MUnitInclude=MUnitInclude and MUnitActive
|
|
12144
12886
|
end
|
|
12145
|
-
if self.Filter.Coalitions then
|
|
12887
|
+
if self.Filter.Coalitions and MUnitInclude then
|
|
12146
12888
|
local MUnitCoalition=false
|
|
12147
12889
|
for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
|
|
12148
12890
|
self:F({"Coalition:",MUnit:GetCoalition(),self.FilterMeta.Coalitions[CoalitionName],CoalitionName})
|
|
@@ -12152,7 +12894,7 @@ end
|
|
|
12152
12894
|
end
|
|
12153
12895
|
MUnitInclude=MUnitInclude and MUnitCoalition
|
|
12154
12896
|
end
|
|
12155
|
-
if self.Filter.Categories then
|
|
12897
|
+
if self.Filter.Categories and MUnitInclude then
|
|
12156
12898
|
local MUnitCategory=false
|
|
12157
12899
|
for CategoryID,CategoryName in pairs(self.Filter.Categories)do
|
|
12158
12900
|
self:T3({"Category:",MUnit:GetDesc().category,self.FilterMeta.Categories[CategoryName],CategoryName})
|
|
@@ -12162,7 +12904,7 @@ end
|
|
|
12162
12904
|
end
|
|
12163
12905
|
MUnitInclude=MUnitInclude and MUnitCategory
|
|
12164
12906
|
end
|
|
12165
|
-
if self.Filter.Types then
|
|
12907
|
+
if self.Filter.Types and MUnitInclude then
|
|
12166
12908
|
local MUnitType=false
|
|
12167
12909
|
for TypeID,TypeName in pairs(self.Filter.Types)do
|
|
12168
12910
|
self:T3({"Type:",MUnit:GetTypeName(),TypeName})
|
|
@@ -12172,7 +12914,7 @@ end
|
|
|
12172
12914
|
end
|
|
12173
12915
|
MUnitInclude=MUnitInclude and MUnitType
|
|
12174
12916
|
end
|
|
12175
|
-
if self.Filter.Countries then
|
|
12917
|
+
if self.Filter.Countries and MUnitInclude then
|
|
12176
12918
|
local MUnitCountry=false
|
|
12177
12919
|
for CountryID,CountryName in pairs(self.Filter.Countries)do
|
|
12178
12920
|
self:T3({"Country:",MUnit:GetCountry(),CountryName})
|
|
@@ -12182,7 +12924,7 @@ end
|
|
|
12182
12924
|
end
|
|
12183
12925
|
MUnitInclude=MUnitInclude and MUnitCountry
|
|
12184
12926
|
end
|
|
12185
|
-
if self.Filter.UnitPrefixes then
|
|
12927
|
+
if self.Filter.UnitPrefixes and MUnitInclude then
|
|
12186
12928
|
local MUnitPrefix=false
|
|
12187
12929
|
for UnitPrefixId,UnitPrefix in pairs(self.Filter.UnitPrefixes)do
|
|
12188
12930
|
self:T3({"Prefix:",string.find(MUnit:GetName(),UnitPrefix,1),UnitPrefix})
|
|
@@ -12192,7 +12934,7 @@ end
|
|
|
12192
12934
|
end
|
|
12193
12935
|
MUnitInclude=MUnitInclude and MUnitPrefix
|
|
12194
12936
|
end
|
|
12195
|
-
if self.Filter.RadarTypes then
|
|
12937
|
+
if self.Filter.RadarTypes and MUnitInclude then
|
|
12196
12938
|
local MUnitRadar=false
|
|
12197
12939
|
for RadarTypeID,RadarType in pairs(self.Filter.RadarTypes)do
|
|
12198
12940
|
self:T3({"Radar:",RadarType})
|
|
@@ -12205,7 +12947,7 @@ end
|
|
|
12205
12947
|
end
|
|
12206
12948
|
MUnitInclude=MUnitInclude and MUnitRadar
|
|
12207
12949
|
end
|
|
12208
|
-
if self.Filter.SEAD then
|
|
12950
|
+
if self.Filter.SEAD and MUnitInclude then
|
|
12209
12951
|
local MUnitSEAD=false
|
|
12210
12952
|
if MUnit:HasSEAD()==true then
|
|
12211
12953
|
self:T3("SEAD Found")
|
|
@@ -12214,7 +12956,7 @@ end
|
|
|
12214
12956
|
MUnitInclude=MUnitInclude and MUnitSEAD
|
|
12215
12957
|
end
|
|
12216
12958
|
end
|
|
12217
|
-
if self.Filter.Zones then
|
|
12959
|
+
if self.Filter.Zones and MUnitInclude then
|
|
12218
12960
|
local MGroupZone=false
|
|
12219
12961
|
for ZoneName,Zone in pairs(self.Filter.Zones)do
|
|
12220
12962
|
self:T3("Zone:",ZoneName)
|
|
@@ -12224,6 +12966,10 @@ end
|
|
|
12224
12966
|
end
|
|
12225
12967
|
MUnitInclude=MUnitInclude and MGroupZone
|
|
12226
12968
|
end
|
|
12969
|
+
if self.Filter.Functions and MUnitInclude then
|
|
12970
|
+
local MUnitFunc=self:_EvalFilterFunctions(MUnit)
|
|
12971
|
+
MUnitInclude=MUnitInclude and MUnitFunc
|
|
12972
|
+
end
|
|
12227
12973
|
self:T2(MUnitInclude)
|
|
12228
12974
|
return MUnitInclude
|
|
12229
12975
|
end
|
|
@@ -12974,7 +13720,7 @@ MClientActive=true
|
|
|
12974
13720
|
end
|
|
12975
13721
|
MClientInclude=MClientInclude and MClientActive
|
|
12976
13722
|
end
|
|
12977
|
-
if self.Filter.Coalitions then
|
|
13723
|
+
if self.Filter.Coalitions and MClientInclude then
|
|
12978
13724
|
local MClientCoalition=false
|
|
12979
13725
|
for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
|
|
12980
13726
|
local ClientCoalitionID=_DATABASE:GetCoalitionFromClientTemplate(MClientName)
|
|
@@ -12986,7 +13732,7 @@ end
|
|
|
12986
13732
|
self:T({"Evaluated Coalition",MClientCoalition})
|
|
12987
13733
|
MClientInclude=MClientInclude and MClientCoalition
|
|
12988
13734
|
end
|
|
12989
|
-
if self.Filter.Categories then
|
|
13735
|
+
if self.Filter.Categories and MClientInclude then
|
|
12990
13736
|
local MClientCategory=false
|
|
12991
13737
|
for CategoryID,CategoryName in pairs(self.Filter.Categories)do
|
|
12992
13738
|
local ClientCategoryID=_DATABASE:GetCategoryFromClientTemplate(MClientName)
|
|
@@ -12998,7 +13744,7 @@ end
|
|
|
12998
13744
|
self:T({"Evaluated Category",MClientCategory})
|
|
12999
13745
|
MClientInclude=MClientInclude and MClientCategory
|
|
13000
13746
|
end
|
|
13001
|
-
if self.Filter.Types then
|
|
13747
|
+
if self.Filter.Types and MClientInclude then
|
|
13002
13748
|
local MClientType=false
|
|
13003
13749
|
for TypeID,TypeName in pairs(self.Filter.Types)do
|
|
13004
13750
|
self:T3({"Type:",MClient:GetTypeName(),TypeName})
|
|
@@ -13009,7 +13755,7 @@ end
|
|
|
13009
13755
|
self:T({"Evaluated Type",MClientType})
|
|
13010
13756
|
MClientInclude=MClientInclude and MClientType
|
|
13011
13757
|
end
|
|
13012
|
-
if self.Filter.Countries then
|
|
13758
|
+
if self.Filter.Countries and MClientInclude then
|
|
13013
13759
|
local MClientCountry=false
|
|
13014
13760
|
for CountryID,CountryName in pairs(self.Filter.Countries)do
|
|
13015
13761
|
local ClientCountryID=_DATABASE:GetCountryFromClientTemplate(MClientName)
|
|
@@ -13021,7 +13767,7 @@ end
|
|
|
13021
13767
|
self:T({"Evaluated Country",MClientCountry})
|
|
13022
13768
|
MClientInclude=MClientInclude and MClientCountry
|
|
13023
13769
|
end
|
|
13024
|
-
if self.Filter.ClientPrefixes then
|
|
13770
|
+
if self.Filter.ClientPrefixes and MClientInclude then
|
|
13025
13771
|
local MClientPrefix=false
|
|
13026
13772
|
for ClientPrefixId,ClientPrefix in pairs(self.Filter.ClientPrefixes)do
|
|
13027
13773
|
self:T3({"Prefix:",string.find(MClient.UnitName,ClientPrefix,1),ClientPrefix})
|
|
@@ -13032,7 +13778,7 @@ end
|
|
|
13032
13778
|
self:T({"Evaluated Prefix",MClientPrefix})
|
|
13033
13779
|
MClientInclude=MClientInclude and MClientPrefix
|
|
13034
13780
|
end
|
|
13035
|
-
if self.Filter.Zones then
|
|
13781
|
+
if self.Filter.Zones and MClientInclude then
|
|
13036
13782
|
local MClientZone=false
|
|
13037
13783
|
for ZoneName,Zone in pairs(self.Filter.Zones)do
|
|
13038
13784
|
self:T3("Zone:",ZoneName)
|
|
@@ -13043,7 +13789,7 @@ end
|
|
|
13043
13789
|
end
|
|
13044
13790
|
MClientInclude=MClientInclude and MClientZone
|
|
13045
13791
|
end
|
|
13046
|
-
if self.Filter.Playernames then
|
|
13792
|
+
if self.Filter.Playernames and MClientInclude then
|
|
13047
13793
|
local MClientPlayername=false
|
|
13048
13794
|
local playername=MClient:GetPlayerName()or"Unknown"
|
|
13049
13795
|
for _,_Playername in pairs(self.Filter.Playernames)do
|
|
@@ -13054,7 +13800,7 @@ end
|
|
|
13054
13800
|
self:T({"Evaluated Playername",MClientPlayername})
|
|
13055
13801
|
MClientInclude=MClientInclude and MClientPlayername
|
|
13056
13802
|
end
|
|
13057
|
-
if self.Filter.Callsigns then
|
|
13803
|
+
if self.Filter.Callsigns and MClientInclude then
|
|
13058
13804
|
local MClientCallsigns=false
|
|
13059
13805
|
local callsign=MClient:GetCallsign()
|
|
13060
13806
|
for _,_Callsign in pairs(self.Filter.Callsigns)do
|
|
@@ -13065,6 +13811,10 @@ end
|
|
|
13065
13811
|
self:T({"Evaluated Callsign",MClientCallsigns})
|
|
13066
13812
|
MClientInclude=MClientInclude and MClientCallsigns
|
|
13067
13813
|
end
|
|
13814
|
+
if self.Filter.Functions and MClientInclude then
|
|
13815
|
+
local MClientFunc=self:_EvalFilterFunctions(MClient)
|
|
13816
|
+
MClientInclude=MClientInclude and MClientFunc
|
|
13817
|
+
end
|
|
13068
13818
|
end
|
|
13069
13819
|
self:T2(MClientInclude)
|
|
13070
13820
|
return MClientInclude
|
|
@@ -13384,7 +14134,6 @@ return AirbaseFound
|
|
|
13384
14134
|
end
|
|
13385
14135
|
function SET_AIRBASE:GetRandomAirbase()
|
|
13386
14136
|
local RandomAirbase=self:GetRandom()
|
|
13387
|
-
self:F({RandomAirbase=RandomAirbase:GetName()})
|
|
13388
14137
|
return RandomAirbase
|
|
13389
14138
|
end
|
|
13390
14139
|
function SET_AIRBASE:FilterCoalitions(Coalitions)
|
|
@@ -13474,7 +14223,7 @@ end
|
|
|
13474
14223
|
self:T({"Evaluated Coalition",MAirbaseCoalition})
|
|
13475
14224
|
MAirbaseInclude=MAirbaseInclude and MAirbaseCoalition
|
|
13476
14225
|
end
|
|
13477
|
-
if self.Filter.Categories then
|
|
14226
|
+
if self.Filter.Categories and MAirbaseInclude then
|
|
13478
14227
|
local MAirbaseCategory=false
|
|
13479
14228
|
for CategoryID,CategoryName in pairs(self.Filter.Categories)do
|
|
13480
14229
|
local AirbaseCategoryID=_DATABASE:GetCategoryFromAirbase(MAirbaseName)
|
|
@@ -14557,7 +15306,7 @@ MGroupActive=true
|
|
|
14557
15306
|
end
|
|
14558
15307
|
MGroupInclude=MGroupInclude and MGroupActive
|
|
14559
15308
|
end
|
|
14560
|
-
if self.Filter.Coalitions then
|
|
15309
|
+
if self.Filter.Coalitions and MGroupInclude then
|
|
14561
15310
|
local MGroupCoalition=false
|
|
14562
15311
|
for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
|
|
14563
15312
|
if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==MGroup:GetCoalition()then
|
|
@@ -14566,7 +15315,7 @@ end
|
|
|
14566
15315
|
end
|
|
14567
15316
|
MGroupInclude=MGroupInclude and MGroupCoalition
|
|
14568
15317
|
end
|
|
14569
|
-
if self.Filter.Categories then
|
|
15318
|
+
if self.Filter.Categories and MGroupInclude then
|
|
14570
15319
|
local MGroupCategory=false
|
|
14571
15320
|
for CategoryID,CategoryName in pairs(self.Filter.Categories)do
|
|
14572
15321
|
if self.FilterMeta.Categories[CategoryName]and self.FilterMeta.Categories[CategoryName]==MGroup:GetCategory()then
|
|
@@ -14575,7 +15324,7 @@ end
|
|
|
14575
15324
|
end
|
|
14576
15325
|
MGroupInclude=MGroupInclude and MGroupCategory
|
|
14577
15326
|
end
|
|
14578
|
-
if self.Filter.Countries then
|
|
15327
|
+
if self.Filter.Countries and MGroupInclude then
|
|
14579
15328
|
local MGroupCountry=false
|
|
14580
15329
|
for CountryID,CountryName in pairs(self.Filter.Countries)do
|
|
14581
15330
|
if country.id[CountryName]==MGroup:GetCountry()then
|
|
@@ -14584,7 +15333,7 @@ end
|
|
|
14584
15333
|
end
|
|
14585
15334
|
MGroupInclude=MGroupInclude and MGroupCountry
|
|
14586
15335
|
end
|
|
14587
|
-
if self.Filter.GroupPrefixes then
|
|
15336
|
+
if self.Filter.GroupPrefixes and MGroupInclude then
|
|
14588
15337
|
local MGroupPrefix=false
|
|
14589
15338
|
for GroupPrefixId,GroupPrefix in pairs(self.Filter.GroupPrefixes)do
|
|
14590
15339
|
if string.find(MGroup:GetName(),GroupPrefix:gsub("-","%%-"),1)then
|
|
@@ -15950,11 +16699,14 @@ Color,FillColor,LineType,ReadOnly,Text or"")
|
|
|
15950
16699
|
else
|
|
15951
16700
|
local s=string.format("trigger.action.markupToAll(7, %d, %d,",Coalition,MarkID)
|
|
15952
16701
|
for _,vec in pairs(vecs)do
|
|
15953
|
-
s=s..string.format("
|
|
16702
|
+
s=s..string.format("{x=%.1f, y=%.1f, z=%.1f},",vec.x,vec.y,vec.z)
|
|
15954
16703
|
end
|
|
15955
|
-
s=s..string.format("
|
|
15956
|
-
|
|
15957
|
-
s=s..string.format(",
|
|
16704
|
+
s=s..string.format("{%.3f, %.3f, %.3f, %.3f},",Color[1],Color[2],Color[3],Color[4])
|
|
16705
|
+
s=s..string.format("{%.3f, %.3f, %.3f, %.3f},",FillColor[1],FillColor[2],FillColor[3],FillColor[4])
|
|
16706
|
+
s=s..string.format("%d,",LineType or 1)
|
|
16707
|
+
s=s..string.format("%s",tostring(ReadOnly))
|
|
16708
|
+
if Text and type(Text)=="string"and string.len(Text)>0 then
|
|
16709
|
+
s=s..string.format(", \"%s\"",tostring(Text))
|
|
15958
16710
|
end
|
|
15959
16711
|
s=s..")"
|
|
15960
16712
|
local success=UTILS.DoString(s)
|
|
@@ -16213,6 +16965,9 @@ end
|
|
|
16213
16965
|
end
|
|
16214
16966
|
return BRAANATO
|
|
16215
16967
|
end
|
|
16968
|
+
function COORDINATE.GetBullseyeCoordinate(Coalition)
|
|
16969
|
+
return COORDINATE:NewFromVec3(coalition.getMainRefPoint(Coalition))
|
|
16970
|
+
end
|
|
16216
16971
|
function COORDINATE:ToStringBULLS(Coalition,Settings,MagVar)
|
|
16217
16972
|
local BullsCoordinate=COORDINATE:NewFromVec3(coalition.getMainRefPoint(Coalition))
|
|
16218
16973
|
local DirectionVec3=BullsCoordinate:GetDirectionVec3(self)
|
|
@@ -16261,6 +17016,36 @@ local lat,lon=coord.LOtoLL(self:GetVec3())
|
|
|
16261
17016
|
local MGRS=coord.LLtoMGRS(lat,lon)
|
|
16262
17017
|
return"MGRS "..UTILS.tostringMGRS(MGRS,MGRS_Accuracy)
|
|
16263
17018
|
end
|
|
17019
|
+
function COORDINATE:NewFromMGRSString(MGRSString)
|
|
17020
|
+
local myparts=UTILS.Split(MGRSString," ")
|
|
17021
|
+
local northing=tostring(myparts[5])or""
|
|
17022
|
+
local easting=tostring(myparts[4])or""
|
|
17023
|
+
if string.len(easting)<5 then easting=easting..string.rep("0",5-string.len(easting))end
|
|
17024
|
+
if string.len(northing)<5 then northing=northing..string.rep("0",5-string.len(northing))end
|
|
17025
|
+
local MGRS={
|
|
17026
|
+
UTMZone=myparts[2],
|
|
17027
|
+
MGRSDigraph=myparts[3],
|
|
17028
|
+
Easting=easting,
|
|
17029
|
+
Northing=northing,
|
|
17030
|
+
}
|
|
17031
|
+
local lat,lon=coord.MGRStoLL(MGRS)
|
|
17032
|
+
local point=coord.LLtoLO(lat,lon,0)
|
|
17033
|
+
local coord=COORDINATE:NewFromVec2({x=point.x,y=point.z})
|
|
17034
|
+
return coord
|
|
17035
|
+
end
|
|
17036
|
+
function COORDINATE:NewFromMGRS(UTMZone,MGRSDigraph,Easting,Northing)
|
|
17037
|
+
if string.len(Easting)<5 then Easting=Easting..string.rep("0",5-string.len(Easting))end
|
|
17038
|
+
if string.len(Northing)<5 then Northing=Northing..string.rep("0",5-string.len(Northing))end
|
|
17039
|
+
local MGRS={
|
|
17040
|
+
UTMZone=UTMZone,
|
|
17041
|
+
MGRSDigraph=MGRSDigraph,
|
|
17042
|
+
Easting=Easting,
|
|
17043
|
+
Northing=Northing,
|
|
17044
|
+
}
|
|
17045
|
+
local lat,lon=coord.MGRStoLL(MGRS)
|
|
17046
|
+
local point=coord.LLtoLO(lat,lon,0)
|
|
17047
|
+
local coord=COORDINATE:NewFromVec2({x=point.x,y=point.z})
|
|
17048
|
+
end
|
|
16264
17049
|
function COORDINATE:ToStringFromRP(ReferenceCoord,ReferenceName,Controllable,Settings,MagVar)
|
|
16265
17050
|
self:F2({ReferenceCoord=ReferenceCoord,ReferenceName=ReferenceName})
|
|
16266
17051
|
local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS
|
|
@@ -16792,7 +17577,7 @@ end
|
|
|
16792
17577
|
if CoalitionSide then
|
|
16793
17578
|
if self.MessageDuration~=0 then
|
|
16794
17579
|
self:T(self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$","").." / "..self.MessageDuration)
|
|
16795
|
-
trigger.action.outTextForCoalition(CoalitionSide,self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration,self.ClearScreen)
|
|
17580
|
+
trigger.action.outTextForCoalition(CoalitionSide,self.MessageCategory..self.MessageText:gsub("\n$",""):gsub("\n$",""),self.MessageDuration,self.ClearScreen)
|
|
16796
17581
|
end
|
|
16797
17582
|
end
|
|
16798
17583
|
self.CoalitionSide=CoalitionSide
|
|
@@ -16848,7 +17633,6 @@ _MESSAGESRS.Culture=Culture or"en-GB"
|
|
|
16848
17633
|
_MESSAGESRS.MSRS:SetGender(Gender)
|
|
16849
17634
|
_MESSAGESRS.Gender=Gender or"female"
|
|
16850
17635
|
_MESSAGESRS.MSRS:SetGoogle(PathToCredentials)
|
|
16851
|
-
_MESSAGESRS.google=PathToCredentials
|
|
16852
17636
|
_MESSAGESRS.MSRS:SetLabel(Label or"MESSAGE")
|
|
16853
17637
|
_MESSAGESRS.label=Label or"MESSAGE"
|
|
16854
17638
|
_MESSAGESRS.MSRS:SetPort(Port or 5002)
|
|
@@ -17439,6 +18223,7 @@ self.SpawnInitModexPrefix=nil
|
|
|
17439
18223
|
self.SpawnInitModexPostfix=nil
|
|
17440
18224
|
self.SpawnInitAirbase=nil
|
|
17441
18225
|
self.TweakedTemplate=false
|
|
18226
|
+
self.SpawnRandomCallsign=false
|
|
17442
18227
|
self.SpawnGroups={}
|
|
17443
18228
|
else
|
|
17444
18229
|
error("SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '"..SpawnTemplatePrefix.."'")
|
|
@@ -17728,6 +18513,18 @@ self:_RandomizeZones(SpawnGroupID)
|
|
|
17728
18513
|
end
|
|
17729
18514
|
return self
|
|
17730
18515
|
end
|
|
18516
|
+
function SPAWN:InitRandomizeCallsign()
|
|
18517
|
+
self.SpawnRandomCallsign=true
|
|
18518
|
+
return self
|
|
18519
|
+
end
|
|
18520
|
+
function SPAWN:InitCallSign(ID,Name,Minor,Major)
|
|
18521
|
+
self.SpawnInitCallSign=true
|
|
18522
|
+
self.SpawnInitCallSignID=ID or 1
|
|
18523
|
+
self.SpawnInitCallSignMinor=Minor or 1
|
|
18524
|
+
self.SpawnInitCallSignMajor=Major or 1
|
|
18525
|
+
self.SpawnInitCallSignName=string.lower(Name)or"enfield"
|
|
18526
|
+
return self
|
|
18527
|
+
end
|
|
17731
18528
|
function SPAWN:InitPositionCoordinate(Coordinate)
|
|
17732
18529
|
self:T({self.SpawnTemplatePrefix,Coordinate:GetVec2()})
|
|
17733
18530
|
self:InitPositionVec2(Coordinate:GetVec2())
|
|
@@ -18849,19 +19646,133 @@ SpawnTemplate.units[UnitID].name=string.format('%s#%03d-%02d',UnitPrefix,SpawnIn
|
|
|
18849
19646
|
SpawnTemplate.units[UnitID].unitId=nil
|
|
18850
19647
|
end
|
|
18851
19648
|
end
|
|
19649
|
+
if self.SpawnRandomCallsign and SpawnTemplate.units[1].callsign then
|
|
19650
|
+
if type(SpawnTemplate.units[1].callsign)~="number"then
|
|
19651
|
+
local min=1
|
|
19652
|
+
local max=8
|
|
19653
|
+
local ctable=CALLSIGN.Aircraft
|
|
19654
|
+
if string.find(SpawnTemplate.units[1].type,"A-10",1,true)then
|
|
19655
|
+
max=12
|
|
19656
|
+
end
|
|
19657
|
+
if string.find(SpawnTemplate.units[1].type,"18",1,true)then
|
|
19658
|
+
min=9
|
|
19659
|
+
max=20
|
|
19660
|
+
ctable=CALLSIGN.F18
|
|
19661
|
+
end
|
|
19662
|
+
if string.find(SpawnTemplate.units[1].type,"16",1,true)then
|
|
19663
|
+
min=9
|
|
19664
|
+
max=20
|
|
19665
|
+
ctable=CALLSIGN.F16
|
|
19666
|
+
end
|
|
19667
|
+
if SpawnTemplate.units[1].type=="F-15E"then
|
|
19668
|
+
min=9
|
|
19669
|
+
max=18
|
|
19670
|
+
ctable=CALLSIGN.F15E
|
|
19671
|
+
end
|
|
19672
|
+
local callsignnr=math.random(min,max)
|
|
19673
|
+
local callsignname="Enfield"
|
|
19674
|
+
for name,value in pairs(ctable)do
|
|
19675
|
+
if value==callsignnr then
|
|
19676
|
+
callsignname=name
|
|
19677
|
+
end
|
|
19678
|
+
end
|
|
19679
|
+
for UnitID=1,#SpawnTemplate.units do
|
|
19680
|
+
SpawnTemplate.units[UnitID].callsign[1]=callsignnr
|
|
19681
|
+
SpawnTemplate.units[UnitID].callsign[2]=UnitID
|
|
19682
|
+
SpawnTemplate.units[UnitID].callsign[3]="1"
|
|
19683
|
+
SpawnTemplate.units[UnitID].callsign["name"]=tostring(callsignname)..tostring(UnitID).."1"
|
|
19684
|
+
end
|
|
19685
|
+
else
|
|
19686
|
+
for UnitID=1,#SpawnTemplate.units do
|
|
19687
|
+
SpawnTemplate.units[UnitID].callsign=math.random(1,999)
|
|
19688
|
+
end
|
|
19689
|
+
end
|
|
19690
|
+
end
|
|
19691
|
+
if self.SpawnInitCallSign then
|
|
19692
|
+
for UnitID=1,#SpawnTemplate.units do
|
|
19693
|
+
local Callsign=SpawnTemplate.units[UnitID].callsign
|
|
19694
|
+
if Callsign and type(Callsign)~="number"then
|
|
19695
|
+
SpawnTemplate.units[UnitID].callsign[1]=self.SpawnInitCallSignID
|
|
19696
|
+
SpawnTemplate.units[UnitID].callsign[2]=self.SpawnInitCallSignMinor
|
|
19697
|
+
SpawnTemplate.units[UnitID].callsign[3]=self.SpawnInitCallSignMajor
|
|
19698
|
+
SpawnTemplate.units[UnitID].callsign["name"]=string.format("%s%d%d",self.SpawnInitCallSignName,self.SpawnInitCallSignMinor,self.SpawnInitCallSignMajor)
|
|
19699
|
+
end
|
|
19700
|
+
end
|
|
19701
|
+
end
|
|
18852
19702
|
for UnitID=1,#SpawnTemplate.units do
|
|
18853
19703
|
local Callsign=SpawnTemplate.units[UnitID].callsign
|
|
18854
19704
|
if Callsign then
|
|
18855
|
-
if type(Callsign)~="number"then
|
|
19705
|
+
if type(Callsign)~="number"and not self.SpawnInitCallSign then
|
|
18856
19706
|
Callsign[2]=((SpawnIndex-1)%10)+1
|
|
18857
19707
|
local CallsignName=SpawnTemplate.units[UnitID].callsign["name"]
|
|
18858
19708
|
CallsignName=string.match(CallsignName,"^(%a+)")
|
|
18859
19709
|
local CallsignLen=CallsignName:len()
|
|
19710
|
+
SpawnTemplate.units[UnitID].callsign[2]=UnitID
|
|
18860
19711
|
SpawnTemplate.units[UnitID].callsign["name"]=CallsignName:sub(1,CallsignLen)..SpawnTemplate.units[UnitID].callsign[2]..SpawnTemplate.units[UnitID].callsign[3]
|
|
18861
|
-
|
|
19712
|
+
elseif type(Callsign)=="number"then
|
|
18862
19713
|
SpawnTemplate.units[UnitID].callsign=Callsign+SpawnIndex
|
|
18863
19714
|
end
|
|
18864
19715
|
end
|
|
19716
|
+
local AddProps=SpawnTemplate.units[UnitID].AddPropAircraft
|
|
19717
|
+
if AddProps then
|
|
19718
|
+
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
|
19719
|
+
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16)~=nil then
|
|
19720
|
+
local octal=SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
|
19721
|
+
local decimal=UTILS.OctalToDecimal(octal)+UnitID-1
|
|
19722
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",UTILS.DecimalToOctal(decimal))
|
|
19723
|
+
else
|
|
19724
|
+
local STN=math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
|
|
19725
|
+
STN=STN+UnitID-1
|
|
19726
|
+
local OSTN=UTILS.DecimalToOctal(STN)
|
|
19727
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",OSTN)
|
|
19728
|
+
end
|
|
19729
|
+
end
|
|
19730
|
+
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
|
19731
|
+
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN)~=nil then
|
|
19732
|
+
local octal=SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
|
19733
|
+
local decimal=UTILS.OctalToDecimal(octal)+UnitID-1
|
|
19734
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",UTILS.DecimalToOctal(decimal))
|
|
19735
|
+
else
|
|
19736
|
+
local STN=math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
|
|
19737
|
+
STN=STN+UnitID-1
|
|
19738
|
+
local OSTN=UTILS.DecimalToOctal(STN)
|
|
19739
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",OSTN)
|
|
19740
|
+
end
|
|
19741
|
+
end
|
|
19742
|
+
if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber and type(Callsign)~="number"then
|
|
19743
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber=SpawnTemplate.units[UnitID].callsign[2]..SpawnTemplate.units[UnitID].callsign[3]
|
|
19744
|
+
end
|
|
19745
|
+
if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel and type(Callsign)~="number"then
|
|
19746
|
+
local CallsignName=SpawnTemplate.units[UnitID].callsign["name"]
|
|
19747
|
+
CallsignName=string.match(CallsignName,"^(%a+)")
|
|
19748
|
+
local label="NY"
|
|
19749
|
+
if not string.find(CallsignName," ")then
|
|
19750
|
+
label=string.upper(string.match(CallsignName,"^%a")..string.match(CallsignName,"%a$"))
|
|
19751
|
+
end
|
|
19752
|
+
SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel=label
|
|
19753
|
+
end
|
|
19754
|
+
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.settings then
|
|
19755
|
+
SpawnTemplate.units[UnitID].datalinks.Link16.settings.flightLead=UnitID==1 and true or false
|
|
19756
|
+
end
|
|
19757
|
+
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.SADL and SpawnTemplate.units[UnitID].datalinks.SADL.settings then
|
|
19758
|
+
SpawnTemplate.units[UnitID].datalinks.SADL.settings.flightLead=UnitID==1 and true or false
|
|
19759
|
+
end
|
|
19760
|
+
end
|
|
19761
|
+
end
|
|
19762
|
+
for UnitID=1,#SpawnTemplate.units do
|
|
19763
|
+
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.network then
|
|
19764
|
+
local team={}
|
|
19765
|
+
local isF16=string.find(SpawnTemplate.units[UnitID].type,"F-16",1,true)and true or false
|
|
19766
|
+
for ID=1,#SpawnTemplate.units do
|
|
19767
|
+
local member={}
|
|
19768
|
+
member.missionUnitId=ID
|
|
19769
|
+
if isF16 then
|
|
19770
|
+
member.TDOA=true
|
|
19771
|
+
end
|
|
19772
|
+
table.insert(team,member)
|
|
19773
|
+
end
|
|
19774
|
+
SpawnTemplate.units[UnitID].datalinks.Link16.network.teamMembers=team
|
|
19775
|
+
end
|
|
18865
19776
|
end
|
|
18866
19777
|
self:T3({"Template:",SpawnTemplate})
|
|
18867
19778
|
return SpawnTemplate
|
|
@@ -23057,32 +23968,35 @@ self:SetOption(AI.Option.Air.id.PROHIBIT_AB,Prohibit)
|
|
|
23057
23968
|
end
|
|
23058
23969
|
return self
|
|
23059
23970
|
end
|
|
23060
|
-
function CONTROLLABLE:
|
|
23971
|
+
function CONTROLLABLE:OptionECM(ECMvalue)
|
|
23061
23972
|
self:F2({self.ControllableName})
|
|
23973
|
+
local DCSControllable=self:GetDCSObject()
|
|
23974
|
+
if DCSControllable then
|
|
23975
|
+
local Controller=self:_GetController()
|
|
23062
23976
|
if self:IsAir()then
|
|
23063
|
-
|
|
23977
|
+
Controller:setOption(AI.Option.Air.id.ECM_USING,ECMvalue or 1)
|
|
23978
|
+
end
|
|
23064
23979
|
end
|
|
23065
23980
|
return self
|
|
23066
23981
|
end
|
|
23067
|
-
function CONTROLLABLE:
|
|
23982
|
+
function CONTROLLABLE:OptionECM_Never()
|
|
23068
23983
|
self:F2({self.ControllableName})
|
|
23069
|
-
|
|
23070
|
-
self
|
|
23984
|
+
self:OptionECM(0)
|
|
23985
|
+
return self
|
|
23071
23986
|
end
|
|
23987
|
+
function CONTROLLABLE:OptionECM_OnlyLockByRadar()
|
|
23988
|
+
self:F2({self.ControllableName})
|
|
23989
|
+
self:OptionECM(1)
|
|
23072
23990
|
return self
|
|
23073
23991
|
end
|
|
23074
23992
|
function CONTROLLABLE:OptionECM_DetectedLockByRadar()
|
|
23075
23993
|
self:F2({self.ControllableName})
|
|
23076
|
-
|
|
23077
|
-
self:SetOption(AI.Option.Air.id.ECM_USING,2)
|
|
23078
|
-
end
|
|
23994
|
+
self:OptionECM(2)
|
|
23079
23995
|
return self
|
|
23080
23996
|
end
|
|
23081
23997
|
function CONTROLLABLE:OptionECM_AlwaysOn()
|
|
23082
23998
|
self:F2({self.ControllableName})
|
|
23083
|
-
|
|
23084
|
-
self:SetOption(AI.Option.Air.id.ECM_USING,3)
|
|
23085
|
-
end
|
|
23999
|
+
self:OptionECM(3)
|
|
23086
24000
|
return self
|
|
23087
24001
|
end
|
|
23088
24002
|
function CONTROLLABLE:WayPointInitialize(WayPoints)
|
|
@@ -23166,7 +24080,7 @@ if DCSControllable then
|
|
|
23166
24080
|
local Controller=self:_GetController()
|
|
23167
24081
|
if Controller then
|
|
23168
24082
|
if self:IsAir()then
|
|
23169
|
-
self:SetOption(AI.Option.Air.
|
|
24083
|
+
self:SetOption(AI.Option.Air.id.MISSILE_ATTACK,range)
|
|
23170
24084
|
end
|
|
23171
24085
|
end
|
|
23172
24086
|
return self
|
|
@@ -23191,12 +24105,19 @@ return self
|
|
|
23191
24105
|
end
|
|
23192
24106
|
return nil
|
|
23193
24107
|
end
|
|
23194
|
-
function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation)
|
|
24108
|
+
function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation,onland)
|
|
23195
24109
|
self:F2({self.ControllableName})
|
|
23196
24110
|
local _coord=self:GetCoordinate()
|
|
23197
24111
|
local _radius=radius or 500
|
|
23198
24112
|
local _speed=speed or 20
|
|
23199
24113
|
local _tocoord=_coord:GetRandomCoordinateInRadius(_radius,100)
|
|
24114
|
+
if onland then
|
|
24115
|
+
for i=1,50 do
|
|
24116
|
+
local island=_tocoord:GetSurfaceType()==land.SurfaceType.LAND and true or false
|
|
24117
|
+
if island then break end
|
|
24118
|
+
_tocoord=_coord:GetRandomCoordinateInRadius(_radius,100)
|
|
24119
|
+
end
|
|
24120
|
+
end
|
|
23200
24121
|
local _onroad=onroad or true
|
|
23201
24122
|
local _grptsk={}
|
|
23202
24123
|
local _candoroad=false
|
|
@@ -24100,7 +25021,7 @@ local Task={
|
|
|
24100
25021
|
table.insert(TaskAerobatics.params["maneuversSequency"],Task)
|
|
24101
25022
|
return TaskAerobatics
|
|
24102
25023
|
end
|
|
24103
|
-
function CONTROLLABLE:PatrolRaceTrack(Point1,Point2,Altitude,Speed,Formation,Delay)
|
|
25024
|
+
function CONTROLLABLE:PatrolRaceTrack(Point1,Point2,Altitude,Speed,Formation,AGL,Delay)
|
|
24104
25025
|
local PatrolGroup=self
|
|
24105
25026
|
if not self:IsInstanceOf("GROUP")then
|
|
24106
25027
|
PatrolGroup=self:GetGroup()
|
|
@@ -24114,8 +25035,10 @@ end
|
|
|
24114
25035
|
local FromCoord=PatrolGroup:GetCoordinate()
|
|
24115
25036
|
local ToCoord=Point1:GetCoordinate()
|
|
24116
25037
|
if Altitude then
|
|
24117
|
-
|
|
24118
|
-
|
|
25038
|
+
local asl=true
|
|
25039
|
+
if AGL then asl=false end
|
|
25040
|
+
FromCoord:SetAltitude(Altitude,asl)
|
|
25041
|
+
ToCoord:SetAltitude(Altitude,asl)
|
|
24119
25042
|
end
|
|
24120
25043
|
local Route={}
|
|
24121
25044
|
Route[#Route+1]=FromCoord:WaypointAir(AltType,COORDINATE.WaypointType.TurningPoint,COORDINATE.WaypointAction.TurningPoint,Speed,true,nil,DCSTasks,description,timeReFuAr)
|
|
@@ -24688,6 +25611,7 @@ if vec3 then
|
|
|
24688
25611
|
local coord=COORDINATE:NewFromVec3(vec3)
|
|
24689
25612
|
local Heading=self:GetHeading()
|
|
24690
25613
|
coord.Heading=Heading
|
|
25614
|
+
return coord
|
|
24691
25615
|
else
|
|
24692
25616
|
BASE:E({"Cannot GetAverageCoordinate",Group=self,Alive=self:IsAlive()})
|
|
24693
25617
|
return nil
|
|
@@ -25664,6 +26588,60 @@ local tankertask=self:EnRouteTaskTanker()
|
|
|
25664
26588
|
self:PushTask(tankertask,delay+2)
|
|
25665
26589
|
return self
|
|
25666
26590
|
end
|
|
26591
|
+
function GROUP:GetGroupSTN()
|
|
26592
|
+
local tSTN={}
|
|
26593
|
+
local units=self:GetUnits()
|
|
26594
|
+
local gname=self:GetName()
|
|
26595
|
+
gname=string.gsub(gname,"(#%d+)$","")
|
|
26596
|
+
local report=REPORT:New()
|
|
26597
|
+
report:Add("Link16 S/TN Report")
|
|
26598
|
+
report:Add("Group: "..gname)
|
|
26599
|
+
report:Add("==================")
|
|
26600
|
+
for _,_unit in pairs(units)do
|
|
26601
|
+
local unit=_unit
|
|
26602
|
+
if unit and unit:IsAlive()then
|
|
26603
|
+
local STN,VCL,VCN,Lead=unit:GetSTN()
|
|
26604
|
+
local name=unit:GetName()
|
|
26605
|
+
tSTN[name]={
|
|
26606
|
+
STN=STN,
|
|
26607
|
+
VCL=VCL,
|
|
26608
|
+
VCN=VCN,
|
|
26609
|
+
Lead=Lead,
|
|
26610
|
+
}
|
|
26611
|
+
local lead=Lead==true and"(*)"or""
|
|
26612
|
+
report:Add(string.format("| %s%s %s %s",tostring(VCL),tostring(VCN),tostring(STN),lead))
|
|
26613
|
+
end
|
|
26614
|
+
end
|
|
26615
|
+
report:Add("==================")
|
|
26616
|
+
local text=report:Text()
|
|
26617
|
+
return tSTN,text
|
|
26618
|
+
end
|
|
26619
|
+
function GROUP:IsSAM()
|
|
26620
|
+
local issam=false
|
|
26621
|
+
local units=self:GetUnits()
|
|
26622
|
+
for _,_unit in pairs(units or{})do
|
|
26623
|
+
local unit=_unit
|
|
26624
|
+
if unit:HasSEAD()and unit:IsGround()and(not unit:HasAttribute("Mobile AAA"))then
|
|
26625
|
+
issam=true
|
|
26626
|
+
break
|
|
26627
|
+
end
|
|
26628
|
+
end
|
|
26629
|
+
return issam
|
|
26630
|
+
end
|
|
26631
|
+
function GROUP:IsAAA()
|
|
26632
|
+
local issam=false
|
|
26633
|
+
local units=self:GetUnits()
|
|
26634
|
+
for _,_unit in pairs(units or{})do
|
|
26635
|
+
local unit=_unit
|
|
26636
|
+
local desc=unit:GetDesc()or{}
|
|
26637
|
+
local attr=desc.attributes or{}
|
|
26638
|
+
if unit:HasSEAD()then return false end
|
|
26639
|
+
if attr["AAA"]or attr["SAM related"]then
|
|
26640
|
+
issam=true
|
|
26641
|
+
end
|
|
26642
|
+
end
|
|
26643
|
+
return issam
|
|
26644
|
+
end
|
|
25667
26645
|
UNIT={
|
|
25668
26646
|
ClassName="UNIT",
|
|
25669
26647
|
UnitName=nil,
|
|
@@ -26458,6 +27436,30 @@ local name=self.UnitName
|
|
|
26458
27436
|
local skill=_DATABASE.Templates.Units[name].Template.skill or"Random"
|
|
26459
27437
|
return skill
|
|
26460
27438
|
end
|
|
27439
|
+
function UNIT:GetSTN()
|
|
27440
|
+
self:F2(self.UnitName)
|
|
27441
|
+
local STN=nil
|
|
27442
|
+
local VCL=nil
|
|
27443
|
+
local VCN=nil
|
|
27444
|
+
local FGL=false
|
|
27445
|
+
local template=self:GetTemplate()
|
|
27446
|
+
if template.AddPropAircraft then
|
|
27447
|
+
if template.AddPropAircraft.STN_L16 then
|
|
27448
|
+
STN=template.AddPropAircraft.STN_L16
|
|
27449
|
+
elseif template.AddPropAircraft.SADL_TN then
|
|
27450
|
+
STN=template.AddPropAircraft.SADL_TN
|
|
27451
|
+
end
|
|
27452
|
+
VCN=template.AddPropAircraft.VoiceCallsignNumber
|
|
27453
|
+
VCL=template.AddPropAircraft.VoiceCallsignLabel
|
|
27454
|
+
end
|
|
27455
|
+
if template.datalinks and template.datalinks.Link16 and template.datalinks.Link16.settings then
|
|
27456
|
+
FGL=template.datalinks.Link16.settings.flightLead
|
|
27457
|
+
end
|
|
27458
|
+
if template.datalinks and template.datalinks.SADL and template.datalinks.SADL.settings then
|
|
27459
|
+
FGL=template.datalinks.SADL.settings.flightLead
|
|
27460
|
+
end
|
|
27461
|
+
return STN,VCL,VCN,FGL
|
|
27462
|
+
end
|
|
26461
27463
|
CLIENT={
|
|
26462
27464
|
ClassName="CLIENT",
|
|
26463
27465
|
ClientName=nil,
|
|
@@ -26981,6 +27983,13 @@ AIRBASE.Normandy={
|
|
|
26981
27983
|
["Broglie"]="Broglie",
|
|
26982
27984
|
["Bernay_Saint_Martin"]="Bernay Saint Martin",
|
|
26983
27985
|
["Saint_Andre_de_lEure"]="Saint-Andre-de-lEure",
|
|
27986
|
+
["Biggin_Hill"]="Biggin Hill",
|
|
27987
|
+
["Manston"]="Manston",
|
|
27988
|
+
["Detling"]="Detling",
|
|
27989
|
+
["Lympne"]="Lympne",
|
|
27990
|
+
["Abbeville_Drucat"]="Abbeville Drucat",
|
|
27991
|
+
["Merville_Calonne"]="Merville Calonne",
|
|
27992
|
+
["Saint_Omer_Wizernes"]="Saint-Omer Wizernes",
|
|
26984
27993
|
}
|
|
26985
27994
|
AIRBASE.PersianGulf={
|
|
26986
27995
|
["Abu_Dhabi_International_Airport"]="Abu Dhabi Intl",
|
|
@@ -28501,6 +29510,13 @@ self.launcherUnit=UNIT:Find(self.launcher)
|
|
|
28501
29510
|
end
|
|
28502
29511
|
self.coordinate=COORDINATE:NewFromVec3(self.launcher:getPoint())
|
|
28503
29512
|
self.lid=string.format("[%s] %s | ",self.typeName,self.name)
|
|
29513
|
+
if self.launcherUnit then
|
|
29514
|
+
self.releaseHeading=self.launcherUnit:GetHeading()
|
|
29515
|
+
self.releaseAltitudeASL=self.launcherUnit:GetAltitude()
|
|
29516
|
+
self.releaseAltitudeAGL=self.launcherUnit:GetAltitude(true)
|
|
29517
|
+
self.releaseCoordinate=self.launcherUnit:GetCoordinate()
|
|
29518
|
+
self.releasePitch=self.launcherUnit:GetPitch()
|
|
29519
|
+
end
|
|
28504
29520
|
self:SetTimeStepTrack()
|
|
28505
29521
|
self:SetDistanceInterceptPoint()
|
|
28506
29522
|
local text=string.format("Weapon v%s\nName=%s, TypeName=%s, Category=%s, Coalition=%d, Country=%d, Launcher=%s",
|
|
@@ -28646,6 +29662,26 @@ end
|
|
|
28646
29662
|
function WEAPON:GetImpactCoordinate()
|
|
28647
29663
|
return self.impactCoord
|
|
28648
29664
|
end
|
|
29665
|
+
function WEAPON:GetReleaseHeading(AccountForMagneticInclination)
|
|
29666
|
+
AccountForMagneticInclination=AccountForMagneticInclination or true
|
|
29667
|
+
if AccountForMagneticInclination then return UTILS.ClampAngle(self.releaseHeading-UTILS.GetMagneticDeclination())else return UTILS.ClampAngle(self.releaseHeading)end
|
|
29668
|
+
end
|
|
29669
|
+
function WEAPON:GetReleaseAltitudeASL()
|
|
29670
|
+
return self.releaseAltitudeASL
|
|
29671
|
+
end
|
|
29672
|
+
function WEAPON:GetReleaseAltitudeAGL()
|
|
29673
|
+
return self.releaseAltitudeAGL
|
|
29674
|
+
end
|
|
29675
|
+
function WEAPON:GetReleaseCoordinate()
|
|
29676
|
+
return self.releaseCoordinate
|
|
29677
|
+
end
|
|
29678
|
+
function WEAPON:GetReleasePitch()
|
|
29679
|
+
return self.releasePitch
|
|
29680
|
+
end
|
|
29681
|
+
function WEAPON:GetImpactHeading(AccountForMagneticInclination)
|
|
29682
|
+
AccountForMagneticInclination=AccountForMagneticInclination or true
|
|
29683
|
+
if AccountForMagneticInclination then return UTILS.ClampAngle(self.impactHeading-UTILS.GetMagneticDeclination())else return self.impactHeading end
|
|
29684
|
+
end
|
|
28649
29685
|
function WEAPON:InAir()
|
|
28650
29686
|
local inAir=nil
|
|
28651
29687
|
if self.weapon then
|
|
@@ -28717,6 +29753,7 @@ if status then
|
|
|
28717
29753
|
self.pos3=pos3
|
|
28718
29754
|
self.vec3=UTILS.DeepCopy(self.pos3.p)
|
|
28719
29755
|
self.coordinate:UpdateFromVec3(self.vec3)
|
|
29756
|
+
self.last_velocity=self.weapon:getVelocity()
|
|
28720
29757
|
self.tracking=true
|
|
28721
29758
|
if self.trackFunc then
|
|
28722
29759
|
self.trackFunc(self,unpack(self.trackArg))
|
|
@@ -28744,6 +29781,7 @@ self:I(self.lid..string.format("FF d(ip, vec3)=%.3f meters",d))
|
|
|
28744
29781
|
end
|
|
28745
29782
|
self.impactVec3=ip or self.vec3
|
|
28746
29783
|
self.impactCoord=COORDINATE:NewFromVec3(self.vec3)
|
|
29784
|
+
self.impactHeading=UTILS.VecHdg(self.last_velocity)
|
|
28747
29785
|
if self.impactMark then
|
|
28748
29786
|
self.impactCoord:MarkToAll(string.format("Impact point of weapon %s\ntype=%s\nlauncher=%s",self.name,self.typeName,self.launcherName))
|
|
28749
29787
|
end
|
|
@@ -29376,7 +30414,7 @@ Reported={},
|
|
|
29376
30414
|
}
|
|
29377
30415
|
function CARGO:New(Type,Name,Weight,LoadRadius,NearRadius)
|
|
29378
30416
|
local self=BASE:Inherit(self,FSM:New())
|
|
29379
|
-
self:
|
|
30417
|
+
self:T({Type,Name,Weight,LoadRadius,NearRadius})
|
|
29380
30418
|
self:SetStartState("UnLoaded")
|
|
29381
30419
|
self:AddTransition({"UnLoaded","Boarding"},"Board","Boarding")
|
|
29382
30420
|
self:AddTransition("Boarding","Boarding","Boarding")
|
|
@@ -29521,7 +30559,7 @@ function CARGO:IsDeployed()
|
|
|
29521
30559
|
return self.Deployed
|
|
29522
30560
|
end
|
|
29523
30561
|
function CARGO:Spawn(PointVec2)
|
|
29524
|
-
self:
|
|
30562
|
+
self:T()
|
|
29525
30563
|
end
|
|
29526
30564
|
function CARGO:Flare(FlareColor)
|
|
29527
30565
|
if self:IsUnLoaded()then
|
|
@@ -29571,7 +30609,7 @@ function CARGO:GetLoadRadius()
|
|
|
29571
30609
|
return self.LoadRadius
|
|
29572
30610
|
end
|
|
29573
30611
|
function CARGO:IsInLoadRadius(Coordinate)
|
|
29574
|
-
self:
|
|
30612
|
+
self:T({Coordinate,LoadRadius=self.LoadRadius})
|
|
29575
30613
|
local Distance=0
|
|
29576
30614
|
if self:IsUnLoaded()then
|
|
29577
30615
|
local CargoCoordinate=self.CargoObject:GetCoordinate()
|
|
@@ -29584,7 +30622,7 @@ end
|
|
|
29584
30622
|
return false
|
|
29585
30623
|
end
|
|
29586
30624
|
function CARGO:IsInReportRadius(Coordinate)
|
|
29587
|
-
self:
|
|
30625
|
+
self:T({Coordinate})
|
|
29588
30626
|
local Distance=0
|
|
29589
30627
|
if self:IsUnLoaded()then
|
|
29590
30628
|
Distance=Coordinate:Get2DDistance(self.CargoObject:GetCoordinate())
|
|
@@ -29686,7 +30724,7 @@ ClassName="CARGO_REPRESENTABLE"
|
|
|
29686
30724
|
}
|
|
29687
30725
|
function CARGO_REPRESENTABLE:New(CargoObject,Type,Name,LoadRadius,NearRadius)
|
|
29688
30726
|
local self=BASE:Inherit(self,CARGO:New(Type,Name,0,LoadRadius,NearRadius))
|
|
29689
|
-
self:
|
|
30727
|
+
self:T({Type,Name,LoadRadius,NearRadius})
|
|
29690
30728
|
local Desc=CargoObject:GetDesc()
|
|
29691
30729
|
self:T({Desc=Desc})
|
|
29692
30730
|
local Weight=math.random(80,120)
|
|
@@ -29701,7 +30739,7 @@ self:SetWeight(Weight)
|
|
|
29701
30739
|
return self
|
|
29702
30740
|
end
|
|
29703
30741
|
function CARGO_REPRESENTABLE:Destroy()
|
|
29704
|
-
self:
|
|
30742
|
+
self:T({CargoName=self:GetName()})
|
|
29705
30743
|
return self
|
|
29706
30744
|
end
|
|
29707
30745
|
function CARGO_REPRESENTABLE:RouteTo(ToPointVec2,Speed)
|
|
@@ -29719,12 +30757,12 @@ local CoordinateZone=ZONE_RADIUS:New("Zone",self:GetCoordinate():GetVec2(),500)
|
|
|
29719
30757
|
CoordinateZone:Scan({Object.Category.UNIT})
|
|
29720
30758
|
for _,DCSUnit in pairs(CoordinateZone:GetScannedUnits())do
|
|
29721
30759
|
local NearUnit=UNIT:Find(DCSUnit)
|
|
29722
|
-
self:
|
|
30760
|
+
self:T({NearUnit=NearUnit})
|
|
29723
30761
|
local NearUnitCoalition=NearUnit:GetCoalition()
|
|
29724
30762
|
local CargoCoalition=self:GetCoalition()
|
|
29725
30763
|
if NearUnitCoalition==CargoCoalition then
|
|
29726
30764
|
local Attributes=NearUnit:GetDesc()
|
|
29727
|
-
self:
|
|
30765
|
+
self:T({Desc=Attributes})
|
|
29728
30766
|
if NearUnit:HasAttribute("Trucks")then
|
|
29729
30767
|
MESSAGE:New(Message,20,NearUnit:GetCallsign().." reporting - Cargo "..self:GetName()):ToGroup(TaskGroup)
|
|
29730
30768
|
break
|
|
@@ -29739,7 +30777,7 @@ ClassName="CARGO_REPORTABLE"
|
|
|
29739
30777
|
}
|
|
29740
30778
|
function CARGO_REPORTABLE:New(Type,Name,Weight,LoadRadius,NearRadius)
|
|
29741
30779
|
local self=BASE:Inherit(self,CARGO:New(Type,Name,Weight,LoadRadius,NearRadius))
|
|
29742
|
-
self:
|
|
30780
|
+
self:T({Type,Name,Weight,LoadRadius,NearRadius})
|
|
29743
30781
|
return self
|
|
29744
30782
|
end
|
|
29745
30783
|
function CARGO_REPORTABLE:MessageToGroup(Message,TaskGroup,Name)
|
|
@@ -29752,13 +30790,13 @@ ClassName="CARGO_PACKAGE"
|
|
|
29752
30790
|
}
|
|
29753
30791
|
function CARGO_PACKAGE:New(CargoCarrier,Type,Name,Weight,LoadRadius,NearRadius)
|
|
29754
30792
|
local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoCarrier,Type,Name,Weight,LoadRadius,NearRadius))
|
|
29755
|
-
self:
|
|
30793
|
+
self:T({Type,Name,Weight,LoadRadius,NearRadius})
|
|
29756
30794
|
self:T(CargoCarrier)
|
|
29757
30795
|
self.CargoCarrier=CargoCarrier
|
|
29758
30796
|
return self
|
|
29759
30797
|
end
|
|
29760
30798
|
function CARGO_PACKAGE:onafterOnBoard(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
|
|
29761
|
-
self:
|
|
30799
|
+
self:T()
|
|
29762
30800
|
self.CargoInAir=self.CargoCarrier:InAir()
|
|
29763
30801
|
self:T(self.CargoInAir)
|
|
29764
30802
|
if not self.CargoInAir then
|
|
@@ -29776,7 +30814,7 @@ end
|
|
|
29776
30814
|
self:Boarded(CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
|
|
29777
30815
|
end
|
|
29778
30816
|
function CARGO_PACKAGE:IsNear(CargoCarrier)
|
|
29779
|
-
self:
|
|
30817
|
+
self:T()
|
|
29780
30818
|
local CargoCarrierPoint=CargoCarrier:GetCoordinate()
|
|
29781
30819
|
local Distance=CargoCarrierPoint:Get2DDistance(self.CargoCarrier:GetCoordinate())
|
|
29782
30820
|
self:T(Distance)
|
|
@@ -29787,7 +30825,7 @@ return false
|
|
|
29787
30825
|
end
|
|
29788
30826
|
end
|
|
29789
30827
|
function CARGO_PACKAGE:onafterOnBoarded(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
|
|
29790
|
-
self:
|
|
30828
|
+
self:T()
|
|
29791
30829
|
if self:IsNear(CargoCarrier)then
|
|
29792
30830
|
self:__Load(1,CargoCarrier,Speed,LoadDistance,Angle)
|
|
29793
30831
|
else
|
|
@@ -29795,7 +30833,7 @@ self:__Boarded(1,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
|
|
|
29795
30833
|
end
|
|
29796
30834
|
end
|
|
29797
30835
|
function CARGO_PACKAGE:onafterUnBoard(From,Event,To,CargoCarrier,Speed,UnLoadDistance,UnBoardDistance,Radius,Angle)
|
|
29798
|
-
self:
|
|
30836
|
+
self:T()
|
|
29799
30837
|
self.CargoInAir=self.CargoCarrier:InAir()
|
|
29800
30838
|
self:T(self.CargoInAir)
|
|
29801
30839
|
if not self.CargoInAir then
|
|
@@ -29814,7 +30852,7 @@ end
|
|
|
29814
30852
|
self:__UnBoarded(1,CargoCarrier,Speed)
|
|
29815
30853
|
end
|
|
29816
30854
|
function CARGO_PACKAGE:onafterUnBoarded(From,Event,To,CargoCarrier,Speed)
|
|
29817
|
-
self:
|
|
30855
|
+
self:T()
|
|
29818
30856
|
if self:IsNear(CargoCarrier)then
|
|
29819
30857
|
self:__UnLoad(1,CargoCarrier,Speed)
|
|
29820
30858
|
else
|
|
@@ -29822,7 +30860,7 @@ self:__UnBoarded(1,CargoCarrier,Speed)
|
|
|
29822
30860
|
end
|
|
29823
30861
|
end
|
|
29824
30862
|
function CARGO_PACKAGE:onafterLoad(From,Event,To,CargoCarrier,Speed,LoadDistance,Angle)
|
|
29825
|
-
self:
|
|
30863
|
+
self:T()
|
|
29826
30864
|
self.CargoCarrier=CargoCarrier
|
|
29827
30865
|
local StartPointVec2=self.CargoCarrier:GetPointVec2()
|
|
29828
30866
|
local CargoCarrierHeading=self.CargoCarrier:GetHeading()
|
|
@@ -29835,7 +30873,7 @@ local TaskRoute=self.CargoCarrier:TaskRoute(Points)
|
|
|
29835
30873
|
self.CargoCarrier:SetTask(TaskRoute,1)
|
|
29836
30874
|
end
|
|
29837
30875
|
function CARGO_PACKAGE:onafterUnLoad(From,Event,To,CargoCarrier,Speed,Distance,Angle)
|
|
29838
|
-
self:
|
|
30876
|
+
self:T()
|
|
29839
30877
|
local StartPointVec2=self.CargoCarrier:GetPointVec2()
|
|
29840
30878
|
local CargoCarrierHeading=self.CargoCarrier:GetHeading()
|
|
29841
30879
|
local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle)
|
|
@@ -29860,7 +30898,7 @@ self:SetEventPriority(5)
|
|
|
29860
30898
|
return self
|
|
29861
30899
|
end
|
|
29862
30900
|
function CARGO_UNIT:onenterUnBoarding(From,Event,To,ToPointVec2,NearRadius)
|
|
29863
|
-
self:
|
|
30901
|
+
self:T({From,Event,To,ToPointVec2,NearRadius})
|
|
29864
30902
|
local Angle=180
|
|
29865
30903
|
local Speed=60
|
|
29866
30904
|
local DeployDistance=9
|
|
@@ -29883,7 +30921,7 @@ self.CargoObject:ReSpawnAt(ToPointVec2,CargoDeployHeading)
|
|
|
29883
30921
|
else
|
|
29884
30922
|
self.CargoObject:ReSpawnAt(FromPointVec2,CargoDeployHeading)
|
|
29885
30923
|
end
|
|
29886
|
-
self:
|
|
30924
|
+
self:T({"CargoUnits:",self.CargoObject:GetGroup():GetName()})
|
|
29887
30925
|
self.CargoCarrier=nil
|
|
29888
30926
|
local Points={}
|
|
29889
30927
|
Points[#Points+1]=FromPointVec2:WaypointGround(Speed,"Vee")
|
|
@@ -29899,7 +30937,7 @@ end
|
|
|
29899
30937
|
end
|
|
29900
30938
|
end
|
|
29901
30939
|
function CARGO_UNIT:onleaveUnBoarding(From,Event,To,ToPointVec2,NearRadius)
|
|
29902
|
-
self:
|
|
30940
|
+
self:T({From,Event,To,ToPointVec2,NearRadius})
|
|
29903
30941
|
local Angle=180
|
|
29904
30942
|
local Speed=10
|
|
29905
30943
|
local Distance=5
|
|
@@ -29908,7 +30946,7 @@ return true
|
|
|
29908
30946
|
end
|
|
29909
30947
|
end
|
|
29910
30948
|
function CARGO_UNIT:onafterUnBoarding(From,Event,To,ToPointVec2,NearRadius)
|
|
29911
|
-
self:
|
|
30949
|
+
self:T({From,Event,To,ToPointVec2,NearRadius})
|
|
29912
30950
|
self.CargoInAir=self.CargoObject:InAir()
|
|
29913
30951
|
self:T(self.CargoInAir)
|
|
29914
30952
|
if not self.CargoInAir then
|
|
@@ -29916,7 +30954,7 @@ end
|
|
|
29916
30954
|
self:__UnLoad(1,ToPointVec2,NearRadius)
|
|
29917
30955
|
end
|
|
29918
30956
|
function CARGO_UNIT:onenterUnLoaded(From,Event,To,ToPointVec2)
|
|
29919
|
-
self:
|
|
30957
|
+
self:T({ToPointVec2,From,Event,To})
|
|
29920
30958
|
local Angle=180
|
|
29921
30959
|
local Speed=10
|
|
29922
30960
|
local Distance=5
|
|
@@ -29937,7 +30975,7 @@ self.OnUnLoadedCallBack=nil
|
|
|
29937
30975
|
end
|
|
29938
30976
|
end
|
|
29939
30977
|
function CARGO_UNIT:onafterBoard(From,Event,To,CargoCarrier,NearRadius,...)
|
|
29940
|
-
self:
|
|
30978
|
+
self:T({From,Event,To,CargoCarrier,NearRadius=NearRadius})
|
|
29941
30979
|
self.CargoInAir=self.CargoObject:InAir()
|
|
29942
30980
|
local Desc=self.CargoObject:GetDesc()
|
|
29943
30981
|
local MaxSpeed=Desc.speedMaxOffRoad
|
|
@@ -29971,8 +31009,8 @@ end
|
|
|
29971
31009
|
end
|
|
29972
31010
|
end
|
|
29973
31011
|
function CARGO_UNIT:onafterBoarding(From,Event,To,CargoCarrier,NearRadius,...)
|
|
29974
|
-
self:
|
|
29975
|
-
self:
|
|
31012
|
+
self:T({From,Event,To,CargoCarrier:GetName(),NearRadius=NearRadius})
|
|
31013
|
+
self:T({IsAlive=self.CargoObject:IsAlive()})
|
|
29976
31014
|
if CargoCarrier and CargoCarrier:IsAlive()then
|
|
29977
31015
|
if(CargoCarrier:IsAir()and not CargoCarrier:InAir())or true then
|
|
29978
31016
|
local NearRadius=NearRadius or CargoCarrier:GetBoundingRadius(NearRadius)+5
|
|
@@ -30010,11 +31048,11 @@ self:CancelBoarding(CargoCarrier,NearRadius,...)
|
|
|
30010
31048
|
self.CargoObject:SetCommand(self.CargoObject:CommandStopRoute(true))
|
|
30011
31049
|
end
|
|
30012
31050
|
else
|
|
30013
|
-
self:
|
|
31051
|
+
self:T("Something is wrong")
|
|
30014
31052
|
end
|
|
30015
31053
|
end
|
|
30016
31054
|
function CARGO_UNIT:onenterLoaded(From,Event,To,CargoCarrier)
|
|
30017
|
-
self:
|
|
31055
|
+
self:T({From,Event,To,CargoCarrier})
|
|
30018
31056
|
self.CargoCarrier=CargoCarrier
|
|
30019
31057
|
if self.CargoObject then
|
|
30020
31058
|
self.CargoObject:Destroy(false)
|
|
@@ -30041,7 +31079,7 @@ ClassName="CARGO_SLINGLOAD"
|
|
|
30041
31079
|
}
|
|
30042
31080
|
function CARGO_SLINGLOAD:New(CargoStatic,Type,Name,LoadRadius,NearRadius)
|
|
30043
31081
|
local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoStatic,Type,Name,nil,LoadRadius,NearRadius))
|
|
30044
|
-
self:
|
|
31082
|
+
self:T({Type,Name,NearRadius})
|
|
30045
31083
|
self.CargoObject=CargoStatic
|
|
30046
31084
|
_EVENTDISPATCHER:CreateEventNewCargo(self)
|
|
30047
31085
|
self:HandleEvent(EVENTS.Dead,self.OnEventCargoDead)
|
|
@@ -30152,7 +31190,7 @@ ClassName="CARGO_CRATE"
|
|
|
30152
31190
|
}
|
|
30153
31191
|
function CARGO_CRATE:New(CargoStatic,Type,Name,LoadRadius,NearRadius)
|
|
30154
31192
|
local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoStatic,Type,Name,nil,LoadRadius,NearRadius))
|
|
30155
|
-
self:
|
|
31193
|
+
self:T({Type,Name,NearRadius})
|
|
30156
31194
|
self.CargoObject=CargoStatic
|
|
30157
31195
|
_EVENTDISPATCHER:CreateEventNewCargo(self)
|
|
30158
31196
|
self:HandleEvent(EVENTS.Dead,self.OnEventCargoDead)
|
|
@@ -30255,21 +31293,21 @@ end
|
|
|
30255
31293
|
return Alive
|
|
30256
31294
|
end
|
|
30257
31295
|
function CARGO_CRATE:RouteTo(Coordinate)
|
|
30258
|
-
self:
|
|
31296
|
+
self:T({Coordinate=Coordinate})
|
|
30259
31297
|
end
|
|
30260
31298
|
function CARGO_CRATE:IsNear(CargoCarrier,NearRadius)
|
|
30261
|
-
self:
|
|
31299
|
+
self:T({NearRadius=NearRadius})
|
|
30262
31300
|
return self:IsNear(CargoCarrier:GetCoordinate(),NearRadius)
|
|
30263
31301
|
end
|
|
30264
31302
|
function CARGO_CRATE:Respawn()
|
|
30265
|
-
self:
|
|
31303
|
+
self:T({"Respawning crate "..self:GetName()})
|
|
30266
31304
|
if self.CargoObject then
|
|
30267
31305
|
self.CargoObject:ReSpawn()
|
|
30268
31306
|
self:__Reset(-0.1)
|
|
30269
31307
|
end
|
|
30270
31308
|
end
|
|
30271
31309
|
function CARGO_CRATE:onafterReset()
|
|
30272
|
-
self:
|
|
31310
|
+
self:T({"Reset crate "..self:GetName()})
|
|
30273
31311
|
if self.CargoObject then
|
|
30274
31312
|
self:SetDeployed(false)
|
|
30275
31313
|
self:SetStartState("UnLoaded")
|
|
@@ -30298,7 +31336,7 @@ ClassName="CARGO_GROUP",
|
|
|
30298
31336
|
}
|
|
30299
31337
|
function CARGO_GROUP:New(CargoGroup,Type,Name,LoadRadius,NearRadius)
|
|
30300
31338
|
local self=BASE:Inherit(self,CARGO_REPORTABLE:New(Type,Name,0,LoadRadius,NearRadius))
|
|
30301
|
-
self:
|
|
31339
|
+
self:T({Type,Name,LoadRadius})
|
|
30302
31340
|
self.CargoSet=SET_CARGO:New()
|
|
30303
31341
|
self.CargoGroup=CargoGroup
|
|
30304
31342
|
self.Grouped=true
|
|
@@ -30342,7 +31380,7 @@ self:SetEventPriority(4)
|
|
|
30342
31380
|
return self
|
|
30343
31381
|
end
|
|
30344
31382
|
function CARGO_GROUP:Respawn()
|
|
30345
|
-
self:
|
|
31383
|
+
self:T({"Respawning"})
|
|
30346
31384
|
for CargoID,CargoData in pairs(self.CargoSet:GetSet())do
|
|
30347
31385
|
local Cargo=CargoData
|
|
30348
31386
|
Cargo:Destroy()
|
|
@@ -30383,7 +31421,7 @@ self.CargoObject=nil
|
|
|
30383
31421
|
end
|
|
30384
31422
|
end
|
|
30385
31423
|
function CARGO_GROUP:Regroup()
|
|
30386
|
-
self:
|
|
31424
|
+
self:T("Regroup")
|
|
30387
31425
|
if self.Grouped==false then
|
|
30388
31426
|
self.Grouped=true
|
|
30389
31427
|
local GroupTemplate=UTILS.DeepCopy(self.CargoTemplate)
|
|
@@ -30392,7 +31430,7 @@ GroupTemplate.groupId=nil
|
|
|
30392
31430
|
GroupTemplate.units={}
|
|
30393
31431
|
for CargoUnitName,CargoUnit in pairs(self.CargoSet:GetSet())do
|
|
30394
31432
|
local CargoUnit=CargoUnit
|
|
30395
|
-
self:
|
|
31433
|
+
self:T({CargoUnit:GetName(),UnLoaded=CargoUnit:IsUnLoaded()})
|
|
30396
31434
|
if CargoUnit:IsUnLoaded()then
|
|
30397
31435
|
CargoUnit.CargoObject:Destroy()
|
|
30398
31436
|
GroupTemplate.units[#GroupTemplate.units+1]=self.CargoUnitTemplate[CargoUnitName]
|
|
@@ -30403,12 +31441,12 @@ GroupTemplate.units[#GroupTemplate.units].heading=CargoUnit:GetHeading()
|
|
|
30403
31441
|
end
|
|
30404
31442
|
end
|
|
30405
31443
|
self.CargoGroup=GROUP:NewTemplate(GroupTemplate,GroupTemplate.CoalitionID,GroupTemplate.CategoryID,GroupTemplate.CountryID)
|
|
30406
|
-
self:
|
|
31444
|
+
self:T({"Regroup",GroupTemplate})
|
|
30407
31445
|
self.CargoObject=_DATABASE:Spawn(GroupTemplate)
|
|
30408
31446
|
end
|
|
30409
31447
|
end
|
|
30410
31448
|
function CARGO_GROUP:OnEventCargoDead(EventData)
|
|
30411
|
-
self:
|
|
31449
|
+
self:T(EventData)
|
|
30412
31450
|
local Destroyed=false
|
|
30413
31451
|
if self:IsDestroyed()or self:IsUnLoaded()or self:IsBoarding()or self:IsUnboarding()then
|
|
30414
31452
|
Destroyed=true
|
|
@@ -30430,15 +31468,15 @@ end
|
|
|
30430
31468
|
end
|
|
30431
31469
|
if Destroyed then
|
|
30432
31470
|
self:Destroyed()
|
|
30433
|
-
self:
|
|
31471
|
+
self:T({"Cargo group destroyed"})
|
|
30434
31472
|
end
|
|
30435
31473
|
end
|
|
30436
31474
|
function CARGO_GROUP:onafterBoard(From,Event,To,CargoCarrier,NearRadius,...)
|
|
30437
|
-
self:
|
|
31475
|
+
self:T({CargoCarrier.UnitName,From,Event,To,NearRadius=NearRadius})
|
|
30438
31476
|
NearRadius=NearRadius or self.NearRadius
|
|
30439
31477
|
self.CargoSet:ForEach(
|
|
30440
31478
|
function(Cargo,...)
|
|
30441
|
-
self:
|
|
31479
|
+
self:T({"Board Unit",Cargo:GetName(),Cargo:IsDestroyed(),Cargo.CargoObject:IsAlive()})
|
|
30442
31480
|
local CargoGroup=Cargo.CargoObject
|
|
30443
31481
|
CargoGroup:OptionAlarmStateGreen()
|
|
30444
31482
|
Cargo:__Board(1,CargoCarrier,NearRadius,...)
|
|
@@ -30479,7 +31517,7 @@ if not Cancelled then
|
|
|
30479
31517
|
if not Boarded then
|
|
30480
31518
|
self:__Boarding(-5,CargoCarrier,NearRadius,...)
|
|
30481
31519
|
else
|
|
30482
|
-
self:
|
|
31520
|
+
self:T("Group Cargo is loaded")
|
|
30483
31521
|
self:__Load(1,CargoCarrier,...)
|
|
30484
31522
|
end
|
|
30485
31523
|
else
|
|
@@ -30490,7 +31528,7 @@ self:__Destroyed(1,CargoCarrier,NearRadius,...)
|
|
|
30490
31528
|
end
|
|
30491
31529
|
end
|
|
30492
31530
|
function CARGO_GROUP:onafterUnBoard(From,Event,To,ToPointVec2,NearRadius,...)
|
|
30493
|
-
self:
|
|
31531
|
+
self:T({From,Event,To,ToPointVec2,NearRadius})
|
|
30494
31532
|
NearRadius=NearRadius or 25
|
|
30495
31533
|
local Timer=1
|
|
30496
31534
|
if From=="Loaded"then
|
|
@@ -30599,12 +31637,12 @@ end
|
|
|
30599
31637
|
)
|
|
30600
31638
|
end
|
|
30601
31639
|
function CARGO_GROUP:IsNear(CargoCarrier,NearRadius)
|
|
30602
|
-
self:
|
|
31640
|
+
self:T({NearRadius=NearRadius})
|
|
30603
31641
|
for _,Cargo in pairs(self.CargoSet:GetSet())do
|
|
30604
31642
|
local Cargo=Cargo
|
|
30605
31643
|
if Cargo:IsAlive()then
|
|
30606
31644
|
if Cargo:IsNear(CargoCarrier:GetCoordinate(),NearRadius)then
|
|
30607
|
-
self:
|
|
31645
|
+
self:T("Near")
|
|
30608
31646
|
return true
|
|
30609
31647
|
end
|
|
30610
31648
|
end
|
|
@@ -30626,7 +31664,7 @@ Distance=Coordinate:Get2DDistance(CargoCoordinate)
|
|
|
30626
31664
|
else
|
|
30627
31665
|
return false
|
|
30628
31666
|
end
|
|
30629
|
-
self:
|
|
31667
|
+
self:T({Distance=Distance,LoadRadius=self.LoadRadius})
|
|
30630
31668
|
if Distance<=self.LoadRadius then
|
|
30631
31669
|
return true
|
|
30632
31670
|
else
|
|
@@ -30638,7 +31676,7 @@ end
|
|
|
30638
31676
|
function CARGO_GROUP:IsInReportRadius(Coordinate)
|
|
30639
31677
|
local Cargo=self:GetFirstAlive()
|
|
30640
31678
|
if Cargo then
|
|
30641
|
-
self:
|
|
31679
|
+
self:T({Cargo})
|
|
30642
31680
|
local Distance=0
|
|
30643
31681
|
if Cargo:IsUnLoaded()then
|
|
30644
31682
|
Distance=Coordinate:Get2DDistance(Cargo.CargoObject:GetCoordinate())
|
|
@@ -32121,7 +33159,7 @@ self:HandleEvent(EVENTS.Shot,self.HandleEventShot)
|
|
|
32121
33159
|
self:SetStartState("Running")
|
|
32122
33160
|
self:AddTransition("*","ManageEvasion","*")
|
|
32123
33161
|
self:AddTransition("*","CalculateHitZone","*")
|
|
32124
|
-
self:I("*** SEAD - Started Version 0.4.
|
|
33162
|
+
self:I("*** SEAD - Started Version 0.4.6")
|
|
32125
33163
|
return self
|
|
32126
33164
|
end
|
|
32127
33165
|
function SEAD:UpdateSet(SEADGroupPrefixes)
|
|
@@ -32293,7 +33331,7 @@ if self.UseEmissionsOnOff then
|
|
|
32293
33331
|
grp:EnableEmission(false)
|
|
32294
33332
|
end
|
|
32295
33333
|
grp:OptionAlarmStateGreen()
|
|
32296
|
-
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
|
33334
|
+
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond",true)
|
|
32297
33335
|
if self.UseCallBack then
|
|
32298
33336
|
local object=self.CallBack
|
|
32299
33337
|
object:SeadSuppressionStart(grp,name,attacker)
|
|
@@ -33504,7 +34542,7 @@ AirbaseNames=nil,
|
|
|
33504
34542
|
}
|
|
33505
34543
|
function ATC_GROUND:New(Airbases,AirbaseList)
|
|
33506
34544
|
local self=BASE:Inherit(self,BASE:New())
|
|
33507
|
-
self:
|
|
34545
|
+
self:T({self.ClassName,Airbases})
|
|
33508
34546
|
self.Airbases=Airbases
|
|
33509
34547
|
self.AirbaseList=AirbaseList
|
|
33510
34548
|
self.SetClient=SET_CLIENT:New():FilterCategories("plane"):FilterStart()
|
|
@@ -33583,7 +34621,7 @@ function(Client)
|
|
|
33583
34621
|
if Client:IsAlive()then
|
|
33584
34622
|
local IsOnGround=Client:InAir()==false
|
|
33585
34623
|
for AirbaseID,AirbaseMeta in pairs(self.Airbases)do
|
|
33586
|
-
self:
|
|
34624
|
+
self:T(AirbaseID,AirbaseMeta.KickSpeed)
|
|
33587
34625
|
if AirbaseMeta.Monitor==true and Client:IsInZone(AirbaseMeta.ZoneBoundary)then
|
|
33588
34626
|
local NotInRunwayZone=true
|
|
33589
34627
|
for ZoneRunwayID,ZoneRunway in pairs(AirbaseMeta.ZoneRunways)do
|
|
@@ -33592,7 +34630,7 @@ end
|
|
|
33592
34630
|
if NotInRunwayZone then
|
|
33593
34631
|
if IsOnGround then
|
|
33594
34632
|
local Taxi=Client:GetState(self,"Taxi")
|
|
33595
|
-
self:
|
|
34633
|
+
self:T(Taxi)
|
|
33596
34634
|
if Taxi==false then
|
|
33597
34635
|
local Velocity=VELOCITY:New(AirbaseMeta.KickSpeed or self.KickSpeed)
|
|
33598
34636
|
Client:Message("Welcome to "..AirbaseID..". The maximum taxiing speed is "..
|
|
@@ -33712,12 +34750,18 @@ KickSpeed=nil,
|
|
|
33712
34750
|
}
|
|
33713
34751
|
function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
|
33714
34752
|
local self=BASE:Inherit(self,BASE:New())
|
|
33715
|
-
self:
|
|
34753
|
+
self:T({self.ClassName})
|
|
33716
34754
|
self.Airbases={}
|
|
33717
34755
|
for _name,_ in pairs(_DATABASE.AIRBASES)do
|
|
33718
34756
|
self.Airbases[_name]={}
|
|
33719
34757
|
end
|
|
33720
34758
|
self.AirbaseList=AirbaseList
|
|
34759
|
+
if not self.AirbaseList then
|
|
34760
|
+
self.AirbaseList={}
|
|
34761
|
+
for _name,_ in pairs(_DATABASE.AIRBASES)do
|
|
34762
|
+
self.AirbaseList[_name]=_name
|
|
34763
|
+
end
|
|
34764
|
+
end
|
|
33721
34765
|
self.SetClient=SET_CLIENT:New():FilterCategories("plane"):FilterStart()
|
|
33722
34766
|
for AirbaseID,Airbase in pairs(self.Airbases)do
|
|
33723
34767
|
if Airbase.ZoneBoundary then
|
|
@@ -33816,12 +34860,13 @@ self:SetMaximumKickSpeed(UTILS.MiphToMps(MaximumKickSpeedMiph),Airbase)
|
|
|
33816
34860
|
return self
|
|
33817
34861
|
end
|
|
33818
34862
|
function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
|
34863
|
+
self:I("_AirbaseMonitor")
|
|
33819
34864
|
self.SetClient:ForEachClient(
|
|
33820
34865
|
function(Client)
|
|
33821
34866
|
if Client:IsAlive()then
|
|
33822
34867
|
local IsOnGround=Client:InAir()==false
|
|
33823
34868
|
for AirbaseID,AirbaseMeta in pairs(self.Airbases)do
|
|
33824
|
-
self:
|
|
34869
|
+
self:T(AirbaseID,AirbaseMeta.KickSpeed)
|
|
33825
34870
|
if AirbaseMeta.Monitor==true and Client:IsInZone(AirbaseMeta.ZoneBoundary)then
|
|
33826
34871
|
local NotInRunwayZone=true
|
|
33827
34872
|
if AirbaseMeta.ZoneRunways then
|
|
@@ -33833,7 +34878,7 @@ end
|
|
|
33833
34878
|
if NotInRunwayZone then
|
|
33834
34879
|
if IsOnGround then
|
|
33835
34880
|
local Taxi=Client:GetState(self,"Taxi")
|
|
33836
|
-
self:
|
|
34881
|
+
self:T(Taxi)
|
|
33837
34882
|
if Taxi==false then
|
|
33838
34883
|
local Velocity=VELOCITY:New(AirbaseMeta.KickSpeed or self.KickSpeed)
|
|
33839
34884
|
Client:Message("Welcome to "..AirbaseID..". The maximum taxiing speed is "..
|
|
@@ -33945,7 +34990,7 @@ return true
|
|
|
33945
34990
|
end
|
|
33946
34991
|
function ATC_GROUND_UNIVERSAL:Start(RepeatScanSeconds)
|
|
33947
34992
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
33948
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
34993
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
33949
34994
|
return self
|
|
33950
34995
|
end
|
|
33951
34996
|
ATC_GROUND_CAUCASUS={
|
|
@@ -33959,7 +35004,7 @@ return self
|
|
|
33959
35004
|
end
|
|
33960
35005
|
function ATC_GROUND_CAUCASUS:Start(RepeatScanSeconds)
|
|
33961
35006
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
33962
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
35007
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
33963
35008
|
end
|
|
33964
35009
|
ATC_GROUND_NEVADA={
|
|
33965
35010
|
ClassName="ATC_GROUND_NEVADA",
|
|
@@ -33972,7 +35017,7 @@ return self
|
|
|
33972
35017
|
end
|
|
33973
35018
|
function ATC_GROUND_NEVADA:Start(RepeatScanSeconds)
|
|
33974
35019
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
33975
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
35020
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
33976
35021
|
end
|
|
33977
35022
|
ATC_GROUND_NORMANDY={
|
|
33978
35023
|
ClassName="ATC_GROUND_NORMANDY",
|
|
@@ -33985,7 +35030,7 @@ return self
|
|
|
33985
35030
|
end
|
|
33986
35031
|
function ATC_GROUND_NORMANDY:Start(RepeatScanSeconds)
|
|
33987
35032
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
33988
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
35033
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
33989
35034
|
end
|
|
33990
35035
|
ATC_GROUND_PERSIANGULF={
|
|
33991
35036
|
ClassName="ATC_GROUND_PERSIANGULF",
|
|
@@ -33997,20 +35042,20 @@ self:SetMaximumKickSpeedKmph(150)
|
|
|
33997
35042
|
end
|
|
33998
35043
|
function ATC_GROUND_PERSIANGULF:Start(RepeatScanSeconds)
|
|
33999
35044
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
34000
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
35045
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
34001
35046
|
end
|
|
34002
35047
|
ATC_GROUND_MARIANAISLANDS={
|
|
34003
35048
|
ClassName="ATC_GROUND_MARIANAISLANDS",
|
|
34004
35049
|
}
|
|
34005
35050
|
function ATC_GROUND_MARIANAISLANDS:New(AirbaseNames)
|
|
34006
|
-
local self=BASE:Inherit(self,ATC_GROUND_UNIVERSAL:New(
|
|
35051
|
+
local self=BASE:Inherit(self,ATC_GROUND_UNIVERSAL:New(AirbaseNames))
|
|
34007
35052
|
self:SetKickSpeedKmph(50)
|
|
34008
35053
|
self:SetMaximumKickSpeedKmph(150)
|
|
34009
35054
|
return self
|
|
34010
35055
|
end
|
|
34011
35056
|
function ATC_GROUND_MARIANAISLANDS:Start(RepeatScanSeconds)
|
|
34012
35057
|
RepeatScanSeconds=RepeatScanSeconds or 0.05
|
|
34013
|
-
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,
|
|
35058
|
+
self.AirbaseMonitor=SCHEDULER:New(self,self._AirbaseMonitor,{self},0,RepeatScanSeconds)
|
|
34014
35059
|
end
|
|
34015
35060
|
do
|
|
34016
35061
|
DETECTION_BASE={
|
|
@@ -34163,6 +35208,28 @@ DetectionAccepted=false
|
|
|
34163
35208
|
end
|
|
34164
35209
|
end
|
|
34165
35210
|
end
|
|
35211
|
+
if self.RadarBlur then
|
|
35212
|
+
MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
|
35213
|
+
local minheight=self.RadarBlurMinHeight or 250
|
|
35214
|
+
local thresheight=self.RadarBlurThresHeight or 90
|
|
35215
|
+
local thresblur=self.RadarBlurThresBlur or 85
|
|
35216
|
+
local dist=math.floor(Distance)
|
|
35217
|
+
if dist<=self.RadarBlurClosing then
|
|
35218
|
+
thresheight=(((dist*dist)/self.RadarBlurClosingSquare)*thresheight)
|
|
35219
|
+
thresblur=(((dist*dist)/self.RadarBlurClosingSquare)*thresblur)
|
|
35220
|
+
end
|
|
35221
|
+
local fheight=math.floor(math.random(1,10000)/100)
|
|
35222
|
+
local fblur=math.floor(math.random(1,10000)/100)
|
|
35223
|
+
local unit=UNIT:FindByName(DetectedObjectName)
|
|
35224
|
+
if unit and unit:IsAlive()then
|
|
35225
|
+
local AGL=unit:GetAltitude(true)
|
|
35226
|
+
MESSAGE:New("Unit "..DetectedObjectName.." is at "..math.floor(AGL).."m. Distance "..math.floor(Distance).."km.",10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
|
35227
|
+
MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
|
35228
|
+
if fblur>thresblur then DetectionAccepted=false end
|
|
35229
|
+
if AGL<=minheight and fheight<thresheight then DetectionAccepted=false end
|
|
35230
|
+
MESSAGE:New("Detection Accepted = "..tostring(DetectionAccepted),10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
|
35231
|
+
end
|
|
35232
|
+
end
|
|
34166
35233
|
if not self.DetectedObjects[DetectedObjectName]and TargetIsVisible and self.DistanceProbability then
|
|
34167
35234
|
local DistanceFactor=Distance/4
|
|
34168
35235
|
local DistanceProbabilityReversed=(1-self.DistanceProbability)*DistanceFactor
|
|
@@ -34323,6 +35390,15 @@ self._.FilterCategories[FilterCategories]=FilterCategories
|
|
|
34323
35390
|
end
|
|
34324
35391
|
return self
|
|
34325
35392
|
end
|
|
35393
|
+
function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur,closing)
|
|
35394
|
+
self.RadarBlur=true
|
|
35395
|
+
self.RadarBlurMinHeight=minheight or 250
|
|
35396
|
+
self.RadarBlurThresHeight=thresheight or 90
|
|
35397
|
+
self.RadarBlurThresBlur=thresblur or 85
|
|
35398
|
+
self.RadarBlurClosing=closing or 20
|
|
35399
|
+
self.RadarBlurClosingSquare=self.RadarBlurClosing*self.RadarBlurClosing
|
|
35400
|
+
return self
|
|
35401
|
+
end
|
|
34326
35402
|
end
|
|
34327
35403
|
do
|
|
34328
35404
|
function DETECTION_BASE:SetRefreshTimeInterval(RefreshTimeInterval)
|
|
@@ -37451,7 +38527,7 @@ if takeoff==RAT.wp.air then
|
|
|
37451
38527
|
departure=departure:GetZone()
|
|
37452
38528
|
end
|
|
37453
38529
|
elseif self:_ZoneExists(_departure)then
|
|
37454
|
-
departure=ZONE:
|
|
38530
|
+
departure=ZONE:FindByName(_departure)
|
|
37455
38531
|
else
|
|
37456
38532
|
local text=string.format("ERROR! Specified departure airport %s does not exist for %s.",_departure,self.alias)
|
|
37457
38533
|
self:E(RAT.id..text)
|
|
@@ -37522,7 +38598,7 @@ if landing==RAT.wp.air or self.returnzone then
|
|
|
37522
38598
|
destination=destination:GetZone()
|
|
37523
38599
|
end
|
|
37524
38600
|
elseif self:_ZoneExists(_destination)then
|
|
37525
|
-
destination=ZONE:
|
|
38601
|
+
destination=ZONE:FindByName(_destination)
|
|
37526
38602
|
else
|
|
37527
38603
|
local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!",_destination,self.alias)
|
|
37528
38604
|
self:E(RAT.id.."ERROR: "..text)
|
|
@@ -37857,7 +38933,7 @@ end
|
|
|
37857
38933
|
end
|
|
37858
38934
|
elseif self:_ZoneExists(name)then
|
|
37859
38935
|
if takeoff==RAT.wp.air then
|
|
37860
|
-
dep=ZONE:
|
|
38936
|
+
dep=ZONE:FindByName(name)
|
|
37861
38937
|
else
|
|
37862
38938
|
self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.",name))
|
|
37863
38939
|
end
|
|
@@ -37929,7 +39005,7 @@ end
|
|
|
37929
39005
|
end
|
|
37930
39006
|
elseif self:_ZoneExists(name)then
|
|
37931
39007
|
if landing==RAT.wp.air then
|
|
37932
|
-
dest=ZONE:
|
|
39008
|
+
dest=ZONE:FindByName(name)
|
|
37933
39009
|
else
|
|
37934
39010
|
self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!",name))
|
|
37935
39011
|
end
|
|
@@ -38891,7 +39967,7 @@ end
|
|
|
38891
39967
|
return false
|
|
38892
39968
|
end
|
|
38893
39969
|
function RAT:_ZoneExists(name)
|
|
38894
|
-
local z=
|
|
39970
|
+
local z=ZONE:FindByName(name)
|
|
38895
39971
|
if z then
|
|
38896
39972
|
return true
|
|
38897
39973
|
end
|
|
@@ -39931,15 +41007,15 @@ self.trackmissiles=false
|
|
|
39931
41007
|
return self
|
|
39932
41008
|
end
|
|
39933
41009
|
function RANGE:SetSRS(PathToSRS,Port,Coalition,Frequency,Modulation,Volume,PathToGoogleKey)
|
|
39934
|
-
if PathToSRS then
|
|
41010
|
+
if PathToSRS or MSRS.path then
|
|
39935
41011
|
self.useSRS=true
|
|
39936
|
-
self.controlmsrs=MSRS:New(PathToSRS,Frequency or 256,Modulation or radio.modulation.AM,Volume or 1.0)
|
|
39937
|
-
self.controlmsrs:SetPort(Port)
|
|
41012
|
+
self.controlmsrs=MSRS:New(PathToSRS or MSRS.path,Frequency or 256,Modulation or radio.modulation.AM,Volume or 1.0)
|
|
41013
|
+
self.controlmsrs:SetPort(Port or MSRS.port)
|
|
39938
41014
|
self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE)
|
|
39939
41015
|
self.controlmsrs:SetLabel("RANGEC")
|
|
39940
41016
|
self.controlsrsQ=MSRSQUEUE:New("CONTROL")
|
|
39941
|
-
self.instructmsrs=MSRS:New(PathToSRS,Frequency or 305,Modulation or radio.modulation.AM,Volume or 1.0)
|
|
39942
|
-
self.instructmsrs:SetPort(Port)
|
|
41017
|
+
self.instructmsrs=MSRS:New(PathToSRS or MSRS.path,Frequency or 305,Modulation or radio.modulation.AM,Volume or 1.0)
|
|
41018
|
+
self.instructmsrs:SetPort(Port or MSRS.port)
|
|
39943
41019
|
self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE)
|
|
39944
41020
|
self.instructmsrs:SetLabel("RANGEI")
|
|
39945
41021
|
self.instructsrsQ=MSRSQUEUE:New("INSTRUCT")
|
|
@@ -39953,6 +41029,10 @@ end
|
|
|
39953
41029
|
return self
|
|
39954
41030
|
end
|
|
39955
41031
|
function RANGE:SetSRSRangeControl(frequency,modulation,voice,culture,gender,relayunitname)
|
|
41032
|
+
if not self.instructmsrs then
|
|
41033
|
+
self:E(self.lid.."Use myrange:SetSRS() once first before using myrange:SetSRSRangeControl!")
|
|
41034
|
+
return self
|
|
41035
|
+
end
|
|
39956
41036
|
self.rangecontrolfreq=frequency or 256
|
|
39957
41037
|
self.controlmsrs:SetFrequencies(self.rangecontrolfreq)
|
|
39958
41038
|
self.controlmsrs:SetModulations(modulation or radio.modulation.AM)
|
|
@@ -39968,6 +41048,10 @@ end
|
|
|
39968
41048
|
return self
|
|
39969
41049
|
end
|
|
39970
41050
|
function RANGE:SetSRSRangeInstructor(frequency,modulation,voice,culture,gender,relayunitname)
|
|
41051
|
+
if not self.instructmsrs then
|
|
41052
|
+
self:E(self.lid.."Use myrange:SetSRS() once first before using myrange:SetSRSRangeInstructor!")
|
|
41053
|
+
return self
|
|
41054
|
+
end
|
|
39971
41055
|
self.instructorfreq=frequency or 305
|
|
39972
41056
|
self.instructmsrs:SetFrequencies(self.instructorfreq)
|
|
39973
41057
|
self.instructmsrs:SetModulations(modulation or radio.modulation.AM)
|
|
@@ -40220,6 +41304,7 @@ return fouldist
|
|
|
40220
41304
|
end
|
|
40221
41305
|
function RANGE:OnEventBirth(EventData)
|
|
40222
41306
|
self:F({eventbirth=EventData})
|
|
41307
|
+
if not EventData.IniPlayerName then return end
|
|
40223
41308
|
local _unitName=EventData.IniUnitName
|
|
40224
41309
|
local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
|
|
40225
41310
|
self:T3(self.lid.."BIRTH: unit = "..tostring(EventData.IniUnitName))
|
|
@@ -40476,7 +41561,7 @@ function RANGE:onafterExitRange(From,Event,To,player)
|
|
|
40476
41561
|
if self.instructor then
|
|
40477
41562
|
if self.useSRS then
|
|
40478
41563
|
local text="You left the bombing range zone. "
|
|
40479
|
-
local r=math.random(
|
|
41564
|
+
local r=math.random(5)
|
|
40480
41565
|
if r==1 then
|
|
40481
41566
|
text=text.."Have a nice day!"
|
|
40482
41567
|
elseif r==2 then
|
|
@@ -48276,11 +49361,22 @@ local _assetattribute
|
|
|
48276
49361
|
local _assetcategory
|
|
48277
49362
|
local _assetairstart=false
|
|
48278
49363
|
if _nassets>0 then
|
|
49364
|
+
local asset=_assets[1]
|
|
48279
49365
|
_assetattribute=_assets[1].attribute
|
|
48280
49366
|
_assetcategory=_assets[1].category
|
|
48281
49367
|
_assetairstart=_assets[1].takeoffType and _assets[1].takeoffType==COORDINATE.WaypointType.TurningPoint or false
|
|
48282
49368
|
if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
|
48283
49369
|
if self.airbase and self.airbase:GetCoalition()==self:GetCoalition()then
|
|
49370
|
+
if self.airbase.storage then
|
|
49371
|
+
local nS=self.airbase.storage:GetAmount(asset.unittype)
|
|
49372
|
+
local nA=asset.nunits*request.nasset
|
|
49373
|
+
if nS<nA then
|
|
49374
|
+
local text=string.format("Warehouse %s: Request denied! DCS Warehouse has only %d assets of type %s ==> NOT enough to spawn the requested %d asset units (%d groups)",
|
|
49375
|
+
self.alias,nS,asset.unittype,nA,request.nasset)
|
|
49376
|
+
self:_InfoMessage(text,5)
|
|
49377
|
+
return false
|
|
49378
|
+
end
|
|
49379
|
+
end
|
|
48284
49380
|
if self:IsRunwayOperational()or _assetairstart then
|
|
48285
49381
|
if _assetairstart then
|
|
48286
49382
|
else
|
|
@@ -48342,6 +49438,7 @@ local text=string.format("Warehouse %s: Request denied! Not close enough to spaw
|
|
|
48342
49438
|
self:_InfoMessage(text,5)
|
|
48343
49439
|
return false
|
|
48344
49440
|
end
|
|
49441
|
+
elseif _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
|
48345
49442
|
end
|
|
48346
49443
|
end
|
|
48347
49444
|
request.cargoassets=_assets
|
|
@@ -50202,7 +51299,7 @@ MANTIS.SamData={
|
|
|
50202
51299
|
["SA-15"]={Range=11,Blindspot=0,Height=6,Type="Short",Radar="Tor 9A331"},
|
|
50203
51300
|
["SA-13"]={Range=5,Blindspot=0,Height=3,Type="Short",Radar="Strela"},
|
|
50204
51301
|
["Avenger"]={Range=4,Blindspot=0,Height=3,Type="Short",Radar="Avenger"},
|
|
50205
|
-
["
|
|
51302
|
+
["Chaparral"]={Range=8,Blindspot=0,Height=3,Type="Short",Radar="Chaparral"},
|
|
50206
51303
|
["Linebacker"]={Range=4,Blindspot=0,Height=3,Type="Short",Radar="Linebacker"},
|
|
50207
51304
|
["Silkworm"]={Range=90,Blindspot=1,Height=0.2,Type="Long",Radar="Silkworm"},
|
|
50208
51305
|
["SA-10B"]={Range=75,Blindspot=0,Height=18,Type="Medium",Radar="SA-10B"},
|
|
@@ -50360,7 +51457,7 @@ end
|
|
|
50360
51457
|
if self.HQ_Template_CC then
|
|
50361
51458
|
self.HQ_CC=GROUP:FindByName(self.HQ_Template_CC)
|
|
50362
51459
|
end
|
|
50363
|
-
self.version="0.8.
|
|
51460
|
+
self.version="0.8.16"
|
|
50364
51461
|
self:I(string.format("***** Starting MANTIS Version %s *****",self.version))
|
|
50365
51462
|
self:SetStartState("Stopped")
|
|
50366
51463
|
self:AddTransition("Stopped","Start","Running")
|
|
@@ -50621,7 +51718,7 @@ local HQGroup=self.HQ_CC
|
|
|
50621
51718
|
if self.autorelocateunits.HQ and self.HQ_CC and HQGroup:IsAlive()then
|
|
50622
51719
|
local _hqgrp=self.HQ_CC
|
|
50623
51720
|
local text=self.lid.." Relocating HQ"
|
|
50624
|
-
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
|
|
51721
|
+
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
|
|
50625
51722
|
end
|
|
50626
51723
|
if self.autorelocateunits.EWR then
|
|
50627
51724
|
local EWR_GRP=SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterOnce()
|
|
@@ -50631,7 +51728,7 @@ if _grp:IsAlive()and _grp:IsGround()then
|
|
|
50631
51728
|
local text=self.lid.." Relocating EWR ".._grp:GetName()
|
|
50632
51729
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
|
50633
51730
|
if self.verbose then self:I(text)end
|
|
50634
|
-
_grp:RelocateGroundRandomInRadius(20,500,true,true)
|
|
51731
|
+
_grp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
|
|
50635
51732
|
end
|
|
50636
51733
|
end
|
|
50637
51734
|
end
|
|
@@ -51859,7 +52956,7 @@ HARD="TOPGUN Graduate",
|
|
|
51859
52956
|
}
|
|
51860
52957
|
AIRBOSS.MenuF10={}
|
|
51861
52958
|
AIRBOSS.MenuF10Root=nil
|
|
51862
|
-
AIRBOSS.version="1.3.
|
|
52959
|
+
AIRBOSS.version="1.3.3"
|
|
51863
52960
|
function AIRBOSS:New(carriername,alias)
|
|
51864
52961
|
local self=BASE:Inherit(self,FSM:New())
|
|
51865
52962
|
self:F2({carriername=carriername,alias=alias})
|
|
@@ -52378,6 +53475,7 @@ self.SRS:SetGender(Gender or"male")
|
|
|
52378
53475
|
self.SRS:SetPath(PathToSRS)
|
|
52379
53476
|
self.SRS:SetPort(Port or 5002)
|
|
52380
53477
|
self.SRS:SetLabel(self.AirbossRadio.alias or"AIRBOSS")
|
|
53478
|
+
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
|
52381
53479
|
if GoogleCreds then
|
|
52382
53480
|
self.SRS:SetGoogle(GoogleCreds)
|
|
52383
53481
|
end
|
|
@@ -55055,7 +56153,7 @@ self:E(self.lid.."ERROR: EventData=nil in event BIRTH!")
|
|
|
55055
56153
|
self:E(EventData)
|
|
55056
56154
|
return
|
|
55057
56155
|
end
|
|
55058
|
-
if EventData.IniUnit==nil then
|
|
56156
|
+
if EventData.IniUnit==nil and(not EventData.IniObjectCategory==Object.Category.STATIC)then
|
|
55059
56157
|
self:E(self.lid.."ERROR: EventData.IniUnit=nil in event BIRTH!")
|
|
55060
56158
|
self:E(EventData)
|
|
55061
56159
|
return
|
|
@@ -56506,7 +57604,7 @@ text=text..string.format("\nWind Vx=%.1f Vy=%.1f Vz=%.1f m/s",wind.x,wind.y,wind
|
|
|
56506
57604
|
end
|
|
56507
57605
|
text=text..string.format("\nPitch=%.1f° | Roll=%.1f° | Yaw=%.1f°",pitch,roll,yaw)
|
|
56508
57606
|
text=text..string.format("\nClimb Angle=%.1f° | Rate=%d ft/min",unit:GetClimbAngle(),velo.y*196.85)
|
|
56509
|
-
local dist=self:_GetOptLandingCoordinate():Get3DDistance(playerData.unit)
|
|
57607
|
+
local dist=self:_GetOptLandingCoordinate():Get3DDistance(playerData.unit:GetVec3())
|
|
56510
57608
|
local vplayer=playerData.unit:GetVelocityKMH()
|
|
56511
57609
|
local vcarrier=self.carrier:GetVelocityKMH()
|
|
56512
57610
|
local dv=math.abs(vplayer-vcarrier)
|
|
@@ -58370,7 +59468,7 @@ self.PilotRadio.alias="PILOT"
|
|
|
58370
59468
|
self.PilotRadio.voice=Voice or MSRS.Voices.Microsoft.David
|
|
58371
59469
|
self.PilotRadio.gender=Gender or"male"
|
|
58372
59470
|
self.PilotRadio.culture=Culture or"en-US"
|
|
58373
|
-
if(not Voice)and self.SRS and self.SRS.
|
|
59471
|
+
if(not Voice)and self.SRS and self.SRS:GetProvider()==MSRS.Provider.GOOGLE then
|
|
58374
59472
|
self.PilotRadio.voice=MSRS.Voices.Google.Standard.en_US_Standard_J
|
|
58375
59473
|
end
|
|
58376
59474
|
return self
|
|
@@ -61653,7 +62751,7 @@ DELIMITER="Punto",
|
|
|
61653
62751
|
}
|
|
61654
62752
|
ATIS.locale="en"
|
|
61655
62753
|
_ATIS={}
|
|
61656
|
-
ATIS.version="0.
|
|
62754
|
+
ATIS.version="1.0.0"
|
|
61657
62755
|
function ATIS:New(AirbaseName,Frequency,Modulation)
|
|
61658
62756
|
local self=BASE:Inherit(self,FSM:New())
|
|
61659
62757
|
self.airbasename=AirbaseName
|
|
@@ -61962,7 +63060,16 @@ self:E(self.lid..string.format("EXPERIMENTAL: Starting ATIS for Helipad %s! SRS
|
|
|
61962
63060
|
self.ATISforFARPs=true
|
|
61963
63061
|
self.useSRS=true
|
|
61964
63062
|
end
|
|
63063
|
+
if type(self.frequency)=="table"then
|
|
63064
|
+
local frequency=table.concat(self.frequency,"/")
|
|
63065
|
+
local modulation=self.modulation
|
|
63066
|
+
if type(self.modulation)=="table"then
|
|
63067
|
+
modulation=table.concat(self.modulation,"/")
|
|
63068
|
+
end
|
|
63069
|
+
self:I(self.lid..string.format("Starting ATIS v%s for airbase %s on %s MHz Modulation=%s",ATIS.version,self.airbasename,frequency,modulation))
|
|
63070
|
+
else
|
|
61965
63071
|
self:I(self.lid..string.format("Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d",ATIS.version,self.airbasename,self.frequency,self.modulation))
|
|
63072
|
+
end
|
|
61966
63073
|
if not self.useSRS then
|
|
61967
63074
|
self.radioqueue=RADIOQUEUE:New(self.frequency,self.modulation,string.format("ATIS %s",self.airbasename))
|
|
61968
63075
|
self.radioqueue:SetSenderCoordinate(self.airbase:GetCoordinate())
|
|
@@ -61994,7 +63101,17 @@ if ru then
|
|
|
61994
63101
|
relayunitstatus=tostring(ru:IsAlive())
|
|
61995
63102
|
end
|
|
61996
63103
|
end
|
|
61997
|
-
local text=
|
|
63104
|
+
local text=""
|
|
63105
|
+
if type(self.frequency)=="table"then
|
|
63106
|
+
local frequency=table.concat(self.frequency,"/")
|
|
63107
|
+
local modulation=self.modulation
|
|
63108
|
+
if type(self.modulation)=="table"then
|
|
63109
|
+
modulation=table.concat(self.modulation,"/")
|
|
63110
|
+
end
|
|
63111
|
+
text=string.format("State %s: Freq=%s MHz %s",fsmstate,frequency,modulation)
|
|
63112
|
+
else
|
|
63113
|
+
text=string.format("State %s: Freq=%.3f MHz %s",fsmstate,self.frequency,UTILS.GetModulationName(self.modulation))
|
|
63114
|
+
end
|
|
61998
63115
|
if self.useSRS then
|
|
61999
63116
|
text=text..string.format(", SRS path=%s (%s), gender=%s, culture=%s, voice=%s",tostring(self.msrs.path),tostring(self.msrs.port),tostring(self.msrs.gender),tostring(self.msrs.culture),tostring(self.msrs.voice))
|
|
62000
63117
|
else
|
|
@@ -62879,7 +63996,17 @@ function ATIS:UpdateMarker(information,runact,wind,altimeter,temperature)
|
|
|
62879
63996
|
if self.markerid then
|
|
62880
63997
|
self.airbase:GetCoordinate():RemoveMark(self.markerid)
|
|
62881
63998
|
end
|
|
62882
|
-
local text=
|
|
63999
|
+
local text=""
|
|
64000
|
+
if type(self.frequency)=="table"then
|
|
64001
|
+
local frequency=table.concat(self.frequency,"/")
|
|
64002
|
+
local modulation=self.modulation
|
|
64003
|
+
if type(modulation)=="table"then
|
|
64004
|
+
modulation=table.concat(self.modulation,"/")
|
|
64005
|
+
end
|
|
64006
|
+
text=string.format("ATIS on %s %s, %s:\n",tostring(frequency),tostring(modulation),tostring(information))
|
|
64007
|
+
else
|
|
64008
|
+
text=string.format("ATIS on %.3f %s, %s:\n",self.frequency,UTILS.GetModulationName(self.modulation),tostring(information))
|
|
64009
|
+
end
|
|
62883
64010
|
text=text..string.format("%s\n",tostring(runact))
|
|
62884
64011
|
text=text..string.format("%s\n",tostring(wind))
|
|
62885
64012
|
text=text..string.format("%s\n",tostring(altimeter))
|
|
@@ -63343,7 +64470,7 @@ CTLD.UnitTypeCapabilities={
|
|
|
63343
64470
|
["AH-64D_BLK_II"]={type="AH-64D_BLK_II",crates=false,troops=true,cratelimit=0,trooplimit=2,length=17,cargoweightlimit=200},
|
|
63344
64471
|
["Bronco-OV-10A"]={type="Bronco-OV-10A",crates=false,troops=true,cratelimit=0,trooplimit=5,length=13,cargoweightlimit=1450},
|
|
63345
64472
|
}
|
|
63346
|
-
CTLD.version="1.0.
|
|
64473
|
+
CTLD.version="1.0.45"
|
|
63347
64474
|
function CTLD:New(Coalition,Prefixes,Alias)
|
|
63348
64475
|
local self=BASE:Inherit(self,FSM:New())
|
|
63349
64476
|
BASE:T({Coalition,Prefixes,Alias})
|
|
@@ -63388,6 +64515,8 @@ self:AddTransition("*","TroopsRTB","*")
|
|
|
63388
64515
|
self:AddTransition("*","CratesDropped","*")
|
|
63389
64516
|
self:AddTransition("*","CratesBuild","*")
|
|
63390
64517
|
self:AddTransition("*","CratesRepaired","*")
|
|
64518
|
+
self:AddTransition("*","CratesBuildStarted","*")
|
|
64519
|
+
self:AddTransition("*","CratesRepairStarted","*")
|
|
63391
64520
|
self:AddTransition("*","Load","*")
|
|
63392
64521
|
self:AddTransition("*","Save","*")
|
|
63393
64522
|
self:AddTransition("*","Stop","Stopped")
|
|
@@ -63807,6 +64936,7 @@ local desttimer=TIMER:New(function()NearestGroup:Destroy(false)end,self)
|
|
|
63807
64936
|
desttimer:Start(self.repairtime-1)
|
|
63808
64937
|
local buildtimer=TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate())
|
|
63809
64938
|
buildtimer:Start(self.repairtime)
|
|
64939
|
+
self:__CratesRepairStarted(1,Group,Unit)
|
|
63810
64940
|
else
|
|
63811
64941
|
if not Engineering then
|
|
63812
64942
|
self:_SendMessage("Can't repair this unit with "..build.Name,10,false,Group)
|
|
@@ -64047,10 +65177,12 @@ realcargo=CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,crat
|
|
|
64047
65177
|
table.insert(droppedcargo,realcargo)
|
|
64048
65178
|
else
|
|
64049
65179
|
realcargo=CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat)
|
|
64050
|
-
Cargo:RemoveStock()
|
|
64051
65180
|
end
|
|
64052
65181
|
table.insert(self.Spawned_Cargo,realcargo)
|
|
64053
65182
|
end
|
|
65183
|
+
if not(drop or pack)then
|
|
65184
|
+
Cargo:RemoveStock()
|
|
65185
|
+
end
|
|
64054
65186
|
local text=string.format("Crates for %s have been positioned near you!",cratename)
|
|
64055
65187
|
if drop then
|
|
64056
65188
|
text=string.format("Crates for %s have been dropped!",cratename)
|
|
@@ -64131,6 +65263,34 @@ self:_SendMessage(string.format("No (loadable) crates within %d meters!",finddis
|
|
|
64131
65263
|
end
|
|
64132
65264
|
return self
|
|
64133
65265
|
end
|
|
65266
|
+
function CTLD:_RemoveCratesNearby(_group,_unit)
|
|
65267
|
+
self:T(self.lid.." _RemoveCratesNearby")
|
|
65268
|
+
local finddist=self.CrateDistance or 35
|
|
65269
|
+
local crates,number=self:_FindCratesNearby(_group,_unit,finddist,true)
|
|
65270
|
+
if number>0 then
|
|
65271
|
+
local text=REPORT:New("Removing Crates Found Nearby:")
|
|
65272
|
+
text:Add("------------------------------------------------------------")
|
|
65273
|
+
for _,_entry in pairs(crates)do
|
|
65274
|
+
local entry=_entry
|
|
65275
|
+
local name=entry:GetName()
|
|
65276
|
+
local dropped=entry:WasDropped()
|
|
65277
|
+
if dropped then
|
|
65278
|
+
text:Add(string.format("Crate for %s, %dkg removed",name,entry.PerCrateMass))
|
|
65279
|
+
else
|
|
65280
|
+
text:Add(string.format("Crate for %s, %dkg removed",name,entry.PerCrateMass))
|
|
65281
|
+
end
|
|
65282
|
+
entry:GetPositionable():Destroy(false)
|
|
65283
|
+
end
|
|
65284
|
+
if text:GetCount()==1 then
|
|
65285
|
+
text:Add(" N O N E")
|
|
65286
|
+
end
|
|
65287
|
+
text:Add("------------------------------------------------------------")
|
|
65288
|
+
self:_SendMessage(text:Text(),30,true,_group)
|
|
65289
|
+
else
|
|
65290
|
+
self:_SendMessage(string.format("No (loadable) crates within %d meters!",finddist),10,false,_group)
|
|
65291
|
+
end
|
|
65292
|
+
return self
|
|
65293
|
+
end
|
|
64134
65294
|
function CTLD:_GetDistance(_point1,_point2)
|
|
64135
65295
|
self:T(self.lid.." _GetDistance")
|
|
64136
65296
|
if _point1 and _point2 then
|
|
@@ -64469,6 +65629,26 @@ else
|
|
|
64469
65629
|
return false
|
|
64470
65630
|
end
|
|
64471
65631
|
end
|
|
65632
|
+
function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
|
65633
|
+
local Positions={}
|
|
65634
|
+
local template=_DATABASE:GetGroupTemplate(Template)
|
|
65635
|
+
UTILS.PrintTableToLog(template)
|
|
65636
|
+
local numbertroops=#template.units
|
|
65637
|
+
local newcenter=Coordinate:Translate(Radius,((Heading+270)%360))
|
|
65638
|
+
for i=1,360,math.floor(360/numbertroops)do
|
|
65639
|
+
local phead=((Heading+270+i)%360)
|
|
65640
|
+
local post=newcenter:Translate(Radius,phead)
|
|
65641
|
+
local pos1=post:GetVec2()
|
|
65642
|
+
local p1t={
|
|
65643
|
+
x=pos1.x,
|
|
65644
|
+
y=pos1.y,
|
|
65645
|
+
heading=phead,
|
|
65646
|
+
}
|
|
65647
|
+
table.insert(Positions,p1t)
|
|
65648
|
+
end
|
|
65649
|
+
UTILS.PrintTableToLog(Positions)
|
|
65650
|
+
return Positions
|
|
65651
|
+
end
|
|
64472
65652
|
function CTLD:_UnloadTroops(Group,Unit)
|
|
64473
65653
|
self:T(self.lid.." _UnloadTroops")
|
|
64474
65654
|
local droppingatbase=false
|
|
@@ -64509,14 +65689,25 @@ factor=cargo:GetCratesNeeded()or 1
|
|
|
64509
65689
|
zoneradius=Unit:GetVelocityMPS()or 100
|
|
64510
65690
|
end
|
|
64511
65691
|
local zone=ZONE_GROUP:New(string.format("Unload zone-%s",unitname),Group,zoneradius*factor)
|
|
64512
|
-
local randomcoord=zone:GetRandomCoordinate(10,30*factor)
|
|
65692
|
+
local randomcoord=zone:GetRandomCoordinate(10,30*factor)
|
|
65693
|
+
local heading=Group:GetHeading()or 0
|
|
65694
|
+
if hoverunload or grounded then
|
|
65695
|
+
randomcoord=Group:GetCoordinate()
|
|
65696
|
+
local Angle=(heading+270)%360
|
|
65697
|
+
local offset=hoverunload and 1.5 or 5
|
|
65698
|
+
randomcoord:Translate(offset,Angle,nil,true)
|
|
65699
|
+
end
|
|
65700
|
+
local tempcount=0
|
|
64513
65701
|
for _,_template in pairs(temptable)do
|
|
64514
65702
|
self.TroopCounter=self.TroopCounter+1
|
|
65703
|
+
tempcount=tempcount+1
|
|
64515
65704
|
local alias=string.format("%s-%d",_template,math.random(1,100000))
|
|
65705
|
+
local rad=2.5+tempcount
|
|
65706
|
+
local Positions=self:_GetUnitPositions(randomcoord,rad,heading,_template)
|
|
64516
65707
|
self.DroppedTroops[self.TroopCounter]=SPAWN:NewWithAlias(_template,alias)
|
|
64517
|
-
:InitRandomizeUnits(true,20,2)
|
|
64518
65708
|
:InitDelayOff()
|
|
64519
|
-
:
|
|
65709
|
+
:InitSetUnitAbsolutePositions(Positions)
|
|
65710
|
+
:SpawnFromVec2(randomcoord:GetVec2())
|
|
64520
65711
|
self:__TroopsDeployed(1,Group,Unit,self.DroppedTroops[self.TroopCounter],type)
|
|
64521
65712
|
end
|
|
64522
65713
|
cargo:SetWasDropped(true)
|
|
@@ -64715,6 +65906,7 @@ if self.buildtime and self.buildtime>0 then
|
|
|
64715
65906
|
local buildtimer=TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
|
|
64716
65907
|
buildtimer:Start(self.buildtime)
|
|
64717
65908
|
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
|
65909
|
+
self:__CratesBuildStarted(1,Group,Unit)
|
|
64718
65910
|
else
|
|
64719
65911
|
self:_BuildObjectFromCrates(Group,Unit,build)
|
|
64720
65912
|
end
|
|
@@ -65008,6 +66200,7 @@ if cancrates then
|
|
|
65008
66200
|
local loadmenu=MENU_GROUP_COMMAND:New(_group,"Load crates",topcrates,self._LoadCratesNearby,self,_group,_unit)
|
|
65009
66201
|
local cratesmenu=MENU_GROUP:New(_group,"Get Crates",topcrates)
|
|
65010
66202
|
local packmenu=MENU_GROUP_COMMAND:New(_group,"Pack crates",topcrates,self._PackCratesNearby,self,_group,_unit)
|
|
66203
|
+
local removecratesmenu=MENU_GROUP:New(_group,"Remove crates",topcrates)
|
|
65011
66204
|
if self.usesubcats then
|
|
65012
66205
|
local subcatmenus={}
|
|
65013
66206
|
for _name,_entry in pairs(self.subcats)do
|
|
@@ -65042,6 +66235,7 @@ menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrat
|
|
|
65042
66235
|
end
|
|
65043
66236
|
end
|
|
65044
66237
|
listmenu=MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates,self._ListCratesNearby,self,_group,_unit)
|
|
66238
|
+
removecrates=MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu,self._RemoveCratesNearby,self,_group,_unit)
|
|
65045
66239
|
local unloadmenu=MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates,self._UnloadCrates,self,_group,_unit)
|
|
65046
66240
|
if not self.nobuildmenu then
|
|
65047
66241
|
local buildmenu=MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates,self._BuildCrates,self,_group,_unit)
|
|
@@ -77079,6 +78273,15 @@ trigger.action.outSoundForUnit(Unit:GetID(),self.UserSoundFileName)
|
|
|
77079
78273
|
end
|
|
77080
78274
|
return self
|
|
77081
78275
|
end
|
|
78276
|
+
function USERSOUND:ToClient(Client,Delay)
|
|
78277
|
+
Delay=Delay or 0
|
|
78278
|
+
if Delay>0 then
|
|
78279
|
+
SCHEDULER:New(nil,USERSOUND.ToClient,{self,Client},Delay)
|
|
78280
|
+
else
|
|
78281
|
+
trigger.action.outSoundForUnit(Client:GetID(),self.UserSoundFileName)
|
|
78282
|
+
end
|
|
78283
|
+
return self
|
|
78284
|
+
end
|
|
77082
78285
|
end
|
|
77083
78286
|
do
|
|
77084
78287
|
SOUNDBASE={
|
|
@@ -77121,18 +78324,25 @@ subtitle=nil,
|
|
|
77121
78324
|
subduration=0,
|
|
77122
78325
|
useSRS=false,
|
|
77123
78326
|
}
|
|
77124
|
-
function SOUNDFILE:New(FileName,Path,Duration)
|
|
78327
|
+
function SOUNDFILE:New(FileName,Path,Duration,UseSrs)
|
|
77125
78328
|
local self=BASE:Inherit(self,BASE:New())
|
|
78329
|
+
self:F({FileName,Path,Duration,UseSrs})
|
|
77126
78330
|
self:SetFileName(FileName)
|
|
78331
|
+
self:SetPlayWithSRS(UseSrs or false)
|
|
77127
78332
|
self:SetPath(Path)
|
|
77128
78333
|
self:SetDuration(Duration)
|
|
77129
|
-
self:T(string.format("New SOUNDFILE: file name=%s, path=%s",self.filename,self.path))
|
|
77130
78334
|
return self
|
|
77131
78335
|
end
|
|
77132
78336
|
function SOUNDFILE:SetPath(Path)
|
|
77133
|
-
self
|
|
77134
|
-
if not Path
|
|
77135
|
-
self.
|
|
78337
|
+
self:F({Path})
|
|
78338
|
+
if not Path then
|
|
78339
|
+
if self.useSRS then
|
|
78340
|
+
self.path=lfs.tempdir().."Mission\\l10n\\DEFAULT"
|
|
78341
|
+
else
|
|
78342
|
+
self.path="l10n/DEFAULT/"
|
|
78343
|
+
end
|
|
78344
|
+
else
|
|
78345
|
+
self.path=Path
|
|
77136
78346
|
end
|
|
77137
78347
|
local nmax=1000;local n=1
|
|
77138
78348
|
while(self.path:sub(-1)=="/"or self.path:sub(-1)==[[\]])and n<=nmax do
|
|
@@ -77140,6 +78350,7 @@ self.path=self.path:sub(1,#self.path-1)
|
|
|
77140
78350
|
n=n+1
|
|
77141
78351
|
end
|
|
77142
78352
|
self.path=self.path.."/"
|
|
78353
|
+
self:T("self.path="..self.path)
|
|
77143
78354
|
return self
|
|
77144
78355
|
end
|
|
77145
78356
|
function SOUNDFILE:GetPath()
|
|
@@ -77167,11 +78378,13 @@ local name=string.format("%s%s",path,filename)
|
|
|
77167
78378
|
return name
|
|
77168
78379
|
end
|
|
77169
78380
|
function SOUNDFILE:SetPlayWithSRS(Switch)
|
|
78381
|
+
self:F({Switch})
|
|
77170
78382
|
if Switch==true or Switch==nil then
|
|
77171
78383
|
self.useSRS=true
|
|
77172
78384
|
else
|
|
77173
78385
|
self.useSRS=false
|
|
77174
78386
|
end
|
|
78387
|
+
self:T("self.useSRS="..tostring(self.useSRS))
|
|
77175
78388
|
return self
|
|
77176
78389
|
end
|
|
77177
78390
|
end
|
|
@@ -77935,6 +79148,7 @@ ClassName="MSRS",
|
|
|
77935
79148
|
lid=nil,
|
|
77936
79149
|
port=5002,
|
|
77937
79150
|
name="MSRS",
|
|
79151
|
+
backend="srsexe",
|
|
77938
79152
|
frequencies={},
|
|
77939
79153
|
modulations={},
|
|
77940
79154
|
coalition=0,
|
|
@@ -77944,13 +79158,14 @@ voice=nil,
|
|
|
77944
79158
|
volume=1,
|
|
77945
79159
|
speed=1,
|
|
77946
79160
|
coordinate=nil,
|
|
79161
|
+
provider="win",
|
|
77947
79162
|
Label="ROBOT",
|
|
77948
|
-
AltBackend=nil,
|
|
77949
79163
|
ConfigFileName="Moose_MSRS.lua",
|
|
77950
79164
|
ConfigFilePath="Config\\",
|
|
77951
79165
|
ConfigLoaded=false,
|
|
79166
|
+
poptions={},
|
|
77952
79167
|
}
|
|
77953
|
-
MSRS.version="0.
|
|
79168
|
+
MSRS.version="0.3.0"
|
|
77954
79169
|
MSRS.Voices={
|
|
77955
79170
|
Microsoft={
|
|
77956
79171
|
["Hedda"]="Microsoft Hedda Desktop",
|
|
@@ -78049,48 +79264,52 @@ Wavenet={
|
|
|
78049
79264
|
},
|
|
78050
79265
|
},
|
|
78051
79266
|
}
|
|
78052
|
-
MSRS.
|
|
78053
|
-
|
|
78054
|
-
|
|
78055
|
-
|
|
78056
|
-
MSRS.
|
|
78057
|
-
|
|
78058
|
-
|
|
78059
|
-
|
|
78060
|
-
|
|
79267
|
+
MSRS.Backend={
|
|
79268
|
+
SRSEXE="srsexe",
|
|
79269
|
+
GRPC="grpc",
|
|
79270
|
+
}
|
|
79271
|
+
MSRS.Provider={
|
|
79272
|
+
WINDOWS="win",
|
|
79273
|
+
GOOGLE="gcloud",
|
|
79274
|
+
AZURE="azure",
|
|
79275
|
+
AMAZON="aws",
|
|
79276
|
+
}
|
|
79277
|
+
function MSRS.uuid()
|
|
79278
|
+
local random=math.random
|
|
79279
|
+
local template='yxxx-xxxxxxxxxxxx'
|
|
79280
|
+
return string.gsub(template,'[xy]',function(c)
|
|
79281
|
+
local v=(c=='x')and random(0,0xf)or random(8,0xb)
|
|
79282
|
+
return string.format('%x',v)
|
|
79283
|
+
end)
|
|
79284
|
+
end
|
|
79285
|
+
function MSRS:New(Path,Frequency,Modulation,Backend)
|
|
79286
|
+
local self=BASE:Inherit(self,BASE:New())
|
|
79287
|
+
self:F({Path,Frequency,Modulation,Backend})
|
|
78061
79288
|
Frequency=Frequency or 143
|
|
78062
79289
|
Modulation=Modulation or radio.modulation.AM
|
|
78063
|
-
|
|
78064
|
-
if
|
|
78065
|
-
|
|
78066
|
-
Backend.Vars=Backend.Vars or{}
|
|
78067
|
-
Backend.Vars.PathToSRS=PathToSRS
|
|
78068
|
-
Backend.Vars.Frequency=UTILS.DeepCopy(Frequency)
|
|
78069
|
-
Backend.Vars.Modulation=UTILS.DeepCopy(Modulation)
|
|
78070
|
-
Backend.Vars.Volume=Volume
|
|
78071
|
-
Backend.Functions=Backend.Functions or{}
|
|
78072
|
-
return self:_NewAltBackend(Backend)
|
|
78073
|
-
end
|
|
78074
|
-
local success=self:LoadConfigFile(nil,nil,self.ConfigLoaded)
|
|
78075
|
-
if(not success)and(not self.ConfigLoaded)then
|
|
78076
|
-
self:SetPath(PathToSRS)
|
|
79290
|
+
self.lid=string.format("%s-%s | ","unknown",self.version)
|
|
79291
|
+
if not self.ConfigLoaded then
|
|
79292
|
+
self:SetPath(Path)
|
|
78077
79293
|
self:SetPort()
|
|
78078
79294
|
self:SetFrequencies(Frequency)
|
|
78079
79295
|
self:SetModulations(Modulation)
|
|
78080
79296
|
self:SetGender()
|
|
78081
79297
|
self:SetCoalition()
|
|
78082
79298
|
self:SetLabel()
|
|
78083
|
-
self:SetVolume(
|
|
79299
|
+
self:SetVolume()
|
|
79300
|
+
self:SetBackend(Backend)
|
|
78084
79301
|
else
|
|
78085
|
-
if
|
|
78086
|
-
self:SetPath(
|
|
79302
|
+
if Path then
|
|
79303
|
+
self:SetPath(Path)
|
|
78087
79304
|
end
|
|
78088
79305
|
if Frequency then
|
|
78089
79306
|
self:SetFrequencies(Frequency)
|
|
79307
|
+
end
|
|
79308
|
+
if Modulation then
|
|
78090
79309
|
self:SetModulations(Modulation)
|
|
78091
79310
|
end
|
|
78092
|
-
if
|
|
78093
|
-
self:
|
|
79311
|
+
if Backend then
|
|
79312
|
+
self:SetBackend(Backend)
|
|
78094
79313
|
end
|
|
78095
79314
|
end
|
|
78096
79315
|
self.lid=string.format("%s-%s | ",self.name,self.version)
|
|
@@ -78099,26 +79318,48 @@ self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
|
|
|
78099
79318
|
end
|
|
78100
79319
|
return self
|
|
78101
79320
|
end
|
|
78102
|
-
function MSRS:
|
|
78103
|
-
|
|
78104
|
-
self
|
|
78105
|
-
return
|
|
79321
|
+
function MSRS:SetBackend(Backend)
|
|
79322
|
+
self:F({Backend=Backend})
|
|
79323
|
+
self.backend=Backend or MSRS.Backend.SRSEXE
|
|
79324
|
+
return self
|
|
78106
79325
|
end
|
|
78107
|
-
|
|
78108
|
-
self
|
|
79326
|
+
function MSRS:SetBackendGRPC()
|
|
79327
|
+
self:F()
|
|
79328
|
+
self:SetBackend(MSRS.Backend.GRPC)
|
|
79329
|
+
return self
|
|
79330
|
+
end
|
|
79331
|
+
function MSRS:SetBackendSRSEXE()
|
|
79332
|
+
self:F()
|
|
79333
|
+
self:SetBackend(MSRS.Backend.SRSEXE)
|
|
79334
|
+
return self
|
|
79335
|
+
end
|
|
79336
|
+
function MSRS.SetDefaultBackend(Backend)
|
|
79337
|
+
self:F({Backend=Backend})
|
|
79338
|
+
MSRS.backend=Backend or MSRS.Backend.SRSEXE
|
|
79339
|
+
end
|
|
79340
|
+
function MSRS.SetDefaultBackendGRPC()
|
|
79341
|
+
self:F()
|
|
79342
|
+
MSRS.backend=MSRS.Backend.GRPC
|
|
79343
|
+
end
|
|
79344
|
+
function MSRS:GetBackend()
|
|
79345
|
+
return self.backend
|
|
79346
|
+
end
|
|
79347
|
+
function MSRS:SetPath(Path)
|
|
79348
|
+
self:F({Path=Path})
|
|
79349
|
+
self.path=Path or"C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
|
78109
79350
|
local n=1;local nmax=1000
|
|
78110
79351
|
while(self.path:sub(-1)=="/"or self.path:sub(-1)==[[\]])and n<=nmax do
|
|
78111
79352
|
self.path=self.path:sub(1,#self.path-1)
|
|
78112
79353
|
n=n+1
|
|
78113
79354
|
end
|
|
78114
|
-
self:
|
|
78115
|
-
end
|
|
79355
|
+
self:F(string.format("SRS path=%s",self:GetPath()))
|
|
78116
79356
|
return self
|
|
78117
79357
|
end
|
|
78118
79358
|
function MSRS:GetPath()
|
|
78119
79359
|
return self.path
|
|
78120
79360
|
end
|
|
78121
79361
|
function MSRS:SetVolume(Volume)
|
|
79362
|
+
self:F({Volume=Volume})
|
|
78122
79363
|
local volume=Volume or 1
|
|
78123
79364
|
if volume>1 then volume=1 elseif volume<0 then volume=0 end
|
|
78124
79365
|
self.volume=volume
|
|
@@ -78128,6 +79369,7 @@ function MSRS:GetVolume()
|
|
|
78128
79369
|
return self.volume
|
|
78129
79370
|
end
|
|
78130
79371
|
function MSRS:SetLabel(Label)
|
|
79372
|
+
self:F({Label=Label})
|
|
78131
79373
|
self.Label=Label or"ROBOT"
|
|
78132
79374
|
return self
|
|
78133
79375
|
end
|
|
@@ -78135,13 +79377,16 @@ function MSRS:GetLabel()
|
|
|
78135
79377
|
return self.Label
|
|
78136
79378
|
end
|
|
78137
79379
|
function MSRS:SetPort(Port)
|
|
79380
|
+
self:F({Port=Port})
|
|
78138
79381
|
self.port=Port or 5002
|
|
79382
|
+
self:T(string.format("SRS port=%s",self:GetPort()))
|
|
78139
79383
|
return self
|
|
78140
79384
|
end
|
|
78141
79385
|
function MSRS:GetPort()
|
|
78142
79386
|
return self.port
|
|
78143
79387
|
end
|
|
78144
79388
|
function MSRS:SetCoalition(Coalition)
|
|
79389
|
+
self:F({Coalition=Coalition})
|
|
78145
79390
|
self.coalition=Coalition or 0
|
|
78146
79391
|
return self
|
|
78147
79392
|
end
|
|
@@ -78149,17 +79394,14 @@ function MSRS:GetCoalition()
|
|
|
78149
79394
|
return self.coalition
|
|
78150
79395
|
end
|
|
78151
79396
|
function MSRS:SetFrequencies(Frequencies)
|
|
78152
|
-
|
|
78153
|
-
|
|
78154
|
-
end
|
|
78155
|
-
self.frequencies=Frequencies
|
|
79397
|
+
self:F(Frequencies)
|
|
79398
|
+
self.frequencies=UTILS.EnsureTable(Frequencies,false)
|
|
78156
79399
|
return self
|
|
78157
79400
|
end
|
|
78158
79401
|
function MSRS:AddFrequencies(Frequencies)
|
|
78159
|
-
|
|
78160
|
-
Frequencies
|
|
78161
|
-
|
|
78162
|
-
for _,_freq in pairs(Frequencies)do
|
|
79402
|
+
self:F(Frequencies)
|
|
79403
|
+
for _,_freq in pairs(UTILS.EnsureTable(Frequencies,false))do
|
|
79404
|
+
self:T(self.lid..string.format("Adding frequency %s",tostring(_freq)))
|
|
78163
79405
|
table.insert(self.frequencies,_freq)
|
|
78164
79406
|
end
|
|
78165
79407
|
return self
|
|
@@ -78168,17 +79410,15 @@ function MSRS:GetFrequencies()
|
|
|
78168
79410
|
return self.frequencies
|
|
78169
79411
|
end
|
|
78170
79412
|
function MSRS:SetModulations(Modulations)
|
|
78171
|
-
|
|
78172
|
-
|
|
78173
|
-
|
|
78174
|
-
self.modulations
|
|
79413
|
+
self:F(Modulations)
|
|
79414
|
+
self.modulations=UTILS.EnsureTable(Modulations,false)
|
|
79415
|
+
self:T(self.lid.."Modulations:")
|
|
79416
|
+
self:T(self.modulations)
|
|
78175
79417
|
return self
|
|
78176
79418
|
end
|
|
78177
79419
|
function MSRS:AddModulations(Modulations)
|
|
78178
|
-
|
|
78179
|
-
Modulations
|
|
78180
|
-
end
|
|
78181
|
-
for _,_mod in pairs(Modulations)do
|
|
79420
|
+
self:F(Modulations)
|
|
79421
|
+
for _,_mod in pairs(UTILS.EnsureTable(Modulations,false))do
|
|
78182
79422
|
table.insert(self.modulations,_mod)
|
|
78183
79423
|
end
|
|
78184
79424
|
return self
|
|
@@ -78187,83 +79427,176 @@ function MSRS:GetModulations()
|
|
|
78187
79427
|
return self.modulations
|
|
78188
79428
|
end
|
|
78189
79429
|
function MSRS:SetGender(Gender)
|
|
79430
|
+
self:F({Gender=Gender})
|
|
78190
79431
|
Gender=Gender or"female"
|
|
78191
79432
|
self.gender=Gender:lower()
|
|
78192
79433
|
self:T("Setting gender to "..tostring(self.gender))
|
|
78193
79434
|
return self
|
|
78194
79435
|
end
|
|
78195
79436
|
function MSRS:SetCulture(Culture)
|
|
79437
|
+
self:F({Culture=Culture})
|
|
78196
79438
|
self.culture=Culture
|
|
78197
79439
|
return self
|
|
78198
79440
|
end
|
|
78199
79441
|
function MSRS:SetVoice(Voice)
|
|
79442
|
+
self:F({Voice=Voice})
|
|
78200
79443
|
self.voice=Voice
|
|
78201
79444
|
return self
|
|
78202
79445
|
end
|
|
78203
|
-
function MSRS:
|
|
78204
|
-
self
|
|
78205
|
-
|
|
78206
|
-
self.
|
|
79446
|
+
function MSRS:SetVoiceProvider(Voice,Provider)
|
|
79447
|
+
self:F({Voice=Voice,Provider=Provider})
|
|
79448
|
+
self.poptions=self.poptions or{}
|
|
79449
|
+
self.poptions[Provider or self:GetProvider()]=Voice
|
|
79450
|
+
return self
|
|
79451
|
+
end
|
|
79452
|
+
function MSRS:SetVoiceWindows(Voice)
|
|
79453
|
+
self:F({Voice=Voice})
|
|
79454
|
+
self:SetVoiceProvider(Voice or"Microsoft Hazel Desktop",MSRS.Provider.WINDOWS)
|
|
78207
79455
|
return self
|
|
78208
79456
|
end
|
|
79457
|
+
function MSRS:SetVoiceGoogle(Voice)
|
|
79458
|
+
self:F({Voice=Voice})
|
|
79459
|
+
self:SetVoiceProvider(Voice or MSRS.Voices.Google.Standard.en_GB_Standard_A,MSRS.Provider.GOOGLE)
|
|
79460
|
+
return self
|
|
79461
|
+
end
|
|
79462
|
+
function MSRS:SetVoiceAzure(Voice)
|
|
79463
|
+
self:F({Voice=Voice})
|
|
79464
|
+
self:SetVoiceProvider(Voice or"en-US-AriaNeural",MSRS.Provider.AZURE)
|
|
79465
|
+
return self
|
|
79466
|
+
end
|
|
79467
|
+
function MSRS:SetVoiceAmazon(Voice)
|
|
79468
|
+
self:F({Voice=Voice})
|
|
79469
|
+
self:SetVoiceProvider(Voice or"Brian",MSRS.Provider.AMAZON)
|
|
79470
|
+
return self
|
|
79471
|
+
end
|
|
79472
|
+
function MSRS:GetVoice(Provider)
|
|
79473
|
+
Provider=Provider or self.provider
|
|
79474
|
+
if Provider and self.poptions[Provider]and self.poptions[Provider].voice then
|
|
79475
|
+
return self.poptions[Provider].voice
|
|
79476
|
+
else
|
|
79477
|
+
return self.voice
|
|
79478
|
+
end
|
|
79479
|
+
end
|
|
78209
79480
|
function MSRS:SetCoordinate(Coordinate)
|
|
79481
|
+
self:F(Coordinate)
|
|
78210
79482
|
self.coordinate=Coordinate
|
|
78211
79483
|
return self
|
|
78212
79484
|
end
|
|
78213
79485
|
function MSRS:SetGoogle(PathToCredentials)
|
|
79486
|
+
self:F({PathToCredentials=PathToCredentials})
|
|
78214
79487
|
if PathToCredentials then
|
|
78215
|
-
self.
|
|
78216
|
-
self
|
|
78217
|
-
self.provider="gcloud"
|
|
78218
|
-
self.GRPCOptions.DefaultProvider="gcloud"
|
|
78219
|
-
self.GRPCOptions.gcloud.key=PathToCredentials
|
|
79488
|
+
self.provider=MSRS.Provider.GOOGLE
|
|
79489
|
+
self:SetProviderOptionsGoogle(PathToCredentials,PathToCredentials)
|
|
78220
79490
|
end
|
|
78221
79491
|
return self
|
|
78222
79492
|
end
|
|
78223
79493
|
function MSRS:SetGoogleAPIKey(APIKey)
|
|
79494
|
+
self:F({APIKey=APIKey})
|
|
78224
79495
|
if APIKey then
|
|
78225
|
-
self.
|
|
78226
|
-
self.
|
|
78227
|
-
self.
|
|
78228
|
-
|
|
79496
|
+
self.provider=MSRS.Provider.GOOGLE
|
|
79497
|
+
if self.poptions[MSRS.Provider.GOOGLE]then
|
|
79498
|
+
self.poptions[MSRS.Provider.GOOGLE].key=APIKey
|
|
79499
|
+
else
|
|
79500
|
+
self:SetProviderOptionsGoogle(nil,APIKey)
|
|
79501
|
+
end
|
|
79502
|
+
end
|
|
79503
|
+
return self
|
|
79504
|
+
end
|
|
79505
|
+
function MSRS:SetProvider(Provider)
|
|
79506
|
+
self:F({Provider=Provider})
|
|
79507
|
+
self.provider=Provider or MSRS.Provider.WINDOWS
|
|
79508
|
+
return self
|
|
79509
|
+
end
|
|
79510
|
+
function MSRS:GetProvider()
|
|
79511
|
+
return self.provider or MSRS.Provider.WINDOWS
|
|
79512
|
+
end
|
|
79513
|
+
function MSRS:SetProviderOptions(Provider,CredentialsFile,AccessKey,SecretKey,Region)
|
|
79514
|
+
self:F({Provider,CredentialsFile,AccessKey,SecretKey,Region})
|
|
79515
|
+
local option=MSRS._CreateProviderOptions(Provider,CredentialsFile,AccessKey,SecretKey,Region)
|
|
79516
|
+
if self then
|
|
79517
|
+
self.poptions=self.poptions or{}
|
|
79518
|
+
self.poptions[Provider]=option
|
|
79519
|
+
else
|
|
79520
|
+
MSRS.poptions=MSRS.poptions or{}
|
|
79521
|
+
MSRS.poptions[Provider]=option
|
|
79522
|
+
end
|
|
79523
|
+
return option
|
|
79524
|
+
end
|
|
79525
|
+
function MSRS._CreateProviderOptions(Provider,CredentialsFile,AccessKey,SecretKey,Region)
|
|
79526
|
+
self:F({Provider,CredentialsFile,AccessKey,SecretKey,Region})
|
|
79527
|
+
local option={}
|
|
79528
|
+
option.provider=Provider
|
|
79529
|
+
option.credentials=CredentialsFile
|
|
79530
|
+
option.key=AccessKey
|
|
79531
|
+
option.secret=SecretKey
|
|
79532
|
+
option.region=Region
|
|
79533
|
+
return option
|
|
79534
|
+
end
|
|
79535
|
+
function MSRS:SetProviderOptionsGoogle(CredentialsFile,AccessKey)
|
|
79536
|
+
self:F({CredentialsFile,AccessKey})
|
|
79537
|
+
self:SetProviderOptions(MSRS.Provider.GOOGLE,CredentialsFile,AccessKey)
|
|
79538
|
+
return self
|
|
79539
|
+
end
|
|
79540
|
+
function MSRS:SetProviderOptionsAmazon(AccessKey,SecretKey,Region)
|
|
79541
|
+
self:F({AccessKey,SecretKey,Region})
|
|
79542
|
+
self:SetProviderOptions(MSRS.Provider.AMAZON,nil,AccessKey,SecretKey,Region)
|
|
79543
|
+
return self
|
|
78229
79544
|
end
|
|
79545
|
+
function MSRS:SetProviderOptionsAzure(AccessKey,Region)
|
|
79546
|
+
self:F({AccessKey,Region})
|
|
79547
|
+
self:SetProviderOptions(MSRS.Provider.AZURE,nil,AccessKey,nil,Region)
|
|
79548
|
+
return self
|
|
79549
|
+
end
|
|
79550
|
+
function MSRS:GetProviderOptions(Provider)
|
|
79551
|
+
return self.poptions[Provider or self.provider]or{}
|
|
79552
|
+
end
|
|
79553
|
+
function MSRS:SetTTSProviderGoogle()
|
|
79554
|
+
self:F()
|
|
79555
|
+
self:SetProvider(MSRS.Provider.GOOGLE)
|
|
79556
|
+
return self
|
|
79557
|
+
end
|
|
79558
|
+
function MSRS:SetTTSProviderMicrosoft()
|
|
79559
|
+
self:F()
|
|
79560
|
+
self:SetProvider(MSRS.Provider.WINDOWS)
|
|
79561
|
+
return self
|
|
79562
|
+
end
|
|
79563
|
+
function MSRS:SetTTSProviderAzure()
|
|
79564
|
+
self:F()
|
|
79565
|
+
self:SetProvider(MSRS.Provider.AZURE)
|
|
79566
|
+
return self
|
|
79567
|
+
end
|
|
79568
|
+
function MSRS:SetTTSProviderAmazon()
|
|
79569
|
+
self:F()
|
|
79570
|
+
self:SetProvider(MSRS.Provider.AMAZON)
|
|
78230
79571
|
return self
|
|
78231
79572
|
end
|
|
78232
79573
|
function MSRS:Help()
|
|
78233
|
-
|
|
78234
|
-
local
|
|
78235
|
-
local
|
|
79574
|
+
self:F()
|
|
79575
|
+
local path=self:GetPath()
|
|
79576
|
+
local exe="DCS-SR-ExternalAudio.exe"
|
|
79577
|
+
local filename=os.getenv('TMP').."\\MSRS-help-"..MSRS.uuid()..".txt"
|
|
78236
79578
|
local command=string.format("%s/%s --help > %s",path,exe,filename)
|
|
78237
79579
|
os.execute(command)
|
|
78238
79580
|
local f=assert(io.open(filename,"rb"))
|
|
78239
79581
|
local data=f:read("*all")
|
|
78240
79582
|
f:close()
|
|
78241
|
-
env.info("SRS
|
|
79583
|
+
env.info("SRS help output:")
|
|
78242
79584
|
env.info("======================================================================")
|
|
78243
79585
|
env.info(data)
|
|
78244
79586
|
env.info("======================================================================")
|
|
78245
79587
|
return self
|
|
78246
79588
|
end
|
|
78247
|
-
function MSRS.SetDefaultBackend(Backend)
|
|
78248
|
-
if type(Backend)=="table"then
|
|
78249
|
-
MSRS.AltBackend=UTILS.DeepCopy(Backend)
|
|
78250
|
-
else
|
|
78251
|
-
return false
|
|
78252
|
-
end
|
|
78253
|
-
return true
|
|
78254
|
-
end
|
|
78255
|
-
function MSRS.ResetDefaultBackend()
|
|
78256
|
-
MSRS.AltBackend=nil
|
|
78257
|
-
return true
|
|
78258
|
-
end
|
|
78259
|
-
function MSRS.SetDefaultBackendGRPC()
|
|
78260
|
-
return MSRS.SetDefaultBackend(MSRS_BACKEND_DCSGRPC)
|
|
78261
|
-
end
|
|
78262
79589
|
function MSRS:PlaySoundFile(Soundfile,Delay)
|
|
79590
|
+
self:F({Soundfile,Delay})
|
|
79591
|
+
local soundfile=Soundfile:GetName()
|
|
79592
|
+
local exists=UTILS.FileExists(soundfile)
|
|
79593
|
+
if not exists then
|
|
79594
|
+
self:E("ERROR: MSRS sound file does not exist! File="..soundfile)
|
|
79595
|
+
return self
|
|
79596
|
+
end
|
|
78263
79597
|
if Delay and Delay>0 then
|
|
78264
79598
|
self:ScheduleOnce(Delay,MSRS.PlaySoundFile,self,Soundfile,0)
|
|
78265
79599
|
else
|
|
78266
|
-
local soundfile=Soundfile:GetName()
|
|
78267
79600
|
local command=self:_GetCommand()
|
|
78268
79601
|
command=command..' --file="'..tostring(soundfile)..'"'
|
|
78269
79602
|
self:_ExecCommand(command)
|
|
@@ -78271,42 +79604,53 @@ end
|
|
|
78271
79604
|
return self
|
|
78272
79605
|
end
|
|
78273
79606
|
function MSRS:PlaySoundText(SoundText,Delay)
|
|
79607
|
+
self:F({SoundText,Delay})
|
|
78274
79608
|
if Delay and Delay>0 then
|
|
78275
79609
|
self:ScheduleOnce(Delay,MSRS.PlaySoundText,self,SoundText,0)
|
|
78276
79610
|
else
|
|
79611
|
+
if self.backend==MSRS.Backend.GRPC then
|
|
79612
|
+
self:_DCSgRPCtts(SoundText.text,nil,SoundText.gender,SoundText.culture,SoundText.voice,SoundText.volume,SoundText.label,SoundText.coordinate)
|
|
79613
|
+
else
|
|
78277
79614
|
local command=self:_GetCommand(nil,nil,nil,SoundText.gender,SoundText.voice,SoundText.culture,SoundText.volume,SoundText.speed)
|
|
78278
79615
|
command=command..string.format(" --text=\"%s\"",tostring(SoundText.text))
|
|
78279
79616
|
self:_ExecCommand(command)
|
|
78280
79617
|
end
|
|
79618
|
+
end
|
|
78281
79619
|
return self
|
|
78282
79620
|
end
|
|
78283
79621
|
function MSRS:PlayText(Text,Delay,Coordinate)
|
|
79622
|
+
self:F({Text,Delay,Coordinate})
|
|
78284
79623
|
if Delay and Delay>0 then
|
|
78285
79624
|
self:ScheduleOnce(Delay,MSRS.PlayText,self,Text,nil,Coordinate)
|
|
78286
79625
|
else
|
|
78287
|
-
|
|
78288
|
-
|
|
78289
|
-
self:
|
|
79626
|
+
if self.backend==MSRS.Backend.GRPC then
|
|
79627
|
+
self:T(self.lid.."Transmitting")
|
|
79628
|
+
self:_DCSgRPCtts(Text,nil,nil,nil,nil,nil,nil,Coordinate)
|
|
79629
|
+
else
|
|
79630
|
+
self:PlayTextExt(Text,Delay,nil,nil,nil,nil,nil,nil,nil,Coordinate)
|
|
79631
|
+
end
|
|
78290
79632
|
end
|
|
78291
79633
|
return self
|
|
78292
79634
|
end
|
|
78293
79635
|
function MSRS:PlayTextExt(Text,Delay,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label,Coordinate)
|
|
79636
|
+
self:F({Text,Delay,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label,Coordinate})
|
|
78294
79637
|
if Delay and Delay>0 then
|
|
78295
79638
|
self:ScheduleOnce(Delay,MSRS.PlayTextExt,self,Text,0,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label,Coordinate)
|
|
78296
79639
|
else
|
|
78297
|
-
|
|
78298
|
-
|
|
78299
|
-
|
|
78300
|
-
|
|
78301
|
-
Modulations={Modulations}
|
|
78302
|
-
end
|
|
78303
|
-
local command=self:_GetCommand(Frequencies,Modulations,nil,Gender,Voice,Culture,Volume,nil,nil,Label,Coordinate)
|
|
79640
|
+
Frequencies=Frequencies or self:GetFrequencies()
|
|
79641
|
+
Modulations=Modulations or self:GetModulations()
|
|
79642
|
+
if self.backend==MSRS.Backend.SRSEXE then
|
|
79643
|
+
local command=self:_GetCommand(UTILS.EnsureTable(Frequencies,false),UTILS.EnsureTable(Modulations,false),nil,Gender,Voice,Culture,Volume,nil,nil,Label,Coordinate)
|
|
78304
79644
|
command=command..string.format(" --text=\"%s\"",tostring(Text))
|
|
78305
79645
|
self:_ExecCommand(command)
|
|
79646
|
+
elseif self.backend==MSRS.Backend.GRPC then
|
|
79647
|
+
self:_DCSgRPCtts(Text,Frequencies,Gender,Culture,Voice,Volume,Label,Coordinate)
|
|
79648
|
+
end
|
|
78306
79649
|
end
|
|
78307
79650
|
return self
|
|
78308
79651
|
end
|
|
78309
79652
|
function MSRS:PlayTextFile(TextFile,Delay)
|
|
79653
|
+
self:F({TextFile,Delay})
|
|
78310
79654
|
if Delay and Delay>0 then
|
|
78311
79655
|
self:ScheduleOnce(Delay,MSRS.PlayTextFile,self,TextFile,0)
|
|
78312
79656
|
else
|
|
@@ -78319,51 +79663,96 @@ local command=self:_GetCommand()
|
|
|
78319
79663
|
command=command..string.format(" --textFile=\"%s\"",tostring(TextFile))
|
|
78320
79664
|
self:T(string.format("MSRS TextFile command=%s",command))
|
|
78321
79665
|
local l=string.len(command)
|
|
79666
|
+
self:T(string.format("Command length=%d",l))
|
|
78322
79667
|
self:_ExecCommand(command)
|
|
78323
79668
|
end
|
|
78324
79669
|
return self
|
|
78325
79670
|
end
|
|
78326
|
-
function MSRS:
|
|
78327
|
-
|
|
78328
|
-
|
|
78329
|
-
|
|
78330
|
-
|
|
78331
|
-
|
|
79671
|
+
function MSRS:_GetLatLongAlt(Coordinate)
|
|
79672
|
+
self:F({Coordinate=Coordinate})
|
|
79673
|
+
local lat=0.0
|
|
79674
|
+
local lon=0.0
|
|
79675
|
+
local alt=0.0
|
|
79676
|
+
if Coordinate then
|
|
79677
|
+
lat,lon,alt=coord.LOtoLL(Coordinate)
|
|
79678
|
+
end
|
|
79679
|
+
return lat,lon,math.floor(alt)
|
|
79680
|
+
end
|
|
79681
|
+
function MSRS:_GetCommand(freqs,modus,coal,gender,voice,culture,volume,speed,port,label,coordinate)
|
|
79682
|
+
self:F({freqs,modus,coal,gender,voice,culture,volume,speed,port,label,coordinate})
|
|
79683
|
+
local path=self:GetPath()
|
|
79684
|
+
local exe="DCS-SR-ExternalAudio.exe"
|
|
79685
|
+
local fullPath=string.format("%s\\%s",path,exe)
|
|
79686
|
+
freqs=table.concat(freqs or self.frequencies,",")
|
|
79687
|
+
modus=table.concat(modus or self.modulations,",")
|
|
79688
|
+
coal=coal or self.coalition
|
|
79689
|
+
gender=gender or self.gender
|
|
79690
|
+
voice=voice or self:GetVoice(self.provider)or self.voice
|
|
79691
|
+
culture=culture or self.culture
|
|
79692
|
+
volume=volume or self.volume
|
|
79693
|
+
speed=speed or self.speed
|
|
79694
|
+
port=port or self.port
|
|
79695
|
+
label=label or self.Label
|
|
79696
|
+
coordinate=coordinate or self.coordinate
|
|
79697
|
+
modus=modus:gsub("0","AM")
|
|
79698
|
+
modus=modus:gsub("1","FM")
|
|
79699
|
+
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"',path,exe,freqs,modus,coal,port,label,volume)
|
|
79700
|
+
if voice then
|
|
79701
|
+
command=command..string.format(" --voice=\"%s\"",tostring(voice))
|
|
79702
|
+
else
|
|
79703
|
+
if gender and gender~="female"then
|
|
79704
|
+
command=command..string.format(" -g %s",tostring(gender))
|
|
79705
|
+
end
|
|
79706
|
+
if culture and culture~="en-GB"then
|
|
79707
|
+
command=command..string.format(" -l %s",tostring(culture))
|
|
78332
79708
|
end
|
|
78333
79709
|
end
|
|
78334
|
-
|
|
78335
|
-
|
|
78336
|
-
|
|
79710
|
+
if coordinate then
|
|
79711
|
+
local lat,lon,alt=self:_GetLatLongAlt(coordinate)
|
|
79712
|
+
command=command..string.format(" -L %.4f -O %.4f -A %d",lat,lon,alt)
|
|
78337
79713
|
end
|
|
78338
|
-
if self.
|
|
78339
|
-
|
|
79714
|
+
if self.provider==MSRS.Provider.GOOGLE then
|
|
79715
|
+
local pops=self:GetProviderOptions()
|
|
79716
|
+
command=command..string.format(' --ssml -G "%s"',pops.credentials)
|
|
79717
|
+
elseif self.provider==MSRS.Provider.WINDOWS then
|
|
79718
|
+
else
|
|
79719
|
+
self:E("ERROR: SRS only supports WINWOWS and GOOGLE as TTS providers! Use DCS-gRPC backend for other providers such as ")
|
|
78340
79720
|
end
|
|
78341
|
-
|
|
79721
|
+
if not UTILS.FileExists(fullPath)then
|
|
79722
|
+
self:E("ERROR: MSRS SRS executable does not exist! FullPath="..fullPath)
|
|
79723
|
+
command="CommandNotFound"
|
|
79724
|
+
end
|
|
79725
|
+
self:T("MSRS command from _GetCommand="..command)
|
|
79726
|
+
return command
|
|
78342
79727
|
end
|
|
78343
79728
|
function MSRS:_ExecCommand(command)
|
|
78344
|
-
self:
|
|
78345
|
-
|
|
79729
|
+
self:F({command=command})
|
|
79730
|
+
if string.find(command,"CommandNotFound")then return 0 end
|
|
79731
|
+
local batContent=command.." && exit"
|
|
79732
|
+
local filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".bat"
|
|
78346
79733
|
local script=io.open(filename,"w+")
|
|
78347
|
-
script:write(
|
|
79734
|
+
script:write(batContent)
|
|
78348
79735
|
script:close()
|
|
78349
|
-
|
|
79736
|
+
self:T("MSRS batch file created: "..filename)
|
|
79737
|
+
self:T("MSRS batch content: "..batContent)
|
|
78350
79738
|
local res=nil
|
|
78351
79739
|
if true then
|
|
78352
|
-
local filenvbs=os.getenv('TMP').."\\MSRS-"..
|
|
79740
|
+
local filenvbs=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".vbs"
|
|
78353
79741
|
local script=io.open(filenvbs,"w+")
|
|
78354
79742
|
script:write(string.format('Dim WinScriptHost\n'))
|
|
78355
79743
|
script:write(string.format('Set WinScriptHost = CreateObject("WScript.Shell")\n'))
|
|
78356
79744
|
script:write(string.format('WinScriptHost.Run Chr(34) & "%s" & Chr(34), 0\n',filename))
|
|
78357
79745
|
script:write(string.format('Set WinScriptHost = Nothing'))
|
|
78358
79746
|
script:close()
|
|
79747
|
+
self:T("MSRS vbs file created to start batch="..filenvbs)
|
|
78359
79748
|
local runvbs=string.format('cscript.exe //Nologo //B "%s"',filenvbs)
|
|
78360
|
-
self:T("MSRS execute command="..command)
|
|
78361
79749
|
self:T("MSRS execute VBS command="..runvbs)
|
|
78362
79750
|
res=os.execute(runvbs)
|
|
78363
79751
|
timer.scheduleFunction(os.remove,filename,timer.getTime()+1)
|
|
78364
79752
|
timer.scheduleFunction(os.remove,filenvbs,timer.getTime()+1)
|
|
79753
|
+
self:T("MSRS vbs and batch file removed")
|
|
78365
79754
|
elseif false then
|
|
78366
|
-
local filenvbs=os.getenv('TMP').."\\MSRS-"..
|
|
79755
|
+
local filenvbs=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".vbs"
|
|
78367
79756
|
local script=io.open(filenvbs,"w+")
|
|
78368
79757
|
script:write(string.format('Set oShell = CreateObject ("Wscript.Shell")\n'))
|
|
78369
79758
|
script:write(string.format('Dim strArgs\n'))
|
|
@@ -78373,261 +79762,118 @@ script:close()
|
|
|
78373
79762
|
local runvbs=string.format('cscript.exe //Nologo //B "%s"',filenvbs)
|
|
78374
79763
|
res=os.execute(runvbs)
|
|
78375
79764
|
else
|
|
79765
|
+
command=string.format('start /b "" "%s"',filename)
|
|
78376
79766
|
self:T("MSRS execute command="..command)
|
|
78377
79767
|
res=os.execute(command)
|
|
78378
79768
|
timer.scheduleFunction(os.remove,filename,timer.getTime()+1)
|
|
78379
79769
|
end
|
|
78380
79770
|
return res
|
|
78381
79771
|
end
|
|
78382
|
-
function MSRS:
|
|
78383
|
-
|
|
78384
|
-
|
|
79772
|
+
function MSRS:_DCSgRPCtts(Text,Frequencies,Gender,Culture,Voice,Volume,Label,Coordinate)
|
|
79773
|
+
self:F("MSRS_BACKEND_DCSGRPC:_DCSgRPCtts()")
|
|
79774
|
+
self:F({Text,Frequencies,Gender,Culture,Voice,Volume,Label,Coordinate})
|
|
79775
|
+
local options={}
|
|
79776
|
+
local ssml=Text or''
|
|
79777
|
+
Frequencies=UTILS.EnsureTable(Frequencies,true)or self:GetFrequencies()
|
|
79778
|
+
options.plaintext=Text
|
|
79779
|
+
options.srsClientName=Label or self.Label
|
|
79780
|
+
if self.coordinate then
|
|
79781
|
+
options.position={}
|
|
79782
|
+
options.position.lat,options.position.lon,options.position.alt=self:_GetLatLongAlt(self.coordinate)
|
|
78385
79783
|
end
|
|
78386
|
-
|
|
78387
|
-
local
|
|
78388
|
-
|
|
78389
|
-
|
|
78390
|
-
|
|
78391
|
-
|
|
78392
|
-
|
|
78393
|
-
voice=
|
|
78394
|
-
culture=culture or self.culture
|
|
78395
|
-
volume=volume or self.volume
|
|
78396
|
-
speed=speed or self.speed
|
|
78397
|
-
port=port or self.port
|
|
78398
|
-
label=label or self.Label
|
|
78399
|
-
coordinate=coordinate or self.coordinate
|
|
78400
|
-
modus=modus:gsub("0","AM")
|
|
78401
|
-
modus=modus:gsub("1","FM")
|
|
78402
|
-
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"',path,exe,freqs,modus,coal,port,label,volume)
|
|
78403
|
-
if voice then
|
|
78404
|
-
command=command..string.format(" --voice=\"%s\"",tostring(voice))
|
|
79784
|
+
options.coalition=UTILS.GetCoalitionName(self.coalition):lower()
|
|
79785
|
+
local provider=self.provider or MSRS.Provider.WINDOWS
|
|
79786
|
+
self:F({provider=provider})
|
|
79787
|
+
options.provider={}
|
|
79788
|
+
options.provider[provider]=self:GetProviderOptions(provider)
|
|
79789
|
+
Voice=Voice or self:GetVoice(self.provider)or self.voice
|
|
79790
|
+
if Voice then
|
|
79791
|
+
options.provider[provider].voice=Voice
|
|
78405
79792
|
else
|
|
78406
|
-
|
|
78407
|
-
|
|
79793
|
+
local preTag,genderProp,langProp,postTag='','','',''
|
|
79794
|
+
local gender=""
|
|
79795
|
+
if self.gender then
|
|
79796
|
+
gender=string.format(' gender=\"%s\"',self.gender)
|
|
78408
79797
|
end
|
|
78409
|
-
|
|
78410
|
-
|
|
79798
|
+
local language=""
|
|
79799
|
+
if self.culture then
|
|
79800
|
+
language=string.format(' language=\"%s\"',self.culture)
|
|
78411
79801
|
end
|
|
79802
|
+
if self.gender or self.culture then
|
|
79803
|
+
ssml=string.format("<voice%s%s>%s</voice>",gender,language,Text)
|
|
78412
79804
|
end
|
|
78413
|
-
if coordinate then
|
|
78414
|
-
local lat,lon,alt=self:_GetLatLongAlt(coordinate)
|
|
78415
|
-
command=command..string.format(" -L %.4f -O %.4f -A %d",lat,lon,alt)
|
|
78416
79805
|
end
|
|
78417
|
-
|
|
78418
|
-
|
|
79806
|
+
for _,freq in pairs(Frequencies)do
|
|
79807
|
+
self:F("Calling GRPC.tts with the following parameter:")
|
|
79808
|
+
self:F({ssml=ssml,freq=freq,options=options})
|
|
79809
|
+
self:F(options.provider[provider])
|
|
79810
|
+
GRPC.tts(ssml,freq*1e6,options)
|
|
78419
79811
|
end
|
|
78420
|
-
self:I("MSRS command="..command)
|
|
78421
|
-
return command
|
|
78422
79812
|
end
|
|
78423
|
-
function MSRS:LoadConfigFile(Path,Filename
|
|
79813
|
+
function MSRS:LoadConfigFile(Path,Filename)
|
|
79814
|
+
if lfs==nil then
|
|
79815
|
+
env.info("*****Note - lfs and os need to be desanitized for MSRS to work!")
|
|
79816
|
+
return false
|
|
79817
|
+
end
|
|
78424
79818
|
local path=Path or lfs.writedir()..MSRS.ConfigFilePath
|
|
78425
79819
|
local file=Filename or MSRS.ConfigFileName or"Moose_MSRS.lua"
|
|
78426
|
-
|
|
79820
|
+
local pathandfile=path..file
|
|
79821
|
+
local filexsists=UTILS.FileExists(pathandfile)
|
|
79822
|
+
if filexsists and not MSRS.ConfigLoaded then
|
|
79823
|
+
env.info("FF reading config file")
|
|
78427
79824
|
assert(loadfile(path..file))()
|
|
78428
79825
|
if MSRS_Config then
|
|
78429
|
-
|
|
78430
|
-
|
|
78431
|
-
|
|
78432
|
-
|
|
78433
|
-
|
|
78434
|
-
|
|
79826
|
+
local Self=self or MSRS
|
|
79827
|
+
Self.path=MSRS_Config.Path or"C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
|
79828
|
+
Self.port=MSRS_Config.Port or 5002
|
|
79829
|
+
Self.backend=MSRS_Config.Backend or MSRS.Backend.SRSEXE
|
|
79830
|
+
Self.frequencies=MSRS_Config.Frequency or{127,243}
|
|
79831
|
+
Self.modulations=MSRS_Config.Modulation or{0,0}
|
|
79832
|
+
Self.coalition=MSRS_Config.Coalition or 0
|
|
78435
79833
|
if MSRS_Config.Coordinate then
|
|
78436
|
-
|
|
78437
|
-
end
|
|
78438
|
-
self.culture=MSRS_Config.Culture or"en-GB"
|
|
78439
|
-
self.gender=MSRS_Config.Gender or"male"
|
|
78440
|
-
self.google=MSRS_Config.Google
|
|
78441
|
-
self.Label=MSRS_Config.Label or"MSRS"
|
|
78442
|
-
self.voice=MSRS_Config.Voice
|
|
78443
|
-
if MSRS_Config.GRPC then
|
|
78444
|
-
self.provider=MSRS_Config.GRPC.DefaultProvider
|
|
78445
|
-
if MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider]then
|
|
78446
|
-
self.APIKey=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].key
|
|
78447
|
-
self.defaultVoice=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].defaultVoice
|
|
78448
|
-
self.region=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].secret
|
|
78449
|
-
self.secret=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].region
|
|
78450
|
-
end
|
|
78451
|
-
end
|
|
78452
|
-
self.ConfigLoaded=true
|
|
78453
|
-
else
|
|
78454
|
-
MSRS.path=MSRS_Config.Path or"C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
|
78455
|
-
MSRS.port=MSRS_Config.Port or 5002
|
|
78456
|
-
MSRS.frequencies=MSRS_Config.Frequency or{127,243}
|
|
78457
|
-
MSRS.modulations=MSRS_Config.Modulation or{0,0}
|
|
78458
|
-
MSRS.coalition=MSRS_Config.Coalition or 0
|
|
78459
|
-
if MSRS_Config.Coordinate then
|
|
78460
|
-
MSRS.coordinate=COORDINATE:New(MSRS_Config.Coordinate[1],MSRS_Config.Coordinate[2],MSRS_Config.Coordinate[3])
|
|
79834
|
+
Self.coordinate=COORDINATE:New(MSRS_Config.Coordinate[1],MSRS_Config.Coordinate[2],MSRS_Config.Coordinate[3])
|
|
78461
79835
|
end
|
|
78462
|
-
|
|
78463
|
-
|
|
78464
|
-
|
|
78465
|
-
|
|
78466
|
-
|
|
78467
|
-
|
|
78468
|
-
|
|
78469
|
-
|
|
78470
|
-
MSRS.APIKey=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].key
|
|
78471
|
-
MSRS.defaultVoice=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].defaultVoice
|
|
78472
|
-
MSRS.region=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].secret
|
|
78473
|
-
MSRS.secret=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].region
|
|
79836
|
+
Self.culture=MSRS_Config.Culture or"en-GB"
|
|
79837
|
+
Self.gender=MSRS_Config.Gender or"male"
|
|
79838
|
+
Self.Label=MSRS_Config.Label or"MSRS"
|
|
79839
|
+
Self.voice=MSRS_Config.Voice
|
|
79840
|
+
Self.provider=MSRS_Config.Provider or MSRS.Provider.WINDOWS
|
|
79841
|
+
for _,provider in pairs(MSRS.Provider)do
|
|
79842
|
+
if MSRS_Config[provider]then
|
|
79843
|
+
Self.poptions[provider]=MSRS_Config[provider]
|
|
78474
79844
|
end
|
|
78475
79845
|
end
|
|
78476
|
-
|
|
79846
|
+
Self.ConfigLoaded=true
|
|
78477
79847
|
end
|
|
79848
|
+
env.info("MSRS - Successfully loaded default configuration from disk!",false)
|
|
78478
79849
|
end
|
|
78479
|
-
|
|
78480
|
-
|
|
78481
|
-
env.info("MSRS - Cannot load default configuration from disk!",false)
|
|
79850
|
+
if not filexsists then
|
|
79851
|
+
env.info("MSRS - Cannot find default configuration file!",false)
|
|
78482
79852
|
return false
|
|
78483
79853
|
end
|
|
78484
79854
|
return true
|
|
78485
79855
|
end
|
|
78486
|
-
|
|
78487
|
-
|
|
78488
|
-
|
|
78489
|
-
|
|
78490
|
-
|
|
78491
|
-
|
|
78492
|
-
|
|
78493
|
-
end
|
|
78494
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetPath=function(self)
|
|
78495
|
-
return self
|
|
78496
|
-
end
|
|
78497
|
-
MSRS_BACKEND_DCSGRPC.Functions.GetPath=function(self)
|
|
78498
|
-
return''
|
|
78499
|
-
end
|
|
78500
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetVolume=function(self)
|
|
78501
|
-
BASE:I('NOTE: MSRS:SetVolume() not used with DCS-gRPC backend.')
|
|
78502
|
-
return self
|
|
78503
|
-
end
|
|
78504
|
-
MSRS_BACKEND_DCSGRPC.Functions.GetVolume=function(self)
|
|
78505
|
-
BASE:I('NOTE: MSRS:GetVolume() not used with DCS-gRPC backend.')
|
|
78506
|
-
return 1
|
|
78507
|
-
end
|
|
78508
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetGender=function(self,Gender)
|
|
78509
|
-
if Gender then
|
|
78510
|
-
self.gender=Gender:lower()
|
|
78511
|
-
end
|
|
78512
|
-
self:T("Setting gender to "..tostring(self.gender))
|
|
78513
|
-
return self
|
|
78514
|
-
end
|
|
78515
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetGoogle=function(self)
|
|
78516
|
-
self.provider='gcloud'
|
|
78517
|
-
return self
|
|
78518
|
-
end
|
|
78519
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetAPIKey=function(self,key)
|
|
78520
|
-
self.APIKey=key
|
|
78521
|
-
return self
|
|
78522
|
-
end
|
|
78523
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetDefaultVoice=function(self,voice)
|
|
78524
|
-
self.defaultVoice=voice
|
|
78525
|
-
return self
|
|
78526
|
-
end
|
|
78527
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetAWS=function(self)
|
|
78528
|
-
self.provider='aws'
|
|
78529
|
-
return self
|
|
78530
|
-
end
|
|
78531
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetAzure=function(self)
|
|
78532
|
-
self.provider='azure'
|
|
78533
|
-
return self
|
|
78534
|
-
end
|
|
78535
|
-
MSRS_BACKEND_DCSGRPC.Functions.SetWin=function(self)
|
|
78536
|
-
self.provider='win'
|
|
78537
|
-
return self
|
|
78538
|
-
end
|
|
78539
|
-
MSRS_BACKEND_DCSGRPC.Functions.Help=function(self)
|
|
78540
|
-
env.info('For DCS-gRPC help, please see: https://github.com/DCS-gRPC/rust-server')
|
|
78541
|
-
return self
|
|
78542
|
-
end
|
|
78543
|
-
MSRS_BACKEND_DCSGRPC.Functions.PlaySoundFile=function(self)
|
|
78544
|
-
BASE:E("ERROR: MSRS:PlaySoundFile() is not supported by the DCS-gRPC backend.")
|
|
78545
|
-
return self
|
|
78546
|
-
end
|
|
78547
|
-
MSRS_BACKEND_DCSGRPC.Functions.PlaySoundText=function(self,SoundText,Delay)
|
|
78548
|
-
if Delay and Delay>0 then
|
|
78549
|
-
self:ScheduleOnce(Delay,self.PlaySoundText,self,SoundText,0)
|
|
78550
|
-
else
|
|
78551
|
-
self:_DCSgRPCtts(tostring(SoundText.text))
|
|
78552
|
-
end
|
|
78553
|
-
return self
|
|
78554
|
-
end
|
|
78555
|
-
MSRS_BACKEND_DCSGRPC.Functions.PlayText=function(self,Text,Delay)
|
|
78556
|
-
if Delay and Delay>0 then
|
|
78557
|
-
self:ScheduleOnce(Delay,self.PlayText,self,Text,0)
|
|
78558
|
-
else
|
|
78559
|
-
self:_DCSgRPCtts(tostring(Text))
|
|
78560
|
-
end
|
|
78561
|
-
return self
|
|
78562
|
-
end
|
|
78563
|
-
MSRS_BACKEND_DCSGRPC.Functions.PlayTextExt=function(self,Text,Delay,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label)
|
|
78564
|
-
if Delay and Delay>0 then
|
|
78565
|
-
self:ScheduleOnce(Delay,self.PlayTextExt,self,Text,0,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label)
|
|
79856
|
+
function MSRS.getSpeechTime(length,speed,isGoogle)
|
|
79857
|
+
local maxRateRatio=3
|
|
79858
|
+
speed=speed or 1.0
|
|
79859
|
+
isGoogle=isGoogle or false
|
|
79860
|
+
local speedFactor=1.0
|
|
79861
|
+
if isGoogle then
|
|
79862
|
+
speedFactor=speed
|
|
78566
79863
|
else
|
|
78567
|
-
|
|
78568
|
-
|
|
78569
|
-
return self
|
|
78570
|
-
end
|
|
78571
|
-
MSRS_BACKEND_DCSGRPC.Functions.PlayTextFile=function(self,TextFile,Delay)
|
|
78572
|
-
BASE:E("ERROR: MSRS:PlayTextFile() is not supported by the DCS-gRPC backend.")
|
|
78573
|
-
return self
|
|
78574
|
-
end
|
|
78575
|
-
MSRS_BACKEND_DCSGRPC.Functions._DCSgRPCtts=function(self,Text,Plaintext,Frequencies,Voice,Label)
|
|
78576
|
-
BASE:T("MSRS_BACKEND_DCSGRPC:_DCSgRPCtts()")
|
|
78577
|
-
BASE:T({Text,Plaintext,Frequencies,Voice,Label})
|
|
78578
|
-
local options=self.ProviderOptions or MSRS.ProviderOptions or{}
|
|
78579
|
-
local ssml=Text or''
|
|
78580
|
-
local XmitFrequencies=Frequencies or self.Frequency
|
|
78581
|
-
if type(XmitFrequencies)~="table"then
|
|
78582
|
-
XmitFrequencies={XmitFrequencies}
|
|
78583
|
-
end
|
|
78584
|
-
options.plaintext=Plaintext
|
|
78585
|
-
options.srsClientName=Label or self.Label
|
|
78586
|
-
options.position={}
|
|
78587
|
-
if self.coordinate then
|
|
78588
|
-
options.position.lat,options.position.lon,options.position.alt=self:_GetLatLongAlt(self.coordinate)
|
|
78589
|
-
end
|
|
78590
|
-
options.position.lat=options.position.lat or 0.0
|
|
78591
|
-
options.position.lon=options.position.lon or 0.0
|
|
78592
|
-
options.position.alt=options.position.alt or 0.0
|
|
78593
|
-
if UTILS.GetCoalitionName(self.coalition)=='Blue'then
|
|
78594
|
-
options.coalition='blue'
|
|
78595
|
-
elseif UTILS.GetCoalitionName(self.coalition)=='Red'then
|
|
78596
|
-
options.coalition='red'
|
|
78597
|
-
end
|
|
78598
|
-
local provider=self.provider or self.GRPCOptions.DefaultProvider or MSRS.GRPCOptions.DefaultProvider
|
|
78599
|
-
options.provider={}
|
|
78600
|
-
options.provider[provider]={}
|
|
78601
|
-
if self.APIKey then
|
|
78602
|
-
options.provider[provider].key=self.APIKey
|
|
78603
|
-
end
|
|
78604
|
-
if self.defaultVoice then
|
|
78605
|
-
options.provider[provider].defaultVoice=self.defaultVoice
|
|
78606
|
-
end
|
|
78607
|
-
if self.voice then
|
|
78608
|
-
options.provider[provider].voice=Voice or self.voice or self.defaultVoice
|
|
78609
|
-
elseif ssml then
|
|
78610
|
-
local preTag,genderProp,langProp,postTag='','','',''
|
|
78611
|
-
if self.gender then
|
|
78612
|
-
genderProp=' gender=\"'..self.gender..'\"'
|
|
78613
|
-
end
|
|
78614
|
-
if self.culture then
|
|
78615
|
-
langProp=' language=\"'..self.culture..'\"'
|
|
79864
|
+
if speed~=0 then
|
|
79865
|
+
speedFactor=math.abs(speed)*(maxRateRatio-1)/10+1
|
|
78616
79866
|
end
|
|
78617
|
-
if
|
|
78618
|
-
|
|
78619
|
-
postTag='</voice>'
|
|
78620
|
-
ssml=preTag..Text..postTag
|
|
79867
|
+
if speed<0 then
|
|
79868
|
+
speedFactor=1/speedFactor
|
|
78621
79869
|
end
|
|
78622
79870
|
end
|
|
78623
|
-
|
|
78624
|
-
local
|
|
78625
|
-
|
|
78626
|
-
|
|
78627
|
-
BASE:T(freq)
|
|
78628
|
-
BASE:T({options})
|
|
78629
|
-
GRPC.tts(ssml,freq,options)
|
|
79871
|
+
local wpm=math.ceil(100*speedFactor)
|
|
79872
|
+
local cps=math.floor((wpm*5)/60)
|
|
79873
|
+
if type(length)=="string"then
|
|
79874
|
+
length=string.len(length)
|
|
78630
79875
|
end
|
|
79876
|
+
return length/cps
|
|
78631
79877
|
end
|
|
78632
79878
|
MSRSQUEUE={
|
|
78633
79879
|
ClassName="MSRSQUEUE",
|
|
@@ -78688,7 +79934,7 @@ return nil
|
|
|
78688
79934
|
end
|
|
78689
79935
|
local transmission={}
|
|
78690
79936
|
transmission.text=text
|
|
78691
|
-
transmission.duration=duration or
|
|
79937
|
+
transmission.duration=duration or MSRS.getSpeechTime(text)
|
|
78692
79938
|
transmission.msrs=msrs
|
|
78693
79939
|
transmission.Tplay=tstart or timer.getAbsTime()
|
|
78694
79940
|
transmission.subtitle=subtitle
|
|
@@ -78811,6 +80057,7 @@ end
|
|
|
78811
80057
|
self:_CheckRadioQueue(dt)
|
|
78812
80058
|
end
|
|
78813
80059
|
end
|
|
80060
|
+
MSRS.LoadConfigFile()
|
|
78814
80061
|
COMMANDCENTER={
|
|
78815
80062
|
ClassName="COMMANDCENTER",
|
|
78816
80063
|
CommandCenterName="",
|