Fix/cas mission2 (#44)
* changed from only units to also statics in targets for CAS * added statics and update docs * optimised hull creation and did not group by group * added cas_mission.png --------- Co-authored-by: dutchie032 <dutchie032> Co-authored-by: ex61wi <tim.rorije@ing.com>
This commit is contained in:
committed by
GitHub
co-authored by
dutchie032 <dutchie032>
ex61wi
parent
74e7d1ca7a
commit
90c8d113fd
Binary file not shown.
|
After Width: | Height: | Size: 2.8 MiB |
@@ -212,6 +212,7 @@
|
||||
CAS missions involve close air support for friendly ground forces. <br />
|
||||
CAS mission have a special "BattleManager" module added by defualt. This will make blue and red units shoot at eachoter. <br/>
|
||||
This creates a nice effect. <br/>
|
||||
To see how it's done see: <a href="./tutorials.html#mission-cas">[Tutorials] Mission: CAS</a>
|
||||
</p>
|
||||
|
||||
<h3 id="strike">STRIKE</h3>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<ul>
|
||||
<li><a href="#mission-1-dead" class="side-nav-h3">Mission: DEAD</a></li>
|
||||
<li><a href="#mission-2-strike" class="side-nav-h3">Mission: STRIKE</a></li>
|
||||
<li><a href="#mission-cas" class="side-nav-h3">Mission: CAS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#mission-briefings" class="side-nav-h2">Mission Briefings</a></li>
|
||||
@@ -244,11 +245,62 @@
|
||||
Even some SHORADS to spice the whole thing up. <br/>
|
||||
In the picture below all units that are selected and who show up as white (they are actually red) have the prefix <span class="inline-lua"><span class="lua-variable">TGT_</span></span> in front of their name. <br/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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. <br/>
|
||||
</p>
|
||||
<img src="../img/strike_target.png"/><br/>
|
||||
|
||||
<h3 id="mission-cas">Mision: CAS</h3>
|
||||
<p>
|
||||
A CAS mission will add an additional layer to the mission. <br/>
|
||||
Whereas BAI, Strike and DEAD missions are somewhat clean, CAS missions are where the chaos starts. <br/>
|
||||
<br/>
|
||||
With CAS missions an additional BattleManager will be activated. <br/>
|
||||
This BattleManager will scan for units and force them to fire at other units in the zone. <br/>
|
||||
Great efforts are made to make AI miss. In the end we want players to be they key factor to mission success. <br/>
|
||||
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. <br/>
|
||||
Please make sure to also read the "Notes" section below the image. <br/>
|
||||
|
||||
<img src="../img/cas_mission.png" style="width: 100%;"></img>
|
||||
|
||||
Notes: <br/>
|
||||
<ul>
|
||||
<li>
|
||||
AAA units will sometimes also follow their lead and fire at targets on the ground.<br/>
|
||||
They will however always prioritize AIR targets as at that point they have a threat themselves and won't follow their lead's targets. <br/>
|
||||
If you really don't like this, it's best to put the AAA units in a separate group.
|
||||
</li>
|
||||
<li>
|
||||
Units will purposely aim past a target. <br/>
|
||||
This simulates a fight, but doesn't actually do anything, so the player is the only person that can complete a mission. <br/>
|
||||
Be aware that if you stagger groups too much, shooting past a target might hit another. <br/>
|
||||
Best would be to always test it. <br/>
|
||||
You can also enable debugging. <br/>
|
||||
This will draw all boxes and lines. <br/>
|
||||
NOTE: Keep DEBUG disabled on an actual mission.
|
||||
</li>
|
||||
<li>
|
||||
When you want AI to shoot through gaps a distance of approx 150ft is required between the two outer units. <br/>
|
||||
These gaps will be automatically detected and can even exist within a group itself. <br/>
|
||||
</li>
|
||||
<li>
|
||||
Line of sight is important, dependent on which type of unit. <br/>
|
||||
Units won't shoot when they can't fire at a certain point. <br/>
|
||||
As a mission editor it's up to you to set the range, line of sight and cover. <br/>
|
||||
</li>
|
||||
<li>
|
||||
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. <br/>
|
||||
It does not really have to think or move. <br/>
|
||||
Ofcourse, there is a balance and too many can be too much. <br/>
|
||||
For now it has been tested with 60+ units in 3 seperate CAS zones active at a time. <br/>
|
||||
No performance degradation was seen at all. <br/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</p>
|
||||
|
||||
<h2 id="mission-briefings">Mission Briefings</h2>
|
||||
<p>
|
||||
So now we've created some missions we also want to add briefings to them. This is pretty easy with Spearhead. <br/>
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -156,7 +156,6 @@ function SpearheadGroup:GetObjects()
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
---comment
|
||||
---@return Array<Unit> 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
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ function BattleManager:Update()
|
||||
end
|
||||
|
||||
|
||||
local drawID = 8633
|
||||
---@private
|
||||
---@param groups Array<SpearheadGroup>
|
||||
---@param targetGroups Array<SpearheadGroup>
|
||||
@@ -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)
|
||||
@@ -130,17 +131,9 @@ function BattleManager:LetUnitsShoot(groups, targetGroups)
|
||||
}
|
||||
}
|
||||
|
||||
---- 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<SpearheadGroup>
|
||||
---@return Vec2?
|
||||
function BattleManager:GetRandomPoint(origin, groups)
|
||||
local group = Spearhead.Util.randomFromList(groups) --[[@as SpearheadGroup]]
|
||||
if not group then return nil end
|
||||
---@return Array<Array<Vec2>>
|
||||
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<Vec2>]]
|
||||
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<Array<Vec2>>
|
||||
---@return Vec2?
|
||||
function BattleManager:GetRandomPoint(origin, groupHulls)
|
||||
|
||||
local hull = Spearhead.Util.randomFromList(groupHulls) --[[@as Array<Vec2>]]
|
||||
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<Array<Vec2>>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user