Merge pull request #4 from ciribob/playerLives

Player lives
This commit is contained in:
Ciaran Fisher
2016-04-22 19:52:09 +01:00
5 changed files with 655 additions and 184 deletions

514
CSAR.lua
View File

@@ -1,6 +1,12 @@
-- CSAR Script for DCS Ciribob - 2015 -- CSAR Script for DCS Ciribob - 2015
-- Version 1.8.4 - 08/02/2016 -- Version 1.9.0 - 25/03/2016
-- DCS 1.5 Compatible - Needs Mist 4.0.55 or higher! -- DCS 1.5 Compatible - Needs Mist 4.0.55 or higher!
--
-- 4 Options:
-- 0 - No Limit - NO Aircraft disabling or pilot lives
-- 1 - Disable Aircraft when its down - Timeout to reenable aircraft
-- 2 - Disable Aircraft for Pilot when he's shot down -- timeout to reenable pilot for aircraft
-- 3 - Pilot Life Limit - No Aircraft Disabling
csar = {} csar = {}
@@ -124,28 +130,36 @@ csar.redmash = {
"RedMASH #10" "RedMASH #10"
} -- The unit that serves as MASH for the red side } -- The unit that serves as MASH for the red side
csar.disableAircraft = true -- DISABLE player aircraft until the pilot is rescued?
csar.disableIfNoEjection = false -- if true disables aircraft even if the pilot doesnt eject csar.csarMode = 0
-- - I recommend you leave the option on below otherwise the -- 0 - No Limit - NO Aircraft disabling
-- 1 - Disable Aircraft when its down - Timeout to reenable aircraft
-- 2 - Disable Aircraft for Pilot when he's shot down -- timeout to reenable pilot for aircraft
-- 3 - Pilot Life Limit - No Aircraft Disabling -- timeout to reset lives?
csar.maxLives = 8 -- Maximum pilot lives
csar.countCSARCrash = false -- If you set to true, pilot lives count for CSAR and CSAR aircraft will count.
csar.reenableIfCSARCrashes = true -- If a CSAR heli crashes, the pilots are counted as rescued anyway. Set to false to Stop this
-- - I recommend you leave the option on below IF USING MODE 1 otherwise the
-- aircraft will be disabled for the duration of the mission -- aircraft will be disabled for the duration of the mission
csar.disableAircraftTimeout = true -- Allow aircraft to be used after 20 minutes if the pilot isnt rescued csar.disableAircraftTimeout = true -- Allow aircraft to be used after 20 minutes if the pilot isnt rescued
csar.disableTimeoutTime = 20 -- Time in minutes for TIMEOUT csar.disableTimeoutTime = 20 -- Time in minutes for TIMEOUT
csar.destructionHeight = 150 -- height in meters an aircraft will be destroyed at if the aircraft is disabled csar.destructionHeight = 150 -- height in meters an aircraft will be destroyed at if the aircraft is disabled
csar.disableCSARAircraft = false -- if set to TRUE then if a CSAR heli crashes or is shot down, it'll have to be rescued by another CSAR Heli!
csar.enableForAI = false -- set to false to disable AI units from being rescued. csar.enableForAI = false -- set to false to disable AI units from being rescued.
csar.enableForRED = true -- enable for red side csar.enableForRED = true -- enable for red side
csar.enableForBLUE = true -- enable for blue side csar.enableForBLUE = true -- enable for blue side
csar.enableSlotBlocking = false -- if set to true, you need to put the csarSlotBlockGameGUI.lua csar.enableSlotBlocking = true -- if set to true, you need to put the csarSlotBlockGameGUI.lua
-- in C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0 -- in C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0
-- For missions using FLAGS and this script, the CSAR flags will NOT interfere with your mission :) -- For missions using FLAGS and this script, the CSAR flags will NOT interfere with your mission :)
csar.bluesmokecolor = 4 -- Color of smokemarker for blue side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue csar.bluesmokecolor = 4 -- Color of smokemarker for blue side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue
csar.redsmokecolor = 1 -- Color of smokemarker for red side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue csar.redsmokecolor = 1 -- Color of smokemarker for red side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue
@@ -169,6 +183,33 @@ csar.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or
-- SETTINGS FOR MISSION DESIGNER ^^^^^^^^^^^^^^^^^^^* -- SETTINGS FOR MISSION DESIGNER ^^^^^^^^^^^^^^^^^^^*
-- ***************************************************************
-- **************** Mission Editor Functions *********************
-- ***************************************************************
-----------------------------------------------------------------
-- Resets all life limits so everyone can spawn again. Usage:
-- csar.resetAllPilotLives()
--
function csar.resetAllPilotLives()
csar.pilotLives = {}
env.info("Pilot Lives Reset!")
end
-----------------------------------------------------------------
-- Resets all life limits so everyone can spawn again. Usage:
-- csar.resetAllPilotLives()
--
function csar.resetPilotLife(_playerName)
csar.pilotLives[_playerName] = nil
env.info("Pilot life Reset!")
end
-- ***************************************************************
-- **************** BE CAREFUL BELOW HERE ************************
-- ***************************************************************
-- Sanity checks of mission designer -- Sanity checks of mission designer
assert(mist ~= nil, "\n\n** HEY MISSION-DESIGNER! **\n\nMiST has not been loaded!\n\nMake sure MiST 4.0.57 or higher is running\n*before* running this script!\n") assert(mist ~= nil, "\n\n** HEY MISSION-DESIGNER! **\n\nMiST has not been loaded!\n\nMake sure MiST 4.0.57 or higher is running\n*before* running this script!\n")
@@ -196,7 +237,11 @@ csar.currentlyDisabled = {} --stored disabled aircraft
csar.hoverStatus = {} -- tracks status of a helis hover above a downed pilot csar.hoverStatus = {} -- tracks status of a helis hover above a downed pilot
csar.pilotDisabled = {} -- tracks what aircraft a pilot is disabled for
csar.pilotLives = {} -- tracks how many lives a pilot has
csar.takenOff = {}
function csar.tableLength(T) function csar.tableLength(T)
@@ -228,8 +273,27 @@ function csar.eventHandler:onEvent(_event)
if _event == nil or _event.initiator == nil then if _event == nil or _event.initiator == nil then
return false return false
elseif _event.id == 3 then -- taken offf
if _event.initiator:getName() then
csar.takenOff[_event.initiator:getName()] = true
end
return true
elseif _event.id == 4 then -- landed
if _event.initiator:getName() then
csar.takenOff[_event.initiator:getName()] = nil
end
return true
elseif _event.id == 15 then --player entered unit elseif _event.id == 15 then --player entered unit
if _event.initiator:getName() then
csar.takenOff[_event.initiator:getName()] = nil
end
-- if its a sar heli, re-add check status script -- if its a sar heli, re-add check status script
for _, _heliName in pairs(csar.csarUnits) do for _, _heliName in pairs(csar.csarUnits) do
@@ -248,13 +312,14 @@ function csar.eventHandler:onEvent(_event)
end end
end end
if _event.initiator:getName() then if _event.initiator:getName() and _event.initiator:getPlayerName() then
env.info("Checking Unit - ".._event.initiator:getName()) env.info("Checking Unit - ".._event.initiator:getName())
csar.checkDisabledAircraftStatus( _event.initiator:getName()) csar.checkDisabledAircraftStatus({_event.initiator:getName(), _event.initiator:getPlayerName() })
end end
return true return true
elseif (_event.id == 9) then elseif (_event.id == 9) then
-- Pilot dead -- Pilot dead
@@ -276,34 +341,13 @@ function csar.eventHandler:onEvent(_event)
return --ignore! return --ignore!
end end
if csar.currentlyDisabled[_unit:getName()] ~= nil then -- Catch multiple events here?
return --already ejected once! if csar.takenOff[_event.initiator:getName()] == true then
end
trigger.action.outTextForCoalition(_unit:getCoalition(), "MAYDAY MAYDAY! " .._unit:getTypeName() .. " shot down. No Chute!", 10) trigger.action.outTextForCoalition(_unit:getCoalition(), "MAYDAY MAYDAY! " .._unit:getTypeName() .. " shot down. No Chute!", 10)
csar.handleEjectOrCrash(_unit, true)
--mark plane as broken and unflyable else
if csar.disableIfNoEjection and _unit:getPlayerName() ~= nil and csar.disableAircraft == true and csar.currentlyDisabled[_unit:getName()] == nil then env.info("Pilot Hasnt taken off, ignore")
if csar.disableCSARAircraft == false then
for _, _heliName in pairs(csar.csarUnits) do
if _unit:getName() == _heliName then
-- IGNORE Crashed CSAR
return
end
end
end
csar.currentlyDisabled[_unit:getName()] = {timeout = (csar.disableTimeoutTime*60) + timer.getTime(),desc="",noPilot = true,unitId=_unit:getID() }
-- disable aircraft
if csar.enableSlotBlocking then
trigger.action.setUserFlag("CSAR_".._unit:getID(),100)
env.info("Unit Disabled: ".._unit:getName().." ID:".._unit:getID())
end
end end
return return
@@ -328,15 +372,19 @@ function csar.eventHandler:onEvent(_event)
return --ignore! return --ignore!
end end
if csar.currentlyDisabled[_unit:getName()] ~= nil then -- TODO catch ejection on runway?
return --already ejected once!
end
if csar.enableForAI == false and _unit:getPlayerName() == nil then if csar.enableForAI == false and _unit:getPlayerName() == nil then
return return
end end
if csar.takenOff[_event.initiator:getName()] ~= true then
env.info("Pilot Hasnt taken off, ignore")
return -- give up, pilot hasnt taken off
end
local _spawnedGroup = csar.spawnGroup(_unit) local _spawnedGroup = csar.spawnGroup(_unit)
csar.addSpecialParametersToGroup(_spawnedGroup) csar.addSpecialParametersToGroup(_spawnedGroup)
@@ -346,6 +394,9 @@ function csar.eventHandler:onEvent(_event)
csar.addBeaconToGroup(_spawnedGroup:getName(),_freq) csar.addBeaconToGroup(_spawnedGroup:getName(),_freq)
--handle lives and plane disabling
csar.handleEjectOrCrash(_unit, false)
-- Generate DESCRIPTION text -- Generate DESCRIPTION text
local _text = " " local _text = " "
if _unit:getPlayerName() ~= nil then if _unit:getPlayerName() ~= nil then
@@ -354,35 +405,7 @@ function csar.eventHandler:onEvent(_event)
_text = "AI Pilot of ".._unit:getName().." - ".._unit:getTypeName() _text = "AI Pilot of ".._unit:getName().." - ".._unit:getTypeName()
end end
--mark plane as broken and unflyable csar.woundedGroups[_spawnedGroup:getName()] = { side = _spawnedGroup:getCoalition(), originalUnit = _unit:getName(), frequency= _freq, desc = _text, player = _unit:getPlayerName() }
if _unit:getPlayerName() ~= nil and csar.disableAircraft == true then
local _disable = true
if csar.disableCSARAircraft == false then
for _, _heliName in pairs(csar.csarUnits) do
if _unit:getName() == _heliName then
-- IGNORE Crashed CSAR and dont disable
_disable = false
break
end
end
end
if _disable then
csar.currentlyDisabled[_unit:getName()] = {timeout = (csar.disableTimeoutTime*60) + timer.getTime(),desc=_text, noPilot = false,unitId=_unit:getID()}
-- timer.scheduleFunction(csar.checkDisabledAircraftStatus, _unit:getName(), timer.getTime() + 1)
-- disable aircraft
if csar.enableSlotBlocking then
trigger.action.setUserFlag("CSAR_".._unit:getID(),100)
env.info("Unit Disabled: ".._unit:getName().." ID:".._unit:getID())
end
end
end
csar.woundedGroups[_spawnedGroup:getName()] = { side = _spawnedGroup:getCoalition(), originalUnit = _unit:getName(), frequency= _freq, desc = _text }
csar.initSARForPilot(_spawnedGroup,_freq) csar.initSARForPilot(_spawnedGroup,_freq)
@@ -392,7 +415,7 @@ function csar.eventHandler:onEvent(_event)
if csar.allowFARPRescue then if csar.allowFARPRescue then
-- env.info("Landing") -- env.info("Landing")
local _unit = _event.initiator local _unit = _event.initiator
@@ -401,22 +424,24 @@ function csar.eventHandler:onEvent(_event)
return -- error! return -- error!
end end
csar.takenOff[_event.initiator:getName()] = nil
local _place = _event.place local _place = _event.place
if _place == nil then if _place == nil then
-- env.info("Landing Place Nil") -- env.info("Landing Place Nil")
return -- error! return -- error!
end end
-- Coalition == 3 seems to be a bug... unless it means contested?! -- Coalition == 3 seems to be a bug... unless it means contested?!
if _place:getCoalition() == _unit:getCoalition() or _place:getCoalition() == 0 or _place:getCoalition() == 3 then if _place:getCoalition() == _unit:getCoalition() or _place:getCoalition() == 0 or _place:getCoalition() == 3 then
csar.rescuePilots(_unit) csar.rescuePilots(_unit)
--env.info("Rescued") --env.info("Rescued")
-- env.info("Rescued by Landing") -- env.info("Rescued by Landing")
else else
-- env.info("Cant Rescue ") env.info("Cant Rescue ")
-- env.info(string.format("airfield %d, unit %d",_place:getCoalition(),_unit:getCoalition())) env.info(string.format("airfield %d, unit %d",_place:getCoalition(),_unit:getCoalition()))
end end
end end
@@ -429,68 +454,305 @@ function csar.eventHandler:onEvent(_event)
end end
end end
function csar.enableAircraft(_name) function csar.handleEjectOrCrash(_unit,_crashed)
--remove from disabled
local _disabledAircraft = csar.currentlyDisabled[_name] -- disable aircraft for ALL pilots
if csar.csarMode == 1 then
if csar.currentlyDisabled[_unit:getName()] ~= nil then
return --already ejected once!
end
-- --mark plane as broken and unflyable
if _unit:getPlayerName() ~= nil and csar.currentlyDisabled[_unit:getName()] == nil then
if csar.countCSARCrash == false then
for _, _heliName in pairs(csar.csarUnits) do
if _unit:getName() == _heliName then
-- IGNORE Crashed CSAR
return
end
end
end
csar.currentlyDisabled[_unit:getName()] = {timeout = (csar.disableTimeoutTime*60) + timer.getTime(),desc="",noPilot = _crashed,unitId=_unit:getID(),name=_unit:getName() }
-- disable aircraft
trigger.action.setUserFlag("CSAR_AIRCRAFT".._unit:getID(),100)
env.info("Unit Disabled: ".._unit:getName().." ID:".._unit:getID())
end
elseif csar.csarMode == 2 then -- disable aircraft for pilot
--csar.pilotDisabled
if _unit:getPlayerName() ~= nil and csar.pilotDisabled[_unit:getPlayerName().."_".._unit:getName()] == nil then
if csar.countCSARCrash == false then
for _, _heliName in pairs(csar.csarUnits) do
if _unit:getName() == _heliName then
-- IGNORE Crashed CSAR
return
end
end
end
csar.pilotDisabled[_unit:getPlayerName().."_".._unit:getName()] = {timeout = (csar.disableTimeoutTime*60) + timer.getTime(),desc="",noPilot = true,unitId=_unit:getID(), player=_unit:getPlayerName(), name=_unit:getName() }
-- disable aircraft
-- strip special characters from name gsub('%W','')
trigger.action.setUserFlag("CSAR_AIRCRAFT".._unit:getPlayerName():gsub('%W','').."_".._unit:getID(),100)
env.info("Unit Disabled for player : ".._unit:getName())
end
elseif csar.csarMode == 3 then -- No Disable - Just reduce player lives
--csar.pilotDisabled
if _unit:getPlayerName() ~= nil then
if csar.countCSARCrash == false then
for _, _heliName in pairs(csar.csarUnits) do
if _unit:getName() == _heliName then
-- IGNORE Crashed CSAR
return
end
end
end
local _lives = csar.pilotLives[_unit:getPlayerName()]
if _lives == nil then
_lives = csar.maxLives + 1 --plus 1 because we'll use flag set to 1 to indicate NO MORE LIVES
end
csar.pilotLives[_unit:getPlayerName()] = _lives - 1
trigger.action.setUserFlag("CSAR_PILOT".._unit:getPlayerName():gsub('%W',''),_lives-1)
end
if _disabledAircraft ~= nil and csar.enableSlotBlocking then
trigger.action.setUserFlag("CSAR_".._disabledAircraft.unitId,0)
env.info("Unit Enable: ".._name.." ID:".._disabledAircraft.unitId)
end end
csar.currentlyDisabled[_name] = nil
end end
function csar.checkDisabledAircraftStatus(_name) function csar.enableAircraft(_name,_playerName)
local _details = csar.currentlyDisabled[_name]
if _details ~= nil then -- enable aircraft for ALL pilots
if csar.csarMode == 1 then
if csar.disableAircraftTimeout and timer.getTime() >= _details.timeout then local _details = csar.currentlyDisabled[_name]
csar.enableAircraft(_name) if _details ~= nil then
csar.currentlyDisabled[_name] = nil -- {timeout = (csar.disableTimeoutTime*60) + timer.getTime(),desc="",noPilot = _crashed,unitId=_unit:getID() }
return --use flag to reenable
trigger.action.setUserFlag("CSAR_AIRCRAFT".._details.unitId,0)
end end
local _unit = Unit.getByName(_name)
local _time = _details.timeout - timer.getTime() elseif csar.csarMode == 2 and _playerName ~= nil then -- enable aircraft for pilot
if _unit ~= nil then local _details = csar.pilotDisabled[_playerName.."_".._name]
if _details.noPilot then if _details ~= nil then
csar.pilotDisabled[_playerName.."_".._name] = nil
if csar.disableAircraftTimeout then trigger.action.setUserFlag("CSAR_AIRCRAFT".._playerName:gsub('%W','').."_".._details.unitId,0)
end
local _text = string.format("This aircraft cannot be flow as the pilot was killed in a crash. Reinforcements in %.2dM,%.2dS\n\nIt will be destroyed on takeoff!", (_time/60), _time%60) elseif csar.csarMode == 3 and _playerName ~= nil then -- No Disable - Just reduce player lives
--display message, -- give back life
csar.displayMessageToSAR(_unit,_text, 10,true)
local _lives = csar.pilotLives[_playerName]
if _lives == nil then
_lives = csar.maxLives + 1 --plus 1 because we'll use flag set to 1 to indicate NO MORE LIVES
else
_lives = _lives + 1 -- give back live!
if csar.maxLives + 1 <= _lives then
_lives = csar.maxLives + 1 --plus 1 because we'll use flag set to 1 to indicate NO MORE LIVES
end
end
csar.pilotLives[_playerName] = _lives
trigger.action.setUserFlag("CSAR_PILOT".._playerName:gsub('%W',''),_lives)
end
end
function csar.reactivateAircraft()
timer.scheduleFunction(csar.reactivateAircraft, nil, timer.getTime() + 5)
-- disable aircraft for ALL pilots
if csar.csarMode == 1 then
for _unitName, _details in pairs(csar.currentlyDisabled) do
if timer.getTime() >= _details.timeout then
csar.enableAircraft(_unitName)
end
end
elseif csar.csarMode == 2 then -- disable aircraft for pilot
for _key, _details in pairs(csar.pilotDisabled) do
if timer.getTime() >= _details.timeout then
csar.enableAircraft(_details.name, _details.player)
end
end
elseif csar.csarMode == 3 then -- No Disable - Just reduce player lives
end
end
function csar.checkDisabledAircraftStatus(_args)
local _name = _args[1]
local _playerName = _args[2]
local _unit = Unit.getByName(_name)
--if its not the same user anymore, stop checking
if _unit ~= nil and _unit:getPlayerName() ~= nil and _playerName == _unit:getPlayerName() then
-- disable aircraft for ALL pilots
if csar.csarMode == 1 then
local _details = csar.currentlyDisabled[_unit:getName()]
if _details ~= nil then
local _time = _details.timeout - timer.getTime()
if _details.noPilot then
if csar.disableAircraftTimeout then
local _text = string.format("This aircraft cannot be flow as the pilot was killed in a crash. Reinforcements in %.2dM,%.2dS\n\nIt will be DESTROYED on takeoff!", (_time/60), _time%60)
--display message,
csar.displayMessageToSAR(_unit,_text, 10,true)
else
--display message,
csar.displayMessageToSAR(_unit, "This aircraft cannot be flown again as the pilot was killed in a crash\n\nIt will be DESTROYED on takeoff!", 10,true)
end
else else
--display message, if csar.disableAircraftTimeout then
csar.displayMessageToSAR(_unit, "This aircraft cannot be flown again as the pilot was killed in a crash\n\nIt will be destroyed on takeoff!", 10,true) --display message,
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued or reinforcements arrive before this aircraft can be flown again! Reinforcements in "..string.format("%.2dM,%.2d",(_time/60), _time%60).."\n\nIt will be DESTROYED on takeoff!", 10,true)
else
--display message,
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued before this aircraft can be flown again!\n\nIt will be DESTROYED on takeoff!", 10,true)
end
end end
else
if csar.disableAircraftTimeout then if csar.destroyUnit(_unit) then
--display message, return --plane destroyed
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued or reinforcements arrive before this aircraft can be flown again! Reinforcements in "..string.format("%.2dM,%.2d",(_time/60), _time%60).."\n\nIt will be destroyed on takeoff!", 10,true)
else else
--display message, --check again in 10 seconds
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued before this aircraft can be flown again!\n\nIt will be destroyed on takeoff!", 10,true) timer.scheduleFunction(csar.checkDisabledAircraftStatus,_args, timer.getTime() + 10)
end end
end end
if csar.destroyUnit(_unit) then
return --plane destroyed
elseif csar.csarMode == 2 then -- disable aircraft for pilot
local _details = csar.pilotDisabled[_unit:getPlayerName().."_".._unit:getName()]
if _details ~= nil then
local _time = _details.timeout - timer.getTime()
if _details.noPilot then
if csar.disableAircraftTimeout then
local _text = string.format("This aircraft cannot be flow as the pilot was killed in a crash. Reinforcements in %.2dM,%.2dS\n\nIt will be DESTROYED on takeoff!", (_time/60), _time%60)
--display message,
csar.displayMessageToSAR(_unit,_text, 10,true)
else
--display message,
csar.displayMessageToSAR(_unit, "This aircraft cannot be flown again as the pilot was killed in a crash\n\nIt will be DESTROYED on takeoff!", 10,true)
end
else
if csar.disableAircraftTimeout then
--display message,
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued or reinforcements arrive before this aircraft can be flown again! Reinforcements in "..string.format("%.2dM,%.2d",(_time/60), _time%60).."\n\nIt will be DESTROYED on takeoff!", 10,true)
else
--display message,
csar.displayMessageToSAR(_unit, _details.desc .. " needs to be rescued before this aircraft can be flown again!\n\nIt will be DESTROYED on takeoff!", 10,true)
end
end
if csar.destroyUnit(_unit) then
return --plane destroyed
else
--check again in 10 seconds
timer.scheduleFunction(csar.checkDisabledAircraftStatus, _args, timer.getTime() + 10)
end
end
elseif csar.csarMode == 3 then -- No Disable - Just reduce player lives
local _lives = csar.pilotLives[_unit:getPlayerName()]
if _lives == nil or _lives > 1 then
if _lives == nil then
_lives = csar.maxLives + 1
end
-- -1 for lives as we use 1 to indicate out of lives!
local _text = string.format("CSAR ACTIVE! \n\nYou have "..(_lives-1).." lives remaining. Make sure you eject!")
csar.displayMessageToSAR(_unit,_text, 20,true)
return
else else
--check again in 10 seconds
timer.scheduleFunction(csar.checkDisabledAircraftStatus, _name, timer.getTime() + 10) local _text = string.format("You have run out of LIVES! Lives will be reset on mission restart or when your pilot is rescued.\n\nThis aircraft will be DESTROYED on takeoff!")
--display message,
csar.displayMessageToSAR(_unit,_text, 10,true)
if csar.destroyUnit(_unit) then
return --plane destroyed
else
--check again in 10 seconds
timer.scheduleFunction(csar.checkDisabledAircraftStatus, _args, timer.getTime() + 10)
end
end end
end end
end end
end end
function csar.destroyUnit(_unit) function csar.destroyUnit(_unit)
@@ -501,7 +763,7 @@ function csar.destroyUnit(_unit)
if csar.heightDiff(_unit) > csar.destructionHeight then if csar.heightDiff(_unit) > csar.destructionHeight then
csar.displayMessageToSAR(_unit, "Aircraft Destroyed as the pilot needs to be rescued!", 10,true) csar.displayMessageToSAR(_unit, "**** Aircraft Destroyed as the pilot needs to be rescued or you have no lives! ****", 10,true)
--if we're off the ground then explode --if we're off the ground then explode
trigger.action.explosion(_unit:getPoint(),100); trigger.action.explosion(_unit:getPoint(),100);
@@ -607,7 +869,7 @@ function csar.spawnGroup(_deadUnit)
local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name)
-- Turn off AI -- Turn off AI
trigger.action.setGroupAIOff(_spawnedGroup) trigger.action.setGroupAIOff(_spawnedGroup)
return _spawnedGroup return _spawnedGroup
@@ -788,7 +1050,8 @@ function csar.pickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
originalUnit = csar.woundedGroups[_woundedGroupName].originalUnit, originalUnit = csar.woundedGroups[_woundedGroupName].originalUnit,
woundedGroup = _woundedGroupName, woundedGroup = _woundedGroupName,
side = _heliUnit:getCoalition(), side = _heliUnit:getCoalition(),
desc = csar.woundedGroups[_woundedGroupName].desc desc = csar.woundedGroups[_woundedGroupName].desc,
player = csar.woundedGroups[_woundedGroupName].player,
} }
Group.destroy(_woundedLeader:getGroup()) Group.destroy(_woundedLeader:getGroup())
@@ -948,16 +1211,18 @@ function csar.scheduledSARFlight(_args)
--helicopter crashed? --helicopter crashed?
-- Put intransit pilots back -- Put intransit pilots back
--TODO possibly respawn the guys --TODO possibly respawn the guys
local _rescuedGroups = csar.inTransitGroups[_args.heliName] if csar.reenableIfCSARCrashes then
local _rescuedGroups = csar.inTransitGroups[_args.heliName]
if _rescuedGroups ~= nil then if _rescuedGroups ~= nil then
-- enable pilots again -- enable pilots again
for _, _rescueGroup in pairs(_rescuedGroups) do for _, _rescueGroup in pairs(_rescuedGroups) do
csar.enableAircraft(_rescueGroup.originalUnit,_rescuedGroups.player )
end
csar.enableAircraft(_rescueGroup.originalUnit)
end end
end end
csar.inTransitGroups[_args.heliName] = nil csar.inTransitGroups[_args.heliName] = nil
@@ -1019,12 +1284,12 @@ function csar.rescuePilots(_heliUnit)
-- enable pilots again -- enable pilots again
for _, _rescueGroup in pairs(_rescuedGroups) do for _, _rescueGroup in pairs(_rescuedGroups) do
csar.enableAircraft(_rescueGroup.originalUnit) csar.enableAircraft(_rescueGroup.originalUnit,_rescueGroup.player)
end end
csar.displayMessageToSAR(_heliUnit, _txt, 10) csar.displayMessageToSAR(_heliUnit, _txt, 10)
-- env.info("Rescued") -- env.info("Rescued")
end end
@@ -1565,10 +1830,18 @@ csar.generateVHFrequencies()
-- Schedule timer to add radio item -- Schedule timer to add radio item
timer.scheduleFunction(csar.addMedevacMenuItem, nil, timer.getTime() + 5) timer.scheduleFunction(csar.addMedevacMenuItem, nil, timer.getTime() + 5)
if csar.disableAircraftTimeout then
-- Schedule timer to reactivate things
timer.scheduleFunction(csar.reactivateAircraft, nil, timer.getTime() + 5)
end
world.addEventHandler(csar.eventHandler) world.addEventHandler(csar.eventHandler)
env.info("CSAR event handler added") env.info("CSAR event handler added")
--save CSAR MODE
trigger.action.setUserFlag("CSAR_MODE",csar.csarMode)
-- disable aircraft -- disable aircraft
if csar.enableSlotBlocking then if csar.enableSlotBlocking then
@@ -1576,4 +1849,3 @@ if csar.enableSlotBlocking then
env.info("CSAR Slot block enabled") env.info("CSAR Slot block enabled")
end end

View File

@@ -1,5 +1,86 @@
# DCS-CSAR # DCS-CSAR
Simplified Medevac script specifically for pilot rescue. Simplified MEDEVAC script specifically for pilot rescue simulating Combat Search and Rescue (CSAR)
By default, any crashed plane with an ejected pilot will be disabled until the pilot is rescued and dropped back safely to a friendly MASH By default, any crashed plane with an ejected pilot will be disabled until the pilot is rescued and dropped back safely to a friendly MASH, Airfield or FARP
## Setup in Mission Editor
### Script Setup
**This script requires MIST version 4.0.57 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.
Load the CSAR script a few seconds after MIST using a second trigger with a "TIME MORE" and a DO SCRIPT of CSAR.lua.
You will also need to load in the **beacon.ogg** sound file for Radio beacon homing. This can be done by adding a Sound To Country action. Pick an unused country, like Australia, so no one actually hears the audio when joining at the start of the mission. If you don't add the Audio file, radio beacons will not work and you will be unable to use ADF to find a downed pilot. Make sure not to rename the file as well.
### Script Configuration
The script has lots of configuration options that can be used to further customise the behaviour. Make sure after making any changes to save your file and re-add to the mission.
````lua
csar.csarMode = 0
-- 0 - No Limit - NO Aircraft disabling
-- 1 - Disable Aircraft when its down - Timeout to reenable aircraft
-- 2 - Disable Aircraft for Pilot when he's shot down -- timeout to reenable pilot for aircraft
-- 3 - Pilot Life Limit - No Aircraft Disabling -- timeout to reset lives?
csar.maxLives = 8 -- Maximum pilot lives
csar.countCSARCrash = false -- If you set to true, pilot lives count for CSAR and CSAR aircraft will count.
csar.reenableIfCSARCrashes = true -- If a CSAR heli crashes, the pilots are counted as rescued anyway. Set to false to Stop this
-- - I recommend you leave the option on below IF USING MODE 1 otherwise the
-- aircraft will be disabled for the duration of the mission
csar.disableAircraftTimeout = true -- Allow aircraft to be used after 20 minutes if the pilot isnt rescued
csar.disableTimeoutTime = 10 -- Time in minutes for TIMEOUT
csar.destructionHeight = 150 -- height in meters an aircraft will be destroyed at if the aircraft is disabled
csar.enableForAI = false -- set to false to disable AI units from being rescued.
csar.enableForRED = true -- enable for red side
csar.enableForBLUE = true -- enable for blue side
csar.enableSlotBlocking = true -- if set to true, you need to put the csarSlotBlockGameGUI.lua
-- in C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0
-- For missions using FLAGS and this script, the CSAR flags will NOT interfere with your mission :)
csar.bluesmokecolor = 4 -- Color of smokemarker for blue side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue
csar.redsmokecolor = 1 -- Color of smokemarker for red side, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue
csar.requestdelay = 2 -- Time in seconds before the survivors will request Medevac
csar.coordtype = 3 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates.
csar.coordaccuracy = 1 -- Precision of the reported coordinates, see MIST-docs at http://wiki.hoggit.us/view/GetMGRSString
-- only applies to _non_ bullseye coords
csar.immortalcrew = true -- Set to true to make wounded crew immortal
csar.invisiblecrew = true -- Set to true to make wounded crew insvisible
csar.messageTime = 30 -- Time to show the intial wounded message for in seconds
csar.loadDistance = 60 -- configure distance for pilot to get in helicopter in meters.
csar.radioSound = "beacon.ogg" -- the name of the sound file to use for the Pilot radio beacons. If this isnt added to the mission BEACONS WONT WORK!
csar.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or Airbase
````
#### Slot Blocking
If you want to enable slot blocking, you'll need to use one of the 3 modes by changing ```csar.csarMode``` in the configuration options, set ```csar.enableSlotBlocking = true``` and copy **csarSlotBlockGameGUI.lua** to C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0.
The 3 modes are:
* Mode 1 - Disable the specific aircraft when it crashes or is destroyed for **All** players - Re-enabled when the pilot is rescued or after a set time
* Mode 2 - Disable the specific aircraft when it crashes or is destroyed for **The pilot that crashed / ejected** - Re-enabled when the pilot is rescued or after a set time
* Mode 3 - No specific aircraft disabling. Each pilot has a number of lives and can no longer fly when their lives are used up
Its recommended that you leave the ```csar.disableAircraftTimeout = true``` if you use Mode 1 as otherwise its possible that all aircraft in a mission could be disabled!
You can configure how long an aircraft is disabled in Mode 1 or Mode 2 by changing ```csar.disableTimeoutTime``` which will control how long until an aircraft will be disabled for in minutes.

Binary file not shown.

View File

@@ -1,43 +1,93 @@
local csarSlotBlock = {} -- DONT REMOVE!!! local csarSlotBlock = {} -- DONT REMOVE!!!
--[[ --[[
CSAR Slot Blocking - V1.8.4 CSAR Slot Blocking - V1.9.0
Put this file in C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0 Put this file in C:/Users/<YOUR USERNAME>/DCS/Scripts for 1.5 or C:/Users/<YOUR USERNAME>/DCS.openalpha/Scripts for 2.0
This script will use flags to disable and enable slots when a pilot is shot down and ejects. This script will use flags to disable and enable slots when a pilot is shot down and ejects.
The flags will not interfere with mission flags The flags will NOT interfere with mission flags
]] ]]
csarSlotBlock.showEnabledMessage = true -- if set to true, the player will be told that the slot is enabled when switching to it csarSlotBlock.showEnabledMessage = true -- if set to true, the player will be told that the slot is enabled when switching to it
csarSlotBlock.version = "1.8.4" csarSlotBlock.version = "1.9.0"
-- Logic for determining if player is allowed in a slot -- Logic for determining if player is allowed in a slot
function csarSlotBlock.shouldAllowSlot(_playerID, _slotID) -- _slotID == Unit ID unless its multi aircraft in which case slotID is unitId_seatID function csarSlotBlock.shouldAllowSlot(_playerID, _slotID) -- _slotID == Unit ID unless its multi aircraft in which case slotID is unitId_seatID
if csarSlotBlock.csarSlotBlockEnabled() then
local _unitId = csarSlotBlock.getUnitId(_slotID); local _unitId = csarSlotBlock.getUnitId(_slotID);
local _status,_error = net.dostring_in('server', " return trigger.misc.getUserFlag(\"CSAR_".._unitId.."\"); ") local _mode = csarSlotBlock.csarMode()
if _mode == 1 then
-- disable aircraft for ALL pilots
local _flag = csarSlotBlock.getFlagValue("CSAR_AIRCRAFT".._unitId)
if _flag == 100 then
return false
end
if not _status and _error then
net.log("error getting flag: ".._error)
return true return true
else
-- net.log("flag value ".._unitId.." value: ".._status)
--disabled
if tonumber(_status) == 100 then elseif _mode == 2 then
-- disable aircraft for a certain player
local _playerName = net.get_player_info(_playerID, 'name')
if _playerName == nil then
return true
end
local _flag = csarSlotBlock.getFlagValue("CSAR_AIRCRAFT".._playerName:gsub('%W','').."_".._unitId)
if _flag == 100 then
return false
end
return true
elseif _mode == 3 then
-- global lives limit
local _playerName = net.get_player_info(_playerID, 'name')
if _playerName == nil then
return true
end
local _flag = csarSlotBlock.getFlagValue("CSAR_PILOT".._playerName:gsub('%W',''))
if _flag == 1 then
return false return false
else else
return true return true
end end
end
end
end
return true
end
function csarSlotBlock.getFlagValue(_flag)
local _status,_error = net.dostring_in('server', " return trigger.misc.getUserFlag(\"".._flag.."\"); ")
if not _status and _error then
net.log("error getting flag: ".._error)
return 0
else
-- net.log("flag value ".._unitId.." value: ".._status)
--disabled
return tonumber(_status)
end
end end
-- _slotID == Unit ID unless its multi aircraft in which case slotID is unitId_seatID -- _slotID == Unit ID unless its multi aircraft in which case slotID is unitId_seatID
@@ -74,10 +124,10 @@ csarSlotBlock.onGameEvent = function(eventName,playerID,arg2,arg3,arg4) -- This
if DCS.isServer() and DCS.isMultiplayer() then if DCS.isServer() and DCS.isMultiplayer() then
if DCS.getModelTime() > 1 then -- must check this to prevent a possible CTD by using a_do_script before the game is ready to use a_do_script. -- Source GRIMES :) if DCS.getModelTime() > 1 then -- must check this to prevent a possible CTD by using a_do_script before the game is ready to use a_do_script. -- Source GRIMES :)
if eventName ~= "connect" if eventName == "self_kill"
and eventName ~= "disconnect" or eventName == "crash"
and eventName ~= "mission_end" or eventName == "eject"
and eventName ~= "change_slot" then or eventName == "pilot_death" then
-- is player in a slot and valid? -- is player in a slot and valid?
local _playerDetails = net.get_player_info(playerID) local _playerDetails = net.get_player_info(playerID)
@@ -98,7 +148,7 @@ end
csarSlotBlock.onPlayerTryChangeSlot = function(playerID, side, slotID) csarSlotBlock.onPlayerTryChangeSlot = function(playerID, side, slotID)
if DCS.isServer() and DCS.isMultiplayer() then if DCS.isServer() and DCS.isMultiplayer() then
if (side ~=0 and slotID ~='' and slotID ~= nil) then if (side ~=0 and slotID ~='' and slotID ~= nil) then
local _allow = csarSlotBlock.shouldAllowSlot(playerID,slotID) local _allow = csarSlotBlock.shouldAllowSlot(playerID,slotID)
@@ -109,21 +159,21 @@ csarSlotBlock.onPlayerTryChangeSlot = function(playerID, side, slotID)
return false return false
else else
local _playerName = net.get_player_info(playerID, 'name') local _playerName = net.get_player_info(playerID, 'name')
if _playerName ~= nil and csarSlotBlock.showEnabledMessage and if _playerName ~= nil and csarSlotBlock.showEnabledMessage and
csarSlotBlock.csarSlotBlockEnabled() then csarSlotBlock.csarSlotBlockEnabled() and csarSlotBlock.csarMode() > 0 then
--Disable chat message to user --Disable chat message to user
local _chatMessage = string.format("*** %s - Aircraft Enabled! If you eject you will need to be rescued by CSAR. Protect the Helis! ***",_playerName) local _chatMessage = string.format("*** %s - Aircraft Enabled! If you will need to be rescued by CSAR. Make sure you eject and Protect the Helis! ***",_playerName)
net.send_chat_to(_chatMessage, playerID) net.send_chat_to(_chatMessage, playerID)
end end
end end
end
net.log("CSAR - allowing - playerid: "..playerID.." side:"..side.." slot: "..slotID) net.log("CSAR - allowing - playerid: "..playerID.." side:"..side.." slot: "..slotID)
end
end
end
return true return true
@@ -131,21 +181,18 @@ end
csarSlotBlock.csarSlotBlockEnabled = function() csarSlotBlock.csarSlotBlockEnabled = function()
local _status,_error = net.dostring_in('server', " return trigger.misc.getUserFlag(\"CSAR_SLOTBLOCK\"); ") local _res = csarSlotBlock.getFlagValue("CSAR_SLOTBLOCK")
if not _status and _error then return _res == 100
net.log("error getting flag: ".._error)
return false
else
-- net.log("flag value ".._unitId.." value: ".._status)
--disabled end
if tonumber(_status) == 100 then
return true
else csarSlotBlock.csarMode = function()
return false
end local _mode = csarSlotBlock.getFlagValue("CSAR_MODE")
end
return _mode
end end
@@ -171,4 +218,4 @@ end
DCS.setUserCallbacks(csarSlotBlock) DCS.setUserCallbacks(csarSlotBlock)
net.log("Loaded - CSAR SLOT BLOCK k v"..csarSlotBlock.version.. " by Ciribob") net.log("Loaded - CSAR SLOT BLOCK k v"..csarSlotBlock.version.. " by Ciribob")

107
mist.lua
View File

@@ -14,8 +14,8 @@ mist = {}
-- don't change these -- don't change these
mist.majorVersion = 4 mist.majorVersion = 4
mist.minorVersion = 0 mist.minorVersion = 1
mist.build = 57 mist.build = 61
-------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------
-- the main area -- the main area
@@ -241,7 +241,7 @@ do
end end
end end
end end
--mist.debug.writeData(mist.utils.serialize,{'msg', newTable}, timer.getAbsTime() ..'Group.lua')
newTable['timeAdded'] = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time newTable['timeAdded'] = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time
--mist.debug.dumpDBs() --mist.debug.dumpDBs()
--end --end
@@ -254,6 +254,7 @@ do
local function checkSpawnedEvents() local function checkSpawnedEvents()
if #tempSpawnedUnits > 0 then if #tempSpawnedUnits > 0 then
local groupsToAdd = {} local groupsToAdd = {}
local added = false
local ltemp = tempSpawnedUnits local ltemp = tempSpawnedUnits
local ltable = table local ltable = table
@@ -265,7 +266,7 @@ do
local spawnedObj = ltemp[x] local spawnedObj = ltemp[x]
if spawnedObj and spawnedObj:isExist() then if spawnedObj and spawnedObj:isExist() then
local found = false local found = false
for index, name in pairs(groupsToAdd) do for name, val in pairs(groupsToAdd) do
if spawnedObj:getCategory() == 1 then -- normal groups if spawnedObj:getCategory() == 1 then -- normal groups
if mist.stringMatch(spawnedObj:getGroup():getName(), name) == true then if mist.stringMatch(spawnedObj:getGroup():getName(), name) == true then
found = true found = true
@@ -280,26 +281,37 @@ do
end end
-- for some reason cargo objects are returning as category == 6. -- for some reason cargo objects are returning as category == 6.
if found == false then if found == false then
added = true
if spawnedObj:getCategory() == 1 then -- normal groups if spawnedObj:getCategory() == 1 then -- normal groups
groupsToAdd[#groupsToAdd + 1] = spawnedObj:getGroup():getName() groupsToAdd[spawnedObj:getGroup():getName()] = true
elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects
groupsToAdd[#groupsToAdd + 1] = spawnedObj:getName() groupsToAdd[spawnedObj:getName()] = true
end end
end end
end end
table.remove(ltemp, x) table.remove(ltemp, x)
if x%updatesPerRun == 0 then if x%updatesPerRun == 0 then
coroutine.yield() coroutine.yield()
end end
end end
if added == true then
if #groupsToAdd > 0 then for groupName, val in pairs(groupsToAdd) do
for groupId, groupName in pairs(groupsToAdd) do local dataChanged = false
if not mist.DBs.groupsByName[groupName] or mist.DBs.groupsByName[groupName] and mist.DBs.groupsByName[groupName].startTime + 10 < timer.getAbsTime() then if mist.DBs.groupsByName[groupName] then
for _index, data in pairs(mist.DBs.groupsByName[groupName]) do
if data.unitName ~= spawnedObj:getName() and data.unitId ~= spawnedObj:getID() and data.type ~= spawnedObj:getTypeName() then
dataChanged = true
break
end
end
if dataChanged == false then
groupsToAdd[groupName] = false
end
end
if groupsToAdd[groupName] == true or not mist.DBs.groupsByName[groupName] then
writeGroups[#writeGroups + 1] = dbUpdate(groupName) writeGroups[#writeGroups + 1] = dbUpdate(groupName)
end end
end end
@@ -309,6 +321,7 @@ do
local function updateDBTables() local function updateDBTables()
local i = 0 local i = 0
for index, newTable in pairs(writeGroups) do for index, newTable in pairs(writeGroups) do
i = i + 1 i = i + 1
@@ -548,7 +561,7 @@ do
if newObj.clone or not newObj.name then if newObj.clone or not newObj.name then
mistDynAddIndex = mistDynAddIndex + 1 mistDynAddIndex = mistDynAddIndex + 1
newObj.name = (newCountry .. ' static ' .. mistDynAddIndex) newObj.name = (country.name[newCountry] .. ' static ' .. mistDynAddIndex)
end end
if not newObj.dead then if not newObj.dead then
@@ -591,6 +604,7 @@ do
-- validate data -- validate data
for countryId, countryName in pairs(country.name) do for countryId, countryName in pairs(country.name) do
if type(cntry) == 'string' then if type(cntry) == 'string' then
cntry = cntry:gsub("%s+", "_")
if tostring(countryName) == string.upper(cntry) then if tostring(countryName) == string.upper(cntry) then
newCountry = countryName newCountry = countryName
end end
@@ -649,7 +663,7 @@ do
end end
if newGroup.clone and mist.DBs.groupsByName[newGroup.name] or not newGroup.name then if newGroup.clone and mist.DBs.groupsByName[newGroup.name] or not newGroup.name then
newGroup['name'] = tostring(tostring(cntry) .. tostring(typeName) .. mistDynAddIndex) newGroup['name'] = tostring(tostring(country.name[cntry]) .. tostring(typeName) .. mistDynAddIndex)
end end
if not newGroup.hidden then if not newGroup.hidden then
@@ -921,7 +935,9 @@ end
function mist.utils.makeVec3(Vec2, y) function mist.utils.makeVec3(Vec2, y)
if not Vec2.z then if not Vec2.z then
if not y then if Vec2.alt and not y then
y = Vec2.alt
elseif not y then
y = 0 y = 0
end end
return {x = Vec2.x, y = y, z = Vec2.y} return {x = Vec2.x, y = y, z = Vec2.y}
@@ -961,7 +977,9 @@ end
-- gets heading-error corrected direction from point along vector vec. -- gets heading-error corrected direction from point along vector vec.
function mist.utils.getDir(vec, point) function mist.utils.getDir(vec, point)
local dir = math.atan2(vec.z, vec.x) local dir = math.atan2(vec.z, vec.x)
dir = dir + mist.getNorthCorrection(point) if point then
dir = dir + mist.getNorthCorrection(point)
end
if dir < 0 then if dir < 0 then
dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi
end end
@@ -980,7 +998,35 @@ function mist.utils.get3DDist(point1, point2)
return mist.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) return mist.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z})
end end
function mist.utils.vecToWP(vec)
local newWP = {}
newWP.x = vec.x
newWP.y = vec.y
if vec.z then
newWP.alt = vec.y
newWP.y = vec.z
else
newWP.alt = land.getHeight({x = vec.x, y = vec.y})
end
return newWP
end
function mist.utils.unitToWP(pUnit)
local unit = mist.utils.deepCopy(pUnit)
if type(unit) == 'string' then
if Unit.getByName(unit) then
unit = Unit.getByName(unit)
end
end
if unit:isExist() == true then
local new = mist.utils.vecToWP(unit:getPosition().p)
new.speed = mist.vec.mag(unit:getVelocity())
new.alt_type = "BARO"
return new
end
return false
end
@@ -1010,6 +1056,15 @@ mist.utils.round = function(num, idp)
return math.floor(num * mult + 0.5) / mult return math.floor(num * mult + 0.5) / mult
end end
mist.utils.roundTbl = function(tbl, idp)
for id, val in pairs(tbl) do
if type(val) == 'number' then
tbl[id] = mist.utils.round(val, idp)
end
end
return tbl
end
-- porting in Slmod's dostring -- porting in Slmod's dostring
mist.utils.dostring = function(s) mist.utils.dostring = function(s)
local f, err = loadstring(s) local f, err = loadstring(s)
@@ -1526,7 +1581,8 @@ mist.tostringBR = function(az, dist, alt, metric)
return s return s
end end
mist.getNorthCorrection = function(point) --gets the correction needed for true north mist.getNorthCorrection = function(gPoint) --gets the correction needed for true north
local point = mist.utils.deepCopy(gPoint)
if not point.z then --Vec2; convert to Vec3 if not point.z then --Vec2; convert to Vec3
point.z = point.y point.z = point.y
point.y = 0 point.y = 0
@@ -3414,6 +3470,21 @@ mist.flagFunc.group_alive_more_than = function(vars)
end end
end end
mist.getAvgPoint = function(points)
local avgX, avgY, avgZ, totNum = 0, 0, 0, 0
for i = 1, #points do
local nPoint = mist.utils.makeVec3(points[i])
if nPoint.z then
avgX = avgX + nPoint.x
avgY = avgY + nPoint.y
avgZ = avgZ + nPoint.z
totNum = totNum + 1
end
end
if totNum ~= 0 then
return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum}
end
end
--Gets the average position of a group of units (by name) --Gets the average position of a group of units (by name)