Beacons Added

Added Radio Beacons to built FOBS
Added Radio menu option to list FOB locations
Merge building of Fobs and normal crates so only 1 radio command is
needed
This commit is contained in:
Ciaran Fisher
2015-05-30 14:42:14 +01:00
parent 177690195d
commit 33bd399654
4 changed files with 300 additions and 130 deletions
+300 -130
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.05 - 24/05/2015 - Event Bug Fix from Latest DCS Patch Version: 1.06 - 29/05/2015 - Event Bug Fix from Latest DCS Patch
]] ]]
@@ -48,6 +48,7 @@ ctld.troopPickupAtFOB = true -- if true, troops can also be picked up at a creat
ctld.buildTimeFOB = 120 --time in seconds for the FOB to be built ctld.buildTimeFOB = 120 --time in seconds for the FOB to be built
ctld.radioSound = "beacon.ogg" -- the name of the sound file to use for the FOB radio beacons
-- ***************** JTAC CONFIGURATION ***************** -- ***************** JTAC CONFIGURATION *****************
@@ -896,10 +897,10 @@ function ctld.loadUnloadFOBCrate(_args)
else else
-- nearest Crate -- nearest Crate
local _crates = ctld.getFOBCratesAndDistance(_heli) local _crates = ctld.getCratesAndDistance(_heli)
local _nearestCrate = ctld.getClosestCrate(_heli, _crates) local _nearestCrate = ctld.getClosestCrate(_heli, _crates, "FOB")
if _nearestCrate ~= nil and _nearestCrate.dist < 100 then if _nearestCrate ~= nil and _nearestCrate.dist < 150 then
ctld.displayMessageToGroup(_heli, "FOB Crate Loaded", 10) ctld.displayMessageToGroup(_heli, "FOB Crate Loaded", 10)
ctld.inTransitFOBCrates[_heli:getName()] = true ctld.inTransitFOBCrates[_heli:getName()] = true
@@ -1143,6 +1144,68 @@ function ctld.checkTransportStatus()
end end
--recreates beacons to make sure they work!
function ctld.refreshRadioBeacons()
timer.scheduleFunction(ctld.refreshRadioBeacons,nil,timer.getTime()+60)
for _fobName,_beaconDetails in ipairs(ctld.fobBeacons) do
local _fob = StaticObject.getByName(_fobName)
if _fob ~= nil and _fob:isExist() and _fob:getLife() > 0 then
ctld.createRadioBeacon(_beaconDetails.frequency,_fob:getPoint())
end
end
end
function ctld.getClockDirection(_heli,_crate)
-- Source: Helicopter Script - Thanks!
local _position = _crate:getPosition().p -- get position of crate
local _playerPosition = _heli:getPosition().p -- get position of helicopter
local _relativePosition = mist.vec.sub(_position,_playerPosition)
local _playerHeading = mist.getHeading(_heli) -- the rest of the code determines the 'o'clock' bearing of the missile relative to the helicopter
local _headingVector = {x = math.cos(_playerHeading),y=0,z=math.sin(_playerHeading)}
local _headingVectorPerpendicular = {x = math.cos(_playerHeading+math.pi/2),y=0,z=math.sin(_playerHeading+math.pi/2)}
local _forwardDistance = mist.vec.dp(_relativePosition,_headingVector)
local _rightDistance = mist.vec.dp(_relativePosition,_headingVectorPerpendicular)
local _angle = math.atan2(_rightDistance,_forwardDistance)*180/math.pi
if _angle < 0 then
_angle = 360+_angle
end
_angle = math.floor(_angle*12/360+0.5)
if _angle == 0 then
_angle = 12
end
return _angle
end
function ctld.getCompassBearing(_ref,_unitPos)
_ref = mist.utils.makeVec3(_ref, 0) -- turn it into Vec3 if it is not already.
_unitPos = mist.utils.makeVec3(_unitPos,0) -- turn it into Vec3 if it is not already.
local _vec = {x = _unitPos.x - _ref.x, y = _unitPos.y - _ref.y, z = _unitPos.z - _ref.z}
local _dir = mist.utils.getDir(_vec, _ref)
local _bearing = mist.utils.round(mist.utils.toDegree(_dir), 0)
return _bearing
end
function ctld.listNearbyCrates(_args) function ctld.listNearbyCrates(_args)
local _message = "" local _message = ""
@@ -1158,18 +1221,17 @@ function ctld.listNearbyCrates(_args)
for _, _crate in pairs(_crates) do for _, _crate in pairs(_crates) do
if _crate.dist < 1000 then if _crate.dist < 1000 and _crate.details.unit ~= "FOB" then
_message = string.format("%s\n%s crate - kg %i - %i m", _message, _crate.details.desc, _crate.details.weight, _crate.dist) _message = string.format("%s\n%s crate - kg %i - %i m - %d o'clock", _message, _crate.details.desc, _crate.details.weight, _crate.dist,ctld.getClockDirection(_heli,_crate.crateUnit))
end end
end end
local _fobCrates = ctld.getFOBCratesAndDistance(_heli)
local _fobMsg = "" local _fobMsg = ""
for _, _fobCrate in pairs(_fobCrates) do for _, _fobCrate in pairs(_crates) do
if _fobCrate.dist < 1000 then if _fobCrate.dist < 1000 and _fobCrate.details.unit == "FOB" then
_fobMsg = _fobMsg..string.format("FOB Crate - %d m\n", _fobCrate.dist) _fobMsg = _fobMsg..string.format("FOB Crate - %d m - %d o'clock\n", _fobCrate.dist, ctld.getClockDirection(_heli,_fobCrate.crateUnit))
end end
end end
@@ -1202,22 +1264,72 @@ function ctld.listNearbyCrates(_args)
end end
end end
function ctld.listFOBS(_args)
local _msg = "FOB Positions:"
local _heli = ctld.getTransportUnit(_args[1])
if _heli == nil then
return -- no heli!
end
-- get fob positions
local _fobs = ctld.getSpawnedFobs(_heli)
-- now check spawned fobs
for _, _fob in ipairs(_fobs) do
_msg = string.format("%s\nFOB @ %s", _msg, ctld.getFOBPositionString(_fob))
end
if _msg == "FOB Positions:" then
ctld.displayMessageToGroup(_heli, "Sorry, there are no active FOBs!", 20)
else
ctld.displayMessageToGroup(_heli, _msg, 20)
end
end
function ctld.getFOBPositionString(_fob)
local _lat, _lon = coord.LOtoLL(_fob:getPosition().p)
local _latLngStr = mist.tostringLL(_lat, _lon,3,false)
local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_fob:getPosition().p)),5)
local _message = _latLngStr .. " - MGRS ".._mgrsString
local _beaconInfo = ctld.fobBeacons[_fob:getName()]
if _beaconInfo ~=nil then
_message= string.format("%s - %.2f FM", _message,_beaconInfo.frequency / 1000000)
end
return _message
end
function ctld.displayMessageToGroup(_unit, _text, _time) function ctld.displayMessageToGroup(_unit, _text, _time)
trigger.action.outTextForGroup(_unit:getGroup():getID(), _text, _time) trigger.action.outTextForGroup(_unit:getGroup():getID(), _text, _time)
end end
--includes fob crates!
function ctld.getCratesAndDistance(_heli) function ctld.getCratesAndDistance(_heli)
local _crates = {} local _crates = {}
local _allCrates local _allCrates
if _heli:getCoalition() == 1 then if _heli:getCoalition() == 1 then
_allCrates = ctld.spawnedCratesRED _allCrates = ctld.spawnedCratesRED
else else
_allCrates = ctld.spawnedCratesBLUE _allCrates = ctld.spawnedCratesBLUE
end end
@@ -1238,23 +1350,14 @@ function ctld.getCratesAndDistance(_heli)
end end
end end
return _crates local _fobCrates
end
function ctld.getFOBCratesAndDistance(_heli)
local _crates = {}
local _allCrates
if _heli:getCoalition() == 1 then if _heli:getCoalition() == 1 then
_fobCrates = ctld.droppedFOBCratesRED
_allCrates = ctld.droppedFOBCratesRED
else else
_fobCrates = ctld.droppedFOBCratesBLUE
_allCrates = ctld.droppedFOBCratesBLUE
end end
for _crateName, _details in pairs(_allCrates) do for _crateName, _details in pairs(_fobCrates) do
--get crate --get crate
local _crate = StaticObject.getByName(_crateName) local _crate = StaticObject.getByName(_crateName)
@@ -1263,7 +1366,7 @@ function ctld.getFOBCratesAndDistance(_heli)
local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint()) local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint())
local _crateDetails = { crateUnit = _crate, dist = _dist, details = {} } local _crateDetails = { crateUnit = _crate, dist = _dist, details = {unit="FOB"}, }
table.insert(_crates, _crateDetails) table.insert(_crates, _crateDetails)
end end
@@ -1272,7 +1375,8 @@ function ctld.getFOBCratesAndDistance(_heli)
return _crates return _crates
end end
function ctld.getClosestCrate(_heli, _crates)
function ctld.getClosestCrate(_heli, _crates,_type)
local _closetCrate = nil local _closetCrate = nil
local _shortestDistance = -1 local _shortestDistance = -1
@@ -1280,11 +1384,13 @@ function ctld.getClosestCrate(_heli, _crates)
for _, _crate in pairs(_crates) do for _, _crate in pairs(_crates) do
_distance = _crate.dist if(_crate.details.unit == _type or _type == nil) then
_distance = _crate.dist
if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then
_shortestDistance = _distance _shortestDistance = _distance
_closetCrate = _crate _closetCrate = _crate
end
end end
end end
@@ -1339,14 +1445,20 @@ function ctld.unpackCrates(_args)
local _crates = ctld.getCratesAndDistance(_heli) local _crates = ctld.getCratesAndDistance(_heli)
local _crate = ctld.getClosestCrate(_heli, _crates) local _crate = ctld.getClosestCrate(_heli, _crates)
if _crate ~= nil and _crate.dist < 200 then if _crate ~= nil and _crate.dist < 750 and _crate.details.unit == "FOB" then
if ctld.inLogisticsZone(_heli) == true then ctld.unpackFOBCrates(_crates,_heli)
ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20) return
return elseif _crate ~= nil and _crate.dist < 200 then
end
-- if ctld.inLogisticsZone(_heli) == true then
--
-- ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20)
--
-- return
-- end
-- is multi crate? -- is multi crate?
if ctld.isMultiCrate(_crate.details) then if ctld.isMultiCrate(_crate.details) then
@@ -1393,95 +1505,132 @@ end
-- builds a fob! -- builds a fob!
function ctld.unpackFOBCrates(_args) function ctld.unpackFOBCrates(_crates,_heli)
local _heli = ctld.getTransportUnit(_args[1]) -- if ctld.inLogisticsZone(_heli) == true then
--
-- ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20)
--
-- return
-- end
if _heli ~= nil and _heli:inAir() == false then -- unpack multi crate
local _nearbyMultiCrates = {}
local _crates = ctld.getFOBCratesAndDistance(_heli) for _, _nearbyCrate in pairs(_crates) do
local _nearestCrate = ctld.getClosestCrate(_heli, _crates)
if _nearestCrate ~= nil and _nearestCrate.dist < 750 then if _nearbyCrate.dist < 750 and _nearbyCrate.details.unit == "FOB" then
if ctld.inLogisticsZone(_heli) == true then table.insert(_nearbyMultiCrates, _nearbyCrate)
ctld.displayMessageToGroup(_heli, "You can't unpack the FOB here! Take it to where it's needed!", 20)
return
end
-- unpack multi crate
local _nearbyMultiCrates = {}
for _, _nearbyCrate in pairs(_crates) do
if _nearbyCrate.dist < 750 then
table.insert(_nearbyMultiCrates, _nearbyCrate)
if #_nearbyMultiCrates == ctld.cratesRequiredForFOB then
break
end
end
end
--- check crate count
if #_nearbyMultiCrates == ctld.cratesRequiredForFOB then if #_nearbyMultiCrates == ctld.cratesRequiredForFOB then
break
-- destroy crates
local _points = {}
for _, _crate in pairs(_nearbyMultiCrates) do
if _heli:getCoalition() == 1 then
ctld.droppedFOBCratesRED[_crate.crateUnit:getName()] = nil
else
ctld.droppedFOBCratesRED[_crate.crateUnit:getName()] = nil
end
table.insert(_points, _crate.crateUnit:getPoint())
--destroy
_crate.crateUnit:destroy()
end
local _centroid = ctld.getCentroid(_points)
timer.scheduleFunction(
function(_args)
local _unitId = mist.getNextUnitId()
local _name = "Deployed FOB #".._unitId
local _fob = ctld.spawnFOB(_args[2],_unitId,_args[1],_name)
--make it able to deploy crates
table.insert(ctld.logisticUnits, _fob:getName())
if ctld.troopPickupAtFOB == true then
table.insert(ctld.builtFOBS, _fob:getName())
trigger.action.outTextForCoalition(_args[3],"Finished building FOB! Crates and Troops can now be picked up.", 10)
else
trigger.action.outTextForCoalition(_args[3],"Finished building FOB! Crates can now be picked up.", 10)
end
end, {_centroid, _heli:getCountry(),_heli:getCoalition()}, timer.getTime() + ctld.buildTimeFOB)
local _txt = string.format("%s started building FOB using %d FOB crates, it will be finished in %d seconds.\nPosition marked with smoke.",ctld.getPlayerNameOrType(_heli),#_nearbyMultiCrates,ctld.buildTimeFOB)
trigger.action.smoke(_centroid,trigger.smokeColor.Green)
trigger.action.outTextForCoalition(_heli:getCoalition(), _txt, 10)
else
local _txt = string.format("Cannot build FOB!\n\nIt requires %d FOB crates and there are %d \n\nOr the crates are not within 750m of each other",ctld.cratesRequiredForFOB,#_nearbyMultiCrates)
ctld.displayMessageToGroup(_heli, _txt, 20)
end end
else
ctld.displayMessageToGroup(_heli, "No friendly FOB crates close enough to unpack", 20)
end end
end end
--- check crate count
if #_nearbyMultiCrates == ctld.cratesRequiredForFOB then
-- destroy crates
local _points = {}
for _, _crate in pairs(_nearbyMultiCrates) do
if _heli:getCoalition() == 1 then
ctld.droppedFOBCratesRED[_crate.crateUnit:getName()] = nil
else
ctld.droppedFOBCratesRED[_crate.crateUnit:getName()] = nil
end
table.insert(_points, _crate.crateUnit:getPoint())
--destroy
_crate.crateUnit:destroy()
end
local _centroid = ctld.getCentroid(_points)
timer.scheduleFunction(
function(_args)
local _unitId = mist.getNextUnitId()
local _name = "Deployed FOB #".._unitId
local _fob = ctld.spawnFOB(_args[2],_unitId,_args[1],_name)
--make it able to deploy crates
table.insert(ctld.logisticUnits, _fob:getName())
local _frequency = ctld.generateRadioFMRadioFrequency()
ctld.fobBeacons[_name] = {frequency=_frequency, point=_fob:getPoint() }
--started radio beacon
ctld.createRadioBeacon(_frequency,_fob:getPoint())
if ctld.troopPickupAtFOB == true then
table.insert(ctld.builtFOBS, _fob:getName())
trigger.action.outTextForCoalition(_args[3],"Finished building FOB! Crates and Troops can now be picked up.", 10)
else
trigger.action.outTextForCoalition(_args[3],"Finished building FOB! Crates can now be picked up.", 10)
end
end, {_centroid, _heli:getCountry(),_heli:getCoalition()}, timer.getTime() + ctld.buildTimeFOB)
local _txt = string.format("%s started building FOB using %d FOB crates, it will be finished in %d seconds.\nPosition marked with smoke.",ctld.getPlayerNameOrType(_heli),#_nearbyMultiCrates,ctld.buildTimeFOB)
trigger.action.smoke(_centroid,trigger.smokeColor.Green)
trigger.action.outTextForCoalition(_heli:getCoalition(), _txt, 10)
else
local _txt = string.format("Cannot build FOB!\n\nIt requires %d FOB crates and there are %d \n\nOr the crates are not within 750m of each other",ctld.cratesRequiredForFOB,#_nearbyMultiCrates)
ctld.displayMessageToGroup(_heli, _txt, 20)
end
end
function ctld.createRadioBeacon(_frequency, _point)
trigger.action.radioTransmission(ctld.radioSound, _point, 1, true, _frequency, 1000)
end
function ctld.generateRadioFMRadioFrequency()
--pick random frequency!
-- first digit 3-7
-- second digit 0-5
-- third digit 0-9
-- fourth digit 0 or 5
-- times by 10000
local _first = math.random(3,7)
local _second = math.random(0,5)
local _third = math.random(0,9)
local _frequency =( (100*_first)+(10*_second)+_third) * 100000 --extra 0 because we didnt bother with 4th digit
local _found = false
for _, _beacon in ipairs(ctld.fobBeacons) do
if _beacon.frequency == _frequency then
_found = true
break
end
end
if _found then
--try again!
return ctld.generateRadioFMFrequency()
else
return _frequency
end
end end
@@ -2024,20 +2173,17 @@ function ctld.inPickupZone(_heli)
end end
end end
local _fobs = ctld.getSpawnedFobs(_heli)
-- now check spawned fobs -- now check spawned fobs
for _, _fobName in ipairs(ctld.builtFOBS) do for _, _fob in ipairs(_fobs) do
local _fob = StaticObject.getByName(_fobName) --get distance to center
if _fob ~= nil and _fob:isExist() and _fob:getCoalition() == _heli:getCoalition() and _fob:getLife() > 0 then local _dist = ctld.getDistance(_heliPoint,_fob:getPoint())
--get distance to center if _dist <= 150 then
return true
local _dist = ctld.getDistance(_heliPoint,_fob:getPoint())
if _dist <= 150 then
return true
end
end end
end end
@@ -2046,6 +2192,24 @@ function ctld.inPickupZone(_heli)
return false return false
end end
function ctld.getSpawnedFobs(_heli)
local _fobs = {}
for _, _fobName in ipairs(ctld.builtFOBS) do
local _fob = StaticObject.getByName(_fobName)
if _fob ~= nil and _fob:isExist() and _fob:getCoalition() == _heli:getCoalition() and _fob:getLife() > 0 then
table.insert(_fobs,_fob)
end
end
return _fobs
end
-- are we in a dropoff zone -- are we in a dropoff zone
function ctld.inDropoffZone(_heli) function ctld.inDropoffZone(_heli)
@@ -2169,7 +2333,7 @@ function ctld.unitCanCarryVehicles(_unit)
for _,_name in ipairs(ctld.vehicleTransportEnabled) do for _,_name in ipairs(ctld.vehicleTransportEnabled) do
local _nameLower = string.lower(_name) local _nameLower = string.lower(_name)
if string.match(_type, _nameLower) then if string.match(_type, _nameLower) then
return true return true
end end
end end
@@ -2183,7 +2347,7 @@ function ctld.isJTACUnitType(_type)
for _,_name in ipairs(ctld.jtacUnitTypes) do for _,_name in ipairs(ctld.jtacUnitTypes) do
local _nameLower = string.lower(_name) local _nameLower = string.lower(_name)
if string.match(_type, _nameLower) then if string.match(_type, _nameLower) then
return true return true
end end
end end
@@ -2265,7 +2429,7 @@ function ctld.addF10MenuOptions()
end end
missionCommands.addCommandForGroup(_groupId, "Check Status", { "Troop Transport" }, ctld.checkTroopStatus, { _unitName }) missionCommands.addCommandForGroup(_groupId, "Check Cargo", { "Troop Transport" }, ctld.checkTroopStatus, { _unitName })
if ctld.enableCrates then if ctld.enableCrates then
@@ -2288,10 +2452,10 @@ function ctld.addF10MenuOptions()
missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands") missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands")
missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", { "CTLD Commands" }, ctld.listNearbyCrates, { _unitName }) missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", { "CTLD Commands" }, ctld.listNearbyCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, "Unpack Sling Crates", { "CTLD Commands" }, ctld.unpackCrates, { _unitName }) missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", { "CTLD Commands" }, ctld.unpackCrates, { _unitName })
if ctld.enabledFOBBuilding then if ctld.enabledFOBBuilding then
missionCommands.addCommandForGroup(_groupId, "Unpack FOB Crates", { "CTLD Commands" }, ctld.unpackFOBCrates, { _unitName }) missionCommands.addCommandForGroup(_groupId, "List FOBs", { "CTLD Commands" }, ctld.listFOBS, { _unitName })
end end
if ctld.enableSmokeDrop then if ctld.enableSmokeDrop then
@@ -2980,6 +3144,11 @@ ctld.builtFOBS = {} -- stores fully built fobs
ctld.completeHawkSystems = {} -- stores complete spawned groups from multiple crates ctld.completeHawkSystems = {} -- stores complete spawned groups from multiple crates
ctld.fobBeacons = {} -- stores radio beacons, refreshed every 60 seconds
--ctld.radioFrequencyRED = 46000000
--used to lookup what the crate will contain --used to lookup what the crate will contain
ctld.crateLookupTable = {} ctld.crateLookupTable = {}
@@ -3058,6 +3227,7 @@ timer.scheduleFunction(ctld.refreshSmoke, nil, timer.getTime() + 5)
timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5)
timer.scheduleFunction(ctld.checkAIStatus,nil,timer.getTime() + 5) 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)
--event handler for deaths --event handler for deaths
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.