mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
Updated Moose
This commit is contained in:
parent
10c963e6a2
commit
492adeefc0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
525
Moose_.lua
525
Moose_.lua
@ -1,4 +1,4 @@
|
||||
env.info('*** MOOSE GITHUB Commit Hash ID: 2025-10-01T15:26:49+02:00-d8281b01032aa44a579c14d690ca79413b671d9d ***')
|
||||
env.info('*** MOOSE GITHUB Commit Hash ID: 2025-10-26T07:31:50+01:00-1965e24860936512d2670eb7d41c8440707a12ff ***')
|
||||
if not MOOSE_DEVELOPMENT_FOLDER then
|
||||
MOOSE_DEVELOPMENT_FOLDER='Scripts'
|
||||
end
|
||||
@ -469,6 +469,7 @@ CH47={},
|
||||
OH58={},
|
||||
UH1H={},
|
||||
AH64D={},
|
||||
UH60L={},
|
||||
}
|
||||
}
|
||||
ENUMS.Storage.weapons.nurs.SNEB_TYPE253_F1B="weapons.nurs.SNEB_TYPE253_F1B"
|
||||
@ -1172,6 +1173,24 @@ ENUMS.Storage.weapons.UH1H.M134_MiniGun_Right_Door={4,15,46,175}
|
||||
ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door={4,15,46,177}
|
||||
ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door={4,15,46,174}
|
||||
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door={4,15,46,176}
|
||||
ENUMS.Storage.weapons.UH60L.M151_HYDRA={4,7,33,147}
|
||||
ENUMS.Storage.weapons.UH60L.M156_HYDRA={4,7,33,148}
|
||||
ENUMS.Storage.weapons.UH60L.M229_HYDRA={4,7,33,148}
|
||||
ENUMS.Storage.weapons.UH60L.M257_HYDRA={4,7,33,151}
|
||||
ENUMS.Storage.weapons.UH60L.M259_HYDRA={4,7,33,151}
|
||||
ENUMS.Storage.weapons.UH60L.M274_HYDRA={4,7,33,150}
|
||||
ENUMS.Storage.weapons.UH60L.M134_DOOR_GUN={4,15,46,3031}
|
||||
ENUMS.Storage.weapons.UH60L.M3M={4,15,46,2496}
|
||||
ENUMS.Storage.weapons.UH60L.M3M_DOOR_GUN={4,15,46,3032}
|
||||
ENUMS.Storage.weapons.UH60L.M60_DOOR_GUN={4,15,46,3033}
|
||||
ENUMS.Storage.weapons.UH60L.FUEL_TANK_200={1,3,43,3023}
|
||||
ENUMS.Storage.weapons.UH60L.FUEL_TANK_230={1,3,43,3024}
|
||||
ENUMS.Storage.weapons.UH60L.FUEL_TANK_450={1,3,43,3025}
|
||||
ENUMS.Storage.weapons.UH60L.FUEL_TANK_DUAL_AUX={1,3,43,3026}
|
||||
ENUMS.Storage.weapons.UH60L.CARGO_SEAT_REAR_ROW={1,3,43,3030}
|
||||
ENUMS.Storage.weapons.UH60L.CARGO_SEAT_THREE_ROWS={1,3,43,3029}
|
||||
ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_1={1,3,43,3027}
|
||||
ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_2={1,3,43,3028}
|
||||
ENUMS.Storage.weapons.OH58.FIM92={4,4,7,449}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P100={4,15,46,2611}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P200={4,15,46,2610}
|
||||
@ -2659,6 +2678,14 @@ if type_name=="UH-60L"and(unit:getDrawArgumentValue(38)>0 or unit:getDrawArgumen
|
||||
BASE:T(unit_name.." front door(s) are open")
|
||||
return true
|
||||
end
|
||||
if type_name=="UH-60L_DAP"and(unit:getDrawArgumentValue(401)==1 or unit:getDrawArgumentValue(402)==1)then
|
||||
BASE:T(unit_name.." cargo door is open")
|
||||
return true
|
||||
end
|
||||
if type_name=="UH-60L_DAP"and(unit:getDrawArgumentValue(38)>0 or unit:getDrawArgumentValue(400)==1)then
|
||||
BASE:T(unit_name.." front door(s) are open")
|
||||
return true
|
||||
end
|
||||
if type_name=="AH-64D_BLK_II"then
|
||||
BASE:T(unit_name.." front door(s) are open")
|
||||
return true
|
||||
@ -3860,7 +3887,55 @@ end
|
||||
UTILS.lcg.seed=(UTILS.lcg.a*UTILS.lcg.seed+UTILS.lcg.c)%UTILS.lcg.m
|
||||
return UTILS.lcg.seed/UTILS.lcg.m
|
||||
end
|
||||
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart)
|
||||
function UTILS.GenerateGridPoints(startVec2,n,spacingX,spacingY)
|
||||
local points={}
|
||||
local gridSize=math.ceil(math.sqrt(n))
|
||||
local count=0
|
||||
local n=n or 1
|
||||
local spacingX=spacingX or 100
|
||||
local spacingY=spacingY or 100
|
||||
local startX=startVec2.x or 100
|
||||
local startY=startVec2.y or 100
|
||||
for row=0,gridSize-1 do
|
||||
for col=0,gridSize-1 do
|
||||
if count>=n then
|
||||
break
|
||||
end
|
||||
local point={
|
||||
x=startX+(col*spacingX),
|
||||
y=startY+(row*spacingY)
|
||||
}
|
||||
table.insert(points,point)
|
||||
count=count+1
|
||||
end
|
||||
if count>=n then
|
||||
break
|
||||
end
|
||||
end
|
||||
return points
|
||||
end
|
||||
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart,NumberPads,SpacingX,SpacingY)
|
||||
local function PopulateStorage(Name,liquids,equip,airframes)
|
||||
local newWH=STORAGE:New(Name)
|
||||
if liquids and liquids>0 then
|
||||
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
||||
end
|
||||
if equip and equip>0 then
|
||||
for cat,nitem in pairs(ENUMS.Storage.weapons)do
|
||||
for name,item in pairs(nitem)do
|
||||
newWH:SetItem(item,equip)
|
||||
end
|
||||
end
|
||||
end
|
||||
if airframes and airframes>0 then
|
||||
for typename in pairs(CSAR.AircraftType)do
|
||||
newWH:SetItem(typename,airframes)
|
||||
end
|
||||
end
|
||||
end
|
||||
local farplocation=Coordinate
|
||||
local farptype=FARPType or ENUMS.FARPType.FARP
|
||||
local Coalition=Coalition or coalition.side.BLUE
|
||||
@ -3878,11 +3953,62 @@ local STypeName=statictypes.TypeName
|
||||
local SShapeName=statictypes.ShapeName
|
||||
local Country=Country or(Coalition==coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
||||
local ReturnObjects={}
|
||||
local NumberPads=NumberPads or 1
|
||||
local SpacingX=SpacingX or 100
|
||||
local SpacingY=SpacingY or 100
|
||||
local FarpVec2=Coordinate:GetVec2()
|
||||
if NumberPads>1 then
|
||||
local Grid=UTILS.GenerateGridPoints(FarpVec2,NumberPads,SpacingX,SpacingY)
|
||||
local groupData={
|
||||
["visible"]=true,
|
||||
["hidden"]=false,
|
||||
["units"]={},
|
||||
["y"]=0,
|
||||
["x"]=0,
|
||||
["name"]=Name,
|
||||
}
|
||||
local unitData={
|
||||
["category"]="Heliports",
|
||||
["type"]=STypeName,
|
||||
["y"]=0,
|
||||
["x"]=0,
|
||||
["name"]=Name,
|
||||
["heading"]=0,
|
||||
["heliport_modulation"]=mod,
|
||||
["heliport_frequency"]=freq,
|
||||
["heliport_callsign_id"]=callsign,
|
||||
["dead"]=false,
|
||||
["shape_name"]=SShapeName,
|
||||
["dynamicSpawn"]=DynamicSpawns,
|
||||
["allowHotStart"]=HotStart,
|
||||
}
|
||||
for id,gridpoint in ipairs(Grid)do
|
||||
local UnitTemplate=UTILS.DeepCopy(unitData)
|
||||
UnitTemplate.x=gridpoint.x
|
||||
UnitTemplate.y=gridpoint.y
|
||||
UnitTemplate.name=Name.."-"..id
|
||||
table.insert(groupData.units,UnitTemplate)
|
||||
if id==1 then
|
||||
groupData.x=gridpoint.x
|
||||
groupData.y=gridpoint.y
|
||||
end
|
||||
end
|
||||
local Static=coalition.addGroup(Country,-1,groupData)
|
||||
local Event={
|
||||
id=EVENTS.Birth,
|
||||
time=timer.getTime(),
|
||||
initiator=Static
|
||||
}
|
||||
world.onEvent(Event)
|
||||
PopulateStorage(Name.."-1",liquids,equip,airframes)
|
||||
else
|
||||
local newfarp=SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country)
|
||||
newfarp:InitShape(SShapeName)
|
||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
||||
local spawnedfarp=newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
||||
table.insert(ReturnObjects,spawnedfarp)
|
||||
PopulateStorage(Name,liquids,equip,airframes)
|
||||
end
|
||||
local FARPStaticObjectsNato={
|
||||
["FUEL"]={TypeName="FARP Fuel Depot",ShapeName="GSM Rus",Category="Fortifications"},
|
||||
["AMMO"]={TypeName="FARP Ammo Dump Coating",ShapeName="SetkaKP",Category="Fortifications"},
|
||||
@ -3911,25 +4037,6 @@ vehicles:InitDelayOff()
|
||||
local spawnedvehicle=vehicles:SpawnFromCoordinate(vcoordinate)
|
||||
table.insert(ReturnObjects,spawnedvehicle)
|
||||
end
|
||||
local newWH=STORAGE:New(Name)
|
||||
if liquids and liquids>0 then
|
||||
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
||||
end
|
||||
if equip and equip>0 then
|
||||
for cat,nitem in pairs(ENUMS.Storage.weapons)do
|
||||
for name,item in pairs(nitem)do
|
||||
newWH:SetItem(item,equip)
|
||||
end
|
||||
end
|
||||
end
|
||||
if airframes and airframes>0 then
|
||||
for typename in pairs(CSAR.AircraftType)do
|
||||
newWH:SetItem(typename,airframes)
|
||||
end
|
||||
end
|
||||
local ADFName
|
||||
if ADF and type(ADF)=="number"then
|
||||
local ADFFreq=ADF*1000
|
||||
@ -9919,6 +10026,16 @@ self.LastVec2=ZoneUNIT:GetVec2()
|
||||
_EVENTDISPATCHER:CreateEventNewZone(self)
|
||||
return self
|
||||
end
|
||||
function ZONE_UNIT:UpdateFromUnit(Unit)
|
||||
if Unit and Unit:IsAlive()then
|
||||
local vec2=Unit:GetVec2()
|
||||
self.LastVec2=vec2
|
||||
elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive()then
|
||||
local ZoneVec2=self.ZoneUNIT:GetVec2()
|
||||
self.LastVec2=ZoneVec2
|
||||
end
|
||||
return self
|
||||
end
|
||||
function ZONE_UNIT:GetVec2()
|
||||
local ZoneVec2=self.ZoneUNIT:GetVec2()
|
||||
if ZoneVec2 then
|
||||
@ -9980,6 +10097,17 @@ ZoneVec2=self._.ZoneVec2Cache
|
||||
end
|
||||
return ZoneVec2
|
||||
end
|
||||
function ZONE_GROUP:UpdateFromGroup(Group)
|
||||
if Group and Group:IsAlive()then
|
||||
local vec2=Group:GetVec2()
|
||||
self.Vec2=vec2
|
||||
elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive()then
|
||||
local ZoneVec2=self._.ZoneGROUP:GetVec2()
|
||||
self.Vec2=ZoneVec2
|
||||
self._.ZoneVec2Cache=ZoneVec2
|
||||
end
|
||||
return self
|
||||
end
|
||||
function ZONE_GROUP:GetRandomVec2()
|
||||
local Point={}
|
||||
local Vec2=self._.ZoneGROUP:GetVec2()
|
||||
@ -21723,7 +21851,7 @@ self:ScheduleOnce(0.3,self.SpawnFunctionHook,mystatic,unpack(self.SpawnFunctionA
|
||||
end
|
||||
if self.StaticCopyFrom~=nil then
|
||||
mystatic.StaticCopyFrom=self.StaticCopyFrom
|
||||
if not _DATABASE.Templates.Statics[Template.name]then
|
||||
end
|
||||
local TemplateGroup={}
|
||||
TemplateGroup.units={}
|
||||
TemplateGroup.units[1]=Template
|
||||
@ -21731,8 +21859,6 @@ TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
_DATABASE:_RegisterStaticTemplate(TemplateGroup,self.CoalitionID,self.CategoryID,CountryID)
|
||||
end
|
||||
end
|
||||
return mystatic
|
||||
end
|
||||
TIMER={
|
||||
@ -26216,6 +26342,46 @@ return self
|
||||
end
|
||||
return nil
|
||||
end
|
||||
function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters)
|
||||
self:F2({self.ControllableName})
|
||||
local meters=meters or 20
|
||||
local DCSControllable=self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller=self:_GetController()
|
||||
if Controller then
|
||||
if self:IsGround()then
|
||||
self:SetOption(27,meters)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return nil
|
||||
end
|
||||
function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters)
|
||||
self:F2({self.ControllableName})
|
||||
local meters=meters or 1000
|
||||
local DCSControllable=self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller=self:_GetController()
|
||||
if Controller then
|
||||
if self:IsGround()then
|
||||
self:SetOption(29,meters)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return nil
|
||||
end
|
||||
function CONTROLLABLE:OptionAAAMinFiringHeightFeet(feet)
|
||||
self:F2({self.ControllableName})
|
||||
local feet=feet or 60
|
||||
return self:OptionAAAMinFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||
end
|
||||
function CONTROLLABLE:OptionAAAMaxFiringHeightfeet(feet)
|
||||
self:F2({self.ControllableName})
|
||||
local feet=feet or 3000
|
||||
return self:OptionAAAMaxFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||
end
|
||||
function CONTROLLABLE:OptionEngageRange(EngageRange)
|
||||
self:F2({self.ControllableName})
|
||||
EngageRange=EngageRange or 100
|
||||
@ -31125,6 +31291,13 @@ end
|
||||
self:T2(string.format("Registered airbase %s",tostring(self.AirbaseName)))
|
||||
return self
|
||||
end
|
||||
function AIRBASE:GetVec2()
|
||||
local runways=self:GetRunways()
|
||||
if runways and#runways>0 then
|
||||
return runways[1].center:GetVec2()
|
||||
end
|
||||
return self:GetCoordinate():GetVec2()
|
||||
end
|
||||
function AIRBASE:_GetCategory()
|
||||
local name=self.AirbaseName
|
||||
local static=StaticObject.getByName(name)
|
||||
@ -33652,6 +33825,8 @@ REMOVED="REMOVED",
|
||||
}
|
||||
DYNAMICCARGO.AircraftTypes={
|
||||
["CH-47Fbl1"]="CH-47Fbl1",
|
||||
["Mi-8MTV2"]="CH-47Fbl1",
|
||||
["Mi-8MT"]="CH-47Fbl1",
|
||||
}
|
||||
DYNAMICCARGO.AircraftDimensions={
|
||||
["CH-47Fbl1"]={
|
||||
@ -33660,8 +33835,20 @@ DYNAMICCARGO.AircraftDimensions={
|
||||
["length"]=11,
|
||||
["ropelength"]=30,
|
||||
},
|
||||
["Mi-8MTV2"]={
|
||||
["width"]=6,
|
||||
["height"]=6,
|
||||
["length"]=15,
|
||||
["ropelength"]=30,
|
||||
},
|
||||
["Mi-8MT"]={
|
||||
["width"]=6,
|
||||
["height"]=6,
|
||||
["length"]=15,
|
||||
["ropelength"]=30,
|
||||
},
|
||||
}
|
||||
DYNAMICCARGO.version="0.0.7"
|
||||
DYNAMICCARGO.version="0.0.9"
|
||||
function DYNAMICCARGO:Register(CargoName)
|
||||
local self=BASE:Inherit(self,POSITIONABLE:New(CargoName))
|
||||
self.StaticName=CargoName
|
||||
@ -35274,7 +35461,9 @@ end
|
||||
end)
|
||||
self.AutoSavePath=SavePath
|
||||
self.AutoSave=AutoSave or true
|
||||
if self.AutoSave==true then
|
||||
self:OpenCSV(GameName)
|
||||
end
|
||||
return self
|
||||
end
|
||||
function SCORING:SetDisplayMessagePrefix(DisplayMessagePrefix)
|
||||
@ -36298,7 +36487,7 @@ TargetUnitCoalition=TargetUnitCoalition or""
|
||||
TargetUnitCategory=TargetUnitCategory or""
|
||||
TargetUnitType=TargetUnitType or""
|
||||
TargetUnitName=TargetUnitName or""
|
||||
if lfs and io and os and self.AutoSave then
|
||||
if lfs and io and os and self.AutoSave==true and self.CSVFile~=nil then
|
||||
self.CSVFile:write(
|
||||
'"'..self.GameName..'"'..','..
|
||||
'"'..self.RunTime..'"'..','..
|
||||
@ -58882,8 +59071,8 @@ end
|
||||
end
|
||||
TIRESIAS={
|
||||
ClassName="TIRESIAS",
|
||||
debug=true,
|
||||
version=" 0.0.7-OPT",
|
||||
debug=false,
|
||||
version=" 0.0.8",
|
||||
Interval=20,
|
||||
GroundSet=nil,
|
||||
VehicleSet=nil,
|
||||
@ -58903,7 +59092,7 @@ self:SetStartState("Stopped")
|
||||
self:AddTransition("Stopped","Start","Running")
|
||||
self:AddTransition("*","Status","*")
|
||||
self:AddTransition("*","Stop","Stopped")
|
||||
self.ExceptionSet=nil
|
||||
self.ExceptionSet=SET_GROUP:New()
|
||||
self._cached_zones={}
|
||||
self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler)
|
||||
self.lid="TIRESIAS "..self.version.." | "
|
||||
@ -58934,10 +59123,7 @@ exception=true,
|
||||
}
|
||||
Set:ForEachGroupAlive(
|
||||
function(grp)
|
||||
local inAAASet=self.AAASet:IsIncludeObject(grp)
|
||||
local inVehSet=self.VehicleSet:IsIncludeObject(grp)
|
||||
local inSAMSet=self.SAMSet:IsIncludeObject(grp)
|
||||
if grp:IsGround()and(not grp.Tiresias)and(not inAAASet)and(not inVehSet)and(not inSAMSet)then
|
||||
if grp:IsGround()and(not grp.Tiresias)then
|
||||
grp.Tiresias=exception_data
|
||||
exceptions:AddGroup(grp,true)
|
||||
BASE:T(" TIRESIAS: Added exception group: "..grp:GetName())
|
||||
@ -59078,19 +59264,14 @@ self:T(self.lid.." _SwitchOnGroups "..group:GetName().." Radius "..radius.." N
|
||||
local group_name=group:GetName()
|
||||
local cache_key=group_name.." _"..radius
|
||||
local zone=self._cached_zones[cache_key]
|
||||
local ground=self._cached_groupsets[cache_key]
|
||||
if not zone then
|
||||
zone=ZONE_GROUP:New(" Zone-"..group_name,group,UTILS.NMToMeters(radius))
|
||||
self._cached_zones[cache_key]=zone
|
||||
else
|
||||
zone:UpdateFromGroup(group)
|
||||
end
|
||||
if not ground then
|
||||
ground=SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce()
|
||||
self._cached_groupsets[cache_key]=ground
|
||||
else
|
||||
ground:FilterZones({zone},true):FilterOnce()
|
||||
end
|
||||
zone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||
local ground=zone:GetScannedSetGroup()
|
||||
local count=ground:CountAlive()
|
||||
if self.debug then
|
||||
self:I(string.format(" There are %d groups around this plane or helo!",count))
|
||||
@ -63489,6 +63670,7 @@ brc=self:GetBRCintoWind(self.recoverywindow.SPEED)
|
||||
end
|
||||
flight.Tcharlie=self:_GetCharlieTime(flight)
|
||||
local Ccharlie=UTILS.SecondsToClock(flight.Tcharlie)
|
||||
brc=brc%360
|
||||
self:_MarshalCallArrived(flight.onboard,flight.case,brc,alt,Ccharlie,P)
|
||||
if self.TACANon and(not flight.ai)and flight.difficulty==AIRBOSS.Difficulty.EASY then
|
||||
local radial=self:GetRadial(flight.case,true,true,true)
|
||||
@ -63852,7 +64034,7 @@ playerData.stable=false
|
||||
playerData.landed=false
|
||||
playerData.Tlso=timer.getTime()
|
||||
playerData.Tgroove=nil
|
||||
playerData.TIG0=nil
|
||||
playerData.TIG0=0
|
||||
playerData.wire=nil
|
||||
playerData.flag=-100
|
||||
playerData.debriefschedulerID=nil
|
||||
@ -64882,77 +65064,9 @@ if self:_CheckAbort(X,Z,self.BreakEntry)then
|
||||
self:_AbortPattern(playerData,X,Z,self.BreakEntry,true)
|
||||
return
|
||||
end
|
||||
local stern=self:_GetSternCoord()
|
||||
local coord=playerData.unit:GetCoordinate()
|
||||
local dist=coord:Get2DDistance(stern)
|
||||
local playerCallsign=playerData.unit:GetCallsign()
|
||||
local playerName=playerData.name
|
||||
local unit=playerData.unit
|
||||
local unitClient=Unit.getByName(unit:GetName())
|
||||
local hookArgument=unitClient:getDrawArgumentValue(25)
|
||||
local hookArgument_Tomcat=unitClient:getDrawArgumentValue(1305)
|
||||
local speedMPS=playerData.unit:GetVelocityMPS()
|
||||
local speedKTS=UTILS.MpsToKnots(speedMPS)
|
||||
local player_alt=playerData.unit:GetAltitude()
|
||||
player_alt_feet=player_alt*3.28
|
||||
player_alt_feet=player_alt_feet/10
|
||||
player_alt_feet=math.floor(player_alt_feet)*10
|
||||
local player_velocity_round=speedKTS*1.00
|
||||
player_velocity_round=player_velocity_round/10
|
||||
player_velocity_round=math.floor(player_velocity_round)*10
|
||||
local player_alt_feet=player_alt*3.28
|
||||
player_alt_feet=player_alt_feet/10
|
||||
player_alt_feet=math.floor(player_alt_feet)*10
|
||||
local Play_SH_Sound=USERSOUND:New("Airboss Soundfiles/GreatBallsOfFire.ogg")
|
||||
local Play_666SH_Sound=USERSOUND:New("Airboss Soundfiles/Runninwiththedevil.ogg")
|
||||
local playerType=playerData.actype
|
||||
if dist<1000 and clientSHBFlag==false then
|
||||
if speedKTS>450 and speedKTS<590 then
|
||||
if player_alt_feet<1500 then
|
||||
if hookArgument>0 or hookArgument_Tomcat>0 then
|
||||
playerData.shb=true
|
||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType,10)
|
||||
local sh_message_to_discord=('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
||||
Play_SH_Sound:ToAll()
|
||||
clientSHBFlag=true
|
||||
else
|
||||
playerData.shb=false
|
||||
end
|
||||
else
|
||||
end
|
||||
elseif speedKTS>589 then
|
||||
if player_alt_feet<625 and player_alt_feet>575 then
|
||||
if hookArgument>0 or hookArgument_Tomcat>0 then
|
||||
playerData.shb=true
|
||||
trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType,10)
|
||||
local sh_message_to_discord=('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
||||
Play_666SH_Sound:ToAll()
|
||||
clientSHBFlag=true
|
||||
else
|
||||
playerData.shb=false
|
||||
end
|
||||
else
|
||||
if hookArgument>0 or hookArgument_Tomcat>0 then
|
||||
playerData.shb=true
|
||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType,10)
|
||||
local sh_message_to_discord=('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
||||
Play_SH_Sound:ToAll()
|
||||
clientSHBFlag=true
|
||||
else
|
||||
playerData.shb=false
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
else
|
||||
end
|
||||
if self:_CheckLimits(X,Z,self.BreakEntry)then
|
||||
self:_PlayerHint(playerData)
|
||||
self:_SetPlayerStep(playerData,AIRBOSS.PatternStep.EARLYBREAK)
|
||||
clientSHBFlag=false
|
||||
end
|
||||
end
|
||||
function AIRBOSS:_Break(playerData,part)
|
||||
@ -65240,19 +65354,19 @@ end
|
||||
if rho>=RAR and rho<=RIM then
|
||||
if gd.LUE>0.22 and lineupError<-0.22 then
|
||||
env.info" Drift Right across centre ==> DR-"
|
||||
gd.Drift=" DR"
|
||||
gd.Drift="DR"
|
||||
self:T(self.lid..string.format("Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f",gs,d,gd.LUE,lineupError))
|
||||
elseif gd.LUE<-0.22 and lineupError>0.22 then
|
||||
env.info" Drift Left ==> DL-"
|
||||
gd.Drift=" DL"
|
||||
gd.Drift="DL"
|
||||
self:T(self.lid..string.format("Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f",gs,d,gd.LUE,lineupError))
|
||||
elseif gd.LUE>0.13 and lineupError<-0.14 then
|
||||
env.info" Little Drift Right across centre ==> (DR-)"
|
||||
gd.Drift=" (DR)"
|
||||
gd.Drift="(DR)"
|
||||
self:T(self.lid..string.format("Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f",gs,d,gd.LUE,lineupError))
|
||||
elseif gd.LUE<-0.13 and lineupError>0.14 then
|
||||
env.info" Little Drift Left across centre ==> (DL-)"
|
||||
gd.Drift=" (DL)"
|
||||
gd.Drift="(DL)"
|
||||
self:E(self.lid..string.format("Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f",gs,d,gd.LUE,lineupError))
|
||||
end
|
||||
end
|
||||
@ -66051,9 +66165,7 @@ local hdg=self.carrier:GetHeading()
|
||||
if magnetic then
|
||||
hdg=hdg-self.magvar
|
||||
end
|
||||
if hdg<0 then
|
||||
hdg=hdg+360
|
||||
end
|
||||
hdg=hdg%360
|
||||
return hdg
|
||||
end
|
||||
function AIRBOSS:GetBRC()
|
||||
@ -66152,7 +66264,7 @@ theta=math.asin(vdeck*math.sin(alpha)/vwind)
|
||||
v=vdeck*math.cos(alpha)-vwind*math.cos(theta)
|
||||
end
|
||||
local magvar=magnetic and self.magvar or 0
|
||||
local intowind=self:GetHeadingIntoWind_old(vdeck)
|
||||
local intowind=(540+(windto-magvar+math.deg(theta)))%360
|
||||
return intowind,v
|
||||
end
|
||||
function AIRBOSS:GetBRCintoWind(vdeck)
|
||||
@ -66343,7 +66455,7 @@ return select(2,string.gsub(base,pattern,""))
|
||||
end
|
||||
local TIG=""
|
||||
if playerData.Tgroove and playerData.Tgroove<=360 and playerData.case<3 then
|
||||
TIG=self:_EvalGrooveTime(playerData)
|
||||
TIG=self:_EvalGrooveTime(playerData)or"N/A"
|
||||
end
|
||||
local GXX,nXX=self:_Flightdata2Text(playerData,AIRBOSS.GroovePos.XX)
|
||||
local GIM,nIM=self:_Flightdata2Text(playerData,AIRBOSS.GroovePos.IM)
|
||||
@ -66358,6 +66470,7 @@ local N=nXX+nIM+nIC+nAR+nIW
|
||||
local nL=count(G,'_')/2
|
||||
local nS=count(G,'%(')
|
||||
local nN=N-nS-nL
|
||||
if TIG=="_OK_"then nL=nL-1 end
|
||||
local Tgroove=playerData.Tgroove
|
||||
local TgrooveUnicorn=Tgroove and(Tgroove>=16.49 and Tgroove<=16.59)or false
|
||||
local TgrooveVstolUnicorn=Tgroove and(Tgroove>=60.0 and Tgroove<=65.0)and playerData.actype==AIRBOSS.AircraftCarrier.AV8B or false
|
||||
@ -66465,14 +66578,8 @@ grade="CUT"
|
||||
points=0.0
|
||||
end
|
||||
end
|
||||
if playerData.wire==1 and points>1 then
|
||||
if points==4 then
|
||||
points=3
|
||||
grade="(OK)"
|
||||
elseif points==3 then
|
||||
points=2
|
||||
grade="--"
|
||||
end
|
||||
if playerData.wire==1 and points>=3 and N>4 then
|
||||
points=points-1
|
||||
end
|
||||
env.info("Returning: "..grade.." "..points.." "..G)
|
||||
return grade,points,G
|
||||
@ -66520,6 +66627,7 @@ O=little("OS")
|
||||
end
|
||||
end
|
||||
local S=nil
|
||||
local A=nil
|
||||
if step~=AIRBOSS.PatternStep.GROOVE_IW then
|
||||
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff==true and playerData.owo==true then
|
||||
else
|
||||
@ -66536,7 +66644,6 @@ S="F"
|
||||
elseif AOA<acaoa.OnSpeedMin then
|
||||
S=little("F")
|
||||
end
|
||||
local A=nil
|
||||
if GSE>self.gle.HIGH then
|
||||
A=underline("H")
|
||||
elseif GSE>self.gle.High then
|
||||
@ -72835,6 +72942,7 @@ if type(Location)=="string"then
|
||||
Location=ZONE:New(Location)
|
||||
end
|
||||
self.Location=Location
|
||||
self.NoMoveToZone=false
|
||||
return self
|
||||
end
|
||||
function CTLD_CARGO:SetStaticTypeAndShape(Category,TypeName,ShapeName)
|
||||
@ -73326,6 +73434,7 @@ self.dropAsCargoCrate=false
|
||||
self.smokedistance=2000
|
||||
self.movetroopstowpzone=true
|
||||
self.movetroopsdistance=5000
|
||||
self.returntroopstobase=true
|
||||
self.troopdropzoneradius=100
|
||||
self.VehicleMoveFormation=AI.Task.VehicleFormation.VEE
|
||||
self.enableHercules=false
|
||||
@ -74698,7 +74807,7 @@ if not inzone then
|
||||
inzone,zonename,zone,distance=self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
||||
end
|
||||
if inzone then
|
||||
droppingatbase=true
|
||||
droppingatbase=self.returntroopstobase
|
||||
end
|
||||
local hoverunload=self:IsCorrectHover(Unit)
|
||||
local IsHerc=self:IsFixedWing(Unit)
|
||||
@ -75384,7 +75493,8 @@ subcatmenus[catName]=MENU_GROUP:New(_group,catName,cratesmenu)
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Crates)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75395,7 +75505,8 @@ end
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Statics)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75407,7 +75518,8 @@ end
|
||||
else
|
||||
for _,cargoObj in pairs(self.Cargo_Crates)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75418,7 +75530,8 @@ end
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Statics)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75429,14 +75542,15 @@ end
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.usesubcats then
|
||||
if self.usesubcats==true then
|
||||
local subcatmenus={}
|
||||
for catName,_ in pairs(self.subcats)do
|
||||
subcatmenus[catName]=MENU_GROUP:New(_group,catName,cratesmenu)
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Crates)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75445,7 +75559,8 @@ end
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Statics)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75455,7 +75570,8 @@ end
|
||||
else
|
||||
for _,cargoObj in pairs(self.Cargo_Crates)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75464,7 +75580,8 @@ end
|
||||
end
|
||||
for _,cargoObj in pairs(self.Cargo_Statics)do
|
||||
if not cargoObj.DontShowInMenu then
|
||||
local txt=string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
local needed=cargoObj:GetCratesNeeded()or 1
|
||||
local txt=string.format("%d crate%s %s (%dkg)",needed,needed==1 and""or"s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||
if cargoObj.Location then txt=txt.."[R]"end
|
||||
local stock=cargoObj:GetStock()
|
||||
if stock>=0 and self.showstockinmenuitems then txt=txt.."["..stock.."]"end
|
||||
@ -75888,7 +76005,7 @@ if not inzone then
|
||||
inzone,zonename,zone,distance=self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
||||
end
|
||||
if inzone then
|
||||
droppingatbase=true
|
||||
droppingatbase=self.returntroopstobase
|
||||
end
|
||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName())then
|
||||
self:_SendMessage("You need to open the door(s) to unload troops!",10,false,Group)
|
||||
@ -76117,6 +76234,34 @@ table.insert(self.Cargo_Crates,cargo)
|
||||
if SubCategory and self.usesubcats~=true then self.usesubcats=true end
|
||||
return self
|
||||
end
|
||||
function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,Category,TypeName,ShapeName)
|
||||
self:T(self.lid.." AddCratesCargoNoMove")
|
||||
if not self:_CheckTemplates(Templates)then
|
||||
self:E(self.lid.."Crates Cargo for "..Name.." has missing template(s)!")
|
||||
return self
|
||||
end
|
||||
self.CargoCounter=self.CargoCounter+1
|
||||
local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||
cargo.NoMoveToZone=true
|
||||
if UnitTypes then
|
||||
cargo:AddUnitTypeName(UnitTypes)
|
||||
end
|
||||
cargo:SetStaticTypeAndShape("Cargos",self.basetype)
|
||||
if TypeName then
|
||||
cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName)
|
||||
end
|
||||
table.insert(self.Cargo_Crates,cargo)
|
||||
self.templateToCargoName=self.templateToCargoName or{}
|
||||
if type(Templates)=="table"then
|
||||
for _,t in pairs(Templates)do self.templateToCargoName[t]=Name end
|
||||
else
|
||||
self.templateToCargoName[Templates]=Name
|
||||
end
|
||||
self.nomovetozone_names=self.nomovetozone_names or{}
|
||||
self.nomovetozone_names[Name]=true
|
||||
if SubCategory and self.usesubcats~=true then self.usesubcats=true end
|
||||
return self
|
||||
end
|
||||
function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Location)
|
||||
self:T(self.lid.." AddStaticsCargo")
|
||||
self.CargoCounter=self.CargoCounter+1
|
||||
@ -76269,7 +76414,12 @@ self:E(self.lid.."**** Ship does not exist: "..Name)
|
||||
return self
|
||||
end
|
||||
end
|
||||
local ctldzone={}
|
||||
local exists=true
|
||||
local ctldzone=self:GetCTLDZone(Name,Type)
|
||||
if not ctldzone then
|
||||
exists=false
|
||||
ctldzone={}
|
||||
end
|
||||
ctldzone.active=Active or false
|
||||
ctldzone.color=Color or SMOKECOLOR.Red
|
||||
ctldzone.name=Name or"NONE"
|
||||
@ -76292,9 +76442,45 @@ if Type==CTLD.CargoZoneType.SHIP then
|
||||
ctldzone.shiplength=Shiplength or 100
|
||||
ctldzone.shipwidth=Shipwidth or 10
|
||||
end
|
||||
if not exists then
|
||||
self:AddZone(ctldzone)
|
||||
end
|
||||
return self
|
||||
end
|
||||
function CTLD:GetCTLDZone(Name,Type)
|
||||
if Type==CTLD.CargoZoneType.LOAD then
|
||||
for _,z in pairs(self.pickupZones)do
|
||||
if z.name==Name then
|
||||
return z
|
||||
end
|
||||
end
|
||||
elseif Type==CTLD.CargoZoneType.DROP then
|
||||
for _,z in pairs(self.dropOffZones)do
|
||||
if z.name==Name then
|
||||
return z
|
||||
end
|
||||
end
|
||||
elseif Type==CTLD.CargoZoneType.SHIP then
|
||||
for _,z in pairs(self.shipZones)do
|
||||
if z.name==Name then
|
||||
return z
|
||||
end
|
||||
end
|
||||
elseif Type==CTLD.CargoZoneType.BEACON then
|
||||
for _,z in pairs(self.droppedBeacons)do
|
||||
if z.name==Name then
|
||||
return z
|
||||
end
|
||||
end
|
||||
else
|
||||
for _,z in pairs(self.wpZones)do
|
||||
if z.name==Name then
|
||||
return z
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
function CTLD:AddCTLDZoneFromAirbase(AirbaseName,Type,Color,Active,HasBeacon)
|
||||
self:T(self.lid.." AddCTLDZoneFromAirbase")
|
||||
local AFB=AIRBASE:FindByName(AirbaseName)
|
||||
@ -77540,9 +77726,12 @@ return self
|
||||
end
|
||||
function CTLD:onafterCratesBuild(From,Event,To,Group,Unit,Vehicle)
|
||||
self:T({From,Event,To})
|
||||
if self.movetroopstowpzone then
|
||||
if self.movetroopstowpzone and Vehicle then
|
||||
local cg=self:GetGenericCargoObjectFromGroupName(Vehicle:GetName())
|
||||
if not(cg and(cg.NoMoveToZone or(self.nomovetozone_names and self.nomovetozone_names[cg:GetName()])))then
|
||||
self:_MoveGroupToZone(Vehicle)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
function CTLD:onbeforeTroopsRTB(From,Event,To,Group,Unit,ZoneName,ZoneObject)
|
||||
@ -78295,7 +78484,7 @@ CSAR.AircraftType["MH-60R"]=10
|
||||
CSAR.AircraftType["OH-6A"]=2
|
||||
CSAR.AircraftType["OH58D"]=2
|
||||
CSAR.AircraftType["CH-47Fbl1"]=31
|
||||
CSAR.version="1.0.33"
|
||||
CSAR.version="1.0.34"
|
||||
function CSAR:New(Coalition,Template,Alias)
|
||||
local self=BASE:Inherit(self,FSM:New())
|
||||
BASE:T({Coalition,Template,Alias})
|
||||
@ -78741,11 +78930,11 @@ return self
|
||||
end
|
||||
local initdcscoord=nil
|
||||
local initcoord=nil
|
||||
if _event.id==EVENTS.Ejection then
|
||||
if _event.id==EVENTS.Ejection and _event.TgtDCSUnit then
|
||||
initdcscoord=_event.TgtDCSUnit:getPoint()
|
||||
initcoord=COORDINATE:NewFromVec3(initdcscoord)
|
||||
self:T({initdcscoord})
|
||||
else
|
||||
elseif _event.IniDCSUnit then
|
||||
initdcscoord=_event.IniDCSUnit:getPoint()
|
||||
initcoord=COORDINATE:NewFromVec3(initdcscoord)
|
||||
self:T({initdcscoord})
|
||||
@ -78808,7 +78997,10 @@ return self
|
||||
end
|
||||
if _place:GetCoalition()==self.coalition or _place:GetCoalition()==coalition.side.NEUTRAL then
|
||||
self:__Landed(2,_event.IniUnitName,_place)
|
||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
|
||||
local IsHeloBase=false
|
||||
local ABName=_place:GetName()
|
||||
if ABName and string.find(ABName,"^H")then IsHeloBase=true end
|
||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true,IsHeloBase)
|
||||
else
|
||||
self:T(string.format("Airfield %d, Unit %d",_place:GetCoalition(),_unit:GetCoalition()))
|
||||
end
|
||||
@ -79163,7 +79355,7 @@ else
|
||||
return false
|
||||
end
|
||||
end
|
||||
function CSAR:_ScheduledSARFlight(heliname,groupname,isairport,noreschedule)
|
||||
function CSAR:_ScheduledSARFlight(heliname,groupname,isairport,noreschedule,IsHeloBase)
|
||||
self:T(self.lid.." _ScheduledSARFlight")
|
||||
self:T({heliname,groupname})
|
||||
local _heliUnit=self:_GetSARHeli(heliname)
|
||||
@ -79181,7 +79373,7 @@ self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Dis
|
||||
return
|
||||
end
|
||||
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
|
||||
if(_dist<self.FARPRescueDistance or isairport)and _heliUnit:InAir()==false then
|
||||
if(_dist<self.FARPRescueDistance or isairport)and((_heliUnit:InAir()==false)or(IsHeloBase==true))then
|
||||
self:T(self.lid.."[Drop off debug] Distance ok, door check")
|
||||
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname)==false then
|
||||
self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me out!",self.messageTime,true,true)
|
||||
@ -79194,7 +79386,7 @@ end
|
||||
end
|
||||
if not noreschedule then
|
||||
self:__Returning(5,heliname,_woundedGroupName,isairport)
|
||||
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname,isairport,noreschedule)
|
||||
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname,isairport,noreschedule,IsHeloBase)
|
||||
end
|
||||
return self
|
||||
end
|
||||
@ -82463,7 +82655,7 @@ mission.DCStask=mission:GetDCSMissionTask()
|
||||
mission.DCStask.params.formation=Formation or"Off Road"
|
||||
return mission
|
||||
end
|
||||
function AUFTRAG:NewCAPTUREZONE(OpsZone,Coalition,Speed,Altitude,Formation)
|
||||
function AUFTRAG:NewCAPTUREZONE(OpsZone,Coalition,Speed,Altitude,Formation,StayInZoneTime)
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE)
|
||||
mission:_TargetFromObject(OpsZone)
|
||||
mission.coalition=Coalition
|
||||
@ -82471,6 +82663,7 @@ mission.missionTask=mission:GetMissionTaskforMissionType(AUFTRAG.Type.CAPTUREZON
|
||||
mission.optionROE=ENUMS.ROE.ReturnFire
|
||||
mission.optionROT=ENUMS.ROT.PassiveDefense
|
||||
mission.optionAlarm=ENUMS.AlarmState.Auto
|
||||
mission.StayInZoneTime=StayInZoneTime
|
||||
mission.missionFraction=0.1
|
||||
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed)or nil
|
||||
mission.missionAltitude=Altitude and UTILS.FeetToMeters(Altitude)or nil
|
||||
@ -83290,6 +83483,15 @@ function AUFTRAG:IsOver()
|
||||
local over=self.status==AUFTRAG.Status.DONE or self.status==AUFTRAG.Status.CANCELLED or self.status==AUFTRAG.Status.SUCCESS or self.status==AUFTRAG.Status.FAILED
|
||||
return over
|
||||
end
|
||||
function AUFTRAG:IsRepeatable()
|
||||
local repeatmeS=self.repeatedSuccess<self.NrepeatSuccess or self.repeated<self.Nrepeat
|
||||
local repeatmeF=self.repeatedFailure<self.NrepeatFailure or self.repeated<self.Nrepeat
|
||||
if repeatmeS==true or repeatmeF==true then return true else return false end
|
||||
return false
|
||||
end
|
||||
function AUFTRAG:IsNotRepeatable()
|
||||
return not self:IsRepeatable()
|
||||
end
|
||||
function AUFTRAG:IsNotOver()
|
||||
return not self:IsOver()
|
||||
end
|
||||
@ -84812,7 +85014,7 @@ end
|
||||
do
|
||||
AWACS={
|
||||
ClassName="AWACS",
|
||||
version="0.2.72",
|
||||
version="0.2.73",
|
||||
lid="",
|
||||
coalition=coalition.side.BLUE,
|
||||
coalitiontxt="blue",
|
||||
@ -85429,6 +85631,11 @@ self:T(self.lid.."SetLocale")
|
||||
self.locale=Locale or"en"
|
||||
return self
|
||||
end
|
||||
function AWACS:SetBullsCoordinate(Coordinate)
|
||||
self:T(self.lid.."SetBullsCoordinate")
|
||||
self.AOCoordinate=Coordinate
|
||||
return self
|
||||
end
|
||||
function AWACS:SetMaxMissionRange(NM)
|
||||
self.MaxMissionRange=NM or 125
|
||||
return self
|
||||
@ -97028,7 +97235,7 @@ if self.verbose>=2 then
|
||||
local text=string.format("Updating MENU: State=%s, ATC=%s [%s]",self:GetState(),
|
||||
self.flightcontrol and self.flightcontrol.airbasename or"None",self.flightcontrol and self.flightcontrol:GetFlightStatus(self)or"Unknown")
|
||||
MESSAGE:New(text,5):ToGroup(self.group)
|
||||
self:I(self.lid..text)
|
||||
self:T(self.lid..text)
|
||||
end
|
||||
local position=self:GetCoordinate(nil,player.name)
|
||||
local fc={}
|
||||
@ -98621,6 +98828,13 @@ local mission=_mission
|
||||
if mission:IsNotOver()and mission:IsReadyToCancel()then
|
||||
mission:Cancel()
|
||||
end
|
||||
local TNow=timer.getTime()
|
||||
if mission:IsOver()and mission:IsNotRepeatable()and mission.DeletionTimstamp==nil then
|
||||
mission.DeletionTimstamp=TNow
|
||||
end
|
||||
if mission.DeletionTimstamp~=nil and TNow-mission.DeletionTimstamp>1800 then
|
||||
mission=nil
|
||||
end
|
||||
end
|
||||
if self:IsAirwing()then
|
||||
if self:IsRunwayOperational()==false then
|
||||
@ -98676,7 +98890,7 @@ if EscortAvail and TransportAvail then
|
||||
self:MissionRequest(mission,assets)
|
||||
if reinforce then
|
||||
mission.reinforce=mission.reinforce-#assets
|
||||
self:I(self.lid..string.format("Reinforced with N=%d Nreinforce=%d",#assets,mission.reinforce))
|
||||
self:T(self.lid..string.format("Reinforced with N=%d Nreinforce=%d",#assets,mission.reinforce))
|
||||
end
|
||||
return true
|
||||
else
|
||||
@ -103616,7 +103830,12 @@ if zoneCurr then
|
||||
self:T(self.lid..string.format("Current target zone=%s owner=%s",zoneCurr:GetName(),zoneCurr:GetOwnerName()))
|
||||
if zoneCurr:GetOwner()==self:GetCoalition()then
|
||||
self:T(self.lid..string.format("Zone %s captured ==> Task DONE!",zoneCurr:GetName()))
|
||||
if Task.StayInZoneTime then
|
||||
local stay=Task.StayInZoneTime
|
||||
self:__TaskDone(stay,Task)
|
||||
else
|
||||
self:TaskDone(Task)
|
||||
end
|
||||
else
|
||||
self:T(self.lid..string.format("Zone %s NOT captured!",zoneCurr:GetName()))
|
||||
if Mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.EXECUTING then
|
||||
@ -104983,7 +105202,7 @@ self.Ndestroyed=self.Ndestroyed+1
|
||||
self:ElementDead(Element)
|
||||
end
|
||||
function OPSGROUP:onafterElementDead(From,Event,To,Element)
|
||||
self:I(self.lid..string.format("Element dead %s at t=%.3f",Element.name,timer.getTime()))
|
||||
self:T(self.lid..string.format("Element dead %s at t=%.3f",Element.name,timer.getTime()))
|
||||
self:_UpdateStatus(Element,OPSGROUP.ElementStatus.DEAD)
|
||||
if self.spot.On and self.spot.element.name==Element.name then
|
||||
self:LaserOff()
|
||||
@ -105256,7 +105475,7 @@ local text=string.format("WARNING: Group is still alive! Current state=%s. Life
|
||||
self:T(self.lid..text)
|
||||
end
|
||||
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
|
||||
self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
|
||||
self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
|
||||
end
|
||||
function OPSGROUP:onafterOutOfAmmo(From,Event,To)
|
||||
self:T(self.lid..string.format("Group is out of ammo at t=%.3f",timer.getTime()))
|
||||
|
||||
269
Patch-MooseMissions/Patch-MooseMissions.ps1
Normal file
269
Patch-MooseMissions/Patch-MooseMissions.ps1
Normal file
@ -0,0 +1,269 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Patches DCS mission files (.miz) with updated Lua scripts.
|
||||
|
||||
.DESCRIPTION
|
||||
This script extracts a DCS mission file (which is a ZIP archive), replaces or adds
|
||||
a Lua script file, and repackages the mission. This allows you to update scripts
|
||||
like Moose_.lua across multiple missions without opening the DCS Mission Editor.
|
||||
|
||||
.PARAMETER MissionPath
|
||||
Path to the .miz mission file to patch. Can be a single file or multiple files.
|
||||
|
||||
.PARAMETER LuaScriptPath
|
||||
Path to the Lua script file to insert/replace in the mission.
|
||||
|
||||
.PARAMETER ScriptName
|
||||
Optional. The name the script should have inside the mission file.
|
||||
If not specified, uses the filename from LuaScriptPath.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional. Directory where patched missions should be saved.
|
||||
If not specified, saves to the same directory as the input mission.
|
||||
|
||||
.PARAMETER NoVersionIncrement
|
||||
If specified, does not increment the version number in the filename.
|
||||
By default, the script automatically increments the patch version (e.g., 1.1.2 -> 1.1.3).
|
||||
WARNING: Using this flag will OVERWRITE the original mission file!
|
||||
|
||||
.EXAMPLE
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "C:\Missions\MyMission-1.2.3.miz" -LuaScriptPath "C:\Scripts\Moose_.lua"
|
||||
Creates: MyMission-1.2.4.miz (original 1.2.3 remains untouched)
|
||||
|
||||
.EXAMPLE
|
||||
Get-ChildItem "C:\Missions\*.miz" | .\Patch-MooseMissions.ps1 -LuaScriptPath "C:\Scripts\Moose_.lua"
|
||||
|
||||
.EXAMPLE
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "Mission-2.1.miz" -LuaScriptPath "MyScript.lua" -NoVersionIncrement
|
||||
WARNING: Overwrites Mission-2.1.miz
|
||||
|
||||
.NOTES
|
||||
Author: F99th-TracerFacer
|
||||
Version: 2.0
|
||||
DCS mission files are ZIP archives containing a 'l10n' folder with a 'DEFAULT' subfolder
|
||||
where Lua scripts are stored.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
|
||||
[Alias("FullName", "Path")]
|
||||
[string[]]$MissionPath,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$LuaScriptPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$ScriptName,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OutputPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$NoVersionIncrement
|
||||
)
|
||||
|
||||
begin {
|
||||
# Verify Lua script exists
|
||||
if (-not (Test-Path $LuaScriptPath)) {
|
||||
throw "Lua script not found: $LuaScriptPath"
|
||||
}
|
||||
|
||||
# Determine script name to use inside mission
|
||||
if ([string]::IsNullOrWhiteSpace($ScriptName)) {
|
||||
$ScriptName = Split-Path $LuaScriptPath -Leaf
|
||||
}
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "DCS Mission Patcher" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Lua Script: $ScriptName" -ForegroundColor Yellow
|
||||
Write-Host "Source: $LuaScriptPath" -ForegroundColor Gray
|
||||
Write-Host "Version Increment: $(if ($NoVersionIncrement) { 'Disabled (OVERWRITES ORIGINAL!)' } else { 'Enabled' })" -ForegroundColor $(if ($NoVersionIncrement) { 'Red' } else { 'Green' })
|
||||
Write-Host ""
|
||||
|
||||
# Validate output path if specified
|
||||
if ($OutputPath -and -not (Test-Path $OutputPath)) {
|
||||
Write-Host "Creating output directory: $OutputPath" -ForegroundColor Yellow
|
||||
New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$successCount = 0
|
||||
$failCount = 0
|
||||
|
||||
# Function to increment version number in filename
|
||||
function Get-IncrementedFilename {
|
||||
param(
|
||||
[string]$FileName
|
||||
)
|
||||
|
||||
# Remove extension
|
||||
$nameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($FileName)
|
||||
$extension = [System.IO.Path]::GetExtension($FileName)
|
||||
|
||||
# Try to find version patterns: X.Y.Z or X.Y or just X at the end
|
||||
# Patterns to match (in order of specificity):
|
||||
# 1. Major.Minor.Patch (e.g., 1.2.3)
|
||||
# 2. Major.Minor (e.g., 1.2)
|
||||
# 3. Just version number at end (e.g., v5 or -5)
|
||||
|
||||
# Pattern 1: X.Y.Z (most common)
|
||||
if ($nameWithoutExt -match '^(.+?)[-_\s]?(\d+)\.(\d+)\.(\d+)$') {
|
||||
$baseName = $matches[1]
|
||||
$major = $matches[2]
|
||||
$minor = $matches[3]
|
||||
$patch = [int]$matches[4]
|
||||
$newPatch = $patch + 1
|
||||
$separator = if ($nameWithoutExt -match '[-_\s](\d+\.\d+\.\d+)$') { $matches[0][0] } else { '' }
|
||||
return "$baseName$separator$major.$minor.$newPatch$extension"
|
||||
}
|
||||
# Pattern 2: X.Y
|
||||
elseif ($nameWithoutExt -match '^(.+?)[-_\s]?(\d+)\.(\d+)$') {
|
||||
$baseName = $matches[1]
|
||||
$major = $matches[2]
|
||||
$minor = [int]$matches[3]
|
||||
$newMinor = $minor + 1
|
||||
$separator = if ($nameWithoutExt -match '[-_\s](\d+\.\d+)$') { $matches[0][0] } else { '' }
|
||||
return "$baseName$separator$major.$newMinor$extension"
|
||||
}
|
||||
# Pattern 3: Just a number at the end
|
||||
elseif ($nameWithoutExt -match '^(.+?)[-_\s]?(\d+)$') {
|
||||
$baseName = $matches[1]
|
||||
$version = [int]$matches[2]
|
||||
$newVersion = $version + 1
|
||||
$separator = if ($nameWithoutExt -match '[-_\s]\d+$') { $matches[0][0] } else { '' }
|
||||
return "$baseName$separator$newVersion$extension"
|
||||
}
|
||||
# No version found - append .1
|
||||
else {
|
||||
return "$nameWithoutExt-1.0.1$extension"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
foreach ($mission in $MissionPath) {
|
||||
try {
|
||||
# Resolve full path
|
||||
$missionFile = Resolve-Path $mission -ErrorAction Stop
|
||||
|
||||
Write-Host "Processing: " -NoNewline -ForegroundColor White
|
||||
Write-Host "$missionFile" -ForegroundColor Cyan
|
||||
|
||||
# Verify mission file exists and is a .miz file
|
||||
if (-not (Test-Path $missionFile)) {
|
||||
throw "Mission file not found: $missionFile"
|
||||
}
|
||||
|
||||
if ([System.IO.Path]::GetExtension($missionFile) -ne ".miz") {
|
||||
throw "File is not a .miz mission file: $missionFile"
|
||||
}
|
||||
|
||||
# Create temporary extraction directory
|
||||
$tempDir = Join-Path $env:TEMP ("DCS_Mission_Patch_" + [System.Guid]::NewGuid().ToString())
|
||||
New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
|
||||
|
||||
try {
|
||||
# Extract mission file (it's a ZIP archive)
|
||||
# Use .NET classes instead of Expand-Archive for better .miz support
|
||||
Write-Host " Extracting mission..." -ForegroundColor Gray
|
||||
|
||||
Add-Type -Assembly System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($missionFile, $tempDir)
|
||||
|
||||
# Determine Lua script destination in mission structure
|
||||
# DCS stores Lua scripts in: l10n/DEFAULT/ folder
|
||||
$luaDestDir = Join-Path $tempDir "l10n\DEFAULT"
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
if (-not (Test-Path $luaDestDir)) {
|
||||
Write-Host " Creating l10n/DEFAULT directory..." -ForegroundColor Yellow
|
||||
New-Item -Path $luaDestDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$luaDestPath = Join-Path $luaDestDir $ScriptName
|
||||
|
||||
# Check if script already exists
|
||||
if (Test-Path $luaDestPath) {
|
||||
Write-Host " Replacing existing script: $ScriptName" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " Adding new script: $ScriptName" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Copy Lua script to mission
|
||||
Copy-Item $LuaScriptPath $luaDestPath -Force
|
||||
|
||||
# Determine output filename and location
|
||||
$originalFileName = Split-Path $missionFile -Leaf
|
||||
|
||||
if ($NoVersionIncrement) {
|
||||
# Keep original filename
|
||||
$outputFileName = $originalFileName
|
||||
} else {
|
||||
# Increment version number
|
||||
$outputFileName = Get-IncrementedFilename -FileName $originalFileName
|
||||
Write-Host " Version increment: $originalFileName -> $outputFileName" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Determine output directory
|
||||
if ($OutputPath) {
|
||||
$outputDir = $OutputPath
|
||||
} else {
|
||||
$outputDir = Split-Path $missionFile -Parent
|
||||
}
|
||||
|
||||
$outputMission = Join-Path $outputDir $outputFileName
|
||||
|
||||
# Remove existing mission file if it exists
|
||||
if (Test-Path $outputMission) {
|
||||
Remove-Item $outputMission -Force
|
||||
}
|
||||
|
||||
# Repackage mission file
|
||||
Write-Host " Repackaging mission..." -ForegroundColor Gray
|
||||
|
||||
# Use .NET classes for better compatibility
|
||||
Add-Type -Assembly System.IO.Compression.FileSystem
|
||||
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
|
||||
|
||||
# Create ZIP from directory (will become .miz)
|
||||
[System.IO.Compression.ZipFile]::CreateFromDirectory($tempDir, $outputMission, $compressionLevel, $false)
|
||||
|
||||
Write-Host " SUCCESS: Mission patched successfully!" -ForegroundColor Green
|
||||
Write-Host " Output: $outputMission" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
$successCount++
|
||||
}
|
||||
finally {
|
||||
# Clean up temporary directory
|
||||
if (Test-Path $tempDir) {
|
||||
Remove-Item $tempDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " ERROR: $_" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
$failCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Patching Complete" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Successful: $successCount" -ForegroundColor Green
|
||||
Write-Host "Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Gray" })
|
||||
Write-Host ""
|
||||
|
||||
if ($successCount -gt 0) {
|
||||
if ($NoVersionIncrement) {
|
||||
Write-Host "WARNING: Original mission files were OVERWRITTEN!" -ForegroundColor Red
|
||||
} else {
|
||||
Write-Host "INFO: Original mission files remain untouched. New versioned files created." -ForegroundColor Green
|
||||
}
|
||||
Write-Host "TIP: Test your patched missions in DCS before using them!" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
283
Patch-MooseMissions/Patch-MyMooseMissions.ps1
Normal file
283
Patch-MooseMissions/Patch-MyMooseMissions.ps1
Normal file
@ -0,0 +1,283 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Batch updates all DCS missions with the latest Moose framework.
|
||||
|
||||
.DESCRIPTION
|
||||
This script scans through the DCS mission development folder structure,
|
||||
finds the latest version of each mission (.miz files with version numbers),
|
||||
and patches them with the updated Moose_.lua script using Patch-MooseMissions.ps1.
|
||||
|
||||
It processes missions in the structure: C:\DCS_MissionDev\DCS_[Terrain]\[MissionFolder]\
|
||||
For each mission folder, it identifies the latest version (by version number or file date)
|
||||
and creates a new patched version.
|
||||
|
||||
.PARAMETER RootPath
|
||||
Root directory containing DCS terrain folders. Defaults to C:\DCS_MissionDev
|
||||
|
||||
.PARAMETER MooseLuaPath
|
||||
Path to the Moose_.lua file to patch into missions. Defaults to C:\DCS_MissionDev\Moose_.lua
|
||||
|
||||
.PARAMETER WhatIf
|
||||
Shows what would be processed without actually patching any files.
|
||||
|
||||
.PARAMETER ExcludeTerrain
|
||||
Array of terrain folder names to exclude from processing (e.g., @("DCS_Normandy", "DCS_Falklands"))
|
||||
|
||||
.EXAMPLE
|
||||
.\Patch-MyMooseMissions.ps1
|
||||
Processes all missions in C:\DCS_MissionDev using the default Moose_.lua
|
||||
|
||||
.EXAMPLE
|
||||
.\Patch-MyMooseMissions.ps1 -WhatIf
|
||||
Shows what missions would be processed without making any changes
|
||||
|
||||
.EXAMPLE
|
||||
.\Patch-MyMooseMissions.ps1 -ExcludeTerrain @("DCS_Normandy", "DCS_Falklands")
|
||||
Processes all missions except those in Normandy and Falklands terrains
|
||||
|
||||
.NOTES
|
||||
Author: F99th-TracerFacer
|
||||
Version: 1.0
|
||||
Requires: Patch-MooseMissions.ps1 in the same directory
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$RootPath = "C:\DCS_MissionDev",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$MooseLuaPath = "C:\DCS_MissionDev\Moose_.lua",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$ExcludeTerrain = @()
|
||||
)
|
||||
|
||||
# Verify paths exist
|
||||
if (-not (Test-Path $RootPath)) {
|
||||
Write-Error "Root path not found: $RootPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $MooseLuaPath)) {
|
||||
Write-Error "Moose_.lua file not found: $MooseLuaPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify the Patch-MooseMissions.ps1 script exists
|
||||
$patchScriptPath = Join-Path $PSScriptRoot "Patch-MooseMissions.ps1"
|
||||
if (-not (Test-Path $patchScriptPath)) {
|
||||
Write-Error "Patch-MooseMissions.ps1 not found in: $PSScriptRoot"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Batch Moose Mission Patcher" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Root Path: $RootPath" -ForegroundColor Yellow
|
||||
Write-Host "Moose Script: $MooseLuaPath" -ForegroundColor Yellow
|
||||
Write-Host "Patch Script: $patchScriptPath" -ForegroundColor Yellow
|
||||
if ($ExcludeTerrain.Count -gt 0) {
|
||||
Write-Host "Excluded Terrains: $($ExcludeTerrain -join ', ')" -ForegroundColor Yellow
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Function to parse version number from filename
|
||||
function Get-VersionNumber {
|
||||
param([string]$FileName)
|
||||
|
||||
$nameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($FileName)
|
||||
|
||||
# Try X.Y.Z pattern
|
||||
if ($nameWithoutExt -match '(\d+)\.(\d+)\.(\d+)') {
|
||||
$major = [int]$matches[1]
|
||||
$minor = [int]$matches[2]
|
||||
$patch = [int]$matches[3]
|
||||
return [PSCustomObject]@{
|
||||
Major = $major
|
||||
Minor = $minor
|
||||
Patch = $patch
|
||||
Value = ($major * 1000000) + ($minor * 1000) + $patch
|
||||
HasVersion = $true
|
||||
}
|
||||
}
|
||||
# Try X.Y pattern
|
||||
elseif ($nameWithoutExt -match '(\d+)\.(\d+)') {
|
||||
$major = [int]$matches[1]
|
||||
$minor = [int]$matches[2]
|
||||
return [PSCustomObject]@{
|
||||
Major = $major
|
||||
Minor = $minor
|
||||
Patch = 0
|
||||
Value = ($major * 1000000) + ($minor * 1000)
|
||||
HasVersion = $true
|
||||
}
|
||||
}
|
||||
# Try single version number
|
||||
elseif ($nameWithoutExt -match '(\d+)$') {
|
||||
$version = [int]$matches[1]
|
||||
return [PSCustomObject]@{
|
||||
Major = $version
|
||||
Minor = 0
|
||||
Patch = 0
|
||||
Value = $version * 1000000
|
||||
HasVersion = $true
|
||||
}
|
||||
}
|
||||
|
||||
# No version found
|
||||
return [PSCustomObject]@{
|
||||
Major = 0
|
||||
Minor = 0
|
||||
Patch = 0
|
||||
Value = 0
|
||||
HasVersion = $false
|
||||
}
|
||||
}
|
||||
|
||||
# Function to get the latest mission file from a directory
|
||||
function Get-LatestMission {
|
||||
param([string]$DirectoryPath)
|
||||
|
||||
# Get all .miz files in the directory (not subdirectories)
|
||||
$mizFiles = Get-ChildItem -Path $DirectoryPath -Filter "*.miz" -File -ErrorAction SilentlyContinue
|
||||
|
||||
if ($mizFiles.Count -eq 0) {
|
||||
return $null
|
||||
}
|
||||
|
||||
# Separate files with version numbers from those without
|
||||
$versionedFiles = @()
|
||||
$nonVersionedFiles = @()
|
||||
|
||||
foreach ($file in $mizFiles) {
|
||||
$version = Get-VersionNumber -FileName $file.Name
|
||||
if ($version.HasVersion) {
|
||||
$versionedFiles += [PSCustomObject]@{
|
||||
File = $file
|
||||
Version = $version
|
||||
}
|
||||
} else {
|
||||
$nonVersionedFiles += $file
|
||||
}
|
||||
}
|
||||
|
||||
# If we have versioned files, return the one with the highest version
|
||||
if ($versionedFiles.Count -gt 0) {
|
||||
$latest = $versionedFiles | Sort-Object -Property { $_.Version.Value } -Descending | Select-Object -First 1
|
||||
return $latest.File
|
||||
}
|
||||
|
||||
# If no versioned files, return the most recently modified file
|
||||
if ($nonVersionedFiles.Count -gt 0) {
|
||||
return $nonVersionedFiles | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
# Get all DCS terrain folders (folders starting with "DCS_")
|
||||
$terrainFolders = Get-ChildItem -Path $RootPath -Directory | Where-Object { $_.Name -match '^DCS_' }
|
||||
|
||||
if ($terrainFolders.Count -eq 0) {
|
||||
Write-Warning "No DCS terrain folders found in: $RootPath"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Found $($terrainFolders.Count) terrain folder(s)" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Track statistics
|
||||
$totalMissionsFound = 0
|
||||
$totalMissionsPatched = 0
|
||||
$totalMissionsFailed = 0
|
||||
$skippedTerrains = 0
|
||||
|
||||
# Process each terrain folder
|
||||
foreach ($terrainFolder in $terrainFolders) {
|
||||
$terrainName = $terrainFolder.Name
|
||||
|
||||
# Check if this terrain should be excluded
|
||||
if ($ExcludeTerrain -contains $terrainName) {
|
||||
Write-Host "SKIPPING TERRAIN: $terrainName (excluded)" -ForegroundColor DarkGray
|
||||
$skippedTerrains++
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host "TERRAIN: $terrainName" -ForegroundColor Cyan
|
||||
|
||||
# Get all subdirectories (mission folders)
|
||||
$missionFolders = Get-ChildItem -Path $terrainFolder.FullName -Directory -ErrorAction SilentlyContinue
|
||||
|
||||
if ($missionFolders.Count -eq 0) {
|
||||
Write-Host " No mission folders found" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host " Found $($missionFolders.Count) mission folder(s)" -ForegroundColor Gray
|
||||
|
||||
# Process each mission folder
|
||||
foreach ($missionFolder in $missionFolders) {
|
||||
$missionFolderName = $missionFolder.Name
|
||||
|
||||
# Get the latest mission file
|
||||
$latestMission = Get-LatestMission -DirectoryPath $missionFolder.FullName
|
||||
|
||||
if ($null -eq $latestMission) {
|
||||
Write-Host " [$missionFolderName] No .miz files found" -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
|
||||
$totalMissionsFound++
|
||||
|
||||
Write-Host " [$missionFolderName] Latest: " -NoNewline -ForegroundColor White
|
||||
Write-Host "$($latestMission.Name)" -ForegroundColor Yellow
|
||||
|
||||
# Execute the patch script
|
||||
if ($PSCmdlet.ShouldProcess($latestMission.FullName, "Patch with Moose_.lua")) {
|
||||
try {
|
||||
# Call Patch-MooseMissions.ps1
|
||||
& $patchScriptPath -MissionPath $latestMission.FullName -LuaScriptPath $MooseLuaPath -ErrorAction Stop
|
||||
|
||||
# Check if it succeeded (the script will output its own messages)
|
||||
if ($LASTEXITCODE -eq 0 -or $null -eq $LASTEXITCODE) {
|
||||
$totalMissionsPatched++
|
||||
} else {
|
||||
$totalMissionsFailed++
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " ERROR: Failed to patch mission - $_" -ForegroundColor Red
|
||||
$totalMissionsFailed++
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host " WHATIF: Would patch this mission" -ForegroundColor Magenta
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Final summary
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Batch Processing Complete" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Terrains Processed: $($terrainFolders.Count - $skippedTerrains)" -ForegroundColor White
|
||||
if ($skippedTerrains -gt 0) {
|
||||
Write-Host "Terrains Skipped: $skippedTerrains" -ForegroundColor DarkGray
|
||||
}
|
||||
Write-Host "Missions Found: $totalMissionsFound" -ForegroundColor White
|
||||
Write-Host "Missions Patched: $totalMissionsPatched" -ForegroundColor Green
|
||||
if ($totalMissionsFailed -gt 0) {
|
||||
Write-Host "Missions Failed: $totalMissionsFailed" -ForegroundColor Red
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
if ($WhatIfPreference) {
|
||||
Write-Host "INFO: This was a WhatIf run - no files were modified" -ForegroundColor Magenta
|
||||
} elseif ($totalMissionsPatched -gt 0) {
|
||||
Write-Host "SUCCESS: All missions have been patched with the latest Moose framework!" -ForegroundColor Green
|
||||
Write-Host "TIP: Test your patched missions in DCS before deployment!" -ForegroundColor Yellow
|
||||
}
|
||||
197
Patch-MooseMissions/README.md
Normal file
197
Patch-MooseMissions/README.md
Normal file
@ -0,0 +1,197 @@
|
||||
# DCS Mission Patcher
|
||||
|
||||
PowerShell script to automatically patch DCS mission files (.miz) with updated Lua scripts and increment version numbers.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Updates Lua scripts in .miz files without opening DCS Mission Editor
|
||||
- ✅ **Automatically increments version numbers** in mission filenames (e.g., 1.2.3 → 1.2.4)
|
||||
- ✅ **Preserves original missions** - creates new versioned files instead of overwriting
|
||||
- ✅ Supports single or batch processing of multiple missions
|
||||
- ✅ Can output to a different directory
|
||||
- ✅ Handles both new script insertion and existing script replacement
|
||||
- ✅ Pipeline support for processing multiple missions
|
||||
- ✅ Smart version detection (supports X.Y.Z, X.Y, and X formats)
|
||||
|
||||
## Version Increment Examples
|
||||
|
||||
| Input Filename | Output Filename |
|
||||
|----------------|-----------------|
|
||||
| `Mission-1.2.3.miz` | `Mission-1.2.4.miz` |
|
||||
| `Operation Black Gold 2.8.miz` | `Operation Black Gold 2.9.miz` |
|
||||
| `F99th-Battle of Gori 1.3.miz` | `F99th-Battle of Gori 1.4.miz` |
|
||||
| `MyMission-5.miz` | `MyMission-6.miz` |
|
||||
| `Test.miz` | `Test-1.0.1.miz` |
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Update a mission with automatic version increment:
|
||||
|
||||
```powershell
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "MyMission-1.2.3.miz" -LuaScriptPath "Moose_.lua"
|
||||
# Original: MyMission-1.2.3.miz (untouched)
|
||||
# Creates: MyMission-1.2.4.miz
|
||||
```
|
||||
|
||||
### Batch Processing
|
||||
|
||||
Update all .miz files in a directory:
|
||||
|
||||
```powershell
|
||||
Get-ChildItem "C:\DCS_Missions\*.miz" | .\Patch-MooseMissions.ps1 -LuaScriptPath "C:\Scripts\Moose_.lua"
|
||||
# Each mission gets a new version
|
||||
```
|
||||
|
||||
### Output to Different Directory
|
||||
|
||||
Patch missions and save versioned outputs to a different folder:
|
||||
|
||||
```powershell
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "Mission-1.5.miz" -LuaScriptPath "Moose_.lua" -OutputPath "C:\PatchedMissions"
|
||||
# Creates: C:\PatchedMissions\Mission-1.6.miz
|
||||
```
|
||||
|
||||
### Disable Version Increment (CAUTION!)
|
||||
|
||||
⚠️ Overwrite the original mission file without creating a new version:
|
||||
|
||||
```powershell
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "Mission-1.2.3.miz" -LuaScriptPath "Moose_.lua" -NoVersionIncrement
|
||||
# WARNING: Overwrites Mission-1.2.3.miz (original is lost!)
|
||||
```
|
||||
|
||||
### Custom Script Name
|
||||
|
||||
Insert a script with a different name than the source file:
|
||||
|
||||
```powershell
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "Mission.miz" -LuaScriptPath "MyScript.lua" -ScriptName "CustomName.lua"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `-MissionPath` | Yes | Path to .miz mission file(s) to patch |
|
||||
| `-LuaScriptPath` | Yes | Path to the Lua script to insert/replace |
|
||||
| `-ScriptName` | No | Name for the script inside the mission (defaults to source filename) |
|
||||
| `-OutputPath` | No | Directory for patched missions (defaults to source directory) |
|
||||
| `-NoVersionIncrement` | No | **CAUTION:** Overwrites original instead of creating new version |
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Update All Caucasus Missions with Version Increment
|
||||
|
||||
```powershell
|
||||
Get-ChildItem "C:\DCS_MissionDev\DCS_Caucasus\*.miz" | .\Patch-MooseMissions.ps1 -LuaScriptPath "C:\Moose\Moose_.lua"
|
||||
# Each mission gets a new version: 1.2.miz -> 1.3.miz
|
||||
# Originals remain untouched
|
||||
```
|
||||
|
||||
### Example 2: Update Specific Missions to Output Folder
|
||||
|
||||
```powershell
|
||||
$missions = @(
|
||||
"F99th-Operation Black Gold 2.8.miz",
|
||||
"F99th-Operation Ronin 1.4.miz",
|
||||
"F99th-Battle of Gori 1.3.miz"
|
||||
)
|
||||
|
||||
$missions | .\Patch-MooseMissions.ps1 -LuaScriptPath "Moose_.lua" -OutputPath "C:\UpdatedMissions"
|
||||
# Creates: Operation Black Gold 2.9.miz, Operation Ronin 1.5.miz, Battle of Gori 1.4.miz in C:\UpdatedMissions
|
||||
```
|
||||
|
||||
### Example 3: Overwrite Original (Use with Caution)
|
||||
|
||||
```powershell
|
||||
.\Patch-MooseMissions.ps1 -MissionPath "TestMission-1.0.miz" -LuaScriptPath "Moose_.lua" -NoVersionIncrement
|
||||
# WARNING: Overwrites TestMission-1.0.miz (original is lost)
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Extraction**: The script treats .miz files as ZIP archives and extracts them to a temporary directory
|
||||
2. **Script Replacement**: Locates the Lua script in `l10n/DEFAULT/` folder and replaces/adds it
|
||||
3. **Version Increment**: Automatically detects version pattern and increments the patch number
|
||||
4. **Repackaging**: Compresses the modified mission into a new .miz file with incremented version
|
||||
5. **Cleanup**: Removes temporary files
|
||||
|
||||
## Version Detection Logic
|
||||
|
||||
The script intelligently detects and increments version numbers:
|
||||
|
||||
- **X.Y.Z format** (e.g., `Mission-1.2.3.miz`) → Increments Z: `Mission-1.2.4.miz`
|
||||
- **X.Y format** (e.g., `Mission-2.8.miz`) → Increments Y: `Mission-2.9.miz`
|
||||
- **X format** (e.g., `Mission-5.miz`) → Increments X: `Mission-6.miz`
|
||||
- **No version** (e.g., `Mission.miz`) → Adds version: `Mission-1.0.1.miz`
|
||||
|
||||
Supports various separators: `-`, `_`, or space
|
||||
|
||||
## Mission File Structure
|
||||
|
||||
DCS mission files (.miz) are ZIP archives with this structure:
|
||||
|
||||
```
|
||||
Mission.miz
|
||||
├── mission
|
||||
├── options
|
||||
├── warehouses
|
||||
├── l10n/
|
||||
│ └── DEFAULT/
|
||||
│ ├── dictionary
|
||||
│ ├── mapResource
|
||||
│ └── *.lua ← Scripts are stored here
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
⚠️ **Always test patched missions** before using them in production or multiplayer!
|
||||
|
||||
⚠️ **Originals are safe**: By default, the script creates NEW versioned files and never modifies originals
|
||||
|
||||
⚠️ **Script order matters**: If your mission has script load order dependencies, this tool only replaces the file content, not the trigger order
|
||||
|
||||
⚠️ **Version increment default**: By default, versions are incremented. Use `-NoVersionIncrement` to overwrite originals (NOT recommended)
|
||||
|
||||
✅ **Safe for**: Updating framework files like Moose_.lua, mist.lua, or any embedded Lua script
|
||||
|
||||
✅ **Preserves originals**: Original missions remain untouched (new versioned files are created)
|
||||
|
||||
✅ **No backups needed**: Since originals aren't modified, you always have your previous version
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "File is not a .miz mission file"
|
||||
- Ensure you're pointing to a valid .miz file, not a .lua or other file type
|
||||
|
||||
### "Lua script not found"
|
||||
- Verify the path to your Lua script is correct and the file exists
|
||||
|
||||
### Mission doesn't work after patching
|
||||
- Restore from backup
|
||||
- Verify the Lua script is valid
|
||||
- Check DCS.log for script errors
|
||||
- Ensure you updated the correct script name
|
||||
|
||||
### Permission errors
|
||||
- Run PowerShell as Administrator if modifying files in protected directories
|
||||
- Ensure mission files are not read-only
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows PowerShell 5.1 or later (or PowerShell Core 7+)
|
||||
- Write permissions to mission file locations
|
||||
- Valid .miz mission files
|
||||
- Valid Lua script to insert
|
||||
|
||||
## Author
|
||||
|
||||
**F99th-TracerFacer**
|
||||
|
||||
Discord: https://discord.gg/7wBVWKK3
|
||||
|
||||
## License
|
||||
|
||||
Free to use and modify for the DCS community.
|
||||
Loading…
x
Reference in New Issue
Block a user