609_Relentov Posted May 16, 2023 Posted May 16, 2023 (edited) I'm wondering if someone in the DCS scripting community can help me. I have a script OpForAC that will spawn 1-4 opposing force AI aircraft (repeatable), which can be fighter, attack, bomber aircraft, or helicopter types. AI aircraft types, engagement scenarios (i.e. BVR, ACM) and pre-set spawn distances are selectable from the F10 menu. The script is mostly complete, and it's working as I'd envisioned, but I'm seeing some odd behavior differences w/regard to the score page, specifically between running missions (using the script) as a multiplayer server vs offline in single player mode. In multiplayer server mode, if I shoot down spawned opposing force (enemy) AI aircraft, they show up as destroyed when I look at the score page. However, in single player mode, if I shoot down spawned enemy AI aircraft, they don't show up as destroyed, and in the score log/debrief details, their country is not showing properly (e.g. it seems they are treated as neutral) - see attached image. Regardless of which mode the mission is played in, if you look at the aircraft in the F10 map, they are showing as red / enemy, so it appears the mission is recognizing the country ID passed to the coalition.addGroup(...) function. I just can't figure out why in single player mode, the scoring is not working properly. Here's a look at the function that spawns AI aircraft, using the example plane group shown in hoggitworld (https://wiki.hoggitworld.com/view/DCS_exam_group_plane ) Spoiler --[[ ############################################################################################ Function: SpawnOpForACGroup Purpose: Spawns 1-4 units of the specified unit type, with two waypoints as specified Parameters: pUnitName - Unit name initiating the spawning of units pCountry - Country ID of group to be spawned (country.id enum) pType - Unit type pNum - Number of units pSkill - Skill of unit(s) pEngScen - Engagement scenario pHeadingRad - Unit heading in radians pWP1Vec3 - Vec3 table (point) w/altitude, longitude and latitude of waypoint 1 pWP2Vec3 - Vec3 table (point) w/altitude, longitude and latitude of waypoint 2 pSpeed - Unit speed at both waypoints Returns: Group object Author: AKA_Relent DCS ver: 2.7 ############################################################################################ ]] function SpawnOpForACGroup(pUnitName, pCountry, pType, pNum, pSkill, pEngScen, pHeadingRad, pWP1Vec3, pWP2Vec3, pSpeed) if (debugFlg == 2) then trigger.action.outText("SpawnOpForACGroup 1", 30) end if (pUnitName == nil or pCountry == nil or pType == nil or pNum == nil or pSkill == nil or pEngScen == nil or pHeadingRad == nil or pWP1Vec3 == nil or pWP2Vec3 == nil or pSpeed == nil) then return end glbUnitId = glbUnitId + 1 glbGroupId = glbGroupId + 1 glbCallSign = glbCallSign + 1 local lName = tostring(pType) .. "-" .. tostring(glbUnitId) --local lGroupID = tostring(pType) .. "-" .. tostring(glbGroupId) local lGroupID = glbGroupId local lAlt1 = pWP1Vec3.y local lLongX1 = pWP1Vec3.x local lLattY1 = pWP1Vec3.z local lAlt2 = pWP2Vec3.y local lLongX2 = pWP2Vec3.x local lLattY2 = pWP2Vec3.z local unitFuel = 2000 local unitFlares = 32 local unitChaff = 32 local unitLivery = "" local unitCategory = Group.Category.AIRPLANE local unitCoalition = coalition.side.NEUTRAL if (debugFlg == 2) then trigger.action.outText("SpawnOpForACGroup 2; lName=" .. lName, 30) end for i=1, #tblFuFlChLiPresets do if (tblFuFlChLiPresets[i].ut == pType and tblFuFlChLiPresets[i].co == pCountry) then unitFuel = tblFuFlChLiPresets[i].fu unitFlares = tblFuFlChLiPresets[i].fl unitChaff = tblFuFlChLiPresets[i].ch unitLivery = tblFuFlChLiPresets[i].li unitCategory = tblFuFlChLiPresets[i].cat unitCoalition = tblFuFlChLiPresets[i].cl break end end if (debugFlg == 2) then trigger.action.outText("SpawnOpForACGroup 3", 30) end local lUnit = Unit.getByName(pUnitName) local lUid = Unit.getID(lUnit) if (debugFlg == 2) then trigger.action.outText("SpawnOpForACGroup 4, unitCategory = " .. unitCategory, 30) end if (debugFlg == 2) then trigger.action.outText("SpawnOpForACGroup: pUnitName: " .. pUnitName .. ", lUid: " .. lUid, 30) end local groupData = { ["lateActivation"] = false, ["tasks"] = { }, -- end of ["tasks"] ["radioSet"] = false, ["task"] = "CAP", ["uncontrolled"] = false, ["route"] = { ["routeRelativeTOT"] = false, ["points"] = { [1] = { ["alt"] = lAlt1, ["action"] = "Turning Point", ["alt_type"] = "BARO", ["speed"] = pSpeed, ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { [1] = { ["enabled"] = true, ["key"] = "CAP", ["id"] = "EngageTargets", ["number"] = 1, ["auto"] = true, ["params"] = { ["targetTypes"] = { [1] = "Air", }, -- end of ["targetTypes"] ["priority"] = 0, }, -- end of ["params"] }, -- end of [1] [2] = { ["enabled"] = true, ["auto"] = true, ["id"] = "WrappedAction", ["number"] = 2, ["params"] = { ["action"] = { ["id"] = "Option", ["params"] = { ["value"] = true, ["name"] = 17, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [2] [3] = { ["enabled"] = true, ["auto"] = true, ["id"] = "WrappedAction", ["number"] = 3, ["params"] = { ["action"] = { ["id"] = "Option", ["params"] = { ["value"] = 4, ["name"] = 18, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [3] [4] = { ["enabled"] = true, ["auto"] = true, ["id"] = "WrappedAction", ["number"] = 4, ["params"] = { ["action"] = { ["id"] = "Option", ["params"] = { ["value"] = true, ["name"] = 19, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [4] [5] = { ["enabled"] = true, ["auto"] = true, ["id"] = "WrappedAction", ["number"] = 5, ["params"] = { ["action"] = { ["id"] = "Option", ["params"] = { ["targetTypes"] = { }, -- end of ["targetTypes"] ["name"] = 21, ["value"] = "none;", ["noTargetTypes"] = { [1] = "Fighters", [2] = "Multirole fighters", [3] = "Bombers", [4] = "Helicopters", [5] = "Infantry", [6] = "Fortifications", [7] = "Tanks", [8] = "IFV", [9] = "APC", [10] = "Artillery", [11] = "Unarmed vehicles", [12] = "AAA", [13] = "SR SAM", [14] = "MR SAM", [15] = "LR SAM", [16] = "Aircraft Carriers", [17] = "Cruisers", [18] = "Destroyers", [19] = "Frigates", [20] = "Corvettes", [21] = "Light armed ships", [22] = "Unarmed ships", [23] = "Submarines", [24] = "Cruise missiles", [25] = "Antiship Missiles", [26] = "AA Missiles", [27] = "AG Missiles", [28] = "SA Missiles", }, -- end of ["noTargetTypes"] }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [5] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["type"] = "Turning Point", ["ETA"] = 0, ["ETA_locked"] = true, ["y"] = lLattY1, ["x"] = lLongX1, ["formation_template"] = "", ["speed_locked"] = true, }, -- end of [1] [2] = { ["alt"] = lAlt2, ["action"] = "Turning Point", ["alt_type"] = "BARO", ["speed"] = pSpeed, ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["type"] = "Turning Point", ["ETA"] = 601.84765346067, ["ETA_locked"] = false, ["y"] = lLattY2, ["x"] = lLongX2, ["formation_template"] = "", ["speed_locked"] = true, }, -- end of [2] }, -- end of ["points"] }, -- end of ["route"] ["groupId"] = lGroupID, ["hidden"] = "false", ["units"] = { [1] = { ["alt"] = lAlt1, ["alt_type"] = "RADIO", ["hardpoint_racks"] = true, ["alt_type"] = "BARO", ["livery_id"] = unitLivery, ["skill"] = pSkill, ["speed"] = pSpeed, ["AddPropAircraft"] = { }, -- end of ["AddPropAircraft"] ["type"] = pType, ["unitId"] = glbUnitId, ["psi"] = pHeadingRad*(-1), ["y"] = lLattY1, ["x"] = lLongX1, ["name"] = lName, ["payload"] = { ["pylons"] = EngagementScenarioLoadOutPresetOpFor(pType, pEngScen), ["fuel"] = unitFuel, ["flare"] = unitFlares, ["chaff"] = unitChaff, ["gun"] = 100, }, -- end of ["payload"] ["heading"] = pHeadingRad, --["callsign"] = glbCallSign, ["callsign"] = { [1] = 1, [2] = 1, ["name"] = "Enfield11", [3] = 1, }, -- end of ["callsign"] ["onboard_num"] = tostring(glbCallSign), }, -- end of [1] }, -- end of ["units"] ["y"] = lLattY1, ["x"] = lLongX1, ["name"] = lName, ["communication"] = true, ["start_time"] = 0, ["modulation"] = 0, ["frequency"] = 127.5, } --[[ Add 2nd through Nth units to group ]] if (pNum > 1 and pNum < 5) then for i = 2,pNum do lLongX1 = lLongX1 + 30 lLattY1 = lLattY1 + 30 groupData.units[i] = AddUnitToGroupOpFor(pType, pCountry, pEngScen, lLongX1, lLattY1, pHeadingRad, lAlt1, i) end end if (debugFlg == 1) then trigger.action.outText("SpawnOpForACGroup 5: coalition.getCountryCoalition(" .. pCountry .. "): " .. coalition.getCountryCoalition(pCountry), 30) end return coalition.addGroup(pCountry, unitCategory, groupData) end function AddUnitToGroupOpFor(pType, pCountry, pEngScen, pLongX1, pLattY1, pHeadingRad, pAlt1, pI) if (pType == nil or pCountry == nil or pEngScen == nil or pLongX1 == nil or pLattY1 == nil or pHeadingRad == nil or pAlt1 == nil) then return end local unitFuel = 2000 local unitFlares = 32 local unitChaff = 32 local unitLivery = "" glbCallSign = glbCallSign + 1 for i=1, #tblFuFlChLiPresets do if (tblFuFlChLiPresets[i].ut == pType and tblFuFlChLiPresets[i].co == pCountry) then unitFuel = tblFuFlChLiPresets[i].fu unitFlares = tblFuFlChLiPresets[i].fl unitChaff = tblFuFlChLiPresets[i].ch unitLivery = tblFuFlChLiPresets[i].li break end end glbUnitId = glbUnitId + 1 local lName = tostring(pType) .. "-" .. tostring(glbUnitId) local unit = { ["alt"] = pAlt1, ["alt_type"] = "RADIO", ["hardpoint_racks"] = true, ["alt_type"] = "BARO", ["livery_id"] = unitLivery, ["skill"] = pSkill, ["speed"] = pSpeed, ["AddPropAircraft"] = { }, -- end of ["AddPropAircraft"] ["type"] = pType, ["unitId"] = glbUnitId, ["psi"] = pHeadingRad*(-1), ["y"] = pLattY1, ["x"] = pLongX1, ["name"] = lName, ["payload"] = { ["pylons"] = EngagementScenarioLoadOutPresetOpFor(pType, pEngScen), ["fuel"] = unitFuel, ["flare"] = unitFlares, ["chaff"] = unitChaff, ["gun"] = 100, }, -- end of ["payload"] ["heading"] = pHeadingRad, --["callsign"] = glbCallSign, ["callsign"] = { [1] = 1, [2] = 1, ["name"] = "Enfield1" .. tostring(pI), [3] = pI, }, -- end of ["callsign"] ["onboard_num"] = tostring(glbCallSign), } return unit end Any hints/observations that may help me figure out this discrepancy when a mission is flown as single player would be appreciated. Thanks! Relent Edited May 16, 2023 by 609_Relentov
Solution Grimes Posted May 16, 2023 Solution Posted May 16, 2023 The debriefing screen has never been great at dealing with anything spawned via scripting. It is simply a symptom of that longstanding problem. Initiator being the unique id, without other data for instance. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
609_Relentov Posted May 16, 2023 Author Posted May 16, 2023 Hey Grimes, thanks for the response - so you think this is one of those things that isn’t fixable (unless the underlying problem you mention is addressed)?
Grimes Posted May 16, 2023 Posted May 16, 2023 It is a DCS problem in general. The only workaround is something I wouldn't quite call a workaround, more of an exploit of the current logic by reusing existing units in the mission. Say you have a JF-17 placed in the miz file, you can use coalition.addGroup and re-use the unit and group names/ids. It could be halfway across the map from where it was placed, but to the game its still the same unit. The debrief screen might then know what that unit is. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
609_Relentov Posted May 16, 2023 Author Posted May 16, 2023 (edited) Interesting, I hadn’t thought of that angle. Of course the whole point of my writing the script was to avoid having to add any enemy aircraft to the mission (e.g. for training type missions). Thanks for the idea though . Edited May 17, 2023 by 609_Relentov
Recommended Posts