Last active
December 17, 2015 19:20
-
-
Save TDC-bob/5660090 to your computer and use it in GitHub Desktop.
Script de medevac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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