Inital Commit

This commit is contained in:
iTracerFacer 2024-11-12 14:18:28 -06:00
commit 949e19c61a
2188 changed files with 988098 additions and 0 deletions

BIN
AllahuAkbar.ogg Normal file

Binary file not shown.

10505
CSAR.lua Normal file

File diff suppressed because one or more lines are too long

1864
CSAR_Custom.lua Normal file

File diff suppressed because it is too large Load Diff

6467
CTLD.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry kind="src" path="src"/>
<buildpathentry combineaccessrules="false" kind="prj" path="/Moose_Framework"/>
</buildpath>

17
DCS_Afgainistan/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>DCS_Afgainistan</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

View File

@ -0,0 +1,400 @@
--[ MOOSE CTLD v1.0]
--[ Created by: F99th-TracerFacer
--[ Date: Nov2024
-- Setup CTLD for Red and Blue Coalitions
local red_helos = SET_GROUP:New():FilterCoalitions("red"):FilterCategoryHelicopter():FilterStart()
local red_ctld = CTLD:New(coalition.side.RED)
red_ctld.SetOwnSetPilotGroups(red_helos)
local blue_helos = SET_GROUP:New():FilterCoalitions("blue"):FilterCategoryHelicopter():FilterStart()
local blue_ctld = CTLD:New(coalition.side.BLUE)
blue_ctld.SetOwnSetPilotGroups(blue_helos)
red_ctld.useprefix = false -- (DO NOT SWITCH THIS OFF UNLESS YOU KNOW WHAT YOU ARE DOING!) Adjust **before** starting CTLD. If set to false, *all* choppers of the coalition side will be enabled for CTLD.
red_ctld.CrateDistance = 35 -- List and Load crates in this radius only.
red_ctld.PackDistance = 35 -- Pack crates in this radius only
red_ctld.dropcratesanywhere = true -- Option to allow crates to be dropped anywhere.
red_ctld.dropAsCargoCrate = false -- Parachuted herc cargo is not unpacked automatically but placed as crate to be unpacked. Needs a cargo with the same name defined like the cargo that was dropped.
red_ctld.maximumHoverHeight = 15 -- Hover max this high to load.
red_ctld.minimumHoverHeight = 4 -- Hover min this low to load.
red_ctld.forcehoverload = true -- Crates (not: troops) can **only** be loaded while hovering.
red_ctld.hoverautoloading = true -- Crates in CrateDistance in a LOAD zone will be loaded automatically if space allows.
red_ctld.smokedistance = 10000 -- Smoke or flares can be request for zones this far away (in meters).
red_ctld.movetroopstowpzone = true -- Troops and vehicles will move to the nearest MOVE zone...
red_ctld.movetroopsdistance = 5000 -- .. but only if this far away (in meters)
red_ctld.suppressmessages = false -- Set to true if you want to script your own messages.
red_ctld.repairtime = 300 -- Number of seconds it takes to repair a unit.
red_ctld.buildtime = 300 -- Number of seconds it takes to build a unit. Set to zero or nil to build instantly.
red_ctld.cratecountry = country.id.GERMANY -- ID of crates. Will default to country.id.RUSSIA for RED coalition setups.
red_ctld.allowcratepickupagain = true -- allow re-pickup crates that were dropped.
red_ctld.enableslingload = false -- allow cargos to be slingloaded - might not work for all cargo types
red_ctld.pilotmustopendoors = false -- force opening of doors
red_ctld.SmokeColor = SMOKECOLOR.Red -- default color to use when dropping smoke from heli
red_ctld.FlareColor = FLARECOLOR.Red -- color to use when flaring from heli
red_ctld.basetype = "container_cargo" -- default shape of the cargo container
red_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes
red_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types.
red_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted.
red_ctld.nobuildinloadzones = true -- forbid players to build stuff in LOAD zones if set to `true`
red_ctld.movecratesbeforebuild = true -- crates must be moved once before they can be build. Set to false for direct builds.
red_ctld.surfacetypes = {land.SurfaceType.LAND,land.SurfaceType.ROAD,land.SurfaceType.RUNWAY,land.SurfaceType.SHALLOW_WATER} -- surfaces for loading back objects.
red_ctld.nobuildmenu = false -- if set to true effectively enforces to have engineers build/repair stuff for you.
red_ctld.RadioSound = "beacon.ogg" -- -- this sound will be hearable if you tune in the beacon frequency. Add the sound file to your miz.
red_ctld.RadioSoundFC3 = "beacon.ogg" -- this sound will be hearable by FC3 users (actually all UHF radios); change to something like "beaconsilent.ogg" and add the sound file to your miz if you don't want to annoy FC3 pilots.
red_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop for CTLD_CARGO.Enum.STATIc types for CTLD for the Chinook
red_ctld.TroopUnloadDistGround = 5 -- If hovering, spawn dropped troops this far away in meters from the helo
red_ctld.TroopUnloadDistHover = 1.5 -- If grounded, spawn dropped troops this far away in meters from the helo
red_ctld.TroopUnloadDistGroundHerc = 25 -- On the ground, unload troops this far behind the Hercules
red_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
red_ctld.EngineerSearch = 2000 -- Search radius for engineers.
blue_ctld.useprefix = false -- (DO NOT SWITCH THIS OFF UNLESS YOU KNOW WHAT YOU ARE DOING!) Adjust **before** starting CTLD. If set to false, *all* choppers of the coalition side will be enabled for CTLD.
blue_ctld.CrateDistance = 35 -- List and Load crates in this radius only.
blue_ctld.PackDistance = 35 -- Pack crates in this radius only
blue_ctld.dropcratesanywhere = true -- Option to allow crates to be dropped anywhere.
blue_ctld.dropAsCargoCrate = false -- Parachuted herc cargo is not unpacked automatically but placed as crate to be unpacked. Needs a cargo with the same name defined like the cargo that was dropped.
blue_ctld.maximumHoverHeight = 15 -- Hover max this high to load.
blue_ctld.minimumHoverHeight = 4 -- Hover min this low to load.
blue_ctld.forcehoverload = true -- Crates (not: troops) can **only** be loaded while hovering.
blue_ctld.hoverautoloading = true -- Crates in CrateDistance in a LOAD zone will be loaded automatically if space allows.
blue_ctld.smokedistance = 10000 -- Smoke or flares can be request for zones this far away (in meters).
blue_ctld.movetroopstowpzone = true -- Troops and vehicles will move to the nearest MOVE zone...
blue_ctld.movetroopsdistance = 5000 -- .. but only if this far away (in meters)
blue_ctld.suppressmessages = false -- Set to true if you want to script your own messages.
blue_ctld.repairtime = 300 -- Number of seconds it takes to repair a unit.
blue_ctld.buildtime = 300 -- Number of seconds it takes to build a unit. Set to zero or nil to build instantly.
blue_ctld.cratecountry = country.id.GERMANY -- ID of crates. Will default to country.id.RUSSIA for RED coalition setups.
blue_ctld.allowcratepickupagain = true -- allow re-pickup crates that were dropped.
blue_ctld.enableslingload = false -- allow cargos to be slingloaded - might not work for all cargo types
blue_ctld.pilotmustopendoors = false -- force opening of doors
blue_ctld.SmokeColor = SMOKECOLOR.Blue -- default color to use when dropping smoke from heli
blue_ctld.FlareColor = FLARECOLOR.Blue -- color to use when flaring from heli
blue_ctld.basetype = "container_cargo" -- default shape of the cargo container
blue_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes
blue_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types.
blue_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted.
blue_ctld.nobuildinloadzones = true -- forbid players to build stuff in LOAD zones if set to `true`
blue_ctld.movecratesbeforebuild = true -- crates must be moved once before they can be build. Set to false for direct builds.
blue_ctld.surfacetypes = {land.SurfaceType.LAND,land.SurfaceType.ROAD,land.SurfaceType.RUNWAY,land.SurfaceType.SHALLOW_WATER} -- surfaces for loading back objects.
blue_ctld.nobuildmenu = false -- if set to true effectively enforces to have engineers build/repair stuff for you.
blue_ctld.RadioSound = "beacon.ogg" -- -- this sound will be hearable if you tune in the beacon frequency. Add the sound file to your miz.
blue_ctld.RadioSoundFC3 = "beacon.ogg" -- this sound will be hearable by FC3 users (actually all UHF radios); change to something like "beaconsilent.ogg" and add the sound file to your miz if you don't want to annoy FC3 pilots.
blue_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop for CTLD_CARGO.Enum.STATIc types for CTLD for the Chinook
blue_ctld.TroopUnloadDistGround = 5 -- If hovering, spawn dropped troops this far away in meters from the helo
blue_ctld.TroopUnloadDistHover = 1.5 -- If grounded, spawn dropped troops this far away in meters from the helo
blue_ctld.TroopUnloadDistGroundHerc = 25 -- On the ground, unload troops this far behind the Hercules
blue_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
blue_ctld.EngineerSearch = 2000 -- Search radius for engineers.
-- Start the CTLD Instances
red_ctld:Start(5)
blue_ctld:Start(5)
-- Add Anti Tank Teams
red_ctld:AddTroopsCargo("Anti-Tank Team Small(3x80kg)",{"Red-ATS"}, CTLD_CARGO.Enum.TROOPS, 3, 80)
red_ctld:AddTroopsCargo("Anti-Tank Team Medium(10x80kg)",{"Red-ATM"}, CTLD_CARGO.Enum.TROOPS, 10, 80)
red_ctld:AddTroopsCargo("Anti-Tank Team Large(24x80kg)",{"Red-ATL"}, CTLD_CARGO.Enum.TROOPS, 24, 80)
blue_ctld:AddTroopsCargo("Anti-Tank Team Small(3x80kg)",{"Blue-ATS"}, CTLD_CARGO.Enum.TROOPS, 3, 80)
blue_ctld:AddTroopsCargo("Anti-Tank Team Medium(10x80kg)",{"Blue-ATM"}, CTLD_CARGO.Enum.TROOPS, 10, 80)
blue_ctld:AddTroopsCargo("Anti-Tank Team Small(20x80kg)",{"Blue-ATL"}, CTLD_CARGO.Enum.TROOPS, 20, 80)
-- Add Mortar Teams
red_ctld:AddTroopsCargo("Mortar Team (3x80kg)",{"Red-MTS"}, CTLD_CARGO.Enum.TROOPS, 3, 80)
red_ctld:AddTroopsCargo("Mortar Team (10x80kg)",{"Red-MTM"}, CTLD_CARGO.Enum.TROOPS, 10, 80)
blue_ctld:AddTroopsCargo("Mortar Team (3x80kg)",{"Blue-MTS"}, CTLD_CARGO.Enum.TROOPS, 3, 80)
blue_ctld:AddTroopsCargo("Mortar Team (10x80kg)",{"Blue-MTM"}, CTLD_CARGO.Enum.TROOPS, 10, 80)
-- Add Anti Air Teams
red_ctld:AddTroopsCargo("Anti-Air (4x80kg)",{"Red-AA"},CTLD_CARGO.Enum.TROOPS, 4, 80, 10)
blue_ctld:AddTroopsCargo("Anti-Air(4x80kg)",{"Blue-AA"},CTLD_CARGO.Enum.TROOPS, 4, 80, 10)
-- Add Engineers
red_ctld:AddTroopsCargo("Engineer Team(3x80kg)",{"Red-Eng"},CTLD_CARGO.Enum.ENGINEERS, 3, 80)
blue_ctld:AddTroopsCargo("Engineer Team(3x80kg)",{"Blue-Eng"},CTLD_CARGO.Enum.ENGINEERS, 3, 80)
-- Add Ammo Trucks
red_ctld:AddCratesCargo("Ammo Truck (2775kg)",{"Red-Ammo"},CTLD_CARGO.Enum.VEHICLE, 2, 2775, 10)
blue_ctld:AddCratesCargo("Ammo Truck (2775kg)",{"Blue-Ammo"},CTLD_CARGO.Enum.VEHICLE, 2, 2775, 10)
-- Add JTACs
--red_ctld:AddCratesCargo("JTAC",{"Red-JTAC"},CTLD_CARGO.Enum.VEHICLE, 1, 2775, 10) -- no soup for you commie bitches!
blue_ctld:AddCratesCargo("JTAC (2775kg)",{"Blue-JTAC"},CTLD_CARGO.Enum.VEHICLE, 1, 2775, 10)
-- Add Tanks
red_ctld:AddCratesCargo("T-90 (20000kg)",{"Red-T90"},CTLD_CARGO.Enum.VEHICLE, 1, 20000, 25)
blue_ctld:AddCratesCargo("M1A2 (20000kg)",{"Blue-M1A2"},CTLD_CARGO.Enum.VEHICLE, 1, 20000, 25)
-- Add FOBs
red_ctld:AddCratesCargo("Forward Ops Base (500kg)",{"Red-FOB"},CTLD_CARGO.Enum.FOB, 4, 500, 8)
blue_ctld:AddCratesCargo("Forward Ops Base (500kg)",{"Blue-FOB"},CTLD_CARGO.Enum.FOB, 4, 500, 8)
-- AA Crates
red_ctld:AddCratesCargo("SA-8",{"SA8"},CTLD_CARGO.Enum.CRATE, 4, 500, 10)
red_ctld:AddCratesCargo("SA-6",{"SA6"},CTLD_CARGO.Enum.CRATE, 4, 500, 10)
red_ctld:AddCratesCargo("SA-10",{"SA10"},CTLD_CARGO.Enum.CRATE, 6, 500, 10)
blue_ctld:AddCratesCargo("Linebacker",{"LINEBACKER"},CTLD_CARGO.Enum.CRATE, 2, 500, 10)
blue_ctld:AddCratesCargo("Hawk Site",{"HAWK"},CTLD_CARGO.Enum.CRATE, 4, 500, 10)
blue_ctld:AddCratesCargo("Patriot Site",{"PATRIOT"},CTLD_CARGO.Enum.CRATE, 6, 500, 10)
-- Add 6 Red Load Zones
red_ctld:AddCTLDZone("RedLoadZone1", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
red_ctld:AddCTLDZone("RedLoadZone2", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
red_ctld:AddCTLDZone("RedLoadZone3", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
red_ctld:AddCTLDZone("RedLoadZone4", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
red_ctld:AddCTLDZone("RedLoadZone5", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
red_ctld:AddCTLDZone("RedLoadZone6", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Red, true, true)
-- Add 6 Blue Load Zones
blue_ctld:AddCTLDZone("BlueLoadZone1", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
blue_ctld:AddCTLDZone("BlueLoadZone2", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
blue_ctld:AddCTLDZone("BlueLoadZone3", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
blue_ctld:AddCTLDZone("BlueLoadZone4", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
blue_ctld:AddCTLDZone("BlueLoadZone5", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
blue_ctld:AddCTLDZone("BlueLoadZone6", CTLD.CargoZoneType.LOAD, SMOKECOLOR.Blue, true, true)
function blue_ctld:OnAfterTroopsDeployed(From,Event,To,Group,Unit,Troops)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Troops:GetName()
local points = pointsAwardedTroopsDeployed
MESSAGE:New("Pilot " .. PlayerName .. " has deployed " .. vname .. " to the field!", msgTime, "[ Mission Info ]", false):ToBlue()
USERSOUND:New("combatAudio5.ogg"):ToCoalition(coalition.side.BLUE)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for deploying troops!", PlayerName, points), points)
end
end
function blue_ctld:OnAfterTroopsExtracted(From,Event,To,Group,Unit,Cargo)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Cargo:GetName()
local points = pointsAwardedTroopsExtracted
MESSAGE:New("Pilot " .. PlayerName .. " has extracted " .. vname .. " from the field!", msgTime, "[ Mission Info ]", false):ToBlue()
USERSOUND:New("getToTheChoppa.ogg"):ToCoalition(coalition.side.BLUE)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for extracting troops!", PlayerName, points), points)
end
end
function blue_ctld:OnAfterTroopsPickedUp(From,Event,To,Group,Unit,Cargo)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Cargo:GetName()
local points = pointsAwardedTroopsPickedup
MESSAGE:New("Pilot " .. PlayerName .. " has picked up " .. vname .. " from a supply base!", msgTime, "[ Mission Info ]", false):ToBlue()
USERSOUND:New("JoinTheArmy.ogg"):ToCoalition(coalition.side.BLUE)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for picking up troops!", PlayerName, points), points)
end
end
function blue_ctld:OnAfterTroopsRTB(From,Event,To,Group,Unit)
if Unit then
local PlayerName = Unit:GetPlayerName()
local points = pointsAwardedTroopsRTB
MESSAGE:New("Pilot " .. PlayerName .. " returned troops to home base!", msgTime, "[ Mission Info ]", false):ToBlue()
USERSOUND:New("cheering.ogg"):ToCoalition(coalition.side.BLUE)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for returning troops!", PlayerName, points), points)
end
end
-- Scoring and messaging
function blue_ctld:OnAfterCratesDropped(From, Event, To, Group, Unit, Cargotable)
if Unit then
local points = pointsAwardedCrateDropped
local PlayerName = Unit:GetPlayerName()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for transporting cargo crates!", PlayerName, points), points)
end
end
function blue_ctld:OnAfterCratesBuild(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateBuilt
local PlayerName = Unit:GetPlayerName()
local vname = Vehicle:GetName()
USERSOUND:New("construction.ogg"):ToCoalition(coalition.side.BLUE)
MESSAGE:New("Pilot " .. PlayerName .. " has deployed " .. vname .. " to the field!", msgTime, "[ Mission Info ]", false):ToBlue()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for the construction of Units!", PlayerName, points), points)
-- Is this a FOB being built? If so add a Load Zone around the deployed crate.
env.info("CRATEBUILD: Is this a fob?: " .. vname,false)
if string.match(vname,"FOB",1,true) then
env.info("CRATEBUILD: Yes, this is a FOB, building: " .. vname,false)
local Coord = Vehicle:GetCoordinate():GetVec2()
local mCoord = Vehicle:GetCoordinate()
local zonename = "FOB-" .. math.random(1,10000)
local fobzone = ZONE_RADIUS:New(zonename,Coord,1000)
local fobmarker = MARKER:New(mCoord, "FORWARD OPERATING BASE:\nBUILT BY: " .. PlayerName .. "\n\nTransport Helos may pick up troops and equipment from this location."):ReadOnly():ToCoalition(coalition.side.BLUE)
fobzone:DrawZone(2,{.25,.63,.79},1,{0,0,0},0.25,2,true)
blue_ctld:AddCTLDZone(zonename,CTLD.CargoZoneType.LOAD,SMOKECOLOR.Blue,true,true)
MESSAGE:New("Pilot " .. PlayerName .. " has created a new loading zone for troops and equipment! See your F10 Map for marker!", msgTime, "[ Mission Info ]", false):ToBlue()
else
env.info("CRATEBUILD: No! Not a FOB: " .. vname,false)
end
end
end
function blue_ctld:OnBeforeCratesRepaired(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateRepair
local GroupCategory = Group:GetCategoryName()
local PlayerName = Unit:GetPlayerName()
MESSAGE:New("Pilot " .. PlayerName .. " has started repairs on " .. GroupCategory .. "! Nice Job!", msgTime, "[ Mission Info ]", false):ToBlue()
end
end
function blue_ctld:OnAfterCratesRepaired(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateRepair
local PlayerName = Unit:GetPlayerName()
USERSOUND:New("repair.ogg"):ToCoalition(coalition.side.BLUE)
MESSAGE:New("Pilot " .. PlayerName .. " has conducted repears on " .. Vehicle "! Nice Job!", msgTime, "[ Mission Info ]", false):ToRed()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for the repair of Units!", PlayerName, points), points)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Red CTLD Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------
function red_ctld:OnAfterTroopsDeployed(From,Event,To,Group,Unit,Troops)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Troops:GetName()
local points = pointsAwardedTroopsDeployed
MESSAGE:New("Pilot " .. PlayerName .. " has deployed " .. vname .. " to the field!", msgTime, "[ Mission Info ]", false):ToRed()
USERSOUND:New("combatAudio5.ogg"):ToCoalition(coalition.side.RED)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for deploying troops!", PlayerName, points), points)
end
end
function red_ctld:OnAfterTroopsExtracted(From,Event,To,Group,Unit,Cargo)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Cargo:GetName()
local points = pointsAwardedTroopsExtracted
MESSAGE:New("Pilot " .. PlayerName .. " has extracted " .. vname .. " from the field!", msgTime, "[ Mission Info ]", false):ToRed()
USERSOUND:New("getToTheChoppa.ogg"):ToCoalition(coalition.side.RED)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for extracting troops!", PlayerName, points), points)
end
end
function red_ctld:OnAfterTroopsPickedUp(From,Event,To,Group,Unit,Cargo)
if Unit then
local PlayerName = Unit:GetPlayerName()
local vname = Cargo:GetName()
local points = pointsAwardedTroopsPickedup
MESSAGE:New("Pilot " .. PlayerName .. " has picked up " .. vname .. " from a supply base!", msgTime, "[ Mission Info ]", false):ToRed()
USERSOUND:New("JoinTheArmy.ogg"):ToCoalition(coalition.side.RED)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for picking up troops!", PlayerName, points), points)
end
end
function red_ctld:OnAfterTroopsRTB(From,Event,To,Group,Unit)
if Unit then
local PlayerName = Unit:GetPlayerName()
local points = pointsAwardedTroopsRTB
MESSAGE:New("Pilot " .. PlayerName .. " returned troops to home base!", msgTime, "[ Mission Info ]", false):ToRed()
USERSOUND:New("cheering.ogg"):ToCoalition(coalition.side.RED)
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for returning troops!", PlayerName, points), points)
end
end
-- Scoring and messaging
function red_ctld:OnAfterCratesDropped(From, Event, To, Group, Unit, Cargotable)
if Unit then
local points = pointsAwardedCrateDropped
local PlayerName = Unit:GetPlayerName()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for transporting cargo crates!", PlayerName, points), points)
end
end
function red_ctld:OnAfterCratesBuild(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateBuilt
local PlayerName = Unit:GetPlayerName()
local vname = Vehicle:GetName()
USERSOUND:New("construction.ogg"):ToCoalition(coalition.side.RED)
MESSAGE:New("Pilot " .. PlayerName .. " has deployed " .. vname .. " to the field!", msgTime, "[ Mission Info ]", false):ToRed()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for the construction of Units!", PlayerName, points), points)
-- Is this a FOB being built? If so add a Load Zone around the deployed crate.
env.info("CRATEBUILD: Is this a fob?: " .. vname,false)
if string.match(vname,"FOB",1,true) then
env.info("CRATEBUILD: Yes, this is a FOB, building: " .. vname,false)
local Coord = Vehicle:GetCoordinate():GetVec2()
local mCoord = Vehicle:GetCoordinate()
local zonename = "FOB-" .. math.random(1,10000)
local fobzone = ZONE_RADIUS:New(zonename,Coord,1000)
local fobmarker = MARKER:New(mCoord, "FORWARD OPERATING BASE:\nBUILT BY: " .. PlayerName .. "\n\nTransport Helos may pick up troops and equipment from this location."):ReadOnly():ToCoalition(coalition.side.RED)
fobzone:DrawZone(2,{.25,.63,.79},1,{0,0,0},0.25,2,true)
red_ctld:AddCTLDZone(zonename,CTLD.CargoZoneType.LOAD,SMOKECOLOR.Red,true,true)
MESSAGE:New("Pilot " .. PlayerName .. " has created a new loading zone for troops and equipment! See your F10 Map for marker!", msgTime, "[ Mission Info ]", false):ToRed()
else
env.info("CRATEBUILD: No! Not a FOB: " .. vname,false)
end
end
end
function red_ctld:OnBeforeCratesRepaired(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateRepair
local GroupCategory = Group:GetCategoryName()
local PlayerName = Unit:GetPlayerName()
MESSAGE:New("Pilot " .. PlayerName .. " has started repairs on " .. GroupCategory .. "! Nice Job!", msgTime, "[ Mission Info ]", false):ToRed()
end
end
function red_ctld:OnAfterCratesRepaired(From, Event, To, Group, Unit, Vehicle)
if Unit then
local points = pointsAwardedCrateRepair
local PlayerName = Unit:GetPlayerName()
USERSOUND:New("repair.ogg"):ToCoalition(coalition.side.RED)
MESSAGE:New("Pilot " .. PlayerName .. " has conducted repears on " .. Vehicle "! Nice Job!", msgTime, "[ Mission Info ]", false):ToRed()
US_Score:_AddPlayerFromUnit( Unit )
US_Score:AddGoalScore(Unit, "CTLD", string.format("Pilot %s has been awarded %d points for the repair of Units!", PlayerName, points), points)
end
end

View File

@ -0,0 +1,964 @@
--[[
Script: Moose_DynamicGroundBattle.lua
Written by: [F99th-TracerFacer]
Version: 1.0.2
Date: 11 November 2024
Updated: 11 November 2024
Description: This script creates a dynamic ground battle between Red and Blue coalitions
along a series of zones which can be arranged in a line or any other configuration creating a dynamic ground battle.
Capture Zone Behavior
- Zone Capture states: Captured, Guarded, Empty, Attacked, Neutral
- Zone Colors: Red, Blue, Green, Orange
Red: Captured by Red
Blue: Captured by Blue
Orange: Contested
Green: Empty
Spawning And Patrol Behavior:
- Infantry and armor groups for both sides spawn at random locations in their own zones.
- Each group then calculates the shortest distance to the nearest enemy zone and moves to that zone to patrol.
- Every ASSIGN_TASKS_SCHED seconds, the script will check the ZONE_CAPTURE states of all zones and assign tasks to groups accordingly.
- Any group NOT moving, will recieve orders to patrol the nearest enemy zone. Any unit already moving will be left alone.
- Any troops dropped off through CTLD in these zones will begin to obey these orders as well.
- Spawn frequency calculated based on the number of alive warehouses.
- Infantry can be disabled from moving patrols if desired.
- In the event of DCS assigning a ridiculous path to an object, simply stop the object and it will be reassigned a new patrol path next round.
Warehouse System & Spawn Frequencey Behavior:
1. Warehouses:
- Each side (Red and Blue) has a set of warehouses defined in the `redWarehouses` and `blueWarehouses` tables.
- The number of warehouses can be adjusted by adding or removing entries from these tables and ensuring there is a matching object in the mission editor.
2. Spawn Frequency Calculation:
- The function `CalculateSpawnFrequency` calculates the spawn frequency based on the number of alive warehouses.
- The spawn frequency is a ratio of alive warehouses to total warehouses.
- If all warehouses are alive, the spawn frequency is (100%) of the base setting.
- If half of the warehouses are alive, the spawn frequency is (50%).
- If no warehouses are alive, the spawn frequency is (0%) (no more spawns).
- So for example, if you set your spawn frequency to 300 seconds, and only 50% of your warehouses are alive, the actual spawn frequency will be 600 seconds.
- This dynamic adjustment ensures that the reinforcement rate is directly impacted by the number of operational warehouses.
3. Mark points are automatically added to the map for each warehouse.
- Include the warehouse name and a list of nearby ground units within a specified radius.
- Uppdated every `UPDATE_MARK_POINTS_SCHED` seconds.
- The maximum distance to search for units near a warehouse is defined by the `MAX_WAREHOUSE_UNIT_LIST_DISTANCE` variable.
- The mark points are displayed to all players on the map as a form of "intel" on the battlefield.
- Can be disabled by setting `ENABLE_WAREHOUSE_MARKERS` to false.
General Setup Requirements:
- The script relies on the MOOSE framework for DCS World. Ensure that the MOOSE framework is installed and running on the mission.
- Ensure that all groups and zones mentioned below are created in the mission editor. You can adjust the names of the groups and zones as needed or
add more groups and zones to the script. Ensure that the names in this script match the names in the mission editor.
Groups and Zones to be created in the editor (all LATE ACTIVATE):
- Red Infantry Groups: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
- Red Armor Groups: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6
- Blue Infantry Groups: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
- Blue Armor Groups: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5
- Red Zones: FrontLine1, FrontLine2, FrontLine3, FrontLine4, FrontLine5, FrontLine6
- Blue Zones: FrontLine7, FrontLine8, FrontLine9, FrontLine10, FrontLine11, FrontLine12
- Red Warehouses: RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1, RedWarehouse4-1, RedWarehouse5-1, RedWarehouse6-1
- Blue Warehouses: BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1, BlueWarehouse4-1, BlueWarehouse5-1, BlueWarehouse6-1
- ** Note Warehouse names are based on the static "unit name" in the mission editor. **
--]]
--[[
--If you don't have command centers setup in another file, uncommnent this section below:
-- Create Command Centers and Missions for each side
-- Must have a blue unit named "BLUEHQ" and a red unit named "REDHQ" in the mission editor.
--Build Command Center and Mission for Blue
US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
US_Mission = MISSION:New( US_CC, "Insurgent Sandstorm", "Primary", "Clear the front lines of enemy activity.", coalition.side.BLUE)
US_Score = SCORING:New( "Insurgent Sandstorm - Blue" )
US_Mission:AddScoring( US_Score )
US_Mission:Start()
US_Score:SetMessagesHit(false)
US_Score:SetMessagesDestroy(false)
US_Score:SetMessagesScore(false)
--Build Command Center and Mission Red
RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
RU_Mission = MISSION:New (RU_CC, "Insurgent Sandstorm", "Primary", "Destroy U.S. and NATO forces.", coalition.side.RED)
RU_Score = SCORING:New("Insurgent Sandstorm - Red")
RU_Mission:AddScoring( RU_Score)
RU_Mission:Start()
RU_Score:SetMessagesHit(false)
RU_Score:SetMessagesDestroy(false)
RU_Score:SetMessagesScore(false)
]]
-- Infantry Patrol Settings
-- Due to some maps or locations where infantry moving is either not desired or has problems with the terrain you can disable infantry moving patrols.
-- Set to false, infantry units will spawn, and never move from their spawn location. This could be considered a defensive position and probably a good idea.
local MOVING_INFANTRY_PATROLS = false
local ENABLE_WAREHOUSE_MARKERS = true -- Enable or disable the warehouse markers on the map.
local UPDATE_MARK_POINTS_SCHED = 60 -- Update the map markers for warehouses every 300 seconds. ENABLE_WAREHOUSE_MARKERS must be set to true for this to work.
local MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Maximum distance to search for units near a warehouse to display on map markers.
-- Control Spawn frequency and limits of ground units.
local INIT_RED_INFANTRY = 5 -- Initial number of Red Infantry groups
local MAX_RED_INFANTRY = 100 -- Maximum number of Red Infantry groups
local SPAWN_SCHED_RED_INFANTRY = 1800 -- Spawn Red Infantry groups every 1800 seconds
local INIT_RED_ARMOR = 25 -- Initial number of Red Armor groups
local MAX_RED_ARMOR = 200 -- Maximum number of Red Armor groups
local SPAWN_SCHED_RED_ARMOR = 300 -- Spawn Red Armor groups every 300 seconds
local INIT_BLUE_INFANTRY = 5 -- Initial number of Blue Infantry groups
local MAX_BLUE_INFANTRY = 100 -- Maximum number of Blue Infantry groups
local SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Spawn Blue Infantry groups every 1800 seconds
local INIT_BLUE_ARMOR = 25 -- Initial number of Blue Armor groups0
local MAX_BLUE_ARMOR = 200 -- Maximum number of Blue Armor groups
local SPAWN_SCHED_BLUE_ARMOR = 300 -- Spawn Blue Armor groups every 300 seconds
local ASSIGN_TASKS_SCHED = 600 -- Assign tasks to groups every 600 seconds. New groups added will wait this long before moving.
-- Define capture zones for each side with a visible radius.
-- These zones will be used to create capture zones for each side. The capture zones will be used to determine the state of each zone (captured, guarded, empty, attacked, neutral).
-- The zones will also be used to spawn ground units for each side.
-- The zones should be created in the mission editor and named accordingly.
-- You can add more zones as needed. The script will create capture zones for each zone and assign tasks to groups based on the zone states.
-- Maybe the zones are along a front line, or they follow a road, or they are scattered around the map. You can arrange the zones in any configuration you like.
local redZones = {
ZONE:New("FrontLine1"),
ZONE:New("FrontLine2"),
ZONE:New("FrontLine3"),
ZONE:New("FrontLine4"),
ZONE:New("FrontLine5"),
ZONE:New("FrontLine6")
}
local blueZones = {
ZONE:New("FrontLine7"),
ZONE:New("FrontLine8"),
ZONE:New("FrontLine9"),
ZONE:New("FrontLine10"),
ZONE:New("FrontLine11"),
ZONE:New("FrontLine12")
}
-- Define warehouses for each side. These warehouses will be used to calculate the spawn frequency of ground units.
-- The warehouses should be created in the mission editor and named accordingly.
local redWarehouses = {
STATIC:FindByName("RedWarehouse1-1"), -- Static units key of off unit name in mission editor rather than just the name field. weird. =\ (hours wasted! ha!)
STATIC:FindByName("RedWarehouse2-1"),
STATIC:FindByName("RedWarehouse3-1"),
STATIC:FindByName("RedWarehouse4-1"),
STATIC:FindByName("RedWarehouse5-1"),
STATIC:FindByName("RedWarehouse6-1")
}
local blueWarehouses = {
STATIC:FindByName("BlueWarehouse1-1"),
STATIC:FindByName("BlueWarehouse2-1"),
STATIC:FindByName("BlueWarehouse3-1"),
STATIC:FindByName("BlueWarehouse4-1"),
STATIC:FindByName("BlueWarehouse5-1"),
STATIC:FindByName("BlueWarehouse6-1")
}
-- Define templates for infantry and armor groups. These templates will be used to randomize the groups spawned in the zones.
-- The templates should be created in the mission editor and named accordingly.
-- You can add more templates as needed. The script will randomly select a template for each group spawned.
-- The more templates you make, the more variety you can add to the groups that are spawned.
local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
"RedInfantry3",
"RedInfantry4",
"RedInfantry5",
"RedInfantry6"
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
"RedArmor3",
"RedArmor4",
"RedArmor5",
"RedArmor6"
}
local blueInfantryTemplates = {
"BlueInfantry1",
"BlueInfantry2",
"BlueInfantry3",
"BlueInfantry4",
"BlueInfantry5",
"BlueInfantry6"
}
local blueArmorTemplates = {
"BlueArmor1",
"BlueArmor2",
"BlueArmor3",
"BlueArmor4",
"BlueArmor5"
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- DO NOT EDIT BELOW THIS LINE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Adds mark points on the map for each warehouse in the provided list.
--- Each mark point includes the warehouse's name and a list of nearby ground units within a specified radius.
-- Function to add mark points on the map for each warehouse in the provided list
local function addMarkPoints(warehouses, coalition)
env.info("addMarkPoints: Updating mark points for warehouses")
for _, warehouse in ipairs(warehouses) do
if warehouse then
local warehousePos = warehouse:GetVec3()
env.info("addMarkPoints: Warehouse Position: " .. warehousePos.x .. ", " .. warehousePos.y .. ", " .. warehousePos.z)
local details
if coalition == 2 then
if warehouse:GetCoalition() == 2 then
details = "Warehouse: " .. warehouse:GetName() .. "\nNearby Units:\nThis warehouse needs to be protected."
else
details = "Warehouse: " .. warehouse:GetName() .. "\nNearby Units:\nThis is a primary target as it is directly supplying enemy units."
end
elseif coalition == 1 then
if warehouse:GetCoalition() == 1 then
details = "Warehouse: " .. warehouse:GetName() .. "\nNearby Units:\nThis warehouse needs to be protected."
else
details = "Warehouse: " .. warehouse:GetName() .. "\nNearby Units:\nThis is a primary target as it is directly supplying enemy units."
end
end
local coordinate = COORDINATE:NewFromVec3(warehousePos)
local nearbyUnits = SET_GROUP:New():FilterCategoryGround():FilterZones({ ZONE_RADIUS:New("Zone", coordinate, MAX_WAREHOUSE_UNIT_LIST_DISTANCE) }):FilterOnce()
if nearbyUnits then
env.info("addMarkPoints: SET_GROUP created in nearbyUnits")
-- Iterate through each group in the nearby units
local unitCounts = {}
local groups = nearbyUnits:GetSet()
env.info("addMarkPoints: Groups in nearbyUnits: " .. #groups)
if groups then
env.info("addMarkPoints: Groups found in nearbyUnits: " .. #groups)
for _, group in ipairs(groups) do
local units = group:GetUnits()
if units then
env.info("addMarkPoints: Units found in group: " .. #units)
for _, unit in ipairs(units) do
local unitType = unit:GetTypeName()
-- Count the units by type
if unitCounts[unitType] then
unitCounts[unitType] = unitCounts[unitType] + 1
else
unitCounts[unitType] = 1
end
end
else
env.info("addMarkPoints: No units found in group")
end
end
-- Add the unit type and count to the details string
for unitType, count in pairs(unitCounts) do
details = details .. "\n" .. unitType .. ": " .. count
env.info("addMarkPoints: Nearby Unit Type: " .. unitType .. ", Count: " .. count)
end
else
env.info("addMarkPoints: No groups found in nearbyUnits")
details = details .. "\nNo nearby units found."
end
else
env.info("addMarkPoints: nearbyUnits is nil")
details = details .. "\nNo nearby units found."
end
env.info("addMarkPoints: Details: " .. details)
local coordinate = COORDINATE:NewFromVec3(warehousePos)
local marker = MARKER:New(coordinate, details):ToCoalition(coalition):ReadOnly()
marker:Remove(UPDATE_MARK_POINTS_SCHED)
else
env.info("addMarkPoints: Warehouse not found or is nil")
end
end
end
local function updateMarkPoints()
addMarkPoints(redWarehouses, 2) -- Blue coalition sees red warehouses as targets
addMarkPoints(blueWarehouses, 2) -- Blue coalition sees blue warehouses as needing protection
addMarkPoints(redWarehouses, 1) -- Red coalition sees red warehouses as needing protection
addMarkPoints(blueWarehouses, 1) -- Red coalition sees blue warehouses as targets
end
-- If enabled, update the mark points for the warehouses every UPDATE_MARK_POINTS_SCHED seconds.
if ENABLE_WAREHOUSE_MARKERS then
SCHEDULER:New(nil, updateMarkPoints, {}, 10, UPDATE_MARK_POINTS_SCHED)
end
-- Table to keep track of zones and their statuses
local zoneStatuses = {}
-- Function to create a capture zone
local function CreateCaptureZone(zone, coalition)
local captureZone = ZONE_CAPTURE_COALITION:New(zone, coalition)
if captureZone then
local coordinate = captureZone:GetCoordinate()
if coordinate then
env.info("Created capture zone at coordinates: " .. coordinate:ToStringLLDMS())
captureZone:Start(5, 30) -- Check every 5 seconds, capture after 30 seconds
else
env.error("Failed to get coordinates for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
else
env.error("Failed to create capture zone for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
return captureZone
end
-- Custom OnEnterCaptured method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterCaptured(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
self:UndrawZone()
self:DrawZone(-1, {0, 0, 1}, 2) -- Draw the zone on the map for 30 seconds, blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterGuarded method
--- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterGuarded(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw zone DARK BLUE for guarded
self:UndrawZone()
self:DrawZone(-1, {0, 0, 0.5}, 2) -- Draw the zone on the map for 30 seconds, dark blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
-- Draw zone DARK RED for guarded
self:UndrawZone()
self:DrawZone(-1, {0.5, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, dark red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterEmpty method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterEmpty(From, Event, To)
if From ~= To then
self:E({ Coalition = "None" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "None" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Custom OnEnterAttacked method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterAttacked(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw the zone orange for contested
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under attack by Russia", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is attacking the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under attack by the USA", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is attacking Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterNeutral method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterNeutral(From, Event, To)
if From ~= To then
self:E({ Coalition = "Neutral" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "Neutral" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Create capture zones for Red and Blue
local redCaptureZones = {}
local blueCaptureZones = {}
-- Iterate over all red zones to create capture zones
for _, zone in ipairs(redZones) do
-- Attempt to create a capture zone for the current red zone
local captureZone = CreateCaptureZone(zone, coalition.side.RED)
if captureZone then
-- If successful, add the capture zone to the redCaptureZones table
table.insert(redCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Red capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, red color, and thickness 2
zone:DrawZone(30, {1, 0, 0}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.RED }
else
-- If creation fails, log an error message
env.error("Failed to create Red capture zone: " .. zone:GetName())
end
end
-- Iterate over all blue zones to create capture zones
for _, zone in ipairs(blueZones) do
-- Attempt to create a capture zone for the current blue zone
local captureZone = CreateCaptureZone(zone, coalition.side.BLUE)
if captureZone then
-- If successful, add the capture zone to the blueCaptureZones table
table.insert(blueCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Blue capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, blue color, and thickness 2
zone:DrawZone(30, {0, 0, 1}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.BLUE }
else
-- If creation fails, log an error message
env.error("Failed to create Blue capture zone: " .. zone:GetName())
end
end
-- Function to handle zone capture
local function OnZoneCaptured(event)
local zone = event.zone
local coalition = event.coalition
if zone and coalition then
env.info("OnZoneCaptured: Zone " .. zone:GetName() .. " captured by coalition " .. coalition)
-- Update the zone state
if coalition == coalition.side.RED then
zoneStates[zone:GetName()] = "RED"
zone:SetCoalition(coalition.side.RED)
elseif coalition == coalition.side.BLUE then
zoneStates[zone:GetName()] = "BLUE"
zone:SetCoalition(coalition.side.BLUE)
else
zoneStates[zone:GetName()] = "NEUTRAL"
zone:SetCoalition(coalition.side.NEUTRAL)
end
else
env.error("OnZoneCaptured: Invalid zone or coalition")
end
end
-- Function to handle zone guarded events
local function OnZoneGuarded(event)
local zone = event.Zone
local coalition = event.Coalition
if coalition == coalition.side.RED then
env.info("Red is guarding zone: " .. zone:GetName())
elseif coalition == coalition.side.BLUE then
env.info("Blue is guarding zone: " .. zone:GetName())
end
end
-- Function to handle zone empty events
local function OnZoneEmpty(event)
local zone = event.Zone
env.info("Zone is empty: " .. zone:GetName())
end
-- Function to handle zone attacked events
local function OnZoneAttacked(event)
local zone = event.Zone
local attackingGroups = zone:GetGroups()
local makeup = {}
for _, group in ipairs(attackingGroups) do
local groupName = group:GetName()
local unitTypes = {}
for _, unit in ipairs(group:GetUnits()) do
local unitType = unit:GetTypeName()
unitTypes[unitType] = (unitTypes[unitType] or 0) + 1
end
table.insert(makeup, {groupName = groupName, unitTypes = unitTypes})
end
local makeupMessage = ""
for _, groupInfo in ipairs(makeup) do
makeupMessage = makeupMessage .. "Group: " .. groupInfo.groupName .. "\n"
for unitType, count in pairs(groupInfo.unitTypes) do
makeupMessage = makeupMessage .. " " .. unitType .. ": " .. count .. "\n"
end
end
local messageText = "Zone is being attacked: " .. zone:GetName() .. "\n" .. makeupMessage
env.info(messageText)
-- Announce to the player
MESSAGE:New(messageText, 15):ToAll()
end
-- Function to handle zone neutral events
local function OnZoneNeutral(event)
local zone = event.Zone
env.info("Zone is neutral: " .. zone:GetName())
end
-- Function to check the ZONE_CAPTURE states of all zones
local function CheckZoneStates()
env.info("Checking zone states...")
local zoneStates = {}
local function processZones(zones, zoneType)
env.info("Processing " .. zoneType)
env.info("Number of zones: " .. #zones)
local allGroups = SET_GROUP:New():FilterActive():FilterStart()
for _, zone in ipairs(zones) do
if zone then
env.info("processZones: Zone object is valid")
-- Check if the zone is of the correct type
if zone.ClassName == "ZONE_CAPTURE_COALITION" then
env.info("processZones: Zone is of type ZONE_CAPTURE_COALITION")
local coalition = zone:GetCoalition()
env.info("processZones: Zone coalition: " .. tostring(coalition))
if coalition == 1 then
zoneStates[zone:GetZoneName()] = "RED"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: RED")
elseif coalition == 2 then
zoneStates[zone:GetZoneName()] = "BLUE"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: BLUE")
else
zoneStates[zone:GetZoneName()] = "NEUTRAL"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: NEUTRAL")
end
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
env.info("processZones: Checking group: " .. group:GetName())
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("processZones: IsCompletelyInZone method not found in group: " .. group:GetName())
-- Log available methods on the group object
for k, v in pairs(group) do
env.info("processZones: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("processZones: Invalid group")
end
end)
env.info("processZones: Number of groups in zone: " .. #groupsInZone)
else
env.error("processZones: Zone is not of type ZONE_CAPTURE_COALITION")
-- Log available methods on the zone object
for k, v in pairs(zone) do
env.info("processZones: Zone method: " .. tostring(k) .. " = " .. tostring(v))
end
end
if not zone.GetZoneName then
env.error("processZones: Missing GetZoneName method in " .. zoneType)
end
else
env.error("processZones: Invalid zone in " .. zoneType)
end
end
end
processZones(redCaptureZones, "redZones")
processZones(blueCaptureZones, "blueZones")
-- Log the zoneStates table
for zoneName, state in pairs(zoneStates) do
env.info("CheckZoneStates: Zone: " .. zoneName .. " State: " .. state)
end
return zoneStates
end
-- Function to assign tasks to groups
local function AssignTasks(group, zoneStates)
if not group or not group.GetCoalition or not group.GetCoordinate or not group.GetVelocity then
env.info("AssignTasks: Invalid group or missing methods")
return
end
local velocity = group:GetVelocityVec3()
local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2)
if speed > 0 then
env.info("AssignTasks: Group " .. group:GetName() .. " is already moving. No new orders sent.")
return
end
env.info("Assigning tasks to group: " .. group:GetName())
local groupCoalition = group:GetCoalition()
local groupCoordinate = group:GetCoordinate()
local closestZone = nil
local closestDistance = math.huge
env.info("Group Coalition: " .. tostring(groupCoalition))
env.info("Group Coordinate: " .. groupCoordinate:ToStringLLDMS())
for zoneName, state in pairs(zoneStates) do
env.info("Checking Zone: " .. zoneName .. " with state: " .. tostring(state))
-- Convert state to a number for comparison
local stateCoalition = (state == "RED" and 1) or (state == "BLUE" and 2) or nil
if stateCoalition and stateCoalition ~= groupCoalition then
local zone = ZONE:FindByName(zoneName)
if zone then
local zoneCoordinate = zone:GetCoordinate()
local distance = groupCoordinate:Get2DDistance(zoneCoordinate)
--env.info("Zone Coordinate: " .. zoneCoordinate:ToStringLLDMS())
--env.info("Distance to zone " .. zoneName .. ": " .. distance)
if distance < closestDistance then
closestDistance = distance
closestZone = zone
env.info("New closest zone: " .. zoneName .. " with distance: " .. distance)
end
else
env.info("AssignTasks: Zone not found - " .. zoneName)
end
else
env.info("Zone " .. zoneName .. " is already controlled by coalition: " .. tostring(state))
end
end
if closestZone then
env.info(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName())
MESSAGE:New(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName(), 10):ToAll()
-- Create a patrol task using the GROUP:PatrolZones method
local patrolZones = {closestZone}
local speed = 20 -- Example speed, adjust as needed
local formation = "Cone" -- Example formation, adjust as needed
local delayMin = 30 -- Example minimum delay, adjust as needed
local delayMax = 60 -- Example maximum delay, adjust as needed
group:PatrolZones(patrolZones, speed, formation, delayMin, delayMax)
else
env.info("AssignTasks: No suitable zone found for group " .. group:GetName())
end
end
-- Function to check if a group contains infantry units
local function IsInfantryGroup(group)
env.info("IsInfantryGroup: Checking group: " .. group:GetName())
for _, unit in ipairs(group:GetUnits()) do
local unitTypeName = unit:GetTypeName()
env.info("IsInfantryGroup: Checking unit: " .. unit:GetName() .. " with type: " .. unitTypeName)
if unitTypeName:find("Infantry") or unitTypeName:find("Soldier") or unitTypeName:find("Paratrooper") then
env.info("IsInfantryGroup: Found infantry unit in group: " .. group:GetName())
return true
end
end
return false
end
-- Function to assign tasks to groups
local function AssignTasksToGroups()
env.info("AssignTasksToGroups: Starting task assignments")
local zoneStates = CheckZoneStates()
local allGroups = SET_GROUP:New():FilterActive():FilterStart()
local function processZone(zone, zoneColor)
if zone then
env.info("AssignTasksToGroups: Processing " .. zoneColor .. " zone: " .. zone:GetName())
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("AssignTasksToGroups: IsCompletelyInZone method not found in group: " .. group:GetName())
for k, v in pairs(group) do
env.info("AssignTasksToGroups: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("AssignTasksToGroups: Invalid group")
end
end)
env.info("AssignTasksToGroups: Found " .. #groupsInZone .. " groups in " .. zoneColor .. " zone: " .. zone:GetName())
for _, group in ipairs(groupsInZone) do
if IsInfantryGroup(group) == true then
if MOVING_INFANTRY_PATROLS == true then
env.info("AssignTasksToGroups: Assigning tasks to infantry group: " .. group:GetName())
AssignTasks(group, zoneStates)
else
env.info("AssignTasksToGroups: Skipping infantry group: " .. group:GetName())
end
else
env.info("AssignTasksToGroups: Assigning tasks to group: " .. group:GetName())
AssignTasks(group, zoneStates)
end
end
else
env.info("AssignTasksToGroups: Invalid " .. zoneColor .. " zone")
end
end
for _, zone in ipairs(redZones) do
processZone(zone, "red")
end
for _, zone in ipairs(blueZones) do
processZone(zone, "blue")
end
env.info("AssignTasksToGroups: Task assignments completed. Running again in " .. ASSIGN_TASKS_SCHED .. " seconds.")
end
-- Function to calculate spawn frequency in seconds
local function CalculateSpawnFrequency(warehouses, baseFrequency)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 or aliveWarehouses == 0 then
return math.huge -- Stop spawning if there are no warehouses or no alive warehouses
end
local frequency = baseFrequency * (totalWarehouses / aliveWarehouses)
return frequency
end
-- Function to calculate spawn frequency percentage
local function CalculateSpawnFrequencyPercentage(warehouses)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 then
return 0 -- Avoid division by zero
end
local percentage = (aliveWarehouses / totalWarehouses) * 100
return percentage
end
-- Add event handlers for zone capture
for _, captureZone in ipairs(redCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
for _, captureZone in ipairs(blueCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses, coalition.side.RED)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses, coalition.side.BLUE)
-- Display spawn frequency percentages to the user
MESSAGE:New("Red side spawn frequency: " .. redSpawnFrequencyPercentage .. "%", 30):ToRed()
MESSAGE:New("Blue side spawn frequency: " .. blueSpawnFrequencyPercentage .. "%", 30):ToBlue()
-- Schedule ground spawns using the calculated frequencies
redInfantrySpawn = SPAWN:New("RedInfantryGroup")
:InitRandomizeTemplate(redInfantryTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_INFANTRY, MAX_RED_INFANTRY)
:SpawnScheduled(redInfantrySpawnFrequency, 0.5)
redArmorSpawn = SPAWN:New("RedArmorGroup")
:InitRandomizeTemplate(redArmorTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_ARMOR, MAX_RED_ARMOR)
:SpawnScheduled(redArmorSpawnFrequency, 0.5)
blueInfantrySpawn = SPAWN:New("BlueInfantryGroup")
:InitRandomizeTemplate(blueInfantryTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_INFANTRY, MAX_BLUE_INFANTRY)
:SpawnScheduled(blueInfantrySpawnFrequency, 0.5)
blueArmorSpawn = SPAWN:New("BlueArmorGroup")
:InitRandomizeTemplate(blueArmorTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_ARMOR, MAX_BLUE_ARMOR)
:SpawnScheduled(blueArmorSpawnFrequency, 0.5)
env.info("Dynamic Ground Battle & Zone capture initialized.")
-- Function to monitor and announce warehouse status
local function MonitorWarehouses()
local blueWarehousesAlive = 0
local redWarehousesAlive = 0
for _, warehouse in ipairs(blueWarehouses) do
if warehouse:IsAlive() then
blueWarehousesAlive = blueWarehousesAlive + 1
end
end
for _, warehouse in ipairs(redWarehouses) do
if warehouse:IsAlive() then
redWarehousesAlive = redWarehousesAlive + 1
end
end
-- Debug messages to check values
env.info("MonitorWarehouses: blueWarehousesAlive = " .. blueWarehousesAlive)
env.info("MonitorWarehouses: redWarehousesAlive = " .. redWarehousesAlive)
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
-- Log the values
env.info("MonitorWarehouses: redInfantrySpawnFrequency = " .. redInfantrySpawnFrequency)
env.info("MonitorWarehouses: redArmorSpawnFrequency = " .. redArmorSpawnFrequency)
env.info("MonitorWarehouses: blueInfantrySpawnFrequency = " .. blueInfantrySpawnFrequency)
env.info("MonitorWarehouses: blueArmorSpawnFrequency = " .. blueArmorSpawnFrequency)
env.info("MonitorWarehouses: redSpawnFrequencyPercentage = " .. redSpawnFrequencyPercentage)
env.info("MonitorWarehouses: blueSpawnFrequencyPercentage = " .. blueSpawnFrequencyPercentage)
local msg = "[Warehouse status:]\n"
msg = msg .. "Red warehouses alive: " .. redWarehousesAlive .. " Reinforcements Capacity: " .. redSpawnFrequencyPercentage .. "%" .. "\n"
msg = msg .. "Blue warehouses alive: " .. blueWarehousesAlive .. " Reinforcements Capacity: " .. blueSpawnFrequencyPercentage .. "%" .. "\n"
MESSAGE:New(msg, 30):ToAll()
end
-- Function to check the wincondition. If either side owns all zones, mission ends.
local function checkWinCondition()
local blueOwned = true
local redOwned = true
for zoneName, owner in pairs(zoneStatuses) do
if owner ~= 1 then
redOwned = false
end
if owner ~= 2 then
blueOwned = false
end
end
if blueOwned then
MESSAGE:New("Blue side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("UsaTheme.ogg"):ToAll()
return true
elseif redOwned then
MESSAGE:New("Red side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("MotherRussia.ogg"):ToAll()
return true
end
return false
end
-- Timer function to periodically check the win condition
local function monitorWinCondition()
if not checkWinCondition() then
-- Schedule the next check in 60 seconds
TIMER:New(monitorWinCondition):Start(60)
end
end
-- Start monitoring the win condition
monitorWinCondition()
-- Scheduler to monitor warehouses every 120 seconds
SCHEDULER:New(nil, MonitorWarehouses, {}, 0, 120)
-- Scheduler to assign tasks to groups periodically
SCHEDULER:New(nil, AssignTasksToGroups, {}, 0, ASSIGN_TASKS_SCHED) -- Check every 600 seconds (10 minutes) - Adjust as needed
-- Create a mission menu
local missionMenu = MENU_MISSION:New("Warehouse Monitoring")
-- Add a menu item to run the MonitorWarehouses function
MENU_MISSION_COMMAND:New("Check Warehouse Status", missionMenu, MonitorWarehouses)

View File

@ -0,0 +1,925 @@
--[[
Script: Moose_DynamicGroundBattle.lua
Written by: [F99th-TracerFacer]
Version: 1.0.2
Date: 11 November 2024
Updated: 12 November 2024
Description: This script creates a dynamic ground battle between Red and Blue coalitions
along a series of zones which can be arranged in a line or any other configuration creating a dynamic ground battle.
Capture Zone Behavior
- Zone Capture states: Captured, Guarded, Empty, Attacked, Neutral
- Zone Colors: Red, Blue, Green, Orange
Red: Captured by Red
Blue: Captured by Blue
Orange: Contested
Green: Empty
Spawning And Patrol Behavior:
- Infantry and armor groups for both sides spawn at random locations in their own zones.
- Each group then calculates the shortest distance to the nearest enemy zone and moves to that zone to patrol.
- Every ASSIGN_TASKS_SCHED seconds, the script will check the ZONE_CAPTURE states of all zones and assign tasks to groups accordingly.
- Any group NOT moving, will recieve orders to patrol the nearest enemy zone. Any unit already moving will be left alone.
- Any troops dropped off through CTLD in these zones will begin to obey these orders as well.
- Spawn frequency calculated based on the number of alive warehouses.
- Infantry can be disabled from moving patrols if desired.
- In the event of DCS assigning a ridiculous path to an object, simply stop the object and it will be reassigned a new patrol path next round.
Warehouse System & Spawn Frequencey Behavior:
1. Warehouses:
- Each side (Red and Blue) has a set of warehouses defined in the `redWarehouses` and `blueWarehouses` tables.
- The number of warehouses can be adjusted by adding or removing entries from these tables and ensuring there is a matching object in the mission editor.
2. Spawn Frequency Calculation:
- The function `CalculateSpawnFrequency` calculates the spawn frequency based on the number of alive warehouses.
- The spawn frequency is a ratio of alive warehouses to total warehouses.
- If all warehouses are alive, the spawn frequency is (100%) of the base setting.
- If half of the warehouses are alive, the spawn frequency is (50%).
- If no warehouses are alive, the spawn frequency is (0%) (no more spawns).
- So for example, if you set your spawn frequency to 300 seconds, and only 50% of your warehouses are alive, the actual spawn frequency will be 600 seconds.
- This dynamic adjustment ensures that the reinforcement rate is directly impacted by the number of operational warehouses.
3. Mark points are automatically added to the map for each warehouse.
- Include the warehouse name and a list of nearby ground units within a specified radius.
- Uppdated every `UPDATE_MARK_POINTS_SCHED` seconds.
- The maximum distance to search for units near a warehouse is defined by the `MAX_WAREHOUSE_UNIT_LIST_DISTANCE` variable.
- The mark points are displayed to all players on the map as a form of "intel" on the battlefield.
- Can be disabled by setting `ENABLE_WAREHOUSE_MARKERS` to false.
General Setup Requirements:
- The script relies on the MOOSE framework for DCS World. Ensure that the MOOSE framework is installed and running on the mission.
- Ensure that all groups and zones mentioned below are created in the mission editor. You can adjust the names of the groups and zones as needed or
add more groups and zones to the script. Ensure that the names in this script match the names in the mission editor.
Groups and Zones to be created in the editor (all LATE ACTIVATE):
- Red Infantry Groups: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
- Red Armor Groups: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6
- Blue Infantry Groups: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
- Blue Armor Groups: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5
- Red Zones: FrontLine1, FrontLine2, FrontLine3, FrontLine4, FrontLine5, FrontLine6
- Blue Zones: FrontLine7, FrontLine8, FrontLine9, FrontLine10, FrontLine11, FrontLine12
- Red Warehouses: RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1, RedWarehouse4-1, RedWarehouse5-1, RedWarehouse6-1
- Blue Warehouses: BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1, BlueWarehouse4-1, BlueWarehouse5-1, BlueWarehouse6-1
- ** Note Warehouse names are based on the static "unit name" in the mission editor. **
--]]
--[[
--If you don't have command centers setup in another file, uncommnent this section below:
-- Create Command Centers and Missions for each side
-- Must have a blue unit named "BLUEHQ" and a red unit named "REDHQ" in the mission editor.
--Build Command Center and Mission for Blue
US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
US_Mission = MISSION:New( US_CC, "Insurgent Sandstorm", "Primary", "Clear the front lines of enemy activity.", coalition.side.BLUE)
US_Score = SCORING:New( "Insurgent Sandstorm - Blue" )
US_Mission:AddScoring( US_Score )
US_Mission:Start()
US_Score:SetMessagesHit(false)
US_Score:SetMessagesDestroy(false)
US_Score:SetMessagesScore(false)
--Build Command Center and Mission Red
RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
RU_Mission = MISSION:New (RU_CC, "Insurgent Sandstorm", "Primary", "Destroy U.S. and NATO forces.", coalition.side.RED)
RU_Score = SCORING:New("Insurgent Sandstorm - Red")
RU_Mission:AddScoring( RU_Score)
RU_Mission:Start()
RU_Score:SetMessagesHit(false)
RU_Score:SetMessagesDestroy(false)
RU_Score:SetMessagesScore(false)
]]
-- Infantry Patrol Settings
-- Due to some maps or locations where infantry moving is either not desired or has problems with the terrain you can disable infantry moving patrols.
-- Set to false, infantry units will spawn, and never move from their spawn location. This could be considered a defensive position and probably a good idea.
local MOVING_INFANTRY_PATROLS = false
local ENABLE_WAREHOUSE_MARKERS = true -- Enable or disable the warehouse markers on the map.
local UPDATE_MARK_POINTS_SCHED = 60 -- Update the map markers for warehouses every 300 seconds. ENABLE_WAREHOUSE_MARKERS must be set to true for this to work.
local MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Maximum distance to search for units near a warehouse to display on map markers.
-- Control Spawn frequency and limits of ground units.
local INIT_RED_INFANTRY = 5 -- Initial number of Red Infantry groups
local MAX_RED_INFANTRY = 100 -- Maximum number of Red Infantry groups
local SPAWN_SCHED_RED_INFANTRY = 1800 -- Spawn Red Infantry groups every 1800 seconds
local INIT_RED_ARMOR = 25 -- Initial number of Red Armor groups
local MAX_RED_ARMOR = 200 -- Maximum number of Red Armor groups
local SPAWN_SCHED_RED_ARMOR = 300 -- Spawn Red Armor groups every 300 seconds
local INIT_BLUE_INFANTRY = 5 -- Initial number of Blue Infantry groups
local MAX_BLUE_INFANTRY = 100 -- Maximum number of Blue Infantry groups
local SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Spawn Blue Infantry groups every 1800 seconds
local INIT_BLUE_ARMOR = 25 -- Initial number of Blue Armor groups0
local MAX_BLUE_ARMOR = 200 -- Maximum number of Blue Armor groups
local SPAWN_SCHED_BLUE_ARMOR = 300 -- Spawn Blue Armor groups every 300 seconds
local ASSIGN_TASKS_SCHED = 600 -- Assign tasks to groups every 600 seconds. New groups added will wait this long before moving.
-- Define capture zones for each side with a visible radius.
-- These zones will be used to create capture zones for each side. The capture zones will be used to determine the state of each zone (captured, guarded, empty, attacked, neutral).
-- The zones will also be used to spawn ground units for each side.
-- The zones should be created in the mission editor and named accordingly.
-- You can add more zones as needed. The script will create capture zones for each zone and assign tasks to groups based on the zone states.
-- Maybe the zones are along a front line, or they follow a road, or they are scattered around the map. You can arrange the zones in any configuration you like.
local redZones = {
ZONE:New("FrontLine1"),
ZONE:New("FrontLine2"),
ZONE:New("FrontLine3"),
ZONE:New("FrontLine4"),
ZONE:New("FrontLine5"),
ZONE:New("FrontLine6")
}
local blueZones = {
ZONE:New("FrontLine7"),
ZONE:New("FrontLine8"),
ZONE:New("FrontLine9"),
ZONE:New("FrontLine10"),
ZONE:New("FrontLine11"),
ZONE:New("FrontLine12")
}
-- Define warehouses for each side. These warehouses will be used to calculate the spawn frequency of ground units.
-- The warehouses should be created in the mission editor and named accordingly.
local redWarehouses = {
STATIC:FindByName("RedWarehouse1-1"), -- Static units key of off unit name in mission editor rather than just the name field. weird. =\ (hours wasted! ha!)
STATIC:FindByName("RedWarehouse2-1"),
STATIC:FindByName("RedWarehouse3-1"),
STATIC:FindByName("RedWarehouse4-1"),
STATIC:FindByName("RedWarehouse5-1"),
STATIC:FindByName("RedWarehouse6-1")
}
local blueWarehouses = {
STATIC:FindByName("BlueWarehouse1-1"),
STATIC:FindByName("BlueWarehouse2-1"),
STATIC:FindByName("BlueWarehouse3-1"),
STATIC:FindByName("BlueWarehouse4-1"),
STATIC:FindByName("BlueWarehouse5-1"),
STATIC:FindByName("BlueWarehouse6-1")
}
-- Define templates for infantry and armor groups. These templates will be used to randomize the groups spawned in the zones.
-- The templates should be created in the mission editor and named accordingly.
-- You can add more templates as needed. The script will randomly select a template for each group spawned.
-- The more templates you make, the more variety you can add to the groups that are spawned.
local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
"RedInfantry3",
"RedInfantry4",
"RedInfantry5",
"RedInfantry6"
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
"RedArmor3",
"RedArmor4",
"RedArmor5",
"RedArmor6",
"RedArmor7",
"RedArmor8",
"RedArmor9",
"RedArmor10"
}
local blueInfantryTemplates = {
"BlueInfantry1",
"BlueInfantry2",
"BlueInfantry3",
"BlueInfantry4",
"BlueInfantry5",
"BlueInfantry6"
}
local blueArmorTemplates = {
"BlueArmor1",
"BlueArmor2",
"BlueArmor3",
"BlueArmor4",
"BlueArmor5"
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- DO NOT EDIT BELOW THIS LINE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Adds mark points on the map for each warehouse in the provided list.
--- Each mark point includes the warehouse's name and a list of nearby ground units within a specified radius.
-- Function to add mark points on the map for each warehouse in the provided list
local function addMarkPoints(warehouses, coalition)
for _, warehouse in ipairs(warehouses) do
if warehouse then
local warehousePos = warehouse:GetVec3()
local details
if coalition == 2 then
if warehouse:GetCoalition() == 2 then
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
else
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
end
elseif coalition == 1 then
if warehouse:GetCoalition() == 1 then
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\nNearby Units:\n"
else
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
end
end
local coordinate = COORDINATE:NewFromVec3(warehousePos)
local marker = MARKER:New(coordinate, details):ToCoalition(coalition):ReadOnly()
marker:Remove(UPDATE_MARK_POINTS_SCHED)
else
env.info("addMarkPoints: Warehouse not found or is nil")
end
end
end
local function updateMarkPoints()
addMarkPoints(redWarehouses, 2) -- Blue coalition sees red warehouses as targets
addMarkPoints(blueWarehouses, 2) -- Blue coalition sees blue warehouses as needing protection
addMarkPoints(redWarehouses, 1) -- Red coalition sees red warehouses as needing protection
addMarkPoints(blueWarehouses, 1) -- Red coalition sees blue warehouses as targets
end
-- If enabled, update the mark points for the warehouses every UPDATE_MARK_POINTS_SCHED seconds.
if ENABLE_WAREHOUSE_MARKERS then
SCHEDULER:New(nil, updateMarkPoints, {}, 10, UPDATE_MARK_POINTS_SCHED)
end
-- Table to keep track of zones and their statuses
local zoneStatuses = {}
-- Function to create a capture zone
local function CreateCaptureZone(zone, coalition)
local captureZone = ZONE_CAPTURE_COALITION:New(zone, coalition)
if captureZone then
local coordinate = captureZone:GetCoordinate()
if coordinate then
env.info("Created capture zone at coordinates: " .. coordinate:ToStringLLDMS())
captureZone:Start(5, 30) -- Check every 5 seconds, capture after 30 seconds
else
env.error("Failed to get coordinates for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
else
env.error("Failed to create capture zone for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
return captureZone
end
-- Custom OnEnterCaptured method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterCaptured(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
self:UndrawZone()
self:DrawZone(-1, {0, 0, 1}, 2) -- Draw the zone on the map for 30 seconds, blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterGuarded method
--- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterGuarded(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw zone DARK BLUE for guarded
self:UndrawZone()
self:DrawZone(-1, {0, 0, 0.5}, 2) -- Draw the zone on the map for 30 seconds, dark blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
-- Draw zone DARK RED for guarded
self:UndrawZone()
self:DrawZone(-1, {0.5, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, dark red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterEmpty method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterEmpty(From, Event, To)
if From ~= To then
self:E({ Coalition = "None" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "None" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Custom OnEnterAttacked method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterAttacked(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw the zone orange for contested
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under attack by Russia", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is attacking the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under attack by the USA", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is attacking Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterNeutral method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterNeutral(From, Event, To)
if From ~= To then
self:E({ Coalition = "Neutral" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "Neutral" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Create capture zones for Red and Blue
local redCaptureZones = {}
local blueCaptureZones = {}
-- Iterate over all red zones to create capture zones
for _, zone in ipairs(redZones) do
-- Attempt to create a capture zone for the current red zone
local captureZone = CreateCaptureZone(zone, coalition.side.RED)
if captureZone then
-- If successful, add the capture zone to the redCaptureZones table
table.insert(redCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Red capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, red color, and thickness 2
zone:DrawZone(30, {1, 0, 0}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.RED }
else
-- If creation fails, log an error message
env.error("Failed to create Red capture zone: " .. zone:GetName())
end
end
-- Iterate over all blue zones to create capture zones
for _, zone in ipairs(blueZones) do
-- Attempt to create a capture zone for the current blue zone
local captureZone = CreateCaptureZone(zone, coalition.side.BLUE)
if captureZone then
-- If successful, add the capture zone to the blueCaptureZones table
table.insert(blueCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Blue capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, blue color, and thickness 2
zone:DrawZone(30, {0, 0, 1}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.BLUE }
else
-- If creation fails, log an error message
env.error("Failed to create Blue capture zone: " .. zone:GetName())
end
end
-- Function to handle zone capture
local function OnZoneCaptured(event)
local zone = event.zone
local coalition = event.coalition
if zone and coalition then
env.info("OnZoneCaptured: Zone " .. zone:GetName() .. " captured by coalition " .. coalition)
-- Update the zone state
if coalition == coalition.side.RED then
zoneStates[zone:GetName()] = "RED"
zone:SetCoalition(coalition.side.RED)
elseif coalition == coalition.side.BLUE then
zoneStates[zone:GetName()] = "BLUE"
zone:SetCoalition(coalition.side.BLUE)
else
zoneStates[zone:GetName()] = "NEUTRAL"
zone:SetCoalition(coalition.side.NEUTRAL)
end
else
env.error("OnZoneCaptured: Invalid zone or coalition")
end
end
-- Function to handle zone guarded events
local function OnZoneGuarded(event)
local zone = event.Zone
local coalition = event.Coalition
if coalition == coalition.side.RED then
env.info("Red is guarding zone: " .. zone:GetName())
elseif coalition == coalition.side.BLUE then
env.info("Blue is guarding zone: " .. zone:GetName())
end
end
-- Function to handle zone empty events
local function OnZoneEmpty(event)
local zone = event.Zone
env.info("Zone is empty: " .. zone:GetName())
end
-- Function to handle zone attacked events
local function OnZoneAttacked(event)
local zone = event.Zone
local attackingGroups = zone:GetGroups()
local makeup = {}
for _, group in ipairs(attackingGroups) do
local groupName = group:GetName()
local unitTypes = {}
for _, unit in ipairs(group:GetUnits()) do
local unitType = unit:GetTypeName()
unitTypes[unitType] = (unitTypes[unitType] or 0) + 1
end
table.insert(makeup, {groupName = groupName, unitTypes = unitTypes})
end
local makeupMessage = ""
for _, groupInfo in ipairs(makeup) do
makeupMessage = makeupMessage .. "Group: " .. groupInfo.groupName .. "\n"
for unitType, count in pairs(groupInfo.unitTypes) do
makeupMessage = makeupMessage .. " " .. unitType .. ": " .. count .. "\n"
end
end
local messageText = "Zone is being attacked: " .. zone:GetName() .. "\n" .. makeupMessage
env.info(messageText)
-- Announce to the player
MESSAGE:New(messageText, 15):ToAll()
end
-- Function to handle zone neutral events
local function OnZoneNeutral(event)
local zone = event.Zone
env.info("Zone is neutral: " .. zone:GetName())
end
-- Function to check the ZONE_CAPTURE states of all zones
local function CheckZoneStates()
env.info("Checking zone states...")
local zoneStates = {}
local function processZones(zones, zoneType)
env.info("Processing " .. zoneType)
env.info("Number of zones: " .. #zones)
local allGroups = SET_GROUP:New():FilterActive():FilterStart()
for _, zone in ipairs(zones) do
if zone then
env.info("processZones: Zone object is valid")
-- Check if the zone is of the correct type
if zone.ClassName == "ZONE_CAPTURE_COALITION" then
env.info("processZones: Zone is of type ZONE_CAPTURE_COALITION")
local coalition = zone:GetCoalition()
env.info("processZones: Zone coalition: " .. tostring(coalition))
if coalition == 1 then
zoneStates[zone:GetZoneName()] = "RED"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: RED")
elseif coalition == 2 then
zoneStates[zone:GetZoneName()] = "BLUE"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: BLUE")
else
zoneStates[zone:GetZoneName()] = "NEUTRAL"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: NEUTRAL")
end
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
env.info("processZones: Checking group: " .. group:GetName())
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("processZones: IsCompletelyInZone method not found in group: " .. group:GetName())
-- Log available methods on the group object
for k, v in pairs(group) do
env.info("processZones: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("processZones: Invalid group")
end
end)
env.info("processZones: Number of groups in zone: " .. #groupsInZone)
else
env.error("processZones: Zone is not of type ZONE_CAPTURE_COALITION")
-- Log available methods on the zone object
for k, v in pairs(zone) do
env.info("processZones: Zone method: " .. tostring(k) .. " = " .. tostring(v))
end
end
if not zone.GetZoneName then
env.error("processZones: Missing GetZoneName method in " .. zoneType)
end
else
env.error("processZones: Invalid zone in " .. zoneType)
end
end
end
processZones(redCaptureZones, "redZones")
processZones(blueCaptureZones, "blueZones")
-- Log the zoneStates table
for zoneName, state in pairs(zoneStates) do
env.info("CheckZoneStates: Zone: " .. zoneName .. " State: " .. state)
end
return zoneStates
end
-- Function to assign tasks to groups
local function AssignTasks(group, zoneStates)
if not group or not group.GetCoalition or not group.GetCoordinate or not group.GetVelocity then
env.info("AssignTasks: Invalid group or missing methods")
return
end
local velocity = group:GetVelocityVec3()
local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2)
if speed > 0 then
env.info("AssignTasks: Group " .. group:GetName() .. " is already moving. No new orders sent.")
return
end
env.info("Assigning tasks to group: " .. group:GetName())
local groupCoalition = group:GetCoalition()
local groupCoordinate = group:GetCoordinate()
local closestZone = nil
local closestDistance = math.huge
env.info("Group Coalition: " .. tostring(groupCoalition))
env.info("Group Coordinate: " .. groupCoordinate:ToStringLLDMS())
for zoneName, state in pairs(zoneStates) do
env.info("Checking Zone: " .. zoneName .. " with state: " .. tostring(state))
-- Convert state to a number for comparison
local stateCoalition = (state == "RED" and 1) or (state == "BLUE" and 2) or nil
if stateCoalition and stateCoalition ~= groupCoalition then
local zone = ZONE:FindByName(zoneName)
if zone then
local zoneCoordinate = zone:GetCoordinate()
local distance = groupCoordinate:Get2DDistance(zoneCoordinate)
--env.info("Zone Coordinate: " .. zoneCoordinate:ToStringLLDMS())
--env.info("Distance to zone " .. zoneName .. ": " .. distance)
if distance < closestDistance then
closestDistance = distance
closestZone = zone
env.info("New closest zone: " .. zoneName .. " with distance: " .. distance)
end
else
env.info("AssignTasks: Zone not found - " .. zoneName)
end
else
env.info("Zone " .. zoneName .. " is already controlled by coalition: " .. tostring(state))
end
end
if closestZone then
env.info(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName())
--MESSAGE:New(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName(), 10):ToAll()
-- Create a patrol task using the GROUP:PatrolZones method
local patrolZones = {closestZone}
local speed = 20 -- Example speed, adjust as needed
local formation = "Cone" -- Example formation, adjust as needed
local delayMin = 30 -- Example minimum delay, adjust as needed
local delayMax = 60 -- Example maximum delay, adjust as needed
group:PatrolZones(patrolZones, speed, formation, delayMin, delayMax)
else
env.info("AssignTasks: No suitable zone found for group " .. group:GetName())
end
end
-- Function to check if a group contains infantry units
local function IsInfantryGroup(group)
env.info("IsInfantryGroup: Checking group: " .. group:GetName())
for _, unit in ipairs(group:GetUnits()) do
local unitTypeName = unit:GetTypeName()
env.info("IsInfantryGroup: Checking unit: " .. unit:GetName() .. " with type: " .. unitTypeName)
if unitTypeName:find("Infantry") or unitTypeName:find("Soldier") or unitTypeName:find("Paratrooper") then
env.info("IsInfantryGroup: Found infantry unit in group: " .. group:GetName())
return true
end
end
return false
end
-- Function to assign tasks to groups
local function AssignTasksToGroups()
env.info("AssignTasksToGroups: Starting task assignments")
local zoneStates = CheckZoneStates()
local allGroups = SET_GROUP:New():FilterActive():FilterStart()
local function processZone(zone, zoneColor)
if zone then
env.info("AssignTasksToGroups: Processing " .. zoneColor .. " zone: " .. zone:GetName())
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("AssignTasksToGroups: IsCompletelyInZone method not found in group: " .. group:GetName())
for k, v in pairs(group) do
env.info("AssignTasksToGroups: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("AssignTasksToGroups: Invalid group")
end
end)
env.info("AssignTasksToGroups: Found " .. #groupsInZone .. " groups in " .. zoneColor .. " zone: " .. zone:GetName())
for _, group in ipairs(groupsInZone) do
if IsInfantryGroup(group) == true then
if MOVING_INFANTRY_PATROLS == true then
env.info("AssignTasksToGroups: Assigning tasks to infantry group: " .. group:GetName())
AssignTasks(group, zoneStates)
else
env.info("AssignTasksToGroups: Skipping infantry group: " .. group:GetName())
end
else
env.info("AssignTasksToGroups: Assigning tasks to group: " .. group:GetName())
AssignTasks(group, zoneStates)
end
end
else
env.info("AssignTasksToGroups: Invalid " .. zoneColor .. " zone")
end
end
for _, zone in ipairs(redZones) do
processZone(zone, "red")
end
for _, zone in ipairs(blueZones) do
processZone(zone, "blue")
end
env.info("AssignTasksToGroups: Task assignments completed. Running again in " .. ASSIGN_TASKS_SCHED .. " seconds.")
end
-- Function to calculate spawn frequency in seconds
local function CalculateSpawnFrequency(warehouses, baseFrequency)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 or aliveWarehouses == 0 then
return math.huge -- Stop spawning if there are no warehouses or no alive warehouses
end
local frequency = baseFrequency * (totalWarehouses / aliveWarehouses)
return frequency
end
-- Function to calculate spawn frequency percentage
local function CalculateSpawnFrequencyPercentage(warehouses)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 then
return 0 -- Avoid division by zero
end
local percentage = (aliveWarehouses / totalWarehouses) * 100
return percentage
end
-- Add event handlers for zone capture
for _, captureZone in ipairs(redCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
for _, captureZone in ipairs(blueCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses, coalition.side.RED)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses, coalition.side.BLUE)
-- Display spawn frequency percentages to the user
MESSAGE:New("Red side spawn frequency: " .. redSpawnFrequencyPercentage .. "%", 30):ToRed()
MESSAGE:New("Blue side spawn frequency: " .. blueSpawnFrequencyPercentage .. "%", 30):ToBlue()
-- Schedule ground spawns using the calculated frequencies
redInfantrySpawn = SPAWN:New("RedInfantryGroup")
:InitRandomizeTemplate(redInfantryTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_INFANTRY, MAX_RED_INFANTRY)
:SpawnScheduled(redInfantrySpawnFrequency, 0.5)
redArmorSpawn = SPAWN:New("RedArmorGroup")
:InitRandomizeTemplate(redArmorTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_ARMOR, MAX_RED_ARMOR)
:SpawnScheduled(redArmorSpawnFrequency, 0.5)
blueInfantrySpawn = SPAWN:New("BlueInfantryGroup")
:InitRandomizeTemplate(blueInfantryTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_INFANTRY, MAX_BLUE_INFANTRY)
:SpawnScheduled(blueInfantrySpawnFrequency, 0.5)
blueArmorSpawn = SPAWN:New("BlueArmorGroup")
:InitRandomizeTemplate(blueArmorTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_ARMOR, MAX_BLUE_ARMOR)
:SpawnScheduled(blueArmorSpawnFrequency, 0.5)
env.info("Dynamic Ground Battle & Zone capture initialized.")
-- Function to monitor and announce warehouse status
local function MonitorWarehouses()
local blueWarehousesAlive = 0
local redWarehousesAlive = 0
for _, warehouse in ipairs(blueWarehouses) do
if warehouse:IsAlive() then
blueWarehousesAlive = blueWarehousesAlive + 1
end
end
for _, warehouse in ipairs(redWarehouses) do
if warehouse:IsAlive() then
redWarehousesAlive = redWarehousesAlive + 1
end
end
-- Debug messages to check values
env.info("MonitorWarehouses: blueWarehousesAlive = " .. blueWarehousesAlive)
env.info("MonitorWarehouses: redWarehousesAlive = " .. redWarehousesAlive)
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
-- Log the values
env.info("MonitorWarehouses: redInfantrySpawnFrequency = " .. redInfantrySpawnFrequency)
env.info("MonitorWarehouses: redArmorSpawnFrequency = " .. redArmorSpawnFrequency)
env.info("MonitorWarehouses: blueInfantrySpawnFrequency = " .. blueInfantrySpawnFrequency)
env.info("MonitorWarehouses: blueArmorSpawnFrequency = " .. blueArmorSpawnFrequency)
env.info("MonitorWarehouses: redSpawnFrequencyPercentage = " .. redSpawnFrequencyPercentage)
env.info("MonitorWarehouses: blueSpawnFrequencyPercentage = " .. blueSpawnFrequencyPercentage)
local msg = "[Warehouse status:]\n"
msg = msg .. "Red warehouses alive: " .. redWarehousesAlive .. " Reinforcements Capacity: " .. redSpawnFrequencyPercentage .. "%" .. "\n"
msg = msg .. "Blue warehouses alive: " .. blueWarehousesAlive .. " Reinforcements Capacity: " .. blueSpawnFrequencyPercentage .. "%" .. "\n"
MESSAGE:New(msg, 30):ToAll()
end
-- Function to check the wincondition. If either side owns all zones, mission ends.
local function checkWinCondition()
local blueOwned = true
local redOwned = true
for zoneName, owner in pairs(zoneStatuses) do
if owner ~= 1 then
redOwned = false
end
if owner ~= 2 then
blueOwned = false
end
end
if blueOwned then
MESSAGE:New("Blue side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("UsaTheme.ogg"):ToAll()
return true
elseif redOwned then
MESSAGE:New("Red side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("MotherRussia.ogg"):ToAll()
return true
end
return false
end
-- Timer function to periodically check the win condition
local function monitorWinCondition()
if not checkWinCondition() then
-- Schedule the next check in 60 seconds
TIMER:New(monitorWinCondition):Start(60)
end
end
-- Start monitoring the win condition
monitorWinCondition()
-- Scheduler to monitor warehouses every 120 seconds
SCHEDULER:New(nil, MonitorWarehouses, {}, 0, 120)
-- Scheduler to assign tasks to groups periodically
SCHEDULER:New(nil, AssignTasksToGroups, {}, 0, ASSIGN_TASKS_SCHED) -- Check every 600 seconds (10 minutes) - Adjust as needed
-- Create a mission menu
local missionMenu = MENU_MISSION:New("Warehouse Monitoring")
-- Add a menu item to run the MonitorWarehouses function
MENU_MISSION_COMMAND:New("Check Warehouse Status", missionMenu, MonitorWarehouses)

View File

@ -0,0 +1,83 @@
--Build Command Center and Mission for Blue
US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
US_Mission = MISSION:New( US_CC, "Insurgent Sandstorm", "Primary", "Clear the front lines of enemy activity.", coalition.side.BLUE)
US_Score = SCORING:New( "Insurgent Sandstorm - Blue" )
US_Mission:AddScoring( US_Score )
US_Mission:Start()
US_Score:SetMessagesHit(false)
US_Score:SetMessagesDestroy(false)
US_Score:SetMessagesScore(false)
--Build Command Center and Mission Red
RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
RU_Mission = MISSION:New (RU_CC, "Insurgent Sandstorm", "Primary", "Destroy U.S. and NATO forces.", coalition.side.RED)
RU_Score = SCORING:New("Insurgent Sandstorm - Red")
RU_Mission:AddScoring( RU_Score)
RU_Mission:Start()
RU_Score:SetMessagesHit(false)
RU_Score:SetMessagesDestroy(false)
RU_Score:SetMessagesScore(false)
PlayerClients = SET_PLAYER:New():FilterStart()
:HandleEvent( EVENTS.Crash )
function PlayerClients:OnEventCrash( EventData )
local coal = EventData.initiator:getCoalition()
local side, oside
if coal == 1 then
side = 'RED'
oside = 'BLUE'
MissionPlayerName = EventData.initiator:getPlayerName()
if MissionPlayerName ~= nil then
MESSAGE:New("\n\nA " .. side .. " player ( " .. MissionPlayerName .. " ) has crashed! ", msgTime, "Alert!"):ToAll()
end
elseif coal == 2 then
side = 'BLUE'
oside = 'RED'
MissionPlayerName = EventData.initiator:getPlayerName()
if MissionPlayerName ~= nil then
local current_time = os.time() -- Get the current date and time
local formatted_time = os.date("%A, %B %d, %Y %I:%M:%S %p", current_time) -- Format the date and time
MESSAGE:New("\n\nAt .. " .. formatted_time .. ": " .. MissionPlayerName .. " ) was shot down! Insurgent fighters could be heard screaming something over the radio about aloha and snack bars..", msgTime, "Alert!"):ToAll()
USERSOUND:New("AllahuAkbar.ogg"):ToAll()
end
else
env.info("**** We should not have gotten here! Moose_insurgentSandstorm.lua ****")
end
end
-- Setup AI A2A Dispatchers
--Red
CCCPBorderZone = ZONE_POLYGON:New( "RED BORDER", GROUP:FindByName( "RED BORDER" ) )
RedA2ADispatcher = AI_A2A_GCICAP:New( { "RED EWR" }, { "FIGHTER SWEEP RED" }, { "RED BORDER" }, CCCPBorderZone )
RedA2ADispatcher:SetDefaultLandingAtEngineShutdown()
RedA2ADispatcher:SetDefaultTakeoffFromParkingHot()
RedA2ADispatcher:SetBorderZone( CCCPBorderZone )
RedA2ADispatcher:SetTacticalDisplay(false)
RedA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
RedA2ADispatcher:SetRefreshTimeInterval( 300 )
RedA2ADispatcher:SetDefaultOverhead(RedA2ADefaultOverhead)
--Blue
BLUEBorderZone = ZONE_POLYGON:New( "BLUE BORDER", GROUP:FindByName( "BLUE BORDER" ) )
BLUEA2ADispatcher = AI_A2A_GCICAP:New( { "BLUE EWR" }, { "FIGHTER SWEEP BLUE" }, { "BLUE BORDER" }, BLUEBorderZone )
BLUEA2ADispatcher:SetDefaultLandingAtEngineShutdown()
BLUEA2ADispatcher:SetDefaultTakeoffFromParkingHot()
BLUEA2ADispatcher:SetBorderZone( BLUEBorderZone )
BLUEA2ADispatcher:SetTacticalDisplay(false)
BLUEA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
BLUEA2ADispatcher:SetRefreshTimeInterval( 300 )
BLUEA2ADispatcher:SetDefaultOverhead(BlueA2ADefaultOverhead)
Blue_Drone = SPAWN:New("BLUE DRONE")
:InitLimit(1, 25)
:SpawnScheduled(600, 0.5)

View File

@ -0,0 +1,43 @@
-- Define the patrol zone
local patrolZone = ZONE:New("AWACS_PatrolZone")
-- Define AWACS and its escorts
local awacsGroup = "BLUE EWR AWACS" -- Name of AWACS group from mission editor
local escortGroup1 = "BlueAWACS_Escort_Group1" -- First escort group
local escortGroup2 = "BlueAWACS_Escort_Group2" -- Second escort group
-- Spawn the AWACS and set up patrol behavior
local awacs = SPAWN:New(awacsGroup)
:InitLimit(1, 0) -- Limit to one active instance of AWACS
:OnSpawnGroup(function(group)
-- Define patrol within the zone
local awacsPatrol = AI_PATROL_ZONE:New(group, patrolZone, 5000, 10000, 500, 800)
awacsPatrol:ManageFuelOn(.7, 300) -- AWACS returns to base when low on fuel
-- Event handler for AWACS being attacked
group:HandleEvent(EVENTS.Hit)
function group:OnEventHit(EventData)
group:RouteRTB() -- AWACS returns to base when attacked
end
end)
:Spawn()
-- Spawn the first escort and attach to AWACS
local escort1 = SPAWN:New(escortGroup1)
:InitLimit(1, 0)
:OnSpawnGroup(function(escortGroup)
-- Attach the escort to follow AWACS
local awacsEscort1 = ESCORT:New(awacs, escortGroup)
awacsEscort1:Escort()
end)
:Spawn()
-- Spawn the second escort and attach to AWACS
local escort2 = SPAWN:New(escortGroup2)
:InitLimit(1, 0)
:OnSpawnGroup(function(escortGroup)
-- Attach the second escort to follow AWACS
local awacsEscort2 = ESCORT:New(awacs, escortGroup)
awacsEscort2:Escort()
end)
:Spawn()

View File

@ -0,0 +1,142 @@
--Ops - Office of Military Intelligence.
--
--Main Features:
---Detect and track contacts consistently
---Detect and track clusters of contacts consistently
---Once detected and still alive, planes will be tracked 10 minutes, helicopters 20 minutes, ships and trains 1 hour, ground units 2 hours
-- Docs: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Ops.Intel.html
-- Setup Detection Group
local msgTime = 15
Blue_Intel_Message_Setting = false
Blue_Intel_Sound_Setting = true
Blue_Intel_DetectionGroup = SET_GROUP:New()
Blue_Intel_DetectionGroup:FilterCoalitions("blue"):FilterActive(true):FilterStart()
-- Setup the INTEL
Blue_Intel = INTEL:New(Blue_Intel_DetectionGroup, "blue", "CIA")
Blue_Intel:SetClusterAnalysis(true, true)
Blue_Intel:SetClusterRadius(5)
Blue_Intel:SetVerbosity(2)
Blue_Intel:__Start(10)
-- On After New Contact
function Blue_Intel:OnAfterNewContact(From, Event, To, Contact)
local text = string.format("NEW contact %s detected by %s", Contact.groupname, Contact.recce or "unknown")
if (Blue_Intel_Message_Setting == true) then
MESSAGE:New(text, msgTime, "CIA"):ToBlue()
if (Blue_Intel_Sound_Setting == true) then
USERSOUND:New("morsecode.ogg"):ToCoalition(coalition.side.BLUE)
end
end
end
-- On After New Cluster
function Blue_Intel:OnAfterNewCluster(From, Event, To, Cluster)
local text = string.format("NEW cluster #%d of size %d", Cluster.index, Cluster.size)
if (Blue_Intel_Message_Setting == true) then
MESSAGE:New(text, msgTime,"CIA"):ToBlue()
if (Blue_Intel_Sound_Setting == true) then
USERSOUND:New("morsecode.ogg"):ToCoalition(coalition.side.BLUE)
end
end
end
function Blue_IntelMessageSettingOn()
if (Blue_Intel_Message_Setting == true) then
MESSAGE:New("Setting INTEL messages to ON", msgTime,"CIA"):ToBlue()
Blue_Intel_Message_Setting = true
end
end
function Blue_IntelMessageSettingOff()
if (Blue_Intel_Message_Setting == true) then
MESSAGE:New("Setting INTEL messages to OFF", msgTime,"CIA"):ToBlue()
Blue_Intel_Message_Setting = false
end
end
function Blue_IntelSoundSettingOff()
MESSAGE:New("Disabling morse code sound", msgTime, "CIA"):ToBlue()
Blue_Intel_Sound_Setting = false
end
function Blue_IntelSoundSettingOn()
MESSAGE:New("Enabling morse code sound", msgTime, "CIA"):ToBlue()
Blue_Intel_Sound_Setting = true
end
local INTELMenu = MENU_COALITION:New(coalition.side.BLUE,"INTEL HQ")
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Display Messages (ON)", INTELMenu, Blue_IntelMessageSettingOn)
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Display Messages (OFF)", INTELMenu, Blue_IntelMessageSettingOff)
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Disable Morse Code Sound", INTELMenu, Blue_IntelSoundSettingOff)
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Enable Morse Code Sound", INTELMenu, Blue_IntelSoundSettingOn)
Red_Intel_Message_Setting = false
Red_Intel_Sound_Setting = true
Red_Intel_DetectionGroup = SET_GROUP:New()
--Red_Intel_DetectionGroup:FilterPrefixes( { "RED EWR", "RED RECON" } )
Red_Intel_DetectionGroup:FilterCoalitions("red"):FilterActive(true):FilterStart()
-- Setup the INTEL
Red_Intel = INTEL:New(Red_Intel_DetectionGroup, "red", "KGB")
Red_Intel:SetClusterAnalysis(true, true)
Red_Intel:SetClusterRadius(5)
Red_Intel:SetVerbosity(2)
Red_Intel:__Start(10)
-- On After New Contact
function Red_Intel:OnAfterNewContact(From, Event, To, Contact)
local text = string.format("NEW contact %s detected by %s", Contact.groupname, Contact.recce or "unknown")
if (Red_Intel_Message_Setting == true) then
MESSAGE:New(text, msgTime, "KGB"):ToRed()
USERSOUND:New("morsecode.ogg"):ToCoalition(coalition.side.RED)
end
end
-- On After New Cluster
function Red_Intel:OnAfterNewCluster(From, Event, To, Cluster)
local text = string.format("NEW cluster #%d of size %d", Cluster.index, Cluster.size)
if (Red_Intel_Message_Setting == true) then
MESSAGE:New(text, msgTime,"KGB"):ToRed()
USERSOUND:New("morsecode.ogg"):ToCoalition(coalition.side.RED)
end
end
function Red_IntelMessageSettingOn()
if (Red_Intel_Message_Setting == true) then
MESSAGE:New("Setting INTEL messages to ON", msgTime,"KGB"):ToRed()
USERSOUND:New("morsecode.ogg"):ToCoalition(coalition.side.RED)
Red_Intel_Message_Setting = true
end
end
function Red_IntelMessageSettingOff()
if (Red_Intel_Message_Setting == true) then
MESSAGE:New("Setting INTEL messages to OFF", msgTime,"KGB"):ToRed()
Red_Intel_Message_Setting = false
end
end
function Red_IntelSoundSettingOff()
MESSAGE:New("Disabling morse code sound", msgTime, "KGB"):ToRed()
Red_Intel_Sound_Setting = false
end
function Red_IntelSoundSettingOn()
MESSAGE:New("Enabling morse code sound", msgTime, "KGB"):ToRed()
Red_Intel_Sound_Setting = true
end
local RedINTELMenu = MENU_COALITION:New(coalition.side.RED,"INTEL HQ")
MENU_COALITION_COMMAND:New(coalition.side.RED, "Dispaly Messages (ON)",RedINTELMenu,Red_IntelMessageSettingOn)
MENU_COALITION_COMMAND:New(coalition.side.RED, "Dispaly Messages (OFF)",RedINTELMenu,Red_IntelMessageSettingOff)
MENU_COALITION_COMMAND:New(coalition.side.RED, "Disable Morse Code Sound", RedINTELMenu, Red_IntelSoundSettingOff)
MENU_COALITION_COMMAND:New(coalition.side.RED, "Enable Morse Code Sound", RedINTELMenu, Red_IntelSoundSettingOn)

Binary file not shown.

View File

@ -0,0 +1,4 @@
local function main()
end
main()

5
DCS_Caucasus/.buildpath Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry kind="src" path="src"/>
<buildpathentry combineaccessrules="false" kind="prj" path="/Moose_Framework"/>
</buildpath>

18
DCS_Caucasus/.project Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>DCS_Caucasus</name>
<comment></comment>
<projects>
<project>Moose_Framework</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,59 @@
--_SETTINGS:SetPlayerMenuOff()
----env.info("Loading Main Script", true)
---- Setup Command Centers. See Moose_ErmenekLiberation_ZoneCapture.lua for remaining code.
---- Set SRS settings
--STTS.DIRECTORY = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
--STTS.SRS_PORT = "5002"
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart()
US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterStart()
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
US_AI_Balancer = AI_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn )
PatrolZone1 = ZONE:New("PatrolZone1")
PatrolZone2 = ZONE:New("PatrolZone2")
Spawn_US_AWACS = SPAWN:New("BLUE EWR E-2D Wizard Group")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)
Spawn_RU_AWACS = SPAWN:New("RED EWR")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)
function US_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone1,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone1)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone2,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone2)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end

View File

@ -0,0 +1,59 @@
--_SETTINGS:SetPlayerMenuOff()
----env.info("Loading Main Script", true)
---- Setup Command Centers. See Moose_ErmenekLiberation_ZoneCapture.lua for remaining code.
---- Set SRS settings
--STTS.DIRECTORY = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
--STTS.SRS_PORT = "5002"
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart()
US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterStart()
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
US_AI_Balancer = AI_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn )
PatrolZone1 = ZONE:New("PatrolZone1")
PatrolZone2 = ZONE:New("PatrolZone2")
Spawn_US_AWACS = SPAWN:New("BLUE EWR E-2D Wizard Group")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)
Spawn_RU_AWACS = SPAWN:New("RED EWR")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)
function US_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone1,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone1)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone2,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone2)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end

View File

@ -0,0 +1,91 @@
--_SETTINGS:SetPlayerMenuOff()
----env.info("Loading Main Script", true)
---- Setup Command Centers. See Moose_ErmenekLiberation_ZoneCapture.lua for remaining code.
---- Set SRS settings
--STTS.DIRECTORY = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
--STTS.SRS_PORT = "5002"
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSetFW190 = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterPrefixes("FW190"):FilterStart()
RU_PlanesClientSetBF109 = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterPrefixes("BF109"):FilterStart()
US_PlanesClientSetP51 = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterPrefixes("P51"):FilterStart()
US_PlanesClientSetSpitFire = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterPrefixes("Spitfire"):FilterStart()
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawnFW190 = SPAWN:New( "AI RU-FW190" ):InitCleanUp( 20 )
RU_PlanesSpawnBF109 = SPAWN:New( "AI RU-BF109" ):InitCleanUp( 20 )
US_PlanesSpawnP51 = SPAWN:New( "AI US-P51" ):InitCleanUp( 20 )
US_PlanesSpawnSpitFire = SPAWN:New( "AI US-SPITFIRE" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_BalancerFW190 = AI_BALANCER:New( RU_PlanesClientSetFW190, RU_PlanesSpawnFW190 )
RU_AI_BalancerBF109 = AI_BALANCER:New( RU_PlanesClientSetBF109, RU_PlanesSpawnBF109 )
US_AI_BalancerP51 = AI_BALANCER:New( US_PlanesClientSetP51, US_PlanesSpawnP51 )
US_AI_BalancerSpitFire = AI_BALANCER:New( US_PlanesClientSetSpitFire, US_PlanesSpawnSpitFire )
PatrolZone1 = ZONE:New("PatrolZone1")
PatrolZone2 = ZONE:New("PatrolZone2")
function US_AI_BalancerP51:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone1,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone1)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
function US_AI_BalancerSpitFire:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone1,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone1)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
function RU_AI_BalancerFW190:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone2,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone2)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
function RU_AI_BalancerBF109:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
--local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
local Patrol = AI_CAP_ZONE:New(PatrolZone2,5000,30000,400,500)
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetEngageZone(PatrolZone2)
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
Spawn_US_AWACS = SPAWN:New("BLUE EWR E-2D Wizard Group")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)
Spawn_RU_AWACS = SPAWN:New("RED EWR")
:InitLimit(1,500)
:InitRepeatOnLanding()
:SpawnScheduled(300, .4)

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry combineaccessrules="false" kind="prj" path="/Moose_Framework"/>
</buildpath>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Battle of Gori</name>
<comment></comment>
<projects>
<project>Moose_Framework</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

View File

@ -0,0 +1,464 @@
--Verion 1.4.2
ProviderChecker = {}
-- Best to leave this on for the most part.
ProviderChecker.TankerFuelChecking = true
-- Only necessary to set if you don't set them to invicible
ProviderChecker.TankerKilledTimer = 60
-- Good to set even if you are using Fuel Check, in case it lands for some weird AI reason.
ProviderChecker.TankerRTBTimer = 60
-- If you want it to respawn when fuel state reaches 20%, instead of having it RTB all the way to base.
ProviderChecker.AWACFuelChecking = true
-- Killed Timer is the time delay to respawn for killed in seconds. Minimum of 5 seconds, anything less will default to 5 seconds
ProviderChecker.AWACKilledTimer = 600
-- RTB Timer is time delay to respawn from landing. Can be 0
ProviderChecker.AWACRTBTimer = 60
ProviderChecker.AWACSeventHandler = {}
ProviderChecker.TankereventHandler = {}
ProviderChecker.TankerTable = {}
ProviderChecker.AwacsTable = {}
ProviderChecker.TankerRefuelingCountBlueFor = 0
ProviderChecker.TankerRefuelingCountRedFor = 0
--Tankers waiting for respawn
ProviderChecker.TankerStandbyTable= {}
function ProviderChecker.TankerRadioStatus(radio_coalition)
local coalition_side = ""
if radio_coalition == 1 then
coalition_side = coalition_side .. "red"
elseif radio_coalition == 2 then
coalition_side = coalition_side .. "blue"
end
local tanker_status_start = "===========================\n"
local tanker_status_end = "==========================="
local tanker_status_mid = ""
for fueler, params in pairs(ProviderChecker.TankerTable) do
if params.coalition == coalition_side then
if params.has_tasking then
local m_tanker_id = Group.getByName(params.name)
local m_tanker_radio = params.radio_freqeuncy
local m_tanker_units = m_tanker_id:getUnits()
local m_tanker_unit = m_tanker_units[1]
local m_tanker_callsign = m_tanker_unit:getCallsign()
local m_tanker_channel = params.channel
local m_tanker_mode = params.modeChannel
local m_tanker_ac_type = m_tanker_unit:getTypeName()
tanker_status_mid = tanker_status_mid .. "Tanker: " .. m_tanker_callsign .. " Radio: " .. m_tanker_radio ..
" TACAN: " .. m_tanker_channel .. m_tanker_mode .. " Aircraft: " .. m_tanker_ac_type .. "\n"
else
local m_tanker_id = Group.getByName(params.name)
local m_tanker_radio = params.radio_freqeuncy
local m_tanker_units = m_tanker_id:getUnits()
local m_tanker_unit = m_tanker_units[1]
local m_tanker_callsign = m_tanker_unit:getCallsign()
tanker_status_mid = tanker_status_mid .. "Tanker: " .. m_tanker_callsign .. " Radio: " .. m_tanker_radio ..
" TACAN: N/A" .. " Aircraft: " .. m_tanker_ac_type .. "\n"
end
end
end
local out_message = tanker_status_start .. tanker_status_mid .. tanker_status_end
trigger.action.outTextForCoalition(radio_coalition, out_message, 30, true)
end
function ProviderChecker.RefreshTACAN(_nil,time)
for fueler, params in pairs(ProviderChecker.TankerTable) do
if params.has_tasking then
local tanker_id = Group.getByName(params.name)
if tanker_id then
local tanker_controller = tanker_id:getController()
local tanker_tacan = {
id = 'ActivateBeacon',
params = {
["type"] = params.type,
["AA"] = params.AA,
["unitId"] = tanker_id,
["modeChannel"] = params.modeChannel,
["channel"] = params.channel,
["system"] = params.system,
["callsign"] = params.callsign,
["bearing"] = params.bearing,
["frequency"] = params.frequency,
}
}
tanker_controller:setCommand(tanker_tacan)
end
end
end
return time + 10
end
--Will Eventually consoldate these to one function. Pass type (awacs or tanker) as argument.
function ProviderChecker.SpawnNewTanker(_unit, time)
--respawn uses the same name, and tankers are tracked by name instead of ID. Will change this for AWACS in future update.
NewGroup = mist.respawnGroup(_unit,true)
NewName = NewGroup.units[1].name
NewUnit = Unit.getByName(NewName)
tanker_controller = NewUnit:getController()
for tanker, params in pairs(ProviderChecker.TankerTable) do
if params.name == NewName then
local frequency = tonumber(params.radio_freqeuncy) * 1000000
SetFrequency = {
id = 'SetFrequency',
params = {
frequency = frequency,
modulation = 0,
}
}
tanker_controller:setCommand(SetFrequency)
trigger.action.outTextForCoalition(NewUnit:getCoalition(),"Tanker " ..NewUnit:getCallsign().. " is back online!", 10, false)
end
end
return nil
end
function ProviderChecker.SpawnNewAwacs(_unit, time)
NewGroup = mist.respawnGroup(_unit,true)
NewName = NewGroup.units[1].name
NewUnit = Unit.getByName(NewName)
awacs_controller = NewUnit:getController()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if params.name == NewName then
local frequency = tonumber(params.radio_freqeuncy) * 1000000
SetFrequency = {
id = 'SetFrequency',
params = {
frequency = frequency,
modulation = 0,
}
}
awacs_controller:setCommand(SetFrequency)
trigger.action.outTextForCoalition(NewUnit:getCoalition(),"AWACS " .. NewUnit:getCallsign() .. " is back online!", 10, false)
end
end
return nil
end
--due to how scheduled functions work, I need to create a class to handle this. Will upgrade later next revision.
function ProviderChecker.checkTankerFuel(_nil,time)
for fueler, params in pairs(ProviderChecker.TankerTable) do
local fueler_group_name = params.name
local fueler_group = Group.getByName(fueler_group_name)
if fueler_group then
local fueler_units = fueler_group:getUnits()
local fueler_id = fueler_units[1]
local fueler_fuel = fueler_id:getFuel()
if fueler_fuel < 0.20 then
if params.coalition == "blue" then
if ProviderChecker.TankerRefuelingCountBlueFor < 1 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, fueler_group_name, timer.getTime() + 5)
elseif ProviderChecker.TankerRefuelingCountBlueFor > 0 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " fuel at less than 20%. Will respawn when no aircraft are refueling",
10
)
end
elseif params.coalition == "red" then
if ProviderChecker.TankerRefuelingCountRedFor < 1 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, fueler_group_name, timer.getTime() + 5)
elseif ProviderChecker.TankerRefuelingCountRedFor > 0 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " fuel at less than 20%. Will respawn when no aircraft are refueling",
10
)
end
end
elseif fueler_fuel < 0.22 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " at 25%. Will respawn at 20% if no aircraft are refueling",
10
)
end
end
end
return time + 120
end
function ProviderChecker.checkAWACSFuel(_nil,time)
--Due to the respawn and scheduledFunction limitations, Checking Refuel requires imediate respawn, else it would loop to respawn again and again.
for awacs, params in pairs(ProviderChecker.AwacsTable) do
local awacs_group_name = params.name
local awacs_group = Group.getByName(awacs_group_name)
if awacs_group then
local awacs_units = awacs_group:getUnits()
local awacs_id = awacs_units[1]
local awacs_fuel = awacs_id:getFuel()
if awacs_fuel < 0.30 then
if params.coalition == "blue" then
trigger.action.outTextForCoalition(
awacs_id:getCoalition(),
"AWACS " .. awacs_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, awacs_group_name, timer.getTime() + 5)
elseif params.coalition == "red" then
trigger.action.outTextForCoalition(
awacs_id:getCoalition(),
"AWACS " .. awacs_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, awacs_group_name, timer.getTime() + 5)
end
end
end
end
return time + 120
end
function ProviderChecker.TankereventHandler:onEvent(_event)
-- Adds up the number of units taking fuel because the event handler is based on unit taking fuel, not giving fuel
-- Solution to this later will be check nearest unit of type tanker and create a "class" out of that.
if (_event.id == 7) and _event.initiator then
local refueling_unit = _event.initiator
local refueling_unit_coalition = refueling_unit:getCoalition()
if refueling_unit_coalition == 2 then
ProviderChecker.TankerRefuelingCountBlueFor = ProviderChecker.TankerRefuelingCountBlueFor + 1
elseif refueling_unit_coalition == 1 then
ProviderChecker.TankerRefuelingCountRedFor = ProviderChecker.TankerRefuelingCountRedFor + 1
end
end
-- Removes the number of units taking fuel
if (_event.id == 14) and _event.initiator then
local refueling_unit = _event.initiator
local refueling_unit_coalition = refueling_unit:getCoalition()
if refueling_unit_coalition == 2 then
ProviderChecker.TankerRefuelingCountBlueFor = ProviderChecker.TankerRefuelingCountBlueFor - 1
elseif refueling_unit_coalition == 1 then
ProviderChecker.TankerRefuelingCountRedFor = ProviderChecker.TankerRefuelingCountRedFor - 1
end
end
-- Checks if tanker landed.
if (_event.id == 4) and _event.initiator then
if _event.initiator then
local LandedUnit = _event.initiator
local LandedUnitName = LandedUnit:getName()
local LandedUnitInfo = Unit.getGroup(LandedUnit)
local LandedUnitGroupName = LandedUnitInfo:getName()
for fueler, params in pairs(ProviderChecker.TankerTable) do
if LandedUnitGroupName == params.name then
if ProviderChecker.TankerRTBTimer > 5 then
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " Landed - Respawning in " .. (ProviderChecker.TankerRTBTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, LandedUnitGroupName, timer.getTime() + ProviderChecker.TankerRTBTimer)
else
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " Landed - Respawning", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, LandedUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
if (_event.id == 5) and _event.initiator then
local DeadUnit = _event.initiator
local DeadUnitName = DeadUnit:getName()
local DeadUnitInfo = Unit.getGroup(DeadUnit)
local DeadUnitGroupName = DeadUnitInfo:getName()
for fueler, params in pairs(ProviderChecker.TankerTable) do
if DeadUnitGroupName == params.name then
if ProviderChecker.TankerKilledTimer > 5 then
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"Tanker " .. DeadUnit:getCallsign() .. " has crashed! Replacement will be on station in " .. (ProviderChecker.TankerKilledTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, DeadUnitGroupName, timer.getTime() + ProviderChecker.TankerKilledTimer)
else
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " has crashed! Replacement will be on station in 5 Seconds", 10,false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, DeadUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
function ProviderChecker.AWACSeventHandler:onEvent(_event)
-- Checks if tanker landed.
if (_event.id == 4) and _event.initiator then
local LandedUnit = _event.initiator
local LandedUnitName = LandedUnit:getName()
local LandedUnitInfo = Unit.getGroup(LandedUnit)
local LandedUnitGroupName = LandedUnitInfo:getName()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if LandedUnitGroupName == params.name then
if ProviderChecker.AWACRTBTimer > 5 then
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"AWACS " .. LandedUnit:getCallsign() .. " Landed - Respawning in " .. (ProviderChecker.AWACRTBTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, LandedUnitGroupName, timer.getTime() + ProviderChecker.AWACRTBTimer)
else
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"AWACS " .. LandedUnit:getCallsign() .. " Landed - Respawning", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, LandedUnitGroupName, timer.getTime() + 5)
end
end
end
end
if (_event.id == 5) and _event.initiator then
local DeadUnit = _event.initiator
local DeadUnitName = DeadUnit:getName()
local DeadUnitInfo = Unit.getGroup(DeadUnit)
local DeadUnitGroupName = DeadUnitInfo:getName()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if DeadUnitGroupName == params.name then
if ProviderChecker.AWACKilledTimer > 5 then
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"AWACS " .. DeadUnit:getCallsign() .. " has been shot down! Replacement will be on station in " .. (ProviderChecker.AWACKilledTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, DeadUnitGroupName, timer.getTime() + ProviderChecker.AWACKilledTimer)
else
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"AWACS " .. DeadUnit:getCallsign() .. " has been shot down! Replacement will be on station in 5 Seconds", 10,false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, DeadUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
-- function ProviderChecker.ServiceCheckerMsg()
function ProviderChecker.GetServicesList()
-- You can -only- get TACAN data from the mission file. So since MIST respawn uses the same TACANs on respawn,
-- I can pull from the mission file and refresh that way
for coa_name, coa_data in pairs(env.mission.coalition) do
if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then
if coa_data.country then --there is a country table
for cntry_id, cntry_data in pairs(coa_data.country) do
for obj_type_name, obj_type_data in pairs(cntry_data) do
if obj_type_name == "plane" then
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group!
for group_num, group_data in pairs(obj_type_data.group) do
group_Id = group_data.groupId
group_radio = group_data.frequency
group_name = env.getValueDictByKey(group_data.name)
if group_data.task == "Refueling" then
if group_data["units"][1]["type"] ~= "IL-78M" then
if group_data.tasks and group_data.tasks.parmas then
for tasks_id, tasks_data in pairs(group_data.tasks) do
if tasks_data.params and tasks_data.params.action and tasks_data.params.action.params then
tasks_data.params.action.params["coalition"] = coa_name
tasks_data.params.action.params["radio_freqeuncy"] = group_radio
tasks_data.params.action.params["name"] = group_name
tasks_data.params.action.params["has_tasking"] = true
ProviderChecker.TankerTable[group_Id] = tasks_data.params.action.params
end --if task_data.params
end -- for tasks_id, tasks_data
-- Because for some weird ass reason, the tasks will be blank so I need to pull them from waypoints instead
elseif group_data.route.points then
for point_id, point_params in pairs(group_data.route.points) do
if point_params.task then
for tasks_id, tasks_data in pairs(point_params.task.params.tasks) do
if tasks_data.params and tasks_data.params.action and tasks_data.params.action.id == "ActivateBeacon" then
tasks_data.params.action.params["coalition"] = coa_name
tasks_data.params.action.params["radio_freqeuncy"] = group_radio
tasks_data.params.action.params["name"] = group_name
tasks_data.params.action.params["has_tasking"] = true
ProviderChecker.TankerTable[group_Id] = tasks_data.params.action.params
end -- if tasks_data.params and
end -- for tasks_id, tasks_data in
end --if point_params.task
end -- for point_id, point_params
end -- if group_data.tasks then
else
ProviderChecker.TankerTable[group_Id] = {}
ProviderChecker.TankerTable[group_Id]["coalition"] = coa_name
ProviderChecker.TankerTable[group_Id]["radio_freqeuncy"] = group_radio
ProviderChecker.TankerTable[group_Id]["name"] = group_name
ProviderChecker.TankerTable[group_Id]["has_tasking"] = false
end -- group_data["units"][1]["type"] ~= "IL-78M" then
elseif group_data.task == "AWACS" then
ProviderChecker.AwacsTable[group_Id] = {}
ProviderChecker.AwacsTable[group_Id]["coalition"] = coa_name
ProviderChecker.AwacsTable[group_Id]["radio_freqeuncy"] = group_radio
ProviderChecker.AwacsTable[group_Id]["name"] = group_name
ProviderChecker.AwacsTable[group_Id]["modeChannel"] = "N/A"
ProviderChecker.AwacsTable[group_Id]["callsign"] = "N/A"
end --if group_data.tas == "Refueling then"
end --for group_num, group_data in pairs(obj_type_data.group) do
end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then
end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then
end --for obj_type_name, obj_type_data in pairs(cntry_data) do
end --for cntry_id, cntry_data in pairs(coa_data.country) do
end --if coa_data.country then --there is a country table
end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then
end --for coa_name, coa_data in pairs(mission.coalition) do
end
world.addEventHandler(ProviderChecker.AWACSeventHandler)
env.info("F99th AWACS Checker event handler added")
world.addEventHandler(ProviderChecker.TankereventHandler)
env.info("F99th Tanker Checker event handler added")
ProviderChecker.GetServicesList()
timer.scheduleFunction(ProviderChecker.RefreshTACAN, nil, timer.getTime() + 10)
missionCommands.addCommandForCoalition(2,"Get Tanker Info",nil, ProviderChecker.TankerRadioStatus,2)
missionCommands.addCommandForCoalition(1,"Get Tanker Info",nil, ProviderChecker.TankerRadioStatus,1)
if ProviderChecker.TankerFuelChecking then
timer.scheduleFunction(ProviderChecker.checkTankerFuel, nil, timer.getTime() + 120)
end
if ProviderChecker.AWACFuelChecking then
timer.scheduleFunction(ProviderChecker.checkAWACSFuel, nil, timer.getTime() + 120)
end

Binary file not shown.

View File

@ -0,0 +1,330 @@
-- The Battle of Gori by F99Th-TracerFacer
_SETTINGS:SetPlayerMenuOff()
ScoreRequiredToWin = 100
BlueCurrentScore = 0
RedCurrentScore = 0
StatBlueCratesMoved = 0
StatBlueRescued = 0
StatRedArtyUnitsDead = 0
StatRedCAPDead = 0
StatBlueCAPDead = 0
PlayerClients = SET_PLAYER:New():FilterStart()
:HandleEvent( EVENTS.Crash )
function PlayerClients:OnEventCrash( EventData )
local coal = EventData.initiator:getCoalition()
local side, oside
if coal == 1 then
side = 'RED'
oside = 'BLUE'
GoriPlayerName = EventData.initiator:getPlayerName()
if GoriPlayerName ~= nil then
MESSAGE:New("\n\nA " .. side .. " player ( " .. GoriPlayerName .. " ) has crashed! " .. oside .. " Team gains 1 point!", 10, "Alert!"):ToAll()
ScoreAddBlue(1)
StatRedCAPDead = StatRedCAPDead + 1
end
elseif coal == 2 then
side = 'BLUE'
oside = 'RED'
GoriPlayerName = EventData.initiator:getPlayerName()
if GoriPlayerName ~= nil then
MESSAGE:New("\n\nA " .. side .. " player ( " .. GoriPlayerName .. " ) has crashed! " .. oside .. " Team gains 1 point!", 10, "Alert!"):ToAll()
ScoreAddRed(1)
StatBlueCAPDead = StatBlueCAPDead + 1
end
else
env.info("**** We should not have gotten here! Moose_BattleofGori.lua ****")
end
end
-- Setup Shelling Zones
local BombZone1 = ZONE_POLYGON:New("BombZone1", GROUP:FindByName( "BombZone1"))
local HighAirShellingZone = ZONE:New("HIGH AIR SHELLING ZONE")
-- Setup Arty Zone
local ArtyTemplate = { "RU_ARTY", "RU_ARTY #001", "RU_ARTY #002", "RU_ARTY_SA8", "RU_ARTY_SA9", "RU_ARTY_SA11" }
local ArtyZone = ZONE_POLYGON:New( "ARTY LOCATIONS", GROUP:FindByName( "ARTY LOCATIONS" ))
local ArtyZoneTable = { ArtyZone }
-- Setup SA10 Zone
local SA10Zone = ZONE_POLYGON:New( "SA10 LOCATIONS", GROUP:FindByName( "SA10 LOCATIONS" ))
local SA10ZoneTable = { SA10Zone }
-- Setup Arty Spawns (Thanks to GoreUncle for helping with the OnEventDead stuff :)
ArtySpawns = SPAWN:New( "Arty Force" )
:InitLimit( 60, 0 )
:InitHeading(260,280)
:InitRandomizeZones( ArtyZoneTable )
:InitRandomizeTemplate( ArtyTemplate )
:OnSpawnGroup(
function(SpawnedGroup)
SpawnedGroup:HandleEvent( EVENTS.Dead )
function SpawnedGroup:OnEventDead( EventData )
MESSAGE:New("NATO Forces have destroyed an Artillery Unit! Blue Team gets 1 point!\n\n", 10, "Alert!", true):ToAll()
ScoreAddBlue(1)
StatRedArtyUnitsDead = StatRedArtyUnitsDead + 1
end
end
):SpawnScheduled( .1, .2 )
-- Mission Status msg - used in F10 menu and when certain units are killed.
function MissionStatus(MsgTime)
MissionStatusMsg = MESSAGE:New(
"\n\n\nBlue Score: " .. BlueCurrentScore ..
"\nRed Score : " .. RedCurrentScore .. "\n\n" ..
"Required to win: " .. ScoreRequiredToWin .. "\n\n", MsgTime, "Mission Status", false):ToAll()
end
function ScoreAddBlue(AddScore)
BlueCurrentScore = BlueCurrentScore + AddScore
MissionStatus(10)
end
function ScoreAddRed(AddScore)
RedCurrentScore = RedCurrentScore + AddScore
MissionStatus(10)
end
local SA10Template = { "SA10_" }
-- Setup SA10 Spawns
SA10Spawns = SPAWN:New( "SA10_" )
:InitLimit( 24, 48 )
:InitHeading(260,280)
:InitRandomizeZones( SA10ZoneTable )
:InitRandomizeTemplate( SA10Template )
:SpawnScheduled( 500, .2 )
-- Different Schedulers are configured for different senarios. Ground Shelling, Low Air Shelling, and High Air Shelling.
-- This shelling works independantly of the actual arty units above.
-- Example:
-- ShellingScheduler = SCHEDULER:New(SchedulerObject,SchedulerFunction,SchedulerArguments,Start,Repeat,RandomizeFactor,Stop)
-- Setup Shelling Zones
local BombZone1 = ZONE_POLYGON:New("BombZone1", GROUP:FindByName( "BombZone1"))
local HighAirShellingZone = ZONE:New("HIGH AIR SHELLING ZONE")
GroundShellingScheduler = SCHEDULER:New( nil,
function()
Exp_Strength = math.random(300, 1000)
Exp_Zone = BombZone1
Blast_Location = Exp_Zone:GetRandomVec2()
Explode = COORDINATE:NewFromVec2( Blast_Location,0)
Explode:Explosion( Exp_Strength )
end, {}, 10, 15, .5
)
AirLowShellingScheduler = SCHEDULER:New( nil,
function()
Exp_Strength = math.random(300, 700)
Exp_Alt = math.random(50, 500)
Exp_Zone = BombZone1
Blast_Location = Exp_Zone:GetRandomVec2()
Explode = COORDINATE:NewFromVec2( Blast_Location, Exp_Alt)
Explode:Explosion( Exp_Strength )
end, {}, 10, 1, .2
)
-- HighAirShellingScheduler = SCHEDULER:New( nil,
--
-- function()
--
-- Exp_Strength = math.random(300, 700)
-- Exp_Alt = math.random(50, 15000)
-- Exp_Zone = HighAirShellingZone
-- Blast_Location = Exp_Zone:GetRandomVec2()
-- Explode = COORDINATE:NewFromVec2( Blast_Location, Exp_Alt)
-- Explode:Explosion( Exp_Strength )
--
--
-- end, {}, 10, 1, .8
-- )
MonitorWinCondition = SCHEDULER:New( nil,
function()
if BlueCurrentScore >= ScoreRequiredToWin then
MsgTime = 218
MESSAGE:New("NATO Forces have won the day!!\n\nMission will restart shortly.\n\n", MsgTime, "Winner!", true):ToAll()
MissionStatus(MsgTime)
MsgScorePercent(MsgTime)
trigger.action.setUserFlag(66, true)
end
if RedCurrentScore >= ScoreRequiredToWin then
MsgTime = 218
MESSAGE:New("Russian Forces have won the day!!\n\nMission will restart shortly.\n\n", MsgTime, "Winner!", true):ToAll()
MissionStatus(MsgTime)
MsgScorePercent(MsgTime)
trigger.action.setUserFlag(66, true)
end
end, {}, 10, 1, 0
)
function MsgScorePercent(MsgTime)
MESSAGE:New("\n\n\nRed:\n" ..
"------Blue Shot Down: " .. StatBlueCAPDead .. "%\n\n" ..
"Blue:\n" ..
"------Red Shot Down: " .. StatRedCAPDead .. "%\n" ..
"------Blue Crates Moved: " .. StatBlueCratesMoved .. "%\n" ..
"------Blue Rescues: " .. StatBlueRescued .. "%\n\n", MsgTime, "Stat Breakdown Percentages", false):ToAll()
end
SEAD_RU_SAM_Defenses = SEAD:New( {
'SA10_#001',
'SA10_#002',
'SA10_#003',
'SA10_#004',
'RU_AAA #001',
'RU_AAA #002',
'RU_AAA #003',
'RU_AAA #004',
'RU_AAA #005',
'RED EWR #003'
} )
-----------Spawn AWACS------------------------------
Spawn_BlueEWR = SPAWN:New("BLUE EWR"):InitLimit( 1, 50 )
:InitRepeatOnEngineShutDown()
:InitCleanUp(120)
:SpawnScheduled(300,.3)
Spawn_RedEWR = SPAWN:New("RED EWR"):InitLimit( 1, 50 )
:InitRepeatOnEngineShutDown()
:InitCleanUp(120)
:SpawnScheduled(300,.4)
Spawn_Blue135 = SPAWN:New("Shell SHL 42 X 253"):InitLimit( 1, 50 )
:InitRepeatOnEngineShutDown()
:InitCleanUp(120)
:SpawnScheduled(300,.3)
Spawn_Blue135MPRS = SPAWN:New("Texaco TEX 41 X 252"):InitLimit( 1, 50 )
:InitRepeatOnEngineShutDown()
:InitCleanUp(120)
:SpawnScheduled(300,.3)
--Setup the BLUEA2A dispatcher, and initialize it.
BLUEBorderZone = ZONE_POLYGON:New( "BLUE BORDER", GROUP:FindByName( "BLUE BORDER" ) )
BLUEA2ADispatcher = AI_A2A_GCICAP:New( { "BLUE EWR" }, { "FIGHTER SWEEP BLUE" }, { "BLUE BORDER" }, 1 )
BLUEA2ADispatcher:SetDefaultLandingAtRunway()
BLUEA2ADispatcher:SetDefaultTakeoffInAir()
BLUEA2ADispatcher:SetBorderZone( BLUEBorderZone )
BLUEA2ADispatcher:SetTacticalDisplay(false)
BLUEA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
BLUEA2ADispatcher:SetRefreshTimeInterval( 300 )
--Setup the RedA2A dispatcher, and initialize it.
CCCPBorderZone = ZONE_POLYGON:New( "RED BORDER", GROUP:FindByName( "RED BORDER" ) )
RedA2ADispatcher = AI_A2A_GCICAP:New( { "RED EWR" }, { "FIGHTER SWEEP RED" }, { "RED BORDER" }, 2 )
RedA2ADispatcher:SetDefaultLandingAtRunway()
RedA2ADispatcher:SetDefaultTakeoffInAir()
RedA2ADispatcher:SetBorderZone( CCCPBorderZone )
RedA2ADispatcher:SetTacticalDisplay(false)
RedA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
RedA2ADispatcher:SetRefreshTimeInterval( 300 )
--Setup the VazianiDispatcher and initialize it.
VazianiBorderZone = ZONE_POLYGON:New( "VAZIANI DEFENSE ZONE", GROUP:FindByName( "VAZIANI DEFENSE ZONE" ) )
VazianiDispatcher = AI_A2A_GCICAP:New( { "RED EWR" }, { "FIGHTER SWEEP RED" }, { "VAZIANI DEFENSE ZONE" }, 0 )
VazianiDispatcher:SetDefaultLandingAtRunway()
VazianiDispatcher:SetDefaultTakeoffInAir()
VazianiDispatcher:SetBorderZone( VazianiBorderZone )
VazianiDispatcher:SetTacticalDisplay(false)
VazianiDispatcher:SetDefaultFuelThreshold( 0.20 )
VazianiDispatcher:SetRefreshTimeInterval( 60 )
VazianiDispatcher:SetDefaultOverhead(2)
--Setup the Kutasi Dispatcher and initialize it.
KutasiBorderZone = ZONE_POLYGON:New( "KUTASI DEFENSE ZONE", GROUP:FindByName( "KUTASI DEFENSE ZONE" ) )
KutasiDispatcher = AI_A2A_GCICAP:New( { "BLUE EWR" }, { "FIGHTER SWEEP BLUE" }, { "KUTASI DEFENSE ZONE" }, 0 )
KutasiDispatcher:SetDefaultLandingAtRunway()
KutasiDispatcher:SetDefaultTakeoffInAir()
KutasiDispatcher:SetBorderZone( KutasiBorderZone )
KutasiDispatcher:SetTacticalDisplay(false)
KutasiDispatcher:SetDefaultFuelThreshold( 0.20 )
KutasiDispatcher:SetRefreshTimeInterval( 60 )
KutasiDispatcher:SetDefaultOverhead(2)
-- Random RU Troop Zones
local T1Z = ZONE_POLYGON:New("RU_TROOPS_ZONE_1", GROUP:FindByName("RU_TROOPS_ZONE_1"))
local TroopZoneTable = { T1Z, T1Z, T1Z, T1Z, T1Z, BombZone1 }
local TroopTemplate = { "RU_TROOPS #001", "RU_TROOPS #002", "RU_TROOPS #003", "RU_TROOPS #004" }
RU_TroopSpawns_Initial = SPAWN:New("Troops")
:InitLimit(150, 1000)
:InitHeading(290, 250)
:InitRandomizeTemplate( TroopTemplate )
:InitRandomizeZones( TroopZoneTable )
:SpawnScheduled( 600, .2 )
-----------US Troops------------------------------
SpawnUSTroops1 = SPAWN:New("US_INFANTRY #001")
:InitLimit( 10, 500 )
:SpawnScheduled(120, .1)
:InitRandomizeRoute( 1, 1, 800)
:InitCleanUp(120)
SpawnUSTroops2 = SPAWN:New("US_INFANTRY #002")
:InitLimit( 10, 500 )
:SpawnScheduled(120, .3)
:InitRandomizeRoute( 1, 1, 800)
:InitCleanUp(120)
SpawnUSTroops3 = SPAWN:New("US_INFANTRY #003")
:InitLimit( 10, 500 )
:SpawnScheduled(120, .2)
:InitRandomizeRoute( 1, 1, 800)
:InitCleanUp(120)

View File

@ -0,0 +1,37 @@
weapRestrict = {}
weapRestrict.playerTakeOff ={}
weapRestrict.weapon2BAN={"weapons.bombs.RN-24","weapons.bombs.RN-28"}
function weapRestrict.playerTakeOff:onEvent(e)
if e.id == world.event.S_EVENT_TAKEOFF and e.initiator then
local playerGroup = e.initiator:getGroup()
local playerGroupID = playerGroup:getID()
local wCount
local i
local bCount
local bwCount
local checkPayload = e.initiator:getAmmo()
local pUnitPos = e.initiator:getPoint()
local uIdS
uIdS = tostring(playerGroupID)
if checkPayload then
for bCount =1, #checkPayload do
for bwCount = 1, #weapRestrict.weapon2BAN do
if weapRestrict.weapon2BAN[bwCount] == checkPayload[bCount].desc.typeName then
local naughty_player = e.initiator:getPlayerName()
trigger.action.outText("Restricted Weapon detected: " .. checkPayload[bCount].desc.typeName .. ", this weapon is BANNED, ".. naughty_player .. " kicking to spectator", 120)
trigger.action.outText("NukeUser:".. naughty_player, 0.01)
return
end
end
end
end
end
end
world.addEventHandler(weapRestrict.playerTakeOff)

View File

@ -0,0 +1,53 @@
onEngineStart = {}
function onEngineStart:onEvent(event)
if world.event.S_EVENT_BIRTH == event.id and event.initiator:getPlayerName() ~= nil then
local playerGroup = event.initiator:getGroup()
local playerUnit = playerGroup:getUnit(1)
local playerName = playerUnit:getPlayerName()
local playerSide = playerGroup:getCoalition()
local playerID = playerGroup:getID()
local playerAircraft = playerUnit:getTypeName()
local MissionName =
"======[ Fighting 99th - Battle of Gori ]======"
local TeamSpeak =
"Please join our TeamSpeak server @ teamspeak.f99th.com for improved comms and a better mission experience!"
local ObjectiveRed =
"===============[ MISSION OBJECTIVE ]==============\n" ..
"CAP - Keep skies over Gori clear of NATO aircraft.\n\n"
local ObjectiveBlue =
"===============[ MISSION OBJECTIVE ]==============\n" ..
"CAP - Control the airspace above the Gori Valley. Protect CAS and HELO aircraft as the attempt to destroy artillery positions and retrieve medvacs from the city.\n\n" ..
"CAS - Destroy Russian AAA and artillery units surrounding the City of Gori. Clear a path for helo operations as they attempt to rescue our people. Leave no one behind!\n\n" ..
"HELO - CAS and AFAC Helos are available. Fly to the town of Gori, land near the blue smoke zones. Use CDLD F10 Menu to pick up MEDVACS. Fly to the green smoke and unload the troops using the same menu.\n\n"
local SmokeZones =
"=================[ SMOKE ZONES ]================\n" ..
"RED SMOKE : AFAC Targets for CAS.\n" ..
"BLUE SMOKE : PICKUP MEDEVACS FROM THIS LOCATION.\n" ..
"GREEN SMOKE: RETURN MEDEVACS TO THIS LOCATION.\n\n"
local EndBrief = "===============[ END MISSION BRIEF ]==============\n\n"
-- Send appropriate message to each coalition.
if playerSide == coalition.side.BLUE then --blue team
trigger.action.outTextForGroup(playerID, "" .. MissionName .. "\n\n" .. "Welcome to a F99th DCS Server, " .. playerName .. "!" .. "\n\n" .. TeamSpeak .. "\n\n" .. ObjectiveBlue .. SmokeZones .. EndBrief, 120)
end
if playerSide == coalition.side.RED then -- red team
trigger.action.outTextForGroup(playerID, "" .. MissionName .. "\n\n" .. "Welcome to a F99th DCS Server, " .. playerName .. "!" .. "\n\n" .. TeamSpeak .. "\n\n" .. ObjectiveRed .. EndBrief, 120)
end
-- trigger.action.outSoundForGroup(playerID, "l10n/DEFAULT/battlemusic.ogg") -- Damn Cry Babbies
end
end
world.addEventHandler(onEngineStart)

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,176 @@
_SETTINGS:SetPlayerMenuOff()
HQ = GROUP:FindByName( "HQ", "Bravo HQ" )
CommandCenter = COMMANDCENTER:New( HQ, "Bravo" )
Scoring = SCORING:New( "Bunker Busting" )
--------------Random Air Traffic--------------
-- local rat130 = RAT:New("RAT_130")
-- rat130:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- rat130:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- rat130:ContinueJourney()
-- rat130:Spawn(1)
--
-- local ratB52 = RAT:New("RAT_B52")
-- ratB52:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratB52:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratB52:ContinueJourney()
-- ratB52:Spawn(1)
--
-- local ratc17 = RAT:New("RAT_C17")
-- ratc17:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratc17:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratc17:ContinueJourney()
-- ratc17:Spawn(1)
--
-- local ratf117 = RAT:New("RAT_F117")
-- ratf117:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratf117:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratf117:ContinueJourney()
-- ratf117:Spawn(1)
--
-- local ratbch53 = RAT:New("RAT_CH53")
-- ratbch53:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratbch53:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratbch53:ContinueJourney()
-- ratbch53:Spawn(1)
--
-- local ratApache = RAT:New("RAT_APACHE")
-- ratApache:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratApache:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratApache:ContinueJourney()
-- ratApache:Spawn(1)
--
-- local ratCobra = RAT:New("RAT_COBRA")
-- ratCobra:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratCobra:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratCobra:ContinueJourney()
-- ratCobra:Spawn(1)
--
-- local ratF4 = RAT:New("RAT_F4")
-- ratF4:SetDeparture({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratF4:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratF4:ContinueJourney()
-- ratF4:Spawn(1)
--
-- local ratS3b = RAT:New("RAT_S3B")
-- ratS3b:SetDeparture({"Senaki-Kolkhi","Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratS3b:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratS3b:ContinueJourney()
-- ratS3b:Spawn(1)
--
-- local ratHawk = RAT:New("RAT_HAWK")
-- ratHawk:SetDeparture({"Senaki-Kolkhi","Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratHawk:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratHawk:ContinueJourney()
-- ratHawk:Spawn(1)
--
-- local ratC101 = RAT:New("RAT_c101")
-- ratC101:SetDeparture({"Senaki-Kolkhi","Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratC101:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratC101:ContinueJourney()
-- ratC101:Spawn(1)
--
-- local ratL39 = RAT:New("RAT_l39")
-- ratL39:SetDeparture({"Senaki-Kolkhi","Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratL39:SetDestination({"Senaki-Kolkhi", "Senaki-Kolkhi", "Sukhumi-Babushara", "Gudauta", "Sochi-Adler"})
-- ratL39:ContinueJourney()
-- ratL39:Spawn(1)
-----------Spawn AWACS------------------------------
-- -- Refueling
-- Spawn_KC135 = SPAWN:New("KC-135"):InitLimit( 1, 50 )
-- Spawn_KC135:InitRepeatOnLanding()
-- Spawn_KC135:SpawnScheduled(600,.1)
--
-- Spawn_KC130 = SPAWN:New("KC-130"):InitLimit( 1, 50 )
-- Spawn_KC130:InitRepeatOnLanding()
-- Spawn_KC130:SpawnScheduled(600,.2)
------------------- CCCP SEAD Defenses------------------------------
SEAD_RU_SAM_Defenses = SEAD:New( {
'AAA 6 #005',
'AAA 6 #003',
'AAA 6 #004',
'AAA 3',
'AAA 4',
'AAA 5',
'AAA 5 #001',
'AAA #006',
'MISSION 6 DEF #001',
'MISSION 6 DEF #002',
} )
local TemplateTable = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N" }
local M1Z = ZONE_POLYGON:New( "MISSION 1 ZONE", GROUP:FindByName( "MISSION 1 ZONE" ))
local M2Z = ZONE_POLYGON:New( "MISSION 2 ZONE", GROUP:FindByName( "MISSION 2 ZONE" ))
local M3Z = ZONE_POLYGON:New( "MISSION 3 ZONE", GROUP:FindByName( "MISSION 3 ZONE" ))
local M4Z = ZONE_POLYGON:New( "MISSION 4 ZONE", GROUP:FindByName( "MISSION 4 ZONE" ))
local M5Z = ZONE_POLYGON:New( "MISSION 5 ZONE", GROUP:FindByName( "MISSION 5 ZONE" ))
local M6Z = ZONE_POLYGON:New( "MISSION 6 ZONE", GROUP:FindByName( "MISSION 6 ZONE" ))
local ZoneTable = { M1Z, M2Z, M3Z, M4Z, M5Z, M6Z }
Spawn_Vehicle_1 = SPAWN:New( "RU GROUND FORCE" )
:InitLimit( 80, 80 )
:InitRandomizeZones( ZoneTable )
:InitRandomizeTemplate( TemplateTable )
:SpawnScheduled( .1, .2 )
--Setup the BLUEA2A dispatcher, and initialize it.
BLUEBorderZone = ZONE_POLYGON:New( "BLUE BORDER", GROUP:FindByName( "BLUE BORDER" ) )
BLUEA2ADispatcher = AI_A2A_GCICAP:New( { "BLUE EWR" }, { "FIGHTER SWEEP BLUE" }, { "BLUE BORDER" }, 2 )
BLUEA2ADispatcher:SetDefaultLandingAtRunway()
BLUEA2ADispatcher:SetDefaultTakeoffFromParkingCold()
BLUEA2ADispatcher:SetBorderZone( BLUEBorderZone )
BLUEA2ADispatcher:SetTacticalDisplay(false)
BLUEA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
BLUEA2ADispatcher:SetRefreshTimeInterval( 240 )
BLUEA2ADispatcher:SetDefaultOverhead(.25)
BLUEA2ADispatcher:SetDefaultCapLimit(2)
--Setup the RedA2A dispatcher, and initialize it.
CCCPBorderZone = ZONE_POLYGON:New( "RED BORDER", GROUP:FindByName( "RED BORDER" ) )
RedA2ADispatcher = AI_A2A_GCICAP:New( { "RED EWR" }, { "FIGHTER SWEEP RED" }, { "RED BORDER" }, 2 )
RedA2ADispatcher:SetDefaultLandingAtRunway()
RedA2ADispatcher:SetDefaultTakeoffFromParkingCold()
RedA2ADispatcher:SetBorderZone( CCCPBorderZone )
RedA2ADispatcher:SetTacticalDisplay(false)
RedA2ADispatcher:SetDefaultFuelThreshold( 0.20 )
RedA2ADispatcher:SetRefreshTimeInterval( 240 )
RedA2ADispatcher:SetDefaultOverhead(.25)
RedA2ADispatcher:SetDefaultCapLimit(4)
--ADDED 2020 ATIS
--atisGudauta=ATIS:New("Gudauta", 126.50)
--atisGudauta:SetTowerFrequencies({259.000, 130.000})
--atisGudauta:Start(50)
--atisSochi=ATIS:New("Sochi-Adler", 126.00)
--atisSochi:SetTowerFrequencies({256.000, 127.000})
--atisSochi:AddILS(111.10, "6")
--atisSochi:Start(30)
--atisSenaki=ATIS:New("Senaki-Kolkhi", 125.50)
--atisSenaki:SetTowerFrequencies({261.000, 132.000})
--atisSenaki:AddILS(108.90, "9")
--atisSenaki:SetTACAN(31)
--atisSenaki:Start(60)
--atisSukhumi=ATIS:New("Sukhumi-Babushara", 125.00)
--atisSukhumi:SetTowerFrequencies({258.000, 129.000})
--atisSukhumi:Start(20)

View File

@ -0,0 +1,54 @@
onEngineStart = {}
function onEngineStart:onEvent(event)
if world.event.S_EVENT_BIRTH == event.id and event.initiator:getPlayerName() ~= nil then
local playerGroup = event.initiator:getGroup()
local playerUnit = playerGroup:getUnit(1)
local playerName = playerUnit:getPlayerName()
local playerSide = playerGroup:getCoalition()
local playerID = playerGroup:getID()
local playerAircraft = playerUnit:getTypeName()
local MissionName =
"======[ Fighting 99th - Bunker Busting ]======"
local TeamSpeak =
"Please join our TeamSpeak server @ teamspeak.f99th.com for improved comms and a better mission experience!"
local ObjectiveRed =
"===============[ MISSION OBJECTIVE ]==============\n" ..
"U.S. intel has discovered our vast network of Command Bunkers located in the caucus mountains. We've hidden them deep in the valleys and small towns.\n\n" ..
"Your Primary objective is protecting the skies above our bunkers. Work closely with your teammates and focus on attack and AFAC aircraft.\n\n"
local ObjectiveBlue =
"===============[ MISSION OBJECTIVE ]==============\n" ..
"CAP - There is heavy enemy fighter presence over the 6 way points in your NAV systems. We need to keep the skies clear of enemy fighters so that CAS aircraft can destroy the Command Bunkers at each location.\n\n" ..
"CAS - Destroy the Command Bunkers at each of the way points in your NAV systems. Expect random AAA resistance. See the Mission Briefing [ Alt-B ] for image of the Bunker.\n\n" ..
"HELO - CAS and AFAC Helos are available. Help eliminate AAA units around each WP. There are multiple FARPS to take off from and land at for re-arm/re-pair.\n\n"
-- local SmokeZones =
-- "=================[ SMOKE ZONES ]================\n" ..
-- "RED SMOKE : OWNED BY RED FORCES.\n" ..
-- "GREEN SMOKE: EMPTY - READY FOR CAPTURE.\n" ..
-- "BLUE SMOKE : OWNED BY U.S. FORCES.\n\n" ..
local EndBrief = "===============[ END MISSION BRIEF ]==============\n\n"
-- Send appropriate message to each coalition.
if playerSide == coalition.side.BLUE then --blue team
trigger.action.outTextForGroup(playerID, "" .. MissionName .. "\n\n" .. "Welcome to a F99th DCS Server, " .. playerName .. "!" .. "\n\n" .. TeamSpeak .. "\n\n" .. ObjectiveBlue .. EndBrief, 120)
end
if playerSide == coalition.side.RED then -- red team
trigger.action.outTextForGroup(playerID, "" .. MissionName .. "\n\n" .. "Welcome to a F99th DCS Server, " .. playerName .. "!" .. "\n\n" .. TeamSpeak .. "\n\n" .. ObjectiveRed .. EndBrief, 120)
end
-- trigger.action.outSoundForGroup(playerID, "l10n/DEFAULT/battlemusic.ogg") -- Damn Cry Babbies
end
end
world.addEventHandler(onEngineStart)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

View File

@ -0,0 +1,464 @@
--Verion 1.4.2
ProviderChecker = {}
-- Best to leave this on for the most part.
ProviderChecker.TankerFuelChecking = true
-- Only necessary to set if you don't set them to invicible
ProviderChecker.TankerKilledTimer = 60
-- Good to set even if you are using Fuel Check, in case it lands for some weird AI reason.
ProviderChecker.TankerRTBTimer = 60
-- If you want it to respawn when fuel state reaches 20%, instead of having it RTB all the way to base.
ProviderChecker.AWACFuelChecking = true
-- Killed Timer is the time delay to respawn for killed in seconds. Minimum of 5 seconds, anything less will default to 5 seconds
ProviderChecker.AWACKilledTimer = 600
-- RTB Timer is time delay to respawn from landing. Can be 0
ProviderChecker.AWACRTBTimer = 60
ProviderChecker.AWACSeventHandler = {}
ProviderChecker.TankereventHandler = {}
ProviderChecker.TankerTable = {}
ProviderChecker.AwacsTable = {}
ProviderChecker.TankerRefuelingCountBlueFor = 0
ProviderChecker.TankerRefuelingCountRedFor = 0
--Tankers waiting for respawn
ProviderChecker.TankerStandbyTable= {}
function ProviderChecker.TankerRadioStatus(radio_coalition)
local coalition_side = ""
if radio_coalition == 1 then
coalition_side = coalition_side .. "red"
elseif radio_coalition == 2 then
coalition_side = coalition_side .. "blue"
end
local tanker_status_start = "===========================\n"
local tanker_status_end = "==========================="
local tanker_status_mid = ""
for fueler, params in pairs(ProviderChecker.TankerTable) do
if params.coalition == coalition_side then
if params.has_tasking then
local m_tanker_id = Group.getByName(params.name)
local m_tanker_radio = params.radio_freqeuncy
local m_tanker_units = m_tanker_id:getUnits()
local m_tanker_unit = m_tanker_units[1]
local m_tanker_callsign = m_tanker_unit:getCallsign()
local m_tanker_channel = params.channel
local m_tanker_mode = params.modeChannel
local m_tanker_ac_type = m_tanker_unit:getTypeName()
tanker_status_mid = tanker_status_mid .. "Tanker: " .. m_tanker_callsign .. " Radio: " .. m_tanker_radio ..
" TACAN: " .. m_tanker_channel .. m_tanker_mode .. " Aircraft: " .. m_tanker_ac_type .. "\n"
else
local m_tanker_id = Group.getByName(params.name)
local m_tanker_radio = params.radio_freqeuncy
local m_tanker_units = m_tanker_id:getUnits()
local m_tanker_unit = m_tanker_units[1]
local m_tanker_callsign = m_tanker_unit:getCallsign()
tanker_status_mid = tanker_status_mid .. "Tanker: " .. m_tanker_callsign .. " Radio: " .. m_tanker_radio ..
" TACAN: N/A" .. " Aircraft: " .. m_tanker_ac_type .. "\n"
end
end
end
local out_message = tanker_status_start .. tanker_status_mid .. tanker_status_end
trigger.action.outTextForCoalition(radio_coalition, out_message, 30, true)
end
function ProviderChecker.RefreshTACAN(_nil,time)
for fueler, params in pairs(ProviderChecker.TankerTable) do
if params.has_tasking then
local tanker_id = Group.getByName(params.name)
if tanker_id then
local tanker_controller = tanker_id:getController()
local tanker_tacan = {
id = 'ActivateBeacon',
params = {
["type"] = params.type,
["AA"] = params.AA,
["unitId"] = tanker_id,
["modeChannel"] = params.modeChannel,
["channel"] = params.channel,
["system"] = params.system,
["callsign"] = params.callsign,
["bearing"] = params.bearing,
["frequency"] = params.frequency,
}
}
tanker_controller:setCommand(tanker_tacan)
end
end
end
return time + 10
end
--Will Eventually consoldate these to one function. Pass type (awacs or tanker) as argument.
function ProviderChecker.SpawnNewTanker(_unit, time)
--respawn uses the same name, and tankers are tracked by name instead of ID. Will change this for AWACS in future update.
NewGroup = mist.respawnGroup(_unit,true)
NewName = NewGroup.units[1].name
NewUnit = Unit.getByName(NewName)
tanker_controller = NewUnit:getController()
for tanker, params in pairs(ProviderChecker.TankerTable) do
if params.name == NewName then
local frequency = tonumber(params.radio_freqeuncy) * 1000000
SetFrequency = {
id = 'SetFrequency',
params = {
frequency = frequency,
modulation = 0,
}
}
tanker_controller:setCommand(SetFrequency)
trigger.action.outTextForCoalition(NewUnit:getCoalition(),"Tanker " ..NewUnit:getCallsign().. " is back online!", 10, false)
end
end
return nil
end
function ProviderChecker.SpawnNewAwacs(_unit, time)
NewGroup = mist.respawnGroup(_unit,true)
NewName = NewGroup.units[1].name
NewUnit = Unit.getByName(NewName)
awacs_controller = NewUnit:getController()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if params.name == NewName then
local frequency = tonumber(params.radio_freqeuncy) * 1000000
SetFrequency = {
id = 'SetFrequency',
params = {
frequency = frequency,
modulation = 0,
}
}
awacs_controller:setCommand(SetFrequency)
trigger.action.outTextForCoalition(NewUnit:getCoalition(),"AWACS " .. NewUnit:getCallsign() .. " is back online!", 10, false)
end
end
return nil
end
--due to how scheduled functions work, I need to create a class to handle this. Will upgrade later next revision.
function ProviderChecker.checkTankerFuel(_nil,time)
for fueler, params in pairs(ProviderChecker.TankerTable) do
local fueler_group_name = params.name
local fueler_group = Group.getByName(fueler_group_name)
if fueler_group then
local fueler_units = fueler_group:getUnits()
local fueler_id = fueler_units[1]
local fueler_fuel = fueler_id:getFuel()
if fueler_fuel < 0.20 then
if params.coalition == "blue" then
if ProviderChecker.TankerRefuelingCountBlueFor < 1 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, fueler_group_name, timer.getTime() + 5)
elseif ProviderChecker.TankerRefuelingCountBlueFor > 0 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " fuel at less than 20%. Will respawn when no aircraft are refueling",
10
)
end
elseif params.coalition == "red" then
if ProviderChecker.TankerRefuelingCountRedFor < 1 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, fueler_group_name, timer.getTime() + 5)
elseif ProviderChecker.TankerRefuelingCountRedFor > 0 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " fuel at less than 20%. Will respawn when no aircraft are refueling",
10
)
end
end
elseif fueler_fuel < 0.22 then
trigger.action.outTextForCoalition(
fueler_id:getCoalition(),
"Tanker " .. fueler_id:getCallsign() .. " at 25%. Will respawn at 20% if no aircraft are refueling",
10
)
end
end
end
return time + 120
end
function ProviderChecker.checkAWACSFuel(_nil,time)
--Due to the respawn and scheduledFunction limitations, Checking Refuel requires imediate respawn, else it would loop to respawn again and again.
for awacs, params in pairs(ProviderChecker.AwacsTable) do
local awacs_group_name = params.name
local awacs_group = Group.getByName(awacs_group_name)
if awacs_group then
local awacs_units = awacs_group:getUnits()
local awacs_id = awacs_units[1]
local awacs_fuel = awacs_id:getFuel()
if awacs_fuel < 0.30 then
if params.coalition == "blue" then
trigger.action.outTextForCoalition(
awacs_id:getCoalition(),
"AWACS " .. awacs_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, awacs_group_name, timer.getTime() + 5)
elseif params.coalition == "red" then
trigger.action.outTextForCoalition(
awacs_id:getCoalition(),
"AWACS " .. awacs_id:getCallsign() .. " Is out of Fuel. Respawning in 5 seconds",
10
)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, awacs_group_name, timer.getTime() + 5)
end
end
end
end
return time + 120
end
function ProviderChecker.TankereventHandler:onEvent(_event)
-- Adds up the number of units taking fuel because the event handler is based on unit taking fuel, not giving fuel
-- Solution to this later will be check nearest unit of type tanker and create a "class" out of that.
if (_event.id == 7) and _event.initiator then
local refueling_unit = _event.initiator
local refueling_unit_coalition = refueling_unit:getCoalition()
if refueling_unit_coalition == 2 then
ProviderChecker.TankerRefuelingCountBlueFor = ProviderChecker.TankerRefuelingCountBlueFor + 1
elseif refueling_unit_coalition == 1 then
ProviderChecker.TankerRefuelingCountRedFor = ProviderChecker.TankerRefuelingCountRedFor + 1
end
end
-- Removes the number of units taking fuel
if (_event.id == 14) and _event.initiator then
local refueling_unit = _event.initiator
local refueling_unit_coalition = refueling_unit:getCoalition()
if refueling_unit_coalition == 2 then
ProviderChecker.TankerRefuelingCountBlueFor = ProviderChecker.TankerRefuelingCountBlueFor - 1
elseif refueling_unit_coalition == 1 then
ProviderChecker.TankerRefuelingCountRedFor = ProviderChecker.TankerRefuelingCountRedFor - 1
end
end
-- Checks if tanker landed.
if (_event.id == 4) and _event.initiator then
if _event.initiator then
local LandedUnit = _event.initiator
local LandedUnitName = LandedUnit:getName()
local LandedUnitInfo = Unit.getGroup(LandedUnit)
local LandedUnitGroupName = LandedUnitInfo:getName()
for fueler, params in pairs(ProviderChecker.TankerTable) do
if LandedUnitGroupName == params.name then
if ProviderChecker.TankerRTBTimer > 5 then
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " Landed - Respawning in " .. (ProviderChecker.TankerRTBTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, LandedUnitGroupName, timer.getTime() + ProviderChecker.TankerRTBTimer)
else
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " Landed - Respawning", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, LandedUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
if (_event.id == 5) and _event.initiator then
local DeadUnit = _event.initiator
local DeadUnitName = DeadUnit:getName()
local DeadUnitInfo = Unit.getGroup(DeadUnit)
local DeadUnitGroupName = DeadUnitInfo:getName()
for fueler, params in pairs(ProviderChecker.TankerTable) do
if DeadUnitGroupName == params.name then
if ProviderChecker.TankerKilledTimer > 5 then
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"Tanker " .. DeadUnit:getCallsign() .. " has crashed! Replacement will be on station in " .. (ProviderChecker.TankerKilledTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, DeadUnitGroupName, timer.getTime() + ProviderChecker.TankerKilledTimer)
else
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"Tanker " .. LandedUnit:getCallsign() .. " has crashed! Replacement will be on station in 5 Seconds", 10,false)
timer.scheduleFunction(ProviderChecker.SpawnNewTanker, DeadUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
function ProviderChecker.AWACSeventHandler:onEvent(_event)
-- Checks if tanker landed.
if (_event.id == 4) and _event.initiator then
local LandedUnit = _event.initiator
local LandedUnitName = LandedUnit:getName()
local LandedUnitInfo = Unit.getGroup(LandedUnit)
local LandedUnitGroupName = LandedUnitInfo:getName()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if LandedUnitGroupName == params.name then
if ProviderChecker.AWACRTBTimer > 5 then
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"AWACS " .. LandedUnit:getCallsign() .. " Landed - Respawning in " .. (ProviderChecker.AWACRTBTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, LandedUnitGroupName, timer.getTime() + ProviderChecker.AWACRTBTimer)
else
trigger.action.outTextForCoalition(
LandedUnit:getCoalition(),
"AWACS " .. LandedUnit:getCallsign() .. " Landed - Respawning", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, LandedUnitGroupName, timer.getTime() + 5)
end
end
end
end
if (_event.id == 5) and _event.initiator then
local DeadUnit = _event.initiator
local DeadUnitName = DeadUnit:getName()
local DeadUnitInfo = Unit.getGroup(DeadUnit)
local DeadUnitGroupName = DeadUnitInfo:getName()
for awacs, params in pairs(ProviderChecker.AwacsTable) do
if DeadUnitGroupName == params.name then
if ProviderChecker.AWACKilledTimer > 5 then
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"AWACS " .. DeadUnit:getCallsign() .. " has been shot down! Replacement will be on station in " .. (ProviderChecker.AWACKilledTimer / 60) .. " minutes", 10, false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, DeadUnitGroupName, timer.getTime() + ProviderChecker.AWACKilledTimer)
else
trigger.action.outTextForCoalition(
DeadUnit:getCoalition(),
"AWACS " .. DeadUnit:getCallsign() .. " has been shot down! Replacement will be on station in 5 Seconds", 10,false)
timer.scheduleFunction(ProviderChecker.SpawnNewAwacs, DeadUnitGroupName, timer.getTime() + 5)
end
end
end
end
end
-- function ProviderChecker.ServiceCheckerMsg()
function ProviderChecker.GetServicesList()
-- You can -only- get TACAN data from the mission file. So since MIST respawn uses the same TACANs on respawn,
-- I can pull from the mission file and refresh that way
for coa_name, coa_data in pairs(env.mission.coalition) do
if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then
if coa_data.country then --there is a country table
for cntry_id, cntry_data in pairs(coa_data.country) do
for obj_type_name, obj_type_data in pairs(cntry_data) do
if obj_type_name == "plane" then
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group!
for group_num, group_data in pairs(obj_type_data.group) do
group_Id = group_data.groupId
group_radio = group_data.frequency
group_name = env.getValueDictByKey(group_data.name)
if group_data.task == "Refueling" then
if group_data["units"][1]["type"] ~= "IL-78M" then
if group_data.tasks and group_data.tasks.parmas then
for tasks_id, tasks_data in pairs(group_data.tasks) do
if tasks_data.params and tasks_data.params.action and tasks_data.params.action.params then
tasks_data.params.action.params["coalition"] = coa_name
tasks_data.params.action.params["radio_freqeuncy"] = group_radio
tasks_data.params.action.params["name"] = group_name
tasks_data.params.action.params["has_tasking"] = true
ProviderChecker.TankerTable[group_Id] = tasks_data.params.action.params
end --if task_data.params
end -- for tasks_id, tasks_data
-- Because for some weird ass reason, the tasks will be blank so I need to pull them from waypoints instead
elseif group_data.route.points then
for point_id, point_params in pairs(group_data.route.points) do
if point_params.task then
for tasks_id, tasks_data in pairs(point_params.task.params.tasks) do
if tasks_data.params and tasks_data.params.action and tasks_data.params.action.id == "ActivateBeacon" then
tasks_data.params.action.params["coalition"] = coa_name
tasks_data.params.action.params["radio_freqeuncy"] = group_radio
tasks_data.params.action.params["name"] = group_name
tasks_data.params.action.params["has_tasking"] = true
ProviderChecker.TankerTable[group_Id] = tasks_data.params.action.params
end -- if tasks_data.params and
end -- for tasks_id, tasks_data in
end --if point_params.task
end -- for point_id, point_params
end -- if group_data.tasks then
else
ProviderChecker.TankerTable[group_Id] = {}
ProviderChecker.TankerTable[group_Id]["coalition"] = coa_name
ProviderChecker.TankerTable[group_Id]["radio_freqeuncy"] = group_radio
ProviderChecker.TankerTable[group_Id]["name"] = group_name
ProviderChecker.TankerTable[group_Id]["has_tasking"] = false
end -- group_data["units"][1]["type"] ~= "IL-78M" then
elseif group_data.task == "AWACS" then
ProviderChecker.AwacsTable[group_Id] = {}
ProviderChecker.AwacsTable[group_Id]["coalition"] = coa_name
ProviderChecker.AwacsTable[group_Id]["radio_freqeuncy"] = group_radio
ProviderChecker.AwacsTable[group_Id]["name"] = group_name
ProviderChecker.AwacsTable[group_Id]["modeChannel"] = "N/A"
ProviderChecker.AwacsTable[group_Id]["callsign"] = "N/A"
end --if group_data.tas == "Refueling then"
end --for group_num, group_data in pairs(obj_type_data.group) do
end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then
end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then
end --for obj_type_name, obj_type_data in pairs(cntry_data) do
end --for cntry_id, cntry_data in pairs(coa_data.country) do
end --if coa_data.country then --there is a country table
end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then
end --for coa_name, coa_data in pairs(mission.coalition) do
end
world.addEventHandler(ProviderChecker.AWACSeventHandler)
env.info("F99th AWACS Checker event handler added")
world.addEventHandler(ProviderChecker.TankereventHandler)
env.info("F99th Tanker Checker event handler added")
ProviderChecker.GetServicesList()
timer.scheduleFunction(ProviderChecker.RefreshTACAN, nil, timer.getTime() + 10)
missionCommands.addCommandForCoalition(2,"Get Tanker Info",nil, ProviderChecker.TankerRadioStatus,2)
missionCommands.addCommandForCoalition(1,"Get Tanker Info",nil, ProviderChecker.TankerRadioStatus,1)
if ProviderChecker.TankerFuelChecking then
timer.scheduleFunction(ProviderChecker.checkTankerFuel, nil, timer.getTime() + 120)
end
if ProviderChecker.AWACFuelChecking then
timer.scheduleFunction(ProviderChecker.checkAWACSFuel, nil, timer.getTime() + 120)
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
-- ************** ADD-ON AAA SPAWNABLE CRATES ******************
-- Weights must be unique as we use the weight to change the cargo to the correct unit
-- when we unpack
--
do
local _addCrates = {
["AA Crates"] = {
{ weight = 421, desc = "AAA Vulcan", unit = "Vulcan", side = 2, cratesRequired = 1 },
{ weight = 422, desc = "AAA Gepard", unit = "Gepard", side = 2, cratesRequired = 2 },
{ weight = 423, desc = "AAA ZU-23", unit = "Ural-375 ZU-23", side = 1, cratesRequired = 1 },
{ weight = 424, desc = "AAA ZSU-23-4 Shilka", unit = "ZSU-23-4 Shilka", side = 1, cratesRequired = 2 },
},
}
-- add extra crate options
for _subMenuName, _crates in pairs(_addCrates) do
for _, _crate in pairs(_crates) do
-- add crate to the menu table
table.insert(ctld.spawnableCrates[_subMenuName], _crate)
-- add crate to the lookup table
ctld.crateLookupTable[tostring(_crate.weight)] = _crate
end
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,23 @@
-- ************** ADD-ON AAA SPAWNABLE CRATES ******************
-- Weights must be unique as we use the weight to change the cargo to the correct unit
-- when we unpack
--
do
local _addCrates = {
["Ground Forces"] = {
{ weight = 300, desc = "MBT M1A2 Abrams", unit = "M-1 Abrams", side = 2 },
{ weight = 305, desc = "MBT T-72B", unit = "T-72B", side = 1 },
},
}
-- add extra crate options
for _subMenuName, _crates in pairs(_addCrates) do
for _, _crate in pairs(_crates) do
-- add crate to the menu table
table.insert(ctld.spawnableCrates[_subMenuName], _crate)
-- add crate to the lookup table
ctld.crateLookupTable[tostring(_crate.weight)] = _crate
end
end
end

Some files were not shown because too many files have changed in this diff Show More