Skip to content

Instantly share code, notes, and snippets.

@TDC-bob
Last active December 17, 2015 19:20
Show Gist options
  • Save TDC-bob/5660090 to your computer and use it in GitHub Desktop.
Save TDC-bob/5660090 to your computer and use it in GitHub Desktop.
Script de medevac
-- MEDEVAC Script for DCS, By RagnarDa 2013
medevac = {}
medevac.medevacunits = {"MEDEVAC #1", "MEDEVAC #2"} -- List of all the MEDEVAC _GROUP NAMES_!
medevac.clonenewgroups = false -- Set to false to not spawn in new units (clone)
medevac.maxbleedtime = 1800 -- Maximum time that the wounded will bleed in the transport before dying
medevac.bluemash = Unit.getByName("BlueMASH") -- The unit that serves as MASH for the blue side
medevac.redmash = Unit.getByName("RedMASH") -- The unit that serves as MASH for the red side
medevac.smokemarkers = {}
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
-- Get average amount of health of group compared to what it started with
function getGroupHealthPercentage(grp)
local sts, rtrn = pcall(
function (_grp)
local units = Group.getUnits(_grp)
local _unitcount = tablelength(units)
local _totalnow = 0
local _totalthen = 0
for nr,x in pairs(units) do
_totalnow = _totalnow + Unit.getLife(x)
if (_totalnow <= 1.0) then _totalnow = 0 end
_totalthen = _totalthen + Unit.getLife0(x)
end
local percentage = ((_totalnow/_totalthen) * 100)
-- if (percentage ~= 100 and (gci.verbose > 0)) then env.info(string.format("%s group health: %d", Group.getName(grp), percentage), false) end
return percentage
end
, grp)
if (sts) then
return rtrn
else
env.warning(string.format("getGroupHealthPercentage() failed! Returning 0. %s", rtrn), false)
return 0
end
end
function measuredistance(v1, v2)
local distance = 0
local v1x = v1.x
local v2x = v2.x
local v1z = v1.z
local v2z = v2.z
if v1x > v2x then
distance = distance + (v1x - v2x)
else
distance = distance + (v2x - v1x)
end
if v1z > v2z then
distance = distance + (v1z - v2z)
else
distance = distance + (v2z - v1z)
end
return distance
end
function SetWaypoints(_groupName, _waypoints)
local _points = {}
for nr,x in pairs(_waypoints) do
_points[nr] = x
end
Mission = {
id = 'Mission',
params = {
route = {
points = _points
},
}
}
local _controller = Group.getByName(_groupName):getController();
--Controller.setOption(_controller, AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN)
_controller:setTask(Mission)
end
function BleedTimer(_argument, _time)
--env.info("Bleed timer.", false)
local _status, _timetoreset = pcall(
function (_argument)
local _medevacunit = _argument[1]
local _pickuptime = _argument[2]
local _oldgroup = _argument[3]
if (_medevacunit == nil) then
env.info("Helicopter is nil.",false)
return nil
end
local sts, rtrn = pcall(
function (_medevacunit)
if (Unit.getLife(_medevacunit) <= 1.0) then
return true
end
end
, _medevacunit)
if (rtrn or not sts) then
env.info("Helicopter is dead.", false)
return nil
end
--local _woundtime = _argument[3]
--local _mash = StaticObject.getByName("MASH")
--assert(not MASH == nil, "There is no MASH!")
local _mash = medevac.bluemash
if (Group.getCoalition(Unit.getGroup(_medevacunit)) == 1) then
_mash = medevac.redmash
end
local _medevacid = Group.getID(Unit.getGroup(_medevacunit))
local _timeleft = math.floor(0 + (_pickuptime - timer.getTime()))
if (_timeleft < 1) then
trigger.action.outTextForGroup(_medevacid, string.format("The wounded has bled out.", _timeleft), 20)
return nil
end
local _mashpos = _mash:getPosition().p
local _status, _helipoint = pcall(
function (_medevacunitarg)
return _medevacunitarg:getPosition().p
end
,_medevacunit)
if (not _status) then env.error(string.format("Error while _evacpoint\n\n%s",_helipoint), true) end
local _status, _distance = pcall(
function (_distargs)
local _rescuepoint = _distargs[1]
local _evacpoint = _distargs[2]
return measuredistance(_rescuepoint, _evacpoint)
end
,{_mashpos, _helipoint})
if (not _status) then env.error(string.format("Error while measuring distance\n\n%s",_distance), true) end
local _velv = _medevacunit:getVelocity()
local _medspeed = mist.vec.mag(_velv)--string.format('%12.2f', mist.vec.mag(_velv))
if (_medspeed < 1 and _distance < 200 and _medevacunit:inAir() == false) then
trigger.action.outTextForGroup(_medevacid, string.format("The wounded has been taken to the\nmedical clinic. Good job!", "Good job!"), 30)
if (medevac.clonenewgroups) then
--sct.cloneInZone(_oldgroup, "SpawnZone", true, 100)
trigger.action.outTextForGroup(_medevacid, string.format("The wounded has been taken to the\nmedical clinic. Good job!\n\nReinforcment have arrived.", "Good job!"), 30)
sct.cloneGroup(_oldgroup, true)
end
return nil
end
trigger.action.outTextForGroup(_medevacid, string.format("Bring them back to the MASH ASAP!\n\nThe wounded will bleed out in: %u seconds.", _timeleft), 2)
return timer.getTime() + 1
end
,_argument)
if (not _status) then env.error(string.format("Error while BleedTime\n\n%s",_timetoreset), true) end
return _timetoreset
end
function LandEvent(_argument, _time)
local _medevacunit = _argument[1]
local _rescuegroup = _argument[2]
local _oldgroup = _argument[3]
local _rescuepoint = Group.getUnits(Group.getByName(_rescuegroup))[1]:getPosition().p
local _medevacid = Group.getID(Unit.getGroup(_medevacunit))
local _evacpoint = {}
if (Unit.getLife(_medevacunit) <= 1.0) then
env.info("Helicopter is dead.", false)
return nil
end
if (getGroupHealthPercentage(Group.getByName(_rescuegroup)) < 0.1) then
env.info("Group to rescue is dead.", false)
return nil
end
local _status, _evacpoint = pcall(
function (_medevacunitarg)
return _medevacunitarg:getPosition().p
end
,_medevacunit)
if (not _status) then env.error(string.format("Error while _evacpoint\n\n%s",_evacpoint), true) end
local _status, _distance = pcall(
function (_distargs)
local _rescuepoint = _distargs[1]
local _evacpoint = _distargs[2]
return measuredistance(_rescuepoint, _evacpoint)
end
,{_rescuepoint, _evacpoint})
if (not _status) then env.error(string.format("Error while measuring distance\n\n%s",_distance), true) end
-- local _alt = land.getHeight(_evacpoint)
-- local _agl = _evacpoint.y - _alt
-- trigger.action.outTextForGroup(_medevacid, string.format("Altitude now: %f", _agl), 10)
local _velv = _medevacunit:getVelocity()
local _medspeed = mist.vec.mag(_velv)--string.format('%12.2f', mist.vec.mag(_velv))
--trigger.action.outTextForGroup(_medevacid, string.format("Speed: %f", _medspeed),10)
local _status, _err = pcall(
function (_args)
_medspeed = _args[1]
_distance = _args[2]
_medevacunit = _args[3]
_medevacid = _args[4]
_rescuegroup = _args[5]
_oldgroup = _args[6]
if (_medspeed < 1 and _distance < 200 and _medevacunit:inAir() == false) then
trigger.action.outTextForGroup(_medevacid, string.format("Units picked up!\n\nBring them back to MASH ASAP!", _agl), 10)
Group.destroy(Group.getByName(_rescuegroup))
timer.scheduleFunction(BleedTimer, {_medevacunit, math.random(0, medevac.maxbleedtime) + timer.getTime(), _oldgroup}, timer.getTime() + 1)
end
end
,{_medspeed, _distance, _medevacunit, _medevacid, _rescuegroup, _oldgroup})
if (not _status) then env.error(string.format("Error while picking up\n\n%s",_err), true) end
if (_distance < 600 and _distance > 500) then
local _moveto = getpointbetween(_rescuepoint, _evacpoint, 0.2)
Mission = {
id = 'Mission',
params = {
route = {
points = {
[1] = {
action = 0,
x = _moveto.x,
y = _moveto.z,
speed = 10,
ETA = 100,
ETA_locked = false,
name = "Pick-up",
task = nil
},
[2] = {
action = 0,
x = _moveto.x,
y = _moveto.z,
speed = 10,
ETA = 100,
ETA_locked = false,
name = "Pick-up2",
task = nil
},
}
},
}
}
local _controller = Group.getByName(_rescuegroup):getController();
Controller.setOption(_controller, AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN)
_controller:setTask(Mission)
-- Controller.setOption(_controller, AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN)
end
return timer.getTime() + 2
end
function SmokeEvent(_argument, _time)
local _rescuepoint = _argument[1]
local _medevacunit = _argument[2]
local _rescuegroup = _argument[3]
local _oldgroup = _argument[4]
if (Unit.getLife(_medevacunit) <= 1.0) then
env.info("Helicopter is dead.", false)
return nil
end
if (getGroupHealthPercentage(Group.getByName(_rescuegroup)) < 0.1) then
env.info("Group to rescue is dead.", false)
return nil
end
local _medevacid = Group.getID(Unit.getGroup(_medevacunit))
local _status, _evacpoint = pcall(
function (_medevacunitarg)
return _medevacunitarg:getPosition().p
end
,_medevacunit)
if (not _status) then env.error(string.format("Error while _evacpoint\n\n%s",_evacpoint), true) end
-- local _evacpoint = _medevacunit:getPosition().p
local _status, _distance = pcall(
function (_distargs)
local _rescuepoint = _distargs[1]
local _evacpoint = _distargs[2]
return measuredistance(_rescuepoint, _evacpoint)
end
,{_rescuepoint, _evacpoint})
if (not _status) then env.error(string.format("Error while measuring distance\n\n%s",_distance), true) end
-- local _distance = measuredistance(_rescuepoint, _evacpoint)
-- trigger.action.outTextForGroup(_medevacid, string.format("Distance now: %f", _distance), 10)
if (_distance < 3000) then
-- Helicopter is within 3km
local _status, _err = pcall(
function (_args)
_medevacid = _args[1]
_rescuepoint = _args[2]
_oldgroup = _args[3]
trigger.action.outTextForGroup(_medevacid, "Land by the red smoke.", 10)
local smokenear = false
for _,x in pairs(medevac.smokemarkers) do
local _smokepoint = x[1]
local _smoketime = x[2]
local _smokedistance = measuredistance(_rescuepoint, _smokepoint)
local _txt = string.format("Land near the smoke.", _smokedistance, ((_smoketime + 300) - timer.getTime() ))
trigger.action.outTextForGroup(_medevacid, _txt, 10)
if (_smokedistance < 400 and ((_smoketime + 300) > timer.getTime() )) then
smokenear = true
end
end
local alt = land.getHeight(_rescuepoint)
if (not smokenear) then
trigger.action.smoke(_rescuepoint, 1)
table.insert(medevac.smokemarkers, {_rescuepoint, timer.getTime()})
end
timer.scheduleFunction(LandEvent, {_medevacunit, _rescuegroup, _oldgroup}, timer.getTime() + 2)
end
,{_medevacid, _rescuepoint, _oldgroup})
if (not _status) then env.error(string.format("Error while planting smoke:\n\n%s",_err), true) end
--trigger.action.smoke({x = _rescuepoint.x + 5, y = _rescuepoint.y, z = _rescupoint.z}, 1)
return nil
end
return timer.getTime() + 10
end
-- Finds a point betweem two points according to a given blend (0.5 = right between, 0.3 = a third from point1)
function getpointbetween(point1, point2, blend)
return {
x = point1.x + blend * (point2.x - point1.x),
y = point1.y + blend * (point2.y - point1.y),
z = point1.z + blend * (point2.z - point1.z)
}
end
-- Removes target from a array/table and returns true if the item was removed
function removeintable(Tbl,trgt)
local removed = false
for nr,x in pairs(Tbl) do
if (x==trgt) then
table.remove(Tbl,nr)
removed=true
end
end
return removed
end
-- Unittest removeintable
local unittesttbl = {1,2,3}
assert(removeintable(unittesttbl,2) == true, "Unittest 1 of removeintable failed!")
assert(unittesttbl[1] == 1 and unittesttbl[2] == 3, "Unittest 2 of removeintable failed!")
-- Handles all world events
medevac.eventhandler = {}
function medevac.eventhandler:onEvent(vnt)
local status, err = pcall(
function (vnt)
assert(vnt ~= nil, "Event is nil!")
if (vnt.id == 8 and vnt.initiator ~= nil) then
-- Unit dead
local _unit = vnt.initiator
if (vnt.initiator == nil) then return nil end
local _grp
local sts, _grp = pcall(
function (_int)
return Group.getName(Unit.getGroup(_int))
end
, vnt.initiator)
if (not sts) then
env.warning(string.format("No event initator", ""), false)
return nil
end
if (Object.hasAttribute(_unit, "Ground vehicles")) then
local _pos = Object.getPoint(_unit)
local _coord1, _coord2, _dist = coord.LOtoLL(_pos)
local _tarpos = _pos
local _idroot = math.random(1000, 10000)
local _groupname = string.format("Wounded infantry #%f", _idroot)
local _woundcoal = Group.getCoalition(Group.getByName(_grp))
local _country = 0
local _infantry = "Soldier AK"
if (_woundcoal == 2) then
_country = 2
_infantry = "Soldier M4"
end
coalition.addGroup(_country, Group.Category.GROUND, {
["visible"] = false,
["taskSelected"] = true,
["route"] =
{
["spans"] =
{
[1] =
{
[1] =
{
["y"] = _tarpos.z,
["x"] = _tarpos.x,
}, -- end of [1]
[2] =
{
["y"] = _tarpos.z,
["x"] = _tarpos.x,
}, -- end of [2]
}, -- end of [1]
}, -- end of ["spans"]
["points"] =
{
[1] =
{
["alt"] = 18,
["type"] = "Turning Point",
["ETA"] = 0,
["alt_type"] = "BARO",
["formation_template"] = "",
["y"] = _tarpos.z,
["x"] = _tarpos.x,
["ETA_locked"] = true,
["speed"] = 5.5555555555556,
["action"] = "Off Road",
["task"] =
{
["id"] = "ComboTask",
["params"] =
{
["tasks"] =
{
[1] =
{
["number"] = 1,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "Option",
["params"] =
{
["value"] = 0,
["name"] = 0,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [1]
[2] =
{
["enabled"] = true,
["auto"] = false,
["id"] = "WrappedAction",
["number"] = 2,
["params"] =
{
["action"] =
{
["id"] = "Option",
["params"] =
{
["value"] = 2,
["name"] = 9,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [2]
}, -- end of ["tasks"]
}, -- end of ["params"]
}, -- end of ["task"]
["speed_locked"] = true,
}, -- end of [1]
}, -- end of ["points"]
}, -- end of ["route"]
["groupId"] = _idroot,
["tasks"] =
{
}, -- end of ["tasks"]
["hidden"] = false,
["units"] =
{
[1] =
{
["y"] = _tarpos.z + 8,
["type"] = _infantry,
["name"] = string.format("%s #1", _groupname),
["unitId"] = _idroot + 1,
["heading"] = 3,
["playerCanDrive"] = true,
["skill"] = "Excellent",
["x"] = _tarpos.x - 4.6,
}, -- end of [1]
[2] =
{
["y"] = _tarpos.z + 6.2,
["type"] = _infantry,
["name"] = string.format("%s #2", _groupname),
["unitId"] = _idroot + 2,
["heading"] = 2,
["playerCanDrive"] = true,
["skill"] = "Excellent",
["x"] = _tarpos.x - 6.2,
}, -- end of [2]
[3] =
{
["y"] = _tarpos.z + 4.6,
["type"] = _infantry,
["name"] = string.format("%s #3", _groupname),
["unitId"] = _idroot + 3,
["heading"] = 2,
["playerCanDrive"] = true,
["skill"] = "Excellent",
["x"] = _tarpos.x - 8,
}, -- end of [3]
}, -- end of ["units"]
["y"] = _tarpos.z,
["x"] = _tarpos.x,
["name"] = _groupname,
["start_time"] = 0,
["task"] = "Ground Nothing",
})
local _leaderpos = Unit.getByName(string.format("%s #1", _groupname)):getPosition().p
local _medevactext = string.format("MEDEVAC REQUESTED AT N%f E%f", _coord1, _coord2)
for nr,x in pairs(medevac.medevacunits) do
local status, err = pcall(
function (_args)
x = _args[1]
_woundcoal = _args[2]
_medevactext = _args[3]
_leaderpos = _args[4]
_groupname = _args[5]
_grp = _args[6]
if (Group.getByName(x) ~= nil and Unit.isActive(Group.getUnits(Group.getByName(x))[1])) then
local _evacoal = Group.getCoalition(Group.getByName(x))
-- Check coalition side
if (_evacoal == _woundcoal) then
-- Display a delayed message
timer.scheduleFunction(delayedhelpevent, {x, _medevactext}, timer.getTime() + 5)
-- Schedule timer to check when to pop smoke
timer.scheduleFunction(SmokeEvent, {_leaderpos, Group.getUnits(Group.getByName(x))[1], _groupname, _grp}, timer.getTime() + 10)
end
end
end
, {x, _woundcoal, _medevactext, _leaderpos, _groupname, _grp})
if (not status) then env.warning(string.format("Error while checking with medevac-units:\n\n%s",err), false) end
end
end
end
end
, vnt)
if (not status) then env.error(string.format("Error while handling event\n\n%s",err), true) end
end
-- Displays a request for medivac
function delayedhelpevent(_args, _time)
local status, err = pcall(
function (_args)
local _medgrname = _args[1]
local _medevactext = _args[2]
local _medevacid = Group.getID(Group.getByName(_medgrname))
trigger.action.outTextForGroup(_medevacid, _medevactext, 120)
end
, _args)
if (not status) then env.error(string.format("Error while handling message\n\n%s",err), true) end
return nil
end
world.addEventHandler(medevac.eventhandler)
env.info("Medevac event handler added", false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment