mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
Inital Commit
This commit is contained in:
commit
949e19c61a
BIN
AllahuAkbar.ogg
Normal file
BIN
AllahuAkbar.ogg
Normal file
Binary file not shown.
1864
CSAR_Custom.lua
Normal file
1864
CSAR_Custom.lua
Normal file
File diff suppressed because it is too large
Load Diff
5
DCS_Afgainistan/.buildpath
Normal file
5
DCS_Afgainistan/.buildpath
Normal 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
17
DCS_Afgainistan/.project
Normal 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>
|
||||||
2
DCS_Afgainistan/.settings/org.eclipse.ldt.prefs
Normal file
2
DCS_Afgainistan/.settings/org.eclipse.ldt.prefs
Normal 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.
Binary file not shown.
400
DCS_Afgainistan/Insurgent_Sandstorm/Moose_CTLD.lua
Normal file
400
DCS_Afgainistan/Insurgent_Sandstorm/Moose_CTLD.lua
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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)
|
||||||
@ -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)
|
||||||
@ -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)
|
||||||
@ -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()
|
||||||
142
DCS_Afgainistan/Insurgent_Sandstorm/Moose_Intel.lua
Normal file
142
DCS_Afgainistan/Insurgent_Sandstorm/Moose_Intel.lua
Normal 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)
|
||||||
BIN
DCS_Afgainistan/Insurgent_Sandstorm/test.miz
Normal file
BIN
DCS_Afgainistan/Insurgent_Sandstorm/test.miz
Normal file
Binary file not shown.
4
DCS_Afgainistan/src/main.lua
Normal file
4
DCS_Afgainistan/src/main.lua
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
local function main()
|
||||||
|
|
||||||
|
end
|
||||||
|
main()
|
||||||
5
DCS_Caucasus/.buildpath
Normal file
5
DCS_Caucasus/.buildpath
Normal 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
18
DCS_Caucasus/.project
Normal 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>
|
||||||
2
DCS_Caucasus/.settings/org.eclipse.ldt.prefs
Normal file
2
DCS_Caucasus/.settings/org.eclipse.ldt.prefs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Grammar__default_id=lua-5.1
|
||||||
|
eclipse.preferences.version=1
|
||||||
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-1.0.0.miz
Normal file
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-1.0.0.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-1.0.1.miz
Normal file
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-1.0.1.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-Mig15vsF86-1.0.0.miz
Normal file
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-Mig15vsF86-1.0.0.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-WWII-1.0.0.miz
Normal file
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar-WWII-1.0.0.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar.miz
Normal file
BIN
DCS_Caucasus/F99th-AirWar/F99th-TheAirWar.miz
Normal file
Binary file not shown.
59
DCS_Caucasus/F99th-AirWar/moose_airwar.lua
Normal file
59
DCS_Caucasus/F99th-AirWar/moose_airwar.lua
Normal 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
|
||||||
|
|
||||||
59
DCS_Caucasus/F99th-AirWar/moose_airwar_15vs86.lua
Normal file
59
DCS_Caucasus/F99th-AirWar/moose_airwar_15vs86.lua
Normal 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
|
||||||
|
|
||||||
91
DCS_Caucasus/F99th-AirWar/moose_airwar_WWII.lua
Normal file
91
DCS_Caucasus/F99th-AirWar/moose_airwar_WWII.lua
Normal 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)
|
||||||
4
DCS_Caucasus/F99th-Battle of Gori/.buildpath
Normal file
4
DCS_Caucasus/F99th-Battle of Gori/.buildpath
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<buildpath>
|
||||||
|
<buildpathentry combineaccessrules="false" kind="prj" path="/Moose_Framework"/>
|
||||||
|
</buildpath>
|
||||||
18
DCS_Caucasus/F99th-Battle of Gori/.project
Normal file
18
DCS_Caucasus/F99th-Battle of Gori/.project
Normal 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>
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
Grammar__default_id=lua-5.1
|
||||||
|
eclipse.preferences.version=1
|
||||||
6084
DCS_Caucasus/F99th-Battle of Gori/CTLD_BattleOfGori.lua
Normal file
6084
DCS_Caucasus/F99th-Battle of Gori/CTLD_BattleOfGori.lua
Normal file
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.
BIN
DCS_Caucasus/F99th-Battle of Gori/F99thMissionBackground.png
Normal file
BIN
DCS_Caucasus/F99th-Battle of Gori/F99thMissionBackground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 395 KiB |
464
DCS_Caucasus/F99th-Battle of Gori/F99thServiceMonitorV1.4.2.lua
Normal file
464
DCS_Caucasus/F99th-Battle of Gori/F99thServiceMonitorV1.4.2.lua
Normal 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
|
||||||
BIN
DCS_Caucasus/F99th-Battle of Gori/Mash theme song.ogg
Normal file
BIN
DCS_Caucasus/F99th-Battle of Gori/Mash theme song.ogg
Normal file
Binary file not shown.
330
DCS_Caucasus/F99th-Battle of Gori/Moose_BattleofGori.lua
Normal file
330
DCS_Caucasus/F99th-Battle of Gori/Moose_BattleofGori.lua
Normal 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@ -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)
|
||||||
53
DCS_Caucasus/F99th-Battle of Gori/OnBirthMessage.lua
Normal file
53
DCS_Caucasus/F99th-Battle of Gori/OnBirthMessage.lua
Normal 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)
|
||||||
BIN
DCS_Caucasus/F99th-Battle of Gori/OnBirthMessage.zip
Normal file
BIN
DCS_Caucasus/F99th-Battle of Gori/OnBirthMessage.zip
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Battle of Gori/battlemusic.ogg
Normal file
BIN
DCS_Caucasus/F99th-Battle of Gori/battlemusic.ogg
Normal file
Binary file not shown.
2766
DCS_Caucasus/F99th-Battle of Gori/fac2_ArtyMarkRecceZone_v2_1_20.lua
Normal file
2766
DCS_Caucasus/F99th-Battle of Gori/fac2_ArtyMarkRecceZone_v2_1_20.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
DCS_Caucasus/F99th-Battle of Gori/logisticUnit.png
Normal file
BIN
DCS_Caucasus/F99th-Battle of Gori/logisticUnit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
6822
DCS_Caucasus/F99th-Battle of Gori/mist_4_3_74.lua
Normal file
6822
DCS_Caucasus/F99th-Battle of Gori/mist_4_3_74.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
DCS_Caucasus/F99th-Bunker Busting/F99th-Bunker Busting 1.9.8.miz
Normal file
BIN
DCS_Caucasus/F99th-Bunker Busting/F99th-Bunker Busting 1.9.8.miz
Normal file
Binary file not shown.
Binary file not shown.
BIN
DCS_Caucasus/F99th-Bunker Busting/F99th-Bunker Busting 1.9.9.miz
Normal file
BIN
DCS_Caucasus/F99th-Bunker Busting/F99th-Bunker Busting 1.9.9.miz
Normal file
Binary file not shown.
Binary file not shown.
176
DCS_Caucasus/F99th-Bunker Busting/Moose_BunkerBusting.T.H.X2.lua
Normal file
176
DCS_Caucasus/F99th-Bunker Busting/Moose_BunkerBusting.T.H.X2.lua
Normal 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)
|
||||||
54
DCS_Caucasus/F99th-Bunker Busting/OnBirthMessage.lua
Normal file
54
DCS_Caucasus/F99th-Bunker Busting/OnBirthMessage.lua
Normal 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)
|
||||||
BIN
DCS_Caucasus/F99th-Bunker Busting/beeps-and-clicks.wav
Normal file
BIN
DCS_Caucasus/F99th-Bunker Busting/beeps-and-clicks.wav
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Bunker Busting/bunker.png
Normal file
BIN
DCS_Caucasus/F99th-Bunker Busting/bunker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
2766
DCS_Caucasus/F99th-Bunker Busting/fac2_ArtyMarkRecceZone_v2_1_20.lua
Normal file
2766
DCS_Caucasus/F99th-Bunker Busting/fac2_ArtyMarkRecceZone_v2_1_20.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
DCS_Caucasus/F99th-Canyon Run 1.2.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Canyon Run 1.2.2.miz
Normal file
Binary file not shown.
6100
DCS_Caucasus/F99th-Canyon Run/CTLD_CanyonRun.lua
Normal file
6100
DCS_Caucasus/F99th-Canyon Run/CTLD_CanyonRun.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
DCS_Caucasus/F99th-Canyon Run/F99th-Canyon Run 1.2.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Canyon Run/F99th-Canyon Run 1.2.2.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Canyon Run/F99thMissionBackground.png
Normal file
BIN
DCS_Caucasus/F99th-Canyon Run/F99thMissionBackground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 395 KiB |
464
DCS_Caucasus/F99th-Canyon Run/F99thServiceMonitorV1.4.2.lua
Normal file
464
DCS_Caucasus/F99th-Canyon Run/F99thServiceMonitorV1.4.2.lua
Normal 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
|
||||||
83561
DCS_Caucasus/F99th-Canyon Run/Moose.lua
Normal file
83561
DCS_Caucasus/F99th-Canyon Run/Moose.lua
Normal file
File diff suppressed because it is too large
Load Diff
25
DCS_Caucasus/F99th-Canyon Run/ctld_aaa.lua
Normal file
25
DCS_Caucasus/F99th-Canyon Run/ctld_aaa.lua
Normal 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
|
||||||
BIN
DCS_Caucasus/F99th-Canyon Run/oilderrick.png
Normal file
BIN
DCS_Caucasus/F99th-Canyon Run/oilderrick.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
6339
DCS_Caucasus/F99th-Iron Hand/CTLD.lua
Normal file
6339
DCS_Caucasus/F99th-Iron Hand/CTLD.lua
Normal file
File diff suppressed because it is too large
Load Diff
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.002.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.002.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.005.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.005.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.1.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.1.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.1_NoScripts.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.1_NoScripts.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.2.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.3.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.3.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.4.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.4.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.5.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.5.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.6.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.6.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.7.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.7.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.8.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.8.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.9.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.1.9.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.0.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.0.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.1.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.1.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.2.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.3.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Iron_Hand_1.2.3.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Test.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/DSMC-Test.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.0
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.0
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.1
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.1
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.1.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.1.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.2.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.3.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.3.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.4.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.4.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.5.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.5.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.6.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.6.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.7.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.7.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.8.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.8.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.9.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.0.9.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.1.1.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/F99th-Iron_Hand_1.1.1.miz
Normal file
Binary file not shown.
BIN
DCS_Caucasus/F99th-Iron Hand/Iron_Hand_1.1.2.miz
Normal file
BIN
DCS_Caucasus/F99th-Iron Hand/Iron_Hand_1.1.2.miz
Normal file
Binary file not shown.
23
DCS_Caucasus/F99th-Iron Hand/MBT.lua
Normal file
23
DCS_Caucasus/F99th-Iron Hand/MBT.lua
Normal 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
Loading…
x
Reference in New Issue
Block a user