@jtff/miztemplate-lib 3.1.8 → 3.1.10

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.
@@ -1,4 +1,4 @@
1
- env.info('*** MOOSE GITHUB Commit Hash ID: 2023-12-10T14:37:41+01:00-c089e56060974539e58a346665f7536a2898c4cf ***')
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",
@@ -2312,15 +2313,15 @@ if string.find(type_name,"Hercules")and(unit:getDrawArgumentValue(1217)==1)then
2312
2313
  BASE:T(unit_name.." side door is open")
2313
2314
  return true
2314
2315
  end
2315
- if string.find(type_name,"Bell-47")then
2316
+ if type_name=="Bell-47"then
2316
2317
  BASE:T(unit_name.." door is open")
2317
2318
  return true
2318
2319
  end
2319
- if string.find(type_name,"UH-60L")and(unit:getDrawArgumentValue(401)==1 or unit:getDrawArgumentValue(402)==1)then
2320
+ if type_name=="UH-60L"and(unit:getDrawArgumentValue(401)==1 or unit:getDrawArgumentValue(402)==1)then
2320
2321
  BASE:T(unit_name.." cargo door is open")
2321
2322
  return true
2322
2323
  end
2323
- if string.find(type_name,"UH-60L")and(unit:getDrawArgumentValue(38)==1 or unit:getDrawArgumentValue(400)==1)then
2324
+ if type_name=="UH-60L"and(unit:getDrawArgumentValue(38)>0 or unit:getDrawArgumentValue(400)==1)then
2324
2325
  BASE:T(unit_name.." front door(s) are open")
2325
2326
  return true
2326
2327
  end
@@ -9211,7 +9212,7 @@ Points={},
9211
9212
  Coords={},
9212
9213
  CenterVec2={x=0,y=0},
9213
9214
  SurfaceArea=0,
9214
- DrawIDs={}
9215
+ DrawID={}
9215
9216
  }
9216
9217
  function _ZONE_TRIANGLE:New(p1,p2,p3)
9217
9218
  local self=BASE:Inherit(self,ZONE_BASE:New())
@@ -9258,15 +9259,28 @@ if not FillAlpha then FillAlpha=1 end
9258
9259
  for i=1,#self.Coords do
9259
9260
  local c1=self.Coords[i]
9260
9261
  local c2=self.Coords[i%#self.Coords+1]
9261
- table.add(self.DrawIDs,c1:LineToAll(c2,Coalition,Color,Alpha,LineType,ReadOnly))
9262
+ local id=c1:LineToAll(c2,Coalition,Color,Alpha,LineType,ReadOnly)
9263
+ self.DrawID[#self.DrawID+1]=id
9262
9264
  end
9263
- return self.DrawIDs
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
9264
9276
  end
9265
9277
  ZONE_POLYGON_BASE={
9266
9278
  ClassName="ZONE_POLYGON_BASE",
9267
9279
  _Triangles={},
9268
9280
  SurfaceArea=0,
9269
- DrawID={}
9281
+ DrawID={},
9282
+ FillTriangles={},
9283
+ Borderlines={},
9270
9284
  }
9271
9285
  function ZONE_POLYGON_BASE:New(ZoneName,PointsArray)
9272
9286
  local self=BASE:Inherit(self,ZONE_BASE:New(ZoneName))
@@ -9472,31 +9486,70 @@ if self._.Polygon and#self._.Polygon>=3 then
9472
9486
  Coalition=Coalition or self:GetDrawCoalition()
9473
9487
  self:SetDrawCoalition(Coalition)
9474
9488
  Color=Color or self:GetColorRGB()
9475
- Alpha=Alpha or 1
9476
- self:SetColor(Color,Alpha)
9489
+ Alpha=Alpha or self:GetColorAlpha()
9477
9490
  FillColor=FillColor or self:GetFillColorRGB()
9478
- if not FillColor then
9479
- UTILS.DeepCopy(Color)
9480
- end
9481
9491
  FillAlpha=FillAlpha or self:GetFillColorAlpha()
9482
- if not FillAlpha then
9483
- FillAlpha=0.15
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={}
9484
9523
  end
9485
- self:SetFillColor(FillColor,FillAlpha)
9486
- IncludeTriangles=IncludeTriangles or false
9487
- if IncludeTriangles then
9488
9524
  for _,triangle in pairs(self._Triangles)do
9489
- local draw_ids=triangle:Draw()
9525
+ local draw_ids=triangle:Fill(coalition,color,alpha,nil)
9526
+ self.FillTriangles=draw_ids
9490
9527
  table.combine(self.DrawID,draw_ids)
9491
9528
  end
9492
- else
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)
9542
+ end
9543
+ self.Borderlines=nil
9544
+ self.Borderlines={}
9545
+ end
9493
9546
  local coords=self:GetVerticiesCoordinates()
9494
9547
  for i=1,#coords do
9495
9548
  local c1=coords[i]
9496
9549
  local c2=coords[i%#coords+1]
9497
- table.add(self.DrawID,c1:LineToAll(c2,Coalition,Color,Alpha,LineType,ReadOnly))
9498
- end
9499
- end
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
9500
9553
  end
9501
9554
  return self
9502
9555
  end
@@ -9679,6 +9732,7 @@ Radius=Radius or 1000
9679
9732
  Alpha=Alpha or 1
9680
9733
  Segments=Segments or 10
9681
9734
  Closed=Closed or false
9735
+ local Limit
9682
9736
  local i=1
9683
9737
  local j=#self._.Polygon
9684
9738
  if(Closed)then
@@ -10508,6 +10562,23 @@ table.remove(points,#points)
10508
10562
  self:I(string.format("Register ZONE: %s (Polygon (free) drawing with %d vertices)",ZoneName,#points))
10509
10563
  local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName,points)
10510
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
10511
10582
  self.ZONENAMES[ZoneName]=ZoneName
10512
10583
  self:AddZone(ZoneName,Zone)
10513
10584
  elseif objectData.polygonMode and objectData.polygonMode=="rect"then
@@ -10523,6 +10594,22 @@ points[4]={x=vec2.x-h/2,y=vec2.y-w/2}
10523
10594
  self:I(string.format("Register ZONE: %s (Polygon (rect) drawing with %d vertices)",ZoneName,#points))
10524
10595
  local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName,points)
10525
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
10526
10613
  self.ZONENAMES[ZoneName]=ZoneName
10527
10614
  self:AddZone(ZoneName,Zone)
10528
10615
  elseif objectData.lineMode and(objectData.lineMode=="segments"or objectData.lineMode=="segment"or objectData.lineMode=="free")and objectData.points and#objectData.points>=2 then
@@ -11328,6 +11415,26 @@ self.CallScheduler=SCHEDULER:New(self)
11328
11415
  self:SetEventPriority(2)
11329
11416
  return self
11330
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
11331
11438
  function SET_BASE:Clear(TriggerEvent)
11332
11439
  for Name,Object in pairs(self.Set)do
11333
11440
  self:Remove(Name,not TriggerEvent)
@@ -11691,6 +11798,7 @@ Categories=nil,
11691
11798
  Countries=nil,
11692
11799
  GroupPrefixes=nil,
11693
11800
  Zones=nil,
11801
+ Functions=nil,
11694
11802
  },
11695
11803
  FilterMeta={
11696
11804
  Coalitions={
@@ -12140,7 +12248,7 @@ MGroupActive=true
12140
12248
  end
12141
12249
  MGroupInclude=MGroupInclude and MGroupActive
12142
12250
  end
12143
- if self.Filter.Coalitions then
12251
+ if self.Filter.Coalitions and MGroupInclude then
12144
12252
  local MGroupCoalition=false
12145
12253
  for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
12146
12254
  self:T3({"Coalition:",MGroup:GetCoalition(),self.FilterMeta.Coalitions[CoalitionName],CoalitionName})
@@ -12150,7 +12258,7 @@ end
12150
12258
  end
12151
12259
  MGroupInclude=MGroupInclude and MGroupCoalition
12152
12260
  end
12153
- if self.Filter.Categories then
12261
+ if self.Filter.Categories and MGroupInclude then
12154
12262
  local MGroupCategory=false
12155
12263
  for CategoryID,CategoryName in pairs(self.Filter.Categories)do
12156
12264
  self:T3({"Category:",MGroup:GetCategory(),self.FilterMeta.Categories[CategoryName],CategoryName})
@@ -12160,7 +12268,7 @@ end
12160
12268
  end
12161
12269
  MGroupInclude=MGroupInclude and MGroupCategory
12162
12270
  end
12163
- if self.Filter.Countries then
12271
+ if self.Filter.Countries and MGroupInclude then
12164
12272
  local MGroupCountry=false
12165
12273
  for CountryID,CountryName in pairs(self.Filter.Countries)do
12166
12274
  self:T3({"Country:",MGroup:GetCountry(),CountryName})
@@ -12170,7 +12278,7 @@ end
12170
12278
  end
12171
12279
  MGroupInclude=MGroupInclude and MGroupCountry
12172
12280
  end
12173
- if self.Filter.GroupPrefixes then
12281
+ if self.Filter.GroupPrefixes and MGroupInclude then
12174
12282
  local MGroupPrefix=false
12175
12283
  for GroupPrefixId,GroupPrefix in pairs(self.Filter.GroupPrefixes)do
12176
12284
  self:T3({"Prefix:",string.find(MGroup:GetName(),GroupPrefix,1),GroupPrefix})
@@ -12180,7 +12288,7 @@ end
12180
12288
  end
12181
12289
  MGroupInclude=MGroupInclude and MGroupPrefix
12182
12290
  end
12183
- if self.Filter.Zones then
12291
+ if self.Filter.Zones and MGroupInclude then
12184
12292
  local MGroupZone=false
12185
12293
  for ZoneName,Zone in pairs(self.Filter.Zones)do
12186
12294
  if MGroup:IsInZone(Zone)then
@@ -12189,6 +12297,11 @@ end
12189
12297
  end
12190
12298
  MGroupInclude=MGroupInclude and MGroupZone
12191
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
12192
12305
  self:T2(MGroupInclude)
12193
12306
  return MGroupInclude
12194
12307
  end
@@ -12229,6 +12342,7 @@ Types=nil,
12229
12342
  Countries=nil,
12230
12343
  UnitPrefixes=nil,
12231
12344
  Zones=nil,
12345
+ Functions=nil,
12232
12346
  },
12233
12347
  FilterMeta={
12234
12348
  Coalitions={
@@ -12770,7 +12884,7 @@ MUnitActive=true
12770
12884
  end
12771
12885
  MUnitInclude=MUnitInclude and MUnitActive
12772
12886
  end
12773
- if self.Filter.Coalitions then
12887
+ if self.Filter.Coalitions and MUnitInclude then
12774
12888
  local MUnitCoalition=false
12775
12889
  for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
12776
12890
  self:F({"Coalition:",MUnit:GetCoalition(),self.FilterMeta.Coalitions[CoalitionName],CoalitionName})
@@ -12780,7 +12894,7 @@ end
12780
12894
  end
12781
12895
  MUnitInclude=MUnitInclude and MUnitCoalition
12782
12896
  end
12783
- if self.Filter.Categories then
12897
+ if self.Filter.Categories and MUnitInclude then
12784
12898
  local MUnitCategory=false
12785
12899
  for CategoryID,CategoryName in pairs(self.Filter.Categories)do
12786
12900
  self:T3({"Category:",MUnit:GetDesc().category,self.FilterMeta.Categories[CategoryName],CategoryName})
@@ -12790,7 +12904,7 @@ end
12790
12904
  end
12791
12905
  MUnitInclude=MUnitInclude and MUnitCategory
12792
12906
  end
12793
- if self.Filter.Types then
12907
+ if self.Filter.Types and MUnitInclude then
12794
12908
  local MUnitType=false
12795
12909
  for TypeID,TypeName in pairs(self.Filter.Types)do
12796
12910
  self:T3({"Type:",MUnit:GetTypeName(),TypeName})
@@ -12800,7 +12914,7 @@ end
12800
12914
  end
12801
12915
  MUnitInclude=MUnitInclude and MUnitType
12802
12916
  end
12803
- if self.Filter.Countries then
12917
+ if self.Filter.Countries and MUnitInclude then
12804
12918
  local MUnitCountry=false
12805
12919
  for CountryID,CountryName in pairs(self.Filter.Countries)do
12806
12920
  self:T3({"Country:",MUnit:GetCountry(),CountryName})
@@ -12810,7 +12924,7 @@ end
12810
12924
  end
12811
12925
  MUnitInclude=MUnitInclude and MUnitCountry
12812
12926
  end
12813
- if self.Filter.UnitPrefixes then
12927
+ if self.Filter.UnitPrefixes and MUnitInclude then
12814
12928
  local MUnitPrefix=false
12815
12929
  for UnitPrefixId,UnitPrefix in pairs(self.Filter.UnitPrefixes)do
12816
12930
  self:T3({"Prefix:",string.find(MUnit:GetName(),UnitPrefix,1),UnitPrefix})
@@ -12820,7 +12934,7 @@ end
12820
12934
  end
12821
12935
  MUnitInclude=MUnitInclude and MUnitPrefix
12822
12936
  end
12823
- if self.Filter.RadarTypes then
12937
+ if self.Filter.RadarTypes and MUnitInclude then
12824
12938
  local MUnitRadar=false
12825
12939
  for RadarTypeID,RadarType in pairs(self.Filter.RadarTypes)do
12826
12940
  self:T3({"Radar:",RadarType})
@@ -12833,7 +12947,7 @@ end
12833
12947
  end
12834
12948
  MUnitInclude=MUnitInclude and MUnitRadar
12835
12949
  end
12836
- if self.Filter.SEAD then
12950
+ if self.Filter.SEAD and MUnitInclude then
12837
12951
  local MUnitSEAD=false
12838
12952
  if MUnit:HasSEAD()==true then
12839
12953
  self:T3("SEAD Found")
@@ -12842,7 +12956,7 @@ end
12842
12956
  MUnitInclude=MUnitInclude and MUnitSEAD
12843
12957
  end
12844
12958
  end
12845
- if self.Filter.Zones then
12959
+ if self.Filter.Zones and MUnitInclude then
12846
12960
  local MGroupZone=false
12847
12961
  for ZoneName,Zone in pairs(self.Filter.Zones)do
12848
12962
  self:T3("Zone:",ZoneName)
@@ -12852,6 +12966,10 @@ end
12852
12966
  end
12853
12967
  MUnitInclude=MUnitInclude and MGroupZone
12854
12968
  end
12969
+ if self.Filter.Functions and MUnitInclude then
12970
+ local MUnitFunc=self:_EvalFilterFunctions(MUnit)
12971
+ MUnitInclude=MUnitInclude and MUnitFunc
12972
+ end
12855
12973
  self:T2(MUnitInclude)
12856
12974
  return MUnitInclude
12857
12975
  end
@@ -13602,7 +13720,7 @@ MClientActive=true
13602
13720
  end
13603
13721
  MClientInclude=MClientInclude and MClientActive
13604
13722
  end
13605
- if self.Filter.Coalitions then
13723
+ if self.Filter.Coalitions and MClientInclude then
13606
13724
  local MClientCoalition=false
13607
13725
  for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
13608
13726
  local ClientCoalitionID=_DATABASE:GetCoalitionFromClientTemplate(MClientName)
@@ -13614,7 +13732,7 @@ end
13614
13732
  self:T({"Evaluated Coalition",MClientCoalition})
13615
13733
  MClientInclude=MClientInclude and MClientCoalition
13616
13734
  end
13617
- if self.Filter.Categories then
13735
+ if self.Filter.Categories and MClientInclude then
13618
13736
  local MClientCategory=false
13619
13737
  for CategoryID,CategoryName in pairs(self.Filter.Categories)do
13620
13738
  local ClientCategoryID=_DATABASE:GetCategoryFromClientTemplate(MClientName)
@@ -13626,7 +13744,7 @@ end
13626
13744
  self:T({"Evaluated Category",MClientCategory})
13627
13745
  MClientInclude=MClientInclude and MClientCategory
13628
13746
  end
13629
- if self.Filter.Types then
13747
+ if self.Filter.Types and MClientInclude then
13630
13748
  local MClientType=false
13631
13749
  for TypeID,TypeName in pairs(self.Filter.Types)do
13632
13750
  self:T3({"Type:",MClient:GetTypeName(),TypeName})
@@ -13637,7 +13755,7 @@ end
13637
13755
  self:T({"Evaluated Type",MClientType})
13638
13756
  MClientInclude=MClientInclude and MClientType
13639
13757
  end
13640
- if self.Filter.Countries then
13758
+ if self.Filter.Countries and MClientInclude then
13641
13759
  local MClientCountry=false
13642
13760
  for CountryID,CountryName in pairs(self.Filter.Countries)do
13643
13761
  local ClientCountryID=_DATABASE:GetCountryFromClientTemplate(MClientName)
@@ -13649,7 +13767,7 @@ end
13649
13767
  self:T({"Evaluated Country",MClientCountry})
13650
13768
  MClientInclude=MClientInclude and MClientCountry
13651
13769
  end
13652
- if self.Filter.ClientPrefixes then
13770
+ if self.Filter.ClientPrefixes and MClientInclude then
13653
13771
  local MClientPrefix=false
13654
13772
  for ClientPrefixId,ClientPrefix in pairs(self.Filter.ClientPrefixes)do
13655
13773
  self:T3({"Prefix:",string.find(MClient.UnitName,ClientPrefix,1),ClientPrefix})
@@ -13660,7 +13778,7 @@ end
13660
13778
  self:T({"Evaluated Prefix",MClientPrefix})
13661
13779
  MClientInclude=MClientInclude and MClientPrefix
13662
13780
  end
13663
- if self.Filter.Zones then
13781
+ if self.Filter.Zones and MClientInclude then
13664
13782
  local MClientZone=false
13665
13783
  for ZoneName,Zone in pairs(self.Filter.Zones)do
13666
13784
  self:T3("Zone:",ZoneName)
@@ -13671,7 +13789,7 @@ end
13671
13789
  end
13672
13790
  MClientInclude=MClientInclude and MClientZone
13673
13791
  end
13674
- if self.Filter.Playernames then
13792
+ if self.Filter.Playernames and MClientInclude then
13675
13793
  local MClientPlayername=false
13676
13794
  local playername=MClient:GetPlayerName()or"Unknown"
13677
13795
  for _,_Playername in pairs(self.Filter.Playernames)do
@@ -13682,7 +13800,7 @@ end
13682
13800
  self:T({"Evaluated Playername",MClientPlayername})
13683
13801
  MClientInclude=MClientInclude and MClientPlayername
13684
13802
  end
13685
- if self.Filter.Callsigns then
13803
+ if self.Filter.Callsigns and MClientInclude then
13686
13804
  local MClientCallsigns=false
13687
13805
  local callsign=MClient:GetCallsign()
13688
13806
  for _,_Callsign in pairs(self.Filter.Callsigns)do
@@ -13693,6 +13811,10 @@ end
13693
13811
  self:T({"Evaluated Callsign",MClientCallsigns})
13694
13812
  MClientInclude=MClientInclude and MClientCallsigns
13695
13813
  end
13814
+ if self.Filter.Functions and MClientInclude then
13815
+ local MClientFunc=self:_EvalFilterFunctions(MClient)
13816
+ MClientInclude=MClientInclude and MClientFunc
13817
+ end
13696
13818
  end
13697
13819
  self:T2(MClientInclude)
13698
13820
  return MClientInclude
@@ -14012,7 +14134,6 @@ return AirbaseFound
14012
14134
  end
14013
14135
  function SET_AIRBASE:GetRandomAirbase()
14014
14136
  local RandomAirbase=self:GetRandom()
14015
- self:F({RandomAirbase=RandomAirbase:GetName()})
14016
14137
  return RandomAirbase
14017
14138
  end
14018
14139
  function SET_AIRBASE:FilterCoalitions(Coalitions)
@@ -14102,7 +14223,7 @@ end
14102
14223
  self:T({"Evaluated Coalition",MAirbaseCoalition})
14103
14224
  MAirbaseInclude=MAirbaseInclude and MAirbaseCoalition
14104
14225
  end
14105
- if self.Filter.Categories then
14226
+ if self.Filter.Categories and MAirbaseInclude then
14106
14227
  local MAirbaseCategory=false
14107
14228
  for CategoryID,CategoryName in pairs(self.Filter.Categories)do
14108
14229
  local AirbaseCategoryID=_DATABASE:GetCategoryFromAirbase(MAirbaseName)
@@ -15185,7 +15306,7 @@ MGroupActive=true
15185
15306
  end
15186
15307
  MGroupInclude=MGroupInclude and MGroupActive
15187
15308
  end
15188
- if self.Filter.Coalitions then
15309
+ if self.Filter.Coalitions and MGroupInclude then
15189
15310
  local MGroupCoalition=false
15190
15311
  for CoalitionID,CoalitionName in pairs(self.Filter.Coalitions)do
15191
15312
  if self.FilterMeta.Coalitions[CoalitionName]and self.FilterMeta.Coalitions[CoalitionName]==MGroup:GetCoalition()then
@@ -15194,7 +15315,7 @@ end
15194
15315
  end
15195
15316
  MGroupInclude=MGroupInclude and MGroupCoalition
15196
15317
  end
15197
- if self.Filter.Categories then
15318
+ if self.Filter.Categories and MGroupInclude then
15198
15319
  local MGroupCategory=false
15199
15320
  for CategoryID,CategoryName in pairs(self.Filter.Categories)do
15200
15321
  if self.FilterMeta.Categories[CategoryName]and self.FilterMeta.Categories[CategoryName]==MGroup:GetCategory()then
@@ -15203,7 +15324,7 @@ end
15203
15324
  end
15204
15325
  MGroupInclude=MGroupInclude and MGroupCategory
15205
15326
  end
15206
- if self.Filter.Countries then
15327
+ if self.Filter.Countries and MGroupInclude then
15207
15328
  local MGroupCountry=false
15208
15329
  for CountryID,CountryName in pairs(self.Filter.Countries)do
15209
15330
  if country.id[CountryName]==MGroup:GetCountry()then
@@ -15212,7 +15333,7 @@ end
15212
15333
  end
15213
15334
  MGroupInclude=MGroupInclude and MGroupCountry
15214
15335
  end
15215
- if self.Filter.GroupPrefixes then
15336
+ if self.Filter.GroupPrefixes and MGroupInclude then
15216
15337
  local MGroupPrefix=false
15217
15338
  for GroupPrefixId,GroupPrefix in pairs(self.Filter.GroupPrefixes)do
15218
15339
  if string.find(MGroup:GetName(),GroupPrefix:gsub("-","%%-"),1)then
@@ -16578,11 +16699,14 @@ Color,FillColor,LineType,ReadOnly,Text or"")
16578
16699
  else
16579
16700
  local s=string.format("trigger.action.markupToAll(7, %d, %d,",Coalition,MarkID)
16580
16701
  for _,vec in pairs(vecs)do
16581
- s=s..string.format("%s,",UTILS._OneLineSerialize(vec))
16702
+ s=s..string.format("{x=%.1f, y=%.1f, z=%.1f},",vec.x,vec.y,vec.z)
16582
16703
  end
16583
- s=s..string.format("%s, %s, %s, %s",UTILS._OneLineSerialize(Color),UTILS._OneLineSerialize(FillColor),tostring(LineType),tostring(ReadOnly))
16584
- if Text and Text~=""then
16585
- s=s..string.format(", \"%s\"",Text)
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))
16586
16710
  end
16587
16711
  s=s..")"
16588
16712
  local success=UTILS.DoString(s)
@@ -16892,6 +17016,36 @@ local lat,lon=coord.LOtoLL(self:GetVec3())
16892
17016
  local MGRS=coord.LLtoMGRS(lat,lon)
16893
17017
  return"MGRS "..UTILS.tostringMGRS(MGRS,MGRS_Accuracy)
16894
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
16895
17049
  function COORDINATE:ToStringFromRP(ReferenceCoord,ReferenceName,Controllable,Settings,MagVar)
16896
17050
  self:F2({ReferenceCoord=ReferenceCoord,ReferenceName=ReferenceName})
16897
17051
  local Settings=Settings or(Controllable and _DATABASE:GetPlayerSettings(Controllable:GetPlayerName()))or _SETTINGS
@@ -17479,7 +17633,6 @@ _MESSAGESRS.Culture=Culture or"en-GB"
17479
17633
  _MESSAGESRS.MSRS:SetGender(Gender)
17480
17634
  _MESSAGESRS.Gender=Gender or"female"
17481
17635
  _MESSAGESRS.MSRS:SetGoogle(PathToCredentials)
17482
- _MESSAGESRS.google=PathToCredentials
17483
17636
  _MESSAGESRS.MSRS:SetLabel(Label or"MESSAGE")
17484
17637
  _MESSAGESRS.label=Label or"MESSAGE"
17485
17638
  _MESSAGESRS.MSRS:SetPort(Port or 5002)
@@ -23815,32 +23968,35 @@ self:SetOption(AI.Option.Air.id.PROHIBIT_AB,Prohibit)
23815
23968
  end
23816
23969
  return self
23817
23970
  end
23818
- function CONTROLLABLE:OptionECM_Never()
23971
+ function CONTROLLABLE:OptionECM(ECMvalue)
23819
23972
  self:F2({self.ControllableName})
23973
+ local DCSControllable=self:GetDCSObject()
23974
+ if DCSControllable then
23975
+ local Controller=self:_GetController()
23820
23976
  if self:IsAir()then
23821
- self:SetOption(AI.Option.Air.id.ECM_USING,0)
23977
+ Controller:setOption(AI.Option.Air.id.ECM_USING,ECMvalue or 1)
23978
+ end
23822
23979
  end
23823
23980
  return self
23824
23981
  end
23825
- function CONTROLLABLE:OptionECM_OnlyLockByRadar()
23982
+ function CONTROLLABLE:OptionECM_Never()
23826
23983
  self:F2({self.ControllableName})
23827
- if self:IsAir()then
23828
- self:SetOption(AI.Option.Air.id.ECM_USING,1)
23984
+ self:OptionECM(0)
23985
+ return self
23829
23986
  end
23987
+ function CONTROLLABLE:OptionECM_OnlyLockByRadar()
23988
+ self:F2({self.ControllableName})
23989
+ self:OptionECM(1)
23830
23990
  return self
23831
23991
  end
23832
23992
  function CONTROLLABLE:OptionECM_DetectedLockByRadar()
23833
23993
  self:F2({self.ControllableName})
23834
- if self:IsAir()then
23835
- self:SetOption(AI.Option.Air.id.ECM_USING,2)
23836
- end
23994
+ self:OptionECM(2)
23837
23995
  return self
23838
23996
  end
23839
23997
  function CONTROLLABLE:OptionECM_AlwaysOn()
23840
23998
  self:F2({self.ControllableName})
23841
- if self:IsAir()then
23842
- self:SetOption(AI.Option.Air.id.ECM_USING,3)
23843
- end
23999
+ self:OptionECM(3)
23844
24000
  return self
23845
24001
  end
23846
24002
  function CONTROLLABLE:WayPointInitialize(WayPoints)
@@ -23949,12 +24105,19 @@ return self
23949
24105
  end
23950
24106
  return nil
23951
24107
  end
23952
- function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation)
24108
+ function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation,onland)
23953
24109
  self:F2({self.ControllableName})
23954
24110
  local _coord=self:GetCoordinate()
23955
24111
  local _radius=radius or 500
23956
24112
  local _speed=speed or 20
23957
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
23958
24121
  local _onroad=onroad or true
23959
24122
  local _grptsk={}
23960
24123
  local _candoroad=false
@@ -24858,7 +25021,7 @@ local Task={
24858
25021
  table.insert(TaskAerobatics.params["maneuversSequency"],Task)
24859
25022
  return TaskAerobatics
24860
25023
  end
24861
- function CONTROLLABLE:PatrolRaceTrack(Point1,Point2,Altitude,Speed,Formation,Delay)
25024
+ function CONTROLLABLE:PatrolRaceTrack(Point1,Point2,Altitude,Speed,Formation,AGL,Delay)
24862
25025
  local PatrolGroup=self
24863
25026
  if not self:IsInstanceOf("GROUP")then
24864
25027
  PatrolGroup=self:GetGroup()
@@ -24872,8 +25035,10 @@ end
24872
25035
  local FromCoord=PatrolGroup:GetCoordinate()
24873
25036
  local ToCoord=Point1:GetCoordinate()
24874
25037
  if Altitude then
24875
- FromCoord:SetAltitude(Altitude)
24876
- ToCoord:SetAltitude(Altitude)
25038
+ local asl=true
25039
+ if AGL then asl=false end
25040
+ FromCoord:SetAltitude(Altitude,asl)
25041
+ ToCoord:SetAltitude(Altitude,asl)
24877
25042
  end
24878
25043
  local Route={}
24879
25044
  Route[#Route+1]=FromCoord:WaypointAir(AltType,COORDINATE.WaypointType.TurningPoint,COORDINATE.WaypointAction.TurningPoint,Speed,true,nil,DCSTasks,description,timeReFuAr)
@@ -26451,6 +26616,32 @@ report:Add("==================")
26451
26616
  local text=report:Text()
26452
26617
  return tSTN,text
26453
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
26454
26645
  UNIT={
26455
26646
  ClassName="UNIT",
26456
26647
  UnitName=nil,
@@ -30223,7 +30414,7 @@ Reported={},
30223
30414
  }
30224
30415
  function CARGO:New(Type,Name,Weight,LoadRadius,NearRadius)
30225
30416
  local self=BASE:Inherit(self,FSM:New())
30226
- self:F({Type,Name,Weight,LoadRadius,NearRadius})
30417
+ self:T({Type,Name,Weight,LoadRadius,NearRadius})
30227
30418
  self:SetStartState("UnLoaded")
30228
30419
  self:AddTransition({"UnLoaded","Boarding"},"Board","Boarding")
30229
30420
  self:AddTransition("Boarding","Boarding","Boarding")
@@ -30368,7 +30559,7 @@ function CARGO:IsDeployed()
30368
30559
  return self.Deployed
30369
30560
  end
30370
30561
  function CARGO:Spawn(PointVec2)
30371
- self:F()
30562
+ self:T()
30372
30563
  end
30373
30564
  function CARGO:Flare(FlareColor)
30374
30565
  if self:IsUnLoaded()then
@@ -30418,7 +30609,7 @@ function CARGO:GetLoadRadius()
30418
30609
  return self.LoadRadius
30419
30610
  end
30420
30611
  function CARGO:IsInLoadRadius(Coordinate)
30421
- self:F({Coordinate,LoadRadius=self.LoadRadius})
30612
+ self:T({Coordinate,LoadRadius=self.LoadRadius})
30422
30613
  local Distance=0
30423
30614
  if self:IsUnLoaded()then
30424
30615
  local CargoCoordinate=self.CargoObject:GetCoordinate()
@@ -30431,7 +30622,7 @@ end
30431
30622
  return false
30432
30623
  end
30433
30624
  function CARGO:IsInReportRadius(Coordinate)
30434
- self:F({Coordinate})
30625
+ self:T({Coordinate})
30435
30626
  local Distance=0
30436
30627
  if self:IsUnLoaded()then
30437
30628
  Distance=Coordinate:Get2DDistance(self.CargoObject:GetCoordinate())
@@ -30533,7 +30724,7 @@ ClassName="CARGO_REPRESENTABLE"
30533
30724
  }
30534
30725
  function CARGO_REPRESENTABLE:New(CargoObject,Type,Name,LoadRadius,NearRadius)
30535
30726
  local self=BASE:Inherit(self,CARGO:New(Type,Name,0,LoadRadius,NearRadius))
30536
- self:F({Type,Name,LoadRadius,NearRadius})
30727
+ self:T({Type,Name,LoadRadius,NearRadius})
30537
30728
  local Desc=CargoObject:GetDesc()
30538
30729
  self:T({Desc=Desc})
30539
30730
  local Weight=math.random(80,120)
@@ -30548,7 +30739,7 @@ self:SetWeight(Weight)
30548
30739
  return self
30549
30740
  end
30550
30741
  function CARGO_REPRESENTABLE:Destroy()
30551
- self:F({CargoName=self:GetName()})
30742
+ self:T({CargoName=self:GetName()})
30552
30743
  return self
30553
30744
  end
30554
30745
  function CARGO_REPRESENTABLE:RouteTo(ToPointVec2,Speed)
@@ -30566,12 +30757,12 @@ local CoordinateZone=ZONE_RADIUS:New("Zone",self:GetCoordinate():GetVec2(),500)
30566
30757
  CoordinateZone:Scan({Object.Category.UNIT})
30567
30758
  for _,DCSUnit in pairs(CoordinateZone:GetScannedUnits())do
30568
30759
  local NearUnit=UNIT:Find(DCSUnit)
30569
- self:F({NearUnit=NearUnit})
30760
+ self:T({NearUnit=NearUnit})
30570
30761
  local NearUnitCoalition=NearUnit:GetCoalition()
30571
30762
  local CargoCoalition=self:GetCoalition()
30572
30763
  if NearUnitCoalition==CargoCoalition then
30573
30764
  local Attributes=NearUnit:GetDesc()
30574
- self:F({Desc=Attributes})
30765
+ self:T({Desc=Attributes})
30575
30766
  if NearUnit:HasAttribute("Trucks")then
30576
30767
  MESSAGE:New(Message,20,NearUnit:GetCallsign().." reporting - Cargo "..self:GetName()):ToGroup(TaskGroup)
30577
30768
  break
@@ -30586,7 +30777,7 @@ ClassName="CARGO_REPORTABLE"
30586
30777
  }
30587
30778
  function CARGO_REPORTABLE:New(Type,Name,Weight,LoadRadius,NearRadius)
30588
30779
  local self=BASE:Inherit(self,CARGO:New(Type,Name,Weight,LoadRadius,NearRadius))
30589
- self:F({Type,Name,Weight,LoadRadius,NearRadius})
30780
+ self:T({Type,Name,Weight,LoadRadius,NearRadius})
30590
30781
  return self
30591
30782
  end
30592
30783
  function CARGO_REPORTABLE:MessageToGroup(Message,TaskGroup,Name)
@@ -30599,13 +30790,13 @@ ClassName="CARGO_PACKAGE"
30599
30790
  }
30600
30791
  function CARGO_PACKAGE:New(CargoCarrier,Type,Name,Weight,LoadRadius,NearRadius)
30601
30792
  local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoCarrier,Type,Name,Weight,LoadRadius,NearRadius))
30602
- self:F({Type,Name,Weight,LoadRadius,NearRadius})
30793
+ self:T({Type,Name,Weight,LoadRadius,NearRadius})
30603
30794
  self:T(CargoCarrier)
30604
30795
  self.CargoCarrier=CargoCarrier
30605
30796
  return self
30606
30797
  end
30607
30798
  function CARGO_PACKAGE:onafterOnBoard(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
30608
- self:F()
30799
+ self:T()
30609
30800
  self.CargoInAir=self.CargoCarrier:InAir()
30610
30801
  self:T(self.CargoInAir)
30611
30802
  if not self.CargoInAir then
@@ -30623,7 +30814,7 @@ end
30623
30814
  self:Boarded(CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
30624
30815
  end
30625
30816
  function CARGO_PACKAGE:IsNear(CargoCarrier)
30626
- self:F()
30817
+ self:T()
30627
30818
  local CargoCarrierPoint=CargoCarrier:GetCoordinate()
30628
30819
  local Distance=CargoCarrierPoint:Get2DDistance(self.CargoCarrier:GetCoordinate())
30629
30820
  self:T(Distance)
@@ -30634,7 +30825,7 @@ return false
30634
30825
  end
30635
30826
  end
30636
30827
  function CARGO_PACKAGE:onafterOnBoarded(From,Event,To,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
30637
- self:F()
30828
+ self:T()
30638
30829
  if self:IsNear(CargoCarrier)then
30639
30830
  self:__Load(1,CargoCarrier,Speed,LoadDistance,Angle)
30640
30831
  else
@@ -30642,7 +30833,7 @@ self:__Boarded(1,CargoCarrier,Speed,BoardDistance,LoadDistance,Angle)
30642
30833
  end
30643
30834
  end
30644
30835
  function CARGO_PACKAGE:onafterUnBoard(From,Event,To,CargoCarrier,Speed,UnLoadDistance,UnBoardDistance,Radius,Angle)
30645
- self:F()
30836
+ self:T()
30646
30837
  self.CargoInAir=self.CargoCarrier:InAir()
30647
30838
  self:T(self.CargoInAir)
30648
30839
  if not self.CargoInAir then
@@ -30661,7 +30852,7 @@ end
30661
30852
  self:__UnBoarded(1,CargoCarrier,Speed)
30662
30853
  end
30663
30854
  function CARGO_PACKAGE:onafterUnBoarded(From,Event,To,CargoCarrier,Speed)
30664
- self:F()
30855
+ self:T()
30665
30856
  if self:IsNear(CargoCarrier)then
30666
30857
  self:__UnLoad(1,CargoCarrier,Speed)
30667
30858
  else
@@ -30669,7 +30860,7 @@ self:__UnBoarded(1,CargoCarrier,Speed)
30669
30860
  end
30670
30861
  end
30671
30862
  function CARGO_PACKAGE:onafterLoad(From,Event,To,CargoCarrier,Speed,LoadDistance,Angle)
30672
- self:F()
30863
+ self:T()
30673
30864
  self.CargoCarrier=CargoCarrier
30674
30865
  local StartPointVec2=self.CargoCarrier:GetPointVec2()
30675
30866
  local CargoCarrierHeading=self.CargoCarrier:GetHeading()
@@ -30682,7 +30873,7 @@ local TaskRoute=self.CargoCarrier:TaskRoute(Points)
30682
30873
  self.CargoCarrier:SetTask(TaskRoute,1)
30683
30874
  end
30684
30875
  function CARGO_PACKAGE:onafterUnLoad(From,Event,To,CargoCarrier,Speed,Distance,Angle)
30685
- self:F()
30876
+ self:T()
30686
30877
  local StartPointVec2=self.CargoCarrier:GetPointVec2()
30687
30878
  local CargoCarrierHeading=self.CargoCarrier:GetHeading()
30688
30879
  local CargoDeployHeading=((CargoCarrierHeading+Angle)>=360)and(CargoCarrierHeading+Angle-360)or(CargoCarrierHeading+Angle)
@@ -30707,7 +30898,7 @@ self:SetEventPriority(5)
30707
30898
  return self
30708
30899
  end
30709
30900
  function CARGO_UNIT:onenterUnBoarding(From,Event,To,ToPointVec2,NearRadius)
30710
- self:F({From,Event,To,ToPointVec2,NearRadius})
30901
+ self:T({From,Event,To,ToPointVec2,NearRadius})
30711
30902
  local Angle=180
30712
30903
  local Speed=60
30713
30904
  local DeployDistance=9
@@ -30730,7 +30921,7 @@ self.CargoObject:ReSpawnAt(ToPointVec2,CargoDeployHeading)
30730
30921
  else
30731
30922
  self.CargoObject:ReSpawnAt(FromPointVec2,CargoDeployHeading)
30732
30923
  end
30733
- self:F({"CargoUnits:",self.CargoObject:GetGroup():GetName()})
30924
+ self:T({"CargoUnits:",self.CargoObject:GetGroup():GetName()})
30734
30925
  self.CargoCarrier=nil
30735
30926
  local Points={}
30736
30927
  Points[#Points+1]=FromPointVec2:WaypointGround(Speed,"Vee")
@@ -30746,7 +30937,7 @@ end
30746
30937
  end
30747
30938
  end
30748
30939
  function CARGO_UNIT:onleaveUnBoarding(From,Event,To,ToPointVec2,NearRadius)
30749
- self:F({From,Event,To,ToPointVec2,NearRadius})
30940
+ self:T({From,Event,To,ToPointVec2,NearRadius})
30750
30941
  local Angle=180
30751
30942
  local Speed=10
30752
30943
  local Distance=5
@@ -30755,7 +30946,7 @@ return true
30755
30946
  end
30756
30947
  end
30757
30948
  function CARGO_UNIT:onafterUnBoarding(From,Event,To,ToPointVec2,NearRadius)
30758
- self:F({From,Event,To,ToPointVec2,NearRadius})
30949
+ self:T({From,Event,To,ToPointVec2,NearRadius})
30759
30950
  self.CargoInAir=self.CargoObject:InAir()
30760
30951
  self:T(self.CargoInAir)
30761
30952
  if not self.CargoInAir then
@@ -30763,7 +30954,7 @@ end
30763
30954
  self:__UnLoad(1,ToPointVec2,NearRadius)
30764
30955
  end
30765
30956
  function CARGO_UNIT:onenterUnLoaded(From,Event,To,ToPointVec2)
30766
- self:F({ToPointVec2,From,Event,To})
30957
+ self:T({ToPointVec2,From,Event,To})
30767
30958
  local Angle=180
30768
30959
  local Speed=10
30769
30960
  local Distance=5
@@ -30784,7 +30975,7 @@ self.OnUnLoadedCallBack=nil
30784
30975
  end
30785
30976
  end
30786
30977
  function CARGO_UNIT:onafterBoard(From,Event,To,CargoCarrier,NearRadius,...)
30787
- self:F({From,Event,To,CargoCarrier,NearRadius=NearRadius})
30978
+ self:T({From,Event,To,CargoCarrier,NearRadius=NearRadius})
30788
30979
  self.CargoInAir=self.CargoObject:InAir()
30789
30980
  local Desc=self.CargoObject:GetDesc()
30790
30981
  local MaxSpeed=Desc.speedMaxOffRoad
@@ -30818,8 +31009,8 @@ end
30818
31009
  end
30819
31010
  end
30820
31011
  function CARGO_UNIT:onafterBoarding(From,Event,To,CargoCarrier,NearRadius,...)
30821
- self:F({From,Event,To,CargoCarrier:GetName(),NearRadius=NearRadius})
30822
- self:F({IsAlive=self.CargoObject:IsAlive()})
31012
+ self:T({From,Event,To,CargoCarrier:GetName(),NearRadius=NearRadius})
31013
+ self:T({IsAlive=self.CargoObject:IsAlive()})
30823
31014
  if CargoCarrier and CargoCarrier:IsAlive()then
30824
31015
  if(CargoCarrier:IsAir()and not CargoCarrier:InAir())or true then
30825
31016
  local NearRadius=NearRadius or CargoCarrier:GetBoundingRadius(NearRadius)+5
@@ -30857,11 +31048,11 @@ self:CancelBoarding(CargoCarrier,NearRadius,...)
30857
31048
  self.CargoObject:SetCommand(self.CargoObject:CommandStopRoute(true))
30858
31049
  end
30859
31050
  else
30860
- self:E("Something is wrong")
31051
+ self:T("Something is wrong")
30861
31052
  end
30862
31053
  end
30863
31054
  function CARGO_UNIT:onenterLoaded(From,Event,To,CargoCarrier)
30864
- self:F({From,Event,To,CargoCarrier})
31055
+ self:T({From,Event,To,CargoCarrier})
30865
31056
  self.CargoCarrier=CargoCarrier
30866
31057
  if self.CargoObject then
30867
31058
  self.CargoObject:Destroy(false)
@@ -30888,7 +31079,7 @@ ClassName="CARGO_SLINGLOAD"
30888
31079
  }
30889
31080
  function CARGO_SLINGLOAD:New(CargoStatic,Type,Name,LoadRadius,NearRadius)
30890
31081
  local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoStatic,Type,Name,nil,LoadRadius,NearRadius))
30891
- self:F({Type,Name,NearRadius})
31082
+ self:T({Type,Name,NearRadius})
30892
31083
  self.CargoObject=CargoStatic
30893
31084
  _EVENTDISPATCHER:CreateEventNewCargo(self)
30894
31085
  self:HandleEvent(EVENTS.Dead,self.OnEventCargoDead)
@@ -30999,7 +31190,7 @@ ClassName="CARGO_CRATE"
30999
31190
  }
31000
31191
  function CARGO_CRATE:New(CargoStatic,Type,Name,LoadRadius,NearRadius)
31001
31192
  local self=BASE:Inherit(self,CARGO_REPRESENTABLE:New(CargoStatic,Type,Name,nil,LoadRadius,NearRadius))
31002
- self:F({Type,Name,NearRadius})
31193
+ self:T({Type,Name,NearRadius})
31003
31194
  self.CargoObject=CargoStatic
31004
31195
  _EVENTDISPATCHER:CreateEventNewCargo(self)
31005
31196
  self:HandleEvent(EVENTS.Dead,self.OnEventCargoDead)
@@ -31102,21 +31293,21 @@ end
31102
31293
  return Alive
31103
31294
  end
31104
31295
  function CARGO_CRATE:RouteTo(Coordinate)
31105
- self:F({Coordinate=Coordinate})
31296
+ self:T({Coordinate=Coordinate})
31106
31297
  end
31107
31298
  function CARGO_CRATE:IsNear(CargoCarrier,NearRadius)
31108
- self:F({NearRadius=NearRadius})
31299
+ self:T({NearRadius=NearRadius})
31109
31300
  return self:IsNear(CargoCarrier:GetCoordinate(),NearRadius)
31110
31301
  end
31111
31302
  function CARGO_CRATE:Respawn()
31112
- self:F({"Respawning crate "..self:GetName()})
31303
+ self:T({"Respawning crate "..self:GetName()})
31113
31304
  if self.CargoObject then
31114
31305
  self.CargoObject:ReSpawn()
31115
31306
  self:__Reset(-0.1)
31116
31307
  end
31117
31308
  end
31118
31309
  function CARGO_CRATE:onafterReset()
31119
- self:F({"Reset crate "..self:GetName()})
31310
+ self:T({"Reset crate "..self:GetName()})
31120
31311
  if self.CargoObject then
31121
31312
  self:SetDeployed(false)
31122
31313
  self:SetStartState("UnLoaded")
@@ -31145,7 +31336,7 @@ ClassName="CARGO_GROUP",
31145
31336
  }
31146
31337
  function CARGO_GROUP:New(CargoGroup,Type,Name,LoadRadius,NearRadius)
31147
31338
  local self=BASE:Inherit(self,CARGO_REPORTABLE:New(Type,Name,0,LoadRadius,NearRadius))
31148
- self:F({Type,Name,LoadRadius})
31339
+ self:T({Type,Name,LoadRadius})
31149
31340
  self.CargoSet=SET_CARGO:New()
31150
31341
  self.CargoGroup=CargoGroup
31151
31342
  self.Grouped=true
@@ -31189,7 +31380,7 @@ self:SetEventPriority(4)
31189
31380
  return self
31190
31381
  end
31191
31382
  function CARGO_GROUP:Respawn()
31192
- self:F({"Respawning"})
31383
+ self:T({"Respawning"})
31193
31384
  for CargoID,CargoData in pairs(self.CargoSet:GetSet())do
31194
31385
  local Cargo=CargoData
31195
31386
  Cargo:Destroy()
@@ -31230,7 +31421,7 @@ self.CargoObject=nil
31230
31421
  end
31231
31422
  end
31232
31423
  function CARGO_GROUP:Regroup()
31233
- self:F("Regroup")
31424
+ self:T("Regroup")
31234
31425
  if self.Grouped==false then
31235
31426
  self.Grouped=true
31236
31427
  local GroupTemplate=UTILS.DeepCopy(self.CargoTemplate)
@@ -31239,7 +31430,7 @@ GroupTemplate.groupId=nil
31239
31430
  GroupTemplate.units={}
31240
31431
  for CargoUnitName,CargoUnit in pairs(self.CargoSet:GetSet())do
31241
31432
  local CargoUnit=CargoUnit
31242
- self:F({CargoUnit:GetName(),UnLoaded=CargoUnit:IsUnLoaded()})
31433
+ self:T({CargoUnit:GetName(),UnLoaded=CargoUnit:IsUnLoaded()})
31243
31434
  if CargoUnit:IsUnLoaded()then
31244
31435
  CargoUnit.CargoObject:Destroy()
31245
31436
  GroupTemplate.units[#GroupTemplate.units+1]=self.CargoUnitTemplate[CargoUnitName]
@@ -31250,12 +31441,12 @@ GroupTemplate.units[#GroupTemplate.units].heading=CargoUnit:GetHeading()
31250
31441
  end
31251
31442
  end
31252
31443
  self.CargoGroup=GROUP:NewTemplate(GroupTemplate,GroupTemplate.CoalitionID,GroupTemplate.CategoryID,GroupTemplate.CountryID)
31253
- self:F({"Regroup",GroupTemplate})
31444
+ self:T({"Regroup",GroupTemplate})
31254
31445
  self.CargoObject=_DATABASE:Spawn(GroupTemplate)
31255
31446
  end
31256
31447
  end
31257
31448
  function CARGO_GROUP:OnEventCargoDead(EventData)
31258
- self:E(EventData)
31449
+ self:T(EventData)
31259
31450
  local Destroyed=false
31260
31451
  if self:IsDestroyed()or self:IsUnLoaded()or self:IsBoarding()or self:IsUnboarding()then
31261
31452
  Destroyed=true
@@ -31277,15 +31468,15 @@ end
31277
31468
  end
31278
31469
  if Destroyed then
31279
31470
  self:Destroyed()
31280
- self:E({"Cargo group destroyed"})
31471
+ self:T({"Cargo group destroyed"})
31281
31472
  end
31282
31473
  end
31283
31474
  function CARGO_GROUP:onafterBoard(From,Event,To,CargoCarrier,NearRadius,...)
31284
- self:F({CargoCarrier.UnitName,From,Event,To,NearRadius=NearRadius})
31475
+ self:T({CargoCarrier.UnitName,From,Event,To,NearRadius=NearRadius})
31285
31476
  NearRadius=NearRadius or self.NearRadius
31286
31477
  self.CargoSet:ForEach(
31287
31478
  function(Cargo,...)
31288
- self:F({"Board Unit",Cargo:GetName(),Cargo:IsDestroyed(),Cargo.CargoObject:IsAlive()})
31479
+ self:T({"Board Unit",Cargo:GetName(),Cargo:IsDestroyed(),Cargo.CargoObject:IsAlive()})
31289
31480
  local CargoGroup=Cargo.CargoObject
31290
31481
  CargoGroup:OptionAlarmStateGreen()
31291
31482
  Cargo:__Board(1,CargoCarrier,NearRadius,...)
@@ -31326,7 +31517,7 @@ if not Cancelled then
31326
31517
  if not Boarded then
31327
31518
  self:__Boarding(-5,CargoCarrier,NearRadius,...)
31328
31519
  else
31329
- self:F("Group Cargo is loaded")
31520
+ self:T("Group Cargo is loaded")
31330
31521
  self:__Load(1,CargoCarrier,...)
31331
31522
  end
31332
31523
  else
@@ -31337,7 +31528,7 @@ self:__Destroyed(1,CargoCarrier,NearRadius,...)
31337
31528
  end
31338
31529
  end
31339
31530
  function CARGO_GROUP:onafterUnBoard(From,Event,To,ToPointVec2,NearRadius,...)
31340
- self:F({From,Event,To,ToPointVec2,NearRadius})
31531
+ self:T({From,Event,To,ToPointVec2,NearRadius})
31341
31532
  NearRadius=NearRadius or 25
31342
31533
  local Timer=1
31343
31534
  if From=="Loaded"then
@@ -31446,12 +31637,12 @@ end
31446
31637
  )
31447
31638
  end
31448
31639
  function CARGO_GROUP:IsNear(CargoCarrier,NearRadius)
31449
- self:F({NearRadius=NearRadius})
31640
+ self:T({NearRadius=NearRadius})
31450
31641
  for _,Cargo in pairs(self.CargoSet:GetSet())do
31451
31642
  local Cargo=Cargo
31452
31643
  if Cargo:IsAlive()then
31453
31644
  if Cargo:IsNear(CargoCarrier:GetCoordinate(),NearRadius)then
31454
- self:F("Near")
31645
+ self:T("Near")
31455
31646
  return true
31456
31647
  end
31457
31648
  end
@@ -31473,7 +31664,7 @@ Distance=Coordinate:Get2DDistance(CargoCoordinate)
31473
31664
  else
31474
31665
  return false
31475
31666
  end
31476
- self:F({Distance=Distance,LoadRadius=self.LoadRadius})
31667
+ self:T({Distance=Distance,LoadRadius=self.LoadRadius})
31477
31668
  if Distance<=self.LoadRadius then
31478
31669
  return true
31479
31670
  else
@@ -31485,7 +31676,7 @@ end
31485
31676
  function CARGO_GROUP:IsInReportRadius(Coordinate)
31486
31677
  local Cargo=self:GetFirstAlive()
31487
31678
  if Cargo then
31488
- self:F({Cargo})
31679
+ self:T({Cargo})
31489
31680
  local Distance=0
31490
31681
  if Cargo:IsUnLoaded()then
31491
31682
  Distance=Coordinate:Get2DDistance(Cargo.CargoObject:GetCoordinate())
@@ -32968,7 +33159,7 @@ self:HandleEvent(EVENTS.Shot,self.HandleEventShot)
32968
33159
  self:SetStartState("Running")
32969
33160
  self:AddTransition("*","ManageEvasion","*")
32970
33161
  self:AddTransition("*","CalculateHitZone","*")
32971
- self:I("*** SEAD - Started Version 0.4.5")
33162
+ self:I("*** SEAD - Started Version 0.4.6")
32972
33163
  return self
32973
33164
  end
32974
33165
  function SEAD:UpdateSet(SEADGroupPrefixes)
@@ -33140,7 +33331,7 @@ if self.UseEmissionsOnOff then
33140
33331
  grp:EnableEmission(false)
33141
33332
  end
33142
33333
  grp:OptionAlarmStateGreen()
33143
- grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
33334
+ grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond",true)
33144
33335
  if self.UseCallBack then
33145
33336
  local object=self.CallBack
33146
33337
  object:SeadSuppressionStart(grp,name,attacker)
@@ -35023,9 +35214,9 @@ local minheight=self.RadarBlurMinHeight or 250
35023
35214
  local thresheight=self.RadarBlurThresHeight or 90
35024
35215
  local thresblur=self.RadarBlurThresBlur or 85
35025
35216
  local dist=math.floor(Distance)
35026
- if dist<=20 then
35027
- thresheight=(((dist*dist)/400)*thresheight)
35028
- thresblur=(((dist*dist)/400)*thresblur)
35217
+ if dist<=self.RadarBlurClosing then
35218
+ thresheight=(((dist*dist)/self.RadarBlurClosingSquare)*thresheight)
35219
+ thresblur=(((dist*dist)/self.RadarBlurClosingSquare)*thresblur)
35029
35220
  end
35030
35221
  local fheight=math.floor(math.random(1,10000)/100)
35031
35222
  local fblur=math.floor(math.random(1,10000)/100)
@@ -35199,11 +35390,13 @@ self._.FilterCategories[FilterCategories]=FilterCategories
35199
35390
  end
35200
35391
  return self
35201
35392
  end
35202
- function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur)
35393
+ function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur,closing)
35203
35394
  self.RadarBlur=true
35204
35395
  self.RadarBlurMinHeight=minheight or 250
35205
35396
  self.RadarBlurThresHeight=thresheight or 90
35206
35397
  self.RadarBlurThresBlur=thresblur or 85
35398
+ self.RadarBlurClosing=closing or 20
35399
+ self.RadarBlurClosingSquare=self.RadarBlurClosing*self.RadarBlurClosing
35207
35400
  return self
35208
35401
  end
35209
35402
  end
@@ -38334,7 +38527,7 @@ if takeoff==RAT.wp.air then
38334
38527
  departure=departure:GetZone()
38335
38528
  end
38336
38529
  elseif self:_ZoneExists(_departure)then
38337
- departure=ZONE:New(_departure)
38530
+ departure=ZONE:FindByName(_departure)
38338
38531
  else
38339
38532
  local text=string.format("ERROR! Specified departure airport %s does not exist for %s.",_departure,self.alias)
38340
38533
  self:E(RAT.id..text)
@@ -38405,7 +38598,7 @@ if landing==RAT.wp.air or self.returnzone then
38405
38598
  destination=destination:GetZone()
38406
38599
  end
38407
38600
  elseif self:_ZoneExists(_destination)then
38408
- destination=ZONE:New(_destination)
38601
+ destination=ZONE:FindByName(_destination)
38409
38602
  else
38410
38603
  local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!",_destination,self.alias)
38411
38604
  self:E(RAT.id.."ERROR: "..text)
@@ -38740,7 +38933,7 @@ end
38740
38933
  end
38741
38934
  elseif self:_ZoneExists(name)then
38742
38935
  if takeoff==RAT.wp.air then
38743
- dep=ZONE:New(name)
38936
+ dep=ZONE:FindByName(name)
38744
38937
  else
38745
38938
  self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.",name))
38746
38939
  end
@@ -38812,7 +39005,7 @@ end
38812
39005
  end
38813
39006
  elseif self:_ZoneExists(name)then
38814
39007
  if landing==RAT.wp.air then
38815
- dest=ZONE:New(name)
39008
+ dest=ZONE:FindByName(name)
38816
39009
  else
38817
39010
  self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!",name))
38818
39011
  end
@@ -39774,7 +39967,7 @@ end
39774
39967
  return false
39775
39968
  end
39776
39969
  function RAT:_ZoneExists(name)
39777
- local z=trigger.misc.getZone(name)
39970
+ local z=ZONE:FindByName(name)
39778
39971
  if z then
39779
39972
  return true
39780
39973
  end
@@ -40814,15 +41007,15 @@ self.trackmissiles=false
40814
41007
  return self
40815
41008
  end
40816
41009
  function RANGE:SetSRS(PathToSRS,Port,Coalition,Frequency,Modulation,Volume,PathToGoogleKey)
40817
- if PathToSRS then
41010
+ if PathToSRS or MSRS.path then
40818
41011
  self.useSRS=true
40819
- self.controlmsrs=MSRS:New(PathToSRS,Frequency or 256,Modulation or radio.modulation.AM,Volume or 1.0)
40820
- 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)
40821
41014
  self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE)
40822
41015
  self.controlmsrs:SetLabel("RANGEC")
40823
41016
  self.controlsrsQ=MSRSQUEUE:New("CONTROL")
40824
- self.instructmsrs=MSRS:New(PathToSRS,Frequency or 305,Modulation or radio.modulation.AM,Volume or 1.0)
40825
- 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)
40826
41019
  self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE)
40827
41020
  self.instructmsrs:SetLabel("RANGEI")
40828
41021
  self.instructsrsQ=MSRSQUEUE:New("INSTRUCT")
@@ -41111,6 +41304,7 @@ return fouldist
41111
41304
  end
41112
41305
  function RANGE:OnEventBirth(EventData)
41113
41306
  self:F({eventbirth=EventData})
41307
+ if not EventData.IniPlayerName then return end
41114
41308
  local _unitName=EventData.IniUnitName
41115
41309
  local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
41116
41310
  self:T3(self.lid.."BIRTH: unit = "..tostring(EventData.IniUnitName))
@@ -41367,7 +41561,7 @@ function RANGE:onafterExitRange(From,Event,To,player)
41367
41561
  if self.instructor then
41368
41562
  if self.useSRS then
41369
41563
  local text="You left the bombing range zone. "
41370
- local r=math.random(2)
41564
+ local r=math.random(5)
41371
41565
  if r==1 then
41372
41566
  text=text.."Have a nice day!"
41373
41567
  elseif r==2 then
@@ -51105,7 +51299,7 @@ MANTIS.SamData={
51105
51299
  ["SA-15"]={Range=11,Blindspot=0,Height=6,Type="Short",Radar="Tor 9A331"},
51106
51300
  ["SA-13"]={Range=5,Blindspot=0,Height=3,Type="Short",Radar="Strela"},
51107
51301
  ["Avenger"]={Range=4,Blindspot=0,Height=3,Type="Short",Radar="Avenger"},
51108
- ["Chaparrel"]={Range=8,Blindspot=0,Height=3,Type="Short",Radar="Chaparral"},
51302
+ ["Chaparral"]={Range=8,Blindspot=0,Height=3,Type="Short",Radar="Chaparral"},
51109
51303
  ["Linebacker"]={Range=4,Blindspot=0,Height=3,Type="Short",Radar="Linebacker"},
51110
51304
  ["Silkworm"]={Range=90,Blindspot=1,Height=0.2,Type="Long",Radar="Silkworm"},
51111
51305
  ["SA-10B"]={Range=75,Blindspot=0,Height=18,Type="Medium",Radar="SA-10B"},
@@ -51263,7 +51457,7 @@ end
51263
51457
  if self.HQ_Template_CC then
51264
51458
  self.HQ_CC=GROUP:FindByName(self.HQ_Template_CC)
51265
51459
  end
51266
- self.version="0.8.15"
51460
+ self.version="0.8.16"
51267
51461
  self:I(string.format("***** Starting MANTIS Version %s *****",self.version))
51268
51462
  self:SetStartState("Stopped")
51269
51463
  self:AddTransition("Stopped","Start","Running")
@@ -51524,7 +51718,7 @@ local HQGroup=self.HQ_CC
51524
51718
  if self.autorelocateunits.HQ and self.HQ_CC and HQGroup:IsAlive()then
51525
51719
  local _hqgrp=self.HQ_CC
51526
51720
  local text=self.lid.." Relocating HQ"
51527
- _hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
51721
+ _hqgrp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
51528
51722
  end
51529
51723
  if self.autorelocateunits.EWR then
51530
51724
  local EWR_GRP=SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterOnce()
@@ -51534,7 +51728,7 @@ if _grp:IsAlive()and _grp:IsGround()then
51534
51728
  local text=self.lid.." Relocating EWR ".._grp:GetName()
51535
51729
  local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
51536
51730
  if self.verbose then self:I(text)end
51537
- _grp:RelocateGroundRandomInRadius(20,500,true,true)
51731
+ _grp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
51538
51732
  end
51539
51733
  end
51540
51734
  end
@@ -52762,7 +52956,7 @@ HARD="TOPGUN Graduate",
52762
52956
  }
52763
52957
  AIRBOSS.MenuF10={}
52764
52958
  AIRBOSS.MenuF10Root=nil
52765
- AIRBOSS.version="1.3.2"
52959
+ AIRBOSS.version="1.3.3"
52766
52960
  function AIRBOSS:New(carriername,alias)
52767
52961
  local self=BASE:Inherit(self,FSM:New())
52768
52962
  self:F2({carriername=carriername,alias=alias})
@@ -53281,6 +53475,7 @@ self.SRS:SetGender(Gender or"male")
53281
53475
  self.SRS:SetPath(PathToSRS)
53282
53476
  self.SRS:SetPort(Port or 5002)
53283
53477
  self.SRS:SetLabel(self.AirbossRadio.alias or"AIRBOSS")
53478
+ self.SRS:SetCoordinate(self.carrier:GetCoordinate())
53284
53479
  if GoogleCreds then
53285
53480
  self.SRS:SetGoogle(GoogleCreds)
53286
53481
  end
@@ -55958,7 +56153,7 @@ self:E(self.lid.."ERROR: EventData=nil in event BIRTH!")
55958
56153
  self:E(EventData)
55959
56154
  return
55960
56155
  end
55961
- if EventData.IniUnit==nil then
56156
+ if EventData.IniUnit==nil and(not EventData.IniObjectCategory==Object.Category.STATIC)then
55962
56157
  self:E(self.lid.."ERROR: EventData.IniUnit=nil in event BIRTH!")
55963
56158
  self:E(EventData)
55964
56159
  return
@@ -57409,7 +57604,7 @@ text=text..string.format("\nWind Vx=%.1f Vy=%.1f Vz=%.1f m/s",wind.x,wind.y,wind
57409
57604
  end
57410
57605
  text=text..string.format("\nPitch=%.1f° | Roll=%.1f° | Yaw=%.1f°",pitch,roll,yaw)
57411
57606
  text=text..string.format("\nClimb Angle=%.1f° | Rate=%d ft/min",unit:GetClimbAngle(),velo.y*196.85)
57412
- local dist=self:_GetOptLandingCoordinate():Get3DDistance(playerData.unit)
57607
+ local dist=self:_GetOptLandingCoordinate():Get3DDistance(playerData.unit:GetVec3())
57413
57608
  local vplayer=playerData.unit:GetVelocityKMH()
57414
57609
  local vcarrier=self.carrier:GetVelocityKMH()
57415
57610
  local dv=math.abs(vplayer-vcarrier)
@@ -59273,7 +59468,7 @@ self.PilotRadio.alias="PILOT"
59273
59468
  self.PilotRadio.voice=Voice or MSRS.Voices.Microsoft.David
59274
59469
  self.PilotRadio.gender=Gender or"male"
59275
59470
  self.PilotRadio.culture=Culture or"en-US"
59276
- if(not Voice)and self.SRS and self.SRS.google then
59471
+ if(not Voice)and self.SRS and self.SRS:GetProvider()==MSRS.Provider.GOOGLE then
59277
59472
  self.PilotRadio.voice=MSRS.Voices.Google.Standard.en_US_Standard_J
59278
59473
  end
59279
59474
  return self
@@ -62556,7 +62751,7 @@ DELIMITER="Punto",
62556
62751
  }
62557
62752
  ATIS.locale="en"
62558
62753
  _ATIS={}
62559
- ATIS.version="0.10.4"
62754
+ ATIS.version="1.0.0"
62560
62755
  function ATIS:New(AirbaseName,Frequency,Modulation)
62561
62756
  local self=BASE:Inherit(self,FSM:New())
62562
62757
  self.airbasename=AirbaseName
@@ -64275,7 +64470,7 @@ CTLD.UnitTypeCapabilities={
64275
64470
  ["AH-64D_BLK_II"]={type="AH-64D_BLK_II",crates=false,troops=true,cratelimit=0,trooplimit=2,length=17,cargoweightlimit=200},
64276
64471
  ["Bronco-OV-10A"]={type="Bronco-OV-10A",crates=false,troops=true,cratelimit=0,trooplimit=5,length=13,cargoweightlimit=1450},
64277
64472
  }
64278
- CTLD.version="1.0.44"
64473
+ CTLD.version="1.0.45"
64279
64474
  function CTLD:New(Coalition,Prefixes,Alias)
64280
64475
  local self=BASE:Inherit(self,FSM:New())
64281
64476
  BASE:T({Coalition,Prefixes,Alias})
@@ -64982,10 +65177,12 @@ realcargo=CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,crat
64982
65177
  table.insert(droppedcargo,realcargo)
64983
65178
  else
64984
65179
  realcargo=CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat)
64985
- Cargo:RemoveStock()
64986
65180
  end
64987
65181
  table.insert(self.Spawned_Cargo,realcargo)
64988
65182
  end
65183
+ if not(drop or pack)then
65184
+ Cargo:RemoveStock()
65185
+ end
64989
65186
  local text=string.format("Crates for %s have been positioned near you!",cratename)
64990
65187
  if drop then
64991
65188
  text=string.format("Crates for %s have been dropped!",cratename)
@@ -78076,6 +78273,15 @@ trigger.action.outSoundForUnit(Unit:GetID(),self.UserSoundFileName)
78076
78273
  end
78077
78274
  return self
78078
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
78079
78285
  end
78080
78286
  do
78081
78287
  SOUNDBASE={
@@ -78118,18 +78324,25 @@ subtitle=nil,
78118
78324
  subduration=0,
78119
78325
  useSRS=false,
78120
78326
  }
78121
- function SOUNDFILE:New(FileName,Path,Duration)
78327
+ function SOUNDFILE:New(FileName,Path,Duration,UseSrs)
78122
78328
  local self=BASE:Inherit(self,BASE:New())
78329
+ self:F({FileName,Path,Duration,UseSrs})
78123
78330
  self:SetFileName(FileName)
78331
+ self:SetPlayWithSRS(UseSrs or false)
78124
78332
  self:SetPath(Path)
78125
78333
  self:SetDuration(Duration)
78126
- self:T(string.format("New SOUNDFILE: file name=%s, path=%s",self.filename,self.path))
78127
78334
  return self
78128
78335
  end
78129
78336
  function SOUNDFILE:SetPath(Path)
78130
- self.path=Path or"l10n/DEFAULT/"
78131
- if not Path and self.useSRS then
78132
- self.path=os.getenv('TMP').."\\DCS\\Mission\\l10n\\DEFAULT"
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
78133
78346
  end
78134
78347
  local nmax=1000;local n=1
78135
78348
  while(self.path:sub(-1)=="/"or self.path:sub(-1)==[[\]])and n<=nmax do
@@ -78137,6 +78350,7 @@ self.path=self.path:sub(1,#self.path-1)
78137
78350
  n=n+1
78138
78351
  end
78139
78352
  self.path=self.path.."/"
78353
+ self:T("self.path="..self.path)
78140
78354
  return self
78141
78355
  end
78142
78356
  function SOUNDFILE:GetPath()
@@ -78164,11 +78378,13 @@ local name=string.format("%s%s",path,filename)
78164
78378
  return name
78165
78379
  end
78166
78380
  function SOUNDFILE:SetPlayWithSRS(Switch)
78381
+ self:F({Switch})
78167
78382
  if Switch==true or Switch==nil then
78168
78383
  self.useSRS=true
78169
78384
  else
78170
78385
  self.useSRS=false
78171
78386
  end
78387
+ self:T("self.useSRS="..tostring(self.useSRS))
78172
78388
  return self
78173
78389
  end
78174
78390
  end
@@ -78932,6 +79148,7 @@ ClassName="MSRS",
78932
79148
  lid=nil,
78933
79149
  port=5002,
78934
79150
  name="MSRS",
79151
+ backend="srsexe",
78935
79152
  frequencies={},
78936
79153
  modulations={},
78937
79154
  coalition=0,
@@ -78941,14 +79158,14 @@ voice=nil,
78941
79158
  volume=1,
78942
79159
  speed=1,
78943
79160
  coordinate=nil,
79161
+ provider="win",
78944
79162
  Label="ROBOT",
78945
- AltBackend=nil,
78946
79163
  ConfigFileName="Moose_MSRS.lua",
78947
79164
  ConfigFilePath="Config\\",
78948
79165
  ConfigLoaded=false,
78949
- ttsprovider="Microsoft",
79166
+ poptions={},
78950
79167
  }
78951
- MSRS.version="0.1.3"
79168
+ MSRS.version="0.3.0"
78952
79169
  MSRS.Voices={
78953
79170
  Microsoft={
78954
79171
  ["Hedda"]="Microsoft Hedda Desktop",
@@ -79047,47 +79264,52 @@ Wavenet={
79047
79264
  },
79048
79265
  },
79049
79266
  }
79050
- MSRS.GRPCOptions={}
79051
- MSRS.GRPCOptions.gcloud={}
79052
- MSRS.GRPCOptions.win={}
79053
- MSRS.GRPCOptions.azure={}
79054
- MSRS.GRPCOptions.aws={}
79055
- MSRS.GRPCOptions.win.defaultVoice="Hedda"
79056
- MSRS.GRPCOptions.win.voice="Hedda"
79057
- MSRS.GRPCOptions.DefaultProvider="win"
79058
- function MSRS:New(PathToSRS,Frequency,Modulation,Volume,AltBackend)
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})
79059
79288
  Frequency=Frequency or 143
79060
79289
  Modulation=Modulation or radio.modulation.AM
79061
- local self=BASE:Inherit(self,BASE:New())
79062
- if type(AltBackend)=="table"or type(self.AltBackend)=="table"then
79063
- local Backend=UTILS.DeepCopy(AltBackend)or UTILS.DeepCopy(self.AltBackend)
79064
- Backend.Vars=Backend.Vars or{}
79065
- Backend.Vars.PathToSRS=PathToSRS
79066
- Backend.Vars.Frequency=UTILS.DeepCopy(Frequency)
79067
- Backend.Vars.Modulation=UTILS.DeepCopy(Modulation)
79068
- Backend.Vars.Volume=Volume
79069
- Backend.Functions=Backend.Functions or{}
79070
- return self:_NewAltBackend(Backend)
79071
- end
79290
+ self.lid=string.format("%s-%s | ","unknown",self.version)
79072
79291
  if not self.ConfigLoaded then
79073
- self:SetPath(PathToSRS)
79292
+ self:SetPath(Path)
79074
79293
  self:SetPort()
79075
79294
  self:SetFrequencies(Frequency)
79076
79295
  self:SetModulations(Modulation)
79077
79296
  self:SetGender()
79078
79297
  self:SetCoalition()
79079
79298
  self:SetLabel()
79080
- self:SetVolume(Volume)
79299
+ self:SetVolume()
79300
+ self:SetBackend(Backend)
79081
79301
  else
79082
- if PathToSRS then
79083
- self:SetPath(PathToSRS)
79302
+ if Path then
79303
+ self:SetPath(Path)
79084
79304
  end
79085
79305
  if Frequency then
79086
79306
  self:SetFrequencies(Frequency)
79307
+ end
79308
+ if Modulation then
79087
79309
  self:SetModulations(Modulation)
79088
79310
  end
79089
- if Volume then
79090
- self:SetVolume(Volume)
79311
+ if Backend then
79312
+ self:SetBackend(Backend)
79091
79313
  end
79092
79314
  end
79093
79315
  self.lid=string.format("%s-%s | ",self.name,self.version)
@@ -79096,26 +79318,48 @@ self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
79096
79318
  end
79097
79319
  return self
79098
79320
  end
79099
- function MSRS:SetPath(Path)
79100
- if Path==nil and not self.path then
79101
- self:E("ERROR: No path to SRS directory specified!")
79102
- return nil
79321
+ function MSRS:SetBackend(Backend)
79322
+ self:F({Backend=Backend})
79323
+ self.backend=Backend or MSRS.Backend.SRSEXE
79324
+ return self
79103
79325
  end
79104
- if Path then
79105
- self.path=Path
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"
79106
79350
  local n=1;local nmax=1000
79107
79351
  while(self.path:sub(-1)=="/"or self.path:sub(-1)==[[\]])and n<=nmax do
79108
79352
  self.path=self.path:sub(1,#self.path-1)
79109
79353
  n=n+1
79110
79354
  end
79111
- self:T(string.format("SRS path=%s",self:GetPath()))
79112
- end
79355
+ self:F(string.format("SRS path=%s",self:GetPath()))
79113
79356
  return self
79114
79357
  end
79115
79358
  function MSRS:GetPath()
79116
79359
  return self.path
79117
79360
  end
79118
79361
  function MSRS:SetVolume(Volume)
79362
+ self:F({Volume=Volume})
79119
79363
  local volume=Volume or 1
79120
79364
  if volume>1 then volume=1 elseif volume<0 then volume=0 end
79121
79365
  self.volume=volume
@@ -79125,6 +79369,7 @@ function MSRS:GetVolume()
79125
79369
  return self.volume
79126
79370
  end
79127
79371
  function MSRS:SetLabel(Label)
79372
+ self:F({Label=Label})
79128
79373
  self.Label=Label or"ROBOT"
79129
79374
  return self
79130
79375
  end
@@ -79132,13 +79377,16 @@ function MSRS:GetLabel()
79132
79377
  return self.Label
79133
79378
  end
79134
79379
  function MSRS:SetPort(Port)
79380
+ self:F({Port=Port})
79135
79381
  self.port=Port or 5002
79382
+ self:T(string.format("SRS port=%s",self:GetPort()))
79136
79383
  return self
79137
79384
  end
79138
79385
  function MSRS:GetPort()
79139
79386
  return self.port
79140
79387
  end
79141
79388
  function MSRS:SetCoalition(Coalition)
79389
+ self:F({Coalition=Coalition})
79142
79390
  self.coalition=Coalition or 0
79143
79391
  return self
79144
79392
  end
@@ -79146,17 +79394,14 @@ function MSRS:GetCoalition()
79146
79394
  return self.coalition
79147
79395
  end
79148
79396
  function MSRS:SetFrequencies(Frequencies)
79149
- if type(Frequencies)~="table"then
79150
- Frequencies={Frequencies}
79151
- end
79152
- self.frequencies=Frequencies
79397
+ self:F(Frequencies)
79398
+ self.frequencies=UTILS.EnsureTable(Frequencies,false)
79153
79399
  return self
79154
79400
  end
79155
79401
  function MSRS:AddFrequencies(Frequencies)
79156
- if type(Frequencies)~="table"then
79157
- Frequencies={Frequencies}
79158
- end
79159
- 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)))
79160
79405
  table.insert(self.frequencies,_freq)
79161
79406
  end
79162
79407
  return self
@@ -79165,17 +79410,15 @@ function MSRS:GetFrequencies()
79165
79410
  return self.frequencies
79166
79411
  end
79167
79412
  function MSRS:SetModulations(Modulations)
79168
- if type(Modulations)~="table"then
79169
- Modulations={Modulations}
79170
- end
79171
- self.modulations=Modulations
79413
+ self:F(Modulations)
79414
+ self.modulations=UTILS.EnsureTable(Modulations,false)
79415
+ self:T(self.lid.."Modulations:")
79416
+ self:T(self.modulations)
79172
79417
  return self
79173
79418
  end
79174
79419
  function MSRS:AddModulations(Modulations)
79175
- if type(Modulations)~="table"then
79176
- Modulations={Modulations}
79177
- end
79178
- for _,_mod in pairs(Modulations)do
79420
+ self:F(Modulations)
79421
+ for _,_mod in pairs(UTILS.EnsureTable(Modulations,false))do
79179
79422
  table.insert(self.modulations,_mod)
79180
79423
  end
79181
79424
  return self
@@ -79184,92 +79427,176 @@ function MSRS:GetModulations()
79184
79427
  return self.modulations
79185
79428
  end
79186
79429
  function MSRS:SetGender(Gender)
79430
+ self:F({Gender=Gender})
79187
79431
  Gender=Gender or"female"
79188
79432
  self.gender=Gender:lower()
79189
79433
  self:T("Setting gender to "..tostring(self.gender))
79190
79434
  return self
79191
79435
  end
79192
79436
  function MSRS:SetCulture(Culture)
79437
+ self:F({Culture=Culture})
79193
79438
  self.culture=Culture
79194
79439
  return self
79195
79440
  end
79196
79441
  function MSRS:SetVoice(Voice)
79442
+ self:F({Voice=Voice})
79197
79443
  self.voice=Voice
79198
79444
  return self
79199
79445
  end
79200
- function MSRS:SetDefaultVoice(Voice)
79201
- self.defaultVoice=Voice
79202
- local provider=self.provider or self.GRPCOptions.DefaultProvider or MSRS.GRPCOptions.DefaultProvider or"win"
79203
- self.GRPCOptions[provider].defaultVoice=Voice
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)
79455
+ return self
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)
79204
79470
  return self
79205
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
79206
79480
  function MSRS:SetCoordinate(Coordinate)
79481
+ self:F(Coordinate)
79207
79482
  self.coordinate=Coordinate
79208
79483
  return self
79209
79484
  end
79210
79485
  function MSRS:SetGoogle(PathToCredentials)
79486
+ self:F({PathToCredentials=PathToCredentials})
79211
79487
  if PathToCredentials then
79212
- self.google=PathToCredentials
79213
- self.APIKey=PathToCredentials
79214
- self.provider="gcloud"
79215
- self.GRPCOptions.DefaultProvider="gcloud"
79216
- self.GRPCOptions.gcloud.key=PathToCredentials
79217
- self.ttsprovider="Google"
79488
+ self.provider=MSRS.Provider.GOOGLE
79489
+ self:SetProviderOptionsGoogle(PathToCredentials,PathToCredentials)
79218
79490
  end
79219
79491
  return self
79220
79492
  end
79221
79493
  function MSRS:SetGoogleAPIKey(APIKey)
79494
+ self:F({APIKey=APIKey})
79222
79495
  if APIKey then
79223
- self.APIKey=APIKey
79224
- self.provider="gcloud"
79225
- self.GRPCOptions.DefaultProvider="gcloud"
79226
- self.GRPCOptions.gcloud.key=APIKey
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
79227
79544
  end
79545
+ function MSRS:SetProviderOptionsAzure(AccessKey,Region)
79546
+ self:F({AccessKey,Region})
79547
+ self:SetProviderOptions(MSRS.Provider.AZURE,nil,AccessKey,nil,Region)
79228
79548
  return self
79229
79549
  end
79550
+ function MSRS:GetProviderOptions(Provider)
79551
+ return self.poptions[Provider or self.provider]or{}
79552
+ end
79230
79553
  function MSRS:SetTTSProviderGoogle()
79231
- self.ttsprovider="Google"
79554
+ self:F()
79555
+ self:SetProvider(MSRS.Provider.GOOGLE)
79232
79556
  return self
79233
79557
  end
79234
79558
  function MSRS:SetTTSProviderMicrosoft()
79235
- self.ttsprovider="Microsoft"
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)
79236
79571
  return self
79237
79572
  end
79238
79573
  function MSRS:Help()
79239
- local path=self:GetPath()or STTS.DIRECTORY
79240
- local exe=STTS.EXECUTABLE or"DCS-SR-ExternalAudio.exe"
79241
- local filename=os.getenv('TMP').."\\MSRS-help-"..STTS.uuid()..".txt"
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"
79242
79578
  local command=string.format("%s/%s --help > %s",path,exe,filename)
79243
79579
  os.execute(command)
79244
79580
  local f=assert(io.open(filename,"rb"))
79245
79581
  local data=f:read("*all")
79246
79582
  f:close()
79247
- env.info("SRS STTS help output:")
79583
+ env.info("SRS help output:")
79248
79584
  env.info("======================================================================")
79249
79585
  env.info(data)
79250
79586
  env.info("======================================================================")
79251
79587
  return self
79252
79588
  end
79253
- function MSRS.SetDefaultBackend(Backend)
79254
- if type(Backend)=="table"then
79255
- MSRS.AltBackend=UTILS.DeepCopy(Backend)
79256
- else
79257
- return false
79258
- end
79259
- return true
79260
- end
79261
- function MSRS.ResetDefaultBackend()
79262
- MSRS.AltBackend=nil
79263
- return true
79264
- end
79265
- function MSRS.SetDefaultBackendGRPC()
79266
- return MSRS.SetDefaultBackend(MSRS_BACKEND_DCSGRPC)
79267
- end
79268
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
79269
79597
  if Delay and Delay>0 then
79270
79598
  self:ScheduleOnce(Delay,MSRS.PlaySoundFile,self,Soundfile,0)
79271
79599
  else
79272
- local soundfile=Soundfile:GetName()
79273
79600
  local command=self:_GetCommand()
79274
79601
  command=command..' --file="'..tostring(soundfile)..'"'
79275
79602
  self:_ExecCommand(command)
@@ -79277,42 +79604,53 @@ end
79277
79604
  return self
79278
79605
  end
79279
79606
  function MSRS:PlaySoundText(SoundText,Delay)
79607
+ self:F({SoundText,Delay})
79280
79608
  if Delay and Delay>0 then
79281
79609
  self:ScheduleOnce(Delay,MSRS.PlaySoundText,self,SoundText,0)
79282
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
79283
79614
  local command=self:_GetCommand(nil,nil,nil,SoundText.gender,SoundText.voice,SoundText.culture,SoundText.volume,SoundText.speed)
79284
79615
  command=command..string.format(" --text=\"%s\"",tostring(SoundText.text))
79285
79616
  self:_ExecCommand(command)
79286
79617
  end
79618
+ end
79287
79619
  return self
79288
79620
  end
79289
79621
  function MSRS:PlayText(Text,Delay,Coordinate)
79622
+ self:F({Text,Delay,Coordinate})
79290
79623
  if Delay and Delay>0 then
79291
79624
  self:ScheduleOnce(Delay,MSRS.PlayText,self,Text,nil,Coordinate)
79292
79625
  else
79293
- local command=self:_GetCommand(nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,Coordinate)
79294
- command=command..string.format(" --text=\"%s\"",tostring(Text))
79295
- self:_ExecCommand(command)
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
79296
79632
  end
79297
79633
  return self
79298
79634
  end
79299
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})
79300
79637
  if Delay and Delay>0 then
79301
79638
  self:ScheduleOnce(Delay,MSRS.PlayTextExt,self,Text,0,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label,Coordinate)
79302
79639
  else
79303
- if Frequencies and type(Frequencies)~="table"then
79304
- Frequencies={Frequencies}
79305
- end
79306
- if Modulations and type(Modulations)~="table"then
79307
- Modulations={Modulations}
79308
- end
79309
- 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)
79310
79644
  command=command..string.format(" --text=\"%s\"",tostring(Text))
79311
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
79312
79649
  end
79313
79650
  return self
79314
79651
  end
79315
79652
  function MSRS:PlayTextFile(TextFile,Delay)
79653
+ self:F({TextFile,Delay})
79316
79654
  if Delay and Delay>0 then
79317
79655
  self:ScheduleOnce(Delay,MSRS.PlayTextFile,self,TextFile,0)
79318
79656
  else
@@ -79325,51 +79663,96 @@ local command=self:_GetCommand()
79325
79663
  command=command..string.format(" --textFile=\"%s\"",tostring(TextFile))
79326
79664
  self:T(string.format("MSRS TextFile command=%s",command))
79327
79665
  local l=string.len(command)
79666
+ self:T(string.format("Command length=%d",l))
79328
79667
  self:_ExecCommand(command)
79329
79668
  end
79330
79669
  return self
79331
79670
  end
79332
- function MSRS:_NewAltBackend(Backend)
79333
- BASE:T('Entering MSRS:_NewAltBackend()')
79334
- for funcName,funcDef in pairs(Backend.Functions)do
79335
- if type(funcDef)=='function'then
79336
- BASE:T('MSRS (re-)defining function MSRS:'..funcName)
79337
- self[funcName]=funcDef
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)
79338
79678
  end
79679
+ return lat,lon,math.floor(alt)
79339
79680
  end
79340
- for varName,varVal in pairs(Backend.Vars)do
79341
- BASE:T('MSRS setting self.'..varName)
79342
- self[varName]=UTILS.DeepCopy(varVal)
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))
79343
79705
  end
79344
- if self._MSRSbackendInit and type(self._MSRSbackendInit)=='function'then
79345
- return self:_MSRSbackendInit()
79706
+ if culture and culture~="en-GB"then
79707
+ command=command..string.format(" -l %s",tostring(culture))
79346
79708
  end
79347
- return self
79709
+ end
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)
79713
+ end
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 ")
79720
+ end
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
79348
79727
  end
79349
79728
  function MSRS:_ExecCommand(command)
79350
- self:T("SRS TTS command="..command)
79351
- local filename=os.getenv('TMP').."\\MSRS-"..STTS.uuid()..".bat"
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"
79352
79733
  local script=io.open(filename,"w+")
79353
- script:write(command.." && exit")
79734
+ script:write(batContent)
79354
79735
  script:close()
79355
- command=string.format('start /b "" "%s"',filename)
79736
+ self:T("MSRS batch file created: "..filename)
79737
+ self:T("MSRS batch content: "..batContent)
79356
79738
  local res=nil
79357
79739
  if true then
79358
- local filenvbs=os.getenv('TMP').."\\MSRS-"..STTS.uuid()..".vbs"
79740
+ local filenvbs=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".vbs"
79359
79741
  local script=io.open(filenvbs,"w+")
79360
79742
  script:write(string.format('Dim WinScriptHost\n'))
79361
79743
  script:write(string.format('Set WinScriptHost = CreateObject("WScript.Shell")\n'))
79362
79744
  script:write(string.format('WinScriptHost.Run Chr(34) & "%s" & Chr(34), 0\n',filename))
79363
79745
  script:write(string.format('Set WinScriptHost = Nothing'))
79364
79746
  script:close()
79747
+ self:T("MSRS vbs file created to start batch="..filenvbs)
79365
79748
  local runvbs=string.format('cscript.exe //Nologo //B "%s"',filenvbs)
79366
- self:T("MSRS execute command="..command)
79367
79749
  self:T("MSRS execute VBS command="..runvbs)
79368
79750
  res=os.execute(runvbs)
79369
79751
  timer.scheduleFunction(os.remove,filename,timer.getTime()+1)
79370
79752
  timer.scheduleFunction(os.remove,filenvbs,timer.getTime()+1)
79753
+ self:T("MSRS vbs and batch file removed")
79371
79754
  elseif false then
79372
- local filenvbs=os.getenv('TMP').."\\MSRS-"..STTS.uuid()..".vbs"
79755
+ local filenvbs=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".vbs"
79373
79756
  local script=io.open(filenvbs,"w+")
79374
79757
  script:write(string.format('Set oShell = CreateObject ("Wscript.Shell")\n'))
79375
79758
  script:write(string.format('Dim strArgs\n'))
@@ -79379,52 +79762,53 @@ script:close()
79379
79762
  local runvbs=string.format('cscript.exe //Nologo //B "%s"',filenvbs)
79380
79763
  res=os.execute(runvbs)
79381
79764
  else
79765
+ command=string.format('start /b "" "%s"',filename)
79382
79766
  self:T("MSRS execute command="..command)
79383
79767
  res=os.execute(command)
79384
79768
  timer.scheduleFunction(os.remove,filename,timer.getTime()+1)
79385
79769
  end
79386
79770
  return res
79387
79771
  end
79388
- function MSRS:_GetLatLongAlt(Coordinate)
79389
- local lat,lon,alt=coord.LOtoLL(Coordinate)
79390
- return lat,lon,math.floor(alt)
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)
79391
79783
  end
79392
- function MSRS:_GetCommand(freqs,modus,coal,gender,voice,culture,volume,speed,port,label,coordinate)
79393
- local path=self:GetPath()or STTS.DIRECTORY
79394
- local exe=STTS.EXECUTABLE or"DCS-SR-ExternalAudio.exe"
79395
- freqs=table.concat(freqs or self.frequencies,",")
79396
- modus=table.concat(modus or self.modulations,",")
79397
- coal=coal or self.coalition
79398
- gender=gender or self.gender
79399
- voice=voice or self.voice
79400
- culture=culture or self.culture
79401
- volume=volume or self.volume
79402
- speed=speed or self.speed
79403
- port=port or self.port
79404
- label=label or self.Label
79405
- coordinate=coordinate or self.coordinate
79406
- modus=modus:gsub("0","AM")
79407
- modus=modus:gsub("1","FM")
79408
- 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)
79409
- if voice then
79410
- 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
79411
79792
  else
79412
- if gender and gender~="female"then
79413
- command=command..string.format(" -g %s",tostring(gender))
79793
+ local preTag,genderProp,langProp,postTag='','','',''
79794
+ local gender=""
79795
+ if self.gender then
79796
+ gender=string.format(' gender=\"%s\"',self.gender)
79414
79797
  end
79415
- if culture and culture~="en-GB"then
79416
- command=command..string.format(" -l %s",tostring(culture))
79798
+ local language=""
79799
+ if self.culture then
79800
+ language=string.format(' language=\"%s\"',self.culture)
79417
79801
  end
79802
+ if self.gender or self.culture then
79803
+ ssml=string.format("<voice%s%s>%s</voice>",gender,language,Text)
79418
79804
  end
79419
- if coordinate then
79420
- local lat,lon,alt=self:_GetLatLongAlt(coordinate)
79421
- command=command..string.format(" -L %.4f -O %.4f -A %d",lat,lon,alt)
79422
79805
  end
79423
- if self.google and self.ttsprovider=="Google"then
79424
- command=command..string.format(' --ssml -G "%s"',self.google)
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)
79425
79811
  end
79426
- self:T("MSRS command="..command)
79427
- return command
79428
79812
  end
79429
79813
  function MSRS:LoadConfigFile(Path,Filename)
79430
79814
  if lfs==nil then
@@ -79436,63 +79820,30 @@ local file=Filename or MSRS.ConfigFileName or"Moose_MSRS.lua"
79436
79820
  local pathandfile=path..file
79437
79821
  local filexsists=UTILS.FileExists(pathandfile)
79438
79822
  if filexsists and not MSRS.ConfigLoaded then
79823
+ env.info("FF reading config file")
79439
79824
  assert(loadfile(path..file))()
79440
79825
  if MSRS_Config then
79441
- if self then
79442
- self.path=MSRS_Config.Path or"C:\\Program Files\\DCS-SimpleRadio-Standalone"
79443
- self.port=MSRS_Config.Port or 5002
79444
- self.frequencies=MSRS_Config.Frequency or{127,243}
79445
- self.modulations=MSRS_Config.Modulation or{0,0}
79446
- self.coalition=MSRS_Config.Coalition or 0
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
79447
79833
  if MSRS_Config.Coordinate then
79448
- self.coordinate=COORDINATE:New(MSRS_Config.Coordinate[1],MSRS_Config.Coordinate[2],MSRS_Config.Coordinate[3])
79449
- end
79450
- self.culture=MSRS_Config.Culture or"en-GB"
79451
- self.gender=MSRS_Config.Gender or"male"
79452
- self.google=MSRS_Config.Google
79453
- if MSRS_Config.Provider then
79454
- self.ttsprovider=MSRS_Config.Provider
79455
- end
79456
- self.Label=MSRS_Config.Label or"MSRS"
79457
- self.voice=MSRS_Config.Voice
79458
- if MSRS_Config.GRPC then
79459
- self.provider=MSRS_Config.GRPC.DefaultProvider
79460
- if MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider]then
79461
- self.APIKey=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].key
79462
- self.defaultVoice=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].defaultVoice
79463
- self.region=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].secret
79464
- self.secret=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].region
79465
- end
79466
- end
79467
- self.ConfigLoaded=true
79468
- else
79469
- MSRS.path=MSRS_Config.Path or"C:\\Program Files\\DCS-SimpleRadio-Standalone"
79470
- MSRS.port=MSRS_Config.Port or 5002
79471
- MSRS.frequencies=MSRS_Config.Frequency or{127,243}
79472
- MSRS.modulations=MSRS_Config.Modulation or{0,0}
79473
- MSRS.coalition=MSRS_Config.Coalition or 0
79474
- if MSRS_Config.Coordinate then
79475
- MSRS.coordinate=COORDINATE:New(MSRS_Config.Coordinate[1],MSRS_Config.Coordinate[2],MSRS_Config.Coordinate[3])
79476
- end
79477
- MSRS.culture=MSRS_Config.Culture or"en-GB"
79478
- MSRS.gender=MSRS_Config.Gender or"male"
79479
- MSRS.google=MSRS_Config.Google
79480
- if MSRS_Config.Provider then
79481
- MSRS.ttsprovider=MSRS_Config.Provider
79482
- end
79483
- MSRS.Label=MSRS_Config.Label or"MSRS"
79484
- MSRS.voice=MSRS_Config.Voice
79485
- if MSRS_Config.GRPC then
79486
- MSRS.provider=MSRS_Config.GRPC.DefaultProvider
79487
- if MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider]then
79488
- MSRS.APIKey=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].key
79489
- MSRS.defaultVoice=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].defaultVoice
79490
- MSRS.region=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].secret
79491
- MSRS.secret=MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider].region
79834
+ Self.coordinate=COORDINATE:New(MSRS_Config.Coordinate[1],MSRS_Config.Coordinate[2],MSRS_Config.Coordinate[3])
79492
79835
  end
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]
79493
79844
  end
79494
- MSRS.ConfigLoaded=true
79495
79845
  end
79846
+ Self.ConfigLoaded=true
79496
79847
  end
79497
79848
  env.info("MSRS - Successfully loaded default configuration from disk!",false)
79498
79849
  end
@@ -79502,151 +79853,27 @@ return false
79502
79853
  end
79503
79854
  return true
79504
79855
  end
79505
- MSRS_BACKEND_DCSGRPC={}
79506
- MSRS_BACKEND_DCSGRPC.version=0.1
79507
- MSRS_BACKEND_DCSGRPC.Functions={}
79508
- MSRS_BACKEND_DCSGRPC.Vars={provider='win'}
79509
- MSRS_BACKEND_DCSGRPC.Functions._MSRSbackendInit=function(self)
79510
- BASE:I('Loaded MSRS DCS-gRPC alternate backend version '..self.AltBackend.version or'unspecified')
79511
- return self
79512
- end
79513
- MSRS_BACKEND_DCSGRPC.Functions.SetPath=function(self)
79514
- return self
79515
- end
79516
- MSRS_BACKEND_DCSGRPC.Functions.GetPath=function(self)
79517
- return''
79518
- end
79519
- MSRS_BACKEND_DCSGRPC.Functions.SetVolume=function(self)
79520
- BASE:I('NOTE: MSRS:SetVolume() not used with DCS-gRPC backend.')
79521
- return self
79522
- end
79523
- MSRS_BACKEND_DCSGRPC.Functions.GetVolume=function(self)
79524
- BASE:I('NOTE: MSRS:GetVolume() not used with DCS-gRPC backend.')
79525
- return 1
79526
- end
79527
- MSRS_BACKEND_DCSGRPC.Functions.SetGender=function(self,Gender)
79528
- if Gender then
79529
- self.gender=Gender:lower()
79530
- end
79531
- self:T("Setting gender to "..tostring(self.gender))
79532
- return self
79533
- end
79534
- MSRS_BACKEND_DCSGRPC.Functions.SetGoogle=function(self)
79535
- self.provider='gcloud'
79536
- return self
79537
- end
79538
- MSRS_BACKEND_DCSGRPC.Functions.SetAPIKey=function(self,key)
79539
- self.APIKey=key
79540
- return self
79541
- end
79542
- MSRS_BACKEND_DCSGRPC.Functions.SetDefaultVoice=function(self,voice)
79543
- self.defaultVoice=voice
79544
- return self
79545
- end
79546
- MSRS_BACKEND_DCSGRPC.Functions.SetAWS=function(self)
79547
- self.provider='aws'
79548
- return self
79549
- end
79550
- MSRS_BACKEND_DCSGRPC.Functions.SetAzure=function(self)
79551
- self.provider='azure'
79552
- return self
79553
- end
79554
- MSRS_BACKEND_DCSGRPC.Functions.SetWin=function(self)
79555
- self.provider='win'
79556
- return self
79557
- end
79558
- MSRS_BACKEND_DCSGRPC.Functions.Help=function(self)
79559
- env.info('For DCS-gRPC help, please see: https://github.com/DCS-gRPC/rust-server')
79560
- return self
79561
- end
79562
- MSRS_BACKEND_DCSGRPC.Functions.PlaySoundFile=function(self)
79563
- BASE:E("ERROR: MSRS:PlaySoundFile() is not supported by the DCS-gRPC backend.")
79564
- return self
79565
- end
79566
- MSRS_BACKEND_DCSGRPC.Functions.PlaySoundText=function(self,SoundText,Delay)
79567
- if Delay and Delay>0 then
79568
- self:ScheduleOnce(Delay,self.PlaySoundText,self,SoundText,0)
79569
- else
79570
- self:_DCSgRPCtts(tostring(SoundText.text))
79571
- end
79572
- return self
79573
- end
79574
- MSRS_BACKEND_DCSGRPC.Functions.PlayText=function(self,Text,Delay)
79575
- if Delay and Delay>0 then
79576
- self:ScheduleOnce(Delay,self.PlayText,self,Text,0)
79577
- else
79578
- self:_DCSgRPCtts(tostring(Text))
79579
- end
79580
- return self
79581
- end
79582
- MSRS_BACKEND_DCSGRPC.Functions.PlayTextExt=function(self,Text,Delay,Frequencies,Modulations,Gender,Culture,Voice,Volume,Label)
79583
- if Delay and Delay>0 then
79584
- 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
79585
79863
  else
79586
- self:_DCSgRPCtts(tostring(Text),nil,Frequencies,Voice,Label)
79587
- end
79588
- return self
79589
- end
79590
- MSRS_BACKEND_DCSGRPC.Functions.PlayTextFile=function(self,TextFile,Delay)
79591
- BASE:E("ERROR: MSRS:PlayTextFile() is not supported by the DCS-gRPC backend.")
79592
- return self
79593
- end
79594
- MSRS_BACKEND_DCSGRPC.Functions._DCSgRPCtts=function(self,Text,Plaintext,Frequencies,Voice,Label)
79595
- BASE:T("MSRS_BACKEND_DCSGRPC:_DCSgRPCtts()")
79596
- BASE:T({Text,Plaintext,Frequencies,Voice,Label})
79597
- local options=self.ProviderOptions or MSRS.ProviderOptions or{}
79598
- local ssml=Text or''
79599
- local XmitFrequencies=Frequencies or self.Frequency
79600
- if type(XmitFrequencies)~="table"then
79601
- XmitFrequencies={XmitFrequencies}
79602
- end
79603
- options.plaintext=Plaintext
79604
- options.srsClientName=Label or self.Label
79605
- options.position={}
79606
- if self.coordinate then
79607
- options.position.lat,options.position.lon,options.position.alt=self:_GetLatLongAlt(self.coordinate)
79608
- end
79609
- options.position.lat=options.position.lat or 0.0
79610
- options.position.lon=options.position.lon or 0.0
79611
- options.position.alt=options.position.alt or 0.0
79612
- if UTILS.GetCoalitionName(self.coalition)=='Blue'then
79613
- options.coalition='blue'
79614
- elseif UTILS.GetCoalitionName(self.coalition)=='Red'then
79615
- options.coalition='red'
79616
- end
79617
- local provider=self.provider or self.GRPCOptions.DefaultProvider or MSRS.GRPCOptions.DefaultProvider
79618
- options.provider={}
79619
- options.provider[provider]={}
79620
- if self.APIKey then
79621
- options.provider[provider].key=self.APIKey
79622
- end
79623
- if self.defaultVoice then
79624
- options.provider[provider].defaultVoice=self.defaultVoice
79625
- end
79626
- if self.voice then
79627
- options.provider[provider].voice=Voice or self.voice or self.defaultVoice
79628
- elseif ssml then
79629
- local preTag,genderProp,langProp,postTag='','','',''
79630
- if self.gender then
79631
- genderProp=' gender=\"'..self.gender..'\"'
79632
- end
79633
- if self.culture then
79634
- langProp=' language=\"'..self.culture..'\"'
79864
+ if speed~=0 then
79865
+ speedFactor=math.abs(speed)*(maxRateRatio-1)/10+1
79635
79866
  end
79636
- if self.culture or self.gender then
79637
- preTag='<voice'..langProp..genderProp..'>'
79638
- postTag='</voice>'
79639
- ssml=preTag..Text..postTag
79867
+ if speed<0 then
79868
+ speedFactor=1/speedFactor
79640
79869
  end
79641
79870
  end
79642
- for _,_freq in ipairs(XmitFrequencies)do
79643
- local freq=_freq*1000000
79644
- BASE:T("GRPC.tts")
79645
- BASE:T(ssml)
79646
- BASE:T(freq)
79647
- BASE:T({options})
79648
- 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)
79649
79875
  end
79876
+ return length/cps
79650
79877
  end
79651
79878
  MSRSQUEUE={
79652
79879
  ClassName="MSRSQUEUE",
@@ -79707,7 +79934,7 @@ return nil
79707
79934
  end
79708
79935
  local transmission={}
79709
79936
  transmission.text=text
79710
- transmission.duration=duration or STTS.getSpeechTime(text)
79937
+ transmission.duration=duration or MSRS.getSpeechTime(text)
79711
79938
  transmission.msrs=msrs
79712
79939
  transmission.Tplay=tstart or timer.getAbsTime()
79713
79940
  transmission.subtitle=subtitle