Added simulated sling load behaviour

This commit is contained in:
Ciaran Fisher
2015-06-26 09:07:07 +01:00
parent 68b4f23323
commit f85651b3ce
2 changed files with 513 additions and 315 deletions
+279 -101
View File
@@ -10,7 +10,7 @@
See https://github.com/ciribob/DCS-CTLD for a user manual and the latest version See https://github.com/ciribob/DCS-CTLD for a user manual and the latest version
Version: 1.22 - 22/06/2015 - Made FOB crates work if sling load crates are disabled Version: 1.22 - 26/06/2015 - New alternative to real sling loading with simulated sling loading. If you have issues with sling loads crashing the server use this
- Crates in Zone now works for Spawned crates and Ones added by the mission editor - Crates in Zone now works for Spawned crates and Ones added by the mission editor
- Enabled multi crate units - Enabled multi crate units
- Added new parameter for the number of launchers to spawn a HAWK with - Added new parameter for the number of launchers to spawn a HAWK with
@@ -35,6 +35,9 @@ ctld = {} -- DONT REMOVE!
ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below
ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS
ctld.slingLoad = true -- if false, crates can be used WITHOUT slingloading, by hovering above the crate, simulating slingloading but not the weight...
-- There are some bug with Sling-loading that can cause crashes, if these occur set slingLoad to false
-- to use the other method.
ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke
@@ -51,7 +54,7 @@ ctld.vehiclesForTransportBLUE = { "M1045 HMMWV TOW", "M1043 HMMWV Armament" } --
ctld.hawkLaunchers = 3 -- controls how many launchers to add to the hawk when its spawned. ctld.hawkLaunchers = 3 -- controls how many launchers to add to the hawk when its spawned.
ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces
ctld.spawnStinger = false -- spawns a stinger / igla soldier with a group of 6 or more soldiers ctld.spawnStinger = false -- spawns a stinger / igla soldier with a group of 6 or more soldiers!
ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 than when unpacked creates a Forward Operating Base (FOB) which is a new place to spawn (crates) and carry crates from ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 than when unpacked creates a Forward Operating Base (FOB) which is a new place to spawn (crates) and carry crates from
-- In future i'd like it to be a FARP but so far that seems impossible... -- In future i'd like it to be a FARP but so far that seems impossible...
@@ -408,7 +411,7 @@ function ctld.cratesInZone(_zone, _flagNumber)
--in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude --in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude
if _crate ~= nil and _crate:getLife() > 0 if _crate ~= nil and _crate:getLife() > 0
and (_crate:inAir() == false or (land.getHeight(_crate:getPoint()) < 200 and mist.vec.mag(_crate:getVelocity()) < 1.0)) then and (_crate:inAir() == false or (ctld.heightDiff(_crate) < 10.0 and mist.vec.mag(_crate:getVelocity()) < 1.0)) then
local _dist = ctld.getDistance(_crate:getPoint(), _zonePos) local _dist = ctld.getDistance(_crate:getPoint(), _zonePos)
@@ -428,9 +431,7 @@ function ctld.cratesInZone(_zone, _flagNumber)
timer.scheduleFunction(function(_args) timer.scheduleFunction(function(_args)
ctld.cratesInZone(_args[1], _args[2]) ctld.cratesInZone(_args[1], _args[2])
end, { _zone, _flagNumber }, timer.getTime() + 5) end, { _zone, _flagNumber }, timer.getTime() + 5)
end end
-- Creates an extraction zone -- Creates an extraction zone
@@ -478,9 +479,7 @@ function ctld.createExtractZone(_zone, _flagNumber, _smoke)
--run local function --run local function
_smokeFunction(_details) _smokeFunction(_details)
end end
end end
-- Creates a radio beacon on a random UHF - VHF and HF/FM frequency for homing -- Creates a radio beacon on a random UHF - VHF and HF/FM frequency for homing
@@ -505,7 +504,6 @@ function ctld.createRadioBeaconAtZone(_zone, _coalition,_batteryLife)
else else
ctld.createRadioBeacon(_zonePos, 2, 2, false, _batteryLife) --1440 ctld.createRadioBeacon(_zonePos, 2, 2, false, _batteryLife) --1440
end end
end end
-- *************************************************************** -- ***************************************************************
@@ -531,7 +529,9 @@ end
function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight) function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight)
local _crate = { local _crate
if ctld.slingLoad then
_crate = {
["category"] = "Cargo", ["category"] = "Cargo",
["shape_name"] = "ab-212_cargo", ["shape_name"] = "ab-212_cargo",
["type"] = "Cargo1", ["type"] = "Cargo1",
@@ -547,8 +547,24 @@ function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight)
-- ["cargoDisplayName"] = "cargo123", -- ["cargoDisplayName"] = "cargo123",
-- ["CargoDisplayName"] = "cargo123", -- ["CargoDisplayName"] = "cargo123",
} }
else
_crate = {
["shape_name"] = "GeneratorF",
["type"] = "GeneratorF",
["unitId"] = _unitId,
["y"] = _point.z,
["x"] = _point.x,
["name"] = _name,
["category"] = "Fortifications",
["canCargo"] = false,
["heading"] = 0,
}
end
local _spawnedCrate = coalition.addStaticObject(_country, _crate) _crate["country"] = _country
mist.dynAddStatic(_crate)
local _spawnedCrate = StaticObject.getByName(_crate["name"])
--local _spawnedCrate = coalition.addStaticObject(_country, _crate)
return _spawnedCrate return _spawnedCrate
end end
@@ -567,7 +583,12 @@ function ctld.spawnFOBCrateStatic(_country, _unitId, _point, _name)
["heading"] = 0, ["heading"] = 0,
} }
local _spawnedCrate = coalition.addStaticObject(_country, _crate) _crate["country"] = _country
mist.dynAddStatic(_crate)
local _spawnedCrate = StaticObject.getByName(_crate["name"])
--local _spawnedCrate = coalition.addStaticObject(_country, _crate)
return _spawnedCrate return _spawnedCrate
end end
@@ -586,7 +607,10 @@ function ctld.spawnFOB(_country, _unitId, _point, _name)
["heading"] = 0, ["heading"] = 0,
} }
local _spawnedCrate = coalition.addStaticObject(_country, _crate) _crate["country"] = _country
mist.dynAddStatic(_crate)
local _spawnedCrate = StaticObject.getByName(_crate["name"])
--local _spawnedCrate = coalition.addStaticObject(_country, _crate)
local _id = mist.getNextUnitId() local _id = mist.getNextUnitId()
local _tower = { local _tower = {
@@ -600,7 +624,10 @@ function ctld.spawnFOB(_country, _unitId, _point, _name)
["canCargo"] = false, ["canCargo"] = false,
["heading"] = 0, ["heading"] = 0,
} }
coalition.addStaticObject(_country, _tower) --coalition.addStaticObject(_country, _tower)
_tower["country"] = _country
mist.dynAddStatic(_tower)
return _spawnedCrate return _spawnedCrate
end end
@@ -707,8 +734,7 @@ end
function ctld.spawnCrate(_arguments) function ctld.spawnCrate(_arguments)
local _status,_err = pcall( local _status, _err = pcall(function(_args)
function(_args)
-- use the cargo weight to guess the type of unit as no way to add description :( -- use the cargo weight to guess the type of unit as no way to add description :(
@@ -751,16 +777,12 @@ function ctld.spawnCrate(_arguments)
local _position = _heli:getPosition() local _position = _heli:getPosition()
--try to spawn at 12 oclock to us
local _angle = math.atan2(_position.x.z, _position.x.x)
local _xOffset = math.cos(_angle) * 30
local _yOffset = math.sin(_angle) * 30
-- trigger.action.outText("Spawn Crate".._args[1].." ".._args[2],10) -- trigger.action.outText("Spawn Crate".._args[1].." ".._args[2],10)
local _heli = ctld.getTransportUnit(_args[1]) local _heli = ctld.getTransportUnit(_args[1])
local _point = _heli:getPoint() local _point = ctld.getPointAt12Oclock(_heli, 30)
local _unitId = mist.getNextUnitId() local _unitId = mist.getNextUnitId()
@@ -768,7 +790,7 @@ function ctld.spawnCrate(_arguments)
local _name = string.format("%s #%i", _crateType.desc, _unitId) local _name = string.format("%s #%i", _crateType.desc, _unitId)
local _spawnedCrate = ctld.spawnCrateStatic(_heli:getCountry(), _unitId, { x = _point.x + _xOffset, z = _point.z + _yOffset }, _name, _crateType.weight) local _spawnedCrate = ctld.spawnCrateStatic(_heli:getCountry(), _unitId, _point, _name, _crateType.weight)
if _side == 1 then if _side == 1 then
-- _spawnedCrate = coalition.addStaticObject(_side, _spawnedCrate) -- _spawnedCrate = coalition.addStaticObject(_side, _spawnedCrate)
@@ -783,15 +805,24 @@ function ctld.spawnCrate(_arguments)
else else
env.info("Couldn't find crate item to spawn") env.info("Couldn't find crate item to spawn")
end end
end, _arguments)
end
, _arguments)
if (not _status) then if (not _status) then
env.error(string.format("CTLD ERROR: %s", _err)) env.error(string.format("CTLD ERROR: %s", _err))
end end
end end
function ctld.getPointAt12Oclock(_unit, _offset)
local _position = _unit:getPosition()
local _angle = math.atan2(_position.x.z, _position.x.x)
local _xOffset = math.cos(_angle) * _offset
local _yOffset = math.sin(_angle) * _offset
local _point = _unit:getPoint()
return { x = _point.x + _xOffset, z = _point.z + _yOffset, y = _point.y }
end
function ctld.troopsOnboard(_heli, _troops) function ctld.troopsOnboard(_heli, _troops)
if ctld.inTransitTroops[_heli:getName()] ~= nil then if ctld.inTransitTroops[_heli:getName()] ~= nil then
@@ -842,7 +873,6 @@ function ctld.inExtractZone(_heli)
if _dist <= _zoneDetails.radius then if _dist <= _zoneDetails.radius then
return _zoneDetails return _zoneDetails
end end
end end
return false return false
@@ -885,9 +915,7 @@ function ctld.deployTroops(_heli, _troops)
ctld.inTransitTroops[_heli:getName()].troops = nil ctld.inTransitTroops[_heli:getName()].troops = nil
trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " dropped troops from " .. _heli:getTypeName() .. " into " .. _extractZone.name, 10) trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " dropped troops from " .. _heli:getTypeName() .. " into " .. _extractZone.name, 10)
end end
end end
else else
@@ -1325,10 +1353,91 @@ function ctld.checkTransportStatus()
--env.info("CTLD Transport Unit Dead event") --env.info("CTLD Transport Unit Dead event")
ctld.inTransitTroops[_name] = nil ctld.inTransitTroops[_name] = nil
ctld.inTransitFOBCrates[_name] = nil ctld.inTransitFOBCrates[_name] = nil
ctld.inTransitSlingLoadCrates[_name] = nil
end end
end end
end end
function ctld.checkHoverStatus()
-- env.info("checkHoverStatus")
timer.scheduleFunction(ctld.checkHoverStatus, nil, timer.getTime() + 1.0)
local _status, _result = pcall(function()
for _, _name in ipairs(ctld.transportPilotNames) do
local _reset = true
local _transUnit = ctld.getTransportUnit(_name)
--only check transports that are hovering and not planes
if _transUnit ~= nil and ctld.inTransitSlingLoadCrates[_name] == nil and _transUnit:inAir() and ctld.unitCanCarryVehicles(_transUnit) == false then
local _crates = ctld.getCratesAndDistance(_transUnit)
for _, _crate in pairs(_crates) do
-- env.info("CRATE: ".._crate.crateUnit:getName().. " ".._crate.dist)
if _crate.dist < 5.0 and _crate.details.unit ~= "FOB" then
--check height!
local _height = _transUnit:getPoint().y - _crate.crateUnit:getPoint().y
env.info("HEIGHT " .. _name .. " " .. _height .. " " .. _transUnit:getPoint().y .. " " .. _crate.crateUnit:getPoint().y)
-- ctld.heightDiff(_transUnit)
--env.info("HEIGHT ABOVE GROUD ".._name.." ".._height.." ".._transUnit:getPoint().y.." ".._crate.crateUnit:getPoint().y)
if _height > 7.5 and _height <= 12.0 then
local _time = ctld.hoverStatus[_transUnit:getName()]
if _time == nil then
ctld.hoverStatus[_transUnit:getName()] = 10
_time = 10
else
_time = ctld.hoverStatus[_transUnit:getName()] - 1
ctld.hoverStatus[_transUnit:getName()] = _time
end
if _time > 0 then
ctld.displayMessageToGroup(_transUnit, "Hovering above " .. _crate.details.desc .. " crate. \n\nHold hover for " .. _time .. " seconds! \n\nIf the countdown stops you're too far away!", 10)
else
ctld.hoverStatus[_transUnit:getName()] = nil
ctld.displayMessageToGroup(_transUnit, "Loaded " .. _crate.details.desc .. " crate!", 10)
if _transUnit:getCoalition() == 1 then
ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil
else
ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil
end
_crate.crateUnit:destroy()
ctld.inTransitSlingLoadCrates[_name] = _crate.details
end
_reset = false
break
elseif _height <= 7.5 then
ctld.displayMessageToGroup(_transUnit, "Too low to hook " .. _crate.details.desc .. " crate.\n\nHold hover for 10 seconds", 5)
break
else
ctld.displayMessageToGroup(_transUnit, "Too high to hook " .. _crate.details.desc .. " crate.\n\nHold hover for 10 seconds", 5)
break
end
end
end
end
if _reset then
ctld.hoverStatus[_name] = nil
end
end
end)
if (not _status) then
env.error(string.format("CTLD ERROR: %s", _result))
end
end
--recreates beacons to make sure they work! --recreates beacons to make sure they work!
function ctld.refreshRadioBeacons() function ctld.refreshRadioBeacons()
@@ -1348,7 +1457,6 @@ function ctld.refreshRadioBeacons()
table.insert(ctld.freeUHFFrequencies, _freq) table.insert(ctld.freeUHFFrequencies, _freq)
table.remove(ctld.usedUHFFrequencies, _i) table.remove(ctld.usedUHFFrequencies, _i)
end end
end end
for _i, _freq in ipairs(ctld.usedVHFFrequencies) do for _i, _freq in ipairs(ctld.usedVHFFrequencies) do
@@ -1357,7 +1465,6 @@ function ctld.refreshRadioBeacons()
table.insert(ctld.freeVHFFrequencies, _freq) table.insert(ctld.freeVHFFrequencies, _freq)
table.remove(ctld.usedVHFFrequencies, _i) table.remove(ctld.usedVHFFrequencies, _i)
end end
end end
for _i, _freq in ipairs(ctld.usedFMFrequencies) do for _i, _freq in ipairs(ctld.usedFMFrequencies) do
@@ -1366,12 +1473,10 @@ function ctld.refreshRadioBeacons()
table.insert(ctld.freeFMFrequencies, _freq) table.insert(ctld.freeFMFrequencies, _freq)
table.remove(ctld.usedFMFrequencies, _i) table.remove(ctld.usedFMFrequencies, _i)
end end
end end
--clean up beacon table --clean up beacon table
table.remove(ctld.deployedRadioBeacons, _index) table.remove(ctld.deployedRadioBeacons, _index)
end end
end end
end end
@@ -1534,6 +1639,16 @@ function ctld.displayMessageToGroup(_unit, _text, _time)
trigger.action.outTextForGroup(_unit:getGroup():getID(), _text, _time) trigger.action.outTextForGroup(_unit:getGroup():getID(), _text, _time)
end end
function ctld.heightDiff(_unit)
local _point = _unit:getPoint()
env.info("heightunit " .. _point.y)
env.info("heightland " .. land.getHeight({ x = _point.x, y = _point.z }))
return _point.y - land.getHeight({ x = _point.x, y = _point.z })
end
--includes fob crates! --includes fob crates!
function ctld.getCratesAndDistance(_heli) function ctld.getCratesAndDistance(_heli)
@@ -1553,7 +1668,7 @@ function ctld.getCratesAndDistance(_heli)
--in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude --in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude
if _crate ~= nil and _crate:getLife() > 0 if _crate ~= nil and _crate:getLife() > 0
and (_crate:inAir() == false or (land.getHeight(_crate:getPoint()) < 200 and mist.vec.mag(_crate:getVelocity()) < 1.0)) then and (_crate:inAir() == false or (ctld.heightDiff(_crate) < 20.0 and mist.vec.mag(_crate:getVelocity()) < 1.0)) then
local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint()) local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint())
@@ -1646,8 +1761,7 @@ end
function ctld.unpackCrates(_arguments) function ctld.unpackCrates(_arguments)
local _status,_err = pcall( local _status, _err = pcall(function(_args)
function(_args)
-- trigger.action.outText("Unpack Crates".._args[1],10) -- trigger.action.outText("Unpack Crates".._args[1],10)
@@ -1666,12 +1780,12 @@ function ctld.unpackCrates(_arguments)
elseif _crate ~= nil and _crate.dist < 200 then elseif _crate ~= nil and _crate.dist < 200 then
if ctld.inLogisticsZone(_heli) == true then -- if ctld.inLogisticsZone(_heli) == true then
--
ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20) -- ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20)
--
return -- return
end -- end
-- is multi crate? -- is multi crate?
if ctld.isMultiCrate(_crate.details) then if ctld.isMultiCrate(_crate.details) then
@@ -1687,7 +1801,9 @@ function ctld.unpackCrates(_arguments)
-- ctld.spawnCrateStatic( _heli:getCoalition(),mist.getNextUnitId(),{x=100,z=100},_crateName,100) -- ctld.spawnCrateStatic( _heli:getCoalition(),mist.getNextUnitId(),{x=100,z=100},_crateName,100)
--remove crate --remove crate
-- _crate.crateUnit:destroy() if ctld.slingLoad == false then
_crate.crateUnit:destroy()
end
local _spawnedGroups = ctld.spawnCrateGroup(_heli, { _cratePoint }, { _crate.details.unit }) local _spawnedGroups = ctld.spawnCrateGroup(_heli, { _cratePoint }, { _crate.details.unit })
@@ -1804,6 +1920,76 @@ function ctld.unpackFOBCrates(_crates, _heli)
end end
end end
--unloads the sling crate when the helicopter is on the ground or between 4.5 - 10 meters
function ctld.dropSlingCrate(_args)
local _heli = ctld.getTransportUnit(_args[1])
if _heli == nil then
return -- no heli!
end
local _currentCrate = ctld.inTransitSlingLoadCrates[_heli:getName()]
if _currentCrate == nil then
ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate, hover for 10 seconds above the crate", 10)
else
local _heli = ctld.getTransportUnit(_args[1])
local _point = _heli:getPoint()
local _unitId = mist.getNextUnitId()
local _side = _heli:getCoalition()
local _name = string.format("%s #%i", _currentCrate.desc, _unitId)
local _heightDiff = ctld.heightDiff(_heli)
if _heightDiff > 40.0 then
ctld.inTransitSlingLoadCrates[_heli:getName()] = nil
ctld.displayMessageToGroup(_heli, "You were too high! The crate has been destroyed", 10)
return
elseif _heightDiff > 7.5 and _heightDiff <= 40.0 then
ctld.displayMessageToGroup(_heli, _currentCrate.desc .. " crate has been safely dropped below you", 10)
else
ctld.displayMessageToGroup(_heli, _currentCrate.desc .. " crate has been safely unhooked and is at your 12 o'clock", 10)
_point = ctld.getPointAt12Oclock(_heli, 30)
end
--remove crate from cargo
ctld.inTransitSlingLoadCrates[_heli:getName()] = nil
local _spawnedCrate = ctld.spawnCrateStatic(_heli:getCountry(), _unitId, _point, _name, _currentCrate.weight)
if _side == 1 then
-- _spawnedCrate = coalition.addStaticObject(_side, _spawnedCrate)
ctld.spawnedCratesRED[_name] = _currentCrate
else
-- _spawnedCrate = coalition.addStaticObject(_side, _spawnedCrate)
ctld.spawnedCratesBLUE[_name] = _currentCrate
end
end
end
-- shows the status of the current simulated cargo status
function ctld.slingCargoStatus(_args)
local _heli = ctld.getTransportUnit(_args[1])
if _heli == nil then
return -- no heli!
end
local _currentCrate = ctld.inTransitSlingLoadCrates[_heli:getName()]
if _currentCrate == nil then
ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate, hover for 10 seconds above the crate", 10)
else
ctld.displayMessageToGroup(_heli, "Currently Transporting: " .. _currentCrate.desc .. " \n\nTo Pickup a crate, hover for 10 seconds above the crate", 10)
end
end
--spawns a radio beacon made up of two units, --spawns a radio beacon made up of two units,
-- one for VHF and one for UHF -- one for VHF and one for UHF
-- The units are set to to NOT engage -- The units are set to to NOT engage
@@ -1866,7 +2052,6 @@ function ctld.createRadioBeacon(_point, _coalition, _country,_isFOB,_batteryTime
table.insert(ctld.deployedRadioBeacons, _beaconDetails) table.insert(ctld.deployedRadioBeacons, _beaconDetails)
return _beaconDetails return _beaconDetails
end end
function ctld.generateADFFrequencies() function ctld.generateADFFrequencies()
@@ -1929,9 +2114,13 @@ function ctld.spawnRadioBeaconUnit(_point, _country, _type)
-- ["x"] = _positions[1].x, -- ["x"] = _positions[1].x,
["name"] = _type .. " Radio Beacon Group #" .. _groupId, ["name"] = _type .. " Radio Beacon Group #" .. _groupId,
["task"] = {}, ["task"] = {},
--added two fields below for MIST
["category"] = Group.Category.GROUND,
["country"] = _country
} }
return coalition.addGroup(_country, Group.Category.GROUND, _radioGroup) -- return coalition.addGroup(_country, Group.Category.GROUND, _radioGroup)
return Group.getByName(mist.dynAdd(_radioGroup).name)
end end
function ctld.updateRadioBeacon(_beaconDetails) function ctld.updateRadioBeacon(_beaconDetails)
@@ -2082,10 +2271,6 @@ function ctld.listRadioBeacons(_args)
ctld.displayMessageToGroup(_heli, "No Active Radio Beacons", 20) ctld.displayMessageToGroup(_heli, "No Active Radio Beacons", 20)
end end
end end
end end
function ctld.dropRadioBeacon(_args) function ctld.dropRadioBeacon(_args)
@@ -2097,15 +2282,9 @@ function ctld.dropRadioBeacon(_args)
--deploy 50 m infront --deploy 50 m infront
--try to spawn at 12 oclock to us --try to spawn at 12 oclock to us
local _position = _heli:getPosition() local _point = ctld.getPointAt12Oclock(_heli, 50)
local _point = _heli:getPoint()
local _angle = math.atan2(_position.x.z, _position.x.x) local _radioBeaconDetails = ctld.createRadioBeacon(_point, _heli:getCoalition(), _heli:getCountry(), false)
local _xOffset = math.cos(_angle) * 50
local _yOffset = math.sin(_angle) * 50
local _radioBeaconDetails = ctld.createRadioBeacon({ x = _point.x + _xOffset, z = _point.z + _yOffset }, _heli:getCoalition(),_heli:getCountry(),false)
-- mark with flare? -- mark with flare?
@@ -2114,8 +2293,6 @@ function ctld.dropRadioBeacon(_args)
else else
ctld.displayMessageToGroup(_heli, "You need to land before you can deploy a Radio Beacon!", 20) ctld.displayMessageToGroup(_heli, "You need to land before you can deploy a Radio Beacon!", 20)
end end
end end
--remove closet radio beacon --remove closet radio beacon
@@ -2174,8 +2351,6 @@ function ctld.removeRadioBeacon(_args)
else else
ctld.displayMessageToGroup(_heli, "You need to land before remove a Radio Beacon", 20) ctld.displayMessageToGroup(_heli, "You need to land before remove a Radio Beacon", 20)
end end
end end
--function ctld.generateRadioFMRadioFrequency() --function ctld.generateRadioFMRadioFrequency()
@@ -2381,7 +2556,6 @@ function ctld.unpackHawk(_heli, _nearestCrate, _nearbyCrates)
table.insert(_posArray, _hawkPart.crateUnit:getPoint()) table.insert(_posArray, _hawkPart.crateUnit:getPoint())
table.insert(_typeArray, _name) table.insert(_typeArray, _name)
end end
end end
end end
@@ -2402,7 +2576,9 @@ function ctld.unpackHawk(_heli, _nearestCrate, _nearbyCrates)
end end
--destroy --destroy
-- _hawkPart.crateUnit:destroy() if ctld.slingLoad == false then
_hawkPart.crateUnit:destroy()
end
end end
-- HAWK READY! -- HAWK READY!
@@ -2515,7 +2691,13 @@ function ctld.spawnCrateGroup(_heli, _positions, _types)
end end
end end
local _spawnedGroup = coalition.addGroup(_heli:getCountry(), Group.Category.GROUND, _group) --mist function
_group.category = Group.Category.GROUND;
_group.country = _heli:getCountry();
local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name)
--local _spawnedGroup = coalition.addGroup(_heli:getCountry(), Group.Category.GROUND, _group)
--activate by moving and so we can set ROE and Alarm state --activate by moving and so we can set ROE and Alarm state
@@ -2576,7 +2758,13 @@ function ctld.spawnDroppedGroup(_point, _details, _spawnBehind, _maxSearch)
end end
end end
local _spawnedGroup = coalition.addGroup(_details.country, Group.Category.GROUND, _group) --switch to MIST
_group.category = Group.Category.GROUND;
_group.country = _details.country;
local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name)
--local _spawnedGroup = coalition.addGroup(_details.country, Group.Category.GROUND, _group)
-- find nearest enemy and head there -- find nearest enemy and head there
@@ -3016,8 +3204,7 @@ end
function ctld.addF10MenuOptions() function ctld.addF10MenuOptions()
-- Loop through all Heli units -- Loop through all Heli units
pcall( pcall(function()
function()
for _, _unitName in pairs(ctld.transportPilotNames) do for _, _unitName in pairs(ctld.transportPilotNames) do
local _unit = ctld.getTransportUnit(_unitName) local _unit = ctld.getTransportUnit(_unitName)
@@ -3031,6 +3218,7 @@ function ctld.addF10MenuOptions()
local _rootPath = missionCommands.addSubMenuForGroup(_groupId, "CTLD") local _rootPath = missionCommands.addSubMenuForGroup(_groupId, "CTLD")
local _troopCommandsPath = missionCommands.addSubMenuForGroup(_groupId, "Troop Transport", _rootPath) local _troopCommandsPath = missionCommands.addSubMenuForGroup(_groupId, "Troop Transport", _rootPath)
missionCommands.addCommandForGroup(_groupId, "Load / Unload Troops", _troopCommandsPath, ctld.loadUnloadTroops, { _unitName, true }) missionCommands.addCommandForGroup(_groupId, "Load / Unload Troops", _troopCommandsPath, ctld.loadUnloadTroops, { _unitName, true })
if ctld.unitCanCarryVehicles(_unit) then if ctld.unitCanCarryVehicles(_unit) then
@@ -3055,7 +3243,8 @@ function ctld.addF10MenuOptions()
local _cratePath = missionCommands.addSubMenuForGroup(_groupId, _subMenuName, _rootPath) local _cratePath = missionCommands.addSubMenuForGroup(_groupId, _subMenuName, _rootPath)
for _, _crate in pairs(_crates) do for _, _crate in pairs(_crates) do
if ctld.isJTACUnitType(_crate.unit) == false or (ctld.isJTACUnitType(_crate.unit) == true and ctld.JTAC_dropEnabled) then if ctld.isJTACUnitType(_crate.unit) == false
or (ctld.isJTACUnitType(_crate.unit) == true and ctld.JTAC_dropEnabled) then
if _crate.side == nil or (_crate.side == _unit:getCoalition()) then if _crate.side == nil or (_crate.side == _unit:getCoalition()) then
missionCommands.addCommandForGroup(_groupId, _crate.desc, _cratePath, ctld.spawnCrate, { _unitName, _crate.weight }) missionCommands.addCommandForGroup(_groupId, _crate.desc, _cratePath, ctld.spawnCrate, { _unitName, _crate.weight })
end end
@@ -3063,21 +3252,31 @@ function ctld.addF10MenuOptions()
end end
end end
end end
end
if ctld.enabledFOBBuilding or ctld.enableCrates then
local _crateCommands = missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands", _rootPath) local _crateCommands = missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands", _rootPath)
missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", _crateCommands, ctld.listNearbyCrates, { _unitName }) missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", _crateCommands, ctld.listNearbyCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", _crateCommands, ctld.unpackCrates, { _unitName }) missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", _crateCommands, ctld.unpackCrates, { _unitName })
if ctld.slingLoad == false then
missionCommands.addCommandForGroup(_groupId, "Drop Crate", _crateCommands, ctld.dropSlingCrate, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Current Cargo Status", _crateCommands, ctld.slingCargoStatus, { _unitName })
end
if ctld.enabledFOBBuilding then if ctld.enabledFOBBuilding then
missionCommands.addCommandForGroup(_groupId, "List FOBs", _crateCommands, ctld.listFOBS, { _unitName }) missionCommands.addCommandForGroup(_groupId, "List FOBs", _crateCommands, ctld.listFOBS, { _unitName })
end end
end
if ctld.enableSmokeDrop then if ctld.enableSmokeDrop then
local _smokeCommands = missionCommands.addSubMenuForGroup(_groupId, "Smoke Markers", _rootPath) missionCommands.addSubMenuForGroup(_groupId, "Smoke Markers")
missionCommands.addCommandForGroup(_groupId, "Drop Red Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Red }) missionCommands.addCommandForGroup(_groupId, "Drop Red Smoke", { "Smoke Markers" }, ctld.dropSmoke, { _unitName, trigger.smokeColor.Red })
missionCommands.addCommandForGroup(_groupId, "Drop Blue Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue }) missionCommands.addCommandForGroup(_groupId, "Drop Blue Smoke", { "Smoke Markers" }, ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue })
missionCommands.addCommandForGroup(_groupId, "Drop Orange Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange }) missionCommands.addCommandForGroup(_groupId, "Drop Orange Smoke", { "Smoke Markers" }, ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange })
missionCommands.addCommandForGroup(_groupId, "Drop Green Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Green }) missionCommands.addCommandForGroup(_groupId, "Drop Green Smoke", { "Smoke Markers" }, ctld.dropSmoke, { _unitName, trigger.smokeColor.Green })
end end
if ctld.enabledRadioBeaconDrop then if ctld.enabledRadioBeaconDrop then
@@ -3085,33 +3284,6 @@ function ctld.addF10MenuOptions()
missionCommands.addCommandForGroup(_groupId, "List Beacons", _radioCommands, ctld.listRadioBeacons, { _unitName }) missionCommands.addCommandForGroup(_groupId, "List Beacons", _radioCommands, ctld.listRadioBeacons, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Drop Beacon", _radioCommands, ctld.dropRadioBeacon, { _unitName }) missionCommands.addCommandForGroup(_groupId, "Drop Beacon", _radioCommands, ctld.dropRadioBeacon, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Remove Closet Beacon", _radioCommands, ctld.removeRadioBeacon, { _unitName }) missionCommands.addCommandForGroup(_groupId, "Remove Closet Beacon", _radioCommands, ctld.removeRadioBeacon, { _unitName })
end
else
if ctld.enableSmokeDrop then
local _smokeCommands = missionCommands.addSubMenuForGroup(_groupId, "Smoke Markers", _rootPath)
missionCommands.addCommandForGroup(_groupId, "Drop Red Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Red })
missionCommands.addCommandForGroup(_groupId, "Drop Blue Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue })
missionCommands.addCommandForGroup(_groupId, "Drop Orange Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange })
missionCommands.addCommandForGroup(_groupId, "Drop Green Smoke", _smokeCommands, ctld.dropSmoke, { _unitName, trigger.smokeColor.Green })
end
if ctld.enabledRadioBeaconDrop then
local _radioCommands = missionCommands.addSubMenuForGroup(_groupId, "Radio Beacons", _rootPath)
missionCommands.addCommandForGroup(_groupId, "List Beacons", _radioCommands, ctld.listRadioBeacons, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Drop Beacon", _radioCommands, ctld.dropRadioBeacon, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Remove Closet Beacon", _radioCommands, ctld.removeRadioBeacon, { _unitName })
end
if ctld.enabledFOBBuilding then
local _crateCommands = missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands", _rootPath)
missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", _crateCommands, ctld.listNearbyCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", _crateCommands, ctld.unpackCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, "List FOBs", _crateCommands, ctld.listFOBS, { _unitName })
end
end end
ctld.addedTo[tostring(_groupId)] = true ctld.addedTo[tostring(_groupId)] = true
@@ -3138,8 +3310,7 @@ function ctld.addF10MenuOptions()
-- get all RED players -- get all RED players
ctld.addJTACRadioCommand(1) ctld.addJTACRadioCommand(1)
end end
end end)
)
timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5)
end end
@@ -3160,7 +3331,6 @@ function ctld.addRadioListCommand(_side)
end end
end end
end end
end end
function ctld.addJTACRadioCommand(_side) function ctld.addJTACRadioCommand(_side)
@@ -3955,6 +4125,8 @@ ctld.inTransitTroops = {}
ctld.inTransitFOBCrates = {} ctld.inTransitFOBCrates = {}
ctld.inTransitSlingLoadCrates = {} -- stores crates that are being transported by helicopters for alternative to real slingload
ctld.droppedFOBCratesRED = {} ctld.droppedFOBCratesRED = {}
ctld.droppedFOBCratesBLUE = {} ctld.droppedFOBCratesBLUE = {}
@@ -3980,6 +4152,7 @@ ctld.crateLookupTable = {}
ctld.extractZones = {} -- stored extract zones ctld.extractZones = {} -- stored extract zones
ctld.missionEditorCargoCrates = {} --crates added by mission editor for triggering cratesinzone ctld.missionEditorCargoCrates = {} --crates added by mission editor for triggering cratesinzone
ctld.hoverStatus = {} -- tracks status of a helis hover above a crate
-- Remove intransit troops when heli / cargo plane dies -- Remove intransit troops when heli / cargo plane dies
--ctld.eventHandler = {} --ctld.eventHandler = {}
@@ -4057,6 +4230,10 @@ timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 5)
timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 5)
timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 5)
if ctld.enableCrates == true and ctld.slingLoad == false then
timer.scheduleFunction(ctld.checkHoverStatus, nil, timer.getTime() + 1)
end
--event handler for deaths --event handler for deaths
--world.addEventHandler(ctld.eventHandler) --world.addEventHandler(ctld.eventHandler)
@@ -4124,6 +4301,7 @@ env.info("END search for crates")
env.info("CTLD READY") env.info("CTLD READY")
--DEBUG FUNCTION --DEBUG FUNCTION
-- for key, value in pairs(getmetatable(_spawnedCrate)) do -- for key, value in pairs(getmetatable(_spawnedCrate)) do
-- env.info(tostring(key)) -- env.info(tostring(key))
+23 -3
View File
@@ -43,7 +43,7 @@ You can also edit the CTLD.lua file to change some configuration options. Make s
##Setup in Mission Editor ##Setup in Mission Editor
###Script Setup ###Script Setup
**This script requires MIST version 3.6 or above: https://github.com/mrSkortch/MissionScriptingTools** **This script requires MIST version 3.7 or above: https://github.com/mrSkortch/MissionScriptingTools**
First make sure MIST is loaded, either as an Initialization Script for the mission or the first DO SCRIPT with a "TIME MORE" of 1. "TIME MORE" means run the actions after X seconds into the mission. First make sure MIST is loaded, either as an Initialization Script for the mission or the first DO SCRIPT with a "TIME MORE" of 1. "TIME MORE" means run the actions after X seconds into the mission.
@@ -59,6 +59,15 @@ An example is shown below:
###Script Configuration ###Script Configuration
The script has lots of configuration options that can be used to further customise the behaviour. The script has lots of configuration options that can be used to further customise the behaviour.
**If you experience crashes with Sling-loading, such as a game crash when shotdown, you can use the simulated sling-load behaviour instead to work around the DCS Bugs.**
To use the simulated behaviour, set the ```ctld.slingLoad``` option to ```false```.
The simulated Sling Loading will use a generator static instead of a crate and you just hover above it for 10 seconds to load it. No Need to use the F6 menu to first select the crate.
The crate can then be dropped using the CTLD Commands section of the Radio menu. Make sure you're not too high when the crate is dropped or it will be destroyed!
Unfortunately there is no way to simulate the added weight of the Simulated Sling Load.
```lua ```lua
-- ************************************************************************ -- ************************************************************************
@@ -67,6 +76,9 @@ The script has lots of configuration options that can be used to further customi
ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below
ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS
ctld.slingLoad = true -- if false, crates can be used WITHOUT slingloading, by hovering above the crate, simulating slingloading but not the weight...
-- There are some bug with Sling-loading that can cause crashes, if these occur set slingLoad to false
-- to use the other method.
ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke
@@ -83,7 +95,7 @@ ctld.vehiclesForTransportBLUE = { "M1045 HMMWV TOW", "M1043 HMMWV Armament" } --
ctld.hawkLaunchers = 3 -- controls how many launchers to add to the hawk when its spawned. ctld.hawkLaunchers = 3 -- controls how many launchers to add to the hawk when its spawned.
ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces
ctld.spawnStinger = false -- spawns a stinger / igla soldier with every group of 5 or more men. ctld.spawnStinger = false -- spawns a stinger / igla soldier with a group of 6 or more soldiers!
ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 than when unpacked creates a Forward Operating Base (FOB) which is a new place to spawn (crates) and carry crates from ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 than when unpacked creates a Forward Operating Base (FOB) which is a new place to spawn (crates) and carry crates from
-- In future i'd like it to be a FARP but so far that seems impossible... -- In future i'd like it to be a FARP but so far that seems impossible...
@@ -446,7 +458,7 @@ The C-130 / IL-76 can also load and unload FOB crates from a Logistics area, see
##Cargo Spawning and Sling Loading ##Cargo Spawning and Sling Loading
Cargo can be spawned by transport helicopters if they are close enough to a friendly logistics unit using the F10 menu. Everything except the HAWK AA Missile system requires only one crate to build. Crates are always spawned off the nose of the unit that requested them. Sling cargo weight differs drastically depending on what you are sling loading. The Huey will need to have 20% fuel and no armaments in order to be able to lift a HMMWV TOW crate! The Mi-8 has a higher max lifting weight than a Huey. Cargo can be spawned by transport helicopters if they are close enough to a friendly logistics unit using the F10 menu. Crates are always spawned off the nose of the unit that requested them. Sling cargo weight differs drastically depending on what you are sling loading. The Huey will need to have 20% fuel and no armaments in order to be able to lift a HMMWV TOW crate! The Mi-8 has a higher max lifting weight than a Huey.
Once spawning the crate, to slingload the F6 menu needs to be used to select a cargo of the correct weight. If you've selected the right cargo RED smoke will appear and you can now sling load by hovering over the crate at a height of 15-30 feet or so. Once spawning the crate, to slingload the F6 menu needs to be used to select a cargo of the correct weight. If you've selected the right cargo RED smoke will appear and you can now sling load by hovering over the crate at a height of 15-30 feet or so.
@@ -463,6 +475,14 @@ You can also list nearby crates that have yet to be unpacked using the F10 CTLD
*Crate damage in the script is currently not implemented so as long as the crate isn't destroyed, you should always be able to unpack.* *Crate damage in the script is currently not implemented so as long as the crate isn't destroyed, you should always be able to unpack.*
**If you experience crashes with Sling-loading, such as a game crash when shotdown, you can use the simulated sling-load behaviour instead to work around the DCS Bugs.**
To use the simulated behaviour, set the ```ctld.slingLoad``` option to ```false```.
The simulated Sling Loading will use a Generator static object instead of a crate and you just hover above it for 10 seconds to load it. No Need to use the F6 menu to first select the crate.
The crate can then be dropped using the CTLD Commands section of the Radio menu. Make sure you're not too high when the crate is dropped or it will be destroyed!
Unfortunately there is no way to simulate the added weight of the Simulated Sling Load.
##Crate Unpacking ##Crate Unpacking
Once you have sling loaded and successfully dropped your crate, you can land and list nearby crates that have yet to be unpacked using the F10 Crate Commands Menu, as well as unpack nearby crates using the same menu. Crates cannot be unpacked near a logistics unit. Once you have sling loaded and successfully dropped your crate, you can land and list nearby crates that have yet to be unpacked using the F10 Crate Commands Menu, as well as unpack nearby crates using the same menu. Crates cannot be unpacked near a logistics unit.