mirror of
https://github.com/akaAgar/the-universal-mission-for-dcs-world.git
synced 2025-11-25 19:31:01 +00:00
Merge branch 'new-wingman-system'
This commit is contained in:
commit
850a4c7c50
@ -198,6 +198,28 @@ do
|
||||
return callsignTable
|
||||
end
|
||||
|
||||
function DCSEx.unitCallsignMaker.getNextGroupCallSign(callsign)
|
||||
if not callsign then return nil end
|
||||
local callsignName = callsign:sub(1, #callsign - 2):lower()
|
||||
local callsignGroupNumber = tonumber(callsign:sub(#callsign - 2, #callsign - 1))
|
||||
local callsignUnitNumber = tonumber(callsign:sub(#callsign - 1, #callsign))
|
||||
|
||||
for csType,_ in pairs(CALLSIGNS) do
|
||||
for csNameIndex,_ in pairs(CALLSIGNS[csType]) do
|
||||
if CALLSIGNS[csType][csNameIndex]:lower() == callsignName then
|
||||
return {
|
||||
[1] = csNameIndex,
|
||||
[2] = callsignGroupNumber,
|
||||
[3] = callsignUnitNumber,
|
||||
["name"] = CALLSIGNS[csType][csNameIndex]..tostring(callsignGroupNumber),
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
do
|
||||
local missionGroups = DCSEx.envMission.getGroups()
|
||||
for _,g in ipairs(missionGroups) do
|
||||
|
||||
@ -101,6 +101,26 @@ do
|
||||
return groupTable
|
||||
end
|
||||
|
||||
local function setAircraftTaskFollow(groupTable, followedGroupID)
|
||||
groupTable.task = "Escort"
|
||||
|
||||
table.insert(groupTable.route.points[1].task.params.tasks,
|
||||
{
|
||||
["enabled"] = true,
|
||||
["auto"] = true,
|
||||
["id"] = "Follow",
|
||||
["number"] = #groupTable.route.points[1].task.params.tasks + 1,
|
||||
["params"] = {
|
||||
groupId = followedGroupID,
|
||||
pos = { x = -100, y = 0, z = -100 },
|
||||
lastWptIndexFlag = false,
|
||||
lastWptIndex = -1
|
||||
},
|
||||
})
|
||||
|
||||
return groupTable
|
||||
end
|
||||
|
||||
local function setAircraftTaskOrbit(groupTable, options)
|
||||
-- TODO: oval orbit
|
||||
table.insert(groupTable.route.points[#groupTable.route.points].task.params.tasks,
|
||||
@ -341,7 +361,11 @@ do
|
||||
if isAirUnit then
|
||||
if options.taskAwacs then setAircraftTaskAwacs(groupTable) end
|
||||
if options.taskCAP then setAircraftTaskCAP(groupTable) end
|
||||
setAircraftTaskOrbit(groupTable, options)
|
||||
if options.taskFollow then
|
||||
setAircraftTaskFollow(groupTable, options.taskFollow)
|
||||
else
|
||||
setAircraftTaskOrbit(groupTable, options)
|
||||
end
|
||||
groupCallsign = DCSEx.unitCallsignMaker.getCallsign(unitTypes[1])
|
||||
groupTable.name = groupCallsign.name
|
||||
end
|
||||
|
||||
@ -70,6 +70,21 @@ Library.radioMessages = {
|
||||
pilotWarningMANPADS = { "MANPADS launch! Flare, flare, flare!", "Flight, MANPADS in the air. Dump flares, now!", "Coming from the ground, MANPADS hot!", "Go defensive, MANPADS off your nose! Flare, flare!", "MANPADS just came up from the deck, break hard and pop everything!" },
|
||||
pilotWarningSAMLaunch = { "Spike! SAM just launched, break!", "SAM up! Defensive now!", "Launch! SAM, coming fast, pump chaff, go cold!", "SAM in the air, break hard!", "SAM fired, visual smoke! Extend, extend!" },
|
||||
|
||||
pilotWingmanOrbit = {
|
||||
"Wilco, holding here.",
|
||||
"Copy, orbiting now.",
|
||||
"Roger, in the hold.",
|
||||
"Affirm, setting up the orbit.",
|
||||
"Orbiting at your pos."
|
||||
},
|
||||
pilotWingmanRejoin = {
|
||||
"Off the perch, rejoining your side.",
|
||||
"Tally visual, coming to you.",
|
||||
"Clear, rejoining to route.",
|
||||
"Pushing up to formation.",
|
||||
"Visual, sliding back into position."
|
||||
},
|
||||
|
||||
atcSafeLanding = { "Be advised: $1 is wheels down at $2 and clear of runway.", "All aircraft, $1 has landed at $2 and vacated active. Runway is open for next inbound.", "Traffic, $1 is on deck at $2 and heading to parking. Runway clear.", "All flights, $1 just rolled out at $2 and cleared the active.", "Heads up, $1 landed at $2 and moving to the ramp. Runway available for next approach." },
|
||||
atcSafeLandingPlayer = { "$1, wheels on deck, welcome back. You may taxi to the parking area.", "$1, good copy on landing. Exit when able, proceed to the parking area.", "$1, touchdown confirmed. Continue to parking.", "$1, welcome home. Clear of runway and taxi to parking area.", "$1, nice landing. Taxi to parking when ready." },
|
||||
|
||||
@ -186,6 +201,21 @@ Library.radioMessages = {
|
||||
"Command, pass coordinates for objective $1.",
|
||||
"Command, confirm grid on objective $1."
|
||||
},
|
||||
playerFlightOrbit = {
|
||||
"Flight, orbit my position.",
|
||||
"Flight, set up an orbit on me.",
|
||||
"Flight, hold on me.",
|
||||
"Flight, anchor on my current pos.",
|
||||
"Flight, orbit overhead"
|
||||
},
|
||||
playerFlightRejoin =
|
||||
{
|
||||
"Flight, rejoin my side",
|
||||
"Flight, push it up, rejoin formation.",
|
||||
"Flight, come back to route.",
|
||||
"Flight, tighten it up.",
|
||||
"Flight, rejoin tactical."
|
||||
},
|
||||
playerJTACSmoke = {
|
||||
"$1, request smoke on objective $2, over.",
|
||||
"$1, mark objective $2 with smoke, how copy?",
|
||||
|
||||
@ -107,11 +107,12 @@ do
|
||||
function eventHandler:onEvent(event)
|
||||
if not event then return end -- No event
|
||||
|
||||
TUM.ambientRadio.onEvent(event) -- Must be first so other (more important) radio messages with interrupt the "ambient" ones
|
||||
TUM.ambientRadio.onEvent(event) -- Must be first so other (more important) radio messages will interrupt the "ambient" ones
|
||||
TUM.ambientWorld.onEvent(event)
|
||||
TUM.objectives.onEvent(event)
|
||||
TUM.playerScore.onEvent(event)
|
||||
TUM.mission.onEvent(event)
|
||||
TUM.supportWingmen.onEvent(event)
|
||||
end
|
||||
|
||||
function TUM.onEvent(event)
|
||||
|
||||
@ -55,6 +55,13 @@ do
|
||||
TUM.playerScore.awardCompletedObjective()
|
||||
end
|
||||
|
||||
local function doSimulatePlayerTakeOff()
|
||||
local playerUnit = coalition.getPlayers(TUM.settings.getPlayerCoalition())[1]
|
||||
|
||||
local takeOffEvent = { id = world.event.S_EVENT_TAKEOFF, initiator = playerUnit }
|
||||
TUM.onEvent(takeOffEvent)
|
||||
end
|
||||
|
||||
local function doSimulatePlayerLanding()
|
||||
local playerUnit = coalition.getPlayers(TUM.settings.getPlayerCoalition())[1]
|
||||
|
||||
@ -72,6 +79,7 @@ do
|
||||
missionCommands.addCommand("Detonate \"boom\" map markers", rootMenu, doMarkersBoom, nil)
|
||||
missionCommands.addCommand("Detonate aircraft near \"airboom\" map markers", rootMenu, doMarkersAirBoom, nil)
|
||||
missionCommands.addCommand("Award 100 points and 1 objective", rootMenu, doAwardPointsAndObjectives, nil)
|
||||
missionCommands.addCommand("Simulate player takeoff", rootMenu, doSimulatePlayerTakeOff, nil)
|
||||
missionCommands.addCommand("Simulate player landing", rootMenu, doSimulatePlayerLanding, nil)
|
||||
missionCommands.addCommand("Reset player stats", rootMenu, TUM.playerCareer.reset, nil)
|
||||
end
|
||||
|
||||
@ -29,6 +29,7 @@ do
|
||||
|
||||
local function closeMission(removeAllUnits)
|
||||
if removeAllUnits then
|
||||
TUM.supportWingmen.removeAll()
|
||||
TUM.airForce.removeAll()
|
||||
TUM.ambientWorld.removeAll()
|
||||
TUM.enemyAirDefense.removeAll()
|
||||
@ -72,7 +73,6 @@ do
|
||||
end
|
||||
|
||||
TUM.supportAWACS.create() -- Create the AWACS aircraft if it wasn't airborne already
|
||||
|
||||
TUM.enemyAirDefense.create() -- Must be called once objectives have been created
|
||||
TUM.airForce.create() -- Must be called once objectives have been created
|
||||
TUM.missionMenu.create() -- Must be called once objectives have been created
|
||||
|
||||
@ -46,6 +46,7 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
TUM.supportWingmen.createMenu()
|
||||
TUM.supportAWACS.createMenu()
|
||||
|
||||
if not TUM.settings.getValue(TUM.settings.id.MULTIPLAYER) then -- If not multiplayer, add "show mission score" command
|
||||
|
||||
129
Script/The Universal Mission/SupportWingmen.lua
Normal file
129
Script/The Universal Mission/SupportWingmen.lua
Normal file
@ -0,0 +1,129 @@
|
||||
-- ====================================================================================
|
||||
-- TUM.SUPPORTWINGMEN - HANDLES THE PLAYER'S WINGMEN
|
||||
-- ====================================================================================
|
||||
-- ====================================================================================
|
||||
|
||||
TUM.supportWingmen = {}
|
||||
|
||||
do
|
||||
TUM.supportWingmen.orderID = {
|
||||
ORBIT = 1,
|
||||
REJOIN = 2,
|
||||
}
|
||||
|
||||
local wingmenGroupID = nil
|
||||
|
||||
local function doWingmenOrder(orderID)
|
||||
local player = world:getPlayer()
|
||||
if not player then return end
|
||||
|
||||
if orderID == TUM.supportWingmen.orderID.ORBIT then
|
||||
TUM.radio.playForAll("playerFlightOrbit", nil, player:getCallsign(), false)
|
||||
elseif orderID == TUM.supportWingmen.orderID.REJOIN then
|
||||
TUM.radio.playForAll("playerFlightRejoin", nil, player:getCallsign(), false)
|
||||
end
|
||||
|
||||
if not wingmenGroupID then return end
|
||||
local wingmenGroup = DCSEx.world.getGroupByID(wingmenGroupID)
|
||||
if not wingmenGroup then return end
|
||||
if #wingmenGroup:getUnits() == 0 then return end
|
||||
local wingmenCtrl = wingmenGroup:getController()
|
||||
if not wingmenCtrl then return end
|
||||
|
||||
local wingmanCallsign = wingmenGroup:getUnit(1):getCallsign()
|
||||
|
||||
local taskTable = nil
|
||||
|
||||
if orderID == TUM.supportWingmen.orderID.ORBIT then
|
||||
taskTable = {
|
||||
id = "Orbit",
|
||||
params = {
|
||||
pattern = "Circle",
|
||||
point = DCSEx.math.vec3ToVec2(player:getPoint()),
|
||||
altitude = player:getPoint().y
|
||||
}
|
||||
}
|
||||
TUM.radio.playForAll("pilotWingmanOrbit", nil, wingmanCallsign, true)
|
||||
elseif orderID == TUM.supportWingmen.orderID.REJOIN then
|
||||
taskTable = {
|
||||
id = "Follow",
|
||||
params = {
|
||||
groupId = DCSEx.dcs.getObjectIDAsNumber(world:getPlayer():getGroup()),
|
||||
pos = { x = -100, y = 0, z = -100 },
|
||||
lastWptIndexFlag = false,
|
||||
lastWptIndex = -1
|
||||
}
|
||||
}
|
||||
TUM.radio.playForAll("pilotWingmanRejoin", nil, wingmanCallsign, true)
|
||||
end
|
||||
|
||||
if not taskTable then return end
|
||||
|
||||
wingmenCtrl:setTask(taskTable)
|
||||
end
|
||||
|
||||
local function createWingmen()
|
||||
TUM.supportWingmen.removeAll() -- Destroy all pre-existing wingmen
|
||||
TUM.log("Creating wingmen...")
|
||||
|
||||
local player = world:getPlayer()
|
||||
if not player then return end
|
||||
|
||||
local playerTypeName = player:getTypeName()
|
||||
|
||||
local groupInfo = DCSEx.unitGroupMaker.create(
|
||||
TUM.settings.getPlayerCoalition(),
|
||||
Group.Category.AIRPLANE, -- TODO: or helicopter!
|
||||
DCSEx.math.randomPointInCircle(DCSEx.math.vec3ToVec2(player:getPoint()), 500, 250),
|
||||
{ playerTypeName, playerTypeName },
|
||||
{
|
||||
callsign = DCSEx.unitCallsignMaker.getNextGroupCallSign(player:getCallsign()),
|
||||
silenced = true,
|
||||
taskFollow = DCSEx.dcs.getObjectIDAsNumber(player:getGroup()),
|
||||
unlimitedFuel = true
|
||||
}
|
||||
)
|
||||
|
||||
if not groupInfo then
|
||||
TUM.log("Failed to spawn AI wingmen", TUM.logLevel.WARNING)
|
||||
return
|
||||
end
|
||||
|
||||
TUM.log("Spawned AI wingmen")
|
||||
wingmenGroupID = groupInfo.groupID
|
||||
end
|
||||
|
||||
function TUM.supportWingmen.removeAll()
|
||||
if wingmenGroupID then TUM.log("Removing all wingmen...") end
|
||||
|
||||
DCSEx.world.destroyGroupByID(wingmenGroupID)
|
||||
|
||||
wingmenGroupID = nil
|
||||
end
|
||||
|
||||
function TUM.supportWingmen.createMenu()
|
||||
if TUM.settings.getValue(TUM.settings.id.MULTIPLAYER) then return end -- No wingmen in multiplayer
|
||||
|
||||
local rootPath = missionCommands.addSubMenu("Flight")
|
||||
missionCommands.addCommand("Orbit", rootPath, doWingmenOrder, TUM.supportWingmen.orderID.ORBIT)
|
||||
missionCommands.addCommand("Rejoin", rootPath, doWingmenOrder, TUM.supportWingmen.orderID.REJOIN)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Called when an event is raised
|
||||
-- @param event The DCS World event
|
||||
-------------------------------------
|
||||
function TUM.supportWingmen.onEvent(event)
|
||||
if TUM.settings.getValue(TUM.settings.id.MULTIPLAYER) then return end -- No wingmen in multiplayer
|
||||
if TUM.mission.getStatus() == TUM.mission.status.NONE then return end
|
||||
if not event.initiator then return end
|
||||
if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end
|
||||
if not event.initiator:getPlayerName() then return end
|
||||
|
||||
if event.id == world.event.S_EVENT_TAKEOFF then -- Create wingmen on takeoff
|
||||
createWingmen()
|
||||
elseif event.id == world.event.S_EVENT_LAND then
|
||||
TUM.supportWingmen.removeAll() -- Remove wingmen on landing
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user