--------------------------------------------------------------------------------------------------------------------------------
-- SAR survivors code, belongs in an action triggered on scen load.
--------------------------------------------------------------------------------------------------------------------------------
---Original code by angster http://www.matrixgames.com/forums/tm.asp?m=4358405
-- modified by TyphoonFr http://www.matrixgames.com/forums/tm.asp?m=4476931&mpage=4&key= and Gunner98------------------------------------
---All Functions
--------------------------------------------------------------------------------------------------------------------------------
---Setup
local maxSuccessScore = 8
local maxFailureScore = -25
local successScore = 1 --amount to increase score if survivor picked up, per survivor
local failureScore = -2 --amount to decrease score if survivor lost, per survivor
local lostOverLandDBID = 2441 --must be facility
local lostOverSeaDBID = 2553 -- must be ship
local survivorSide = "Survivors" --side for survivors, can't be your own or over water they will pick themselves up - must exist
local maxPickupSpeed = 56
local maxPickupAltitude = 101
local crewSurvivalPercentage =5 -- between 1 and 9, higher is more likely to survive
local survivorTimeToRescue = 35 -- amount of time in seconds rescuers must remain in the area to recover each survivor - multiplied by the number of survivors
--------------------------------------------------------------------------------------------------------------------------------
-- SAR Target GUID Helpers
--------------------------------------------------------------------------------------------------------------------------------
function GetSARTargetsGUID()
local pilotString = ScenEdit_GetKeyValue("CONST_SAR_TARGET_GUID")
if pilotString == nil then
pilotString = ""
end
return split(pilotString,",")
end
function AddSARTargetGUID(pilotKey)
local pilotString = ScenEdit_GetKeyValue("CONST_SAR_TARGET_GUID")
if pilotString == nil then
pilotString = pilotKey
else
pilotString = pilotString..","..pilotKey
end
ScenEdit_SetKeyValue("CONST_SAR_TARGET_GUID",pilotString)
end
function RemoveSARTargetGUID(pilotKey)
local table = GetSARTargetsGUID()
local pilotString = nil
for k, v in pairs(table) do
if guid ~= v then
if pilotString then
pilotString = pilotString..","..v
else
pilotString = v
end
end
end
ScenEdit_SetKeyValue("CONST_SAR_TARGET_GUID",pilotString)
end
function SARTargetGUIDExists(guid)
local table = GetSARTargetsGUID()
for k, v in pairs(table) do
if guid == v then
return true
end
end
return false
end
function GetTargetGUIDCloseToSAR(sarUnit)
local pilotsTable = GetSARTargetsGUID()
for i,v in pairs(pilotsTable) do
-- Check In Area
if sarUnit:inArea({v.."-1",v.."-2",v.."-3",v.."-4"}) then
return v
end
end
return ""
end
--------------------------------------------------------------------------------------------------------------------------------
-- Helper
--------------------------------------------------------------------------------------------------------------------------------
function split(s, sep)
local fields = {}
local sep = sep or " "
local pattern = string.format("([^%s]+)", sep)
string.gsub(s, pattern, function(c) fields[#fields + 1] = c end)
return fields
end
-- Time helper
function timeFromNowDotNetTime(addSeconds)
local time = ScenEdit_CurrentTime()
local offSet = 62135596801 --number of seconds from 01-01-0001 to 01-01-1970
local newTime = (time + offSet + addSeconds)*10000000
local timeToUse = string.format("%18.0f",newTime)
return timeToUse
end
--------------------------------------------------------------------------------------------------------------------------------
--Score Helper Functions
--------------------------------------------------------------------------------------------------------------------------------
function AddScoreToSide(side,score,reason)
local currentScore = ScenEdit_GetScore(side)
currentScore = currentScore + score
ScenEdit_SetScore(side,currentScore,reason)
end
--------------------------------------------------------------------------------------------------------------------------------
-- Create Survivor From Trigger Unit
--------------------------------------------------------------------------------------------------------------------------------
function CreateDownedPilotFromTriggerUnit(triggerUnit,passengers)
if triggerUnit and not SARTargetGUIDExists(triggerUnit.guid) then
print("------attempting to create survivors-----")
-- print("Subtype: "..triggerUnit.subtype)
print("unit.condition: "..triggerUnit.condition)
local worldElevation = World_GetElevation({latitude= triggerUnit.latitude, longitude=triggerUnit.longitude})
if triggerUnit.type == "Aircraft" and (triggerUnit.altitude - worldElevation) < 5 then --check f AC is on the ground
return
end
if triggerUnit.subtype == '8201' or triggerUnit.subtype == '8202' then --check if it is uav, if so quit, may be more subtypes for uav that need to be added here
return
end
if triggerUnit.condition == 'Docked' then --ship is not at sea, no survivors
return
end
math.randomseed(os.time())
--are there survivors?
local didAnyoneSurvive = math.random(1,10)
if didAnyoneSurvive > crewSurvivalPercentage then--they did not survive, exit
print("no Survivors, percent chance did not work out " ..didAnyoneSurvive)
return
end
-- Add Unit, check if over water or land
local elevation = World_GetElevation({latitude= triggerUnit.latitude+ 0.001, longitude=triggerUnit.longitude+ 0.001}) --survivor will be offset slightly to avoid blast damage
local unitLostDBID = lostOverSeaDBID --default is lost over sea
local unitType = "Ship"
if elevation > -1 then
unitLostDBID = lostOverLandDBID
unitType = "Facility"
end
local numberWhoSurvived = 1
local timeToRescue = survivorTimeToRescue
local timeToRescueMinutes = math.ceil((numberWhoSurvived * survivorTimeToRescue)/ 60)
if passengers then
if passengers == 0 then --if 0 is passed in as the crew count then quit
return
end
print("Crew: " ..passengers)
numberWhoSurvived = math.floor(passengers * (didAnyoneSurvive/10))
if numberWhoSurvived < 1 then
numberWhoSurvived = 1
end
print("Survivors "..numberWhoSurvived)
timeToRescue = numberWhoSurvived * survivorTimeToRescue
print("Time needed to rescue: "..timeToRescue)
timeToRescueMinutes = math.ceil(timeToRescue/ 60)
end
-- print(unitType.." "..numberWhoSurvived.." Survivor(s) of "..triggerUnit.name.." dbid: "..unitLostDBID)
local downedPilot = ScenEdit_AddUnit({type=unitType, name =numberWhoSurvived.." Survivor(s) of "..triggerUnit.name, side = survivorSide, DBID = unitLostDBID, Latitude=triggerUnit.latitude + 0.001, Longitude=triggerUnit.longitude + 0.001})
-- print("guid of survivor unit: "..downedPilot.guid)
-- Set Attributes
downedPilot.manualSpeed = 0
-- Check Downed Pilot Is Created
if downedPilot then
-- Create Reference Points Box
local referencePointOne = ScenEdit_AddReferencePoint( {side = survivorSide, name = downedPilot.guid.."-1",lat = triggerUnit.latitude - 0.02, lon = triggerUnit.longitude - 0.02, clear=true})
local referencePointTwo = ScenEdit_AddReferencePoint( {side = survivorSide, name = downedPilot.guid.."-2",lat = triggerUnit.latitude + 0.02, lon = triggerUnit.longitude - 0.02, clear=true})
local referencePointThree = ScenEdit_AddReferencePoint( {side = survivorSide, name = downedPilot.guid.."-3",lat = triggerUnit.latitude + 0.02, lon = triggerUnit.longitude + 0.02, clear=true})
local referencePointFour = ScenEdit_AddReferencePoint( {side = survivorSide, name = downedPilot.guid.."-4",lat = triggerUnit.latitude - 0.02, lon = triggerUnit.longitude + 0.02, clear=true})
-- create triggers, probably could do it with one trigger for any type of unit but targettype =0 doesn't work
-- Create Trigger With Reference Points for Aircraft
local addedTrigger = ScenEdit_SetTrigger({mode="add",type='UnitRemainsInArea',name="air-"..downedPilot.guid, targetfilter={TargetType = '1' , TargetSide=triggerUnit.side},area={referencePointOne.name,referencePointTwo.name,referencePointThree.name,referencePointFour.name},TD=timeToRescue})
-- Create Trigger With Reference Points for Ship
local addedTrigger = ScenEdit_SetTrigger({mode="add",type='UnitRemainsInArea',name="ship-"..downedPilot.guid, targetfilter={TargetType = '2' , TargetSide=triggerUnit.side},area={referencePointOne.name,referencePointTwo.name,referencePointThree.name,referencePointFour.name},TD=timeToRescue})
-- Create Trigger With Reference Points for Subs
local addedTrigger = ScenEdit_SetTrigger({mode="add",type='UnitRemainsInArea',name="sub-"..downedPilot.guid, targetfilter={TargetType = '3' , TargetSide=triggerUnit.side},area={referencePointOne.name,referencePointTwo.name,referencePointThree.name,referencePointFour.name},TD=timeToRescue})
-- Create Trigger With Reference Points for Ground Units
local addedTrigger = ScenEdit_SetTrigger({mode="add",type='UnitRemainsInArea',name="ground-"..downedPilot.guid,
targetfilter={TargetType = '4' , TargetSide=triggerUnit.side},area={referencePointOne.name,referencePointTwo.name,referencePointThree.name,referencePointFour.name},TD=timeToRescue})
-- Add GUID
AddSARTargetGUID(downedPilot.guid)
-- Set Trigger To SAR Mission
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="add", name="air-"..downedPilot.guid})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="add", name="ship-"..downedPilot.guid})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="add", name="sub-"..downedPilot.guid})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="add", name="ground-"..downedPilot.guid})
-- Create Event For Destruction
ScenEdit_SetEvent("Event - Cancel Pilot"..downedPilot.guid, {mode="add",IsRepeatable=0})
local cancelEvent = ScenEdit_GetEvent("Event - Cancel Pilot"..downedPilot.guid)
SetLongKeyValuePairs(cancelEvent.guid,downedPilot.guid)
local timeToLive = math.random(1800,108000) --time to live in seconds
if timeToLive > 50000 then --if it is over 50k then try it again, just trying to give greater chance of it being lower
timeToLive = math.random(1800,108000)
end
local timeToLiveMessage = "Surviving crew members are in fair condition, likely to survive for several hours."
if timeToLive < 7200 then
timeToLiveMessage = "Surviving crew members are in poor condition, immediate evacuation required!"
elseif timeToLive > 36000 then
timeToLiveMessage = "Surviving crew members are in good condition, likely to survive for at least 10 hours."
end
--print("Time they will survive in seconds: "..timeToLive)
local randInterval = timeFromNowDotNetTime(timeToLive)
-- Add Create Trigger
local addedTrigger = ScenEdit_SetTrigger({mode="add", type="Time", name="Trigger - Cancel Pilot"..downedPilot.guid, Time= randInterval})
-- Add Create Action
ScenEdit_SetAction({mode="add", type="LuaScript", name="Action - Cancel Pilot"..downedPilot.guid, scriptText="StartSARFailedTargetPickup(ScenEdit_EventX())"})
-- Set Triggers And Actions
ScenEdit_SetEventTrigger("Event - Cancel Pilot"..downedPilot.guid, {mode="add", name="Trigger - Cancel Pilot"..downedPilot.guid})
ScenEdit_SetEventAction("Event - Cancel Pilot"..downedPilot.guid, {mode="add", name="Action - Cancel Pilot"..downedPilot.guid})
-- Message Pilot Ejected
ScenEdit_SpecialMessage(ScenEdit_PlayerSide(),triggerUnit.name.." has been destroyed but there are survivors!
Number of Survivors: "..numberWhoSurvived.."
"..timeToLiveMessage..
"
In order to rescue them you will need to move a unit (sub, ship, AC or ground unit) to their location and remain on site for "..timeToRescueMinutes.." minutes, at an altitude of less than "..maxPickupAltitude.." feet and a speed of less that " ..maxPickupSpeed.." kts. Submarines will need to be on the surface in order to perform a rescue.")
print("------end create survivors-----")
end
end
end
--------------------------------------------------------------------------------------------------------------------------------
-- Start SAR Target Pickup
--------------------------------------------------------------------------------------------------------------------------------
function StartSARTargetPickup(triggerUnit)
local elevation = World_GetElevation({latitude= triggerUnit.latitude, longitude=triggerUnit.longitude})
if elevation < 0 then
elevation = 0
end
local altitudeAGL = triggerUnit.altitude - elevation
if triggerUnit.altitude < -5 then --if sub is submerged don't let it pickup survivor
return
end
if triggerUnit.type == "Ship" and triggerUnit.damage.dp < 1 then --if ship is sinking don't let it pickup survivors. Weird cause ground units seem to have dp =0
return
end
if triggerUnit and triggerUnit.speed < maxPickupSpeed and altitudeAGL < maxPickupAltitude then
--print(maxPickupAltitude)
-- print("triggerunit alt: " ..triggerUnit.altitude)
-- Get Triggered Areas
local triggeredAreas = triggerUnit.areaTriggersFired
local triggeredGUID = ""
-- Get Trigger GUID
for k, v in pairs(triggeredAreas) do
triggeredGUID = v
end
-- Find Pilot
local keyGUID = GetTargetGUIDCloseToSAR(triggerUnit)
local unit = ScenEdit_GetUnit({guid=keyGUID})
-- Scoring
if unit then
-- Add Score
local s = string.gmatch(unit.name, "[^ ]+") -- get first part of name which is the number of survivors
local totalSuccessScore = successScore * s() --calculate total score
print("Total calculated score for " ..unit.name..": " ..totalSuccessScore)
if totalSuccessScore > maxSuccessScore then totalSuccessScore = maxSuccessScore end -- check to see if score is outside max limits
AddScoreToSide(ScenEdit_PlayerSide(),totalSuccessScore ,"Pilot Saved- "..unit.name.." safely on board of "..triggerUnit.name)
print("Total score used (max/min checked): " ..totalSuccessScore)
-- Message Pilot Saved
ScenEdit_SpecialMessage(ScenEdit_PlayerSide (),unit.name.." safely on board of "..triggerUnit.name..".")
-- Remove Pilot Unit
ScenEdit_DeleteUnit({side=triggerUnit.side, guid=keyGUID})
-- Remove All Triggers From Events
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="air-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="ship-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="sub-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="ground-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Cancel Pilot"..keyGUID, {mode="remove", name="Trigger - Cancel Pilot"..keyGUID})
-- Remove All Actions From Events
ScenEdit_SetEventAction("Event - Cancel Pilot"..keyGUID, {mode="remove", name="Action - Cancel Pilot"..keyGUID})
-- Remove Actual Trigger
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="air-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="ship-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="sub-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="ground-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="RegularTime",name="Trigger - Cancel Pilot"..keyGUID})
-- Remove Actual Action
ScenEdit_SetAction({mode="remove", name="Action - Cancel Pilot"..keyGUID})
-- Remove Actual Event
ScenEdit_SetEvent("Event - Cancel Pilot"..keyGUID, {mode="remove"})
-- Remove GUID
RemoveSARTargetGUID(keyGUID)
-- Remove All Reference Points
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-1"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-2"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-3"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-4"})
end
end
end
--------------------------------------------------------------------------------------------------------------------------------
-- Start SAR Failed Target Pickup
--------------------------------------------------------------------------------------------------------------------------------
function StartSARFailedTargetPickup(triggerEvent)
-- Triggered Id
local keyGUID = GetLongKeyValuePairs(triggerEvent.guid)
local unit = ScenEdit_GetUnit({guid=keyGUID})
-- Scoring
if unit then
-- Add Score
local s = string.gmatch(unit.name, "[^ ]+") -- get first part of name which is the number of survivors
local totalSuccessScore = failureScore * s() --calculate total score
print("Total calculated score for " ..unit.name..": " ..totalSuccessScore)
if totalSuccessScore < maxFailureScore then totalSuccessScore = maxFailureScore end
print("Total score used (max/min checked): " ..totalSuccessScore)
AddScoreToSide(ScenEdit_PlayerSide(),totalSuccessScore,"Survivor Lost-"..unit.name)
-- Remove Pilot Unit
ScenEdit_DeleteUnit({side=survivorSide , guid=keyGUID})
-- Message Lost Pilot
ScenEdit_SpecialMessage(ScenEdit_PlayerSide (),"Sorry, we lost contact with "..unit.name)
end
-- Remove All Triggers From Events
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="air-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="ship-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="sub-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Start SAR Target Pickup", {mode="remove", name="ground-"..keyGUID})
ScenEdit_SetEventTrigger("Event - Cancel Pilot"..keyGUID, {mode="remove", name="Trigger - Cancel Pilot"..keyGUID})
-- Remove All Actions From Events
ScenEdit_SetEventAction("Event - Cancel Pilot"..keyGUID, {mode="remove", name="Action - Cancel Pilot"..keyGUID})
-- Remove Actual Trigger
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="air-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="ship-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="sub-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="UnitRemainsInArea",name="ground-"..keyGUID})
ScenEdit_SetTrigger({mode="remove",type="RegularTime",name="Trigger - Cancel Pilot"..keyGUID})
-- Remove Actual Action
ScenEdit_SetAction({mode="remove", name="Action - Cancel Pilot"..keyGUID})
-- Remove Actual Event --
ScenEdit_SetEvent("Event - Cancel Pilot"..keyGUID, {mode="remove"})
-- Remove GUID
RemoveSARTargetGUID(keyGUID)
RemoveLongKeyValuePairs(triggerEvent.guid)
-- Remove All Reference Points
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-1"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-2"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-3"})
ScenEdit_DeleteReferencePoint({side=survivorSide,name=keyGUID.."-4"})
end
--------------------------------------------------------------------------------------------------------------------------------
-- Save Pair Values (Long Keys Cause Errors)
--------------------------------------------------------------------------------------------------------------------------------
function GetLongKeyValuePairs(key)
-- Local Values
local keyValueString = ScenEdit_GetKeyValue("CONST_LONG_KEY_VALUE")
-- Check Key Value
if keyValueString == nil then
return ""
end
-- Split
local table = split(keyValueString,",")
for a, b in pairs(table) do
-- Split Some More
local subTable = split(b,"|")
if #subTable == 2 then
if subTable[1] == key then
return subTable[2]
end
end
end
end
function SetLongKeyValuePairs(key,value)
-- Local Values
local keyValueString = ScenEdit_GetKeyValue("CONST_LONG_KEY_VALUE")
-- Check Key Value
if keyValueString == nil then
keyValueString = key.."-"..value
else
keyValueString = keyValueString..","..key.."|"..value
end
-- Adding To Key Value
ScenEdit_SetKeyValue("CONST_LONG_KEY_VALUE",keyValueString)
end
function RemoveLongKeyValuePairs(key)
-- Local Values
local keyValueString = ScenEdit_GetKeyValue("CONST_LONG_KEY_VALUE")
local newKeyValueString = ""
-- Check Key Value
if keyValueString == nil then
return ""
end
-- Split
local table = split(keyValueString,",")
for a, b in pairs(table) do
-- Split Some More
local subTable = split(b,"|")
if #subTable == 2 then
if subTable[1] ~= key then
if newKeyValueString ~= "" then
newKeyValueString = newKeyValueString..","..b
else
newKeyValueString = b
end
end
end
end
-- Save To Key Value
ScenEdit_SetKeyValue("CONST_LONG_KEY_VALUE",newKeyValueString)
end
--------------------------------------------------------------------------------------------------------------------------------
-- michaelm75au's OOB script http://www.matrixgames.com/forums/tm.asp?m=4233608
-- slightly modified to display subtype, used to get subtype of units to set individual crew counts
-- run GetOOBWithSubType() in the lua console
--------------------------------------------------------------------------------------------------------------------------------
function GetOOBWithSubType()
local s = VP_GetSide({name=ScenEdit_PlayerSide()})
local function split(str, pat)
local t = {}
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
local function sortName(a,b)
return(ScenEdit_GetUnit({guid=a}).name