diff --git a/CTLD.lua b/CTLD.lua index 16d8c47..9418c6d 100644 --- a/CTLD.lua +++ b/CTLD.lua @@ -13,7 +13,12 @@ Contributors: - Steggles - https://github.com/Bob7heBuilder - Version: 1.52 - 20/02/2015 - BUG FIX - Disabled Crate static until ED bug is fixed + Version: 1.60 - 20/03/2015 + - Added ability to disable hover pickup and instead load crates with F10 + - Added new function - ctld.removeExtractZone to stop an extract zone after a while + - Added ability to limit the number of AA systems that can be built and active at one time + + ]] ctld = {} -- DONT REMOVE! @@ -22,14 +27,17 @@ ctld = {} -- DONT REMOVE! -- ********************* USER CONFIGURATION ****************************** -- ************************************************************************ -ctld.staticBugFix = true -- When statics are destroyed, DCS Crashes. Set this to FALSE when this bug is fixed :) +ctld.staticBugFix = true -- When statics are destroyed, DCS Crashes. Set this to FALSE when this bug is fixed or if you want to use REAL sling loads :) ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below +ctld.hoverPickup = true -- if set to false you can load crates with the F10 menu instead of hovering... + ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS ctld.slingLoad = false -- if false, crates can be used WITHOUT slingloading, by hovering above the crate, simulating slingloading but not the weight... -- There are some bug with Sling-loading that can cause crashes, if these occur set slingLoad to false -- to use the other method. +-- Set staticBugFix to FALSE if use set ctld.slingLoad to TRUE ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke @@ -82,6 +90,19 @@ ctld.hoverTime = 10 -- Time to hold hover above a crate for loading in seconds -- end of Simulated Sling load configuration +-- AA SYSTEM CONFIG -- +-- Sets a limit on the number of active AA systems that can be built for RED. +-- A system is counted as Active if its fully functional and has all parts +-- If a system is partially destroyed, it no longer counts towards the total +-- When this limit is hit, a player will still be able to get crates for an AA system, just unable +-- to unpack them + +ctld.AASystemLimitRED = 20 -- Red side limit + +ctld.AASystemLimitBLUE = 20 -- Blue side limit + +--END AA SYSTEM CONFIG -- + -- ***************** JTAC CONFIGURATION ***************** ctld.JTAC_LIMIT_RED = 10 -- max number of JTAC Crates for the RED Side @@ -642,8 +663,9 @@ function ctld.createExtractZone(_zone, _flagNumber, _smoke) trigger.action.setUserFlag(_flagNumber, 0) --start at 0 - local _details = { point = _pos3, name = _zone, smoke = _smoke, flag = _flagNumber, radius = _triggerZone.radius } - table.insert(ctld.extractZones, _details) + local _details = { point = _pos3, name = _zone, smoke = _smoke, flag = _flagNumber, radius = _triggerZone.radius} + + ctld.extractZones[_zone.."-".._flagNumber] = _details if _smoke ~= nil and _smoke > -1 then @@ -651,6 +673,14 @@ function ctld.createExtractZone(_zone, _flagNumber, _smoke) _smokeFunction = function(_args) + local _extractDetails = ctld.extractZones[_zone.."-".._flagNumber] + -- check zone is still active + if _extractDetails == nil then + -- stop refreshing smoke, zone is done + return + end + + trigger.action.smoke(_args.point, _args.smoke) --refresh in 5 minutes timer.scheduleFunction(_smokeFunction, _args, timer.getTime() + 300) @@ -661,6 +691,29 @@ function ctld.createExtractZone(_zone, _flagNumber, _smoke) end end + +-- Removes an extraction zone +-- +-- The smoke will take up to 5 minutes to disappear depending on the last time the smoke was activated +-- +-- The ctld.removeExtractZone function needs to be called once in a trigger action do script. +-- +-- e.g. ctld.removeExtractZone("extractzone1", 2) will remove an extraction zone at trigger zone "extractzone1" +-- that was setup with flag 2 +-- +-- +-- +function ctld.removeExtractZone(_zone,_flagNumber) + + local _extractDetails = ctld.extractZones[_zone.."-".._flagNumber] + + if _extractDetails ~= nil then + --remove zone + ctld.extractZones[_zone.."-".._flagNumber] = nil + + end +end + -- CONTINUOUS TRIGGER FUNCTION -- This function will count the current number of extractable RED and BLUE -- GROUPS in a zone and store the values in two flags @@ -1141,7 +1194,7 @@ function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight,_side) local _crate local _spawnedCrate - if ctld.staticBugFix then + if ctld.staticBugFix and ctld.slingLoad == false then local _groupId = mist.getNextGroupId() local _groupName = "Crate Group #".._groupId @@ -1162,7 +1215,7 @@ function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight,_side) _group.category = Group.Category.GROUND; _group.country = _country; - local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) + local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) -- Turn off AI trigger.action.setGroupAIOff(_spawnedGroup) @@ -2193,6 +2246,53 @@ function ctld.checkHoverStatus() end end +function ctld.loadNearbyCrate(_name) + local _transUnit = ctld.getTransportUnit(_name) + + if _transUnit ~= nil then + + if ctld.inAir(_transUnit) then + ctld.displayMessageToGroup(_transUnit, "You must land before you can load a crate!", 10,true) + return + end + + if ctld.inTransitSlingLoadCrates[_name] == nil then + local _crates = ctld.getCratesAndDistance(_transUnit) + + for _, _crate in pairs(_crates) do + + if _crate.dist < 50.0 then + ctld.displayMessageToGroup(_transUnit, "Loaded " .. _crate.details.desc .. " crate!", 10,true) + + if _transUnit:getCoalition() == 1 then + ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil + else + ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil + end + + _crate.crateUnit:destroy() + + local _copiedCrate = mist.utils.deepCopy(_crate.details) + + ctld.inTransitSlingLoadCrates[_name] = _copiedCrate + return + end + end + + ctld.displayMessageToGroup(_transUnit, "No Crates within 50m to load!", 10,true) + + else + -- crate onboard + + local _currentCrate = mist.utils.deepCopy(ctld.inTransitSlingLoadCrates[_name]) + + ctld.displayMessageToGroup(_transUnit, "You already have a ".._currentCrate.desc.." crate onboard!", 10,true) + end + end + + +end + --recreates beacons to make sure they work! function ctld.refreshRadioBeacons() @@ -2763,7 +2863,11 @@ function ctld.dropSlingCrate(_args) local _currentCrate = ctld.inTransitSlingLoadCrates[_heli:getName()] if _currentCrate == nil then - ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate, hover for 10 seconds above the crate", 10) + if ctld.hoverPickup then + ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate, hover for "..ctld.hoverTime.." seconds above the crate", 10) + else + ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate - land and use F10 Crate Commands to load one.", 10) + end else local _heli = ctld.getTransportUnit(_args[1]) @@ -3251,7 +3355,7 @@ function ctld.getAASystemDetails(_hawkGroup,_aaSystemTemplate) local _hawkDetails = {} for _, _unit in pairs(_units) do - table.insert(_hawkDetails, { point = _unit:getPoint(), unit = _unit:getTypeName(), name = _unit:getName(), system=_aaSystemTemplate}) + table.insert(_hawkDetails, { point = _unit:getPoint(), unit = _unit:getTypeName(), name = _unit:getName(), system =_aaSystemTemplate}) end return _hawkDetails @@ -3350,7 +3454,18 @@ function ctld.unpackAASystem(_heli, _nearestCrate, _nearbyCrates,_aaSystemTempla end end - if _txt ~= "" then + local _activeLaunchers = ctld.countCompleteAASystems(_heli) + + local _allowed = ctld.getAllowedAASystems(_heli) + + env.info("Active: ".._activeLaunchers.." Allowed: ".._allowed) + + if _activeLaunchers + 1 > _allowed then + trigger.action.outTextForCoalition(_heli:getCoalition(), "Out of parts for AA Systems. Current limit is ".._allowed.." \n", 10) + return + end + + if _txt ~= "" then ctld.displayMessageToGroup(_heli, "Cannot build ".._aaSystemTemplate.name.."\n" .. _txt .. "\n\nOr the crates are not close enough together", 20) return else @@ -3377,11 +3492,70 @@ function ctld.unpackAASystem(_heli, _nearestCrate, _nearbyCrates,_aaSystemTempla ctld.processCallback({unit = _heli, crate = _nearestCrate , spawnedGroup = _spawnedGroup, action = "unpack"}) - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully deployed a full ".._aaSystemTemplate.name.." to the field", 10) + trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully deployed a full ".._aaSystemTemplate.name.." to the field. \n\nAA Active System limit is: ".._allowed.."\nActive: "..(_activeLaunchers+1), 10) end end +--count the number of captured cities, sets the amount of allowed AA Systems +function ctld.getAllowedAASystems(_heli) + + if _heli:getCoalition() == 1 then + return ctld.AASystemLimitBLUE + else + return ctld.AASystemLimitRED + end + + +end + + +function ctld.countCompleteAASystems(_heli) + + local _count = 0 + + for _groupName, _hawkDetails in pairs(ctld.completeAASystems) do + + local _hawkGroup = Group.getByName(_groupName) + + -- env.info(_groupName..": "..mist.utils.tableShow(_hawkDetails)) + if _hawkGroup ~= nil and _hawkGroup:getCoalition() == _heli:getCoalition() then + + local _units = _hawkGroup:getUnits() + + if _units ~=nil and #_units > 0 then + --get the system template + local _aaSystemTemplate = _hawkDetails[1].system + + local _uniqueTypes = {} -- stores each unique part of system + local _types = {} + local _points = {} + + if _units ~= nil and #_units > 0 then + + for x = 1, #_units do + if _units[x]:getLife() > 0 then + + --this allows us to count each type once + _uniqueTypes[_units[x]:getTypeName()] = _units[x]:getTypeName() + + table.insert(_points, _units[x]:getPoint()) + table.insert(_types, _units[x]:getTypeName()) + end + end + end + + -- do we have the correct number of unique pieces and do we have enough points for all the pieces + if ctld.countTableEntries(_uniqueTypes) == _aaSystemTemplate.count and #_points >= _aaSystemTemplate.count then + _count = _count +1 + end + end + end + end + + return _count +end + function ctld.repairAASystem(_heli, _nearestCrate,_aaSystem) @@ -4224,6 +4398,9 @@ function ctld.addF10MenuOptions() if ctld.enabledFOBBuilding or ctld.enableCrates then local _crateCommands = missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands", _rootPath) + if ctld.hoverPickup == false then + missionCommands.addCommandForGroup(_groupId, "Load Nearby Crate", _crateCommands, ctld.loadNearbyCrate, _unitName ) + end missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", _crateCommands, ctld.unpackCrates, { _unitName }) @@ -4386,7 +4563,7 @@ ctld.jtacLaserPointCodes = {} function ctld.JTACAutoLase(_jtacGroupName, _laserCode, _smoke, _lock, _colour) if ctld.jtacStop[_jtacGroupName] == true then - ctld.jtacStop[_jtacGroupName] = nil + ctld.jtacStop[_jtacGroupName] = nil -- allow it to be started again ctld.cleanupJTAC(_jtacGroupName) return end @@ -5391,7 +5568,7 @@ timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 1) timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 5) -if ctld.enableCrates == true and ctld.slingLoad == false then +if ctld.enableCrates == true and ctld.slingLoad == false and ctld.hoverPickup then timer.scheduleFunction(ctld.checkHoverStatus, nil, timer.getTime() + 1) end @@ -5467,4 +5644,4 @@ env.info("CTLD READY") -- for key, value in pairs(getmetatable(_spawnedCrate)) do -- env.info(tostring(key)) -- env.info(tostring(value)) --- end +-- end \ No newline at end of file diff --git a/Cargo Spawn Test.miz b/Cargo Spawn Test.miz index 730408d..ab009bc 100644 Binary files a/Cargo Spawn Test.miz and b/Cargo Spawn Test.miz differ diff --git a/Pickup-Dropoff-Demo.miz b/Pickup-Dropoff-Demo.miz index 9ceb10a..0037683 100644 Binary files a/Pickup-Dropoff-Demo.miz and b/Pickup-Dropoff-Demo.miz differ diff --git a/README.md b/README.md index fcb6b15..9159a65 100644 --- a/README.md +++ b/README.md @@ -96,26 +96,34 @@ To use the real cargo sling behaviour, set the ```ctld.slingLoad``` option to `` -- ************************************************************************ -- ********************* USER CONFIGURATION ****************************** -- ************************************************************************ +ctld.staticBugFix = true -- When statics are destroyed, DCS Crashes. Set this to FALSE when this bug is fixed or if you want to use REAL sling loads :) + ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below +ctld.hoverPickup = true -- if set to false you can load crates with the F10 menu instead of hovering...! + ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS ctld.slingLoad = false -- if false, crates can be used WITHOUT slingloading, by hovering above the crate, simulating slingloading but not the weight... -- There are some bug with Sling-loading that can cause crashes, if these occur set slingLoad to false -- to use the other method. +-- Set staticBugFix to FALSE if use set ctld.slingLoad to TRUE ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke ctld.maxExtractDistance = 125 -- max distance from vehicle to troops to allow a group extraction ctld.maximumDistanceLogistic = 200 -- max distance from vehicle to logistics to allow a loading or spawning operation ctld.maximumSearchDistance = 4000 -- max distance for troops to search for enemy -ctld.maximumMoveDistance = 1000 -- max distance for troops to move from drop point if no enemy is nearby +ctld.maximumMoveDistance = 2000 -- max distance for troops to move from drop point if no enemy is nearby ctld.numberOfTroops = 10 -- default number of troops to load on a transport heli or C-130 +ctld.enableFastRopeInsertion = true -- allows you to drop troops by fast rope +ctld.fastRopeMaximumHeight = 18.28 -- in meters which is 60 ft max fast rope (not rappell) safe height ctld.vehiclesForTransportRED = { "BRDM-2", "BTR_D" } -- vehicles to load onto Il-76 - Alternatives {"Strela-1 9P31","BMP-1"} ctld.vehiclesForTransportBLUE = { "M1045 HMMWV TOW", "M1043 HMMWV Armament" } -- vehicles to load onto c130 - Alternatives {"M1128 Stryker MGS","M1097 Avenger"} -ctld.hawkLaunchers = 3 -- controls how many launchers to add to the hawk when its spawned. +ctld.aaLaunchers = 3 -- controls how many launchers to add to the kub/buk when its spawned. +ctld.hawkLaunchers = 5 -- controls how many launchers to add to the hawk when its spawned. ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces ctld.spawnStinger = false -- spawns a stinger / igla soldier with a group of 6 or more soldiers! @@ -125,7 +133,9 @@ ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 tha -- You can also enable troop Pickup at FOBS ctld.cratesRequiredForFOB = 3 -- The amount of crates required to build a FOB. Once built, helis can spawn crates at this outpost to be carried and deployed in another area. --- The crates can only be loaded and dropped by large aircraft, like the C-130 and listed in ctld.vehicleTransportEnabled +-- The large crates can only be loaded and dropped by large aircraft, like the C-130 and listed in ctld.vehicleTransportEnabled +-- Small FOB crates can be moved by helicopter. The FOB will require ctld.cratesRequiredForFOB larges crates and small crates are 1/3 of a large fob crate +-- To build the FOB entirely out of small crates you will need ctld.cratesRequiredForFOB * 3 ctld.troopPickupAtFOB = true -- if true, troops can also be picked up at a created FOB @@ -134,9 +144,34 @@ ctld.buildTimeFOB = 120 --time in seconds for the FOB to be built ctld.radioSound = "beacon.ogg" -- the name of the sound file to use for the FOB radio beacons. If this isnt added to the mission BEACONS WONT WORK! ctld.radioSoundFC3 = "beaconsilent.ogg" -- name of the second silent radio file, used so FC3 aircraft dont hear ALL the beacon noises... :) -ctld.deployedBeaconBattery = 20 -- the battery on deployed beacons will last for this number minutes before needing to be re-deployed +ctld.deployedBeaconBattery = 30 -- the battery on deployed beacons will last for this number minutes before needing to be re-deployed ctld.enabledRadioBeaconDrop = true -- if its set to false then beacons cannot be dropped by units + +ctld.allowRandomAiTeamPickups = false -- Allows the AI to randomize the loading of infantry teams (specified below) at pickup zones + +-- Simulated Sling load configuration + +ctld.minimumHoverHeight = 7.5 -- Lowest allowable height for crate hover +ctld.maximumHoverHeight = 12.0 -- Highest allowable height for crate hover +ctld.maxDistanceFromCrate = 5.5 -- Maximum distance from from crate for hover +ctld.hoverTime = 10 -- Time to hold hover above a crate for loading in seconds + +-- end of Simulated Sling load configuration + +-- AA SYSTEM CONFIG -- +-- Sets a limit on the number of active AA systems that can be built for RED. +-- A system is counted as Active if its fully functional and has all parts +-- If a system is partially destroyed, it no longer counts towards the total +-- When this limit is hit, a player will still be able to get crates for an AA system, just unable +-- to unpack them + +ctld.AASystemLimitRED = 20 -- Red side limit + +ctld.AASystemLimitBLUE = 20 -- Blue side limit + +--END AA SYSTEM CONFIG -- + ``` To change what units can be dropped from crates modify the spawnable crates section. An extra parameter, ```cratesRequired = NUMBER``` can be added so you need more than one crate to build a unit. This parameter cannot be used for the HAWK, BUK or KUB system as that is already broken into 3 crates. You can also specify the coalition side so RED and BLUE have different crates to drop. If the parameter is missing the crate will appear for both sides. @@ -326,7 +361,7 @@ Spawned beacons will broadcast on HF/FM, UHF and VHF until their battery runs ou **Again, beacons will not work if beacon.ogg and beaconsilent.ogg are not in the mission!** -#### Create Extract Zone +#### Create / Remove Extract Zone An extact zone is a zone where troops (not vehicles) can be dropped by transports and used to trigger another action based on the number of troops dropped. The radius of the zone sets how big the extract zone will be. When troops are dropped, the troops disappear and the number of troops dropped added to the flag number configured by the function. This means you can make a trigger such that 10 troops have to be rescued and dropped at the extract zone, and when this happens you can trigger another action. @@ -336,6 +371,10 @@ Where ```"extractzone1"``` is the name of a Trigger Zone added using the mission The settings for smoke are: Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4, NO SMOKE = -1 +An extract zone can be removed by using DO SCRIPT action of ```ctld.removeExtractZone("extractzone1", 2)```. Where again ```"extractzone1"``` is the name of a Trigger Zone added using the mission editor, ```2``` is the flag + +The smoke for the extract zone will take up to 5 minutes to disappate. + #### Count Extractable UNITS in zone You can count the number of extractable UNITS in a zone using: ```ctld.countDroppedUnitsInZone(_zone, _blueFlag, _redFlag)``` as a DO SCRIPT of a CONTINUOUS TRIGGER. @@ -478,7 +517,7 @@ Smoke colours are: Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4 The script doesn't care if the unit isn't activated when run, as it'll automatically activate when the JTAC is activated in the mission but there can be a delay of up to 30 seconds after activation for the JTAC to start searching for targets. -You can also change the name of a unit (unit, not group) to include "hpriority" to make it high priority for the JTAC, or "priority" to set it to be medium priority. JTAC's will prioritize targets within view by first marking hpriority targets, then priority targets, and finally all others. This works seemlessly with the all/vehicle/troop functionality as well. In this way you can have them lase SAMS, then AAA, then armor, or any other order you decide is preferable. +You can also change the **name of a unit*** (unit, not group) to include "**hpriority**" to make it high priority for the JTAC, or "**priority**" to set it to be medium priority. JTAC's will prioritize targets within view by first marking hpriority targets, then priority targets, and finally all others. This works seemlessly with the all/vehicle/troop functionality as well. In this way you can have them lase SAMS, then AAA, then armor, or any other order you decide is preferable. ### Pickup and Dropoff Zones Setup Pickup zones are used by transport aircraft and helicopters to load troops and vehicles. A transport unit must be inside of the radius of the trigger and the right side (RED or BLUE or BOTH) in order to load troops and vehicles. @@ -687,6 +726,8 @@ Once you've loaded the crate, fly to where you want to drop it and drop using th Once on the ground unpack as normal using the CTLD Commands Menu - CTLD->CTLD Commands->Unpack Crate +**Note: You can also set ```ctld.hoverPickup = false``` so you can load crates using the F10 menu instead of Hovering. ** + ### Real Sling Loading This uses the inbuilt DCS Sling cargo system and crates. Sling cargo weight differs drastically depending on what you are sling loading. The Huey will need to have 20% fuel and no armaments in order to be able to lift a HMMWV TOW crate! The Mi-8 has a higher max lifting weight than a Huey. diff --git a/mist.lua b/mist.lua index ad4d2d0..1b42f52 100644 --- a/mist.lua +++ b/mist.lua @@ -14,855 +14,869 @@ mist = {} -- don't change these mist.majorVersion = 4 -mist.minorVersion = 0 -mist.build = 57 +mist.minorVersion = 1 +mist.build = 61 -------------------------------------------------------------------------------------------------------------- -- the main area do - local coroutines = {} - - local tempSpawnedUnits = {} -- birth events added here - local mistAddedObjects = {} -- mist.dynAdd unit data added here - local mistAddedGroups = {} -- mist.dynAdd groupdata added here - local writeGroups = {} - local lastUpdateTime = 0 - - local function update_alive_units() -- coroutine function - local lalive_units = mist.DBs.aliveUnits -- local references for faster execution - local lunits = mist.DBs.unitsByNum - local ldeepcopy = mist.utils.deepCopy - local lUnit = Unit - local lremovedAliveUnits = mist.DBs.removedAliveUnits - local updatedUnits = {} - - if #lunits > 0 then - local units_per_run = math.ceil(#lunits/20) - if units_per_run < 5 then - units_per_run = 5 - end - - for i = 1, #lunits do - if lunits[i].category ~= 'static' then -- can't get statics with Unit.getByName :( - local unit = lUnit.getByName(lunits[i].unitName) - if unit then - --print('unit named ' .. lunits[i].unitName .. ' alive!') - local pos = unit:getPosition() - local newtbl = ldeepcopy(lunits[i]) - if pos then - newtbl['pos'] = pos.p - end - newtbl['unit'] = unit - --newtbl['rt_id'] = unit.id_ - lalive_units[unit.id_] = newtbl - updatedUnits[unit.id_] = true - end - end - if i%units_per_run == 0 then - --print('yielding at: ' .. tostring(i)) - coroutine.yield() - --print('resuming at: ' .. tostring(i)) - end - end - -- All units updated, remove any "alive" units that were not updated- they are dead! - for unit_id, unit in pairs(lalive_units) do - if not updatedUnits[unit_id] then - lremovedAliveUnits[unit_id] = unit - lalive_units[unit_id] = nil - end - end - end - end - - local function dbUpdate(event) - local newTable = {} - - newTable['startTime'] = 0 - - if type(event) == 'string' then -- if name of an object. - local newObject - local newType = 'group' - if Group.getByName(event) then - newObject = Group.getByName(event) - elseif StaticObject.getByName(event) then - newObject = StaticObject.getByName(event) - newType = 'static' - -- env.info('its static') - else - env.info('WTF') - return false - end - + local coroutines = {} + + local tempSpawnedUnits = {} -- birth events added here + local mistAddedObjects = {} -- mist.dynAdd unit data added here + local mistAddedGroups = {} -- mist.dynAdd groupdata added here + local writeGroups = {} + local lastUpdateTime = 0 + + local function update_alive_units() -- coroutine function + local lalive_units = mist.DBs.aliveUnits -- local references for faster execution + local lunits = mist.DBs.unitsByNum + local ldeepcopy = mist.utils.deepCopy + local lUnit = Unit + local lremovedAliveUnits = mist.DBs.removedAliveUnits + local updatedUnits = {} + + if #lunits > 0 then + local units_per_run = math.ceil(#lunits/20) + if units_per_run < 5 then + units_per_run = 5 + end + + for i = 1, #lunits do + if lunits[i].category ~= 'static' then -- can't get statics with Unit.getByName :( + local unit = lUnit.getByName(lunits[i].unitName) + if unit then + --print('unit named ' .. lunits[i].unitName .. ' alive!') + local pos = unit:getPosition() + local newtbl = ldeepcopy(lunits[i]) + if pos then + newtbl['pos'] = pos.p + end + newtbl['unit'] = unit + --newtbl['rt_id'] = unit.id_ + lalive_units[unit.id_] = newtbl + updatedUnits[unit.id_] = true + end + end + if i%units_per_run == 0 then + --print('yielding at: ' .. tostring(i)) + coroutine.yield() + --print('resuming at: ' .. tostring(i)) + end + end + -- All units updated, remove any "alive" units that were not updated- they are dead! + for unit_id, unit in pairs(lalive_units) do + if not updatedUnits[unit_id] then + lremovedAliveUnits[unit_id] = unit + lalive_units[unit_id] = nil + end + end + end + end + + local function dbUpdate(event) + local newTable = {} + + newTable['startTime'] = 0 + + if type(event) == 'string' then -- if name of an object. + local newObject + local newType = 'group' + if Group.getByName(event) then + newObject = Group.getByName(event) + elseif StaticObject.getByName(event) then + newObject = StaticObject.getByName(event) + newType = 'static' + -- env.info('its static') + else + env.info('WTF') + return false + end + - - newTable.name = newObject:getName() - newTable.groupId = tonumber(newObject:getID()) - newTable.groupName = newObject:getName() - local unitOneRef - if newType == 'static' then - unitOneRef = newObject - newTable.countryId = tonumber(newObject:getCountry()) - newTable.coalitionId = tonumber(newObject:getCoalition()) - newTable.category = 'static' - else - unitOneRef = newObject:getUnits() - newTable.countryId = tonumber(unitOneRef[1]:getCountry()) - newTable.coalitionId = tonumber(unitOneRef[1]:getCoalition()) - newTable.category = tonumber(newObject:getCategory()) - end - for countryData, countryId in pairs(country.id) do - if newTable.country and string.upper(countryData) == string.upper(newTable.country) or countryId == newTable.countryId then - newTable['countryId'] = countryId - newTable['country'] = string.lower(countryData) - for coaData, coaId in pairs(coalition.side) do - if coaId == coalition.getCountryCoalition(countryId) then - newTable['coalition'] = string.lower(coaData) - end - end - end - end - for catData, catId in pairs(Unit.Category) do - if newType == 'group' and Group.getByName(newTable.groupName):isExist() then - if catId == Group.getByName(newTable.groupName):getCategory() then - newTable['category'] = string.lower(catData) - end - elseif newType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then - if catId == StaticObject.getByName(newTable.groupName):getCategory() then - newTable['category'] = string.lower(catData) - end - - end - end - local gfound = false - for index, data in pairs(mistAddedGroups) do - if mist.stringMatch(data.name, newTable.groupName) == true then - gfound = true - newTable.task = data.task - newTable.modulation = data.modulation - newTable.uncontrolled = data.uncontrolled - newTable.radioSet = data.radioSet - newTable.hidden = data.hidden - newTable.startTime = data.start_time - mistAddedGroups[index] = nil - end - end - - if gfound == false then - newTable.uncontrolled = false - newTable.hidden = false - end - - newTable.units = {} - if newType == 'group' then - for unitId, unitData in pairs(unitOneRef) do - newTable.units[unitId] = {} - newTable.units[unitId].unitName = unitData:getName() - - newTable.units[unitId].x = mist.utils.round(unitData:getPosition().p.x) - newTable.units[unitId].y = mist.utils.round(unitData:getPosition().p.z) - newTable.units[unitId].point = {} - newTable.units[unitId].point.x = newTable.units[unitId].x - newTable.units[unitId].point.y = newTable.units[unitId].y - newTable.units[unitId].alt = mist.utils.round(unitData:getPosition().p.y) - newTable.units[unitId].speed = mist.vec.mag(unitData:getVelocity()) - - newTable.units[unitId].heading = mist.getHeading(unitData, true) + + newTable.name = newObject:getName() + newTable.groupId = tonumber(newObject:getID()) + newTable.groupName = newObject:getName() + local unitOneRef + if newType == 'static' then + unitOneRef = newObject + newTable.countryId = tonumber(newObject:getCountry()) + newTable.coalitionId = tonumber(newObject:getCoalition()) + newTable.category = 'static' + else + unitOneRef = newObject:getUnits() + newTable.countryId = tonumber(unitOneRef[1]:getCountry()) + newTable.coalitionId = tonumber(unitOneRef[1]:getCoalition()) + newTable.category = tonumber(newObject:getCategory()) + end + for countryData, countryId in pairs(country.id) do + if newTable.country and string.upper(countryData) == string.upper(newTable.country) or countryId == newTable.countryId then + newTable['countryId'] = countryId + newTable['country'] = string.lower(countryData) + for coaData, coaId in pairs(coalition.side) do + if coaId == coalition.getCountryCoalition(countryId) then + newTable['coalition'] = string.lower(coaData) + end + end + end + end + for catData, catId in pairs(Unit.Category) do + if newType == 'group' and Group.getByName(newTable.groupName):isExist() then + if catId == Group.getByName(newTable.groupName):getCategory() then + newTable['category'] = string.lower(catData) + end + elseif newType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then + if catId == StaticObject.getByName(newTable.groupName):getCategory() then + newTable['category'] = string.lower(catData) + end + + end + end + local gfound = false + for index, data in pairs(mistAddedGroups) do + if mist.stringMatch(data.name, newTable.groupName) == true then + gfound = true + newTable.task = data.task + newTable.modulation = data.modulation + newTable.uncontrolled = data.uncontrolled + newTable.radioSet = data.radioSet + newTable.hidden = data.hidden + newTable.startTime = data.start_time + mistAddedGroups[index] = nil + end + end + + if gfound == false then + newTable.uncontrolled = false + newTable.hidden = false + end + + newTable.units = {} + if newType == 'group' then + for unitId, unitData in pairs(unitOneRef) do + newTable.units[unitId] = {} + newTable.units[unitId].unitName = unitData:getName() + + newTable.units[unitId].x = mist.utils.round(unitData:getPosition().p.x) + newTable.units[unitId].y = mist.utils.round(unitData:getPosition().p.z) + newTable.units[unitId].point = {} + newTable.units[unitId].point.x = newTable.units[unitId].x + newTable.units[unitId].point.y = newTable.units[unitId].y + newTable.units[unitId].alt = mist.utils.round(unitData:getPosition().p.y) + newTable.units[unitId].speed = mist.vec.mag(unitData:getVelocity()) + + newTable.units[unitId].heading = mist.getHeading(unitData, true) - newTable.units[unitId].type = unitData:getTypeName() - newTable.units[unitId].unitId = tonumber(unitData:getID()) - - - newTable.units[unitId].groupName = newTable.groupName - newTable.units[unitId].groupId = newTable.groupId - newTable.units[unitId].countryId = newTable.countryId - newTable.units[unitId].coalitionId = newTable.coalitionId - newTable.units[unitId].coalition = newTable.coalition - newTable.units[unitId].country = newTable.country - local found = false - for index, data in pairs(mistAddedObjects) do - if mist.stringMatch(data.name, newTable.units[unitId].unitName) == true then - found = true - newTable.units[unitId].livery_id = data.livery_id - newTable.units[unitId].skill = data.skill - newTable.units[unitId].alt_type = data.alt_type - newTable.units[unitId].callsign = data.callsign - newTable.units[unitId].psi = data.psi - mistAddedObjects[index] = nil - end - if found == false then - newTable.units[unitId].skill = "High" - newTable.units[unitId].alt_type = "BARO" - end - end - - end - else -- its a static - newTable.category = 'static' - newTable.units[1] = {} - newTable.units[1].unitName = newObject:getName() - newTable.units[1].category = 'static' - newTable.units[1].x = mist.utils.round(newObject:getPosition().p.x) - newTable.units[1].y = mist.utils.round(newObject:getPosition().p.z) - newTable.units[1].point = {} - newTable.units[1].point.x = newTable.units[1].x - newTable.units[1].point.y = newTable.units[1].y - newTable.units[1].alt = mist.utils.round(newObject:getPosition().p.y) - newTable.units[1].heading = mist.getHeading(newObject, true) - newTable.units[1].type = newObject:getTypeName() - newTable.units[1].unitId = tonumber(newObject:getID()) - newTable.units[1].groupName = newTable.name - newTable.units[1].groupId = newTable.groupId - newTable.units[1].countryId = newTable.countryId - newTable.units[1].country = newTable.country - newTable.units[1].coalitionId = newTable.coalitionId - newTable.units[1].coalition = newTable.coalition - if newObject:getCategory() == 6 and newObject:getCargoDisplayName() then - local mass = newObject:getCargoDisplayName() - mass = string.gsub(mass, ' ', '') - mass = string.gsub(mass, 'kg', '') - newTable.units[1].mass = tonumber(mass) - newTable.units[1].categoryStatic = 'Cargos' - newTable.units[1].canCargo = true - newTable.units[1].shape_name = 'ab-212_cargo' - end - - ----- search mist added objects for extra data if applicable - for index, data in pairs(mistAddedObjects) do - if mist.stringMatch(data.name, newTable.units[1].unitName) == true then - newTable.units[1].shape_name = data.shape_name -- for statics - newTable.units[1].livery_id = data.livery_id - newTable.units[1].airdromeId = data.airdromeId - newTable.units[1].mass = data.mass - newTable.units[1].canCargo = data.canCargo - newTable.units[1].categoryStatic = data.categoryStatic - newTable.units[1].type = 'cargo1' - mistAddedObjects[index] = nil - end - end - end - end - - newTable['timeAdded'] = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time - --mist.debug.dumpDBs() - --end - - return newTable - end - + newTable.units[unitId].type = unitData:getTypeName() + newTable.units[unitId].unitId = tonumber(unitData:getID()) + + + newTable.units[unitId].groupName = newTable.groupName + newTable.units[unitId].groupId = newTable.groupId + newTable.units[unitId].countryId = newTable.countryId + newTable.units[unitId].coalitionId = newTable.coalitionId + newTable.units[unitId].coalition = newTable.coalition + newTable.units[unitId].country = newTable.country + local found = false + for index, data in pairs(mistAddedObjects) do + if mist.stringMatch(data.name, newTable.units[unitId].unitName) == true then + found = true + newTable.units[unitId].livery_id = data.livery_id + newTable.units[unitId].skill = data.skill + newTable.units[unitId].alt_type = data.alt_type + newTable.units[unitId].callsign = data.callsign + newTable.units[unitId].psi = data.psi + mistAddedObjects[index] = nil + end + if found == false then + newTable.units[unitId].skill = "High" + newTable.units[unitId].alt_type = "BARO" + end + end + + end + else -- its a static + newTable.category = 'static' + newTable.units[1] = {} + newTable.units[1].unitName = newObject:getName() + newTable.units[1].category = 'static' + newTable.units[1].x = mist.utils.round(newObject:getPosition().p.x) + newTable.units[1].y = mist.utils.round(newObject:getPosition().p.z) + newTable.units[1].point = {} + newTable.units[1].point.x = newTable.units[1].x + newTable.units[1].point.y = newTable.units[1].y + newTable.units[1].alt = mist.utils.round(newObject:getPosition().p.y) + newTable.units[1].heading = mist.getHeading(newObject, true) + newTable.units[1].type = newObject:getTypeName() + newTable.units[1].unitId = tonumber(newObject:getID()) + newTable.units[1].groupName = newTable.name + newTable.units[1].groupId = newTable.groupId + newTable.units[1].countryId = newTable.countryId + newTable.units[1].country = newTable.country + newTable.units[1].coalitionId = newTable.coalitionId + newTable.units[1].coalition = newTable.coalition + if newObject:getCategory() == 6 and newObject:getCargoDisplayName() then + local mass = newObject:getCargoDisplayName() + mass = string.gsub(mass, ' ', '') + mass = string.gsub(mass, 'kg', '') + newTable.units[1].mass = tonumber(mass) + newTable.units[1].categoryStatic = 'Cargos' + newTable.units[1].canCargo = true + newTable.units[1].shape_name = 'ab-212_cargo' + end + + ----- search mist added objects for extra data if applicable + for index, data in pairs(mistAddedObjects) do + if mist.stringMatch(data.name, newTable.units[1].unitName) == true then + newTable.units[1].shape_name = data.shape_name -- for statics + newTable.units[1].livery_id = data.livery_id + newTable.units[1].airdromeId = data.airdromeId + newTable.units[1].mass = data.mass + newTable.units[1].canCargo = data.canCargo + newTable.units[1].categoryStatic = data.categoryStatic + newTable.units[1].type = 'cargo1' + mistAddedObjects[index] = nil + end + end + end + end + --mist.debug.writeData(mist.utils.serialize,{'msg', newTable}, timer.getAbsTime() ..'Group.lua') + newTable['timeAdded'] = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time + --mist.debug.dumpDBs() + --end + + return newTable + end + - - local function checkSpawnedEvents() - if #tempSpawnedUnits > 0 then - local groupsToAdd = {} - local ltemp = tempSpawnedUnits - local ltable = table + + local function checkSpawnedEvents() + if #tempSpawnedUnits > 0 then + local groupsToAdd = {} + local added = false + local ltemp = tempSpawnedUnits + local ltable = table - local updatesPerRun = math.ceil(#tempSpawnedUnits/20) - if updatesPerRun < 5 then - updatesPerRun = 5 - end - for x = 1, #tempSpawnedUnits do - local spawnedObj = ltemp[x] - if spawnedObj and spawnedObj:isExist() then - local found = false - for index, name in pairs(groupsToAdd) do - if spawnedObj:getCategory() == 1 then -- normal groups - if mist.stringMatch(spawnedObj:getGroup():getName(), name) == true then - found = true - break - end - elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects - if mist.stringMatch(spawnedObj:getName(), name) == true then - found = true - break - end - end - end - -- for some reason cargo objects are returning as category == 6. - if found == false then - if spawnedObj:getCategory() == 1 then -- normal groups - groupsToAdd[#groupsToAdd + 1] = spawnedObj:getGroup():getName() - elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects - groupsToAdd[#groupsToAdd + 1] = spawnedObj:getName() - end - end - end - + local updatesPerRun = math.ceil(#tempSpawnedUnits/20) + if updatesPerRun < 5 then + updatesPerRun = 5 + end + for x = 1, #tempSpawnedUnits do + local spawnedObj = ltemp[x] + if spawnedObj and spawnedObj:isExist() then + local found = false + for name, val in pairs(groupsToAdd) do + if spawnedObj:getCategory() == 1 then -- normal groups + if mist.stringMatch(spawnedObj:getGroup():getName(), name) == true then + found = true + break + end + elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects + if mist.stringMatch(spawnedObj:getName(), name) == true then + found = true + break + end + end + end + -- for some reason cargo objects are returning as category == 6. + if found == false then + added = true + if spawnedObj:getCategory() == 1 then -- normal groups + groupsToAdd[spawnedObj:getGroup():getName()] = true + elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects + groupsToAdd[spawnedObj:getName()] = true + end + + end + end - table.remove(ltemp, x) - if x%updatesPerRun == 0 then - coroutine.yield() - end - - end - - - if #groupsToAdd > 0 then - for groupId, groupName in pairs(groupsToAdd) do - if not mist.DBs.groupsByName[groupName] or mist.DBs.groupsByName[groupName] and mist.DBs.groupsByName[groupName].startTime + 10 < timer.getAbsTime() then - writeGroups[#writeGroups + 1] = dbUpdate(groupName) - end - end - end - end - end - - - local function updateDBTables() - local i = 0 - for index, newTable in pairs(writeGroups) do - i = i + 1 - end - local savesPerRun = math.ceil(i/10) - if savesPerRun < 5 then - savesPerRun = 5 - end - if i > 0 then - local ldeepCopy = mist.utils.deepCopy - for x = 1, i do - local newTable = writeGroups[x] - local mistCategory - if type(newTable.category) == 'string' then - mistCategory = string.lower(newTable.category) - end + table.remove(ltemp, x) + if x%updatesPerRun == 0 then + coroutine.yield() + end + end - if string.upper(newTable['category']) == 'GROUND_UNIT' then - mistCategory = 'vehicle' - newTable['category'] = mistCategory - elseif string.upper(newTable['category']) == 'AIRPLANE' then - mistCategory = 'plane' - newTable['category'] = mistCategory - elseif string.upper(newTable['category']) == 'HELICOPTER' then - mistCategory = 'helicopter' - newTable['category'] = mistCategory - elseif string.upper(newTable['category']) == 'SHIP' then - mistCategory = 'ship' - newTable['category'] = mistCategory - end - for newId, newUnitData in pairs(newTable.units) do - newUnitData.category = mistCategory - if newUnitData.unitId then - mist.DBs.unitsById[tonumber(newUnitData.unitId)] = ldeepCopy(newUnitData) - end - - mist.DBs.unitsByName[newUnitData.unitName] = ldeepCopy(newUnitData) - mist.DBs.unitsByCat[mistCategory][#mist.DBs.unitsByCat[mistCategory] + 1] = ldeepCopy(newUnitData) - mist.DBs.unitsByNum[#mist.DBs.unitsByNum + 1] = ldeepCopy(newUnitData) - end - -- this is a really annoying DB to populate. Gotta create new tables in case its missing - if not mist.DBs.units[newTable.coalition] then - mist.DBs.units[newTable.coalition] = {} - end + if added == true then + for groupName, val in pairs(groupsToAdd) do + local dataChanged = false + if mist.DBs.groupsByName[groupName] then + for _index, data in pairs(mist.DBs.groupsByName[groupName]) do + if data.unitName ~= spawnedObj:getName() and data.unitId ~= spawnedObj:getID() and data.type ~= spawnedObj:getTypeName() then + dataChanged = true + break + end + end + if dataChanged == false then + groupsToAdd[groupName] = false + end + end + if groupsToAdd[groupName] == true or not mist.DBs.groupsByName[groupName] then + writeGroups[#writeGroups + 1] = dbUpdate(groupName) + end + end + end + end + end + + + local function updateDBTables() + + local i = 0 + for index, newTable in pairs(writeGroups) do + i = i + 1 + end + local savesPerRun = math.ceil(i/10) + if savesPerRun < 5 then + savesPerRun = 5 + end + if i > 0 then + local ldeepCopy = mist.utils.deepCopy + for x = 1, i do + local newTable = writeGroups[x] + local mistCategory + if type(newTable.category) == 'string' then + mistCategory = string.lower(newTable.category) + end - if not mist.DBs.units[newTable.coalition][newTable.country] then - mist.DBs.units[newTable.coalition][(newTable.country)] = {} - mist.DBs.units[newTable.coalition][(newTable.country)]['countryId'] = newTable.countryId - end - if not mist.DBs.units[newTable.coalition][newTable.country][mistCategory] then - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] = {} - end - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][#mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] + 1] = ldeepCopy(newTable) - - if newTable.groupId then - mist.DBs.groupsById[newTable.groupId] = ldeepCopy(newTable) - end - - mist.DBs.groupsByName[newTable.name] = ldeepCopy(newTable) - mist.DBs.dynGroupsAdded[#mist.DBs.dynGroupsAdded + 1] = ldeepCopy(newTable) - - writeGroups[x] = nil - if x%savesPerRun == 0 then - coroutine.yield() - end - end - if timer.getTime() > lastUpdateTime then - lastUpdateTime = timer.getTime() - end - end - end - - local update_alive_units_counter = 0 - local write_DB_table_counter = 0 - local check_spawn_events_counter = 0 - - -- THE MAIN FUNCTION -- Accessed 100 times/sec. - mist.main = function() - timer.scheduleFunction(mist.main, {}, timer.getTime() + 0.01) --reschedule first in case of Lua error - ---------------------------------------------------------------------------------------------------------- - --area to add new stuff in - write_DB_table_counter = write_DB_table_counter + 1 - if write_DB_table_counter == 10 then - - write_DB_table_counter = 0 - - if not coroutines.updateDBTables then - coroutines['updateDBTables'] = coroutine.create(updateDBTables) - end - - coroutine.resume(coroutines.updateDBTables) - - if coroutine.status(coroutines.updateDBTables) == 'dead' then - coroutines.updateDBTables = nil - end - end + if string.upper(newTable['category']) == 'GROUND_UNIT' then + mistCategory = 'vehicle' + newTable['category'] = mistCategory + elseif string.upper(newTable['category']) == 'AIRPLANE' then + mistCategory = 'plane' + newTable['category'] = mistCategory + elseif string.upper(newTable['category']) == 'HELICOPTER' then + mistCategory = 'helicopter' + newTable['category'] = mistCategory + elseif string.upper(newTable['category']) == 'SHIP' then + mistCategory = 'ship' + newTable['category'] = mistCategory + end + for newId, newUnitData in pairs(newTable.units) do + newUnitData.category = mistCategory + if newUnitData.unitId then + mist.DBs.unitsById[tonumber(newUnitData.unitId)] = ldeepCopy(newUnitData) + end + + mist.DBs.unitsByName[newUnitData.unitName] = ldeepCopy(newUnitData) + mist.DBs.unitsByCat[mistCategory][#mist.DBs.unitsByCat[mistCategory] + 1] = ldeepCopy(newUnitData) + mist.DBs.unitsByNum[#mist.DBs.unitsByNum + 1] = ldeepCopy(newUnitData) + end + -- this is a really annoying DB to populate. Gotta create new tables in case its missing + if not mist.DBs.units[newTable.coalition] then + mist.DBs.units[newTable.coalition] = {} + end - check_spawn_events_counter = check_spawn_events_counter + 1 - if check_spawn_events_counter == 10 then - - check_spawn_events_counter = 0 - - if not coroutines.checkSpawnedEvents then - coroutines['checkSpawnedEvents'] = coroutine.create(checkSpawnedEvents) - end - - coroutine.resume(coroutines.checkSpawnedEvents) - - if coroutine.status(coroutines.checkSpawnedEvents) == 'dead' then - coroutines.checkSpawnedEvents = nil - end - end - - ----------------------------------------------------------------------------------------------------------- - --updating alive units - update_alive_units_counter = update_alive_units_counter + 1 - if update_alive_units_counter == 5 then - update_alive_units_counter = 0 - - if not coroutines.update_alive_units then - coroutines['update_alive_units'] = coroutine.create(update_alive_units) - end - - coroutine.resume(coroutines.update_alive_units) - - if coroutine.status(coroutines.update_alive_units) == 'dead' then - coroutines.update_alive_units = nil - end - end - - mist.do_scheduled_functions() - end -- end of mist.main - -------------------------------------------- - ------------ mist dyn add stuff for coroutines - local mistGpId = 7000 - local mistUnitId = 7000 - local mistDynAddIndex = 1 - - - mist.nextGroupId = 1 - mist.nextUnitId = 1 - - mist.getNextUnitId = function() - mist.nextUnitId = mist.nextUnitId + 1 - if mist.nextUnitId > 6900 then - mist.nextUnitId = 14000 - end - return mist.nextUnitId - end - - mist.getNextGroupId = function() - mist.nextGroupId = mist.nextGroupId + 1 - if mist.nextGroupId > 6900 then - mist.nextGroupId = 14000 - end - return mist.nextGroupId - end - - mist.getLastDBUpdateTime = function() - return lastUpdateTime - end - - local function groupSpawned(event) - if event.id == world.event.S_EVENT_BIRTH and timer.getTime0() < timer.getAbsTime()then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line - table.insert(tempSpawnedUnits,(event.initiator)) - end - end + if not mist.DBs.units[newTable.coalition][newTable.country] then + mist.DBs.units[newTable.coalition][(newTable.country)] = {} + mist.DBs.units[newTable.coalition][(newTable.country)]['countryId'] = newTable.countryId + end + if not mist.DBs.units[newTable.coalition][newTable.country][mistCategory] then + mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] = {} + end + mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][#mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] + 1] = ldeepCopy(newTable) + + if newTable.groupId then + mist.DBs.groupsById[newTable.groupId] = ldeepCopy(newTable) + end + + mist.DBs.groupsByName[newTable.name] = ldeepCopy(newTable) + mist.DBs.dynGroupsAdded[#mist.DBs.dynGroupsAdded + 1] = ldeepCopy(newTable) + + writeGroups[x] = nil + if x%savesPerRun == 0 then + coroutine.yield() + end + end + if timer.getTime() > lastUpdateTime then + lastUpdateTime = timer.getTime() + end + end + end + + local update_alive_units_counter = 0 + local write_DB_table_counter = 0 + local check_spawn_events_counter = 0 + + -- THE MAIN FUNCTION -- Accessed 100 times/sec. + mist.main = function() + timer.scheduleFunction(mist.main, {}, timer.getTime() + 0.01) --reschedule first in case of Lua error + ---------------------------------------------------------------------------------------------------------- + --area to add new stuff in + write_DB_table_counter = write_DB_table_counter + 1 + if write_DB_table_counter == 10 then + + write_DB_table_counter = 0 + + if not coroutines.updateDBTables then + coroutines['updateDBTables'] = coroutine.create(updateDBTables) + end + + coroutine.resume(coroutines.updateDBTables) + + if coroutine.status(coroutines.updateDBTables) == 'dead' then + coroutines.updateDBTables = nil + end + end - - - - mist.dynAddStatic = function(staticObj) - local newObj = {} - newObj.groupId = staticObj.groupId - newObj.category = staticObj.category - newObj.type = staticObj.type - newObj.unitId = staticObj.unitId - newObj.y = staticObj.y - newObj.x = staticObj.x - newObj.heading = staticObj.heading - newObj.name = staticObj.name - newObj.dead = staticObj.dead - newObj.country = staticObj.country - newObj.countryId = staticObj.countryId - newObj.clone = staticObj.clone - newObj.shape_name = staticObj.shape_name - newObj.canCargo = staticObj.canCargo - newObj.mass = staticObj.mass - newObj.categoryStatic = staticObj.categoryStatic - if staticObj.units then -- if its mist format - newObj.groupId = staticObj.units[1].groupId - newObj.category = staticObj.units[1].category - newObj.type = staticObj.units[1].type - newObj.unitId = staticObj.units[1].unitId - newObj.y = staticObj.units[1].y - newObj.x = staticObj.units[1].x - newObj.heading = staticObj.units[1].heading - newObj.name = staticObj.units[1].name - newObj.dead = staticObj.units[1].dead - newObj.country = staticObj.units[1].country - newObj.countryId = staticObj.units[1].countryId - newObj.shape_name = staticObj.units[1].shape_name - newObj.canCargo = staticObj.units[1].canCargo - newObj.mass = staticObj.units[1].mass - newObj.categoryStatic = staticObj.units[1].categoryStatic - end - - if not newObj.country then - return false - end - - local newCountry = newObj.country - if newObj.countryId then - newCountry = newObj.countryId - end - for countryId, countryName in pairs(country.name) do - if type(newObj.country) == 'string' then - if tostring(countryName) == string.upper(newObj.country) then - newCountry = countryName - end - elseif type(newObj.country) == 'number' then - if countryId == newObj.country then - newCountry = countryName - end - end - end - - if newObj.clone or not newObj.groupId then - mistGpId = mistGpId + 1 - newObj.groupId = mistGpId - end - - if newObj.clone or not newObj.unitId then - mistUnitId = mistUnitId + 1 - newObj.unitId = mistUnitId - end - - if newObj.clone or not newObj.name then - mistDynAddIndex = mistDynAddIndex + 1 - newObj.name = (newCountry .. ' static ' .. mistDynAddIndex) - end - - if not newObj.dead then - newObj.dead = false - end - - if not newObj.heading then - newObj.heading = math.random(360) - end - - if newObj.categoryStatic then - newObj.category = newObj.categoryStatic - end - if newObj.mass then - newObj.category = 'Cargos' - end - mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newObj) - if newObj.x and newObj.y and newObj.type and type(newObj.x) == 'number' and type(newObj.y) == 'number' and type(newObj.type) == 'string' then - coalition.addStaticObject(country.id[newCountry], newObj) + check_spawn_events_counter = check_spawn_events_counter + 1 + if check_spawn_events_counter == 10 then + + check_spawn_events_counter = 0 + + if not coroutines.checkSpawnedEvents then + coroutines['checkSpawnedEvents'] = coroutine.create(checkSpawnedEvents) + end + + coroutine.resume(coroutines.checkSpawnedEvents) + + if coroutine.status(coroutines.checkSpawnedEvents) == 'dead' then + coroutines.checkSpawnedEvents = nil + end + end + + ----------------------------------------------------------------------------------------------------------- + --updating alive units + update_alive_units_counter = update_alive_units_counter + 1 + if update_alive_units_counter == 5 then + update_alive_units_counter = 0 + + if not coroutines.update_alive_units then + coroutines['update_alive_units'] = coroutine.create(update_alive_units) + end + + coroutine.resume(coroutines.update_alive_units) + + if coroutine.status(coroutines.update_alive_units) == 'dead' then + coroutines.update_alive_units = nil + end + end + + mist.do_scheduled_functions() + end -- end of mist.main + -------------------------------------------- + ------------ mist dyn add stuff for coroutines + local mistGpId = 7000 + local mistUnitId = 7000 + local mistDynAddIndex = 1 + + + mist.nextGroupId = 1 + mist.nextUnitId = 1 + + mist.getNextUnitId = function() + mist.nextUnitId = mist.nextUnitId + 1 + if mist.nextUnitId > 6900 then + mist.nextUnitId = 14000 + end + return mist.nextUnitId + end + + mist.getNextGroupId = function() + mist.nextGroupId = mist.nextGroupId + 1 + if mist.nextGroupId > 6900 then + mist.nextGroupId = 14000 + end + return mist.nextGroupId + end + + mist.getLastDBUpdateTime = function() + return lastUpdateTime + end + + local function groupSpawned(event) + if event.id == world.event.S_EVENT_BIRTH and timer.getTime0() < timer.getAbsTime()then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line + table.insert(tempSpawnedUnits,(event.initiator)) + end + end - return newObj - end - return false - end + + + + mist.dynAddStatic = function(staticObj) + local newObj = {} + newObj.groupId = staticObj.groupId + newObj.category = staticObj.category + newObj.type = staticObj.type + newObj.unitId = staticObj.unitId + newObj.y = staticObj.y + newObj.x = staticObj.x + newObj.heading = staticObj.heading + newObj.name = staticObj.name + newObj.dead = staticObj.dead + newObj.country = staticObj.country + newObj.countryId = staticObj.countryId + newObj.clone = staticObj.clone + newObj.shape_name = staticObj.shape_name + newObj.canCargo = staticObj.canCargo + newObj.mass = staticObj.mass + newObj.categoryStatic = staticObj.categoryStatic + if staticObj.units then -- if its mist format + newObj.groupId = staticObj.units[1].groupId + newObj.category = staticObj.units[1].category + newObj.type = staticObj.units[1].type + newObj.unitId = staticObj.units[1].unitId + newObj.y = staticObj.units[1].y + newObj.x = staticObj.units[1].x + newObj.heading = staticObj.units[1].heading + newObj.name = staticObj.units[1].name + newObj.dead = staticObj.units[1].dead + newObj.country = staticObj.units[1].country + newObj.countryId = staticObj.units[1].countryId + newObj.shape_name = staticObj.units[1].shape_name + newObj.canCargo = staticObj.units[1].canCargo + newObj.mass = staticObj.units[1].mass + newObj.categoryStatic = staticObj.units[1].categoryStatic + end + + if not newObj.country then + return false + end + + local newCountry = newObj.country + if newObj.countryId then + newCountry = newObj.countryId + end + for countryId, countryName in pairs(country.name) do + if type(newObj.country) == 'string' then + if tostring(countryName) == string.upper(newObj.country) then + newCountry = countryName + end + elseif type(newObj.country) == 'number' then + if countryId == newObj.country then + newCountry = countryName + end + end + end + + if newObj.clone or not newObj.groupId then + mistGpId = mistGpId + 1 + newObj.groupId = mistGpId + end + + if newObj.clone or not newObj.unitId then + mistUnitId = mistUnitId + 1 + newObj.unitId = mistUnitId + end + + if newObj.clone or not newObj.name then + mistDynAddIndex = mistDynAddIndex + 1 + newObj.name = (country.name[newCountry] .. ' static ' .. mistDynAddIndex) + end + + if not newObj.dead then + newObj.dead = false + end + + if not newObj.heading then + newObj.heading = math.random(360) + end + + if newObj.categoryStatic then + newObj.category = newObj.categoryStatic + end + if newObj.mass then + newObj.category = 'Cargos' + end + mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newObj) + if newObj.x and newObj.y and newObj.type and type(newObj.x) == 'number' and type(newObj.y) == 'number' and type(newObj.type) == 'string' then + coalition.addStaticObject(country.id[newCountry], newObj) - mist.dynAdd = function(newGroup) -- same as coalition.add function in SSE. checks the passed data to see if its valid. + return newObj + end + return false + end + + mist.dynAdd = function(newGroup) -- same as coalition.add function in SSE. checks the passed data to see if its valid. --Will generate groupId, groupName, unitId, and unitName if needed -- - - + + - --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroupOrig.lua') - local cntry = newGroup.country - if newGroup.countryId then - cntry = newGroup.countryId - end - - local groupType = newGroup.category - local newCountry = '' - -- validate data - for countryId, countryName in pairs(country.name) do - if type(cntry) == 'string' then - if tostring(countryName) == string.upper(cntry) then - newCountry = countryName - end - elseif type(cntry) == 'number' then - if countryId == cntry then - newCountry = countryName - end - end - end - - if newCountry == '' then - return false - end - - local newCat = '' - for catName, catId in pairs(Unit.Category) do - if type(groupType) == 'string' then - if tostring(catName) == string.upper(groupType) then - newCat = catName - end - elseif type(groupType) == 'number' then - if catId == groupType then - newCat = catName - end - end - - if catName == 'GROUND_UNIT' and (string.upper(groupType) == 'VEHICLE' or string.upper(groupType) == 'GROUND') then - newCat = 'GROUND_UNIT' - elseif catName == 'AIRPLANE' and string.upper(groupType) == 'PLANE' then - newCat = 'AIRPLANE' - end - end - local typeName - if newCat == 'GROUND_UNIT' then - typeName = ' gnd ' - elseif newCat == 'AIRPLANE' then - typeName = ' air ' - elseif newCat == 'HELICOPTER' then - typeName = ' hel ' - elseif newCat == 'SHIP' then - typeName = ' shp ' - elseif newCat == 'BUILDING' then - typeName = ' bld ' - end - if newGroup.clone or not newGroup.groupId then - mistDynAddIndex = mistDynAddIndex + 1 - mistGpId = mistGpId + 1 - newGroup.groupId = mistGpId - end - if newGroup.groupName or newGroup.name then - if newGroup.groupName then - newGroup['name'] = newGroup.groupName - elseif newGroup.name then - newGroup['name'] = newGroup.name - end - end - - if newGroup.clone and mist.DBs.groupsByName[newGroup.name] or not newGroup.name then - newGroup['name'] = tostring(tostring(cntry) .. tostring(typeName) .. mistDynAddIndex) - end - - if not newGroup.hidden then - newGroup.hidden = false - end - - if not newGroup.visible then - newGroup.visible = false - end - - if (newGroup.start_time and type(newGroup.start_time) ~= 'number') or not newGroup.start_time then - if newGroup.startTime then - newGroup.start_time = mist.utils.round(newGroup.startTime) - else - newGroup.start_time = 0 - end - end - - - for unitIndex, unitData in pairs(newGroup.units) do - local originalName = newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name - if newGroup.clone or not unitData.unitId then - mistUnitId = mistUnitId + 1 - newGroup.units[unitIndex]['unitId'] = mistUnitId - end - if newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name then - if newGroup.units[unitIndex].unitName then - newGroup.units[unitIndex].name = newGroup.units[unitIndex].unitName - elseif newGroup.units[unitIndex].name then - newGroup.units[unitIndex].name = newGroup.units[unitIndex].name - end - end - if newGroup.clone or not unitData.name then - newGroup.units[unitIndex].name = tostring(newGroup.name .. ' unit' .. unitIndex) - end - - if not unitData.skill then - newGroup.units[unitIndex].skill = 'Random' - end - - if not unitData.alt then - if newCat == 'AIRPLANE' then - newGroup.units[unitIndex].alt = 2000 - newGroup.units[unitIndex].alt_type = 'RADIO' - newGroup.units[unitIndex].speed = 150 - elseif newCat == 'HELICOPTER' then - newGroup.units[unitIndex].alt = 500 - newGroup.units[unitIndex].alt_type = 'RADIO' - newGroup.units[unitIndex].speed = 60 - else - --[[env.info('check height') - newGroup.units[unitIndex].alt = land.getHeight({x = newGroup.units[unitIndex].x, y = newGroup.units[unitIndex].y}) - newGroup.units[unitIndex].alt_type = 'BARO']] - end - + --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroupOrig.lua') + local cntry = newGroup.country + if newGroup.countryId then + cntry = newGroup.countryId + end + + local groupType = newGroup.category + local newCountry = '' + -- validate data + for countryId, countryName in pairs(country.name) do + if type(cntry) == 'string' then + cntry = cntry:gsub("%s+", "_") + if tostring(countryName) == string.upper(cntry) then + newCountry = countryName + end + elseif type(cntry) == 'number' then + if countryId == cntry then + newCountry = countryName + end + end + end + + if newCountry == '' then + return false + end + + local newCat = '' + for catName, catId in pairs(Unit.Category) do + if type(groupType) == 'string' then + if tostring(catName) == string.upper(groupType) then + newCat = catName + end + elseif type(groupType) == 'number' then + if catId == groupType then + newCat = catName + end + end + + if catName == 'GROUND_UNIT' and (string.upper(groupType) == 'VEHICLE' or string.upper(groupType) == 'GROUND') then + newCat = 'GROUND_UNIT' + elseif catName == 'AIRPLANE' and string.upper(groupType) == 'PLANE' then + newCat = 'AIRPLANE' + end + end + local typeName + if newCat == 'GROUND_UNIT' then + typeName = ' gnd ' + elseif newCat == 'AIRPLANE' then + typeName = ' air ' + elseif newCat == 'HELICOPTER' then + typeName = ' hel ' + elseif newCat == 'SHIP' then + typeName = ' shp ' + elseif newCat == 'BUILDING' then + typeName = ' bld ' + end + if newGroup.clone or not newGroup.groupId then + mistDynAddIndex = mistDynAddIndex + 1 + mistGpId = mistGpId + 1 + newGroup.groupId = mistGpId + end + if newGroup.groupName or newGroup.name then + if newGroup.groupName then + newGroup['name'] = newGroup.groupName + elseif newGroup.name then + newGroup['name'] = newGroup.name + end + end + + if newGroup.clone and mist.DBs.groupsByName[newGroup.name] or not newGroup.name then + newGroup['name'] = tostring(tostring(country.name[cntry]) .. tostring(typeName) .. mistDynAddIndex) + end + + if not newGroup.hidden then + newGroup.hidden = false + end + + if not newGroup.visible then + newGroup.visible = false + end + + if (newGroup.start_time and type(newGroup.start_time) ~= 'number') or not newGroup.start_time then + if newGroup.startTime then + newGroup.start_time = mist.utils.round(newGroup.startTime) + else + newGroup.start_time = 0 + end + end + + + for unitIndex, unitData in pairs(newGroup.units) do + local originalName = newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name + if newGroup.clone or not unitData.unitId then + mistUnitId = mistUnitId + 1 + newGroup.units[unitIndex]['unitId'] = mistUnitId + end + if newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name then + if newGroup.units[unitIndex].unitName then + newGroup.units[unitIndex].name = newGroup.units[unitIndex].unitName + elseif newGroup.units[unitIndex].name then + newGroup.units[unitIndex].name = newGroup.units[unitIndex].name + end + end + if newGroup.clone or not unitData.name then + newGroup.units[unitIndex].name = tostring(newGroup.name .. ' unit' .. unitIndex) + end + + if not unitData.skill then + newGroup.units[unitIndex].skill = 'Random' + end + + if not unitData.alt then + if newCat == 'AIRPLANE' then + newGroup.units[unitIndex].alt = 2000 + newGroup.units[unitIndex].alt_type = 'RADIO' + newGroup.units[unitIndex].speed = 150 + elseif newCat == 'HELICOPTER' then + newGroup.units[unitIndex].alt = 500 + newGroup.units[unitIndex].alt_type = 'RADIO' + newGroup.units[unitIndex].speed = 60 + else + --[[env.info('check height') + newGroup.units[unitIndex].alt = land.getHeight({x = newGroup.units[unitIndex].x, y = newGroup.units[unitIndex].y}) + newGroup.units[unitIndex].alt_type = 'BARO']] + end + - end - - if newCat == 'AIRPLANE' or newCat == 'HELICOPTER' then - if newGroup.units[unitIndex].alt_type and newGroup.units[unitIndex].alt_type ~= 'BARO' or not newGroup.units[unitIndex].alt_type then - newGroup.units[unitIndex].alt_type = 'RADIO' - end - if not unitData.speed then - if newCat == 'AIRPLANE' then - newGroup.units[unitIndex].speed = 150 - elseif newCat == 'HELICOPTER' then - newGroup.units[unitIndex].speed = 60 - end - end - if not unitData.payload then - newGroup.units[unitIndex].payload = mist.getPayload(originalName) - end - end - mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newGroup.units[unitIndex]) - end - mistAddedGroups[#mistAddedGroups + 1] = mist.utils.deepCopy(newGroup) - if newGroup.route and not newGroup.route.points then - if not newGroup.route.points and newGroup.route[1] then - local copyRoute = newGroup.route - newGroup.route = {} - newGroup.route.points = copyRoute - end - end - newGroup.country = newCountry - - - --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroup.lua') - - -- sanitize table - newGroup.groupName = nil - newGroup.clone = nil - newGroup.category = nil - newGroup.country = nil - - newGroup.tasks = {} - - for unitIndex, unitData in pairs(newGroup.units) do - newGroup.units[unitIndex].unitName = nil - end - - coalition.addGroup(country.id[newCountry], Unit.Category[newCat], newGroup) - - return newGroup - - end + end + + if newCat == 'AIRPLANE' or newCat == 'HELICOPTER' then + if newGroup.units[unitIndex].alt_type and newGroup.units[unitIndex].alt_type ~= 'BARO' or not newGroup.units[unitIndex].alt_type then + newGroup.units[unitIndex].alt_type = 'RADIO' + end + if not unitData.speed then + if newCat == 'AIRPLANE' then + newGroup.units[unitIndex].speed = 150 + elseif newCat == 'HELICOPTER' then + newGroup.units[unitIndex].speed = 60 + end + end + if not unitData.payload then + newGroup.units[unitIndex].payload = mist.getPayload(originalName) + end + end + mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newGroup.units[unitIndex]) + end + mistAddedGroups[#mistAddedGroups + 1] = mist.utils.deepCopy(newGroup) + if newGroup.route and not newGroup.route.points then + if not newGroup.route.points and newGroup.route[1] then + local copyRoute = newGroup.route + newGroup.route = {} + newGroup.route.points = copyRoute + end + end + newGroup.country = newCountry + + + --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroup.lua') + + -- sanitize table + newGroup.groupName = nil + newGroup.clone = nil + newGroup.category = nil + newGroup.country = nil + + newGroup.tasks = {} + + for unitIndex, unitData in pairs(newGroup.units) do + newGroup.units[unitIndex].unitName = nil + end + + coalition.addGroup(country.id[newCountry], Unit.Category[newCat], newGroup) + + return newGroup + + end --------------------------------------------------------------------------------------------- --Modified Slmod task scheduler, superior to timer.scheduleFunction - - local Tasks = {} - local task_id = 0 - --[[ mist.scheduleFunction: - int id = mist.schedule_task(f function, vars table, t number, rep number, st number) - id - integer id of this function task - f - function to run - vars - table of vars for that function - t - time to run function - rep - time between repetitions of this function (OPTIONAL) - st - time when repetitions of this function will stop automatically (OPTIONAL) - ]] - mist.scheduleFunction = function(f, vars, t, rep, st) - --verify correct types - assert(type(f) == 'function', 'variable 1, expected function, got ' .. type(f)) - assert(type(vars) == 'table' or vars == nil, 'variable 2, expected table or nil, got ' .. type(f)) - assert(type(t) == 'number', 'variable 3, expected number, got ' .. type(t)) - assert(type(rep) == 'number' or rep == nil, 'variable 4, expected number or nil, got ' .. type(rep)) - assert(type(st) == 'number' or st == nil, 'variable 5, expected number or nil, got ' .. type(st)) - if not vars then - vars = {} - end - task_id = task_id + 1 - table.insert(Tasks, {f = f, vars = vars, t = t, rep = rep, st = st, id = task_id}) - return task_id - end - - -- removes a scheduled function based on the function's id. returns true if successful, false if not successful. - mist.removeFunction = function(id) - local i = 1 - while i <= #Tasks do - if Tasks[i].id == id then - table.remove(Tasks, i) - else - i = i + 1 - end - end - end + + local Tasks = {} + local task_id = 0 + --[[ mist.scheduleFunction: + int id = mist.schedule_task(f function, vars table, t number, rep number, st number) + id - integer id of this function task + f - function to run + vars - table of vars for that function + t - time to run function + rep - time between repetitions of this function (OPTIONAL) + st - time when repetitions of this function will stop automatically (OPTIONAL) + ]] + mist.scheduleFunction = function(f, vars, t, rep, st) + --verify correct types + assert(type(f) == 'function', 'variable 1, expected function, got ' .. type(f)) + assert(type(vars) == 'table' or vars == nil, 'variable 2, expected table or nil, got ' .. type(f)) + assert(type(t) == 'number', 'variable 3, expected number, got ' .. type(t)) + assert(type(rep) == 'number' or rep == nil, 'variable 4, expected number or nil, got ' .. type(rep)) + assert(type(st) == 'number' or st == nil, 'variable 5, expected number or nil, got ' .. type(st)) + if not vars then + vars = {} + end + task_id = task_id + 1 + table.insert(Tasks, {f = f, vars = vars, t = t, rep = rep, st = st, id = task_id}) + return task_id + end + + -- removes a scheduled function based on the function's id. returns true if successful, false if not successful. + mist.removeFunction = function(id) + local i = 1 + while i <= #Tasks do + if Tasks[i].id == id then + table.remove(Tasks, i) + else + i = i + 1 + end + end + end - -------------------------------------------------------------------------------------------------------------------- - -- not intended for users to use this function. - mist.do_scheduled_functions = function() - local i = 1 - while i <= #Tasks do - if not Tasks[i].rep then -- not a repeated process - if Tasks[i].t <= timer.getTime() then - local Task = Tasks[i] -- local reference - table.remove(Tasks, i) - local err, errmsg = pcall(Task.f, unpack(Task.vars, 1, table.maxn(Task.vars))) - if not err then - env.info('mist.scheduleFunction, error in scheduled function: ' .. errmsg) - end - --Task.f(unpack(Task.vars, 1, table.maxn(Task.vars))) -- do the task, do not increment i - else - i = i + 1 - end - else - if Tasks[i].st and Tasks[i].st <= timer.getTime() then --if a stoptime was specified, and the stop time exceeded - table.remove(Tasks, i) -- stop time exceeded, do not execute, do not increment i - elseif Tasks[i].t <= timer.getTime() then - local Task = Tasks[i] -- local reference - Task.t = timer.getTime() + Task.rep --schedule next run - local err, errmsg = pcall(Task.f, unpack(Task.vars, 1, table.maxn(Task.vars))) - if not err then - env.info('mist.scheduleFunction, error in scheduled function: ' .. errmsg) - end - --Tasks[i].f(unpack(Tasks[i].vars, 1, table.maxn(Tasks[i].vars))) -- do the task - i = i + 1 - else - i = i + 1 - end - end - end - end + -------------------------------------------------------------------------------------------------------------------- + -- not intended for users to use this function. + mist.do_scheduled_functions = function() + local i = 1 + while i <= #Tasks do + if not Tasks[i].rep then -- not a repeated process + if Tasks[i].t <= timer.getTime() then + local Task = Tasks[i] -- local reference + table.remove(Tasks, i) + local err, errmsg = pcall(Task.f, unpack(Task.vars, 1, table.maxn(Task.vars))) + if not err then + env.info('mist.scheduleFunction, error in scheduled function: ' .. errmsg) + end + --Task.f(unpack(Task.vars, 1, table.maxn(Task.vars))) -- do the task, do not increment i + else + i = i + 1 + end + else + if Tasks[i].st and Tasks[i].st <= timer.getTime() then --if a stoptime was specified, and the stop time exceeded + table.remove(Tasks, i) -- stop time exceeded, do not execute, do not increment i + elseif Tasks[i].t <= timer.getTime() then + local Task = Tasks[i] -- local reference + Task.t = timer.getTime() + Task.rep --schedule next run + local err, errmsg = pcall(Task.f, unpack(Task.vars, 1, table.maxn(Task.vars))) + if not err then + env.info('mist.scheduleFunction, error in scheduled function: ' .. errmsg) + end + --Tasks[i].f(unpack(Tasks[i].vars, 1, table.maxn(Tasks[i].vars))) -- do the task + i = i + 1 + else + i = i + 1 + end + end + end + end - + - local idNum = 0 + local idNum = 0 - --Simplified event handler - mist.addEventHandler = function(f) --id is optional! - local handler = {} - idNum = idNum + 1 - handler.id = idNum - handler.f = f - handler.onEvent = function(self, event) - self.f(event) - end - world.addEventHandler(handler) - return handler.id - end + --Simplified event handler + mist.addEventHandler = function(f) --id is optional! + local handler = {} + idNum = idNum + 1 + handler.id = idNum + handler.f = f + handler.onEvent = function(self, event) + self.f(event) + end + world.addEventHandler(handler) + return handler.id + end - mist.removeEventHandler = function(id) - for key, handler in pairs(world.eventHandlers) do - if handler.id and handler.id == id then - world.eventHandlers[key] = nil - return true - end - end - return false - end + mist.removeEventHandler = function(id) + for key, handler in pairs(world.eventHandlers) do + if handler.id and handler.id == id then + world.eventHandlers[key] = nil + return true + end + end + return false + end - mist.addEventHandler(groupSpawned) --- mist.scheduleFunction(checkSpawnedEvents, {}, timer.getTime() + 5, 1) - + mist.addEventHandler(groupSpawned) +-- mist.scheduleFunction(checkSpawnedEvents, {}, timer.getTime() + 5, 1) + end ------------------------------------------------------------------------------------------------------------ @@ -872,135 +886,167 @@ end mist.utils = {} mist.utils.toDegree = function(angle) - return angle*180/math.pi + return angle*180/math.pi end mist.utils.toRadian = function(angle) - return angle*math.pi/180 + return angle*math.pi/180 end mist.utils.metersToNM = function(meters) - return meters/1852 + return meters/1852 end mist.utils.metersToFeet = function(meters) - return meters/0.3048 + return meters/0.3048 end mist.utils.NMToMeters = function(NM) - return NM*1852 + return NM*1852 end mist.utils.feetToMeters = function(feet) - return feet*0.3048 + return feet*0.3048 end mist.utils.mpsToKnots = function(mps) - return mps*3600/1852 + return mps*3600/1852 end mist.utils.mpsToKmph = function(mps) - return mps*3.6 + return mps*3.6 end mist.utils.knotsToMps = function(knots) - return knots*1852/3600 + return knots*1852/3600 end mist.utils.kmphToMps = function(kmph) - return kmph/3.6 + return kmph/3.6 end function mist.utils.makeVec2(Vec3) - if Vec3.z then - return {x = Vec3.x, y = Vec3.z} - else - return {x = Vec3.x, y = Vec3.y} -- it was actually already vec2. - end + if Vec3.z then + return {x = Vec3.x, y = Vec3.z} + else + return {x = Vec3.x, y = Vec3.y} -- it was actually already vec2. + end end function mist.utils.makeVec3(Vec2, y) - if not Vec2.z then - if not y then - y = 0 - end - return {x = Vec2.x, y = y, z = Vec2.y} - else - return {x = Vec2.x, y = Vec2.y, z = Vec2.z} -- it was already Vec3, actually. - end + if not Vec2.z then + if Vec2.alt and not y then + y = Vec2.alt + elseif not y then + y = 0 + end + return {x = Vec2.x, y = y, z = Vec2.y} + else + return {x = Vec2.x, y = Vec2.y, z = Vec2.z} -- it was already Vec3, actually. + end end function mist.utils.makeVec3GL(Vec2, offset) - local adj = offset or 0 - - if not Vec2.z then - return {x = Vec2.x, y = (land.getHeight(Vec2) + adj), z = Vec2.y} - else - return {x = Vec2.x, y = (land.getHeight({x = Vec2.x, y = Vec2.z}) + adj), z = Vec2.z} - end + local adj = offset or 0 + + if not Vec2.z then + return {x = Vec2.x, y = (land.getHeight(Vec2) + adj), z = Vec2.y} + else + return {x = Vec2.x, y = (land.getHeight({x = Vec2.x, y = Vec2.z}) + adj), z = Vec2.z} + end end mist.utils.zoneToVec3 = function(zone) - local new = {} - if type(zone) == 'table' and zone.point then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - elseif type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - if zone then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - end - end + local new = {} + if type(zone) == 'table' and zone.point then + new.x = zone.point.x + new.y = zone.point.y + new.z = zone.point.z + return new + elseif type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + if zone then + new.x = zone.point.x + new.y = zone.point.y + new.z = zone.point.z + return new + end + end end -- gets heading-error corrected direction from point along vector vec. function mist.utils.getDir(vec, point) - local dir = math.atan2(vec.z, vec.x) - dir = dir + mist.getNorthCorrection(point) - if dir < 0 then - dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi - end - return dir + local dir = math.atan2(vec.z, vec.x) + if point then + dir = dir + mist.getNorthCorrection(point) + end + if dir < 0 then + dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi + end + return dir end -- gets distance in meters between two points (2 dimensional) function mist.utils.get2DDist(point1, point2) - point1 = mist.utils.makeVec3(point1) - point2 = mist.utils.makeVec3(point2) - return mist.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) + point1 = mist.utils.makeVec3(point1) + point2 = mist.utils.makeVec3(point2) + return mist.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) end -- gets distance in meters between two points (3 dimensional) function mist.utils.get3DDist(point1, point2) - return mist.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) + return mist.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) end +function mist.utils.vecToWP(vec) + local newWP = {} + newWP.x = vec.x + newWP.y = vec.y + if vec.z then + newWP.alt = vec.y + newWP.y = vec.z + else + newWP.alt = land.getHeight({x = vec.x, y = vec.y}) + end + return newWP +end +function mist.utils.unitToWP(pUnit) + local unit = mist.utils.deepCopy(pUnit) + if type(unit) == 'string' then + if Unit.getByName(unit) then + unit = Unit.getByName(unit) + end + end + if unit:isExist() == true then + local new = mist.utils.vecToWP(unit:getPosition().p) + new.speed = mist.vec.mag(unit:getVelocity()) + new.alt_type = "BARO" + + return new + end + return false +end --from http://lua-users.org/wiki/CopyTable mist.utils.deepCopy = function(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - return _copy(object) + local lookup_table = {} + local function _copy(object) + if type(object) ~= "table" then + return object + elseif lookup_table[object] then + return lookup_table[object] + end + local new_table = {} + lookup_table[object] = new_table + for index, value in pairs(object) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(object)) + end + return _copy(object) end -- From http://lua-users.org/wiki/SimpleRound @@ -1010,14 +1056,23 @@ mist.utils.round = function(num, idp) return math.floor(num * mult + 0.5) / mult end +mist.utils.roundTbl = function(tbl, idp) + for id, val in pairs(tbl) do + if type(val) == 'number' then + tbl[id] = mist.utils.round(val, idp) + end + end + return tbl +end + -- porting in Slmod's dostring mist.utils.dostring = function(s) - local f, err = loadstring(s) - if f then - return true, f() - else - return false, err - end + local f, err = loadstring(s) + if f then + return true, f() + else + return false, err + end end @@ -1037,328 +1092,328 @@ var_tbl must have a string at one of the following table keys: "text", "msg", or the table key "display_mode" must be either a string or nil, and the table key "coa" must be either a string or nil. ]] function mist.utils.typeCheck(fname, type_tbl, var_tbl) - --env.info('type check') - for type_key, type_val in pairs(type_tbl) do - --print('type_key:') - --print(type_key) - --print('type_val:') - --print(type_val) - - --type_key can be a table of accepted keys- so try to find one that is not nil - local type_key_str = '' - local act_key = type_key -- actual key within var_tbl - necessary to use for multiple possible key variables. Initialize to type_key - if type(type_key) == 'table' then - - for i = 1, #type_key do - if i ~= 1 then - type_key_str = type_key_str .. '/' - end - type_key_str = type_key_str .. tostring(type_key[i]) - if var_tbl[type_key[i]] ~= nil then - act_key = type_key[i] -- found a non-nil entry, make act_key now this val. - end - end - else - type_key_str = tostring(type_key) - end - - local err_msg = 'Error in function ' .. fname .. ', parameter "' .. type_key_str .. '", expected: ' - local passed_check = false - - if type(type_tbl[type_key]) == 'table' then - --print('err_msg, before and after:') - --print(err_msg) - for j = 1, #type_tbl[type_key] do - - if j == 1 then - err_msg = err_msg .. type_tbl[type_key][j] - else - err_msg = err_msg .. ' or ' .. type_tbl[type_key][j] - end - - if type(var_tbl[act_key]) == type_tbl[type_key][j] then - passed_check = true - end - end - --print(err_msg) - else - --print('err_msg, before and after:') - --print(err_msg) - err_msg = err_msg .. type_tbl[type_key] - --print(err_msg) - if type(var_tbl[act_key]) == type_tbl[type_key] then - passed_check = true - - end - - end - - if not passed_check then - err_msg = err_msg .. ', got ' .. type(var_tbl[act_key]) - return false, err_msg - end - end - return true + --env.info('type check') + for type_key, type_val in pairs(type_tbl) do + --print('type_key:') + --print(type_key) + --print('type_val:') + --print(type_val) + + --type_key can be a table of accepted keys- so try to find one that is not nil + local type_key_str = '' + local act_key = type_key -- actual key within var_tbl - necessary to use for multiple possible key variables. Initialize to type_key + if type(type_key) == 'table' then + + for i = 1, #type_key do + if i ~= 1 then + type_key_str = type_key_str .. '/' + end + type_key_str = type_key_str .. tostring(type_key[i]) + if var_tbl[type_key[i]] ~= nil then + act_key = type_key[i] -- found a non-nil entry, make act_key now this val. + end + end + else + type_key_str = tostring(type_key) + end + + local err_msg = 'Error in function ' .. fname .. ', parameter "' .. type_key_str .. '", expected: ' + local passed_check = false + + if type(type_tbl[type_key]) == 'table' then + --print('err_msg, before and after:') + --print(err_msg) + for j = 1, #type_tbl[type_key] do + + if j == 1 then + err_msg = err_msg .. type_tbl[type_key][j] + else + err_msg = err_msg .. ' or ' .. type_tbl[type_key][j] + end + + if type(var_tbl[act_key]) == type_tbl[type_key][j] then + passed_check = true + end + end + --print(err_msg) + else + --print('err_msg, before and after:') + --print(err_msg) + err_msg = err_msg .. type_tbl[type_key] + --print(err_msg) + if type(var_tbl[act_key]) == type_tbl[type_key] then + passed_check = true + + end + + end + + if not passed_check then + err_msg = err_msg .. ', got ' .. type(var_tbl[act_key]) + return false, err_msg + end + end + return true end --porting in Slmod's "safestring" basic serialize mist.utils.basicSerialize = function(s) - if s == nil then - return "\"\"" - else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) - return s - end - end + if s == nil then + return "\"\"" + else + if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then + return tostring(s) + elseif type(s) == 'string' then + s = string.format('%q', s) + return s + end + end end --porting in Slmod's serialize_slmod mist.utils.serialize = function(name, value, level) - -----Based on ED's serialize_simple2 - local basicSerialize = function (o) - if type(o) == "number" then - return tostring(o) - elseif type(o) == "boolean" then - return tostring(o) - else -- assume it is a string - return mist.utils.basicSerialize(o) - end - end - - local serialize_to_t = function (name, value, level) - ----Based on ED's serialize_simple2 + -----Based on ED's serialize_simple2 + local basicSerialize = function (o) + if type(o) == "number" then + return tostring(o) + elseif type(o) == "boolean" then + return tostring(o) + else -- assume it is a string + return mist.utils.basicSerialize(o) + end + end + + local serialize_to_t = function (name, value, level) + ----Based on ED's serialize_simple2 - local var_str_tbl = {} - if level == nil then level = "" end - if level ~= "" then level = level.." " end - - table.insert(var_str_tbl, level .. name .. " = ") - - if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then - table.insert(var_str_tbl, basicSerialize(value) .. ",\n") - elseif type(value) == "table" then - table.insert(var_str_tbl, "\n"..level.."{\n") - - for k,v in pairs(value) do -- serialize its fields - local key - if type(k) == "number" then - key = string.format("[%s]", k) - else - key = string.format("[%q]", k) - end + local var_str_tbl = {} + if level == nil then level = "" end + if level ~= "" then level = level.." " end + + table.insert(var_str_tbl, level .. name .. " = ") + + if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then + table.insert(var_str_tbl, basicSerialize(value) .. ",\n") + elseif type(value) == "table" then + table.insert(var_str_tbl, "\n"..level.."{\n") + + for k,v in pairs(value) do -- serialize its fields + local key + if type(k) == "number" then + key = string.format("[%s]", k) + else + key = string.format("[%q]", k) + end - table.insert(var_str_tbl, mist.utils.serialize(key, v, level.." ")) + table.insert(var_str_tbl, mist.utils.serialize(key, v, level.." ")) - end - if level == "" then - table.insert(var_str_tbl, level.."} -- end of "..name.."\n") + end + if level == "" then + table.insert(var_str_tbl, level.."} -- end of "..name.."\n") - else - table.insert(var_str_tbl, level.."}, -- end of "..name.."\n") + else + table.insert(var_str_tbl, level.."}, -- end of "..name.."\n") - end - else - env.info("Cannot serialize a "..type(value)) - end - return var_str_tbl - end - - local t_str = serialize_to_t(name, value, level) - - return table.concat(t_str) + end + else + env.info("Cannot serialize a "..type(value)) + end + return var_str_tbl + end + + local t_str = serialize_to_t(name, value, level) + + return table.concat(t_str) end -- porting in slmod's serialize_wcycles mist.utils.serializeWithCycles = function(name, value, saved) - --mostly straight out of Programming in Lua - local basicSerialize = function (o) - if type(o) == "number" then - return tostring(o) - elseif type(o) == "boolean" then - return tostring(o) - else -- assume it is a string - return mist.utils.basicSerialize(o) - end - end - - local t_str = {} - saved = saved or {} -- initial value - if ((type(value) == 'string') or (type(value) == 'number') or (type(value) == 'table') or (type(value) == 'boolean')) then - table.insert(t_str, name .. " = ") - if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then - table.insert(t_str, basicSerialize(value) .. "\n") - else + --mostly straight out of Programming in Lua + local basicSerialize = function (o) + if type(o) == "number" then + return tostring(o) + elseif type(o) == "boolean" then + return tostring(o) + else -- assume it is a string + return mist.utils.basicSerialize(o) + end + end + + local t_str = {} + saved = saved or {} -- initial value + if ((type(value) == 'string') or (type(value) == 'number') or (type(value) == 'table') or (type(value) == 'boolean')) then + table.insert(t_str, name .. " = ") + if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then + table.insert(t_str, basicSerialize(value) .. "\n") + else - if saved[value] then -- value already saved? - table.insert(t_str, saved[value] .. "\n") - else - saved[value] = name -- save name for next time - table.insert(t_str, "{}\n") - for k,v in pairs(value) do -- save its fields - local fieldname = string.format("%s[%s]", name, basicSerialize(k)) - table.insert(t_str, mist.utils.serializeWithCycles(fieldname, v, saved)) - end - end - end - return table.concat(t_str) - else - return "" - end + if saved[value] then -- value already saved? + table.insert(t_str, saved[value] .. "\n") + else + saved[value] = name -- save name for next time + table.insert(t_str, "{}\n") + for k,v in pairs(value) do -- save its fields + local fieldname = string.format("%s[%s]", name, basicSerialize(k)) + table.insert(t_str, mist.utils.serializeWithCycles(fieldname, v, saved)) + end + end + end + return table.concat(t_str) + else + return "" + end end -- porting in Slmod's serialize_slmod2 mist.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - if type(tbl) == 'table' then --function only works for tables! + if type(tbl) == 'table' then --function only works for tables! - local tbl_str = {} + local tbl_str = {} - tbl_str[#tbl_str + 1] = '{ ' - - for ind,val in pairs(tbl) do -- serialize its fields - if type(ind) == "number" then - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = tostring(ind) - tbl_str[#tbl_str + 1] = '] = ' - else --must be a string - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) - tbl_str[#tbl_str + 1] = '] = ' - end - - if ((type(val) == 'number') or (type(val) == 'boolean')) then - tbl_str[#tbl_str + 1] = tostring(val) - tbl_str[#tbl_str + 1] = ', ' - elseif type(val) == 'string' then - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) - tbl_str[#tbl_str + 1] = ', ' - elseif type(val) == 'nil' then -- won't ever happen, right? - tbl_str[#tbl_str + 1] = 'nil, ' - elseif type(val) == 'table' then - tbl_str[#tbl_str + 1] = mist.utils.oneLineSerialize(val) - tbl_str[#tbl_str + 1] = ', ' --I think this is right, I just added it - else - env.info('unable to serialize value type ' .. mist.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) - end + tbl_str[#tbl_str + 1] = '{ ' + + for ind,val in pairs(tbl) do -- serialize its fields + if type(ind) == "number" then + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = tostring(ind) + tbl_str[#tbl_str + 1] = '] = ' + else --must be a string + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) + tbl_str[#tbl_str + 1] = '] = ' + end + + if ((type(val) == 'number') or (type(val) == 'boolean')) then + tbl_str[#tbl_str + 1] = tostring(val) + tbl_str[#tbl_str + 1] = ', ' + elseif type(val) == 'string' then + tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) + tbl_str[#tbl_str + 1] = ', ' + elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = 'nil, ' + elseif type(val) == 'table' then + tbl_str[#tbl_str + 1] = mist.utils.oneLineSerialize(val) + tbl_str[#tbl_str + 1] = ', ' --I think this is right, I just added it + else + env.info('unable to serialize value type ' .. mist.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) + end + + end + tbl_str[#tbl_str + 1] = '}' + return table.concat(tbl_str) + end end --Function to create string for viewing the contents of a table -NOT for serialization mist.utils.tableShow = function(tbl, loc, indent, tableshow_tbls) --based on serialize_slmod, this is a _G serialization - tableshow_tbls = tableshow_tbls or {} --create table of tables - loc = loc or "" - indent = indent or "" - if type(tbl) == 'table' then --function only works for tables! - tableshow_tbls[tbl] = loc - - local tbl_str = {} + tableshow_tbls = tableshow_tbls or {} --create table of tables + loc = loc or "" + indent = indent or "" + if type(tbl) == 'table' then --function only works for tables! + tableshow_tbls[tbl] = loc + + local tbl_str = {} - tbl_str[#tbl_str + 1] = indent .. '{\n' - - for ind,val in pairs(tbl) do -- serialize its fields - if type(ind) == "number" then - tbl_str[#tbl_str + 1] = indent - tbl_str[#tbl_str + 1] = loc .. '[' - tbl_str[#tbl_str + 1] = tostring(ind) - tbl_str[#tbl_str + 1] = '] = ' - else - tbl_str[#tbl_str + 1] = indent - tbl_str[#tbl_str + 1] = loc .. '[' - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) - tbl_str[#tbl_str + 1] = '] = ' - end - - if ((type(val) == 'number') or (type(val) == 'boolean')) then - tbl_str[#tbl_str + 1] = tostring(val) - tbl_str[#tbl_str + 1] = ',\n' - elseif type(val) == 'string' then - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) - tbl_str[#tbl_str + 1] = ',\n' - elseif type(val) == 'nil' then -- won't ever happen, right? - tbl_str[#tbl_str + 1] = 'nil,\n' - elseif type(val) == 'table' then - if tableshow_tbls[val] then - tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n' - else - tableshow_tbls[val] = loc .. '[' .. mist.utils.basicSerialize(ind) .. ']' - tbl_str[#tbl_str + 1] = tostring(val) .. ' ' - tbl_str[#tbl_str + 1] = mist.utils.tableShow(val, loc .. '[' .. mist.utils.basicSerialize(ind).. ']', indent .. ' ', tableshow_tbls) - tbl_str[#tbl_str + 1] = ',\n' - end - elseif type(val) == 'function' then - if debug and debug.getinfo then - local fcnname = tostring(val) - local info = debug.getinfo(val, "S") - if info.what == "C" then - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n' - else - if (string.sub(info.source, 1, 2) == [[./]]) then - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n' - else - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' - end - end - - else - tbl_str[#tbl_str + 1] = 'a function,\n' - end - else - tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. mist.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind) - end - end - - tbl_str[#tbl_str + 1] = indent .. '}' - return table.concat(tbl_str) - end + tbl_str[#tbl_str + 1] = indent .. '{\n' + + for ind,val in pairs(tbl) do -- serialize its fields + if type(ind) == "number" then + tbl_str[#tbl_str + 1] = indent + tbl_str[#tbl_str + 1] = loc .. '[' + tbl_str[#tbl_str + 1] = tostring(ind) + tbl_str[#tbl_str + 1] = '] = ' + else + tbl_str[#tbl_str + 1] = indent + tbl_str[#tbl_str + 1] = loc .. '[' + tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) + tbl_str[#tbl_str + 1] = '] = ' + end + + if ((type(val) == 'number') or (type(val) == 'boolean')) then + tbl_str[#tbl_str + 1] = tostring(val) + tbl_str[#tbl_str + 1] = ',\n' + elseif type(val) == 'string' then + tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) + tbl_str[#tbl_str + 1] = ',\n' + elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = 'nil,\n' + elseif type(val) == 'table' then + if tableshow_tbls[val] then + tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n' + else + tableshow_tbls[val] = loc .. '[' .. mist.utils.basicSerialize(ind) .. ']' + tbl_str[#tbl_str + 1] = tostring(val) .. ' ' + tbl_str[#tbl_str + 1] = mist.utils.tableShow(val, loc .. '[' .. mist.utils.basicSerialize(ind).. ']', indent .. ' ', tableshow_tbls) + tbl_str[#tbl_str + 1] = ',\n' + end + elseif type(val) == 'function' then + if debug and debug.getinfo then + local fcnname = tostring(val) + local info = debug.getinfo(val, "S") + if info.what == "C" then + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n' + else + if (string.sub(info.source, 1, 2) == [[./]]) then + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n' + else + tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' + end + end + + else + tbl_str[#tbl_str + 1] = 'a function,\n' + end + else + tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. mist.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind) + end + end + + tbl_str[#tbl_str + 1] = indent .. '}' + return table.concat(tbl_str) + end end mist.debug = {} mist.debug.dump_G = function(fname) - if lfs and io then - local fdir = lfs.writedir() .. [[Logs\]] .. fname - local f = io.open(fdir, 'w') - f:write(mist.utils.tableShow(_G)) - f:close() - local errmsg = 'mist.debug.dump_G wrote data to ' .. fdir - env.info(errmsg) - trigger.action.outText(errmsg, 10) - else - local errmsg = 'Error: insufficient libraries to run mist.debug.dump_G, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua' - env.info(errmsg) - trigger.action.outText(errmsg, 10) - end + if lfs and io then + local fdir = lfs.writedir() .. [[Logs\]] .. fname + local f = io.open(fdir, 'w') + f:write(mist.utils.tableShow(_G)) + f:close() + local errmsg = 'mist.debug.dump_G wrote data to ' .. fdir + env.info(errmsg) + trigger.action.outText(errmsg, 10) + else + local errmsg = 'Error: insufficient libraries to run mist.debug.dump_G, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua' + env.info(errmsg) + trigger.action.outText(errmsg, 10) + end end mist.debug.writeData = function(fcn, fcnVars, fname) - if lfs and io then - local fdir = lfs.writedir() .. [[Logs\]] .. fname - local f = io.open(fdir, 'w') - f:write(fcn(unpack(fcnVars, 1, table.maxn(fcnVars)))) - f:close() - local errmsg = 'mist.debug.writeData wrote data to ' .. fdir - env.info(errmsg) - trigger.action.outText(errmsg, 10) - else - local errmsg = 'Error: insufficient libraries to run mist.debug.writeData, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua' - env.info(errmsg) - trigger.action.outText(errmsg, 10) - end + if lfs and io then + local fdir = lfs.writedir() .. [[Logs\]] .. fname + local f = io.open(fdir, 'w') + f:write(fcn(unpack(fcnVars, 1, table.maxn(fcnVars)))) + f:close() + local errmsg = 'mist.debug.writeData wrote data to ' .. fdir + env.info(errmsg) + trigger.action.outText(errmsg, 10) + else + local errmsg = 'Error: insufficient libraries to run mist.debug.writeData, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua' + env.info(errmsg) + trigger.action.outText(errmsg, 10) + end end mist.debug.dumpDBs = function() - for DBname, DB in pairs(mist.DBs) do - if type(DB) == 'table' and type(DBname) == 'string' then - mist.debug.writeData(mist.utils.serialize, {DBname, DB}, 'mist_DBs_' .. DBname .. '.lua') - end - end + for DBname, DB in pairs(mist.DBs) do + if type(DB) == 'table' and type(DBname) == 'string' then + mist.debug.writeData(mist.utils.serialize, {DBname, DB}, 'mist_DBs_' .. DBname .. '.lua') + end + end end ----------------------------------------------------------------------------------------------------------------- @@ -1366,49 +1421,49 @@ end mist.vec = {} mist.vec.add = function(vec1, vec2) - return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} + return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} end mist.vec.sub = function(vec1, vec2) - return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} + return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} end mist.vec.scalarMult = function(vec, mult) - return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} + return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} end mist.vec.scalar_mult = mist.vec.scalarMult mist.vec.dp = function(vec1, vec2) - return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z + return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z end mist.vec.cp = function(vec1, vec2) - return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} + return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} end mist.vec.mag = function(vec) - return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 + return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 end mist.vec.getUnitVec = function(vec) - local mag = mist.vec.mag(vec) - return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } + local mag = mist.vec.mag(vec) + return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } end mist.vec.rotateVec2 = function(vec2, theta) - return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} + return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} end --------------------------------------------------------------------------------------------------------------------------- -- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. mist.tostringMGRS = function(MGRS, acc) - if acc == 0 then - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph - else - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Easting/(10^(5-acc)), 0)) - .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Northing/(10^(5-acc)), 0)) - end + if acc == 0 then + return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph + else + return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Easting/(10^(5-acc)), 0)) + .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Northing/(10^(5-acc)), 0)) + end end --[[acc: @@ -1419,173 +1474,174 @@ So: 42.32 - acc of 2. ]] mist.tostringLL = function(lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = mist.utils.round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = mist.utils.round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi + + local latHemi, lonHemi + if lat > 0 then + latHemi = 'N' + else + latHemi = 'S' + end + + if lon > 0 then + lonHemi = 'E' + else + lonHemi = 'W' + end + + lat = math.abs(lat) + lon = math.abs(lon) + + local latDeg = math.floor(lat) + local latMin = (lat - latDeg)*60 + + local lonDeg = math.floor(lon) + local lonMin = (lon - lonDeg)*60 + + if DMS then -- degrees, minutes, and seconds. + local oldLatMin = latMin + latMin = math.floor(latMin) + local latSec = mist.utils.round((oldLatMin - latMin)*60, acc) + + local oldLonMin = lonMin + lonMin = math.floor(lonMin) + local lonSec = mist.utils.round((oldLonMin - lonMin)*60, acc) + + if latSec == 60 then + latSec = 0 + latMin = latMin + 1 + end + + if lonSec == 60 then + lonSec = 0 + lonMin = lonMin + 1 + end + + local secFrmtStr -- create the formatting string for the seconds place + if acc <= 0 then -- no decimal place. + secFrmtStr = '%02d' + else + local width = 3 + acc -- 01.310 - that's a width of 6, for example. + secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' + end + + return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' + .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - else -- degrees, decimal minutes. - latMin = mist.utils.round(latMin, acc) - lonMin = mist.utils.round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end + else -- degrees, decimal minutes. + latMin = mist.utils.round(latMin, acc) + lonMin = mist.utils.round(lonMin, acc) + + if latMin == 60 then + latMin = 0 + latDeg = latDeg + 1 + end + + if lonMin == 60 then + lonMin = 0 + lonDeg = lonDeg + 1 + end + + local minFrmtStr -- create the formatting string for the minutes place + if acc <= 0 then -- no decimal place. + minFrmtStr = '%02d' + else + local width = 3 + acc -- 01.310 - that's a width of 6, for example. + minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' + end + + return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' + .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi + + end end --[[ required: az - radian required: dist - meters - optional: alt - meters (set to false or nil if you don't want to use it). - optional: metric - set true to get dist and alt in km and m. - precision will always be nearest degree and NM or km.]] + optional: alt - meters (set to false or nil if you don't want to use it). + optional: metric - set true to get dist and alt in km and m. + precision will always be nearest degree and NM or km.]] mist.tostringBR = function(az, dist, alt, metric) - az = mist.utils.round(mist.utils.toDegree(az), 0) - - if metric then - dist = mist.utils.round(dist/1000, 0) - else - dist = mist.utils.round(mist.utils.metersToNM(dist), 0) - end - - local s = string.format('%03d', az) .. ' for ' .. dist - - if alt then - if metric then - s = s .. ' at ' .. mist.utils.round(alt, 0) - else - s = s .. ' at ' .. mist.utils.round(mist.utils.metersToFeet(alt), 0) - end - end - return s + az = mist.utils.round(mist.utils.toDegree(az), 0) + + if metric then + dist = mist.utils.round(dist/1000, 0) + else + dist = mist.utils.round(mist.utils.metersToNM(dist), 0) + end + + local s = string.format('%03d', az) .. ' for ' .. dist + + if alt then + if metric then + s = s .. ' at ' .. mist.utils.round(alt, 0) + else + s = s .. ' at ' .. mist.utils.round(mist.utils.metersToFeet(alt), 0) + end + end + return s end -mist.getNorthCorrection = function(point) --gets the correction needed for true north - if not point.z then --Vec2; convert to Vec3 - point.z = point.y - point.y = 0 - end - local lat, lon = coord.LOtoLL(point) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2(north_posit.z - point.z, north_posit.x - point.x) +mist.getNorthCorrection = function(gPoint) --gets the correction needed for true north + local point = mist.utils.deepCopy(gPoint) + if not point.z then --Vec2; convert to Vec3 + point.z = point.y + point.y = 0 + end + local lat, lon = coord.LOtoLL(point) + local north_posit = coord.LLtoLO(lat + 1, lon) + return math.atan2(north_posit.z - point.z, north_posit.x - point.x) end mist.getUnitSkill = function(unitName) - if Unit.getByName(unitName) and Unit.getByName(unitName):isExist() == true then - local lunit = Unit.getByName(unitName) - for name, data in pairs(mist.DBs.unitsByName) do - if name == unitName and data.type == lunit:getTypeName() and data.unitId == lunit:getID() and data.skill then - return data.skill - end - end - end - return false + if Unit.getByName(unitName) and Unit.getByName(unitName):isExist() == true then + local lunit = Unit.getByName(unitName) + for name, data in pairs(mist.DBs.unitsByName) do + if name == unitName and data.type == lunit:getTypeName() and data.unitId == lunit:getID() and data.skill then + return data.skill + end + end + end + return false end function mist.getGroupPoints(groupIdent) -- if groupname exists in env.mission, then returns table of the group's points in numerical order, such as: { [1] = {x = 299435.224, y = -1146632.6773}, [2] = { x = 663324.6563, y = 322424.1112}} - -- refactor to search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - for point_num, point in pairs(group_data.route.points) do - if not point.point then - points[point_num] = { x = point.x, y = point.y } - else - points[point_num] = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - end - return points - end - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do + -- refactor to search by groupId and allow groupId and groupName as inputs + local gpId = groupIdent + if type(groupIdent) == 'string' and not tonumber(groupIdent) then + gpId = mist.DBs.MEgroupsByName[groupIdent].groupId + end + + for coa_name, coa_data in pairs(env.mission.coalition) do + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + for obj_type_name, obj_type_data in pairs(cntry_data) do + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + for group_num, group_data in pairs(obj_type_data.group) do + if group_data and group_data.groupId == gpId then -- this is the group we are looking for + if group_data.route and group_data.route.points and #group_data.route.points > 0 then + local points = {} + for point_num, point in pairs(group_data.route.points) do + if not point.point then + points[point_num] = { x = point.x, y = point.y } + else + points[point_num] = point.point --it's possible that the ME could move to the point = Vec2 notation. + end + end + return points + end + return + end --if group_data and group_data.name and group_data.name == 'groupname' + end --for group_num, group_data in pairs(obj_type_data.group) do + end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then + end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then + end --for obj_type_name, obj_type_data in pairs(cntry_data) do + end --for cntry_id, cntry_data in pairs(coa_data.country) do + end --if coa_data.country then --there is a country table + end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then + end --for coa_name, coa_data in pairs(mission.coalition) do end @@ -1593,204 +1649,204 @@ end --[[ table attitude = getAttitude(string unitname) -- will work on any unit, even if not an aircraft. attitude = { - Heading = number, -- in radians, range of 0 to 2*pi, relative to true north - Pitch = number, -- in radians, range of -pi/2 to pi/2 - Roll = number, -- in radians, range of 0 to 2*pi, right roll is positive direction - - --Yaw, AoA, ClimbAngle - relative to earth reference- DOES NOT TAKE INTO ACCOUNT WIND. - Yaw = number, -- in radians, range of -pi to pi, right yaw is positive direction - AoA = number, -- in radians, range of -pi to pi, rotation of aircraft to the right in comparison to flight direction being positive - ClimbAngle = number, -- in radians, range of -pi/2 to pi/2 - - --Maybe later? - AxialVel = table, velocity of the aircraft transformed into directions of aircraft axes - Speed = number -- absolute velocity in meters/sec + Heading = number, -- in radians, range of 0 to 2*pi, relative to true north + Pitch = number, -- in radians, range of -pi/2 to pi/2 + Roll = number, -- in radians, range of 0 to 2*pi, right roll is positive direction + + --Yaw, AoA, ClimbAngle - relative to earth reference- DOES NOT TAKE INTO ACCOUNT WIND. + Yaw = number, -- in radians, range of -pi to pi, right yaw is positive direction + AoA = number, -- in radians, range of -pi to pi, rotation of aircraft to the right in comparison to flight direction being positive + ClimbAngle = number, -- in radians, range of -pi/2 to pi/2 + + --Maybe later? + AxialVel = table, velocity of the aircraft transformed into directions of aircraft axes + Speed = number -- absolute velocity in meters/sec - } + } ]] function mist.getAttitude(unit) - local unitpos = unit:getPosition() - if unitpos then - - local Heading = math.atan2(unitpos.x.z, unitpos.x.x) - - Heading = Heading + mist.getNorthCorrection(unitpos.p) - - if Heading < 0 then - Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi - end - ---- heading complete.---- - - local Pitch = math.asin(unitpos.x.y) - ---- pitch complete.---- - - -- now get roll: - --maybe not the best way to do it, but it works. - - --first, make a vector that is perpendicular to y and unitpos.x with cross product - local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) - - --now, get dot product of of this cross product with unitpos.z - local dp = mist.vec.dp(cp, unitpos.z) - - --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) - local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) + local unitpos = unit:getPosition() + if unitpos then + + local Heading = math.atan2(unitpos.x.z, unitpos.x.x) + + Heading = Heading + mist.getNorthCorrection(unitpos.p) + + if Heading < 0 then + Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi + end + ---- heading complete.---- + + local Pitch = math.asin(unitpos.x.y) + ---- pitch complete.---- + + -- now get roll: + --maybe not the best way to do it, but it works. + + --first, make a vector that is perpendicular to y and unitpos.x with cross product + local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) + + --now, get dot product of of this cross product with unitpos.z + local dp = mist.vec.dp(cp, unitpos.z) + + --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) + local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) - --now, have to get sign of roll. - -- by convention, making right roll positive - -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. - - if unitpos.z.y > 0 then -- left roll, flip the sign of the roll - Roll = -Roll - end - ---- roll complete. ---- - - --now, work on yaw, AoA, climb, and abs velocity - local Yaw - local AoA - local ClimbAngle - - -- get unit velocity - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - --Yaw is the angle between unitpos.x and the x and z velocities - --define right yaw as positive - Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) - - --now set correct direction: - if AxialVel.z > 0 then - Yaw = -Yaw - end - - -- AoA is angle between unitpos.x and the x and y velocities - AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) - - --now set correct direction: - if AxialVel.y > 0 then - AoA = -AoA - end - - ClimbAngle = math.asin(unitvel.y/mist.vec.mag(unitvel)) - end - return { Heading = Heading, Pitch = Pitch, Roll = Roll, Yaw = Yaw, AoA = AoA, ClimbAngle = ClimbAngle} - else - env.info('unit:getPosition() is nil!') - end + --now, have to get sign of roll. + -- by convention, making right roll positive + -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. + + if unitpos.z.y > 0 then -- left roll, flip the sign of the roll + Roll = -Roll + end + ---- roll complete. ---- + + --now, work on yaw, AoA, climb, and abs velocity + local Yaw + local AoA + local ClimbAngle + + -- get unit velocity + local unitvel = unit:getVelocity() + if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! + local AxialVel = {} --unit velocity transformed into aircraft axes directions + + --transform velocity components in direction of aircraft axes. + AxialVel.x = mist.vec.dp(unitpos.x, unitvel) + AxialVel.y = mist.vec.dp(unitpos.y, unitvel) + AxialVel.z = mist.vec.dp(unitpos.z, unitvel) + + --Yaw is the angle between unitpos.x and the x and z velocities + --define right yaw as positive + Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) + + --now set correct direction: + if AxialVel.z > 0 then + Yaw = -Yaw + end + + -- AoA is angle between unitpos.x and the x and y velocities + AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) + + --now set correct direction: + if AxialVel.y > 0 then + AoA = -AoA + end + + ClimbAngle = math.asin(unitvel.y/mist.vec.mag(unitvel)) + end + return { Heading = Heading, Pitch = Pitch, Roll = Roll, Yaw = Yaw, AoA = AoA, ClimbAngle = ClimbAngle} + else + env.info('unit:getPosition() is nil!') + end end function mist.getHeading(unit, rawHeading) - local unitpos = unit:getPosition() - if unitpos then - local Heading = math.atan2(unitpos.x.z, unitpos.x.x) - if not rawHeading then - Heading = Heading + mist.getNorthCorrection(unitpos.p) - end - if Heading < 0 then - Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi - end - return Heading - end + local unitpos = unit:getPosition() + if unitpos then + local Heading = math.atan2(unitpos.x.z, unitpos.x.x) + if not rawHeading then + Heading = Heading + mist.getNorthCorrection(unitpos.p) + end + if Heading < 0 then + Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi + end + return Heading + end end function mist.getPitch(unit) - local unitpos = unit:getPosition() - if unitpos then - return math.asin(unitpos.x.y) - end + local unitpos = unit:getPosition() + if unitpos then + return math.asin(unitpos.x.y) + end end function mist.getRoll(unit) - local unitpos = unit:getPosition() - if unitpos then - -- now get roll: - --maybe not the best way to do it, but it works. - - --first, make a vector that is perpendicular to y and unitpos.x with cross product - local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) - - --now, get dot product of of this cross product with unitpos.z - local dp = mist.vec.dp(cp, unitpos.z) - - --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) - local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) + local unitpos = unit:getPosition() + if unitpos then + -- now get roll: + --maybe not the best way to do it, but it works. + + --first, make a vector that is perpendicular to y and unitpos.x with cross product + local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) + + --now, get dot product of of this cross product with unitpos.z + local dp = mist.vec.dp(cp, unitpos.z) + + --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) + local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) - --now, have to get sign of roll. - -- by convention, making right roll positive - -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. - - if unitpos.z.y > 0 then -- left roll, flip the sign of the roll - Roll = -Roll - end - return Roll - end + --now, have to get sign of roll. + -- by convention, making right roll positive + -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. + + if unitpos.z.y > 0 then -- left roll, flip the sign of the roll + Roll = -Roll + end + return Roll + end end function mist.getYaw(unit) - local unitpos = unit:getPosition() - if unitpos then - -- get unit velocity - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - --Yaw is the angle between unitpos.x and the x and z velocities - --define right yaw as positive - local Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) - - --now set correct direction: - if AxialVel.z > 0 then - Yaw = -Yaw - end - return Yaw - end - end + local unitpos = unit:getPosition() + if unitpos then + -- get unit velocity + local unitvel = unit:getVelocity() + if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! + local AxialVel = {} --unit velocity transformed into aircraft axes directions + + --transform velocity components in direction of aircraft axes. + AxialVel.x = mist.vec.dp(unitpos.x, unitvel) + AxialVel.y = mist.vec.dp(unitpos.y, unitvel) + AxialVel.z = mist.vec.dp(unitpos.z, unitvel) + + --Yaw is the angle between unitpos.x and the x and z velocities + --define right yaw as positive + local Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) + + --now set correct direction: + if AxialVel.z > 0 then + Yaw = -Yaw + end + return Yaw + end + end end function mist.getAoA(unit) - local unitpos = unit:getPosition() - if unitpos then - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - -- AoA is angle between unitpos.x and the x and y velocities - local AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) - - --now set correct direction: - if AxialVel.y > 0 then - AoA = -AoA - end - return AoA - end - end + local unitpos = unit:getPosition() + if unitpos then + local unitvel = unit:getVelocity() + if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! + local AxialVel = {} --unit velocity transformed into aircraft axes directions + + --transform velocity components in direction of aircraft axes. + AxialVel.x = mist.vec.dp(unitpos.x, unitvel) + AxialVel.y = mist.vec.dp(unitpos.y, unitvel) + AxialVel.z = mist.vec.dp(unitpos.z, unitvel) + + -- AoA is angle between unitpos.x and the x and y velocities + local AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) + + --now set correct direction: + if AxialVel.y > 0 then + AoA = -AoA + end + return AoA + end + end end function mist.getClimbAngle(unit) - local unitpos = unit:getPosition() - if unitpos then - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - return math.asin(unitvel.y/mist.vec.mag(unitvel)) - end - end + local unitpos = unit:getPosition() + if unitpos then + local unitvel = unit:getVelocity() + if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! + return math.asin(unitvel.y/mist.vec.mag(unitvel)) + end + end end ----------------------------------------------------------------------------------------------------------- -- Database building @@ -1799,22 +1855,22 @@ mist.DBs = {} mist.DBs.missionData = {} ----------------------------------------- if env.mission then - - mist.DBs.missionData['startTime'] = env.mission.start_time - mist.DBs.missionData['theatre'] = env.mission.theatre - mist.DBs.missionData['version'] = env.mission.version - mist.DBs.missionData['files'] = {} - if type(env.mission.resourceCounter) == 'table' then - for fIndex, fData in pairs (env.mission.resourceCounter) do - mist.DBs.missionData.files[#mist.DBs.missionData.files + 1] = mist.utils.deepCopy(fIndex) - end - end - mist.DBs.missionData['bullseye'] = {['red'] = {}, ['blue'] = {}} -- if we add more coalition specific data then bullsye should be categorized by coaliton. For now its just the bullseye table - mist.DBs.missionData.bullseye.red['x'] = env.mission.coalition.red.bullseye.x --should it be point.x? - mist.DBs.missionData.bullseye.red['y'] = env.mission.coalition.red.bullseye.y - mist.DBs.missionData.bullseye.blue['x'] = env.mission.coalition.blue.bullseye.x - mist.DBs.missionData.bullseye.blue['y'] = env.mission.coalition.blue.bullseye.y - + + mist.DBs.missionData['startTime'] = env.mission.start_time + mist.DBs.missionData['theatre'] = env.mission.theatre + mist.DBs.missionData['version'] = env.mission.version + mist.DBs.missionData['files'] = {} + if type(env.mission.resourceCounter) == 'table' then + for fIndex, fData in pairs (env.mission.resourceCounter) do + mist.DBs.missionData.files[#mist.DBs.missionData.files + 1] = mist.utils.deepCopy(fIndex) + end + end + mist.DBs.missionData['bullseye'] = {['red'] = {}, ['blue'] = {}} -- if we add more coalition specific data then bullsye should be categorized by coaliton. For now its just the bullseye table + mist.DBs.missionData.bullseye.red['x'] = env.mission.coalition.red.bullseye.x --should it be point.x? + mist.DBs.missionData.bullseye.red['y'] = env.mission.coalition.red.bullseye.y + mist.DBs.missionData.bullseye.blue['x'] = env.mission.coalition.blue.bullseye.x + mist.DBs.missionData.bullseye.blue['y'] = env.mission.coalition.blue.bullseye.y + end ---------------------------------------- @@ -1824,19 +1880,19 @@ mist.DBs.zonesByNum = {} if env.mission.triggers and env.mission.triggers.zones then - for zone_ind, zone_data in pairs(env.mission.triggers.zones) do - if type(zone_data) == 'table' then - local zone = mist.utils.deepCopy(zone_data) - zone['point'] = {} -- point is used by SSE - zone['point']['x'] = zone_data.x - zone['point']['y'] = 0 - zone['point']['z'] = zone_data.y - - mist.DBs.zonesByName[zone_data.name] = zone - mist.DBs.zonesByNum[#mist.DBs.zonesByNum + 1] = mist.utils.deepCopy(zone) --[[deepcopy so that the zone in zones_by_name and the zone in - zones_by_num se are different objects.. don't want them linked.]] - end - end + for zone_ind, zone_data in pairs(env.mission.triggers.zones) do + if type(zone_data) == 'table' then + local zone = mist.utils.deepCopy(zone_data) + zone['point'] = {} -- point is used by SSE + zone['point']['x'] = zone_data.x + zone['point']['y'] = 0 + zone['point']['z'] = zone_data.y + + mist.DBs.zonesByName[zone_data.name] = zone + mist.DBs.zonesByNum[#mist.DBs.zonesByNum + 1] = mist.utils.deepCopy(zone) --[[deepcopy so that the zone in zones_by_name and the zone in + zones_by_num se are different objects.. don't want them linked.]] + end + end end mist.DBs.navPoints = {} @@ -1844,140 +1900,140 @@ mist.DBs.units = {} --Build mist.db.units and mist.DBs.navPoints for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - mist.DBs.units[coa_name] = {} - - ---------------------------------------------- - -- build nav points DB - mist.DBs.navPoints[coa_name] = {} - if coa_data.nav_points then --navpoints - --mist.debug.writeData (mist.utils.serialize,{'NavPoints',coa_data.nav_points}, 'NavPoints.txt') - for nav_ind, nav_data in pairs(coa_data.nav_points) do - - if type(nav_data) == 'table' then - mist.DBs.navPoints[coa_name][nav_ind] = mist.utils.deepCopy(nav_data) + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + mist.DBs.units[coa_name] = {} + + ---------------------------------------------- + -- build nav points DB + mist.DBs.navPoints[coa_name] = {} + if coa_data.nav_points then --navpoints + --mist.debug.writeData (mist.utils.serialize,{'NavPoints',coa_data.nav_points}, 'NavPoints.txt') + for nav_ind, nav_data in pairs(coa_data.nav_points) do + + if type(nav_data) == 'table' then + mist.DBs.navPoints[coa_name][nav_ind] = mist.utils.deepCopy(nav_data) - mist.DBs.navPoints[coa_name][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. - mist.DBs.navPoints[coa_name][nav_ind]['point'] = {} -- point is used by SSE, support it. - mist.DBs.navPoints[coa_name][nav_ind]['point']['x'] = nav_data.x - mist.DBs.navPoints[coa_name][nav_ind]['point']['y'] = 0 - mist.DBs.navPoints[coa_name][nav_ind]['point']['z'] = nav_data.y - end - end - end - ------------------------------------------------- - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - - local countryName = string.lower(cntry_data.name) - mist.DBs.units[coa_name][countryName] = {} - mist.DBs.units[coa_name][countryName]["countryId"] = cntry_data.id + mist.DBs.navPoints[coa_name][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. + mist.DBs.navPoints[coa_name][nav_ind]['point'] = {} -- point is used by SSE, support it. + mist.DBs.navPoints[coa_name][nav_ind]['point']['x'] = nav_data.x + mist.DBs.navPoints[coa_name][nav_ind]['point']['y'] = 0 + mist.DBs.navPoints[coa_name][nav_ind]['point']['z'] = nav_data.y + end + end + end + ------------------------------------------------- + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + + local countryName = string.lower(cntry_data.name) + mist.DBs.units[coa_name][countryName] = {} + mist.DBs.units[coa_name][countryName]["countryId"] = cntry_data.id - if type(cntry_data) == 'table' then --just making sure - - for obj_type_name, obj_type_data in pairs(cntry_data) do - - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check - - local category = obj_type_name - - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - - mist.DBs.units[coa_name][countryName][category] = {} - - for group_num, group_data in pairs(obj_type_data.group) do - - if group_data and group_data.units and type(group_data.units) == 'table' then --making sure again- this is a valid group - - mist.DBs.units[coa_name][countryName][category][group_num] = {} - local groupName = group_data.name - if env.mission.version > 7 then - groupName = env.getValueDictByKey(groupName) - end - mist.DBs.units[coa_name][countryName][category][group_num]["groupName"] = groupName - mist.DBs.units[coa_name][countryName][category][group_num]["groupId"] = group_data.groupId - mist.DBs.units[coa_name][countryName][category][group_num]["category"] = category - mist.DBs.units[coa_name][countryName][category][group_num]["coalition"] = coa_name - mist.DBs.units[coa_name][countryName][category][group_num]["country"] = countryName - mist.DBs.units[coa_name][countryName][category][group_num]["countryId"] = cntry_data.id - mist.DBs.units[coa_name][countryName][category][group_num]["startTime"] = group_data.start_time - mist.DBs.units[coa_name][countryName][category][group_num]["task"] = group_data.task - mist.DBs.units[coa_name][countryName][category][group_num]["hidden"] = group_data.hidden - - mist.DBs.units[coa_name][countryName][category][group_num]["units"] = {} - - mist.DBs.units[coa_name][countryName][category][group_num]["radioSet"] = group_data.radioSet - mist.DBs.units[coa_name][countryName][category][group_num]["uncontrolled"] = group_data.uncontrolled - mist.DBs.units[coa_name][countryName][category][group_num]["frequency"] = group_data.frequency - mist.DBs.units[coa_name][countryName][category][group_num]["modulation"] = group_data.modulation + if type(cntry_data) == 'table' then --just making sure + + for obj_type_name, obj_type_data in pairs(cntry_data) do + + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check + + local category = obj_type_name + + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + + mist.DBs.units[coa_name][countryName][category] = {} + + for group_num, group_data in pairs(obj_type_data.group) do + + if group_data and group_data.units and type(group_data.units) == 'table' then --making sure again- this is a valid group + + mist.DBs.units[coa_name][countryName][category][group_num] = {} + local groupName = group_data.name + if env.mission.version > 7 then + groupName = env.getValueDictByKey(groupName) + end + mist.DBs.units[coa_name][countryName][category][group_num]["groupName"] = groupName + mist.DBs.units[coa_name][countryName][category][group_num]["groupId"] = group_data.groupId + mist.DBs.units[coa_name][countryName][category][group_num]["category"] = category + mist.DBs.units[coa_name][countryName][category][group_num]["coalition"] = coa_name + mist.DBs.units[coa_name][countryName][category][group_num]["country"] = countryName + mist.DBs.units[coa_name][countryName][category][group_num]["countryId"] = cntry_data.id + mist.DBs.units[coa_name][countryName][category][group_num]["startTime"] = group_data.start_time + mist.DBs.units[coa_name][countryName][category][group_num]["task"] = group_data.task + mist.DBs.units[coa_name][countryName][category][group_num]["hidden"] = group_data.hidden + + mist.DBs.units[coa_name][countryName][category][group_num]["units"] = {} + + mist.DBs.units[coa_name][countryName][category][group_num]["radioSet"] = group_data.radioSet + mist.DBs.units[coa_name][countryName][category][group_num]["uncontrolled"] = group_data.uncontrolled + mist.DBs.units[coa_name][countryName][category][group_num]["frequency"] = group_data.frequency + mist.DBs.units[coa_name][countryName][category][group_num]["modulation"] = group_data.modulation - for unit_num, unit_data in pairs(group_data.units) do - local units_tbl = mist.DBs.units[coa_name][countryName][category][group_num]["units"] --pointer to the units table for this group - - units_tbl[unit_num] = {} - if env.mission.version > 7 then - units_tbl[unit_num]["unitName"] = env.getValueDictByKey(unit_data.name) - else - units_tbl[unit_num]["unitName"] = unit_data.name - end - units_tbl[unit_num]["type"] = unit_data.type - units_tbl[unit_num]["skill"] = unit_data.skill --will be nil for statics - units_tbl[unit_num]["unitId"] = unit_data.unitId - units_tbl[unit_num]["category"] = category - units_tbl[unit_num]["coalition"] = coa_name - units_tbl[unit_num]["country"] = countryName - units_tbl[unit_num]["countryId"] = cntry_data.id - units_tbl[unit_num]["heading"] = unit_data.heading - units_tbl[unit_num]["playerCanDrive"] = unit_data.playerCanDrive - units_tbl[unit_num]["alt"] = unit_data.alt - units_tbl[unit_num]["alt_type"] = unit_data.alt_type - units_tbl[unit_num]["speed"] = unit_data.speed - units_tbl[unit_num]["livery_id"] = unit_data.livery_id - if unit_data.point then --ME currently does not work like this, but it might one day - units_tbl[unit_num]["point"] = unit_data.point - else - units_tbl[unit_num]["point"] = {} - units_tbl[unit_num]["point"]["x"] = unit_data.x - units_tbl[unit_num]["point"]["y"] = unit_data.y - end - units_tbl[unit_num]['x'] = unit_data.x - units_tbl[unit_num]['y'] = unit_data.y - - units_tbl[unit_num]["callsign"] = unit_data.callsign - units_tbl[unit_num]["onboard_num"] = unit_data.onboard_num - units_tbl[unit_num]["hardpoint_racks"] = unit_data.hardpoint_racks - units_tbl[unit_num]["psi"] = unit_data.psi + for unit_num, unit_data in pairs(group_data.units) do + local units_tbl = mist.DBs.units[coa_name][countryName][category][group_num]["units"] --pointer to the units table for this group + + units_tbl[unit_num] = {} + if env.mission.version > 7 then + units_tbl[unit_num]["unitName"] = env.getValueDictByKey(unit_data.name) + else + units_tbl[unit_num]["unitName"] = unit_data.name + end + units_tbl[unit_num]["type"] = unit_data.type + units_tbl[unit_num]["skill"] = unit_data.skill --will be nil for statics + units_tbl[unit_num]["unitId"] = unit_data.unitId + units_tbl[unit_num]["category"] = category + units_tbl[unit_num]["coalition"] = coa_name + units_tbl[unit_num]["country"] = countryName + units_tbl[unit_num]["countryId"] = cntry_data.id + units_tbl[unit_num]["heading"] = unit_data.heading + units_tbl[unit_num]["playerCanDrive"] = unit_data.playerCanDrive + units_tbl[unit_num]["alt"] = unit_data.alt + units_tbl[unit_num]["alt_type"] = unit_data.alt_type + units_tbl[unit_num]["speed"] = unit_data.speed + units_tbl[unit_num]["livery_id"] = unit_data.livery_id + if unit_data.point then --ME currently does not work like this, but it might one day + units_tbl[unit_num]["point"] = unit_data.point + else + units_tbl[unit_num]["point"] = {} + units_tbl[unit_num]["point"]["x"] = unit_data.x + units_tbl[unit_num]["point"]["y"] = unit_data.y + end + units_tbl[unit_num]['x'] = unit_data.x + units_tbl[unit_num]['y'] = unit_data.y + + units_tbl[unit_num]["callsign"] = unit_data.callsign + units_tbl[unit_num]["onboard_num"] = unit_data.onboard_num + units_tbl[unit_num]["hardpoint_racks"] = unit_data.hardpoint_racks + units_tbl[unit_num]["psi"] = unit_data.psi - - units_tbl[unit_num]["groupName"] = groupName - units_tbl[unit_num]["groupId"] = group_data.groupId - - if unit_data.AddPropAircraft then - units_tbl[unit_num]["AddPropAircraft"] = unit_data.AddPropAircraft - end - - if category == 'static' then - units_tbl[unit_num]["categoryStatic"] = unit_data.category - units_tbl[unit_num]["shape_name"] = unit_data.shape_name - if unit_data.mass then - units_tbl[unit_num]["mass"] = unit_data.mass - end - - if unit_data.canCargo then - units_tbl[unit_num]["canCargo"] = unit_data.canCargo - end - end - - end --for unit_num, unit_data in pairs(group_data.units) do - end --if group_data and group_data.units then - end --for group_num, group_data in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --if type(cntry_data) == 'table' then - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then + + units_tbl[unit_num]["groupName"] = groupName + units_tbl[unit_num]["groupId"] = group_data.groupId + + if unit_data.AddPropAircraft then + units_tbl[unit_num]["AddPropAircraft"] = unit_data.AddPropAircraft + end + + if category == 'static' then + units_tbl[unit_num]["categoryStatic"] = unit_data.category + units_tbl[unit_num]["shape_name"] = unit_data.shape_name + if unit_data.mass then + units_tbl[unit_num]["mass"] = unit_data.mass + end + + if unit_data.canCargo then + units_tbl[unit_num]["canCargo"] = unit_data.canCargo + end + end + + end --for unit_num, unit_data in pairs(group_data.units) do + end --if group_data and group_data.units then + end --for group_num, group_data in pairs(obj_type_data.group) do + end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then + end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then + end --for obj_type_name, obj_type_data in pairs(cntry_data) do + end --if type(cntry_data) == 'table' then + end --for cntry_id, cntry_data in pairs(coa_data.country) do + end --if coa_data.country then --there is a country table + end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then end --for coa_name, coa_data in pairs(mission.coalition) do mist.DBs.unitsByName = {} @@ -2005,64 +2061,64 @@ mist.DBs.aliveUnits = {} -- will be filled in by the "update_alive_units" corou mist.DBs.removedAliveUnits = {} -- will be filled in by the "update_alive_units" coroutine in mist.main. -- create mist.DBs.oldAliveUnits -- do - -- local intermediate_alive_units = {} -- between 0 and 0.5 secs old - -- local function make_old_alive_units() -- called every 0.5 secs, makes the old_alive_units DB which is just a copy of alive_units that is 0.5 to 1 sec old - -- if intermediate_alive_units then - -- mist.DBs.oldAliveUnits = mist.utils.deepCopy(intermediate_alive_units) - -- end - -- intermediate_alive_units = mist.utils.deepCopy(mist.DBs.aliveUnits) - -- timer.scheduleFunction(make_old_alive_units, nil, timer.getTime() + 0.5) - -- end - - -- make_old_alive_units() + -- local intermediate_alive_units = {} -- between 0 and 0.5 secs old + -- local function make_old_alive_units() -- called every 0.5 secs, makes the old_alive_units DB which is just a copy of alive_units that is 0.5 to 1 sec old + -- if intermediate_alive_units then + -- mist.DBs.oldAliveUnits = mist.utils.deepCopy(intermediate_alive_units) + -- end + -- intermediate_alive_units = mist.utils.deepCopy(mist.DBs.aliveUnits) + -- timer.scheduleFunction(make_old_alive_units, nil, timer.getTime() + 0.5) + -- end + + -- make_old_alive_units() -- end --Build DBs for coa_name, coa_data in pairs(mist.DBs.units) do - for cntry_name, cntry_data in pairs(coa_data) do - for category_name, category_data in pairs(cntry_data) do - if type(category_data) == 'table' then - for group_ind, group_data in pairs(category_data) do - if type(group_data) == 'table' and group_data.units and type(group_data.units) == 'table' and #group_data.units > 0 then -- OCD paradigm programming - mist.DBs.groupsByName[group_data.groupName] = mist.utils.deepCopy(group_data) - mist.DBs.groupsById[group_data.groupId] = mist.utils.deepCopy(group_data) - for unit_ind, unit_data in pairs(group_data.units) do - mist.DBs.unitsByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) - mist.DBs.unitsById[unit_data.unitId] = mist.utils.deepCopy(unit_data) - - mist.DBs.unitsByCat[unit_data.category] = mist.DBs.unitsByCat[unit_data.category] or {} -- future-proofing against new categories... - table.insert(mist.DBs.unitsByCat[unit_data.category], mist.utils.deepCopy(unit_data)) - --print('inserting ' .. unit_data.unitName) - table.insert(mist.DBs.unitsByNum, mist.utils.deepCopy(unit_data)) - - if unit_data.skill and (unit_data.skill == "Client" or unit_data.skill == "Player") then - mist.DBs.humansByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) - mist.DBs.humansById[unit_data.unitId] = mist.utils.deepCopy(unit_data) - --if Unit.getByName(unit_data.unitName) then - -- mist.DBs.activeHumans[unit_data.unitName] = mist.utils.deepCopy(unit_data) - -- mist.DBs.activeHumans[unit_data.unitName].playerName = Unit.getByName(unit_data.unitName):getPlayerName() - --end - end - end - end - end - end - end - end + for cntry_name, cntry_data in pairs(coa_data) do + for category_name, category_data in pairs(cntry_data) do + if type(category_data) == 'table' then + for group_ind, group_data in pairs(category_data) do + if type(group_data) == 'table' and group_data.units and type(group_data.units) == 'table' and #group_data.units > 0 then -- OCD paradigm programming + mist.DBs.groupsByName[group_data.groupName] = mist.utils.deepCopy(group_data) + mist.DBs.groupsById[group_data.groupId] = mist.utils.deepCopy(group_data) + for unit_ind, unit_data in pairs(group_data.units) do + mist.DBs.unitsByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) + mist.DBs.unitsById[unit_data.unitId] = mist.utils.deepCopy(unit_data) + + mist.DBs.unitsByCat[unit_data.category] = mist.DBs.unitsByCat[unit_data.category] or {} -- future-proofing against new categories... + table.insert(mist.DBs.unitsByCat[unit_data.category], mist.utils.deepCopy(unit_data)) + --print('inserting ' .. unit_data.unitName) + table.insert(mist.DBs.unitsByNum, mist.utils.deepCopy(unit_data)) + + if unit_data.skill and (unit_data.skill == "Client" or unit_data.skill == "Player") then + mist.DBs.humansByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) + mist.DBs.humansById[unit_data.unitId] = mist.utils.deepCopy(unit_data) + --if Unit.getByName(unit_data.unitName) then + -- mist.DBs.activeHumans[unit_data.unitName] = mist.utils.deepCopy(unit_data) + -- mist.DBs.activeHumans[unit_data.unitName].playerName = Unit.getByName(unit_data.unitName):getPlayerName() + --end + end + end + end + end + end + end + end end -------------- -------- mist unitID funcs do - for id, idData in pairs(mist.DBs.unitsById) do - if idData.unitId > mist.nextUnitId then - mist.nextUnitId = mist.utils.deepCopy(idData.unitId) - end - if idData.groupId > mist.nextGroupId then - mist.nextGroupId = mist.utils.deepCopy(idData.groupId) - end - end + for id, idData in pairs(mist.DBs.unitsById) do + if idData.unitId > mist.nextUnitId then + mist.nextUnitId = mist.utils.deepCopy(idData.unitId) + end + if idData.groupId > mist.nextGroupId then + mist.nextGroupId = mist.utils.deepCopy(idData.groupId) + end + end end --DynDBs @@ -2079,159 +2135,159 @@ mist.DBs.MEgroupsById = mist.utils.deepCopy(mist.DBs.groupsById) mist.DBs.deadObjects = {} do - local mt = {} - - mt.__newindex = function(t, key, val) - --------------------------------------------------------------- - local original_key = key --only for duplicate runtime IDs. - local key_ind = 1 - while mist.DBs.deadObjects[key] do - --print('duplicate runtime id of previously dead object- key: ' .. tostring(key)) - key = tostring(original_key) .. ' #' .. tostring(key_ind) - key_ind = key_ind + 1 - end - --------------------------------------------------------------- - - if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then - --print('object found in alive_units') - val['objectData'] = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val['objectPos'] = pos.p - end - val['objectType'] = mist.DBs.aliveUnits[val.object.id_].category - - elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units - --print('object found in old_alive_units') - val['objectData'] = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val['objectPos'] = pos.p - end - val['objectType'] = mist.DBs.removedAliveUnits[val.object.id_].category - - else --attempt to determine if static object... - --print('object not found in alive units or old alive units') - local pos = Object.getPosition(val.object) - if pos then - local static_found = false - for ind, static in pairs(mist.DBs.unitsByCat['static']) do - if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... - --print('correlated dead static object to position') - val['objectData'] = static - val['objectPos'] = pos.p - val['objectType'] = 'static' - static_found = true - break - end - end - if not static_found then - val['objectPos'] = pos.p - val['objectType'] = 'building' - end - else - val['objectType'] = 'unknown' - end - end - rawset(t, key, val) - end + local mt = {} + + mt.__newindex = function(t, key, val) + --------------------------------------------------------------- + local original_key = key --only for duplicate runtime IDs. + local key_ind = 1 + while mist.DBs.deadObjects[key] do + --print('duplicate runtime id of previously dead object- key: ' .. tostring(key)) + key = tostring(original_key) .. ' #' .. tostring(key_ind) + key_ind = key_ind + 1 + end + --------------------------------------------------------------- + + if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then + --print('object found in alive_units') + val['objectData'] = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) + local pos = Object.getPosition(val.object) + if pos then + val['objectPos'] = pos.p + end + val['objectType'] = mist.DBs.aliveUnits[val.object.id_].category + + elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units + --print('object found in old_alive_units') + val['objectData'] = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) + local pos = Object.getPosition(val.object) + if pos then + val['objectPos'] = pos.p + end + val['objectType'] = mist.DBs.removedAliveUnits[val.object.id_].category + + else --attempt to determine if static object... + --print('object not found in alive units or old alive units') + local pos = Object.getPosition(val.object) + if pos then + local static_found = false + for ind, static in pairs(mist.DBs.unitsByCat['static']) do + if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... + --print('correlated dead static object to position') + val['objectData'] = static + val['objectPos'] = pos.p + val['objectType'] = 'static' + static_found = true + break + end + end + if not static_found then + val['objectPos'] = pos.p + val['objectType'] = 'building' + end + else + val['objectType'] = 'unknown' + end + end + rawset(t, key, val) + end - setmetatable(mist.DBs.deadObjects, mt) + setmetatable(mist.DBs.deadObjects, mt) end -- Event handler to start creating the dead_objects table do - local function addDeadObject(event) - if event.id == world.event.S_EVENT_DEAD or event.id == world.event.S_EVENT_CRASH then - if event.initiator and event.initiator.id_ and event.initiator.id_ > 0 then - - local id = event.initiator.id_ -- initial ID, could change if there is a duplicate id_ already dead. - local val = {object = event.initiator} -- the new entry in mist.DBs.deadObjects. - - --------------------------------------------------------------- - local original_id = id --only for duplicate runtime IDs. - local id_ind = 1 - while mist.DBs.deadObjects[id] do - --print('duplicate runtime id of previously dead object- id: ' .. tostring(id)) - id = tostring(original_id) .. ' #' .. tostring(id_ind) - id_ind = id_ind + 1 - end - --------------------------------------------------------------- - - if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then - --print('object found in alive_units') - val['objectData'] = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val['objectPos'] = pos.p - end - val['objectType'] = mist.DBs.aliveUnits[val.object.id_].category - --[[if mist.DBs.activeHumans[Unit.getName(val.object)] then - --trigger.action.outText('remove via death: ' .. Unit.getName(val.object),20) - mist.DBs.activeHumans[Unit.getName(val.object)] = nil - end]] - elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units - --print('object found in old_alive_units') - val['objectData'] = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val['objectPos'] = pos.p - end - val['objectType'] = mist.DBs.removedAliveUnits[val.object.id_].category - - else --attempt to determine if static object... - --print('object not found in alive units or old alive units') - local pos = Object.getPosition(val.object) - if pos then - local static_found = false - for ind, static in pairs(mist.DBs.unitsByCat['static']) do - if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... - --print('correlated dead static object to position') - val['objectData'] = static - val['objectPos'] = pos.p - val['objectType'] = 'static' - static_found = true - break - end - end - if not static_found then - val['objectPos'] = pos.p - val['objectType'] = 'building' - end - else - val['objectType'] = 'unknown' - end - end - mist.DBs.deadObjects[id] = val + local function addDeadObject(event) + if event.id == world.event.S_EVENT_DEAD or event.id == world.event.S_EVENT_CRASH then + if event.initiator and event.initiator.id_ and event.initiator.id_ > 0 then + + local id = event.initiator.id_ -- initial ID, could change if there is a duplicate id_ already dead. + local val = {object = event.initiator} -- the new entry in mist.DBs.deadObjects. + + --------------------------------------------------------------- + local original_id = id --only for duplicate runtime IDs. + local id_ind = 1 + while mist.DBs.deadObjects[id] do + --print('duplicate runtime id of previously dead object- id: ' .. tostring(id)) + id = tostring(original_id) .. ' #' .. tostring(id_ind) + id_ind = id_ind + 1 + end + --------------------------------------------------------------- + + if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then + --print('object found in alive_units') + val['objectData'] = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) + local pos = Object.getPosition(val.object) + if pos then + val['objectPos'] = pos.p + end + val['objectType'] = mist.DBs.aliveUnits[val.object.id_].category + --[[if mist.DBs.activeHumans[Unit.getName(val.object)] then + --trigger.action.outText('remove via death: ' .. Unit.getName(val.object),20) + mist.DBs.activeHumans[Unit.getName(val.object)] = nil + end]] + elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units + --print('object found in old_alive_units') + val['objectData'] = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) + local pos = Object.getPosition(val.object) + if pos then + val['objectPos'] = pos.p + end + val['objectType'] = mist.DBs.removedAliveUnits[val.object.id_].category + + else --attempt to determine if static object... + --print('object not found in alive units or old alive units') + local pos = Object.getPosition(val.object) + if pos then + local static_found = false + for ind, static in pairs(mist.DBs.unitsByCat['static']) do + if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... + --print('correlated dead static object to position') + val['objectData'] = static + val['objectPos'] = pos.p + val['objectType'] = 'static' + static_found = true + break + end + end + if not static_found then + val['objectPos'] = pos.p + val['objectType'] = 'building' + end + else + val['objectType'] = 'unknown' + end + end + mist.DBs.deadObjects[id] = val - end - end - end + end + end + end - - mist.addEventHandler(addDeadObject) - - --[[ - local function addClientsToActive(event) - if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT or event.id == world.event.S_EVENT_BIRTH then - env.info(mist.utils.tableShow(event)) - if Unit.getPlayerName(event.initiator) then - env.info(Unit.getPlayerName(event.initiator)) - local newU = mist.utils.deepCopy(mist.DBs.unitsByName[Unit.getName(event.initiator)]) - newU.playerName = Unit.getPlayerName(event.initiator) - mist.DBs.activeHumans[Unit.getName(event.initiator)] = newU - --trigger.action.outText('added: ' .. Unit.getName(event.initiator), 20) - end - elseif event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and event.initiator then - if mist.DBs.activeHumans[Unit.getName(event.initiator)] then - mist.DBs.activeHumans[Unit.getName(event.initiator)] = nil - -- trigger.action.outText('removed via control: ' .. Unit.getName(event.initiator), 20) - end - end - end - - mist.addEventHandler(addClientsToActive)]] + + mist.addEventHandler(addDeadObject) + + --[[ + local function addClientsToActive(event) + if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT or event.id == world.event.S_EVENT_BIRTH then + env.info(mist.utils.tableShow(event)) + if Unit.getPlayerName(event.initiator) then + env.info(Unit.getPlayerName(event.initiator)) + local newU = mist.utils.deepCopy(mist.DBs.unitsByName[Unit.getName(event.initiator)]) + newU.playerName = Unit.getPlayerName(event.initiator) + mist.DBs.activeHumans[Unit.getName(event.initiator)] = newU + --trigger.action.outText('added: ' .. Unit.getName(event.initiator), 20) + end + elseif event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and event.initiator then + if mist.DBs.activeHumans[Unit.getName(event.initiator)] then + mist.DBs.activeHumans[Unit.getName(event.initiator)] = nil + -- trigger.action.outText('removed via control: ' .. Unit.getName(event.initiator), 20) + end + end + end + + mist.addEventHandler(addClientsToActive)]] end @@ -2315,341 +2371,341 @@ Country names to be used in [c] and [-c] short-cuts: "Italy" ]] - --Assumption: will be passed a table of strings, sequential - local units_by_name = {} + --Assumption: will be passed a table of strings, sequential + local units_by_name = {} - local l_munits = mist.DBs.units --local reference for faster execution - for i = 1, #tbl do - local unit = tbl[i] - if unit:sub(1,4) == '[-u]' then --subtract a unit - if units_by_name[unit:sub(5)] then -- 5 to end - units_by_name[unit:sub(5)] = nil --remove - end - elseif unit:sub(1,3) == '[g]' then -- add a group - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(4) then -- index 4 to end - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - elseif unit:sub(1,4) == '[-g]' then -- subtract a group - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(5) then -- index 5 to end - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - elseif unit:sub(1,3) == '[c]' then -- add a country - local category = '' - local country_start = 4 - if unit:sub(4,15) == '[helicopter]' then - category = 'helicopter' - country_start = 16 - elseif unit:sub(4,10) == '[plane]' then - category = 'plane' - country_start = 11 - elseif unit:sub(4,9) == '[ship]' then - category = 'ship' - country_start = 10 - elseif unit:sub(4,12) == '[vehicle]' then - category = 'vehicle' - country_start = 13 - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - if country == string.lower(unit:sub(country_start)) then -- match - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,4) == '[-c]' then -- subtract a country - local category = '' - local country_start = 5 - if unit:sub(5,16) == '[helicopter]' then - category = 'helicopter' - country_start = 17 - elseif unit:sub(5,11) == '[plane]' then - category = 'plane' - country_start = 12 - elseif unit:sub(5,10) == '[ship]' then - category = 'ship' - country_start = 11 - elseif unit:sub(5,13) == '[vehicle]' then - category = 'vehicle' - country_start = 14 - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - if country == string.lower(unit:sub(country_start)) then -- match - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[blue]' then -- add blue coalition - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'blue' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,7) == '[-blue]' then -- subtract blue coalition - local category = '' - if unit:sub(8) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(8) == '[plane]' then - category = 'plane' - elseif unit:sub(8) == '[ship]' then - category = 'ship' - elseif unit:sub(8) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'blue' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,5) == '[red]' then -- add red coalition - local category = '' - if unit:sub(6) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(6) == '[plane]' then - category = 'plane' - elseif unit:sub(6) == '[ship]' then - category = 'ship' - elseif unit:sub(6) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'red' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[-red]' then -- subtract red coalition - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'red' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,5) == '[all]' then -- add all of a certain category (or all categories) - local category = '' - if unit:sub(6) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(6) == '[plane]' then - category = 'plane' - elseif unit:sub(6) == '[ship]' then - category = 'ship' - elseif unit:sub(6) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[-all]' then -- subtract all of a certain category (or all categories) - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - else -- just a regular unit - units_by_name[unit] = true --add - end - end - - local units_tbl = {} -- indexed sequentially - for unit_name, val in pairs(units_by_name) do - if val then - units_tbl[#units_tbl + 1] = unit_name -- add all the units to the table - end - end - - - units_tbl['processed'] = timer.getTime() --add the processed flag - return units_tbl + local l_munits = mist.DBs.units --local reference for faster execution + for i = 1, #tbl do + local unit = tbl[i] + if unit:sub(1,4) == '[-u]' then --subtract a unit + if units_by_name[unit:sub(5)] then -- 5 to end + units_by_name[unit:sub(5)] = nil --remove + end + elseif unit:sub(1,3) == '[g]' then -- add a group + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(4) then -- index 4 to end + for unit_ind, unit in pairs(group_tbl.units) do + units_by_name[unit.unitName] = true --add + end + end + end + end + end + end + end + elseif unit:sub(1,4) == '[-g]' then -- subtract a group + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(5) then -- index 5 to end + for unit_ind, unit in pairs(group_tbl.units) do + if units_by_name[unit.unitName] then + units_by_name[unit.unitName] = nil --remove + end + end + end + end + end + end + end + end + elseif unit:sub(1,3) == '[c]' then -- add a country + local category = '' + local country_start = 4 + if unit:sub(4,15) == '[helicopter]' then + category = 'helicopter' + country_start = 16 + elseif unit:sub(4,10) == '[plane]' then + category = 'plane' + country_start = 11 + elseif unit:sub(4,9) == '[ship]' then + category = 'ship' + country_start = 10 + elseif unit:sub(4,12) == '[vehicle]' then + category = 'vehicle' + country_start = 13 + end + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + if country == string.lower(unit:sub(country_start)) then -- match + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + units_by_name[unit.unitName] = true --add + end + end + end + end + end + end + end + end + elseif unit:sub(1,4) == '[-c]' then -- subtract a country + local category = '' + local country_start = 5 + if unit:sub(5,16) == '[helicopter]' then + category = 'helicopter' + country_start = 17 + elseif unit:sub(5,11) == '[plane]' then + category = 'plane' + country_start = 12 + elseif unit:sub(5,10) == '[ship]' then + category = 'ship' + country_start = 11 + elseif unit:sub(5,13) == '[vehicle]' then + category = 'vehicle' + country_start = 14 + end + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + if country == string.lower(unit:sub(country_start)) then -- match + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + if units_by_name[unit.unitName] then + units_by_name[unit.unitName] = nil --remove + end + end + end + end + end + end + end + end + end + elseif unit:sub(1,6) == '[blue]' then -- add blue coalition + local category = '' + if unit:sub(7) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(7) == '[plane]' then + category = 'plane' + elseif unit:sub(7) == '[ship]' then + category = 'ship' + elseif unit:sub(7) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + if coa == 'blue' then + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + units_by_name[unit.unitName] = true --add + end + end + end + end + end + end + end + end + elseif unit:sub(1,7) == '[-blue]' then -- subtract blue coalition + local category = '' + if unit:sub(8) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(8) == '[plane]' then + category = 'plane' + elseif unit:sub(8) == '[ship]' then + category = 'ship' + elseif unit:sub(8) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + if coa == 'blue' then + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + if units_by_name[unit.unitName] then + units_by_name[unit.unitName] = nil --remove + end + end + end + end + end + end + end + end + end + elseif unit:sub(1,5) == '[red]' then -- add red coalition + local category = '' + if unit:sub(6) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(6) == '[plane]' then + category = 'plane' + elseif unit:sub(6) == '[ship]' then + category = 'ship' + elseif unit:sub(6) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + if coa == 'red' then + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + units_by_name[unit.unitName] = true --add + end + end + end + end + end + end + end + end + elseif unit:sub(1,6) == '[-red]' then -- subtract red coalition + local category = '' + if unit:sub(7) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(7) == '[plane]' then + category = 'plane' + elseif unit:sub(7) == '[ship]' then + category = 'ship' + elseif unit:sub(7) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + if coa == 'red' then + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + if units_by_name[unit.unitName] then + units_by_name[unit.unitName] = nil --remove + end + end + end + end + end + end + end + end + end + elseif unit:sub(1,5) == '[all]' then -- add all of a certain category (or all categories) + local category = '' + if unit:sub(6) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(6) == '[plane]' then + category = 'plane' + elseif unit:sub(6) == '[ship]' then + category = 'ship' + elseif unit:sub(6) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + units_by_name[unit.unitName] = true --add + end + end + end + end + end + end + end + elseif unit:sub(1,6) == '[-all]' then -- subtract all of a certain category (or all categories) + local category = '' + if unit:sub(7) == '[helicopter]' then + category = 'helicopter' + elseif unit:sub(7) == '[plane]' then + category = 'plane' + elseif unit:sub(7) == '[ship]' then + category = 'ship' + elseif unit:sub(7) == '[vehicle]' then + category = 'vehicle' + end + for coa, coa_tbl in pairs(l_munits) do + for country, country_table in pairs(coa_tbl) do + for unit_type, unit_type_tbl in pairs(country_table) do + if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) then + for group_ind, group_tbl in pairs(unit_type_tbl) do + if type(group_tbl) == 'table' then + for unit_ind, unit in pairs(group_tbl.units) do + if units_by_name[unit.unitName] then + units_by_name[unit.unitName] = nil --remove + end + end + end + end + end + end + end + end + else -- just a regular unit + units_by_name[unit] = true --add + end + end + + local units_tbl = {} -- indexed sequentially + for unit_name, val in pairs(units_by_name) do + if val then + units_tbl[#units_tbl + 1] = unit_name -- add all the units to the table + end + end + + + units_tbl['processed'] = timer.getTime() --add the processed flag + return units_tbl end mist.getDeadMapObjsInZones = function(zone_names) -- zone_names: table of zone names -- returns: table of dead map objects (indexed numerically) - local map_objs = {} - local zones = {} - for i = 1, #zone_names do - if mist.DBs.zonesByName[zone_names[i]] then - zones[#zones + 1] = mist.DBs.zonesByName[zone_names[i]] - end - end - for obj_id, obj in pairs(mist.DBs.deadObjects) do - if obj.objectType and obj.objectType == 'building' then --dead map object - for i = 1, #zones do - if ((zones[i].point.x - obj.objectPos.x)^2 + (zones[i].point.z - obj.objectPos.z)^2)^0.5 <= zones[i].radius then - map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) - end - end - end - end - return map_objs + local map_objs = {} + local zones = {} + for i = 1, #zone_names do + if mist.DBs.zonesByName[zone_names[i]] then + zones[#zones + 1] = mist.DBs.zonesByName[zone_names[i]] + end + end + for obj_id, obj in pairs(mist.DBs.deadObjects) do + if obj.objectType and obj.objectType == 'building' then --dead map object + for i = 1, #zones do + if ((zones[i].point.x - obj.objectPos.x)^2 + (zones[i].point.z - obj.objectPos.z)^2)^0.5 <= zones[i].radius then + map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) + end + end + end + end + return map_objs end mist.getDeadMapObjsInPolygonZone = function(zone) -- zone_names: table of zone names -- returns: table of dead map objects (indexed numerically) - local map_objs = {} - for obj_id, obj in pairs(mist.DBs.deadObjects) do - if obj.objectType and obj.objectType == 'building' then --dead map object - if mist.pointInPolygon(obj.objectPos, zone) then - map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) - end - end - end - return map_objs + local map_objs = {} + for obj_id, obj in pairs(mist.DBs.deadObjects) do + if obj.objectType and obj.objectType == 'building' then --dead map object + if mist.pointInPolygon(obj.objectPos, zone) then + map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) + end + end + end + return map_objs end mist.flagFunc = {} @@ -2666,37 +2722,37 @@ initial_number ]] -- type_tbl - local type_tbl = { - [{'zones', 'zone'}] = {'table', 'string'}, - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_zones', type_tbl, vars) - assert(err, errmsg) - local zones = vars.zones or vars.zone - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local req_num = vars.req_num or vars.reqnum or 1 - local initial_number = vars.initial_number - - if type(zones) == 'string' then - zones = {zones} - end - - if not initial_number then - initial_number = #mist.getDeadMapObjsInZones(zones) - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (#mist.getDeadMapObjsInZones(zones) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - return - else - mist.scheduleFunction(mist.flagFunc.mapobjs_dead_zones, {{zones = zones, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) - end - end + local type_tbl = { + [{'zones', 'zone'}] = {'table', 'string'}, + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_zones', type_tbl, vars) + assert(err, errmsg) + local zones = vars.zones or vars.zone + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local req_num = vars.req_num or vars.reqnum or 1 + local initial_number = vars.initial_number + + if type(zones) == 'string' then + zones = {zones} + end + + if not initial_number then + initial_number = #mist.getDeadMapObjsInZones(zones) + end + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if (#mist.getDeadMapObjsInZones(zones) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + return + else + mist.scheduleFunction(mist.flagFunc.mapobjs_dead_zones, {{zones = zones, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) + end + end end @@ -2713,90 +2769,90 @@ initial_number ]] -- type_tbl - local type_tbl = { - [{'zone', 'polyzone'}] = 'table', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_polygon', type_tbl, vars) - assert(err, errmsg) - local zone = vars.zone or vars.polyzone - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local req_num = vars.req_num or vars.reqnum or 1 - local initial_number = vars.initial_number - - if not initial_number then - initial_number = #mist.getDeadMapObjsInPolygonZone(zone) - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (#mist.getDeadMapObjsInPolygonZone(zone) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - return - else - mist.scheduleFunction(mist.flagFunc.mapobjs_dead_polygon, {{zone = zone, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) - end - end + local type_tbl = { + [{'zone', 'polyzone'}] = 'table', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_polygon', type_tbl, vars) + assert(err, errmsg) + local zone = vars.zone or vars.polyzone + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local req_num = vars.req_num or vars.reqnum or 1 + local initial_number = vars.initial_number + + if not initial_number then + initial_number = #mist.getDeadMapObjsInPolygonZone(zone) + end + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if (#mist.getDeadMapObjsInPolygonZone(zone) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + return + else + mist.scheduleFunction(mist.flagFunc.mapobjs_dead_polygon, {{zone = zone, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) + end + end end function mist.pointInPolygon(point, poly, maxalt) --raycasting point in polygon. Code from http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm - --[[local type_tbl = { - point = {'table'}, - poly = {'table'}, - maxalt = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.pointInPolygon', type_tbl, {point, poly, maxalt}) - assert(err, errmsg) - ]] - point = mist.utils.makeVec3(point) - local px = point.x - local pz = point.z - local cn = 0 - local newpoly = mist.utils.deepCopy(poly) - - if not maxalt or (point.y <= maxalt) then - local polysize = #newpoly - newpoly[#newpoly + 1] = newpoly[1] - - newpoly[1] = mist.utils.makeVec3(newpoly[1]) - - for k = 1, polysize do - newpoly[k+1] = mist.utils.makeVec3(newpoly[k+1]) - if ((newpoly[k].z <= pz) and (newpoly[k+1].z > pz)) or ((newpoly[k].z > pz) and (newpoly[k+1].z <= pz)) then - local vt = (pz - newpoly[k].z) / (newpoly[k+1].z - newpoly[k].z) - if (px < newpoly[k].x + vt*(newpoly[k+1].x - newpoly[k].x)) then - cn = cn + 1 - end - end - end - - return cn%2 == 1 - else - return false - end + --[[local type_tbl = { + point = {'table'}, + poly = {'table'}, + maxalt = {'number', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.pointInPolygon', type_tbl, {point, poly, maxalt}) + assert(err, errmsg) + ]] + point = mist.utils.makeVec3(point) + local px = point.x + local pz = point.z + local cn = 0 + local newpoly = mist.utils.deepCopy(poly) + + if not maxalt or (point.y <= maxalt) then + local polysize = #newpoly + newpoly[#newpoly + 1] = newpoly[1] + + newpoly[1] = mist.utils.makeVec3(newpoly[1]) + + for k = 1, polysize do + newpoly[k+1] = mist.utils.makeVec3(newpoly[k+1]) + if ((newpoly[k].z <= pz) and (newpoly[k+1].z > pz)) or ((newpoly[k].z > pz) and (newpoly[k+1].z <= pz)) then + local vt = (pz - newpoly[k].z) / (newpoly[k+1].z - newpoly[k].z) + if (px < newpoly[k].x + vt*(newpoly[k+1].x - newpoly[k].x)) then + cn = cn + 1 + end + end + end + + return cn%2 == 1 + else + return false + end end mist.getUnitsInPolygon = function (unit_names, polyZone, max_alt) - local units = {} - - for i = 1, #unit_names do - units[#units + 1] = Unit.getByName(unitNames[i]) - end - - local inZoneUnits = {} - for i =1, #units do - if units[i]:isActive() and mist.pointInPolygon(units[i]:getPosition().p, polyZone, max_alt) then - inZoneUnits[inZoneUnits + 1] = units[i] - end - end - - return inZoneUnits + local units = {} + + for i = 1, #unit_names do + units[#units + 1] = Unit.getByName(unitNames[i]) + end + + local inZoneUnits = {} + for i =1, #units do + if units[i]:isActive() and mist.pointInPolygon(units[i]:getPosition().p, polyZone, max_alt) then + inZoneUnits[inZoneUnits + 1] = units[i] + end + end + + return inZoneUnits end function mist.flagFunc.units_in_polygon(vars) @@ -2812,360 +2868,360 @@ toggle = boolean or nil unitTableDef = table or nil ]] -- type_tbl - local type_tbl = { - [{'units', 'unit'}] = 'table', - [{'zone', 'polyzone'}] = 'table', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'maxalt', 'alt'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_polygon', type_tbl, vars) - assert(err, errmsg) - local units = vars.units or vars.unit - local zone = vars.zone or vars.polyzone - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local maxalt = vars.maxalt or vars.alt - local req_num = vars.req_num or vars.reqnum or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - units = mist.makeUnitTable(unitTableDef) - end + local type_tbl = { + [{'units', 'unit'}] = 'table', + [{'zone', 'polyzone'}] = 'table', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'maxalt', 'alt'}] = {'number', 'nil'}, + interval = {'number', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + unitTableDef = {'table', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_polygon', type_tbl, vars) + assert(err, errmsg) + local units = vars.units or vars.unit + local zone = vars.zone or vars.polyzone + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local maxalt = vars.maxalt or vars.alt + local req_num = vars.req_num or vars.reqnum or 1 + local toggle = vars.toggle or nil + local unitTableDef = vars.unitTableDef + + if not units.processed then + unitTableDef = mist.utils.deepCopy(units) + end + + if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts + units = mist.makeUnitTable(unitTableDef) + end - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then - local num_in_zone = 0 - for i = 1, #units do - local unit = Unit.getByName(units[i]) - if unit then - local pos = unit:getPosition().p - if mist.pointInPolygon(pos, zone, maxalt) then - num_in_zone = num_in_zone + 1 - if num_in_zone >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - break - end - end - end - end - if toggle and (num_in_zone < req_num) and trigger.misc.getUserFlag(flag) > 0 then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then - mist.scheduleFunction(mist.flagFunc.units_in_polygon, {{units = units, zone = zone, flag = flag, stopflag = stopflag, interval = interval, req_num = req_num, maxalt = maxalt, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) - end - end - + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then + local num_in_zone = 0 + for i = 1, #units do + local unit = Unit.getByName(units[i]) + if unit then + local pos = unit:getPosition().p + if mist.pointInPolygon(pos, zone, maxalt) then + num_in_zone = num_in_zone + 1 + if num_in_zone >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + break + end + end + end + end + if toggle and (num_in_zone < req_num) and trigger.misc.getUserFlag(flag) > 0 then + trigger.action.setUserFlag(flag, false) + end + -- do another check in case stopflag was set true by this function + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then + mist.scheduleFunction(mist.flagFunc.units_in_polygon, {{units = units, zone = zone, flag = flag, stopflag = stopflag, interval = interval, req_num = req_num, maxalt = maxalt, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) + end + end + end function mist.getUnitsInZones(unit_names, zone_names, zone_type) - - zone_type = zone_type or 'cylinder' - if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then - zone_type = 'cylinder' - end - if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then - zone_type = 'sphere' - end - - assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) + + zone_type = zone_type or 'cylinder' + if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then + zone_type = 'cylinder' + end + if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then + zone_type = 'sphere' + end + + assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) - local units = {} - local zones = {} + local units = {} + local zones = {} - for k = 1, #unit_names do - local unit = Unit.getByName(unit_names[k]) - if unit then - units[#units + 1] = unit - end - end - - - for k = 1, #zone_names do - local zone = trigger.misc.getZone(zone_names[k]) - if zone then - zones[#zones + 1] = {radius = zone.radius, x = zone.point.x, y = zone.point.y, z = zone.point.z} - end - end - - local in_zone_units = {} - - for units_ind = 1, #units do - for zones_ind = 1, #zones do - if zone_type == 'sphere' then --add land height value for sphere zone type - local alt = land.getHeight({x = zones[zones_ind].x, y = zones[zones_ind].z}) - if alt then - zones[zones_ind].y = alt - end - end - local unit_pos = units[units_ind]:getPosition().p - if unit_pos and units[units_ind]:isActive() == true then - if zone_type == 'cylinder' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then - in_zone_units[#in_zone_units + 1] = units[units_ind] - break - elseif zone_type == 'sphere' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.y - zones[zones_ind].y)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then - in_zone_units[#in_zone_units + 1] = units[units_ind] - break - end - end - end - end - return in_zone_units + for k = 1, #unit_names do + local unit = Unit.getByName(unit_names[k]) + if unit then + units[#units + 1] = unit + end + end + + + for k = 1, #zone_names do + local zone = trigger.misc.getZone(zone_names[k]) + if zone then + zones[#zones + 1] = {radius = zone.radius, x = zone.point.x, y = zone.point.y, z = zone.point.z} + end + end + + local in_zone_units = {} + + for units_ind = 1, #units do + for zones_ind = 1, #zones do + if zone_type == 'sphere' then --add land height value for sphere zone type + local alt = land.getHeight({x = zones[zones_ind].x, y = zones[zones_ind].z}) + if alt then + zones[zones_ind].y = alt + end + end + local unit_pos = units[units_ind]:getPosition().p + if unit_pos and units[units_ind]:isActive() == true then + if zone_type == 'cylinder' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then + in_zone_units[#in_zone_units + 1] = units[units_ind] + break + elseif zone_type == 'sphere' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.y - zones[zones_ind].y)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then + in_zone_units[#in_zone_units + 1] = units[units_ind] + break + end + end + end + end + return in_zone_units end function mist.flagFunc.units_in_zones(vars) - --[[vars needs to be: - units = table, - zones = table, - flag = number, - stopflag = number or nil, - zone_type = string or nil, - req_num = number or nil, - interval = number or nil - toggle = boolean or nil - ]] - -- type_tbl - local type_tbl = { - units = 'table', - zones = 'table', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'zone_type', 'zonetype'}] = {'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_zones', type_tbl, vars) - assert(err, errmsg) - local units = vars.units - local zones = vars.zones - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local zone_type = vars.zone_type or vars.zonetype or 'cylinder' - local req_num = vars.req_num or vars.reqnum or 1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - units = mist.makeUnitTable(unitTableDef) - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local in_zone_units = mist.getUnitsInZones(units, zones, zone_type) - - if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #in_zone_units < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_in_zones, {{units = units, zones = zones, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) - end - end - + --[[vars needs to be: + units = table, + zones = table, + flag = number, + stopflag = number or nil, + zone_type = string or nil, + req_num = number or nil, + interval = number or nil + toggle = boolean or nil + ]] + -- type_tbl + local type_tbl = { + units = 'table', + zones = 'table', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'zone_type', 'zonetype'}] = {'string', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + unitTableDef = {'table', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_zones', type_tbl, vars) + assert(err, errmsg) + local units = vars.units + local zones = vars.zones + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local zone_type = vars.zone_type or vars.zonetype or 'cylinder' + local req_num = vars.req_num or vars.reqnum or 1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + local unitTableDef = vars.unitTableDef + + if not units.processed then + unitTableDef = mist.utils.deepCopy(units) + end + + if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts + units = mist.makeUnitTable(unitTableDef) + end + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + + local in_zone_units = mist.getUnitsInZones(units, zones, zone_type) + + if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + elseif #in_zone_units < req_num and toggle then + trigger.action.setUserFlag(flag, false) + end + -- do another check in case stopflag was set true by this function + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.units_in_zones, {{units = units, zones = zones, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) + end + end + end function mist.getUnitsInMovingZones(unit_names, zone_unit_names, radius, zone_type) - - zone_type = zone_type or 'cylinder' - if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then - zone_type = 'cylinder' - end - if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then - zone_type = 'sphere' - end - - assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) + + zone_type = zone_type or 'cylinder' + if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then + zone_type = 'cylinder' + end + if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then + zone_type = 'sphere' + end + + assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) - local units = {} - local zone_units = {} + local units = {} + local zone_units = {} - for k = 1, #unit_names do - local unit = Unit.getByName(unit_names[k]) - if unit then - units[#units + 1] = unit - end - end - - for k = 1, #zone_unit_names do - local unit = Unit.getByName(zone_unit_names[k]) - if unit then - zone_units[#zone_units + 1] = unit - end - end + for k = 1, #unit_names do + local unit = Unit.getByName(unit_names[k]) + if unit then + units[#units + 1] = unit + end + end + + for k = 1, #zone_unit_names do + local unit = Unit.getByName(zone_unit_names[k]) + if unit then + zone_units[#zone_units + 1] = unit + end + end - local in_zone_units = {} - - for units_ind = 1, #units do - for zone_units_ind = 1, #zone_units do - local unit_pos = units[units_ind]:getPosition().p - local zone_unit_pos = zone_units[zone_units_ind]:getPosition().p - if unit_pos and zone_unit_pos and units[units_ind]:isActive() == true then - if zone_type == 'cylinder' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then - in_zone_units[#in_zone_units + 1] = units[units_ind] - break - elseif zone_type == 'sphere' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.y - zone_unit_pos.y)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then - in_zone_units[#in_zone_units + 1] = units[units_ind] - break - end - end - end - end - return in_zone_units + local in_zone_units = {} + + for units_ind = 1, #units do + for zone_units_ind = 1, #zone_units do + local unit_pos = units[units_ind]:getPosition().p + local zone_unit_pos = zone_units[zone_units_ind]:getPosition().p + if unit_pos and zone_unit_pos and units[units_ind]:isActive() == true then + if zone_type == 'cylinder' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then + in_zone_units[#in_zone_units + 1] = units[units_ind] + break + elseif zone_type == 'sphere' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.y - zone_unit_pos.y)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then + in_zone_units[#in_zone_units + 1] = units[units_ind] + break + end + end + end + end + return in_zone_units end function mist.flagFunc.units_in_moving_zones(vars) - --[[vars needs to be: - units = table, - zone_units = table, - radius = number, - flag = number, - stopflag = number or nil, - zone_type = string or nil, - req_num = number or nil, - interval = number or nil - toggle = boolean or nil - ]] - -- type_tbl - local type_tbl = { - units = 'table', - [{'zone_units', 'zoneunits'}] = 'table', - radius = 'number', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'zone_type', 'zonetype'}] = {'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - zUnitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_moving_zones', type_tbl, vars) - assert(err, errmsg) - local units = vars.units - local zone_units = vars.zone_units or vars.zoneunits - local radius = vars.radius - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local zone_type = vars.zone_type or vars.zonetype or 'cylinder' - local req_num = vars.req_num or vars.reqnum or 1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - local zUnitTableDef = vars.zUnitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if not zone_units.processed then - zUnitTableDef = mist.utils.deepCopy(zone_units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - units = mist.makeUnitTable(unitTableDef) - end - - if (zone_units.processed and zone_units.processed < mist.getLastDBUpdateTime()) or not zone_units.processed then -- run unit table short cuts - zone_units = mist.makeUnitTable(zUnitTableDef) - end + --[[vars needs to be: + units = table, + zone_units = table, + radius = number, + flag = number, + stopflag = number or nil, + zone_type = string or nil, + req_num = number or nil, + interval = number or nil + toggle = boolean or nil + ]] + -- type_tbl + local type_tbl = { + units = 'table', + [{'zone_units', 'zoneunits'}] = 'table', + radius = 'number', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'zone_type', 'zonetype'}] = {'string', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + unitTableDef = {'table', 'nil'}, + zUnitTableDef = {'table', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_moving_zones', type_tbl, vars) + assert(err, errmsg) + local units = vars.units + local zone_units = vars.zone_units or vars.zoneunits + local radius = vars.radius + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local zone_type = vars.zone_type or vars.zonetype or 'cylinder' + local req_num = vars.req_num or vars.reqnum or 1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + local unitTableDef = vars.unitTableDef + local zUnitTableDef = vars.zUnitTableDef + + if not units.processed then + unitTableDef = mist.utils.deepCopy(units) + end + + if not zone_units.processed then + zUnitTableDef = mist.utils.deepCopy(zone_units) + end + + if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts + units = mist.makeUnitTable(unitTableDef) + end + + if (zone_units.processed and zone_units.processed < mist.getLastDBUpdateTime()) or not zone_units.processed then -- run unit table short cuts + zone_units = mist.makeUnitTable(zUnitTableDef) + end - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local in_zone_units = mist.getUnitsInMovingZones(units, zone_units, radius, zone_type) - - if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #in_zone_units < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_in_moving_zones, {{units = units, zone_units = zone_units, radius = radius, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef, zUnitTableDef = zUnitTableDef}}, timer.getTime() + interval) - end - end - + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + + local in_zone_units = mist.getUnitsInMovingZones(units, zone_units, radius, zone_type) + + if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + elseif #in_zone_units < req_num and toggle then + trigger.action.setUserFlag(flag, false) + end + -- do another check in case stopflag was set true by this function + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.units_in_moving_zones, {{units = units, zone_units = zone_units, radius = radius, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef, zUnitTableDef = zUnitTableDef}}, timer.getTime() + interval) + end + end + end mist.getUnitsLOS = function(unitset1, altoffset1, unitset2, altoffset2, radius) - radius = radius or math.huge - - local unit_info1 = {} - local unit_info2 = {} - - -- get the positions all in one step, saves execution time. - for unitset1_ind = 1, #unitset1 do - local unit1 = Unit.getByName(unitset1[unitset1_ind]) - if unit1 and unit1:isActive() == true then - unit_info1[#unit_info1 + 1] = {} - unit_info1[#unit_info1]["unit"] = unit1 - unit_info1[#unit_info1]["pos"] = unit1:getPosition().p - end - end - - for unitset2_ind = 1, #unitset2 do - local unit2 = Unit.getByName(unitset2[unitset2_ind]) - if unit2 and unit2:isActive() == true then - unit_info2[#unit_info2 + 1] = {} - unit_info2[#unit_info2]["unit"] = unit2 - unit_info2[#unit_info2]["pos"] = unit2:getPosition().p - end - end + radius = radius or math.huge + + local unit_info1 = {} + local unit_info2 = {} + + -- get the positions all in one step, saves execution time. + for unitset1_ind = 1, #unitset1 do + local unit1 = Unit.getByName(unitset1[unitset1_ind]) + if unit1 and unit1:isActive() == true then + unit_info1[#unit_info1 + 1] = {} + unit_info1[#unit_info1]["unit"] = unit1 + unit_info1[#unit_info1]["pos"] = unit1:getPosition().p + end + end + + for unitset2_ind = 1, #unitset2 do + local unit2 = Unit.getByName(unitset2[unitset2_ind]) + if unit2 and unit2:isActive() == true then + unit_info2[#unit_info2 + 1] = {} + unit_info2[#unit_info2]["unit"] = unit2 + unit_info2[#unit_info2]["pos"] = unit2:getPosition().p + end + end - local LOS_data = {} - -- now compute los - for unit1_ind = 1, #unit_info1 do - local unit_added = false - for unit2_ind = 1, #unit_info2 do - if radius == math.huge or (mist.vec.mag(mist.vec.sub(unit_info1[unit1_ind].pos, unit_info2[unit2_ind].pos)) < radius) then -- inside radius - local point1 = { x = unit_info1[unit1_ind].pos.x, y = unit_info1[unit1_ind].pos.y + altoffset1, z = unit_info1[unit1_ind].pos.z} - local point2 = { x = unit_info2[unit2_ind].pos.x, y = unit_info2[unit2_ind].pos.y + altoffset2, z = unit_info2[unit2_ind].pos.z} - if land.isVisible(point1, point2) then - if unit_added == false then - unit_added = true - LOS_data[#LOS_data + 1] = {} - LOS_data[#LOS_data]['unit'] = unit_info1[unit1_ind].unit - LOS_data[#LOS_data]['vis'] = {} - LOS_data[#LOS_data]['vis'][#LOS_data[#LOS_data]['vis'] + 1] = unit_info2[unit2_ind].unit - else - LOS_data[#LOS_data]['vis'][#LOS_data[#LOS_data]['vis'] + 1] = unit_info2[unit2_ind].unit - end - end - end - end - end - - return LOS_data + local LOS_data = {} + -- now compute los + for unit1_ind = 1, #unit_info1 do + local unit_added = false + for unit2_ind = 1, #unit_info2 do + if radius == math.huge or (mist.vec.mag(mist.vec.sub(unit_info1[unit1_ind].pos, unit_info2[unit2_ind].pos)) < radius) then -- inside radius + local point1 = { x = unit_info1[unit1_ind].pos.x, y = unit_info1[unit1_ind].pos.y + altoffset1, z = unit_info1[unit1_ind].pos.z} + local point2 = { x = unit_info2[unit2_ind].pos.x, y = unit_info2[unit2_ind].pos.y + altoffset2, z = unit_info2[unit2_ind].pos.z} + if land.isVisible(point1, point2) then + if unit_added == false then + unit_added = true + LOS_data[#LOS_data + 1] = {} + LOS_data[#LOS_data]['unit'] = unit_info1[unit1_ind].unit + LOS_data[#LOS_data]['vis'] = {} + LOS_data[#LOS_data]['vis'][#LOS_data[#LOS_data]['vis'] + 1] = unit_info2[unit2_ind].unit + else + LOS_data[#LOS_data]['vis'][#LOS_data[#LOS_data]['vis'] + 1] = unit_info2[unit2_ind].unit + end + end + end + end + end + + return LOS_data end mist.flagFunc.units_LOS = function(vars) @@ -3182,67 +3238,67 @@ req_num = number or nil toggle = boolean or nil ]] -- type_tbl - local type_tbl = { - [{'unitset1', 'units1'}] = 'table', - [{'altoffset1', 'alt1'}] = 'number', - [{'unitset2', 'units2'}] = 'table', - [{'altoffset2', 'alt2'}] = 'number', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - radius = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef1 = {'table', 'nil'}, - unitTableDef2 = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_LOS', type_tbl, vars) - assert(err, errmsg) - local unitset1 = vars.unitset1 or vars.units1 - local altoffset1 = vars.altoffset1 or vars.alt1 - local unitset2 = vars.unitset2 or vars.units2 - local altoffset2 = vars.altoffset2 or vars.alt2 - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local radius = vars.radius or math.huge - local req_num = vars.req_num or vars.reqnum or 1 - local toggle = vars.toggle or nil - local unitTableDef1 = vars.unitTableDef1 - local unitTableDef2 = vars.unitTableDef2 - - if not unitset1.processed then - unitTableDef1 = mist.utils.deepCopy(unitset1) - end - - if not unitset2.processed then - unitTableDef2 = mist.utils.deepCopy(unitset2) - end - - if (unitset1.processed and unitset1.processed < mist.getLastDBUpdateTime()) or not unitset1.processed then -- run unit table short cuts - unitset1 = mist.makeUnitTable(unitTableDef1) - end - - if (unitset2.processed and unitset2.processed < mist.getLastDBUpdateTime()) or not unitset2.processed then -- run unit table short cuts - unitset2 = mist.makeUnitTable(unitTableDef2) - end - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local unitLOSdata = mist.getUnitsLOS(unitset1, altoffset1, unitset2, altoffset2, radius) - - if #unitLOSdata >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #unitLOSdata < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_LOS, {{unitset1 = unitset1, altoffset1 = altoffset1, unitset2 = unitset2, altoffset2 = altoffset2, flag = flag, stopflag = stopflag, radius = radius, req_num = req_num, interval = interval, toggle = toggle, unitTableDef1 = unitTableDef1, unitTableDef2 = unitTableDef2}}, timer.getTime() + interval) - end - end + local type_tbl = { + [{'unitset1', 'units1'}] = 'table', + [{'altoffset1', 'alt1'}] = 'number', + [{'unitset2', 'units2'}] = 'table', + [{'altoffset2', 'alt2'}] = 'number', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + [{'req_num', 'reqnum'}] = {'number', 'nil'}, + interval = {'number', 'nil'}, + radius = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + unitTableDef1 = {'table', 'nil'}, + unitTableDef2 = {'table', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_LOS', type_tbl, vars) + assert(err, errmsg) + local unitset1 = vars.unitset1 or vars.units1 + local altoffset1 = vars.altoffset1 or vars.alt1 + local unitset2 = vars.unitset2 or vars.units2 + local altoffset2 = vars.altoffset2 or vars.alt2 + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local radius = vars.radius or math.huge + local req_num = vars.req_num or vars.reqnum or 1 + local toggle = vars.toggle or nil + local unitTableDef1 = vars.unitTableDef1 + local unitTableDef2 = vars.unitTableDef2 + + if not unitset1.processed then + unitTableDef1 = mist.utils.deepCopy(unitset1) + end + + if not unitset2.processed then + unitTableDef2 = mist.utils.deepCopy(unitset2) + end + + if (unitset1.processed and unitset1.processed < mist.getLastDBUpdateTime()) or not unitset1.processed then -- run unit table short cuts + unitset1 = mist.makeUnitTable(unitTableDef1) + end + + if (unitset2.processed and unitset2.processed < mist.getLastDBUpdateTime()) or not unitset2.processed then -- run unit table short cuts + unitset2 = mist.makeUnitTable(unitTableDef2) + end + + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + + local unitLOSdata = mist.getUnitsLOS(unitset1, altoffset1, unitset2, altoffset2, radius) + + if #unitLOSdata >= req_num and trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + elseif #unitLOSdata < req_num and toggle then + trigger.action.setUserFlag(flag, false) + end + -- do another check in case stopflag was set true by this function + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.units_LOS, {{unitset1 = unitset1, altoffset1 = altoffset1, unitset2 = unitset2, altoffset2 = altoffset2, flag = flag, stopflag = stopflag, radius = radius, req_num = req_num, interval = interval, toggle = toggle, unitTableDef1 = unitTableDef1, unitTableDef2 = unitTableDef2}}, timer.getTime() + interval) + end + end end mist.flagFunc.group_alive = function(vars) @@ -3254,203 +3310,218 @@ interval stopFlag ]] - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true and #Group.getByName(groupName):getUnits() > 0 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) - end + local type_tbl = { + [{'group', 'groupname', 'gp', 'groupName'}] = 'string', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive', type_tbl, vars) + assert(err, errmsg) + + local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true and #Group.getByName(groupName):getUnits() > 0 then + if trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + end + else + if toggle then + trigger.action.setUserFlag(flag, false) + end + end + end + + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.group_alive, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) + end end mist.flagFunc.group_dead = function(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_dead', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (Group.getByName(groupName) and Group.getByName(groupName):isExist() == false) or (Group.getByName(groupName) and #Group.getByName(groupName):getUnits() < 1) or not Group.getByName(groupName) then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_dead, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) - end + local type_tbl = { + [{'group', 'groupname', 'gp', 'groupName'}] = 'string', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_dead', type_tbl, vars) + assert(err, errmsg) + + local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname + local flag = vars.flag + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if (Group.getByName(groupName) and Group.getByName(groupName):isExist() == false) or (Group.getByName(groupName) and #Group.getByName(groupName):getUnits() < 1) or not Group.getByName(groupName) then + if trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + end + else + if toggle then + trigger.action.setUserFlag(flag, false) + end + end + end + + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.group_dead, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) + end end mist.flagFunc.group_alive_less_than = function(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - percent = 'number', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_less_than', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local percent = vars.percent - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() < percent/100 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - else - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive_less_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) - end + local type_tbl = { + [{'group', 'groupname', 'gp', 'groupName'}] = 'string', + percent = 'number', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_less_than', type_tbl, vars) + assert(err, errmsg) + + local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname + local flag = vars.flag + local percent = vars.percent + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then + if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() < percent/100 then + if trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + end + else + if toggle then + trigger.action.setUserFlag(flag, false) + end + end + else + if trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + end + end + end + + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.group_alive_less_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) + end end mist.flagFunc.group_alive_more_than = function(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - percent = 'number', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_more_than', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local percent = vars.percent - local stopflag = vars.stopflag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() > percent/100 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle and trigger.misc.getUserFlag(flag) == 1 then - trigger.action.setUserFlag(flag, false) - end - end - else --- just in case - if toggle and trigger.misc.getUserFlag(flag) == 1 then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive_more_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) - end + local type_tbl = { + [{'group', 'groupname', 'gp', 'groupName'}] = 'string', + percent = 'number', + flag = {'number', 'string'}, + stopflag = {'number', 'string', 'nil'}, + interval = {'number', 'nil'}, + toggle = {'boolean', 'nil'}, + } + + local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_more_than', type_tbl, vars) + assert(err, errmsg) + + local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname + local flag = vars.flag + local percent = vars.percent + local stopflag = vars.stopflag or -1 + local interval = vars.interval or 1 + local toggle = vars.toggle or nil + + + if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then + if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() > percent/100 then + if trigger.misc.getUserFlag(flag) == 0 then + trigger.action.setUserFlag(flag, true) + end + else + if toggle and trigger.misc.getUserFlag(flag) == 1 then + trigger.action.setUserFlag(flag, false) + end + end + else --- just in case + if toggle and trigger.misc.getUserFlag(flag) == 1 then + trigger.action.setUserFlag(flag, false) + end + end + end + + if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then + mist.scheduleFunction(mist.flagFunc.group_alive_more_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) + end end +mist.getAvgPoint = function(points) + local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 + for i = 1, #points do + local nPoint = mist.utils.makeVec3(points[i]) + if nPoint.z then + avgX = avgX + nPoint.x + avgY = avgY + nPoint.y + avgZ = avgZ + nPoint.z + totNum = totNum + 1 + end + end + if totNum ~= 0 then + return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} + end +end --Gets the average position of a group of units (by name) mist.getAvgPos = function(unitNames) - local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 - for i = 1, #unitNames do - local unit - if Unit.getByName(unitNames[i]) then - unit = Unit.getByName(unitNames[i]) - elseif StaticObject.getByName(unitNames[i]) then - unit = StaticObject.getByName(unitNames[i]) - end - if unit then - local pos = unit:getPosition().p - if pos then -- you never know O.o - avgX = avgX + pos.x - avgY = avgY + pos.y - avgZ = avgZ + pos.z - totNum = totNum + 1 - end - end - end - if totNum ~= 0 then - return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} - end + local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 + for i = 1, #unitNames do + local unit + if Unit.getByName(unitNames[i]) then + unit = Unit.getByName(unitNames[i]) + elseif StaticObject.getByName(unitNames[i]) then + unit = StaticObject.getByName(unitNames[i]) + end + if unit then + local pos = unit:getPosition().p + if pos then -- you never know O.o + avgX = avgX + pos.x + avgY = avgY + pos.y + avgZ = avgZ + pos.z + totNum = totNum + 1 + end + end + end + if totNum ~= 0 then + return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} + end end mist.getAvgGroupPos = function(groupName) - if type(groupName) == 'string' and Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - groupName = Group.getByName(groupName) - end - local units = {} - for i = 1, #groupName:getSize() do - table.insert(units, groupName.getUnit(i):getName()) - end - - return mist.getAvgPos(units) + if type(groupName) == 'string' and Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then + groupName = Group.getByName(groupName) + end + local units = {} + for i = 1, #groupName:getSize() do + table.insert(units, groupName.getUnit(i):getName()) + end + + return mist.getAvgPos(units) end @@ -3459,115 +3530,115 @@ end mist.demos = {} mist.demos.printFlightData = function(unit) - if unit:isExist() then - local function printData(unit, prevVel, prevE, prevTime) - local angles = mist.getAttitude(unit) - if angles then - local Heading = angles.Heading - local Pitch = angles.Pitch - local Roll = angles.Roll - local Yaw = angles.Yaw - local AoA = angles.AoA - local ClimbAngle = angles.ClimbAngle - - if not Heading then - Heading = 'NA' - else - Heading = string.format('%12.2f', mist.utils.toDegree(Heading)) - end - - if not Pitch then - Pitch = 'NA' - else - Pitch = string.format('%12.2f', mist.utils.toDegree(Pitch)) - end - - if not Roll then - Roll = 'NA' - else - Roll = string.format('%12.2f', mist.utils.toDegree(Roll)) - end - - local AoAplusYaw = 'NA' - if AoA and Yaw then - AoAplusYaw = string.format('%12.2f', mist.utils.toDegree((AoA^2 + Yaw^2)^0.5)) - end - - if not Yaw then - Yaw = 'NA' - else - Yaw = string.format('%12.2f', mist.utils.toDegree(Yaw)) - end - - if not AoA then - AoA = 'NA' - else - AoA = string.format('%12.2f', mist.utils.toDegree(AoA)) - end - - if not ClimbAngle then - ClimbAngle = 'NA' - else - ClimbAngle = string.format('%12.2f', mist.utils.toDegree(ClimbAngle)) - end - local unitPos = unit:getPosition() - local unitVel = unit:getVelocity() - local curTime = timer.getTime() - local absVel = string.format('%12.2f', mist.vec.mag(unitVel)) - - - local unitAcc = 'NA' - local Gs = 'NA' - local axialGs = 'NA' - local transGs = 'NA' - if prevVel and prevTime then - local xAcc = (unitVel.x - prevVel.x)/(curTime - prevTime) - local yAcc = (unitVel.y - prevVel.y)/(curTime - prevTime) - local zAcc = (unitVel.z - prevVel.z)/(curTime - prevTime) - - unitAcc = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc, z = zAcc})) - Gs = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc + 9.81, z = zAcc})/9.81) - axialGs = string.format('%12.2f', mist.vec.dp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x)/9.81) - transGs = string.format('%12.2f', mist.vec.mag(mist.vec.cp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x))/9.81) - end - - local E = 0.5*mist.vec.mag(unitVel)^2 + 9.81*unitPos.p.y - - local energy = string.format('%12.2e', E) - - local dEdt = 'NA' - if prevE and prevTime then - dEdt = string.format('%12.2e', (E - prevE)/(curTime - prevTime)) - end - - trigger.action.outText(string.format('%-25s', 'Heading: ') .. Heading .. ' degrees\n' .. string.format('%-25s', 'Roll: ') .. Roll .. ' degrees\n' .. string.format('%-25s', 'Pitch: ') .. Pitch - .. ' degrees\n' .. string.format('%-25s', 'Yaw: ') .. Yaw .. ' degrees\n' .. string.format('%-25s', 'AoA: ') .. AoA .. ' degrees\n' .. string.format('%-25s', 'AoA plus Yaw: ') .. AoAplusYaw .. ' degrees\n' .. string.format('%-25s', 'Climb Angle: ') .. - ClimbAngle .. ' degrees\n' .. string.format('%-25s', 'Absolute Velocity: ') .. absVel .. ' m/s\n' .. string.format('%-25s', 'Absolute Acceleration: ') .. unitAcc ..' m/s^2\n' - .. string.format('%-25s', 'Axial G loading: ') .. axialGs .. ' g\n' .. string.format('%-25s', 'Transverse G loading: ') .. transGs .. ' g\n' .. string.format('%-25s', 'Absolute G loading: ') .. Gs .. ' g\n' .. string.format('%-25s', 'Energy: ') .. energy .. ' J/kg\n' .. string.format('%-25s', 'dE/dt: ') .. dEdt .. - ' J/(kg*s)', 1) + if unit:isExist() then + local function printData(unit, prevVel, prevE, prevTime) + local angles = mist.getAttitude(unit) + if angles then + local Heading = angles.Heading + local Pitch = angles.Pitch + local Roll = angles.Roll + local Yaw = angles.Yaw + local AoA = angles.AoA + local ClimbAngle = angles.ClimbAngle + + if not Heading then + Heading = 'NA' + else + Heading = string.format('%12.2f', mist.utils.toDegree(Heading)) + end + + if not Pitch then + Pitch = 'NA' + else + Pitch = string.format('%12.2f', mist.utils.toDegree(Pitch)) + end + + if not Roll then + Roll = 'NA' + else + Roll = string.format('%12.2f', mist.utils.toDegree(Roll)) + end + + local AoAplusYaw = 'NA' + if AoA and Yaw then + AoAplusYaw = string.format('%12.2f', mist.utils.toDegree((AoA^2 + Yaw^2)^0.5)) + end + + if not Yaw then + Yaw = 'NA' + else + Yaw = string.format('%12.2f', mist.utils.toDegree(Yaw)) + end + + if not AoA then + AoA = 'NA' + else + AoA = string.format('%12.2f', mist.utils.toDegree(AoA)) + end + + if not ClimbAngle then + ClimbAngle = 'NA' + else + ClimbAngle = string.format('%12.2f', mist.utils.toDegree(ClimbAngle)) + end + local unitPos = unit:getPosition() + local unitVel = unit:getVelocity() + local curTime = timer.getTime() + local absVel = string.format('%12.2f', mist.vec.mag(unitVel)) + + + local unitAcc = 'NA' + local Gs = 'NA' + local axialGs = 'NA' + local transGs = 'NA' + if prevVel and prevTime then + local xAcc = (unitVel.x - prevVel.x)/(curTime - prevTime) + local yAcc = (unitVel.y - prevVel.y)/(curTime - prevTime) + local zAcc = (unitVel.z - prevVel.z)/(curTime - prevTime) + + unitAcc = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc, z = zAcc})) + Gs = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc + 9.81, z = zAcc})/9.81) + axialGs = string.format('%12.2f', mist.vec.dp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x)/9.81) + transGs = string.format('%12.2f', mist.vec.mag(mist.vec.cp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x))/9.81) + end + + local E = 0.5*mist.vec.mag(unitVel)^2 + 9.81*unitPos.p.y + + local energy = string.format('%12.2e', E) + + local dEdt = 'NA' + if prevE and prevTime then + dEdt = string.format('%12.2e', (E - prevE)/(curTime - prevTime)) + end + + trigger.action.outText(string.format('%-25s', 'Heading: ') .. Heading .. ' degrees\n' .. string.format('%-25s', 'Roll: ') .. Roll .. ' degrees\n' .. string.format('%-25s', 'Pitch: ') .. Pitch + .. ' degrees\n' .. string.format('%-25s', 'Yaw: ') .. Yaw .. ' degrees\n' .. string.format('%-25s', 'AoA: ') .. AoA .. ' degrees\n' .. string.format('%-25s', 'AoA plus Yaw: ') .. AoAplusYaw .. ' degrees\n' .. string.format('%-25s', 'Climb Angle: ') .. + ClimbAngle .. ' degrees\n' .. string.format('%-25s', 'Absolute Velocity: ') .. absVel .. ' m/s\n' .. string.format('%-25s', 'Absolute Acceleration: ') .. unitAcc ..' m/s^2\n' + .. string.format('%-25s', 'Axial G loading: ') .. axialGs .. ' g\n' .. string.format('%-25s', 'Transverse G loading: ') .. transGs .. ' g\n' .. string.format('%-25s', 'Absolute G loading: ') .. Gs .. ' g\n' .. string.format('%-25s', 'Energy: ') .. energy .. ' J/kg\n' .. string.format('%-25s', 'dE/dt: ') .. dEdt .. + ' J/(kg*s)', 1) - return unitVel, E, curTime - end - end - - local function frameFinder(unit, prevVel, prevE, prevTime) - if unit:isExist() then - local currVel = unit:getVelocity() - if prevVel and (prevVel.x ~= currVel.x or prevVel.y ~= currVel.y or prevVel.z ~= currVel.z) or (prevTime and (timer.getTime() - prevTime) > 0.25) then - prevVel, prevE, prevTime = printData(unit, prevVel, prevE, prevTime) - end - mist.scheduleFunction(frameFinder, {unit, prevVel, prevE, prevTime}, timer.getTime() + 0.005) -- it can't go this fast, limited to the 100 times a sec check right now. - end - end - - - local curVel = unit:getVelocity() - local curTime = timer.getTime() - local curE = 0.5*mist.vec.mag(curVel)^2 + 9.81*unit:getPosition().p.y - frameFinder(unit, curVel, curE, curTime) - - end - + return unitVel, E, curTime + end + end + + local function frameFinder(unit, prevVel, prevE, prevTime) + if unit:isExist() then + local currVel = unit:getVelocity() + if prevVel and (prevVel.x ~= currVel.x or prevVel.y ~= currVel.y or prevVel.z ~= currVel.z) or (prevTime and (timer.getTime() - prevTime) > 0.25) then + prevVel, prevE, prevTime = printData(unit, prevVel, prevE, prevTime) + end + mist.scheduleFunction(frameFinder, {unit, prevVel, prevE, prevTime}, timer.getTime() + 0.005) -- it can't go this fast, limited to the 100 times a sec check right now. + end + end + + + local curVel = unit:getVelocity() + local curTime = timer.getTime() + local curE = 0.5*mist.vec.mag(curVel)^2 + 9.81*unit:getPosition().p.y + frameFinder(unit, curVel, curE, curTime) + + end + end -------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------- @@ -3582,82 +3653,82 @@ mist.air.fixedWing = {} mist.air.heli = {} mist.goRoute = function(group, path) - local misTask = { - id = 'Mission', - params = { - route = { - points = mist.utils.deepCopy(path), - }, - }, - } - if type(group) == 'string' then - group = Group.getByName(group) - end - local groupCon = nil - if group then - groupCon = group:getController() - if groupCon then - groupCon:setTask(misTask) - return true - end - end - --Controller.setTask(groupCon, misTask) - return false + local misTask = { + id = 'Mission', + params = { + route = { + points = mist.utils.deepCopy(path), + }, + }, + } + if type(group) == 'string' then + group = Group.getByName(group) + end + local groupCon = nil + if group then + groupCon = group:getController() + if groupCon then + groupCon:setTask(misTask) + return true + end + end + --Controller.setTask(groupCon, misTask) + return false end function mist.getGroupRoute(groupIdent, task) -- same as getGroupPoints but returns speed and formation type along with vec2 of point} - -- refactor to search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - - for point_num, point in pairs(group_data.route.points) do - local routeData = {} - if not point.point then - routeData.x = point.x - routeData.y = point.y - else - routeData.point = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - routeData.form = point.action - routeData.speed = point.speed - routeData.alt = point.alt - routeData.alt_type = point.alt_type - routeData.airdromeId = point.airdromeId - routeData.helipadId = point.helipadId - routeData.type = point.type - routeData.action = point.action - if task then - routeData.task = point.task - end - points[point_num] = routeData - end - - return points - end - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do + -- refactor to search by groupId and allow groupId and groupName as inputs + local gpId = groupIdent + if type(groupIdent) == 'string' and not tonumber(groupIdent) then + gpId = mist.DBs.MEgroupsByName[groupIdent].groupId + end + + for coa_name, coa_data in pairs(env.mission.coalition) do + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + for obj_type_name, obj_type_data in pairs(cntry_data) do + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + for group_num, group_data in pairs(obj_type_data.group) do + if group_data and group_data.groupId == gpId then -- this is the group we are looking for + if group_data.route and group_data.route.points and #group_data.route.points > 0 then + local points = {} + + for point_num, point in pairs(group_data.route.points) do + local routeData = {} + if not point.point then + routeData.x = point.x + routeData.y = point.y + else + routeData.point = point.point --it's possible that the ME could move to the point = Vec2 notation. + end + routeData.form = point.action + routeData.speed = point.speed + routeData.alt = point.alt + routeData.alt_type = point.alt_type + routeData.airdromeId = point.airdromeId + routeData.helipadId = point.helipadId + routeData.type = point.type + routeData.action = point.action + if task then + routeData.task = point.task + end + points[point_num] = routeData + end + + return points + end + return + end --if group_data and group_data.name and group_data.name == 'groupname' + end --for group_num, group_data in pairs(obj_type_data.group) do + end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then + end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then + end --for obj_type_name, obj_type_data in pairs(cntry_data) do + end --for cntry_id, cntry_data in pairs(coa_data.country) do + end --if coa_data.country then --there is a country table + end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then + end --for coa_name, coa_data in pairs(mission.coalition) do end @@ -3668,177 +3739,177 @@ mist.ground.buildPath = function() end -- ???? -- No longer accepts path mist.ground.buildWP = function(point, overRideForm, overRideSpeed) - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - local form, speed - - if point.speed and not overRideSpeed then - wp.speed = point.speed - elseif type(overRideSpeed) == 'number' then - wp.speed = overRideSpeed - else - wp.speed = mist.utils.kmphToMps(20) - end - - if point.form and not overRideForm then - form = point.form - else - form = overRideForm - end - - if not form then - wp.action = 'Cone' - else - form = string.lower(form) - if form == 'off_road' or form == 'off road' then - wp.action = 'Off Road' - elseif form == 'on_road' or form == 'on road' then - wp.action = 'On Road' - elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then - wp.action = 'Rank' - elseif form == 'cone' then - wp.action = 'Cone' - elseif form == 'diamond' then - wp.action = 'Diamond' - elseif form == 'vee' then - wp.action = 'Vee' - elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then - wp.action = 'EchelonL' - elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then - wp.action = 'EchelonR' - else - wp.action = 'Cone' -- if nothing matched - end - end + local wp = {} + wp.x = point.x + + if point.z then + wp.y = point.z + else + wp.y = point.y + end + local form, speed + + if point.speed and not overRideSpeed then + wp.speed = point.speed + elseif type(overRideSpeed) == 'number' then + wp.speed = overRideSpeed + else + wp.speed = mist.utils.kmphToMps(20) + end + + if point.form and not overRideForm then + form = point.form + else + form = overRideForm + end + + if not form then + wp.action = 'Cone' + else + form = string.lower(form) + if form == 'off_road' or form == 'off road' then + wp.action = 'Off Road' + elseif form == 'on_road' or form == 'on road' then + wp.action = 'On Road' + elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then + wp.action = 'Rank' + elseif form == 'cone' then + wp.action = 'Cone' + elseif form == 'diamond' then + wp.action = 'Diamond' + elseif form == 'vee' then + wp.action = 'Vee' + elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then + wp.action = 'EchelonL' + elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then + wp.action = 'EchelonR' + else + wp.action = 'Cone' -- if nothing matched + end + end - wp.type = 'Turning Point' + wp.type = 'Turning Point' - return wp + return wp end mist.fixedWing.buildWP = function(point, WPtype, speed, alt, altType) - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 2000 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or altType == 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or altType == 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = mist.utils.kmphToMps(500) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp + local wp = {} + wp.x = point.x + + if point.z then + wp.y = point.z + else + wp.y = point.y + end + + if alt and type(alt) == 'number' then + wp.alt = alt + else + wp.alt = 2000 + end + + if altType then + altType = string.lower(altType) + if altType == 'radio' or altType == 'agl' then + wp.alt_type = 'RADIO' + elseif altType == 'baro' or altType == 'asl' then + wp.alt_type = 'BARO' + end + else + wp.alt_type = 'RADIO' + end + + if point.speed then + speed = point.speed + end + + if point.type then + WPtype = point.type + end + + if not speed then + wp.speed = mist.utils.kmphToMps(500) + else + wp.speed = speed + end + + if not WPtype then + wp.action = 'Turning Point' + else + WPtype = string.lower(WPtype) + if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then + wp.action = 'Fly Over Point' + elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then + wp.action = 'Turning Point' + else + wp.action = 'Turning Point' + end + end + + wp.type = 'Turning Point' + return wp end mist.heli.buildWP = function(point, WPtype, speed, alt, altType) - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 500 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or altType == 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or altType == 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = mist.utils.kmphToMps(200) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp + local wp = {} + wp.x = point.x + + if point.z then + wp.y = point.z + else + wp.y = point.y + end + + if alt and type(alt) == 'number' then + wp.alt = alt + else + wp.alt = 500 + end + + if altType then + altType = string.lower(altType) + if altType == 'radio' or altType == 'agl' then + wp.alt_type = 'RADIO' + elseif altType == 'baro' or altType == 'asl' then + wp.alt_type = 'BARO' + end + else + wp.alt_type = 'RADIO' + end + + if point.speed then + speed = point.speed + end + + if point.type then + WPtype = point.type + end + + if not speed then + wp.speed = mist.utils.kmphToMps(200) + else + wp.speed = speed + end + + if not WPtype then + wp.action = 'Turning Point' + else + WPtype = string.lower(WPtype) + if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then + wp.action = 'Fly Over Point' + elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then + wp.action = 'Turning Point' + else + wp.action = 'Turning Point' + end + end + + wp.type = 'Turning Point' + return wp end @@ -3850,234 +3921,234 @@ end -- need to return a Vec3 or Vec2? function mist.getRandPointInCircle(point, radius, innerRadius) - local theta = 2*math.pi*math.random() - local rad = math.random() + math.random() - if rad > 1 then - rad = 2 - rad - end - - local radMult - if innerRadius and innerRadius <= radius then - radMult = (radius - innerRadius)*rad + innerRadius - else - radMult = radius*rad - end - - if not point.z then --might as well work with vec2/3 - point.z = point.y - end - - local rndCoord - if radius > 0 then - rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} - else - rndCoord = {x = point.x, y = point.z} - end - return rndCoord + local theta = 2*math.pi*math.random() + local rad = math.random() + math.random() + if rad > 1 then + rad = 2 - rad + end + + local radMult + if innerRadius and innerRadius <= radius then + radMult = (radius - innerRadius)*rad + innerRadius + else + radMult = radius*rad + end + + if not point.z then --might as well work with vec2/3 + point.z = point.y + end + + local rndCoord + if radius > 0 then + rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} + else + rndCoord = {x = point.x, y = point.z} + end + return rndCoord end mist.getRandomPointInZone = function(zoneName, innerRadius) - if type(zoneName) == 'string' and type(trigger.misc.getZone(zoneName)) == 'table' then - return mist.getRandPointInCircle(trigger.misc.getZone(zoneName).point, trigger.misc.getZone(zoneName).radius, innerRadius) - end - return false + if type(zoneName) == 'string' and type(trigger.misc.getZone(zoneName)) == 'table' then + return mist.getRandPointInCircle(trigger.misc.getZone(zoneName).point, trigger.misc.getZone(zoneName).radius, innerRadius) + end + return false end mist.groupToRandomPoint = function(vars) - local group = vars.group --Required - local point = vars.point --required - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - local form = vars.form or 'Cone' - local heading = vars.heading or math.random()*2*math.pi - local headingDegrees = vars.headingDegrees - local speed = vars.speed or mist.utils.kmphToMps(20) - - - local useRoads - if not vars.disableRoads then - useRoads = true - else - useRoads = false - end - - local path = {} - - if headingDegrees then - heading = headingDegrees*math.pi/180 - end - - if heading >= 2*math.pi then - heading = heading - 2*math.pi - end - - local rndCoord = mist.getRandPointInCircle(point, radius, innerRadius) - - local offset = {} - local posStart = mist.getLeadPos(group) + local group = vars.group --Required + local point = vars.point --required + local radius = vars.radius or 0 + local innerRadius = vars.innerRadius + local form = vars.form or 'Cone' + local heading = vars.heading or math.random()*2*math.pi + local headingDegrees = vars.headingDegrees + local speed = vars.speed or mist.utils.kmphToMps(20) + + + local useRoads + if not vars.disableRoads then + useRoads = true + else + useRoads = false + end + + local path = {} + + if headingDegrees then + heading = headingDegrees*math.pi/180 + end + + if heading >= 2*math.pi then + heading = heading - 2*math.pi + end + + local rndCoord = mist.getRandPointInCircle(point, radius, innerRadius) + + local offset = {} + local posStart = mist.getLeadPos(group) - offset.x = mist.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) - offset.z = mist.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) - path[#path + 1] = mist.ground.buildWP(posStart, form, speed) + offset.x = mist.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) + offset.z = mist.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) + path[#path + 1] = mist.ground.buildWP(posStart, form, speed) - - if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then - path[#path + 1] = mist.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed) - path[#path + 1] = mist.ground.buildWP(posStart, 'on_road', speed) - path[#path + 1] = mist.ground.buildWP(offset, 'on_road', speed) - else - path[#path + 1] = mist.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed) - end - - path[#path + 1] = mist.ground.buildWP(offset, form, speed) - path[#path + 1] = mist.ground.buildWP(rndCoord, form, speed) - - mist.goRoute(group, path) - - return + + if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then + path[#path + 1] = mist.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed) + path[#path + 1] = mist.ground.buildWP(posStart, 'on_road', speed) + path[#path + 1] = mist.ground.buildWP(offset, 'on_road', speed) + else + path[#path + 1] = mist.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed) + end + + path[#path + 1] = mist.ground.buildWP(offset, form, speed) + path[#path + 1] = mist.ground.buildWP(rndCoord, form, speed) + + mist.goRoute(group, path) + + return end mist.groupRandomDistSelf = function(gpData, dist, form, heading, speed) - local pos = mist.getLeadPos(gpData) - local fakeZone = {} - fakeZone.radius = dist or math.random(300, 1000) - fakeZone.point = {x = pos.x, y = pos.y, z = pos.z} - mist.groupToRandomZone(gpData, fakeZone, form, heading, speed) + local pos = mist.getLeadPos(gpData) + local fakeZone = {} + fakeZone.radius = dist or math.random(300, 1000) + fakeZone.point = {x = pos.x, y = pos.y, z = pos.z} + mist.groupToRandomZone(gpData, fakeZone, form, heading, speed) - return + return end mist.groupToRandomZone = function(gpData, zone, form, heading, speed) - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end + if type(gpData) == 'string' then + gpData = Group.getByName(gpData) + end + + if type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + elseif type(zone) == 'table' and not zone.radius then + zone = trigger.misc.getZone(zone[math.random(1, #zone)]) + end - if speed then - speed = mist.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.radius = zone.radius - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.point = mist.utils.zoneToVec3(zone) - - mist.groupToRandomPoint(vars) + if speed then + speed = mist.utils.kmphToMps(speed) + end + + local vars = {} + vars.group = gpData + vars.radius = zone.radius + vars.form = form + vars.headingDegrees = heading + vars.speed = speed + vars.point = mist.utils.zoneToVec3(zone) + + mist.groupToRandomPoint(vars) - return + return end mist.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types - if coord.z then - coord.y = coord.z - end - local typeConverted = {} - - if type(terrainTypes) == 'string' then -- if its a string it does this check - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then - table.insert(typeConverted, constId) - end - end - elseif type(terrainTypes) == 'table' then -- if its a table it does this check - for typeId, typeData in pairs(terrainTypes) do - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then - table.insert(typeConverted, constId) - end - end - end - end - for validIndex, validData in pairs(typeConverted) do - if land.getSurfaceType(coord) == land.SurfaceType[validData] then - return true - end - end - return false + if coord.z then + coord.y = coord.z + end + local typeConverted = {} + + if type(terrainTypes) == 'string' then -- if its a string it does this check + for constId, constData in pairs(land.SurfaceType) do + if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then + table.insert(typeConverted, constId) + end + end + elseif type(terrainTypes) == 'table' then -- if its a table it does this check + for typeId, typeData in pairs(terrainTypes) do + for constId, constData in pairs(land.SurfaceType) do + if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then + table.insert(typeConverted, constId) + end + end + end + end + for validIndex, validData in pairs(typeConverted) do + if land.getSurfaceType(coord) == land.SurfaceType[validData] then + return true + end + end + return false end mist.terrainHeightDiff = function(coord, searchSize) - local samples = {} - local searchRadius = 5 - if searchSize then - searchRadius = searchSize - end - if type(coord) == 'string' then - coord = mist.utils.zoneToVec3(coord) - end - - coord = mist.utils.makeVec2(coord) - - samples[#samples + 1] = land.getHeight(coord) - for i = 0, 360, 30 do - samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*searchRadius)), y = (coord.y + (math.cos(math.rad(i))*searchRadius))}) - if searchRadius >= 20 then -- if search radius is sorta large, take a sample halfway between center and outer edge - samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*(searchRadius/2))), y = (coord.y + (math.cos(math.rad(i))*(searchRadius/2)))}) - end - end - local tMax, tMin = 0, 1000000 - for index, height in pairs(samples) do - if height > tMax then - tMax = height - end - if height < tMin then - tMin = height - end - end - return mist.utils.round(tMax - tMin, 2) + local samples = {} + local searchRadius = 5 + if searchSize then + searchRadius = searchSize + end + if type(coord) == 'string' then + coord = mist.utils.zoneToVec3(coord) + end + + coord = mist.utils.makeVec2(coord) + + samples[#samples + 1] = land.getHeight(coord) + for i = 0, 360, 30 do + samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*searchRadius)), y = (coord.y + (math.cos(math.rad(i))*searchRadius))}) + if searchRadius >= 20 then -- if search radius is sorta large, take a sample halfway between center and outer edge + samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*(searchRadius/2))), y = (coord.y + (math.cos(math.rad(i))*(searchRadius/2)))}) + end + end + local tMax, tMin = 0, 1000000 + for index, height in pairs(samples) do + if height > tMax then + tMax = height + end + if height < tMin then + tMin = height + end + end + return mist.utils.round(tMax - tMin, 2) end mist.groupToPoint = function(gpData, point, form, heading, speed, useRoads) - if type(point) == 'string' then - point = trigger.misc.getZone(point) - end - if speed then - speed = mist.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.disableRoads = useRoads - vars.point = mist.utils.zoneToVec3(point) - mist.groupToRandomPoint(vars) - - return + if type(point) == 'string' then + point = trigger.misc.getZone(point) + end + if speed then + speed = mist.utils.kmphToMps(speed) + end + + local vars = {} + vars.group = gpData + vars.form = form + vars.headingDegrees = heading + vars.speed = speed + vars.disableRoads = useRoads + vars.point = mist.utils.zoneToVec3(point) + mist.groupToRandomPoint(vars) + + return end mist.getLeadPos = function(group) - if type(group) == 'string' then -- group name - group = Group.getByName(group) - end - - local units = group:getUnits() - - local leader = units[1] - if not Unit.isExist(leader) then -- SHOULD be good, but if there is a bug, this code future-proofs it then. - local lowestInd = math.huge - for ind, unit in pairs(units) do - if Unit.isExist(unit) and ind < lowestInd then - lowestInd = ind - return unit:getPosition().p - end - end - end - if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... - return leader:getPosition().p - end + if type(group) == 'string' then -- group name + group = Group.getByName(group) + end + + local units = group:getUnits() + + local leader = units[1] + if not Unit.isExist(leader) then -- SHOULD be good, but if there is a bug, this code future-proofs it then. + local lowestInd = math.huge + for ind, unit in pairs(units) do + if Unit.isExist(unit) and ind < lowestInd then + lowestInd = ind + return unit:getPosition().p + end + end + end + if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... + return leader:getPosition().p + end end -- end of Mission task functions @@ -4093,348 +4164,348 @@ end -------MESAGGES------ do - local messageList = {} - local messageDisplayRate = 0.1 -- this defines the max refresh rate of the message box it honestly only needs to go faster than this for precision timing stuff (which could be its own function) - local messageID = 0 - local displayActive = false - local displayFuncId = 0 - - local caSlots = false - local caMSGtoGroup = false - - if env.mission.groundControl then -- just to be sure? - for index, value in pairs(env.mission.groundControl) do - if type(value) == 'table' then - for roleName, roleVal in pairs(value) do - for rIndex, rVal in pairs(roleVal) do - if rIndex == 'red' or rIndex == 'blue' then - if env.mission.groundControl[index][roleName][rIndex] > 0 then - caSlots = true - break - end - end - end - end - elseif type(value) == 'boolean' and value == true then - caSlots = true - break - end - end - end - - local function mistdisplayV5() - --[[thoughts to improve upon - event handler based activeClients table. - display messages only when there is an update - possibly co-routine it. + local messageList = {} + local messageDisplayRate = 0.1 -- this defines the max refresh rate of the message box it honestly only needs to go faster than this for precision timing stuff (which could be its own function) + local messageID = 0 + local displayActive = false + local displayFuncId = 0 + + local caSlots = false + local caMSGtoGroup = false + + if env.mission.groundControl then -- just to be sure? + for index, value in pairs(env.mission.groundControl) do + if type(value) == 'table' then + for roleName, roleVal in pairs(value) do + for rIndex, rVal in pairs(roleVal) do + if rIndex == 'red' or rIndex == 'blue' then + if env.mission.groundControl[index][roleName][rIndex] > 0 then + caSlots = true + break + end + end + end + end + elseif type(value) == 'boolean' and value == true then + caSlots = true + break + end + end + end + + local function mistdisplayV5() + --[[thoughts to improve upon + event handler based activeClients table. + display messages only when there is an update + possibly co-routine it. ]] - end - - local function mistdisplayV4() - local activeClients = {} + end + + local function mistdisplayV4() + local activeClients = {} - for clientId, clientData in pairs(mist.DBs.humansById) do - if Unit.getByName(clientData.unitName) and Unit.getByName(clientData.unitName):isExist() == true then - activeClients[clientData.groupId] = clientData.groupName - end - end - - --[[if caSlots == true and caMSGtoGroup == true then - - end]] + for clientId, clientData in pairs(mist.DBs.humansById) do + if Unit.getByName(clientData.unitName) and Unit.getByName(clientData.unitName):isExist() == true then + activeClients[clientData.groupId] = clientData.groupName + end + end + + --[[if caSlots == true and caMSGtoGroup == true then + + end]] - - if #messageList > 0 then - if displayActive == false then - displayActive = true - end - --mist.debug.writeData(mist.utils.serialize,{'msg', messageList}, 'messageList.lua') - local msgTableText = {} - local msgTableSound = {} - - for messageId, messageData in pairs(messageList) do - if messageData.displayedFor > messageData.displayTime then - messageData:remove() -- now using the remove/destroy function. - else - if messageData.displayedFor then - messageData.displayedFor = messageData.displayedFor + messageDisplayRate - end - local nextSound = 1000 - local soundIndex = 0 - - if messageData.multSound and #messageData.multSound > 0 then - for index, sData in pairs(messageData.multSound) do - if sData.time <= messageData.displayedFor and sData.played == false and sData.time < nextSound then -- find index of the next sound to be played - nextSound = sData.time - soundIndex = index - end - end - if soundIndex ~= 0 then - messageData.multSound[soundIndex].played = true - end - end - - for recIndex, recData in pairs(messageData.msgFor) do -- iterate recipiants - if recData == 'RED' or recData == 'BLUE' or activeClients[recData] then -- rec exists - if messageData.text then -- text - if not msgTableText[recData] then -- create table entry for text - msgTableText[recData] = {} - msgTableText[recData].text = {} - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[1] = '-------Combined Arms Message-------- \n' - end - msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else -- add to table entry and adjust display time if needed - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- Combined Arms Message: \n' - else - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- \n' - end - msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text - if msgTableText[recData].displayTime < messageData.displayTime - messageData.displayedFor then - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else - msgTableText[recData].displayTime = 1 - end - end - end - if soundIndex ~= 0 then - msgTableSound[recData] = messageData.multSound[soundIndex].file - end - end - end - - - end - end - ------- new display - - if caSlots == true and caMSGtoGroup == false then - if msgTableText['RED'] then - trigger.action.outTextForCoalition(coalition.side.RED, table.concat(msgTableText['RED'].text), msgTableText['RED'].displayTime, true) + + if #messageList > 0 then + if displayActive == false then + displayActive = true + end + --mist.debug.writeData(mist.utils.serialize,{'msg', messageList}, 'messageList.lua') + local msgTableText = {} + local msgTableSound = {} + + for messageId, messageData in pairs(messageList) do + if messageData.displayedFor > messageData.displayTime then + messageData:remove() -- now using the remove/destroy function. + else + if messageData.displayedFor then + messageData.displayedFor = messageData.displayedFor + messageDisplayRate + end + local nextSound = 1000 + local soundIndex = 0 + + if messageData.multSound and #messageData.multSound > 0 then + for index, sData in pairs(messageData.multSound) do + if sData.time <= messageData.displayedFor and sData.played == false and sData.time < nextSound then -- find index of the next sound to be played + nextSound = sData.time + soundIndex = index + end + end + if soundIndex ~= 0 then + messageData.multSound[soundIndex].played = true + end + end + + for recIndex, recData in pairs(messageData.msgFor) do -- iterate recipiants + if recData == 'RED' or recData == 'BLUE' or activeClients[recData] then -- rec exists + if messageData.text then -- text + if not msgTableText[recData] then -- create table entry for text + msgTableText[recData] = {} + msgTableText[recData].text = {} + if recData == 'RED' or recData == 'BLUE' then + msgTableText[recData].text[1] = '-------Combined Arms Message-------- \n' + end + msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text + msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor + else -- add to table entry and adjust display time if needed + if recData == 'RED' or recData == 'BLUE' then + msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- Combined Arms Message: \n' + else + msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- \n' + end + msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text + if msgTableText[recData].displayTime < messageData.displayTime - messageData.displayedFor then + msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor + else + msgTableText[recData].displayTime = 1 + end + end + end + if soundIndex ~= 0 then + msgTableSound[recData] = messageData.multSound[soundIndex].file + end + end + end + + + end + end + ------- new display + + if caSlots == true and caMSGtoGroup == false then + if msgTableText['RED'] then + trigger.action.outTextForCoalition(coalition.side.RED, table.concat(msgTableText['RED'].text), msgTableText['RED'].displayTime, true) - end - if msgTableText['BLUE'] then - trigger.action.outTextForCoalition(coalition.side.BLUE, table.concat(msgTableText['BLUE'].text), msgTableText['BLUE'].displayTime, true) - end - end - - for index, msgData in pairs(msgTableText) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outTextForGroup(index, table.concat(msgData.text), msgData.displayTime, true) - end - end - --- new audio - if msgTableSound['RED'] then - trigger.action.outSoundForCoalition(coalition.side.RED, msgTableSound['RED']) - end - if msgTableSound['BLUE'] then - trigger.action.outSoundForCoalition(coalition.side.BLUE, msgTableSound['BLUE']) - end - - - for index, file in pairs(msgTableSound) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outSoundForGroup(index, file) - end - end - else - mist.removeFunction(displayFuncId) - displayActive = false - end - - end - - local typeBase = { - ['Mi-8MT'] = {'Mi-8MTV2', 'Mi-8MTV', 'Mi-8'}, - ['MiG-21Bis'] = {'Mig-21'}, - ['MiG-15bis'] = {'Mig-15'}, - ['FW-190D9'] = {'FW-190'}, - ['Bf-109K-4'] = {'Bf-109'}, - } - - --[[mist.setCAGroupMSG = function(val) - if type(val) == 'boolean' then - caMSGtoGroup = val - return true - end - return false - end]] + end + if msgTableText['BLUE'] then + trigger.action.outTextForCoalition(coalition.side.BLUE, table.concat(msgTableText['BLUE'].text), msgTableText['BLUE'].displayTime, true) + end + end + + for index, msgData in pairs(msgTableText) do + if type(index) == 'number' then -- its a groupNumber + trigger.action.outTextForGroup(index, table.concat(msgData.text), msgData.displayTime, true) + end + end + --- new audio + if msgTableSound['RED'] then + trigger.action.outSoundForCoalition(coalition.side.RED, msgTableSound['RED']) + end + if msgTableSound['BLUE'] then + trigger.action.outSoundForCoalition(coalition.side.BLUE, msgTableSound['BLUE']) + end + + + for index, file in pairs(msgTableSound) do + if type(index) == 'number' then -- its a groupNumber + trigger.action.outSoundForGroup(index, file) + end + end + else + mist.removeFunction(displayFuncId) + displayActive = false + end + + end + + local typeBase = { + ['Mi-8MT'] = {'Mi-8MTV2', 'Mi-8MTV', 'Mi-8'}, + ['MiG-21Bis'] = {'Mig-21'}, + ['MiG-15bis'] = {'Mig-15'}, + ['FW-190D9'] = {'FW-190'}, + ['Bf-109K-4'] = {'Bf-109'}, + } + + --[[mist.setCAGroupMSG = function(val) + if type(val) == 'boolean' then + caMSGtoGroup = val + return true + end + return false + end]] - mist.message = { - + mist.message = { + - add = function(vars) - local function msgSpamFilter(recList, spamBlockOn) - for id, name in pairs(recList) do - if name == spamBlockOn then - -- env.info('already on recList') - return recList - end - end - --env.info('add to recList') - table.insert(recList, spamBlockOn) - return recList - end - - --[[ - local vars = {} - vars.text = 'Hello World' - vars.displayTime = 20 - vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} - mist.message.add(vars) + add = function(vars) + local function msgSpamFilter(recList, spamBlockOn) + for id, name in pairs(recList) do + if name == spamBlockOn then + -- env.info('already on recList') + return recList + end + end + --env.info('add to recList') + table.insert(recList, spamBlockOn) + return recList + end + + --[[ + local vars = {} + vars.text = 'Hello World' + vars.displayTime = 20 + vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} + mist.message.add(vars) - Displays the message for all red coalition players. Players belonging to Ukraine and Georgia, and all A-10Cs on the map - - ]] - - - local new = {} - new.text = vars.text -- The actual message - new.displayTime = vars.displayTime -- How long will the message appear for - new.displayedFor = 0 -- how long the message has been displayed so far - new.name = vars.name -- ID to overwrite the older message (if it exists) Basically it replaces a message that is displayed with new text. - new.addedAt = timer.getTime() - new.update = true - - if vars.multSound and vars.multSound[1] then - new.multSound = vars.multSound - else - new.multSound = {} - end - - if vars.sound or vars.fileName then -- converts old sound file system into new multSound format - local sound = vars.sound - if vars.fileName then - sound = vars.fileName - end - new.multSound[#new.multSound+1] = {time = 0.1, file = sound} - end - - if #new.multSound > 0 then - for i, data in pairs(new.multSound) do - data.played = false - end - end - - local newMsgFor = {} -- list of all groups message displays for - for forIndex, forData in pairs(vars.msgFor) do - for list, listData in pairs(forData) do - for clientId, clientData in pairs(mist.DBs.humansById) do - forIndex = string.lower(forIndex) - if type(listData) == 'string' then - listData = string.lower(listData) - end - if (forIndex == 'coa' and (listData == string.lower(clientData.coalition) or listData == 'all')) or (forIndex == 'countries' and string.lower(clientData.country) == listData) or (forIndex == 'units' and string.lower(clientData.unitName) == listData) then -- - newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- so units dont get the same message twice if complex rules are given - --table.insert(newMsgFor, clientId) - elseif forIndex == 'unittypes' then - for typeId, typeData in pairs(listData) do - local found = false - for clientDataEntry, clientDataVal in pairs(clientData) do - if type(clientDataVal) == 'string' then - if mist.matchString(list, clientDataVal) == true or list == 'all' then - local sString = typeData - for rName, pTbl in pairs(typeBase) do -- just a quick check to see if the user may have meant something and got the specific type of the unit wrong - for pIndex, pName in pairs(pTbl) do - if mist.stringMatch(sString, pName) then - sString = rName - end - end - end - if sString == clientData.type then - found = true - newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- sends info oto other function to see if client is already recieving the current message. - --table.insert(newMsgFor, clientId) - end - end - end - if found == true then -- shouldn't this be elsewhere too? - break - end - end - end + Displays the message for all red coalition players. Players belonging to Ukraine and Georgia, and all A-10Cs on the map + + ]] + + + local new = {} + new.text = vars.text -- The actual message + new.displayTime = vars.displayTime -- How long will the message appear for + new.displayedFor = 0 -- how long the message has been displayed so far + new.name = vars.name -- ID to overwrite the older message (if it exists) Basically it replaces a message that is displayed with new text. + new.addedAt = timer.getTime() + new.update = true + + if vars.multSound and vars.multSound[1] then + new.multSound = vars.multSound + else + new.multSound = {} + end + + if vars.sound or vars.fileName then -- converts old sound file system into new multSound format + local sound = vars.sound + if vars.fileName then + sound = vars.fileName + end + new.multSound[#new.multSound+1] = {time = 0.1, file = sound} + end + + if #new.multSound > 0 then + for i, data in pairs(new.multSound) do + data.played = false + end + end + + local newMsgFor = {} -- list of all groups message displays for + for forIndex, forData in pairs(vars.msgFor) do + for list, listData in pairs(forData) do + for clientId, clientData in pairs(mist.DBs.humansById) do + forIndex = string.lower(forIndex) + if type(listData) == 'string' then + listData = string.lower(listData) + end + if (forIndex == 'coa' and (listData == string.lower(clientData.coalition) or listData == 'all')) or (forIndex == 'countries' and string.lower(clientData.country) == listData) or (forIndex == 'units' and string.lower(clientData.unitName) == listData) then -- + newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- so units dont get the same message twice if complex rules are given + --table.insert(newMsgFor, clientId) + elseif forIndex == 'unittypes' then + for typeId, typeData in pairs(listData) do + local found = false + for clientDataEntry, clientDataVal in pairs(clientData) do + if type(clientDataVal) == 'string' then + if mist.matchString(list, clientDataVal) == true or list == 'all' then + local sString = typeData + for rName, pTbl in pairs(typeBase) do -- just a quick check to see if the user may have meant something and got the specific type of the unit wrong + for pIndex, pName in pairs(pTbl) do + if mist.stringMatch(sString, pName) then + sString = rName + end + end + end + if sString == clientData.type then + found = true + newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- sends info oto other function to see if client is already recieving the current message. + --table.insert(newMsgFor, clientId) + end + end + end + if found == true then -- shouldn't this be elsewhere too? + break + end + end + end - end - end - for coaData, coaId in pairs(coalition.side) do - if string.lower(forIndex) == 'coa' or string.lower(forIndex) == 'ca' then - if listData == string.lower(coaData) or listData == 'all' then - newMsgFor = msgSpamFilter(newMsgFor, coaData) - end - end - end - end - end - - if #newMsgFor > 0 then - new.msgFor = newMsgFor -- I swear its not confusing - - else - return false - end - - - if vars.name and type(vars.name) == 'string' then - for i = 1, #messageList do - if messageList[i].name then - if messageList[i].name == vars.name then - --env.info('updateMessage') - messageList[i].displayedFor = 0 - messageList[i].addedAt = timer.getTime() - messageList[i].sound = new.sound - messageList[i].text = new.text - messageList[i].msgFor = new.msgFor - messageList[i].multSound = new.multSound - messageList[i].update = true - return messageList[i].messageID - end - end - end - end - - messageID = messageID + 1 - new.messageID = messageID + end + end + for coaData, coaId in pairs(coalition.side) do + if string.lower(forIndex) == 'coa' or string.lower(forIndex) == 'ca' then + if listData == string.lower(coaData) or listData == 'all' then + newMsgFor = msgSpamFilter(newMsgFor, coaData) + end + end + end + end + end + + if #newMsgFor > 0 then + new.msgFor = newMsgFor -- I swear its not confusing + + else + return false + end + + + if vars.name and type(vars.name) == 'string' then + for i = 1, #messageList do + if messageList[i].name then + if messageList[i].name == vars.name then + --env.info('updateMessage') + messageList[i].displayedFor = 0 + messageList[i].addedAt = timer.getTime() + messageList[i].sound = new.sound + messageList[i].text = new.text + messageList[i].msgFor = new.msgFor + messageList[i].multSound = new.multSound + messageList[i].update = true + return messageList[i].messageID + end + end + end + end + + messageID = messageID + 1 + new.messageID = messageID - --mist.debug.writeData(mist.utils.serialize,{'msg', new}, 'newMsg.lua') + --mist.debug.writeData(mist.utils.serialize,{'msg', new}, 'newMsg.lua') - - messageList[#messageList + 1] = new - - local mt = { __index = mist.message} - setmetatable(new, mt) + + messageList[#messageList + 1] = new + + local mt = { __index = mist.message} + setmetatable(new, mt) - if displayActive == false then - displayActive = true - displayFuncId = mist.scheduleFunction(mistdisplayV4, {}, timer.getTime() + messageDisplayRate, messageDisplayRate) - end - - return messageID - - end, - - remove = function(self) -- Now a self variable; the former functionality taken up by mist.message.removeById. - for i, msgData in pairs(messageList) do - if messageList[i] == self then - table.remove(messageList, i) - return true --removal successful - end - end - return false -- removal not successful this script fails at life! - end, - - removeById = function(id) -- This function is NOT passed a self variable; it is the remove by id function. - for i, msgData in pairs(messageList) do - if messageList[i].messageID == id then - table.remove(messageList, i) - return true --removal successful - end - end - return false -- removal not successful this script fails at life! - end, - } - + if displayActive == false then + displayActive = true + displayFuncId = mist.scheduleFunction(mistdisplayV4, {}, timer.getTime() + messageDisplayRate, messageDisplayRate) + end + + return messageID + + end, + + remove = function(self) -- Now a self variable; the former functionality taken up by mist.message.removeById. + for i, msgData in pairs(messageList) do + if messageList[i] == self then + table.remove(messageList, i) + return true --removal successful + end + end + return false -- removal not successful this script fails at life! + end, + + removeById = function(id) -- This function is NOT passed a self variable; it is the remove by id function. + for i, msgData in pairs(messageList) do + if messageList[i].messageID == id then + table.remove(messageList, i) + return true --removal successful + end + end + return false -- removal not successful this script fails at life! + end, + } + end -- End of message system -------------------------------------------------------------------------------------------------------------------------------------------- @@ -4487,12 +4558,12 @@ vars.units - table of unit names (NOT unitNameTable- maybe this should change). vars.acc - integer between 0 and 5, inclusive ]] mist.getMGRSString = function(vars) - local units = vars.units - local acc = vars.acc or 5 - local avgPos = mist.getAvgPos(units) - if avgPos then - return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) - end + local units = vars.units + local acc = vars.acc or 5 + local avgPos = mist.getAvgPos(units) + if avgPos then + return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) + end end --[[ vars for mist.getLLString @@ -4503,14 +4574,14 @@ vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in d ]] mist.getLLString = function(vars) - local units = vars.units - local acc = vars.acc or 3 - local DMS = vars.DMS - local avgPos = mist.getAvgPos(units) - if avgPos then - local lat, lon = coord.LOtoLL(avgPos) - return mist.tostringLL(lat, lon, acc, DMS) - end + local units = vars.units + local acc = vars.acc or 3 + local DMS = vars.DMS + local avgPos = mist.getAvgPos(units) + if avgPos then + local lat, lon = coord.LOtoLL(avgPos) + return mist.tostringLL(lat, lon, acc, DMS) + end end @@ -4521,20 +4592,20 @@ vars.alt - boolean, if used, includes altitude in string vars.metric - boolean, gives distance in km instead of NM. ]] mist.getBRString = function(vars) - local units = vars.units - local ref = mist.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - local avgPos = mist.getAvgPos(units) - if avgPos then - local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} - local dir = mist.utils.getDir(vec, ref) - local dist = mist.utils.get2DDist(avgPos, ref) - if alt then - alt = avgPos.y - end - return mist.tostringBR(dir, dist, alt, metric) - end + local units = vars.units + local ref = mist.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. + local alt = vars.alt + local metric = vars.metric + local avgPos = mist.getAvgPos(units) + if avgPos then + local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} + local dir = mist.utils.getDir(vec, ref) + local dist = mist.utils.get2DDist(avgPos, ref) + if alt then + alt = avgPos.y + end + return mist.tostringBR(dir, dist, alt, metric) + end end -- Returns the Vec3 coordinates of the average position of the concentration of units most in the heading direction. @@ -4545,53 +4616,53 @@ vars.radius - number vars.headingDegrees - boolean, switches heading to degrees ]] mist.getLeadingPos = function(vars) - local units = vars.units - local heading = vars.heading - local radius = vars.radius - if vars.headingDegrees then - heading = mist.utils.toRadian(vars.headingDegrees) - end - - local unitPosTbl = {} - for i = 1, #units do - local unit = Unit.getByName(units[i]) - if unit and unit:isExist() then - unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p - end - end - if #unitPosTbl > 0 then -- one more more units found. - -- first, find the unit most in the heading direction - local maxPos = -math.huge - - local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = - for i = 1, #unitPosTbl do - local rotatedVec2 = mist.vec.rotateVec2(mist.utils.makeVec2(unitPosTbl[i]), heading) - if (not maxPos) or maxPos < rotatedVec2.x then - maxPos = rotatedVec2.x - maxPosInd = i - end - end - - --now, get all the units around this unit... - local avgPos - if radius then - local maxUnitPos = unitPosTbl[maxPosInd] - local avgx, avgy, avgz, totNum = 0, 0, 0, 0 - for i = 1, #unitPosTbl do - if mist.utils.get2DDist(maxUnitPos, unitPosTbl[i]) <= radius then - avgx = avgx + unitPosTbl[i].x - avgy = avgy + unitPosTbl[i].y - avgz = avgz + unitPosTbl[i].z - totNum = totNum + 1 - end - end - avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} - else - avgPos = unitPosTbl[maxPosInd] - end - - return avgPos - end + local units = vars.units + local heading = vars.heading + local radius = vars.radius + if vars.headingDegrees then + heading = mist.utils.toRadian(vars.headingDegrees) + end + + local unitPosTbl = {} + for i = 1, #units do + local unit = Unit.getByName(units[i]) + if unit and unit:isExist() then + unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p + end + end + if #unitPosTbl > 0 then -- one more more units found. + -- first, find the unit most in the heading direction + local maxPos = -math.huge + + local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = + for i = 1, #unitPosTbl do + local rotatedVec2 = mist.vec.rotateVec2(mist.utils.makeVec2(unitPosTbl[i]), heading) + if (not maxPos) or maxPos < rotatedVec2.x then + maxPos = rotatedVec2.x + maxPosInd = i + end + end + + --now, get all the units around this unit... + local avgPos + if radius then + local maxUnitPos = unitPosTbl[maxPosInd] + local avgx, avgy, avgz, totNum = 0, 0, 0, 0 + for i = 1, #unitPosTbl do + if mist.utils.get2DDist(maxUnitPos, unitPosTbl[i]) <= radius then + avgx = avgx + unitPosTbl[i].x + avgy = avgy + unitPosTbl[i].y + avgz = avgz + unitPosTbl[i].z + totNum = totNum + 1 + end + end + avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} + else + avgPos = unitPosTbl[maxPosInd] + end + + return avgPos + end end @@ -4603,11 +4674,11 @@ vars.headingDegrees - boolean, switches heading to degrees vars.acc - number, 0 to 5. ]] mist.getLeadingMGRSString = function(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local acc = vars.acc or 5 - return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) - end + local pos = mist.getLeadingPos(vars) + if pos then + local acc = vars.acc or 5 + return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) + end end --[[ vars for mist.getLeadingLLString: @@ -4619,13 +4690,13 @@ vars.acc - number of digits after decimal point (can be negative) vars.DMS - boolean, true if you want DMS. ]] mist.getLeadingLLString = function(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local acc = vars.acc or 3 - local DMS = vars.DMS - local lat, lon = coord.LOtoLL(pos) - return mist.tostringLL(lat, lon, acc, DMS) - end + local pos = mist.getLeadingPos(vars) + if pos then + local acc = vars.acc or 3 + local DMS = vars.DMS + local lat, lon = coord.LOtoLL(pos) + return mist.tostringLL(lat, lon, acc, DMS) + end end @@ -4640,26 +4711,26 @@ vars.alt - boolean, if true, include altitude. vars.ref - vec3/vec2 reference point. ]] mist.getLeadingBRString = function(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local ref = vars.ref - local alt = vars.alt - local metric = vars.metric - - local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} - local dir = mist.utils.getDir(vec, ref) - local dist = mist.utils.get2DDist(pos, ref) - if alt then - alt = pos.y - end - return mist.tostringBR(dir, dist, alt, metric) - end + local pos = mist.getLeadingPos(vars) + if pos then + local ref = vars.ref + local alt = vars.alt + local metric = vars.metric + + local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} + local dir = mist.utils.getDir(vec, ref) + local dist = mist.utils.get2DDist(pos, ref) + if alt then + alt = pos.y + end + return mist.tostringBR(dir, dist, alt, metric) + end end --[[ vars for mist.message.add - vars.text = 'Hello World' - vars.displayTime = 20 - vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} + vars.text = 'Hello World' + vars.displayTime = 20 + vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} ]] @@ -4671,28 +4742,28 @@ vars.displayTime - self explanatory vars.msgFor - scope ]] mist.msgMGRS = function(vars) - local units = vars.units - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getMGRSString{units = units, acc = acc} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units + local acc = vars.acc + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getMGRSString{units = units, acc = acc} + local newText + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end --[[ vars for mist.msgLL @@ -4704,30 +4775,30 @@ vars.displayTime - self explanatory vars.msgFor - scope ]] mist.msgLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLLString{units = units, acc = acc, DMS = DMS} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local acc = vars.acc + local DMS = vars.DMS + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getLLString{units = units, acc = acc, DMS = DMS} + local newText + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end @@ -4742,31 +4813,31 @@ vars.displayTime vars.msgFor - scope ]] mist.msgBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString - local alt = vars.alt - local metric = vars.metric - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getBRString{units = units, ref = ref, alt = alt, metric = metric} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString + local alt = vars.alt + local metric = vars.metric + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getBRString{units = units, ref = ref, alt = alt, metric = metric} + local newText + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end @@ -4783,13 +4854,13 @@ vars.displayTime vars.msgFor - scope ]] mist.msgBullseye = function(vars) - if string.lower(vars.ref) == 'red' then - vars.ref = mist.DBs.missionData.bullseye.red - mist.msgBR(vars) - elseif string.lower(vars.ref) == 'blue' then - vars.ref = mist.DBs.missionData.bullseye.blue - mist.msgBR(vars) - end + if string.lower(vars.ref) == 'red' then + vars.ref = mist.DBs.missionData.bullseye.red + mist.msgBR(vars) + elseif string.lower(vars.ref) == 'blue' then + vars.ref = mist.DBs.missionData.bullseye.blue + mist.msgBR(vars) + end end --[[ @@ -4803,13 +4874,13 @@ vars.msgFor - scope ]] mist.msgBRA = function(vars) - if Unit.getByName(vars.ref) and Unit.getByName(vars.ref):isExist() == true then - vars.ref = Unit.getByName(vars.ref):getPosition().p - if not vars.alt then - vars.alt = true - end - mist.msgBR(vars) - end + if Unit.getByName(vars.ref) and Unit.getByName(vars.ref):isExist() == true then + vars.ref = Unit.getByName(vars.ref):getPosition().p + if not vars.alt then + vars.alt = true + end + mist.msgBR(vars) + end end -------------------------------------------------------------------------------------------- @@ -4824,32 +4895,32 @@ vars.displayTime vars.msgFor - scope ]] mist.msgLeadingMGRS = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local acc = vars.acc + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} + local newText + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end @@ -4865,34 +4936,34 @@ vars.displayTime vars.msgFor - scope ]] mist.msgLeadingLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} - local newText - - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local acc = vars.acc + local DMS = vars.DMS + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} + local newText + + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end @@ -4909,35 +4980,35 @@ vars.displayTime vars.msgFor - scope ]] mist.msgLeadingBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local metric = vars.metric - local alt = vars.alt - local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} - local newText - - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local metric = vars.metric + local alt = vars.alt + local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = mist.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} + local newText + + if text then + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + else + newText = s + end + + mist.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } end @@ -4948,799 +5019,799 @@ end -- start of sct Merge do -- all function uses of group and unit Ids must be in this do statement - - + + mist.groupTableCheck = function(groupData) - local isOk = false - - if groupData.country then - isOk = true - end - if groupData.category then - isOk = true - else - isOk = false - end - if groupData.units then - for unitId, unitData in pairs(groupData.units) do - if unitData.x and unitData.y and unitData.type then - isOk = true - end - end - else - isOk = false - end - - return isOk -end + local isOk = false + + if groupData.country then + isOk = true + end + if groupData.category then + isOk = true + else + isOk = false + end + if groupData.units then + for unitId, unitData in pairs(groupData.units) do + if unitData.x and unitData.y and unitData.type then + isOk = true + end + end + else + isOk = false + end + + return isOk +end mist.getCurrentGroupData = function(gpName) - local dbData = mist.getGroupData(gpName) - - if Group.getByName(gpName) and Group.getByName(gpName):isExist() == true then - local newGroup = Group.getByName(gpName) - local newData = {} - newData.name = gpName - newData.groupId = tonumber(newGroup:getID()) - newData.category = newGroup:getCategory() - newData.groupName = gpName + local dbData = mist.getGroupData(gpName) + + if Group.getByName(gpName) and Group.getByName(gpName):isExist() == true then + local newGroup = Group.getByName(gpName) + local newData = {} + newData.name = gpName + newData.groupId = tonumber(newGroup:getID()) + newData.category = newGroup:getCategory() + newData.groupName = gpName newData.hidden = dbData.hidden - - if newData.category == 2 then - newData.category = 'vehicle' - elseif newData.category == 3 then - newData.category = 'ship' - end + + if newData.category == 2 then + newData.category = 'vehicle' + elseif newData.category == 3 then + newData.category = 'ship' + end - newData.units = {} - local newUnits = newGroup:getUnits() - for unitNum, unitData in pairs(newGroup:getUnits()) do - newData.units[unitNum] = {} - newData.units[unitNum]["unitId"] = tonumber(unitData:getID()) - newData.units[unitNum]['point'] = unitData.point - newData.units[unitNum]['x'] = unitData:getPosition().p.x - newData.units[unitNum]['y'] = unitData:getPosition().p.z - newData.units[unitNum]["type"] = unitData:getTypeName() - newData.units[unitNum]["skill"] = mist.getUnitSkill(unitData:getName()) - - -- get velocity needed - newData.units[unitNum]["unitName"] = unitData:getName() - newData.units[unitNum]["heading"] = mist.getHeading(unitData, true) -- added to DBs - newData.units[unitNum]['alt'] = unitData:getPosition().p.y - newData.country = string.lower(country.name[unitData:getCountry()]) - newData.units[unitNum]['callsign'] = unitData:getCallsign() - end + newData.units = {} + local newUnits = newGroup:getUnits() + for unitNum, unitData in pairs(newGroup:getUnits()) do + newData.units[unitNum] = {} + newData.units[unitNum]["unitId"] = tonumber(unitData:getID()) + newData.units[unitNum]['point'] = unitData.point + newData.units[unitNum]['x'] = unitData:getPosition().p.x + newData.units[unitNum]['y'] = unitData:getPosition().p.z + newData.units[unitNum]["type"] = unitData:getTypeName() + newData.units[unitNum]["skill"] = mist.getUnitSkill(unitData:getName()) + + -- get velocity needed + newData.units[unitNum]["unitName"] = unitData:getName() + newData.units[unitNum]["heading"] = mist.getHeading(unitData, true) -- added to DBs + newData.units[unitNum]['alt'] = unitData:getPosition().p.y + newData.country = string.lower(country.name[unitData:getCountry()]) + newData.units[unitNum]['callsign'] = unitData:getCallsign() + end - return newData - elseif StaticObject.getByName(gpName) and StaticObject.getByName(gpName):isExist() == true then - local staticObj = StaticObject.getByName(gpName) - dbData.units[1].x = staticObj:getPosition().p.x - dbData.units[1].y = staticObj:getPosition().p.z - dbData.units[1].alt = staticObj:getPosition().p.y - dbData.units[1].heading = mist.getHeading(staticObj, true) - - return dbData - end + return newData + elseif StaticObject.getByName(gpName) and StaticObject.getByName(gpName):isExist() == true then + local staticObj = StaticObject.getByName(gpName) + dbData.units[1].x = staticObj:getPosition().p.x + dbData.units[1].y = staticObj:getPosition().p.z + dbData.units[1].alt = staticObj:getPosition().p.y + dbData.units[1].heading = mist.getHeading(staticObj, true) + + return dbData + end end mist.getGroupData = function(gpName) - local found = false - local newData = {} - if mist.DBs.groupsByName[gpName] then - newData = mist.utils.deepCopy(mist.DBs.groupsByName[gpName]) - found = true - end - - if found == false then - for groupName, groupData in pairs(mist.DBs.groupsByName) do - if mist.stringMatch(groupName, gpName) == true then - newData = mist.utils.deepCopy(groupData) - newData.groupName = groupName - found = true - break - end - end - end - - local payloads - if newData.category == 'plane' or newData.category == 'helicopter' then - payloads = mist.getGroupPayload(newData.groupName) - end - if found == true then - --newData.hidden = false -- maybe add this to DBs + local found = false + local newData = {} + if mist.DBs.groupsByName[gpName] then + newData = mist.utils.deepCopy(mist.DBs.groupsByName[gpName]) + found = true + end + + if found == false then + for groupName, groupData in pairs(mist.DBs.groupsByName) do + if mist.stringMatch(groupName, gpName) == true then + newData = mist.utils.deepCopy(groupData) + newData.groupName = groupName + found = true + break + end + end + end + + local payloads + if newData.category == 'plane' or newData.category == 'helicopter' then + payloads = mist.getGroupPayload(newData.groupName) + end + if found == true then + --newData.hidden = false -- maybe add this to DBs - for unitNum, unitData in pairs(newData.units) do - newData.units[unitNum] = {} - - newData.units[unitNum]["unitId"] = unitData.unitId - --newData.units[unitNum]['point'] = unitData.point - newData.units[unitNum]['x'] = unitData.point.x - newData.units[unitNum]['y'] = unitData.point.y - newData.units[unitNum]['alt'] = unitData.alt - newData.units[unitNum]['alt_type'] = unitData.alt_type - newData.units[unitNum]['speed'] = unitData.speed - newData.units[unitNum]["type"] = unitData.type - newData.units[unitNum]["skill"] = unitData.skill - newData.units[unitNum]["unitName"] = unitData.unitName - newData.units[unitNum]["heading"] = unitData.heading -- added to DBs - newData.units[unitNum]["playerCanDrive"] = unitData.playerCanDrive -- added to DBs - - - if newData.category == 'plane' or newData.category == 'helicopter' then - newData.units[unitNum]["payload"] = payloads[unitNum] - newData.units[unitNum]['livery_id'] = unitData.livery_id - newData.units[unitNum]['onboard_num'] = unitData.onboard_num - newData.units[unitNum]['callsign'] = unitData.callsign - newData.units[unitNum]['AddPropAircraft'] = unitData.AddPropAircraft - end - if newData.category == 'static' then - newData.units[unitNum]['categoryStatic'] = unitData.categoryStatic - newData.units[unitNum]['mass'] = unitData.mass - newData.units[unitNum]['canCargo'] = unitData.canCargo - newData.units[unitNum]['shape_name'] = unitData.shape_name - end - end - - return newData - else - env.info(gpName .. ' not found in mist.getGroupData') - return - end + for unitNum, unitData in pairs(newData.units) do + newData.units[unitNum] = {} + + newData.units[unitNum]["unitId"] = unitData.unitId + --newData.units[unitNum]['point'] = unitData.point + newData.units[unitNum]['x'] = unitData.point.x + newData.units[unitNum]['y'] = unitData.point.y + newData.units[unitNum]['alt'] = unitData.alt + newData.units[unitNum]['alt_type'] = unitData.alt_type + newData.units[unitNum]['speed'] = unitData.speed + newData.units[unitNum]["type"] = unitData.type + newData.units[unitNum]["skill"] = unitData.skill + newData.units[unitNum]["unitName"] = unitData.unitName + newData.units[unitNum]["heading"] = unitData.heading -- added to DBs + newData.units[unitNum]["playerCanDrive"] = unitData.playerCanDrive -- added to DBs + + + if newData.category == 'plane' or newData.category == 'helicopter' then + newData.units[unitNum]["payload"] = payloads[unitNum] + newData.units[unitNum]['livery_id'] = unitData.livery_id + newData.units[unitNum]['onboard_num'] = unitData.onboard_num + newData.units[unitNum]['callsign'] = unitData.callsign + newData.units[unitNum]['AddPropAircraft'] = unitData.AddPropAircraft + end + if newData.category == 'static' then + newData.units[unitNum]['categoryStatic'] = unitData.categoryStatic + newData.units[unitNum]['mass'] = unitData.mass + newData.units[unitNum]['canCargo'] = unitData.canCargo + newData.units[unitNum]['shape_name'] = unitData.shape_name + end + end + + return newData + else + env.info(gpName .. ' not found in mist.getGroupData') + return + end end mist.getPayload = function(unitIdent) - -- refactor to search by groupId and allow groupId and groupName as inputs - local unitId = unitIdent - if type(unitIdent) == 'string' and not tonumber(unitIdent) then - unitId = mist.DBs.MEunitsByName[unitIdent].unitId - end - local gpId = mist.DBs.MEunitsById[unitId].groupId - - if gpId and unitId then - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then - for unitIndex, unitData in pairs(group_data.units) do --group index - if unitData.unitId == unitId then - return unitData.payload - end - end - end - end - end - end - end - end - end - end - end - else - env.info('mist.getPayload got ' .. type(unitIdent)) - return false - end - env.info('mist.getPayload, payload not found') - return + -- refactor to search by groupId and allow groupId and groupName as inputs + local unitId = unitIdent + if type(unitIdent) == 'string' and not tonumber(unitIdent) then + unitId = mist.DBs.MEunitsByName[unitIdent].unitId + end + local gpId = mist.DBs.MEunitsById[unitId].groupId + + if gpId and unitId then + for coa_name, coa_data in pairs(env.mission.coalition) do + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + for obj_type_name, obj_type_data in pairs(cntry_data) do + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + for group_num, group_data in pairs(obj_type_data.group) do + if group_data and group_data.groupId == gpId then + for unitIndex, unitData in pairs(group_data.units) do --group index + if unitData.unitId == unitId then + return unitData.payload + end + end + end + end + end + end + end + end + end + end + end + else + env.info('mist.getPayload got ' .. type(unitIdent)) + return false + end + env.info('mist.getPayload, payload not found') + return end mist.getGroupPayload = function(groupIdent) - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - end - - if gpId then - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then - local payloads = {} - for unitIndex, unitData in pairs(group_data.units) do --group index - payloads[unitIndex] = unitData.payload - end - return payloads - end - end - end - end - end - end - end - end - end - else - env.info('mist.getGroupPayload got ' .. type(groupName)) - return false - end - env.info('mist.getGroupPayload, payload not found') - return + local gpId = groupIdent + if type(groupIdent) == 'string' and not tonumber(groupIdent) then + gpId = mist.DBs.MEgroupsByName[groupIdent].groupId + end + + if gpId then + for coa_name, coa_data in pairs(env.mission.coalition) do + if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + for obj_type_name, obj_type_data in pairs(cntry_data) do + if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! + for group_num, group_data in pairs(obj_type_data.group) do + if group_data and group_data.groupId == gpId then + local payloads = {} + for unitIndex, unitData in pairs(group_data.units) do --group index + payloads[unitIndex] = unitData.payload + end + return payloads + end + end + end + end + end + end + end + end + end + else + env.info('mist.getGroupPayload got ' .. type(groupName)) + return false + end + env.info('mist.getGroupPayload, payload not found') + return end mist.teleportToPoint = function(vars) -- main teleport function that all of teleport/respawn functions call - local point = vars.point - - local gpName - if vars.gpName then - gpName = vars.gpName - elseif vars.groupName then - gpName = vars.groupName - else - env.info('teleportToPoint missing either vars.groupName or vars.gpName') - end - - local action = vars.action - - local disperse = vars.disperse or false - local maxDisp = vars.maxDisp - if not vars.maxDisp then - maxDisp = 200 - else - maxDisp = vars.maxDisp - end - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - - local route = vars.route - local dbData = false - - local newGroupData - if gpName and not vars.groupData then - if string.lower(action) == 'teleport' or string.lower(action) == 'tele' then - newGroupData = mist.getCurrentGroupData(gpName) - elseif string.lower(action) == 'respawn' then - newGroupData = mist.getGroupData(gpName) - dbData = true - elseif string.lower(action) == 'clone' then - newGroupData = mist.getGroupData(gpName) - newGroupData.clone = 'order66' - dbData = true - else - action = 'tele' - newGroupData = mist.getCurrentGroupData(gpName) - end - else - action = 'tele' - newGroupData = vars.groupData - end + local point = vars.point + + local gpName + if vars.gpName then + gpName = vars.gpName + elseif vars.groupName then + gpName = vars.groupName + else + env.info('teleportToPoint missing either vars.groupName or vars.gpName') + end + + local action = vars.action + + local disperse = vars.disperse or false + local maxDisp = vars.maxDisp + if not vars.maxDisp then + maxDisp = 200 + else + maxDisp = vars.maxDisp + end + local radius = vars.radius or 0 + local innerRadius = vars.innerRadius + + local route = vars.route + local dbData = false + + local newGroupData + if gpName and not vars.groupData then + if string.lower(action) == 'teleport' or string.lower(action) == 'tele' then + newGroupData = mist.getCurrentGroupData(gpName) + elseif string.lower(action) == 'respawn' then + newGroupData = mist.getGroupData(gpName) + dbData = true + elseif string.lower(action) == 'clone' then + newGroupData = mist.getGroupData(gpName) + newGroupData.clone = 'order66' + dbData = true + else + action = 'tele' + newGroupData = mist.getCurrentGroupData(gpName) + end + else + action = 'tele' + newGroupData = vars.groupData + end - local diff = {['x'] = 0, ['y'] = 0} - local newCoord, origCoord - if point then - local valid = false - - local validTerrain - if string.lower(newGroupData.category) == 'ship' then - validTerrain = {'SHALLOW_WATER' , 'WATER'} - elseif string.lower(newGroupData.category) == 'vehicle' then - validTerrain = {'LAND', 'ROAD'} - else - validTerrain = {'LAND', 'ROAD', 'SHALLOW_WATER', 'WATER', 'RUNWAY'} - end - - for i = 1, 100 do - newCoord = mist.getRandPointInCircle(point, radius, innerRadius) - if mist.isTerrainValid(newCoord, validTerrain) then - origCoord = mist.utils.deepCopy(newCoord) - diff = {['x'] = (newCoord.x - newGroupData.units[1].x), ['y'] = (newCoord.y - newGroupData.units[1].y)} - valid = true - break - end - end - if valid == false then - env.info('mist.teleportToPoint; vars.point not a valid coordinate') - return false - end - end - if not newGroupData.country and mist.DBs.groupsByName[newGroupData.groupName].country then - newGroupData.country = mist.DBs.groupsByName[newGroupData.groupName].country - end - if not newGroupData.category and mist.DBs.groupsByName[newGroupData.groupName].category then - newGroupData.category = mist.DBs.groupsByName[newGroupData.groupName].category - end - - for unitNum, unitData in pairs(newGroupData.units) do - if disperse then - if maxDisp and type(maxDisp) == 'number' and unitNum ~= 1 then - newCoord = mist.getRandPointInCircle(origCoord, maxDisp) - --else - --newCoord = mist.getRandPointInCircle(zone.point, zone.radius) - end + local diff = {['x'] = 0, ['y'] = 0} + local newCoord, origCoord + if point then + local valid = false + + local validTerrain + if string.lower(newGroupData.category) == 'ship' then + validTerrain = {'SHALLOW_WATER' , 'WATER'} + elseif string.lower(newGroupData.category) == 'vehicle' then + validTerrain = {'LAND', 'ROAD'} + else + validTerrain = {'LAND', 'ROAD', 'SHALLOW_WATER', 'WATER', 'RUNWAY'} + end + + for i = 1, 100 do + newCoord = mist.getRandPointInCircle(point, radius, innerRadius) + if mist.isTerrainValid(newCoord, validTerrain) then + origCoord = mist.utils.deepCopy(newCoord) + diff = {['x'] = (newCoord.x - newGroupData.units[1].x), ['y'] = (newCoord.y - newGroupData.units[1].y)} + valid = true + break + end + end + if valid == false then + env.info('mist.teleportToPoint; vars.point not a valid coordinate') + return false + end + end + if not newGroupData.country and mist.DBs.groupsByName[newGroupData.groupName].country then + newGroupData.country = mist.DBs.groupsByName[newGroupData.groupName].country + end + if not newGroupData.category and mist.DBs.groupsByName[newGroupData.groupName].category then + newGroupData.category = mist.DBs.groupsByName[newGroupData.groupName].category + end + + for unitNum, unitData in pairs(newGroupData.units) do + if disperse then + if maxDisp and type(maxDisp) == 'number' and unitNum ~= 1 then + newCoord = mist.getRandPointInCircle(origCoord, maxDisp) + --else + --newCoord = mist.getRandPointInCircle(zone.point, zone.radius) + end - newGroupData.units[unitNum]['x'] = newCoord.x - newGroupData.units[unitNum]['y'] = newCoord.y - else - newGroupData.units[unitNum]["x"] = unitData.x + diff.x - newGroupData.units[unitNum]["y"] = unitData.y + diff.y - end - if point then - if (newGroupData.category == 'plane' or newGroupData.category == 'helicopter') then - if point.z and point.y > 0 and point.y > land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + 10 then - newGroupData.units[unitNum]["alt"] = point.y - else - if newGroupData.category == 'plane' then - newGroupData.units[unitNum]["alt"] = land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + math.random(300, 9000) - else - newGroupData.units[unitNum]["alt"] = land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + math.random(200, 3000) - end - end - end - end - end - - if newGroupData.start_time then - newGroupData.startTime = newGroupData.start_time - end - - if newGroupData.startTime and newGroupData.startTime ~= 0 and dbData == true then - local timeDif = timer.getAbsTime() - timer.getTime0() - if timeDif > newGroupData.startTime then - newGroupData.startTime = 0 - else - newGroupData.startTime = newGroupData.startTime - timeDif - end - - end + newGroupData.units[unitNum]['x'] = newCoord.x + newGroupData.units[unitNum]['y'] = newCoord.y + else + newGroupData.units[unitNum]["x"] = unitData.x + diff.x + newGroupData.units[unitNum]["y"] = unitData.y + diff.y + end + if point then + if (newGroupData.category == 'plane' or newGroupData.category == 'helicopter') then + if point.z and point.y > 0 and point.y > land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + 10 then + newGroupData.units[unitNum]["alt"] = point.y + else + if newGroupData.category == 'plane' then + newGroupData.units[unitNum]["alt"] = land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + math.random(300, 9000) + else + newGroupData.units[unitNum]["alt"] = land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + math.random(200, 3000) + end + end + end + end + end + + if newGroupData.start_time then + newGroupData.startTime = newGroupData.start_time + end + + if newGroupData.startTime and newGroupData.startTime ~= 0 and dbData == true then + local timeDif = timer.getAbsTime() - timer.getTime0() + if timeDif > newGroupData.startTime then + newGroupData.startTime = 0 + else + newGroupData.startTime = newGroupData.startTime - timeDif + end + + end - if route then - newGroupData.route = route - end - --mist.debug.writeData(mist.utils.serialize,{'teleportToPoint', newGroupData}, 'newGroupData.lua') - if string.lower(newGroupData.category) == 'static' then - return mist.dynAddStatic(newGroupData) - end - return mist.dynAdd(newGroupData) - + if route then + newGroupData.route = route + end + --mist.debug.writeData(mist.utils.serialize,{'teleportToPoint', newGroupData}, 'newGroupData.lua') + if string.lower(newGroupData.category) == 'static' then + return mist.dynAddStatic(newGroupData) + end + return mist.dynAdd(newGroupData) + end mist.respawnInZone = function(gpName, zone, disperse, maxDisp) - if type(gpName) == 'table' and gpName:getName() then - gpName = gpName:getName() - elseif type(gpName) == 'table' and gpName[1]:getName() then - gpName = math.random(#gpName) - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end - local vars = {} - vars.gpName = gpName - vars.action = 'respawn' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - return mist.teleportToPoint(vars) + if type(gpName) == 'table' and gpName:getName() then + gpName = gpName:getName() + elseif type(gpName) == 'table' and gpName[1]:getName() then + gpName = math.random(#gpName) + else + gpName = tostring(gpName) + end + + if type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + elseif type(zone) == 'table' and not zone.radius then + zone = trigger.misc.getZone(zone[math.random(1, #zone)]) + end + local vars = {} + vars.gpName = gpName + vars.action = 'respawn' + vars.point = zone.point + vars.radius = zone.radius + vars.disperse = disperse + vars.maxDisp = maxDisp + return mist.teleportToPoint(vars) end mist.cloneInZone = function(gpName, zone, disperse, maxDisp) - - if type(gpName) == 'table' then - gpName = gpName:getName() - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end - local vars = {} - vars.gpName = gpName - vars.action = 'clone' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - return mist.teleportToPoint(vars) + + if type(gpName) == 'table' then + gpName = gpName:getName() + else + gpName = tostring(gpName) + end + + if type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + elseif type(zone) == 'table' and not zone.radius then + zone = trigger.misc.getZone(zone[math.random(1, #zone)]) + end + local vars = {} + vars.gpName = gpName + vars.action = 'clone' + vars.point = zone.point + vars.radius = zone.radius + vars.disperse = disperse + vars.maxDisp = maxDisp + return mist.teleportToPoint(vars) end mist.teleportInZone = function(gpName, zone, disperse, maxDisp) -- groupName, zoneName or table of Zone Names, keepForm is a boolean - if type(gpName) == 'table' and gpName:getName() then - gpName = gpName:getName() - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end - - local vars = {} - vars.gpName = gpName - vars.action = 'tele' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - return mist.teleportToPoint(vars) + if type(gpName) == 'table' and gpName:getName() then + gpName = gpName:getName() + else + gpName = tostring(gpName) + end + + if type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + elseif type(zone) == 'table' and not zone.radius then + zone = trigger.misc.getZone(zone[math.random(1, #zone)]) + end + + local vars = {} + vars.gpName = gpName + vars.action = 'tele' + vars.point = zone.point + vars.radius = zone.radius + vars.disperse = disperse + vars.maxDisp = maxDisp + return mist.teleportToPoint(vars) end mist.respawnGroup = function(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'respawn' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup + local vars = {} + vars.gpName = gpName + vars.action = 'respawn' + if task and type(task) ~= 'number' then + vars.route = mist.getGroupRoute(gpName, 'task') + end + local newGroup = mist.teleportToPoint(vars) + if task and type(task) == 'number' then + local newRoute = mist.getGroupRoute(gpName, 'task') + mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) + end + return newGroup end mist.cloneGroup = function(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'clone' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup + local vars = {} + vars.gpName = gpName + vars.action = 'clone' + if task and type(task) ~= 'number' then + vars.route = mist.getGroupRoute(gpName, 'task') + end + local newGroup = mist.teleportToPoint(vars) + if task and type(task) == 'number' then + local newRoute = mist.getGroupRoute(gpName, 'task') + mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) + end + return newGroup end mist.teleportGroup = function(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'teleport' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup + local vars = {} + vars.gpName = gpName + vars.action = 'teleport' + if task and type(task) ~= 'number' then + vars.route = mist.getGroupRoute(gpName, 'task') + end + local newGroup = mist.teleportToPoint(vars) + if task and type(task) == 'number' then + local newRoute = mist.getGroupRoute(gpName, 'task') + mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) + end + return newGroup end mist.spawnRandomizedGroup = function(groupName, vars) -- need to debug - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - local gpData = mist.getGroupData(groupName) - gpData.units = mist.randomizeGroupOrder(gpData.units, vars) - gpData.route = mist.getGroupRoute(groupName, 'task') - - mist.dynAdd(gpData) - end - - return true + if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then + local gpData = mist.getGroupData(groupName) + gpData.units = mist.randomizeGroupOrder(gpData.units, vars) + gpData.route = mist.getGroupRoute(groupName, 'task') + + mist.dynAdd(gpData) + end + + return true end - + mist.randomizeNumTable = function(vars) - local newTable = {} - - local excludeIndex = {} - local randomTable = {} - - if vars and vars.exclude and type(vars.exclude) == 'table' then - for index, data in pairs(vars.exclude) do - excludeIndex[data] = true - end - end - - local low, hi, size - - if vars.size then - size = vars.size - end - - if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then - low = mist.utils.round(vars.lowerLimit) - else - low = 1 - end - - if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then - hi = mist.utils.round(vars.upperLimit) - else - hi = size - end + local newTable = {} + + local excludeIndex = {} + local randomTable = {} + + if vars and vars.exclude and type(vars.exclude) == 'table' then + for index, data in pairs(vars.exclude) do + excludeIndex[data] = true + end + end + + local low, hi, size + + if vars.size then + size = vars.size + end + + if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then + low = mist.utils.round(vars.lowerLimit) + else + low = 1 + end + + if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then + hi = mist.utils.round(vars.upperLimit) + else + hi = size + end - local choices = {} - -- add to exclude list and create list of what to randomize - for i = 1, size do - if not (i >= low and i <= hi) then + local choices = {} + -- add to exclude list and create list of what to randomize + for i = 1, size do + if not (i >= low and i <= hi) then - excludeIndex[i] = true - end - if not excludeIndex[i] then - table.insert(choices, i) - else - newTable[i] = i - end - end + excludeIndex[i] = true + end + if not excludeIndex[i] then + table.insert(choices, i) + else + newTable[i] = i + end + end - for ind, num in pairs(choices) do - local found = false - local x = 0 - while found == false do - x = mist.random(size) -- get random number from list - local addNew = true - for index, _ in pairs(excludeIndex) do - if index == x then - addNew = false - break - end - end - if addNew == true then - excludeIndex[x] = true - found = true - end - excludeIndex[x] = true - - end - newTable[num] = x - end - --[[ - for i = 1, #newTable do - env.info(newTable[i]) - end - ]] - return newTable + for ind, num in pairs(choices) do + local found = false + local x = 0 + while found == false do + x = mist.random(size) -- get random number from list + local addNew = true + for index, _ in pairs(excludeIndex) do + if index == x then + addNew = false + break + end + end + if addNew == true then + excludeIndex[x] = true + found = true + end + excludeIndex[x] = true + + end + newTable[num] = x + end + --[[ + for i = 1, #newTable do + env.info(newTable[i]) + end + ]] + return newTable end mist.randomizeGroupOrder = function(passedUnits, vars) - -- figure out what to exclude, and send data to other func - local units = passedUnits - - if passedUnits.units then - units = passUnits.units - end - - local exclude = {} - local excludeNum = {} - if vars and vars.excludeType and type(vars.excludeType) == 'table' then - exclude = vars.excludeType - end - - if vars and vars.excludeNum and type(vars.excludeNum) == 'table' then - excludeNum = vars.excludeNum - end - - local low, hi - - if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then - low = mist.utils.round(vars.lowerLimit) - else - low = 1 - end - - if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then - hi = mist.utils.round(vars.upperLimit) - else - hi = #units - end - + -- figure out what to exclude, and send data to other func + local units = passedUnits + + if passedUnits.units then + units = passUnits.units + end + + local exclude = {} + local excludeNum = {} + if vars and vars.excludeType and type(vars.excludeType) == 'table' then + exclude = vars.excludeType + end + + if vars and vars.excludeNum and type(vars.excludeNum) == 'table' then + excludeNum = vars.excludeNum + end + + local low, hi + + if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then + low = mist.utils.round(vars.lowerLimit) + else + low = 1 + end + + if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then + hi = mist.utils.round(vars.upperLimit) + else + hi = #units + end + - local excludeNum = {} - for unitIndex, unitData in pairs(units) do - if unitIndex >= low and unitIndex <= hi then -- if within range - local found = false - if #exclude > 0 then - for excludeType, index in pairs(exclude) do -- check if excluded - if mist.stringMatch(excludeType, unitData.type) then -- if excluded - excludeNum[unitIndex] = unitIndex - found = true - end - end - end - else -- unitIndex is either to low, or to high: added to exclude list - excludeNum[unitIndex] = unitId - end - end - - local newGroup = {} - local newOrder = mist.randomizeNumTable({exclude = excludeNum, size = #units}) + local excludeNum = {} + for unitIndex, unitData in pairs(units) do + if unitIndex >= low and unitIndex <= hi then -- if within range + local found = false + if #exclude > 0 then + for excludeType, index in pairs(exclude) do -- check if excluded + if mist.stringMatch(excludeType, unitData.type) then -- if excluded + excludeNum[unitIndex] = unitIndex + found = true + end + end + end + else -- unitIndex is either to low, or to high: added to exclude list + excludeNum[unitIndex] = unitId + end + end + + local newGroup = {} + local newOrder = mist.randomizeNumTable({exclude = excludeNum, size = #units}) - for unitIndex, unitData in pairs(units) do - for i = 1, #newOrder do - if newOrder[i] == unitIndex then - newGroup[i] = mist.utils.deepCopy(units[i]) -- gets all of the unit data - newGroup[i].type = mist.utils.deepCopy(unitData.type) - newGroup[i].skill = mist.utils.deepCopy(unitData.skill) - newGroup[i].unitName = mist.utils.deepCopy(unitData.unitName) - newGroup[i].unitIndex = mist.utils.deepCopy(unitData.unitIndex) -- replaces the units data with a new type - end - end - end - return newGroup -end + for unitIndex, unitData in pairs(units) do + for i = 1, #newOrder do + if newOrder[i] == unitIndex then + newGroup[i] = mist.utils.deepCopy(units[i]) -- gets all of the unit data + newGroup[i].type = mist.utils.deepCopy(unitData.type) + newGroup[i].skill = mist.utils.deepCopy(unitData.skill) + newGroup[i].unitName = mist.utils.deepCopy(unitData.unitName) + newGroup[i].unitIndex = mist.utils.deepCopy(unitData.unitIndex) -- replaces the units data with a new type + end + end + end + return newGroup +end mist.ground.patrolRoute = function(vars) - - - local tempRoute = {} - local useRoute = {} - local gpData = vars.gpData - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - local useGroupRoute - if not vars.useGroupRoute then - useGroupRoute = vars.gpData - else - useGroupRoute = vars.useGroupRoute - end - local routeProvided = false - if not vars.route then - if useGroupRoute then - tempRoute = mist.getGroupRoute(useGroupRoute) - end - else - useRoute = vars.route - local posStart = mist.getLeadPos(gpData) - useRoute[1] = mist.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) - routeProvided = true - end - - - local overRideSpeed = vars.speed or 'default' - local pType = vars.pType - local offRoadForm = vars.offRoadForm or 'default' - local onRoadForm = vars.onRoadForm or 'default' - - if routeProvided == false and #tempRoute > 0 then - local posStart = mist.getLeadPos(gpData) - - - useRoute[#useRoute + 1] = mist.ground.buildWP(posStart, offRoadForm, overRideSpeed) - for i = 1, #tempRoute do - local tempForm = tempRoute[i].action - local tempSpeed = tempRoute[i].speed - - if offRoadForm == 'default' then - tempForm = tempRoute[i].action - end - if onRoadForm == 'default' then - onRoadForm = 'On Road' - end - if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then - tempForm = onRoadForm - else - tempForm = offRoadForm - end - - if type(overRideSpeed) == 'number' then - tempSpeed = overRideSpeed - end - - - useRoute[#useRoute + 1] = mist.ground.buildWP(tempRoute[i], tempForm, tempSpeed) - end - - if pType and string.lower(pType) == 'doubleback' then - local curRoute = mist.utils.deepCopy(useRoute) - for i = #curRoute, 2, -1 do - useRoute[#useRoute + 1] = mist.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) - end - end - - useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP - end - - local cTask3 = {} - local newPatrol = {} - newPatrol.route = useRoute - newPatrol.gpData = gpData:getName() - cTask3[#cTask3 + 1] = 'mist.ground.patrolRoute(' - cTask3[#cTask3 + 1] = mist.utils.oneLineSerialize(newPatrol) - cTask3[#cTask3 + 1] = ')' - cTask3 = table.concat(cTask3) - local tempTask = { - id = 'WrappedAction', - params = { - action = { - id = 'Script', - params = { - command = cTask3, - - }, - }, - }, - } + + + local tempRoute = {} + local useRoute = {} + local gpData = vars.gpData + if type(gpData) == 'string' then + gpData = Group.getByName(gpData) + end + + local useGroupRoute + if not vars.useGroupRoute then + useGroupRoute = vars.gpData + else + useGroupRoute = vars.useGroupRoute + end + local routeProvided = false + if not vars.route then + if useGroupRoute then + tempRoute = mist.getGroupRoute(useGroupRoute) + end + else + useRoute = vars.route + local posStart = mist.getLeadPos(gpData) + useRoute[1] = mist.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) + routeProvided = true + end + + + local overRideSpeed = vars.speed or 'default' + local pType = vars.pType + local offRoadForm = vars.offRoadForm or 'default' + local onRoadForm = vars.onRoadForm or 'default' + + if routeProvided == false and #tempRoute > 0 then + local posStart = mist.getLeadPos(gpData) + + + useRoute[#useRoute + 1] = mist.ground.buildWP(posStart, offRoadForm, overRideSpeed) + for i = 1, #tempRoute do + local tempForm = tempRoute[i].action + local tempSpeed = tempRoute[i].speed + + if offRoadForm == 'default' then + tempForm = tempRoute[i].action + end + if onRoadForm == 'default' then + onRoadForm = 'On Road' + end + if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then + tempForm = onRoadForm + else + tempForm = offRoadForm + end + + if type(overRideSpeed) == 'number' then + tempSpeed = overRideSpeed + end + + + useRoute[#useRoute + 1] = mist.ground.buildWP(tempRoute[i], tempForm, tempSpeed) + end + + if pType and string.lower(pType) == 'doubleback' then + local curRoute = mist.utils.deepCopy(useRoute) + for i = #curRoute, 2, -1 do + useRoute[#useRoute + 1] = mist.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) + end + end + + useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP + end + + local cTask3 = {} + local newPatrol = {} + newPatrol.route = useRoute + newPatrol.gpData = gpData:getName() + cTask3[#cTask3 + 1] = 'mist.ground.patrolRoute(' + cTask3[#cTask3 + 1] = mist.utils.oneLineSerialize(newPatrol) + cTask3[#cTask3 + 1] = ')' + cTask3 = table.concat(cTask3) + local tempTask = { + id = 'WrappedAction', + params = { + action = { + id = 'Script', + params = { + command = cTask3, + + }, + }, + }, + } - - useRoute[#useRoute].task = tempTask - mist.goRoute(gpData, useRoute) - - return + + useRoute[#useRoute].task = tempTask + mist.goRoute(gpData, useRoute) + + return end mist.ground.patrol = function(gpData, pType, form, speed) - local vars = {} - - if type(gpData) == 'table' and gpData:getName() then - gpData = gpData:getName() - end - - vars.useGroupRoute = gpData - vars.gpData = gpData - vars.pType = pType - vars.offRoadForm = form - vars.speed = speed - - mist.ground.patrolRoute(vars) + local vars = {} + + if type(gpData) == 'table' and gpData:getName() then + gpData = gpData:getName() + end + + vars.useGroupRoute = gpData + vars.gpData = gpData + vars.pType = pType + vars.offRoadForm = form + vars.speed = speed + + mist.ground.patrolRoute(vars) - return + return end mist.random = function(firstNum, secondNum) -- no support for decimals - local lowNum, highNum - if not secondNum then - highNum = firstNum - lowNum = 1 - else - lowNum = firstNum - highNum = secondNum - end - local total = 1 - if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50 - total = math.modf(50/math.abs(highNum - lowNum + 1)) -- make x copies required to be above 50 - end - local choices = {} - for i = 1, total do -- iterate required number of times - for x = lowNum, highNum do -- iterate between the range - choices[#choices +1] = x -- add each entry to a table - end - end - local rtnVal = math.random(#choices) -- will now do a math.random of at least 50 choices - for i = 1, 10 do - rtnVal = math.random(#choices) -- iterate a few times for giggles - end - return choices[rtnVal] + local lowNum, highNum + if not secondNum then + highNum = firstNum + lowNum = 1 + else + lowNum = firstNum + highNum = secondNum + end + local total = 1 + if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50 + total = math.modf(50/math.abs(highNum - lowNum + 1)) -- make x copies required to be above 50 + end + local choices = {} + for i = 1, total do -- iterate required number of times + for x = lowNum, highNum do -- iterate between the range + choices[#choices +1] = x -- add each entry to a table + end + end + local rtnVal = math.random(#choices) -- will now do a math.random of at least 50 choices + for i = 1, 10 do + rtnVal = math.random(#choices) -- iterate a few times for giggles + end + return choices[rtnVal] end mist.stringMatch = function(s1, s2, bool) - local exclude = {'%-', '%(', '%)', '%_', '%[', '%]', '%.', '%#', '% ', '%{', '%}', '%$', '%%', '%?', '%+', '%^'} - if type(s1) == 'string' and type(s2) == 'string' then - for i , str in pairs(exclude) do - s1 = string.gsub(s1, str, '') - s2 = string.gsub(s2, str, '') - end - if not bool then - s1 = string.lower(s1) - s2 = string.lower(s2) - end - - if s1 == s2 then - return true - else - return false - end - else - env.info('mist.stringMatch; Either the first or second variable were not a string') - return false - end + local exclude = {'%-', '%(', '%)', '%_', '%[', '%]', '%.', '%#', '% ', '%{', '%}', '%$', '%%', '%?', '%+', '%^'} + if type(s1) == 'string' and type(s2) == 'string' then + for i , str in pairs(exclude) do + s1 = string.gsub(s1, str, '') + s2 = string.gsub(s2, str, '') + end + if not bool then + s1 = string.lower(s1) + s2 = string.lower(s2) + end + + if s1 == s2 then + return true + else + return false + end + else + env.info('mist.stringMatch; Either the first or second variable were not a string') + return false + end end mist.matchString = mist.stringMatch -- both commands work because order out type of I @@ -5751,88 +5822,88 @@ mist.time = {} -- if present current time in mil time is returned -- if number or table the time is converted into mil tim mist.time.convertToSec = function(timeTable) - - timeInSec = 0 - if timeTable and type(timeTable) == 'number' then - timeInSec = timeTable - elseif timeTable and type(timeTable) == 'table' and (timeTable.d or timeTable.h or timeTable.m or timeTable.s) then - if timeTable.d and type(timeTable.d) == 'number' then - timeInSec = timeInSec + (timeTable.d*86400) - end - if timeTable.h and type(timeTable.h) == 'number' then - timeInSec = timeInSec + (timeTable.h*3600) - end - if timeTable.m and type(timeTable.m) == 'number' then - timeInSec = timeInSec + (timeTable.m*60) - end - if timeTable.s and type(timeTable.s) == 'number' then - timeInSec = timeInSec + timeTable.s - end - - end - return timeInSec + + timeInSec = 0 + if timeTable and type(timeTable) == 'number' then + timeInSec = timeTable + elseif timeTable and type(timeTable) == 'table' and (timeTable.d or timeTable.h or timeTable.m or timeTable.s) then + if timeTable.d and type(timeTable.d) == 'number' then + timeInSec = timeInSec + (timeTable.d*86400) + end + if timeTable.h and type(timeTable.h) == 'number' then + timeInSec = timeInSec + (timeTable.h*3600) + end + if timeTable.m and type(timeTable.m) == 'number' then + timeInSec = timeInSec + (timeTable.m*60) + end + if timeTable.s and type(timeTable.s) == 'number' then + timeInSec = timeInSec + timeTable.s + end + + end + return timeInSec end mist.time.getDHMS = function(timeInSec) - if timeInSec and type(timeInSec) == 'number' then - local tbl = {d = 0, h = 0, m = 0, s = 0} - if timeInSec > 86400 then - while timeInSec > 86400 do - tbl.d = tbl.d + 1 - timeInSec = timeInSec - 86400 - end - end - if timeInSec > 3600 then - while timeInSec > 3600 do - tbl.h = tbl.h + 1 - timeInSec = timeInSec - 3600 - end - end - if timeInSec > 60 then - while timeInSec > 60 do - tbl.m = tbl.m + 1 - timeInSec = timeInSec - 60 - end - end - tbl.s = timeInSec - return tbl - else - env.info('mist.time.getDHMS didnt recieve number') - return - end + if timeInSec and type(timeInSec) == 'number' then + local tbl = {d = 0, h = 0, m = 0, s = 0} + if timeInSec > 86400 then + while timeInSec > 86400 do + tbl.d = tbl.d + 1 + timeInSec = timeInSec - 86400 + end + end + if timeInSec > 3600 then + while timeInSec > 3600 do + tbl.h = tbl.h + 1 + timeInSec = timeInSec - 3600 + end + end + if timeInSec > 60 then + while timeInSec > 60 do + tbl.m = tbl.m + 1 + timeInSec = timeInSec - 60 + end + end + tbl.s = timeInSec + return tbl + else + env.info('mist.time.getDHMS didnt recieve number') + return + end end mist.getMilString = function(theTime) - local timeInSec = 0 - if theTime then - timeInSec = mist.time.convertToSec(theTime) - else - timeInSec = mist.utils.round(timer.getAbsTime(), 0) - end - - local DHMS = mist.time.getDHMS(timeInSec) - - return tostring(string.format('%02d', DHMS.h) .. string.format('%02d',DHMS.m)) + local timeInSec = 0 + if theTime then + timeInSec = mist.time.convertToSec(theTime) + else + timeInSec = mist.utils.round(timer.getAbsTime(), 0) + end + + local DHMS = mist.time.getDHMS(timeInSec) + + return tostring(string.format('%02d', DHMS.h) .. string.format('%02d',DHMS.m)) end mist.getClockString = function(theTime, hour) - local timeInSec = 0 - if theTime then - timeInSec = mist.time.convertToSec(theTime) - else - timeInSec = mist.utils.round(timer.getAbsTime(), 0) - end - local DHMS = mist.time.getDHMS(timeInSec) - if hour then - if DHMS.h > 12 then - DHMS.h = DHMS.h - 12 - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' PM') - else - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' AM') - end - else - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s)) - end + local timeInSec = 0 + if theTime then + timeInSec = mist.time.convertToSec(theTime) + else + timeInSec = mist.utils.round(timer.getAbsTime(), 0) + end + local DHMS = mist.time.getDHMS(timeInSec) + if hour then + if DHMS.h > 12 then + DHMS.h = DHMS.h - 12 + return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' PM') + else + return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' AM') + end + else + return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s)) + end end -- returns the date in string format @@ -5840,196 +5911,196 @@ end -- first val returns with the month as a string -- 2nd val defins if it should be written the American way or the wrong way. mist.time.getDate = function(convert) - local cal = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -- starts at june. 2011. 2012 is leap year, sigh. add a simple check for leap year - local date = {} - date.d = 0 - date.m = 6 - date.y = 2011 + local cal = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -- starts at june. 2011. 2012 is leap year, sigh. add a simple check for leap year + local date = {} + date.d = 0 + date.m = 6 + date.y = 2011 - local start = 0 - local timeInSec = mist.utils.round(timer.getAbsTime()) - if convert and type(convert) == 'number' then - timeInSec = convert - end - - while start < timeInSec do - - if date.d == cal[date.m] then - --if y % 4 >= 0 and i == 2 then -- for leap year. DCS doesnt do leapyear, but I am keeping the code dormant because maybe with WW2 the mission year may become relevant - - --else - date.m = date.m + 1 - date.d = 0 - --end - end - if date.m == 13 then - date.m = 1 - date.y = date.y + 1 - end - date.d = date.d + 1 - start = start + 86400 - end - return date + local start = 0 + local timeInSec = mist.utils.round(timer.getAbsTime()) + if convert and type(convert) == 'number' then + timeInSec = convert + end + + while start < timeInSec do + + if date.d == cal[date.m] then + --if y % 4 >= 0 and i == 2 then -- for leap year. DCS doesnt do leapyear, but I am keeping the code dormant because maybe with WW2 the mission year may become relevant + + --else + date.m = date.m + 1 + date.d = 0 + --end + end + if date.m == 13 then + date.m = 1 + date.y = date.y + 1 + end + date.d = date.d + 1 + start = start + 86400 + end + return date end mist.time.relativeToStart = function(time) - if type(time) == 'number' then - return time - timer.getTime0() - end + if type(time) == 'number' then + return time - timer.getTime0() + end end mist.getDateString = function(rtnType, murica, oTime) -- returns date based on time - local word = {'January', 'Feburary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' } -- 'etc - local curTime = 0 - if oTime then - curTime = oTime - else - curTime = mist.utils.round(timer.getAbsTime()) - end - local tbl = mist.time.getDate(curTime) - - if rtnType then - if murica then - return tostring(word[tbl.m] .. ' ' .. tbl.d .. ' ' .. tbl.y) - else - return tostring(tbl.d .. ' ' .. word[tbl.m] .. ' ' .. tbl.y) - end - else - if murica then - return tostring(tbl.m .. '.' .. tbl.d .. '.' .. tbl.y) - else - return tostring(tbl.d .. '.' .. tbl.m .. '.' .. tbl.y) - end - end + local word = {'January', 'Feburary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' } -- 'etc + local curTime = 0 + if oTime then + curTime = oTime + else + curTime = mist.utils.round(timer.getAbsTime()) + end + local tbl = mist.time.getDate(curTime) + + if rtnType then + if murica then + return tostring(word[tbl.m] .. ' ' .. tbl.d .. ' ' .. tbl.y) + else + return tostring(tbl.d .. ' ' .. word[tbl.m] .. ' ' .. tbl.y) + end + else + if murica then + return tostring(tbl.m .. '.' .. tbl.d .. '.' .. tbl.y) + else + return tostring(tbl.d .. '.' .. tbl.m .. '.' .. tbl.y) + end + end end --WIP mist.time.milToGame = function(milString, rtnType) --converts a military time. By default returns the abosolute time that event would occur. With optional value it returns how many seconds from time of call till that time. - local curTime = mist.utils.round(timer.getAbsTime()) - local milTimeInSec = 0 + local curTime = mist.utils.round(timer.getAbsTime()) + local milTimeInSec = 0 - if milString and type(milString) == 'string' and string.len(milString) >= 4 then - local hr = tonumber(string.sub(milString, 1, 2)) - local mi = tonumber(string.sub(milString, 3)) - milTimeInSec = milTimeInSec + (mi*60) + (hr*3600) - elseif milString and type(milString) == 'table' and (milString.d or milString.h or milString.m or milString.s) then - milTimeInSec = mist.time.convertToSec(milString) - end - - local startTime = timer.getTime0() - local daysOffset = 0 - if startTime > 86400 then - daysOffset = mist.utils.round(startTime/86400) - if daysOffset > 0 then - milTimeInSec = milTimeInSec *daysOffset - end - end - - if curTime > milTimeInSec then - milTimeInSec = milTimeInSec + 86400 - end - if rtnType then - milTimeInSec = milTimeInSec - startTime - end - return milTimeInSec + if milString and type(milString) == 'string' and string.len(milString) >= 4 then + local hr = tonumber(string.sub(milString, 1, 2)) + local mi = tonumber(string.sub(milString, 3)) + milTimeInSec = milTimeInSec + (mi*60) + (hr*3600) + elseif milString and type(milString) == 'table' and (milString.d or milString.h or milString.m or milString.s) then + milTimeInSec = mist.time.convertToSec(milString) + end + + local startTime = timer.getTime0() + local daysOffset = 0 + if startTime > 86400 then + daysOffset = mist.utils.round(startTime/86400) + if daysOffset > 0 then + milTimeInSec = milTimeInSec *daysOffset + end + end + + if curTime > milTimeInSec then + milTimeInSec = milTimeInSec + 86400 + end + if rtnType then + milTimeInSec = milTimeInSec - startTime + end + return milTimeInSec end mist.DBs.const = {} --[[ - ['LAND'] = 1, - ['SHALLOW_WATER'] = 2, - ['WATER'] = 3, - ['ROAD'] = 4, - ['RUNWAY'] = 5 + ['LAND'] = 1, + ['SHALLOW_WATER'] = 2, + ['WATER'] = 3, + ['ROAD'] = 4, + ['RUNWAY'] = 5 ]] --[[mist.DBs.const.ME_SSE_terms = { - ['ME'] = { - ['vehicle'] = {'GROUND', 'GROUND_UNIT'}, - ['plane'] = {'AIRPLANE'}, - }, - ['SSE'] = { - }, + ['ME'] = { + ['vehicle'] = {'GROUND', 'GROUND_UNIT'}, + ['plane'] = {'AIRPLANE'}, + }, + ['SSE'] = { + }, }]] mist.DBs.const.callsigns = { -- not accessible by SSE, must use static list :-/ - ['NATO'] = { - ['rules'] = { - ['groupLimit'] = 9, - }, - ['AWACS'] = { - ['Overlord'] = 1, - ['Magic'] = 2, - ['Wizard'] = 3, - ['Focus'] = 4, - ['Darkstar'] = 5, - }, - ['TANKER'] = { - ['Texaco'] = 1, - ['Arco'] = 2, - ['Shell'] = 3, - }, - ['JTAC'] = { - ['Axeman'] = 1, - ['Darknight'] = 2, - ['Warrior'] = 3, - ['Pointer'] = 4, - ['Eyeball'] = 5, - ['Moonbeam'] = 6, - ['Whiplash'] = 7, - ['Finger'] = 8, - ['Pinpoint'] = 9, - ['Ferret'] = 10, - ['Shaba'] = 11, - ['Playboy'] = 12, - ['Hammer'] = 13, - ['Jaguar'] = 14, - ['Deathstar'] = 15, - ['Anvil'] = 16, - ['Firefly'] = 17, - ['Mantis'] = 18, - ['Badger'] = 19, - }, - ['aircraft'] = { - ['Enfield'] = 1, - ['Springfield'] = 2, - ['Uzi'] = 3, - ['Colt'] = 4, - ['Dodge'] = 5, - ['Ford'] = 6, - ['Chevy'] = 7, - ['Pontiac'] = 8, - }, - - ['unique'] = { - ['A10'] = { - ['Hawg'] = 9, - ['Boar'] = 10, - ['Pig'] = 11, - ['Tusk'] = 12, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'A-10C', - 'A-10A', - }, - }, - }, - }, - }, + ['NATO'] = { + ['rules'] = { + ['groupLimit'] = 9, + }, + ['AWACS'] = { + ['Overlord'] = 1, + ['Magic'] = 2, + ['Wizard'] = 3, + ['Focus'] = 4, + ['Darkstar'] = 5, + }, + ['TANKER'] = { + ['Texaco'] = 1, + ['Arco'] = 2, + ['Shell'] = 3, + }, + ['JTAC'] = { + ['Axeman'] = 1, + ['Darknight'] = 2, + ['Warrior'] = 3, + ['Pointer'] = 4, + ['Eyeball'] = 5, + ['Moonbeam'] = 6, + ['Whiplash'] = 7, + ['Finger'] = 8, + ['Pinpoint'] = 9, + ['Ferret'] = 10, + ['Shaba'] = 11, + ['Playboy'] = 12, + ['Hammer'] = 13, + ['Jaguar'] = 14, + ['Deathstar'] = 15, + ['Anvil'] = 16, + ['Firefly'] = 17, + ['Mantis'] = 18, + ['Badger'] = 19, + }, + ['aircraft'] = { + ['Enfield'] = 1, + ['Springfield'] = 2, + ['Uzi'] = 3, + ['Colt'] = 4, + ['Dodge'] = 5, + ['Ford'] = 6, + ['Chevy'] = 7, + ['Pontiac'] = 8, + }, + + ['unique'] = { + ['A10'] = { + ['Hawg'] = 9, + ['Boar'] = 10, + ['Pig'] = 11, + ['Tusk'] = 12, + ['rules'] = { + ['canUseAircraft'] = true, + ['appliesTo'] = { + 'A-10C', + 'A-10A', + }, + }, + }, + }, + }, } --[[ scope: - { - units = {...}, -- unit names. - coa = {...}, -- coa names - countries = {...}, -- country names - CA = {...}, -- looks just like coa. - unitTypes = { red = {}, blue = {}, all = {}, Russia = {},} - } - - + { + units = {...}, -- unit names. + coa = {...}, -- coa names + countries = {...}, -- country names + CA = {...}, -- looks just like coa. + unitTypes = { red = {}, blue = {}, all = {}, Russia = {},} + } + + scope examples: { units = { 'Hawg11', 'Hawg12' }, CA = {'blue'} } diff --git a/test-fob.miz b/test-fob.miz index fd2d500..7d97f9a 100644 Binary files a/test-fob.miz and b/test-fob.miz differ diff --git a/test-mission.miz b/test-mission.miz index e457ab3..cafc445 100644 Binary files a/test-mission.miz and b/test-mission.miz differ