From 6ee0d6a76d0533f037c67c11e723fa42c8673a59 Mon Sep 17 00:00:00 2001 From: Ciaran Fisher Date: Wed, 2 Dec 2015 09:03:16 +0000 Subject: [PATCH] Bug fix for AI Auto troop load --- CTLD.lua | 50 +- Pickup-Dropoff-Demo.miz | Bin 482235 -> 483779 bytes mist.lua | 4290 ++++++++++++++++++++------------------- test-mission.miz | Bin 496390 -> 496970 bytes 4 files changed, 2185 insertions(+), 2155 deletions(-) diff --git a/CTLD.lua b/CTLD.lua index 3ef3f15..b77a47c 100644 --- a/CTLD.lua +++ b/CTLD.lua @@ -13,9 +13,10 @@ Contributors: - Steggles - https://github.com/Bob7heBuilder - Version: 1.41 - 11/11/2015 - Added new callback interface + Version: 1.42 - 11/11/2015 - Added new callback interface - Added Different Pickup Groups for F10 and for the spawn group command - EWR now activates + - Bug fix for AI Group Load ]] @@ -1423,7 +1424,7 @@ function ctld.loadTroops(_heli, _troops, _numberOrTemplate) local _onboard = ctld.inTransitTroops[_heli:getName()] --number doesnt apply to vehicles - if _numberOrTemplate == nil then + if _numberOrTemplate == nil or (type(_numberOrTemplate) ~= "table" and type(_numberOrTemplate) ~= "number") then _numberOrTemplate = ctld.numberOfTroops end @@ -3848,36 +3849,45 @@ function ctld.checkAIStatus() timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 2) + for _, _unitName in pairs(ctld.transportPilotNames) do + local status, error = pcall(function() - local _unit = ctld.getTransportUnit(_unitName) + local _unit = ctld.getTransportUnit(_unitName) - -- no player name means AI! - if _unit ~= nil and _unit:getPlayerName() == nil then - local _zone = ctld.inPickupZone(_unit) + -- no player name means AI! + if _unit ~= nil and _unit:getPlayerName() == nil then + local _zone = ctld.inPickupZone(_unit) + -- env.error("Checking.. ".._unit:getName()) + if _zone.inZone == true and not ctld.troopsOnboard(_unit, true) then + -- env.error("in zone, loading.. ".._unit:getName()) + ctld.loadTroopsFromZone({ _unitName, true,"",true }) - if _zone.inZone == true and not ctld.troopsOnboard(_unit, true) then + elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, true) then + -- env.error("in dropoff zone, unloading.. ".._unit:getName()) + ctld.unloadTroops( { _unitName, true }) + end - ctld.loadTroopsFromZone({ _unitName, true,"",true }) + if ctld.unitCanCarryVehicles(_unit) then - elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, true) then + if _zone.inZone == true and not ctld.troopsOnboard(_unit, false) then - ctld.unloadTroops( { _unitName, true }) - end + ctld.loadTroopsFromZone({ _unitName, false,"",true }) - if ctld.unitCanCarryVehicles(_unit) then + elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, false) then - if _zone.inZone == true and not ctld.troopsOnboard(_unit, false) then - - ctld.loadTroopsFromZone({ _unitName, false,"",true }) - - elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, false) then - - ctld.unloadTroops( { _unitName, false }) + ctld.unloadTroops( { _unitName, false }) + end end end + end) + + if (not status) then + env.error(string.format("Error with ai status: %s", error), false) end end + + end @@ -5039,7 +5049,7 @@ end timer.scheduleFunction(ctld.refreshSmoke, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5) -timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 5) +timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 1) timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 5) timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 5) diff --git a/Pickup-Dropoff-Demo.miz b/Pickup-Dropoff-Demo.miz index 38fd6abe1c27d5e7a0661e1514d1a9cbf35f406d..c3a0c39800412b7184932b906318ebdb85cac0b8 100644 GIT binary patch delta 34766 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 delta 33232 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 Pm!n|^8U|un2LJ#7flMTJ diff --git a/mist.lua b/mist.lua index 84fca47..ad4d2d0 100644 --- a/mist.lua +++ b/mist.lua @@ -15,242 +15,242 @@ mist = {} -- don't change these mist.majorVersion = 4 mist.minorVersion = 0 -mist.build = 55 +mist.build = 57 -------------------------------------------------------------------------------------------------------------- -- 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 + 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 - 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 + -- 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 - 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 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) + + 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 - 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) + 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 - elseif newType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then - if catId == StaticObject.getByName(newTable.groupName):getCategory() then - newTable['category'] = string.lower(catData) + 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 - 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 + + if gfound == false then + newTable.uncontrolled = false + newTable.hidden = false end - 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) - 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 + 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[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 + 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 - 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 + - - + local function checkSpawnedEvents() if #tempSpawnedUnits > 0 then local groupsToAdd = {} @@ -267,36 +267,36 @@ do 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 + 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 + 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() + groupsToAdd[#groupsToAdd + 1] = spawnedObj:getGroup():getName() elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects - groupsToAdd[#groupsToAdd + 1] = spawnedObj:getName() + groupsToAdd[#groupsToAdd + 1] = spawnedObj:getName() end end end - + table.remove(ltemp, x) - if x%updatesPerRun == 0 then + if x%updatesPerRun == 0 then coroutine.yield() - end - + 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 @@ -306,8 +306,8 @@ do end end end - - + + local function updateDBTables() local i = 0 for index, newTable in pairs(writeGroups) do @@ -321,7 +321,7 @@ do local ldeepCopy = mist.utils.deepCopy for x = 1, i do local newTable = writeGroups[x] - local mistCategory + local mistCategory if type(newTable.category) == 'string' then mistCategory = string.lower(newTable.category) end @@ -337,19 +337,19 @@ do newTable['category'] = mistCategory elseif string.upper(newTable['category']) == 'SHIP' then mistCategory = 'ship' - newTable['category'] = mistCategory + 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) + 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) + 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 + -- 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 @@ -362,16 +362,16 @@ do 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 + if x%savesPerRun == 0 then coroutine.yield() end end @@ -380,65 +380,65 @@ do 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 - + 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 check_spawn_events_counter = check_spawn_events_counter + 1 - if check_spawn_events_counter == 10 then - + 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 + 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 -------------------------------------------- @@ -446,11 +446,11 @@ do local mistGpId = 7000 local mistUnitId = 7000 local mistDynAddIndex = 1 - - - mist.nextGroupId = 1 - mist.nextUnitId = 1 - + + + mist.nextGroupId = 1 + mist.nextUnitId = 1 + mist.getNextUnitId = function() mist.nextUnitId = mist.nextUnitId + 1 if mist.nextUnitId > 6900 then @@ -458,7 +458,7 @@ do end return mist.nextUnitId end - + mist.getNextGroupId = function() mist.nextGroupId = mist.nextGroupId + 1 if mist.nextGroupId > 6900 then @@ -466,20 +466,20 @@ do 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)) + table.insert(tempSpawnedUnits,(event.initiator)) end end - - - + + + mist.dynAddStatic = function(staticObj) local newObj = {} newObj.groupId = staticObj.groupId @@ -492,37 +492,39 @@ do 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.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 + 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 - - - newObj.country = staticObj.country - + if not newObj.country then return false end - - local newCountry - for countryName, countryId in pairs(country.id) do + + 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 @@ -533,30 +535,30 @@ do end end end - + if newObj.clone or not newObj.groupId then - mistGpId = mistGpId + 1 + mistGpId = mistGpId + 1 newObj.groupId = mistGpId end - + if newObj.clone or not newObj.unitId then - mistUnitId = mistUnitId + 1 + 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 @@ -568,21 +570,26 @@ do coalition.addStaticObject(country.id[newCountry], newObj) return newObj - end + 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 - -- +--Will generate groupId, groupName, unitId, and unitName if needed +-- + + - - --env.info('dynAdd') + --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 countryName, countryId in pairs(country.id) do + for countryId, countryName in pairs(country.name) do if type(cntry) == 'string' then if tostring(countryName) == string.upper(cntry) then newCountry = countryName @@ -593,11 +600,11 @@ do end end end - + if newCountry == '' then return false end - + local newCat = '' for catName, catId in pairs(Unit.Category) do if type(groupType) == 'string' then @@ -609,15 +616,14 @@ do 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 + local typeName if newCat == 'GROUND_UNIT' then typeName = ' gnd ' elseif newCat == 'AIRPLANE' then @@ -629,10 +635,9 @@ do elseif newCat == 'BUILDING' then typeName = ' bld ' end - if newGroup.clone or not newGroup.groupId then mistDynAddIndex = mistDynAddIndex + 1 - mistGpId = mistGpId + 1 + mistGpId = mistGpId + 1 newGroup.groupId = mistGpId end if newGroup.groupName or newGroup.name then @@ -642,19 +647,19 @@ do 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) @@ -662,11 +667,12 @@ do 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 + mistUnitId = mistUnitId + 1 newGroup.units[unitIndex]['unitId'] = mistUnitId end if newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name then @@ -679,11 +685,11 @@ do if newGroup.clone or not unitData.name then newGroup.units[unitIndex].name = tostring(newGroup.name .. ' unit' .. unitIndex) end - - if not unitData.skill then + + 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 @@ -695,13 +701,13 @@ do 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']] + 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' @@ -720,7 +726,6 @@ do 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 @@ -729,42 +734,42 @@ do 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 - +--------------------------------------------------------------------------------------------- +--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) - ]] + 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)) @@ -779,7 +784,7 @@ do 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 @@ -798,20 +803,20 @@ do 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) + 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 - --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 + 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 @@ -828,21 +833,21 @@ do end end - + 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 + 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) @@ -853,11 +858,11 @@ do end end return false - end + end mist.addEventHandler(groupSpawned) - -- mist.scheduleFunction(checkSpawnedEvents, {}, timer.getTime() + 5, 1) - +-- mist.scheduleFunction(checkSpawnedEvents, {}, timer.getTime() + 5, 1) + end ------------------------------------------------------------------------------------------------------------ @@ -927,7 +932,7 @@ 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 @@ -1001,8 +1006,8 @@ end -- From http://lua-users.org/wiki/SimpleRound -- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place mist.utils.round = function(num, idp) - local mult = 10^(idp or 0) - return math.floor(num * mult + 0.5) / mult + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult end -- porting in Slmod's dostring @@ -1038,12 +1043,12 @@ function mist.utils.typeCheck(fname, type_tbl, var_tbl) --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 .. '/' @@ -1056,21 +1061,21 @@ function mist.utils.typeCheck(fname, type_tbl, var_tbl) 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 @@ -1083,11 +1088,11 @@ function mist.utils.typeCheck(fname, type_tbl, var_tbl) --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 @@ -1107,63 +1112,63 @@ mist.utils.basicSerialize = function(s) s = string.format('%q', s) return s end - 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 + 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 end - + local serialize_to_t = function (name, value, level) - ----Based on ED's serialize_simple2 + ----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 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) + key = string.format("[%s]", k) else - key = string.format("[%q]", k) + key = string.format("[%q]", k) end 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 + 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 @@ -1176,10 +1181,10 @@ mist.utils.serializeWithCycles = function(name, value, saved) elseif type(o) == "boolean" then return tostring(o) else -- assume it is a string - return mist.utils.basicSerialize(o) + 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 @@ -1189,13 +1194,13 @@ mist.utils.serializeWithCycles = function(name, value, saved) else if saved[value] then -- value already saved? - table.insert(t_str, saved[value] .. "\n") + 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)) + local fieldname = string.format("%s[%s]", name, basicSerialize(k)) + table.insert(t_str, mist.utils.serializeWithCycles(fieldname, v, saved)) end end end @@ -1207,111 +1212,111 @@ 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 + 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 = {} -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' + 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] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' + 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 - - else - tbl_str[#tbl_str + 1] = 'a function,\n' + + tbl_str[#tbl_str + 1] = indent .. '}' + return table.concat(tbl_str) 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 = {} @@ -1386,7 +1391,7 @@ mist.vec.mag = function(vec) return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 end -mist.vec.getUnitVec = function(vec) +mist.vec.getUnitVec = function(vec) local mag = mist.vec.mag(vec) return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } end @@ -1397,12 +1402,12 @@ end --------------------------------------------------------------------------------------------------------------------------- -- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -mist.tostringMGRS = function(MGRS, acc) +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)) + 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 @@ -1414,121 +1419,121 @@ 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 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 - + 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 + 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) + 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) @@ -1545,42 +1550,42 @@ 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 @@ -1588,92 +1593,92 @@ 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))) --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 + 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)) + 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 @@ -1707,22 +1712,22 @@ function mist.getRoll(unit) 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 + Roll = -Roll end return Roll end @@ -1734,22 +1739,22 @@ function mist.getYaw(unit) -- 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 + 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 @@ -1759,21 +1764,21 @@ function mist.getAoA(unit) 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 + 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 @@ -1783,7 +1788,7 @@ function mist.getClimbAngle(unit) 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)) + return math.asin(unitvel.y/mist.vec.mag(unitvel)) end end end @@ -1793,8 +1798,8 @@ mist.DBs = {} mist.DBs.missionData = {} ----------------------------------------- -if env.mission then - +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 @@ -1809,7 +1814,7 @@ if env.mission then 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 ---------------------------------------- @@ -1826,151 +1831,151 @@ if env.mission.triggers and env.mission.triggers.zones then 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.]] + zones_by_num se are different objects.. don't want them linked.]] end end end mist.DBs.navPoints = {} mist.DBs.units = {} ---Build mist.db.units and mist.DBs.navPoints + --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 + --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 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 + 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 - end - ------------------------------------------------- + ------------------------------------------------- if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do + 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 - 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 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 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 - - - 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 + + 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 @@ -2000,16 +2005,16 @@ 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 @@ -2020,23 +2025,27 @@ for coa_name, coa_data in pairs(mist.DBs.units) 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) + 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 @@ -2071,7 +2080,7 @@ mist.DBs.deadObjects = {} do local mt = {} - + mt.__newindex = function(t, key, val) --------------------------------------------------------------- local original_key = key --only for duplicate runtime IDs. @@ -2082,7 +2091,7 @@ do 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_]) @@ -2091,38 +2100,38 @@ do 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 - + --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 + --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 - if not static_found then - val['objectPos'] = pos.p - val['objectType'] = 'building' - end - else - val['objectType'] = 'unknown' - end end rawset(t, key, val) end @@ -2131,15 +2140,15 @@ do end -- Event handler to start creating the dead_objects table -do +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 @@ -2149,7 +2158,7 @@ do 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_]) @@ -2158,38 +2167,41 @@ do 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 - + --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 + --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 - if not static_found then - val['objectPos'] = pos.p - val['objectType'] = 'building' - end - else - val['objectType'] = 'unknown' - end end mist.DBs.deadObjects[id] = val @@ -2197,29 +2209,29 @@ do end end - + mist.addEventHandler(addDeadObject) - - - --[[local function addClientsToActive(event) - if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT then - if not mist.DBs.activeHumans[Unit.getName(event.initiator)] then - local newU = mist.utils.deepCopy(mist.DBs.unitsByName[Unit.getName(event.initiator)]) - if Unit.getPlayerName(event.initiator) then - newU.playerName = Unit.getPlayerName(event.initiator) - end - mist.DBs.activeHumans[Unit.getName(event.initiator)] = newU - end - elseif event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT or event.id == world.event.S_EVENT_DEATH then - if mist.DBs.activeHumans[Unit.getName(event.initiator)] then - mist.DBs.activeHumans[Unit.getName(event.initiator)] = nil - end - elseif event.id == world.event.S_EVENT_BIRTH then -- do client check - - end - end - - mist.addEventHandler(addClientsToActive)]] + + --[[ + 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 @@ -2228,7 +2240,7 @@ end function mist.makeUnitTable(tbl) - --[[ +--[[ Prefixes: "[-u]" - subtract this unit if its in the table "[g]" - add this group to the table @@ -2310,160 +2322,161 @@ Country names to be used in [c] and [-c] short-cuts: 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 + 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 + 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 - 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 + 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 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 + 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 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 + 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 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 + 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 - 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 + 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 @@ -2471,28 +2484,28 @@ Country names to be used in [c] and [-c] short-cuts: 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 + 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 @@ -2500,23 +2513,77 @@ Country names to be used in [c] and [-c] short-cuts: 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 + 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 + 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 @@ -2529,83 +2596,28 @@ Country names to be used in [c] and [-c] short-cuts: 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 + end else -- just a regular unit - units_by_name[unit] = true --add + 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 + 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) +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 @@ -2615,26 +2627,26 @@ mist.getDeadMapObjsInZones = function(zone_names) 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) + 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 end return map_objs end -mist.getDeadMapObjsInPolygonZone = function(zone) - -- zone_names: table of zone names - -- returns: table of dead map objects (indexed numerically) +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 + if mist.pointInPolygon(obj.objectPos, zone) then + map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) + end end end return map_objs @@ -2643,7 +2655,7 @@ end mist.flagFunc = {} mist.flagFunc.mapobjs_dead_zones = function(vars) - --[[vars needs to be: +--[[vars needs to be: zones = table or string, flag = number, stopflag = number or nil, @@ -2653,14 +2665,14 @@ AND used by function, initial_number ]] - -- type_tbl +-- type_tbl local type_tbl = { [{'zones', 'zone'}] = {'table', 'string'}, - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, + 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 @@ -2668,15 +2680,15 @@ initial_number 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 + + 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) @@ -2690,7 +2702,7 @@ end mist.flagFunc.mapobjs_dead_polygon = function(vars) - --[[vars needs to be: +--[[vars needs to be: zone = table, flag = number, stopflag = number or nil, @@ -2700,14 +2712,14 @@ AND used by function, initial_number ]] - -- type_tbl +-- type_tbl local type_tbl = { [{'zone', 'polyzone'}] = 'table', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, + 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 @@ -2715,11 +2727,11 @@ initial_number 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 + + 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) @@ -2733,62 +2745,62 @@ 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 + --[[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 - - 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 end function mist.flagFunc.units_in_polygon(vars) - --[[vars needs to be: +--[[vars needs to be: units = table, zone = table, flag = number, @@ -2799,19 +2811,19 @@ req_num = number or nil toggle = boolean or nil unitTableDef = table or nil ]] - -- type_tbl +-- 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'}, + [{'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'}, + 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 @@ -2823,13 +2835,13 @@ unitTableDef = table or nil 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) + 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 @@ -2855,14 +2867,14 @@ unitTableDef = table or nil 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' @@ -2870,7 +2882,7 @@ function mist.getUnitsInZones(unit_names, zone_names, zone_type) 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 = {} @@ -2882,24 +2894,24 @@ function mist.getUnitsInZones(unit_names, zone_names, zone_type) 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 + 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 @@ -2919,28 +2931,28 @@ 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 - ]] + 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'}, + 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 @@ -2952,35 +2964,35 @@ function mist.flagFunc.units_in_zones(vars) 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) + 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 + 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' @@ -2988,7 +3000,7 @@ function mist.getUnitsInMovingZones(unit_names, zone_unit_names, radius, zone_ty 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 = {} @@ -3000,7 +3012,7 @@ function mist.getUnitsInMovingZones(unit_names, zone_unit_names, radius, zone_ty units[#units + 1] = unit end end - + for k = 1, #zone_unit_names do local unit = Unit.getByName(zone_unit_names[k]) if unit then @@ -3009,7 +3021,7 @@ function mist.getUnitsInMovingZones(unit_names, zone_unit_names, radius, zone_ty 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 @@ -3032,30 +3044,31 @@ 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 - ]] + 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', + units = 'table', + [{'zone_units', 'zoneunits'}] = 'table', radius = 'number', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - [{'zone_type', 'zonetype'}] = {'string', 'nil'}, + 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 @@ -3068,39 +3081,48 @@ function mist.flagFunc.units_in_moving_zones(vars) 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) + 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 + 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}}, timer.getTime() + interval) + 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]) @@ -3110,7 +3132,7 @@ mist.getUnitsLOS = function(unitset1, altoffset1, unitset2, altoffset2, radius) 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 @@ -3126,28 +3148,28 @@ mist.getUnitsLOS = function(unitset1, altoffset1, unitset2, altoffset2, radius) 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 + 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 end - + return LOS_data end mist.flagFunc.units_LOS = function(vars) - --[[vars needs to be: +--[[vars needs to be: unitset1 = table, altoffset1 = number, unitset2 = table, @@ -3159,22 +3181,22 @@ interval = number or nil, req_num = number or nil toggle = boolean or nil ]] - -- type_tbl +-- 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'}, + [{'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 @@ -3189,33 +3211,33 @@ toggle = boolean or nil 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 - units = mist.makeUnitTable(unitTableDef1) + unitset1 = mist.makeUnitTable(unitTableDef1) end - + if (unitset2.processed and unitset2.processed < mist.getLastDBUpdateTime()) or not unitset2.processed then -- run unit table short cuts - units = mist.makeUnitTable(unitTableDef2) + 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 + 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) @@ -3224,7 +3246,7 @@ toggle = boolean or nil end mist.flagFunc.group_alive = function(vars) - --[[vars +--[[vars groupName flag toggle @@ -3233,23 +3255,23 @@ stopFlag ]] local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - flag = {'number', 'string'}, - stopflag = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, + [{'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 @@ -3261,7 +3283,7 @@ stopFlag 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 @@ -3270,23 +3292,23 @@ 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'}, + [{'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 @@ -3298,7 +3320,7 @@ mist.flagFunc.group_dead = function(vars) 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 @@ -3306,25 +3328,25 @@ 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'}, + [{'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 @@ -3342,7 +3364,7 @@ mist.flagFunc.group_alive_less_than = function(vars) 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 @@ -3350,25 +3372,25 @@ 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'}, + [{'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 @@ -3381,12 +3403,12 @@ mist.flagFunc.group_alive_more_than = function(vars) end end else --- just in case - if toggle and trigger.misc.getUserFlag(flag) == 1 then - trigger.action.setUserFlag(flag, false) - end + 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 @@ -3398,7 +3420,7 @@ end mist.getAvgPos = function(unitNames) local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 for i = 1, #unitNames do - local unit + local unit if Unit.getByName(unitNames[i]) then unit = Unit.getByName(unitNames[i]) elseif StaticObject.getByName(unitNames[i]) then @@ -3407,12 +3429,12 @@ mist.getAvgPos = function(unitNames) 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 + avgX = avgX + pos.x + avgY = avgY + pos.y + avgZ = avgZ + pos.z + totNum = totNum + 1 end - end + end end if totNum ~= 0 then return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} @@ -3427,7 +3449,7 @@ mist.getAvgGroupPos = function(groupName) for i = 1, #groupName:getSize() do table.insert(units, groupName.getUnit(i):getName()) end - + return mist.getAvgPos(units) end @@ -3447,43 +3469,43 @@ mist.demos.printFlightData = function(unit) 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 + + 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 + + if not ClimbAngle then ClimbAngle = 'NA' else ClimbAngle = string.format('%12.2f', mist.utils.toDegree(ClimbAngle)) @@ -3492,8 +3514,8 @@ mist.demos.printFlightData = function(unit) 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' @@ -3502,32 +3524,32 @@ mist.demos.printFlightData = function(unit) 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) + .. ' 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() @@ -3537,15 +3559,15 @@ mist.demos.printFlightData = function(unit) 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 -------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------- @@ -3560,14 +3582,14 @@ mist.air.fixedWing = {} mist.air.heli = {} mist.goRoute = function(group, path) - local misTask = { - id = 'Mission', - params = { - route = { + local misTask = { + id = 'Mission', + params = { + route = { points = mist.utils.deepCopy(path), - }, + }, }, - } + } if type(group) == 'string' then group = Group.getByName(group) end @@ -3584,58 +3606,58 @@ mist.goRoute = function(group, path) 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 @@ -3648,28 +3670,28 @@ 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 + + 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 + else form = overRideForm end - + if not form then wp.action = 'Cone' else @@ -3697,7 +3719,7 @@ mist.ground.buildWP = function(point, overRideForm, overRideSpeed) wp.type = 'Turning Point' - return wp + return wp end @@ -3705,19 +3727,19 @@ 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 @@ -3728,21 +3750,21 @@ mist.fixedWing.buildWP = function(point, WPtype, speed, alt, altType) else wp.alt_type = 'RADIO' end - - if point.speed then + + 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 @@ -3755,28 +3777,28 @@ mist.fixedWing.buildWP = function(point, WPtype, speed, alt, altType) wp.action = 'Turning Point' end end - + wp.type = 'Turning Point' - return wp + 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 @@ -3787,21 +3809,21 @@ mist.heli.buildWP = function(point, WPtype, speed, alt, altType) else wp.alt_type = 'RADIO' end - - if point.speed then + + 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 @@ -3814,9 +3836,9 @@ mist.heli.buildWP = function(point, WPtype, speed, alt, altType) wp.action = 'Turning Point' end end - + wp.type = 'Turning Point' - return wp + return wp end @@ -3830,21 +3852,21 @@ end function mist.getRandPointInCircle(point, radius, innerRadius) local theta = 2*math.pi*math.random() local rad = math.random() + math.random() - if rad > 1 then + 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 + 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} @@ -3870,27 +3892,27 @@ mist.groupToRandomPoint = function(vars) 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) @@ -3898,20 +3920,20 @@ mist.groupToRandomPoint = function(vars) 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 + 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 @@ -3919,7 +3941,7 @@ 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} + fakeZone.point = {x = pos.x, y = pos.y, z = pos.z} mist.groupToRandomZone(gpData, fakeZone, form, heading, speed) return @@ -3929,7 +3951,7 @@ 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 @@ -3939,7 +3961,7 @@ mist.groupToRandomZone = function(gpData, zone, form, heading, speed) if speed then speed = mist.utils.kmphToMps(speed) end - + local vars = {} vars.group = gpData vars.radius = zone.radius @@ -3947,39 +3969,39 @@ mist.groupToRandomZone = function(gpData, zone, form, heading, speed) vars.headingDegrees = heading vars.speed = speed vars.point = mist.utils.zoneToVec3(zone) - + mist.groupToRandomPoint(vars) 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) + if coord.z then + coord.y = coord.z 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) + 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 -end -end -for validIndex, validData in pairs(typeConverted) do - if land.getSurfaceType(coord) == land.SurfaceType[validData] then - return true + for validIndex, validData in pairs(typeConverted) do + if land.getSurfaceType(coord) == land.SurfaceType[validData] then + return true + end end -end -return false + return false end mist.terrainHeightDiff = function(coord, searchSize) @@ -3991,14 +4013,14 @@ mist.terrainHeightDiff = function(coord, searchSize) 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)))}) + 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 @@ -4022,7 +4044,7 @@ mist.groupToPoint = function(gpData, point, form, heading, speed, useRoads) if speed then speed = mist.utils.kmphToMps(speed) end - + local vars = {} vars.group = gpData vars.form = form @@ -4031,30 +4053,30 @@ mist.groupToPoint = function(gpData, point, form, heading, speed, useRoads) 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) + 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 + 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 - end if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... - return leader:getPosition().p + return leader:getPosition().p end end @@ -4076,37 +4098,39 @@ do local messageID = 0 local displayActive = false local displayFuncId = 0 - + local caSlots = false local caMSGtoGroup = false - - 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 + + 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 - elseif type(value) == 'boolean' and value == true then - caSlots = true - break 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. + --[[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 function mistdisplayV4() local activeClients = {} for clientId, clientData in pairs(mist.DBs.humansById) do @@ -4114,12 +4138,12 @@ do activeClients[clientData.groupId] = clientData.groupName end end - + --[[if caSlots == true and caMSGtoGroup == true then - - end]] - + + end]] + if #messageList > 0 then if displayActive == false then displayActive = true @@ -4127,7 +4151,7 @@ do --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. @@ -4137,55 +4161,55 @@ do 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 + 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' + 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 - 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) @@ -4193,13 +4217,12 @@ do 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) + trigger.action.outTextForGroup(index, table.concat(msgData.text), msgData.displayTime, true) end end --- new audio @@ -4209,20 +4232,20 @@ do 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) + trigger.action.outSoundForGroup(index, file) end end else mist.removeFunction(displayFuncId) - displayActive = false + displayActive = false end - + end - + local typeBase = { ['Mi-8MT'] = {'Mi-8MTV2', 'Mi-8MTV', 'Mi-8'}, ['MiG-21Bis'] = {'Mig-21'}, @@ -4230,23 +4253,23 @@ do ['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]] + if type(val) == 'boolean' then + caMSGtoGroup = val + return true + end + return false + end]] 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') + -- env.info('already on recList') return recList end end @@ -4254,19 +4277,19 @@ do 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 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 @@ -4274,29 +4297,29 @@ do 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 + 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 + local sound = vars.sound + if vars.fileName then + sound = vars.fileName + end + new.multSound[#new.multSound+1] = {time = 0.1, file = sound} 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 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) @@ -4304,8 +4327,8 @@ do 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) + 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 @@ -4314,12 +4337,12 @@ do 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 + for pIndex, pName in pairs(pTbl) do + if mist.stringMatch(sString, pName) then + sString = rName + end 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. @@ -4328,7 +4351,7 @@ do end end if found == true then -- shouldn't this be elsewhere too? - break + break end end end @@ -4339,22 +4362,20 @@ 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) - --table.insert(newMsgFor, coaData) - -- added redca or blueca to list end 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 @@ -4372,48 +4393,48 @@ do end end end - + messageID = messageID + 1 new.messageID = messageID --mist.debug.writeData(mist.utils.serialize,{'msg', new}, 'newMsg.lua') - + messageList[#messageList + 1] = new - + local mt = { __index = mist.message} - setmetatable(new, mt) + 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 + for i, msgData in pairs(messageList) do + if messageList[i] == self then + table.remove(messageList, i) + return true --removal successful + end end - end - return false -- removal not successful this script fails at life! + 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 + for i, msgData in pairs(messageList) do + if messageList[i].messageID == id then + table.remove(messageList, i) + return true --removal successful + end end - end - return false -- removal not successful this script fails at life! + return false -- removal not successful this script fails at life! end, - } - + } + end -- End of message system -------------------------------------------------------------------------------------------------------------------------------------------- @@ -4530,7 +4551,7 @@ mist.getLeadingPos = function(vars) if vars.headingDegrees then heading = mist.utils.toRadian(vars.headingDegrees) end - + local unitPosTbl = {} for i = 1, #units do local unit = Unit.getByName(units[i]) @@ -4539,37 +4560,37 @@ mist.getLeadingPos = function(vars) 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 + -- 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 - 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 + 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 - avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} - else - avgPos = unitPosTbl[maxPosInd] - end - - return avgPos + + --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 @@ -4624,7 +4645,7 @@ mist.getLeadingBRString = function(vars) 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) @@ -4636,9 +4657,9 @@ mist.getLeadingBRString = function(vars) 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'}} ]] @@ -4655,14 +4676,14 @@ mist.msgMGRS = function(vars) 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s @@ -4689,19 +4710,19 @@ mist.msgLL = function(vars) 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s end - + mist.message.add{ text = newText, displayTime = displayTime, @@ -4728,19 +4749,19 @@ mist.msgBR = function(vars) 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s end - + mist.message.add{ text = newText, displayTime = displayTime, @@ -4804,26 +4825,26 @@ 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 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s end - + mist.message.add{ text = newText, displayTime = displayTime, @@ -4845,7 +4866,7 @@ 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 heading = vars.heading local radius = vars.radius local headingDegrees = vars.headingDegrees local acc = vars.acc @@ -4853,20 +4874,20 @@ mist.msgLeadingLL = function(vars) 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s end - + mist.message.add{ text = newText, displayTime = displayTime, @@ -4889,7 +4910,7 @@ 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 heading = vars.heading local radius = vars.radius local headingDegrees = vars.headingDegrees local metric = vars.metric @@ -4898,20 +4919,20 @@ mist.msgLeadingBR = function(vars) 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 + newText = string.format(text, s) -- insert the coordinates into the message else -- else, just append to the end. - newText = text .. s + newText = text .. s end else newText = s end - + mist.message.add{ text = newText, displayTime = displayTime, @@ -4927,11 +4948,11 @@ 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 @@ -4949,13 +4970,13 @@ mist.groupTableCheck = function(groupData) else isOk = false end - + return isOk -end +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 = {} @@ -4964,7 +4985,7 @@ mist.getCurrentGroupData = function(gpName) newData.category = newGroup:getCategory() newData.groupName = gpName newData.hidden = dbData.hidden - + if newData.category == 2 then newData.category = 'vehicle' elseif newData.category == 3 then @@ -4981,7 +5002,7 @@ mist.getCurrentGroupData = function(gpName) 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 @@ -4997,7 +5018,7 @@ mist.getCurrentGroupData = function(gpName) 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 @@ -5009,8 +5030,8 @@ mist.getGroupData = function(gpName) if mist.DBs.groupsByName[gpName] then newData = mist.utils.deepCopy(mist.DBs.groupsByName[gpName]) found = true - end - + end + if found == false then for groupName, groupData in pairs(mist.DBs.groupsByName) do if mist.stringMatch(groupName, gpName) == true then @@ -5021,7 +5042,7 @@ mist.getGroupData = function(gpName) end end end - + local payloads if newData.category == 'plane' or newData.category == 'helicopter' then payloads = mist.getGroupPayload(newData.groupName) @@ -5031,7 +5052,7 @@ mist.getGroupData = function(gpName) 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 @@ -5044,8 +5065,8 @@ mist.getGroupData = function(gpName) 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 @@ -5060,8 +5081,8 @@ mist.getGroupData = function(gpName) newData.units[unitNum]['shape_name'] = unitData.shape_name end end - - return newData + + return newData else env.info(gpName .. ' not found in mist.getGroupData') return @@ -5069,35 +5090,35 @@ mist.getGroupData = function(gpName) end mist.getPayload = function(unitIdent) - -- refactor to search by groupId and allow groupId and groupName as inputs + -- 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_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 + 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 - end end end else @@ -5105,7 +5126,7 @@ mist.getPayload = function(unitIdent) return false end env.info('mist.getPayload, payload not found') - return + return end mist.getGroupPayload = function(groupIdent) @@ -5113,29 +5134,29 @@ mist.getGroupPayload = function(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_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 + 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 - return payloads end end - end - end end end - end end end else @@ -5143,145 +5164,144 @@ mist.getGroupPayload = function(groupIdent) return false end env.info('mist.getGroupPayload, payload not found') - return + 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 + 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 = 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'} + newGroupData = vars.groupData 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 + local diff = {['x'] = 0, ['y'] = 0} + local newCoord, origCoord 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) + 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 - newGroupData.units[unitNum]["alt"] = land.getHeight({newGroupData.units[unitNum]["x"], newGroupData.units[unitNum]["y"]}) + math.random(200, 3000) + 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 -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 + + 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 -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) @@ -5293,7 +5313,7 @@ mist.respawnInZone = function(gpName, zone, disperse, maxDisp) else gpName = tostring(gpName) end - + if type(zone) == 'string' then zone = trigger.misc.getZone(zone) elseif type(zone) == 'table' and not zone.radius then @@ -5310,13 +5330,13 @@ mist.respawnInZone = function(gpName, zone, disperse, maxDisp) 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 @@ -5333,26 +5353,26 @@ mist.cloneInZone = function(gpName, zone, disperse, maxDisp) 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) @@ -5391,7 +5411,7 @@ mist.teleportGroup = function(gpName, task) vars.action = 'teleport' if task and type(task) ~= 'number' then vars.route = mist.getGroupRoute(gpName, 'task') - end + end local newGroup = mist.teleportToPoint(vars) if task and type(task) == 'number' then local newRoute = mist.getGroupRoute(gpName, 'task') @@ -5401,41 +5421,41 @@ mist.teleportGroup = function(gpName, task) 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) + 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 - -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 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 @@ -5451,7 +5471,7 @@ mist.randomizeNumTable = function(vars) end if not excludeIndex[i] then table.insert(choices, i) - else + else newTable[i] = i end end @@ -5473,68 +5493,68 @@ mist.randomizeNumTable = function(vars) found = true end excludeIndex[x] = true - + end newTable[num] = x end --[[ - for i = 1, #newTable do - env.info(newTable[i]) - end - ]] + for i = 1, #newTable do + env.info(newTable[i]) + end + ]] return newTable end -mist.randomizeGroupOrder = function(passedUnits, vars) +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 + exclude = vars.excludeType end - + if vars and vars.excludeNum and type(vars.excludeNum) == 'table' then - excludeNum = vars.excludeNum + 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 + 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 - end - end else -- unitIndex is either to low, or to high: added to exclude list - excludeNum[unitIndex] = unitId + excludeNum[unitIndex] = unitId end - end - + end + local newGroup = {} local newOrder = mist.randomizeNumTable({exclude = excludeNum, size = #units}) @@ -5548,21 +5568,21 @@ mist.randomizeGroupOrder = function(passedUnits, vars) newGroup[i].unitIndex = mist.utils.deepCopy(unitData.unitIndex) -- replaces the units data with a new type end end - end + end return newGroup -end +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 + + local useGroupRoute if not vars.useGroupRoute then useGroupRoute = vars.gpData else @@ -5579,22 +5599,22 @@ mist.ground.patrolRoute = function(vars) 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 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 @@ -5606,25 +5626,25 @@ mist.ground.patrolRoute = function(vars) 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 @@ -5634,38 +5654,38 @@ mist.ground.patrolRoute = function(vars) cTask3[#cTask3 + 1] = ')' cTask3 = table.concat(cTask3) local tempTask = { - id = 'WrappedAction', - params = { + id = 'WrappedAction', + params = { action = { id = 'Script', params = { - command = cTask3, - + command = cTask3, + }, }, }, } - + 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) return @@ -5673,29 +5693,29 @@ 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 @@ -5711,7 +5731,7 @@ mist.stringMatch = function(s1, s2, bool) s1 = string.lower(s1) s2 = string.lower(s2) end - + if s1 == s2 then return true else @@ -5731,7 +5751,7 @@ 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 @@ -5748,7 +5768,7 @@ mist.time.convertToSec = function(timeTable) if timeTable.s and type(timeTable.s) == 'number' then timeInSec = timeInSec + timeTable.s end - + end return timeInSec end @@ -5756,29 +5776,29 @@ 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 + if timeInSec > 86400 then + while timeInSec > 86400 do + tbl.d = tbl.d + 1 + timeInSec = timeInSec - 86400 + end end - end - if timeInSec > 3600 then - while timeInSec > 3600 do - tbl.h = tbl.h + 1 - timeInSec = timeInSec - 3600 + if timeInSec > 3600 then + while timeInSec > 3600 do + tbl.h = tbl.h + 1 + timeInSec = timeInSec - 3600 + end end - end - if timeInSec > 60 then - while timeInSec > 60 do - tbl.m = tbl.m + 1 - timeInSec = timeInSec - 60 + if timeInSec > 60 then + while timeInSec > 60 do + tbl.m = tbl.m + 1 + timeInSec = timeInSec - 60 + end end - end - tbl.s = timeInSec + tbl.s = timeInSec return tbl else env.info('mist.time.getDHMS didnt recieve number') - return + return end end @@ -5789,9 +5809,9 @@ mist.getMilString = function(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 @@ -5807,7 +5827,7 @@ mist.getClockString = function(theTime, hour) 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 + else return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' AM') end else @@ -5831,12 +5851,12 @@ mist.time.getDate = function(convert) 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 @@ -5859,76 +5879,76 @@ mist.time.relativeToStart = function(time) 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) + 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 -else - if murica then - return tostring(tbl.m .. '.' .. tbl.d .. '.' .. tbl.y) + 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 - return tostring(tbl.d .. '.' .. tbl.m .. '.' .. tbl.y) + if murica then + return tostring(tbl.m .. '.' .. tbl.d .. '.' .. tbl.y) + else + return tostring(tbl.d .. '.' .. tbl.m .. '.' .. tbl.y) + end 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 + 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 -end - -if curTime > milTimeInSec then - milTimeInSec = milTimeInSec + 86400 -end -if rtnType then - milTimeInSec = milTimeInSec - startTime -end -return milTimeInSec + + 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'] = { + }, }]] @@ -5942,8 +5962,8 @@ mist.DBs.const.callsigns = { -- not accessible by SSE, must use static list :-/ ['Overlord'] = 1, ['Magic'] = 2, ['Wizard'] = 3, - ['Focus'] = 4, - ['Darkstar'] = 5, + ['Focus'] = 4, + ['Darkstar'] = 5, }, ['TANKER'] = { ['Texaco'] = 1, @@ -5953,8 +5973,8 @@ mist.DBs.const.callsigns = { -- not accessible by SSE, must use static list :-/ ['JTAC'] = { ['Axeman'] = 1, ['Darknight'] = 2, - ['Warrior'] = 3, - ['Pointer'] = 4, + ['Warrior'] = 3, + ['Pointer'] = 4, ['Eyeball'] = 5, ['Moonbeam'] = 6, ['Whiplash'] = 7, @@ -5965,29 +5985,29 @@ mist.DBs.const.callsigns = { -- not accessible by SSE, must use static list :-/ ['Playboy'] = 12, ['Hammer'] = 13, ['Jaguar'] = 14, - ['Deathstar'] = 15, + ['Deathstar'] = 15, ['Anvil'] = 16, - ['Firefly'] = 17, + ['Firefly'] = 17, ['Mantis'] = 18, ['Badger'] = 19, }, ['aircraft'] = { ['Enfield'] = 1, ['Springfield'] = 2, - ['Uzi'] = 3, + ['Uzi'] = 3, ['Colt'] = 4, - ['Dodge'] = 5, + ['Dodge'] = 5, ['Ford'] = 6, ['Chevy'] = 7, ['Pontiac'] = 8, }, - + ['unique'] = { ['A10'] = { ['Hawg'] = 9, ['Boar'] = 10, ['Pig'] = 11, - ['Tusk'] = 12, + ['Tusk'] = 12, ['rules'] = { ['canUseAircraft'] = true, ['appliesTo'] = { @@ -6001,15 +6021,15 @@ mist.DBs.const.callsigns = { -- not accessible by SSE, must use static list :-/ } --[[ 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'} } @@ -6022,4 +6042,4 @@ scope examples: ]] end mist.main() -env.info(('Mist version ' .. mist.majorVersion .. '.' .. mist.minorVersion .. '.' .. mist.build .. ' loaded.')) +env.info(('Mist version ' .. mist.majorVersion .. '.' .. mist.minorVersion .. '.' .. mist.build .. ' loaded.')) \ No newline at end of file diff --git a/test-mission.miz b/test-mission.miz index 2c3b09b2a2545d5251af113df161e9446dbaabf3..55627ac95e6d70e7386a5d179548482aed8ad273 100644 GIT binary patch delta 56423 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%0At-#>*GIb#)ZcIFx85n5 zDSRr4Of<&tViZW_Y*cEU*iBg|DXr7&x1Oefh&PoNYhEi!9)zn6(qaBq^I}9Qx@cg3 z^U4kNN9le(lR04N-Hzmgbuvpb-lcO2zJO(H2us}ESvH;BdOHJ==M^1=%~(s%J}EWT z%L_&gsT3XW*{?xtQ7Oq^d_q<9PgCB`q?LEDG%J_S4k>hl%O(nH!HT@<>g(flWQ`DV zU=ax#KowX7NZiR0{@}nwEiXW(kS#JIKQl8H0rkqG3JPBi4+8oqXhkOY;l5g-7%;C% z=Q!aUaQl7NXg=tq@!rm`?#m)B^{oOkz}Xl4cI3Y5wpRW;FB!v-0Q=kEv#F z7w_7zH`-a~vkUiv5zr0fdX{J1eL3cvkUg^dt**5I)IA1mka7IjS1x1~!h-2)2gu*9E}&2S}`+p<)Y1O)n2zKNoHXPmOHE z+u(qh{t&qltB-{{dsxYSWA}(2%bz2MzP*)ko?IOjPU%#hUjC1_VBT}{$O+6sX}wFM5@7?Q;(jch`QrVFipkknXsOTHD|0-=KLlQy+< zhZt00Dv0Vf(EW`LdfP^W0FGkb)VD(>y8ank#`9U8>a-D5E_TZb*Re0482{$w8JIMm zk#<1))}OKcKOw<1aZPr!6k*ga%o&G|@o3hOY*ny{?sbx!KckY&b5hSkU<0h8u?%3q zK~XYN?R2zu=b0?ES418sfU=~z03Pi3Z}LeW&_G+kWyEGK^i;vxKt1+}P5f6xkQF>#wAg z4{=KWSMfO;cKcb#^pt2Qb|4{{Qgf`-*1>n#?5hz?P?L3l8IL%&JYsyLM+ksi&v$QD z6e7|0VQ-v@qBA2PEEkT~e6E6qrG>-jV08oI$S<3YY&;zF*DfnvoSTfL57Z5>L{0on zWgU`OL&h}g9M+%)U_9-Sdn!-Y+8`~NGhPfOL9-xO;alb3C{*lG z86p=Pm^Ijf^fEIubEUxTZ`X1-NWb#&D2oj0N7|y5o@2#H86a zJGu(SMb@{@3V-dS=MC{jy1QK1Q(M)ko7-d6I3|b*kJAy)kZkW1zU0veoM!P^NXze7 zAS^L@oSQ(tBvQ>j&WHX+wdf(*4t@w9NRrK>o6vecS)Xo9PStOu<;i28YRQ;?BB>Gi z1<{4CUTGY{G4X7ZnbBlL{bwgAY1orLfN9X+!f5azHK+^kWZM92#bbq~L-SCXK$jGNS^eA=R_#6Q;c{o-fN(}Jhtr{qvE@-W zguB}CYivXuG?RNiID#b2sSdp-lb7I=CF<9u+wLtQU@&_y!Jk1W#=l+4Isg8i@2~ye zv&y~&*`kX!A%OhjpYuzs^z`;gWn! zfxC>boXlab8qTWr-0ZG2yTGda_(1CNJ>$mu4Xm#@~xG!;6>FE3__4T&QY%j(q<;7;KqU`P|ZIN?XO{|!i zZW@&Vm51*~r({{nycic-l{>{|!5ue?U_xzwQvAweb1!rzm|Me(s^*&EQiea*n1cU1 zfnApt6bsSNZWPcg)J<{t0r?4;mam84+r*?!IPT&F*AQeCqTHFirTBjCL~Dj5g%20p zqe^z)sIx8-Y&uAid1|;yf1WHkG50hmrLTMDDSmawk0}zINT#3_<=S}KPLHb@O#A~` zdRfgVXw#8yrjIaXV{)>ok(vd!|3BV@kNLMiLA;ZHs6+hU3Kl~#CR&28NN1@>j z?+@0jTb8NUVyNTm67VUdkI1IBTFft7B5TTn53!h+zhQZ|<`3=AI7?MXpiMK@flrQ& zDSXGtSitF(lB+S*qc5w%ZZsWAyW)T?!4ekHykwl8P!gHH&31@3FP_voVvCx*F)5%vs@?CxB&2)p6VQB-*8aJqJavyI|NN*lGG zA$+fL3R;q!^O{e@ik_Y&cIVJ1dA)45Z#2Z^g7hHIoj#QaMFtF9X+KQdi8}koikMk|y4Pr~ zDyxc_%VTbm#%V=K>dG@3d}j{D7bmsN{M*tDlO_OabzmT@(nNj7RlrN1zbDs&NYH9t zYw*#*B0y4ds^b9+ETZbH81)lxVxqq;ES);MGq;S$Snh8gJo9Na_I|(PTtRU@7eVot zBdB%8`4&*s9=ncGG)LvBD6)3oZgf^%E2mEN<{1#yObPvaLem|!xkM)|1x>-{A6CR) z?{L#?EhYV(^2tf@ts3Yb>5ka|cW*~qaIM#sw<5==7NaLFBD?7HTBH95Q$Vc0{q|Oz z9skyHzig>5JCZ&SB-L_Azw$1Ux}IZD<`pC+zquJ=Fugthe-FiABKbXypOTIgBaGDh zOF}5%Hs*Xt0Jc5+qKOLjdRwry>zCgn2MdQf{#&O$ZQvy^tqxhJfNn@GK~2Q!$=jw>(RX@5hAFr`6~;5_s&Ewgo~f(nm8DjHm89K7Ih@jw_ScKM}g`M^ZkWu@8JAE z6IX=gmSDrpe>x%n3GT_a;}{`4V>5^JZzH3d8iaa^D@LW&{8RCRV%e|mxOJR)T~9b* zzRSqdXj5PDy_Js*m;p!1PMk(EkC7x9{#iGq+^G<{5F9B~BY08))e9xYok<${gH{-z z%D~Df#-dPnw*WjpvT9jt#!w@$Wu{+g$4sL(jMKBbe==O`wD|`!T|(>R4LV-+8FKGv z9gDxSvMYV&f>klPMjz?mii+T+BWGgTP0dqxKf>h4u7%(r*5EXTDp`!($dK3}Ii~_f ztRE+=DNW&I#4#t3Zd&iSVEmB_-s!w2=bJPdcwL**gz6f(o^v>{ubv|N1ynRtvC@qtpei31YjD<>4x+HtnRoO@ zqnA4N<0p&=OpA6D$My;l{BXIvd;TAuI%NhAqBw#1>qgD@nEA=M-I^h{VLQc_VasjnzET0n+eK;4OX0D!}-0C zH(W_CROU{C5QrKiGrwn$dcQLsxB>E^NLO$jAqDl}thjn@JSWr&4M!^wC=Mikx`cn| ze^TJR=xxX24!(jH0x+v_13dqD9HE~@k{g~H>CHz1M-y~QWMXr0bpbeW`My#sp&u4* zo`>Y*?%Nc2b;X0L%2Rr&K5z(+15wt5FiC=1WazA$CAkV|FcBM!MhK3CyKdU#YJk?i zCRyb-Tn(_VxWHjfKPt5K9^9NQ*H@Vhe~0C*3eh$tA1t-FNSrrN4SaS?ex7Dt$uH9o z7NL$Mjvhw$_#G#mU{3?iz-$`o8UxIsZ9LHAtqBHw74{1nG46?EGw$4JLS_}F$H&bX zT9-Uh|KRmgD$*b1RL(AhR#ceeR}wosG*VsyNIDTWz=Pvz$q?Di0y5|(qsM*V zV4ZBge~p}}EhWuarMiM6m>`Is0!)Ln_Qf+0j4a_UX21vdx$7CcF=>P4F#8B3GvT*= z3HIQDAh`CiQa2l+KM8_S=Y9qhe?&TQdx1n~kbi26PA{+F1b1z+RwouNCAkVCZ;9g&D^L!L)V44W0&=^Gr%8()eXu zctvh0;Ag>Y1I1l;rxy|ktfmo+doGm`o>=AE*&ud)e`BLTHG^5O7Ml&rf3HuEXza}e z9-;9b=|;H7QzXJWIxcdvAEdH!fms@nE}j&ME~{!aEj$hSxT{x{pste=m(~A2+`%9 z6l-^<1VbI@Xfan9M<$bXKm0eB7}55KHEItP8&o{&C%Q~@EtY>|=^WiPTCV;Q#MdDI zy~xvJx?*5av06NjEawFDK)qx{k78mJSx!pFmpPaQB!BCi!U!a{Zr5y6yY;@UAJp=I zLQ7h;^@n)yoR52m$3=Ka7Jw%@uM=_Na_`s%U{`R+k0|e+8M6J=&WAC6x-UW>|nuHMory6l4`f{y= zQ~i61ViwBxwZeE+>7+>&lTS|ABX6u;K6%t<5-L`j$)`pVs&1jPyo@r?>ZFwUK|dSW zcY+5|Qav4}W;&ics)?R|1bm9=JiUcSr-QMK#(!g>6ih+!@>FKY#R*kvviu0h@r~?X zN8-64>$aGqVRG;^;Ef*JBv$L6J6V57o|`($n#6KLk=AJX7!BWXWgV`|GcVe$4YqrUS zK-EAq6liSxD7Fm9OO<34A_rOEJAyPQzke=sYW5*wA zNXD|H@C)hAFJuu`C&?bYuC+aN=&ioKMy_sVLl|f81{-H=zmlt1yRtcqb`Fyse}4t* z!PDuKw>PNaiV1r((cdVk!BwC=9j0Uw}079C-&lx zmP^IR?4Vy;nfuPg-&-i99uzZ0>N4ik)2wX)cgrmXraQE#Y~1|vpXJDtzP5-z4PiZ{ z#uxM=^cVS$8IyFve*dX6LJh9c5`Ae@&xQQuOj0e!;Cd38!t`GJW&D@%OUM&V*`Yy5 ztLa~80YRyzt9w}X0MiK3mVfY|yd8^b3byLJoI!{orT3eN>^4(@(`}V!uC9O0#=h}5 z1qN3VS_7I=XuD`aOt-^}QE-faB{oW84|XTK>?f%q8`G)T*uWE_Kz`Rdz+v&Mf+uJx zx&IM+nps{R3w*USFotUKIz9eeO!DkQx`+;-u-XR{(qblRIu{_3Cx7JRoR(5rlpmVR ziEc!`^ft6ekrQUSiGXO(@4M?ErYgPLE{Z$oBX=My{1Cj1up)2@abJyV#gVtk6>ZYH z!M(?KbO#kJBxBc5!OjDOEx|hFBF`lGG3a=deaJ;Mo8S^>E^f=ohkO3od6HjBxYsAy zpeUbF)n@LKNX4}Ggnw4Y1e8(-P=wSuVaqOS;R|1iSjq>yjqui%Cfia@Gu^)a(Dpt| zWyQAR!P5RZiu7WLcrX_%Cp#S#9X_itopJuRSw8L;Ib`;sO`|qmKzpI$@n&Nv=tD6{ z7XW}yEU572<^H~f9bZ@i^J9I9u-EGG`R|Od;qHwr_<>V^K2|;H%f?7 zdv2i+g_x9TD+$LiY2e4a!b7k954(jF=XO6`dyb4)?sUXyIh*wJpT$f0y49&S)N1)H+MEo8I2#M*eBPi`cG75&*TTiBq~K=|dR5I>2{M$LOw0%W9=xy>fV zJ<3OPAk9vH#M>VF{(cND6TYMUx=`!GYo2()FsY5Ol8tO|- z8kM7)tg4>T1OQ@Rwkh3+B)1_Zyw<})mxh7iDapU3YHZM?gEosPCFp{$(1Bt~mmW@a zC~{Z9RE?zIs?STqc7|W_keMACV)qlcoF&@bPk-v_QT<`AKg?CC6aC?{{_r`N34>zd z_TUQc3zP#Zn?{TN(q~C6Y@Awhxi%iGu@}>FH@}j)a}8Qp2P*hutKg*0c}q}77~4au z{CEuih}MgOheF(81dU}@g*4=tC{d2y3wU;k%@`E(x?YpL7mG-+Dbm~6*l4;dBG|)d z7k^yg{g?3{^!>{nxOMpth5WDlX9WKl=-ZWH#ixL@W9#tXC0)1N<{fA^vMa3Lh+hoh z+AD#Czj#$$DaPPrmLHxsrnD{`65D>^^nO}HZ-bHk)$OM9CLx_&a{p!AYI_(hq@F3= zh=97+nlmWU1n8zP=AkDR%z}_47g{nbrhi4Vo%&z>EPIRY9aY;yIvAxic1_WM$B)nf z?~#`uIbxOjwNyvUU{+%7NQ!uLTf*rvu+P^`2MPIP|LVMBJgSEsjB{OXosN`PN+?mV zWP0q5O5uz`Yh_GKPZFvd#JeQWX+o^i%moT+tEu|=?=Ilgia`#TSv6E1PVyTU{eP$A zao?A3J)w{7+^SFo<(LP^RUoW*>Pjf!E_oHHA`%>k_y3e%P8PDFLVnOhJ)M%(B;h(v zJ0=PMd^i-|{8`KztoV|S;MBh;-vtI^qW9i7N{d~B z9pYNAFYVkx_waaH9v)(0e<>NMe1AB;lF+q@G%aa-puU0J7F+(^m>5l=r@+;uA_RRX zuU?#-t|_DrrzQWh21jXvZKtg#i?dgR+zbcf%Tlwo1g=~N?{q_v&|p?CddQ*9`T(uh z-MkdPzWgj)8^c0HN7qlNkJp!j`l=4<%s{lS6MH&rz| z`&;ZWWwM}FG;2L7W9$M5y0*=xY*!ElYPk6WCIeQsFF92t8kFJm_~Nh9cn6|Bo1;Lr zO|E~t5FxKg0r%bKqe@)NuCC_dwwPXPBM&YSzZ9xaQQrA-Xpd=Tp!=SNF5fJu#5I*5s4#$lFr@rSj%ok#qZ2E&Iz0P8~qZR z$xPGs7Demi#W(8-kXTdi=7DR)tc-+qJGXy@YWJMhST=dK8TsFR=MFghm|R$O&j7{K3tS~OYcbClYz<=0et<^F`w@S^ z*zL(24d%P@hXPp8lw@4E7U?MT6q_~`ehKN3y2&|4I0GnB+#Q8;Z`#3Q_`>-k#v~S0 z!iHiergwHu=hZYHDPBo)NHu+#-F`qj?rzxxZ9*lUu4NOuzKBAU`{n3nm``(!Z|X?Q zHA52r%f*su%G1`unuNAYx7)%ndG3EOhlzZ8UEZ#7Ou4%bb%8;Fi#hW)q9&s1!_-pE zyz9NEQ@>|wCeW0q5tT5BP$fETgIue^m_9varHwzxCv46ll-N-bc%Z+k2JbArY9Q40 z!`UMg?G{{f*{+}OHskfPuuKws!$ z5|m?JO{+%(D)AIM3>Zopqwm55e>YkG0~s*rP@G}rMPGtd`WRI{0gsP&hRXGC!hykW9?EfRhw5%TNc6OtFiR- zHqE2$^p=>nMH8|y8+&5_Gs}ON(UAG7!7fQtKFfbr%=T80(oL~iVI7ta+FpRtR5 zsF-Z4pN;QN1@&FvsX1`h-V9o78b)^re6Mx;|CdqTC+l-Vsv70#^jGnQ}(Qgw)LTazkOesijFG^hqif2X4c$$j0#YWDEaI#tTkNm=mFgXij%#?V0`ajvh%t->0cjcYHljMNy@ z>ZrA=4HsbDAIN$kXo;p^dz{<)vYzt1Y`$;X+kcHCCvwjuJe|%+iBQVGS}GID%n@EV zv=j8TTj+jm3pXw&Xbh`RYziiY*B#)meuV4{(H>9ie<32Zro`YddZTFOgIf&B?vN=_ z0!Kxi!;F@K>f$Z^3kmIErO$cBj{9Q+Jc>ylo&6#psOV`7F9o-^g82YyMi*Zq1!;P3=nm{a?Z0Mej zY6S&Je<`@YFu-`miySXpku_#FL2`C@;rxApM@9R7CI}1e_VGC`x&C!MY&{UZ$<7g3HD%()z#ne z!*jVfnRH)F@_bwer1>J)%bgfc_8A+`=h+yR4oECyRLs;e6%(?PDtAbAERG72mEWNF z@dQ_ox`?{p2nJFPwzO48aPm)zoNG}+T|KNZgDg6r>)zPat^{hLygMDbABD~*qEk*; zf039Vaq65w1V?X4FI60pwC^tR>8%_y@u0g68G<&%2+lkPITgWf!gzYb-&g}|ESB3F ziARTPnly+F*JjRaGLa04Sn1Z&c}p~-MdD{&Kry5i50rBmmI5f($|f;hfr;?6jX~*# z&PqYbNG?P1eLI>tL&c97rfdaMBbXe^e+>w$xWrxO3k<)Y{Bn1rDvgKFA5P5vuggV&iKZ^$&8z!S$ zycRsm&C1xCD*|uvOuWri5-vz$b5ESwofASyAY6HhCZjil~aw3~nJE5HqP#zL|s;*mEdw>fT2HEv}@O|7|GUwV|{Gn$Hbt zXAHHU^)6dnINuer4u2w}!&U`)J9ILdQ6^=9Yy^1qwxm1Y+sMvvT_Cje_T@fmB>nfB zm;3k~L@pM`VZgj+CH(K`_)NBZg=eC?jDOmphe%5=n>-7CqnNWY?IN4X1;reet@5v; z;%irJMP6U(O=CN&SxYoCY-_58mh4Q+om(GQg!DFmbU9iH(Eh8I-#bc-q~|;BE$-~{ z>`nYU6OkDm9CEGf08*6XlaUcOJ{NTfi9qNxag!BM$DXP3e-sbn)21GxgAs=j2!EvX ziBF`ePsOh|hqBX~B_BV0b<_$m`yCfF9&YG@wM{+&v?7rzb0pa}Xet*;q)% zfGK}dN;@hP_#7qu69rR8wG4srha z^0Rw}Q$w+bO`8LI6$R#>F&X!vHQ%_XS!~Vq%s&aViPPUydCUQpqW-$Y{ z;EaKoIhV(+1}%RJGb?I(htBy#=CycrmKeu=O`c@0m)x*biv`2{hp+_PirGk!qDoJM zDG_#iTO53%(sh(8B~oB(;68`Qu%2a8_e27rVub3thikLW!yyT2=61iC?Ybg|DiyZkg{EHTvxNWFp@JG9aNc)9Q0fI4f zC0Y0>*7yiNznXLYyufua806zbZCqI3H`XM6>P22sojJ9o&c?T6MSyfzs;7kkZOvl^nzG!BU*xzB|gu_yOZK0p@zrA zV`Zxk#c)U+-TTzfheNr@jCb=BC)y{k$nW;g-`RgB>(*pMS9xaORNCi6*-w$OyvYVc zCq`6Mk8#yBt3D9lxEN;`hYL$w3|+01ixU>KuMSSnIEcQ~(O2b!dWH>lpQ~40xEbYW z*J)8rOhQ}zLElXPft3i3ze;%u%*>9r#i!u9Ba^87l{wFdvw1Kd?+gZOyi!-iuSBhq z#+H9lxIXsV5Azypq+RLL7{V+8!5Wzh0H}gdnRZx~H-g8j!Gg>5&bi}|8NwK@BNwXf zMTe0B5&xi8ZLMv*mB{TCn`5+n}gf50EG4*QQku(|L*p}7ZwD>L2#s$RJ9pRrjJZY$U+k_tcM z@O*xaz?&@t&tsJcIL#P~gCmvfRriZ{1v(wfCU>2E1mEbe7!?>3q{u#$V`CJ8aNK`y zG$af&t2fW}S{eSU?$-*kxay%_hXUF)Y=&&!;y@X`Iy{$L!ZtkDFh$~2Jx+t?C4})v z+X5VFRK;EbZa>C%@iBNrEgP`vDZFuqjX6~2`l`uxcpv)^dJQ9~#2Iq+2{wmsrk<5?VFglKCEQqR58`^*AidS=S zEyn@g=%_fXF2^Vn%$t%%l9-MzZuS0coJ@F0~ZA; z<%o@Ch;{yOC6R`fN<>Rtt=$OZ%a|Zlu6NpL)tk?E`k0*4Y05uIWxATP-N7(Y&sh+B zNA_AWy8#?}00tA=8)76`?{ZS=lP~mHF05cv5`8P+w}coc3|GRlX5oLG?hS*Sw%yZF zSek@YeR#gtnm)szR=0~I@%aMgnYTxP^=kH5BNNGaYlBP1HXPsG2_u?fR5HaRUkYRhT?TcR?R8Z%;9ppGmK_bNE*6;DV=S(!Q6si12`H7OoJ&OFLEjOa)^+^ z;C01>E>doOTxTy{#}|KLW+rDtKDv~ng}__lqjKf1c7Hf`3_EWz8v=o+KChDQmo*M+Ovm+j3rMwpn*2(Z z4fR08Yd8i%^5r5k!fBHGErKqDU2fohX_nF9fy zS|698B>WmxHo(AI;?Ni4v)n{S0 zH#SDysFg~8-kGviO4sdmT1P|rT?*%f^Gf*y+$ot{N{->k4usCY0oZ$3QY{H@q}?pb z?LI%HucQYlQaXQ@nlld$(*hQ1T1`QLO(70qqpg$lqGHpRTv8M4rU3=Ty=!2K*`wvZ zKblP*{uSda`q(#3a9d8YaKC ziLafc*HqC-o}J8s8p%23?`_DrtRi?u*|dM{mQv?JS}%Whe*4wW;vxscD@*~WC+YxK zm^~~}?$1F&5(#<{POWEeVi+x~_UoHxEnlrVZVhjKi3LYdmk@HV*T3Y^w6o{fi(Eniu&jB7LeSma>V(2gW14<=< z$iaU$`yhV~kHnLmt=`6~-a?|MLA8FJU5L%so7;d;Xf}c?OU`hi0Ep+uuU;SSo$c{{ z+tPY&Qeo_-vg?|rbcKfz5J7OBW$$&Ojjcr9I~!c^w^N1&vyar*|Yn$S+yHA}q-hFxxs5H!z3Qwmq1&?et9K!j78D7$id&)#_%9vbl3$rnM z=b!>-xKr#j>kc`Z1g`t?Kz1eu_nLM8!b2?IVD{56woy7ggp(Xy*zr1BXcwCQ!$HT%|FXG2@FA%G=;hqK;25OK+!;v5*epj^s_Qd1zft0lOZgnF!Pcw zzl+bK~0Q|oQPZBo)<94{%x+7h!+n>=w+0`7QaX|$j)b@=@_v|VQ8LT5cWpW} z@md<@m8-gOc(n-xW&Ax*r=n!#cV@|D!+Z71=_K;9VlPeRcXdAAw0tpZ&@e32PEW*> z)81pbPIFp0?~<_I>t&w$7(%Me_YLQY`5HA+Jy<<7 zU|9VG9;Z|{l<&c^blrXkqf2BWG$6+kXbFElErXah4eu7Sz*(~dVxA0GfY(9}!1dya zbBl|V#k0ndGtD~uHB%?F_`Fv!6E0Nt?5%%)7q#)}R6CPNHW$|G!<<3>ClsOT*tqT} zlcA>XF#&4IC-=8?$>y>%qf^yZPSy;JBETz%7aLy*a5sy?4E7uHNf5CFkLEVFm8yRD zy^F7%)=uS+_pf1pBulrr0^G9+WC*SSyKo*YB}sAkmywzt<)6K2NQ%0qn+nDR-2exF z3F0n?0zlUD)52k>7iUpgIC7~0B@DX1zIk@1-3NF}cApz(_+l7lJ_mz)05RUc;d?uW zLb56u4nTlPWVDCa(Sfo^9h6g5If6~etSUWGi*b>0D>y zfn2O%&h8ueW2op-QL-agq(@u|=n4&gMOwJ|VP}D(h2sU?4H0%100`GZgV>*IB3tly zSEM&#N!mdb=#q~#62H`pnou!>a7nA^7nA-F(mhH|M)$BLJTUMmb(P`$F;D5R>P;d3 zC^qH)uSsk=qPH%7ir`ZV@6+++B}9)Yi2V}cfT4|b3APux)|J(ryLILK@aooo);5j` ztuYh#+a%_vw^6J%cwq}#b;-Hpc&_%2_3rPF7W-h6M?e0i16dH-DV*@Xhnoz#7O-i` z>*c(N%A_PRwbYBWw-ka4-DxOfq=<}#G&cyca8jfueY-lKM9boIV$`T_!jB4Zd>)=G z?u1F|^`}*hLU>kiHYXg-@!_t2@%+ZwDdk*V9(+tOC=v!VSk8?cL#9bsm4}iXQZyfb zLeoVm*WLfRXTPqrCuAm{nLdu3`hGh?%j^WLx)Bt;Bj7jE4 zoWNYJ_qGNxCh<56i3*Rh`1%M7z0UuN=n92IIUH~VmfVeXXBHVVaK=i18heqpaMx70 zkrwq)7TSAx<4RYBw7U-iPa-k^s&`|0Ivxao#bMg8(t#LJyJWDv?MKk8LP=kmMhZuF zvsaQ>$zAM!Em=h~`0ppHsQu++RsDALl9t0=ZBHj+bMIn1I#kc`?dPTJg%lbQdx5pT zbWpIeS815#Ag9Nd2DdAJj!H4eMiNwweXGQYiDj0;dz8w+8QW)!+*9i4EO&>{-;X9A zfwxiDAP!N*vtsb5zn`XHqT9iedMUURCz}F{F4Gku$KqBEVDL>bsvCk(fyC+6rJ6q> z85MJ4Ep3J9iizp^72D7TvO8OCo?kp-t;D(Pc|fzyH@(x%Vd!QC+nA|<(?yqIyap40 zr%$q8$APE)qjz?L`%1UPErGmk-S-!zHBQ85v}i%!7OUSXr!cBLwPUdE*PzR5L>AOb z+5qq*?0^Uocjh`+681Or8~B(k;WP-iZV5A6A2U(cI;X{kYo0D+7q4s>M;GzVmZ?%; zEca}D75<0HSzX)Psc3pNxmc=BJ;v{UD6%-OY|OK3oRlo{Tz_@caQu{isA4xcQTJE4 z#R;sv;1;Jk5;YN`iwU{d+O4_nDVlULoDt_HNnfz`RMf_MA)6$d#0Bw@ic&;Ski!vI zU^fenBa z%Jep)N|CAvOF=d9sou1FgHnxzlDdk?0#S9>-3=b10m|WuvVf8Y1QT8Wx@#UO#gAgU z?T-b$>}_teO;?g~g*FQbgnQ6ZL5!If%Mq2;NE7zFxC_c6lsIYOamXvnCg{t_nxdu# z88<$GASQhjy;N=M#G4|KcGE3?Tw=ZwS4yZ9CcZRrRV~53il@y);3i|H#yMe9M3Q+1 zxTMp1Qd71OP>dhJIJlULQTegJ8%zceEq|M1mJ!(VJUQOOw>v{P(F0e=22n|E{l?z4IInO<3DLXIgXgM5O`o|UhE%8ybxQF|$j z+62u|LWgPd;!fIRvll-Go*(KXOA*DkOZQo+u|XTpa%x*O@hq3h9P)9EvQHHDQ>((X z+BPrmSR*;`SIn9G53Qbzg5u;)2i@_=3pefp=2}FbfwX>V4uwa=IZ>EPbZ+F=N%e&> z96z|AqCjc`H?}sSb!r2b@4f~Pe^xyBf(6$tQ^~~)oDwcs z9_)tt_)l(WtB}pghF<;Y@2HPGRGMgG-H5wEoR9O-991u*YNwT=m1IVBFvOio{5y@e zd{K;MBYLUR{shCL`iX77E=`g*w)MORpKLePrFUA>g&J*D4XsgVrkAb11}1;jK0ilj zp{i1MCT{v8ON~3+Ckcn-sMdN3e$xwc$4yrcYI6Z7%QV_MN`{E_juQBo&z(vplNhlj zO=YxwpcpQR~08xK`B)!;P)d5W%?HP1)#l2SZ*T7G}0+iKWPBm15b@9MbQzsGcMIC-Af~sM1gWZ4hP4?=A?vYFG{;alNW*W z>@(&}D}%>{i!G@wBk`2UIzg4rr zfT-2r3GcX)!=k&^fAo8@P*i_9P}qEzUETXMon(D8 z?dw#g_I!9-d5$*1HS{8lAWr$9PBC=#f8ze0>JRgI#l|UppeqH`=U& z3nvEd2WJ~acl*ol@xXui@2^$UBAn^C+D%&iETxO#0mp(|Jn41IMOIOM`Bc~W;|v;K z`dIDCypbs=2@S6w#;=?`v~!r#7Ix`08<30FFF_2Xe8$cfs+T@Z0goFO;dCBBwH-7Q zUH;!^+xS^Hf$$n>S8rC+|mL0a_i@1Hn?4B2)q_%&xjSAH&z^T<1cBdpt z1Sexd0M*1Z)a{CLZw#cKgcAdwGX9=KHFJHQm(Od45YykI+oKnwSs~ zIsJD)11j^2)v>k6)>v$5^qm`WWDU{__GX+vMXO0#xNM{!+;hJ#Ki_YMAG4VxO!7{^ zn{1MesyJ9LnWFb6>jm6qL!%^dNO~6a+jhi63Ge&fM9P0g*&^wtB1zn)eWPNWK^1>K z8rfkr0S&2N@J1T>!Wzxqu>|?Ct@dz{-MSb_^4sgRP{Xvv{o~6^aZ+Z3`*=gd`jQY? zZ(^_M^d9N5y0rA2vg`&9*D5VAPjP3XXj4mY&N-CX1dDabkV`L zpRD#%*Is|}#Gphjb}9zlox`1zSLdf^J7;@|o1a*T?#`RDj^cTrBz@Z!C>s3;=}5+k{uQ3Amr2EimCW{`N1jHo?zjSHiHChkj^d#l4#1#`Gn% zDppZ+3R@jhC&}6eS`rl){Mcl0KrEOP)peKp!v-E+Yalb_UNzObE-cy%$#0DOJ@9nHVFMNXtp5>N5@KezX?}xNwc1pWv z`|_0#E!d1&~lx%}d(?GmvR_blXc25?K1KfMJ z;mTa5cf)lh{kgOp|5G}HXnIK8Aq)?^$Pe1VSumjv_T6;<_}OVfq{9$C6{k~a`1Ox} zFaDbMr`+4AfCglSTKp(6j7m}ML7M!vb^FSliDoYO?|JzJemd8j1!7RwlNNz9MCZi9 zF)g17xOlFVW^Y{4@6y+=()96bTbEVhwK^O+aZG4_CnfIOvgFFK#gq_kRp-9XtCj z*t+h)8ylw-@To3SBc8@F*<|W*0i|Cy6-kRZadqzFxWx3B?uh0;zVoLc>LLCLC-+U4NB1P?qa*-#0e)pNF zR%F_CYQiqRQeMK-c;UmEtzY~wXhCbb#hTR*Yp3}N2%ZM3Aivncm5{e&VXyr8SB|Ch zQ=p-X6>?Zn!N%Fn(JqQZ_!EQKJ0CxqyRR$)%NMT9vSQ455^RbLIoubOx$fTD#kN&AUEN{3*?l#P&V}YY^86y2Ejr? z?yGJ+HR6$KBv#&Am-~+U&XmxFbxcQz0DiIs0{9IOj2Z zUb7zTv*9cZiud5cIo_oKznJ9eV)h!yFHZLMj+O>}EJxyMA=bwyJ4Y`ZmqW(}Cx3oo zR!@lftCZ<%j8IoT(x^~k9F(0+^OzLV=h^sqHkr)d=GR4ksO~G8`jb_KEvVya!}1mq zsX#$Dej#bQ@+I|0YROFay)hU(12^1WwF~tRp|zlKWxML~g`W!qH)R=sn13m1=B;Se z71e*9?K}tJMT6xeVv5txDN;wVzkg1%zJ^@=lhbK-GsvbnsA7z<0TlJ6n1kZ-GO&l4 z!TOF$zEA0ZRC!!V*M9wx8uwI2U5#I&;l=eBYD@11D&^BRRX*7tW>>+M z1cTSE!!zayf(K5QnSj=0{oZ>>tn?J+(&9$alF3iZaNbwHcDN;BQi-UK-hV1tzfP@? z;Q;0g9AMJSnV}lFfhu+bGgum!mJ$f5PWfxI21bvl7-6hM)ai$C?JV4nC%#hFf6kH z{W%-cZ!B4nTcwiU;fN~%rGGEzY$++N8tsk;kvV|J&cP|-V5wVYggRA{R_JEH5}=#h zfK>!H)k^1eF)Xn_iaBN!50o%ZHF#&FDTJJ2awu4Dl*?L@%J&?0AlQ5Xr8TM5`Q%%v z-QN35Ye>>Q&Q7YM!Fj__rK{cS%CP_lU=m-V4~*pT_@c}v0|L~>Vt?ry3b7t=$Qjn% zpOhoS;)@*w0?}@@+Sp=vyPYyjRaYEeG4{pg6<-xWVq!vZO$4}!-`72i!bP=4u*Pai z;;=gLQJ1Cx!_#O4Xip_Q1n_+2Ff>KAW-QeGN|A-Oql|(VY1y|kkfLjpk7tF-Pz!Po zSCY^w$ggaQl1n>1f`90?{ockaS)ZaWD(%^kpbtTEPOm4py9{7o8n8`7TL3yK-dOsa zyOM8O_o3Qpp!rspitzYCFU2CN6%0MWC}`c#3wo0fZMq3vuZ{yXe@p7;gR}D8v?QIo zrfaXicO`Ee3_J>3$;Z>z6o;lFWS*C!k(??OG;%t-fFYI(KYtbFq?&=WmQuU7qMh+t zz}cpOuGADxHerSf4G4vHEdr5N)bCg;Z*XD@n%S7V#7DdxN`Q6)X}mg0>I_T+oN_8z zkJMeE^&BGuqzbtz>u^Hr2QktH5JPJLLS`E%8?3}KnDY&Ei2w}{#j<9UNKRqv-bRGc zR

FZ;_Ms{(mE9E!xlq9v+s)jZp6u>_};ID%_E(YXhF;MiEH_H@8?E#>g**>g|+r zjxZRbRy(Z+`4i~G;A8sp*H|nEWFSTh_KGFlTekUyGDa&pqifq4cI&wr5Ls0nw#vr@O!$N(c?g1g1t zrW&#WmS1UrYUdL?%XP&Q@@e!Ji}@5n(TzU-xZ_6&2^)=E6Zw!#`;&U~E)Aful8C_g zF3S;2EG%leLsxylN`N9k0TQsWpPx4Mphl|*HDaoBm08kNZ3x&BJGL{PdcKxCG4vXe z2Oi^2!+$KNc9*}ubVuMZ3rWv0PHAFY25JsfKN8ioCg9B~8w*3xbJ#mEdk)Ra0{*~4 zgBsEH2CNkTAMbU{3|XZ?c$N}83J;aG)Np|kHa2OfCnHt0TiilhC@cMEq3q;Oo?%t?n}1qJm`r|WJhxKU!Q2=}P>yJ@%qj&Q zP2$F>ru}ERE`eXGzB3rP0LX;Xq|v-s4xi_<$s`|7$xskv0i-ZP5@Eq*Ed_WMusS@; zp?(M{A`GoTUS3Q9 zy?@~aRY0OFEp8|l@fAg6En#^rM|JECMB-p`(2T*D&rAwP^48DMh@M5`u>yJ+(Q_C0 zA)s%7pbFo)3ltToZ-69)FWm)>1gXIqDfQWtEGOBZD4*q7zZ@?&xgfH=Tv?xEvx3_F zb`uQ68gGQ-%p@Bl!jdXxIechFVLK^wfPWPjI^PnT6S@%VIi#hSEZu5AZ^mpVOrLMyuR)~VYxCdChgSNly zZQxB9+B>M?A+X}Q-h*_|pg$PZm)`+X=lKSuTuRRM4!=2HJrHu8ERBTADeWfioPX>c zommX^jv%ANaso%T4kssIhY?~$Rr{XHLbDBmgL$qPc5QRr=QalKWN&v#a6O;6-XPm` zHbkwFmAc=H1xqc}Er58!=HXX%D*zYimilShspsIOxEJpm(HPcnupzMeL3gFAO>9-& z>|o0!gyFf!Hg+(Qm=@LaPKU@UpnqN-QwmI}ygJ|t(G?OqyV|Ej#lTI&980Qh&EXLx z^cKh^B-6J-$TR=11ckddL(tO)`XDY^qgx*CT%X-Kn+ayD&>1%Eut@i%aQ z^xyR^F)IQl8j+tfi=6&WFLU$)9&sw zm7DL``~Z48o{cVe$UP(kTz_w8iK_0$6z)Fj#`#nq=ynS^N{1E0v};BMUGek8a5=3UPG)@`qu2e!KhC|6pPiZ% zVyEGHHNB6Yy;gUN%S-v0TJI1nr@ksMR|V!&z@Zo2Lh!fAbdA9MQGxwY)&3*>cio9p zvyZ@u#9mMlGY<~43Q`#s_9Acd>EI;(9v9Q#z6riSH&kX(*)r%L2!9Sn43GhFet_Ac z<_oK;9G7R=L=I~J*v?iB{X?GLKo~JNlw}*Y*X8|6TvI-Nfr~6NDN%_rU@!7<4qmtc z_WgM|$Suwu*ehLB0vq5d*E#H2%I4_6)LcwvV<81$l%f_i5#429Aj{5dT0;3XG;ncJ ztNoLq#!Y)P;9c4O(0|q^bR5M7Us91~>LW9z;e|6j>5o(o-nqzOem{erCwfdtUkiFY zTn}mi@9-`$NM={;2ls85mZH<4G$~+OVN=+Lru$Gp>lvZ5-7gF-G7E`M_La%VL4^%htI8x~SmPyM^A|=HF<%p~9CzN+x04#pvQwnW^ zrDv6hCL}Y*-~5Lko##)&EyMXjMR3G9Lw{Vr8VJzaE5JUg$K%GmO+#qXQS(E02=mh8T~T1T^wrk>EMh2OSBq)~kDaX51k)`u ziE0J)k+iU=IVPsJqGI~*CYrZ4(n7)a;M2WUN-Sv0RV_;3?V6!;TO?=(gTbI!eVth3 z)C+Qpw|_pkk&kWw@_`%@jpJgVo=g$cdF{P8+k5p|yg52J69-58$3K%o;0<96I_ZS) z8*t(oKX)F%R$>bO;hCZW_)dMGqN&V{9{tkGOy_=c=RhRc5j;`77*m5&q^VMq(XLau zVOdSP;qB@K@D#2q|SGEqqxC?xkU5jlLcc*ii}K@?R)t*iAog z>2g?gHy#r>Anbx!VjwZ1dXN`=eO?cNT7jQtt*}%@9zC9)f<#FS_l5pD&e)d1@~0Bj19Q; zg|j9Y7`j}7CW`yfv2&Odb4w8z1?94sRMQwNc!-s;pqY8#0yfxlw-T>dYo)-?MvREf z1396P+iFUya;@*s&fN{U56XT*y8rY>_J3-a!(5d^*>%7{CW%(JYe1^MBTV~`V7TGu1OKPNe7P?bVWWS3LfJ$9_RuQA391cWvQ~J7Sk$>(` z&;o8g9hSFu%+mh=OufxDCflnJvx;0zKuN47w4>a2nFsiJ+2G8&%l$6b_HC0`OaIz3 zzaE%h+mK8qy5&~8WK!b@WhMftBiBTKomJ?A?q`|-bFrA*!T8w0qWf^u5UaE~|u)53k8 zi#)&SmRDD;Oh`X|7`gY$e{yv2#6HK#PMDP6@qLyNC?3Rzo5joWw|wYA4?R<@=7ka(f=-vpcXQ zrQvLuHO{Mw+@RUrJpX($zRmknjQM}8nT=ujH<-B&ceB}~q;Kx5RPQ3wQhi~`B~?4p z99e3rxK)?uEYqIZsMT=d%K^Le8D`O|iJK%-6YQZOdUwB|F5U-zM3$yz4#t<0>?9xX zB{h+KgD7nXyMZz;9H&HkLqk=+Nu>Ac?Rgx_+t$%Gh=To;hau7|QCwubU}Jww@9&+Q z9G~b_FOfVF{2X|vVCboIR}sEum8zRWdB9~oTYf_nYF|zY$vFs4+EH@C-(PIg>SrO> z!rbvtM(58&s^Suo`%9Ui9Zk5<@o6?llECspEfp5hps2(lxh~=z?{>AD;yyF}>&a2C zxxyaQ^g38bIn$aFat70y3yFW^Zlx{(7mShgte=RU^HH^t(r~(kgOjD;n;)t*6&J3Y zX~Vgw@}aDs573K6-hPZgf#9I~z*f^@2-c3k<4=(gw&r^bj-bZo9IeYYikI1FFw{{X zp?&7AZwOO6@(sZpY(ckctJSD?_D$V%8~dakZf<8;;1Da|IN$VpPYHih6=guX;dMNxnJ?HNw1-Hlq9Tu zZAc=(U+jYWe3X6CP$M%>_xmF`xP4*O>FDdNhLA5nPAjz%x;Cq!tb#i##~AvIYO6w7 z-OpwfTr*J3AUf}6NUDF1CgZiNQr~srAeBCXhx0B{ z1kR60fG-NneYi}1OgkI`MJ|L^U>FJ>Hz}&|{i(PB7m{)W$pL@PiopBRWTS+*1>E}W zb3Ms?d!DoEQ(=mk6bwE;JC*Uud*@9-ZvyFDMFiTF*`tU_Gex5}OtgnzIqD9QPGKZ7 zN@tTka>=j=4nlY*Ea>gpW}D)Oy3eKRyecR2?u(P-H%Gf#4LBBK19-g!@B+26Se6Hc z7wZbA(jvuGtDS#*%|;*PjF6mMRM(Q=(%7@UPWXrss>o4o@qUFh4p^P(mS z%wamenzbvvN}7YU%D^gX7M53DV)TQmle#Vr9_-#H-90Lw&IF{Rd8M?d@*LX8NNj*) z&xUfLHJB^?fH!VPYNFuBt7))w{DLS8|2C`S(B5PfxS)TFh%kglkEU*@HqVe=ciBtQ zlHr%|aHvRX)h)8J9MOillfXxa>hPs(-5o2%sz@qF(a#k zvGBEr*n)rUUHzmDNB;>8NkTJbO-Ab`ZAAmP%_MJf{NVAdMMv|RxE=k`*KdnR0?+rb z-fG*tOKYya*}#OZE4;EXSPvGSm>r^rv3YG}<5>QzuNpXB8hwm@2wv7$wcK=a5Rd6v zZvF-kv{B8VaG%0dzQa>RQ#i|QRxnbb87U&|;%t9RXT4#}fzx z34W=_ERa^`$6TLAo0KEGUE)Su%+PJ8{`!f?Kg#B)%r9(0_ta6$HEtLYLfqtkqpT@1 zZ?8R!b0t~pvKY!$P(IKV@pKv_iID4}ig&`Pr4}caX<6gkjbUH2n}U4-;9}0}Nc{1K z>u5-~_XB_b=jdfOmqFVG6E6e5*Gg}jJCZA*{*cY(U=dR2{aAn>cBm+QFGR$<0hy0k z+ix$Tc9#=H@YCF#%$I}P1~?^_Sg$ViBne0ZwdoMK7efO3|0FM_!4)_5B&$b5mNCFu zP7Q7$m*Cq5A%9Qx+5EGevp1(di@%KjGB)=k;xu-eQEDcBL$+=(a#KBor3%StOvu5* zafJVHer4^%!^%xvE(^IEz<2AKZz&tU#-Bo?6SJzgi^gM_=9>W#fMzpD1B6<3>nD1a z*9Qe;VsKJE1$dnHT5pbiJv#o4Ul0jTWD#Y27r{t4mLG#Z6!v4I5Px_W%bK4M8k{`! zMz$7sm=}f$w^XEXYnPzh1{Qya=erSMv$lwd>+mQnHGyB3)&IV$xrBB)li9O(21 z;+>93!>DT&ie~DCH!8X-|G>|uMpv&%+!43B0qhkP!{@-c(N zkT!`8Yi!;3D27)#D*25-?*1yrPKVNbfGC|$uPK(6wgaZ-yt-TgDW_97qK-3(tJV03 z$88Vh$_o*uo>_d)q(zXA(ee^RT8tOK#Fn_2=*dTPMDNk#$8D@3|EHH06revSt_sYG zf!0Mnfhgk1i=Tzq<8@klRT&Dw#G$1y@iyOJuLgUi!~8VLJC7` zr9A{iXIEG9kE#>^0G2g?>0?B1L;iY1l?{q=Kbw;A&q&e@rxX! zM~_IiP{Ci|_@ZluPz6*mp_f{>O#l7SHlrWq3dUaRrQ0ry-x^kFi^mC993WL+^U2CJ zH`1OSXEjqdR&DBY)b-ct*khx86_pN^{B=D%7n3~u;J%J48+gocsvke*In zpu9&CdHQiy!p47Opa`yu>IlC>Q&ci2fB*$v!s>7qtNcF@+~qQjQ`;+`{vwYl_;*qQ0;%W@BTK3$ZTqu7i`2g#)OIr&X`Ss<0lS+{s zGlUdAum#h0?dTj(v?+Hrm%_oRaTgp91n5V;appaJ7ABr1>76>d$xJM7R+Y;K2 zRHE5+#z?*OxYy=?J>Y+BY;?Cb_>10Vcbom)>pkLsZavs!e?8jTu7$O|)!pDP9z5WG zJ$k}xZ*PCPfANwJpE!RxB{!e+y0ut5@Q{4setzP#)Z2LI0Dt5V3uwbjZ$EbM+TgU= zeDcUG{K&=XF>mLI^KG-oTkUPg{z_6y8}o^zn0T-)|JmAj)D{mP$#+|uPvk%F;n5?9 z_!2kqXambiinJxa%PNoL2uO$kY`f>s1zsU>oY8-NEZcjyDO*NB+wxa$6Rh1Qk`H{! zZaTD*WEBtKpRHa`{__~Id?+;zfO`nYA%(n=5Dy=6B0hfj5ZZpEQ4^0hHwkm`06Pz8 z^m>msO@T)MWP9_m(>17%d@UYBH<1Xc{KE%5{0KD>F#x#X42M+ffQ9U={IUVvLh?O& zL`8p$$v_bz(nON7!<(gQKSxhvX)J>Pmf}l3%;F&XjLmx`)TzQRAlT#+I4T6l1(Aab z3{2Rg-Dg}3*^=6^3qedG*g{q=`M_RxWll6D71jA8l7}1*h;U*}tlN*LH*BPleYK-N zrmxuu4U2G~+6wRWpfUZY89DXiN9?guoUDJWDfeK*eur_w%oH^PEH%`>2iT?gcNpHU z7+@MOGr-dPnbeH$Q#3yQJ;L98g!P}{_-=dS%Z$rSuokzTJQ1&6{&yRenv;B#Lo!Nf z>Pd|%-=>VmH*w?9p#7$)f*=jC;T!o{Tu9_LtV*aS)tg16O3)@koaW@|;Gqkn*~owM zu+@3=N?GKBi$(gn(b@jh`ATz2e|*A$mb1z9T7Lq+#Wt^3j3jL@=6VW4-qHAQ?Z2uY zF6aAQjn-0xr=K{ziIPvnmb6%$VaKnElz7Z%JDBHKgy@MSo<#RHwTw}Hh6s|iHAzG% z9jJ9UODbQ$-_#zwAh_#Fgun`{gI9kL%YnJbDMtDhoJRw>aK4}*0$2oz2YLiUMB zj7FQ`=`HW$>-h9iJ>r&*di5|i7idI5mvND$R;(@8nG8S8P6;Jdfw0ZKTv`vhhsV?M z@Q}yD>wwVijqf6mwGYQv5>4@x5-e*+FaR*1+rT9H5S3GZbTz4{lRkh~FHV0>*AzmB z(~|#Lhu?Y|57$#8y7S`ynav4}F76L>1b|iFEGn*i`J?}c)4j7duf^%}lY`f1!Dpxi zF_e;1pg(F?rwyA4e;LclFZcdSygE2NJvctfU0yhXKa;1t@b?~UI>(Tjk zIII{hjesd|UXEU&y~gfGeQ|H<`>DPhkd;Fc&2k0NdQRxdR+{q8Xn{z zvh0VL=zZs-=O#eG03zEzg#g~;Kt$=Dp6|WgJ32ex`_D4H=V#I~py*MJAnQM3`#6TJ z?Ku*bqBeCW_Wnu-b0s7UHQAM&vJ|E1|xqJw1Grc3r<>GINTPv zn7A*Q3{96z+(2}ZRMM5WDl&d}940WXB7`z`N4cc5xG$}}>rr-dpEjdOcwum^l3=vi zjAu3#4szz_Lt5cl@KG_xZgas;>I!NcymKWd%rG#Mw}OP@kZk#;=mYhY@YAG&KRtp| zL6o4J*viO<3OawF1b&y@(R zO%o&UF(`klgYlU$E?p_`K9OP76lid=8=la+=X)F444^S#boDS+bpb$F$ks!Q`3Pwo zRI18>G2<(-Hkpm_E~Wx3`Z?06F0rLzf>X*?iN2|Lg33A|QY`QHHoy)$zCkorhJ?qO zcMeWfnyasYVh$O6B``%H_s+-~SpWC`6wcMNdNF^QP*l!2J=*|W~SG;YNO?c9LGJjEL#f}YU>J;yRLEp<2skzing4Jl><{3qvbI2 zt%6e6Ml>`ss4W@Yt4#kFZRX9(eZd?CK~uqISgg4iltg=P7qk~dZpGS*07*8u|EjjV zVE2D0)?NsM1Pi-cLpitPTgAxW_d7a1Q|@$fX*fA6fGdms@dd0h;dB##!E7^fDOZ)_ zcnd-;Zan9R6q{3Aa$D?AoiKhv3NS~-V-V2`LjCt{HqERi0%)qGt|`J5k(|P7E-;v- z_oeZ2Uj*&oC(!Qx6-*eWJip1;Ts%`gYX#ov?Cw2#^Fr*uIYN&v z_mTn}Jd@-VFmzfF)(f~L`6nHRZLVb zZE16KE^KvSP)h*<6aW+e000O8ae;kD98dhmNrnIbL6`yn6#xJL000000RSKX001Zb cmyeVOCztt@2O0vSgO?SR2QLP#kOu$&0I*#Fs{jB1