mirror of
https://github.com/akaAgar/the-universal-mission-for-dcs-world.git
synced 2026-09-03 00:13:16 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e323f7c39 | |||
| d62557da89 | |||
| 211cb15015 | |||
| 1905b4061a | |||
| b93bcb4734 | |||
| 61e017fbe8 | |||
| 655b5bc6aa | |||
| d13d94f1bb | |||
| 0be508c42c | |||
| b9ce5ef340 | |||
| 3453bccf85 | |||
| b392c55828 | |||
| ff15793f06 | |||
| e7f9ba4f92 | |||
| 98baf8a3c0 | |||
| 4a94770322 | |||
| 885b14315f | |||
| 4f1ad38eeb | |||
| 404095967d | |||
| 4ebbf398d2 | |||
| babc9a183e | |||
| 0b792e4b25 |
@@ -0,0 +1,25 @@
|
||||
Library.tasks.heloHuntAttack = {
|
||||
taskFamily = DCSEx.enums.taskFamily.HELO_HUNT,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
"Locate and neutralize all enemy rotary-wing assets in the area.",
|
||||
"Enemy attack helicopters are staging nearby, you are to eliminate them before they launch their attack.",
|
||||
"Intel confirms a group of hostile gunships in the area. You must render them combat-ineffective.",
|
||||
"Engage and destroy rotary assets nearby, crippling enemy air support.",
|
||||
},
|
||||
short = "Destroy enemy attack helicopters",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { },
|
||||
minimumDistance = DCSEx.converter.nmToMeters(10.0),
|
||||
safeRadius = 100,
|
||||
surfaceType = nil,
|
||||
targetCount = { 2, 3 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.HELICOPTER_ATTACK },
|
||||
waypointInaccuracy = DCSEx.converter.nmToMeters(6.0)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
Library.tasks.heloHuntTransport = {
|
||||
taskFamily = DCSEx.enums.taskFamily.HELO_HUNT,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
"",
|
||||
},
|
||||
short = "Destroy enemy transport helicopters",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { },
|
||||
minimumDistance = DCSEx.converter.nmToMeters(10.0),
|
||||
safeRadius = 100,
|
||||
surfaceType = nil,
|
||||
targetCount = { 2, 3 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.HELICOPTER_TRANSPORT },
|
||||
waypointInaccuracy = DCSEx.converter.nmToMeters(6.0)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
-- Library.tasks.ocaAirbase = {
|
||||
-- taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
-- description =
|
||||
-- {
|
||||
-- briefing = {
|
||||
-- "Neutralizing this enemy airbase will eliminate their ability to conduct sustained air sorties and restore local air superiority.",
|
||||
-- "Taking out this airbase will disrupt their logistics and sortie tempo, buying time for our ground forces to consolidate.",
|
||||
-- "This airbase is the hub of enemy reconnaissance and close air support—removing it reduces battlefield intelligence and strike pressure.",
|
||||
-- "Outlasting enemy air campaign requires degrading that facility's operational capacity to prevent rotational sorties.",
|
||||
-- "Disabling this node of their air network constrains their command-and-control reach and limits coordinated strikes."
|
||||
-- },
|
||||
-- short = "Destroy enemy airbase",
|
||||
-- },
|
||||
-- conditions = {
|
||||
-- difficultyMinimum = 0,
|
||||
-- eras = {},
|
||||
-- },
|
||||
-- completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
-- flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.AIRBASE_TARGET },
|
||||
-- minimumDistance = 0.0,
|
||||
-- safeRadius = 0,
|
||||
-- surfaceType = land.SurfaceType.LAND,
|
||||
-- targetCount = { 1, 1 },
|
||||
-- targetFamilies = { DCSEx.enums.unitFamily.STATIC_SCENERY },
|
||||
-- waypointInaccuracy = 0.0
|
||||
-- }
|
||||
@@ -0,0 +1,22 @@
|
||||
Library.tasks.ocaBomberStrike = {
|
||||
taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
""
|
||||
},
|
||||
short = "Destroy enemy bomber on the ramp",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET },
|
||||
minimumDistance = 0.0,
|
||||
safeRadius = 0,
|
||||
surfaceType = land.SurfaceType.LAND,
|
||||
targetCount = { 1, 1 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.PLANE_BOMBER },
|
||||
waypointInaccuracy = 0.0
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
Library.tasks.ocaFighterStrike = {
|
||||
taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
"Destroying enemy fighters on the ramp will prevent immediate sortie generation and blunt their ability to provide CAS against our advancing forces.",
|
||||
"A ramp strike against enemy aircraft will pre-empt an imminent scramble warning we have intel for, preventing a coordinated mass launch.",
|
||||
"Removing enemy fighters on the ramp will degrade enemy air superiority over the battlespace and protects our medevac and resupply corridors.",
|
||||
"Priority is to eliminate immediate airborne threats on the ramp to safeguard coalition force freedom of maneuver.",
|
||||
},
|
||||
short = "Destroy enemy fighter on the ramp",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET },
|
||||
minimumDistance = 0.0,
|
||||
safeRadius = 0,
|
||||
surfaceType = land.SurfaceType.LAND,
|
||||
targetCount = { 1, 1 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.PLANE_FIGHTER },
|
||||
waypointInaccuracy = 0.0
|
||||
}
|
||||
@@ -26,7 +26,7 @@ The Universal Mission for DCS World is a fully dynamic single-player/PvE mission
|
||||
|
||||
**Please read the "planned development" section below for more information.**
|
||||
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Germany, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- Not all mission types are supported yet
|
||||
- Career progress may be lost because of future updates, don't get too attached to it
|
||||
|
||||
@@ -75,10 +75,13 @@ Please also note that PvP is not supported at the moment and that the mission wi
|
||||
|
||||
- Additional content
|
||||
- [ ] More objectives types
|
||||
- [x] Helicopter hunt
|
||||
- [ ] Offensive counter-air
|
||||
- Balance improvements
|
||||
- [ ] Tweaked XP requirements for medals/promotions
|
||||
- Bug fixes
|
||||
- [ ] AWACS datalinked contacts not showing on SA pages
|
||||
- [X] AWACS can now detect enemy helicopters
|
||||
- Extras
|
||||
- [ ] GitHub page
|
||||
- Improvements
|
||||
@@ -156,13 +159,13 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
|
||||
- **0.3.250914** (09/14/2025)
|
||||
- **MAJOR CHANGE:**
|
||||
- Use of "Client" slot instead of "Player" slot even in single-player missions, allowing the player to respawn on death/ejection instead of having to start the whole mission again
|
||||
- "Player" should not be used anymore. Single-player missions must use a single "Client" slot instead
|
||||
- Use of "Client" slots instead of "Player" slots even in single-player missions, allowing the player to respawn on death/ejection instead of having to start the whole mission again
|
||||
- "Player" slots should not be used anymore. Single-player missions must now use a single "Client" slot instead
|
||||
- Additional content
|
||||
- Added new units (Currenthill unit pack) from DCS 2.9.19.13478
|
||||
- Support for "Cold War Germany" theater
|
||||
- Balance improvements
|
||||
- Enemy CAP respawn rate now decreases the more enemy planes are shot
|
||||
- Enemy CAP respawn rate now decreases as more enemy planes are shot down
|
||||
- Bug fixes
|
||||
- Some player callsigns were causing a script error at startup
|
||||
- Fixed wrong filename in "enemy infantry killed" messages
|
||||
@@ -176,7 +179,7 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
- Mission now autostarts (if it wasn't started yet) when all players have taken off
|
||||
- Quality of life/minor tweaks
|
||||
- Increased AWACS aircraft spawn altitude
|
||||
- Target coordinates radio message displayed for a longer time so players have the time to write them down or enter them in their flight computer
|
||||
- Target coordinates radio message displayed for a longer time so players have time to write them down or enter them in their flight computer
|
||||
- **0.2.250729** (07/29/2025)
|
||||
- **MAJOR CHANGE:** Added all new wingman system
|
||||
- Far for perfect but a lot better than DCS's default wingmen
|
||||
|
||||
@@ -39,26 +39,28 @@ DCSEx.enums.taskEvent = {
|
||||
-------------------------------------
|
||||
DCSEx.enums.taskFamily = {
|
||||
ANTISHIP = 1,
|
||||
-- CAP = 2, -- TODO
|
||||
-- CAS = 3, -- TODO
|
||||
GROUND_ATTACK = 2, -- 4
|
||||
-- HELICOPTER = XXX, -- 5
|
||||
-- HELO_HUNT = XXX, -- 6
|
||||
INTERCEPTION = 3, -- 7
|
||||
-- OCA = XXX, -- 8
|
||||
SEAD = 4, --9
|
||||
STRIKE = 5, -- 10
|
||||
-- CAP = XXX,
|
||||
-- CAS = XXX,
|
||||
GROUND_ATTACK = 2,
|
||||
-- HELICOPTER = XXX,
|
||||
HELO_HUNT = 3,
|
||||
INTERCEPTION = 4,
|
||||
OCA = 5,
|
||||
SEAD = 6,
|
||||
STRIKE = 7,
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
-- Special events for tasks
|
||||
-------------------------------------
|
||||
DCSEx.enums.taskFlag = {
|
||||
ALLOW_JTAC = 1,
|
||||
DESTROY_TRACK_RADARS_ONLY = 2,
|
||||
MOVING = 3,
|
||||
ON_ROADS = 4,
|
||||
SCENERY_TARGET = 5
|
||||
AIRBASE_TARGET = 1,
|
||||
ALLOW_JTAC = 2,
|
||||
DESTROY_TRACK_RADARS_ONLY = 3,
|
||||
MOVING = 4,
|
||||
ON_ROADS = 5,
|
||||
PARKED_AIRCRAFT_TARGET = 6,
|
||||
SCENERY_TARGET = 7,
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
|
||||
@@ -374,6 +374,14 @@ do
|
||||
setAircraftTaskOrbit(groupTable, options)
|
||||
end
|
||||
|
||||
-- For parked aircraft
|
||||
if options.airbaseID and options.parkingID then
|
||||
groupTable.route.points[1].action = "From Parking Area"
|
||||
groupTable.route.points[1].airdromeId = options.airbaseID
|
||||
groupTable.route.points[1].type = "TakeOffParking"
|
||||
groupTable.uncontrolled = true
|
||||
end
|
||||
|
||||
if options.callsign then
|
||||
groupCallsign = options.callsign
|
||||
else
|
||||
@@ -449,6 +457,12 @@ do
|
||||
if aircraftDB.properties then
|
||||
unitTable.AddPropAircraft = DCSEx.table.deepCopy(aircraftDB.properties)
|
||||
end
|
||||
|
||||
-- For parked aircraft
|
||||
if options.airbaseID and options.parkingID then
|
||||
unitTable.parking = tostring(options.parkingID)
|
||||
end
|
||||
|
||||
-- Setup datalink
|
||||
local datalinkString = tostring(dataLinkID)
|
||||
if #datalinkString == 3 then
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
-- DCSEX.ZONES - FUNCTIONS RELATED TO MAP TRIGGER ZONES
|
||||
-- ====================================================================================
|
||||
-- DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawName, readOnly)
|
||||
-- DCSEx.zones.getAirbases(zone, coalition)
|
||||
-- DCSEx.zones.getAll()
|
||||
-- DCSEx.zones.getByName(name)
|
||||
-- DCSEx.zones.getCenter(zoneTable)
|
||||
@@ -72,6 +73,30 @@ function DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawNa
|
||||
return markerID
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all airbases in the zone
|
||||
-------------------------------------
|
||||
-- @param zoneTable Table of the zone in which to search
|
||||
-- @param coalition Coalition (from the coalition.side enum) the airbase must belong to. Default is nil, which means "all coalitions"
|
||||
-- @return Table of airbases
|
||||
-------------------------------------
|
||||
function DCSEx.zones.getAirbases(zoneTable, coalition)
|
||||
coalition = coalition or nil
|
||||
|
||||
local coalitions = { coalition.side.RED, coalition.side.BLUE }
|
||||
if coalition then coalitions = { coalition } end
|
||||
|
||||
local validAirbases = {}
|
||||
for _,side in ipairs(coalitions) do
|
||||
for _,ab in ipairs(coalition.getAirbases(side)) do
|
||||
if DCSEx.zones.isPointInside(zoneTable, ab:getPoint()) then
|
||||
table.insert(validAirbases, ab)
|
||||
end
|
||||
end
|
||||
end
|
||||
return validAirbases
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all trigger zones
|
||||
-------------------------------------
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -174,7 +174,13 @@ do
|
||||
if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
|
||||
if not event.initiator then return end
|
||||
|
||||
if objectives[index].isSceneryTarget then
|
||||
if objectives[index].isAirbaseTarget then
|
||||
if Object.getCategory(event.initiator) == Object.Category.BASE then
|
||||
if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
|
||||
timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
|
||||
end
|
||||
end
|
||||
elseif objectives[index].isSceneryTarget then
|
||||
if Object.getCategory(event.initiator) == Object.Category.SCENERY then
|
||||
if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
|
||||
timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
|
||||
|
||||
@@ -51,8 +51,10 @@ do
|
||||
end
|
||||
local objectiveDB = Library.tasks[taskID]
|
||||
|
||||
local parkingInfo = nil
|
||||
local spawnPoint2 = nil
|
||||
local spawnPoint3 = nil
|
||||
local isAirbaseTarget = false
|
||||
local isSceneryTarget = false
|
||||
|
||||
if DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.SCENERY_TARGET) then
|
||||
@@ -66,6 +68,36 @@ do
|
||||
spawnPoint3 = DCSEx.table.deepCopy(pickedScenery:getPoint())
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
isSceneryTarget = true
|
||||
elseif DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.AIRBASE_TARGET) then
|
||||
local validAirbases = DCSEx.zones.getAirbases(zone, TUM.settings.getEnemyCoalition())
|
||||
if #validAirbases == 0 then
|
||||
TUM.log("Failed to find a valid airbase to use as target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedAirbase = DCSEx.table.getRandom(validAirbases)
|
||||
spawnPoint3 = DCSEx.table.deepCopy(pickedAirbase:getPoint())
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
isAirbaseTarget = true
|
||||
elseif DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET) then
|
||||
local validAirbases = DCSEx.zones.getAirbases(zone, TUM.settings.getEnemyCoalition())
|
||||
if #validAirbases == 0 then
|
||||
TUM.log("Failed to find a valid airbase to use as target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedAirbase = DCSEx.table.getRandom(validAirbases)
|
||||
local parkings = pickedAirbase:getParking()
|
||||
local validParkings = {}
|
||||
for _,p in pairs(parkings) do
|
||||
if p.Term_Type == 104 then table.insert(validParkings, p) end
|
||||
end
|
||||
if #validParkings == 0 then
|
||||
TUM.log("Failed to find a valid airbase parking to spawn a target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedParking = DCSEx.table.getRandom(validParkings)
|
||||
parkingInfo = { airbaseID = pickedAirbase:getID(), parkingID = pickedParking.Term_Index }
|
||||
spawnPoint3 = pickedParking.vTerminalPos
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
elseif objectiveDB.surfaceType == land.SurfaceType.WATER then
|
||||
spawnPoint2 = pickWaterPoint(zone)
|
||||
if not spawnPoint2 then
|
||||
@@ -89,10 +121,12 @@ do
|
||||
local objective = {
|
||||
completed = false,
|
||||
completedUnitsID = {},
|
||||
isAirbaseTarget = isAirbaseTarget,
|
||||
isSceneryTarget = isSceneryTarget,
|
||||
markerID = DCSEx.world.getNextMarkerID(),
|
||||
markerTextID = DCSEx.world.getNextMarkerID(),
|
||||
name = Library.objectiveNames.get():upper(),
|
||||
parkingInfo = parkingInfo,
|
||||
point2 = DCSEx.table.deepCopy(spawnPoint2),
|
||||
point3 = DCSEx.table.deepCopy(spawnPoint3),
|
||||
preciseCoordinates = objectiveDB.waypointInaccuracy <= 0,
|
||||
@@ -108,7 +142,7 @@ do
|
||||
objective.waypoint3 = DCSEx.math.vec2ToVec3(objective.waypoint2, "land")
|
||||
end
|
||||
|
||||
if not DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.SCENERY_TARGET) then
|
||||
if not isAirbaseTarget and not isSceneryTarget then
|
||||
-- Check group options
|
||||
local groupOptions = {}
|
||||
if DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.MOVING) then
|
||||
@@ -123,6 +157,12 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- Parked aircraft only
|
||||
if parkingInfo then
|
||||
groupOptions.airbaseID = parkingInfo.airbaseID
|
||||
groupOptions.parkingID = parkingInfo.parkingID
|
||||
end
|
||||
|
||||
local units = Library.factions.getUnits(TUM.settings.getEnemyFaction(), objectiveDB.targetFamilies, math.random(objectiveDB.targetCount[1], objectiveDB.targetCount[2]))
|
||||
|
||||
local groupInfo = nil
|
||||
|
||||
@@ -68,8 +68,8 @@ do
|
||||
if objectDesc.attributes["Planes"] then return math.floor(25 * groundMultiplier) end
|
||||
|
||||
-- Rotary wing
|
||||
if objectDesc.attributes["Attack helicopters"] then return math.floor(30 * groundMultiplier) end
|
||||
if objectDesc.attributes["Helicopters"] then return math.floor(25 * groundMultiplier) end
|
||||
if objectDesc.attributes["Attack helicopters"] then return math.floor(25 * groundMultiplier) end
|
||||
if objectDesc.attributes["Helicopters"] then return math.floor(15 * groundMultiplier) end
|
||||
|
||||
-- Default air
|
||||
if objectDesc.attributes["Air"] then return math.floor(20 * groundMultiplier) end
|
||||
|
||||
@@ -52,7 +52,7 @@ do
|
||||
[TUM.settings.id.PLAYER_COALITION] = { "Red", "Blue" }, -- Must match values in the coalition.side enum
|
||||
[TUM.settings.id.TARGET_COUNT] = { "1", "2", "3", "4" },
|
||||
[TUM.settings.id.TARGET_LOCATION] = { },
|
||||
[TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Interception", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Helicopter hunt", "Interception", "OCA", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TIME_PERIOD] = { "World War 2", "Korea War", "Vietnam War", "Late Cold War", "Modern" }, -- Must match values in the DCSEx.enums.timePeriod enum
|
||||
[TUM.settings.id.WINGMEN] = { "None", "1", "2", "3" }
|
||||
}
|
||||
|
||||
@@ -43,6 +43,15 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
detectedGroups = coalition.getGroups(TUM.settings.getEnemyCoalition(), Group.Category.HELICOPTER)
|
||||
for _,g in pairs(detectedGroups) do
|
||||
local units = g:getUnits()
|
||||
for _,u in pairs(units) do
|
||||
if u:inAir() then
|
||||
table.insert(detectedAircraft, u)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- No aircraft on picture
|
||||
if #detectedAircraft == 0 then
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
-- ====================================================================================
|
||||
-- TUM.SUPPORTJTAC - HANDLES FRIENDLY JTAC SMOKE MARKERS AND LASING
|
||||
-- ====================================================================================
|
||||
-- (local) destroyAllLasers()
|
||||
-- (local) doCommandLaser(index)
|
||||
-- (local) doCommandLaserStop(index)
|
||||
-- (local) doCommandSmoke(index)
|
||||
-- (local) spawnSmoke(args)
|
||||
-- (local) updateLaserPositions()
|
||||
-- TUM.supportJTAC.setupJTACOnObjective(index, menuRoot)
|
||||
-- ====================================================================================
|
||||
|
||||
TUM.supportJTAC = {}
|
||||
@@ -28,14 +35,57 @@ do
|
||||
"Whiplash",
|
||||
}
|
||||
|
||||
local LASER_CODE = 1688
|
||||
local LASER_DESIGNATION_PENALTY = -15
|
||||
local SMOKE_DURATION = 300 -- in seconds
|
||||
local SMOKE_MARKER_PENALTY = -25
|
||||
|
||||
local jtacName = {}
|
||||
local lastSmoke = {}
|
||||
local laserSpots = {}
|
||||
local laserTargets = {}
|
||||
|
||||
local function spawnSmoke(args)
|
||||
trigger.action.smoke(args.point3, args.smokeColor)
|
||||
local function destroyAllLasers()
|
||||
if #laserSpots == 0 and #laserTargets == 0 then return end
|
||||
|
||||
for _,l in pairs(laserSpots) do
|
||||
if l then l:destroy() end
|
||||
end
|
||||
|
||||
laserSpots = {}
|
||||
laserTargets = {}
|
||||
end
|
||||
|
||||
local function doCommandLaser(index)
|
||||
local obj = TUM.objectives.getObjective(index)
|
||||
if not obj then return end
|
||||
|
||||
if laserSpots[index] then
|
||||
laserSpots[index]:destroy()
|
||||
laserSpots[index] = nil
|
||||
end
|
||||
|
||||
local sourceObject = nil
|
||||
local targetPoint = {x = 0, y = 0, z = 0}
|
||||
|
||||
laserSpots[index] = Spot.createLaser(sourceObject, {x = 0, y = 1, z = 0}, targetPoint, LASER_CODE)
|
||||
end
|
||||
|
||||
local function doCommandLaserStop(index)
|
||||
local obj = TUM.objectives.getObjective(index)
|
||||
if not obj then return end
|
||||
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "playerJTACLaserStop", { jtacName[index], obj.name }, TUM.mission.getPlayerCallsign(), false)
|
||||
|
||||
-- Not lasing this objective at the moment
|
||||
if not laserSpots[index] then
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "jtacLaserStopNoLaser", { jtacName[index], obj.name }, jtacName[index], true)
|
||||
return
|
||||
end
|
||||
|
||||
laserSpots[index]:destroy()
|
||||
laserSpots[index] = nil
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "jtacLaserStop", { jtacName[index], obj.name }, jtacName[index], true)
|
||||
end
|
||||
|
||||
local function doCommandSmoke(index)
|
||||
@@ -60,7 +110,7 @@ do
|
||||
return
|
||||
end
|
||||
|
||||
if obj.isSceneryTarget then
|
||||
if obj.isAirbaseTarget or obj.isSceneryTarget then
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "jtacSmokeOK", { jtacName[index], smokeColorName }, jtacName[index], true, spawnSmoke, { point3 = obj.point3, smokeColor = smokeColor })
|
||||
else
|
||||
for _,id in ipairs(obj.unitsID) do
|
||||
@@ -79,6 +129,24 @@ do
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "jtacSmokeNoTarget", { jtacName[index] }, jtacName[index], true)
|
||||
end
|
||||
|
||||
local function spawnSmoke(args)
|
||||
trigger.action.smoke(args.point3, args.smokeColor)
|
||||
end
|
||||
|
||||
local function updateLaserPositions()
|
||||
-- Not in a mission? Destroy all lasers
|
||||
if TUM.mission.getStatus() == TUM.mission.status.NONE then
|
||||
destroyAllLasers()
|
||||
return timer.getTime() + 0.5
|
||||
end
|
||||
|
||||
for i=1,TUM.objectives.getCount() do
|
||||
-- TODO
|
||||
end
|
||||
|
||||
return timer.getTime() + 0.5
|
||||
end
|
||||
|
||||
function TUM.supportJTAC.setupJTACOnObjective(index, menuRoot)
|
||||
local obj = TUM.objectives.getObjective(index)
|
||||
if not obj then return end
|
||||
@@ -89,5 +157,10 @@ do
|
||||
if not DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.ALLOW_JTAC) then return end -- No JTAC for this objective
|
||||
|
||||
missionCommands.addCommand("Smoke marker on target ("..tostring(SMOKE_MARKER_PENALTY).."xp)", menuRoot, doCommandSmoke, index)
|
||||
missionCommands.addCommand("Designate target with laser (code "..tostring(LASER_CODE)..", "..tostring(LASER_DESIGNATION_PENALTY).."xp)", menuRoot, doCommandLaser, index)
|
||||
missionCommands.addCommand("Stop designating target with laser", menuRoot, doCommandLaserStop, index)
|
||||
end
|
||||
|
||||
-- Schedule the laser updating function to be called every 0.5 seconds
|
||||
timer.scheduleFunction(updateLaserPositions, {}, timer.getTime() + 0.5)
|
||||
end
|
||||
|
||||
@@ -23,11 +23,11 @@ do
|
||||
elseif taskingID == DCSEx.enums.taskFamily.GROUND_ATTACK then
|
||||
return "attack"
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.HELICOPTER then
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.HELO_HUN then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.HELO_HUNT then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.INTERCEPTION then
|
||||
return "cap"
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.OCA then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.SEAD then
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.OCA then
|
||||
return "sead"
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.STRIKE then
|
||||
-- return "strike"
|
||||
|
||||
Reference in New Issue
Block a user