diff --git a/_docs/img/cas_mission.png b/_docs/img/cas_mission.png
new file mode 100644
index 0000000..ec7de3e
Binary files /dev/null and b/_docs/img/cas_mission.png differ
diff --git a/_docs/pages/reference.html b/_docs/pages/reference.html
index f15ee47..6352d42 100644
--- a/_docs/pages/reference.html
+++ b/_docs/pages/reference.html
@@ -212,6 +212,7 @@
CAS missions involve close air support for friendly ground forces.
CAS mission have a special "BattleManager" module added by defualt. This will make blue and red units shoot at eachoter.
This creates a nice effect.
+ To see how it's done see: [Tutorials] Mission: CAS
STRIKE
diff --git a/_docs/pages/tutorials.html b/_docs/pages/tutorials.html
index 49999af..b3a5080 100644
--- a/_docs/pages/tutorials.html
+++ b/_docs/pages/tutorials.html
@@ -58,6 +58,7 @@
Mission Briefings
@@ -244,11 +245,62 @@
Even some SHORADS to spice the whole thing up.
In the picture below all units that are selected and who show up as white (they are actually red) have the prefix TGT_ in front of their name.
+
This will make it so the mission will be marked as complete when those units are destroyed. The rest of the units will exist until the entire stage is cleaned up.

+ Mision: CAS
+
+ A CAS mission will add an additional layer to the mission.
+ Whereas BAI, Strike and DEAD missions are somewhat clean, CAS missions are where the chaos starts.
+
+ With CAS missions an additional BattleManager will be activated.
+ This BattleManager will scan for units and force them to fire at other units in the zone.
+ Great efforts are made to make AI miss. In the end we want players to be they key factor to mission success.
+ If AI do seem to be hitting more than 1 or 2 unfortunate targets, it is most likely you either have another script controlling the units, or you have placed the units too staggered.
+ Please make sure to also read the "Notes" section below the image.
+
+
+
+ Notes:
+
+ -
+ AAA units will sometimes also follow their lead and fire at targets on the ground.
+ They will however always prioritize AIR targets as at that point they have a threat themselves and won't follow their lead's targets.
+ If you really don't like this, it's best to put the AAA units in a separate group.
+
+ -
+ Units will purposely aim past a target.
+ This simulates a fight, but doesn't actually do anything, so the player is the only person that can complete a mission.
+ Be aware that if you stagger groups too much, shooting past a target might hit another.
+ Best would be to always test it.
+ You can also enable debugging.
+ This will draw all boxes and lines.
+ NOTE: Keep DEBUG disabled on an actual mission.
+
+ -
+ When you want AI to shoot through gaps a distance of approx 150ft is required between the two outer units.
+ These gaps will be automatically detected and can even exist within a group itself.
+
+ -
+ Line of sight is important, dependent on which type of unit.
+ Units won't shoot when they can't fire at a certain point.
+ As a mission editor it's up to you to set the range, line of sight and cover.
+
+ -
+ As Performance is something that's on any multiplayer mission maker's mind, this is a very optimised way.
+ AI does not have to know, scan, priorise targets every second.
+ It does not really have to think or move.
+ Ofcourse, there is a balance and too many can be too much.
+ For now it has been tested with 60+ units in 3 seperate CAS zones active at a time.
+ No performance degradation was seen at all.
+
+
+
+
+
Mission Briefings
So now we've created some missions we also want to add briefings to them. This is pretty easy with Spearhead.
diff --git a/_miz/SPEARHEADDEV.miz b/_miz/SPEARHEADDEV.miz
index 8320c2f..05f3822 100644
Binary files a/_miz/SPEARHEADDEV.miz and b/_miz/SPEARHEADDEV.miz differ
diff --git a/classes/spearhead_base.lua b/classes/spearhead_base.lua
index d398132..5d45616 100644
--- a/classes/spearhead_base.lua
+++ b/classes/spearhead_base.lua
@@ -1203,9 +1203,10 @@ do -- INIT DCS_UTIL
---@param location table? vector 3 data. { x , z, alt }
---@param route table? route of the group. If nil wil be the default route.
---@param uncontrolled boolean? Sets the group to be uncontrolled on spawn
+ ---@param countryId CountryID? Overwrites the country
---@return table? new_group the Group class that was spawned
---@return boolean? isStatic whether the group is a static or not
- function DCS_UTIL.SpawnGroupTemplate(groupName, location, route, uncontrolled)
+ function DCS_UTIL.SpawnGroupTemplate(groupName, location, route, uncontrolled, countryId)
if groupName == nil then
return nil, nil
end
@@ -1217,7 +1218,8 @@ do -- INIT DCS_UTIL
if template.category == DCS_UTIL.GroupCategory.STATIC then
--TODO: Implement location and route stuff
local spawn_template = template.group_template
- return coalition.addStaticObject(template.country_id, spawn_template), true
+ local country = countryId or template.country_id
+ return coalition.addStaticObject(country, spawn_template), true
else
local spawn_template = template.group_template
if location ~= nil then
@@ -1244,11 +1246,21 @@ do -- INIT DCS_UTIL
if uncontrolled ~= nil then
spawn_template.uncontrolled = uncontrolled
end
- local new_group = coalition.addGroup(template.country_id, template.category, spawn_template)
+ local country = countryId or template.country_id
+ local new_group = coalition.addGroup(country, template.category, spawn_template)
return new_group, false
end
end
+ ---@return number? id
+ function DCS_UTIL.GetNeutralCountry()
+ for name, id in pairs(country.id) do
+ if coalition.getCountryCoalition(id) == DCS_UTIL.Coalition.NEUTRAL then
+ return id
+ end
+ end
+ end
+
function DCS_UTIL.IsBingoFuel(groupName, offset)
if offset == nil then offset = 0 end
local bingoSetting = 0.20
diff --git a/classes/stageClasses/Groups/SpearheadGroup.lua b/classes/stageClasses/Groups/SpearheadGroup.lua
index a964353..69dae1f 100644
--- a/classes/stageClasses/Groups/SpearheadGroup.lua
+++ b/classes/stageClasses/Groups/SpearheadGroup.lua
@@ -156,7 +156,6 @@ function SpearheadGroup:GetObjects()
return result
end
-
---comment
---@return Array result list of objects
function SpearheadGroup:GetAsUnits()
@@ -195,15 +194,21 @@ end
function SpearheadGroup:SetInvisible()
- local group = Group.getByName(self.groupName)
- if group then
- local setInvisible = {
- id = 'SetInvisible',
- params = {
- value = true
+ if self._isStatic == true then
+ local country = Spearhead.DcsUtil.GetNeutralCountry()
+ Spearhead.DcsUtil.SpawnGroupTemplate(self.groupName, nil, nil, nil, country)
+ else
+ local group = Group.getByName(self.groupName)
+ if group then
+ local setInvisible = {
+ id = 'SetInvisible',
+ params = {
+ value = true
+ }
}
- }
- group:getController():setCommand(setInvisible)
+ group:getController():setCommand(setInvisible)
+ end
+
end
end
diff --git a/classes/stageClasses/helpers/BattleManager.lua b/classes/stageClasses/helpers/BattleManager.lua
index 3242934..3215526 100644
--- a/classes/stageClasses/helpers/BattleManager.lua
+++ b/classes/stageClasses/helpers/BattleManager.lua
@@ -93,7 +93,6 @@ function BattleManager:Update()
end
-local drawID = 8633
---@private
---@param groups Array
---@param targetGroups Array
@@ -101,6 +100,8 @@ function BattleManager:LetUnitsShoot(groups, targetGroups)
local shootChance = math.random(3, 7) / 10
+ local targetHulls = self:ToShootingHulls(targetGroups)
+
for _, group in pairs(groups) do
local units = group:GetAsUnits()
@@ -115,7 +116,7 @@ function BattleManager:LetUnitsShoot(groups, targetGroups)
if math.random() <= shootChance then
local unitPos = unit:getPoint()
- local point = self:GetRandomPoint({x = unitPos.x, y = unitPos.z }, targetGroups)
+ local point = self:GetRandomPoint({x = unitPos.x, y = unitPos.z }, targetHulls)
if point then
local ammo, qty = self:getBestAmmo(unit)
@@ -129,18 +130,10 @@ function BattleManager:LetUnitsShoot(groups, targetGroups)
expendQtyEnabled = true
}
}
-
- ---- DEBUG ONLY!!
- --- DRAWS THE SHOOTING LINE
- -- do
- -- local color = {r = 1, g = 0, b = 0, a = 1}
- -- if unit:getCoalition() == 2 then
- -- color = {r = 0, g = 0, b = 1, a = 1}
- -- end
-
- -- Spearhead.DcsUtil.DrawLine(unitPos, {x = point.x, y = 0, z = point.y}, color, 1)
- -- end
+ if SpearheadConfig and SpearheadConfig.debugEnabled == true then
+ self:DrawDebugLine(point, unit)
+ end
self._logger:debug("Red unit " .. unit:getName() .. " will shoot " .. qty .. " rounds at point: " .. tostring(point))
@@ -207,56 +200,85 @@ function BattleManager:IsUnitApplicable(unit)
end
---@private
----@param origin Vec2
---@param groups Array
----@return Vec2?
-function BattleManager:GetRandomPoint(origin, groups)
- local group = Spearhead.Util.randomFromList(groups) --[[@as SpearheadGroup]]
- if not group then return nil end
+---@return Array>
+function BattleManager:ToShootingHulls(groups)
+ local result = {}
local points = {}
- for _, unit in pairs(group:GetAsUnits()) do
- local pos = unit:getPoint()
- table.insert(points, {x = pos.x, y = pos.z})
+ for _, group in pairs(groups) do
+ for _, unit in pairs(group:GetObjects()) do
+ local pos = unit:getPoint()
+ table.insert(points, {x = pos.x, y = pos.z})
+ end
end
local hulls = Spearhead.Util.getSeparatedConvexHulls(points, 50)
- local hull = Spearhead.Util.randomFromList(hulls) --[[@as Array]]
+ local enlargedHulls = {}
+ for _, hull in pairs(hulls) do
+ local enlarged = Spearhead.Util.enlargeConvexHull(hull, 25)
+ if enlarged then
+ table.insert(enlargedHulls, enlarged)
+ end
+ end
+
+ for _, hull in pairs(enlargedHulls) do
+ if #hull > 2 then
+ table.insert(result, hull)
+ end
+ end
+
+ return result
+end
+
+---@private
+---@param origin Vec2
+---@param groupHulls Array>
+---@return Vec2?
+function BattleManager:GetRandomPoint(origin, groupHulls)
+
+ local hull = Spearhead.Util.randomFromList(groupHulls) --[[@as Array]]
if not hull then return nil end
- local enlargedHull = Spearhead.Util.enlargeConvexHull(hull, 25)
- local shootPoints = Spearhead.Util.GetTangentHullPointsFromOrigin(enlargedHull, origin)
-
- ---- DEBUG ONLY!!
- ---- DRAWS the hulls of the units
- -- for _, drawHull in pairs(hulls) do
-
- -- ---@type SpearheadTriggerZone
- -- local zone = {
- -- name = "temp",
- -- zone_type = "Polygon",
- -- radius = 0,
- -- verts = drawHull,
- -- location = { x=drawHull[1].x, y=drawHull[1].y },
- -- }
-
- -- Spearhead.DcsUtil.DrawZone(zone, {r =0, g= 1, b =0, a = 0.5} ,{r =0, g= 1, b =0, a = 0}, 1)
-
- -- local enlarged = Spearhead.Util.enlargeConvexHull(drawHull, 25)
- -- local enlargedZone = {
- -- name = "temp_enlarged",
- -- zone_type = "Polygon",
- -- radius = 0,
- -- verts = enlarged,
- -- location = { x=enlarged[1].x, y=enlarged[1].y },
- -- }
- -- Spearhead.DcsUtil.DrawZone(enlargedZone, {r =0, g= 0, b =1, a = 0.5} ,{r =0, g= 1, b =0, a = 0}, 1)
-
- -- end
+ local shootPoints = Spearhead.Util.GetTangentHullPointsFromOrigin(hull, origin)
+ if SpearheadConfig and SpearheadConfig.debugEnabled == true then
+ self:DrawDebugZone({ hull })
+ end
return Spearhead.Util.randomFromList(shootPoints) --[[@as Vec2]]
end
+do --DEBUG
+
+ ---@param unit Unit
+ ---@param target Vec2
+ function BattleManager:DrawDebugLine(target, unit)
+ local color = {r = 1, g = 0, b = 0, a = 1}
+ if unit:getCoalition() == 2 then
+ color = {r = 0, g = 0, b = 1, a = 1}
+ end
+
+ Spearhead.DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1)
+ end
+
+ ---@param hulls Array>
+ function BattleManager:DrawDebugZone(hulls)
+ for _, drawHull in pairs(hulls) do
+
+ ---@type SpearheadTriggerZone
+ local zone = {
+ name = "temp",
+ zone_type = "Polygon",
+ radius = 0,
+ verts = drawHull,
+ location = { x=drawHull[1].x, y=drawHull[1].y },
+ }
+
+ Spearhead.DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1)
+ end
+ end
+end --DEBUG
+
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end