... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:Couldn't find the mission AMILCAR
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:UnitX was not found in the scenario unit list!
... 
Function:ScenEdit_AssignUnitToMission (0)  Error:Couldn't find the mission AMILCAR
07/10/2026 17:17:11 -- Bv1.10 - Build 1900.20 -- 
Console: 
print(obj)
nil
...
07/10/2026 17:17:23 -- Bv1.10 - Build 1900.20 -- 
Console: 
print(obj)print(obj)
nil
nil
...
07/10/2026 17:17:30 -- Bv1.10 - Build 1900.20 -- 
Console: 
   ScenEdit_MsgBox('hello', 0)
...
07/10/2026 17:18:08 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX LAND FORCES + ZERO-SUM SCORING
--  Command: Modern Operations - run from Editor > Lua Script Console
-- =====================================================================
--  What it does
--   1. Finds the right database IDs in YOUR database by itself (it briefly
--      creates and deletes one facility per DBID on a temporary side and
--      reads its class name). No IDs are hard-coded.
--   2. Places the Royal Netherlands Army / Korps Mariniers and the Belgian
--      Land Component at their real peacetime garrisons, plus brigade and
--      army HQs and logistic depots.
--   3. Creates one repeatable event that scores every loss on both sides:
--      the killer gains what the owner loses. Each side's whole force is
--      worth exactly SCORE_SCALE points, so the score runs from
--      -1000 (you lost everything, killed nothing) to +1000 (the reverse).
--
--  How to use
--   a. Merge your two scenarios first, save a backup copy.
--   b. Set SIDE_NL / SIDE_BE below to the exact side names in the scenario.
--   c. Paste the whole file into the Lua console and run it. The first run
--      scans the database and can freeze the game for a minute or two.
--   d. Read the report it prints. If a role picked the wrong unit, put the
--      DBID you want in DBID_OVERRIDE and run again (existing units are
--      skipped, missing ones are added).
--   e. If you add or remove units later, run again with
--      STEPS.land_units = false so the +/-1000 scale is recalculated.
--
--  Order of battle reflects the early/mid-2020s structure. Coordinates are
--  approximate (town/barracks level) - nudge units in the editor if needed.
-- =====================================================================

local CONFIG = {
  SIDE_NL = "Netherlands",        -- exact side name in your scenario
  SIDE_BE = "Belgium",            -- exact side name in your scenario

  STEPS = { land_units = true, scoring = true },

  SCAN_ONLY      = false,         -- true = only print what the DB scan finds
  FORCE_RESCAN   = false,         -- true = ignore IDs cached by an earlier run
  SCAN_MAX_DBID  = 6000,          -- highest facility DBID to try
  SCAN_LAT = 52.10, SCAN_LON = 5.60,   -- any point on land

  PLATOONS_PER_COMPANY = 3,       -- 1 = one unit per company (lighter scenario)

  INCLUDE_AIR_DEFENCE = false,    -- Dutch Patriot/NASAMS/Stinger at Vredepeel.
                                  -- Off because your scenarios already have AA sites.
  INCLUDE_414_TANK_BN = false,    -- Dutch Leopard 2A6 squadron; really based at
                                  -- Bergen-Lohheide in Germany, outside the map area.

  SCORE_SCALE     = 1000,         -- total value of each side's force
  END_SCENARIO_AT = nil,          -- e.g. 600 = end the game when a side reaches +600
}

-- Force a specific DBID for a role, e.g.  nl_cv90 = 1234,
local DBID_OVERRIDE = {
}

-- ---------------------------------------------------------------------
--  ROLES: what to look for in the database.
--  want  = alternatives in priority order; every word in one alternative
--          must appear in the class name (lower case, plain text).
--  avoid = class names containing any of these are rejected.
--  fb    = role to fall back on when nothing matches.
-- ---------------------------------------------------------------------
local ROLES = {
  -- generic
  inf       = { want = { {"inf plt"}, {"infantry plt"}, {"infantry platoon"}, {"inf sec"}, {"infantry"} },
                avoid = {"mech", "mot ", "motor", "armor", "sam", "marine", "manpad", "atgm"} },
  mech      = { want = { {"mech inf plt"}, {"mech inf"}, {"mechanized inf"} }, fb = "inf" },
  recon     = { want = { {"recon plt"}, {"recce plt"}, {"recon"}, {"recce"} }, avoid = {"uav", "radar"}, fb = "inf" },
  armor     = { want = { {"armored plt"}, {"armor plt"}, {"tank plt"} }, fb = "mech" },
  arty      = { want = { {"arty bty", "155mm"}, {"arty bty"} } },
  eng       = { want = { {"engineer"}, {"eng plt"}, {"sapper"} }, fb = "inf" },
  mortar81  = { want = { {"mortar", "81mm"}, {"mortar", "82mm"}, {"mortar"} }, fb = "inf" },
  mortar120 = { want = { {"mortar", "120mm"}, {"mortar"} }, fb = "arty" },
  sof       = { want = { {"sof"}, {"special forces"}, {"commando"}, {"spetsnaz"} }, avoid = {"sam"}, fb = "inf" },
  -- Netherlands
  nl_airmobile = { want = { {"air assault"}, {"airmobile"}, {"air mobile"} }, avoid = {"sam"}, fb = "inf" },
  nl_marine    = { want = { {"marine", "inf"}, {"marines"} }, fb = "inf" },
  nl_cv90      = { want = { {"cv9035"}, {"cv 9035"}, {"cv90"}, {"cv 90"} }, fb = "mech" },
  nl_boxer     = { want = { {"boxer"} }, fb = "mech" },
  nl_fennek    = { want = { {"fennek"} }, avoid = {"stinger", "sam"}, fb = "recon" },
  nl_leo2      = { want = { {"leopard 2a6"}, {"leopard 2a7"}, {"leopard 2"} }, fb = "armor" },
  nl_pzh       = { want = { {"pzh 2000"}, {"pzh2000"}, {"pzh-2000"} }, fb = "arty" },
  sam_patriot  = { want = { {"patriot", "pac-3"}, {"patriot"} } },
  sam_nasams   = { want = { {"nasams"} } },
  sam_stinger  = { want = { {"fennek", "stinger"}, {"stinger"} } },
  -- Belgium
  be_piranha = { want = { {"piranha iiic"}, {"piranha iii"}, {"piranha"} }, fb = "mech" },
  be_dingo   = { want = { {"dingo"}, {"mot inf plt"}, {"mot inf"} }, fb = "inf" },
  be_pandur  = { want = { {"pandur"} }, fb = "recon" },
  be_lg1     = { want = { {"lg1"}, {"lg-1"}, {"arty bty", "105mm"} }, fb = "arty" },
  be_paracdo = { want = { {"para", "inf"}, {"airborne"}, {"paratroop"} }, avoid = {"sam"}, fb = "inf" },
  -- structures
  hq     = { want = { {"headquarters"}, {"command", "bunker"}, {"command", "post"}, {"command", "cent"}, {"hq"} },
             avoid = {"hq-", "sam", "radar", "vehicle"} },
  ammo   = { want = { {"ammo", "bunker"}, {"ammo", "shelter"}, {"ammo", "depot"}, {"ammunition"}, {"ammo"} },
             avoid = {"truck", "vehicle"} },
  fuel   = { want = { {"fuel", "depot"}, {"fuel", "tank"}, {"fuel"} }, avoid = {"truck", "vehicle"} },
  supply = { want = { {"warehouse"}, {"supply", "depot"}, {"depot"}, {"storage"}, {"supply"} },
             avoid = {"ammo", "fuel", "truck", "vehicle"} },
}

-- ---------------------------------------------------------------------
--  ORDER OF BATTLE
--  coy = true  -> one unit per platoon (PLATOONS_PER_COMPANY of them)
--  n   = N     -> exactly N units
--  tag is used by the scoring ([HQ] and [DEPOT] are the high-value targets)
-- ---------------------------------------------------------------------
local function coys(tag, bn, role, letters)
  local t = {}
  for _, l in ipairs(letters) do
    t[#t + 1] = { tag = tag, name = bn .. " " .. l, role = role, coy = true }
  end
  return t
end

local function join(...)
  local out = {}
  for _, list in ipairs({ ... }) do
    for _, e in ipairs(list) do out[#out + 1] = e end
  end
  return out
end

local ABC = { "A-Cie", "B-Cie", "C-Cie" }

local OOB_NL = {
  { site = "Utrecht (Kromhout Kazerne)", lat = 52.083, lon = 5.140, els = {
      { tag = "HQ", name = "Staf Commando Landstrijdkrachten", role = "hq" } } },

  { site = "Schaarsbergen (Oranjekazerne)", lat = 52.036, lon = 5.866, els = join(
      { { tag = "HQ", name = "Staf 11 Luchtmobiele Brigade", role = "hq" } },
      coys("INF", "11 Infbat GGJ", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "11 Infbat GGJ Mortieren 81mm", role = "mortar81" } },
      coys("INF", "12 Infbat RvH", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "12 Infbat RvH Mortieren 81mm", role = "mortar81" },
        { tag = "RECON", name = "11 Brigade Verkenningseskadron", role = "recon", n = 2 },
        { tag = "ENG", name = "11 Geniecompagnie Luchtmobiel", role = "eng" } }) },

  { site = "Assen (Johan Willem Frisokazerne)", lat = 52.978, lon = 6.530, els = join(
      coys("INF", "13 Infbat RSPB", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "13 Infbat RSPB Mortieren 81mm", role = "mortar81" },
        { tag = "INF", name = "10 Natresbataljon", role = "inf", n = 2 } }) },

  { site = "Oirschot (De Ruyter van Steveninckkazerne)", lat = 51.485, lon = 5.350, els = join(
      { { tag = "HQ", name = "Staf 13 Lichte Brigade", role = "hq" } },
      coys("MECH", "17 Painfbat GFPI", "nl_boxer", ABC),
      coys("MECH", "42 Painfbat RLJ", "nl_boxer", ABC),
      { { tag = "RECON", name = "42 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 },
        { tag = "ENG", name = "41 Pantsergeniebataljon", role = "eng", n = 2 } }) },

  { site = "Havelte (Johannes Postkazerne)", lat = 52.789, lon = 6.213, els = join(
      { { tag = "HQ", name = "Staf 43 Gemechaniseerde Brigade", role = "hq" } },
      coys("MECH", "44 Painfbat RIJWF", "nl_cv90", ABC),
      { { tag = "RECON", name = "43 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 } }) },

  { site = "Ermelo (Generaal Spoorkazerne)", lat = 52.290, lon = 5.640, els =
      coys("MECH", "45 Painfbat RIOG", "nl_cv90", ABC) },

  { site = "Wezep (Prinses Margrietkazerne)", lat = 52.455, lon = 6.010, els = {
      { tag = "ENG", name = "11 Pantsergeniebataljon", role = "eng", n = 2 },
      { tag = "ENG", name = "101 Geniebataljon", role = "eng" } } },

  { site = "'t Harde (Legerplaats bij Oldebroek)", lat = 52.415, lon = 5.905, els = {
      { tag = "HQ", name = "Staf Vuursteun Commando", role = "hq" },
      { tag = "ARTY", name = "41 Afdeling Artillerie A-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie B-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie C-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie Mortieren 120mm", role = "mortar120" } } },

  { site = "Apeldoorn", lat = 52.210, lon = 5.970, els = {
      { tag = "HQ", name = "Staf Operationeel Ondersteuningscommando Land", role = "hq" } } },

  { site = "Stroe (Generaal-Majoor Kootkazerne)", lat = 52.205, lon = 5.700, els = {
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando Brandstof", role = "fuel" } } },

  { site = "Roosendaal (Engelbrecht van Nassaukazerne)", lat = 51.535, lon = 4.440, els = {
      { tag = "HQ", name = "Staf Korps Commandotroepen", role = "hq" },
      { tag = "SOF", name = "103 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "104 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "105 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "108 Commandotroepencompagnie", role = "sof" } } },

  { site = "Rotterdam (Van Ghentkazerne)", lat = 51.925, lon = 4.490, els = {
      { tag = "HQ", name = "Staf Korps Mariniers", role = "hq" } } },

  { site = "Doorn (Van Braam Houckgeestkazerne)", lat = 52.035, lon = 5.340, els = join(
      coys("INF", "1 Marine Combat Group", "nl_marine", { "10 Sqn", "11 Sqn", "12 Sqn" }),
      coys("INF", "2 Marine Combat Group", "nl_marine", { "21 Sqn", "22 Sqn", "23 Sqn" }),
      { { tag = "SOF", name = "NLMARSOF", role = "sof", n = 2 } }) },

  { site = "Texel (Joost Dourleinkazerne)", lat = 53.005, lon = 4.790, els = {
      { tag = "INF", name = "Surface Assault and Training Group", role = "nl_marine" } } },

  { site = "Den Haag (Frederikkazerne)", lat = 52.100, lon = 4.320, els = {
      { tag = "INF", name = "20 Natresbataljon", role = "inf", n = 2 } } },

  { site = "Vught (Van Brederodekazerne)", lat = 51.660, lon = 5.290, els = {
      { tag = "INF", name = "30 Natresbataljon", role = "inf", n = 2 } } },

  -- logistics
  { site = "Veenhuizen", lat = 53.030, lon = 6.380, els = {
      { tag = "DEPOT", name = "Munitiecomplex Veenhuizen", role = "ammo", n = 3 } } },
  { site = "Alphen (Noord-Brabant)", lat = 51.480, lon = 4.950, els = {
      { tag = "DEPOT", name = "Munitiecomplex Alphen", role = "ammo", n = 3 } } },
  { site = "Soesterberg (Kamp Soesterberg)", lat = 52.125, lon = 5.285, els = {
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg Brandstof", role = "fuel" } } },
  { site = "Coevorden", lat = 52.670, lon = 6.750, els = {
      { tag = "DEPOT", name = "Materieeldepot Coevorden", role = "supply", n = 2 } } },
  { site = "Vriezenveen", lat = 52.420, lon = 6.630, els = {
      { tag = "DEPOT", name = "Materieeldepot Vriezenveen", role = "supply", n = 2 } } },

  -- optional
  { site = "Vredepeel (Luitenant-generaal Bestkazerne)", lat = 51.540, lon = 5.870, opt = "INCLUDE_AIR_DEFENCE", els = {
      { tag = "HQ", name = "Staf DGLC", role = "hq" },
      { tag = "AD", name = "802 Squadron Patriot", role = "sam_patriot", n = 3 },
      { tag = "AD", name = "13 Luchtverdedigingsbatterij NASAMS", role = "sam_nasams", n = 2 },
      { tag = "AD", name = "11 Luchtverdedigingsbatterij Stinger", role = "sam_stinger", n = 2 } } },
  { site = "Bergen-Lohheide (DE)", lat = 52.800, lon = 9.920, opt = "INCLUDE_414_TANK_BN", els = {
      { tag = "ARMOR", name = "414 Tankbataljon 4 (NLD) Eskadron", role = "nl_leo2", n = 4 } } },
}

local OOB_BE = {
  { site = "Evere (Kwartier Koningin Elisabeth)", lat = 50.875, lon = 4.420, els = {
      { tag = "HQ", name = "Staf Landcomponent", role = "hq" } } },

  { site = "Leopoldsburg (Kamp van Beverlo)", lat = 51.117, lon = 5.257, els = join(
      { { tag = "HQ", name = "Staf Gemotoriseerde Brigade", role = "hq" } },
      coys("MECH", "Bn Bevrijding-5 Linie", "be_piranha", ABC),
      coys("INF", "Bn Carabiniers-Grenadiers", "be_dingo", ABC),
      { { tag = "DEPOT", name = "18 Bataljon Logistiek", role = "supply" } }) },

  { site = "Marche-en-Famenne (Camp Roi Albert)", lat = 50.245, lon = 5.325, els = join(
      coys("MECH", "Bn Chasseurs Ardennais", "be_piranha", ABC),
      coys("MECH", "Bn 1/3 Lanciers", "be_piranha", ABC),
      { { tag = "DEPOT", name = "4 Bataillon Logistique", role = "supply" } }) },

  { site = "Spa", lat = 50.487, lon = 5.870, els =
      coys("INF", "Bn 12 de Ligne-13 de Ligne", "be_dingo", ABC) },

  { site = "Heverlee", lat = 50.855, lon = 4.690, els = join(
      { { tag = "HQ", name = "Staf Special Operations Regiment", role = "hq" } },
      coys("RECON", "Bn Jagers te Paard ISTAR", "be_pandur", { "A-Esk", "B-Esk", "C-Esk" }),
      { { tag = "SOF", name = "Special Forces Group", role = "sof", n = 2 } }) },

  { site = "Flawinne", lat = 50.455, lon = 4.800, els =
      coys("INF", "2 Bataillon de Commandos", "be_paracdo", ABC) },

  { site = "Tielen", lat = 51.240, lon = 4.895, els =
      coys("INF", "3 Bataljon Parachutisten", "be_paracdo", ABC) },

  { site = "Brasschaat", lat = 51.325, lon = 4.495, els = {
      { tag = "ARTY", name = "Artilleriebataljon Bt LG1 105mm", role = "be_lg1", n = 2 },
      { tag = "ARTY", name = "Artilleriebataljon Bt Mortieren 120mm", role = "mortar120", n = 2 } } },

  { site = "Amay", lat = 50.548, lon = 5.310, els = {
      { tag = "ENG", name = "4 Bataillon de Genie", role = "eng", n = 2 } } },

  { site = "Burcht", lat = 51.205, lon = 4.340, els = {
      { tag = "ENG", name = "11 Bataljon Genie", role = "eng", n = 2 } } },

  -- logistics
  { site = "Bertrix (Jehonville)", lat = 49.900, lon = 5.210, els = {
      { tag = "DEPOT", name = "Depot de munitions Bertrix", role = "ammo", n = 3 } } },
  { site = "Houthulst", lat = 50.975, lon = 2.950, els = {
      { tag = "DEPOT", name = "Munitiedepot Houthulst", role = "ammo" } } },
  { site = "Rocourt", lat = 50.675, lon = 5.545, els = {
      { tag = "DEPOT", name = "Arsenal Rocourt", role = "supply", n = 2 } } },
  { site = "Peutie", lat = 50.925, lon = 4.455, els = {
      { tag = "DEPOT", name = "Logistiek depot Peutie", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek depot Peutie Brandstof", role = "fuel" } } },
}

-- ---------------------------------------------------------------------
--  SCORING WEIGHTS (relative values; each side is rescaled to SCORE_SCALE)
--  This text is also embedded in the scoring event, so edit it here and
--  re-run the script rather than editing the event.
-- ---------------------------------------------------------------------
local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"

Tool_EmulateNoConsole(true)

local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end

local function getKey(k) return try(ScenEdit_GetKeyValue, k) or "" end
local function setKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local function sideExists(name)
  local sides = try(VP_GetSides) or {}
  for _, s in pairs(sides) do
    if type(s) == "table" or type(s) == "userdata" then
      if s.name == name then return true end
    end
  end
  return false
end

local function listSides()
  local names = {}
  for _, s in pairs(try(VP_GetSides) or {}) do names[#names + 1] = tostring(s.name) end
  return table.concat(names, ", ")
end

-- ----------------------------- DB scan --------------------------------
local resolved, resolvedName, candidates = {}, {}, {}

local function matches(cls, alt, avoid)
  for _, w in ipairs(alt) do
    if not string.find(cls, w, 1, true) then return false end
  end
  if avoid then
    for _, w in ipairs(avoid) do
      if string.find(cls, w, 1, true) then return false end
    end
  end
  return true
end

local function loadCache()
  local all = true
  for role, _ in pairs(ROLES) do
    local id = tonumber(getKey(KEY .. "dbid_" .. role))
    if id then
      resolved[role] = id
      resolvedName[role] = getKey(KEY .. "name_" .. role)
    elseif getKey(KEY .. "dbid_" .. role) ~= "none" then
      all = false
    end
  end
  return all
end

local function scanDatabase()
  local tmp = "~LOOB scan"
  local scanSide = tmp
  if not sideExists(tmp) then try(ScenEdit_AddSide, { side = tmp }) end
  if not sideExists(tmp) then scanSide = CONFIG.SIDE_NL end

  local names, real, found = {}, {}, 0
  for id = 1, CONFIG.SCAN_MAX_DBID do
    local u = try(ScenEdit_AddUnit, { side = scanSide, type = "Facility", unitname = "LOOB scan " .. id,
                                      dbid = id, latitude = CONFIG.SCAN_LAT, longitude = CONFIG.SCAN_LON })
    if u then
      local cls = tostring(u.classname or "")
      if cls ~= "" then
        names[id] = string.lower(cls)
        real[id] = cls
        found = found + 1
      end
      try(ScenEdit_DeleteUnit, { side = scanSide, guid = u.guid })
    end
  end
  if scanSide == tmp then try(ScenEdit_RemoveSide, { side = tmp }) end
  print("Database scan: " .. found .. " facility classes read (DBID 1-" .. CONFIG.SCAN_MAX_DBID .. ")")

  for role, def in pairs(ROLES) do
    candidates[role] = {}
    for _, alt in ipairs(def.want) do
      for id = 1, CONFIG.SCAN_MAX_DBID do
        if names[id] and matches(names[id], alt, def.avoid) then
          candidates[role][#candidates[role] + 1] = { id = id, name = real[id] }
        end
      end
      if #candidates[role] > 0 then break end
    end
    local pick = candidates[role][1]
    if pick then
      resolved[role], resolvedName[role] = pick.id, pick.name
      setKey(KEY .. "dbid_" .. role, pick.id)
      setKey(KEY .. "name_" .. role, pick.name)
    else
      resolved[role], resolvedName[role] = nil, nil
      setKey(KEY .. "dbid_" .. role, "none")
    end
  end
  return found
end

local function effective(role, depth)
  depth = depth or 0
  if DBID_OVERRIDE[role] then return DBID_OVERRIDE[role], "manual override", role end
  if resolved[role] then return resolved[role], resolvedName[role], role end
  local fb = ROLES[role] and ROLES[role].fb
  if fb and depth < 5 then return effective(fb, depth + 1) end
  return nil
end

local function printRoleReport()
  local order = {}
  for role, _ in pairs(ROLES) do order[#order + 1] = role end
  table.sort(order)
  print("---- Units chosen from your database ----")
  for _, role in ipairs(order) do
    local id, name, via = effective(role)
    if id then
      local note = (via ~= role) and ("   <- nothing specific found, using '" .. via .. "'") or ""
      print(string.format("  %-13s DBID %-5s %s%s", role, tostring(id), tostring(name), note))
    else
      print(string.format("  %-13s NOT FOUND - units with this role are skipped", role))
    end
    local c = candidates[role]
    if c and #c > 1 then
      local alt = {}
      for i = 2, math.min(#c, 6) do alt[#alt + 1] = c[i].id .. " " .. c[i].name end
      print("                other matches: " .. table.concat(alt, " | ")
            .. ((#c > 6) and (" | +" .. (#c - 6) .. " more") or ""))
    end
  end
end

-- --------------------------- unit placement ----------------------------
local stats = { added = 0, existed = 0, failed = 0, norole = 0 }

local function offset(lat, lon, km, bearingDeg)
  local r = math.rad(bearingDeg)
  local dlat = (km * math.cos(r)) / 111.32
  local dlon = (km * math.sin(r)) / (111.32 * math.cos(math.rad(lat)))
  return lat + dlat, lon + dlon
end

local function addUnit(side, name, role, lat, lon)
  local id = effective(role)
  if not id then stats.norole = stats.norole + 1 return end
  if try(ScenEdit_GetUnit, { side = side, unitname = name }) then
    stats.existed = stats.existed + 1
    return
  end
  local u = try(ScenEdit_AddUnit, { side = side, type = "Facility", unitname = name, dbid = id,
                                    latitude = lat, longitude = lon })
  if u then
    stats.added = stats.added + 1
  else
    stats.failed = stats.failed + 1
    print("  could not add '" .. name .. "' (DBID " .. tostring(id) .. ") " .. tostring(_errmsg_ or ""))
  end
end

local function buildSite(side, site)
  local n = #site.els
  local perRing = 6
  for i, e in ipairs(site.els) do
    local count = e.coy and CONFIG.PLATOONS_PER_COMPANY or (e.n or 1)
    local ring = math.floor((i - 1) / perRing)
    local bearing = (i - 1) * (360 / math.min(n, perRing)) + ring * 30
    local radius = (n == 1) and 0 or (1.0 + 0.8 * ring)
    local clat, clon = offset(site.lat, site.lon, radius, bearing)
    for p = 1, count do
      local plat, plon = offset(clat, clon, 0.3 * (p - 1), bearing + 90)
      local nm = "[" .. e.tag .. "] " .. e.name .. ((count > 1) and (" /" .. p) or "")
      addUnit(side, nm, e.role, plat, plon)
    end
  end
end

local function buildSide(side, oob)
  for _, site in ipairs(oob) do
    if (not site.opt) or CONFIG[site.opt] then buildSite(side, site) end
  end
end

-- ------------------------------ scoring --------------------------------
local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function compileWeight()
  local loader = load or loadstring
  local chunk, err = loader(WEIGHT_SRC .. "\nreturn LS_weight")
  if not chunk then error("WEIGHT_SRC does not compile: " .. tostring(err)) end
  return chunk()
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = compileWeight()
  local problems = 0

  print("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      print("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      setKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      setKey(KEY .. "scale_" .. side, scale)
      print(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        print(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    setKey(KEY .. "lost_" .. side, 0)
  end
  setKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    print("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      print("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    print("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    print("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    print("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  print("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  print("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- -------------------------------- main ---------------------------------
local function main()
  local A, B = CONFIG.SIDE_NL, CONFIG.SIDE_BE
  if not sideExists(A) or not sideExists(B) then
    print("STOPPED: side '" .. A .. "' or '" .. B .. "' does not exist.")
    print("Sides in this scenario: " .. listSides())
    print("Edit SIDE_NL / SIDE_BE at the top of the script and run it again.")
    return
  end

  if CONFIG.STEPS.land_units or CONFIG.SCAN_ONLY then
    local cached = (not CONFIG.FORCE_RESCAN) and (not CONFIG.SCAN_ONLY) and loadCache()
    if cached then
      print("Using database IDs found by an earlier run (set FORCE_RESCAN = true to scan again)")
    else
      print("Scanning the database, this can take a minute or two...")
      if scanDatabase() == 0 then
        print("STOPPED: the scan could not read any facility from the database.")
        print("Fill in DBID_OVERRIDE by hand (DB viewer) and run again with those IDs.")
        local any = false
        for _, _ in pairs(DBID_OVERRIDE) do any = true end
        if not any then return end
      end
    end
    printRoleReport()
    if CONFIG.SCAN_ONLY then return end

    buildSide(A, OOB_NL)
    buildSide(B, OOB_BE)
    print("---- Land units ----")
    print(string.format("  added %d, already present %d, failed %d, skipped (no DB match) %d",
                        stats.added, stats.existed, stats.failed, stats.norole))
  end

  if CONFIG.STEPS.scoring then setupScoring(A, B) end
  print("Done.")
end

local ok, err = pcall(main)
Tool_EmulateNoConsole(false)
if not ok then print("SCRIPT ERROR: " .. tostring(err)) end
Scanning the database, this can take a minute or two...
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
Database scan: 5535 facility classes read (DBID 1-6000)
---- Units chosen from your database ----
  ammo          DBID 322   Ammo Bunker (Surface)
                other matches: 325 Ammo Bunker (Underground) | 1731 Ammo Bunker (Mountain)
  armor         DBID 117   Armored Plt (T-34/85 MBT x 4)
                other matches: 205 Armored Plt (T-72 MBT x 4) | 206 Armored Plt (T-80 MBT x 4) | 486 Armored Plt (T-80 MBT x 4) | 499 Armored Plt (T-72 MBT x 4) | 523 Armored Plt (M1 Abrams MBT x 4) | +338 more
  arty          DBID 222   Coastal Arty Bty (155mm/39 Tampella 155 K83 Towed Gun x 4)
                other matches: 682 Arty Bty (155mm/39 M109A3GN Self-Propelled Howitzer x 6) | 772 Arty Bty (155mm/39 GCT AUF1 Self-Propelled Howitzer) | 821 Arty Bty (155mm/45 G6 Self-Propelled Howitzer x 6) | 822 Arty Bty (155mm/45 G5 Towed Howitzer x6) | 1724 Arty Bty (155mm/52 T-155 Self-Propelled Firtina Howitzer x 6) | +140 more
  be_dingo      DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  be_lg1        DBID 330   Arty Bty/3 (105mm/37 L118 Towed Light Gun x 2)
                other matches: 366 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 410 Arty Bty (105mm/37 L118 Towed Light Gun x 6) | 1799 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 1800 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 1801 Arty Bty (105mm/32 M102 Towed Howitzer x 6) | +18 more
  be_pandur     DBID 2947  Motor Inf Plt (Pandur I APC x 4)
                other matches: 2948 Motor Inf Plt (Pandur I APC x 4) | 2949 Motor Inf Plt (Pandur II APC [12.5mm MMG] x 4) | 2950 Motor Inf Plt (Pandur II IFV [Steyr 30mm + SPIKE] x 4) | 4500 Motor Inf Plt (Pandur II IFV [Steyr 30mm + SPIKE] x 4) | 5177 Motor Inf Plt (Pandur I APC x 4) | +3 more
  be_paracdo    DBID 209   Inf Plt (British Paratroopers)
                other matches: 700 Inf Plt (Soviet Paratroopers) | 875 Inf Plt (Russian Paratroopers) | 2384 Inf Plt (Canadian Paratroopers) | 2796 Inf Plt (Paratrooper) | 3035 Inf Plt (Parachute Regiment) | +1 more
  be_piranha    DBID 2866  Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
                other matches: 4473 Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
  eng           DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  fuel          DBID 248   Support Plt (Helicopter Expeditionary Refueling System)
  hq            DBID 3730  Command Post
  inf           DBID 202   Inf Plt (Russian Army)
                other matches: 203 Inf Plt (Soviet Red Army) | 209 Inf Plt (British Paratroopers) | 212 Inf Plt (Chinese Naval Infantry) | 237 Inf Plt (Russian Spetsnaz Platoon [Generic Laser Designator]) | 240 Inf Plt (SAS Troop [Generic Laser Designator]) | +74 more
  mech          DBID 635   Mech Inf Plt (ZSD-89 [Type 89] APC x 4)
                other matches: 636 Mech Inf Plt (ZSD-63 [Type 63] APC x 4) | 637 Mech Inf Plt (ZSL-90 [Type 90] APC x 4) | 646 Mech Inf Plt (Soviet Red Army) | 670 Mech Inf Plt (United States Army) | 707 Mech Inf Plt (British Army) | +274 more
  mortar120     DBID 2058  Mortar Plt (120mm Mortar)
                other matches: 2059 Mortar Plt (120mm Mortar [STRIX]) | 2071 Arty Bty (120mm 2S9-S Nona-S Self-Propelled Mortar x 6) | 2072 Arty Bty (120mm 2S9-S Nona-S Self-Propelled Mortar x 6) | 2073 Arty Bty (120mm 2S9-1 Sviristelka Self-Propelled Mortar x 6) | 2074 Arty Bty (120mm 2S9-1 Sviristelka Self-Propelled Mortar x 6) | +20 more
  mortar81      DBID 2060  Mortar Plt (81mm Mortar)
                other matches: 3422 Mortar Plt (81mm Mortar) | 3697 Mortar Sec (81mm Mortar) | 3698 Mortar Sec (81mm Mortar) | 4547 Arty Bty (81mm Aras-2 Self-Propelled Mortar x 3)
  nl_airmobile  DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  nl_boxer      DBID 2316  Mech Inf Plt (Boxer APC x 3)
                other matches: 2878 Motor Inf Plt (Boxer APC x 4)
  nl_cv90       DBID 5095  Mech Inf Plt (CV 9035 x 4)
                other matches: 5096 Mech Inf Plt (CV 9035DK x 4) | 5097 Mech Inf Plt (CV 9035NL x 4) | 5098 Mech Inf Plt (CV 9035EE x 4)
  nl_fennek     DBID 614   Inf Sec (Recon)   <- nothing specific found, using 'recon'
  nl_leo2       DBID 2341  Armored Plt (Leopard 2A6 MBT x 3)
                other matches: 2381 Armored Plt (Leopard 2A6M MBT x 4) | 3848 Armored Plt (Leopard 2A6M MBT x 4) | 3920 Armored Plt (Leopard 2A6 MBT x 3)
  nl_marine     DBID 211   Inf Plt (British Royal Marines)
                other matches: 714 Inf Plt (US Marines) | 2319 Inf Plt (Marines) | 2404 Inf Plt (Indonesia Marines) | 2870 Inf Plt (Philippine Marines) | 2967 Inf Sec (Marine Force Recon Team [AN/PAQ-1 LTD]) | +4 more
  nl_pzh        DBID 2133  Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
                other matches: 2134 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 2978 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 3631 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 5079 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 5088 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
  recon         DBID 614   Inf Sec (Recon)
                other matches: 884 Inf Sec (US Navy SEAL Recon Team) | 1904 Inf Plt (Recon) | 1910 Inf Sec (US Navy SEAL Recon Team [AN/PAQ-1 LTD]) | 1943 Inf Sec (Spetsnaz GRU Recon Squad [Generic Laser Designator]) | 1947 Inf Sec (Spetsnaz Recon Squad [Generic Laser Designator]) | +10 more
  sam_nasams    DBID 147   Radar (AN/TPQ-36A [NASAMS])
                other matches: 204 SAM Plt (NASAMS) | 460 SAM Plt/2 (NASAMS II) | 579 Sensor (NTAS FLIR/LR [NASAMS]) | 653 SAM Plt/2 (NASAMS II) | 860 SAM Plt/2 (NASAMS II) | +29 more
  sam_patriot   DBID 294   SAM Bty (Patriot [PAC-2 GEM+, PAC-3 CRI])
                other matches: 1863 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2224 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2225 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2226 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2227 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | +18 more
  sam_stinger   DBID 7     SAM Sec (Stinger MANPADS x 5)
                other matches: 14 SAM Sec (Stinger MANPADS x 5) | 64 SAM Sec (Stinger MANPADS x 5) | 242 SAM Sec (Stinger MANPADS x 5) | 268 SAM Sec (Stinger Dual MANPADS x 2) | 1264 SAM Sec (Stinger MANPADS x 5) | +21 more
  sof           DBID 835   Vehicle (Soft Ball ELS [KRTP-81 Ramona])
                other matches: 2519 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2520 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2521 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2522 Vehicle (Soft Ball ELS [KRTP-81M Ramona]) | 2523 Vehicle (Soft Ball ELS [KRTP-81M Ramona]) | +6 more
  supply        DBID 3098  Container Storage Park
---- Land units ----
  added 235, already present 0, failed 0, skipped (no DB match) 0
SCRIPT ERROR: [string "Console"]:524: attempt to call a nil value (local 'loader')
...
07/10/2026 17:19:42 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX LAND FORCES + ZERO-SUM SCORING
--  Command: Modern Operations - run from Editor > Lua Script Console
-- =====================================================================
--  What it does
--   1. Finds the right database IDs in YOUR database by itself (it briefly
--      creates and deletes one facility per DBID on a temporary side and
--      reads its class name). No IDs are hard-coded.
--   2. Places the Royal Netherlands Army / Korps Mariniers and the Belgian
--      Land Component at their real peacetime garrisons, plus brigade and
--      army HQs and logistic depots.
--   3. Creates one repeatable event that scores every loss on both sides:
--      the killer gains what the owner loses. Each side's whole force is
--      worth exactly SCORE_SCALE points, so the score runs from
--      -1000 (you lost everything, killed nothing) to +1000 (the reverse).
--
--  How to use
--   a. Merge your two scenarios first, save a backup copy.
--   b. Set SIDE_NL / SIDE_BE below to the exact side names in the scenario.
--   c. Paste the whole file into the Lua console and run it. The first run
--      scans the database and can freeze the game for a minute or two.
--   d. Read the report it prints. If a role picked the wrong unit, put the
--      DBID you want in DBID_OVERRIDE and run again (existing units are
--      skipped, missing ones are added).
--   e. If you add or remove units later, run again with
--      STEPS.land_units = false so the +/-1000 scale is recalculated.
--
--  Order of battle reflects the early/mid-2020s structure. Coordinates are
--  approximate (town/barracks level) - nudge units in the editor if needed.
-- =====================================================================

local CONFIG = {
  SIDE_NL = "Netherlands",        -- exact side name in your scenario
  SIDE_BE = "Belgium",            -- exact side name in your scenario

  STEPS = { land_units = true, scoring = true },

  SCAN_ONLY      = false,         -- true = only print what the DB scan finds
  FORCE_RESCAN   = false,         -- true = ignore IDs cached by an earlier run
  SCAN_MAX_DBID  = 6000,          -- highest facility DBID to try
  SCAN_LAT = 52.10, SCAN_LON = 5.60,   -- any point on land

  PLATOONS_PER_COMPANY = 3,       -- 1 = one unit per company (lighter scenario)

  INCLUDE_AIR_DEFENCE = false,    -- Dutch Patriot/NASAMS/Stinger at Vredepeel.
                                  -- Off because your scenarios already have AA sites.
  INCLUDE_414_TANK_BN = false,    -- Dutch Leopard 2A6 squadron; really based at
                                  -- Bergen-Lohheide in Germany, outside the map area.

  SCORE_SCALE     = 1000,         -- total value of each side's force
  END_SCENARIO_AT = nil,          -- e.g. 600 = end the game when a side reaches +600
}

-- Force a specific DBID for a role, e.g.  nl_cv90 = 1234,
local DBID_OVERRIDE = {
}

-- ---------------------------------------------------------------------
--  ROLES: what to look for in the database.
--  want  = alternatives in priority order; every word in one alternative
--          must appear in the class name (lower case, plain text).
--  avoid = class names containing any of these are rejected.
--  fb    = role to fall back on when nothing matches.
-- ---------------------------------------------------------------------
local ROLES = {
  -- generic
  inf       = { want = { {"inf plt"}, {"infantry plt"}, {"infantry platoon"}, {"inf sec"}, {"infantry"} },
                avoid = {"mech", "mot ", "motor", "armor", "sam", "marine", "manpad", "atgm"} },
  mech      = { want = { {"mech inf plt"}, {"mech inf"}, {"mechanized inf"} }, fb = "inf" },
  recon     = { want = { {"recon plt"}, {"recce plt"}, {"recon"}, {"recce"} }, avoid = {"uav", "radar"}, fb = "inf" },
  armor     = { want = { {"armored plt"}, {"armor plt"}, {"tank plt"} }, fb = "mech" },
  arty      = { want = { {"arty bty", "155mm"}, {"arty bty"} } },
  eng       = { want = { {"engineer"}, {"eng plt"}, {"sapper"} }, fb = "inf" },
  mortar81  = { want = { {"mortar", "81mm"}, {"mortar", "82mm"}, {"mortar"} }, fb = "inf" },
  mortar120 = { want = { {"mortar", "120mm"}, {"mortar"} }, fb = "arty" },
  sof       = { want = { {"sof"}, {"special forces"}, {"commando"}, {"spetsnaz"} }, avoid = {"sam"}, fb = "inf" },
  -- Netherlands
  nl_airmobile = { want = { {"air assault"}, {"airmobile"}, {"air mobile"} }, avoid = {"sam"}, fb = "inf" },
  nl_marine    = { want = { {"marine", "inf"}, {"marines"} }, fb = "inf" },
  nl_cv90      = { want = { {"cv9035"}, {"cv 9035"}, {"cv90"}, {"cv 90"} }, fb = "mech" },
  nl_boxer     = { want = { {"boxer"} }, fb = "mech" },
  nl_fennek    = { want = { {"fennek"} }, avoid = {"stinger", "sam"}, fb = "recon" },
  nl_leo2      = { want = { {"leopard 2a6"}, {"leopard 2a7"}, {"leopard 2"} }, fb = "armor" },
  nl_pzh       = { want = { {"pzh 2000"}, {"pzh2000"}, {"pzh-2000"} }, fb = "arty" },
  sam_patriot  = { want = { {"patriot", "pac-3"}, {"patriot"} } },
  sam_nasams   = { want = { {"nasams"} } },
  sam_stinger  = { want = { {"fennek", "stinger"}, {"stinger"} } },
  -- Belgium
  be_piranha = { want = { {"piranha iiic"}, {"piranha iii"}, {"piranha"} }, fb = "mech" },
  be_dingo   = { want = { {"dingo"}, {"mot inf plt"}, {"mot inf"} }, fb = "inf" },
  be_pandur  = { want = { {"pandur"} }, fb = "recon" },
  be_lg1     = { want = { {"lg1"}, {"lg-1"}, {"arty bty", "105mm"} }, fb = "arty" },
  be_paracdo = { want = { {"para", "inf"}, {"airborne"}, {"paratroop"} }, avoid = {"sam"}, fb = "inf" },
  -- structures
  hq     = { want = { {"headquarters"}, {"command", "bunker"}, {"command", "post"}, {"command", "cent"}, {"hq"} },
             avoid = {"hq-", "sam", "radar", "vehicle"} },
  ammo   = { want = { {"ammo", "bunker"}, {"ammo", "shelter"}, {"ammo", "depot"}, {"ammunition"}, {"ammo"} },
             avoid = {"truck", "vehicle"} },
  fuel   = { want = { {"fuel", "depot"}, {"fuel", "tank"}, {"fuel"} }, avoid = {"truck", "vehicle"} },
  supply = { want = { {"warehouse"}, {"supply", "depot"}, {"depot"}, {"storage"}, {"supply"} },
             avoid = {"ammo", "fuel", "truck", "vehicle"} },
}

-- ---------------------------------------------------------------------
--  ORDER OF BATTLE
--  coy = true  -> one unit per platoon (PLATOONS_PER_COMPANY of them)
--  n   = N     -> exactly N units
--  tag is used by the scoring ([HQ] and [DEPOT] are the high-value targets)
-- ---------------------------------------------------------------------
local function coys(tag, bn, role, letters)
  local t = {}
  for _, l in ipairs(letters) do
    t[#t + 1] = { tag = tag, name = bn .. " " .. l, role = role, coy = true }
  end
  return t
end

local function join(...)
  local out = {}
  for _, list in ipairs({ ... }) do
    for _, e in ipairs(list) do out[#out + 1] = e end
  end
  return out
end

local ABC = { "A-Cie", "B-Cie", "C-Cie" }

local OOB_NL = {
  { site = "Utrecht (Kromhout Kazerne)", lat = 52.083, lon = 5.140, els = {
      { tag = "HQ", name = "Staf Commando Landstrijdkrachten", role = "hq" } } },

  { site = "Schaarsbergen (Oranjekazerne)", lat = 52.036, lon = 5.866, els = join(
      { { tag = "HQ", name = "Staf 11 Luchtmobiele Brigade", role = "hq" } },
      coys("INF", "11 Infbat GGJ", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "11 Infbat GGJ Mortieren 81mm", role = "mortar81" } },
      coys("INF", "12 Infbat RvH", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "12 Infbat RvH Mortieren 81mm", role = "mortar81" },
        { tag = "RECON", name = "11 Brigade Verkenningseskadron", role = "recon", n = 2 },
        { tag = "ENG", name = "11 Geniecompagnie Luchtmobiel", role = "eng" } }) },

  { site = "Assen (Johan Willem Frisokazerne)", lat = 52.978, lon = 6.530, els = join(
      coys("INF", "13 Infbat RSPB", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "13 Infbat RSPB Mortieren 81mm", role = "mortar81" },
        { tag = "INF", name = "10 Natresbataljon", role = "inf", n = 2 } }) },

  { site = "Oirschot (De Ruyter van Steveninckkazerne)", lat = 51.485, lon = 5.350, els = join(
      { { tag = "HQ", name = "Staf 13 Lichte Brigade", role = "hq" } },
      coys("MECH", "17 Painfbat GFPI", "nl_boxer", ABC),
      coys("MECH", "42 Painfbat RLJ", "nl_boxer", ABC),
      { { tag = "RECON", name = "42 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 },
        { tag = "ENG", name = "41 Pantsergeniebataljon", role = "eng", n = 2 } }) },

  { site = "Havelte (Johannes Postkazerne)", lat = 52.789, lon = 6.213, els = join(
      { { tag = "HQ", name = "Staf 43 Gemechaniseerde Brigade", role = "hq" } },
      coys("MECH", "44 Painfbat RIJWF", "nl_cv90", ABC),
      { { tag = "RECON", name = "43 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 } }) },

  { site = "Ermelo (Generaal Spoorkazerne)", lat = 52.290, lon = 5.640, els =
      coys("MECH", "45 Painfbat RIOG", "nl_cv90", ABC) },

  { site = "Wezep (Prinses Margrietkazerne)", lat = 52.455, lon = 6.010, els = {
      { tag = "ENG", name = "11 Pantsergeniebataljon", role = "eng", n = 2 },
      { tag = "ENG", name = "101 Geniebataljon", role = "eng" } } },

  { site = "'t Harde (Legerplaats bij Oldebroek)", lat = 52.415, lon = 5.905, els = {
      { tag = "HQ", name = "Staf Vuursteun Commando", role = "hq" },
      { tag = "ARTY", name = "41 Afdeling Artillerie A-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie B-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie C-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie Mortieren 120mm", role = "mortar120" } } },

  { site = "Apeldoorn", lat = 52.210, lon = 5.970, els = {
      { tag = "HQ", name = "Staf Operationeel Ondersteuningscommando Land", role = "hq" } } },

  { site = "Stroe (Generaal-Majoor Kootkazerne)", lat = 52.205, lon = 5.700, els = {
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando Brandstof", role = "fuel" } } },

  { site = "Roosendaal (Engelbrecht van Nassaukazerne)", lat = 51.535, lon = 4.440, els = {
      { tag = "HQ", name = "Staf Korps Commandotroepen", role = "hq" },
      { tag = "SOF", name = "103 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "104 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "105 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "108 Commandotroepencompagnie", role = "sof" } } },

  { site = "Rotterdam (Van Ghentkazerne)", lat = 51.925, lon = 4.490, els = {
      { tag = "HQ", name = "Staf Korps Mariniers", role = "hq" } } },

  { site = "Doorn (Van Braam Houckgeestkazerne)", lat = 52.035, lon = 5.340, els = join(
      coys("INF", "1 Marine Combat Group", "nl_marine", { "10 Sqn", "11 Sqn", "12 Sqn" }),
      coys("INF", "2 Marine Combat Group", "nl_marine", { "21 Sqn", "22 Sqn", "23 Sqn" }),
      { { tag = "SOF", name = "NLMARSOF", role = "sof", n = 2 } }) },

  { site = "Texel (Joost Dourleinkazerne)", lat = 53.005, lon = 4.790, els = {
      { tag = "INF", name = "Surface Assault and Training Group", role = "nl_marine" } } },

  { site = "Den Haag (Frederikkazerne)", lat = 52.100, lon = 4.320, els = {
      { tag = "INF", name = "20 Natresbataljon", role = "inf", n = 2 } } },

  { site = "Vught (Van Brederodekazerne)", lat = 51.660, lon = 5.290, els = {
      { tag = "INF", name = "30 Natresbataljon", role = "inf", n = 2 } } },

  -- logistics
  { site = "Veenhuizen", lat = 53.030, lon = 6.380, els = {
      { tag = "DEPOT", name = "Munitiecomplex Veenhuizen", role = "ammo", n = 3 } } },
  { site = "Alphen (Noord-Brabant)", lat = 51.480, lon = 4.950, els = {
      { tag = "DEPOT", name = "Munitiecomplex Alphen", role = "ammo", n = 3 } } },
  { site = "Soesterberg (Kamp Soesterberg)", lat = 52.125, lon = 5.285, els = {
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg Brandstof", role = "fuel" } } },
  { site = "Coevorden", lat = 52.670, lon = 6.750, els = {
      { tag = "DEPOT", name = "Materieeldepot Coevorden", role = "supply", n = 2 } } },
  { site = "Vriezenveen", lat = 52.420, lon = 6.630, els = {
      { tag = "DEPOT", name = "Materieeldepot Vriezenveen", role = "supply", n = 2 } } },

  -- optional
  { site = "Vredepeel (Luitenant-generaal Bestkazerne)", lat = 51.540, lon = 5.870, opt = "INCLUDE_AIR_DEFENCE", els = {
      { tag = "HQ", name = "Staf DGLC", role = "hq" },
      { tag = "AD", name = "802 Squadron Patriot", role = "sam_patriot", n = 3 },
      { tag = "AD", name = "13 Luchtverdedigingsbatterij NASAMS", role = "sam_nasams", n = 2 },
      { tag = "AD", name = "11 Luchtverdedigingsbatterij Stinger", role = "sam_stinger", n = 2 } } },
  { site = "Bergen-Lohheide (DE)", lat = 52.800, lon = 9.920, opt = "INCLUDE_414_TANK_BN", els = {
      { tag = "ARMOR", name = "414 Tankbataljon 4 (NLD) Eskadron", role = "nl_leo2", n = 4 } } },
}

local OOB_BE = {
  { site = "Evere (Kwartier Koningin Elisabeth)", lat = 50.875, lon = 4.420, els = {
      { tag = "HQ", name = "Staf Landcomponent", role = "hq" } } },

  { site = "Leopoldsburg (Kamp van Beverlo)", lat = 51.117, lon = 5.257, els = join(
      { { tag = "HQ", name = "Staf Gemotoriseerde Brigade", role = "hq" } },
      coys("MECH", "Bn Bevrijding-5 Linie", "be_piranha", ABC),
      coys("INF", "Bn Carabiniers-Grenadiers", "be_dingo", ABC),
      { { tag = "DEPOT", name = "18 Bataljon Logistiek", role = "supply" } }) },

  { site = "Marche-en-Famenne (Camp Roi Albert)", lat = 50.245, lon = 5.325, els = join(
      coys("MECH", "Bn Chasseurs Ardennais", "be_piranha", ABC),
      coys("MECH", "Bn 1/3 Lanciers", "be_piranha", ABC),
      { { tag = "DEPOT", name = "4 Bataillon Logistique", role = "supply" } }) },

  { site = "Spa", lat = 50.487, lon = 5.870, els =
      coys("INF", "Bn 12 de Ligne-13 de Ligne", "be_dingo", ABC) },

  { site = "Heverlee", lat = 50.855, lon = 4.690, els = join(
      { { tag = "HQ", name = "Staf Special Operations Regiment", role = "hq" } },
      coys("RECON", "Bn Jagers te Paard ISTAR", "be_pandur", { "A-Esk", "B-Esk", "C-Esk" }),
      { { tag = "SOF", name = "Special Forces Group", role = "sof", n = 2 } }) },

  { site = "Flawinne", lat = 50.455, lon = 4.800, els =
      coys("INF", "2 Bataillon de Commandos", "be_paracdo", ABC) },

  { site = "Tielen", lat = 51.240, lon = 4.895, els =
      coys("INF", "3 Bataljon Parachutisten", "be_paracdo", ABC) },

  { site = "Brasschaat", lat = 51.325, lon = 4.495, els = {
      { tag = "ARTY", name = "Artilleriebataljon Bt LG1 105mm", role = "be_lg1", n = 2 },
      { tag = "ARTY", name = "Artilleriebataljon Bt Mortieren 120mm", role = "mortar120", n = 2 } } },

  { site = "Amay", lat = 50.548, lon = 5.310, els = {
      { tag = "ENG", name = "4 Bataillon de Genie", role = "eng", n = 2 } } },

  { site = "Burcht", lat = 51.205, lon = 4.340, els = {
      { tag = "ENG", name = "11 Bataljon Genie", role = "eng", n = 2 } } },

  -- logistics
  { site = "Bertrix (Jehonville)", lat = 49.900, lon = 5.210, els = {
      { tag = "DEPOT", name = "Depot de munitions Bertrix", role = "ammo", n = 3 } } },
  { site = "Houthulst", lat = 50.975, lon = 2.950, els = {
      { tag = "DEPOT", name = "Munitiedepot Houthulst", role = "ammo" } } },
  { site = "Rocourt", lat = 50.675, lon = 5.545, els = {
      { tag = "DEPOT", name = "Arsenal Rocourt", role = "supply", n = 2 } } },
  { site = "Peutie", lat = 50.925, lon = 4.455, els = {
      { tag = "DEPOT", name = "Logistiek depot Peutie", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek depot Peutie Brandstof", role = "fuel" } } },
}

-- ---------------------------------------------------------------------
--  SCORING WEIGHTS (relative values; each side is rescaled to SCORE_SCALE)
--  This text is also embedded in the scoring event, so edit it here and
--  re-run the script rather than editing the event.
-- ---------------------------------------------------------------------
local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"

Tool_EmulateNoConsole(true)

local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end

local function getKey(k) return try(ScenEdit_GetKeyValue, k) or "" end
local function setKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local function sideExists(name)
  local sides = try(VP_GetSides) or {}
  for _, s in pairs(sides) do
    if type(s) == "table" or type(s) == "userdata" then
      if s.name == name then return true end
    end
  end
  return false
end

local function listSides()
  local names = {}
  for _, s in pairs(try(VP_GetSides) or {}) do names[#names + 1] = tostring(s.name) end
  return table.concat(names, ", ")
end

-- ----------------------------- DB scan --------------------------------
local resolved, resolvedName, candidates = {}, {}, {}

local function matches(cls, alt, avoid)
  for _, w in ipairs(alt) do
    if not string.find(cls, w, 1, true) then return false end
  end
  if avoid then
    for _, w in ipairs(avoid) do
      if string.find(cls, w, 1, true) then return false end
    end
  end
  return true
end

local function loadCache()
  local all = true
  for role, _ in pairs(ROLES) do
    local id = tonumber(getKey(KEY .. "dbid_" .. role))
    if id then
      resolved[role] = id
      resolvedName[role] = getKey(KEY .. "name_" .. role)
    elseif getKey(KEY .. "dbid_" .. role) ~= "none" then
      all = false
    end
  end
  return all
end

local function scanDatabase()
  local tmp = "~LOOB scan"
  local scanSide = tmp
  if not sideExists(tmp) then try(ScenEdit_AddSide, { side = tmp }) end
  if not sideExists(tmp) then scanSide = CONFIG.SIDE_NL end

  local names, real, found = {}, {}, 0
  for id = 1, CONFIG.SCAN_MAX_DBID do
    local u = try(ScenEdit_AddUnit, { side = scanSide, type = "Facility", unitname = "LOOB scan " .. id,
                                      dbid = id, latitude = CONFIG.SCAN_LAT, longitude = CONFIG.SCAN_LON })
    if u then
      local cls = tostring(u.classname or "")
      if cls ~= "" then
        names[id] = string.lower(cls)
        real[id] = cls
        found = found + 1
      end
      try(ScenEdit_DeleteUnit, { side = scanSide, guid = u.guid })
    end
  end
  if scanSide == tmp then try(ScenEdit_RemoveSide, { side = tmp }) end
  print("Database scan: " .. found .. " facility classes read (DBID 1-" .. CONFIG.SCAN_MAX_DBID .. ")")

  for role, def in pairs(ROLES) do
    candidates[role] = {}
    for _, alt in ipairs(def.want) do
      for id = 1, CONFIG.SCAN_MAX_DBID do
        if names[id] and matches(names[id], alt, def.avoid) then
          candidates[role][#candidates[role] + 1] = { id = id, name = real[id] }
        end
      end
      if #candidates[role] > 0 then break end
    end
    local pick = candidates[role][1]
    if pick then
      resolved[role], resolvedName[role] = pick.id, pick.name
      setKey(KEY .. "dbid_" .. role, pick.id)
      setKey(KEY .. "name_" .. role, pick.name)
    else
      resolved[role], resolvedName[role] = nil, nil
      setKey(KEY .. "dbid_" .. role, "none")
    end
  end
  return found
end

local function effective(role, depth)
  depth = depth or 0
  if DBID_OVERRIDE[role] then return DBID_OVERRIDE[role], "manual override", role end
  if resolved[role] then return resolved[role], resolvedName[role], role end
  local fb = ROLES[role] and ROLES[role].fb
  if fb and depth < 5 then return effective(fb, depth + 1) end
  return nil
end

local function printRoleReport()
  local order = {}
  for role, _ in pairs(ROLES) do order[#order + 1] = role end
  table.sort(order)
  print("---- Units chosen from your database ----")
  for _, role in ipairs(order) do
    local id, name, via = effective(role)
    if id then
      local note = (via ~= role) and ("   <- nothing specific found, using '" .. via .. "'") or ""
      print(string.format("  %-13s DBID %-5s %s%s", role, tostring(id), tostring(name), note))
    else
      print(string.format("  %-13s NOT FOUND - units with this role are skipped", role))
    end
    local c = candidates[role]
    if c and #c > 1 then
      local alt = {}
      for i = 2, math.min(#c, 6) do alt[#alt + 1] = c[i].id .. " " .. c[i].name end
      print("                other matches: " .. table.concat(alt, " | ")
            .. ((#c > 6) and (" | +" .. (#c - 6) .. " more") or ""))
    end
  end
end

-- --------------------------- unit placement ----------------------------
local stats = { added = 0, existed = 0, failed = 0, norole = 0 }

local function offset(lat, lon, km, bearingDeg)
  local r = math.rad(bearingDeg)
  local dlat = (km * math.cos(r)) / 111.32
  local dlon = (km * math.sin(r)) / (111.32 * math.cos(math.rad(lat)))
  return lat + dlat, lon + dlon
end

local function addUnit(side, name, role, lat, lon)
  local id = effective(role)
  if not id then stats.norole = stats.norole + 1 return end
  if try(ScenEdit_GetUnit, { side = side, unitname = name }) then
    stats.existed = stats.existed + 1
    return
  end
  local u = try(ScenEdit_AddUnit, { side = side, type = "Facility", unitname = name, dbid = id,
                                    latitude = lat, longitude = lon })
  if u then
    stats.added = stats.added + 1
  else
    stats.failed = stats.failed + 1
    print("  could not add '" .. name .. "' (DBID " .. tostring(id) .. ") " .. tostring(_errmsg_ or ""))
  end
end

local function buildSite(side, site)
  local n = #site.els
  local perRing = 6
  for i, e in ipairs(site.els) do
    local count = e.coy and CONFIG.PLATOONS_PER_COMPANY or (e.n or 1)
    local ring = math.floor((i - 1) / perRing)
    local bearing = (i - 1) * (360 / math.min(n, perRing)) + ring * 30
    local radius = (n == 1) and 0 or (1.0 + 0.8 * ring)
    local clat, clon = offset(site.lat, site.lon, radius, bearing)
    for p = 1, count do
      local plat, plon = offset(clat, clon, 0.3 * (p - 1), bearing + 90)
      local nm = "[" .. e.tag .. "] " .. e.name .. ((count > 1) and (" /" .. p) or "")
      addUnit(side, nm, e.role, plat, plon)
    end
  end
end

local function buildSide(side, oob)
  for _, site in ipairs(oob) do
    if (not site.opt) or CONFIG[site.opt] then buildSite(side, site) end
  end
end

-- ------------------------------ scoring --------------------------------
local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function compileWeight()
  local loader = load or loadstring
  local chunk, err = loader(WEIGHT_SRC .. "\nreturn LS_weight")
  if not chunk then error("WEIGHT_SRC does not compile: " .. tostring(err)) end
  return chunk()
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = compileWeight()
  local problems = 0

  print("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      print("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      setKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      setKey(KEY .. "scale_" .. side, scale)
      print(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        print(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    setKey(KEY .. "lost_" .. side, 0)
  end
  setKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    print("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      print("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    print("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    print("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    print("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  print("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  print("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- -------------------------------- main ---------------------------------
local function main()
  local A, B = CONFIG.SIDE_NL, CONFIG.SIDE_BE
  if not sideExists(A) or not sideExists(B) then
    print("STOPPED: side '" .. A .. "' or '" .. B .. "' does not exist.")
    print("Sides in this scenario: " .. listSides())
    print("Edit SIDE_NL / SIDE_BE at the top of the script and run it again.")
    return
  end

  if CONFIG.STEPS.land_units or CONFIG.SCAN_ONLY then
    local cached = (not CONFIG.FORCE_RESCAN) and (not CONFIG.SCAN_ONLY) and loadCache()
    if cached then
      print("Using database IDs found by an earlier run (set FORCE_RESCAN = true to scan again)")
    else
      print("Scanning the database, this can take a minute or two...")
      if scanDatabase() == 0 then
        print("STOPPED: the scan could not read any facility from the database.")
        print("Fill in DBID_OVERRIDE by hand (DB viewer) and run again with those IDs.")
        local any = false
        for _, _ in pairs(DBID_OVERRIDE) do any = true end
        if not any then return end
      end
    end
    printRoleReport()
    if CONFIG.SCAN_ONLY then return end

    buildSide(A, OOB_NL)
    buildSide(B, OOB_BE)
    print("---- Land units ----")
    print(string.format("  added %d, already present %d, failed %d, skipped (no DB match) %d",
                        stats.added, stats.existed, stats.failed, stats.norole))
  end

  if CONFIG.STEPS.scoring then setupScoring(A, B) end
  print("Done.")
end

local ok, err = pcall(main)
Tool_EmulateNoConsole(false)
if not ok then print("SCRIPT ERROR: " .. tostring(err)) end
Using database IDs found by an earlier run (set FORCE_RESCAN = true to scan again)
---- Units chosen from your database ----
  ammo          DBID 322   Ammo Bunker (Surface)
  armor         DBID 117   Armored Plt (T-34/85 MBT x 4)
  arty          DBID 222   Coastal Arty Bty (155mm/39 Tampella 155 K83 Towed Gun x 4)
  be_dingo      DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  be_lg1        DBID 330   Arty Bty/3 (105mm/37 L118 Towed Light Gun x 2)
  be_pandur     DBID 2947  Motor Inf Plt (Pandur I APC x 4)
  be_paracdo    DBID 209   Inf Plt (British Paratroopers)
  be_piranha    DBID 2866  Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
  eng           DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  fuel          DBID 248   Support Plt (Helicopter Expeditionary Refueling System)
  hq            DBID 3730  Command Post
  inf           DBID 202   Inf Plt (Russian Army)
  mech          DBID 635   Mech Inf Plt (ZSD-89 [Type 89] APC x 4)
  mortar120     DBID 2058  Mortar Plt (120mm Mortar)
  mortar81      DBID 2060  Mortar Plt (81mm Mortar)
  nl_airmobile  DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  nl_boxer      DBID 2316  Mech Inf Plt (Boxer APC x 3)
  nl_cv90       DBID 5095  Mech Inf Plt (CV 9035 x 4)
  nl_fennek     DBID 614   Inf Sec (Recon)   <- nothing specific found, using 'recon'
  nl_leo2       DBID 2341  Armored Plt (Leopard 2A6 MBT x 3)
  nl_marine     DBID 211   Inf Plt (British Royal Marines)
  nl_pzh        DBID 2133  Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
  recon         DBID 614   Inf Sec (Recon)
  sam_nasams    DBID 147   Radar (AN/TPQ-36A [NASAMS])
  sam_patriot   DBID 294   SAM Bty (Patriot [PAC-2 GEM+, PAC-3 CRI])
  sam_stinger   DBID 7     SAM Sec (Stinger MANPADS x 5)
  sof           DBID 835   Vehicle (Soft Ball ELS [KRTP-81 Ramona])
  supply        DBID 3098  Container Storage Park
---- Land units ----
  added 0, already present 235, failed 0, skipped (no DB match) 0
SCRIPT ERROR: [string "Console"]:524: attempt to call a nil value (local 'loader')
...
07/10/2026 17:24:47 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX LAND FORCES + ZERO-SUM SCORING
--  Command: Modern Operations - run from Editor > Lua Script Console
-- =====================================================================
--  What it does
--   1. Finds the right database IDs in YOUR database by itself (it briefly
--      creates and deletes one facility per DBID on a temporary side and
--      reads its class name). No IDs are hard-coded.
--   2. Places the Royal Netherlands Army / Korps Mariniers and the Belgian
--      Land Component at their real peacetime garrisons, plus brigade and
--      army HQs and logistic depots.
--   3. Creates one repeatable event that scores every loss on both sides:
--      the killer gains what the owner loses. Each side's whole force is
--      worth exactly SCORE_SCALE points, so the score runs from
--      -1000 (you lost everything, killed nothing) to +1000 (the reverse).
--
--  How to use
--   a. Merge your two scenarios first, save a backup copy.
--   b. Set SIDE_NL / SIDE_BE below to the exact side names in the scenario.
--   c. Paste the whole file into the Lua console and run it. The first run
--      scans the database and can freeze the game for a minute or two.
--   d. Read the report it prints. If a role picked the wrong unit, put the
--      DBID you want in DBID_OVERRIDE and run again (existing units are
--      skipped, missing ones are added).
--   e. If you add or remove units later, run again with
--      STEPS.land_units = false so the +/-1000 scale is recalculated.
--
--  Order of battle reflects the early/mid-2020s structure. Coordinates are
--  approximate (town/barracks level) - nudge units in the editor if needed.
-- =====================================================================

-- Messages are collected and shown when the script finishes (console + pop-up).
local LOOB_LOG = {}
local LOOB_rawprint = print
local function print(msg) LOOB_LOG[#LOOB_LOG + 1] = tostring(msg) end
LOOB_rawprint("Benelux script started - the game may freeze while it works...")

local CONFIG = {
  SIDE_NL = "Netherlands",        -- exact side name in your scenario
  SIDE_BE = "Belgium",            -- exact side name in your scenario

  STEPS = { land_units = true, scoring = true },

  SCAN_ONLY      = false,         -- true = only print what the DB scan finds
  FORCE_RESCAN   = false,         -- true = ignore IDs cached by an earlier run
  SCAN_MAX_DBID  = 6000,          -- highest facility DBID to try
  SCAN_LAT = 52.10, SCAN_LON = 5.60,   -- any point on land

  PLATOONS_PER_COMPANY = 3,       -- 1 = one unit per company (lighter scenario)

  INCLUDE_AIR_DEFENCE = false,    -- Dutch Patriot/NASAMS/Stinger at Vredepeel.
                                  -- Off because your scenarios already have AA sites.
  INCLUDE_414_TANK_BN = false,    -- Dutch Leopard 2A6 squadron; really based at
                                  -- Bergen-Lohheide in Germany, outside the map area.

  SCORE_SCALE     = 1000,         -- total value of each side's force
  END_SCENARIO_AT = nil,          -- e.g. 600 = end the game when a side reaches +600
}

-- Force a specific DBID for a role, e.g.  nl_cv90 = 1234,
local DBID_OVERRIDE = {
}

-- ---------------------------------------------------------------------
--  ROLES: what to look for in the database.
--  want  = alternatives in priority order; every word in one alternative
--          must appear in the class name (lower case, plain text).
--  avoid = class names containing any of these are rejected.
--  fb    = role to fall back on when nothing matches.
-- ---------------------------------------------------------------------
local ROLES = {
  -- generic
  inf       = { want = { {"inf plt"}, {"infantry plt"}, {"infantry platoon"}, {"inf sec"}, {"infantry"} },
                avoid = {"mech", "mot ", "motor", "armor", "sam", "marine", "manpad", "atgm"} },
  mech      = { want = { {"mech inf plt"}, {"mech inf"}, {"mechanized inf"} }, fb = "inf" },
  recon     = { want = { {"recon plt"}, {"recce plt"}, {"recon"}, {"recce"} }, avoid = {"uav", "radar"}, fb = "inf" },
  armor     = { want = { {"armored plt"}, {"armor plt"}, {"tank plt"} }, fb = "mech" },
  arty      = { want = { {"arty bty", "155mm"}, {"arty bty"} } },
  eng       = { want = { {"engineer"}, {"eng plt"}, {"sapper"} }, fb = "inf" },
  mortar81  = { want = { {"mortar", "81mm"}, {"mortar", "82mm"}, {"mortar"} }, fb = "inf" },
  mortar120 = { want = { {"mortar", "120mm"}, {"mortar"} }, fb = "arty" },
  sof       = { want = { {"sof"}, {"special forces"}, {"commando"}, {"spetsnaz"} }, avoid = {"sam"}, fb = "inf" },
  -- Netherlands
  nl_airmobile = { want = { {"air assault"}, {"airmobile"}, {"air mobile"} }, avoid = {"sam"}, fb = "inf" },
  nl_marine    = { want = { {"marine", "inf"}, {"marines"} }, fb = "inf" },
  nl_cv90      = { want = { {"cv9035"}, {"cv 9035"}, {"cv90"}, {"cv 90"} }, fb = "mech" },
  nl_boxer     = { want = { {"boxer"} }, fb = "mech" },
  nl_fennek    = { want = { {"fennek"} }, avoid = {"stinger", "sam"}, fb = "recon" },
  nl_leo2      = { want = { {"leopard 2a6"}, {"leopard 2a7"}, {"leopard 2"} }, fb = "armor" },
  nl_pzh       = { want = { {"pzh 2000"}, {"pzh2000"}, {"pzh-2000"} }, fb = "arty" },
  sam_patriot  = { want = { {"patriot", "pac-3"}, {"patriot"} } },
  sam_nasams   = { want = { {"nasams"} } },
  sam_stinger  = { want = { {"fennek", "stinger"}, {"stinger"} } },
  -- Belgium
  be_piranha = { want = { {"piranha iiic"}, {"piranha iii"}, {"piranha"} }, fb = "mech" },
  be_dingo   = { want = { {"dingo"}, {"mot inf plt"}, {"mot inf"} }, fb = "inf" },
  be_pandur  = { want = { {"pandur"} }, fb = "recon" },
  be_lg1     = { want = { {"lg1"}, {"lg-1"}, {"arty bty", "105mm"} }, fb = "arty" },
  be_paracdo = { want = { {"para", "inf"}, {"airborne"}, {"paratroop"} }, avoid = {"sam"}, fb = "inf" },
  -- structures
  hq     = { want = { {"headquarters"}, {"command", "bunker"}, {"command", "post"}, {"command", "cent"}, {"hq"} },
             avoid = {"hq-", "sam", "radar", "vehicle"} },
  ammo   = { want = { {"ammo", "bunker"}, {"ammo", "shelter"}, {"ammo", "depot"}, {"ammunition"}, {"ammo"} },
             avoid = {"truck", "vehicle"} },
  fuel   = { want = { {"fuel", "depot"}, {"fuel", "tank"}, {"fuel"} }, avoid = {"truck", "vehicle"} },
  supply = { want = { {"warehouse"}, {"supply", "depot"}, {"depot"}, {"storage"}, {"supply"} },
             avoid = {"ammo", "fuel", "truck", "vehicle"} },
}

-- ---------------------------------------------------------------------
--  ORDER OF BATTLE
--  coy = true  -> one unit per platoon (PLATOONS_PER_COMPANY of them)
--  n   = N     -> exactly N units
--  tag is used by the scoring ([HQ] and [DEPOT] are the high-value targets)
-- ---------------------------------------------------------------------
local function coys(tag, bn, role, letters)
  local t = {}
  for _, l in ipairs(letters) do
    t[#t + 1] = { tag = tag, name = bn .. " " .. l, role = role, coy = true }
  end
  return t
end

local function join(...)
  local out = {}
  for _, list in ipairs({ ... }) do
    for _, e in ipairs(list) do out[#out + 1] = e end
  end
  return out
end

local ABC = { "A-Cie", "B-Cie", "C-Cie" }

local OOB_NL = {
  { site = "Utrecht (Kromhout Kazerne)", lat = 52.083, lon = 5.140, els = {
      { tag = "HQ", name = "Staf Commando Landstrijdkrachten", role = "hq" } } },

  { site = "Schaarsbergen (Oranjekazerne)", lat = 52.036, lon = 5.866, els = join(
      { { tag = "HQ", name = "Staf 11 Luchtmobiele Brigade", role = "hq" } },
      coys("INF", "11 Infbat GGJ", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "11 Infbat GGJ Mortieren 81mm", role = "mortar81" } },
      coys("INF", "12 Infbat RvH", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "12 Infbat RvH Mortieren 81mm", role = "mortar81" },
        { tag = "RECON", name = "11 Brigade Verkenningseskadron", role = "recon", n = 2 },
        { tag = "ENG", name = "11 Geniecompagnie Luchtmobiel", role = "eng" } }) },

  { site = "Assen (Johan Willem Frisokazerne)", lat = 52.978, lon = 6.530, els = join(
      coys("INF", "13 Infbat RSPB", "nl_airmobile", ABC),
      { { tag = "ARTY", name = "13 Infbat RSPB Mortieren 81mm", role = "mortar81" },
        { tag = "INF", name = "10 Natresbataljon", role = "inf", n = 2 } }) },

  { site = "Oirschot (De Ruyter van Steveninckkazerne)", lat = 51.485, lon = 5.350, els = join(
      { { tag = "HQ", name = "Staf 13 Lichte Brigade", role = "hq" } },
      coys("MECH", "17 Painfbat GFPI", "nl_boxer", ABC),
      coys("MECH", "42 Painfbat RLJ", "nl_boxer", ABC),
      { { tag = "RECON", name = "42 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 },
        { tag = "ENG", name = "41 Pantsergeniebataljon", role = "eng", n = 2 } }) },

  { site = "Havelte (Johannes Postkazerne)", lat = 52.789, lon = 6.213, els = join(
      { { tag = "HQ", name = "Staf 43 Gemechaniseerde Brigade", role = "hq" } },
      coys("MECH", "44 Painfbat RIJWF", "nl_cv90", ABC),
      { { tag = "RECON", name = "43 Brigade Verkenningseskadron", role = "nl_fennek", n = 3 } }) },

  { site = "Ermelo (Generaal Spoorkazerne)", lat = 52.290, lon = 5.640, els =
      coys("MECH", "45 Painfbat RIOG", "nl_cv90", ABC) },

  { site = "Wezep (Prinses Margrietkazerne)", lat = 52.455, lon = 6.010, els = {
      { tag = "ENG", name = "11 Pantsergeniebataljon", role = "eng", n = 2 },
      { tag = "ENG", name = "101 Geniebataljon", role = "eng" } } },

  { site = "'t Harde (Legerplaats bij Oldebroek)", lat = 52.415, lon = 5.905, els = {
      { tag = "HQ", name = "Staf Vuursteun Commando", role = "hq" },
      { tag = "ARTY", name = "41 Afdeling Artillerie A-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie B-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie C-Bt PzH2000", role = "nl_pzh" },
      { tag = "ARTY", name = "41 Afdeling Artillerie Mortieren 120mm", role = "mortar120" } } },

  { site = "Apeldoorn", lat = 52.210, lon = 5.970, els = {
      { tag = "HQ", name = "Staf Operationeel Ondersteuningscommando Land", role = "hq" } } },

  { site = "Stroe (Generaal-Majoor Kootkazerne)", lat = 52.205, lon = 5.700, els = {
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Bevoorradings- en Transportcommando Brandstof", role = "fuel" } } },

  { site = "Roosendaal (Engelbrecht van Nassaukazerne)", lat = 51.535, lon = 4.440, els = {
      { tag = "HQ", name = "Staf Korps Commandotroepen", role = "hq" },
      { tag = "SOF", name = "103 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "104 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "105 Commandotroepencompagnie", role = "sof" },
      { tag = "SOF", name = "108 Commandotroepencompagnie", role = "sof" } } },

  { site = "Rotterdam (Van Ghentkazerne)", lat = 51.925, lon = 4.490, els = {
      { tag = "HQ", name = "Staf Korps Mariniers", role = "hq" } } },

  { site = "Doorn (Van Braam Houckgeestkazerne)", lat = 52.035, lon = 5.340, els = join(
      coys("INF", "1 Marine Combat Group", "nl_marine", { "10 Sqn", "11 Sqn", "12 Sqn" }),
      coys("INF", "2 Marine Combat Group", "nl_marine", { "21 Sqn", "22 Sqn", "23 Sqn" }),
      { { tag = "SOF", name = "NLMARSOF", role = "sof", n = 2 } }) },

  { site = "Texel (Joost Dourleinkazerne)", lat = 53.005, lon = 4.790, els = {
      { tag = "INF", name = "Surface Assault and Training Group", role = "nl_marine" } } },

  { site = "Den Haag (Frederikkazerne)", lat = 52.100, lon = 4.320, els = {
      { tag = "INF", name = "20 Natresbataljon", role = "inf", n = 2 } } },

  { site = "Vught (Van Brederodekazerne)", lat = 51.660, lon = 5.290, els = {
      { tag = "INF", name = "30 Natresbataljon", role = "inf", n = 2 } } },

  -- logistics
  { site = "Veenhuizen", lat = 53.030, lon = 6.380, els = {
      { tag = "DEPOT", name = "Munitiecomplex Veenhuizen", role = "ammo", n = 3 } } },
  { site = "Alphen (Noord-Brabant)", lat = 51.480, lon = 4.950, els = {
      { tag = "DEPOT", name = "Munitiecomplex Alphen", role = "ammo", n = 3 } } },
  { site = "Soesterberg (Kamp Soesterberg)", lat = 52.125, lon = 5.285, els = {
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek Centrum Soesterberg Brandstof", role = "fuel" } } },
  { site = "Coevorden", lat = 52.670, lon = 6.750, els = {
      { tag = "DEPOT", name = "Materieeldepot Coevorden", role = "supply", n = 2 } } },
  { site = "Vriezenveen", lat = 52.420, lon = 6.630, els = {
      { tag = "DEPOT", name = "Materieeldepot Vriezenveen", role = "supply", n = 2 } } },

  -- optional
  { site = "Vredepeel (Luitenant-generaal Bestkazerne)", lat = 51.540, lon = 5.870, opt = "INCLUDE_AIR_DEFENCE", els = {
      { tag = "HQ", name = "Staf DGLC", role = "hq" },
      { tag = "AD", name = "802 Squadron Patriot", role = "sam_patriot", n = 3 },
      { tag = "AD", name = "13 Luchtverdedigingsbatterij NASAMS", role = "sam_nasams", n = 2 },
      { tag = "AD", name = "11 Luchtverdedigingsbatterij Stinger", role = "sam_stinger", n = 2 } } },
  { site = "Bergen-Lohheide (DE)", lat = 52.800, lon = 9.920, opt = "INCLUDE_414_TANK_BN", els = {
      { tag = "ARMOR", name = "414 Tankbataljon 4 (NLD) Eskadron", role = "nl_leo2", n = 4 } } },
}

local OOB_BE = {
  { site = "Evere (Kwartier Koningin Elisabeth)", lat = 50.875, lon = 4.420, els = {
      { tag = "HQ", name = "Staf Landcomponent", role = "hq" } } },

  { site = "Leopoldsburg (Kamp van Beverlo)", lat = 51.117, lon = 5.257, els = join(
      { { tag = "HQ", name = "Staf Gemotoriseerde Brigade", role = "hq" } },
      coys("MECH", "Bn Bevrijding-5 Linie", "be_piranha", ABC),
      coys("INF", "Bn Carabiniers-Grenadiers", "be_dingo", ABC),
      { { tag = "DEPOT", name = "18 Bataljon Logistiek", role = "supply" } }) },

  { site = "Marche-en-Famenne (Camp Roi Albert)", lat = 50.245, lon = 5.325, els = join(
      coys("MECH", "Bn Chasseurs Ardennais", "be_piranha", ABC),
      coys("MECH", "Bn 1/3 Lanciers", "be_piranha", ABC),
      { { tag = "DEPOT", name = "4 Bataillon Logistique", role = "supply" } }) },

  { site = "Spa", lat = 50.487, lon = 5.870, els =
      coys("INF", "Bn 12 de Ligne-13 de Ligne", "be_dingo", ABC) },

  { site = "Heverlee", lat = 50.855, lon = 4.690, els = join(
      { { tag = "HQ", name = "Staf Special Operations Regiment", role = "hq" } },
      coys("RECON", "Bn Jagers te Paard ISTAR", "be_pandur", { "A-Esk", "B-Esk", "C-Esk" }),
      { { tag = "SOF", name = "Special Forces Group", role = "sof", n = 2 } }) },

  { site = "Flawinne", lat = 50.455, lon = 4.800, els =
      coys("INF", "2 Bataillon de Commandos", "be_paracdo", ABC) },

  { site = "Tielen", lat = 51.240, lon = 4.895, els =
      coys("INF", "3 Bataljon Parachutisten", "be_paracdo", ABC) },

  { site = "Brasschaat", lat = 51.325, lon = 4.495, els = {
      { tag = "ARTY", name = "Artilleriebataljon Bt LG1 105mm", role = "be_lg1", n = 2 },
      { tag = "ARTY", name = "Artilleriebataljon Bt Mortieren 120mm", role = "mortar120", n = 2 } } },

  { site = "Amay", lat = 50.548, lon = 5.310, els = {
      { tag = "ENG", name = "4 Bataillon de Genie", role = "eng", n = 2 } } },

  { site = "Burcht", lat = 51.205, lon = 4.340, els = {
      { tag = "ENG", name = "11 Bataljon Genie", role = "eng", n = 2 } } },

  -- logistics
  { site = "Bertrix (Jehonville)", lat = 49.900, lon = 5.210, els = {
      { tag = "DEPOT", name = "Depot de munitions Bertrix", role = "ammo", n = 3 } } },
  { site = "Houthulst", lat = 50.975, lon = 2.950, els = {
      { tag = "DEPOT", name = "Munitiedepot Houthulst", role = "ammo" } } },
  { site = "Rocourt", lat = 50.675, lon = 5.545, els = {
      { tag = "DEPOT", name = "Arsenal Rocourt", role = "supply", n = 2 } } },
  { site = "Peutie", lat = 50.925, lon = 4.455, els = {
      { tag = "DEPOT", name = "Logistiek depot Peutie", role = "supply", n = 2 },
      { tag = "DEPOT", name = "Logistiek depot Peutie Brandstof", role = "fuel" } } },
}

-- ---------------------------------------------------------------------
--  SCORING WEIGHTS (relative values; each side is rescaled to SCORE_SCALE)
--  This text is embedded in the scoring event; an identical copy follows it as
--  real code for this script. Edit both and re-run the script.
-- ---------------------------------------------------------------------
local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

-- The same function as real code (this console has no load/loadstring, so the
-- text above cannot be compiled here). If you change the values, change BOTH copies.
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"

pcall(Tool_EmulateNoConsole, true)

local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end

local function getKey(k) return try(ScenEdit_GetKeyValue, k) or "" end
local function setKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local function sideExists(name)
  local sides = try(VP_GetSides) or {}
  for _, s in pairs(sides) do
    if type(s) == "table" or type(s) == "userdata" then
      if s.name == name then return true end
    end
  end
  return false
end

local function listSides()
  local names = {}
  for _, s in pairs(try(VP_GetSides) or {}) do names[#names + 1] = tostring(s.name) end
  return table.concat(names, ", ")
end

-- ----------------------------- DB scan --------------------------------
local resolved, resolvedName, candidates = {}, {}, {}

local function matches(cls, alt, avoid)
  for _, w in ipairs(alt) do
    if not string.find(cls, w, 1, true) then return false end
  end
  if avoid then
    for _, w in ipairs(avoid) do
      if string.find(cls, w, 1, true) then return false end
    end
  end
  return true
end

local function loadCache()
  local all = true
  for role, _ in pairs(ROLES) do
    local id = tonumber(getKey(KEY .. "dbid_" .. role))
    if id then
      resolved[role] = id
      resolvedName[role] = getKey(KEY .. "name_" .. role)
    elseif getKey(KEY .. "dbid_" .. role) ~= "none" then
      all = false
    end
  end
  return all
end

local function scanDatabase()
  local tmp = "~LOOB scan"
  local scanSide = tmp
  if not sideExists(tmp) then try(ScenEdit_AddSide, { side = tmp }) end
  if not sideExists(tmp) then scanSide = CONFIG.SIDE_NL end

  local names, real, found = {}, {}, 0
  for id = 1, CONFIG.SCAN_MAX_DBID do
    local u = try(ScenEdit_AddUnit, { side = scanSide, type = "Facility", unitname = "LOOB scan " .. id,
                                      dbid = id, latitude = CONFIG.SCAN_LAT, longitude = CONFIG.SCAN_LON })
    if u then
      local cls = tostring(u.classname or "")
      if cls ~= "" then
        names[id] = string.lower(cls)
        real[id] = cls
        found = found + 1
      end
      try(ScenEdit_DeleteUnit, { side = scanSide, guid = u.guid })
    end
  end
  if scanSide == tmp then try(ScenEdit_RemoveSide, { side = tmp }) end
  print("Database scan: " .. found .. " facility classes read (DBID 1-" .. CONFIG.SCAN_MAX_DBID .. ")")

  for role, def in pairs(ROLES) do
    candidates[role] = {}
    for _, alt in ipairs(def.want) do
      for id = 1, CONFIG.SCAN_MAX_DBID do
        if names[id] and matches(names[id], alt, def.avoid) then
          candidates[role][#candidates[role] + 1] = { id = id, name = real[id] }
        end
      end
      if #candidates[role] > 0 then break end
    end
    local pick = candidates[role][1]
    if pick then
      resolved[role], resolvedName[role] = pick.id, pick.name
      setKey(KEY .. "dbid_" .. role, pick.id)
      setKey(KEY .. "name_" .. role, pick.name)
    else
      resolved[role], resolvedName[role] = nil, nil
      setKey(KEY .. "dbid_" .. role, "none")
    end
  end
  return found
end

local function effective(role, depth)
  depth = depth or 0
  if DBID_OVERRIDE[role] then return DBID_OVERRIDE[role], "manual override", role end
  if resolved[role] then return resolved[role], resolvedName[role], role end
  local fb = ROLES[role] and ROLES[role].fb
  if fb and depth < 5 then return effective(fb, depth + 1) end
  return nil
end

local function printRoleReport()
  local order = {}
  for role, _ in pairs(ROLES) do order[#order + 1] = role end
  table.sort(order)
  print("---- Units chosen from your database ----")
  for _, role in ipairs(order) do
    local id, name, via = effective(role)
    if id then
      local note = (via ~= role) and ("   <- nothing specific found, using '" .. via .. "'") or ""
      print(string.format("  %-13s DBID %-5s %s%s", role, tostring(id), tostring(name), note))
    else
      print(string.format("  %-13s NOT FOUND - units with this role are skipped", role))
    end
    local c = candidates[role]
    if c and #c > 1 then
      local alt = {}
      for i = 2, math.min(#c, 6) do alt[#alt + 1] = c[i].id .. " " .. c[i].name end
      print("                other matches: " .. table.concat(alt, " | ")
            .. ((#c > 6) and (" | +" .. (#c - 6) .. " more") or ""))
    end
  end
end

-- --------------------------- unit placement ----------------------------
local stats = { added = 0, existed = 0, failed = 0, norole = 0 }

local function offset(lat, lon, km, bearingDeg)
  local r = math.rad(bearingDeg)
  local dlat = (km * math.cos(r)) / 111.32
  local dlon = (km * math.sin(r)) / (111.32 * math.cos(math.rad(lat)))
  return lat + dlat, lon + dlon
end

local function addUnit(side, name, role, lat, lon)
  local id = effective(role)
  if not id then stats.norole = stats.norole + 1 return end
  if try(ScenEdit_GetUnit, { side = side, unitname = name }) then
    stats.existed = stats.existed + 1
    return
  end
  local u = try(ScenEdit_AddUnit, { side = side, type = "Facility", unitname = name, dbid = id,
                                    latitude = lat, longitude = lon })
  if u then
    stats.added = stats.added + 1
  else
    stats.failed = stats.failed + 1
    print("  could not add '" .. name .. "' (DBID " .. tostring(id) .. ") " .. tostring(_errmsg_ or ""))
  end
end

local function buildSite(side, site)
  local n = #site.els
  local perRing = 6
  for i, e in ipairs(site.els) do
    local count = e.coy and CONFIG.PLATOONS_PER_COMPANY or (e.n or 1)
    local ring = math.floor((i - 1) / perRing)
    local bearing = (i - 1) * (360 / math.min(n, perRing)) + ring * 30
    local radius = (n == 1) and 0 or (1.0 + 0.8 * ring)
    local clat, clon = offset(site.lat, site.lon, radius, bearing)
    for p = 1, count do
      local plat, plon = offset(clat, clon, 0.3 * (p - 1), bearing + 90)
      local nm = "[" .. e.tag .. "] " .. e.name .. ((count > 1) and (" /" .. p) or "")
      addUnit(side, nm, e.role, plat, plon)
    end
  end
end

local function buildSide(side, oob)
  for _, site in ipairs(oob) do
    if (not site.opt) or CONFIG[site.opt] then buildSite(side, site) end
  end
end

-- ------------------------------ scoring --------------------------------
local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function compileWeight()
  return LS_weight
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = compileWeight()
  local problems = 0

  print("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      print("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      setKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      setKey(KEY .. "scale_" .. side, scale)
      print(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        print(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    setKey(KEY .. "lost_" .. side, 0)
  end
  setKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    print("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      print("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    print("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    print("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    print("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  print("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  print("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- -------------------------------- main ---------------------------------
local function main()
  local A, B = CONFIG.SIDE_NL, CONFIG.SIDE_BE
  if not sideExists(A) or not sideExists(B) then
    print("STOPPED: side '" .. A .. "' or '" .. B .. "' does not exist.")
    print("Sides in this scenario: " .. listSides())
    print("Edit SIDE_NL / SIDE_BE at the top of the script and run it again.")
    return
  end

  if CONFIG.STEPS.land_units or CONFIG.SCAN_ONLY then
    local cached = (not CONFIG.FORCE_RESCAN) and (not CONFIG.SCAN_ONLY) and loadCache()
    if cached then
      print("Using database IDs found by an earlier run (set FORCE_RESCAN = true to scan again)")
    else
      print("Scanning the database, this can take a minute or two...")
      if scanDatabase() == 0 then
        print("STOPPED: the scan could not read any facility from the database.")
        print("Fill in DBID_OVERRIDE by hand (DB viewer) and run again with those IDs.")
        local any = false
        for _, _ in pairs(DBID_OVERRIDE) do any = true end
        if not any then return end
      end
    end
    printRoleReport()
    if CONFIG.SCAN_ONLY then return end

    buildSide(A, OOB_NL)
    buildSide(B, OOB_BE)
    print("---- Land units ----")
    print(string.format("  added %d, already present %d, failed %d, skipped (no DB match) %d",
                        stats.added, stats.existed, stats.failed, stats.norole))
  end

  if CONFIG.STEPS.scoring then setupScoring(A, B) end
  print("Done.")
end

local ok, err = pcall(main)
pcall(Tool_EmulateNoConsole, false)
if not ok then print("SCRIPT ERROR: " .. tostring(err)) end
local LOOB_text = table.concat(LOOB_LOG, "\n")
LOOB_rawprint(LOOB_text)
local LOOB_tail = {}
for i = math.max(1, #LOOB_LOG - 14), #LOOB_LOG do LOOB_tail[#LOOB_tail + 1] = LOOB_LOG[i] end
pcall(ScenEdit_MsgBox, "Benelux script finished. Full report is in the Lua console.\n\n" .. table.concat(LOOB_tail, "\n"), 0)
Benelux script started - the game may freeze while it works...
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_AddUnit (0)  Error:The requested object has been deprecated in the database
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands unit destroyed)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium unit destroyed)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - apply points)!
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands decisive)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium decisive)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - end scenario)!
Scanning the database, this can take a minute or two...
Database scan: 5535 facility classes read (DBID 1-6000)
---- Units chosen from your database ----
  ammo          DBID 322   Ammo Bunker (Surface)
                other matches: 325 Ammo Bunker (Underground) | 1731 Ammo Bunker (Mountain)
  armor         DBID 117   Armored Plt (T-34/85 MBT x 4)
                other matches: 205 Armored Plt (T-72 MBT x 4) | 206 Armored Plt (T-80 MBT x 4) | 486 Armored Plt (T-80 MBT x 4) | 499 Armored Plt (T-72 MBT x 4) | 523 Armored Plt (M1 Abrams MBT x 4) | +338 more
  arty          DBID 222   Coastal Arty Bty (155mm/39 Tampella 155 K83 Towed Gun x 4)
                other matches: 682 Arty Bty (155mm/39 M109A3GN Self-Propelled Howitzer x 6) | 772 Arty Bty (155mm/39 GCT AUF1 Self-Propelled Howitzer) | 821 Arty Bty (155mm/45 G6 Self-Propelled Howitzer x 6) | 822 Arty Bty (155mm/45 G5 Towed Howitzer x6) | 1724 Arty Bty (155mm/52 T-155 Self-Propelled Firtina Howitzer x 6) | +140 more
  be_dingo      DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  be_lg1        DBID 330   Arty Bty/3 (105mm/37 L118 Towed Light Gun x 2)
                other matches: 366 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 410 Arty Bty (105mm/37 L118 Towed Light Gun x 6) | 1799 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 1800 Arty Bty (105mm/22 M101 Towed Howitzer x 6) | 1801 Arty Bty (105mm/32 M102 Towed Howitzer x 6) | +18 more
  be_pandur     DBID 2947  Motor Inf Plt (Pandur I APC x 4)
                other matches: 2948 Motor Inf Plt (Pandur I APC x 4) | 2949 Motor Inf Plt (Pandur II APC [12.5mm MMG] x 4) | 2950 Motor Inf Plt (Pandur II IFV [Steyr 30mm + SPIKE] x 4) | 4500 Motor Inf Plt (Pandur II IFV [Steyr 30mm + SPIKE] x 4) | 5177 Motor Inf Plt (Pandur I APC x 4) | +3 more
  be_paracdo    DBID 209   Inf Plt (British Paratroopers)
                other matches: 700 Inf Plt (Soviet Paratroopers) | 875 Inf Plt (Russian Paratroopers) | 2384 Inf Plt (Canadian Paratroopers) | 2796 Inf Plt (Paratrooper) | 3035 Inf Plt (Parachute Regiment) | +1 more
  be_piranha    DBID 2866  Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
                other matches: 4473 Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
  eng           DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  fuel          DBID 248   Support Plt (Helicopter Expeditionary Refueling System)
  hq            DBID 3730  Command Post
  inf           DBID 202   Inf Plt (Russian Army)
                other matches: 203 Inf Plt (Soviet Red Army) | 209 Inf Plt (British Paratroopers) | 212 Inf Plt (Chinese Naval Infantry) | 237 Inf Plt (Russian Spetsnaz Platoon [Generic Laser Designator]) | 240 Inf Plt (SAS Troop [Generic Laser Designator]) | +74 more
  mech          DBID 635   Mech Inf Plt (ZSD-89 [Type 89] APC x 4)
                other matches: 636 Mech Inf Plt (ZSD-63 [Type 63] APC x 4) | 637 Mech Inf Plt (ZSL-90 [Type 90] APC x 4) | 646 Mech Inf Plt (Soviet Red Army) | 670 Mech Inf Plt (United States Army) | 707 Mech Inf Plt (British Army) | +274 more
  mortar120     DBID 2058  Mortar Plt (120mm Mortar)
                other matches: 2059 Mortar Plt (120mm Mortar [STRIX]) | 2071 Arty Bty (120mm 2S9-S Nona-S Self-Propelled Mortar x 6) | 2072 Arty Bty (120mm 2S9-S Nona-S Self-Propelled Mortar x 6) | 2073 Arty Bty (120mm 2S9-1 Sviristelka Self-Propelled Mortar x 6) | 2074 Arty Bty (120mm 2S9-1 Sviristelka Self-Propelled Mortar x 6) | +20 more
  mortar81      DBID 2060  Mortar Plt (81mm Mortar)
                other matches: 3422 Mortar Plt (81mm Mortar) | 3697 Mortar Sec (81mm Mortar) | 3698 Mortar Sec (81mm Mortar) | 4547 Arty Bty (81mm Aras-2 Self-Propelled Mortar x 3)
  nl_airmobile  DBID 202   Inf Plt (Russian Army)   <- nothing specific found, using 'inf'
  nl_boxer      DBID 2316  Mech Inf Plt (Boxer APC x 3)
                other matches: 2878 Motor Inf Plt (Boxer APC x 4)
  nl_cv90       DBID 5095  Mech Inf Plt (CV 9035 x 4)
                other matches: 5096 Mech Inf Plt (CV 9035DK x 4) | 5097 Mech Inf Plt (CV 9035NL x 4) | 5098 Mech Inf Plt (CV 9035EE x 4)
  nl_fennek     DBID 614   Inf Sec (Recon)   <- nothing specific found, using 'recon'
  nl_leo2       DBID 2341  Armored Plt (Leopard 2A6 MBT x 3)
                other matches: 2381 Armored Plt (Leopard 2A6M MBT x 4) | 3848 Armored Plt (Leopard 2A6M MBT x 4) | 3920 Armored Plt (Leopard 2A6 MBT x 3)
  nl_marine     DBID 211   Inf Plt (British Royal Marines)
                other matches: 714 Inf Plt (US Marines) | 2319 Inf Plt (Marines) | 2404 Inf Plt (Indonesia Marines) | 2870 Inf Plt (Philippine Marines) | 2967 Inf Sec (Marine Force Recon Team [AN/PAQ-1 LTD]) | +4 more
  nl_pzh        DBID 2133  Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
                other matches: 2134 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 2978 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 3631 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 5079 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6) | 5088 Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
  recon         DBID 614   Inf Sec (Recon)
                other matches: 884 Inf Sec (US Navy SEAL Recon Team) | 1904 Inf Plt (Recon) | 1910 Inf Sec (US Navy SEAL Recon Team [AN/PAQ-1 LTD]) | 1943 Inf Sec (Spetsnaz GRU Recon Squad [Generic Laser Designator]) | 1947 Inf Sec (Spetsnaz Recon Squad [Generic Laser Designator]) | +10 more
  sam_nasams    DBID 147   Radar (AN/TPQ-36A [NASAMS])
                other matches: 204 SAM Plt (NASAMS) | 460 SAM Plt/2 (NASAMS II) | 579 Sensor (NTAS FLIR/LR [NASAMS]) | 653 SAM Plt/2 (NASAMS II) | 860 SAM Plt/2 (NASAMS II) | +29 more
  sam_patriot   DBID 294   SAM Bty (Patriot [PAC-2 GEM+, PAC-3 CRI])
                other matches: 1863 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2224 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2225 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2226 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | 2227 SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | +18 more
  sam_stinger   DBID 7     SAM Sec (Stinger MANPADS x 5)
                other matches: 14 SAM Sec (Stinger MANPADS x 5) | 64 SAM Sec (Stinger MANPADS x 5) | 242 SAM Sec (Stinger MANPADS x 5) | 268 SAM Sec (Stinger Dual MANPADS x 2) | 1264 SAM Sec (Stinger MANPADS x 5) | +21 more
  sof           DBID 835   Vehicle (Soft Ball ELS [KRTP-81 Ramona])
                other matches: 2519 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2520 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2521 Vehicle (Soft Ball ELS [KRTP-81 Ramona]) | 2522 Vehicle (Soft Ball ELS [KRTP-81M Ramona]) | 2523 Vehicle (Soft Ball ELS [KRTP-81M Ramona]) | +6 more
  supply        DBID 3098  Container Storage Park
---- Land units ----
  added 235, already present 0, failed 0, skipped (no DB match) 0
---- Scoring ----
  Netherlands: 320 units = 1000 points for the enemy if all are destroyed
      aircraft                              353 pts
      bases, radars and air defence          62 pts
      land forces (added by script)         437 pts
      other facilities                        1 pts
      ships                                 146 pts
  Belgium: 238 units = 1000 points for the enemy if all are destroyed
      aircraft                              409 pts
      bases, radars and air defence          65 pts
      land forces (added by script)         439 pts
      other facilities                        1 pts
      ships                                  87 pts
  event 'Loss scoring (zero-sum)' created. Open the Event Editor and check it is ticked as repeatable.
  Now set the thresholds for BOTH sides in the editor's scoring window:
  Disaster -1000 ... Triumph +1000 (e.g. -1000 / -400 / +400 / +1000).
Done.
...
07/10/2026 17:28:07 -- Bv1.10 - Build 1900.20 -- 
Console: 
local function try(f, ...) local ok, r = pcall(f, ...) if ok then return r end end
local out = {}
for _, s in pairs(VP_GetSides()) do
  local side = VP_GetSide({ side = s.name })
  local total, left, del = 0, 0, 0
  for _, ref in pairs(side.units) do
    total = total + 1
    if string.sub(tostring(ref.name), 1, 9) == "LOOB scan" then
      left = left + 1
      if try(ScenEdit_DeleteUnit, { side = s.name, guid = ref.guid })
         or try(ScenEdit_DeleteUnit, { side = s.name, unitname = ref.name }) then
        del = del + 1
      end
    end
  end
  out[#out + 1] = s.name .. ": " .. total .. " units, " .. left .. " scan leftovers, " .. del .. " deleted"
end
try(ScenEdit_RemoveSide, { side = "~LOOB scan" })
print(table.concat(out, "\n"))
Belgium: 238 units, 0 scan leftovers, 0 deleted
Netherlands: 320 units, 0 scan leftovers, 0 deleted
...
07/10/2026 18:04:27 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  INVENTORY (read-only) - changes nothing in the scenario
--  Run in Editor > Lua Script Console, then send back everything it prints.
-- =====================================================================
local SIDES = { "Netherlands", "Belgium" }

local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function s(v) if v == nil then return "-" end return tostring(v) end

local function dump(v, depth)
  depth = depth or 0
  if type(v) ~= "table" then return tostring(v) end
  if depth > 2 then return "{...}" end
  local parts, n = {}, 0
  for k, x in pairs(v) do
    n = n + 1
    if n > 25 then parts[#parts + 1] = "..." break end
    parts[#parts + 1] = tostring(k) .. "=" .. dump(x, depth + 1)
  end
  return "{" .. table.concat(parts, ", ") .. "}"
end

local function count(t)
  local n = 0
  if type(t) == "table" then for _, _ in pairs(t) do n = n + 1 end end
  return n
end

local function magSummary(u)
  local mags = prop(u, "magazines")
  local nm, nw, qty = 0, 0, 0
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      nm = nm + 1
      local w = prop(m, "weapons") or prop(m, "mag_weapons")
      if type(w) == "table" then
        for _, e in pairs(w) do
          nw = nw + 1
          qty = qty + (tonumber(prop(e, "wpn_current")) or 0)
        end
      end
    end
  end
  return nm, nw, qty
end

local function hostInfo(u)
  local b = prop(u, "base")
  if not b then return "-", "-", "-" end
  local g = prop(b, "group")
  return s(prop(b, "name")), s(prop(b, "classname")), s(prop(g, "name"))
end

local sampled = {}
local function sample(kind, u)
  if sampled[kind] then return end
  sampled[kind] = true
  say("FIELDS " .. kind .. " (" .. s(prop(u, "name")) .. "): " .. dump(prop(u, "fields")))
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      say("  MAG " .. dump(m))
      break
    end
  end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      say("  MOUNT " .. dump(m))
      break
    end
  end
end

local function main()
  say("BUILD " .. s(try(GetBuildNumber)))
  local scen = try(VP_GetScenario)
  say("SCENARIO " .. s(prop(scen, "Title")) .. " | DB " .. s(prop(scen, "DBUsed")) .. " | start " .. s(prop(scen, "StartTime")))
  for _, sideName in ipairs(SIDES) do
    local side = try(VP_GetSide, { side = sideName })
    say("==== SIDE " .. sideName .. (side and "" or " NOT FOUND"))
    if side then
      local air, ships, magFac, portFac, other = {}, {}, {}, {}, {}
      for _, ref in pairs(side.units) do
        local u = try(ScenEdit_GetUnit, { guid = ref.guid })
        if u then
          local t = s(prop(u, "type"))
          local cls = s(prop(u, "classname"))
          local dbid = s(prop(u, "dbid"))
          if t == "Aircraft" then
            sample("AIRCRAFT", u)
            local lo = try(ScenEdit_GetLoadout, { unitname = ref.guid, LoadoutID = 0 })
            local hn, hc, hg = hostInfo(u)
            local key = table.concat({ dbid, cls, s(prop(u, "loadoutdbid")), s(prop(lo, "name")), hn, hc, hg }, " | ")
            air[key] = (air[key] or 0) + 1
          elseif t == "Ship" or t == "Submarine" then
            sample(string.upper(t), u)
            local hn, hc, hg = hostInfo(u)
            local nm, nw, qty = magSummary(u)
            ships[#ships + 1] = table.concat({ t, dbid, cls, s(prop(u, "name")), "base: " .. hn, hc, hg,
              "mags " .. nm .. "/" .. nw .. " recs/" .. qty .. " wpns", "mounts " .. count(prop(u, "mounts")),
              "hosted " .. count(prop(u, "embarkedUnits")) }, " | ")
          else
            local nm, nw, qty = magSummary(u)
            local low = string.lower(cls)
            local g = s(prop(prop(u, "group"), "name"))
            if nm > 0 and not string.find(s(prop(u, "name")), "^%[") then
              sample("MAGAZINE FACILITY", u)
              magFac[#magFac + 1] = table.concat({ dbid, cls, s(prop(u, "name")), "group: " .. g,
                "mags " .. nm .. "/" .. nw .. " recs/" .. qty .. " wpns" }, " | ")
            end
            if string.find(low, "pier") or string.find(low, "dock") or string.find(low, "harbo")
               or string.find(low, "port") or string.find(low, "quay") or string.find(low, "berth")
               or string.find(low, "naval") then
              portFac[#portFac + 1] = table.concat({ dbid, cls, s(prop(u, "name")), "group: " .. g,
                "lat " .. s(prop(u, "latitude")), "lon " .. s(prop(u, "longitude")),
                "hosted " .. count(prop(u, "embarkedUnits")) }, " | ")
            end
            other[t .. " " .. cls] = (other[t .. " " .. cls] or 0) + 1
          end
        end
      end
      say("-- AIRCRAFT: count x dbid | class | loadout id | loadout | host | host class | host group")
      local keys = {}
      for k, _ in pairs(air) do keys[#keys + 1] = k end
      table.sort(keys)
      for _, k in ipairs(keys) do say("A " .. air[k] .. " x " .. k) end
      say("-- SHIPS / SUBMARINES")
      table.sort(ships)
      for _, l in ipairs(ships) do say("S " .. l) end
      say("-- FACILITIES WITH MAGAZINES")
      table.sort(magFac)
      for _, l in ipairs(magFac) do say("M " .. l) end
      say("-- PORT FACILITIES")
      table.sort(portFac)
      for _, l in ipairs(portFac) do say("P " .. l) end
      say("-- ALL OTHER UNIT CLASSES")
      keys = {}
      for k, _ in pairs(other) do keys[#keys + 1] = k end
      table.sort(keys)
      for _, k in ipairs(keys) do say("O " .. other[k] .. " x " .. k) end
    end
  end
  say("END OF INVENTORY")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
BUILD v1.10 - Build 1900.20
SCENARIO Belgium: Facilities and Units | DB DB3K_519.db3 | start 10/08/2021 4:39:23
==== SIDE Netherlands
FIELDS AIRCRAFT (No.7 #4): {property_9=.manualThrottle , Object , True , True, method_18=:getUnitMountMagazine , Command_Core.Lua.LuaWrapper_Device_Magazine, property_27=.beingPickedUp , Boolean , True , True, property_74=.desiredSpeed , Object , True , True, property_106=.outOfComms , Boolean , False , True, property_23=.obeyEMCON , Boolean , True , True, property_114=.noiseLevel , LuaTable , False , True, property_28=.pickUpTarget , LuaWrapper_ActiveUnit , True , True, method_5=:createUnitCargo , Command_Core.Lua.LuaWrapper_Cargo, property_107=.jammed , Boolean , False , True, property_59=.guid , String , False , True, method_12=:filterOnComponent , NLua.LuaTable, property_110=.crew , Int32 , False , True, property_89=.unitstate , String , False , True, property_33=.oldDamagePercent , Single , True , False, property_11=.course , LuaTable , True , True, property_66=.timeunderway , Object , False , True, property_73=.desiredAltitude , Object , True , True, property_3=.autodetectable , Boolean , True , True, property_56=.dbid , Int32 , False , True, property_72=.desiredHeading , Object , True , True, property_1=.latitude , Double , True , True, property_58=.SettledTime , Double , True , True, property_76=.desiredPitch , Single , True , True, property_38=.doctrine , LuaWrapper_Doctrine , False , True, ...}
  MAG {mag_name=Magazine for mount: Saphir-M x 2 [104 Cartridges], mag_guid=I8MHTP-0HNP4GVAGJDN2, mag_weapons={}, mag_capacity=0, mag_dbid=0}
  MOUNT {mount_name=Saphir-M x 2 [104 Cartridges], mount_guid=3ONU4R-0HMARMQSETA2I, mount_status=Operational, mount_dbid=2006, mount_weapons={1={wpn_name=Generic Chaff Salvo [4x Cartridges], wpn_maxcap=18, wpn_default=18, wpn_current=18, wpn_type=2005, wpn_guid=3ONU4R-0HMARMQSETA2K, wpn_dbid=524}, 2={wpn_name=Generic Flare Salvo [4x Cartridges, Dual Spectral], wpn_maxcap=8, wpn_default=8, wpn_current=8, wpn_type=2005, wpn_guid=3ONU4R-0HMARMQSETA2L, wpn_dbid=2050}}}
FIELDS SHIP (F 804 De Ruyter [De Zeven Provinciën]): {property_9=.autonomylevel , Object , True , True, method_18=:getUnitMountMagazine , Command_Core.Lua.LuaWrapper_Device_Magazine, property_27=.obeyEMCON , Boolean , True , True, property_74=.desiredAltitude , Object , True , True, property_106=.outOfComms , Boolean , False , True, property_23=.sprintDrift , Boolean , True , True, property_114=.noiseLevel , LuaTable , False , True, property_28=.sensors , LuaTable , True , True, method_5=:createUnitCargo , Command_Core.Lua.LuaWrapper_Cargo, property_107=.jammed , Boolean , False , True, property_59=.SettledTime , Double , True , True, method_12=:filterOnComponent , NLua.LuaTable, property_110=.crew , Int32 , False , True, property_89=.condition_v , String , False , True, property_33=.readytime , Object , True , True, property_11=.manualAltitude , Object , True , True, property_66=.airbornetime_v , Object , False , True, property_73=.desiredHeading , Object , True , True, property_3=.dbid , Int32 , False , True, property_56=.typeN , Int32 , False , True, property_72=.ascontact , LuaTable , False , True, property_1=.type , String , False , True, property_58=.category , String , False , True, property_76=.desiredRoll , Single , True , True, property_38=.roll , Single , True , True, ...}
  MAG {mag_name=12.7mm/50 MG, mag_guid=3ONU4R-0HMARMQSET9KN, mag_weapons={1={wpn_name=12.7mm/50 MG Burst [10 rnds], wpn_maxcap=200, wpn_default=200, wpn_current=200, wpn_guid=3ONU4R-0HMARMQSET9KO, wpn_dbid=1695}}, mag_capacity=200, mag_dbid=761}
  MOUNT {mount_name=12.7mm/50 MG, mount_guid=3ONU4R-0HMARMQSET9IP, mount_status=Operational, mount_dbid=561, mount_weapons={1={wpn_name=12.7mm/50 MG Burst [10 rnds], wpn_maxcap=10, wpn_default=10, wpn_current=10, wpn_type=2004, wpn_guid=3ONU4R-0HMARMQSET9IR, wpn_dbid=1695}}}
FIELDS MAGAZINE FACILITY (SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT])): {property_9=.autonomylevel , Object , True , True, method_18=:getUnitMountMagazine , Command_Core.Lua.LuaWrapper_Device_Magazine, property_27=.obeyEMCON , Boolean , True , True, property_74=.desiredAltitude , Object , True , True, property_106=.outOfComms , Boolean , False , True, property_23=.sprintDrift , Boolean , True , True, property_114=.noiseLevel , LuaTable , False , True, property_28=.sensors , LuaTable , True , True, method_5=:createUnitCargo , Command_Core.Lua.LuaWrapper_Cargo, property_107=.jammed , Boolean , False , True, property_59=.SettledTime , Double , True , True, method_12=:filterOnComponent , NLua.LuaTable, property_110=.crew , Int32 , False , True, property_89=.condition_v , String , False , True, property_33=.readytime , Object , True , True, property_11=.manualAltitude , Object , True , True, property_66=.airbornetime_v , Object , False , True, property_73=.desiredHeading , Object , True , True, property_3=.dbid , Int32 , False , True, property_56=.typeN , Int32 , False , True, property_72=.ascontact , LuaTable , False , True, property_1=.type , String , False , True, property_58=.category , String , False , True, property_76=.desiredRoll , Single , True , True, property_38=.roll , Single , True , True, ...}
  MAG {mag_name=Patriot, mag_guid=3ONU4R-0HMARMQSET90O, mag_weapons={1={wpn_name=MIM-104E Patriot PAC-2 GEM+, wpn_maxcap=12, wpn_default=12, wpn_current=12, wpn_guid=3ONU4R-0HMARMQSET90P, wpn_dbid=642}, 2={wpn_name=MIM-104F Patriot PAC-3 CRI, wpn_maxcap=16, wpn_default=16, wpn_current=16, wpn_guid=3ONU4R-0HMARMQSET90Q, wpn_dbid=1150}}, mag_capacity=28, mag_dbid=1432}
  MOUNT {mount_name=Patriot M901, mount_guid=3ONU4R-0HMARMQSET905, mount_status=Operational, mount_dbid=816, mount_weapons={1={wpn_name=MIM-104E Patriot PAC-2 GEM+, wpn_maxcap=4, wpn_default=4, wpn_current=4, wpn_type=2001, wpn_guid=3ONU4R-0HMARMQSET907, wpn_dbid=642}}}
-- AIRCRAFT: count x dbid | class | loadout id | loadout | host | host class | host group
A 1 x 2956 | Gulfstream G-IV SP | 0 | - | Eindhoven AB | Single-Unit Airfield (1x 2600-3200m, Runway) | -
A 49 x 3167 | F-16AM Falcon MLU | 0 | - | Volkel AB | Single-Unit Airfield (2x 2601-3200m Runways) | -
A 15 x 3902 | F-35A Lightning II | 0 | - | Leeuwarden AB | Single-Unit Airfield (2x 2001-2600m Runways) | -
A 4 x 3960 | MQ-9A Reaper UAV | 0 | - | Leeuwarden AB | Single-Unit Airfield (2x 2001-2600m Runways) | -
A 2 x 4067 | C-130H-30 Hercules | 0 | - | Eindhoven AB | Single-Unit Airfield (1x 2600-3200m, Runway) | -
A 2 x 4068 | C-130H Hercules | 0 | - | Eindhoven AB | Single-Unit Airfield (1x 2600-3200m, Runway) | -
A 12 x 4069 | AS.532U2 Cougar Mk2 | 0 | - | Gilze-Rijen AB | Single-Unit Airfield (2x 2001-2600m Runways) | -
A 20 x 4070 | CH-47F Chinook | 0 | - | Gilze-Rijen AB | Single-Unit Airfield (2x 2001-2600m Runways) | -
A 3 x 4708 | Airbus A.330-200 MRTT [MFF] | 0 | - | Eindhoven AB | Single-Unit Airfield (1x 2600-3200m, Runway) | -
A 28 x 4824 | AH-64D Apache | 0 | - | Gilze-Rijen AB | Single-Unit Airfield (2x 2001-2600m Runways) | -
A 20 x 656 | NH90 NFH | 0 | - | De Kooy Airfield | Single-Unit Airfield (1x 901-1400m Runway) | -
-- SHIPS / SUBMARINES
S Ship | 1726 | A 836 Amsterdam | A 833 Karel Doorman | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 9/5 recs/380 wpns | mounts 5 | hosted 2
S Ship | 2496 | P 840 Holland | P 840 Holland | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 14/4 recs/1260 wpns | mounts 10 | hosted 2
S Ship | 2496 | P 840 Holland | P 841 Zeeland | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 14/4 recs/1260 wpns | mounts 10 | hosted 2
S Ship | 2496 | P 840 Holland | P 842 Friesland | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 14/4 recs/1260 wpns | mounts 10 | hosted 2
S Ship | 2496 | P 840 Holland | P 843 Groningen | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 14/4 recs/1260 wpns | mounts 10 | hosted 2
S Ship | 2521 | F 802 De Zeven Provinciën | F 802 De Zeven Provinciën | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 20/7 recs/812 wpns | mounts 15 | hosted 2
S Ship | 2521 | F 802 De Zeven Provinciën | F 803 Tromp [De Zeven Provinciën] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 20/7 recs/812 wpns | mounts 15 | hosted 2
S Ship | 2521 | F 802 De Zeven Provinciën | F 804 De Ruyter [De Zeven Provinciën] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 20/7 recs/812 wpns | mounts 15 | hosted 2
S Ship | 2521 | F 802 De Zeven Provinciën | F 805 Evertsen [De Zeven Provinciën] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 20/7 recs/812 wpns | mounts 15 | hosted 2
S Ship | 2522 | F 827 Karel Doorman | F 831 Van Amstel [Karel Doorman] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 17/6 recs/378 wpns | mounts 12 | hosted 2
S Ship | 825 | L 800 Rotterdam [Enforcer] | L 800 Rotterdam [Rotterdam] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 15/5 recs/430 wpns | mounts 11 | hosted 2
S Ship | 825 | L 800 Rotterdam [Enforcer] | L 801 John de Witt [Rotterdam] | base: Nieuwu Haven NB (Den Helder) | Single-Unit Port | - | mags 15/5 recs/430 wpns | mounts 11 | hosted 2
-- FACILITIES WITH MAGAZINES
M 1594 | Single-Unit Airfield (1x 901-1400m Runway) | De Kooy Airfield | group: - | mags 1/0 recs/0 wpns
M 1713 | Single-Unit Airfield (2x 2001-2600m Runways) | Gilze-Rijen AB | group: - | mags 1/0 recs/0 wpns
M 1713 | Single-Unit Airfield (2x 2001-2600m Runways) | Leeuwarden AB | group: - | mags 1/0 recs/0 wpns
M 1714 | Single-Unit Airfield (2x 2601-3200m Runways) | Volkel AB | group: - | mags 1/0 recs/0 wpns
M 1877 | Single-Unit Airfield (1x 2600-3200m, Runway) | Eindhoven AB | group: - | mags 1/0 recs/0 wpns
M 2224 | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | group: - | mags 7/2 recs/28 wpns
M 2224 | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | group: - | mags 7/2 recs/28 wpns
M 2224 | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT]) | group: - | mags 7/2 recs/28 wpns
M 2980 | Single-Unit Port | Nieuwu Haven NB (Den Helder) | group: - | mags 1/0 recs/0 wpns
M 860 | SAM Plt/2 (NASAMS II) | SAM Plt/2 (NASAMS II) | group: - | mags 4/1 recs/12 wpns
M 860 | SAM Plt/2 (NASAMS II) | SAM Plt/2 (NASAMS II) | group: - | mags 4/1 recs/12 wpns
-- PORT FACILITIES
P 248 | Support Plt (Helicopter Expeditionary Refueling System) | [DEPOT] Bevoorradings- en Transportcommando Brandstof | group: - | lat 52.19601688825 | lon 5.7 | hosted 2
P 248 | Support Plt (Helicopter Expeditionary Refueling System) | [DEPOT] Logistiek Centrum Soesterberg Brandstof | group: - | lat 52.11601688825 | lon 5.285 | hosted 2
P 2980 | Single-Unit Port | Nieuwu Haven NB (Den Helder) | group: - | lat 52.954181354374 | lon 4.789451583778 | hosted 2
-- ALL OTHER UNIT CLASSES
O 6 x Facility Ammo Bunker (Surface)
O 3 x Facility Arty Bty (155mm/52 PzH 2000 Self-Propelled Howitzer x 6)
O 8 x Facility Command Post
O 8 x Facility Container Storage Park
O 19 x Facility Inf Plt (British Royal Marines)
O 39 x Facility Inf Plt (Russian Army)
O 8 x Facility Inf Sec (Recon)
O 18 x Facility Mech Inf Plt (Boxer APC x 3)
O 18 x Facility Mech Inf Plt (CV 9035 x 4)
O 1 x Facility Mortar Plt (120mm Mortar)
O 3 x Facility Mortar Plt (81mm Mortar)
O 2 x Facility Radar (Tall Rack [55Zh6M Nebo M, RLM-D L-Band])
O 3 x Facility SAM Bty (Patriot [PAC-2 GEM+, PAC-3 ERINT])
O 2 x Facility SAM Plt/2 (NASAMS II)
O 1 x Facility Single-Unit Airfield (1x 2600-3200m, Runway)
O 1 x Facility Single-Unit Airfield (1x 901-1400m Runway)
O 2 x Facility Single-Unit Airfield (2x 2001-2600m Runways)
O 1 x Facility Single-Unit Airfield (2x 2601-3200m Runways)
O 1 x Facility Single-Unit Port
O 2 x Facility Support Plt (Helicopter Expeditionary Refueling System)
O 6 x Facility Vehicle (Soft Ball ELS [KRTP-81 Ramona])
==== SIDE Belgium
-- AIRCRAFT: count x dbid | class | loadout id | loadout | host | host class | host group
A 13 x 1512 | A-109BA Agusta [HA, Anti-Armor] | 0 | - | Beauvechain AB | Single-Unit Airfield (2x 2601-3200m Runways) | -
A 13 x 2001 | RQ-5A Hunter-B UAV | 0 | - | Florennes AB | Single-Unit Airfield (3x 2601-3200m Runways) | -
A 7 x 2246 | C-130H Hercules | 4336 | Cargo, 19 tons | Melsbroek AB | Single-Unit Airfield (3x 3201-4000m Runways) | -
A 22 x 2248 | F-16AM Falcon MLU | 0 | - | Florennes AB | Single-Unit Airfield (3x 2601-3200m Runways) | -
A 22 x 2248 | F-16AM Falcon MLU | 0 | - | Kleine-Brogel AB | Single-Unit Airfield (2x 2601-3200m Runways) | -
A 8 x 2356 | NH90 TTH | 13593 | Cargo, 4 tons, Slung Load | Koksijde AB | Single-Unit Airfield (1x 2001-2600m Runway) | -
A 1 x 2549 | Airbus A.321-200 | 9952 | Passengers, 199x, 19.9 tons | Melsbroek AB | Single-Unit Airfield (3x 3201-4000m Runways) | -
A 8 x 3263 | F-16BM Falcon MLU | 0 | - | Kleine-Brogel AB | Single-Unit Airfield (2x 2601-3200m Runways) | -
A 32 x 4416 | SF.260EA [T-260B] | 22400 | Training | Beauvechain AB | Single-Unit Airfield (2x 2601-3200m Runways) | -
-- SHIPS / SUBMARINES
S Ship | 2132 | M 915 Aster [Flower, Tripartite Class] | M 916 Bellis [Tripartite Class] | base: Zeebrugge NB | Single-Unit Port | - | mags 5/1 recs/300 wpns | mounts 4 | hosted 2
S Ship | 2132 | M 915 Aster [Flower, Tripartite Class] | M 917 Crocus [Tripartite Class] | base: Zeebrugge NB | Single-Unit Port | - | mags 5/1 recs/300 wpns | mounts 4 | hosted 2
S Ship | 2132 | M 915 Aster [Flower, Tripartite Class] | M 921 Lobella [Tripartite Class] | base: Zeebrugge NB | Single-Unit Port | - | mags 5/1 recs/300 wpns | mounts 4 | hosted 2
S Ship | 2132 | M 915 Aster [Flower, Tripartite Class] | M 923 Narcis [Tripartite Class] | base: Zeebrugge NB | Single-Unit Port | - | mags 5/1 recs/300 wpns | mounts 4 | hosted 2
S Ship | 2132 | M 915 Aster [Flower, Tripartite Class] | M 924 Primula [Tripartite Class] | base: Zeebrugge NB | Single-Unit Port | - | mags 5/1 recs/300 wpns | mounts 4 | hosted 2
S Ship | 2737 | F 930 Leopold I [Karel Doorman] | F 930 Leopold I [Karel Doorman] | base: Zeebrugge NB | Single-Unit Port | - | mags 17/6 recs/378 wpns | mounts 12 | hosted 2
S Ship | 2737 | F 930 Leopold I [Karel Doorman] | F 931 Louise-Marie [Karel Doorman] | base: Zeebrugge NB | Single-Unit Port | - | mags 17/6 recs/378 wpns | mounts 12 | hosted 2
-- FACILITIES WITH MAGAZINES
M 1712 | Single-Unit Airfield (1x 2001-2600m Runway) | Koksijde AB | group: - | mags 1/0 recs/0 wpns
M 1714 | Single-Unit Airfield (2x 2601-3200m Runways) | Beauvechain AB | group: - | mags 1/0 recs/0 wpns
M 1714 | Single-Unit Airfield (2x 2601-3200m Runways) | Kleine-Brogel AB | group: - | mags 1/0 recs/0 wpns
M 2414 | Single-Unit Airfield (3x 2601-3200m Runways) | Florennes AB | group: - | mags 1/0 recs/0 wpns
M 2415 | Single-Unit Airfield (3x 3201-4000m Runways) | Melsbroek AB | group: - | mags 1/0 recs/0 wpns
M 2980 | Single-Unit Port | Zeebrugge NB | group: - | mags 1/0 recs/0 wpns
-- PORT FACILITIES
P 248 | Support Plt (Helicopter Expeditionary Refueling System) | [DEPOT] Logistiek depot Peutie Brandstof | group: - | lat 50.91601688825 | lon 4.455 | hosted 2
P 2980 | Single-Unit Port | Zeebrugge NB | group: - | lat 51.337350573941 | lon 3.199462455593 | hosted 2
-- ALL OTHER UNIT CLASSES
O 4 x Facility Ammo Bunker (Surface)
O 2 x Facility Arty Bty/3 (105mm/37 L118 Towed Light Gun x 2)
O 3 x Facility Command Post
O 6 x Facility Container Storage Park
O 18 x Facility Inf Plt (British Paratroopers)
O 22 x Facility Inf Plt (Russian Army)
O 27 x Facility Mech Inf Plt (Piranha 3H [12.7mm/50 M2 MG] x 4)
O 2 x Facility Mortar Plt (120mm Mortar)
O 9 x Facility Motor Inf Plt (Pandur I APC x 4)
O 2 x Facility Radar (Generic Air Traffic Control)
O 1 x Facility Radar (S-723)
O 1 x Facility Single-Unit Airfield (1x 2001-2600m Runway)
O 2 x Facility Single-Unit Airfield (2x 2601-3200m Runways)
O 1 x Facility Single-Unit Airfield (3x 2601-3200m Runways)
O 1 x Facility Single-Unit Airfield (3x 3201-4000m Runways)
O 1 x Facility Single-Unit Port
O 1 x Facility Support Plt (Helicopter Expeditionary Refueling System)
O 2 x Facility Vehicle (Soft Ball ELS [KRTP-81 Ramona])
END OF INVENTORY
...
07/10/2026 18:26:36 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX WAR READINESS
--  Command: Modern Operations 1.10 (build 1900.20), DB3K_519
--  Run from Editor > Lua Script Console.  SAVE A COPY OF THE SCENARIO FIRST.
-- =====================================================================
--  All IDs below were read from your DB3K_519 database and your inventory.
--  Phases (each can be switched off in CONFIG.PHASES):
--   1 swaps     replace stand-in land units with the closest real entry
--   2 loadouts  give aircraft combat loadouts, armed and ready
--   3 airbases  stock each airfield with sortie reloads for its aircraft
--   4 topup     fill every ship / SAM / land unit weapon record to maximum
--   5 landmags  give each land combat unit its own magazine with one extra
--               basic load of exactly the ammunition its weapons fire
--   6 trucks    ammo truck platoons with each garrison, pre-loaded
--   7 depots    fill the [DEPOT] ammo bunkers
--   8 ports     stock each naval base with reloads for the ships homed there
--   9 scoring   (re)build the zero-sum loss scoring so that each side's whole
--               force, including everything added above, is worth 1000 points
--  Phase 1b (airdefence) adds Belgian Mistral platoons at airfields, the port
--  and the two brigade garrisons.
--
--  The functions this script has never used in your build (stocking a
--  magazine, adding a magazine, deleting a unit) are each checked on the
--  first unit by reading the result back. If a check fails, that phase
--  stops and says so; nothing is done blind.
--  Stock phases refuse to run twice (that would double the stocks) unless
--  ALLOW_REPEAT = true.
-- =====================================================================

local CONFIG = {
  SIDES = { "Netherlands", "Belgium" },
  PHASES = { swaps = true, airdefence = true, loadouts = true, airbases = true, topup = true,
             landmags = true, trucks = true, depots = true, ports = true, scoring = true },

  SORTIES_PER_AIRCRAFT = 6,     -- reloads of its loadout stocked at the home airfield
  TRANSPORT_SORTIES    = 2,     -- same, for troop / cargo / passenger loads
  LAND_EXTRA_LOADS     = 1,     -- basic loads in each land unit's own magazine
  TRUCK_LOADS          = 2,     -- basic loads of the garrison carried by its ammo trucks
  DEPOT_LOADS          = 3,     -- basic loads of the whole army spread over its ammo bunkers
  PORT_RELOADS         = 2,     -- full reloads per ship stocked at its naval base
  ALLOW_REPEAT         = false,

  SCORE_SCALE     = 1000,       -- total value of each side's force
  END_SCENARIO_AT = nil,        -- e.g. 600 = end the game when a side reaches +600
}

-- extra air defence: one platoon beside every airfield and port of the side, plus the listed points
local AIR_DEFENCE = {
  Belgium = {
    dbid = 1664,                -- SAM Plt (Mistral ATLAS), Belgium
    label = "Mistral",
    extra = {
      { name = "Leopoldsburg", lat = 51.117, lon = 5.257 },
      { name = "Marche-en-Famenne", lat = 50.245, lon = 5.325 },
    },
  },
}

-- aircraft DBID -> loadout IDs, dealt out in turn to the aircraft of that type
local LOADOUTS = {
  -- Netherlands
  [3167] = { 16877, 16898, 16877, 19854 },  -- F-16AM: AIM-120B air-to-air / GBU-49 strike / air-to-air / SDB
  [3902] = { 19576, 21735, 19576, 19583 },  -- F-35A: AIM-120C-7 internal / SDB / air-to-air / JDAM
  [4824] = { 5816, 5815 },                  -- AH-64D: Hellfire + rockets / Hellfire only
  [656]  = { 5764, 5764, 15377 },           -- NH90 NFH: ASW torpedoes + sonobuoys / maritime surveillance
  [3960] = { 19856 },                       -- MQ-9A: recon
  [4067] = { 20185 }, [4068] = { 20185 },   -- C-130H: cargo
  [4069] = { 20191 },                       -- Cougar: troops
  [4070] = { 20198 },                       -- CH-47F: troops
  [4708] = { 30311 },                       -- A330 MRTT: tanker
  [2956] = { 15778 },                       -- Gulfstream: passengers
  -- Belgium
  -- Belgian fighters get the AIM-120D on purpose (later than the scenario date) to offset
  -- the Dutch advantage in numbers, radar and SAMs. For the period-correct AIM-120B use 15507.
  [2248] = { 32301, 5385, 32301, 11259 },   -- F-16AM: AIM-120D air-to-air / GBU-12 strike / air-to-air / JDAM
  [3263] = { 32301, 5385, 32301, 11259 },   -- F-16BM: same
  [1512] = { 247, 247, 15946 },             -- A-109BA: TOW / TOW / scout
  [2001] = { 8870 },                        -- RQ-5A: recon
}

-- loadout ID -> stores it needs: { weapon DBID, quantity }
local LOADOUT_STORES = {
  [16877] = { {446,4}, {1763,2}, {2780,2}, {149,1}, {544,1} },
  [16898] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {2061,2} },
  [19854] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {484,8} },
  [19576] = { {718,4} },
  [21735] = { {484,8}, {718,2} },
  [19583] = { {554,2}, {718,2} },
  [5816]  = { {683,8}, {1929,38} },
  [5815]  = { {683,16} },
  [5764]  = { {1647,2}, {2478,34}, {2481,16} },
  [247]   = { {833,8} },
  [15507] = { {446,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  [32301] = { {51,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  -- transports: troops / cargo / passengers (stocked for TRANSPORT_SORTIES only)
  [20185] = { {2611,1} }, [20191] = { {801,20} }, [20198] = { {801,33} }, [15778] = { {2624,18} },
  [5385]  = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {1906,2} },
  [11259] = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {93,2} },
}

-- land unit swaps: current class name -> replacement facility DBID per side
local SWAPS = {
  Netherlands = {
    ["Inf Plt (Russian Army)"]                 = 550,   -- Inf Plt (German Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 3244, -- Inf Sec (Kommando Spezialkraefte)
    ["Mech Inf Plt (Boxer APC x 3)"]           = 2878,  -- Motor Inf Plt (Boxer APC x 4), Netherlands
    ["Mech Inf Plt (CV 9035 x 4)"]             = 5097,  -- Mech Inf Plt (CV 9035NL x 4)
  },
  Belgium = {
    ["Inf Plt (Russian Army)"]                 = 2317,  -- Inf Plt (French Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 2724, -- Inf Sec (COS Recon)
    ["Motor Inf Plt (Pandur I APC x 4)"]       = 2948,  -- the Belgian Pandur entry
  },
}

local GENERIC_MAGAZINE_DBID = 1423   -- "Generic Magazine", capacity 10000, empty
local AMMO_TRUCK_DBID       = 2086   -- "Vehicles (Ammo Truck x 4)"
local TRANSPORT_STORES = { [801] = true, [2611] = true, [2624] = true }   -- Trooper, Cargo, Passenger
local COMBAT_TAGS = { "[INF]", "[MECH]", "[ARTY]", "[RECON]", "[ENG]", "[SOF]", "[ARMOR]" }

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function num(v) return tonumber(v) or 0 end
local function getUnit(guid) return try(ScenEdit_GetUnit, { guid = guid }) end
local function key(k) return try(ScenEdit_GetKeyValue, "LOOB2_" .. k) or "" end
local function setKey(k) try(ScenEdit_SetKeyValue, "LOOB2_" .. k, "yes") end
local function done(k)
  return (not CONFIG.ALLOW_REPEAT) and key(k) == "yes"
end

local function isSmallArms(name)
  local n = string.lower(tostring(name or ""))
  return string.find(n, "mg burst", 1, true) or string.find(n, "minigun", 1, true)
      or string.find(n, "rifle", 1, true) or string.find(n, "ar burst", 1, true)
end

local function hasTag(name)
  for _, t in ipairs(COMBAT_TAGS) do
    if string.sub(tostring(name), 1, #t) == t then return true end
  end
  return false
end

-- ---- reading magazines and mounts (field names taken from your inventory) ----
local function realMagazine(u)            -- the unit's real magazine (not a mount's own reload bin)
  local best
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then
        if not best or num(m.mag_capacity) > num(best.mag_capacity) then best = m end
      end
    end
  end
  return best
end

local function magRecord(mag, wpn)
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do
      if num(w.wpn_dbid) == wpn then return w end
    end
  end
  return nil
end

local function magUsed(mag)
  local n = 0
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do n = n + num(w.wpn_current) end
  end
  return n
end

local function unitTotal(u)               -- every round on the unit, mounts + magazines
  local n = 0
  local mags = prop(u, "magazines")
  if type(mags) == "table" then for _, m in pairs(mags) do n = n + magUsed(m) end end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do n = n + num(w.wpn_current) end
      end
    end
  end
  return n
end

-- one full load of the unit: weapon DBID -> { n = quantity at maximum, name = ... }
local function fullLoad(u, includeMagazines)
  local load = {}
  local function add(w)
    local id = num(w.wpn_dbid)
    if id ~= 0 and num(w.wpn_maxcap) > 0 then
      if not load[id] then load[id] = { n = 0, name = tostring(w.wpn_name) } end
      load[id].n = load[id].n + num(w.wpn_maxcap)
    end
  end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then for _, w in pairs(m.mount_weapons) do add(w) end end
    end
  end
  if includeMagazines then
    local mags = prop(u, "magazines")
    if type(mags) == "table" then
      for _, m in pairs(mags) do
        if type(m.mag_weapons) == "table" then for _, w in pairs(m.mag_weapons) do add(w) end end
      end
    end
  end
  return load
end

local function mergeLoad(into, load, times)
  for id, e in pairs(load) do
    if not into[id] then into[id] = { n = 0, name = e.name } end
    into[id].n = into[id].n + e.n * (times or 1)
  end
end

-- ---- stocking a magazine, with a read-back check on first use ----
local stockVariant = nil     -- which argument form works in this build
local stockBroken = false

local function stockCall(variant, guid, magGuid, wpn, n, cap)
  local t = { guid = guid, wpn_dbid = wpn, number = n, new = true }
  if variant == 1 or variant == 3 then t.mag_guid = magGuid end
  if variant == 1 or variant == 2 then t.maxcap = cap end
  return try(ScenEdit_AddWeaponToUnitMagazine, t)
end

local function stock(guid, wpn, n)        -- returns quantity actually added
  n = math.floor(n)
  if n <= 0 or stockBroken then return 0 end
  local u = getUnit(guid)
  local mag = u and realMagazine(u)
  if not mag then return 0 end
  local rec = magRecord(mag, wpn)
  local before = rec and num(rec.wpn_current) or 0
  local cap = math.max(rec and num(rec.wpn_maxcap) or 0, before + n)
  if stockVariant then
    stockCall(stockVariant, guid, mag.mag_guid, wpn, n, cap)
    return n
  end
  for v = 1, 4 do                          -- first use: find the form that works
    stockCall(v, guid, mag.mag_guid, wpn, n, cap)
    local u2 = getUnit(guid)
    local rec2 = u2 and magRecord(realMagazine(u2), wpn)
    local after = rec2 and num(rec2.wpn_current) or 0
    if after > before then
      stockVariant = v
      return after - before
    end
  end
  stockBroken = true
  say("  !! CHECK FAILED: could not add weapons to a magazine in this build (ScenEdit_AddWeaponToUnitMagazine).")
  say("     All stocking phases are skipped. Tell me this line and I will use another method.")
  return 0
end

-- fill a magazine from a load table, most important ammunition first, within capacity
local function stockLoad(guid, load, times)
  local u = getUnit(guid)
  local mag = u and realMagazine(u)
  if not mag then return 0, 0 end
  local room = num(mag.mag_capacity) - magUsed(mag)
  if num(mag.mag_capacity) <= 0 then room = 100000 end
  local order = {}
  for id, e in pairs(load) do order[#order + 1] = { id = id, n = e.n * (times or 1), small = (isSmallArms(e.name) or TRANSPORT_STORES[id]) and 1 or 0 } end
  table.sort(order, function(a, b)
    if a.small ~= b.small then return a.small < b.small end
    return a.id < b.id
  end)
  local added, cut = 0, 0
  for _, o in ipairs(order) do
    local want = math.floor(o.n)
    local give = math.min(want, math.max(room, 0))
    if give > 0 then
      local got = stock(guid, o.id, give)
      added = added + got
      room = room - give
    end
    cut = cut + (want - give)
  end
  return added, cut
end

-- ---- collecting units ----
local function collect(sideName)
  local side = try(VP_GetSide, { side = sideName })
  local r = { air = {}, ships = {}, land = {}, bunkers = {}, others = {} }
  if not side then return nil end
  for _, ref in pairs(side.units) do
    local u = getUnit(ref.guid)
    if u then
      local t = tostring(prop(u, "type"))
      local name = tostring(prop(u, "name"))
      local cls = tostring(prop(u, "classname"))
      local e = { guid = ref.guid, name = name, cls = cls, dbid = num(prop(u, "dbid")),
                  lat = num(prop(u, "latitude")), lon = num(prop(u, "longitude")) }
      if t == "Aircraft" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.air[#r.air + 1] = e
      elseif t == "Ship" or t == "Submarine" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.ships[#r.ships + 1] = e
      elseif t == "Facility" then
        if hasTag(name) then
          r.land[#r.land + 1] = e
        elseif string.sub(name, 1, 7) == "[DEPOT]" and string.find(cls, "Ammo", 1, true) then
          r.bunkers[#r.bunkers + 1] = e
        else
          r.others[#r.others + 1] = e
        end
      end
    end
  end
  local byName = function(a, b) return a.name < b.name end
  table.sort(r.air, byName) table.sort(r.ships, byName) table.sort(r.land, byName) table.sort(r.bunkers, byName)
  return r
end

-- ---- scoring (zero-sum, each side scaled to SCORE_SCALE) ----
-- The weights exist twice: as text (stored inside the scoring event) and as
-- real code (used now). If you change the values, change BOTH copies.
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"
local function scoreKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = LS_weight
  local problems = 0

  say("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      say("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      scoreKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      scoreKey(KEY .. "scale_" .. side, scale)
      say(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        say(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    scoreKey(KEY .. "lost_" .. side, 0)
  end
  scoreKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    say("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      say("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    say("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    say("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    say("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  say("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  say("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- ============================ phases ============================
local function phaseAirDefence(sideName, r)
  local ad = AIR_DEFENCE[sideName]
  if not ad then return end
  local spots = {}
  for _, e in ipairs(r.others) do
    if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true) then
      spots[#spots + 1] = { name = e.name, lat = e.lat, lon = e.lon }
    end
  end
  for _, x in ipairs(ad.extra or {}) do spots[#spots + 1] = x end
  local made, existed, failed = 0, 0, 0
  for _, sp in ipairs(spots) do
    local name = "[AD] " .. ad.label .. " " .. sp.name
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    elseif try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = ad.dbid,
                                   latitude = sp.lat + 0.008, longitude = sp.lon - 0.012 }) then
      made = made + 1
    else
      failed = failed + 1
    end
  end
  say("  air defence: " .. made .. " " .. ad.label .. " platoons placed, " .. existed .. " already there, " .. failed .. " failed")
end

local function phaseSwaps(sideName, r)
  local map = SWAPS[sideName]
  if not map then return end
  local okN, failN, checked = 0, 0, false
  for _, e in ipairs(r.land) do
    local target = map[e.cls]
    if target and e.dbid ~= target then
      try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
      if not checked then
        checked = true
        if getUnit(e.guid) then
          say("  !! CHECK FAILED: could not delete a unit, so no land units were swapped on this side.")
          return
        end
      end
      local nu = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = target,
                                         latitude = e.lat, longitude = e.lon })
      if nu then
        okN = okN + 1
      else
        failN = failN + 1
        local back = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = e.dbid,
                                             latitude = e.lat, longitude = e.lon })
        say("  could not create DBID " .. target .. " for '" .. e.name .. "'" .. (back and " - original restored" or " - UNIT LOST, re-add it by hand"))
      end
    end
  end
  say("  swaps: " .. okN .. " land units replaced, " .. failN .. " failed")
end

local function phaseLoadouts(sideName, r)
  local dealt, setN, failN, kept = {}, 0, 0, 0
  for _, e in ipairs(r.air) do
    local list = LOADOUTS[e.dbid]
    if list then
      dealt[e.dbid] = (dealt[e.dbid] or 0) + 1
      local want = list[((dealt[e.dbid] - 1) % #list) + 1]
      try(ScenEdit_SetLoadout, { unitname = e.guid, LoadoutID = want, TimeToReady_Minutes = 0, IgnoreMagazines = true })
      local u = getUnit(e.guid)
      if u and num(prop(u, "loadoutdbid")) == want then
        setN = setN + 1
        e.loadout = want
      else
        failN = failN + 1
        e.loadout = u and num(prop(u, "loadoutdbid")) or 0
      end
    else
      kept = kept + 1
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
  end
  say("  loadouts: " .. setN .. " aircraft armed, " .. failN .. " failed, " .. kept .. " left as they were")
end

local function phaseAirbases(sideName, r)
  if done("air_" .. sideName) then say("  airbases: already stocked by an earlier run - skipped") return end
  local bases = {}
  for _, e in ipairs(r.air) do
    if e.loadout == nil then
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
    local stores = LOADOUT_STORES[e.loadout]
    if e.base and stores then
      if not bases[e.base] then bases[e.base] = { name = e.baseName, load = {} } end
      for _, s in ipairs(stores) do
        local l = bases[e.base].load
        if not l[s[1]] then l[s[1]] = { n = 0, name = "" } end
        l[s[1]].n = l[s[1]].n + s[2] * (TRANSPORT_STORES[s[1]] and CONFIG.TRANSPORT_SORTIES or CONFIG.SORTIES_PER_AIRCRAFT)
      end
    end
  end
  for guid, b in pairs(bases) do
    local added, cut = stockLoad(guid, b.load, 1)
    say("  airbase " .. tostring(b.name) .. ": " .. added .. " stores added" .. ((cut > 0) and (", " .. cut .. " did not fit") or ""))
  end
  if not stockBroken then setKey("air_" .. sideName) end
end

local function topUpUnit(guid)
  local u = getUnit(guid)
  if not u then return 0 end
  local before = unitTotal(u)
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do
          if num(w.wpn_current) < num(w.wpn_maxcap) then
            try(ScenEdit_AddReloadsToUnit, { guid = guid, mount_guid = m.mount_guid, wpn_dbid = num(w.wpn_dbid), fillout = true })
          end
        end
      end
    end
  end
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 and type(m.mag_weapons) == "table" then
        for _, w in pairs(m.mag_weapons) do
          if num(w.wpn_default) > 0 and num(w.wpn_current) < num(w.wpn_default) then
            try(ScenEdit_AddWeaponToUnitMagazine, { guid = guid, mag_guid = m.mag_guid, wpn_dbid = num(w.wpn_dbid),
                                                    number = num(w.wpn_default) - num(w.wpn_current) })
          end
        end
      end
    end
  end
  local u2 = getUnit(guid)
  return (u2 and unitTotal(u2) or before) - before
end

local function phaseTopUp(sideName, r)
  local gained, n = 0, 0
  for _, list in ipairs({ r.ships, r.land, r.others }) do
    for _, e in ipairs(list) do
      local g = topUpUnit(e.guid)
      if g > 0 then gained = gained + g n = n + 1 end
    end
  end
  say("  top-up: " .. n .. " units were below maximum, " .. gained .. " rounds added")
end

local magBroken = false
local function phaseLandMags(sideName, r)
  local addedMag, had, stocked, failed = 0, 0, 0, 0
  for _, e in ipairs(r.land) do
    if magBroken then break end
    local u = getUnit(e.guid)
    if u then
      if realMagazine(u) then
        had = had + 1
      else
        try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        u = getUnit(e.guid)
        if not (u and realMagazine(u)) then
          try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine_only", dbid = GENERIC_MAGAZINE_DBID })
          u = getUnit(e.guid)
        end
        if u and realMagazine(u) then
          addedMag = addedMag + 1
          local got = stockLoad(e.guid, fullLoad(u, false), CONFIG.LAND_EXTRA_LOADS)
          stocked = stocked + got
        else
          failed = failed + 1
          if addedMag == 0 then
            magBroken = true
            say("  !! CHECK FAILED: could not add a magazine to '" .. e.name .. "' (ScenEdit_UpdateUnit add_magazine).")
            say("     Land units keep only what they carry. Tell me this line and I will try another method.")
          end
        end
      end
    end
  end
  say("  land magazines: " .. addedMag .. " units given a magazine (" .. stocked .. " rounds), "
      .. had .. " already had one, " .. failed .. " failed")
end

local function clusters(r)
  local cl = {}
  for _, e in ipairs(r.land) do
    local k = math.floor(e.lat * 10 + 0.5) .. "," .. math.floor(e.lon * 10 + 0.5)
    if not cl[k] then cl[k] = { units = {}, lat = 0, lon = 0 } end
    local c = cl[k]
    c.units[#c.units + 1] = e
    c.lat = c.lat + e.lat
    c.lon = c.lon + e.lon
  end
  local list = {}
  for k, c in pairs(cl) do
    if #c.units >= 3 then
      c.key = k
      c.lat = c.lat / #c.units
      c.lon = c.lon / #c.units
      list[#list + 1] = c
    end
  end
  table.sort(list, function(a, b) return a.key < b.key end)
  return list
end

local function phaseTrucks(sideName, r)
  local made, existed, rounds = 0, 0, 0
  for i, c in ipairs(clusters(r)) do
    local name = "[SUPPLY] Ammo trucks " .. i
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local t = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = AMMO_TRUCK_DBID,
                                        latitude = c.lat + 0.004, longitude = c.lon + 0.006 })
      if t then
        made = made + 1
        local load = {}
        for _, e in ipairs(c.units) do
          local u = getUnit(e.guid)
          if u then mergeLoad(load, fullLoad(u, false), 1) end
        end
        rounds = rounds + stockLoad(t.guid, load, CONFIG.TRUCK_LOADS)
      end
    end
  end
  say("  ammo trucks: " .. made .. " platoons placed (" .. rounds .. " rounds loaded), " .. existed .. " already there")
end

local function phaseDepots(sideName, r)
  if done("depot_" .. sideName) then say("  depots: already filled by an earlier run - skipped") return end
  if #r.bunkers == 0 then say("  depots: no [DEPOT] ammo bunkers found") return end
  local load = {}
  for _, e in ipairs(r.land) do
    local u = getUnit(e.guid)
    if u then mergeLoad(load, fullLoad(u, false), 1) end
  end
  local total, cutAll = 0, 0
  for _, b in ipairs(r.bunkers) do
    local added, cut = stockLoad(b.guid, load, CONFIG.DEPOT_LOADS / #r.bunkers)
    total = total + added
    cutAll = cutAll + cut
  end
  say("  depots: " .. #r.bunkers .. " ammo bunkers filled with " .. total .. " rounds"
      .. ((cutAll > 0) and (" (" .. cutAll .. " small-arms/low-priority rounds did not fit)") or ""))
  if not stockBroken then setKey("depot_" .. sideName) end
end

local function phasePorts(sideName, r)
  if done("port_" .. sideName) then say("  ports: already stocked by an earlier run - skipped") return end
  local ports, homeless = {}, 0
  for _, e in ipairs(r.ships) do
    if e.base then
      if not ports[e.base] then ports[e.base] = { name = e.baseName, load = {}, n = 0 } end
      local u = getUnit(e.guid)
      if u then
        mergeLoad(ports[e.base].load, fullLoad(u, true), 1)
        ports[e.base].n = ports[e.base].n + 1
      end
    else
      homeless = homeless + 1
    end
  end
  for guid, p in pairs(ports) do
    local added, cut = stockLoad(guid, p.load, CONFIG.PORT_RELOADS)
    say("  port " .. tostring(p.name) .. ": reloads for " .. p.n .. " ships, " .. added .. " rounds added"
        .. ((cut > 0) and (", " .. cut .. " low-priority rounds did not fit") or ""))
  end
  if homeless > 0 then say("  " .. homeless .. " ships have no home base - no port stock added for them") end
  if not stockBroken then setKey("port_" .. sideName) end
end

-- ============================== main ==============================
local function main()
  say("Benelux war readiness - build " .. tostring(try(GetBuildNumber)))
  local P = CONFIG.PHASES
  for _, sideName in ipairs(CONFIG.SIDES) do
    local r = collect(sideName)
    if not r then
      say("==== " .. sideName .. ": side not found - skipped")
    else
      say("==== " .. sideName .. ": " .. #r.air .. " aircraft, " .. #r.ships .. " ships, " .. #r.land
          .. " land combat units, " .. #r.bunkers .. " ammo bunkers")
      if P.swaps then
        phaseSwaps(sideName, r)
        r = collect(sideName)            -- swapped units have new IDs
      end
      if P.airdefence then
        phaseAirDefence(sideName, r)
        r = collect(sideName)            -- include the new platoons in the later steps
      end
      if P.loadouts then phaseLoadouts(sideName, r) end
      if P.airbases then phaseAirbases(sideName, r) end
      if P.topup then phaseTopUp(sideName, r) end
      if P.landmags then phaseLandMags(sideName, r) end
      if P.trucks then phaseTrucks(sideName, r) end
      if P.depots then phaseDepots(sideName, r) end
      if P.ports then phasePorts(sideName, r) end
    end
  end
  if P.scoring then
    if #CONFIG.SIDES == 2 then
      setupScoring(CONFIG.SIDES[1], CONFIG.SIDES[2])
    else
      say("Scoring needs exactly two sides in CONFIG.SIDES - skipped")
    end
  end
  say("Finished. Check one airfield, one platoon and one port in the editor before saving.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GRSQLP6U
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GRSQLS3J
... 
Function:ScenEdit_AddUnit (0)  Error:Attempted to place facility: [AD] Mistral Zeebrugge NB (Class: SAM Plt (Mistral ATLAS) - DBID: 1664) at coordinates: Lat: 51,3453505739414 - Lon: 3,18746245559302 . This point appears to be underwater. Placement aborted!
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands decisive)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium decisive)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - end scenario)!
Benelux war readiness - build v1.10 - Build 1900.20
==== Netherlands: 156 aircraft, 12 ships, 115 land combat units, 6 ammo bunkers
  swaps: 81 land units replaced, 0 failed
  loadouts: 156 aircraft armed, 0 failed, 0 left as they were
  airbase Volkel AB: 3372 stores added
  airbase Eindhoven AB: 44 stores added
  airbase Gilze-Rijen AB: 7008 stores added
  airbase Leeuwarden AB: 504 stores added
  airbase De Kooy Airfield: 4368 stores added
  top-up: 29 units were below maximum, 8104 rounds added
  land magazines: 115 units given a magazine (51736 rounds), 0 already had one, 0 failed
  ammo trucks: 10 platoons placed (67716 rounds loaded), 0 already there
  depots: 6 ammo bunkers filled with 60000 rounds (95208 small-arms/low-priority rounds did not fit)
  port Nieuwu Haven NB (Den Helder): reloads for 12 ships, 10000 rounds added, 20572 low-priority rounds did not fit
==== Belgium: 126 aircraft, 7 ships, 82 land combat units, 4 ammo bunkers
  swaps: 33 land units replaced, 0 failed
  air defence: 7 Mistral platoons placed, 0 already there, 1 failed
  loadouts: 78 aircraft armed, 0 failed, 48 left as they were
  airbase Florennes AB: 1320 stores added
  airbase Kleine-Brogel AB: 1800 stores added
  airbase Beauvechain AB: 432 stores added
  top-up: 2 units were below maximum, 24 rounds added
  land magazines: 82 units given a magazine (16016 rounds), 0 already had one, 0 failed
  ammo trucks: 10 platoons placed (29536 rounds loaded), 0 already there
  depots: 4 ammo bunkers filled with 40000 rounds (8048 small-arms/low-priority rounds did not fit)
  port Zeebrugge NB: reloads for 7 ships, 5568 rounds added
---- Scoring ----
  Netherlands: 330 units = 1000 points for the enemy if all are destroyed
      aircraft                              344 pts
      bases, radars and air defence          61 pts
      land forces (added by script)         452 pts
      other facilities                        1 pts
      ships                                 142 pts
  Belgium: 255 units = 1000 points for the enemy if all are destroyed
      aircraft                              378 pts
      bases, radars and air defence          60 pts
      land forces (added by script)         481 pts
      other facilities                        1 pts
      ships                                  80 pts
  event 'Loss scoring (zero-sum)' created. Open the Event Editor and check it is ticked as repeatable.
  Now set the thresholds for BOTH sides in the editor's scoring window:
  Disaster -1000 ... Triumph +1000 (e.g. -1000 / -400 / +400 / +1000).
Finished. Check one airfield, one platoon and one port in the editor before saving.
...
07/10/2026 18:47:06 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX WAR READINESS
--  Command: Modern Operations 1.10 (build 1900.20), DB3K_519
--  Run from Editor > Lua Script Console.  SAVE A COPY OF THE SCENARIO FIRST.
-- =====================================================================
--  All IDs below were read from your DB3K_519 database and your inventory.
--  Phases (each can be switched off in CONFIG.PHASES):
--   1 swaps     replace stand-in land units with the closest real entry
--   2 loadouts  give aircraft combat loadouts, armed and ready
--   3 airbases  stock each airfield with sortie reloads for its aircraft
--   4 topup     fill every ship / SAM / land unit weapon record to maximum
--   5 landmags  give each land combat unit its own magazine with one extra
--               basic load of exactly the ammunition its weapons fire
--   6 trucks    ammo truck platoons with each garrison, pre-loaded
--   7 depots    fill the [DEPOT] ammo bunkers
--   8 ports     stock each naval base with reloads for the ships homed there
--   9 scoring   (re)build the zero-sum loss scoring so that each side's whole
--               force, including everything added above, is worth 1000 points
--  Phase 1a (airswaps) replaces the unarmed Belgian SF.260EA trainers with armed SF.260W.
--  Phase 1b (airdefence) adds Belgian Mistral platoons at airfields, the port
--  and the two brigade garrisons.
--
--  The functions this script has never used in your build (stocking a
--  magazine, adding a magazine, deleting a unit) are each checked on the
--  first unit by reading the result back. If a check fails, that phase
--  stops and says so; nothing is done blind.
--  Safe to run again: every stock is topped up to its target, never doubled,
--  and units that already exist are skipped.
-- =====================================================================

local CONFIG = {
  SIDES = { "Netherlands", "Belgium" },
  PHASES = { swaps = true, airswaps = true, airdefence = true, loadouts = true, airbases = true, topup = true,
             landmags = true, trucks = true, depots = true, ports = true, scoring = true },

  SORTIES_PER_AIRCRAFT = 6,     -- reloads of its loadout stocked at the home airfield
  TRANSPORT_SORTIES    = 2,     -- same, for troop / cargo / passenger loads
  LAND_EXTRA_LOADS     = 1,     -- basic loads in each land unit's own magazine
  TRUCK_LOADS          = 2,     -- basic loads of the garrison carried by its ammo trucks
  DEPOT_LOADS          = 3,     -- basic loads of the whole army spread over its ammo bunkers
  PORT_RELOADS         = 2,     -- full reloads per ship stocked at its naval base

  SCORE_SCALE     = 1000,       -- total value of each side's force
  END_SCENARIO_AT = nil,        -- e.g. 600 = end the game when a side reaches +600
}

-- extra air defence: one platoon beside every airfield and port of the side, plus the listed points
local AIR_DEFENCE = {
  Belgium = {
    dbid = 1664,                -- SAM Plt (Mistral ATLAS), Belgium
    label = "Mistral",
    extra = {
      { name = "Leopoldsburg", lat = 51.117, lon = 5.257 },
      { name = "Marche-en-Famenne", lat = 50.245, lon = 5.325 },
    },
  },
}

-- aircraft DBID -> loadout IDs, dealt out in turn to the aircraft of that type
local LOADOUTS = {
  -- Netherlands
  [3167] = { 16877, 16898, 16877, 19854 },  -- F-16AM: AIM-120B air-to-air / GBU-49 strike / air-to-air / SDB
  [3902] = { 19576, 21735, 19576, 19583 },  -- F-35A: AIM-120C-7 internal / SDB / air-to-air / JDAM
  [4824] = { 5816, 5815 },                  -- AH-64D: Hellfire + rockets / Hellfire only
  [656]  = { 5764, 5764, 15377 },           -- NH90 NFH: ASW torpedoes + sonobuoys / maritime surveillance
  [3960] = { 19856 },                       -- MQ-9A: recon
  [4067] = { 20185 }, [4068] = { 20185 },   -- C-130H: cargo
  [4069] = { 20191 },                       -- Cougar: troops
  [4070] = { 20198 },                       -- CH-47F: troops
  [4708] = { 30311 },                       -- A330 MRTT: tanker
  [2956] = { 15778 },                       -- Gulfstream: passengers
  -- Belgium
  -- Belgian fighters get the AIM-120D on purpose (later than the scenario date) to offset
  -- the Dutch advantage in numbers, radar and SAMs. For the period-correct AIM-120B use 15507.
  [2248] = { 32301, 5385, 32301, 11259 },   -- F-16AM: AIM-120D air-to-air / GBU-12 strike / air-to-air / JDAM
  [3263] = { 32301, 5385, 32301, 11259 },   -- F-16BM: same
  [1512] = { 247, 247, 15946 },             -- A-109BA: TOW / TOW / scout
  [2001] = { 8870 },                        -- RQ-5A: recon
  [8132] = { 22410, 22410, 22410, 22409 },  -- SF.260W Warrior: 68mm rockets x3 / 7.62mm gun pods
}

-- loadout ID -> stores it needs: { weapon DBID, quantity }
local LOADOUT_STORES = {
  [16877] = { {446,4}, {1763,2}, {2780,2}, {149,1}, {544,1} },
  [16898] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {2061,2} },
  [19854] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {484,8} },
  [19576] = { {718,4} },
  [21735] = { {484,8}, {718,2} },
  [19583] = { {554,2}, {718,2} },
  [5816]  = { {683,8}, {1929,38} },
  [5815]  = { {683,16} },
  [5764]  = { {1647,2}, {2478,34}, {2481,16} },
  [247]   = { {833,8} },
  [15507] = { {446,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  [32301] = { {51,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  -- transports: troops / cargo / passengers (stocked for TRANSPORT_SORTIES only)
  [20185] = { {2611,1} }, [20191] = { {801,20} }, [20198] = { {801,33} }, [15778] = { {2624,18} },
  [22410] = { {163,12} }, [22409] = { {2655,15} },   -- SF.260W: SNEB rockets / gun pod ammunition
  [4336] = { {2225,1} }, [13593] = { {2121,1} }, [9952] = { {2624,199} },
  [5385]  = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {1906,2} },
  [11259] = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {93,2} },
}

-- land unit swaps: current class name -> replacement facility DBID per side
local SWAPS = {
  Netherlands = {
    ["Inf Plt (Russian Army)"]                 = 550,   -- Inf Plt (German Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 3244, -- Inf Sec (Kommando Spezialkraefte)
    ["Mech Inf Plt (Boxer APC x 3)"]           = 2878,  -- Motor Inf Plt (Boxer APC x 4), Netherlands
    ["Mech Inf Plt (CV 9035 x 4)"]             = 5097,  -- Mech Inf Plt (CV 9035NL x 4)
  },
  Belgium = {
    ["Inf Plt (Russian Army)"]                 = 2317,  -- Inf Plt (French Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 2724, -- Inf Sec (COS Recon)
    ["Motor Inf Plt (Pandur I APC x 4)"]       = 2948,  -- the Belgian Pandur entry
  },
}

-- aircraft swaps: current aircraft DBID -> replacement (kept at the same base, same name)
local AIRCRAFT_SWAPS = {
  Belgium = {
    [4416] = { dbid = 8132, loadout = 22410 },   -- SF.260EA trainer -> SF.260W Warrior (armed)
  },
}

local GENERIC_MAGAZINE_DBID = 1423   -- "Generic Magazine", capacity 10000, empty
local AMMO_TRUCK_DBID       = 2086   -- "Vehicles (Ammo Truck x 4)"
local TRANSPORT_STORES = { [801] = true, [2611] = true, [2624] = true, [2225] = true, [2121] = true }   -- Trooper, Cargo, Passenger
local COMBAT_TAGS = { "[INF]", "[MECH]", "[ARTY]", "[RECON]", "[ENG]", "[SOF]", "[ARMOR]" }

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function num(v) return tonumber(v) or 0 end
local function getUnit(guid) return try(ScenEdit_GetUnit, { guid = guid }) end
local function key(k) return try(ScenEdit_GetKeyValue, "LOOB2_" .. k) or "" end
local function setKey(k) try(ScenEdit_SetKeyValue, "LOOB2_" .. k, "yes") end
local function done(k)
  return (not CONFIG.ALLOW_REPEAT) and key(k) == "yes"
end

local function isSmallArms(name)
  local n = string.lower(tostring(name or ""))
  return string.find(n, "mg burst", 1, true) or string.find(n, "minigun", 1, true)
      or string.find(n, "rifle", 1, true) or string.find(n, "ar burst", 1, true)
end

local function hasTag(name)
  for _, t in ipairs(COMBAT_TAGS) do
    if string.sub(tostring(name), 1, #t) == t then return true end
  end
  return false
end

-- ---- reading magazines and mounts (field names taken from your inventory) ----
local function realMagazine(u)            -- the unit's real magazine (not a mount's own reload bin)
  local best
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then
        if not best or num(m.mag_capacity) > num(best.mag_capacity) then best = m end
      end
    end
  end
  return best
end

local function magRecord(mag, wpn)
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do
      if num(w.wpn_dbid) == wpn then return w end
    end
  end
  return nil
end

local function magUsed(mag)
  local n = 0
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do n = n + num(w.wpn_current) end
  end
  return n
end

local function unitTotal(u)               -- every round on the unit, mounts + magazines
  local n = 0
  local mags = prop(u, "magazines")
  if type(mags) == "table" then for _, m in pairs(mags) do n = n + magUsed(m) end end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do n = n + num(w.wpn_current) end
      end
    end
  end
  return n
end

-- one full load of the unit: weapon DBID -> { n = quantity at maximum, name = ... }
local function fullLoad(u, includeMagazines)
  local load = {}
  local function add(w)
    local id = num(w.wpn_dbid)
    if id ~= 0 and num(w.wpn_maxcap) > 0 then
      if not load[id] then load[id] = { n = 0, name = tostring(w.wpn_name) } end
      load[id].n = load[id].n + num(w.wpn_maxcap)
    end
  end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then for _, w in pairs(m.mount_weapons) do add(w) end end
    end
  end
  if includeMagazines then
    local mags = prop(u, "magazines")
    if type(mags) == "table" then
      for _, m in pairs(mags) do
        if type(m.mag_weapons) == "table" then for _, w in pairs(m.mag_weapons) do add(w) end end
      end
    end
  end
  return load
end

local function mergeLoad(into, load, times)
  for id, e in pairs(load) do
    if not into[id] then into[id] = { n = 0, name = e.name } end
    into[id].n = into[id].n + e.n * (times or 1)
  end
end

-- ---- stocking magazines: tops each weapon up to a target, so re-running never doubles ----
local stockVariant = nil     -- which argument form works in this build
local stockBroken = false

local function realMagazines(u)
  local list = {}
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then list[#list + 1] = m end
    end
  end
  return list
end

local function haveQty(u, wpn)
  local n = 0
  for _, m in ipairs(realMagazines(u)) do
    local rec = magRecord(m, wpn)
    if rec then n = n + num(rec.wpn_current) end
  end
  return n
end

local function roomiest(u)                -- real magazine with the most free space
  local best, bestRoom
  for _, m in ipairs(realMagazines(u)) do
    local room = (num(m.mag_capacity) > 0) and (num(m.mag_capacity) - magUsed(m)) or 100000
    if not best or room > bestRoom then best, bestRoom = m, room end
  end
  return best, bestRoom or 0
end

local function stockCall(variant, guid, magGuid, wpn, n, cap)
  local t = { guid = guid, wpn_dbid = wpn, number = n, new = true }
  if variant == 1 or variant == 3 then t.mag_guid = magGuid end
  if variant == 1 or variant == 2 then t.maxcap = cap end
  return try(ScenEdit_AddWeaponToUnitMagazine, t)
end

local function stock(guid, mag, wpn, n)   -- put n of a weapon into one magazine
  n = math.floor(n)
  if n <= 0 or stockBroken then return 0 end
  local rec = magRecord(mag, wpn)
  local inMag = rec and num(rec.wpn_current) or 0
  local cap = math.max(rec and num(rec.wpn_maxcap) or 0, inMag + n)
  if stockVariant then
    stockCall(stockVariant, guid, mag.mag_guid, wpn, n, cap)
    return n
  end
  local u = getUnit(guid)
  local before = u and haveQty(u, wpn) or 0
  for v = 1, 4 do                          -- first use: find the form that works
    stockCall(v, guid, mag.mag_guid, wpn, n, cap)
    local u2 = getUnit(guid)
    local after = u2 and haveQty(u2, wpn) or 0
    if after > before then
      stockVariant = v
      return after - before
    end
  end
  stockBroken = true
  say("  !! CHECK FAILED: could not add weapons to a magazine in this build (ScenEdit_AddWeaponToUnitMagazine).")
  say("     All stocking phases are skipped. Tell me this line and I will use another method.")
  return 0
end

-- Bring a unit's magazines up to the target load. Scarce items (missiles, torpedoes) go in
-- first, bulk ammunition next, small arms and troop/cargo loads last. With extraMags > 0 the
-- unit is given further magazines when it runs out of room.
local function stockLoad(guid, load, times, extraMags)
  local order = {}
  for id, e in pairs(load) do
    order[#order + 1] = { id = id, n = math.floor(e.n * (times or 1)),
                          low = (isSmallArms(e.name) or TRANSPORT_STORES[id]) and 1 or 0 }
  end
  table.sort(order, function(a, b)
    if a.low ~= b.low then return a.low < b.low end
    if a.n ~= b.n then return a.n < b.n end
    return a.id < b.id
  end)
  local added, cut, grown = 0, 0, 0
  for _, o in ipairs(order) do
    local u = getUnit(guid)
    if not u or stockBroken then break end
    local need = o.n - haveQty(u, o.id)
    local guard = 0
    while need > 0 and guard < 8 do
      guard = guard + 1
      local mag, room = roomiest(u)
      if not mag then break end
      if room <= 0 then
        if grown >= (extraMags or 0) then break end
        try(ScenEdit_UpdateUnit, { guid = guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        grown = grown + 1
      else
        local give = math.min(need, room)
        local got = stock(guid, mag, o.id, give)
        if got <= 0 then break end
        added = added + got
        need = need - give
      end
      u = getUnit(guid)
      if not u then break end
    end
    if need > 0 then cut = cut + need end
  end
  return added, cut, grown
end

-- ---- collecting units ----
local function collect(sideName)
  local side = try(VP_GetSide, { side = sideName })
  local r = { air = {}, ships = {}, land = {}, bunkers = {}, others = {} }
  if not side then return nil end
  for _, ref in pairs(side.units) do
    local u = getUnit(ref.guid)
    if u then
      local t = tostring(prop(u, "type"))
      local name = tostring(prop(u, "name"))
      local cls = tostring(prop(u, "classname"))
      local e = { guid = ref.guid, name = name, cls = cls, dbid = num(prop(u, "dbid")),
                  lat = num(prop(u, "latitude")), lon = num(prop(u, "longitude")) }
      if t == "Aircraft" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.air[#r.air + 1] = e
      elseif t == "Ship" or t == "Submarine" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.ships[#r.ships + 1] = e
      elseif t == "Facility" then
        if hasTag(name) then
          r.land[#r.land + 1] = e
        elseif string.sub(name, 1, 7) == "[DEPOT]" and string.find(cls, "Ammo", 1, true) then
          r.bunkers[#r.bunkers + 1] = e
        else
          r.others[#r.others + 1] = e
        end
      end
    end
  end
  local byName = function(a, b) return a.name < b.name end
  table.sort(r.air, byName) table.sort(r.ships, byName) table.sort(r.land, byName) table.sort(r.bunkers, byName)
  return r
end

-- ---- scoring (zero-sum, each side scaled to SCORE_SCALE) ----
-- The weights exist twice: as text (stored inside the scoring event) and as
-- real code (used now). If you change the values, change BOTH copies.
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"
local function scoreKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = LS_weight
  local problems = 0

  say("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      say("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      scoreKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      scoreKey(KEY .. "scale_" .. side, scale)
      say(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        say(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    scoreKey(KEY .. "lost_" .. side, 0)
  end
  scoreKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    say("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      say("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    say("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    say("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    say("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  say("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  say("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- ============================ phases ============================
local function phaseAirDefence(sideName, r)
  local ad = AIR_DEFENCE[sideName]
  if not ad then return end
  local spots = {}
  for _, e in ipairs(r.others) do
    if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true) then
      spots[#spots + 1] = { name = e.name, lat = e.lat, lon = e.lon }
    end
  end
  for _, x in ipairs(ad.extra or {}) do spots[#spots + 1] = x end
  local made, existed, failed = 0, 0, 0
  for _, sp in ipairs(spots) do
    local name = "[AD] " .. ad.label .. " " .. sp.name
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local placed = false
      for _, o in ipairs({ { 0.008, -0.012 }, { -0.008, 0.012 }, { -0.010, -0.014 }, { 0.010, 0.014 }, { -0.020, 0.0 }, { 0.0, 0.030 } }) do
        if try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = ad.dbid,
                                   latitude = sp.lat + o[1], longitude = sp.lon + o[2] }) then
          placed = true
          break
        end
      end
      if placed then made = made + 1 else failed = failed + 1 say("  could not place '" .. name .. "'") end
    end
  end
  say("  air defence: " .. made .. " " .. ad.label .. " platoons placed, " .. existed .. " already there, " .. failed .. " failed")
end

local function phaseAirSwaps(sideName, r)
  local map = AIRCRAFT_SWAPS[sideName]
  if not map then return end
  local okN, failN, stuck = 0, 0, 0
  for _, e in ipairs(r.air) do
    local sw = map[e.dbid]
    if sw and e.base then
      -- create the replacement first, so nothing is lost if this build refuses it
      local nu
      for _, t in ipairs({ "Air", "Aircraft" }) do
        nu = try(ScenEdit_AddUnit, { side = sideName, type = t, unitname = e.name, dbid = sw.dbid,
                                     loadoutid = sw.loadout, base = e.base })
        if nu then break end
      end
      if not nu then
        failN = failN + 1
        if okN == 0 then
          say("  !! CHECK FAILED: could not create an aircraft inside " .. tostring(e.baseName)
              .. ", so no aircraft were swapped on this side. Nothing was removed.")
          return
        end
      else
        try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
        if getUnit(e.guid) then stuck = stuck + 1 end
        okN = okN + 1
      end
    end
  end
  say("  aircraft swaps: " .. okN .. " replaced, " .. failN .. " failed"
      .. ((stuck > 0) and (", " .. stuck .. " old aircraft could not be removed - delete them by hand") or ""))
end

local function phaseSwaps(sideName, r)
  local map = SWAPS[sideName]
  if not map then return end
  local okN, failN, checked = 0, 0, false
  for _, e in ipairs(r.land) do
    local target = map[e.cls]
    if target and e.dbid ~= target then
      try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
      if not checked then
        checked = true
        if getUnit(e.guid) then
          say("  !! CHECK FAILED: could not delete a unit, so no land units were swapped on this side.")
          return
        end
      end
      local nu = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = target,
                                         latitude = e.lat, longitude = e.lon })
      if nu then
        okN = okN + 1
      else
        failN = failN + 1
        local back = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = e.dbid,
                                             latitude = e.lat, longitude = e.lon })
        say("  could not create DBID " .. target .. " for '" .. e.name .. "'" .. (back and " - original restored" or " - UNIT LOST, re-add it by hand"))
      end
    end
  end
  say("  swaps: " .. okN .. " land units replaced, " .. failN .. " failed")
end

local function phaseLoadouts(sideName, r)
  local dealt, setN, failN, kept = {}, 0, 0, 0
  for _, e in ipairs(r.air) do
    local list = LOADOUTS[e.dbid]
    if list then
      dealt[e.dbid] = (dealt[e.dbid] or 0) + 1
      local want = list[((dealt[e.dbid] - 1) % #list) + 1]
      try(ScenEdit_SetLoadout, { unitname = e.guid, LoadoutID = want, TimeToReady_Minutes = 0, IgnoreMagazines = true })
      local u = getUnit(e.guid)
      if u and num(prop(u, "loadoutdbid")) == want then
        setN = setN + 1
        e.loadout = want
      else
        failN = failN + 1
        e.loadout = u and num(prop(u, "loadoutdbid")) or 0
      end
    else
      kept = kept + 1
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
  end
  say("  loadouts: " .. setN .. " aircraft armed, " .. failN .. " failed, " .. kept .. " left as they were")
end

local function phaseAirbases(sideName, r)
  local bases = {}
  for _, e in ipairs(r.air) do
    if e.loadout == nil then
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
    local stores = LOADOUT_STORES[e.loadout]
    if e.base and stores then
      if not bases[e.base] then bases[e.base] = { name = e.baseName, load = {} } end
      for _, s in ipairs(stores) do
        local l = bases[e.base].load
        if not l[s[1]] then l[s[1]] = { n = 0, name = "" } end
        l[s[1]].n = l[s[1]].n + s[2] * (TRANSPORT_STORES[s[1]] and CONFIG.TRANSPORT_SORTIES or CONFIG.SORTIES_PER_AIRCRAFT)
      end
    end
  end
  for guid, b in pairs(bases) do
    local added, cut = stockLoad(guid, b.load, 1, 2)
    say("  airbase " .. tostring(b.name) .. ": " .. added .. " stores added" .. ((cut > 0) and (", " .. cut .. " did not fit") or ""))
  end
end

local function topUpUnit(guid)
  local u = getUnit(guid)
  if not u then return 0 end
  local before = unitTotal(u)
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do
          if num(w.wpn_current) < num(w.wpn_maxcap) then
            try(ScenEdit_AddReloadsToUnit, { guid = guid, mount_guid = m.mount_guid, wpn_dbid = num(w.wpn_dbid), fillout = true })
          end
        end
      end
    end
  end
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 and type(m.mag_weapons) == "table" then
        for _, w in pairs(m.mag_weapons) do
          if num(w.wpn_default) > 0 and num(w.wpn_current) < num(w.wpn_default) then
            try(ScenEdit_AddWeaponToUnitMagazine, { guid = guid, mag_guid = m.mag_guid, wpn_dbid = num(w.wpn_dbid),
                                                    number = num(w.wpn_default) - num(w.wpn_current) })
          end
        end
      end
    end
  end
  local u2 = getUnit(guid)
  return (u2 and unitTotal(u2) or before) - before
end

local function phaseTopUp(sideName, r)
  local gained, n = 0, 0
  for _, list in ipairs({ r.ships, r.land, r.others }) do
    for _, e in ipairs(list) do
      local g = topUpUnit(e.guid)
      if g > 0 then gained = gained + g n = n + 1 end
    end
  end
  say("  top-up: " .. n .. " units were below maximum, " .. gained .. " rounds added")
end

local magBroken = false
local function phaseLandMags(sideName, r)
  local addedMag, had, stocked, failed = 0, 0, 0, 0
  for _, e in ipairs(r.land) do
    if magBroken then break end
    local u = getUnit(e.guid)
    if u then
      if realMagazine(u) then
        had = had + 1
      else
        try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        u = getUnit(e.guid)
        if not (u and realMagazine(u)) then
          try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine_only", dbid = GENERIC_MAGAZINE_DBID })
          u = getUnit(e.guid)
        end
        if u and realMagazine(u) then
          addedMag = addedMag + 1
          local got = stockLoad(e.guid, fullLoad(u, false), CONFIG.LAND_EXTRA_LOADS)
          stocked = stocked + got
        else
          failed = failed + 1
          if addedMag == 0 then
            magBroken = true
            say("  !! CHECK FAILED: could not add a magazine to '" .. e.name .. "' (ScenEdit_UpdateUnit add_magazine).")
            say("     Land units keep only what they carry. Tell me this line and I will try another method.")
          end
        end
      end
    end
  end
  say("  land magazines: " .. addedMag .. " units given a magazine (" .. stocked .. " rounds), "
      .. had .. " already had one, " .. failed .. " failed")
end

local function clusters(r)
  local cl = {}
  for _, e in ipairs(r.land) do
    local k = math.floor(e.lat * 10 + 0.5) .. "," .. math.floor(e.lon * 10 + 0.5)
    if not cl[k] then cl[k] = { units = {}, lat = 0, lon = 0 } end
    local c = cl[k]
    c.units[#c.units + 1] = e
    c.lat = c.lat + e.lat
    c.lon = c.lon + e.lon
  end
  local list = {}
  for k, c in pairs(cl) do
    if #c.units >= 3 then
      c.key = k
      c.lat = c.lat / #c.units
      c.lon = c.lon / #c.units
      list[#list + 1] = c
    end
  end
  table.sort(list, function(a, b) return a.key < b.key end)
  return list
end

local function phaseTrucks(sideName, r)
  local made, existed, rounds = 0, 0, 0
  for i, c in ipairs(clusters(r)) do
    local name = "[SUPPLY] Ammo trucks " .. i
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local t = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = AMMO_TRUCK_DBID,
                                        latitude = c.lat + 0.004, longitude = c.lon + 0.006 })
      if t then
        made = made + 1
        local load = {}
        for _, e in ipairs(c.units) do
          local u = getUnit(e.guid)
          if u then mergeLoad(load, fullLoad(u, false), 1) end
        end
        rounds = rounds + stockLoad(t.guid, load, CONFIG.TRUCK_LOADS)
      end
    end
  end
  say("  ammo trucks: " .. made .. " platoons placed (" .. rounds .. " rounds loaded), " .. existed .. " already there")
end

local function phaseDepots(sideName, r)
  if #r.bunkers == 0 then say("  depots: no [DEPOT] ammo bunkers found") return end
  local load = {}
  for _, e in ipairs(r.land) do
    local u = getUnit(e.guid)
    if u then mergeLoad(load, fullLoad(u, false), 1) end
  end
  local total, cutAll = 0, 0
  for _, b in ipairs(r.bunkers) do
    local added, cut = stockLoad(b.guid, load, CONFIG.DEPOT_LOADS / #r.bunkers, 0)
    total = total + added
    cutAll = cutAll + cut
  end
  say("  depots: " .. #r.bunkers .. " ammo bunkers filled with " .. total .. " rounds"
      .. ((cutAll > 0) and (" (" .. cutAll .. " rounds of the lowest-priority ammunition did not fit)") or ""))
end

local function phasePorts(sideName, r)
  local ports, homeless = {}, 0
  for _, e in ipairs(r.ships) do
    if e.base then
      if not ports[e.base] then ports[e.base] = { name = e.baseName, load = {}, n = 0 } end
      local u = getUnit(e.guid)
      if u then
        mergeLoad(ports[e.base].load, fullLoad(u, true), 1)
        ports[e.base].n = ports[e.base].n + 1
      end
    else
      homeless = homeless + 1
    end
  end
  for guid, p in pairs(ports) do
    local added, cut, grown = stockLoad(guid, p.load, CONFIG.PORT_RELOADS, 4)
    say("  port " .. tostring(p.name) .. ": reloads for " .. p.n .. " ships, " .. added .. " rounds added"
        .. ((grown > 0) and (", " .. grown .. " extra magazines built") or "")
        .. ((cut > 0) and (", " .. cut .. " rounds of the lowest-priority ammunition did not fit") or ""))
  end
  if homeless > 0 then say("  " .. homeless .. " ships have no home base - no port stock added for them") end

end

-- ============================== main ==============================
local function main()
  say("Benelux war readiness - build " .. tostring(try(GetBuildNumber)))
  local P = CONFIG.PHASES
  for _, sideName in ipairs(CONFIG.SIDES) do
    local r = collect(sideName)
    if not r then
      say("==== " .. sideName .. ": side not found - skipped")
    else
      say("==== " .. sideName .. ": " .. #r.air .. " aircraft, " .. #r.ships .. " ships, " .. #r.land
          .. " land combat units, " .. #r.bunkers .. " ammo bunkers")
      if P.swaps then
        phaseSwaps(sideName, r)
        r = collect(sideName)            -- swapped units have new IDs
      end
      if P.airswaps then
        phaseAirSwaps(sideName, r)
        r = collect(sideName)
      end
      if P.airdefence then
        phaseAirDefence(sideName, r)
        r = collect(sideName)            -- include the new platoons in the later steps
      end
      if P.loadouts then phaseLoadouts(sideName, r) end
      if P.airbases then phaseAirbases(sideName, r) end
      if P.topup then phaseTopUp(sideName, r) end
      if P.landmags then phaseLandMags(sideName, r) end
      if P.trucks then phaseTrucks(sideName, r) end
      if P.depots then phaseDepots(sideName, r) end
      if P.ports then phasePorts(sideName, r) end
    end
  end
  if P.scoring then
    if #CONFIG.SIDES == 2 then
      setupScoring(CONFIG.SIDES[1], CONFIG.SIDES[2])
    else
      say("Scoring needs exactly two sides in CONFIG.SIDES - skipped")
    end
  end
  say("Finished. Check one airfield, one platoon and one port in the editor before saving.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO58F
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO59J
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO58L
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO55L
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO56D
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO58R
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO553
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO591
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO59P
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO5AN
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO561
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO57T
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO56P
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO567
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO59V
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO56J
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO5A5
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO56V
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO59D
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO55R
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO54T
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO575
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO57H
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO55F
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO57B
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO5AB
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO583
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO597
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO5AH
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO559
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO57N
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid 3ONU4R-0HMARMQSEO589
... 
Function:ScenEdit_AddUnit (0)  Error:Attempted to place facility: [AD] Mistral Zeebrugge NB (Class: SAM Plt (Mistral ATLAS) - DBID: 1664) at coordinates: Lat: 51,3453505739414 - Lon: 3,18746245559302 . This point appears to be underwater. Placement aborted!
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands decisive)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium decisive)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - end scenario)!
Benelux war readiness - build v1.10 - Build 1900.20
==== Netherlands: 156 aircraft, 12 ships, 115 land combat units, 6 ammo bunkers
  swaps: 0 land units replaced, 0 failed
  loadouts: 156 aircraft armed, 0 failed, 0 left as they were
  airbase Volkel AB: 0 stores added
  airbase Eindhoven AB: 0 stores added
  airbase Gilze-Rijen AB: 0 stores added
  airbase Leeuwarden AB: 0 stores added
  airbase De Kooy Airfield: 0 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 0 units given a magazine (0 rounds), 115 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  depots: 6 ammo bunkers filled with 0 rounds (95208 rounds of the lowest-priority ammunition did not fit)
  port Nieuwu Haven NB (Den Helder): reloads for 12 ships, 20572 rounds added, 3 extra magazines built
==== Belgium: 126 aircraft, 7 ships, 82 land combat units, 4 ammo bunkers
  swaps: 0 land units replaced, 0 failed
  aircraft swaps: 32 replaced, 0 failed
  air defence: 1 Mistral platoons placed, 7 already there, 0 failed
  loadouts: 110 aircraft armed, 0 failed, 16 left as they were
  airbase Kleine-Brogel AB: 0 stores added
  airbase Koksijde AB: 16 stores added
  airbase Melsbroek AB: 412 stores added
  airbase Florennes AB: 0 stores added
  airbase Beauvechain AB: 2064 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 0 units given a magazine (0 rounds), 82 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  depots: 4 ammo bunkers filled with 0 rounds (8048 rounds of the lowest-priority ammunition did not fit)
  port Zeebrugge NB: reloads for 7 ships, 0 rounds added
---- Scoring ----
  Netherlands: 330 units = 1000 points for the enemy if all are destroyed
      aircraft                              344 pts
      bases, radars and air defence          61 pts
      land forces (added by script)         452 pts
      other facilities                        1 pts
      ships                                 142 pts
  Belgium: 256 units = 1000 points for the enemy if all are destroyed
      aircraft                              376 pts
      bases, radars and air defence          59 pts
      land forces (added by script)         484 pts
      other facilities                        1 pts
      ships                                  80 pts
  event 'Loss scoring (zero-sum)' created. Open the Event Editor and check it is ticked as repeatable.
  Now set the thresholds for BOTH sides in the editor's scoring window:
  Disaster -1000 ... Triumph +1000 (e.g. -1000 / -400 / +400 / +1000).
Finished. Check one airfield, one platoon and one port in the editor before saving.
...
07/10/2026 19:13:57 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX WAR READINESS
--  Command: Modern Operations 1.10 (build 1900.20), DB3K_519
--  Run from Editor > Lua Script Console.  SAVE A COPY OF THE SCENARIO FIRST.
-- =====================================================================
--  All IDs below were read from your DB3K_519 database and your inventory.
--  Phases (each can be switched off in CONFIG.PHASES):
--   1 swaps     replace stand-in land units with the closest real entry
--   2 loadouts  give aircraft combat loadouts, armed and ready
--   3 airbases  stock each airfield with sortie reloads for its aircraft
--   4 topup     fill every ship / SAM / land unit weapon record to maximum
--   5 landmags  give each land combat unit its own magazine with one extra
--               basic load of exactly the ammunition its weapons fire
--   6 trucks    ammo truck platoons with each garrison, pre-loaded
--   7 depots    fill the [DEPOT] ammo bunkers
--   8 ports     stock each naval base with reloads for the ships homed there
--   9 scoring   (re)build the zero-sum loss scoring so that each side's whole
--               force, including everything added above, is worth 1000 points
--  10 resupply  a repeating event: an ammo truck parked within RESUPPLY_RANGE_KM of a
--               friendly [DEPOT] ammo bunker is refilled from the bunker's stock
--  11 capture   a repeating event: airfields, ports and [DEPOT] buildings change side when
--               enemy land combat units hold them with no defenders nearby
--  Phase 1a (airswaps) replaces the unarmed Belgian SF.260EA trainers with armed SF.260W.
--  Phase 1b (airdefence) adds Belgian Mistral platoons at airfields, the port
--  and the two brigade garrisons.
--
--  The functions this script has never used in your build (stocking a
--  magazine, adding a magazine, deleting a unit) are each checked on the
--  first unit by reading the result back. If a check fails, that phase
--  stops and says so; nothing is done blind.
--  Safe to run again: every stock is topped up to its target, never doubled,
--  and units that already exist are skipped.
-- =====================================================================

local CONFIG = {
  SIDES = { "Netherlands", "Belgium" },
  PHASES = { swaps = true, airswaps = true, airdefence = true, loadouts = true, airbases = true, topup = true,
             landmags = true, trucks = true, depots = true, ports = true, scoring = true, resupply = true, capture = true },

  SORTIES_PER_AIRCRAFT = 6,     -- reloads of its loadout stocked at the home airfield
  TRANSPORT_SORTIES    = 2,     -- same, for troop / cargo / passenger loads
  LAND_EXTRA_LOADS     = 1,     -- basic loads in each land unit's own magazine
  TRUCK_LOADS          = 2,     -- basic loads of the garrison carried by its ammo trucks
  DEPOT_LOADS          = 3,     -- basic loads of the whole army spread over its ammo bunkers
  PORT_RELOADS         = 2,     -- full reloads per ship stocked at its naval base

  RESUPPLY_RANGE_KM      = 1.0, -- how close a truck must park to a bunker to be refilled
  RESUPPLY_EVERY_MINUTES = 5,   -- how often the refill check runs (game time)

  CAPTURE_RANGE_KM     = 2.0,   -- attackers must be this close, with no defending land unit this close
  CAPTURE_HOLD_MINUTES = 10,    -- for this long (game time)

  SCORE_SCALE     = 1000,       -- total value of each side's force
  END_SCENARIO_AT = nil,        -- e.g. 600 = end the game when a side reaches +600
}

-- extra air defence: one platoon beside every airfield and port of the side, plus the listed points
local AIR_DEFENCE = {
  Belgium = {
    dbid = 1664,                -- SAM Plt (Mistral ATLAS), Belgium
    label = "Mistral",
    extra = {
      { name = "Leopoldsburg", lat = 51.117, lon = 5.257 },
      { name = "Marche-en-Famenne", lat = 50.245, lon = 5.325 },
    },
  },
}

-- aircraft DBID -> loadout IDs, dealt out in turn to the aircraft of that type
local LOADOUTS = {
  -- Netherlands
  [3167] = { 16877, 16898, 16877, 19854 },  -- F-16AM: AIM-120B air-to-air / GBU-49 strike / air-to-air / SDB
  [3902] = { 19576, 21735, 19576, 19583 },  -- F-35A: AIM-120C-7 internal / SDB / air-to-air / JDAM
  [4824] = { 5816, 5815 },                  -- AH-64D: Hellfire + rockets / Hellfire only
  [656]  = { 5764, 5764, 15377 },           -- NH90 NFH: ASW torpedoes + sonobuoys / maritime surveillance
  [3960] = { 19856 },                       -- MQ-9A: recon
  [4067] = { 20185 }, [4068] = { 20185 },   -- C-130H: cargo
  [4069] = { 20191 },                       -- Cougar: troops
  [4070] = { 20198 },                       -- CH-47F: troops
  [4708] = { 30311 },                       -- A330 MRTT: tanker
  [2956] = { 15778 },                       -- Gulfstream: passengers
  -- Belgium
  -- Belgian fighters get the AIM-120D on purpose (later than the scenario date) to offset
  -- the Dutch advantage in numbers, radar and SAMs. For the period-correct AIM-120B use 15507.
  [2248] = { 32301, 5385, 32301, 11259 },   -- F-16AM: AIM-120D air-to-air / GBU-12 strike / air-to-air / JDAM
  [3263] = { 32301, 5385, 32301, 11259 },   -- F-16BM: same
  [1512] = { 247, 247, 15946 },             -- A-109BA: TOW / TOW / scout
  [2001] = { 8870 },                        -- RQ-5A: recon
  [8132] = { 22410, 22410, 22410, 22409 },  -- SF.260W Warrior: 68mm rockets x3 / 7.62mm gun pods
}

-- loadout ID -> stores it needs: { weapon DBID, quantity }
local LOADOUT_STORES = {
  [16877] = { {446,4}, {1763,2}, {2780,2}, {149,1}, {544,1} },
  [16898] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {2061,2} },
  [19854] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {484,8} },
  [19576] = { {718,4} },
  [21735] = { {484,8}, {718,2} },
  [19583] = { {554,2}, {718,2} },
  [5816]  = { {683,8}, {1929,38} },
  [5815]  = { {683,16} },
  [5764]  = { {1647,2}, {2478,34}, {2481,16} },
  [247]   = { {833,8} },
  [15507] = { {446,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  [32301] = { {51,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  -- transports: troops / cargo / passengers (stocked for TRANSPORT_SORTIES only)
  [20185] = { {2611,1} }, [20191] = { {801,20} }, [20198] = { {801,33} }, [15778] = { {2624,18} },
  [22410] = { {163,12} }, [22409] = { {2655,15} },   -- SF.260W: SNEB rockets / gun pod ammunition
  [4336] = { {2225,1} }, [13593] = { {2121,1} }, [9952] = { {2624,199} },
  [5385]  = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {1906,2} },
  [11259] = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {93,2} },
}

-- land unit swaps: current class name -> replacement facility DBID per side
local SWAPS = {
  Netherlands = {
    ["Inf Plt (Russian Army)"]                 = 550,   -- Inf Plt (German Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 3244, -- Inf Sec (Kommando Spezialkraefte)
    ["Mech Inf Plt (Boxer APC x 3)"]           = 2878,  -- Motor Inf Plt (Boxer APC x 4), Netherlands
    ["Mech Inf Plt (CV 9035 x 4)"]             = 5097,  -- Mech Inf Plt (CV 9035NL x 4)
  },
  Belgium = {
    ["Inf Plt (Russian Army)"]                 = 2317,  -- Inf Plt (French Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 2724, -- Inf Sec (COS Recon)
    ["Motor Inf Plt (Pandur I APC x 4)"]       = 2948,  -- the Belgian Pandur entry
  },
}

-- aircraft swaps: current aircraft DBID -> replacement (kept at the same base, same name)
local AIRCRAFT_SWAPS = {
  Belgium = {
    [4416] = { dbid = 8132, loadout = 22410 },   -- SF.260EA trainer -> SF.260W Warrior (armed)
  },
}

local GENERIC_MAGAZINE_DBID = 1423   -- "Generic Magazine", capacity 10000, empty
local AMMO_TRUCK_DBID       = 2086   -- "Vehicles (Ammo Truck x 4)"
local TRANSPORT_STORES = { [801] = true, [2611] = true, [2624] = true, [2225] = true, [2121] = true }   -- Trooper, Cargo, Passenger
local COMBAT_TAGS = { "[INF]", "[MECH]", "[ARTY]", "[RECON]", "[ENG]", "[SOF]", "[ARMOR]" }

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function num(v) return tonumber(v) or 0 end
local function getUnit(guid) return try(ScenEdit_GetUnit, { guid = guid }) end
local function key(k) return try(ScenEdit_GetKeyValue, "LOOB2_" .. k) or "" end
local function setKey(k) try(ScenEdit_SetKeyValue, "LOOB2_" .. k, "yes") end
local function done(k)
  return (not CONFIG.ALLOW_REPEAT) and key(k) == "yes"
end

local function isSmallArms(name)
  local n = string.lower(tostring(name or ""))
  return string.find(n, "mg burst", 1, true) or string.find(n, "minigun", 1, true)
      or string.find(n, "rifle", 1, true) or string.find(n, "ar burst", 1, true)
end

local function hasTag(name)
  for _, t in ipairs(COMBAT_TAGS) do
    if string.sub(tostring(name), 1, #t) == t then return true end
  end
  return false
end

-- ---- reading magazines and mounts (field names taken from your inventory) ----
local function realMagazine(u)            -- the unit's real magazine (not a mount's own reload bin)
  local best
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then
        if not best or num(m.mag_capacity) > num(best.mag_capacity) then best = m end
      end
    end
  end
  return best
end

local function magRecord(mag, wpn)
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do
      if num(w.wpn_dbid) == wpn then return w end
    end
  end
  return nil
end

local function magUsed(mag)
  local n = 0
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do n = n + num(w.wpn_current) end
  end
  return n
end

local function unitTotal(u)               -- every round on the unit, mounts + magazines
  local n = 0
  local mags = prop(u, "magazines")
  if type(mags) == "table" then for _, m in pairs(mags) do n = n + magUsed(m) end end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do n = n + num(w.wpn_current) end
      end
    end
  end
  return n
end

-- one full load of the unit: weapon DBID -> { n = quantity at maximum, name = ... }
local function fullLoad(u, includeMagazines)
  local load = {}
  local function add(w)
    local id = num(w.wpn_dbid)
    if id ~= 0 and num(w.wpn_maxcap) > 0 then
      if not load[id] then load[id] = { n = 0, name = tostring(w.wpn_name) } end
      load[id].n = load[id].n + num(w.wpn_maxcap)
    end
  end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then for _, w in pairs(m.mount_weapons) do add(w) end end
    end
  end
  if includeMagazines then
    local mags = prop(u, "magazines")
    if type(mags) == "table" then
      for _, m in pairs(mags) do
        if type(m.mag_weapons) == "table" then for _, w in pairs(m.mag_weapons) do add(w) end end
      end
    end
  end
  return load
end

local function mergeLoad(into, load, times)
  for id, e in pairs(load) do
    if not into[id] then into[id] = { n = 0, name = e.name } end
    into[id].n = into[id].n + e.n * (times or 1)
  end
end

-- ---- stocking magazines: tops each weapon up to a target, so re-running never doubles ----
local stockVariant = nil     -- which argument form works in this build
local stockBroken = false

local function realMagazines(u)
  local list = {}
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then list[#list + 1] = m end
    end
  end
  return list
end

local function haveQty(u, wpn)
  local n = 0
  for _, m in ipairs(realMagazines(u)) do
    local rec = magRecord(m, wpn)
    if rec then n = n + num(rec.wpn_current) end
  end
  return n
end

local function roomiest(u)                -- real magazine with the most free space
  local best, bestRoom
  for _, m in ipairs(realMagazines(u)) do
    local room = (num(m.mag_capacity) > 0) and (num(m.mag_capacity) - magUsed(m)) or 100000
    if not best or room > bestRoom then best, bestRoom = m, room end
  end
  return best, bestRoom or 0
end

local function stockCall(variant, guid, magGuid, wpn, n, cap)
  local t = { guid = guid, wpn_dbid = wpn, number = n, new = true }
  if variant == 1 or variant == 3 then t.mag_guid = magGuid end
  if variant == 1 or variant == 2 then t.maxcap = cap end
  return try(ScenEdit_AddWeaponToUnitMagazine, t)
end

local function stock(guid, mag, wpn, n)   -- put n of a weapon into one magazine
  n = math.floor(n)
  if n <= 0 or stockBroken then return 0 end
  local rec = magRecord(mag, wpn)
  local inMag = rec and num(rec.wpn_current) or 0
  local cap = math.max(rec and num(rec.wpn_maxcap) or 0, inMag + n)
  if stockVariant then
    stockCall(stockVariant, guid, mag.mag_guid, wpn, n, cap)
    return n
  end
  local u = getUnit(guid)
  local before = u and haveQty(u, wpn) or 0
  for v = 1, 4 do                          -- first use: find the form that works
    stockCall(v, guid, mag.mag_guid, wpn, n, cap)
    local u2 = getUnit(guid)
    local after = u2 and haveQty(u2, wpn) or 0
    if after > before then
      stockVariant = v
      try(ScenEdit_SetKeyValue, "LOOB2_variant", tostring(v))
      return after - before
    end
  end
  stockBroken = true
  say("  !! CHECK FAILED: could not add weapons to a magazine in this build (ScenEdit_AddWeaponToUnitMagazine).")
  say("     All stocking phases are skipped. Tell me this line and I will use another method.")
  return 0
end

-- Bring a unit's magazines up to the target load. Scarce items (missiles, torpedoes) go in
-- first, bulk ammunition next, small arms and troop/cargo loads last. With extraMags > 0 the
-- unit is given further magazines when it runs out of room.
local function stockLoad(guid, load, times, extraMags)
  local order = {}
  for id, e in pairs(load) do
    order[#order + 1] = { id = id, n = math.floor(e.n * (times or 1)),
                          low = (isSmallArms(e.name) or TRANSPORT_STORES[id]) and 1 or 0 }
  end
  table.sort(order, function(a, b)
    if a.low ~= b.low then return a.low < b.low end
    if a.n ~= b.n then return a.n < b.n end
    return a.id < b.id
  end)
  local added, cut, grown = 0, 0, 0
  for _, o in ipairs(order) do
    local u = getUnit(guid)
    if not u or stockBroken then break end
    local need = o.n - haveQty(u, o.id)
    local guard = 0
    while need > 0 and guard < 8 do
      guard = guard + 1
      local mag, room = roomiest(u)
      if not mag then break end
      if room <= 0 then
        if grown >= (extraMags or 0) then break end
        try(ScenEdit_UpdateUnit, { guid = guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        grown = grown + 1
      else
        local give = math.min(need, room)
        local got = stock(guid, mag, o.id, give)
        if got <= 0 then break end
        added = added + got
        need = need - give
      end
      u = getUnit(guid)
      if not u then break end
    end
    if need > 0 then cut = cut + need end
  end
  return added, cut, grown
end

-- ---- collecting units ----
local function collect(sideName)
  local side = try(VP_GetSide, { side = sideName })
  local r = { air = {}, ships = {}, land = {}, bunkers = {}, others = {} }
  if not side then return nil end
  for _, ref in pairs(side.units) do
    local u = getUnit(ref.guid)
    if u then
      local t = tostring(prop(u, "type"))
      local name = tostring(prop(u, "name"))
      local cls = tostring(prop(u, "classname"))
      local e = { guid = ref.guid, name = name, cls = cls, dbid = num(prop(u, "dbid")),
                  lat = num(prop(u, "latitude")), lon = num(prop(u, "longitude")) }
      if t == "Aircraft" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.air[#r.air + 1] = e
      elseif t == "Ship" or t == "Submarine" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.ships[#r.ships + 1] = e
      elseif t == "Facility" then
        if hasTag(name) then
          r.land[#r.land + 1] = e
        elseif string.sub(name, 1, 7) == "[DEPOT]" and string.find(cls, "Ammo", 1, true) then
          r.bunkers[#r.bunkers + 1] = e
        else
          r.others[#r.others + 1] = e
        end
      end
    end
  end
  local byName = function(a, b) return a.name < b.name end
  table.sort(r.air, byName) table.sort(r.ships, byName) table.sort(r.land, byName) table.sort(r.bunkers, byName)
  return r
end

-- ---- scoring (zero-sum, each side scaled to SCORE_SCALE) ----
-- The weights exist twice: as text (stored inside the scoring event) and as
-- real code (used now). If you change the values, change BOTH copies.
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"
local function scoreKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = LS_weight
  local problems = 0

  say("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      say("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      scoreKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      scoreKey(KEY .. "scale_" .. side, scale)
      say(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        say(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    scoreKey(KEY .. "lost_" .. side, 0)
  end
  scoreKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    say("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      say("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    say("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    say("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    say("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  say("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  say("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- ============================ phases ============================
local function phaseAirDefence(sideName, r)
  local ad = AIR_DEFENCE[sideName]
  if not ad then return end
  local spots = {}
  for _, e in ipairs(r.others) do
    if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true) then
      spots[#spots + 1] = { name = e.name, lat = e.lat, lon = e.lon }
    end
  end
  for _, x in ipairs(ad.extra or {}) do spots[#spots + 1] = x end
  local made, existed, failed = 0, 0, 0
  for _, sp in ipairs(spots) do
    local name = "[AD] " .. ad.label .. " " .. sp.name
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local placed = false
      for _, o in ipairs({ { 0.008, -0.012 }, { -0.008, 0.012 }, { -0.010, -0.014 }, { 0.010, 0.014 }, { -0.020, 0.0 }, { 0.0, 0.030 } }) do
        if try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = ad.dbid,
                                   latitude = sp.lat + o[1], longitude = sp.lon + o[2] }) then
          placed = true
          break
        end
      end
      if placed then made = made + 1 else failed = failed + 1 say("  could not place '" .. name .. "'") end
    end
  end
  say("  air defence: " .. made .. " " .. ad.label .. " platoons placed, " .. existed .. " already there, " .. failed .. " failed")
end

local function phaseAirSwaps(sideName, r)
  local map = AIRCRAFT_SWAPS[sideName]
  if not map then return end
  local okN, failN, stuck = 0, 0, 0
  for _, e in ipairs(r.air) do
    local sw = map[e.dbid]
    if sw and e.base then
      -- create the replacement first, so nothing is lost if this build refuses it
      local nu
      for _, t in ipairs({ "Air", "Aircraft" }) do
        nu = try(ScenEdit_AddUnit, { side = sideName, type = t, unitname = e.name, dbid = sw.dbid,
                                     loadoutid = sw.loadout, base = e.base })
        if nu then break end
      end
      if not nu then
        failN = failN + 1
        if okN == 0 then
          say("  !! CHECK FAILED: could not create an aircraft inside " .. tostring(e.baseName)
              .. ", so no aircraft were swapped on this side. Nothing was removed.")
          return
        end
      else
        try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
        if getUnit(e.guid) then stuck = stuck + 1 end
        okN = okN + 1
      end
    end
  end
  say("  aircraft swaps: " .. okN .. " replaced, " .. failN .. " failed"
      .. ((stuck > 0) and (", " .. stuck .. " old aircraft could not be removed - delete them by hand") or ""))
end

local function phaseSwaps(sideName, r)
  local map = SWAPS[sideName]
  if not map then return end
  local okN, failN, checked = 0, 0, false
  for _, e in ipairs(r.land) do
    local target = map[e.cls]
    if target and e.dbid ~= target then
      try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
      if not checked then
        checked = true
        if getUnit(e.guid) then
          say("  !! CHECK FAILED: could not delete a unit, so no land units were swapped on this side.")
          return
        end
      end
      local nu = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = target,
                                         latitude = e.lat, longitude = e.lon })
      if nu then
        okN = okN + 1
      else
        failN = failN + 1
        local back = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = e.dbid,
                                             latitude = e.lat, longitude = e.lon })
        say("  could not create DBID " .. target .. " for '" .. e.name .. "'" .. (back and " - original restored" or " - UNIT LOST, re-add it by hand"))
      end
    end
  end
  say("  swaps: " .. okN .. " land units replaced, " .. failN .. " failed")
end

local function phaseLoadouts(sideName, r)
  local dealt, setN, failN, kept = {}, 0, 0, 0
  for _, e in ipairs(r.air) do
    local list = LOADOUTS[e.dbid]
    if list then
      dealt[e.dbid] = (dealt[e.dbid] or 0) + 1
      local want = list[((dealt[e.dbid] - 1) % #list) + 1]
      try(ScenEdit_SetLoadout, { unitname = e.guid, LoadoutID = want, TimeToReady_Minutes = 0, IgnoreMagazines = true })
      local u = getUnit(e.guid)
      if u and num(prop(u, "loadoutdbid")) == want then
        setN = setN + 1
        e.loadout = want
      else
        failN = failN + 1
        e.loadout = u and num(prop(u, "loadoutdbid")) or 0
      end
    else
      kept = kept + 1
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
  end
  say("  loadouts: " .. setN .. " aircraft armed, " .. failN .. " failed, " .. kept .. " left as they were")
end

local function phaseAirbases(sideName, r)
  local bases = {}
  for _, e in ipairs(r.air) do
    if e.loadout == nil then
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
    local stores = LOADOUT_STORES[e.loadout]
    if e.base and stores then
      if not bases[e.base] then bases[e.base] = { name = e.baseName, load = {} } end
      for _, s in ipairs(stores) do
        local l = bases[e.base].load
        if not l[s[1]] then l[s[1]] = { n = 0, name = "" } end
        l[s[1]].n = l[s[1]].n + s[2] * (TRANSPORT_STORES[s[1]] and CONFIG.TRANSPORT_SORTIES or CONFIG.SORTIES_PER_AIRCRAFT)
      end
    end
  end
  for guid, b in pairs(bases) do
    local added, cut = stockLoad(guid, b.load, 1, 2)
    say("  airbase " .. tostring(b.name) .. ": " .. added .. " stores added" .. ((cut > 0) and (", " .. cut .. " did not fit") or ""))
  end
end

local function topUpUnit(guid)
  local u = getUnit(guid)
  if not u then return 0 end
  local before = unitTotal(u)
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do
          if num(w.wpn_current) < num(w.wpn_maxcap) then
            try(ScenEdit_AddReloadsToUnit, { guid = guid, mount_guid = m.mount_guid, wpn_dbid = num(w.wpn_dbid), fillout = true })
          end
        end
      end
    end
  end
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 and type(m.mag_weapons) == "table" then
        for _, w in pairs(m.mag_weapons) do
          if num(w.wpn_default) > 0 and num(w.wpn_current) < num(w.wpn_default) then
            try(ScenEdit_AddWeaponToUnitMagazine, { guid = guid, mag_guid = m.mag_guid, wpn_dbid = num(w.wpn_dbid),
                                                    number = num(w.wpn_default) - num(w.wpn_current) })
          end
        end
      end
    end
  end
  local u2 = getUnit(guid)
  return (u2 and unitTotal(u2) or before) - before
end

local function phaseTopUp(sideName, r)
  local gained, n = 0, 0
  for _, list in ipairs({ r.ships, r.land, r.others }) do
    for _, e in ipairs(list) do
      local g = topUpUnit(e.guid)
      if g > 0 then gained = gained + g n = n + 1 end
    end
  end
  say("  top-up: " .. n .. " units were below maximum, " .. gained .. " rounds added")
end

local magBroken = false
local function phaseLandMags(sideName, r)
  local addedMag, had, stocked, failed = 0, 0, 0, 0
  for _, e in ipairs(r.land) do
    if magBroken then break end
    local u = getUnit(e.guid)
    if u then
      if realMagazine(u) then
        had = had + 1
      else
        try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        u = getUnit(e.guid)
        if not (u and realMagazine(u)) then
          try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine_only", dbid = GENERIC_MAGAZINE_DBID })
          u = getUnit(e.guid)
        end
        if u and realMagazine(u) then
          addedMag = addedMag + 1
          local got = stockLoad(e.guid, fullLoad(u, false), CONFIG.LAND_EXTRA_LOADS)
          stocked = stocked + got
        else
          failed = failed + 1
          if addedMag == 0 then
            magBroken = true
            say("  !! CHECK FAILED: could not add a magazine to '" .. e.name .. "' (ScenEdit_UpdateUnit add_magazine).")
            say("     Land units keep only what they carry. Tell me this line and I will try another method.")
          end
        end
      end
    end
  end
  say("  land magazines: " .. addedMag .. " units given a magazine (" .. stocked .. " rounds), "
      .. had .. " already had one, " .. failed .. " failed")
end

local function clusters(r)
  local cl = {}
  for _, e in ipairs(r.land) do
    local k = math.floor(e.lat * 10 + 0.5) .. "," .. math.floor(e.lon * 10 + 0.5)
    if not cl[k] then cl[k] = { units = {}, lat = 0, lon = 0 } end
    local c = cl[k]
    c.units[#c.units + 1] = e
    c.lat = c.lat + e.lat
    c.lon = c.lon + e.lon
  end
  local list = {}
  for k, c in pairs(cl) do
    if #c.units >= 3 then
      c.key = k
      c.lat = c.lat / #c.units
      c.lon = c.lon / #c.units
      list[#list + 1] = c
    end
  end
  table.sort(list, function(a, b) return a.key < b.key end)
  return list
end

local function phaseTrucks(sideName, r)
  local made, existed, rounds = 0, 0, 0
  for i, c in ipairs(clusters(r)) do
    local name = "[SUPPLY] Ammo trucks " .. i
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local t = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = AMMO_TRUCK_DBID,
                                        latitude = c.lat + 0.004, longitude = c.lon + 0.006 })
      if t then
        made = made + 1
        local load = {}
        for _, e in ipairs(c.units) do
          local u = getUnit(e.guid)
          if u then mergeLoad(load, fullLoad(u, false), 1) end
        end
        rounds = rounds + stockLoad(t.guid, load, CONFIG.TRUCK_LOADS)
      end
    end
  end
  say("  ammo trucks: " .. made .. " platoons placed (" .. rounds .. " rounds loaded), " .. existed .. " already there")
end

local function phaseDepots(sideName, r)
  if #r.bunkers == 0 then say("  depots: no [DEPOT] ammo bunkers found") return end
  local load = {}
  for _, e in ipairs(r.land) do
    local u = getUnit(e.guid)
    if u then mergeLoad(load, fullLoad(u, false), 1) end
  end
  local total, cutAll = 0, 0
  for _, b in ipairs(r.bunkers) do
    local added, cut = stockLoad(b.guid, load, CONFIG.DEPOT_LOADS / #r.bunkers, 6)
    total = total + added
    cutAll = cutAll + cut
  end
  say("  depots: " .. #r.bunkers .. " ammo bunkers filled with " .. total .. " rounds"
      .. ((cutAll > 0) and (" (" .. cutAll .. " rounds of the lowest-priority ammunition did not fit)") or ""))
end

local function phasePorts(sideName, r)
  local ports, homeless = {}, 0
  for _, e in ipairs(r.ships) do
    if e.base then
      if not ports[e.base] then ports[e.base] = { name = e.baseName, load = {}, n = 0 } end
      local u = getUnit(e.guid)
      if u then
        mergeLoad(ports[e.base].load, fullLoad(u, true), 1)
        ports[e.base].n = ports[e.base].n + 1
      end
    else
      homeless = homeless + 1
    end
  end
  for guid, p in pairs(ports) do
    local added, cut, grown = stockLoad(guid, p.load, CONFIG.PORT_RELOADS, 4)
    say("  port " .. tostring(p.name) .. ": reloads for " .. p.n .. " ships, " .. added .. " rounds added"
        .. ((grown > 0) and (", " .. grown .. " extra magazines built") or "")
        .. ((cut > 0) and (", " .. cut .. " rounds of the lowest-priority ammunition did not fit") or ""))
  end
  if homeless > 0 then say("  " .. homeless .. " ships have no home base - no port stock added for them") end

end

-- ---- ammo truck resupply at depots (repeating event) ----
local EV_RESUPPLY = "Ammo truck resupply at depots"
local RESUPPLY_SRC = [==[
local now = ScenEdit_CurrentTime()
local last = tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_last')) or 0
local every = (tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_min')) or 5) * 60
if now - last < every then return end
ScenEdit_SetKeyValue('LOOB2_resupply_last', tostring(now))
local RANGE = tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_km')) or 1
local variant = tonumber(ScenEdit_GetKeyValue('LOOB2_variant')) or 1
local function try(f, ...) local ok, r = pcall(f, ...) if ok then return r end return nil end
local function split(s) local t = {} for g in string.gmatch(s or '', '[^,]+') do t[#t + 1] = g end return t end
local function n(v) return tonumber(v) or 0 end
local function km(a, b)
  local r = math.rad
  local dlat, dlon = r(n(b.latitude) - n(a.latitude)), r(n(b.longitude) - n(a.longitude))
  local h = math.sin(dlat / 2) ^ 2 + math.cos(r(n(a.latitude))) * math.cos(r(n(b.latitude))) * math.sin(dlon / 2) ^ 2
  return 6371 * 2 * math.asin(math.sqrt(h))
end
local function mags(u)
  local list = {}
  if u and type(u.magazines) == 'table' then
    for _, m in pairs(u.magazines) do
      if n(m.mag_dbid) ~= 0 and type(m.mag_weapons) == 'table' then list[#list + 1] = m end
    end
  end
  return list
end
for _, side in ipairs(split(ScenEdit_GetKeyValue('LOOB2_sides'))) do
  local bunkers = {}
  for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_bunkers_' .. side))) do
    local b = try(ScenEdit_GetUnit, { guid = g })
    if b then bunkers[#bunkers + 1] = b end
  end
  for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_trucks_' .. side))) do
    local t = try(ScenEdit_GetUnit, { guid = g })
    if t then
      for _, b in ipairs(bunkers) do
        if km(t, b) <= RANGE then
          local moved = 0
          local bm = mags(b)
          local avail = {}
          for _, sm in ipairs(bm) do
            for _, sw in pairs(sm.mag_weapons) do avail[tostring(sm.mag_guid) .. '|' .. n(sw.wpn_dbid)] = n(sw.wpn_current) end
          end
          for _, m in ipairs(mags(t)) do
            for _, w in pairs(m.mag_weapons) do
              local need = n(w.wpn_maxcap) - n(w.wpn_current)
              for _, sm in ipairs(bm) do
                if need <= 0 then break end
                for _, sw in pairs(sm.mag_weapons) do
                  local ak = tostring(sm.mag_guid) .. '|' .. n(sw.wpn_dbid)
                  if n(sw.wpn_dbid) == n(w.wpn_dbid) and (avail[ak] or 0) > 0 and need > 0 then
                    local take = math.floor(math.min(need, avail[ak]))
                    local add = { guid = t.guid, wpn_dbid = n(w.wpn_dbid), number = take, new = true }
                    if variant == 1 or variant == 3 then add.mag_guid = m.mag_guid end
                    if variant == 1 or variant == 2 then add.maxcap = n(w.wpn_maxcap) end
                    try(ScenEdit_AddWeaponToUnitMagazine, add)
                    try(ScenEdit_AddWeaponToUnitMagazine, { guid = b.guid, mag_guid = sm.mag_guid, wpn_dbid = n(w.wpn_dbid), number = take, remove = true })
                    avail[ak] = avail[ak] - take
                    need = need - take
                    moved = moved + take
                  end
                end
              end
            end
          end
          if moved > 0 then
            try(ScenEdit_SpecialMessage, side, tostring(t.name) .. ' took on ' .. moved .. ' rounds at ' .. tostring(b.name))
          end
          break
        end
      end
    end
  end
end
]==]

local function setupResupply(sideData)
  local sides = {}
  local nTrucks, nBunkers = 0, 0
  for sideName, r in pairs(sideData) do
    sides[#sides + 1] = sideName
    local trucks, bunkers = {}, {}
    for _, e in ipairs(r.others) do
      if string.sub(e.name, 1, 8) == "[SUPPLY]" then trucks[#trucks + 1] = e.guid end
    end
    for _, e in ipairs(r.bunkers) do bunkers[#bunkers + 1] = e.guid end
    try(ScenEdit_SetKeyValue, "LOOB2_trucks_" .. sideName, table.concat(trucks, ","))
    try(ScenEdit_SetKeyValue, "LOOB2_bunkers_" .. sideName, table.concat(bunkers, ","))
    nTrucks = nTrucks + #trucks
    nBunkers = nBunkers + #bunkers
  end
  table.sort(sides)
  try(ScenEdit_SetKeyValue, "LOOB2_sides", table.concat(sides, ","))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_km", tostring(CONFIG.RESUPPLY_RANGE_KM))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_min", tostring(CONFIG.RESUPPLY_EVERY_MINUTES))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_last", "0")

  local trig, act = "Ammo truck resupply - timer", "Ammo truck resupply - refill"
  try(ScenEdit_SetEvent, EV_RESUPPLY, { mode = "remove" })
  try(ScenEdit_SetTrigger, { mode = "remove", type = "RegularTime", name = trig })
  try(ScenEdit_SetAction, { mode = "remove", type = "LuaScript", name = act })
  local body = string.gsub(string.gsub(RESUPPLY_SRC, "\r\n", "\n"), "\n", "\r\n")
  local ok = true
  if not try(ScenEdit_SetEvent, EV_RESUPPLY, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then ok = false end
  if not try(ScenEdit_SetTrigger, { mode = "add", type = "RegularTime", name = trig, interval = 4 }) then ok = false end
  try(ScenEdit_SetEventTrigger, EV_RESUPPLY, { mode = "add", name = trig })
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = act, ScriptText = body }) then ok = false end
  try(ScenEdit_SetEventAction, EV_RESUPPLY, { mode = "add", name = act })
  say("---- Truck resupply ----")
  if ok then
    say("  event '" .. EV_RESUPPLY .. "' created for " .. nTrucks .. " truck platoons and " .. nBunkers .. " ammo bunkers.")
    say("  A truck parked within " .. CONFIG.RESUPPLY_RANGE_KM .. " km of a friendly ammo bunker is refilled from it, checked every "
        .. CONFIG.RESUPPLY_EVERY_MINUTES .. " game minutes.")
    say("  In the Event Editor: check it is repeatable and its timer trigger shows an interval of 1 minute or less.")
  else
    say("  !! could not create the resupply event: " .. tostring(_errmsg_ or ""))
  end
end

-- ---- capture of airfields, ports and depots (repeating event) ----
local EV_CAPTURE = "Base and depot capture"
local CAPTURE_SRC = [==[
local now = ScenEdit_CurrentTime()
local last = tonumber(ScenEdit_GetKeyValue('LOOB2_capture_last')) or 0
if now - last < 60 then return end
ScenEdit_SetKeyValue('LOOB2_capture_last', tostring(now))
local RANGE = tonumber(ScenEdit_GetKeyValue('LOOB2_capture_km')) or 2
local HOLD = (tonumber(ScenEdit_GetKeyValue('LOOB2_capture_min')) or 10) * 60
local A, B = ScenEdit_GetKeyValue('LOOB2_scoreA'), ScenEdit_GetKeyValue('LOOB2_scoreB')
local function try(f, ...) local ok, r = pcall(f, ...) if ok then return r end return nil end
local function split(s) local t = {} for g in string.gmatch(s or '', '[^,]+') do t[#t + 1] = g end return t end
local function n(v) return tonumber(v) or 0 end
local function km(a, b)
  local r = math.rad
  local dlat, dlon = r(n(b.latitude) - n(a.latitude)), r(n(b.longitude) - n(a.longitude))
  local h = math.sin(dlat / 2) ^ 2 + math.cos(r(n(a.latitude))) * math.cos(r(n(b.latitude))) * math.sin(dlon / 2) ^ 2
  return 6371 * 2 * math.asin(math.sqrt(h))
end
local function tell(side, text) try(ScenEdit_SpecialMessage, side, text) end
-- land combat units by the side they belong to NOW
local land = { [A] = {}, [B] = {} }
for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_land'))) do
  local u = try(ScenEdit_GetUnit, { guid = g })
  if u and land[tostring(u.side)] then
    local l = land[tostring(u.side)]
    l[#l + 1] = { latitude = u.latitude, longitude = u.longitude }
  end
end
local function near(list, site)
  local c = 0
  for _, p in ipairs(list) do if km(p, site) <= RANGE then c = c + 1 end end
  return c
end
local function guidsIn(t, out, depth)
  if depth > 3 then return end
  if type(t) == 'string' then out[#out + 1] = t
  elseif type(t) == 'table' then
    if type(t.guid) == 'string' then out[#out + 1] = t.guid
    else for _, v in pairs(t) do guidsIn(v, out, depth + 1) end end
  end
end
local function scoreLoss(owner, u)
  local w = LS_weight(u)
  if w <= 0 then return end
  local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
  local lostKey = 'LOOB_lost_' .. owner
  ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
  local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
  local delta = netA - num('LOOB_applied')
  if delta ~= 0 then
    local why = owner .. ' lost ' .. tostring(u.name) .. ' (captured)'
    ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
    ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
    ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
  end
end
local function moveKey(prefix, guid, from, to)
  local keep = {}
  for _, g in ipairs(split(ScenEdit_GetKeyValue(prefix .. from))) do if g ~= guid then keep[#keep + 1] = g end end
  local had = #keep ~= #split(ScenEdit_GetKeyValue(prefix .. from))
  if had then
    ScenEdit_SetKeyValue(prefix .. from, table.concat(keep, ','))
    local dest = split(ScenEdit_GetKeyValue(prefix .. to))
    dest[#dest + 1] = guid
    ScenEdit_SetKeyValue(prefix .. to, table.concat(dest, ','))
  end
end
for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_sites'))) do
  local site = try(ScenEdit_GetUnit, { guid = g })
  local owner = site and tostring(site.side)
  if site and (owner == A or owner == B) then
    local enemy = (owner == A) and B or A
    local capKey = 'LOOB2_cap_' .. g
    if near(land[enemy], site) > 0 and near(land[owner], site) == 0 then
      local since = tonumber(ScenEdit_GetKeyValue(capKey)) or 0
      if since == 0 then
        ScenEdit_SetKeyValue(capKey, tostring(now))
        tell(owner, tostring(site.name) .. ' is undefended and enemy troops are on it. It will be captured in ' .. math.floor(HOLD / 60) .. ' minutes unless you get land units there.')
        tell(enemy, 'Your troops are taking ' .. tostring(site.name) .. '. Hold it for ' .. math.floor(HOLD / 60) .. ' minutes.')
      elseif now - since >= HOLD then
        local hosted = {}
        guidsIn(site.hostedUnits, hosted, 0)
        guidsIn(site.embarkedUnits, hosted, 0)
        try(ScenEdit_SetUnitSide, { side = owner, guid = g, newside = enemy })
        local after = try(ScenEdit_GetUnit, { guid = g })
        if after and tostring(after.side) == enemy then
          scoreLoss(owner, site)
          local taken, seen = 0, {}
          for _, hg in ipairs(hosted) do
            if not seen[hg] then
              seen[hg] = true
              local hu = try(ScenEdit_GetUnit, { guid = hg })
              if hu then
                if tostring(hu.side) ~= enemy then try(ScenEdit_SetUnitSide, { side = owner, guid = hg, newside = enemy }) end
                local hu2 = try(ScenEdit_GetUnit, { guid = hg })
                if hu2 and tostring(hu2.side) == enemy then
                  taken = taken + 1
                  scoreLoss(owner, hu)
                end
              end
            end
          end
          moveKey('LOOB2_bunkers_', g, owner, enemy)
          local extra = (taken > 0) and (' with ' .. taken .. ' aircraft or ships') or ''
          tell(owner, tostring(site.name) .. ' has been captured by ' .. enemy .. extra .. '.')
          tell(enemy, 'You have captured ' .. tostring(site.name) .. extra .. '.')
        end
        ScenEdit_SetKeyValue(capKey, '0')
      end
    else
      if (tonumber(ScenEdit_GetKeyValue(capKey)) or 0) ~= 0 then ScenEdit_SetKeyValue(capKey, '0') end
    end
  end
end
]==]

local function setupCapture(sideData)
  if #CONFIG.SIDES ~= 2 then say("Capture needs exactly two sides in CONFIG.SIDES - skipped") return end
  local sites, land = {}, {}
  for _, r in pairs(sideData) do
    for _, e in ipairs(r.others) do
      if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true)
         or string.sub(e.name, 1, 7) == "[DEPOT]" then
        sites[#sites + 1] = e.guid
      end
    end
    for _, e in ipairs(r.bunkers) do sites[#sites + 1] = e.guid end
    for _, e in ipairs(r.land) do land[#land + 1] = e.guid end
  end
  local function put(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end
  put("LOOB2_sites", table.concat(sites, ","))
  put("LOOB2_land", table.concat(land, ","))
  put("LOOB2_scoreA", CONFIG.SIDES[1])
  put("LOOB2_scoreB", CONFIG.SIDES[2])
  put("LOOB2_capture_km", CONFIG.CAPTURE_RANGE_KM)
  put("LOOB2_capture_min", CONFIG.CAPTURE_HOLD_MINUTES)
  put("LOOB2_capture_last", 0)
  for _, g in ipairs(sites) do put("LOOB2_cap_" .. g, 0) end

  local trig, act = "Capture - timer", "Capture - check sites"
  try(ScenEdit_SetEvent, EV_CAPTURE, { mode = "remove" })
  try(ScenEdit_SetTrigger, { mode = "remove", type = "RegularTime", name = trig })
  try(ScenEdit_SetAction, { mode = "remove", type = "LuaScript", name = act })
  local body = string.gsub(string.gsub(WEIGHT_SRC .. CAPTURE_SRC, "\r\n", "\n"), "\n", "\r\n")
  local ok = true
  if not try(ScenEdit_SetEvent, EV_CAPTURE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then ok = false end
  if not try(ScenEdit_SetTrigger, { mode = "add", type = "RegularTime", name = trig, interval = 4 }) then ok = false end
  try(ScenEdit_SetEventTrigger, EV_CAPTURE, { mode = "add", name = trig })
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = act, ScriptText = body }) then ok = false end
  try(ScenEdit_SetEventAction, EV_CAPTURE, { mode = "add", name = act })
  say("---- Capture ----")
  if ok then
    say("  event '" .. EV_CAPTURE .. "' created: " .. #sites .. " capturable sites, " .. #land .. " land combat units watched.")
    say("  A site changes side when enemy land combat units are within " .. CONFIG.CAPTURE_RANGE_KM
        .. " km, no defending land combat unit is, for " .. CONFIG.CAPTURE_HOLD_MINUTES .. " game minutes.")
    say("  Aircraft and ships at the site change side with it; site and units count as losses in the score.")
    say("  In the Event Editor: check it is repeatable and its timer trigger shows 1 minute or less.")
  else
    say("  !! could not create the capture event: " .. tostring(_errmsg_ or ""))
  end
end

-- ============================== main ==============================
local function main()
  say("Benelux war readiness - build " .. tostring(try(GetBuildNumber)))
  local P = CONFIG.PHASES
  local sideData = {}
  for _, sideName in ipairs(CONFIG.SIDES) do
    local r = collect(sideName)
    if not r then
      say("==== " .. sideName .. ": side not found - skipped")
    else
      say("==== " .. sideName .. ": " .. #r.air .. " aircraft, " .. #r.ships .. " ships, " .. #r.land
          .. " land combat units, " .. #r.bunkers .. " ammo bunkers")
      if P.swaps then
        phaseSwaps(sideName, r)
        r = collect(sideName)            -- swapped units have new IDs
      end
      if P.airswaps then
        phaseAirSwaps(sideName, r)
        r = collect(sideName)
      end
      if P.airdefence then
        phaseAirDefence(sideName, r)
        r = collect(sideName)            -- include the new platoons in the later steps
      end
      if P.loadouts then phaseLoadouts(sideName, r) end
      if P.airbases then phaseAirbases(sideName, r) end
      if P.topup then phaseTopUp(sideName, r) end
      if P.landmags then phaseLandMags(sideName, r) end
      if P.trucks then phaseTrucks(sideName, r) end
      if P.depots then phaseDepots(sideName, r) end
      if P.ports then phasePorts(sideName, r) end
      sideData[sideName] = collect(sideName)
    end
  end
  if P.resupply then setupResupply(sideData) end
  if P.capture then setupCapture(sideData) end
  if P.scoring then
    if #CONFIG.SIDES == 2 then
      setupScoring(CONFIG.SIDES[1], CONFIG.SIDES[2])
    else
      say("Scoring needs exactly two sides in CONFIG.SIDES - skipped")
    end
  end
  say("Finished. Check one airfield, one platoon and one port in the editor before saving.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Ammo truck resupply - timer)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Ammo truck resupply - refill)!
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Capture - timer)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Capture - check sites)!
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands decisive)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium decisive)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - end scenario)!
Benelux war readiness - build v1.10 - Build 1900.20
==== Netherlands: 156 aircraft, 12 ships, 115 land combat units, 6 ammo bunkers
  swaps: 0 land units replaced, 0 failed
  loadouts: 156 aircraft armed, 0 failed, 0 left as they were
  airbase Volkel AB: 0 stores added
  airbase Eindhoven AB: 0 stores added
  airbase Gilze-Rijen AB: 0 stores added
  airbase Leeuwarden AB: 0 stores added
  airbase De Kooy Airfield: 0 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 0 units given a magazine (0 rounds), 115 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  depots: 6 ammo bunkers filled with 95208 rounds
  port Nieuwu Haven NB (Den Helder): reloads for 12 ships, 0 rounds added
==== Belgium: 126 aircraft, 7 ships, 82 land combat units, 4 ammo bunkers
  swaps: 0 land units replaced, 0 failed
  aircraft swaps: 0 replaced, 0 failed
  air defence: 0 Mistral platoons placed, 8 already there, 0 failed
  loadouts: 110 aircraft armed, 0 failed, 16 left as they were
  airbase Kleine-Brogel AB: 0 stores added
  airbase Koksijde AB: 0 stores added
  airbase Melsbroek AB: 0 stores added
  airbase Florennes AB: 0 stores added
  airbase Beauvechain AB: 0 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 0 units given a magazine (0 rounds), 82 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  depots: 4 ammo bunkers filled with 8048 rounds
  port Zeebrugge NB: reloads for 7 ships, 0 rounds added
---- Truck resupply ----
  event 'Ammo truck resupply at depots' created for 20 truck platoons and 10 ammo bunkers.
  A truck parked within 1.0 km of a friendly ammo bunker is refilled from it, checked every 5 game minutes.
  In the Event Editor: check it is repeatable and its timer trigger shows an interval of 1 minute or less.
---- Capture ----
  event 'Base and depot capture' created: 39 capturable sites, 197 land combat units watched.
  A site changes side when enemy land combat units are within 2.0 km, no defending land combat unit is, for 10 game minutes.
  Aircraft and ships at the site change side with it; site and units count as losses in the score.
  In the Event Editor: check it is repeatable and its timer trigger shows 1 minute or less.
---- Scoring ----
  Netherlands: 330 units = 1000 points for the enemy if all are destroyed
      aircraft                              344 pts
      bases, radars and air defence          61 pts
      land forces (added by script)         452 pts
      other facilities                        1 pts
      ships                                 142 pts
  Belgium: 256 units = 1000 points for the enemy if all are destroyed
      aircraft                              376 pts
      bases, radars and air defence          59 pts
      land forces (added by script)         484 pts
      other facilities                        1 pts
      ships                                  80 pts
  event 'Loss scoring (zero-sum)' created. Open the Event Editor and check it is ticked as repeatable.
  Now set the thresholds for BOTH sides in the editor's scoring window:
  Disaster -1000 ... Triumph +1000 (e.g. -1000 / -400 / +400 / +1000).
Finished. Check one airfield, one platoon and one port in the editor before saving.
...
07/10/2026 19:24:21 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  TROOP TRUCK TEST  - run on a SCRATCH COPY of the scenario
--  Places three Ural-4320 trucks (29 seats each) beside one Dutch infantry
--  platoon and tries one scripted load, to find out whether trucks can
--  carry your platoon-type units in this build.
--  To remove the test units afterwards, set CLEANUP = true and run again.
-- =====================================================================
local SIDE         = "Netherlands"
local ANCHOR_NAME  = "[INF] 11 Infbat GGJ A-Cie"   -- trucks go beside the first platoon of this company
local TRUCK_DBID   = 310      -- Ural-4320 (ground-unit class), carries 29 troops
local PLATOON_DBID = 550      -- Inf Plt (German Army), 16 troops - what your Dutch infantry now are
local CLEANUP      = false

local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function dump(v, depth)
  depth = depth or 0
  if type(v) ~= "table" then return tostring(v) end
  if depth > 3 then return "{...}" end
  local parts, n = {}, 0
  for k, x in pairs(v) do
    n = n + 1
    if n > 30 then parts[#parts + 1] = "..." break end
    parts[#parts + 1] = tostring(k) .. "=" .. dump(x, depth + 1)
  end
  return "{" .. table.concat(parts, ", ") .. "}"
end

local function main()
  local side = try(VP_GetSide, { side = SIDE })
  if not side then say("Side '" .. SIDE .. "' not found") return end

  local anchor, old = nil, {}
  for _, ref in pairs(side.units) do
    local u = try(ScenEdit_GetUnit, { guid = ref.guid })
    local name = tostring(prop(u, "name"))
    if u and string.sub(name, 1, 6) == "[TEST]" then old[#old + 1] = ref.guid end
    if u and not anchor and string.sub(name, 1, #ANCHOR_NAME) == ANCHOR_NAME then anchor = u end
  end

  if CLEANUP then
    local n = 0
    for _, g in ipairs(old) do
      try(ScenEdit_DeleteUnit, { side = SIDE, guid = g })
      if not try(ScenEdit_GetUnit, { guid = g }) then n = n + 1 end
    end
    say("Cleanup: removed " .. n .. " of " .. #old .. " test units")
    return
  end
  if #old > 0 then say("Test units already exist (" .. #old .. "). Set CLEANUP = true to remove them first.") return end
  if not anchor then say("Could not find a unit whose name starts with '" .. ANCHOR_NAME .. "'") return end
  local lat, lon = tonumber(prop(anchor, "latitude")), tonumber(prop(anchor, "longitude"))
  say("Anchor: " .. tostring(prop(anchor, "name")) .. " [" .. tostring(prop(anchor, "classname")) .. "] at " .. lat .. ", " .. lon)

  -- 1. which unit type name creates a ground-unit-class vehicle?
  local workingType, trucks = nil, {}
  for _, t in ipairs({ "Ground", "GroundUnit", "Ground Unit", "Land", "Mobile", "Vehicle", "Facility" }) do
    local u = try(ScenEdit_AddUnit, { side = SIDE, type = t, unitname = "[TEST] Truck 1", dbid = TRUCK_DBID,
                                      latitude = lat + 0.002, longitude = lon + 0.002 })
    if u then
      local cls = tostring(prop(u, "classname"))
      if string.find(string.lower(cls), "ural", 1, true) then
        workingType = t
        trucks[1] = u
        say("1. Truck created with type = '" .. t .. "': " .. cls .. " (unit type reported as " .. tostring(prop(u, "type")) .. ")")
        break
      else
        say("   type '" .. t .. "' created the wrong thing (" .. cls .. ") - removed")
        try(ScenEdit_DeleteUnit, { side = SIDE, guid = u.guid })
      end
    end
  end
  if not workingType then
    say("1. FAILED: no unit type name created a Ural truck. Trucks cannot be scripted in this build as written.")
    say("   Try adding one by hand in the editor (Add Unit > ground units > Ural-4320) and tell me what you see.")
    return
  end
  for i = 2, 3 do
    trucks[i] = try(ScenEdit_AddUnit, { side = SIDE, type = workingType, unitname = "[TEST] Truck " .. i, dbid = TRUCK_DBID,
                                        latitude = lat + 0.002 + 0.001 * i, longitude = lon + 0.002 })
  end
  say("   trucks placed: " .. ((trucks[2] and trucks[3]) and "3" or "fewer than 3"))

  -- 2. what does an empty truck's cargo look like?
  local t1 = try(ScenEdit_GetUnit, { guid = trucks[1].guid })
  say("2. Empty truck cargo: " .. dump(prop(t1, "cargo")))

  -- 3. scripted load: one infantry platoon (platoon-type unit) into truck 3
  if trucks[3] then
    local r = try(ScenEdit_UpdateUnitCargo, { guid = trucks[3].guid, mode = "add_cargo", cargo = { { 1, PLATOON_DBID, 3 } } })
    local t3 = try(ScenEdit_GetUnit, { guid = trucks[3].guid })
    say("3. Scripted load of one infantry platoon into Truck 3: " .. (r and "call accepted" or ("call refused " .. tostring(_errmsg_ or ""))))
    say("   Truck 3 cargo now: " .. dump(prop(t3, "cargo")))
  end
  say("Now do the manual test described in the chat with Truck 1 and Truck 2.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_AddUnit (0)  Error:Type cannot be GROUND please choose one of the following: SHIP, SUB, AIRCRAFT, FACILITY, GROUND UNIT, SATELLITE, WEAPON
... 
Function:ScenEdit_AddUnit (0)  Error:Type cannot be GROUNDUNIT please choose one of the following: SHIP, SUB, AIRCRAFT, FACILITY, GROUND UNIT, SATELLITE, WEAPON
Anchor: [INF] 11 Infbat GGJ A-Cie /1 [Inf Plt (German Army)] at 52.040491555875, 5.8786463426873
1. Truck created with type = 'Ground Unit': Ural-4320 (unit type reported as Vehicle)
   trucks placed: 3
2. Empty truck cargo: {}
3. Scripted load of one infantry platoon into Truck 3: call accepted
   Truck 3 cargo now: {1={guid=I8MHTP-0HNP4GVAGOGKH, cargo={1={mass=1.6000000238419, name=Inf Plt (German Army) #6280, crew=16.0, area=2.5599999427795, status=Operational, guid=I8MHTP-0HNP4GVAGOGKO, quantity=1, Type=3, dbid=550}}, name=[TEST] Truck 3}}
Now do the manual test described in the chat with Truck 1 and Truck 2.
...
07/10/2026 19:40:59 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX WAR READINESS
--  Command: Modern Operations 1.10 (build 1900.20), DB3K_519
--  Run from Editor > Lua Script Console.  SAVE A COPY OF THE SCENARIO FIRST.
-- =====================================================================
--  All IDs below were read from your DB3K_519 database and your inventory.
--  Phases (each can be switched off in CONFIG.PHASES):
--   1 swaps     replace stand-in land units with the closest real entry
--   2 loadouts  give aircraft combat loadouts, armed and ready
--   3 airbases  stock each airfield with sortie reloads for its aircraft
--   4 topup     fill every ship / SAM / land unit weapon record to maximum
--   5 landmags  give each land combat unit its own magazine with one extra
--               basic load of exactly the ammunition its weapons fire
--   6 trucks    ammo truck platoons with each garrison, pre-loaded
--   7 depots    fill the [DEPOT] ammo bunkers
--   8 ports     stock each naval base with reloads for the ships homed there
--   9 scoring   (re)build the zero-sum loss scoring so that each side's whole
--               force, including everything added above, is worth 1000 points
--  10 resupply  a repeating event: an ammo truck parked within RESUPPLY_RANGE_KM of a
--               friendly [DEPOT] ammo bunker is refilled from the bunker's stock
--  11 capture   a repeating event: airfields, ports and [DEPOT] buildings change side when
--               enemy land combat units hold them with no defenders nearby
--  12 trooptrucks  one Ural-4320 (29 seats) per foot-infantry platoon at each garrison
--  Phase 1a (airswaps) replaces the unarmed Belgian SF.260EA trainers with armed SF.260W.
--  Phase 1b (airdefence) adds Belgian Mistral platoons at airfields, the port
--  and the two brigade garrisons.
--
--  The functions this script has never used in your build (stocking a
--  magazine, adding a magazine, deleting a unit) are each checked on the
--  first unit by reading the result back. If a check fails, that phase
--  stops and says so; nothing is done blind.
--  Safe to run again: every stock is topped up to its target, never doubled,
--  and units that already exist are skipped.
-- =====================================================================

local CONFIG = {
  SIDES = { "Netherlands", "Belgium" },
  PHASES = { swaps = true, airswaps = true, airdefence = true, loadouts = true, airbases = true, topup = true,
             landmags = true, trucks = true, depots = true, ports = true, scoring = true, resupply = true, capture = true, trooptrucks = true },

  SORTIES_PER_AIRCRAFT = 6,     -- reloads of its loadout stocked at the home airfield
  TRANSPORT_SORTIES    = 2,     -- same, for troop / cargo / passenger loads
  LAND_EXTRA_LOADS     = 1,     -- basic loads in each land unit's own magazine
  TRUCK_LOADS          = 2,     -- basic loads of the garrison carried by its ammo trucks
  DEPOT_LOADS          = 3,     -- basic loads of the whole army spread over its ammo bunkers
  PORT_RELOADS         = 2,     -- full reloads per ship stocked at its naval base

  RESUPPLY_RANGE_KM      = 1.0, -- how close a truck must park to a bunker to be refilled
  RESUPPLY_EVERY_MINUTES = 5,   -- how often the refill check runs (game time)

  CAPTURE_RANGE_KM     = 2.0,   -- attackers must be this close, with no defending land unit this close
  CAPTURE_HOLD_MINUTES = 10,    -- for this long (game time)

  SCORE_SCALE     = 1000,       -- total value of each side's force
  END_SCENARIO_AT = nil,        -- e.g. 600 = end the game when a side reaches +600
}

-- extra air defence: one platoon beside every airfield and port of the side, plus the listed points
local AIR_DEFENCE = {
  Belgium = {
    dbid = 1664,                -- SAM Plt (Mistral ATLAS), Belgium
    label = "Mistral",
    extra = {
      { name = "Leopoldsburg", lat = 51.117, lon = 5.257 },
      { name = "Marche-en-Famenne", lat = 50.245, lon = 5.325 },
    },
  },
}

-- aircraft DBID -> loadout IDs, dealt out in turn to the aircraft of that type
local LOADOUTS = {
  -- Netherlands
  [3167] = { 16877, 16898, 16877, 19854 },  -- F-16AM: AIM-120B air-to-air / GBU-49 strike / air-to-air / SDB
  [3902] = { 19576, 21735, 19576, 19583 },  -- F-35A: AIM-120C-7 internal / SDB / air-to-air / JDAM
  [4824] = { 5816, 5815 },                  -- AH-64D: Hellfire + rockets / Hellfire only
  [656]  = { 5764, 5764, 15377 },           -- NH90 NFH: ASW torpedoes + sonobuoys / maritime surveillance
  [3960] = { 19856 },                       -- MQ-9A: recon
  [4067] = { 20185 }, [4068] = { 20185 },   -- C-130H: cargo
  [4069] = { 20191 },                       -- Cougar: troops
  [4070] = { 20198 },                       -- CH-47F: troops
  [4708] = { 30311 },                       -- A330 MRTT: tanker
  [2956] = { 15778 },                       -- Gulfstream: passengers
  -- Belgium
  -- Belgian fighters get the AIM-120D on purpose (later than the scenario date) to offset
  -- the Dutch advantage in numbers, radar and SAMs. For the period-correct AIM-120B use 15507.
  [2248] = { 32301, 5385, 32301, 11259 },   -- F-16AM: AIM-120D air-to-air / GBU-12 strike / air-to-air / JDAM
  [3263] = { 32301, 5385, 32301, 11259 },   -- F-16BM: same
  [1512] = { 247, 247, 15946 },             -- A-109BA: TOW / TOW / scout
  [2001] = { 8870 },                        -- RQ-5A: recon
  [8132] = { 22410, 22410, 22410, 22409 },  -- SF.260W Warrior: 68mm rockets x3 / 7.62mm gun pods
}

-- loadout ID -> stores it needs: { weapon DBID, quantity }
local LOADOUT_STORES = {
  [16877] = { {446,4}, {1763,2}, {2780,2}, {149,1}, {544,1} },
  [16898] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {2061,2} },
  [19854] = { {446,2}, {544,1}, {1763,2}, {2780,2}, {149,1}, {484,8} },
  [19576] = { {718,4} },
  [21735] = { {484,8}, {718,2} },
  [19583] = { {554,2}, {718,2} },
  [5816]  = { {683,8}, {1929,38} },
  [5815]  = { {683,16} },
  [5764]  = { {1647,2}, {2478,34}, {2481,16} },
  [247]   = { {833,8} },
  [15507] = { {446,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  [32301] = { {51,4}, {1763,2}, {1384,2}, {149,1}, {459,1} },
  -- transports: troops / cargo / passengers (stocked for TRANSPORT_SORTIES only)
  [20185] = { {2611,1} }, [20191] = { {801,20} }, [20198] = { {801,33} }, [15778] = { {2624,18} },
  [22410] = { {163,12} }, [22409] = { {2655,15} },   -- SF.260W: SNEB rockets / gun pod ammunition
  [4336] = { {2225,1} }, [13593] = { {2121,1} }, [9952] = { {2624,199} },
  [5385]  = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {1906,2} },
  [11259] = { {459,1}, {446,2}, {1763,2}, {1384,2}, {149,1}, {93,2} },
}

-- land unit swaps: current class name -> replacement facility DBID per side
local SWAPS = {
  Netherlands = {
    ["Inf Plt (Russian Army)"]                 = 550,   -- Inf Plt (German Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 3244, -- Inf Sec (Kommando Spezialkraefte)
    ["Mech Inf Plt (Boxer APC x 3)"]           = 2878,  -- Motor Inf Plt (Boxer APC x 4), Netherlands
    ["Mech Inf Plt (CV 9035 x 4)"]             = 5097,  -- Mech Inf Plt (CV 9035NL x 4)
  },
  Belgium = {
    ["Inf Plt (Russian Army)"]                 = 2317,  -- Inf Plt (French Army)
    ["Vehicle (Soft Ball ELS [KRTP-81 Ramona])"] = 3244, -- Inf Sec (Kommando Spezialkraefte), has C-4 like the Dutch
    ["Inf Sec (COS Recon [Laser Designator])"]   = 3244, -- replaces the earlier pick, which had no explosives
    ["Motor Inf Plt (Pandur I APC x 4)"]       = 2948,  -- the Belgian Pandur entry
  },
}

-- aircraft swaps: current aircraft DBID -> replacement (kept at the same base, same name)
local AIRCRAFT_SWAPS = {
  Belgium = {
    [4416] = { dbid = 8132, loadout = 22410 },   -- SF.260EA trainer -> SF.260W Warrior (armed)
  },
}

local GENERIC_MAGAZINE_DBID = 1423   -- "Generic Magazine", capacity 10000, empty
local AMMO_TRUCK_DBID       = 2086   -- "Vehicles (Ammo Truck x 4)"
local TROOP_TRUCK_DBID      = 310    -- Ural-4320 (ground-unit class), carries 29 troops = one infantry platoon
local TROOP_TRUCK_MATCH     = "ural" -- the created unit's class must contain this, as a safety check
local TRANSPORT_STORES = { [801] = true, [2611] = true, [2624] = true, [2225] = true, [2121] = true }   -- Trooper, Cargo, Passenger
local COMBAT_TAGS = { "[INF]", "[MECH]", "[ARTY]", "[RECON]", "[ENG]", "[SOF]", "[ARMOR]" }

-- =====================================================================
--  Nothing below here needs editing
-- =====================================================================
local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end
local function num(v) return tonumber(v) or 0 end
local function getUnit(guid) return try(ScenEdit_GetUnit, { guid = guid }) end
local function key(k) return try(ScenEdit_GetKeyValue, "LOOB2_" .. k) or "" end
local function setKey(k) try(ScenEdit_SetKeyValue, "LOOB2_" .. k, "yes") end
local function done(k)
  return (not CONFIG.ALLOW_REPEAT) and key(k) == "yes"
end

local function isSmallArms(name)
  local n = string.lower(tostring(name or ""))
  return string.find(n, "mg burst", 1, true) or string.find(n, "minigun", 1, true)
      or string.find(n, "rifle", 1, true) or string.find(n, "ar burst", 1, true)
end

local function hasTag(name)
  for _, t in ipairs(COMBAT_TAGS) do
    if string.sub(tostring(name), 1, #t) == t then return true end
  end
  return false
end

-- ---- reading magazines and mounts (field names taken from your inventory) ----
local function realMagazine(u)            -- the unit's real magazine (not a mount's own reload bin)
  local best
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then
        if not best or num(m.mag_capacity) > num(best.mag_capacity) then best = m end
      end
    end
  end
  return best
end

local function magRecord(mag, wpn)
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do
      if num(w.wpn_dbid) == wpn then return w end
    end
  end
  return nil
end

local function magUsed(mag)
  local n = 0
  if mag and type(mag.mag_weapons) == "table" then
    for _, w in pairs(mag.mag_weapons) do n = n + num(w.wpn_current) end
  end
  return n
end

local function unitTotal(u)               -- every round on the unit, mounts + magazines
  local n = 0
  local mags = prop(u, "magazines")
  if type(mags) == "table" then for _, m in pairs(mags) do n = n + magUsed(m) end end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do n = n + num(w.wpn_current) end
      end
    end
  end
  return n
end

-- one full load of the unit: weapon DBID -> { n = quantity at maximum, name = ... }
local function fullLoad(u, includeMagazines)
  local load = {}
  local function add(w)
    local id = num(w.wpn_dbid)
    if id ~= 0 and num(w.wpn_maxcap) > 0 then
      if not load[id] then load[id] = { n = 0, name = tostring(w.wpn_name) } end
      load[id].n = load[id].n + num(w.wpn_maxcap)
    end
  end
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then for _, w in pairs(m.mount_weapons) do add(w) end end
    end
  end
  if includeMagazines then
    local mags = prop(u, "magazines")
    if type(mags) == "table" then
      for _, m in pairs(mags) do
        if type(m.mag_weapons) == "table" then for _, w in pairs(m.mag_weapons) do add(w) end end
      end
    end
  end
  return load
end

local function mergeLoad(into, load, times)
  for id, e in pairs(load) do
    if not into[id] then into[id] = { n = 0, name = e.name } end
    into[id].n = into[id].n + e.n * (times or 1)
  end
end

-- ---- stocking magazines: tops each weapon up to a target, so re-running never doubles ----
local stockVariant = nil     -- which argument form works in this build
local stockBroken = false

local function realMagazines(u)
  local list = {}
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 then list[#list + 1] = m end
    end
  end
  return list
end

local function haveQty(u, wpn)
  local n = 0
  for _, m in ipairs(realMagazines(u)) do
    local rec = magRecord(m, wpn)
    if rec then n = n + num(rec.wpn_current) end
  end
  return n
end

local function roomiest(u)                -- real magazine with the most free space
  local best, bestRoom
  for _, m in ipairs(realMagazines(u)) do
    local room = (num(m.mag_capacity) > 0) and (num(m.mag_capacity) - magUsed(m)) or 100000
    if not best or room > bestRoom then best, bestRoom = m, room end
  end
  return best, bestRoom or 0
end

local function stockCall(variant, guid, magGuid, wpn, n, cap)
  local t = { guid = guid, wpn_dbid = wpn, number = n, new = true }
  if variant == 1 or variant == 3 then t.mag_guid = magGuid end
  if variant == 1 or variant == 2 then t.maxcap = cap end
  return try(ScenEdit_AddWeaponToUnitMagazine, t)
end

local function stock(guid, mag, wpn, n)   -- put n of a weapon into one magazine
  n = math.floor(n)
  if n <= 0 or stockBroken then return 0 end
  local rec = magRecord(mag, wpn)
  local inMag = rec and num(rec.wpn_current) or 0
  local cap = math.max(rec and num(rec.wpn_maxcap) or 0, inMag + n)
  if stockVariant then
    stockCall(stockVariant, guid, mag.mag_guid, wpn, n, cap)
    return n
  end
  local u = getUnit(guid)
  local before = u and haveQty(u, wpn) or 0
  for v = 1, 4 do                          -- first use: find the form that works
    stockCall(v, guid, mag.mag_guid, wpn, n, cap)
    local u2 = getUnit(guid)
    local after = u2 and haveQty(u2, wpn) or 0
    if after > before then
      stockVariant = v
      try(ScenEdit_SetKeyValue, "LOOB2_variant", tostring(v))
      return after - before
    end
  end
  stockBroken = true
  say("  !! CHECK FAILED: could not add weapons to a magazine in this build (ScenEdit_AddWeaponToUnitMagazine).")
  say("     All stocking phases are skipped. Tell me this line and I will use another method.")
  return 0
end

-- Bring a unit's magazines up to the target load. Scarce items (missiles, torpedoes) go in
-- first, bulk ammunition next, small arms and troop/cargo loads last. With extraMags > 0 the
-- unit is given further magazines when it runs out of room.
local function stockLoad(guid, load, times, extraMags)
  local order = {}
  for id, e in pairs(load) do
    order[#order + 1] = { id = id, n = math.floor(e.n * (times or 1)),
                          low = (isSmallArms(e.name) or TRANSPORT_STORES[id]) and 1 or 0 }
  end
  table.sort(order, function(a, b)
    if a.low ~= b.low then return a.low < b.low end
    if a.n ~= b.n then return a.n < b.n end
    return a.id < b.id
  end)
  local added, cut, grown = 0, 0, 0
  for _, o in ipairs(order) do
    local u = getUnit(guid)
    if not u or stockBroken then break end
    local need = o.n - haveQty(u, o.id)
    local guard = 0
    while need > 0 and guard < 8 do
      guard = guard + 1
      local mag, room = roomiest(u)
      if not mag then break end
      if room <= 0 then
        if grown >= (extraMags or 0) then break end
        try(ScenEdit_UpdateUnit, { guid = guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        grown = grown + 1
      else
        local give = math.min(need, room)
        local got = stock(guid, mag, o.id, give)
        if got <= 0 then break end
        added = added + got
        need = need - give
      end
      u = getUnit(guid)
      if not u then break end
    end
    if need > 0 then cut = cut + need end
  end
  return added, cut, grown
end

-- ---- collecting units ----
local function collect(sideName)
  local side = try(VP_GetSide, { side = sideName })
  local r = { air = {}, ships = {}, land = {}, bunkers = {}, others = {} }
  if not side then return nil end
  for _, ref in pairs(side.units) do
    local u = getUnit(ref.guid)
    if u then
      local t = tostring(prop(u, "type"))
      local name = tostring(prop(u, "name"))
      local cls = tostring(prop(u, "classname"))
      local e = { guid = ref.guid, name = name, cls = cls, dbid = num(prop(u, "dbid")),
                  lat = num(prop(u, "latitude")), lon = num(prop(u, "longitude")) }
      if t == "Aircraft" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.air[#r.air + 1] = e
      elseif t == "Ship" or t == "Submarine" then
        local b = prop(u, "base")
        e.base = b and prop(b, "guid") or nil
        e.baseName = b and tostring(prop(b, "name")) or nil
        r.ships[#r.ships + 1] = e
      elseif t == "Facility" then
        if hasTag(name) then
          r.land[#r.land + 1] = e
        elseif string.sub(name, 1, 7) == "[DEPOT]" and string.find(cls, "Ammo", 1, true) then
          r.bunkers[#r.bunkers + 1] = e
        else
          r.others[#r.others + 1] = e
        end
      end
    end
  end
  local byName = function(a, b) return a.name < b.name end
  table.sort(r.air, byName) table.sort(r.ships, byName) table.sort(r.land, byName) table.sort(r.bunkers, byName)
  return r
end

-- ---- scoring (zero-sum, each side scaled to SCORE_SCALE) ----
-- The weights exist twice: as text (stored inside the scoring event) and as
-- real code (used now). If you change the values, change BOTH copies.
local KEY = "LOOB_"
local EV_SCORE = "Loss scoring (zero-sum)"
local EV_END = "Loss scoring - decisive result"
local function scoreKey(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end

local WEIGHT_SRC = [[
local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[truck]', 2}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end
]]

local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[truck]', 2}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

local function quote(s)
  s = string.gsub(tostring(s), "\\", "\\\\")
  s = string.gsub(s, '"', '\\"')
  return '"' .. s .. '"'
end

local function sideTotal(side, weight)
  local s = try(VP_GetSide, { side = side })
  local total, count, buckets = 0, 0, {}
  if s and s.units then
    for _, ref in pairs(s.units) do
      local u = try(ScenEdit_GetUnit, { guid = ref.guid })
      if u then
        local w, bucket = weight(u)
        if w > 0 then
          total = total + w
          count = count + 1
          buckets[bucket] = (buckets[bucket] or 0) + w
        end
      end
    end
  end
  return total, count, buckets
end

local function actionScript(A, B)
  local body = WEIGHT_SRC .. [[
local A, B = ]] .. quote(A) .. ", " .. quote(B) .. [[

local u = ScenEdit_UnitX()
if u == nil then return end
local owner = tostring(u.side or '')
if owner ~= A and owner ~= B then return end
local w = LS_weight(u)
if w <= 0 then return end
local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
local lostKey = 'LOOB_lost_' .. owner
ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
local delta = netA - num('LOOB_applied')
if delta ~= 0 then
  local why = owner .. ' lost ' .. tostring(u.name)
  ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
  ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
  ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
end
]]
  body = string.gsub(body, "\r\n", "\n")
  body = string.gsub(body, "\n", "\r\n")
  return body
end

local function removeEvent(ev, triggers, actions)
  try(ScenEdit_SetEvent, ev, { mode = "remove" })
  for _, t in ipairs(triggers) do try(ScenEdit_SetTrigger, { mode = "remove", type = t.type, name = t.name }) end
  for _, a in ipairs(actions) do try(ScenEdit_SetAction, { mode = "remove", type = a.type, name = a.name }) end
end

local function setupScoring(A, B)
  local weight = LS_weight
  local problems = 0

  say("---- Scoring ----")
  for _, side in ipairs({ A, B }) do
    local total, count, buckets = sideTotal(side, weight)
    if total <= 0 then
      say("  " .. side .. ": no scoreable units found - scoring NOT set up for this side")
      problems = problems + 1
      scoreKey(KEY .. "scale_" .. side, 0)
    else
      local scale = CONFIG.SCORE_SCALE / total
      scoreKey(KEY .. "scale_" .. side, scale)
      say(string.format("  %s: %d units = %d points for the enemy if all are destroyed", side, count, CONFIG.SCORE_SCALE))
      local names = {}
      for b, _ in pairs(buckets) do names[#names + 1] = b end
      table.sort(names)
      for _, b in ipairs(names) do
        say(string.format("      %-34s %6.0f pts", b, buckets[b] * scale))
      end
    end
    scoreKey(KEY .. "lost_" .. side, 0)
  end
  scoreKey(KEY .. "applied", 0)

  local trigs = {
    { type = "UnitDestroyed", name = "Loss scoring - " .. A .. " unit destroyed", side = A },
    { type = "UnitDestroyed", name = "Loss scoring - " .. B .. " unit destroyed", side = B },
  }
  local acts = { { type = "LuaScript", name = "Loss scoring - apply points" } }
  removeEvent(EV_SCORE, trigs, acts)

  if not try(ScenEdit_SetEvent, EV_SCORE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then
    say("  could not create the event: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  for _, t in ipairs(trigs) do
    if not try(ScenEdit_SetTrigger, { mode = "add", type = t.type, name = t.name,
                                      TargetFilter = { TargetSide = t.side } }) then
      say("  could not create trigger '" .. t.name .. "': " .. tostring(_errmsg_ or ""))
      problems = problems + 1
    end
    try(ScenEdit_SetEventTrigger, EV_SCORE, { mode = "add", name = t.name })
  end
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = acts[1].name,
                                   ScriptText = actionScript(A, B) }) then
    say("  could not create the scoring action: " .. tostring(_errmsg_ or ""))
    problems = problems + 1
  end
  try(ScenEdit_SetEventAction, EV_SCORE, { mode = "add", name = acts[1].name })

  -- optional early end
  local endTrigs = {
    { type = "Points", name = "Loss scoring - " .. A .. " decisive", side = A },
    { type = "Points", name = "Loss scoring - " .. B .. " decisive", side = B },
  }
  local endActs = { { type = "EndScenario", name = "Loss scoring - end scenario" } }
  removeEvent(EV_END, endTrigs, endActs)
  if CONFIG.END_SCENARIO_AT then
    try(ScenEdit_SetEvent, EV_END, { mode = "add", IsActive = true, IsRepeatable = false, IsShown = true })
    for _, t in ipairs(endTrigs) do
      try(ScenEdit_SetTrigger, { mode = "add", type = "Points", name = t.name, SideID = t.side,
                                 PointValue = CONFIG.END_SCENARIO_AT, ReachDirection = 0 })
      try(ScenEdit_SetEventTrigger, EV_END, { mode = "add", name = t.name })
    end
    try(ScenEdit_SetAction, { mode = "add", type = "EndScenario", name = endActs[1].name })
    try(ScenEdit_SetEventAction, EV_END, { mode = "add", name = endActs[1].name })
    say("  scenario ends when either side reaches +" .. CONFIG.END_SCENARIO_AT)
  end

  if problems == 0 then
    say("  event '" .. EV_SCORE .. "' created. Open the Event Editor and check it is ticked as repeatable.")
  end
  say("  Now set the thresholds for BOTH sides in the editor's scoring window:")
  say("  Disaster -" .. CONFIG.SCORE_SCALE .. " ... Triumph +" .. CONFIG.SCORE_SCALE .. " (e.g. -1000 / -400 / +400 / +1000).")
end

-- ============================ phases ============================
local function phaseAirDefence(sideName, r)
  local ad = AIR_DEFENCE[sideName]
  if not ad then return end
  local spots = {}
  for _, e in ipairs(r.others) do
    if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true) then
      spots[#spots + 1] = { name = e.name, lat = e.lat, lon = e.lon }
    end
  end
  for _, x in ipairs(ad.extra or {}) do spots[#spots + 1] = x end
  local made, existed, failed = 0, 0, 0
  for _, sp in ipairs(spots) do
    local name = "[AD] " .. ad.label .. " " .. sp.name
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local placed = false
      for _, o in ipairs({ { 0.008, -0.012 }, { -0.008, 0.012 }, { -0.010, -0.014 }, { 0.010, 0.014 }, { -0.020, 0.0 }, { 0.0, 0.030 } }) do
        if try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = ad.dbid,
                                   latitude = sp.lat + o[1], longitude = sp.lon + o[2] }) then
          placed = true
          break
        end
      end
      if placed then made = made + 1 else failed = failed + 1 say("  could not place '" .. name .. "'") end
    end
  end
  say("  air defence: " .. made .. " " .. ad.label .. " platoons placed, " .. existed .. " already there, " .. failed .. " failed")
end

local function phaseAirSwaps(sideName, r)
  local map = AIRCRAFT_SWAPS[sideName]
  if not map then return end
  local okN, failN, stuck = 0, 0, 0
  for _, e in ipairs(r.air) do
    local sw = map[e.dbid]
    if sw and e.base then
      -- create the replacement first, so nothing is lost if this build refuses it
      local nu
      for _, t in ipairs({ "Air", "Aircraft" }) do
        nu = try(ScenEdit_AddUnit, { side = sideName, type = t, unitname = e.name, dbid = sw.dbid,
                                     loadoutid = sw.loadout, base = e.base })
        if nu then break end
      end
      if not nu then
        failN = failN + 1
        if okN == 0 then
          say("  !! CHECK FAILED: could not create an aircraft inside " .. tostring(e.baseName)
              .. ", so no aircraft were swapped on this side. Nothing was removed.")
          return
        end
      else
        try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
        if getUnit(e.guid) then stuck = stuck + 1 end
        okN = okN + 1
      end
    end
  end
  say("  aircraft swaps: " .. okN .. " replaced, " .. failN .. " failed"
      .. ((stuck > 0) and (", " .. stuck .. " old aircraft could not be removed - delete them by hand") or ""))
end

local function phaseSwaps(sideName, r)
  local map = SWAPS[sideName]
  if not map then return end
  local okN, failN, checked = 0, 0, false
  for _, e in ipairs(r.land) do
    local target = map[e.cls]
    if target and e.dbid ~= target then
      try(ScenEdit_DeleteUnit, { side = sideName, guid = e.guid })
      if not checked then
        checked = true
        if getUnit(e.guid) then
          say("  !! CHECK FAILED: could not delete a unit, so no land units were swapped on this side.")
          return
        end
      end
      local nu = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = target,
                                         latitude = e.lat, longitude = e.lon })
      if nu then
        okN = okN + 1
      else
        failN = failN + 1
        local back = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = e.name, dbid = e.dbid,
                                             latitude = e.lat, longitude = e.lon })
        say("  could not create DBID " .. target .. " for '" .. e.name .. "'" .. (back and " - original restored" or " - UNIT LOST, re-add it by hand"))
      end
    end
  end
  say("  swaps: " .. okN .. " land units replaced, " .. failN .. " failed")
end

local function phaseLoadouts(sideName, r)
  local dealt, setN, failN, kept = {}, 0, 0, 0
  for _, e in ipairs(r.air) do
    local list = LOADOUTS[e.dbid]
    if list then
      dealt[e.dbid] = (dealt[e.dbid] or 0) + 1
      local want = list[((dealt[e.dbid] - 1) % #list) + 1]
      try(ScenEdit_SetLoadout, { unitname = e.guid, LoadoutID = want, TimeToReady_Minutes = 0, IgnoreMagazines = true })
      local u = getUnit(e.guid)
      if u and num(prop(u, "loadoutdbid")) == want then
        setN = setN + 1
        e.loadout = want
      else
        failN = failN + 1
        e.loadout = u and num(prop(u, "loadoutdbid")) or 0
      end
    else
      kept = kept + 1
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
  end
  say("  loadouts: " .. setN .. " aircraft armed, " .. failN .. " failed, " .. kept .. " left as they were")
end

local function phaseAirbases(sideName, r)
  local bases = {}
  for _, e in ipairs(r.air) do
    if e.loadout == nil then
      local u = getUnit(e.guid)
      e.loadout = u and num(prop(u, "loadoutdbid")) or 0
    end
    local stores = LOADOUT_STORES[e.loadout]
    if e.base and stores then
      if not bases[e.base] then bases[e.base] = { name = e.baseName, load = {} } end
      for _, s in ipairs(stores) do
        local l = bases[e.base].load
        if not l[s[1]] then l[s[1]] = { n = 0, name = "" } end
        l[s[1]].n = l[s[1]].n + s[2] * (TRANSPORT_STORES[s[1]] and CONFIG.TRANSPORT_SORTIES or CONFIG.SORTIES_PER_AIRCRAFT)
      end
    end
  end
  for guid, b in pairs(bases) do
    local added, cut = stockLoad(guid, b.load, 1, 2)
    say("  airbase " .. tostring(b.name) .. ": " .. added .. " stores added" .. ((cut > 0) and (", " .. cut .. " did not fit") or ""))
  end
end

local function topUpUnit(guid)
  local u = getUnit(guid)
  if not u then return 0 end
  local before = unitTotal(u)
  local mounts = prop(u, "mounts")
  if type(mounts) == "table" then
    for _, m in pairs(mounts) do
      if type(m.mount_weapons) == "table" then
        for _, w in pairs(m.mount_weapons) do
          if num(w.wpn_current) < num(w.wpn_maxcap) then
            try(ScenEdit_AddReloadsToUnit, { guid = guid, mount_guid = m.mount_guid, wpn_dbid = num(w.wpn_dbid), fillout = true })
          end
        end
      end
    end
  end
  local mags = prop(u, "magazines")
  if type(mags) == "table" then
    for _, m in pairs(mags) do
      if num(m.mag_dbid) ~= 0 and type(m.mag_weapons) == "table" then
        for _, w in pairs(m.mag_weapons) do
          if num(w.wpn_default) > 0 and num(w.wpn_current) < num(w.wpn_default) then
            try(ScenEdit_AddWeaponToUnitMagazine, { guid = guid, mag_guid = m.mag_guid, wpn_dbid = num(w.wpn_dbid),
                                                    number = num(w.wpn_default) - num(w.wpn_current) })
          end
        end
      end
    end
  end
  local u2 = getUnit(guid)
  return (u2 and unitTotal(u2) or before) - before
end

local function phaseTopUp(sideName, r)
  local gained, n = 0, 0
  for _, list in ipairs({ r.ships, r.land, r.others }) do
    for _, e in ipairs(list) do
      local g = topUpUnit(e.guid)
      if g > 0 then gained = gained + g n = n + 1 end
    end
  end
  say("  top-up: " .. n .. " units were below maximum, " .. gained .. " rounds added")
end

local magBroken = false
local function phaseLandMags(sideName, r)
  local addedMag, had, stocked, failed = 0, 0, 0, 0
  for _, e in ipairs(r.land) do
    if magBroken then break end
    local u = getUnit(e.guid)
    if u then
      if realMagazine(u) then
        had = had + 1
      else
        try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine", dbid = GENERIC_MAGAZINE_DBID })
        u = getUnit(e.guid)
        if not (u and realMagazine(u)) then
          try(ScenEdit_UpdateUnit, { guid = e.guid, mode = "add_magazine_only", dbid = GENERIC_MAGAZINE_DBID })
          u = getUnit(e.guid)
        end
        if u and realMagazine(u) then
          addedMag = addedMag + 1
          local got = stockLoad(e.guid, fullLoad(u, false), CONFIG.LAND_EXTRA_LOADS)
          stocked = stocked + got
        else
          failed = failed + 1
          if addedMag == 0 then
            magBroken = true
            say("  !! CHECK FAILED: could not add a magazine to '" .. e.name .. "' (ScenEdit_UpdateUnit add_magazine).")
            say("     Land units keep only what they carry. Tell me this line and I will try another method.")
          end
        end
      end
    end
  end
  say("  land magazines: " .. addedMag .. " units given a magazine (" .. stocked .. " rounds), "
      .. had .. " already had one, " .. failed .. " failed")
end

local function clusters(r, minUnits)
  local cl = {}
  for _, e in ipairs(r.land) do
    local k = math.floor(e.lat * 10 + 0.5) .. "," .. math.floor(e.lon * 10 + 0.5)
    if not cl[k] then cl[k] = { units = {}, lat = 0, lon = 0 } end
    local c = cl[k]
    c.units[#c.units + 1] = e
    c.lat = c.lat + e.lat
    c.lon = c.lon + e.lon
  end
  local list = {}
  for k, c in pairs(cl) do
    if #c.units >= (minUnits or 3) then
      c.key = k
      c.lat = c.lat / #c.units
      c.lon = c.lon / #c.units
      list[#list + 1] = c
    end
  end
  table.sort(list, function(a, b) return a.key < b.key end)
  return list
end

local function phaseTrucks(sideName, r)
  local made, existed, rounds = 0, 0, 0
  for i, c in ipairs(clusters(r)) do
    local name = "[SUPPLY] Ammo trucks " .. i
    if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
      existed = existed + 1
    else
      local t = try(ScenEdit_AddUnit, { side = sideName, type = "Facility", unitname = name, dbid = AMMO_TRUCK_DBID,
                                        latitude = c.lat + 0.004, longitude = c.lon + 0.006 })
      if t then
        made = made + 1
        local load = {}
        for _, e in ipairs(c.units) do
          local u = getUnit(e.guid)
          if u then mergeLoad(load, fullLoad(u, false), 1) end
        end
        rounds = rounds + stockLoad(t.guid, load, CONFIG.TRUCK_LOADS)
      end
    end
  end
  say("  ammo trucks: " .. made .. " platoons placed (" .. rounds .. " rounds loaded), " .. existed .. " already there")
end

-- ---- troop trucks ----
local groundType = nil
local function addGroundVehicle(sideName, name, lat, lon)
  local types = groundType and { groundType } or { "Ground Unit", "GroundUnit", "Ground" }   -- "Ground Unit" is the one your build accepted in the test
  local known = try(ScenEdit_GetKeyValue, "LOOB2_gtype")
  if not groundType and known and known ~= "" then types = { known } end
  for _, t in ipairs(types) do
    local u = try(ScenEdit_AddUnit, { side = sideName, type = t, unitname = name, dbid = TROOP_TRUCK_DBID,
                                      latitude = lat, longitude = lon })
    if u then
      if string.find(string.lower(tostring(prop(u, "classname"))), TROOP_TRUCK_MATCH, 1, true) then
        if not groundType then
          groundType = t
          try(ScenEdit_SetKeyValue, "LOOB2_gtype", t)
        end
        return u
      end
      try(ScenEdit_DeleteUnit, { side = sideName, guid = u.guid })   -- wrong thing was created
    end
  end
  return nil
end

local function isFootInfantry(e)
  return string.sub(e.cls, 1, 4) == "Inf " and e.cls ~= "Inf Sec (Recon)"
end

local function phaseTroopTrucks(sideName, r)
  local made, existed, failed = 0, 0, 0
  for i, c in ipairs(clusters(r, 1)) do
    local n = 0
    for _, e in ipairs(c.units) do if isFootInfantry(e) then n = n + 1 end end
    for k = 1, n do
      local name = "[TRUCK] Convoy " .. i .. " /" .. k
      if try(ScenEdit_GetUnit, { side = sideName, unitname = name }) then
        existed = existed + 1
      else
        local row, col = math.floor((k - 1) / 8), (k - 1) % 8
        if addGroundVehicle(sideName, name, c.lat - 0.006 - row * 0.001, c.lon - 0.006 + col * 0.0015) then
          made = made + 1
        else
          failed = failed + 1
          if made == 0 then
            say("  !! CHECK FAILED: could not create a troop truck (ground-unit class) on this side - skipped.")
            return
          end
        end
      end
    end
  end
  say("  troop trucks: " .. made .. " placed" .. (groundType and (" (unit type '" .. groundType .. "')") or "")
      .. ", " .. existed .. " already there, " .. failed .. " failed")
end

local function phaseDepots(sideName, r)
  if #r.bunkers == 0 then say("  depots: no [DEPOT] ammo bunkers found") return end
  local load = {}
  for _, e in ipairs(r.land) do
    local u = getUnit(e.guid)
    if u then mergeLoad(load, fullLoad(u, false), 1) end
  end
  local total, cutAll = 0, 0
  for _, b in ipairs(r.bunkers) do
    local added, cut = stockLoad(b.guid, load, CONFIG.DEPOT_LOADS / #r.bunkers, 6)
    total = total + added
    cutAll = cutAll + cut
  end
  say("  depots: " .. #r.bunkers .. " ammo bunkers filled with " .. total .. " rounds"
      .. ((cutAll > 0) and (" (" .. cutAll .. " rounds of the lowest-priority ammunition did not fit)") or ""))
end

local function phasePorts(sideName, r)
  local ports, homeless = {}, 0
  for _, e in ipairs(r.ships) do
    if e.base then
      if not ports[e.base] then ports[e.base] = { name = e.baseName, load = {}, n = 0 } end
      local u = getUnit(e.guid)
      if u then
        mergeLoad(ports[e.base].load, fullLoad(u, true), 1)
        ports[e.base].n = ports[e.base].n + 1
      end
    else
      homeless = homeless + 1
    end
  end
  for guid, p in pairs(ports) do
    local added, cut, grown = stockLoad(guid, p.load, CONFIG.PORT_RELOADS, 4)
    say("  port " .. tostring(p.name) .. ": reloads for " .. p.n .. " ships, " .. added .. " rounds added"
        .. ((grown > 0) and (", " .. grown .. " extra magazines built") or "")
        .. ((cut > 0) and (", " .. cut .. " rounds of the lowest-priority ammunition did not fit") or ""))
  end
  if homeless > 0 then say("  " .. homeless .. " ships have no home base - no port stock added for them") end

end

-- ---- ammo truck resupply at depots (repeating event) ----
local EV_RESUPPLY = "Ammo truck resupply at depots"
local RESUPPLY_SRC = [==[
local now = ScenEdit_CurrentTime()
local last = tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_last')) or 0
local every = (tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_min')) or 5) * 60
if now - last < every then return end
ScenEdit_SetKeyValue('LOOB2_resupply_last', tostring(now))
local RANGE = tonumber(ScenEdit_GetKeyValue('LOOB2_resupply_km')) or 1
local variant = tonumber(ScenEdit_GetKeyValue('LOOB2_variant')) or 1
local function try(f, ...) local ok, r = pcall(f, ...) if ok then return r end return nil end
local function split(s) local t = {} for g in string.gmatch(s or '', '[^,]+') do t[#t + 1] = g end return t end
local function n(v) return tonumber(v) or 0 end
local function km(a, b)
  local r = math.rad
  local dlat, dlon = r(n(b.latitude) - n(a.latitude)), r(n(b.longitude) - n(a.longitude))
  local h = math.sin(dlat / 2) ^ 2 + math.cos(r(n(a.latitude))) * math.cos(r(n(b.latitude))) * math.sin(dlon / 2) ^ 2
  return 6371 * 2 * math.asin(math.sqrt(h))
end
local function mags(u)
  local list = {}
  if u and type(u.magazines) == 'table' then
    for _, m in pairs(u.magazines) do
      if n(m.mag_dbid) ~= 0 and type(m.mag_weapons) == 'table' then list[#list + 1] = m end
    end
  end
  return list
end
for _, side in ipairs(split(ScenEdit_GetKeyValue('LOOB2_sides'))) do
  local bunkers = {}
  for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_bunkers_' .. side))) do
    local b = try(ScenEdit_GetUnit, { guid = g })
    if b then bunkers[#bunkers + 1] = b end
  end
  for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_trucks_' .. side))) do
    local t = try(ScenEdit_GetUnit, { guid = g })
    if t then
      for _, b in ipairs(bunkers) do
        if km(t, b) <= RANGE then
          local moved = 0
          local bm = mags(b)
          local avail = {}
          for _, sm in ipairs(bm) do
            for _, sw in pairs(sm.mag_weapons) do avail[tostring(sm.mag_guid) .. '|' .. n(sw.wpn_dbid)] = n(sw.wpn_current) end
          end
          for _, m in ipairs(mags(t)) do
            for _, w in pairs(m.mag_weapons) do
              local need = n(w.wpn_maxcap) - n(w.wpn_current)
              for _, sm in ipairs(bm) do
                if need <= 0 then break end
                for _, sw in pairs(sm.mag_weapons) do
                  local ak = tostring(sm.mag_guid) .. '|' .. n(sw.wpn_dbid)
                  if n(sw.wpn_dbid) == n(w.wpn_dbid) and (avail[ak] or 0) > 0 and need > 0 then
                    local take = math.floor(math.min(need, avail[ak]))
                    local add = { guid = t.guid, wpn_dbid = n(w.wpn_dbid), number = take, new = true }
                    if variant == 1 or variant == 3 then add.mag_guid = m.mag_guid end
                    if variant == 1 or variant == 2 then add.maxcap = n(w.wpn_maxcap) end
                    try(ScenEdit_AddWeaponToUnitMagazine, add)
                    try(ScenEdit_AddWeaponToUnitMagazine, { guid = b.guid, mag_guid = sm.mag_guid, wpn_dbid = n(w.wpn_dbid), number = take, remove = true })
                    avail[ak] = avail[ak] - take
                    need = need - take
                    moved = moved + take
                  end
                end
              end
            end
          end
          if moved > 0 then
            try(ScenEdit_SpecialMessage, side, tostring(t.name) .. ' took on ' .. moved .. ' rounds at ' .. tostring(b.name))
          end
          break
        end
      end
    end
  end
end
]==]

local function setupResupply(sideData)
  local sides = {}
  local nTrucks, nBunkers = 0, 0
  for sideName, r in pairs(sideData) do
    sides[#sides + 1] = sideName
    local trucks, bunkers = {}, {}
    for _, e in ipairs(r.others) do
      if string.sub(e.name, 1, 8) == "[SUPPLY]" then trucks[#trucks + 1] = e.guid end
    end
    for _, e in ipairs(r.bunkers) do bunkers[#bunkers + 1] = e.guid end
    try(ScenEdit_SetKeyValue, "LOOB2_trucks_" .. sideName, table.concat(trucks, ","))
    try(ScenEdit_SetKeyValue, "LOOB2_bunkers_" .. sideName, table.concat(bunkers, ","))
    nTrucks = nTrucks + #trucks
    nBunkers = nBunkers + #bunkers
  end
  table.sort(sides)
  try(ScenEdit_SetKeyValue, "LOOB2_sides", table.concat(sides, ","))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_km", tostring(CONFIG.RESUPPLY_RANGE_KM))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_min", tostring(CONFIG.RESUPPLY_EVERY_MINUTES))
  try(ScenEdit_SetKeyValue, "LOOB2_resupply_last", "0")

  local trig, act = "Ammo truck resupply - timer", "Ammo truck resupply - refill"
  try(ScenEdit_SetEvent, EV_RESUPPLY, { mode = "remove" })
  try(ScenEdit_SetTrigger, { mode = "remove", type = "RegularTime", name = trig })
  try(ScenEdit_SetAction, { mode = "remove", type = "LuaScript", name = act })
  local body = string.gsub(string.gsub(RESUPPLY_SRC, "\r\n", "\n"), "\n", "\r\n")
  local ok = true
  if not try(ScenEdit_SetEvent, EV_RESUPPLY, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then ok = false end
  if not try(ScenEdit_SetTrigger, { mode = "add", type = "RegularTime", name = trig, interval = 4 }) then ok = false end
  try(ScenEdit_SetEventTrigger, EV_RESUPPLY, { mode = "add", name = trig })
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = act, ScriptText = body }) then ok = false end
  try(ScenEdit_SetEventAction, EV_RESUPPLY, { mode = "add", name = act })
  say("---- Truck resupply ----")
  if ok then
    say("  event '" .. EV_RESUPPLY .. "' created for " .. nTrucks .. " truck platoons and " .. nBunkers .. " ammo bunkers.")
    say("  A truck parked within " .. CONFIG.RESUPPLY_RANGE_KM .. " km of a friendly ammo bunker is refilled from it, checked every "
        .. CONFIG.RESUPPLY_EVERY_MINUTES .. " game minutes.")
    say("  In the Event Editor: check it is repeatable and its timer trigger shows an interval of 1 minute or less.")
  else
    say("  !! could not create the resupply event: " .. tostring(_errmsg_ or ""))
  end
end

-- ---- capture of airfields, ports and depots (repeating event) ----
local EV_CAPTURE = "Base and depot capture"
local CAPTURE_SRC = [==[
local now = ScenEdit_CurrentTime()
local last = tonumber(ScenEdit_GetKeyValue('LOOB2_capture_last')) or 0
if now - last < 60 then return end
ScenEdit_SetKeyValue('LOOB2_capture_last', tostring(now))
local RANGE = tonumber(ScenEdit_GetKeyValue('LOOB2_capture_km')) or 2
local HOLD = (tonumber(ScenEdit_GetKeyValue('LOOB2_capture_min')) or 10) * 60
local A, B = ScenEdit_GetKeyValue('LOOB2_scoreA'), ScenEdit_GetKeyValue('LOOB2_scoreB')
local function try(f, ...) local ok, r = pcall(f, ...) if ok then return r end return nil end
local function split(s) local t = {} for g in string.gmatch(s or '', '[^,]+') do t[#t + 1] = g end return t end
local function n(v) return tonumber(v) or 0 end
local function km(a, b)
  local r = math.rad
  local dlat, dlon = r(n(b.latitude) - n(a.latitude)), r(n(b.longitude) - n(a.longitude))
  local h = math.sin(dlat / 2) ^ 2 + math.cos(r(n(a.latitude))) * math.cos(r(n(b.latitude))) * math.sin(dlon / 2) ^ 2
  return 6371 * 2 * math.asin(math.sqrt(h))
end
local function tell(side, text) try(ScenEdit_SpecialMessage, side, text) end
-- land combat units by the side they belong to NOW
local land = { [A] = {}, [B] = {} }
for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_land'))) do
  local u = try(ScenEdit_GetUnit, { guid = g })
  if u and land[tostring(u.side)] then
    local l = land[tostring(u.side)]
    l[#l + 1] = { latitude = u.latitude, longitude = u.longitude }
  end
end
local function near(list, site)
  local c = 0
  for _, p in ipairs(list) do if km(p, site) <= RANGE then c = c + 1 end end
  return c
end
local function guidsIn(t, out, depth)
  if depth > 3 then return end
  if type(t) == 'string' then out[#out + 1] = t
  elseif type(t) == 'table' then
    if type(t.guid) == 'string' then out[#out + 1] = t.guid
    else for _, v in pairs(t) do guidsIn(v, out, depth + 1) end end
  end
end
local function scoreLoss(owner, u)
  local w = LS_weight(u)
  if w <= 0 then return end
  local function num(k) return tonumber(ScenEdit_GetKeyValue(k)) or 0 end
  local lostKey = 'LOOB_lost_' .. owner
  ScenEdit_SetKeyValue(lostKey, tostring(num(lostKey) + w * num('LOOB_scale_' .. owner)))
  local netA = math.floor(num('LOOB_lost_' .. B) - num('LOOB_lost_' .. A) + 0.5)
  local delta = netA - num('LOOB_applied')
  if delta ~= 0 then
    local why = owner .. ' lost ' .. tostring(u.name) .. ' (captured)'
    ScenEdit_SetScore(A, ScenEdit_GetScore(A) + delta, why)
    ScenEdit_SetScore(B, ScenEdit_GetScore(B) - delta, why)
    ScenEdit_SetKeyValue('LOOB_applied', tostring(netA))
  end
end
local function moveKey(prefix, guid, from, to)
  local keep = {}
  for _, g in ipairs(split(ScenEdit_GetKeyValue(prefix .. from))) do if g ~= guid then keep[#keep + 1] = g end end
  local had = #keep ~= #split(ScenEdit_GetKeyValue(prefix .. from))
  if had then
    ScenEdit_SetKeyValue(prefix .. from, table.concat(keep, ','))
    local dest = split(ScenEdit_GetKeyValue(prefix .. to))
    dest[#dest + 1] = guid
    ScenEdit_SetKeyValue(prefix .. to, table.concat(dest, ','))
  end
end
for _, g in ipairs(split(ScenEdit_GetKeyValue('LOOB2_sites'))) do
  local site = try(ScenEdit_GetUnit, { guid = g })
  local owner = site and tostring(site.side)
  if site and (owner == A or owner == B) then
    local enemy = (owner == A) and B or A
    local capKey = 'LOOB2_cap_' .. g
    if near(land[enemy], site) > 0 and near(land[owner], site) == 0 then
      local since = tonumber(ScenEdit_GetKeyValue(capKey)) or 0
      if since == 0 then
        ScenEdit_SetKeyValue(capKey, tostring(now))
        tell(owner, tostring(site.name) .. ' is undefended and enemy troops are on it. It will be captured in ' .. math.floor(HOLD / 60) .. ' minutes unless you get land units there.')
        tell(enemy, 'Your troops are taking ' .. tostring(site.name) .. '. Hold it for ' .. math.floor(HOLD / 60) .. ' minutes.')
      elseif now - since >= HOLD then
        local hosted = {}
        guidsIn(site.hostedUnits, hosted, 0)
        guidsIn(site.embarkedUnits, hosted, 0)
        try(ScenEdit_SetUnitSide, { side = owner, guid = g, newside = enemy })
        local after = try(ScenEdit_GetUnit, { guid = g })
        if after and tostring(after.side) == enemy then
          scoreLoss(owner, site)
          local taken, seen = 0, {}
          for _, hg in ipairs(hosted) do
            if not seen[hg] then
              seen[hg] = true
              local hu = try(ScenEdit_GetUnit, { guid = hg })
              if hu then
                if tostring(hu.side) ~= enemy then try(ScenEdit_SetUnitSide, { side = owner, guid = hg, newside = enemy }) end
                local hu2 = try(ScenEdit_GetUnit, { guid = hg })
                if hu2 and tostring(hu2.side) == enemy then
                  taken = taken + 1
                  scoreLoss(owner, hu)
                end
              end
            end
          end
          moveKey('LOOB2_bunkers_', g, owner, enemy)
          local extra = (taken > 0) and (' with ' .. taken .. ' aircraft or ships') or ''
          tell(owner, tostring(site.name) .. ' has been captured by ' .. enemy .. extra .. '.')
          tell(enemy, 'You have captured ' .. tostring(site.name) .. extra .. '.')
        end
        ScenEdit_SetKeyValue(capKey, '0')
      end
    else
      if (tonumber(ScenEdit_GetKeyValue(capKey)) or 0) ~= 0 then ScenEdit_SetKeyValue(capKey, '0') end
    end
  end
end
]==]

local function setupCapture(sideData)
  if #CONFIG.SIDES ~= 2 then say("Capture needs exactly two sides in CONFIG.SIDES - skipped") return end
  local sites, land = {}, {}
  for _, r in pairs(sideData) do
    for _, e in ipairs(r.others) do
      if string.find(e.cls, "Single-Unit Airfield", 1, true) or string.find(e.cls, "Single-Unit Port", 1, true)
         or string.sub(e.name, 1, 7) == "[DEPOT]" then
        sites[#sites + 1] = e.guid
      end
    end
    for _, e in ipairs(r.bunkers) do sites[#sites + 1] = e.guid end
    for _, e in ipairs(r.land) do land[#land + 1] = e.guid end
  end
  local function put(k, v) try(ScenEdit_SetKeyValue, k, tostring(v)) end
  put("LOOB2_sites", table.concat(sites, ","))
  put("LOOB2_land", table.concat(land, ","))
  put("LOOB2_scoreA", CONFIG.SIDES[1])
  put("LOOB2_scoreB", CONFIG.SIDES[2])
  put("LOOB2_capture_km", CONFIG.CAPTURE_RANGE_KM)
  put("LOOB2_capture_min", CONFIG.CAPTURE_HOLD_MINUTES)
  put("LOOB2_capture_last", 0)
  for _, g in ipairs(sites) do put("LOOB2_cap_" .. g, 0) end

  local trig, act = "Capture - timer", "Capture - check sites"
  try(ScenEdit_SetEvent, EV_CAPTURE, { mode = "remove" })
  try(ScenEdit_SetTrigger, { mode = "remove", type = "RegularTime", name = trig })
  try(ScenEdit_SetAction, { mode = "remove", type = "LuaScript", name = act })
  local body = string.gsub(string.gsub(WEIGHT_SRC .. CAPTURE_SRC, "\r\n", "\n"), "\n", "\r\n")
  local ok = true
  if not try(ScenEdit_SetEvent, EV_CAPTURE, { mode = "add", IsActive = true, IsRepeatable = true, IsShown = false }) then ok = false end
  if not try(ScenEdit_SetTrigger, { mode = "add", type = "RegularTime", name = trig, interval = 4 }) then ok = false end
  try(ScenEdit_SetEventTrigger, EV_CAPTURE, { mode = "add", name = trig })
  if not try(ScenEdit_SetAction, { mode = "add", type = "LuaScript", name = act, ScriptText = body }) then ok = false end
  try(ScenEdit_SetEventAction, EV_CAPTURE, { mode = "add", name = act })
  say("---- Capture ----")
  if ok then
    say("  event '" .. EV_CAPTURE .. "' created: " .. #sites .. " capturable sites, " .. #land .. " land combat units watched.")
    say("  A site changes side when enemy land combat units are within " .. CONFIG.CAPTURE_RANGE_KM
        .. " km, no defending land combat unit is, for " .. CONFIG.CAPTURE_HOLD_MINUTES .. " game minutes.")
    say("  Aircraft and ships at the site change side with it; site and units count as losses in the score.")
    say("  In the Event Editor: check it is repeatable and its timer trigger shows 1 minute or less.")
  else
    say("  !! could not create the capture event: " .. tostring(_errmsg_ or ""))
  end
end

-- ============================== main ==============================
local function main()
  say("Benelux war readiness - build " .. tostring(try(GetBuildNumber)))
  local P = CONFIG.PHASES
  local sideData = {}
  for _, sideName in ipairs(CONFIG.SIDES) do
    local r = collect(sideName)
    if not r then
      say("==== " .. sideName .. ": side not found - skipped")
    else
      say("==== " .. sideName .. ": " .. #r.air .. " aircraft, " .. #r.ships .. " ships, " .. #r.land
          .. " land combat units, " .. #r.bunkers .. " ammo bunkers")
      if P.swaps then
        phaseSwaps(sideName, r)
        r = collect(sideName)            -- swapped units have new IDs
      end
      if P.airswaps then
        phaseAirSwaps(sideName, r)
        r = collect(sideName)
      end
      if P.airdefence then
        phaseAirDefence(sideName, r)
        r = collect(sideName)            -- include the new platoons in the later steps
      end
      if P.loadouts then phaseLoadouts(sideName, r) end
      if P.airbases then phaseAirbases(sideName, r) end
      if P.topup then phaseTopUp(sideName, r) end
      if P.landmags then phaseLandMags(sideName, r) end
      if P.trucks then phaseTrucks(sideName, r) end
      if P.trooptrucks then phaseTroopTrucks(sideName, r) end
      if P.depots then phaseDepots(sideName, r) end
      if P.ports then phasePorts(sideName, r) end
      sideData[sideName] = collect(sideName)
    end
  end
  if P.resupply then setupResupply(sideData) end
  if P.capture then setupCapture(sideData) end
  if P.scoring then
    if #CONFIG.SIDES == 2 then
      setupScoring(CONFIG.SIDES[1], CONFIG.SIDES[2])
    else
      say("Scoring needs exactly two sides in CONFIG.SIDES - skipped")
    end
  end
  say("Finished. Check one airfield, one platoon and one port in the editor before saving.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGM80G
... 
Function:ScenEdit_SetEvent (0)  Error:Unable to identify the desired Event!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Netherlands decisive)!
... 
Function:ScenEdit_SetTrigger (0)  Error:Event trigger not found (Loss scoring - Belgium decisive)!
... 
Function:ScenEdit_SetAction (0)  Error:Event action not found (Loss scoring - end scenario)!
Benelux war readiness - build v1.10 - Build 1900.20
==== Netherlands: 156 aircraft, 12 ships, 115 land combat units, 6 ammo bunkers
  swaps: 0 land units replaced, 0 failed
  loadouts: 156 aircraft armed, 0 failed, 0 left as they were
  airbase Volkel AB: 0 stores added
  airbase Eindhoven AB: 0 stores added
  airbase Gilze-Rijen AB: 0 stores added
  airbase Leeuwarden AB: 0 stores added
  airbase De Kooy Airfield: 0 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 0 units given a magazine (0 rounds), 115 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  troop trucks: 64 placed (unit type 'Ground Unit'), 0 already there, 0 failed
  depots: 6 ammo bunkers filled with 0 rounds
  port Nieuwu Haven NB (Den Helder): reloads for 12 ships, 0 rounds added
==== Belgium: 126 aircraft, 7 ships, 82 land combat units, 4 ammo bunkers
  swaps: 2 land units replaced, 0 failed
  aircraft swaps: 0 replaced, 0 failed
  air defence: 0 Mistral platoons placed, 8 already there, 0 failed
  loadouts: 110 aircraft armed, 0 failed, 16 left as they were
  airbase Kleine-Brogel AB: 0 stores added
  airbase Koksijde AB: 0 stores added
  airbase Melsbroek AB: 0 stores added
  airbase Florennes AB: 0 stores added
  airbase Beauvechain AB: 0 stores added
  top-up: 0 units were below maximum, 0 rounds added
  land magazines: 2 units given a magazine (132 rounds), 80 already had one, 0 failed
  ammo trucks: 0 platoons placed (0 rounds loaded), 10 already there
  troop trucks: 42 placed (unit type 'Ground Unit'), 0 already there, 0 failed
  depots: 4 ammo bunkers filled with 156 rounds
  port Zeebrugge NB: reloads for 7 ships, 0 rounds added
---- Truck resupply ----
  event 'Ammo truck resupply at depots' created for 20 truck platoons and 10 ammo bunkers.
  A truck parked within 1.0 km of a friendly ammo bunker is refilled from it, checked every 5 game minutes.
  In the Event Editor: check it is repeatable and its timer trigger shows an interval of 1 minute or less.
---- Capture ----
  event 'Base and depot capture' created: 39 capturable sites, 197 land combat units watched.
  A site changes side when enemy land combat units are within 2.0 km, no defending land combat unit is, for 10 game minutes.
  Aircraft and ships at the site change side with it; site and units count as losses in the score.
  In the Event Editor: check it is repeatable and its timer trigger shows 1 minute or less.
---- Scoring ----
  Netherlands: 394 units = 1000 points for the enemy if all are destroyed
      aircraft                              333 pts
      bases, radars and air defence          59 pts
      land forces (added by script)         470 pts
      other facilities                        1 pts
      ships                                 138 pts
  Belgium: 298 units = 1000 points for the enemy if all are destroyed
      aircraft                              364 pts
      bases, radars and air defence          57 pts
      land forces (added by script)         501 pts
      other facilities                        1 pts
      ships                                  77 pts
  event 'Loss scoring (zero-sum)' created. Open the Event Editor and check it is ticked as repeatable.
  Now set the thresholds for BOTH sides in the editor's scoring window:
  Disaster -1000 ... Triumph +1000 (e.g. -1000 / -400 / +400 / +1000).
Finished. Check one airfield, one platoon and one port in the editor before saving.
...
07/10/2026 22:22:57 -- Bv1.10 - Build 1900.20 -- 
Console: 
-- =====================================================================
--  BENELUX: REMOVE THE TIMED EVENTS AND THE TROOP TRUCKS
--  Run from Editor > Lua Script Console on a saved copy of the scenario.
--  Removes:
--    - the "Base and depot capture" event, with its timer and script
--    - the "Ammo truck resupply at depots" event, with its timer and script
--    - every [TRUCK] troop truck (Ural-4320) and any leftover [TEST] unit
--  Keeps: all other units, stocks and loadouts, and the loss-scoring event.
--  The score scale is recalculated so each side is worth SCORE_SCALE again.
--  Safe to run more than once.
-- =====================================================================
local SIDES = { "Netherlands", "Belgium" }
local SCORE_SCALE = 1000
local REMOVE_PREFIXES = { "[TRUCK]", "[TEST]" }

local EVENTS = {
  { event = "Base and depot capture", trigger = "Capture - timer", action = "Capture - check sites" },
  { event = "Ammo truck resupply at depots", trigger = "Ammo truck resupply - timer", action = "Ammo truck resupply - refill" },
}

local LOG = {}
local function say(s) LOG[#LOG + 1] = tostring(s) end
local function try(f, ...)
  local ok, r = pcall(f, ...)
  if ok then return r end
  return nil
end
local function prop(obj, key)
  if obj == nil then return nil end
  local ok, v = pcall(function() return obj[key] end)
  if ok then return v end
  return nil
end

local function LS_weight(u)
  local t = tostring(u.type or '')
  if t == 'Weapon' or t == 'Aimpoint' or t == 'Satellite' then return 0, 'ignored' end
  local n = string.lower(tostring(u.name or ''))
  local c = string.lower(tostring(u.classname or ''))
  local tags = {
    {'[hq]', 60}, {'[depot]', 40}, {'[ad]', 12}, {'[supply]', 10}, {'[truck]', 2}, {'[armor]', 8}, {'[arty]', 8},
    {'[sof]', 8}, {'[mech]', 6}, {'[recon]', 4}, {'[eng]', 3}, {'[inf]', 3},
  }
  for i = 1, #tags do
    if string.find(n, tags[i][1], 1, true) then return tags[i][2], 'land forces (added by script)' end
  end
  if t == 'Submarine' then return 80, 'submarines' end
  if t == 'Ship' then
    local p = string.match(c, '^(%a)%s?%d')
    local byPennant = { f = 60, l = 60, a = 30, p = 25, m = 15, y = 3 }
    return (p and byPennant[p]) or 20, 'ships'
  end
  if t == 'Aircraft' then
    local air = {
      {'f-35', 16}, {'a330', 16}, {'a400', 12}, {'f-16', 10}, {'c-130', 8}, {'ah-64', 8},
      {'mq-9', 6}, {'nh90', 6}, {'nh-90', 6}, {'ch-47', 6},
    }
    for i = 1, #air do
      if string.find(c, air[i][1], 1, true) then return air[i][2], 'aircraft' end
    end
    return 5, 'aircraft'
  end
  local fac = {
    {'runway access', 2}, {'taxiway', 2}, {'runway', 20}, {'single-unit airfield', 40},
    {'pier', 10}, {'dock', 10}, {'radar', 15}, {'patriot', 25}, {'nasams', 15}, {'sam', 12},
    {'ammo', 5}, {'fuel', 5}, {'hangar', 3}, {'shelter', 3}, {'control tower', 6},
    {'tarmac', 1}, {'parking', 1}, {'revetment', 1}, {'pad', 1},
  }
  for i = 1, #fac do
    if string.find(c, fac[i][1], 1, true) then return fac[i][2], 'bases, radars and air defence' end
  end
  return 2, 'other facilities'
end

local function eventExists(name)
  return try(ScenEdit_GetEvent, name, 4) ~= nil
end

local function main()
  say("---- Events ----")
  for _, e in ipairs(EVENTS) do
    local had = eventExists(e.event)
    try(ScenEdit_SetEvent, e.event, { mode = "remove" })
    try(ScenEdit_SetTrigger, { mode = "remove", type = "RegularTime", name = e.trigger })
    try(ScenEdit_SetAction, { mode = "remove", type = "LuaScript", name = e.action })
    if eventExists(e.event) then
      say("  !! '" .. e.event .. "' is STILL THERE - delete it by hand in the Event Editor (event, then its trigger and action)")
    else
      say("  '" .. e.event .. "': " .. (had and "removed" or "was not present"))
    end
  end

  say("---- Units ----")
  for _, sideName in ipairs(SIDES) do
    local side = try(VP_GetSide, { side = sideName })
    if not side then
      say("  side '" .. sideName .. "' not found")
    else
      local found, gone = 0, 0
      for _, ref in pairs(side.units) do
        local u = try(ScenEdit_GetUnit, { guid = ref.guid })
        local name = tostring(prop(u, "name"))
        local hit = false
        for _, p in ipairs(REMOVE_PREFIXES) do
          if string.sub(name, 1, #p) == p then hit = true end
        end
        if u and hit then
          found = found + 1
          try(ScenEdit_DeleteUnit, { side = sideName, guid = ref.guid })
          if not try(ScenEdit_GetUnit, { guid = ref.guid }) then gone = gone + 1 end
        end
      end
      say("  " .. sideName .. ": " .. gone .. " of " .. found .. " truck/test units removed"
          .. ((gone < found) and "  !! some could not be deleted" or ""))
    end
  end

  say("---- Scoring ----")
  for _, sideName in ipairs(SIDES) do
    local side = try(VP_GetSide, { side = sideName })
    local total, count = 0, 0
    if side then
      for _, ref in pairs(side.units) do
        local u = try(ScenEdit_GetUnit, { guid = ref.guid })
        if u then
          local w = LS_weight(u)
          if w > 0 then total = total + w count = count + 1 end
        end
      end
    end
    if total > 0 then
      try(ScenEdit_SetKeyValue, "LOOB_scale_" .. sideName, tostring(SCORE_SCALE / total))
      say("  " .. sideName .. ": " .. count .. " units = " .. SCORE_SCALE .. " points")
    else
      say("  " .. sideName .. ": no units found - score scale left unchanged")
    end
  end
  say("Open the Event Editor and confirm only 'Loss scoring (zero-sum)' is left.")
  say("Done. Save the scenario under a new name. Do not re-run the old war-readiness script on it:")
  say("use the updated copy, which no longer adds these.")
end

local ok, err = pcall(main)
if not ok then say("SCRIPT ERROR: " .. tostring(err)) end
print(table.concat(LOG, "\n"))
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6DH
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ67D
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ66H
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6C7
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6FU
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6DO
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ657
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ68U
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ66O
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6CS
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6AM
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6FG
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ65S
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ63M
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ68G
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6C0
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ650
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6BB
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ64B
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6DV
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ66V
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6G5
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6F9
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ695
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6D3
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6GQ
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ689
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6EK
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ663
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6CE
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ69Q
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ67K
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6BI
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ65E
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6GC
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ64I
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ69C
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6E6
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6AT
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6FN
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ676
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ63T
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6ER
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ68N
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6CL
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ67R
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ65L
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6A1
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6H1
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6DA
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ66A
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6B4
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6A8
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ644
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6AF
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6F2
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6BP
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ638
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6GJ
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ63F
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ682
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ6ED
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ64P
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQ69J
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBE9
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBC3
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB79
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBDR
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBDD
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB6R
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBAP
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBD6
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBFJ
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB8J
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBA4
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBCA
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBEG
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB9M
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBBS
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB7G
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB91
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBB7
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBCV
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBCH
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBAB
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB9T
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB98
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBBE
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBFQ
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBDK
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB8Q
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBF5
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB85
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBEN
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB7N
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBBL
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBE2
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB72
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB9F
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBB0
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBAI
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBFC
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBEU
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQBCO
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB8C
... 
Function:ScenEdit_GetUnit (0)  Error:Can't find guid I8MHTP-0HNP4GVAGQB7U
---- Events ----
  'Base and depot capture': removed
  'Ammo truck resupply at depots': removed
---- Units ----
  Netherlands: 64 of 64 truck/test units removed
  Belgium: 42 of 42 truck/test units removed
---- Scoring ----
  Netherlands: 330 units = 1000 points
  Belgium: 256 units = 1000 points
Open the Event Editor and confirm only 'Loss scoring (zero-sum)' is left.
Done. Save the scenario under a new name. Do not re-run the old war-readiness script on it:
use the updated copy, which no longer adds these.
...
