CMANO map

CommandOps

A player created website for CMANO - Command: Modern Air/Naval Operations

Useful Links:

CMANO Database Viewer CMANO Lua Docs Matrix CMANO Forum baloogancampaign.com inst Web Based Designer Command Theater AI - Ares v1.0 (forum post) Downed Pilot/Survivor Script Lua Scoring Example Video - CMANO basics Starter Scenario Special Actions

Lua Code Samples

Below are some handy Lua code samples. Please note that they may need some interpretation and may not work perfectly as is due to a variety of reasons, but hopefully they can give you some ideas.

Remove Sensors from all Air Units with a Specific DBID

local a,b,c,d = W_GetSideUnitTotalsTable('Blue') --special function in starter scen
for k,v in ipairs(a) do
local u = ScenEdit_GetUnit({guid=v})
if u.dbid == 310 then
print(u.name)
ScenEdit_UpdateUnit({guid=v,mode='remove_sensor',dbid=937})
ScenEdit_UpdateUnit({guid=v,mode='remove_sensor',dbid=444})
end
--print(u.name) 
end

Create a handful of sides via script


local W_sides ={ {side='Blue',awareness='Normal',proficiency='Regular'}, {side='Red', awareness='Normal',proficiency='Regular'},{side='Targets',awareness='Blind',proficiency='Regular'},{side='Bios',awareness='Blind',proficiency='Regular'},{side='Survivors',awareness='Blind',proficiency='Regular'} }
--proficiency values - Novice, Cadet, Regular, Veteran, Ace


function W_SetupSides()
 for k,v in ipairs(W_sides) do
print('Creating side: '..v.side)
 ScenEdit_AddSide({side=v.side})
 ScenEdit_SetSideOptions({side=v.side,awareness=v.awareness,proficiency=v.proficiency})
end

ScenEdit_SetSidePosture ('Blue', 'Red', 'H')
ScenEdit_SetSidePosture ('Red', 'Blue', 'H')
ScenEdit_SetSidePosture ('Survivors', 'Blue', 'F')
ScenEdit_SetSidePosture ('Blue', 'Survivors', 'F')
ScenEdit_SetSidePosture ('Blue', 'Targets', 'U')
ScenEdit_SetSidePosture ('Targets', 'Blue', 'U')

ScenEdit_MsgBox ('The sides should be setup, please double check them. Also you should change the Bios, Targets and Survivors to Computer only. If you plan to use the Create Targets Special Action I think it works better with Collective Responsibility set to No.', 1)

end--function end
W_SetupSides()
Add a handful of units, add some to a group, change WCS to engage opportunities - yes. Using this to pretend to offload units from a ship and set them up where they are needed.
Submitted by whicker on April 07, 51559 | Edit
--sam site
ScenEdit_AddUnit({side='Crimson Commonwealth', type='Facility', name='SAM Site 1', dbid=399, autodetectable=false, latitude='17.9755369694901', longitude='-76.805865481985'})
--203mm arty
local lat='17.9775500173216'
local lon='-76.8068606459053'
for i=1,6 do
local u = ScenEdit_AddUnit({side='Crimson Commonwealth', type='Facility', name='Arty 203 #'..i, dbid=2392, autodetectable=false, Lat=lat, Lon=lon})
u.holdposition =true
ScenEdit_SetDoctrine({side="Crimson Commonwealth", unitname=u.name}, {engage_opportunity_targets= "yes" })
lat=lat +.0005
end --arty
--Manpads
local lat='17.9767240346245'
local lon='-76.8068606459053'
for i=1,6 do
local u = ScenEdit_AddUnit({side='Crimson Commonwealth', type='Facility', name='SA-7 #'..i, dbid=426, autodetectable=false, Lat=lat, Lon=lon})
lat=lat +.0005
end --sa-7s

local u = ScenEdit_AddUnit({side='Crimson Commonwealth', type='Facility', name='Radar - Manly', dbid=1455, autodetectable=false, Lat='17.9802486954862', Lon='-76.8039160521666'})
ScenEdit_SetEMCON('Unit', u.name, 'Radar=Active')
Change proficiency of AC by randomly selecting a set number of Flight names from a table.
Submitted by whicker on August 15, 2019 | Edit
Tool_EmulateNoConsole(true) 
-- decrease Gripens first

for i=2,21 do
local u = ScenEdit_GetUnit({side='Republic of Azure', name='Gripen #'..i})
if u ~= nil then
ScenEdit_SetUnit({guid=u.guid,proficiency=3})
print(u.name..' - '..u.proficiency)
end --if

end--inner

--loop thru some of the rest of the flights to decrease their proficiency

local flights={'Picadura','Euro','Snake','Bam Bam','Prowler','Outcast','Voodoo','Hawk','Falcon','Raptor','Trident','Lightning','Lancer','Spirit','Buffy','Tophatters','Gunslingers','Swordsmen','Venom','Harry'} -- add flight names to table

local affected={}
local class
local n = 7 --number of flights affected

for i = 1,7 do
local r=math.random(1,#flights)
for j=1,12 do
local u = ScenEdit_GetUnit({side='Republic of Azure', name=flights[r]..' #'..j})
if u ~= nil then
ScenEdit_SetUnit({guid=u.guid,proficiency=3})
print(u.name..' - '..u.proficiency)
class=u.classname
end --if

end--inner

table.insert(affected,flights[r]..'<small> -- ('..class..')</small>')
print(flights[r].name)
table.remove(flights,r)
end -- outer

print(affected)

local message1 =('Commander,<br><br>We have lost the VC 10 from Sangster AFB that had ammo and supplies on board as well as most of our Air Logistics team. There will be a serious lack of supplies for our Gripens now - there are minimal supplies at NAS Merida and possibly other usable loadouts scattered around.<br><br> The following flights will have decreased proficiency due to this loss: <br><br>Gripens <small> -- JAS 39D Gripen</small><br>')
for i = 1,#affected do
local m1 = affected[i]
--local m2 =

message1 = message1 ..m1..'<br>'
end --for

print(message1)
ScenEdit_SpecialMessage ('Republic of Azure', message1)
Better logic for returning ground units when they run out of ammo. If unit is armor or artillery ignore small arms in ammo count. Return if total ammo is less than 5.
Submitted by whicker on August 11, 2019 | Edit
local returnCourseLat =20.0792774513933
local returnCourseLon =-75.9280542142649

local m = ScenEdit_GetMission ('Crimson Commonwealth', 'Assault - Industrial')
print(m.unitlist)
for i =1,#m.unitlist do
local u = SE_GetUnit({guid=m.unitlist[i]})
print(u.name)
--print(u.mounts)

local ammo =0
for k,v in pairs(u.mounts) do --outer mounts loop

for k,v in pairs(u.mounts[k].mount_weapons) do --loop thru each mounts weapons

print(v.wpn_name..' '.. v.wpn_current)
if string.match(u.name,'Arty') and (string.match(v.wpn_name,'7.62') or string.match(v.wpn_name,'30mm') or string.match(v.wpn_name,'12.7mm')) then
ammo=ammo --if arty dont count 7.62 

elseif string.match(u.name,'Armor') and (string.match(v.wpn_name,'7.62') or string.match(v.wpn_name,'30mm') or string.match(v.wpn_name,'12.7mm')) then
ammo=ammo
else 
ammo = ammo + v.wpn_current
print("total ammo: "..ammo)
end --if arty

end --inner loop

end --outer loop

if ammo <5 then
print('unit is running out of ammo, should send back to LZ')
ScenEdit_AssignUnitToMission(u.name, 'NONE')
u.course = { [1] = {latitude=returnCourseLat, longitude=returnCourseLon, TypeOf = 'ManualPlottedCourseWaypoint'} }
returnCourseLat=returnCourseLat + W_PathOffset()
returnCourseLon=returnCourseLon + W_PathOffset()
else
print('unit still has ammo')
end
print('-------------------')
end
Add weapon/ammo to an ammo pad. Trick is that the ID listed in the add weapon UI is not the DBID - you need to search for Weapons in the Weapons DB.
Submitted by whicker on August 10, 2019 | Edit
local u = SE_GetUnit({name='Ammo Pad', guid='01563bf0-12c5-4ce4-bdd7-e370c449c77f'})
print(u.magazines)
ScenEdit_AddWeaponToUnitMagazine({unitname=u.name, wpn_dbid=2983, number=12, w_max=48})
Check land units on a mission to see if they still have ammo - if not return them to a specific location.
Submitted by whicker on August 08, 2019 | Edit
local returnCourse = { [1] = { latitude='20.0176142061058', longitude='-75.9143283023575', TypeOf = 'ManualPlottedCourseWaypoint'} }

local m = ScenEdit_GetMission ('Crimson Commonwealth', 'Assault - Industrial')
--print(#m.unitlist)


for i =1,#m.unitlist do
local u = SE_GetUnit({guid=m.unitlist[i]})
print(u.name)
local ammo =0
for k,v in pairs(u.mounts) do --outer mounts loop

for k,v in pairs(u.mounts[k].mount_weapons) do --loop thru each mounts weapons

print(v.wpn_name..' '.. v.wpn_current)
ammo = ammo + v.wpn_current
print("total ammo: "..ammo)
end
end
if ammo == 0 then
print('unit is out of ammo, should send back to LZ')
ScenEdit_AssignUnitToMission(u.name, 'NONE')
u.course = returnCourse
else
print('unit still has ammo')
end
print('-------------------')
end
Manpads on mission - stop every minute (40% of the time), stay stopped if firing at something.
Submitted by whicker on August 07, 2019 | Edit
math.randomseed(os.clock())

local m = ScenEdit_GetMission ('A', 'AAW')
--print(#m.unitlist)


for i =1,#m.unitlist do
local r = math.random(0,10)
print(r)
local u = SE_GetUnit({guid=m.unitlist[i]})
if u.speed ~= 0 and r > 6 then
u.manualSpeed=0
elseif
u.firingAt ~=nil then
u.manualSpeed=0
print('firing at something, stay at stop')
else
u.manualSpeed=20
end
end --loop
Get units from a particular mission and change their speed. For instance to stop manpads so they can actually shoot. Probably need to turn their speed on and off at an interval, otherwise they never stop and can never shoot.
Submitted by whicker on August 07, 2019 | Edit
local m = ScenEdit_GetMission ('Blue', 'Manpads')
print(#m.unitlist)

for i =1,#m.unitlist do
local u = SE_GetUnit({guid=m.unitlist[i]})
u.manualSpeed=0
end --loop
Special action for enemy losses - start with known pre war stats, subtract current number of ships,subs and ac to get losses.
Submitted by whicker on August 05, 2019 | Edit
function WW_GetUnitTotals(side)
local a = VP_GetSide({Side =side})  -- put your side name here

local Ships = {} --create empty array(table) to store group guids

local AC = {}
local Subs = {}
local Facilities = {}
for i = 1, #a.units do -- loops thru all units on the side

local u = ScenEdit_GetUnit({guid = a.units[i].guid}) --convert VP guid to Unit wrapper

if u.type == 'Ship' then -- check if group, if so add the group guid to the table

    table.insert(Ships, u.guid) 
elseif u.type == 'Aircraft' then -- check if group, if so add the group guid to the table

    table.insert(AC, u.guid) 
elseif u.type == 'Submarine' then -- check if group, if so add the group guid to the table

    table.insert(Subs, u.guid) 
end
end
print("Ships: "..#Ships..", Aircraft: "..#AC..", Submarines: "..#Subs)
print('Please note that this function may use a lot of memory if there are a lot of units, you may need to restart soon.')
print('==================================================================================================================')

return #AC,#Ships,#Subs
end -- function end


local AC,Ships,Subs = GetUnitTotals('Crimson Commonwealth')
print(AC)

local startAC,startShips,startSubs = 275,35,8
local AClost = startAC-AC
local ShipsLost=startShips -Ships
local SubsLost = startSubs-Subs

local message = '<h3>Intel Report - Enemy Losses</h3><p>Our pre-war intel says that the Crimson Commonwealth had the following unit totals:<br>'..
'Aircraft: 275<br>Ships: 35<br>Subs: 8 </p>'..
'<p>Enemy losses to date are:<br>'..
AClost..' Aircraft<br>'..ShipsLost..' Ships<br>'..SubsLost..' Subs</p>'

ScenEdit_SpecialMessage('playerside',message)
loop thru cargo on a pier and unload it. Unloads all of one type into one unit. If you have something like a SA-10 it doesn't have radar, somehow need to have that in the cargo and then pair it together so it could work?
Submitted by whicker on August 02, 2019 | Edit
local u = SE_GetUnit({name='Structure (Pier [Extra Large, 200-500m])', guid='921183c8-8a56-499b-8024-3f74eadf6806'})
print(u.cargo[1].cargo)

for k,v in pairs (u.cargo[1].cargo) do
print(v.dbid)
ScenEdit_UnloadCargo(u.name, { {v.quantity,v.dbid}})
end
Simple OOB of enemy contacts - just listing AC and SAMs so far. Could make this a special action.
Submitted by whicker on July 13, 2019 | Edit
local vp = VP_GetSide({name = "USN"})
local cp = vp.contacts --List Of contacts

local ac={}
local sams = {}
for k,v in ipairs(cp) do
local u = ScenEdit_GetContact({side='USN', guid=cp[k].guid })
if u.type == 'Air' then
--print(v)

table.insert(ac,v)
end --if AC

if u.type == 'Fixed Facility' then
if string.match(u.name,'SAM') then
--print(u.name)

table.insert(sams,v)
else -- not sam, do somethign with them at bottom

end --if fixed facility

end --if AC

end
print('------ Air Contacts ---------------------------------------')
for k,v in ipairs(ac) do
print(v.name)
end -- ac table


print('------ SAM Contacts ---------------------------------------')
for k,v in ipairs(sams) do
print(v.name)
end -- ac table
Move 2 ref points a random number of miles from where they are, in this case only changing the latitude.
Submitted by whicker on July 07, 2019 | Edit
math.randomseed(os.clock())
local d=math.random(1,350)
local p =World_GetPointFromBearing({latitude='13.984442921467', longitude='109.05782487399',bearing=180, distance=d})
ScenEdit_SetReferencePoint({side="USSR", name="Holding-1", lat=p.latitude})
ScenEdit_SetReferencePoint({side="USSR", name="Holding-2", lat=p.latitude})
Check a group of units detectability - can optionally only change some units based on their name like 'runway'.
Submitted by whicker on June 26, 2019 | Edit
function WW_SetGroupAutodetectable(side,groupName, trueOrFalse, onlyUnitsWithName)
local u = ScenEdit_GetUnit({name=groupName, side=side})
unitsToChange = u.group.unitlist
for i = 1, #unitsToChange
do
local uu = SE_GetUnit({guid=unitsToChange[i]}) 
if onlyUnitsWithName == nil or string.match(uu.name, onlyUnitsWithName) then
uu.autodetectable = trueOrFalse
print(uu.name..' is it autodetectable? '..tostring(uu.autodetectable))
else
print(uu.name..' is it autodetectable? '..tostring(uu.autodetectable))
end --if name used

end --loop

end --function end


WW_SetGroupAutodetectable('Abandoned','Kantorpos Field', true, 'Runway')
Function to make a simple airbase.
Submitted by whicker on June 25, 2019 | Edit
function WW_CreateAirBase(basename,latlonTable, runways, taxiways, accesspoints, tarmacspaces, ammopads)
local lat=latlonTable['latitude']
local lon=latlonTable['longitude']
for i=1,runways do
local u = ScenEdit_AddUnit({side='Abandoned', type='Facility', name='Runway '..i, dbid=55, autodetectable=true, Lat=lat, Lon=lon})
u.group =basename 
lat=lat +.004
end --runways

lat=latlonTable['latitude'] --reset lat and add to lon

lon=latlonTable['longitude'] + .002
for i=1,taxiways do
local u = ScenEdit_AddUnit({side='Abandoned', type='Facility', name='Taxiway '..i, dbid=1424, autodetectable=true, Lat=lat, Lon=lon})
u.group =basename 
lat=lat +.004
end
lat=latlonTable['latitude'] --reset lat and add to lon

lon=latlonTable['longitude'] + .004
for i=1,accesspoints do
local u = ScenEdit_AddUnit({side='Abandoned', type='Facility', name='Access Point '..i, dbid=353, autodetectable=true, Lat=lat, Lon=lon})
u.group =basename 
lat=lat +.004
end
lat=latlonTable['latitude'] --reset lat and add to lon

lon=latlonTable['longitude'] + .006
for i=1,accesspoints do
local u = ScenEdit_AddUnit({side='Abandoned', type='Facility', name='Tarmac Space '..i, dbid=344, autodetectable=true, Lat=lat, Lon=lon})
u.group =basename 
lat=lat +.002
end
lat=latlonTable['latitude'] --reset lat and add to lon

lon=latlonTable['longitude'] + .008
for i=1,ammopads do
local u = ScenEdit_AddUnit({side='Abandoned', type='Facility', name='Ammo Pad '..i, dbid=1496, autodetectable=true, Lat=lat, Lon=lon})
u.group =basename 
lat=lat +.002
end
end --function end


WW_CreateAirBase('Red FOB',{latitude='-5.49435412429', longitude='120.125068245739'},2,2,4,8,2)
Print out unit name and dbid of units in a group.
Submitted by whicker on June 25, 2019 | Edit
local u = SE_GetUnit({name='Tanete Feild', guid='d2677f47-9c8f-41ae-8564-4f77fc9a5e72'})
unitsToCheck = u.group.unitlist
for i = 1, #unitsToCheck do
local uu = SE_GetUnit({guid=unitsToCheck[i]}) 
print(uu.name..' dbid: '..uu.dbid)
end
Change a group/base to a different side.
Submitted by whicker on June 24, 2019 | Edit
function WW_SetGroupSide(groupName, newSide)
local u = ScenEdit_GetUnit({name=groupName})
unitsToChange = u.group.unitlist
for i = 1, #unitsToChange
do
local uu = SE_GetUnit({guid=unitsToChange[i]}) 
ScenEdit_SetUnitSide({side=uu.side, Name=unitsToChange[i], newside=newSide})
uu.group = groupName
end --loop

end --function end


WW_SetGroupSide('Group 632', 'Abandoned')
Check to see if an AC is on the ground and if so change its mission and loadout. Airbornetime is a string for some reason.
Submitted by whicker on May 27, 2019 | Edit
local tmp; 
for i = 1,10 do 
tmp = ScenEdit_GetUnit({name ="Harrier #".. i}) 
if tmp ~= nil and tmp.airbornetime == '0' then 
ScenEdit_SetLoadout({UnitName =tmp.name, LoadoutID =4695})
ScenEdit_AssignUnitToMission(tmp.name, 'Harrier Attack'); 
print('Harrier #' .. i .. ' Added to  Harrier Attack Mission.'); 
else 
print('Harrier #' .. i .. ' does not exist or is airborne, skipping.')
print(tmp.airbornetime)
end 
end
After cargo drop off, assign units to go to certain co-ordinates - assuming they are recon units.
Submitted by whicker on May 26, 2019 | Edit
local t ={{latitude='-0.765117507753304', longitude='-91.1350164860851'},
{latitude='-0.786440951539722', longitude='-91.1723105640674'},
{latitude='-0.898615248793162', longitude='-91.4113109884621'},
{latitude='-0.940265113997278', longitude='-91.4156491636998'},
{latitude='-0.440303719004694', longitude='-91.1648090615147'},
{latitude='0.00588535114367335', longitude='-91.3635273233471'},
{latitude='-0.954108155701674', longitude='-91.3866590642809'},
{latitude='-0.855716297836393', longitude='-91.1322275574939'},
{latitude='-0.452922251700375', longitude='-91.1384572006042'},
{latitude='-0.160841638087961', longitude='-91.3026679234585'},
{latitude='0.0105327932462405', longitude='-91.3680814974655'},
{latitude='-0.0106982805829027', longitude='-91.5495894731476'}
}
local u = ScenEdit_UnitX ()
local counter = ScenEdit_GetKeyValue('recon-counter')
print('counter equals '..counter)
if counter == '' then counter =1
print('counter was not set')
else
	counter=tonumber(counter)
print('must be set to '..counter)
end
local newCourse = { [1] = { longitude = t[counter].longitude, latitude = t[counter].latitude, TypeOf = 'ManualPlottedCourseWaypoint' }}
u.course = newCourse
counter = counter +1
if counter >12 then counter = 1 end
ScenEdit_SetKeyValue('recon-counter',tostring(counter))
World_GetPointFromBearing example. Can add a ref point there, or use to set course waypoint.
Submitted by whicker on May 19, 2019 | Edit
local p =World_GetPointFromBearing ({latitude='17.9157389252343', longitude='-77.1091624293097',bearing=90, distance=1})
ScenEdit_AddReferencePoint( {side="red", name="new ref point", lat=p.latitude, lon=p.longitude, highlighted=true})
Working on AI ground units that return to an area when they are out of ammo. Would use this with a trigger of every x minutes once the cargo drop takes place? and maybe checking an area for the units? not sure how to get UnitX yet. Could build a table as the units are dropped off but you wouldn't be able to save it as a key value. Or could maybe rename the unit as it is dropped off by the cargo mission - that gives you unitX, then the name could have a specific part to it which would allow you to loop thru all land units using sting.match to single out the land units you want to control in this way.
Submitted by whicker on May 19, 2019 | Edit
local returnCourse = { [1] = { longitude = -77.2684808114843, TypeOf = 'ManualPlottedCourseWaypoint', latitude = 17.8398961272957 }, [2] = { longitude = -77.2207384588076, TypeOf = 'ManualPlottedCourseWaypoint', latitude = 17.7514818092388 }, [3] = { longitude = -77.1871543567516, TypeOf = 'ManualPlottedCourseWaypoint', latitude = 17.7304140641624 } }
local u = ScenEdit_GetUnit({name='Mech Inf #459', guid='ed2a5ff4-3e9e-4ee4-94d3-f63f01641ae5'})
local ammo =0
for k,v in pairs(u.mounts) do --outer mounts loop


for k,v in pairs(u.mounts[k].mount_weapons) do --loop thru each mounts weapons

print(v.wpn_name..' '.. v.wpn_current)
ammo = ammo + v.wpn_current
print("total ammo: "..ammo)
end
end
if ammo == 0 then
print('unit is out of ammo, should send back to LZ')
ScenEdit_AssignUnitToMission(u.name, 'NONE')
u.course = returnCourse
else
print('unit still has ammo')
end
print('-------------------')
Playing with the Sin function, working on a weather model.
Submitted by whicker on April 24, 2019 | Edit
function round(num, numDecimalPlaces)
  if numDecimalPlaces and numDecimalPlaces>0 then
    local mult = 10^numDecimalPlaces
    return math.floor(num * mult + 0.5) / mult
  end
  return math.floor(num + 0.5)
end

local angle =0
local weatherStart = .2
local weatherMax = .5
local weatherStartTime =29 --in hours

local weatherTime = 36
local increment = round(math.pi/weatherTime,2)
local angle = weatherStartTime*increment

for i=1,60 do
--print("angle: "..angle)

local sin = math.sin(angle)
print(i..') sin: '..sin..'  angle: '..angle)
angle=angle + increment
end
print '--------------------------------------------'
Playing around with creating a table of weather in lua. This is basically how to make a table of tables programatically.
Submitted by whicker on March 16, 2019 | Edit
weatherTable = {}

for i = 1,15 do
local t=math.random(10,38)
local r=math.random(0,51)
local u=math.random(0,10)/10
local s=math.random(0,9)

local ww = {}
ww.t=t
ww.r=r
ww.u=u
ww.s=s
--print(ww)

table.insert(weatherTable,ww )
end
--print(weatherTable)
Take a course and modify the way points by adding or subtracting a random number. Used this as part of an event to help ships leave port and have random paths.
Submitted by whicker on March 11, 2019 | Edit
math.randomseed(os.clock())
local pathOut =  { [1] = { longitude = 29.504992491273, latitude = 40.7526965507348, TypeOf = 'ManualPlottedCourseWaypoint' }, [2] = { longitude = 29.3745803276918, latitude = 40.7278136152586, TypeOf = 'ManualPlottedCourseWaypoint' }, [3] = { longitude = 29.1246010812686, latitude = 40.7689734953455, TypeOf = 'ManualPlottedCourseWaypoint' }, [4] = { longitude = 28.9500444423617, latitude = 40.9075743371518, TypeOf = 'ManualPlottedCourseWaypoint' }, [5] = { longitude = 29.0111772910605, latitude = 41.0375941194471, TypeOf = 'ManualPlottedCourseWaypoint' }, [6] = { longitude = 29.0839186785473, latitude = 41.1281200761105, TypeOf = 'ManualPlottedCourseWaypoint' }, [7] = { longitude = 29.1226787477602, latitude = 41.2136790481829, TypeOf = 'ManualPlottedCourseWaypoint' }, [8] = { longitude = 29.1642381406793, latitude = 41.2627082444442, TypeOf = 'ManualPlottedCourseWaypoint' } }

function ShipPathOffset() --provides tiny offset to lat/lon

  local offset = math.random(300,699)
  print('offset before manipulation: '..offset)
  offset = (offset- 500)/20000
  print('offset after (subtract 500, divide by 20000: '..offset)
   return offset
end --end function


local u = ScenEdit_UnitX ()
if u.condition == 'Returning to base' then
	print(u.name.. ' is returning to base')
	else
print(u.name.. ' is leaving port, assigning new course')
local newCourse = pathOut --create new course object to manipulate

print('waypoints: '..#pathOut)
for i = 1, #newCourse do
--print(newCourse[i].longitude)

newCourse[i].latitude = newCourse[i].latitude + ShipPathOffset()
newCourse[i].longitude = newCourse[i].longitude + ShipPathOffset()
end --end table loop

u.course = newCourse	

ScenEdit_SetDoctrine({side="NATO", unitname=u.name}, {ignore_plotted_course= "no" })
end --end condition check
Exception: [string "ScenLoadOverlays"]:1: unexpected symbol near char(145) - of you see something like this where you copied code from somewhere it is possible the Quote mark is an illegal character - it is very hard to see, but some quotes are curly and these are not actual quotes as far as lua is concerned.
Submitted by whicker on March 10, 2019 | Edit
ScenEdit_UseAttachment('76856ec9-d23c-4a1c-baf7-599afdf7054a')  --good quotes


ScenEdit_UseAttachment(5083bee2-7d99-4e40-a17c-29dd97e75f07) --bad curly quotes but very hard to tell
Example of changing path of AI ship to get it out of a land locked port. You would need to change the course to the actual course needed to get out. Use this as the lua part of an action with a trigger of unit enters area that is set around a port but not including the port (ships in port are already in the area I think). You also need to change the ignore plotted course to no or else it may go off on its own if it is engaged offensive.
Submitted by whicker on March 10, 2019 | Edit
local u = ScenEdit_UnitX ()
if u.condition == 'Returning to base' then
	print(u.name.. ' is returning to base')
	else
		print(u.name.. ' is leaving port, assigning new course')
	u.course = { [1] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.511367359561, latitude = 40.7534711752442 }, [2] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.2849350470461, latitude = 40.708544893319 }, [3] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 28.946962290674, latitude = 40.9060242141018 }, [4] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.0087148482458, latitude = 41.0104256921841 }, [5] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.0139878489167, latitude = 41.0400486033816 }, [6] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.0679263467765, latitude = 41.0953141495635 }, [7] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.077122962378, latitude = 41.161667121539 }, [8] = { TypeOf = 'ManualPlottedCourseWaypoint', longitude = 29.1744302883196, latitude = 41.2669619417466 } }

	ScenEdit_SetDoctrine({side="NATO", unitname=u.name}, {ignore_plotted_course= "no" })
end
Get all properties of side - as a function. Some properties look like they are functions that could be run with additional parameters.
Submitted by whicker on February 12, 2019 | Edit
function GetSideProperties(side)
local u = VP_GetSide({side=side})
local tables = {}
for k,v in pairs(u.fields) do
local t = string.find(v," , ") -- location of first comma - v example:'.fuel , table, false' just need the key part - fuel

local t2=(string.sub(v,2,t-1))  --t finds the location of the first comma - 6, and then gets characters 2-5 which should equal fuel

    if type(u[t2]) ~= 'table' and type(u[t2]) ~= 'userdata' then --check if it is not a table

    print(t2..': '.. tostring(u[t2])) --need tostring for booleans for some reason

    elseif type(u[t2]) == 'userdata' then
    print('Possible Function: '..t2..': '..tostring(u[t2]))
    elseif type(u[t2]) == 'table' then
   table.insert(tables, t2) -- do tables later to make it easier to read

    end --end first try - strings, numbers, nils and booleans

end
print('------------- Table Data -------------------------')
for k,v in pairs(tables) do --display table info

 print(v..': ')
    for k,v in pairs(u[v]) do
    print(k)
    print(v)
    end --item table loop

    print('------ End '..v..' Table Data ------')
    print('-----------------------------------------------------------------------')
    print('-----------------------------------------------------------------------')
end --tables loop

print('-----end---------')
end

--GetSideProperties('Blue')
Same - Get all properties from unit wrapper - except as a function, can pass in either just the name as a string or the unit id with the name and guid as a table.
Submitted by whicker on February 10, 2019 | Edit
function GetUnitProperties(unitName)
if unitName == nil then 
print("You did not pass a unit name in")
end
print(type(unitName))
print(unitName)
local u
if (type(unitName)) == 'table' then
u = ScenEdit_GetUnit(unitName)
else
u = ScenEdit_GetUnit({name=unitName})
end
local tables = {}
for k,v in pairs(u.fields) do
    local t = string.find(v," , ")
    local t2 = (string.sub(v,2,t-1))
    if type(u[t2]) ~= 'table' then
    print(t2..': '..tostring(u[t2]))
    else
    table.insert(tables, t2)
    end --end check type


end -- end main pairs loop


print'==================== Table Data ======================'
for k,v in pairs(tables) do
    print(v..': ')
    for k,v in pairs(u[v]) do
    print(k)
    print(v)
    end --inner table


print('---------- End '..v..' table data ------------------')
print('----------------------------------------------------')
end --end tables loop

end --function


-- either way should work:

--GetUnitProperties({name='F-14D Tomcat', guid='78407e18-3841-4f63-bcc2-df202cc3dc3c'})

--GetUnitProperties('F-14D Tomcat')
Get all properties from unit wrapper
Submitted by whicker on February 09, 2019 | Edit
local u = ScenEdit_GetUnit({name='LPD 17 San Antonio', guid='63917afb-6cdb-47b5-9f2a-ffd3e9e86224'})
local tables = {}
for k,v in pairs(u.fields) do
    local t = string.find(v," , ")
    local t2 = (string.sub(v,2,t-1))
    if type(u[t2]) ~= 'table' then
    print(t2..': '..tostring(u[t2]))
    else
    table.insert(tables, t2)
    end --end check type

end -- end main pairs loop

print'==================== Table Data ======================'
for k,v in pairs(tables) do
    print(v..': ')
    for k,v in pairs(u[v]) do
    print(k)
    print(v)
    end --inner table

print('---------- End '..v..' table data ------------------')
print('----------------------------------------------------')
end --end tables loop
Working code for creating random bios and false contacts using 4 RP's in a rectangle. You can pass in the spacing and some jitter to make it less of a perfect grid and control how close together the units are. The script will set up a sea control patrol for the bios to be in if it does not exist. You need to set up a side called 'Biologics' set to computer only and Blind awareness.
Submitted by whicker on February 03, 2019 | Edit
-- creates random bios and false contact based on units in the bio_DBID table. 92 is in there twice to make it more likely a bio is chosen than a false contact

-- The script takes in 4 Reference Points that should be in the shape of a rectangle, the goal is to evenly distrbute contacts through out the area

-- if the location for a unit is below the minDepth then a placeholder Cessna is put there and then removed at the end

-- the previous unit placed determines where the current unit goes. Same thing happens at the start, first unit is a Cessna that will be deleted.

-- The script will create a sea control mission from the 4 RPs (with a unique name that includes the top to RP's). 

--If you run it more than once with the same RP's it will use the existing mission


-- user config stuff:

Tool_EmulateNoConsole(true) -- this is needed in the console due to the mission check, if you need to debug you should comment the GetMission bits in the randomBios function. 

bio_DBIDs = { 92, 92,355,354,93,94,95 } --list of units to choose from - fish and false contacts

bioUnitsToDelete = {} -- create an empty table to store placeholders used when depth is too shallow

local side = 'Biologics' --you need a side named Biologics, set to computer only and awareness set to blind. Please create this before running.

local topLeftPoint = 'RP-2954' --the four RP's that make up your rectangle, starting at top left

local topRightPoint = 'RP-2955'
local bottomRightPoint = 'RP-2956' --careful, we are going clockwise

local bottomLeftPoint = 'RP-2957'
local spacingInMiles = 90 -- how far apart should we spread them?

local minDepth = -40 -- min depth to place a unit

local distanceJitter = 10 -- varies the distance between units so it is not a perfect grid

local angleJitter =5 -- varies the angle used to place units so it is not a perfect grid

-- see very bottom for where we actually use the info above to call the main function (there are 2 used).


--there are 2 functions, this function is called by the function below multiple times - you do not use this function on its own (normally)

function placeRandomBiologic(side,unit,distance,distanceJitter,angle,angleJitter,minDepth, mission) -- main code to create the unit, called at the bottom

--math.randomseed(os.time()) --should uncomment this if it is in an event. Comment it out if running in the console.

local u = ScenEdit_GetUnit({guid=unit})
--print(u)

if u ~= nil then
  local m = math.random(distance-distanceJitter,distance+distanceJitter) -- get random distance based on jitter

  local b = math.random(angle-angleJitter,angle+angleJitter) -- get random angle based on jitter

  local point = ScenEdit_AddReferencePoint( {side=side, name="possible", RelativeTo=unit, bearing=b ,distance=m}) -- create a reference point relative to unit passed in

  ScenEdit_DeleteReferencePoint({side=side, name ="possible"})  --delete the point itself, we just need the corridinates

  local elevation = World_GetElevation({latitude = point.latitude, longitude= point.longitude}) --get the elevation of the point

  --print(elevation) 

        if elevation < minDepth then -- check to see if we passed the check, can repurpose elevation if so

            if elevation < -300 then elevation = -300 --don't go too deep, want to use this for random depth as well so changing it to -300m if it is deeper

            end
        rDepth = math.random(40,-elevation) --choose random depth between 40 and the elevation (which is limited to -300) to use for new units depth

        --print(rDepth)

        DBID = bio_DBIDs[math.random( 1, #bio_DBIDs)] --choose a random unit from the list

        local new_bio = ScenEdit_AddUnit({side='Biologics', type='Submarine',name='Biologic/False Contact', dbid=DBID,latitude=point.latitude,longitude=point.longitude, 
        manualAltitude= -rDepth, depth = rDepth}) --create new unit

            if DBID == 92 or DBID == 355 or DBID == 354 then --if it is bio then assign to mission and give random speed

            new_bio.manualSpeed=math.random(0, 4)
            ScenEdit_AssignUnitToMission( new_bio.guid, mission)   
            --print(DBID)

            end -- end dbid check  

        return new_bio--exit, we are done, passback unit wrapper to where it was called to use on next iteration


        else --if not deep enough then place an AC as a marker so we have something to return for next pass

        local unitToDelete = ScenEdit_AddUnit({side='Biologics', type='Aircraft',name='AC Holder to be deleted', dbid=1571, loadoutid = 8397,latitude=point.latitude,longitude=point.longitude, altitude = 5000}) 
        table.insert(bioUnitsToDelete, unitToDelete.guid) -- add the unitToDelete to the list of units to delete, will delete at the end      

        return unitToDelete --exit, we are done, passback unit wrapper to where it was called to use on next iteration  

        end --end elevation if


 else -- if unit check fails

print('unit does not exist')
end --end unit check

end --end function


-- this is the function you actually call (below - functions always load first)

function randomBios(side,topLeftPoint,topRightPoint,bottomRightPoint,bottomLeftPoint,spacingInMiles,minDepth,distanceJitter,angleJitter)
local mission = ScenEdit_GetMission(side, 'Biologics '..topLeftPoint..'-'..topRightPoint) -- first check to see if mission exists

if mission == nil then --if mission does not exist create it

mission = ScenEdit_AddMission(side, 'Biologics '..topLeftPoint..'-'..topRightPoint, 'patrol', {type= 'SEA'})
mission = ScenEdit_SetMission('Biologics', 'Biologics '..topLeftPoint..'-'..topRightPoint, {patrolzone={topLeftPoint,topRightPoint, bottomRightPoint, bottomLeftPoint}, onethirdrule=false })
end -- end mission check

local spacingInMiles1 = 0 --first time thru you don't offset

local rowAngle =  90 --angle to use for bearing of new unit

local rowAngleReverse = 180 -- each row reverses the angle so this will be added to 90 = 270

topLeftPoint = ScenEdit_GetReferencePoint({side=side, name=topLeftPoint})
topRightPoint = ScenEdit_GetReferencePoint({side=side, name=topRightPoint})
bottomLeftPoint = ScenEdit_GetReferencePoint({side=side, name=bottomLeftPoint})
-- don't need bottom right, we're just measuring the width and height from first RP

local width = Tool_Range({latitude = topLeftPoint.latitude, longitude=topLeftPoint.longitude},{latitude =topRightPoint.latitude, longitude=topRightPoint.longitude})
local height = Tool_Range({latitude = topLeftPoint.latitude, longitude=topLeftPoint.longitude},{latitude =bottomLeftPoint.latitude, longitude=bottomLeftPoint.longitude})
--print(width)

--print(height)

local rows = math.floor(height/spacingInMiles) --divide height by spacing specified in setup, this gives us the number of iterations to do in one loop

--print('Rows: '..rows)

local columns = math.floor(width/spacingInMiles) --divide width by spacing specified in setup, this gives us the number of iterations to do in the other loop

--print('Columns: '..columns)

local unit = ScenEdit_AddUnit({side=side, type='Aircraft',name='AC Holder to be deleted', dbid=1571, loadoutid = 8397,latitude=topLeftPoint.latitude,longitude=topLeftPoint.longitude, altitude = 5000, mission.name}) 
        table.insert(bioUnitsToDelete, unit.guid) --need an initial unit to start process, using a Cessna, will delete later

local unitguid = unit.guid 
--unitguid is what we use to create every unit, so we set it to the previous unit after every iteration, so that the next unit can use the previous units position as a starting point

for i = 1,rows do --this gets complicated, we have an outer loop to go across (?)

   local newBio = placeRandomBiologic('Biologics',unitguid,spacingInMiles1, distanceJitter, 180, angleJitter, minDepth, mission.name) --call the function, will return the created unit

    unitguid = newBio.guid --change unitguid to newly created unit for next pass

    spacingInMiles1 = spacingInMiles --after first use, reset the spacing to what it should be (was 0 on first unit)

    for i = 1,columns do --inner loop to go down

        local newBio = placeRandomBiologic('Biologics',unitguid,spacingInMiles, distanceJitter, rowAngle, angleJitter, minDepth, mission.name) -- call the function, will return the created units

        unitguid = newBio.guid --change unitguid to newly created unit for next pass

    end -- rows loop

      rowAngle = rowAngle + rowAngleReverse --we are done with one row (?) which was going to the right, now we need to come back and go to the left, otherwise it just keeps going to the right 

      rowAngleReverse = -rowAngleReverse -- if we go from 90 to 270 you can't add 180 again or you are past 360, so you need to subtract 180 next time

end -- columns loop

--print(#bioUnitsToDelete)

for i = 1, #bioUnitsToDelete do -- we are done creating units, need to delete any placeholder Cessnas 

local guidToDelete = bioUnitsToDelete[i]
ScenEdit_DeleteUnit({guid = guidToDelete})
end --end loop to delete 

--print(bioUnitsToDelete)

end --end function


-- call the main function with the arguments set at the top:

randomBios(side,topLeftPoint,topRightPoint,bottomRightPoint,bottomLeftPoint,spacingInMiles,minDepth,distanceJitter,angleJitter)
Not quite perfect code to lay out bios or false contacts in a grid with some jitter on the angle and distance apart. having trouble with the depth - they get assigned a nice random depth but then go to something else. Seems to be different based on if they are on a mission or not (sea control). Places a Cessna if the depth is not right, need to delete those at the end.
Submitted by whicker on February 02, 2019 | Edit
local DBIDTABLE = { 92,355,354,93,94,95 }
local unitsToDelete = {}

function placeRandomBiologic(side,unit,distance,distanceJitter,angle,angleJitter,minDepth)
--math.randomseed(os.time())

local u = ScenEdit_GetUnit({guid=unit})
print(u)
if u ~= nil then
  local m = math.random(distance-distanceJitter,distance+distanceJitter)
  local b = math.random(angle-angleJitter,angle+angleJitter)
  local point = ScenEdit_AddReferencePoint( {side=side, name="possible", RelativeTo=unit, bearing=b ,distance=m})
  ScenEdit_DeleteReferencePoint({side=side, name ="possible"}) 
  local elevation = World_GetElevation({latitude = point.latitude, longitude= point.longitude})
  print(elevation) 
        if elevation < minDepth then
        DBID = DBIDTABLE[math.random( 1, #DBIDTABLE)]
        local new_bio = ScenEdit_AddUnit({side='Biologics', type='Submarine',name='Biologic/False Contact', dbid=DBID,latitude=point.latitude,longitude=point.longitude, manualAltitude= true, depth=math.random(50, 300), manualSpeed=math.random(0, 4)}) 
ScenEdit_AssignUnitToMission( new_bio.guid, 'Bios')        
return new_bio--exit, we are done

        else
        local unitToDelete = ScenEdit_AddUnit({side='Biologics', type='Aircraft',name='AC Holder to be deleted', dbid=1571, loadoutid = 8397,latitude=point.latitude,longitude=point.longitude, altitude = 5000}) 
        return unitToDelete     
-- need to add the unitToDelete to the list of units to delete and then need to delete them 

        end --end elevation if

 else 
print('unit does not exist')
end --end unit check

end --end function


local distance = 75
local distanceJitter = 6
local angleJitter =4
local angle =  90
local minDepth = -40
local columns = 2
local u = '71cd57be-342c-4be3-86f4-fe4b0d5157cd' --guid of unit used to start the grid

for i = 1,columns do
local newBio = placeRandomBiologic('Biologics',u,distance, distanceJitter, 0, angleJitter, minDepth) -- call the function

u= newBio.guid
for i = 1,columns do
local newBio = placeRandomBiologic('Biologics',u,distance, distanceJitter, angle, angleJitter, minDepth) -- call the function

u= newBio.guid
end
if angle == 90 then
angle = 270
else angle = 90
end
end
Function to place a ship/sub/group at a random distance from its current location. You can set the minimum acceptable depth as well as a bearing range to control which direction - if it is 1 and 360 then it can be anywhere around. If it is 180 and 270 then it would be anywhere southwest of the current location.
Submitted by whicker on February 01, 2019 | Edit
function placeShipRandomly(side,unit,distance,bMin,bMax,depth)
math.randomseed(os.time())
local u = ScenEdit_GetUnit({name=unit})
if u ~= nil then
  for i = 1,20 do
    local m = math.random(1,distance)
    local b = math.random(bMin, bMax)
    local point = ScenEdit_AddReferencePoint( {side=side, name="possible"..i, RelativeTo=unit, bearing=b ,distance=m})
    ScenEdit_DeleteReferencePoint({side=side, name ="possible"..i}) 
    local elevation = World_GetElevation({latitude = point.latitude, longitude= point.longitude})
    print(elevation) 
        if elevation < depth then
        u.latitude =  point.latitude
        u.longitude = point.longitude
        return --exit, we mare done

        end
  end
 print('no suitable location found, unit not moved')
else 
print('unit does not exist')
end
end

placeShipRandomly('Blue','Group 106',155,1,359,-3010) -- call the function
Get table of guids for units in a given group.
Submitted by whicker on January 31, 2019 | Edit
local u = ScenEdit_GetUnit({name='Group 106'})
print(u.group.unitlist)

-- { [1] = 'b566a8cd-4b8d-44c6-bcd4-bd9196d811e5', [2] = 'a75c47e9-0cc9-4589-afb2-3058e47cb0eb', [3] = '0ca6edaa-0998-4135-b10b-29e5881b4946' }
If all 8 Orel bombers are dead then change sub to nuke strike mission.
Submitted by whicker on January 20, 2019 | Edit
Tool_EmulateNoConsole(true) --used so it works in the console

local Orels =0
for i=1,8 do 

if ScenEdit_GetUnit({Side='Russian Federation', Name="Orel #"..i,}) == nil then --counts if it does not exist

Orels = Orels + 1
print(Orels)

end
end
print(Orels)
if Orels == 8 then -- all Orels dead, activate sub strike

print(" no more orels")
if ScenEdit_GetUnit({Side='Russian Federation', Name='PLARB-955 A [Borey II]',}) ~= nil then
print("Sub still alive")
ScenEdit_AssignUnitToMission('PLARB-955 A [Borey II]', 'Borey II Nuclear Strike on Chitose AB')
end
print("Sub is dead - end scenario?")
end
Set a subs diesel engine to medium damage. Just need the last line, first part is to see what components there are. 2 apparently means medium damage. Could also be "none" for no damage.
Submitted by whicker on January 01, 2019 | Edit
local unit = ScenEdit_GetUnit({guid='24c5dd8d-c54b-4904-9262-417e39781f6b'})
print(unit)
print(unit.components)

ScenEdit_SetUnitDamage({guid='24c5dd8d-c54b-4904-9262-417e39781f6b',  components={{"Diesels",2}}})
Print damaged unit info to lua log. Create triggers for each side you want to show in the log. Use snaketail log viewer as supplemental log viewer.
Submitted by whicker on November 10, 2018 | Edit
local unit = ScenEdit_UnitX()
if unit.type ~= 'Weapon' then
local TimeVar = ScenEdit_CurrentTime() 
print('[Damaged Unit] [' ..unit.side.. '] ' ..unit.name.. ', Type:  ' ..unit.classname.. ' on ' ..os.date("!%A %B %d %H%M",TimeVar).. 'Z')
end
Print destroyed unit info to lua log - [Red] <<-- change to side name it is for. Also prints current score.
Submitted by whicker on November 10, 2018 | Edit
print("[**Unit Destroyed**] [Red] "..unit.name.. " ("..UnitX().classname.." Sub Type: "..unit.subtype.." ) Points:  "..points)
ScenEdit_SetScore(side, currentScore, unit.name.. " ("..unit.classname.." Sub Type: "..unit.subtype.." ) Destroyed, Points:  "..points)
print("Current Score: " ..currentScore)
Get total number of units for a side, and break down of how many ships/subs/AC/facilities. This is a memory hog if there are a lot of units, game restart may be needed afterwards. For me 1100 units sucks up 300 or so MB, so after running it a couple times I need to restart the game to free the memory.
Submitted by whicker on October 29, 2018 | Edit
local a = VP_GetSide({Side ="Republic of Azure"})  -- put your side name here

print("Total Number of Units: "..#a.units)
local Ships = {} --create empty array(table) to store group guids

local AC = {}
local Subs = {}
local Facilities = {}
for i = 1, #a.units do -- loops thru all units on the side

local u = ScenEdit_GetUnit({guid = a.units[i].guid}) --convert VP guid to Unit wrapper

if u.type == 'Ship' then -- check if group, if so add the group guid to the table

table.insert(Ships, u.guid) 
elseif u.type == 'Aircraft' then -- check if group, if so add the group guid to the table

table.insert(AC, u.guid) 
elseif u.type == 'Submarine' then -- check if group, if so add the group guid to the table

table.insert(Subs, u.guid) 
elseif u.type == 'Facility' then -- check if group, if so add the group guid to the table

table.insert(Facilities, u.guid) 
end
end
print("Ships: "..#Ships.." - Aircraft: "..#AC.." - Submarines: "..#Subs.." - Facilities: "..#Facilities)
Change all groups and units from one side to another, basically merging 2 sides. The side you are changing to must exist. It is setup as 2 separate functions, one that changes groups, and then one that changes units after that. When I tried to do them at the same time it would always error at some point. Caveats: barely tested, uses up significant memory (150MB on a few hundred units).
Submitted by whicker on October 27, 2018 | Edit
local oldside = "test" --set name of old side

local newside =  "Republic of Azure" --set name of new side, must exist


function changesSidesGroups(newSide, oldSide) --function number one

local a = VP_GetSide({Side =oldSide}) -- get all units from old side

local groups = {} --create empty array(table) to store group guids

for i = 1, #a.units do -- loops thru all units on the side

local u = ScenEdit_GetUnit({guid = a.units[i].guid}) --convert VP guid to Unit wrapper

if u.type == 'Group' then -- check if group, if so add the group guid to the table

table.insert(groups, u.guid) 
print(u.name.. " side: "..u.side ) --testing by printing to console

end --closes if statement

end --closes loop

for i = 1, #groups do --loop thru new table of group guids

print(groups[i]) --testing by printing to console

ScenEdit_SetUnitSide({side=oldSide, guid=groups[i], newside=newSide}) --change side from old to new

end --closes loop

changeSidesUnits(newSide, oldSide) -- call second function to change units that are not in groups

end --closes function


function changeSidesUnits(newSide,oldSide) --function number two for non grouped units

local a2 = VP_GetSide({Side =oldSide}) -- get all units from old side - won't include groups as they are already done

local units = {} --create another empty table

for i = 1, #a2.units do --loop thru units and push them into the table

table.insert(units, a2.units[i].guid) 
end --closes loop


for i = 1, #units do --loop thru table of units

print(units[i]) --testing by printing to console

ScenEdit_SetUnitSide({side=oldSide, guid=units[i], newside=newSide}) --change side

end --closes loop

end -- closes second function 


changesSidesGroups(newside, oldside) --call function number one to do all the magic stuff, it will call function number two.
In game timer using Special Actions. Create a Special Action named Timer and use this in the lua part.
Submitted by whicker on September 10, 2018 | Edit
function TimerTimeFromNowDotNetTime(addSeconds) -- Time helper cause event times are weird

    local time = ScenEdit_CurrentTime()
    local offSet = 62135596801 --number of seconds from 01-01-0001 to 01-01-1970

    local newTime = (time + offSet + addSeconds)*10000000
    local timeToUse = string.format("%18.0f",newTime)
    return timeToUse
end

function CreateTimerEvent(minutes,message)
 local t = ScenEdit_CurrentTime() --need to add something to the names to make them unique, using time

ScenEdit_SetEvent(minutes.." Minute Timer ("..message..")"..t, {mode="add",IsRepeatable=0})
ScenEdit_SetTrigger({mode="add", type="Time", name=minutes.." Minute Timer Trigger ("..message..")"..t, Time=TimerTimeFromNowDotNetTime(minutes*60) })
 ScenEdit_SetAction({mode="add", type="LuaScript", name=minutes.." Minute Timer Action ("..message..")"..t,
 scriptText='ScenEdit_SpecialMessage (ScenEdit_PlayerSide(),"Your Timer is Up:  '..message..' ")'})
ScenEdit_SetEventTrigger(minutes.." Minute Timer ("..message..")"..t, {mode="add", name=minutes.." Minute Timer Trigger ("..message..")"..t})
ScenEdit_SetEventAction(minutes.." Minute Timer ("..message..")"..t, {mode="add", name=minutes.." Minute Timer Action ("..message..")"..t})
end

local timerMinutes = ScenEdit_InputBox('How long do want the timer to be in minutes?') 
print('Response was ' ..timerMinutes) 
local timerMessage = ScenEdit_InputBox('What do you want to call the timer?') 
print('Response2 was ' .. timerMessage) 
CreateTimerEvent(timerMinutes,timerMessage)
Check if a unit is damaged and set to Unavailable loadout if it is. Could use this on a trigger of Unit enters Area around an Airfield, then when the unit lands if it is damaged set it to Unavailable rather than let it be repaired. Not 100% sure about this as sometimes the startdp seems to be 0?
Submitted by whicker on September 07, 2018 | Edit
local u = ScenEdit_GetUnit({name="DHL #2"})
print(u.damage.startdp)
print(u.damage.dp)
if tonumber(u.damage.dp) ~= tonumber(u.damage.startdp) then
ScenEdit_SetLoadout({UnitName =u.name, LoadoutID =4}) --if damaged set to unavailable loadout

else
print("unit is not damaged")
end
Lua to see if a string contains a sub string. Works well except for special characters (such as .()[]+-) which have to be escaped by putting a % in front of them. This could be used as a score keeping mechanism - all scoring could be in one bit of lua, comparing the UnitX.classname to things - so if classname contains F-15 then score = 10, or reaper then score = 3. F-15 would need to be F%-15.
Submitted by whicker on August 31, 2018 | Edit
local z = ScenEdit_GetUnit({name='SSN 23 Jimmy Carter [Seawolf Class]', guid='fdb4f976-56b3-4ed7-9787-5ffcd757c213'})
print(z.classname)

local str = z.classname
local zz = "%[Seawolf"
if string.match(str, zz) then
  print ("The word " ..zz.. " was found.")
else
  print ("The word " ..zz.. "  was not found.")
end
Get contents of an existing trigger.
Submitted by whicker on August 11, 2018 | Edit
local a = ScenEdit_SetTrigger({mode="list", name="triggername"})
print(a)
Mission status reverser - if the mission is active, make it inactive. If it is inactive, make it active. Use this in an event to turn on and off a mission at a regular time.
Submitted by whicker on August 05, 2018 | Edit
local a = ScenEdit_GetMission('Red','Kobler Patrol')
if a.isactive == false then
a.isactive = true
else 
a.isactive = false
end
Adding a unit to an escort mission, you just have true - no escort = true
Submitted by whicker on August 04, 2018 | Edit
ScenEdit_AssignUnitToMission ("F-15I-1", "Strike-Baghdad", true)
Set a units loadout and ready time.
Submitted by whicker on July 26, 2018 | Edit
local unit = ScenEdit_GetUnit({name='FedEx #313'})
ScenEdit_SetLoadout({UnitName = unit.name, LoadoutID = 8378, TimeToReady_Minutes = 0})

ScenEdit_AssignUnitToMission(unit.name, "Ferry 11")
print(unit)
print(unit.readytime)

-- or use with unitx on a trigger of unit remains in area, this example will take a C-17 that lands and change it to the ferry loadout (8378) and set its ready time to 0 so it will launch immediately - well, 2 minutes.


ScenEdit_SetLoadout({UnitName =UnitX().name, LoadoutID = 8378, TimeToReady_Minutes = 0})
ScenEdit_AssignUnitToMission(UnitX().name, "Ferry 11")
updated code for random bios. Sets a random speed between 0 and 4 and a random depth (max 270m or so). Use with a mission named 'Whales' set to patrol - sea control.
Submitted by whicker on July 08, 2018 | Edit
math.randomseed(os.time()) 
bio_num = math.random(35,55) --change to your specified minimum and maximum number of bios 


for i = 1,bio_num do 
redo_count = 0 
::redo:: 
local lat_var = math.random(1,(10^13)) --don't change 

local lon_var = math.random(1,(10^13)) --don't change 

v_lat = math.random(14,26) + (lat_var/(10^13)) --change the first set (south is negative) to your specified minimum and maximum latitude values; it's important that the first number is smaller than the second. 

v_lon = math.random(-78,-60) + (lon_var/(10^13)) --change first set (west is negative!) to your specified minimum and maximum longitude values; it's important that the first number is smaller than the second. 

elevation = World_GetElevation({latitude=v_lat, longitude=v_lon}) 
if elevation > -40 then --(meters?) Checks to see if the water is deep enough, adjust as you please 


redo_count = redo_count + 1 
print("picked bad co-ordinates") 
if redo_count >50 then 
print ('units were not able to find a suitable spot for placement. Re-check latitude and longitude settings') 
break --this cuts the loop if there are no suitable positions found after 50 tries, prevents infinite loop/game freeze 


else 
goto redo --retries the placement if the water is too shallow 

end 
end 

DBIDTABLE = { 92,355,354 } --list of dbids for bios, could be subs 

local actual_depth = elevation --need 2 variables for depth - actual depth at that location and the depth the unit is set to, though this is only for the print to log 

if elevation < -300 then elevation = -299 end -- max depth for bios is 300, if actual depth is more than 300m set to 299 so random depth is achievable 

local bio_depth = -1*elevation*math.random(100, 900)/1000 --have to reverse the sign, depth is a positive number, multiply by random percent between 10 and 90% 

DBID = DBIDTABLE[math.random( 1, #DBIDTABLE)] --choose random dbid for unit 

local new_bio = ScenEdit_AddUnit({side='Biologics', type='Submarine',name='Biologic #'..i, dbid=DBID,latitude=v_lat,longitude=v_lon, depth='bio_depth', manualSpeed=math.random(0, 4)}) 

ScenEdit_AssignUnitToMission( new_bio.name, 'Whales') --add to mission which helps with the course 

print (new_bio.name..' with dbid '..DBID..' was created in water with a depth of '..actual_depth..'m, at a depth of ' ..bio_depth ) 
end
Change current fuel on a unit to a random value around 60-80% of max fuel for that unit. Each unit has a type of fuel for itself, and sometimes other types of fuel for units it hosts. You have to match the correct type of fuel. This example is for an aircraft, with only one type (AviationFuel) which is type 2001. The fuel object will tell you max fuel and current fuel, you'll want to change current fuel.
Submitted by whicker on July 01, 2018 | Edit
local a = ScenEdit_GetUnit({guid='1298e86b-a6a8-4bb0-bf94-dd77c6559eaa'})
local fuel = a.fuel
print(fuel) --before change

fuel[2001].current = fuel[2001].max*math.random(600, 800)/1000
a.fuel = fuel
print(fuel) --after change
Rename a unit using their guid - can also use their name but if the name is not unique you'll probably have trouble.
Submitted by whicker on July 01, 2018 | Edit
ScenEdit_SetUnit({side="Mexico", guid='6b937b60-3dce-4b82-8f22-6a1280cdc908', newname="Horchata #5"})
a = ScenEdit_GetUnit({guid='6b937b60-3dce-4b82-8f22-6a1280cdc908'})
print (a.name)
Get the name and guid of all hosted units - Aircraft or Boats, but you need to specify one it looks like.
Submitted by whicker on July 01, 2018 | Edit
local a = ScenEdit_GetUnit({side="Mexico", unitname='NAS Veracruz'})
local allHosted = a.hostedUnits.Aircraft

for i = 1, #allHosted do
local hosted = ScenEdit_GetUnit({guid=allHosted[i]})
print(hosted.name.. ' , ' ..hosted.guid)
end
Take a list of units and change them from one side to another. If the units are in a group you can just pass in the group name. Doesn't seem to work with bases.
Submitted by whicker on July 01, 2018 | Edit
unitsToChange = {"HMCS Halifax", "HMCS Toronto", "HMCS Iroquois" }
for i = 1, #unitsToChange
do
if ScenEdit_GetUnit({Side='Canada', Name=unitsToChange[i]}) ~= nil then --check to make sure it is still in the scenario

ScenEdit_SetUnitSide({side="Canada", Name=unitsToChange[i], newside="United States"}); 
a = ScenEdit_GetUnit({name =unitsToChange[i]})
print(a.name..',' ..a.side)
end
end
Spawn units at random locations within an area.
Submitted by whicker on June 30, 2018 | Edit
math.randomseed(os.time())
--probably need a global counter for unit number

local unitNumber = 240
for i = 1,5 do
redo_count = 0
::redo::
local lat_var = math.random(1,(9999))
local lon_var = math.random(1,(9999))
v_lat = math.random(1927,1939)/100 + (lat_var/(999990)) --(for more precision do 4 digits with no period then divide by 100) change the first set (south is negative) to your specified minimum and maximum latitude values; it's important that the first number is smaller than the second.


v_lon = math.random(-8139,-8108)/100 + (lon_var/(999990)) --change first set (west is negative!) to your specified minimum and maximum longitude values; it's important that the first number is smaller than the second.


elevation = World_GetElevation({latitude=v_lat, longitude=v_lon})
if elevation < 2 then --Checks to see if point is on land (meters?), adjust as you please


redo_count = redo_count + 1
print("spot not suitable " ..redo_count)
if redo_count >50 then
print (redo_count .. 'not able to find a suitable spot for placement. Re-check latitude and longitude settings')
break --this cuts the loop if there are no suitable positions found after 50 tries, prevents infinite loop/game freeze


else
goto redo --retries the placement if the water is too shallow


end
end
--spawn units

ScenEdit_AddUnit({type = 'facility', name = 'Cayman Inf #'..unitNumber, dbid = 2273, side = 'Havana Pact', Latitude=v_lat,Longitude=v_lon,
autodetectable="false"})

local a =ScenEdit_GetUnit({ Side='Havana Pact', unitname='Cayman Inf #'..unitNumber}) 
print(a)
unitNumber = unitNumber + 1
end
Unloading cargo from a pier to random locations within an area. Uses the same code for random merchants more or less. By putting in your lat/long as 4 digits with no decimal - 1234 instead of 12.34 and then dividing by 100 you can get a more precise area. You need to know the dbid of the cargo (and the name of the pier), and what the unit will be called, the first one is like `inf #100` and then they go in sequence. Can only do one db type at a time.
Submitted by whicker on June 30, 2018 | Edit
math.randomseed(os.time())

local unitNumber = 104
for i = 1,40 do
redo_count = 0
::redo::
local lat_var = math.random(1,(9999))
local lon_var = math.random(1,(9999))
v_lat = math.random(1927,1939)/100 + (lat_var/(999990)) --(for more precision do 4 digits with no period then divide by 100) change the first set (south is negative) to your specified minimum and maximum latitude values; it's important that the first number is smaller than the second.


v_lon = math.random(-8139,-8108)/100 + (lon_var/(999990)) --change first set (west is negative!) to your specified minimum and maximum longitude values; it's important that the first number is smaller than the second.


elevation = World_GetElevation({latitude=v_lat, longitude=v_lon})
if elevation < 2 then --Checks to see if point is on land (meters?), adjust as you please


redo_count = redo_count + 1
print("spot not suitable " ..redo_count)
if redo_count >50 then
print (redo_count .. 'not able to find a suitable spot for placement. Re-check latitude and longitude settings')
break --this cuts the loop if there are no suitable positions found after 50 tries, prevents infinite loop/game freeze


else
goto redo --retries the placement if the water is too shallow


end
end
--unload a cargo unit - first is qty, then dbid of cargo

ScenEdit_UnloadCargo('Port of Grand Cayman', { {1,2884}}) 
-- get that units lat and long, got to know the seqence number of the unit name 

local a =ScenEdit_GetUnit({ unitname='Inf #'..unitNumber}) 
a.course = {{ lat =a.latitude, lon=a.longitude}, {lat=v_lat, lon=v_lon} } 
unitNumber = unitNumber + 1
print (a.name..' was created on land with an elevation of '..elevation..'m at ' ..a.latitude..', '..a.longitude)
end
Set a units course, assumes you know the unit name or guid. This example is for a land unit but I think it would work for a ship or maybe ac if they were airborne? First it gets the current location, and uses that as one end of the course to be set.
Submitted by whicker on June 29, 2018 | Edit
local a =ScenEdit_GetUnit({ unitname='Mech Inf #105'}) 
a.course = {{ lat =a.latitude, lon=a.longitude}, {lat=19.3874718855336, lon=-81.3869183989322} } 
print (a.course)
Unload cargo from unit - requires the name of the port/unit with the cargo as well as the dbid of the cargo you want to unload - and the qty of that unit. So rather than the cargo all unloading into one unit you can control how many get stuck together. The unit unloaded gets a generic name like Mech Inf #100 which seems to go in sequence.
Submitted by whicker on June 29, 2018 | Edit
ScenEdit_UnloadCargo('Port of Grand Cayman', { {2,2380}}) -- unloads 2 units of dbid 2380 (mech inf)
Weather function - returns weather report, not just cloud number. You can run this every hour or 4 hours to give a current weather report. Some of the message is hard coded (area I think).
Submitted by whicker Credit to Apache85 on June 29, 2018 | Edit
function DTG(TimeVar) 
if TimeVar == nil then 
TimeVar = ScenEdit_CurrentTime() 
end 
local msgtime = os.date("!%d%H%M" .. "Z" .. " " .. "%b %y", TimeVar) 
local msgtime = string.upper(msgtime) 
return msgtime 
end 

function Round(num, numDecimalPlaces) 
local mult = 10^(numDecimalPlaces or 0) 
return math.floor(num * mult + 0.5) / mult 
end 

function ACP126(rec_station,snd_station,precedence,from,to,classification,body) 
--rec_station --4 letter code (e.g. YDCX) 

--snd_station --4 letter code +/- NR 3 number (e.g. YBDN NR 270) 

--precedence --Flash (Z), Immediate (O), Priority (P), Routine (R), Flash Override (Y) 

local dtg = DTG() 
--from --e.g. MET FLT OPS 

--to --e.g. SSN 21 SEAWOLF 

--classification --Unclass +/- SBU / FOUO / NOFORN (Restricted), Confidential, Secret, Top Secret 

--body 

_,gr = body:gsub("%S+","") 
local sig_string = string.upper('<P><FONT face=Consolas>'..rec_station..' <BR>'.. 
'DE '..snd_station..' <BR>'.. 
precedence..' '..dtg..' <BR>'.. 
'fm '..from..' <BR>'.. 
'to '..to..' <BR>'.. 
'wd gr'..gr..' <BR>'.. 
'bt <BR>'.. 
classification..' <BR>'.. 
body..' <BR>'.. 
'bt <BR>'.. 
'nnnn </P>') 
return sig_string 
end 

function WeatherReport(outlook) 
if outlook == nil then outlook = 'next forecast at '..DTG(ScenEdit_CurrentTime()+21600) end 
--Generate special message to player 

local weather = ScenEdit_GetWeather() --Get new weather parameters 

local temp, cloud, rain, sea = weather.temp, weather.undercloud, weather.rainfall, weather.seastate 

local f_temp = Round((temp*1.8) + 32,0) --Convert to Fahrenheit 


--create rain/precipitation descriptor (based on in-game descriptions) 

if rain == 0 then precipdesc = 'nil' 
elseif rain < 5 then precipdesc = 'very light' 
elseif rain < 11 then precipdesc = 'light' 
elseif rain < 20 then precipdesc = 'moderate' 
elseif rain < 30 then precipdesc = 'heavy' 
elseif rain < 40 then precipdesc = 'very heavy' 
else precipdesc = 'extreme' 
end 

--create cloud descriptor (based on in-game descriptions) 

if cloud == 0 then clouddesc = 'clear skies' 
elseif cloud < 0.2 then clouddesc = 'light low clouds' 
elseif cloud < 0.3 then clouddesc = 'light middle clouds' 
elseif cloud < 0.4 then clouddesc = 'light high clouds' 
elseif cloud < 0.5 then clouddesc = 'moderate low clouds' 
elseif cloud < 0.6 then clouddesc = 'moderate middle clouds' 
elseif cloud < 0.7 then clouddesc = 'moderate high clouds' 
elseif cloud < 0.8 then clouddesc = 'moderate middle clouds & light high clouds' 
elseif cloud < 0.9 then clouddesc = 'solid middle clouds & moderate high clouds' 
elseif cloud < 1.0 then clouddesc = 'thin fog & solid cloud cover' 
else clouddesc = 'thick fog & solid cloud cover' 
end 

--rec_station,snd_station,precedence,from,to,classification,body 

local wx_time = DTG() 
local wx_report = ACP126('NEWC','JOCMETOPS','r','HQJOC METEOROLOGICAL OFFICE','FFG 06 NEWCASTLE <BR> INFO ALL STATIONS','unclass','WX REPORT ' .. wx_time .. ' - EAST COAST AND BASS STRAIT <BR>AVERAGE TEMP '.. temp ..'°C / '..f_temp..'°F <BR> SEA STATE '.. sea ..' <BR>'..precipdesc..' PRECIPITATION <BR>'..clouddesc..'<BR>'..outlook) 
ScenEdit_SpecialMessage('playerside',wx_report) 
end 

WeatherReport()
Random ship/merchant/fish generator
Submitted by whicker credit to Apache85 via http://thestrategygamer.com on June 28, 2018 | Edit
math.randomseed(os.time())

merch_num = math.random(5,10) --change 5 or 10 to your specified minimum and maximum number of merchants


for i = 1,merch_num do
redo_count = 0
::redo::
local lat_var = math.random(1,(10^13))
local lon_var = math.random(1,(10^13))
v_lat = math.random(20,28) + (lat_var/(10^13)) --change the first set (south is negative) to your specified minimum and maximum latitude values; it's important that the first number is smaller than the second.

v_lon = math.random(-95,-63) + (lon_var/(10^13)) --change first set (west is negative!) to your specified minimum and maximum longitude values; it's important that the first number is smaller than the second.

elevation = World_GetElevation({latitude=v_lat, longitude=v_lon})
if elevation > -10 then --Checks to see if the water is deep enough, adjust as you please

redo_count = redo_count + 1
print("no")
if redo_count >50 then
print (redo_count .. 'ships were not able to find a suitable spot for placement. Re-check latitude and longitude settings')
break --this cuts the loop if there are no suitable positions found after 50 tries, prevents infinite loop/game freeze

else
goto redo --retries the placement if the water is too shallow

end
end
DBIDTABLE = { 775, 2027, 2029, 2028, 2030, 774, 2026, 2031, 2775, 2023, 773, 2774, 1001, 1374, 2773, 2776, 1006, 222, 1599, 2034, 1002, 1317, 144, 339, 275, 145, 2022, 259 } --list of DBIDs

DBID = DBIDTABLE[math.random( 1, #DBIDTABLE)]
local new_merch = ScenEdit_AddUnit({side='Merchant', type='Ship',name='Merchant #'..i, dbid=DBID,latitude=v_lat,longitude=v_lon})
local fuel = new_merch.fuel
fuel[3001].current = fuel[3001].max*math.random(600, 800)/1000
new_merch.fuel = fuel
--ScenEdit_AssignUnitToMission( new_merch.name, 'VLADIVOSTOK')

print (new_merch.name..' with dbid '..DBID..' was created in water with a depth of '..elevation..'m')
end
Cargo - Here is an example to transform different type of units as they disembark (Mech, Inf, Armored, Arty)
Submitted by whicker Credit to TyphoonFr on June 28, 2018 | Edit
s="GTIA" 
local cargo = ScenEdit_UnitX() 
local elev = World_GetElevation({latitude=cargo.latitude,longitude=cargo.longitude}) 

ScenEdit_DeleteUnit({s,name=cargo.name}) 

if cargo.dbid ==2984 then --a unit Mech Inf becomes a Mech Inf Plt (VBCI) 

local sgtia = ScenEdit_AddUnit({ 
side=s, 
type='Facility', 
dbid=2396, 
name='92RI', 
latitude=cargo.latitude, 
longitude=cargo.longitude}) 

elseif cargo.dbid ==2990 then --a unit Landed Detachment becomes a Vehicule VBL 

local sgtia = ScenEdit_AddUnit({ 
side=s, 
type='Facility', 
dbid=2200, 
name='3RICM', 
latitude=cargo.latitude, 
longitude=cargo.longitude}) 

elseif cargo.dbid ==2983 then --a unit Armored Plt Generic becomes a Armored Plt Amx-10RC 

local sgtia = ScenEdit_AddUnit({ 
side=s, 
type='Facility', 
dbid=2198, 
name='3RICM', 
latitude=cargo.latitude, 
longitude=cargo.longitude}) 

elseif cargo.dbid ==2985 then -- a unit Arty Generic becomes a Arty Bty Caésar 

local sgtia = ScenEdit_AddUnit({ 
side=s, 
type='Facility', 
dbid=2401, 
name='11RA', 
latitude=cargo.latitude, 
longitude=cargo.longitude}) 

end
Weather: Night and Morning Low Clouds Part 2 - This goes in an event that triggers every 30 minutes.
Submitted by whicker on June 28, 2018 | Edit
math.randomseed(os.time());
local scenarioWeather = ScenEdit_GetWeather();
local clouds = scenarioWeather.undercloud;
-- Check and set hour, used to track hour of day

local halfHour = ScenEdit_GetKeyValue("HalfHour");
halfHour = tonumber(halfHour);
-- early clouds is used for the early morning hours to have the change be slower

local earlyClouds = ScenEdit_GetKeyValue("EarlyClouds");
earlyClouds = tonumber(earlyClouds);
print("halfHour = " ..halfHour);
print("early clouds = " ..earlyClouds);

if halfHour >=0 and halfHour <=10  then
halfHour = halfHour + 1;
local rain = 0;
local seas = 1
-- if there is heavy fog add light rain

	if earlyClouds >= 1.06 then 
		rain = 4;
		seas = 3
	end
ScenEdit_SetWeather(28,rain,earlyClouds,seas);
ScenEdit_SetKeyValue("HalfHour", tostring(halfHour));
earlyClouds = earlyClouds - .02;
ScenEdit_SetKeyValue("EarlyClouds", tostring(earlyClouds));

elseif halfHour >= 11 and halfHour <=35 then
clouds = clouds - .04;
  if clouds <= .05 then clouds = 0;
  end
halfHour = halfHour + 1;
ScenEdit_SetWeather(31,0,clouds,2);
ScenEdit_SetKeyValue("HalfHour", tostring(halfHour));

elseif halfHour >=36 and halfHour <=46 then
clouds = clouds +.07;
halfHour = halfHour + 1;
ScenEdit_SetWeather(29,0,clouds,3);
ScenEdit_SetKeyValue("HalfHour", tostring(halfHour));

elseif halfHour == 47 then
clouds = .7;
halfHour = 0;
ScenEdit_SetWeather(29,0,clouds,2);
local w = ScenEdit_GetWeather();
local wtemp = w.temp;
local wclouds = w.undercloud;
local wseas = w.seastate;
local wrain = w.rainfall;
ScenEdit_SetKeyValue("HalfHour", tostring(halfHour));
--reset earlyClouds - random, 1.1 is heavy fog, .7 is cloudy

earlyClouds = math.random(7,11)/10;
ScenEdit_SetKeyValue("EarlyClouds", tostring(earlyClouds));
print (earlyClouds);
local TimeVar = ScenEdit_CurrentTime();
TimeVar = TimeVar + 7200; --adjust time to key west

local time = (os.date("%A %B %d %H%M ",TimeVar));

local fogMessage = "";
local veryHeavyFog = "*****VERY HEAVY FOG TONIGHT, LIGHT RAIN*****<br><br>We expect to see very heavy fog and light rain starting in the next 30-40 minutes, the Sea State will also increase slightly while it is raining. The rain should not last long. The fog will last for several hours, then should begin to clear by 0600. Solid low clouds will persist till mid morning. We expect clear skies for at least an hour or two in the late afternoon."
local heavyFog = "***HEAVY FOG TONIGHT***<br><br>We expect to see heavy fog starting in the next 30-40 minutes, lasting for several hours. The fog should begin to clear by 0430. Solid low clouds will persist till mid morning. We expect clear skies for at least an hour or two in the late afternoon."
local moderateFog = "**MODERATE FOG TONIGHT**<br><br>We expect to see fog tonight starting in the next 30-40 minutes, lasting for a couple hours. The fog should begin to clear by 0300. Solid low clouds should start to break up by early morning. We expect clear skies for a few hours this afternoon."
--local lightFog = "***LIGHT FOG TONIGHT*** We expect to see fog tonight starting in the next hour, lasting for an hour or so. It should clear quickly and we still expect clear skies for several hours this afternoon."

local noFog = "No fog tonight, skies should be clear by late morning with several hours of clear skies."
  	if earlyClouds <= .8 then fogMessage = noFog;
  		elseif earlyClouds == .9 then fogMessage = moderateFog;
  			elseif earlyClouds == 1 then fogMessage = heavyFog;
  				elseif earlyClouds == 1.1 then fogMessage = veryHeavyFog;
  			end

ScenEdit_SpecialMessage(ScenEdit_PlayerSide(), '<div style="text-transform: uppercase;font-family:Courier New;"><p>' .. time .. ' (KeyWest)</p><P>COMMANDER,</P><P>CURRENT WEATHER REPORT,</P> TEMPERATURE: ' .. wtemp .. 'C (High: 41C, Low: 25C) <br>RAIN STATE: ' .. wrain .. '<br>CLOUD LEVEL: Moderate middle clouds, 7-16k feet, light high clouds 27-30k feet<br>SEA STATE: ' .. wseas .. '<p>' .. fogMessage .. '</p><p>It looks like the weather for the next few days should be more of the same, night and morning low clouds with a chance of fog in the very early morning hours.</p><p>Sea State has been fairly mild, usually 1-2 in the early morning, increasing to 3 in the afternoon and evening.</p></div>');
else
 print("Something is wrong, halfhour not set?");
end

print(ScenEdit_GetWeather());
Weather: Night and Morning Low Clouds Part 1 - This is the setup for the weather, goes in the `On Scenario Loaded` event
Submitted by whicker on June 28, 2018 | Edit
math.randomseed(os.time());
-- Check and set hour, used to track hour of day

local halfHour = 34;
ScenEdit_SetWeather(15,0,0,1);
ScenEdit_SetKeyValue("HalfHour",  tostring(halfHour));
local earlyClouds = math.random(8,10)/10;
ScenEdit_SetKeyValue("EarlyClouds", tostring(earlyClouds));
print("Scen loaded halfhour = " ..halfHour);