srhZSOC Posted August 13, 2023 Posted August 13, 2023 Hi, I've started getting in getting DCS ME and would like to use scripting within a mission that I am building. (I've got very little experience with coding or DCS ME, but keen to learn!) I want an infantry unit to spawn from a specific vehicle that the player has destroyed. I saw a suggestion on the DCS forums for something similar (spawning infantry from landing craft), so came up with the below code but it does not work. Grateful for suggestions on how to make it work, or perhaps an alternative approach? -- vehicle_destroyed_test is the group name of the vehicle that the player destroys -- escaper is the infantry unit that is supposed to escape the vehicle (set to late activation) -- trigger has the condition UNIT DEAD (vehicle_destroyed_test) -- DO SCRIPT Action using the below... local vehicle01 = GROUP:FindByName("vehicle_destroyed_test") local infantry01 = SPAWN:New("escaper") escape_from_vehicle = infantry01:SpawnFromUnit(vehicle01)
Maverick87Shaka Posted August 13, 2023 Posted August 13, 2023 (edited) First of all you have to load MOOSE, since you've not mentioned anywhere is worth to mention. After that, you have to make sure of what code you have to use, since you're trying to retrieve information from a DEAD unit, that is not possible in DCS. So you have to save the coordinate from dead event if available, and use that for spawn the infantry. Edited August 13, 2023 by Maverick87Shaka FlighRIG => CPU: RyZen 5900x | RAM: 64GB Corsair 3000Mhz | GPU: nVIDIA RTX 4090 FE | OS Storage: SSD NVMe Samsung 850 Pro 512GB, DCS Storage: SSD NVMe Sabrent 1TB | Device: Multipurpose-UFC, VirPil T-50, TM WARTHOG Throttle, TrackHat, MFD Cougar with screen. Our Servers => [ITA] Banshee | Krasnodar - PvE | PersianConquest PvE Live Map&Stats | Syria Liberation PvE Conquest Support us on twitch subscribing with amazon prime account linked, it's free!
srhZSOC Posted August 13, 2023 Author Posted August 13, 2023 Thanks @Maverick87Shaka, MOOSE is loaded at the start of the mission (and MIST), and I didn't realise that once a unit is dead, information can't be retrieved. How would I save a coordinate from a dead event? Is that using MOOSE?
Maverick87Shaka Posted August 13, 2023 Posted August 13, 2023 5 minutes ago, srhZSOC said: Thanks @Maverick87Shaka, MOOSE is loaded at the start of the mission (and MIST), and I didn't realise that once a unit is dead, information can't be retrieved. How would I save a coordinate from a dead event? Is that using MOOSE? Yes, with moose you can subscribe for events and use it. Dead event doesn't contain position, so you have to deal with it (welcome to the workaround zone!) If it's not a fast moving vehicle that you have to track, you can create a scheduler that check and update position every 10 seconds for example, and after event dead retrieve that information updated from the scheduler, and spawn the infantry from there. 1 FlighRIG => CPU: RyZen 5900x | RAM: 64GB Corsair 3000Mhz | GPU: nVIDIA RTX 4090 FE | OS Storage: SSD NVMe Samsung 850 Pro 512GB, DCS Storage: SSD NVMe Sabrent 1TB | Device: Multipurpose-UFC, VirPil T-50, TM WARTHOG Throttle, TrackHat, MFD Cougar with screen. Our Servers => [ITA] Banshee | Krasnodar - PvE | PersianConquest PvE Live Map&Stats | Syria Liberation PvE Conquest Support us on twitch subscribing with amazon prime account linked, it's free!
MegaTherion666 Posted August 15, 2023 Posted August 15, 2023 (edited) I'm rather new to mist/MOOSE scripting for DCS, but this was one of the first things I wanted to use it for too There's surely a much better/cleaner method of doing this, but it was fun to figure out, seems to work well enough, and it's been a nice addition for my missions... (this uses a mist scheduler, I've been meaning to convert this to 100% moose functions... but BG3 came out :P) load mist & moose. No need to add infantry templates in the ME, uses vehicle type & coalition/country to determine troop-types; (this includes spawning wwii troops from wwii units, & some insurgent mods I've picked up somewhere for other vehicle types....) -- script to spawn crew from destroyed/disabled ground vehicles, populate Bodies.on.Battlefield (BoB) env.info("GROUND CREW LOADING...") local survivalRate = 75 -- (of 100), aka 3/4ths survival rate -- min & max radus from vehicle local spawnRadiusMin = 1 local spawnRadiusMax = 8 -- match crew number to vehicle local crewManifest = { ["BTR-80"] = { crew = 3 }, -- ["BTR-82A"] = { crew = 3 }, -- ["AAV7"] = { crew = 3 }, -- ["BMP-1"] = { crew = 3 }, -- ["BMP-2"] = { crew = 3 }, -- ["BMP-3"] = { crew = 3 }, -- ["T-55"] = { crew = 4 }, -- ["T-72B"] = { crew = 3 }, -- ["T-72B3"] = { crew = 4 }, -- ["T-80UD"] = { crew = 3 }, -- ["T-90"] = { crew = 3 }, -- ["SA-11 Buk LN 9A310M1"] = { crew = 2 }, --? ["SA-11 Buk CC 9S470M1"] = { crew = 3 }, --? ["SA-11 Buk SR 9S18M1"] = { crew = 3 }, --? ["M1126_Stryker"] = { crew = 2 }, --? For M1126 Stryker, the typical crew is 2, including the driver and commander. ["M1134 Stryker ATGM"] = { crew = 2 }, -- ["M113"] = { crew = 2 }, -- For M113, the typical crew is 2, including the driver and commander. ["M-1 Abrams"] = { crew = 4 }, --? ["M2_Bradley"] = { crew = 3 }, --? For M2 Bradley, the typical crew is 3, including the driver, gunner, and commander. ["M-2 Bradley"] = { crew = 3 }, --? For M2 Bradley, the typical crew is 3, including the driver, gunner, and commander. ["M2A2_ODS_Bradley"] = { crew = 3 }, --? ["Marder"] = { crew = 3 }, --? ["Leopard-2"] = { crew = 4 }, --? ["Challenger2"] = { crew = 4 }, --? ["M-109"] = { crew = 5 }, --? ["2S19_Msta"] = { crew = 5 }, --? ["Kub 2P25 ln"] = { crew = 3 }, -- ["M1043 HMMWV Armament"] = { crew = 2 }, -- ["M1045 HMMWV TOW"] = { crew = 2 }, -- ["M1126 Stryker ICV"] = { crew = 3 }, -- ["BRDM-2"] = { crew = 2 }, -- ["TPZ"] = { crew = 2 }, -- ["MTLB"] = { crew = 4 }, -- ["M-60"] = { crew = 4 }, -- ["M-113"] = { crew = 4 }, -- ["BTR_D"] = { crew = 4 }, -- ["LAV-25"] = { crew = 4 }, -- ["VAB_Mephisto"] = { crew = 4 }, -- ["ZSU-23-4 Shilka"] = { crew = 3 }, -- ["Ural-375"] = { crew = 4 }, -- ["CH_TigrM"] = { crew = 4 }, -- CurrentHill Mods ["CH_OshkoshLATV_M2"] = { crew = 4 }, -- CurrentHill Mods ["CH_OshkoshMATV_M2"] = { crew = 4 }, -- CurrentHill Mods ["CH_OshkoshLATV_MK19"] = { crew = 4 }, -- CurrentHill Mods ["CH_OshkoshMATV_MK19"] = { crew = 4 }, -- CurrentHill Mods ["Cobra"] = { crew = 4 }, -- CurrentHill Mods ["HPG_Toyota_ISIS"] = { crew = 2, isInsurgent = true }, -- Insurgent vehicles should spawn insurgents ["HPG_Ural_Isis_Troops"] = { crew = 4, isInsurgent = true}, -- ["HPG_Ural_Isis_Covered"] = { crew = 7, isInsurgent = true}, -- ["HPGToyotaISISDShK"] = { crew = 2, isInsurgent = true }, -- ["HPGUralIsisFlak"] = { crew = 2, isInsurgent = true }, -- ["HPGUralIsisZU23"] = { crew = 2, isInsurgent = true }, -- ["ERO_Toyota_White"] = { crew = 2, isInsurgent = true }, -- ["ERO_TOYOTA_Desert"] = { crew = 2, isInsurgent = true }, -- ["ERO_Toyota_Camo"] = { crew = 2, isInsurgent = true }, -- ["ERO_Toyota_Clown"] = { crew = 2, isInsurgent = true }, -- ["ERO_ZU23_Toyota_armored"] = { crew = 2, isInsurgent = true }, -- ["tt_DSHK"] = { crew = 1, isInsurgent = true }, -- ["tt_KORD"] = { crew = 1, isInsurgent = true }, -- ["HL_DSHK"] = { crew = 1, isInsurgent = true }, -- ["HL_KORD"] = { crew = 1, isInsurgent = true }, -- ["Centaur_IV"] = { crew = 5, WWII = true }, -- WWII allies -- ["Cromwell_IV"] = { crew = 5, WWII = true }, -- ["Churchill_VII"] = { crew = 5, WWII = true }, -- ["M4_Sherman"] = { crew = 5, WWII = true }, -- ["M4A4_Sherman_FF"] = { crew = 5, WWII = true }, -- ["Tetrarch"] = { crew = 2, WWII = true }, -- ["M2A1_halftrack"] = { crew = 2, WWII = true }, -- ["M4_Tractor"] = { crew = 2, WWII = true }, -- ["M10_GMC"] = { crew = 5, WWII = true }, -- ["SPH_M109_Paladin_155mm"] = { crew = 5, WWII = true }, --? ["M8_Greyhound"] = { crew = 2, WWII = true }, -- ["Truck_Bedford"] = { crew = 2, WWII = true }, --? ["Bedford_MWD"] = { crew = 2, WWII = true }, -- ["Car_Willys_Jeep"] = { crew = 1, WWII = true }, --? ["Truck_GMC_Jimmy_6x6"] = { crew = 2, WWII = true }, --? ["Tiger_II_H"] = { crew = 5, WWII = true }, -- WWII axis -- ["Tiger_I"] = { crew = 5, WWII = true }, -- ["Pz_IV_H"] = { crew = 5, WWII = true }, -- ["Pz_V_Panther_G"] = { crew = 5, WWII = true }, -- ["Stug_IV"] = { crew = 4, WWII = true }, -- ["Stug_III"] = { crew = 4, WWII = true }, -- ["JagdPz_IV"] = { crew = 4, WWII = true }, -- ["Jagdpanther_G1"] = { crew = 4, WWII = true }, -- ["Elefant_SdKfz_184"] = { crew = 6, WWII = true }, -- The Elefant had a crew of 6, including the driver, radio operator, commander, gunner, and two loaders. ["SPG_Brummbaer_AG"] = { crew = 5, WWII = true }, --? ["Sd_Kfz_234_2_Puma"] = { crew = 4, WWII = true }, -- The Puma had a crew of 4, including the driver, radio operator, commander, and gunner. ["Sd_Kfz_251"] = { crew = 4, WWII = true }, -- The Puma had a crew of 4, including the driver, radio operator, commander, and gunner. ["APC_Sd.Kfz.251_Halftrack"] = { crew = 2, WWII = true }, --? For the Sd.Kfz.251 Halftrack, the typical crew is 2, including the driver and commander. ["SturmPzIV"] = { crew = 2, WWII = true }, -- ["Daimler_AC"] = { crew = 1, WWII = true }, -- --["Bedford_MWD"] = { crew = 2, WWII = true }, -- } -- Modern soldier types local BlueSoldiers = { "Soldier M4", --repitition = odds 1/10 for stinger / rpg "Soldier M4", "Soldier M4", "Soldier M4", "Soldier M4", "Soldier M4", "Soldier M4", "Soldier M4", "Soldier M249", "Soldier stinger", } local RedSoldiers = { "Infantry AK", --"Infantry AK ver1", causes "unknown unit" error? "Infantry AK ver2", "Infantry AK ver3", "Infantry AK", "Infantry AK ver2", "Infantry AK ver3", "Infantry AK", "Infantry AK ver2", "Infantry AK ver3", --"Soldier RPG", } -- for WWII, we'll make use of specific soldiers by name as well as randomized local USsoldier = "soldier_wwii_us" local UKsoldier = "soldier_wwii_br_01" local GermanSoldier = "soldier_mauser98" local WWII_BlueSoldiers = { USsoldier, UKsoldier, } local WWII_RedSoldiers = { GermanSoldier, } local Insurgents = { "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "InsurgentMod", "Soldier RPG", --"Insurgent AK-74", } local targetBailPercentage = 50 -- at what health percentage does the crew bail? (must be monitoring S_EVENT_HIT) -- DEPRECATED local spawnedGroups = {} --track units that have spawned crew local debugFlag = USERFLAG:New( "debug" ) --flag set in mission editor? local debugFlagValue = debugFlag:Get() --BASE:TraceAll(true) --BASE:TraceOnOff( true ) --BASE:TraceLevel( 3 ) -- define template data for crew local function SoldierTemplate (groupName, groupType) --bare minimum template data; populate name & type here local unitTemplate = { ["name"] = groupName, ["units"] = { [1] = { ["skill"] = "Average", ["coldAtStart"] = false, ["type"] = groupType, ["playerCanDrive"] = false, }, -- end of [1] }, -- end of ["units"] } return unitTemplate end -- Define the vehicle destruction event handler function onGroundVehicleDamaged(event) --if event.id == world.event.S_EVENT_HIT then if event.id == world.event.S_EVENT_BDA then local survivalCoinFlip = math.random(1, 100) if survivalCoinFlip <= survivalRate then if event.initiator ~= nil and event.target ~= nil then -- Get details on participants to the event local InitiatorUnit = event.initiator:getName() local InitiatorType = event.initiator:getTypeName() local InitiatorCoal = event.initiator:getCoalition() local TargetName = event.target:getName() local TargetType = event.target:getTypeName() local TargetCat = event.target:getDesc().category local TargetCoal = event.target:getCoalition() or 3 local TargetPos = event.target:getPosition().p local TargetCountry = event.target:getCountry() if debugFlagValue == 1 then MESSAGE:New("DEBUG EVENT: " .. InitiatorUnit .. " type(" .. InitiatorType .. ") -> " .. TargetName .. " type(" .. TargetType .. ")(" .. TargetCat .. ") TargetCoal: " .. TargetCoal, 10,"Ground Crew"):ToAll() end if TargetCat == 2 then -- if ground targets ... if crewManifest[TargetType] then -- if unit included on crewManifest, returns true local targetHealth = event.target:getLife() local targetMaxHealth = event.target:getLife0() local targetHealthPercentage = targetHealth / targetMaxHealth * 100 -- When unit is injured beyond certain point, crew bails --if targetHealthPercentage < targetBailPercentage then --track spawnedGroups so no dupes local groupKey = TargetName .. "_" .. TargetType if not spawnedGroups[groupKey] then spawnedGroups[groupKey] = true if debugFlagValue == 1 then MESSAGE:New(TargetName .. "'s (" .. TargetType .. ") health is below 10% = " .. targetHealthPercentage .. "% at " .. TargetPos.x .. " x " .. TargetPos.z, 10,"Ground Crew"):ToAll() end --define crew compliment according to manifest, randomize crewAlive local crewMax = crewManifest[TargetType].crew or 2 -- Default to 2 if TargetType not found (should be crewmax) local crewAlive = math.random(1, crewMax) local crewCount = 0 for i = 1, crewAlive do -- for each member of the crew... crewCount = crewCount + 1 -- Define the randomized radius around the damaged vehicle where infantry will be spawned local radius = math.random(spawnRadiusMin, spawnRadiusMax) local heading = math.random(0, 360) -- Randomize the heading of the infantry units local offsetX = radius * math.cos(math.rad(heading + (i * 360 / crewAlive))) local offsetY = radius * math.sin(math.rad(heading + (i * 360 / crewAlive))) local spawnPosition = { x = TargetPos.x, y = TargetPos.z, -- CRITICAL mis-match -- y-to-z here makes correct placement?? z = land.getHeight({ x = TargetPos.x, y = TargetPos.y }) -- Get the ground altitude at the target's x, y position } -- Add the offsets to the spawn position spawnPosition.x = spawnPosition.x + offsetX spawnPosition.y = spawnPosition.y + offsetY -- get them to run away from vehicle by routing to a further WP local waypointDistance = math.random(50, 300) local waypointHeading = math.random(0, 360) local waypointPosition = { x = spawnPosition.x + waypointDistance * math.cos(math.rad(heading)), y = spawnPosition.y + waypointDistance * math.sin(math.rad(heading)), z = land.getHeight({ x = spawnPosition.x, y = spawnPosition.y }) } --random selection from the list of coalition groups local initCoal = nil local initSide = nil local RandomUnit = nil -- select solider type on some conditions... if TargetCoal == 1 then if crewManifest[TargetType].WWII == true then --RandomUnit = WWII_RedSoldiers[math.random(1, #WWII_RedSoldiers)] RandomUnit = GermanSoldier else RandomUnit = RedSoldiers[math.random(1, #RedSoldiers)] -- move to puremoose no ME end initSide = coalition.side.RED elseif TargetCoal == 2 then if crewManifest[TargetType].WWII == true then if TargetCountry == country.id.UK then RandomUnit = UKsoldier elseif TargetCountry == country.id.USA then RandomUnit = USsoldier else RandomUnit = WWII_BlueSoldiers[math.random(1, #WWII_BlueSoldiers)] end else RandomUnit = BlueSoldiers[math.random(1, #BlueSoldiers)] -- see if you can replace the previous method end initSide = coalition.side.BLUE end -- insurgents could be from anywhere/anytime if crewManifest[TargetType].isInsurgent == true then RandomUnit = Insurgents[math.random(1, #Insurgents)] end local RandomN = math.random(1,1000000) local newGroupName = RandomUnit .. "_" .. TargetName .. "-" .. i local Template = SoldierTemplate(newGroupName, RandomUnit) --populate customized template local newAlias = "Soldier-" .. RandomN -- generic name, can be same alias among soldiers local initCoal = TargetCountry --units should inherit the vehicle country local initCat = Group.Category.GROUND -- must be set on init local heading = math.random(1, 360) -- random heading for everyone local walkSpeed = 10 -- WP travel speed -- spawn from modified template rather than require placed unit local soldier = SPAWN:NewFromTemplate(Template, newGroupName, newAlias) :InitCountry(initCoal) :InitCoalition(initSide) :InitCategory(initCat) :InitHeading(heading) :InitLimit(1, 1) --TEST: (maxunits, maxgroups to spawn) :InitDelayOn() --TEST --:InitPositionVec2(spawnPosition) --TEST :OnSpawnGroup( function(grp) if debugFlagValue == 1 then MESSAGE:New(initSide .. " Spawned: "..grp:GetName(),15,"Ground Crew"):ToAll() end grp:RouteToVec2(waypointPosition, walkSpeed) --get them to run away end ) :SpawnScheduled(5, 0.5) --TEST :SpawnFromVec2(spawnPosition) --soldier:SpawnScheduleStop() --TEST if debugFlagValue == 1 then MESSAGE:New(" ... SPAWN from '" .. TargetType .. "' (" .. RandomUnit .. ") " .. crewCount .. " of " .. crewMax .. " crew at " .. spawnPosition.x .. " x " .. spawnPosition.y , 10,"Ground Crew"):ToAll() end end -- end crew foreach end else -- log VechicleTypes we don't have included on the CrewManifest, but ignore soldier types local isBlueSoldier = false local isRedSoldier = false local isWWIIBlueSoldier = false local isWWIIRedSoldier = false local isInsurgent = false for _, unitType in ipairs(RedSoldiers) do if unitType == TargetType then isRedSoldier = true break end end for _, unitType in ipairs(BlueSoldiers) do if unitType == TargetType then isBlueSoldier = true break end end for _, unitType in ipairs(WWII_RedSoldiers) do if unitType == TargetType then isWWIIRedSoldier = true break end end for _, unitType in ipairs(WWII_BlueSoldiers) do if unitType == TargetType then isWWIIBlueSoldier = true break end end for _, unitType in ipairs(Insurgents) do if unitType == TargetType then isInsurgent = true break end end if not (isRedSoldier or isBlueSoldier or isWWIIRedSoldier or isWWIIBlueSoldier or isInsurgent) then --if debugFlagValue == 1 then MESSAGE:New("ADD MISSING VEHICLE in script :----> No crewManifest for TargetType '" .. TargetType .. "' ", 15,"Ground Crew"):ToAll() --end env.info("GROUND CREW NOTICE: ADD MISSING VECHILE ----> No crewManifest for TargetType: " .. TargetType .. " ") end --end --if targetHealthPercentage end end end end --coinflip end end -- Register the event handler for the unit damage event mist.addEventHandler(onGroundVehicleDamaged) --local eventHandler = EVENTHANDLER:New() --eventHandler:OnEvent(onGroundVehicleDamaged) --sendMessageToAll("Ground Vehicle Crews LOADED", 10) MESSAGE:New("Ground Vehicle Crews LOADED", 10,"Ground Crew"):ToAll() env.info("GROUND CREW LOADED.") Spawn_Vehicle_Crew_on_Destruction.lua Edited June 10, 2024 by MegaTherion666
srhZSOC Posted August 19, 2023 Author Posted August 19, 2023 Thanks @MegaTherion666, will give this a go!
Recommended Posts