diff --git a/.gitignore b/.gitignore index 3496f3e86..135102f04 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ *.pydevproject .project .metadata -bin/ tmp/ *.tmp *.bak @@ -45,7 +44,6 @@ local.properties [Rr]elease/ x64/ build/ -[Bb]in/ [Oo]bj/ # MSTest test Results diff --git a/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch b/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch index d89fe4052..4d645a201 100644 --- a/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch +++ b/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch @@ -3,7 +3,7 @@ - + diff --git a/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch b/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch index 67d5396d7..c55f6dd26 100644 --- a/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch +++ b/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch @@ -3,7 +3,7 @@ - + diff --git a/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch b/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch index 7d31f4e74..121638ba4 100644 --- a/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch +++ b/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch @@ -3,7 +3,7 @@ - + diff --git a/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch b/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch index e8747fbee..d959c8bf5 100644 --- a/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch +++ b/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch @@ -4,6 +4,6 @@ - + diff --git a/Moose Mission Setup/Moose Mission Update/7-zip.chm b/Moose Mission Setup/Moose Mission Update/7-zip.chm deleted file mode 100644 index 68f152ccb..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7-zip.chm and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7-zip.dll b/Moose Mission Setup/Moose Mission Update/7-zip.dll deleted file mode 100644 index 6f0bd373f..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7-zip.dll and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7-zip32.dll b/Moose Mission Setup/Moose Mission Update/7-zip32.dll deleted file mode 100644 index 1ea1da918..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7-zip32.dll and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7z.dll b/Moose Mission Setup/Moose Mission Update/7z.dll deleted file mode 100644 index 450acaf6f..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7z.dll and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7z.exe b/Moose Mission Setup/Moose Mission Update/7z.exe deleted file mode 100644 index e444ddf5e..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7z.exe and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7z.sfx b/Moose Mission Setup/Moose Mission Update/7z.sfx deleted file mode 100644 index acf79e62e..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7z.sfx and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7zCon.sfx b/Moose Mission Setup/Moose Mission Update/7zCon.sfx deleted file mode 100644 index 531e1778a..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7zCon.sfx and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7zFM.exe b/Moose Mission Setup/Moose Mission Update/7zFM.exe deleted file mode 100644 index 89e81f9c0..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7zFM.exe and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/7zG.exe b/Moose Mission Setup/Moose Mission Update/7zG.exe deleted file mode 100644 index 4ceeb0f68..000000000 Binary files a/Moose Mission Setup/Moose Mission Update/7zG.exe and /dev/null differ diff --git a/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat b/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat index 1c542fd99..82b6c3406 100644 --- a/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat +++ b/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat @@ -17,7 +17,7 @@ For /R %1 %%M IN (*.miz) do ( copy ..\..\Moose.lua l10n\DEFAULT > NUL: copy "%%~pM%%~nM.lua" l10n\DEFAULT\*.* > NUL: rem dir l10n\DEFAULT - 7z -bb0 u "%%M" "l10n\DEFAULT\*.lua" > NUL: + "%~dp0..\..\Utils\7-Zip\7z" -bb0 u "%%M" "l10n\DEFAULT\*.lua" > NUL: cd .. rmdir /S /Q Temp ) \ No newline at end of file diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 132185bbf..d3784431a 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,74 +1,35878 @@ -env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170401_1103' ) +env.info( '*** MOOSE STATIC INCLUDE START *** ' ) +env.info( 'Moose Generation Timestamp: 20170402_1214' ) -local base = _G +--- Various routines +-- @module routines +-- @author Flightcontrol -__Moose = {} +env.setErrorMessageBoxEnabled(false) -__Moose.Include = function( IncludeFile ) - if not __Moose.Includes[ IncludeFile ] then - __Moose.Includes[IncludeFile] = IncludeFile - local f = assert( base.loadfile( __Moose.ProgramPath .. IncludeFile ) ) - if f == nil then - error ("Moose: Could not load Moose file " .. IncludeFile ) +--- Extract of MIST functions. +-- @author Grimes + +routines = {} + + +-- don't change these +routines.majorVersion = 3 +routines.minorVersion = 3 +routines.build = 22 + +----------------------------------------------------------------------------------------------------------------- + +---------------------------------------------------------------------------------------------- +-- Utils- conversion, Lua utils, etc. +routines.utils = {} + +--from http://lua-users.org/wiki/CopyTable +routines.utils.deepCopy = function(object) + local lookup_table = {} + local function _copy(object) + if type(object) ~= "table" then + return object + elseif lookup_table[object] then + return lookup_table[object] + end + local new_table = {} + lookup_table[object] = new_table + for index, value in pairs(object) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(object)) + end + local objectreturn = _copy(object) + return objectreturn +end + + +-- porting in Slmod's serialize_slmod2 +routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function + + lookup_table = {} + + local function _Serialize( tbl ) + + if type(tbl) == 'table' then --function only works for tables! + + if lookup_table[tbl] then + return lookup_table[object] + end + + local tbl_str = {} + + lookup_table[tbl] = tbl_str + + tbl_str[#tbl_str + 1] = '{' + + for ind,val in pairs(tbl) do -- serialize its fields + local ind_str = {} + if type(ind) == "number" then + ind_str[#ind_str + 1] = '[' + ind_str[#ind_str + 1] = tostring(ind) + ind_str[#ind_str + 1] = ']=' + else --must be a string + ind_str[#ind_str + 1] = '[' + ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) + ind_str[#ind_str + 1] = ']=' + end + + local val_str = {} + if ((type(val) == 'number') or (type(val) == 'boolean')) then + val_str[#val_str + 1] = tostring(val) + val_str[#val_str + 1] = ',' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'string' then + val_str[#val_str + 1] = routines.utils.basicSerialize(val) + val_str[#val_str + 1] = ',' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'nil' then -- won't ever happen, right? + val_str[#val_str + 1] = 'nil,' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'table' then + if ind == "__index" then + -- tbl_str[#tbl_str + 1] = "__index" + -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + else + + val_str[#val_str + 1] = _Serialize(val) + val_str[#val_str + 1] = ',' --I think this is right, I just added it + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + end + elseif type(val) == 'function' then + -- tbl_str[#tbl_str + 1] = "function " .. tostring(ind) + -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + else +-- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) +-- env.info( debug.traceback() ) + end + + end + tbl_str[#tbl_str + 1] = '}' + return table.concat(tbl_str) else - env.info( "Moose: " .. IncludeFile .. " dynamically loaded from " .. __Moose.ProgramPath ) - return f() + return tostring(tbl) + end + end + + local objectreturn = _Serialize(tbl) + return objectreturn +end + +--porting in Slmod's "safestring" basic serialize +routines.utils.basicSerialize = function(s) + if s == nil then + return "\"\"" + else + if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then + return tostring(s) + elseif type(s) == 'string' then + s = string.format('%q', s) + return s end end end -__Moose.ProgramPath = "Scripts/Moose/" -__Moose.Includes = {} -__Moose.Include( 'Utilities/Routines.lua' ) -__Moose.Include( 'Utilities/Utils.lua' ) -__Moose.Include( 'Core/Base.lua' ) -__Moose.Include( 'Core/Scheduler.lua' ) -__Moose.Include( 'Core/ScheduleDispatcher.lua' ) -__Moose.Include( 'Core/Event.lua' ) -__Moose.Include( 'Core/Menu.lua' ) -__Moose.Include( 'Core/Zone.lua' ) -__Moose.Include( 'Core/Database.lua' ) -__Moose.Include( 'Core/Set.lua' ) -__Moose.Include( 'Core/Point.lua' ) -__Moose.Include( 'Core/Message.lua' ) -__Moose.Include( 'Core/Fsm.lua' ) -__Moose.Include( 'Core/Radio.lua' ) -__Moose.Include( 'Wrapper/Object.lua' ) -__Moose.Include( 'Wrapper/Identifiable.lua' ) -__Moose.Include( 'Wrapper/Positionable.lua' ) -__Moose.Include( 'Wrapper/Controllable.lua' ) -__Moose.Include( 'Wrapper/Group.lua' ) -__Moose.Include( 'Wrapper/Unit.lua' ) -__Moose.Include( 'Wrapper/Client.lua' ) -__Moose.Include( 'Wrapper/Static.lua' ) -__Moose.Include( 'Wrapper/Airbase.lua' ) -__Moose.Include( 'Wrapper/Scenery.lua' ) -__Moose.Include( 'Functional/Scoring.lua' ) -__Moose.Include( 'Functional/CleanUp.lua' ) -__Moose.Include( 'Functional/Spawn.lua' ) -__Moose.Include( 'Functional/Movement.lua' ) -__Moose.Include( 'Functional/Sead.lua' ) -__Moose.Include( 'Functional/Escort.lua' ) -__Moose.Include( 'Functional/MissileTrainer.lua' ) -__Moose.Include( 'Functional/AirbasePolice.lua' ) -__Moose.Include( 'Functional/Detection.lua' ) -__Moose.Include( 'AI/AI_Balancer.lua' ) -__Moose.Include( 'AI/AI_Patrol.lua' ) -__Moose.Include( 'AI/AI_Cap.lua' ) -__Moose.Include( 'AI/AI_Cas.lua' ) -__Moose.Include( 'AI/AI_Cargo.lua' ) -__Moose.Include( 'Actions/Act_Assign.lua' ) -__Moose.Include( 'Actions/Act_Route.lua' ) -__Moose.Include( 'Actions/Act_Account.lua' ) -__Moose.Include( 'Actions/Act_Assist.lua' ) -__Moose.Include( 'Tasking/CommandCenter.lua' ) -__Moose.Include( 'Tasking/Mission.lua' ) -__Moose.Include( 'Tasking/Task.lua' ) -__Moose.Include( 'Tasking/DetectionManager.lua' ) -__Moose.Include( 'Tasking/Task_A2G_Dispatcher.lua' ) -__Moose.Include( 'Tasking/Task_A2G.lua' ) -__Moose.Include( 'Moose.lua' ) -BASE:TraceOnOff( true ) +routines.utils.toDegree = function(angle) + return angle*180/math.pi +end + +routines.utils.toRadian = function(angle) + return angle*math.pi/180 +end + +routines.utils.metersToNM = function(meters) + return meters/1852 +end + +routines.utils.metersToFeet = function(meters) + return meters/0.3048 +end + +routines.utils.NMToMeters = function(NM) + return NM*1852 +end + +routines.utils.feetToMeters = function(feet) + return feet*0.3048 +end + +routines.utils.mpsToKnots = function(mps) + return mps*3600/1852 +end + +routines.utils.mpsToKmph = function(mps) + return mps*3.6 +end + +routines.utils.knotsToMps = function(knots) + return knots*1852/3600 +end + +routines.utils.kmphToMps = function(kmph) + return kmph/3.6 +end + +function routines.utils.makeVec2(Vec3) + if Vec3.z then + return {x = Vec3.x, y = Vec3.z} + else + return {x = Vec3.x, y = Vec3.y} -- it was actually already vec2. + end +end + +function routines.utils.makeVec3(Vec2, y) + if not Vec2.z then + if not y then + y = 0 + end + return {x = Vec2.x, y = y, z = Vec2.y} + else + return {x = Vec2.x, y = Vec2.y, z = Vec2.z} -- it was already Vec3, actually. + end +end + +function routines.utils.makeVec3GL(Vec2, offset) + local adj = offset or 0 + + if not Vec2.z then + return {x = Vec2.x, y = (land.getHeight(Vec2) + adj), z = Vec2.y} + else + return {x = Vec2.x, y = (land.getHeight({x = Vec2.x, y = Vec2.z}) + adj), z = Vec2.z} + end +end + +routines.utils.zoneToVec3 = function(zone) + local new = {} + if type(zone) == 'table' and zone.point then + new.x = zone.point.x + new.y = zone.point.y + new.z = zone.point.z + return new + elseif type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + if zone then + new.x = zone.point.x + new.y = zone.point.y + new.z = zone.point.z + return new + end + end +end + +-- gets heading-error corrected direction from point along vector vec. +function routines.utils.getDir(vec, point) + local dir = math.atan2(vec.z, vec.x) + dir = dir + routines.getNorthCorrection(point) + if dir < 0 then + dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi + end + return dir +end + +-- gets distance in meters between two points (2 dimensional) +function routines.utils.get2DDist(point1, point2) + point1 = routines.utils.makeVec3(point1) + point2 = routines.utils.makeVec3(point2) + return routines.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) +end + +-- gets distance in meters between two points (3 dimensional) +function routines.utils.get3DDist(point1, point2) + return routines.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) +end + + + + + +--3D Vector manipulation +routines.vec = {} + +routines.vec.add = function(vec1, vec2) + return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} +end + +routines.vec.sub = function(vec1, vec2) + return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} +end + +routines.vec.scalarMult = function(vec, mult) + return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} +end + +routines.vec.scalar_mult = routines.vec.scalarMult + +routines.vec.dp = function(vec1, vec2) + return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z +end + +routines.vec.cp = function(vec1, vec2) + return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} +end + +routines.vec.mag = function(vec) + return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 +end + +routines.vec.getUnitVec = function(vec) + local mag = routines.vec.mag(vec) + return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } +end + +routines.vec.rotateVec2 = function(vec2, theta) + return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} +end +--------------------------------------------------------------------------------------------------------------------------- + + + + +-- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. +routines.tostringMGRS = function(MGRS, acc) + if acc == 0 then + return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph + else + return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Easting/(10^(5-acc)), 0)) + .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Northing/(10^(5-acc)), 0)) + end +end + +--[[acc: +in DM: decimal point of minutes. +In DMS: decimal point of seconds. +position after the decimal of the least significant digit: +So: +42.32 - acc of 2. +]] +routines.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 = routines.utils.round((oldLatMin - latMin)*60, acc) + + local oldLonMin = lonMin + lonMin = math.floor(lonMin) + local lonSec = routines.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 = routines.utils.round(latMin, acc) + lonMin = routines.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.]] +routines.tostringBR = function(az, dist, alt, metric) + az = routines.utils.round(routines.utils.toDegree(az), 0) + + if metric then + dist = routines.utils.round(dist/1000, 2) + else + dist = routines.utils.round(routines.utils.metersToNM(dist), 2) + end + + local s = string.format('%03d', az) .. ' for ' .. dist + + if alt then + if metric then + s = s .. ' at ' .. routines.utils.round(alt, 0) + else + s = s .. ' at ' .. routines.utils.round(routines.utils.metersToFeet(alt), 0) + end + end + return s +end + +routines.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) +end + + +do + local idNum = 0 + + --Simplified event handler + routines.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) + end + + routines.removeEventHandler = function(id) + for key, handler in pairs(world.eventHandlers) do + if handler.id and handler.id == id then + world.eventHandlers[key] = nil + return true + end + end + return false + end +end + +-- need to return a Vec3 or Vec2? +function routines.getRandPointInCircle(point, radius, innerRadius) + local theta = 2*math.pi*math.random() + local rad = math.random() + math.random() + if rad > 1 then + rad = 2 - rad + end + + local radMult + if innerRadius and innerRadius <= radius then + radMult = (radius - innerRadius)*rad + innerRadius + else + radMult = radius*rad + end + + if not point.z then --might as well work with vec2/3 + point.z = point.y + end + + local rndCoord + if radius > 0 then + rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} + else + rndCoord = {x = point.x, y = point.z} + end + return rndCoord +end + +routines.goRoute = function(group, path) + local misTask = { + id = 'Mission', + params = { + route = { + points = routines.utils.deepCopy(path), + }, + }, + } + if type(group) == 'string' then + group = Group.getByName(group) + end + local groupCon = group:getController() + if groupCon then + groupCon:setTask(misTask) + return true + end + + Controller.setTask(groupCon, misTask) + return false +end + + +-- Useful atomic functions from mist, ported. + +routines.ground = {} +routines.fixedWing = {} +routines.heli = {} + +routines.ground.buildWP = function(point, overRideForm, overRideSpeed) + + local wp = {} + wp.x = point.x + + if point.z then + wp.y = point.z + else + wp.y = point.y + end + local form, speed + + if point.speed and not overRideSpeed then + wp.speed = point.speed + elseif type(overRideSpeed) == 'number' then + wp.speed = overRideSpeed + else + wp.speed = routines.utils.kmphToMps(20) + end + + if point.form and not overRideForm then + form = point.form + else + form = overRideForm + end + + if not form then + wp.action = 'Cone' + else + form = string.lower(form) + if form == 'off_road' or form == 'off road' then + wp.action = 'Off Road' + elseif form == 'on_road' or form == 'on road' then + wp.action = 'On Road' + elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then + wp.action = 'Rank' + elseif form == 'cone' then + wp.action = 'Cone' + elseif form == 'diamond' then + wp.action = 'Diamond' + elseif form == 'vee' then + wp.action = 'Vee' + elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then + wp.action = 'EchelonL' + elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then + wp.action = 'EchelonR' + else + wp.action = 'Cone' -- if nothing matched + end + end + + wp.type = 'Turning Point' + + return wp + +end + +routines.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 'agl' then + wp.alt_type = 'RADIO' + elseif altType == 'baro' or 'asl' then + wp.alt_type = 'BARO' + end + else + wp.alt_type = 'RADIO' + end + + if point.speed then + speed = point.speed + end + + if point.type then + WPtype = point.type + end + + if not speed then + wp.speed = routines.utils.kmphToMps(500) + else + wp.speed = speed + end + + if not WPtype then + wp.action = 'Turning Point' + else + WPtype = string.lower(WPtype) + if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then + wp.action = 'Fly Over Point' + elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then + wp.action = 'Turning Point' + else + wp.action = 'Turning Point' + end + end + + wp.type = 'Turning Point' + return wp +end + +routines.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 'agl' then + wp.alt_type = 'RADIO' + elseif altType == 'baro' or 'asl' then + wp.alt_type = 'BARO' + end + else + wp.alt_type = 'RADIO' + end + + if point.speed then + speed = point.speed + end + + if point.type then + WPtype = point.type + end + + if not speed then + wp.speed = routines.utils.kmphToMps(200) + else + wp.speed = speed + end + + if not WPtype then + wp.action = 'Turning Point' + else + WPtype = string.lower(WPtype) + if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then + wp.action = 'Fly Over Point' + elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then + wp.action = 'Turning Point' + else + wp.action = 'Turning Point' + end + end + + wp.type = 'Turning Point' + return wp +end + +routines.groupToRandomPoint = function(vars) + local group = vars.group --Required + local point = vars.point --required + local radius = vars.radius or 0 + local innerRadius = vars.innerRadius + local form = vars.form or 'Cone' + local heading = vars.heading or math.random()*2*math.pi + local headingDegrees = vars.headingDegrees + local speed = vars.speed or routines.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 = routines.getRandPointInCircle(point, radius, innerRadius) + + local offset = {} + local posStart = routines.getLeadPos(group) + + offset.x = routines.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) + offset.z = routines.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) + path[#path + 1] = routines.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] = routines.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed) + path[#path + 1] = routines.ground.buildWP(posStart, 'on_road', speed) + path[#path + 1] = routines.ground.buildWP(offset, 'on_road', speed) + else + path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed) + end + + path[#path + 1] = routines.ground.buildWP(offset, form, speed) + path[#path + 1] = routines.ground.buildWP(rndCoord, form, speed) + + routines.goRoute(group, path) + + return +end + +routines.groupRandomDistSelf = function(gpData, dist, form, heading, speed) + local pos = routines.getLeadPos(gpData) + local fakeZone = {} + fakeZone.radius = dist or math.random(300, 1000) + fakeZone.point = {x = pos.x, y, pos.y, z = pos.z} + routines.groupToRandomZone(gpData, fakeZone, form, heading, speed) + + return +end + +routines.groupToRandomZone = function(gpData, zone, form, heading, speed) + if type(gpData) == 'string' then + gpData = Group.getByName(gpData) + end + + if type(zone) == 'string' then + zone = trigger.misc.getZone(zone) + elseif type(zone) == 'table' and not zone.radius then + zone = trigger.misc.getZone(zone[math.random(1, #zone)]) + end + + if speed then + speed = routines.utils.kmphToMps(speed) + end + + local vars = {} + vars.group = gpData + vars.radius = zone.radius + vars.form = form + vars.headingDegrees = heading + vars.speed = speed + vars.point = routines.utils.zoneToVec3(zone) + + routines.groupToRandomPoint(vars) + + return +end + +routines.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types + if coord.z then + coord.y = coord.z + end + local typeConverted = {} + + if type(terrainTypes) == 'string' then -- if its a string it does this check + for constId, constData in pairs(land.SurfaceType) do + if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then + table.insert(typeConverted, constId) + end + end + elseif type(terrainTypes) == 'table' then -- if its a table it does this check + for typeId, typeData in pairs(terrainTypes) do + for constId, constData in pairs(land.SurfaceType) do + if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then + table.insert(typeConverted, constId) + end + end + end + end + for validIndex, validData in pairs(typeConverted) do + if land.getSurfaceType(coord) == land.SurfaceType[validData] then + return true + end + end + return false +end + +routines.groupToPoint = function(gpData, point, form, heading, speed, useRoads) + if type(point) == 'string' then + point = trigger.misc.getZone(point) + end + if speed then + speed = routines.utils.kmphToMps(speed) + end + + local vars = {} + vars.group = gpData + vars.form = form + vars.headingDegrees = heading + vars.speed = speed + vars.disableRoads = useRoads + vars.point = routines.utils.zoneToVec3(point) + routines.groupToRandomPoint(vars) + + return +end + + +routines.getLeadPos = function(group) + if type(group) == 'string' then -- group name + group = Group.getByName(group) + end + + local units = group:getUnits() + + local leader = units[1] + if not 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 ind < lowestInd then + lowestInd = ind + leader = unit + end + end + end + if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... + return leader:getPosition().p + end +end + +--[[ vars for routines.getMGRSString: +vars.units - table of unit names (NOT unitNameTable- maybe this should change). +vars.acc - integer between 0 and 5, inclusive +]] +routines.getMGRSString = function(vars) + local units = vars.units + local acc = vars.acc or 5 + local avgPos = routines.getAvgPos(units) + if avgPos then + return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) + end +end + +--[[ vars for routines.getLLString +vars.units - table of unit names (NOT unitNameTable- maybe this should change). +vars.acc - integer, number of numbers after decimal place +vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. + + +]] +routines.getLLString = function(vars) + local units = vars.units + local acc = vars.acc or 3 + local DMS = vars.DMS + local avgPos = routines.getAvgPos(units) + if avgPos then + local lat, lon = coord.LOtoLL(avgPos) + return routines.tostringLL(lat, lon, acc, DMS) + end +end + +--[[ +vars.zone - table of a zone name. +vars.ref - vec3 ref point, maybe overload for vec2 as well? +vars.alt - boolean, if used, includes altitude in string +vars.metric - boolean, gives distance in km instead of NM. +]] +routines.getBRStringZone = function(vars) + local zone = trigger.misc.getZone( vars.zone ) + local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. + local alt = vars.alt + local metric = vars.metric + if zone then + local vec = {x = zone.point.x - ref.x, y = zone.point.y - ref.y, z = zone.point.z - ref.z} + local dir = routines.utils.getDir(vec, ref) + local dist = routines.utils.get2DDist(zone.point, ref) + if alt then + alt = zone.y + end + return routines.tostringBR(dir, dist, alt, metric) + else + env.info( 'routines.getBRStringZone: error: zone is nil' ) + end +end + +--[[ +vars.units- table of unit names (NOT unitNameTable- maybe this should change). +vars.ref - vec3 ref point, maybe overload for vec2 as well? +vars.alt - boolean, if used, includes altitude in string +vars.metric - boolean, gives distance in km instead of NM. +]] +routines.getBRString = function(vars) + local units = vars.units + local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. + local alt = vars.alt + local metric = vars.metric + local avgPos = routines.getAvgPos(units) + if avgPos then + local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} + local dir = routines.utils.getDir(vec, ref) + local dist = routines.utils.get2DDist(avgPos, ref) + if alt then + alt = avgPos.y + end + return routines.tostringBR(dir, dist, alt, metric) + end +end + + +-- Returns the Vec3 coordinates of the average position of the concentration of units most in the heading direction. +--[[ vars for routines.getLeadingPos: +vars.units - table of unit names +vars.heading - direction +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees +]] +routines.getLeadingPos = function(vars) + local units = vars.units + local heading = vars.heading + local radius = vars.radius + if vars.headingDegrees then + heading = routines.utils.toRadian(vars.headingDegrees) + end + + local unitPosTbl = {} + for i = 1, #units do + local unit = Unit.getByName(units[i]) + if unit and unit:isExist() then + unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p + end + end + if #unitPosTbl > 0 then -- one more more units found. + -- first, find the unit most in the heading direction + local maxPos = -math.huge + + local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = + for i = 1, #unitPosTbl do + local rotatedVec2 = routines.vec.rotateVec2(routines.utils.makeVec2(unitPosTbl[i]), heading) + if (not maxPos) or maxPos < rotatedVec2.x then + maxPos = rotatedVec2.x + maxPosInd = i + end + end + + --now, get all the units around this unit... + local avgPos + if radius then + local maxUnitPos = unitPosTbl[maxPosInd] + local avgx, avgy, avgz, totNum = 0, 0, 0, 0 + for i = 1, #unitPosTbl do + if routines.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 + + +--[[ vars for routines.getLeadingMGRSString: +vars.units - table of unit names +vars.heading - direction +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees +vars.acc - number, 0 to 5. +]] +routines.getLeadingMGRSString = function(vars) + local pos = routines.getLeadingPos(vars) + if pos then + local acc = vars.acc or 5 + return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) + end +end + +--[[ vars for routines.getLeadingLLString: +vars.units - table of unit names +vars.heading - direction, number +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees +vars.acc - number of digits after decimal point (can be negative) +vars.DMS - boolean, true if you want DMS. +]] +routines.getLeadingLLString = function(vars) + local pos = routines.getLeadingPos(vars) + if pos then + local acc = vars.acc or 3 + local DMS = vars.DMS + local lat, lon = coord.LOtoLL(pos) + return routines.tostringLL(lat, lon, acc, DMS) + end +end + + + +--[[ vars for routines.getLeadingBRString: +vars.units - table of unit names +vars.heading - direction, number +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees +vars.metric - boolean, if true, use km instead of NM. +vars.alt - boolean, if true, include altitude. +vars.ref - vec3/vec2 reference point. +]] +routines.getLeadingBRString = function(vars) + local pos = routines.getLeadingPos(vars) + if pos then + local ref = vars.ref + local alt = vars.alt + local metric = vars.metric + + local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} + local dir = routines.utils.getDir(vec, ref) + local dist = routines.utils.get2DDist(pos, ref) + if alt then + alt = pos.y + end + return routines.tostringBR(dir, dist, alt, metric) + end +end + +--[[ vars for routines.message.add + vars.text = 'Hello World' + vars.displayTime = 20 + vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} + +]] + +--[[ vars for routines.msgMGRS +vars.units - table of unit names (NOT unitNameTable- maybe this should change). +vars.acc - integer between 0 and 5, inclusive +vars.text - text in the message +vars.displayTime - self explanatory +vars.msgFor - scope +]] +routines.msgMGRS = function(vars) + local units = vars.units + local acc = vars.acc + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getMGRSString{units = units, acc = acc} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } +end + +--[[ vars for routines.msgLL +vars.units - table of unit names (NOT unitNameTable- maybe this should change) (Yes). +vars.acc - integer, number of numbers after decimal place +vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. +vars.text - text in the message +vars.displayTime - self explanatory +vars.msgFor - scope +]] +routines.msgLL = function(vars) + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local acc = vars.acc + local DMS = vars.DMS + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getLLString{units = units, acc = acc, DMS = DMS} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } + +end + + +--[[ +vars.units- table of unit names (NOT unitNameTable- maybe this should change). +vars.ref - vec3 ref point, maybe overload for vec2 as well? +vars.alt - boolean, if used, includes altitude in string +vars.metric - boolean, gives distance in km instead of NM. +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] +routines.msgBR = function(vars) + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString + local alt = vars.alt + local metric = vars.metric + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getBRString{units = units, ref = ref, alt = alt, metric = metric} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } + +end + + +-------------------------------------------------------------------------------------------- +-- basically, just sub-types of routines.msgBR... saves folks the work of getting the ref point. +--[[ +vars.units- table of unit names (NOT unitNameTable- maybe this should change). +vars.ref - string red, blue +vars.alt - boolean, if used, includes altitude in string +vars.metric - boolean, gives distance in km instead of NM. +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] +routines.msgBullseye = function(vars) + if string.lower(vars.ref) == 'red' then + vars.ref = routines.DBs.missionData.bullseye.red + routines.msgBR(vars) + elseif string.lower(vars.ref) == 'blue' then + vars.ref = routines.DBs.missionData.bullseye.blue + routines.msgBR(vars) + end +end + +--[[ +vars.units- table of unit names (NOT unitNameTable- maybe this should change). +vars.ref - unit name of reference point +vars.alt - boolean, if used, includes altitude in string +vars.metric - boolean, gives distance in km instead of NM. +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] + +routines.msgBRA = function(vars) + if Unit.getByName(vars.ref) then + vars.ref = Unit.getByName(vars.ref):getPosition().p + if not vars.alt then + vars.alt = true + end + routines.msgBR(vars) + end +end +-------------------------------------------------------------------------------------------- + +--[[ vars for routines.msgLeadingMGRS: +vars.units - table of unit names +vars.heading - direction +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees (optional) +vars.acc - number, 0 to 5. +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] +routines.msgLeadingMGRS = function(vars) + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local acc = vars.acc + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } + + +end +--[[ vars for routines.msgLeadingLL: +vars.units - table of unit names +vars.heading - direction, number +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees (optional) +vars.acc - number of digits after decimal point (can be negative) +vars.DMS - boolean, true if you want DMS. (optional) +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] +routines.msgLeadingLL = function(vars) + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local acc = vars.acc + local DMS = vars.DMS + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } + +end + +--[[ +vars.units - table of unit names +vars.heading - direction, number +vars.radius - number +vars.headingDegrees - boolean, switches heading to degrees (optional) +vars.metric - boolean, if true, use km instead of NM. (optional) +vars.alt - boolean, if true, include altitude. (optional) +vars.ref - vec3/vec2 reference point. +vars.text - text of the message +vars.displayTime +vars.msgFor - scope +]] +routines.msgLeadingBR = function(vars) + local units = vars.units -- technically, I don't really need to do this, but it helps readability. + local heading = vars.heading + local radius = vars.radius + local headingDegrees = vars.headingDegrees + local metric = vars.metric + local alt = vars.alt + local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString + local text = vars.text + local displayTime = vars.displayTime + local msgFor = vars.msgFor + + local s = routines.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} + local newText + if string.find(text, '%%s') then -- look for %s + newText = string.format(text, s) -- insert the coordinates into the message + else -- else, just append to the end. + newText = text .. s + end + + routines.message.add{ + text = newText, + displayTime = displayTime, + msgFor = msgFor + } +end + + +function spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + + +function routines.IsPartOfGroupInZones( CargoGroup, LandingZones ) +--trace.f() + + local CurrentZoneID = nil + + if CargoGroup then + local CargoUnits = CargoGroup:getUnits() + for CargoUnitID, CargoUnit in pairs( CargoUnits ) do + if CargoUnit and CargoUnit:getLife() >= 1.0 then + CurrentZoneID = routines.IsUnitInZones( CargoUnit, LandingZones ) + if CurrentZoneID then + break + end + end + end + end + +--trace.r( "", "", { CurrentZoneID } ) + return CurrentZoneID +end + + + +function routines.IsUnitInZones( TransportUnit, LandingZones ) +--trace.f("", "routines.IsUnitInZones" ) + + local TransportZoneResult = nil + local TransportZonePos = nil + local TransportZone = nil + + -- fill-up some local variables to support further calculations to determine location of units within the zone. + if TransportUnit then + local TransportUnitPos = TransportUnit:getPosition().p + if type( LandingZones ) == "table" then + for LandingZoneID, LandingZoneName in pairs( LandingZones ) do + TransportZone = trigger.misc.getZone( LandingZoneName ) + if TransportZone then + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then + TransportZoneResult = LandingZoneID + break + end + end + end + else + TransportZone = trigger.misc.getZone( LandingZones ) + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then + TransportZoneResult = 1 + end + end + if TransportZoneResult then + --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) + else + --trace.i( "routines", "TransportZone:nil logic" ) + end + return TransportZoneResult + else + --trace.i( "routines", "TransportZone:nil hard" ) + return nil + end +end + +function routines.IsUnitNearZonesRadius( TransportUnit, LandingZones, ZoneRadius ) +--trace.f("", "routines.IsUnitInZones" ) + + local TransportZoneResult = nil + local TransportZonePos = nil + local TransportZone = nil + + -- fill-up some local variables to support further calculations to determine location of units within the zone. + if TransportUnit then + local TransportUnitPos = TransportUnit:getPosition().p + if type( LandingZones ) == "table" then + for LandingZoneID, LandingZoneName in pairs( LandingZones ) do + TransportZone = trigger.misc.getZone( LandingZoneName ) + if TransportZone then + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then + TransportZoneResult = LandingZoneID + break + end + end + end + else + TransportZone = trigger.misc.getZone( LandingZones ) + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then + TransportZoneResult = 1 + end + end + if TransportZoneResult then + --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) + else + --trace.i( "routines", "TransportZone:nil logic" ) + end + return TransportZoneResult + else + --trace.i( "routines", "TransportZone:nil hard" ) + return nil + end +end + + +function routines.IsStaticInZones( TransportStatic, LandingZones ) +--trace.f() + + local TransportZoneResult = nil + local TransportZonePos = nil + local TransportZone = nil + + -- fill-up some local variables to support further calculations to determine location of units within the zone. + local TransportStaticPos = TransportStatic:getPosition().p + if type( LandingZones ) == "table" then + for LandingZoneID, LandingZoneName in pairs( LandingZones ) do + TransportZone = trigger.misc.getZone( LandingZoneName ) + if TransportZone then + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then + TransportZoneResult = LandingZoneID + break + end + end + end + else + TransportZone = trigger.misc.getZone( LandingZones ) + TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} + if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then + TransportZoneResult = 1 + end + end + +--trace.r( "", "", { TransportZoneResult } ) + return TransportZoneResult +end + + +function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius ) +--trace.f() + + local Valid = true + + -- fill-up some local variables to support further calculations to determine location of units within the zone. + local CargoPos = CargoUnit:getPosition().p + local ReferenceP = ReferencePosition.p + + if (((CargoPos.x - ReferenceP.x)^2 + (CargoPos.z - ReferenceP.z)^2)^0.5 <= Radius) then + else + Valid = false + end + + return Valid +end + +function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius ) +--trace.f() + + local Valid = true + + Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid ) + + -- fill-up some local variables to support further calculations to determine location of units within the zone + local CargoUnits = CargoGroup:getUnits() + for CargoUnitId, CargoUnit in pairs( CargoUnits ) do + local CargoUnitPos = CargoUnit:getPosition().p +-- env.info( 'routines.IsPartOfGroupInRadius: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z ) + local ReferenceP = ReferencePosition.p +-- env.info( 'routines.IsPartOfGroupInRadius: ReferenceGroupPos.x = ' .. ReferenceGroupPos.x .. ' ReferenceGroupPos.z = ' .. ReferenceGroupPos.z ) + + if ((( CargoUnitPos.x - ReferenceP.x)^2 + (CargoUnitPos.z - ReferenceP.z)^2)^0.5 <= Radius) then + else + Valid = false + break + end + end + + return Valid +end + + +function routines.ValidateString( Variable, VariableName, Valid ) +--trace.f() + + if type( Variable ) == "string" then + if Variable == "" then + error( "routines.ValidateString: error: " .. VariableName .. " must be filled out!" ) + Valid = false + end + else + error( "routines.ValidateString: error: " .. VariableName .. " is not a string." ) + Valid = false + end + +--trace.r( "", "", { Valid } ) + return Valid +end + +function routines.ValidateNumber( Variable, VariableName, Valid ) +--trace.f() + + if type( Variable ) == "number" then + else + error( "routines.ValidateNumber: error: " .. VariableName .. " is not a number." ) + Valid = false + end + +--trace.r( "", "", { Valid } ) + return Valid + +end + +function routines.ValidateGroup( Variable, VariableName, Valid ) +--trace.f() + + if Variable == nil then + error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) + Valid = false + end + +--trace.r( "", "", { Valid } ) + return Valid +end + +function routines.ValidateZone( LandingZones, VariableName, Valid ) +--trace.f() + + if LandingZones == nil then + error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) + Valid = false + end + + if type( LandingZones ) == "table" then + for LandingZoneID, LandingZoneName in pairs( LandingZones ) do + if trigger.misc.getZone( LandingZoneName ) == nil then + error( "routines.ValidateGroup: error: Zone " .. LandingZoneName .. " does not exist!" ) + Valid = false + break + end + end + else + if trigger.misc.getZone( LandingZones ) == nil then + error( "routines.ValidateGroup: error: Zone " .. LandingZones .. " does not exist!" ) + Valid = false + end + end + +--trace.r( "", "", { Valid } ) + return Valid +end + +function routines.ValidateEnumeration( Variable, VariableName, Enum, Valid ) +--trace.f() + + local ValidVariable = false + + for EnumId, EnumData in pairs( Enum ) do + if Variable == EnumData then + ValidVariable = true + break + end + end + + if ValidVariable then + else + error( 'TransportValidateEnum: " .. VariableName .. " is not a valid type.' .. Variable ) + Valid = false + end + +--trace.r( "", "", { Valid } ) + return Valid +end + +function routines.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 = _DATABASE.Templates.Groups[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 + +routines.ground.patrolRoute = function(vars) + + + local tempRoute = {} + local useRoute = {} + local gpData = vars.gpData + if type(gpData) == 'string' then + gpData = Group.getByName(gpData) + end + + local useGroupRoute + if not vars.useGroupRoute then + useGroupRoute = vars.gpData + else + useGroupRoute = vars.useGroupRoute + end + local routeProvided = false + if not vars.route then + if useGroupRoute then + tempRoute = routines.getGroupRoute(useGroupRoute) + end + else + useRoute = vars.route + local posStart = routines.getLeadPos(gpData) + useRoute[1] = routines.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) + routeProvided = true + end + + + local overRideSpeed = vars.speed or 'default' + local pType = vars.pType + local offRoadForm = vars.offRoadForm or 'default' + local onRoadForm = vars.onRoadForm or 'default' + + if routeProvided == false and #tempRoute > 0 then + local posStart = routines.getLeadPos(gpData) + + + useRoute[#useRoute + 1] = routines.ground.buildWP(posStart, offRoadForm, overRideSpeed) + for i = 1, #tempRoute do + local tempForm = tempRoute[i].action + local tempSpeed = tempRoute[i].speed + + if offRoadForm == 'default' then + tempForm = tempRoute[i].action + end + if onRoadForm == 'default' then + onRoadForm = 'On Road' + end + if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then + tempForm = onRoadForm + else + tempForm = offRoadForm + end + + if type(overRideSpeed) == 'number' then + tempSpeed = overRideSpeed + end + + + useRoute[#useRoute + 1] = routines.ground.buildWP(tempRoute[i], tempForm, tempSpeed) + end + + if pType and string.lower(pType) == 'doubleback' then + local curRoute = routines.utils.deepCopy(useRoute) + for i = #curRoute, 2, -1 do + useRoute[#useRoute + 1] = routines.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) + end + end + + useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP + end + + local cTask3 = {} + local newPatrol = {} + newPatrol.route = useRoute + newPatrol.gpData = gpData:getName() + cTask3[#cTask3 + 1] = 'routines.ground.patrolRoute(' + cTask3[#cTask3 + 1] = routines.utils.oneLineSerialize(newPatrol) + cTask3[#cTask3 + 1] = ')' + cTask3 = table.concat(cTask3) + local tempTask = { + id = 'WrappedAction', + params = { + action = { + id = 'Script', + params = { + command = cTask3, + + }, + }, + }, + } + + + useRoute[#useRoute].task = tempTask + routines.goRoute(gpData, useRoute) + + return +end + +routines.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 + + routines.ground.patrolRoute(vars) + + return +end + +function routines.GetUnitHeight( CheckUnit ) +--trace.f( "routines" ) + + local UnitPoint = CheckUnit:getPoint() + local UnitPosition = { x = UnitPoint.x, y = UnitPoint.z } + local UnitHeight = UnitPoint.y + + local LandHeight = land.getHeight( UnitPosition ) + + --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) + + --trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight ) + + return UnitHeight - LandHeight + +end + + + +Su34Status = { status = {} } +boardMsgRed = { statusMsg = "" } +boardMsgAll = { timeMsg = "" } +SpawnSettings = {} +Su34MenuPath = {} +Su34Menus = 0 + + +function Su34AttackCarlVinson(groupName) +--trace.menu("", "Su34AttackCarlVinson") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34.getController(groupSu34) + local groupCarlVinson = Group.getByName("US Carl Vinson #001") + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + if groupCarlVinson ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupCarlVinson:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) + end + Su34Status.status[groupName] = 1 + MessageToRed( string.format('%s: ',groupName) .. 'Attacking carrier Carl Vinson. ', 10, 'RedStatus' .. groupName ) +end + +function Su34AttackWest(groupName) +--trace.f("","Su34AttackWest") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34.getController(groupSu34) + local groupShipWest1 = Group.getByName("US Ship West #001") + local groupShipWest2 = Group.getByName("US Ship West #002") + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + if groupShipWest1 ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) + end + if groupShipWest2 ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) + end + Su34Status.status[groupName] = 2 + MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the west. ', 10, 'RedStatus' .. groupName ) +end + +function Su34AttackNorth(groupName) +--trace.menu("","Su34AttackNorth") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34.getController(groupSu34) + local groupShipNorth1 = Group.getByName("US Ship North #001") + local groupShipNorth2 = Group.getByName("US Ship North #002") + local groupShipNorth3 = Group.getByName("US Ship North #003") + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + if groupShipNorth1 ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) + end + if groupShipNorth2 ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) + end + if groupShipNorth3 ~= nil then + controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth3:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) + end + Su34Status.status[groupName] = 3 + MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the north. ', 10, 'RedStatus' .. groupName ) +end + +function Su34Orbit(groupName) +--trace.menu("","Su34Orbit") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34:getController() + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + controllerSu34:pushTask( {id = 'ControlledTask', params = { task = { id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } } ) + Su34Status.status[groupName] = 4 + MessageToRed( string.format('%s: ',groupName) .. 'In orbit and awaiting further instructions. ', 10, 'RedStatus' .. groupName ) +end + +function Su34TakeOff(groupName) +--trace.menu("","Su34TakeOff") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34:getController() + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + Su34Status.status[groupName] = 8 + MessageToRed( string.format('%s: ',groupName) .. 'Take-Off. ', 10, 'RedStatus' .. groupName ) +end + +function Su34Hold(groupName) +--trace.menu("","Su34Hold") + local groupSu34 = Group.getByName( groupName ) + local controllerSu34 = groupSu34:getController() + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + Su34Status.status[groupName] = 5 + MessageToRed( string.format('%s: ',groupName) .. 'Holding Weapons. ', 10, 'RedStatus' .. groupName ) +end + +function Su34RTB(groupName) +--trace.menu("","Su34RTB") + Su34Status.status[groupName] = 6 + MessageToRed( string.format('%s: ',groupName) .. 'Return to Krasnodar. ', 10, 'RedStatus' .. groupName ) +end + +function Su34Destroyed(groupName) +--trace.menu("","Su34Destroyed") + Su34Status.status[groupName] = 7 + MessageToRed( string.format('%s: ',groupName) .. 'Destroyed. ', 30, 'RedStatus' .. groupName ) +end + +function GroupAlive( groupName ) +--trace.menu("","GroupAlive") + local groupTest = Group.getByName( groupName ) + + local groupExists = false + + if groupTest then + groupExists = groupTest:isExist() + end + + --trace.r( "", "", { groupExists } ) + return groupExists +end + +function Su34IsDead() +--trace.f() + +end + +function Su34OverviewStatus() +--trace.menu("","Su34OverviewStatus") + local msg = "" + local currentStatus = 0 + local Exists = false + + for groupName, currentStatus in pairs(Su34Status.status) do + + env.info(('Su34 Overview Status: GroupName = ' .. groupName )) + Alive = GroupAlive( groupName ) + + if Alive then + if currentStatus == 1 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Attacking carrier Carl Vinson. " + elseif currentStatus == 2 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Attacking supporting ships in the west. " + elseif currentStatus == 3 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Attacking invading ships in the north. " + elseif currentStatus == 4 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "In orbit and awaiting further instructions. " + elseif currentStatus == 5 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Holding Weapons. " + elseif currentStatus == 6 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Return to Krasnodar. " + elseif currentStatus == 7 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Destroyed. " + elseif currentStatus == 8 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Take-Off. " + end + else + if currentStatus == 7 then + msg = msg .. string.format("%s: ",groupName) + msg = msg .. "Destroyed. " + else + Su34Destroyed(groupName) + end + end + end + + boardMsgRed.statusMsg = msg +end + + +function UpdateBoardMsg() +--trace.f() + Su34OverviewStatus() + MessageToRed( boardMsgRed.statusMsg, 15, 'RedStatus' ) +end + +function MusicReset( flg ) +--trace.f() + trigger.action.setUserFlag(95,flg) +end + +function PlaneActivate(groupNameFormat, flg) +--trace.f() + local groupName = groupNameFormat .. string.format("#%03d", trigger.misc.getUserFlag(flg)) + --trigger.action.outText(groupName,10) + trigger.action.activateGroup(Group.getByName(groupName)) +end + +function Su34Menu(groupName) +--trace.f() + + --env.info(( 'Su34Menu(' .. groupName .. ')' )) + local groupSu34 = Group.getByName( groupName ) + + if Su34Status.status[groupName] == 1 or + Su34Status.status[groupName] == 2 or + Su34Status.status[groupName] == 3 or + Su34Status.status[groupName] == 4 or + Su34Status.status[groupName] == 5 then + if Su34MenuPath[groupName] == nil then + if planeMenuPath == nil then + planeMenuPath = missionCommands.addSubMenuForCoalition( + coalition.side.RED, + "SU-34 anti-ship flights", + nil + ) + end + Su34MenuPath[groupName] = missionCommands.addSubMenuForCoalition( + coalition.side.RED, + "Flight " .. groupName, + planeMenuPath + ) + + missionCommands.addCommandForCoalition( + coalition.side.RED, + "Attack carrier Carl Vinson", + Su34MenuPath[groupName], + Su34AttackCarlVinson, + groupName + ) + + missionCommands.addCommandForCoalition( + coalition.side.RED, + "Attack ships in the west", + Su34MenuPath[groupName], + Su34AttackWest, + groupName + ) + + missionCommands.addCommandForCoalition( + coalition.side.RED, + "Attack ships in the north", + Su34MenuPath[groupName], + Su34AttackNorth, + groupName + ) + + missionCommands.addCommandForCoalition( + coalition.side.RED, + "Hold position and await instructions", + Su34MenuPath[groupName], + Su34Orbit, + groupName + ) + + missionCommands.addCommandForCoalition( + coalition.side.RED, + "Report status", + Su34MenuPath[groupName], + Su34OverviewStatus + ) + end + else + if Su34MenuPath[groupName] then + missionCommands.removeItemForCoalition(coalition.side.RED, Su34MenuPath[groupName]) + end + end +end + +--- Obsolete function, but kept to rework in framework. + +function ChooseInfantry ( TeleportPrefixTable, TeleportMax ) +--trace.f("Spawn") + --env.info(( 'ChooseInfantry: ' )) + + TeleportPrefixTableCount = #TeleportPrefixTable + TeleportPrefixTableIndex = math.random( 1, TeleportPrefixTableCount ) + + --env.info(( 'ChooseInfantry: TeleportPrefixTableIndex = ' .. TeleportPrefixTableIndex .. ' TeleportPrefixTableCount = ' .. TeleportPrefixTableCount .. ' TeleportMax = ' .. TeleportMax )) + + local TeleportFound = false + local TeleportLoop = true + local Index = TeleportPrefixTableIndex + local TeleportPrefix = '' + + while TeleportLoop do + TeleportPrefix = TeleportPrefixTable[Index] + if SpawnSettings[TeleportPrefix] then + if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then + SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 + TeleportFound = true + else + TeleportFound = false + end + else + SpawnSettings[TeleportPrefix] = {} + SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 + TeleportFound = true + end + if TeleportFound then + TeleportLoop = false + else + if Index < TeleportPrefixTableCount then + Index = Index + 1 + else + TeleportLoop = false + end + end + --env.info(( 'ChooseInfantry: Loop 1 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) + end + + if TeleportFound == false then + TeleportLoop = true + Index = 1 + while TeleportLoop do + TeleportPrefix = TeleportPrefixTable[Index] + if SpawnSettings[TeleportPrefix] then + if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then + SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 + TeleportFound = true + else + TeleportFound = false + end + else + SpawnSettings[TeleportPrefix] = {} + SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 + TeleportFound = true + end + if TeleportFound then + TeleportLoop = false + else + if Index < TeleportPrefixTableIndex then + Index = Index + 1 + else + TeleportLoop = false + end + end + --env.info(( 'ChooseInfantry: Loop 2 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) + end + end + + local TeleportGroupName = '' + if TeleportFound == true then + TeleportGroupName = TeleportPrefix .. string.format("#%03d", SpawnSettings[TeleportPrefix]['SpawnCount'] ) + else + TeleportGroupName = '' + end + + --env.info(('ChooseInfantry: TeleportGroupName = ' .. TeleportGroupName )) + --env.info(('ChooseInfantry: return')) + + return TeleportGroupName +end + +SpawnedInfantry = 0 + +function LandCarrier ( CarrierGroup, LandingZonePrefix ) +--trace.f() + --env.info(( 'LandCarrier: ' )) + --env.info(( 'LandCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) + --env.info(( 'LandCarrier: LandingZone = ' .. LandingZonePrefix )) + + local controllerGroup = CarrierGroup:getController() + + local LandingZone = trigger.misc.getZone(LandingZonePrefix) + local LandingZonePos = {} + LandingZonePos.x = LandingZone.point.x + math.random(LandingZone.radius * -1, LandingZone.radius) + LandingZonePos.y = LandingZone.point.z + math.random(LandingZone.radius * -1, LandingZone.radius) + + controllerGroup:pushTask( { id = 'Land', params = { point = LandingZonePos, durationFlag = true, duration = 10 } } ) + + --env.info(( 'LandCarrier: end' )) +end + +EscortCount = 0 +function EscortCarrier ( CarrierGroup, EscortPrefix, EscortLastWayPoint, EscortEngagementDistanceMax, EscortTargetTypes ) +--trace.f() + --env.info(( 'EscortCarrier: ' )) + --env.info(( 'EscortCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) + --env.info(( 'EscortCarrier: EscortPrefix = ' .. EscortPrefix )) + + local CarrierName = CarrierGroup:getName() + + local EscortMission = {} + local CarrierMission = {} + + local EscortMission = SpawnMissionGroup( EscortPrefix ) + local CarrierMission = SpawnMissionGroup( CarrierGroup:getName() ) + + if EscortMission ~= nil and CarrierMission ~= nil then + + EscortCount = EscortCount + 1 + EscortMissionName = string.format( EscortPrefix .. '#Escort %s', CarrierName ) + EscortMission.name = EscortMissionName + EscortMission.groupId = nil + EscortMission.lateActivation = false + EscortMission.taskSelected = false + + local EscortUnits = #EscortMission.units + for u = 1, EscortUnits do + EscortMission.units[u].name = string.format( EscortPrefix .. '#Escort %s %02d', CarrierName, u ) + EscortMission.units[u].unitId = nil + end + + + EscortMission.route.points[1].task = { id = "ComboTask", + params = + { + tasks = + { + [1] = + { + enabled = true, + auto = false, + id = "Escort", + number = 1, + params = + { + lastWptIndexFlagChangedManually = false, + groupId = CarrierGroup:getID(), + lastWptIndex = nil, + lastWptIndexFlag = false, + engagementDistMax = EscortEngagementDistanceMax, + targetTypes = EscortTargetTypes, + pos = + { + y = 20, + x = 20, + z = 0, + } -- end of ["pos"] + } -- end of ["params"] + } -- end of [1] + } -- end of ["tasks"] + } -- end of ["params"] + } -- end of ["task"] + + SpawnGroupAdd( EscortPrefix, EscortMission ) + + end +end + +function SendMessageToCarrier( CarrierGroup, CarrierMessage ) +--trace.f() + + if CarrierGroup ~= nil then + MessageToGroup( CarrierGroup, CarrierMessage, 30, 'Carrier/' .. CarrierGroup:getName() ) + end + +end + +function MessageToGroup( MsgGroup, MsgText, MsgTime, MsgName ) +--trace.f() + + if type(MsgGroup) == 'string' then + --env.info( 'MessageToGroup: Converted MsgGroup string "' .. MsgGroup .. '" into a Group structure.' ) + MsgGroup = Group.getByName( MsgGroup ) + end + + if MsgGroup ~= nil then + local MsgTable = {} + MsgTable.text = MsgText + MsgTable.displayTime = MsgTime + MsgTable.msgFor = { units = { MsgGroup:getUnits()[1]:getName() } } + MsgTable.name = MsgName + --routines.message.add( MsgTable ) + --env.info(('MessageToGroup: Message sent to ' .. MsgGroup:getUnits()[1]:getName() .. ' -> ' .. MsgText )) + end +end + +function MessageToUnit( UnitName, MsgText, MsgTime, MsgName ) +--trace.f() + + if UnitName ~= nil then + local MsgTable = {} + MsgTable.text = MsgText + MsgTable.displayTime = MsgTime + MsgTable.msgFor = { units = { UnitName } } + MsgTable.name = MsgName + --routines.message.add( MsgTable ) + end +end + +function MessageToAll( MsgText, MsgTime, MsgName ) +--trace.f() + + MESSAGE:New( MsgText, MsgTime, "Message" ):ToCoalition( coalition.side.RED ):ToCoalition( coalition.side.BLUE ) +end + +function MessageToRed( MsgText, MsgTime, MsgName ) +--trace.f() + + MESSAGE:New( MsgText, MsgTime, "To Red Coalition" ):ToCoalition( coalition.side.RED ) +end + +function MessageToBlue( MsgText, MsgTime, MsgName ) +--trace.f() + + MESSAGE:New( MsgText, MsgTime, "To Blue Coalition" ):ToCoalition( coalition.side.RED ) +end + +function getCarrierHeight( CarrierGroup ) +--trace.f() + + if CarrierGroup ~= nil then + if table.getn(CarrierGroup:getUnits()) == 1 then + local CarrierUnit = CarrierGroup:getUnits()[1] + local CurrentPoint = CarrierUnit:getPoint() + + local CurrentPosition = { x = CurrentPoint.x, y = CurrentPoint.z } + local CarrierHeight = CurrentPoint.y + + local LandHeight = land.getHeight( CurrentPosition ) + + --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) + + return CarrierHeight - LandHeight + else + return 999999 + end + else + return 999999 + end + +end + +function GetUnitHeight( CheckUnit ) +--trace.f() + + local UnitPoint = CheckUnit:getPoint() + local UnitPosition = { x = CurrentPoint.x, y = CurrentPoint.z } + local UnitHeight = CurrentPoint.y + + local LandHeight = land.getHeight( CurrentPosition ) + + --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) + + return UnitHeight - LandHeight + +end + + +_MusicTable = {} +_MusicTable.Files = {} +_MusicTable.Queue = {} +_MusicTable.FileCnt = 0 + + +function MusicRegister( SndRef, SndFile, SndTime ) +--trace.f() + + env.info(( 'MusicRegister: SndRef = ' .. SndRef )) + env.info(( 'MusicRegister: SndFile = ' .. SndFile )) + env.info(( 'MusicRegister: SndTime = ' .. SndTime )) + + + _MusicTable.FileCnt = _MusicTable.FileCnt + 1 + + _MusicTable.Files[_MusicTable.FileCnt] = {} + _MusicTable.Files[_MusicTable.FileCnt].Ref = SndRef + _MusicTable.Files[_MusicTable.FileCnt].File = SndFile + _MusicTable.Files[_MusicTable.FileCnt].Time = SndTime + + if not _MusicTable.Function then + _MusicTable.Function = routines.scheduleFunction( MusicScheduler, { }, timer.getTime() + 10, 10) + end + +end + +function MusicToPlayer( SndRef, PlayerName, SndContinue ) +--trace.f() + + --env.info(( 'MusicToPlayer: SndRef = ' .. SndRef )) + + local PlayerUnits = AlivePlayerUnits() + for PlayerUnitIdx, PlayerUnit in pairs(PlayerUnits) do + local PlayerUnitName = PlayerUnit:getPlayerName() + --env.info(( 'MusicToPlayer: PlayerUnitName = ' .. PlayerUnitName )) + if PlayerName == PlayerUnitName then + PlayerGroup = PlayerUnit:getGroup() + if PlayerGroup then + --env.info(( 'MusicToPlayer: PlayerGroup = ' .. PlayerGroup:getName() )) + MusicToGroup( SndRef, PlayerGroup, SndContinue ) + end + break + end + end + + --env.info(( 'MusicToPlayer: end' )) + +end + +function MusicToGroup( SndRef, SndGroup, SndContinue ) +--trace.f() + + --env.info(( 'MusicToGroup: SndRef = ' .. SndRef )) + + if SndGroup ~= nil then + if _MusicTable and _MusicTable.FileCnt > 0 then + if SndGroup:isExist() then + if MusicCanStart(SndGroup:getUnit(1):getPlayerName()) then + --env.info(( 'MusicToGroup: OK for Sound.' )) + local SndIdx = 0 + if SndRef == '' then + --env.info(( 'MusicToGroup: SndRef as empty. Queueing at random.' )) + SndIdx = math.random( 1, _MusicTable.FileCnt ) + else + for SndIdx = 1, _MusicTable.FileCnt do + if _MusicTable.Files[SndIdx].Ref == SndRef then + break + end + end + end + --env.info(( 'MusicToGroup: SndIdx = ' .. SndIdx )) + --env.info(( 'MusicToGroup: Queueing Music ' .. _MusicTable.Files[SndIdx].File .. ' for Group ' .. SndGroup:getID() )) + trigger.action.outSoundForGroup( SndGroup:getID(), _MusicTable.Files[SndIdx].File ) + MessageToGroup( SndGroup, 'Playing ' .. _MusicTable.Files[SndIdx].File, 15, 'Music-' .. SndGroup:getUnit(1):getPlayerName() ) + + local SndQueueRef = SndGroup:getUnit(1):getPlayerName() + if _MusicTable.Queue[SndQueueRef] == nil then + _MusicTable.Queue[SndQueueRef] = {} + end + _MusicTable.Queue[SndQueueRef].Start = timer.getTime() + _MusicTable.Queue[SndQueueRef].PlayerName = SndGroup:getUnit(1):getPlayerName() + _MusicTable.Queue[SndQueueRef].Group = SndGroup + _MusicTable.Queue[SndQueueRef].ID = SndGroup:getID() + _MusicTable.Queue[SndQueueRef].Ref = SndIdx + _MusicTable.Queue[SndQueueRef].Continue = SndContinue + _MusicTable.Queue[SndQueueRef].Type = Group + end + end + end + end +end + +function MusicCanStart(PlayerName) +--trace.f() + + --env.info(( 'MusicCanStart:' )) + + local MusicOut = false + + if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then + --env.info(( 'MusicCanStart: PlayerName = ' .. PlayerName )) + local PlayerFound = false + local MusicStart = 0 + local MusicTime = 0 + for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do + if SndQueue.PlayerName == PlayerName then + PlayerFound = true + MusicStart = SndQueue.Start + MusicTime = _MusicTable.Files[SndQueue.Ref].Time + break + end + end + if PlayerFound then + --env.info(( 'MusicCanStart: MusicStart = ' .. MusicStart )) + --env.info(( 'MusicCanStart: MusicTime = ' .. MusicTime )) + --env.info(( 'MusicCanStart: timer.getTime() = ' .. timer.getTime() )) + + if MusicStart + MusicTime <= timer.getTime() then + MusicOut = true + end + else + MusicOut = true + end + end + + if MusicOut then + --env.info(( 'MusicCanStart: true' )) + else + --env.info(( 'MusicCanStart: false' )) + end + + return MusicOut +end + +function MusicScheduler() +--trace.scheduled("", "MusicScheduler") + + --env.info(( 'MusicScheduler:' )) + if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then + --env.info(( 'MusicScheduler: Walking Sound Queue.')) + for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do + if SndQueue.Continue then + if MusicCanStart(SndQueue.PlayerName) then + --env.info(('MusicScheduler: MusicToGroup')) + MusicToPlayer( '', SndQueue.PlayerName, true ) + end + end + end + end + +end + + +env.info(( 'Init: Scripts Loaded v1.1' )) + +--- This module contains derived utilities taken from the MIST framework, +-- which are excellent tools to be reused in an OO environment!. +-- +-- ### Authors: +-- +-- * Grimes : Design & Programming of the MIST framework. +-- +-- ### Contributions: +-- +-- * FlightControl : Rework to OO framework +-- +-- @module Utils + + +--- @type SMOKECOLOR +-- @field Green +-- @field Red +-- @field White +-- @field Orange +-- @field Blue + +SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR + +--- @type FLARECOLOR +-- @field Green +-- @field Red +-- @field White +-- @field Yellow + +FLARECOLOR = trigger.flareColor -- #FLARECOLOR + +--- Utilities static class. +-- @type UTILS +UTILS = {} + + +--from http://lua-users.org/wiki/CopyTable +UTILS.DeepCopy = function(object) + local lookup_table = {} + local function _copy(object) + if type(object) ~= "table" then + return object + elseif lookup_table[object] then + return lookup_table[object] + end + local new_table = {} + lookup_table[object] = new_table + for index, value in pairs(object) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(object)) + end + local objectreturn = _copy(object) + return objectreturn +end + + +-- porting in Slmod's serialize_slmod2 +UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function + + lookup_table = {} + + local function _Serialize( tbl ) + + if type(tbl) == 'table' then --function only works for tables! + + if lookup_table[tbl] then + return lookup_table[object] + end + + local tbl_str = {} + + lookup_table[tbl] = tbl_str + + tbl_str[#tbl_str + 1] = '{' + + for ind,val in pairs(tbl) do -- serialize its fields + local ind_str = {} + if type(ind) == "number" then + ind_str[#ind_str + 1] = '[' + ind_str[#ind_str + 1] = tostring(ind) + ind_str[#ind_str + 1] = ']=' + else --must be a string + ind_str[#ind_str + 1] = '[' + ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) + ind_str[#ind_str + 1] = ']=' + end + + local val_str = {} + if ((type(val) == 'number') or (type(val) == 'boolean')) then + val_str[#val_str + 1] = tostring(val) + val_str[#val_str + 1] = ',' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'string' then + val_str[#val_str + 1] = routines.utils.basicSerialize(val) + val_str[#val_str + 1] = ',' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'nil' then -- won't ever happen, right? + val_str[#val_str + 1] = 'nil,' + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + elseif type(val) == 'table' then + if ind == "__index" then + -- tbl_str[#tbl_str + 1] = "__index" + -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + else + + val_str[#val_str + 1] = _Serialize(val) + val_str[#val_str + 1] = ',' --I think this is right, I just added it + tbl_str[#tbl_str + 1] = table.concat(ind_str) + tbl_str[#tbl_str + 1] = table.concat(val_str) + end + elseif type(val) == 'function' then + tbl_str[#tbl_str + 1] = "f() " .. tostring(ind) + tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + else + env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) + env.info( debug.traceback() ) + end + + end + tbl_str[#tbl_str + 1] = '}' + return table.concat(tbl_str) + else + return tostring(tbl) + end + end + + local objectreturn = _Serialize(tbl) + return objectreturn +end + +--porting in Slmod's "safestring" basic serialize +UTILS.BasicSerialize = function(s) + if s == nil then + return "\"\"" + else + if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then + return tostring(s) + elseif type(s) == 'string' then + s = string.format('%q', s) + return s + end + end +end + + +UTILS.ToDegree = function(angle) + return angle*180/math.pi +end + +UTILS.ToRadian = function(angle) + return angle*math.pi/180 +end + +UTILS.MetersToNM = function(meters) + return meters/1852 +end + +UTILS.MetersToFeet = function(meters) + return meters/0.3048 +end + +UTILS.NMToMeters = function(NM) + return NM*1852 +end + +UTILS.FeetToMeters = function(feet) + return feet*0.3048 +end + +UTILS.MpsToKnots = function(mps) + return mps*3600/1852 +end + +UTILS.MpsToKmph = function(mps) + return mps*3.6 +end + +UTILS.KnotsToMps = function(knots) + return knots*1852/3600 +end + +UTILS.KmphToMps = function(kmph) + return kmph/3.6 +end + +--[[acc: +in DM: decimal point of minutes. +In DMS: decimal point of seconds. +position after the decimal of the least significant digit: +So: +42.32 - acc of 2. +]] +UTILS.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 = UTILS.Round((oldLatMin - latMin)*60, acc) + + local oldLonMin = lonMin + lonMin = math.floor(lonMin) + local lonSec = 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 = UTILS.Round(latMin, acc) + lonMin = 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 + + +--- From http://lua-users.org/wiki/SimpleRound +-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place +function UTILS.Round( num, idp ) + local mult = 10 ^ ( idp or 0 ) + return math.floor( num * mult + 0.5 ) / mult +end + +-- porting in Slmod's dostring +function UTILS.DoString( s ) + local f, err = loadstring( s ) + if f then + return true, f() + else + return false, err + end +end +--- **Core** - BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE. +-- +-- ![Banner Image](..\Presentations\BASE\Dia1.JPG) +-- +-- === +-- +-- The @{#BASE} class is the core root class from where every other class in moose is derived. +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) +-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added +-- +-- Hereby the change log: +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * None. +-- +-- ### Authors: +-- +-- * **FlightControl**: Design & Programming +-- +-- @module Base + + + +local _TraceOnOff = true +local _TraceLevel = 1 +local _TraceAll = false +local _TraceClass = {} +local _TraceClassMethod = {} + +local _ClassID = 0 + +--- @type BASE +-- @field ClassName The name of the class. +-- @field ClassID The ID number of the class. +-- @field ClassNameAndID The name of the class concatenated with the ID number of the class. + +--- # 1) #BASE class +-- +-- All classes within the MOOSE framework are derived from the BASE class. +-- +-- BASE provides facilities for : +-- +-- * The construction and inheritance of MOOSE classes. +-- * The class naming and numbering system. +-- * The class hierarchy search system. +-- * The tracing of information or objects during mission execution for debuggin purposes. +-- * The subscription to DCS events for event handling in MOOSE objects. +-- +-- Note: The BASE class is an abstract class and is not meant to be used directly. +-- +-- ## 1.1) BASE constructor +-- +-- Any class derived from BASE, will use the @{Base#BASE.New} constructor embedded in the @{Base#BASE.Inherit} method. +-- See an example at the @{Base#BASE.New} method how this is done. +-- +-- ## 1.2) Trace information for debugging +-- +-- The BASE class contains trace methods to trace progress within a mission execution of a certain object. +-- These trace methods are inherited by each MOOSE class interiting BASE, soeach object created from derived class from BASE can use the tracing methods to trace its execution. +-- +-- Any type of information can be passed to these tracing methods. See the following examples: +-- +-- self:E( "Hello" ) +-- +-- Result in the word "Hello" in the dcs.log. +-- +-- local Array = { 1, nil, "h", { "a","b" }, "x" } +-- self:E( Array ) +-- +-- Results with the text [1]=1,[3]="h",[4]={[1]="a",[2]="b"},[5]="x"} in the dcs.log. +-- +-- local Object1 = "Object1" +-- local Object2 = 3 +-- local Object3 = { Object 1, Object 2 } +-- self:E( { Object1, Object2, Object3 } ) +-- +-- Results with the text [1]={[1]="Object",[2]=3,[3]={[1]="Object",[2]=3}} in the dcs.log. +-- +-- local SpawnObject = SPAWN:New( "Plane" ) +-- local GroupObject = GROUP:FindByName( "Group" ) +-- self:E( { Spawn = SpawnObject, Group = GroupObject } ) +-- +-- Results with the text [1]={Spawn={....),Group={...}} in the dcs.log. +-- +-- Below a more detailed explanation of the different method types for tracing. +-- +-- ### 1.2.1) Tracing methods categories +-- +-- There are basically 3 types of tracing methods available: +-- +-- * @{#BASE.F}: Used to trace the entrance of a function and its given parameters. An F is indicated at column 44 in the DCS.log file. +-- * @{#BASE.T}: Used to trace further logic within a function giving optional variables or parameters. A T is indicated at column 44 in the DCS.log file. +-- * @{#BASE.E}: Used to always trace information giving optional variables or parameters. An E is indicated at column 44 in the DCS.log file. +-- +-- ### 1.2.2) Tracing levels +-- +-- There are 3 tracing levels within MOOSE. +-- These tracing levels were defined to avoid bulks of tracing to be generated by lots of objects. +-- +-- As such, the F and T methods have additional variants to trace level 2 and 3 respectively: +-- +-- * @{#BASE.F2}: Trace the beginning of a function and its given parameters with tracing level 2. +-- * @{#BASE.F3}: Trace the beginning of a function and its given parameters with tracing level 3. +-- * @{#BASE.T2}: Trace further logic within a function giving optional variables or parameters with tracing level 2. +-- * @{#BASE.T3}: Trace further logic within a function giving optional variables or parameters with tracing level 3. +-- +-- ### 1.2.3) Trace activation. +-- +-- Tracing can be activated in several ways: +-- +-- * Switch tracing on or off through the @{#BASE.TraceOnOff}() method. +-- * Activate all tracing through the @{#BASE.TraceAll}() method. +-- * Activate only the tracing of a certain class (name) through the @{#BASE.TraceClass}() method. +-- * Activate only the tracing of a certain method of a certain class through the @{#BASE.TraceClassMethod}() method. +-- * Activate only the tracing of a certain level through the @{#BASE.TraceLevel}() method. +-- +-- ### 1.2.4) Check if tracing is on. +-- +-- The method @{#BASE.IsTrace}() will validate if tracing is activated or not. +-- +-- ## 1.3 DCS simulator Event Handling +-- +-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, +-- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently. +-- +-- ### 1.3.1 Subscribe / Unsubscribe to DCS Events +-- +-- At first, the mission designer will need to **Subscribe** to a specific DCS event for the class. +-- So, when the DCS event occurs, the class will be notified of that event. +-- There are two methods which you use to subscribe to or unsubscribe from an event. +-- +-- * @{#BASE.HandleEvent}(): Subscribe to a DCS Event. +-- * @{#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event. +-- +-- ### 1.3.2 Event Handling of DCS Events +-- +-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called +-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information +-- about the event that occurred. +-- +-- Find below an example of the prototype how to write an event handling function for two units: +-- +-- local Tank1 = UNIT:FindByName( "Tank A" ) +-- local Tank2 = UNIT:FindByName( "Tank B" ) +-- +-- -- Here we subscribe to the Dead events. So, if one of these tanks dies, the Tank1 or Tank2 objects will be notified. +-- Tank1:HandleEvent( EVENTS.Dead ) +-- Tank2:HandleEvent( EVENTS.Dead ) +-- +-- --- This function is an Event Handling function that will be called when Tank1 is Dead. +-- -- @param Wrapper.Unit#UNIT self +-- -- @param Core.Event#EVENTDATA EventData +-- function Tank1:OnEventDead( EventData ) +-- +-- self:SmokeGreen() +-- end +-- +-- --- This function is an Event Handling function that will be called when Tank2 is Dead. +-- -- @param Wrapper.Unit#UNIT self +-- -- @param Core.Event#EVENTDATA EventData +-- function Tank2:OnEventDead( EventData ) +-- +-- self:SmokeBlue() +-- end +-- +-- +-- +-- See the @{Event} module for more information about event handling. +-- +-- ## 1.4) Class identification methods +-- +-- BASE provides methods to get more information of each object: +-- +-- * @{#BASE.GetClassID}(): Gets the ID (number) of the object. Each object created is assigned a number, that is incremented by one. +-- * @{#BASE.GetClassName}(): Gets the name of the object, which is the name of the class the object was instantiated from. +-- * @{#BASE.GetClassNameAndID}(): Gets the name and ID of the object. +-- +-- ## 1.5) All objects derived from BASE can have "States" +-- +-- A mechanism is in place in MOOSE, that allows to let the objects administer **states**. +-- States are essentially properties of objects, which are identified by a **Key** and a **Value**. +-- +-- The method @{#BASE.SetState}() can be used to set a Value with a reference Key to the object. +-- To **read or retrieve** a state Value based on a Key, use the @{#BASE.GetState} method. +-- +-- These two methods provide a very handy way to keep state at long lasting processes. +-- Values can be stored within the objects, and later retrieved or changed when needed. +-- There is one other important thing to note, the @{#BASE.SetState}() and @{#BASE.GetState} methods +-- receive as the **first parameter the object for which the state needs to be set**. +-- Thus, if the state is to be set for the same object as the object for which the method is used, then provide the same +-- object name to the method. +-- +-- ## 1.10) Inheritance +-- +-- The following methods are available to implement inheritance +-- +-- * @{#BASE.Inherit}: Inherits from a class. +-- * @{#BASE.GetParent}: Returns the parent object from the object it is handling, or nil if there is no parent object. +-- +-- === +-- +-- @field #BASE BASE +-- +BASE = { + ClassName = "BASE", + ClassID = 0, + _Private = {}, + Events = {}, + States = {} +} + +--- The Formation Class +-- @type FORMATION +-- @field Cone A cone formation. +FORMATION = { + Cone = "Cone" +} + + + +--- BASE constructor. +-- +-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE. +-- +-- function EVENT:New() +-- local self = BASE:Inherit( self, BASE:New() ) -- #EVENT +-- return self +-- end +-- +-- @param #BASE self +-- @return #BASE +function BASE:New() + local self = routines.utils.deepCopy( self ) -- Create a new self instance + local MetaTable = {} + setmetatable( self, MetaTable ) + self.__index = self + _ClassID = _ClassID + 1 + self.ClassID = _ClassID + + + return self +end + +function BASE:_Destructor() + --self:E("_Destructor") + + --self:EventRemoveAll() +end + + +-- THIS IS WHY WE NEED LUA 5.2 ... +function BASE:_SetDestructor() + + -- TODO: Okay, this is really technical... + -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak... + -- Therefore, I am parking this logic until I've properly discussed all this with the community. + + local proxy = newproxy(true) + local proxyMeta = getmetatable(proxy) + + proxyMeta.__gc = function () + env.info("In __gc for " .. self:GetClassNameAndID() ) + if self._Destructor then + self:_Destructor() + end + end + + -- keep the userdata from newproxy reachable until the object + -- table is about to be garbage-collected - then the __gc hook + -- will be invoked and the destructor called + rawset( self, '__proxy', proxy ) + +end + +--- This is the worker method to inherit from a parent class. +-- @param #BASE self +-- @param Child is the Child class that inherits. +-- @param #BASE Parent is the Parent class that the Child inherits from. +-- @return #BASE Child +function BASE:Inherit( Child, Parent ) + local Child = routines.utils.deepCopy( Child ) + --local Parent = routines.utils.deepCopy( Parent ) + --local Parent = Parent + if Child ~= nil then + setmetatable( Child, Parent ) + Child.__index = Child + + --Child:_SetDestructor() + end + --self:T( 'Inherited from ' .. Parent.ClassName ) + return Child +end + +--- This is the worker method to retrieve the Parent class. +-- Note that the Parent class must be passed to call the parent class method. +-- +-- self:GetParent(self):ParentMethod() +-- +-- +-- @param #BASE self +-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved. +-- @return #BASE +function BASE:GetParent( Child ) + local Parent = getmetatable( Child ) +-- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName ) + return Parent +end + +--- Get the ClassName + ClassID of the class instance. +-- The ClassName + ClassID is formatted as '%s#%09d'. +-- @param #BASE self +-- @return #string The ClassName + ClassID of the class instance. +function BASE:GetClassNameAndID() + return string.format( '%s#%09d', self.ClassName, self.ClassID ) +end + +--- Get the ClassName of the class instance. +-- @param #BASE self +-- @return #string The ClassName of the class instance. +function BASE:GetClassName() + return self.ClassName +end + +--- Get the ClassID of the class instance. +-- @param #BASE self +-- @return #string The ClassID of the class instance. +function BASE:GetClassID() + return self.ClassID +end + +do -- Event Handling + + --- Returns the event dispatcher + -- @param #BASE self + -- @return Core.Event#EVENT + function BASE:EventDispatcher() + + return _EVENTDISPATCHER + end + + + --- Get the Class @{Event} processing Priority. + -- The Event processing Priority is a number from 1 to 10, + -- reflecting the order of the classes subscribed to the Event to be processed. + -- @param #BASE self + -- @return #number The @{Event} processing Priority. + function BASE:GetEventPriority() + return self._Private.EventPriority or 5 + end + + --- Set the Class @{Event} processing Priority. + -- The Event processing Priority is a number from 1 to 10, + -- reflecting the order of the classes subscribed to the Event to be processed. + -- @param #BASE self + -- @param #number EventPriority The @{Event} processing Priority. + -- @return self + function BASE:SetEventPriority( EventPriority ) + self._Private.EventPriority = EventPriority + end + + --- Remove all subscribed events + -- @param #BASE self + -- @return #BASE + function BASE:EventRemoveAll() + + self:EventDispatcher():RemoveAll( self ) + + return self + end + + --- Subscribe to a DCS Event. + -- @param #BASE self + -- @param Core.Event#EVENTS Event + -- @param #function EventFunction (optional) The function to be called when the event occurs for the unit. + -- @return #BASE + function BASE:HandleEvent( Event, EventFunction ) + + self:EventDispatcher():OnEventGeneric( EventFunction, self, Event ) + + return self + end + + --- UnSubscribe to a DCS event. + -- @param #BASE self + -- @param Core.Event#EVENTS Event + -- @return #BASE + function BASE:UnHandleEvent( Event ) + + self:EventDispatcher():Remove( self, Event ) + + return self + end + + -- Event handling function prototypes + + --- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart. + -- @function [parent=#BASE] OnEventShot + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs whenever an object is hit by a weapon. + -- initiator : The unit object the fired the weapon + -- weapon: Weapon object that hit the target + -- target: The Object that was hit. + -- @function [parent=#BASE] OnEventHit + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when an aircraft takes off from an airbase, farp, or ship. + -- initiator : The unit that tookoff + -- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships + -- @function [parent=#BASE] OnEventTakeoff + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when an aircraft lands at an airbase, farp or ship + -- initiator : The unit that has landed + -- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships + -- @function [parent=#BASE] OnEventLand + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any aircraft crashes into the ground and is completely destroyed. + -- initiator : The unit that has crashed + -- @function [parent=#BASE] OnEventCrash + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when a pilot ejects from an aircraft + -- initiator : The unit that has ejected + -- @function [parent=#BASE] OnEventEjection + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when an aircraft connects with a tanker and begins taking on fuel. + -- initiator : The unit that is receiving fuel. + -- @function [parent=#BASE] OnEventRefueling + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when an object is completely destroyed. + -- initiator : The unit that is was destroyed. + -- @function [parent=#BASE] OnEvent + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane. + -- initiator : The unit that the pilot has died in. + -- @function [parent=#BASE] OnEventPilotDead + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when a ground unit captures either an airbase or a farp. + -- initiator : The unit that captured the base + -- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction. + -- @function [parent=#BASE] OnEventBaseCaptured + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when a mission starts + -- @function [parent=#BASE] OnEventMissionStart + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when a mission ends + -- @function [parent=#BASE] OnEventMissionEnd + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when an aircraft is finished taking fuel. + -- initiator : The unit that was receiving fuel. + -- @function [parent=#BASE] OnEventRefuelingStop + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any object is spawned into the mission. + -- initiator : The unit that was spawned + -- @function [parent=#BASE] OnEventBirth + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any system fails on a human controlled aircraft. + -- initiator : The unit that had the failure + -- @function [parent=#BASE] OnEventHumanFailure + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any aircraft starts its engines. + -- initiator : The unit that is starting its engines. + -- @function [parent=#BASE] OnEventEngineStartup + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any aircraft shuts down its engines. + -- initiator : The unit that is stopping its engines. + -- @function [parent=#BASE] OnEventEngineShutdown + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any player assumes direct control of a unit. + -- initiator : The unit that is being taken control of. + -- @function [parent=#BASE] OnEventPlayerEnterUnit + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any player relieves control of a unit to the AI. + -- initiator : The unit that the player left. + -- @function [parent=#BASE] OnEventPlayerLeaveUnit + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns. + -- initiator : The unit that is doing the shooing. + -- target: The unit that is being targeted. + -- @function [parent=#BASE] OnEventShootingStart + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + + --- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event. + -- initiator : The unit that was doing the shooing. + -- @function [parent=#BASE] OnEventShootingEnd + -- @param #BASE self + -- @param Core.Event#EVENTDATA EventData The EventData structure. + +end + + +--- Creation of a Birth Event. +-- @param #BASE self +-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. +-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +-- @param #string IniUnitName The initiating unit name. +-- @param place +-- @param subplace +function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace ) + self:F( { EventTime, Initiator, IniUnitName, place, subplace } ) + + local Event = { + id = world.event.S_EVENT_BIRTH, + time = EventTime, + initiator = Initiator, + IniUnitName = IniUnitName, + place = place, + subplace = subplace + } + + world.onEvent( Event ) +end + +--- Creation of a Crash Event. +-- @param #BASE self +-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. +-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. +function BASE:CreateEventCrash( EventTime, Initiator ) + self:F( { EventTime, Initiator } ) + + local Event = { + id = world.event.S_EVENT_CRASH, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end + +-- TODO: Complete Dcs.DCSTypes#Event structure. +--- The main event handling function... This function captures all events generated for the class. +-- @param #BASE self +-- @param Dcs.DCSTypes#Event event +function BASE:onEvent(event) + --self:F( { BaseEventCodes[event.id], event } ) + + if self then + for EventID, EventObject in pairs( self.Events ) do + if EventObject.EventEnabled then + --env.info( 'onEvent Table EventObject.Self = ' .. tostring(EventObject.Self) ) + --env.info( 'onEvent event.id = ' .. tostring(event.id) ) + --env.info( 'onEvent EventObject.Event = ' .. tostring(EventObject.Event) ) + if event.id == EventObject.Event then + if self == EventObject.Self then + if event.initiator and event.initiator:isExist() then + event.IniUnitName = event.initiator:getName() + end + if event.target and event.target:isExist() then + event.TgtUnitName = event.target:getName() + end + --self:T( { BaseEventCodes[event.id], event } ) + --EventObject.EventFunction( self, event ) + end + end + end + end + end +end + +--- Set a state or property of the Object given a Key and a Value. +-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone. +-- @param #BASE self +-- @param Object The object that will hold the Value set by the Key. +-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type! +-- @param Value The value to is stored in the object. +-- @return The Value set. +-- @return #nil The Key was not found and thus the Value could not be retrieved. +function BASE:SetState( Object, Key, Value ) + + local ClassNameAndID = Object:GetClassNameAndID() + + self.States[ClassNameAndID] = self.States[ClassNameAndID] or {} + self.States[ClassNameAndID][Key] = Value + self:T2( { ClassNameAndID, Key, Value } ) + + return self.States[ClassNameAndID][Key] +end + + +--- Get a Value given a Key from the Object. +-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone. +-- @param #BASE self +-- @param Object The object that holds the Value set by the Key. +-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type! +-- @param Value The value to is stored in the Object. +-- @return The Value retrieved. +function BASE:GetState( Object, Key ) + + local ClassNameAndID = Object:GetClassNameAndID() + + if self.States[ClassNameAndID] then + local Value = self.States[ClassNameAndID][Key] or false + self:T2( { ClassNameAndID, Key, Value } ) + return Value + end + + return nil +end + +function BASE:ClearState( Object, StateName ) + + local ClassNameAndID = Object:GetClassNameAndID() + if self.States[ClassNameAndID] then + self.States[ClassNameAndID][StateName] = nil + end +end + +-- Trace section + +-- Log a trace (only shown when trace is on) +-- TODO: Make trace function using variable parameters. + +--- Set trace on or off +-- Note that when trace is off, no debug statement is performed, increasing performance! +-- When Moose is loaded statically, (as one file), tracing is switched off by default. +-- So tracing must be switched on manually in your mission if you are using Moose statically. +-- When moose is loading dynamically (for moose class development), tracing is switched on by default. +-- @param #BASE self +-- @param #boolean TraceOnOff Switch the tracing on or off. +-- @usage +-- -- Switch the tracing On +-- BASE:TraceOnOff( true ) +-- +-- -- Switch the tracing Off +-- BASE:TraceOnOff( false ) +function BASE:TraceOnOff( TraceOnOff ) + _TraceOnOff = TraceOnOff +end + + +--- Enquires if tracing is on (for the class). +-- @param #BASE self +-- @return #boolean +function BASE:IsTrace() + + if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + return true + else + return false + end +end + +--- Set trace level +-- @param #BASE self +-- @param #number Level +function BASE:TraceLevel( Level ) + _TraceLevel = Level + self:E( "Tracing level " .. Level ) +end + +--- Trace all methods in MOOSE +-- @param #BASE self +-- @param #boolean TraceAll true = trace all methods in MOOSE. +function BASE:TraceAll( TraceAll ) + + _TraceAll = TraceAll + + if _TraceAll then + self:E( "Tracing all methods in MOOSE " ) + else + self:E( "Switched off tracing all methods in MOOSE" ) + end +end + +--- Set tracing for a class +-- @param #BASE self +-- @param #string Class +function BASE:TraceClass( Class ) + _TraceClass[Class] = true + _TraceClassMethod[Class] = {} + self:E( "Tracing class " .. Class ) +end + +--- Set tracing for a specific method of class +-- @param #BASE self +-- @param #string Class +-- @param #string Method +function BASE:TraceClassMethod( Class, Method ) + if not _TraceClassMethod[Class] then + _TraceClassMethod[Class] = {} + _TraceClassMethod[Class].Method = {} + end + _TraceClassMethod[Class].Method[Method] = true + self:E( "Tracing method " .. Method .. " of class " .. Class ) +end + +--- Trace a function call. This function is private. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) + + if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + + local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) + local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) + + local Function = "function" + if DebugInfoCurrent.name then + Function = DebugInfoCurrent.name + end + + if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then + local LineCurrent = 0 + if DebugInfoCurrent.currentline then + LineCurrent = DebugInfoCurrent.currentline + end + local LineFrom = 0 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end + env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) + end + end +end + +--- Trace a function call. Must be at the beginning of the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:F( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 1 then + self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + + +--- Trace a function call level 2. Must be at the beginning of the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:F2( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 2 then + self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + +--- Trace a function call level 3. Must be at the beginning of the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:F3( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 3 then + self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + +--- Trace a function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) + + if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + + local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) + local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) + + local Function = "function" + if DebugInfoCurrent.name then + Function = DebugInfoCurrent.name + end + + if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then + local LineCurrent = 0 + if DebugInfoCurrent.currentline then + LineCurrent = DebugInfoCurrent.currentline + end + local LineFrom = 0 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end + env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) + end + end +end + +--- Trace a function logic level 1. Can be anywhere within the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:T( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 1 then + self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + + +--- Trace a function logic level 2. Can be anywhere within the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:T2( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 2 then + self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + +--- Trace a function logic level 3. Can be anywhere within the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:T3( Arguments ) + + if debug and _TraceOnOff then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + if _TraceLevel >= 3 then + self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) + end + end +end + +--- Log an exception which will be traced always. Can be anywhere within the function logic. +-- @param #BASE self +-- @param Arguments A #table or any field. +function BASE:E( Arguments ) + + if debug then + local DebugInfoCurrent = debug.getinfo( 2, "nl" ) + local DebugInfoFrom = debug.getinfo( 3, "l" ) + + local Function = "function" + if DebugInfoCurrent.name then + Function = DebugInfoCurrent.name + end + + local LineCurrent = DebugInfoCurrent.currentline + local LineFrom = -1 + if DebugInfoFrom then + LineFrom = DebugInfoFrom.currentline + end + + env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) + end + +end + + + +--- **Core** - SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**. +-- +-- ![Banner Image](..\Presentations\SCHEDULER\Dia1.JPG) +-- +-- === +-- +-- # 1) @{Scheduler#SCHEDULER} class, extends @{Base#BASE} +-- +-- The @{Scheduler#SCHEDULER} class creates schedule. +-- +-- ## 1.1) SCHEDULER constructor +-- +-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters: +-- +-- * @{Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection. +-- * @{Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. +-- * @{Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. +-- * @{Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. +-- +-- ## 1.2) SCHEDULER timer stopping and (re-)starting. +-- +-- The SCHEDULER can be stopped and restarted with the following methods: +-- +-- * @{Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started. +-- * @{Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped. +-- +-- ## 1.3) Create a new schedule +-- +-- With @{Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned. +-- +-- === +-- +-- ### Contributions: +-- +-- * FlightControl : Concept & Testing +-- +-- ### Authors: +-- +-- * FlightControl : Design & Programming +-- +-- ### Test Missions: +-- +-- * SCH - Scheduler +-- +-- === +-- +-- @module Scheduler + + +--- The SCHEDULER class +-- @type SCHEDULER +-- @field #number ScheduleID the ID of the scheduler. +-- @extends Core.Base#BASE +SCHEDULER = { + ClassName = "SCHEDULER", + Schedules = {}, +} + +--- SCHEDULER constructor. +-- @param #SCHEDULER self +-- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. +-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. +-- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. +-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. +-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. +-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. +-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. +-- @return #SCHEDULER self. +-- @return #number The ScheduleID of the planned schedule. +function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( { Start, Repeat, RandomizeFactor, Stop } ) + + local ScheduleID = nil + + self.MasterObject = SchedulerObject + + if SchedulerFunction then + ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) + end + + return self, ScheduleID +end + +--function SCHEDULER:_Destructor() +-- --self:E("_Destructor") +-- +-- _SCHEDULEDISPATCHER:RemoveSchedule( self.CallID ) +--end + +--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also. +-- @param #SCHEDULER self +-- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. +-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. +-- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. +-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. +-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. +-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. +-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. +-- @return #number The ScheduleID of the planned schedule. +function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) + self:F2( { Start, Repeat, RandomizeFactor, Stop } ) + self:T3( { SchedulerArguments } ) + + local ObjectName = "-" + if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then + ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID + end + self:F3( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) + self.SchedulerObject = SchedulerObject + + local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( + self, + SchedulerFunction, + SchedulerArguments, + Start, + Repeat, + RandomizeFactor, + Stop + ) + + self.Schedules[#self.Schedules+1] = ScheduleID + + return ScheduleID +end + +--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided. +-- @param #SCHEDULER self +-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. +function SCHEDULER:Start( ScheduleID ) + self:F3( { ScheduleID } ) + + _SCHEDULEDISPATCHER:Start( self, ScheduleID ) +end + +--- Stops the schedules or a specific schedule if a valid ScheduleID is provided. +-- @param #SCHEDULER self +-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. +function SCHEDULER:Stop( ScheduleID ) + self:F3( { ScheduleID } ) + + _SCHEDULEDISPATCHER:Stop( self, ScheduleID ) +end + +--- Removes a specific schedule if a valid ScheduleID is provided. +-- @param #SCHEDULER self +-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. +function SCHEDULER:Remove( ScheduleID ) + self:F3( { ScheduleID } ) + + _SCHEDULEDISPATCHER:Remove( self, ScheduleID ) +end + +--- Clears all pending schedules. +-- @param #SCHEDULER self +function SCHEDULER:Clear() + self:F3( ) + + _SCHEDULEDISPATCHER:Clear( self ) +end + + + + + + + + + + + + + + +--- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER. +-- +-- === +-- +-- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects. +-- +-- This class is tricky and needs some thorought explanation. +-- SCHEDULE classes are used to schedule functions for objects, or as persistent objects. +-- The SCHEDULEDISPATCHER class ensures that: +-- +-- - Scheduled functions are planned according the SCHEDULER object parameters. +-- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters. +-- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters. +-- +-- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection: +-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER +-- object is _persistent_ within memory. +-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection! +-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected. +-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object, +-- these will not be executed anymore when the SCHEDULER object has been destroyed. +-- +-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object. +-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER. +-- The SCHEDULER object plans new scheduled functions through the @{Scheduler#SCHEDULER.Schedule}() method. +-- The Schedule() method returns the CallID that is the reference ID for each planned schedule. +-- +-- === +-- +-- === +-- +-- ### Contributions: - +-- ### Authors: FlightControl : Design & Programming +-- +-- @module ScheduleDispatcher + +--- The SCHEDULEDISPATCHER structure +-- @type SCHEDULEDISPATCHER +SCHEDULEDISPATCHER = { + ClassName = "SCHEDULEDISPATCHER", + CallID = 0, +} + +function SCHEDULEDISPATCHER:New() + local self = BASE:Inherit( self, BASE:New() ) + self:F3() + return self +end + +--- Add a Schedule to the ScheduleDispatcher. +-- The development of this method was really tidy. +-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified. +-- Nothing of this code should be modified without testing it thoroughly. +-- @param #SCHEDULEDISPATCHER self +-- @param Core.Scheduler#SCHEDULER Scheduler +function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop ) + self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } ) + + self.CallID = self.CallID + 1 + + -- Initialize the ObjectSchedulers array, which is a weakly coupled table. + -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. + self.PersistentSchedulers = self.PersistentSchedulers or {} + + -- Initialize the ObjectSchedulers array, which is a weakly coupled table. + -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. + self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) -- or {} + + if Scheduler.MasterObject then + self.ObjectSchedulers[self.CallID] = Scheduler + self:F3( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) + else + self.PersistentSchedulers[self.CallID] = Scheduler + self:F3( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) + end + + self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) + self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} + self.Schedule[Scheduler][self.CallID] = {} + self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction + self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments + self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 ) + self.Schedule[Scheduler][self.CallID].Start = Start + .1 + self.Schedule[Scheduler][self.CallID].Repeat = Repeat + self.Schedule[Scheduler][self.CallID].Randomize = Randomize + self.Schedule[Scheduler][self.CallID].Stop = Stop + + self:T3( self.Schedule[Scheduler][self.CallID] ) + + self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID ) + self:F2( CallID ) + + local ErrorHandler = function( errmsg ) + env.info( "Error in timer function: " .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + return errmsg + end + + local Scheduler = self.ObjectSchedulers[CallID] + if not Scheduler then + Scheduler = self.PersistentSchedulers[CallID] + end + + self:T3( { Scheduler = Scheduler } ) + + if Scheduler then + + local Schedule = self.Schedule[Scheduler][CallID] + + self:T3( { Schedule = Schedule } ) + + local ScheduleObject = Scheduler.SchedulerObject + --local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID() + local ScheduleFunction = Schedule.Function + local ScheduleArguments = Schedule.Arguments + local Start = Schedule.Start + local Repeat = Schedule.Repeat or 0 + local Randomize = Schedule.Randomize or 0 + local Stop = Schedule.Stop or 0 + local ScheduleID = Schedule.ScheduleID + + local Status, Result + if ScheduleObject then + local function Timer() + return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) ) + end + Status, Result = xpcall( Timer, ErrorHandler ) + else + local function Timer() + return ScheduleFunction( unpack( ScheduleArguments ) ) + end + Status, Result = xpcall( Timer, ErrorHandler ) + end + + local CurrentTime = timer.getTime() + local StartTime = CurrentTime + Start + + if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then + if Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then + local ScheduleTime = + CurrentTime + + Repeat + + math.random( + - ( Randomize * Repeat / 2 ), + ( Randomize * Repeat / 2 ) + ) + + 0.01 + self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } ) + return ScheduleTime -- returns the next time the function needs to be called. + else + self:Stop( Scheduler, CallID ) + end + else + self:Stop( Scheduler, CallID ) + end + else + self:E( "Scheduled obscolete call for CallID: " .. CallID ) + end + + return nil + end + + self:Start( Scheduler, self.CallID ) + + return self.CallID +end + +function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID ) + self:F2( { Remove = CallID, Scheduler = Scheduler } ) + + if CallID then + self:Stop( Scheduler, CallID ) + self.Schedule[Scheduler][CallID] = nil + end +end + +function SCHEDULEDISPATCHER:Start( Scheduler, CallID ) + self:F2( { Start = CallID, Scheduler = Scheduler } ) + + if CallID then + local Schedule = self.Schedule[Scheduler] + -- Only start when there is no ScheduleID defined! + -- This prevents to "Start" the scheduler twice with the same CallID... + if not Schedule[CallID].ScheduleID then + Schedule[CallID].ScheduleID = timer.scheduleFunction( + Schedule[CallID].CallHandler, + CallID, + timer.getTime() + Schedule[CallID].Start + ) + end + else + for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do + self:Start( Scheduler, CallID ) -- Recursive + end + end +end + +function SCHEDULEDISPATCHER:Stop( Scheduler, CallID ) + self:F2( { Stop = CallID, Scheduler = Scheduler } ) + + if CallID then + local Schedule = self.Schedule[Scheduler] + -- Only stop when there is a ScheduleID defined for the CallID. + -- So, when the scheduler was stopped before, do nothing. + if Schedule[CallID].ScheduleID then + timer.removeFunction( Schedule[CallID].ScheduleID ) + Schedule[CallID].ScheduleID = nil + end + else + for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do + self:Stop( Scheduler, CallID ) -- Recursive + end + end +end + +function SCHEDULEDISPATCHER:Clear( Scheduler ) + self:F2( { Scheduler = Scheduler } ) + + for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do + self:Stop( Scheduler, CallID ) -- Recursive + end +end + + + +--- **Core** - EVENT models DCS **event dispatching** using a **publish-subscribe** model. +-- +-- ![Banner Image](..\Presentations\EVENT\Dia1.JPG) +-- +-- === +-- +-- # 1) Event Handling Overview +-- +-- ![Objects](..\Presentations\EVENT\Dia2.JPG) +-- +-- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc. +-- This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission. +-- +-- ![Objects](..\Presentations\EVENT\Dia3.JPG) +-- +-- Objects can subscribe to different events. The Event dispatcher will publish the received DCS events to the subscribed MOOSE objects, in a specified order. +-- In this way, the subscribed MOOSE objects are kept in sync with your evolving running mission. +-- +-- ## 1.1) Event Dispatching +-- +-- ![Objects](..\Presentations\EVENT\Dia4.JPG) +-- +-- The _EVENTDISPATCHER object is automatically created within MOOSE, +-- and handles the dispatching of DCS Events occurring +-- in the simulator to the subscribed objects +-- in the correct processing order. +-- +-- ![Objects](..\Presentations\EVENT\Dia5.JPG) +-- +-- There are 5 levels of kind of objects that the _EVENTDISPATCHER services: +-- +-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database. +-- * SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority. +-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object. +-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object. +-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object. +-- +-- ![Objects](..\Presentations\EVENT\Dia6.JPG) +-- +-- For most DCS events, the above order of updating will be followed. +-- +-- ![Objects](..\Presentations\EVENT\Dia7.JPG) +-- +-- But for some DCS events, the publishing order is reversed. This is due to the fact that objects need to be **erased** instead of added. +-- +-- ## 1.2) Event Handling +-- +-- ![Objects](..\Presentations\EVENT\Dia8.JPG) +-- +-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{BASE} class, @{UNIT} class and @{GROUP} class. +-- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE. +-- +-- ![Objects](..\Presentations\EVENT\Dia9.JPG) +-- +-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, +-- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently. +-- +-- ### 1.2.1 Subscribe / Unsubscribe to DCS Events +-- +-- At first, the mission designer will need to **Subscribe** to a specific DCS event for the class. +-- So, when the DCS event occurs, the class will be notified of that event. +-- There are two functions which you use to subscribe to or unsubscribe from an event. +-- +-- * @{Base#BASE.HandleEvent}(): Subscribe to a DCS Event. +-- * @{Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event. +-- +-- Note that for a UNIT, the event will be handled **for that UNIT only**! +-- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**! +-- +-- For all objects of other classes, the subscribed events will be handled for **all UNITs within the Mission**! +-- So if a UNIT within the mission has the subscribed event for that object, +-- then the object event handler will receive the event for that UNIT! +-- +-- ### 1.3.2 Event Handling of DCS Events +-- +-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called +-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information +-- about the event that occurred. +-- +-- Find below an example of the prototype how to write an event handling function for two units: +-- +-- local Tank1 = UNIT:FindByName( "Tank A" ) +-- local Tank2 = UNIT:FindByName( "Tank B" ) +-- +-- -- Here we subscribe to the Dead events. So, if one of these tanks dies, the Tank1 or Tank2 objects will be notified. +-- Tank1:HandleEvent( EVENTS.Dead ) +-- Tank2:HandleEvent( EVENTS.Dead ) +-- +-- --- This function is an Event Handling function that will be called when Tank1 is Dead. +-- -- @param Wrapper.Unit#UNIT self +-- -- @param Core.Event#EVENTDATA EventData +-- function Tank1:OnEventDead( EventData ) +-- +-- self:SmokeGreen() +-- end +-- +-- --- This function is an Event Handling function that will be called when Tank2 is Dead. +-- -- @param Wrapper.Unit#UNIT self +-- -- @param Core.Event#EVENTDATA EventData +-- function Tank2:OnEventDead( EventData ) +-- +-- self:SmokeBlue() +-- end +-- +-- ### 1.3.3 Event Handling methods that are automatically called upon subscribed DCS events +-- +-- ![Objects](..\Presentations\EVENT\Dia10.JPG) +-- +-- The following list outlines which EVENTS item in the structure corresponds to which Event Handling method. +-- Always ensure that your event handling methods align with the events being subscribed to, or nothing will be executed. +-- +-- # 2) EVENTS type +-- +-- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the +-- @{Base#BASE.HandleEvent}() method. +-- +-- # 3) EVENTDATA type +-- +-- The @{Event#EVENTDATA} structure contains all the fields that are populated with event information before +-- an Event Handler method is being called by the event dispatcher. +-- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events. +-- There are basically 4 main categories of information stored in the EVENTDATA structure: +-- +-- * Initiator Unit data: Several fields documenting the initiator unit related to the event. +-- * Target Unit data: Several fields documenting the target unit related to the event. +-- * Weapon data: Certain events populate weapon information. +-- * Place data: Certain events populate place information. +-- +-- --- This function is an Event Handling function that will be called when Tank1 is Dead. +-- -- EventData is an EVENTDATA structure. +-- -- We use the EventData.IniUnit to smoke the tank Green. +-- -- @param Wrapper.Unit#UNIT self +-- -- @param Core.Event#EVENTDATA EventData +-- function Tank1:OnEventDead( EventData ) +-- +-- EventData.IniUnit:SmokeGreen() +-- end +-- +-- +-- Find below an overview which events populate which information categories: +-- +-- ![Objects](..\Presentations\EVENT\Dia14.JPG) +-- +-- **IMPORTANT NOTE:** Some events can involve not just UNIT objects, but also STATIC objects!!! +-- In that case the initiator or target unit fields will refer to a STATIC object! +-- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. +-- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event. +-- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory. +-- Example code snippet: +-- +-- if Event.IniObjectCategory == Object.Category.UNIT then +-- ... +-- end +-- if Event.IniObjectCategory == Object.Category.STATIC then +-- ... +-- end +-- +-- When a static object is involved in the event, the Group and Player fields won't be populated. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) +-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added +-- +-- Hereby the change log: +-- +-- * 2017-03-07: Added the correct event dispatching in case the event is subscribed by a GROUP. +-- +-- * 2017-02-07: Did a complete revision of the Event Handing API and underlying mechanisms. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- ### Authors: +-- +-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. +-- +-- @module Event + + +--- The EVENT structure +-- @type EVENT +-- @field #EVENT.Events Events +-- @extends Core.Base#BASE +EVENT = { + ClassName = "EVENT", + ClassID = 0, +} + +--- The different types of events supported by MOOSE. +-- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method. +-- @type EVENTS +EVENTS = { + Shot = world.event.S_EVENT_SHOT, + Hit = world.event.S_EVENT_HIT, + Takeoff = world.event.S_EVENT_TAKEOFF, + Land = world.event.S_EVENT_LAND, + Crash = world.event.S_EVENT_CRASH, + Ejection = world.event.S_EVENT_EJECTION, + Refueling = world.event.S_EVENT_REFUELING, + Dead = world.event.S_EVENT_DEAD, + PilotDead = world.event.S_EVENT_PILOT_DEAD, + BaseCaptured = world.event.S_EVENT_BASE_CAPTURED, + MissionStart = world.event.S_EVENT_MISSION_START, + MissionEnd = world.event.S_EVENT_MISSION_END, + TookControl = world.event.S_EVENT_TOOK_CONTROL, + RefuelingStop = world.event.S_EVENT_REFUELING_STOP, + Birth = world.event.S_EVENT_BIRTH, + HumanFailure = world.event.S_EVENT_HUMAN_FAILURE, + EngineStartup = world.event.S_EVENT_ENGINE_STARTUP, + EngineShutdown = world.event.S_EVENT_ENGINE_SHUTDOWN, + PlayerEnterUnit = world.event.S_EVENT_PLAYER_ENTER_UNIT, + PlayerLeaveUnit = world.event.S_EVENT_PLAYER_LEAVE_UNIT, + PlayerComment = world.event.S_EVENT_PLAYER_COMMENT, + ShootingStart = world.event.S_EVENT_SHOOTING_START, + ShootingEnd = world.event.S_EVENT_SHOOTING_END, +} + +--- The Event structure +-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event: +-- +-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event. +-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event. +-- +-- @type EVENTDATA +-- @field #number id The identifier of the event. +-- +-- @field Dcs.DCSUnit#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}. +-- @field Dcs.DCSObject#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field Dcs.DCSUnit#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. +-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name. +-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Unit#UNIT} of the initiator Unit object. +-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName). +-- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}. +-- @field #string IniDCSGroupName (UNIT) The initiating Group name. +-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Group#GROUP} of the initiator Group object. +-- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName). +-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot. +-- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator. +-- @field Dcs.DCSUnit#Unit.Category IniCategory (UNIT) The category of the initiator. +-- @field #string IniTypeName (UNIT) The type name of the initiator. +-- +-- @field Dcs.DCSUnit#Unit target (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. +-- @field Dcs.DCSObject#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). +-- @field Dcs.DCSUnit#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}. +-- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name. +-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Unit#UNIT} of the target Unit object. +-- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName). +-- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}. +-- @field #string TgtDCSGroupName (UNIT) The target Group name. +-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Group#GROUP} of the target Group object. +-- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName). +-- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot. +-- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target. +-- @field Dcs.DCSUnit#Unit.Category TgtCategory (UNIT) The category of the target. +-- @field #string TgtTypeName (UNIT) The type name of the target. +-- +-- @field weapon The weapon used during the event. +-- @field Weapon +-- @field WeaponName +-- @field WeaponTgtDCSUnit + + +local _EVENTMETA = { + [world.event.S_EVENT_SHOT] = { + Order = 1, + Event = "OnEventShot", + Text = "S_EVENT_SHOT" + }, + [world.event.S_EVENT_HIT] = { + Order = 1, + Event = "OnEventHit", + Text = "S_EVENT_HIT" + }, + [world.event.S_EVENT_TAKEOFF] = { + Order = 1, + Event = "OnEventTakeoff", + Text = "S_EVENT_TAKEOFF" + }, + [world.event.S_EVENT_LAND] = { + Order = 1, + Event = "OnEventLand", + Text = "S_EVENT_LAND" + }, + [world.event.S_EVENT_CRASH] = { + Order = -1, + Event = "OnEventCrash", + Text = "S_EVENT_CRASH" + }, + [world.event.S_EVENT_EJECTION] = { + Order = 1, + Event = "OnEventEjection", + Text = "S_EVENT_EJECTION" + }, + [world.event.S_EVENT_REFUELING] = { + Order = 1, + Event = "OnEventRefueling", + Text = "S_EVENT_REFUELING" + }, + [world.event.S_EVENT_DEAD] = { + Order = -1, + Event = "OnEventDead", + Text = "S_EVENT_DEAD" + }, + [world.event.S_EVENT_PILOT_DEAD] = { + Order = 1, + Event = "OnEventPilotDead", + Text = "S_EVENT_PILOT_DEAD" + }, + [world.event.S_EVENT_BASE_CAPTURED] = { + Order = 1, + Event = "OnEventBaseCaptured", + Text = "S_EVENT_BASE_CAPTURED" + }, + [world.event.S_EVENT_MISSION_START] = { + Order = 1, + Event = "OnEventMissionStart", + Text = "S_EVENT_MISSION_START" + }, + [world.event.S_EVENT_MISSION_END] = { + Order = 1, + Event = "OnEventMissionEnd", + Text = "S_EVENT_MISSION_END" + }, + [world.event.S_EVENT_TOOK_CONTROL] = { + Order = 1, + Event = "OnEventTookControl", + Text = "S_EVENT_TOOK_CONTROL" + }, + [world.event.S_EVENT_REFUELING_STOP] = { + Order = 1, + Event = "OnEventRefuelingStop", + Text = "S_EVENT_REFUELING_STOP" + }, + [world.event.S_EVENT_BIRTH] = { + Order = 1, + Event = "OnEventBirth", + Text = "S_EVENT_BIRTH" + }, + [world.event.S_EVENT_HUMAN_FAILURE] = { + Order = 1, + Event = "OnEventHumanFailure", + Text = "S_EVENT_HUMAN_FAILURE" + }, + [world.event.S_EVENT_ENGINE_STARTUP] = { + Order = 1, + Event = "OnEventEngineStartup", + Text = "S_EVENT_ENGINE_STARTUP" + }, + [world.event.S_EVENT_ENGINE_SHUTDOWN] = { + Order = 1, + Event = "OnEventEngineShutdown", + Text = "S_EVENT_ENGINE_SHUTDOWN" + }, + [world.event.S_EVENT_PLAYER_ENTER_UNIT] = { + Order = 1, + Event = "OnEventPlayerEnterUnit", + Text = "S_EVENT_PLAYER_ENTER_UNIT" + }, + [world.event.S_EVENT_PLAYER_LEAVE_UNIT] = { + Order = -1, + Event = "OnEventPlayerLeaveUnit", + Text = "S_EVENT_PLAYER_LEAVE_UNIT" + }, + [world.event.S_EVENT_PLAYER_COMMENT] = { + Order = 1, + Event = "OnEventPlayerComment", + Text = "S_EVENT_PLAYER_COMMENT" + }, + [world.event.S_EVENT_SHOOTING_START] = { + Order = 1, + Event = "OnEventShootingStart", + Text = "S_EVENT_SHOOTING_START" + }, + [world.event.S_EVENT_SHOOTING_END] = { + Order = 1, + Event = "OnEventShootingEnd", + Text = "S_EVENT_SHOOTING_END" + }, +} + + +--- The Events structure +-- @type EVENT.Events +-- @field #number IniUnit + +function EVENT:New() + local self = BASE:Inherit( self, BASE:New() ) + self:F2() + self.EventHandler = world.addEventHandler( self ) + return self +end + +function EVENT:EventText( EventID ) + + local EventText = _EVENTMETA[EventID].Text + + return EventText +end + + +--- Initializes the Events structure for the event +-- @param #EVENT self +-- @param Dcs.DCSWorld#world.event EventID +-- @param Core.Base#BASE EventClass +-- @return #EVENT.Events +function EVENT:Init( EventID, EventClass ) + self:F3( { _EVENTMETA[EventID].Text, EventClass } ) + + if not self.Events[EventID] then + -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. + self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) + end + + -- Each event has a subtable of EventClasses, ordered by EventPriority. + local EventPriority = EventClass:GetEventPriority() + if not self.Events[EventID][EventPriority] then + self.Events[EventID][EventPriority] = setmetatable( {}, { __mode = "k" } ) + end + + if not self.Events[EventID][EventPriority][EventClass] then + self.Events[EventID][EventPriority][EventClass] = setmetatable( {}, { __mode = "v" } ) + end + return self.Events[EventID][EventPriority][EventClass] +end + +--- Removes an Events entry +-- @param #EVENT self +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. +-- @param Dcs.DCSWorld#world.event EventID +-- @return #EVENT.Events +function EVENT:Remove( EventClass, EventID ) + self:F3( { EventClass, _EVENTMETA[EventID].Text } ) + + local EventClass = EventClass + local EventPriority = EventClass:GetEventPriority() + self.Events[EventID][EventPriority][EventClass] = nil +end + +--- Removes an Events entry for a UNIT. +-- @param #EVENT self +-- @param #string UnitName The name of the UNIT. +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. +-- @param Dcs.DCSWorld#world.event EventID +-- @return #EVENT.Events +function EVENT:RemoveForUnit( UnitName, EventClass, EventID ) + self:F3( { EventClass, _EVENTMETA[EventID].Text } ) + + local EventClass = EventClass + local EventPriority = EventClass:GetEventPriority() + local Event = self.Events[EventID][EventPriority][EventClass] + Event.EventUnit[UnitName] = nil +end + +--- Removes an Events entry for a GROUP. +-- @param #EVENT self +-- @param #string GroupName The name of the GROUP. +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. +-- @param Dcs.DCSWorld#world.event EventID +-- @return #EVENT.Events +function EVENT:RemoveForGroup( GroupName, EventClass, EventID ) + self:F3( { EventClass, _EVENTMETA[EventID].Text } ) + + local EventClass = EventClass + local EventPriority = EventClass:GetEventPriority() + local Event = self.Events[EventID][EventPriority][EventClass] + Event.EventGroup[GroupName] = nil +end + +--- Clears all event subscriptions for a @{Base#BASE} derived object. +-- @param #EVENT self +-- @param Core.Base#BASE EventObject +function EVENT:RemoveAll( EventObject ) + self:F3( { EventObject:GetClassNameAndID() } ) + + local EventClass = EventObject:GetClassNameAndID() + local EventPriority = EventClass:GetEventPriority() + for EventID, EventData in pairs( self.Events ) do + self.Events[EventID][EventPriority][EventClass] = nil + end +end + + + +--- Create an OnDead event handler for a group +-- @param #EVENT self +-- @param #table EventTemplate +-- @param #function EventFunction The function to be called when the event occurs for the unit. +-- @param EventClass The instance of the class for which the event is. +-- @param #function OnEventFunction +-- @return #EVENT +function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EventID ) + self:F2( EventTemplate.name ) + + for EventUnitID, EventUnit in pairs( EventTemplate.units ) do + self:OnEventForUnit( EventUnit.name, EventFunction, EventClass, EventID ) + end + return self +end + +--- Set a new listener for an S_EVENT_X event independent from a unit or a weapon. +-- @param #EVENT self +-- @param #function EventFunction The function to be called when the event occurs for the unit. +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided. +-- @param EventID +-- @return #EVENT +function EVENT:OnEventGeneric( EventFunction, EventClass, EventID ) + self:F2( { EventID } ) + + local EventData = self:Init( EventID, EventClass ) + EventData.EventFunction = EventFunction + EventData.EventClass = EventClass + + return self +end + + +--- Set a new listener for an S_EVENT_X event for a UNIT. +-- @param #EVENT self +-- @param #string UnitName The name of the UNIT. +-- @param #function EventFunction The function to be called when the event occurs for the GROUP. +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. +-- @param EventID +-- @return #EVENT +function EVENT:OnEventForUnit( UnitName, EventFunction, EventClass, EventID ) + self:F2( UnitName ) + + local EventData = self:Init( EventID, EventClass ) + if not EventData.EventUnit then + EventData.EventUnit = {} + end + EventData.EventUnit[UnitName] = {} + EventData.EventUnit[UnitName].EventFunction = EventFunction + EventData.EventUnit[UnitName].EventClass = EventClass + return self +end + +--- Set a new listener for an S_EVENT_X event for a GROUP. +-- @param #EVENT self +-- @param #string GroupName The name of the GROUP. +-- @param #function EventFunction The function to be called when the event occurs for the GROUP. +-- @param Core.Base#BASE EventClass The self instance of the class for which the event is. +-- @param EventID +-- @return #EVENT +function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID ) + self:F2( GroupName ) + + local Event = self:Init( EventID, EventClass ) + if not Event.EventGroup then + Event.EventGroup = {} + end + Event.EventGroup[GroupName] = {} + Event.EventGroup[GroupName].EventFunction = EventFunction + Event.EventGroup[GroupName].EventClass = EventClass + return self +end + +do -- OnBirth + + --- Create an OnBirth event handler for a group + -- @param #EVENT self + -- @param Wrapper.Group#GROUP EventGroup + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Birth ) + + return self + end + +end + +do -- OnCrash + + --- Create an OnCrash event handler for a group + -- @param #EVENT self + -- @param Wrapper.Group#GROUP EventGroup + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Crash ) + + return self + end + +end + +do -- OnDead + + --- Create an OnDead event handler for a group + -- @param #EVENT self + -- @param Wrapper.Group#GROUP EventGroup + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Dead ) + + return self + end + +end + + +do -- OnLand + --- Create an OnLand event handler for a group + -- @param #EVENT self + -- @param #table EventTemplate + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Land ) + + return self + end + +end + +do -- OnTakeOff + --- Create an OnTakeOff event handler for a group + -- @param #EVENT self + -- @param #table EventTemplate + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Takeoff ) + + return self + end + +end + +do -- OnEngineShutDown + + --- Create an OnDead event handler for a group + -- @param #EVENT self + -- @param #table EventTemplate + -- @param #function EventFunction The function to be called when the event occurs for the unit. + -- @param EventClass The self instance of the class for which the event is. + -- @return #EVENT + function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventClass ) + self:F2( EventTemplate.name ) + + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.EngineShutdown ) + + return self + end + +end + + +--- @param #EVENT self +-- @param #EVENTDATA Event +function EVENT:onEvent( Event ) + + local ErrorHandler = function( errmsg ) + + env.info( "Error in SCHEDULER function:" .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + + return errmsg + end + + self:E( _EVENTMETA[Event.id].Text, Event ) + + if self and self.Events and self.Events[Event.id] then + + + if Event.initiator then + + Event.IniObjectCategory = Event.initiator:getCategory() + + if Event.IniObjectCategory == Object.Category.UNIT then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniDCSGroup = Event.IniDCSUnit:getGroup() + Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName ) + if not Event.IniUnit then + -- Unit can be a CLIENT. Most likely this will be the case ... + Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true ) + end + Event.IniDCSGroupName = "" + if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then + Event.IniDCSGroupName = Event.IniDCSGroup:getName() + Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) + if Event.IniGroup then + Event.IniGroupName = Event.IniDCSGroupName + end + end + Event.IniPlayerName = Event.IniDCSUnit:getPlayerName() + Event.IniCoalition = Event.IniDCSUnit:getCoalition() + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + Event.IniCategory = Event.IniDCSUnit:getDesc().category + end + + if Event.IniObjectCategory == Object.Category.STATIC then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniUnit = STATIC:FindByName( Event.IniDCSUnitName, false ) + Event.IniCoalition = Event.IniDCSUnit:getCoalition() + Event.IniCategory = Event.IniDCSUnit:getDesc().category + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + end + + if Event.IniObjectCategory == Object.Category.SCENERY then + Event.IniDCSUnit = Event.initiator + Event.IniDCSUnitName = Event.IniDCSUnit:getName() + Event.IniUnitName = Event.IniDCSUnitName + Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator ) + Event.IniCategory = Event.IniDCSUnit:getDesc().category + Event.IniTypeName = Event.IniDCSUnit:getTypeName() + end + end + + if Event.target then + + Event.TgtObjectCategory = Event.target:getCategory() + + if Event.TgtObjectCategory == Object.Category.UNIT then + Event.TgtDCSUnit = Event.target + Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup() + Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = UNIT:FindByName( Event.TgtDCSUnitName ) + Event.TgtDCSGroupName = "" + if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then + Event.TgtDCSGroupName = Event.TgtDCSGroup:getName() + Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName ) + if Event.TgtGroup then + Event.TgtGroupName = Event.TgtDCSGroupName + end + end + Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName() + Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end + + if Event.TgtObjectCategory == Object.Category.STATIC then + Event.TgtDCSUnit = Event.target + Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName ) + Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end + + if Event.TgtObjectCategory == Object.Category.SCENERY then + Event.TgtDCSUnit = Event.target + Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target ) + Event.TgtCategory = Event.TgtDCSUnit:getDesc().category + Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() + end + end + + if Event.weapon then + Event.Weapon = Event.weapon + Event.WeaponName = Event.Weapon:getTypeName() + Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit! + Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName() + Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition() + Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category + Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName() + --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() + end + + local PriorityOrder = _EVENTMETA[Event.id].Order + local PriorityBegin = PriorityOrder == -1 and 5 or 1 + local PriorityEnd = PriorityOrder == -1 and 1 or 5 + + if Event.IniObjectCategory ~= 3 then + self:E( { _EVENTMETA[Event.id].Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) + end + + for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do + + if self.Events[Event.id][EventPriority] then + + -- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. + for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do + + Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) + Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName ) + + -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. + if ( Event.IniDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.IniDCSUnitName] ) or + ( Event.TgtDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.TgtDCSUnitName] ) then + + if EventData.EventUnit[Event.IniDCSUnitName] then + + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventUnit[Event.IniDCSUnitName].EventFunction then + + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventData.EventUnit[Event.IniDCSUnitName].EventFunction( EventClass, Event ) + end, ErrorHandler ) + + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) + end, ErrorHandler ) + end + end + end + + if EventData.EventUnit[Event.TgtDCSUnitName] then + + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventUnit[Event.TgtDCSUnitName].EventFunction then + + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventData.EventUnit[Event.TgtDCSUnitName].EventFunction( EventClass, Event ) + end, ErrorHandler ) + + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) + end, ErrorHandler ) + end + end + end + + else + + -- If the EventData is for a GROUP, the call directly the EventClass EventFunction for the UNIT in that GROUP. + if ( Event.IniDCSUnitName and Event.IniDCSGroupName and Event.IniGroupName and EventData.EventGroup and EventData.EventGroup[Event.IniGroupName] ) or + ( Event.TgtDCSUnitName and Event.TgtDCSGroupName and Event.TgtGroupName and EventData.EventGroup and EventData.EventGroup[Event.TgtGroupName] ) then + + if EventData.EventGroup[Event.IniGroupName] then + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventGroup[Event.IniGroupName].EventFunction then + + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventData.EventGroup[Event.IniGroupName].EventFunction( EventClass, Event ) + end, ErrorHandler ) + + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) + end, ErrorHandler ) + end + end + end + + if EventData.EventGroup[Event.TgtGroupName] then + if EventData.EventGroup[Event.TgtGroupName].EventFunction then + + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventData.EventGroup[Event.TgtGroupName].EventFunction( EventClass, Event ) + end, ErrorHandler ) + + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) + end, ErrorHandler ) + end + end + end + + else + + -- If the EventData is not bound to a specific unit, then call the EventClass EventFunction. + -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. + if (Event.IniDCSUnit or Event.WeaponUNIT) and not EventData.EventUnit then + + if EventClass == EventData.EventClass then + + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventFunction then + + -- There is an EventFunction defined, so call the EventFunction. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + local Result, Value = xpcall( + function() + return EventData.EventFunction( EventClass, Event ) + end, ErrorHandler ) + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + local Result, Value = EventFunction( EventClass, Event ) + return Result, Value + end, ErrorHandler ) + end + end + end + end + end + end + end + end + end + else + self:E( { _EVENTMETA[Event.id].Text, Event } ) + end + + Event = nil +end + +--- The EVENTHANDLER structure +-- @type EVENTHANDLER +-- @extends Core.Base#BASE +EVENTHANDLER = { + ClassName = "EVENTHANDLER", + ClassID = 0, +} + +--- The EVENTHANDLER constructor +-- @param #EVENTHANDLER self +-- @return #EVENTHANDLER +function EVENTHANDLER:New() + self = BASE:Inherit( self, BASE:New() ) -- #EVENTHANDLER + return self +end +--- **Core** -- MENU_ classes model the definition of **hierarchical menu structures** and **commands for players** within a mission. +-- +-- === +-- +-- DCS Menus can be managed using the MENU classes. +-- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scanerios where you need to +-- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing +-- menus is not a easy feat if you have complex menu hierarchies defined. +-- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy. +-- On top, MOOSE implements **variable parameter** passing for command menus. +-- +-- There are basically two different MENU class types that you need to use: +-- +-- ### To manage **main menus**, the classes begin with **MENU_**: +-- +-- * @{Menu#MENU_MISSION}: Manages main menus for whole mission file. +-- * @{Menu#MENU_COALITION}: Manages main menus for whole coalition. +-- * @{Menu#MENU_GROUP}: Manages main menus for GROUPs. +-- * @{Menu#MENU_CLIENT}: Manages main menus for CLIENTs. This manages menus for units with the skill level "Client". +-- +-- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**: +-- +-- * @{Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. +-- * @{Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. +-- * @{Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. +-- * @{Menu#MENU_CLIENT_COMMAND}: Manages command menus for CLIENTs. This manages menus for units with the skill level "Client". +-- +-- === +-- +-- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these): +-- +-- 1) MENU_ BASE abstract base classes (don't use them) +-- ==================================================== +-- The underlying base menu classes are **NOT** to be used within your missions. +-- These are simply abstract base classes defining a couple of fields that are used by the +-- derived MENU_ classes to manage menus. +-- +-- 1.1) @{#MENU_BASE} class, extends @{Base#BASE} +-- -------------------------------------------------- +-- The @{#MENU_BASE} class defines the main MENU class where other MENU classes are derived from. +-- +-- 1.2) @{#MENU_COMMAND_BASE} class, extends @{Base#BASE} +-- ---------------------------------------------------------- +-- The @{#MENU_COMMAND_BASE} class defines the main MENU class where other MENU COMMAND_ classes are derived from, in order to set commands. +-- +-- === +-- +-- **The next menus define the MENU classes that you can use within your missions.** +-- +-- 2) MENU MISSION classes +-- ====================== +-- The underlying classes manage the menus for a complete mission file. +-- +-- 2.1) @{#MENU_MISSION} class, extends @{Menu#MENU_BASE} +-- --------------------------------------------------------- +-- The @{Menu#MENU_MISSION} class manages the main menus for a complete mission. +-- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. +-- +-- 2.2) @{#MENU_MISSION_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE} +-- ------------------------------------------------------------------------- +-- The @{Menu#MENU_MISSION_COMMAND} class manages the command menus for a complete mission, which allow players to execute functions during mission execution. +-- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. +-- +-- === +-- +-- 3) MENU COALITION classes +-- ========================= +-- The underlying classes manage the menus for whole coalitions. +-- +-- 3.1) @{#MENU_COALITION} class, extends @{Menu#MENU_BASE} +-- ------------------------------------------------------------ +-- The @{Menu#MENU_COALITION} class manages the main menus for coalitions. +-- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. +-- +-- 3.2) @{Menu#MENU_COALITION_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE} +-- ---------------------------------------------------------------------------- +-- The @{Menu#MENU_COALITION_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. +-- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. +-- +-- === +-- +-- 4) MENU GROUP classes +-- ===================== +-- The underlying classes manage the menus for groups. Note that groups can be inactive, alive or can be destroyed. +-- +-- 4.1) @{Menu#MENU_GROUP} class, extends @{Menu#MENU_BASE} +-- -------------------------------------------------------- +-- The @{Menu#MENU_GROUP} class manages the main menus for coalitions. +-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. +-- +-- 4.2) @{Menu#MENU_GROUP_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE} +-- ------------------------------------------------------------------------ +-- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. +-- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. +-- +-- === +-- +-- 5) MENU CLIENT classes +-- ====================== +-- The underlying classes manage the menus for units with skill level client or player. +-- +-- 5.1) @{Menu#MENU_CLIENT} class, extends @{Menu#MENU_BASE} +-- --------------------------------------------------------- +-- The @{Menu#MENU_CLIENT} class manages the main menus for coalitions. +-- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}. +-- +-- 5.2) @{Menu#MENU_CLIENT_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE} +-- ------------------------------------------------------------------------- +-- The @{Menu#MENU_CLIENT_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. +-- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_COMMAND object and returns you the object reference. +-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT_COMMAND.Remove}. +-- +-- === +-- +-- ### Contributions: - +-- ### Authors: FlightControl : Design & Programming +-- +-- @module Menu + + +do -- MENU_BASE + + --- The MENU_BASE class + -- @type MENU_BASE + -- @extends Base#BASE + MENU_BASE = { + ClassName = "MENU_BASE", + MenuPath = nil, + MenuText = "", + MenuParentPath = nil + } + + --- Consructor + -- @param #MENU_BASE + -- @return #MENU_BASE + function MENU_BASE:New( MenuText, ParentMenu ) + + local MenuParentPath = {} + if ParentMenu ~= nil then + MenuParentPath = ParentMenu.MenuPath + end + + local self = BASE:Inherit( self, BASE:New() ) + + self.MenuPath = nil + self.MenuText = MenuText + self.MenuParentPath = MenuParentPath + self.Menus = {} + self.MenuCount = 0 + self.MenuRemoveParent = false + self.MenuTime = timer.getTime() + + return self + end + + --- Gets a @{Menu} from a parent @{Menu} + -- @param #MENU_BASE self + -- @param #string MenuText The text of the child menu. + -- @return #MENU_BASE + function MENU_BASE:GetMenu( MenuText ) + self:F( { self.Menus, MenuText } ) + return self.Menus[MenuText] + end + + --- Sets a @{Menu} to remove automatically the parent menu when the menu removed is the last child menu of that parent @{Menu}. + -- @param #MENU_BASE self + -- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}. + -- @return #MENU_BASE + function MENU_BASE:SetRemoveParent( RemoveParent ) + self:F( { RemoveParent } ) + self.MenuRemoveParent = RemoveParent + return self + end + + + --- Sets a time stamp for later prevention of menu removal. + -- @param #MENU_BASE self + -- @param MenuTime + -- @return #MENU_BASE + function MENU_BASE:SetTime( MenuTime ) + self.MenuTime = MenuTime + return self + end + +end + +do -- MENU_COMMAND_BASE + + --- The MENU_COMMAND_BASE class + -- @type MENU_COMMAND_BASE + -- @field #function MenuCallHandler + -- @extends Core.Menu#MENU_BASE + MENU_COMMAND_BASE = { + ClassName = "MENU_COMMAND_BASE", + CommandMenuFunction = nil, + CommandMenuArgument = nil, + MenuCallHandler = nil, + } + + --- Constructor + -- @param #MENU_COMMAND_BASE + -- @return #MENU_COMMAND_BASE + function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) + + local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) + + self.CommandMenuFunction = CommandMenuFunction + self.MenuCallHandler = function( CommandMenuArguments ) + self.CommandMenuFunction( unpack( CommandMenuArguments ) ) + end + + return self + end + +end + + +do -- MENU_MISSION + + --- The MENU_MISSION class + -- @type MENU_MISSION + -- @extends Core.Menu#MENU_BASE + MENU_MISSION = { + ClassName = "MENU_MISSION" + } + + --- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file. + -- @param #MENU_MISSION self + -- @param #string MenuText The text for the menu. + -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). + -- @return #MENU_MISSION + function MENU_MISSION:New( MenuText, ParentMenu ) + + local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) + + self:F( { MenuText, ParentMenu } ) + + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self.Menus = {} + + self:T( { MenuText } ) + + self.MenuPath = missionCommands.addSubMenu( MenuText, self.MenuParentPath ) + + self:T( { self.MenuPath } ) + + if ParentMenu and ParentMenu.Menus then + ParentMenu.Menus[self.MenuPath] = self + end + + return self + end + + --- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept! + -- @param #MENU_MISSION self + -- @return #MENU_MISSION + function MENU_MISSION:RemoveSubMenus() + self:F( self.MenuPath ) + + for MenuID, Menu in pairs( self.Menus ) do + Menu:Remove() + end + + end + + --- Removes the main menu and the sub menus recursively of this MENU_MISSION. + -- @param #MENU_MISSION self + -- @return #nil + function MENU_MISSION:Remove() + self:F( self.MenuPath ) + + self:RemoveSubMenus() + missionCommands.removeItem( self.MenuPath ) + if self.ParentMenu then + self.ParentMenu.Menus[self.MenuPath] = nil + end + + return nil + end + +end + +do -- MENU_MISSION_COMMAND + + --- The MENU_MISSION_COMMAND class + -- @type MENU_MISSION_COMMAND + -- @extends Core.Menu#MENU_COMMAND_BASE + MENU_MISSION_COMMAND = { + ClassName = "MENU_MISSION_COMMAND" + } + + --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. + -- @param #MENU_MISSION_COMMAND self + -- @param #string MenuText The text for the menu. + -- @param Menu#MENU_MISSION ParentMenu The parent menu. + -- @param CommandMenuFunction A function that is called when the menu key is pressed. + -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. + -- @return #MENU_MISSION_COMMAND self + function MENU_MISSION_COMMAND:New( MenuText, ParentMenu, CommandMenuFunction, ... ) + + local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) + + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self:T( { MenuText, CommandMenuFunction, arg } ) + + + self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) + + ParentMenu.Menus[self.MenuPath] = self + + return self + end + + --- Removes a radio command item for a coalition + -- @param #MENU_MISSION_COMMAND self + -- @return #nil + function MENU_MISSION_COMMAND:Remove() + self:F( self.MenuPath ) + + missionCommands.removeItem( self.MenuPath ) + if self.ParentMenu then + self.ParentMenu.Menus[self.MenuPath] = nil + end + return nil + end + +end + + + +do -- MENU_COALITION + + --- The MENU_COALITION class + -- @type MENU_COALITION + -- @extends Core.Menu#MENU_BASE + -- @usage + -- -- This demo creates a menu structure for the planes within the red coalition. + -- -- To test, join the planes, then look at the other radio menus (Option F10). + -- -- Then switch planes and check if the menu is still there. + -- + -- local Plane1 = CLIENT:FindByName( "Plane 1" ) + -- local Plane2 = CLIENT:FindByName( "Plane 2" ) + -- + -- + -- -- This would create a menu for the red coalition under the main DCS "Others" menu. + -- local MenuCoalitionRed = MENU_COALITION:New( coalition.side.RED, "Manage Menus" ) + -- + -- + -- local function ShowStatus( StatusText, Coalition ) + -- + -- MESSAGE:New( Coalition, 15 ):ToRed() + -- Plane1:Message( StatusText, 15 ) + -- Plane2:Message( StatusText, 15 ) + -- end + -- + -- local MenuStatus -- Menu#MENU_COALITION + -- local MenuStatusShow -- Menu#MENU_COALITION_COMMAND + -- + -- local function RemoveStatusMenu() + -- MenuStatus:Remove() + -- end + -- + -- local function AddStatusMenu() + -- + -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. + -- MenuStatus = MENU_COALITION:New( coalition.side.RED, "Status for Planes" ) + -- MenuStatusShow = MENU_COALITION_COMMAND:New( coalition.side.RED, "Show Status", MenuStatus, ShowStatus, "Status of planes is ok!", "Message to Red Coalition" ) + -- end + -- + -- local MenuAdd = MENU_COALITION_COMMAND:New( coalition.side.RED, "Add Status Menu", MenuCoalitionRed, AddStatusMenu ) + -- local MenuRemove = MENU_COALITION_COMMAND:New( coalition.side.RED, "Remove Status Menu", MenuCoalitionRed, RemoveStatusMenu ) + MENU_COALITION = { + ClassName = "MENU_COALITION" + } + + --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. + -- @param #MENU_COALITION self + -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. + -- @param #string MenuText The text for the menu. + -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). + -- @return #MENU_COALITION self + function MENU_COALITION:New( Coalition, MenuText, ParentMenu ) + + local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) + + self:F( { Coalition, MenuText, ParentMenu } ) + + self.Coalition = Coalition + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self.Menus = {} + + self:T( { MenuText } ) + + self.MenuPath = missionCommands.addSubMenuForCoalition( Coalition, MenuText, self.MenuParentPath ) + + self:T( { self.MenuPath } ) + + if ParentMenu and ParentMenu.Menus then + ParentMenu.Menus[self.MenuPath] = self + end + + return self + end + + --- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept! + -- @param #MENU_COALITION self + -- @return #MENU_COALITION + function MENU_COALITION:RemoveSubMenus() + self:F( self.MenuPath ) + + for MenuID, Menu in pairs( self.Menus ) do + Menu:Remove() + end + + end + + --- Removes the main menu and the sub menus recursively of this MENU_COALITION. + -- @param #MENU_COALITION self + -- @return #nil + function MENU_COALITION:Remove() + self:F( self.MenuPath ) + + self:RemoveSubMenus() + missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) + if self.ParentMenu then + self.ParentMenu.Menus[self.MenuPath] = nil + end + + return nil + end + +end + +do -- MENU_COALITION_COMMAND + + --- The MENU_COALITION_COMMAND class + -- @type MENU_COALITION_COMMAND + -- @extends Core.Menu#MENU_COMMAND_BASE + MENU_COALITION_COMMAND = { + ClassName = "MENU_COALITION_COMMAND" + } + + --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. + -- @param #MENU_COALITION_COMMAND self + -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. + -- @param #string MenuText The text for the menu. + -- @param Menu#MENU_COALITION ParentMenu The parent menu. + -- @param CommandMenuFunction A function that is called when the menu key is pressed. + -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. + -- @return #MENU_COALITION_COMMAND + function MENU_COALITION_COMMAND:New( Coalition, MenuText, ParentMenu, CommandMenuFunction, ... ) + + local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) + + self.MenuCoalition = Coalition + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self:T( { MenuText, CommandMenuFunction, arg } ) + + + self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) + + ParentMenu.Menus[self.MenuPath] = self + + return self + end + + --- Removes a radio command item for a coalition + -- @param #MENU_COALITION_COMMAND self + -- @return #nil + function MENU_COALITION_COMMAND:Remove() + self:F( self.MenuPath ) + + missionCommands.removeItemForCoalition( self.MenuCoalition, self.MenuPath ) + if self.ParentMenu then + self.ParentMenu.Menus[self.MenuPath] = nil + end + return nil + end + +end + +do -- MENU_CLIENT + + -- This local variable is used to cache the menus registered under clients. + -- Menus don't dissapear when clients are destroyed and restarted. + -- So every menu for a client created must be tracked so that program logic accidentally does not create + -- the same menus twice during initialization logic. + -- These menu classes are handling this logic with this variable. + local _MENUCLIENTS = {} + + --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. + -- @type MENU_CLIENT + -- @extends Core.Menu#MENU_BASE + -- @usage + -- -- This demo creates a menu structure for the two clients of planes. + -- -- Each client will receive a different menu structure. + -- -- To test, join the planes, then look at the other radio menus (Option F10). + -- -- Then switch planes and check if the menu is still there. + -- -- And play with the Add and Remove menu options. + -- + -- -- Note that in multi player, this will only work after the DCS clients bug is solved. + -- + -- local function ShowStatus( PlaneClient, StatusText, Coalition ) + -- + -- MESSAGE:New( Coalition, 15 ):ToRed() + -- PlaneClient:Message( StatusText, 15 ) + -- end + -- + -- local MenuStatus = {} + -- + -- local function RemoveStatusMenu( MenuClient ) + -- local MenuClientName = MenuClient:GetName() + -- MenuStatus[MenuClientName]:Remove() + -- end + -- + -- --- @param Wrapper.Client#CLIENT MenuClient + -- local function AddStatusMenu( MenuClient ) + -- local MenuClientName = MenuClient:GetName() + -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. + -- MenuStatus[MenuClientName] = MENU_CLIENT:New( MenuClient, "Status for Planes" ) + -- MENU_CLIENT_COMMAND:New( MenuClient, "Show Status", MenuStatus[MenuClientName], ShowStatus, MenuClient, "Status of planes is ok!", "Message to Red Coalition" ) + -- end + -- + -- SCHEDULER:New( nil, + -- function() + -- local PlaneClient = CLIENT:FindByName( "Plane 1" ) + -- if PlaneClient and PlaneClient:IsAlive() then + -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) + -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneClient ) + -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneClient ) + -- end + -- end, {}, 10, 10 ) + -- + -- SCHEDULER:New( nil, + -- function() + -- local PlaneClient = CLIENT:FindByName( "Plane 2" ) + -- if PlaneClient and PlaneClient:IsAlive() then + -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) + -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneClient ) + -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneClient ) + -- end + -- end, {}, 10, 10 ) + MENU_CLIENT = { + ClassName = "MENU_CLIENT" + } + + --- MENU_CLIENT constructor. Creates a new radio menu item for a client. + -- @param #MENU_CLIENT self + -- @param Wrapper.Client#CLIENT Client The Client owning the menu. + -- @param #string MenuText The text for the menu. + -- @param #table ParentMenu The parent menu. + -- @return #MENU_CLIENT self + function MENU_CLIENT:New( Client, MenuText, ParentMenu ) + + -- Arrange meta tables + local MenuParentPath = {} + if ParentMenu ~= nil then + MenuParentPath = ParentMenu.MenuPath + end + + local self = BASE:Inherit( self, MENU_BASE:New( MenuText, MenuParentPath ) ) + self:F( { Client, MenuText, ParentMenu } ) + + self.MenuClient = Client + self.MenuClientGroupID = Client:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self.Menus = {} + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) + + local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText + if MenuPath[MenuPathID] then + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) + end + + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) + MenuPath[MenuPathID] = self.MenuPath + + self:T( { Client:GetClientGroupName(), self.MenuPath } ) + + if ParentMenu and ParentMenu.Menus then + ParentMenu.Menus[self.MenuPath] = self + end + return self + end + + --- Removes the sub menus recursively of this @{#MENU_CLIENT}. + -- @param #MENU_CLIENT self + -- @return #MENU_CLIENT self + function MENU_CLIENT:RemoveSubMenus() + self:F( self.MenuPath ) + + for MenuID, Menu in pairs( self.Menus ) do + Menu:Remove() + end + + end + + --- Removes the sub menus recursively of this MENU_CLIENT. + -- @param #MENU_CLIENT self + -- @return #nil + function MENU_CLIENT:Remove() + self:F( self.MenuPath ) + + self:RemoveSubMenus() + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then + MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil + end + + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) + self.ParentMenu.Menus[self.MenuPath] = nil + return nil + end + + + --- The MENU_CLIENT_COMMAND class + -- @type MENU_CLIENT_COMMAND + -- @extends Core.Menu#MENU_COMMAND + MENU_CLIENT_COMMAND = { + ClassName = "MENU_CLIENT_COMMAND" + } + + --- MENU_CLIENT_COMMAND constructor. Creates a new radio command item for a client, which can invoke a function with parameters. + -- @param #MENU_CLIENT_COMMAND self + -- @param Wrapper.Client#CLIENT Client The Client owning the menu. + -- @param #string MenuText The text for the menu. + -- @param #MENU_BASE ParentMenu The parent menu. + -- @param CommandMenuFunction A function that is called when the menu key is pressed. + -- @return Menu#MENU_CLIENT_COMMAND self + function MENU_CLIENT_COMMAND:New( Client, MenuText, ParentMenu, CommandMenuFunction, ... ) + + -- Arrange meta tables + + local MenuParentPath = {} + if ParentMenu ~= nil then + MenuParentPath = ParentMenu.MenuPath + end + + local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, MenuParentPath, CommandMenuFunction, arg ) ) -- Menu#MENU_CLIENT_COMMAND + + self.MenuClient = Client + self.MenuClientGroupID = Client:GetClientGroupID() + self.MenuParentPath = MenuParentPath + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, arg } ) + + local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText + if MenuPath[MenuPathID] then + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) + end + + self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler, arg ) + MenuPath[MenuPathID] = self.MenuPath + + if ParentMenu and ParentMenu.Menus then + ParentMenu.Menus[self.MenuPath] = self + end + + return self + end + + --- Removes a menu structure for a client. + -- @param #MENU_CLIENT_COMMAND self + -- @return #nil + function MENU_CLIENT_COMMAND:Remove() + self:F( self.MenuPath ) + + if not _MENUCLIENTS[self.MenuClientGroupID] then + _MENUCLIENTS[self.MenuClientGroupID] = {} + end + + local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] + + if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then + MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil + end + + missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) + self.ParentMenu.Menus[self.MenuPath] = nil + return nil + end +end + +--- MENU_GROUP + +do + -- This local variable is used to cache the menus registered under groups. + -- Menus don't dissapear when groups for players are destroyed and restarted. + -- So every menu for a client created must be tracked so that program logic accidentally does not create. + -- the same menus twice during initialization logic. + -- These menu classes are handling this logic with this variable. + local _MENUGROUPS = {} + + --- The MENU_GROUP class + -- @type MENU_GROUP + -- @extends Core.Menu#MENU_BASE + -- @usage + -- -- This demo creates a menu structure for the two groups of planes. + -- -- Each group will receive a different menu structure. + -- -- To test, join the planes, then look at the other radio menus (Option F10). + -- -- Then switch planes and check if the menu is still there. + -- -- And play with the Add and Remove menu options. + -- + -- -- Note that in multi player, this will only work after the DCS groups bug is solved. + -- + -- local function ShowStatus( PlaneGroup, StatusText, Coalition ) + -- + -- MESSAGE:New( Coalition, 15 ):ToRed() + -- PlaneGroup:Message( StatusText, 15 ) + -- end + -- + -- local MenuStatus = {} + -- + -- local function RemoveStatusMenu( MenuGroup ) + -- local MenuGroupName = MenuGroup:GetName() + -- MenuStatus[MenuGroupName]:Remove() + -- end + -- + -- --- @param Wrapper.Group#GROUP MenuGroup + -- local function AddStatusMenu( MenuGroup ) + -- local MenuGroupName = MenuGroup:GetName() + -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. + -- MenuStatus[MenuGroupName] = MENU_GROUP:New( MenuGroup, "Status for Planes" ) + -- MENU_GROUP_COMMAND:New( MenuGroup, "Show Status", MenuStatus[MenuGroupName], ShowStatus, MenuGroup, "Status of planes is ok!", "Message to Red Coalition" ) + -- end + -- + -- SCHEDULER:New( nil, + -- function() + -- local PlaneGroup = GROUP:FindByName( "Plane 1" ) + -- if PlaneGroup and PlaneGroup:IsAlive() then + -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) + -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneGroup ) + -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneGroup ) + -- end + -- end, {}, 10, 10 ) + -- + -- SCHEDULER:New( nil, + -- function() + -- local PlaneGroup = GROUP:FindByName( "Plane 2" ) + -- if PlaneGroup and PlaneGroup:IsAlive() then + -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) + -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneGroup ) + -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneGroup ) + -- end + -- end, {}, 10, 10 ) + -- + MENU_GROUP = { + ClassName = "MENU_GROUP" + } + + --- MENU_GROUP constructor. Creates a new radio menu item for a group. + -- @param #MENU_GROUP self + -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. + -- @param #string MenuText The text for the menu. + -- @param #table ParentMenu The parent menu. + -- @return #MENU_GROUP self + function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu ) + + -- Determine if the menu was not already created and already visible at the group. + -- If it is visible, then return the cached self, otherwise, create self and cache it. + + MenuGroup._Menus = MenuGroup._Menus or {} + local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText + if MenuGroup._Menus[Path] then + self = MenuGroup._Menus[Path] + else + self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) + MenuGroup._Menus[Path] = self + + self.MenuGroup = MenuGroup + self.Path = Path + self.MenuGroupID = MenuGroup:GetID() + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self:T( { "Adding Menu ", MenuText, self.MenuParentPath } ) + self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, self.MenuParentPath ) + + if self.ParentMenu and self.ParentMenu.Menus then + self.ParentMenu.Menus[MenuText] = self + self:F( { self.ParentMenu.Menus, MenuText } ) + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1 + end + end + + --self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) + + return self + end + + --- Removes the sub menus recursively of this MENU_GROUP. + -- @param #MENU_GROUP self + -- @param MenuTime + -- @return #MENU_GROUP self + function MENU_GROUP:RemoveSubMenus( MenuTime ) + self:F2( { self.MenuPath, MenuTime, self.MenuTime } ) + + self:T( { "Removing Group SubMenus:", self.MenuGroup:GetName(), self.MenuPath } ) + for MenuText, Menu in pairs( self.Menus ) do + Menu:Remove( MenuTime ) + end + + end + + + --- Removes the main menu and sub menus recursively of this MENU_GROUP. + -- @param #MENU_GROUP self + -- @param MenuTime + -- @return #nil + function MENU_GROUP:Remove( MenuTime ) + self:F( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } ) + + self:RemoveSubMenus( MenuTime ) + + if not MenuTime or self.MenuTime ~= MenuTime then + if self.MenuGroup._Menus[self.Path] then + self = self.MenuGroup._Menus[self.Path] + + missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) + if self.ParentMenu then + self.ParentMenu.Menus[self.MenuText] = nil + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1 + if self.ParentMenu.MenuCount == 0 then + if self.MenuRemoveParent == true then + self:T( "Removing Parent Menu " ) + self.ParentMenu:Remove() + end + end + end + self:T( { "Removing Group Menu:", self.MenuGroup:GetName(), self.MenuGroup._Menus[self.Path].Path } ) + self.MenuGroup._Menus[self.Path] = nil + self = nil + end + end + + return nil + end + + + --- The MENU_GROUP_COMMAND class + -- @type MENU_GROUP_COMMAND + -- @extends Core.Menu#MENU_BASE + MENU_GROUP_COMMAND = { + ClassName = "MENU_GROUP_COMMAND" + } + + --- Creates a new radio command item for a group + -- @param #MENU_GROUP_COMMAND self + -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. + -- @param MenuText The text for the menu. + -- @param ParentMenu The parent menu. + -- @param CommandMenuFunction A function that is called when the menu key is pressed. + -- @param CommandMenuArgument An argument for the function. + -- @return #MENU_GROUP_COMMAND + function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, ... ) + + MenuGroup._Menus = MenuGroup._Menus or {} + local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText + if MenuGroup._Menus[Path] then + self = MenuGroup._Menus[Path] + self:T( { "Re-using Group Command Menu:", MenuGroup:GetName(), MenuText } ) + else + self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) + MenuGroup._Menus[Path] = self + + self.Path = Path + self.MenuGroup = MenuGroup + self.MenuGroupID = MenuGroup:GetID() + self.MenuText = MenuText + self.ParentMenu = ParentMenu + + self:T( { "Adding Group Command Menu:", MenuGroup:GetName(), MenuText, self.MenuParentPath } ) + self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) + + if self.ParentMenu and self.ParentMenu.Menus then + self.ParentMenu.Menus[MenuText] = self + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1 + self:F( { ParentMenu.Menus, MenuText } ) + end + end + + return self + end + + --- Removes a menu structure for a group. + -- @param #MENU_GROUP_COMMAND self + -- @param MenuTime + -- @return #nil + function MENU_GROUP_COMMAND:Remove( MenuTime ) + self:F( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } ) + + if not MenuTime or self.MenuTime ~= MenuTime then + if self.MenuGroup._Menus[self.Path] then + self = self.MenuGroup._Menus[self.Path] + + missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) + self:T( { "Removing Group Command Menu:", self.MenuGroup:GetName(), self.MenuText, self.Path, self.MenuGroup._Menus[self.Path].Path } ) + + self.ParentMenu.Menus[self.MenuText] = nil + self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1 + if self.ParentMenu.MenuCount == 0 then + if self.MenuRemoveParent == true then + self:T( "Removing Parent Menu " ) + self.ParentMenu:Remove() + end + end + + self.MenuGroup._Menus[self.Path] = nil + self = nil + end + end + + return nil + end + +end + +--- **Core** - ZONE classes define **zones** within your mission of **various forms**, with **various capabilities**. +-- +-- ![Banner Image](..\Presentations\ZONE\Dia1.JPG) +-- +-- === +-- +-- There are essentially two core functions that zones accomodate: +-- +-- * Test if an object is within the zone boundaries. +-- * Provide the zone behaviour. Some zones are static, while others are moveable. +-- +-- The object classes are using the zone classes to test the zone boundaries, which can take various forms: +-- +-- * Test if completely within the zone. +-- * Test if partly within the zone (for @{Group#GROUP} objects). +-- * Test if not in the zone. +-- * Distance to the nearest intersecting point of the zone. +-- * Distance to the center of the zone. +-- * ... +-- +-- Each of these ZONE classes have a zone name, and specific parameters defining the zone type: +-- +-- * @{#ZONE_BASE}: The ZONE_BASE class defining the base for all other zone classes. +-- * @{#ZONE_RADIUS}: The ZONE_RADIUS class defined by a zone name, a location and a radius. +-- * @{#ZONE}: The ZONE class, defined by the zone name as defined within the Mission Editor. +-- * @{#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Unit#UNIT} with a radius. +-- * @{#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. +-- * @{#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-02-28: ZONE\_BASE:**IsVec2InZone()** replaces ZONE\_BASE:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_BASE:**IsVec3InZone()** replaces ZONE\_BASE:_IsPointVec3InZone()_. +-- 2017-02-28: ZONE\_RADIUS:**IsVec2InZone()** replaces ZONE\_RADIUS:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_RADIUS:**IsVec3InZone()** replaces ZONE\_RADIUS:_IsPointVec3InZone()_. +-- 2017-02-28: ZONE\_POLYGON:**IsVec2InZone()** replaces ZONE\_POLYGON:_IsPointVec2InZone()_. +-- 2017-02-28: ZONE\_POLYGON:**IsVec3InZone()** replaces ZONE\_POLYGON:_IsPointVec3InZone()_. +-- +-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec2()** added. +-- +-- 2017-02-18: ZONE\_POLYGON_BASE:**GetRandomPointVec3()** added. +-- +-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec3( inner, outer )** added. +-- +-- 2017-02-18: ZONE\_RADIUS:**GetRandomPointVec2( inner, outer )** added. +-- +-- 2016-08-15: ZONE\_BASE:**GetName()** added. +-- +-- 2016-08-15: ZONE\_BASE:**SetZoneProbability( ZoneProbability )** added. +-- +-- 2016-08-15: ZONE\_BASE:**GetZoneProbability()** added. +-- +-- 2016-08-15: ZONE\_BASE:**GetZoneMaybe()** added. +-- +-- === +-- +-- @module Zone + + +--- The ZONE_BASE class +-- @type ZONE_BASE +-- @field #string ZoneName Name of the zone. +-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. +-- @extends Core.Base#BASE + + +--- # 1) ZONE_BASE class, extends @{Base#BASE} +-- +-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. +-- +-- ## 1.1) Each zone has a name: +-- +-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone. +-- +-- ## 1.2) Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}: +-- +-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a Vec2 is within the zone. +-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a Vec3 is within the zone. +-- +-- ## 1.3) A zone has a probability factor that can be set to randomize a selection between zones: +-- +-- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% ) +-- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% ) +-- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate. +-- +-- ## 1.4) A zone manages Vectors: +-- +-- * @{#ZONE_BASE.GetVec2}(): Returns the @{DCSTypes#Vec2} coordinate of the zone. +-- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{DCSTypes#Vec2} within the zone. +-- +-- ## 1.5) A zone has a bounding square: +-- +-- * @{#ZONE_BASE.GetBoundingSquare}(): Get the outer most bounding square of the zone. +-- +-- ## 1.6) A zone can be marked: +-- +-- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color. +-- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color. +-- +-- === +-- @field #ZONE_BASE ZONE_BASE +ZONE_BASE = { + ClassName = "ZONE_BASE", + ZoneName = "", + ZoneProbability = 1, + } + + +--- The ZONE_BASE.BoundingSquare +-- @type ZONE_BASE.BoundingSquare +-- @field Dcs.DCSTypes#Distance x1 The lower x coordinate (left down) +-- @field Dcs.DCSTypes#Distance y1 The lower y coordinate (left down) +-- @field Dcs.DCSTypes#Distance x2 The higher x coordinate (right up) +-- @field Dcs.DCSTypes#Distance y2 The higher y coordinate (right up) + + +--- ZONE_BASE constructor +-- @param #ZONE_BASE self +-- @param #string ZoneName Name of the zone. +-- @return #ZONE_BASE self +function ZONE_BASE:New( ZoneName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( ZoneName ) + + self.ZoneName = ZoneName + + return self +end + +--- Returns the name of the zone. +-- @param #ZONE_BASE self +-- @return #string The name of the zone. +function ZONE_BASE:GetName() + self:F2() + + return self.ZoneName +end +--- Returns if a location is within the zone. +-- @param #ZONE_BASE self +-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. +-- @return #boolean true if the location is within the zone. +function ZONE_BASE:IsVec2InZone( Vec2 ) + self:F2( Vec2 ) + + return false +end + +--- Returns if a point is within the zone. +-- @param #ZONE_BASE self +-- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. +-- @return #boolean true if the point is within the zone. +function ZONE_BASE:IsVec3InZone( Vec3 ) + self:F2( Vec3 ) + + local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) + + return InZone +end + +--- Returns the @{DCSTypes#Vec2} coordinate of the zone. +-- @param #ZONE_BASE self +-- @return #nil. +function ZONE_BASE:GetVec2() + self:F2( self.ZoneName ) + + return nil +end + +--- Returns a @{Point#POINT_VEC2} of the zone. +-- @param #ZONE_BASE self +-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @return Core.Point#POINT_VEC2 The PointVec2 of the zone. +function ZONE_BASE:GetPointVec2() + self:F2( self.ZoneName ) + + local Vec2 = self:GetVec2() + + local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 ) + + self:T2( { PointVec2 } ) + + return PointVec2 +end + + +--- Returns the @{DCSTypes#Vec3} of the zone. +-- @param #ZONE_BASE self +-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @return Dcs.DCSTypes#Vec3 The Vec3 of the zone. +function ZONE_BASE:GetVec3( Height ) + self:F2( self.ZoneName ) + + Height = Height or 0 + + local Vec2 = self:GetVec2() + + local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } + + self:T2( { Vec3 } ) + + return Vec3 +end + +--- Returns a @{Point#POINT_VEC3} of the zone. +-- @param #ZONE_BASE self +-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @return Core.Point#POINT_VEC3 The PointVec3 of the zone. +function ZONE_BASE:GetPointVec3( Height ) + self:F2( self.ZoneName ) + + local Vec3 = self:GetVec3( Height ) + + local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) + + self:T2( { PointVec3 } ) + + return PointVec3 +end + + +--- Define a random @{DCSTypes#Vec2} within the zone. +-- @param #ZONE_BASE self +-- @return Dcs.DCSTypes#Vec2 The Vec2 coordinates. +function ZONE_BASE:GetRandomVec2() + return nil +end + +--- Define a random @{Point#POINT_VEC2} within the zone. +-- @param #ZONE_BASE self +-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates. +function ZONE_BASE:GetRandomPointVec2() + return nil +end + +--- Define a random @{Point#POINT_VEC3} within the zone. +-- @param #ZONE_BASE self +-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates. +function ZONE_BASE:GetRandomPointVec3() + return nil +end + +--- Get the bounding square the zone. +-- @param #ZONE_BASE self +-- @return #nil The bounding square. +function ZONE_BASE:GetBoundingSquare() + --return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } + return nil +end + +--- Bound the zone boundaries with a tires. +-- @param #ZONE_BASE self +function ZONE_BASE:BoundZone() + self:F2() + +end + +--- Smokes the zone boundaries in a color. +-- @param #ZONE_BASE self +-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. +function ZONE_BASE:SmokeZone( SmokeColor ) + self:F2( SmokeColor ) + +end + +--- Set the randomization probability of a zone to be selected. +-- @param #ZONE_BASE self +-- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. +function ZONE_BASE:SetZoneProbability( ZoneProbability ) + self:F2( ZoneProbability ) + + self.ZoneProbability = ZoneProbability or 1 + return self +end + +--- Get the randomization probability of a zone to be selected. +-- @param #ZONE_BASE self +-- @return #number A value between 0 and 1. 0 = 0% and 1 = 100% probability. +function ZONE_BASE:GetZoneProbability() + self:F2() + + return self.ZoneProbability +end + +--- Get the zone taking into account the randomization probability of a zone to be selected. +-- @param #ZONE_BASE self +-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor. +-- @return #nil The zone is not selected taking into account the randomization probability factor. +function ZONE_BASE:GetZoneMaybe() + self:F2() + + local Randomization = math.random() + if Randomization <= self.ZoneProbability then + return self + else + return nil + end +end + + +--- The ZONE_RADIUS class, defined by a zone name, a location and a radius. +-- @type ZONE_RADIUS +-- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone. +-- @field Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @extends Core.Zone#ZONE_BASE + +--- # 2) @{Zone#ZONE_RADIUS} class, extends @{Zone#ZONE_BASE} +-- +-- The ZONE_RADIUS class defined by a zone name, a location and a radius. +-- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties. +-- +-- ## 2.1) @{Zone#ZONE_RADIUS} constructor +-- +-- * @{#ZONE_RADIUS.New}(): Constructor. +-- +-- ## 2.2) Manage the radius of the zone +-- +-- * @{#ZONE_RADIUS.SetRadius}(): Sets the radius of the zone. +-- * @{#ZONE_RADIUS.GetRadius}(): Returns the radius of the zone. +-- +-- ## 2.3) Manage the location of the zone +-- +-- * @{#ZONE_RADIUS.SetVec2}(): Sets the @{DCSTypes#Vec2} of the zone. +-- * @{#ZONE_RADIUS.GetVec2}(): Returns the @{DCSTypes#Vec2} of the zone. +-- * @{#ZONE_RADIUS.GetVec3}(): Returns the @{DCSTypes#Vec3} of the zone, taking an additional height parameter. +-- +-- ## 2.4) Zone point randomization +-- +-- Various functions exist to find random points within the zone. +-- +-- * @{#ZONE_RADIUS.GetRandomVec2}(): Gets a random 2D point in the zone. +-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Point#POINT_VEC2} object representing a random 2D point in the zone. +-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight. +-- +-- === +-- +-- @field #ZONE_RADIUS ZONE_RADIUS +-- +ZONE_RADIUS = { + ClassName="ZONE_RADIUS", + } + +--- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius. +-- @param #ZONE_RADIUS self +-- @param #string ZoneName Name of the zone. +-- @param Dcs.DCSTypes#Vec2 Vec2 The location of the zone. +-- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @return #ZONE_RADIUS self +function ZONE_RADIUS:New( ZoneName, Vec2, Radius ) + local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) -- #ZONE_RADIUS + self:F( { ZoneName, Vec2, Radius } ) + + self.Radius = Radius + self.Vec2 = Vec2 + + return self +end + +--- Bounds the zone with tires. +-- @param #ZONE_RADIUS self +-- @param #number Points (optional) The amount of points in the circle. +-- @param #boolean UnBound If true the tyres will be destroyed. +-- @return #ZONE_RADIUS self +function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound ) + + local Point = {} + local Vec2 = self:GetVec2() + + Points = Points and Points or 360 + + local Angle + local RadialBase = math.pi*2 + + -- + for Angle = 0, 360, (360 / Points ) do + local Radial = Angle * RadialBase / 360 + Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() + Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() + + local CountryName = _DATABASE.COUNTRY_NAME[CountryID] + + local Tire = { + ["country"] = CountryName, + ["category"] = "Fortifications", + ["canCargo"] = false, + ["shape_name"] = "H-tyre_B_WF", + ["type"] = "Black_Tyre_WF", + --["unitId"] = Angle + 10000, + ["y"] = Point.y, + ["x"] = Point.x, + ["name"] = string.format( "%s-Tire #%0d", self:GetName(), Angle ), + ["heading"] = 0, + } -- end of ["group"] + + local Group = coalition.addStaticObject( CountryID, Tire ) + if UnBound and UnBound == true then + Group:destroy() + end + end + + return self +end + + +--- Smokes the zone boundaries in a color. +-- @param #ZONE_RADIUS self +-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. +-- @param #number Points (optional) The amount of points in the circle. +-- @return #ZONE_RADIUS self +function ZONE_RADIUS:SmokeZone( SmokeColor, Points ) + self:F2( SmokeColor ) + + local Point = {} + local Vec2 = self:GetVec2() + + Points = Points and Points or 360 + + local Angle + local RadialBase = math.pi*2 + + for Angle = 0, 360, 360 / Points do + local Radial = Angle * RadialBase / 360 + Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() + Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() + POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor ) + end + + return self +end + + +--- Flares the zone boundaries in a color. +-- @param #ZONE_RADIUS self +-- @param Utilities.Utils#FLARECOLOR FlareColor The flare color. +-- @param #number Points (optional) The amount of points in the circle. +-- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. +-- @return #ZONE_RADIUS self +function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth ) + self:F2( { FlareColor, Azimuth } ) + + local Point = {} + local Vec2 = self:GetVec2() + + Points = Points and Points or 360 + + local Angle + local RadialBase = math.pi*2 + + for Angle = 0, 360, 360 / Points do + local Radial = Angle * RadialBase / 360 + Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() + Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() + POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth ) + end + + return self +end + +--- Returns the radius of the zone. +-- @param #ZONE_RADIUS self +-- @return Dcs.DCSTypes#Distance The radius of the zone. +function ZONE_RADIUS:GetRadius() + self:F2( self.ZoneName ) + + self:T2( { self.Radius } ) + + return self.Radius +end + +--- Sets the radius of the zone. +-- @param #ZONE_RADIUS self +-- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @return Dcs.DCSTypes#Distance The radius of the zone. +function ZONE_RADIUS:SetRadius( Radius ) + self:F2( self.ZoneName ) + + self.Radius = Radius + self:T2( { self.Radius } ) + + return self.Radius +end + +--- Returns the @{DCSTypes#Vec2} of the zone. +-- @param #ZONE_RADIUS self +-- @return Dcs.DCSTypes#Vec2 The location of the zone. +function ZONE_RADIUS:GetVec2() + self:F2( self.ZoneName ) + + self:T2( { self.Vec2 } ) + + return self.Vec2 +end + +--- Sets the @{DCSTypes#Vec2} of the zone. +-- @param #ZONE_RADIUS self +-- @param Dcs.DCSTypes#Vec2 Vec2 The new location of the zone. +-- @return Dcs.DCSTypes#Vec2 The new location of the zone. +function ZONE_RADIUS:SetVec2( Vec2 ) + self:F2( self.ZoneName ) + + self.Vec2 = Vec2 + + self:T2( { self.Vec2 } ) + + return self.Vec2 +end + +--- Returns the @{DCSTypes#Vec3} of the ZONE_RADIUS. +-- @param #ZONE_RADIUS self +-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @return Dcs.DCSTypes#Vec3 The point of the zone. +function ZONE_RADIUS:GetVec3( Height ) + self:F2( { self.ZoneName, Height } ) + + Height = Height or 0 + local Vec2 = self:GetVec2() + + local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } + + self:T2( { Vec3 } ) + + return Vec3 +end + + +--- Returns if a location is within the zone. +-- @param #ZONE_RADIUS self +-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. +-- @return #boolean true if the location is within the zone. +function ZONE_RADIUS:IsVec2InZone( Vec2 ) + self:F2( Vec2 ) + + local ZoneVec2 = self:GetVec2() + + if ZoneVec2 then + if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then + return true + end + end + + return false +end + +--- Returns if a point is within the zone. +-- @param #ZONE_RADIUS self +-- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. +-- @return #boolean true if the point is within the zone. +function ZONE_RADIUS:IsVec3InZone( Vec3 ) + self:F2( Vec3 ) + + local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } ) + + return InZone +end + +--- Returns a random Vec2 location within the zone. +-- @param #ZONE_RADIUS self +-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. +-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. +-- @return Dcs.DCSTypes#Vec2 The random location within the zone. +function ZONE_RADIUS:GetRandomVec2( inner, outer ) + self:F( self.ZoneName, inner, outer ) + + local Point = {} + local Vec2 = self:GetVec2() + local _inner = inner or 0 + local _outer = outer or self:GetRadius() + + local angle = math.random() * math.pi * 2; + Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer); + Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer); + + self:T( { Point } ) + + return Point +end + +--- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone. +-- @param #ZONE_RADIUS self +-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. +-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. +-- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone. +function ZONE_RADIUS:GetRandomPointVec2( inner, outer ) + self:F( self.ZoneName, inner, outer ) + + local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() ) + + self:T3( { PointVec2 } ) + + return PointVec2 +end + +--- Returns a @{Point#POINT_VEC3} object reflecting a random 3D location within the zone. +-- @param #ZONE_RADIUS self +-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0. +-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. +-- @return Core.Point#POINT_VEC3 The @{Point#POINT_VEC3} object reflecting the random 3D location within the zone. +function ZONE_RADIUS:GetRandomPointVec3( inner, outer ) + self:F( self.ZoneName, inner, outer ) + + local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() ) + + self:T3( { PointVec3 } ) + + return PointVec3 +end + + + +-- @type ZONE +-- @extends Core.Zone#ZONE_RADIUS + + +--- # 3) ZONE class, extends @{Zone#ZONE_RADIUS} +-- +-- The ZONE class, defined by the zone name as defined within the Mission Editor. +-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. +-- +-- === +-- +-- @field #ZONE ZONE +-- +ZONE = { + ClassName="ZONE", + } + + +--- Constructor of ZONE, taking the zone name. +-- @param #ZONE self +-- @param #string ZoneName The name of the zone as defined within the mission editor. +-- @return #ZONE +function ZONE:New( ZoneName ) + + local Zone = trigger.misc.getZone( ZoneName ) + + if not Zone then + error( "Zone " .. ZoneName .. " does not exist." ) + return nil + end + + local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, { x = Zone.point.x, y = Zone.point.z }, Zone.radius ) ) + self:F( ZoneName ) + + self.Zone = Zone + + return self +end + + +--- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. +-- @type ZONE_UNIT +-- @field Wrapper.Unit#UNIT ZoneUNIT +-- @extends Core.Zone#ZONE_RADIUS + +--- # 4) #ZONE_UNIT class, extends @{Zone#ZONE_RADIUS} +-- +-- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius. +-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties. +-- +-- === +-- +-- @field #ZONE_UNIT ZONE_UNIT +-- +ZONE_UNIT = { + ClassName="ZONE_UNIT", + } + +--- Constructor to create a ZONE_UNIT instance, taking the zone name, a zone unit and a radius. +-- @param #ZONE_UNIT self +-- @param #string ZoneName Name of the zone. +-- @param Wrapper.Unit#UNIT ZoneUNIT The unit as the center of the zone. +-- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @return #ZONE_UNIT self +function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) + local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) ) + self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } ) + + self.ZoneUNIT = ZoneUNIT + self.LastVec2 = ZoneUNIT:GetVec2() + + return self +end + + +--- Returns the current location of the @{Unit#UNIT}. +-- @param #ZONE_UNIT self +-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Unit#UNIT}location. +function ZONE_UNIT:GetVec2() + self:F( self.ZoneName ) + + local ZoneVec2 = self.ZoneUNIT:GetVec2() + if ZoneVec2 then + self.LastVec2 = ZoneVec2 + return ZoneVec2 + else + return self.LastVec2 + end + + self:T( { ZoneVec2 } ) + + return nil +end + +--- Returns a random location within the zone. +-- @param #ZONE_UNIT self +-- @return Dcs.DCSTypes#Vec2 The random location within the zone. +function ZONE_UNIT:GetRandomVec2() + self:F( self.ZoneName ) + + local RandomVec2 = {} + local Vec2 = self.ZoneUNIT:GetVec2() + + if not Vec2 then + Vec2 = self.LastVec2 + end + + local angle = math.random() * math.pi*2; + RandomVec2.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); + RandomVec2.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); + + self:T( { RandomVec2 } ) + + return RandomVec2 +end + +--- Returns the @{DCSTypes#Vec3} of the ZONE_UNIT. +-- @param #ZONE_UNIT self +-- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. +-- @return Dcs.DCSTypes#Vec3 The point of the zone. +function ZONE_UNIT:GetVec3( Height ) + self:F2( self.ZoneName ) + + Height = Height or 0 + + local Vec2 = self:GetVec2() + + local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } + + self:T2( { Vec3 } ) + + return Vec3 +end + +--- @type ZONE_GROUP +-- @field Wrapper.Group#GROUP ZoneGROUP +-- @extends Core.Zone#ZONE_RADIUS + + +--- # 5) #ZONE_GROUP class, extends @{Zone#ZONE_RADIUS} +-- +-- The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. The current leader of the group defines the center of the zone. +-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- +-- === +-- +-- @field #ZONE_GROUP ZONE_GROUP +-- +ZONE_GROUP = { + ClassName="ZONE_GROUP", + } + +--- Constructor to create a ZONE_GROUP instance, taking the zone name, a zone @{Group#GROUP} and a radius. +-- @param #ZONE_GROUP self +-- @param #string ZoneName Name of the zone. +-- @param Wrapper.Group#GROUP ZoneGROUP The @{Group} as the center of the zone. +-- @param Dcs.DCSTypes#Distance Radius The radius of the zone. +-- @return #ZONE_GROUP self +function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) + local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) ) + self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } ) + + self.ZoneGROUP = ZoneGROUP + + return self +end + + +--- Returns the current location of the @{Group}. +-- @param #ZONE_GROUP self +-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location. +function ZONE_GROUP:GetVec2() + self:F( self.ZoneName ) + + local ZoneVec2 = self.ZoneGROUP:GetVec2() + + self:T( { ZoneVec2 } ) + + return ZoneVec2 +end + +--- Returns a random location within the zone of the @{Group}. +-- @param #ZONE_GROUP self +-- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Group} location. +function ZONE_GROUP:GetRandomVec2() + self:F( self.ZoneName ) + + local Point = {} + local Vec2 = self.ZoneGROUP:GetVec2() + + local angle = math.random() * math.pi*2; + Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); + Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); + + self:T( { Point } ) + + return Point +end + + + +--- @type ZONE_POLYGON_BASE +-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}. +-- @extends Core.Zone#ZONE_BASE + + +--- # 6) ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE} +-- +-- The ZONE_POLYGON_BASE class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. +-- +-- ## 6.1) Zone point randomization +-- +-- Various functions exist to find random points within the zone. +-- +-- * @{#ZONE_POLYGON_BASE.GetRandomVec2}(): Gets a random 2D point in the zone. +-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Point#POINT_VEC2} object representing a random 2D point within the zone. +-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. +-- +-- === +-- +-- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE +-- +ZONE_POLYGON_BASE = { + ClassName="ZONE_POLYGON_BASE", + } + +--- A points array. +-- @type ZONE_POLYGON_BASE.ListVec2 +-- @list + +--- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{DCSTypes#Vec2}, forming a polygon. +-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. +-- @param #ZONE_POLYGON_BASE self +-- @param #string ZoneName Name of the zone. +-- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{DCSTypes#Vec2}, forming a polygon.. +-- @return #ZONE_POLYGON_BASE self +function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) + local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) + self:F( { ZoneName, PointsArray } ) + + local i = 0 + + self.Polygon = {} + + for i = 1, #PointsArray do + self.Polygon[i] = {} + self.Polygon[i].x = PointsArray[i].x + self.Polygon[i].y = PointsArray[i].y + end + + return self +end + +--- Flush polygon coordinates as a table in DCS.log. +-- @param #ZONE_POLYGON_BASE self +-- @return #ZONE_POLYGON_BASE self +function ZONE_POLYGON_BASE:Flush() + self:F2() + + self:E( { Polygon = self.ZoneName, Coordinates = self.Polygon } ) + + return self +end + +--- Smokes the zone boundaries in a color. +-- @param #ZONE_POLYGON_BASE self +-- @param #boolean UnBound If true, the tyres will be destroyed. +-- @return #ZONE_POLYGON_BASE self +function ZONE_POLYGON_BASE:BoundZone( UnBound ) + + local i + local j + local Segments = 10 + + i = 1 + j = #self.Polygon + + while i <= #self.Polygon do + self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) + + local DeltaX = self.Polygon[j].x - self.Polygon[i].x + local DeltaY = self.Polygon[j].y - self.Polygon[i].y + + for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. + local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) + local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) + local Tire = { + ["country"] = "USA", + ["category"] = "Fortifications", + ["canCargo"] = false, + ["shape_name"] = "H-tyre_B_WF", + ["type"] = "Black_Tyre_WF", + ["y"] = PointY, + ["x"] = PointX, + ["name"] = string.format( "%s-Tire #%0d", self:GetName(), ((i - 1) * Segments) + Segment ), + ["heading"] = 0, + } -- end of ["group"] + + local Group = coalition.addStaticObject( country.id.USA, Tire ) + if UnBound and UnBound == true then + Group:destroy() + end + + end + j = i + i = i + 1 + end + + return self +end + + + +--- Smokes the zone boundaries in a color. +-- @param #ZONE_POLYGON_BASE self +-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. +-- @return #ZONE_POLYGON_BASE self +function ZONE_POLYGON_BASE:SmokeZone( SmokeColor ) + self:F2( SmokeColor ) + + local i + local j + local Segments = 10 + + i = 1 + j = #self.Polygon + + while i <= #self.Polygon do + self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) + + local DeltaX = self.Polygon[j].x - self.Polygon[i].x + local DeltaY = self.Polygon[j].y - self.Polygon[i].y + + for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. + local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) + local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) + POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor ) + end + j = i + i = i + 1 + end + + return self +end + + + + +--- Returns if a location is within the zone. +-- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html +-- @param #ZONE_POLYGON_BASE self +-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. +-- @return #boolean true if the location is within the zone. +function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 ) + self:F2( Vec2 ) + + local Next + local Prev + local InPolygon = false + + Next = 1 + Prev = #self.Polygon + + while Next <= #self.Polygon do + self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) + if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and + ( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) + ) then + InPolygon = not InPolygon + end + self:T2( { InPolygon = InPolygon } ) + Prev = Next + Next = Next + 1 + end + + self:T( { InPolygon = InPolygon } ) + return InPolygon +end + +--- Define a random @{DCSTypes#Vec2} within the zone. +-- @param #ZONE_POLYGON_BASE self +-- @return Dcs.DCSTypes#Vec2 The Vec2 coordinate. +function ZONE_POLYGON_BASE:GetRandomVec2() + self:F2() + + --- It is a bit tricky to find a random point within a polygon. Right now i am doing it the dirty and inefficient way... + local Vec2Found = false + local Vec2 + local BS = self:GetBoundingSquare() + + self:T2( BS ) + + while Vec2Found == false do + Vec2 = { x = math.random( BS.x1, BS.x2 ), y = math.random( BS.y1, BS.y2 ) } + self:T2( Vec2 ) + if self:IsVec2InZone( Vec2 ) then + Vec2Found = true + end + end + + self:T2( Vec2 ) + + return Vec2 +end + +--- Return a @{Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. +-- @param #ZONE_POLYGON_BASE self +-- @return @{Point#POINT_VEC2} +function ZONE_POLYGON_BASE:GetRandomPointVec2() + self:F2() + + local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() ) + + self:T2( PointVec2 ) + + return PointVec2 +end + +--- Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. +-- @param #ZONE_POLYGON_BASE self +-- @return @{Point#POINT_VEC3} +function ZONE_POLYGON_BASE:GetRandomPointVec3() + self:F2() + + local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() ) + + self:T2( PointVec3 ) + + return PointVec3 +end + + +--- Get the bounding square the zone. +-- @param #ZONE_POLYGON_BASE self +-- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square. +function ZONE_POLYGON_BASE:GetBoundingSquare() + + local x1 = self.Polygon[1].x + local y1 = self.Polygon[1].y + local x2 = self.Polygon[1].x + local y2 = self.Polygon[1].y + + for i = 2, #self.Polygon do + self:T2( { self.Polygon[i], x1, y1, x2, y2 } ) + x1 = ( x1 > self.Polygon[i].x ) and self.Polygon[i].x or x1 + x2 = ( x2 < self.Polygon[i].x ) and self.Polygon[i].x or x2 + y1 = ( y1 > self.Polygon[i].y ) and self.Polygon[i].y or y1 + y2 = ( y2 < self.Polygon[i].y ) and self.Polygon[i].y or y2 + + end + + return { x1 = x1, y1 = y1, x2 = x2, y2 = y2 } +end + + +--- @type ZONE_POLYGON +-- @extends Core.Zone#ZONE_POLYGON_BASE + + +--- # 7) ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE} +-- +-- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon. +-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties. +-- +-- === +-- +-- @field #ZONE_POLYGON ZONE_POLYGON +-- +ZONE_POLYGON = { + ClassName="ZONE_POLYGON", + } + +--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Group#GROUP} defined within the Mission Editor. +-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. +-- @param #ZONE_POLYGON self +-- @param #string ZoneName Name of the zone. +-- @param Wrapper.Group#GROUP ZoneGroup The GROUP waypoints as defined within the Mission Editor define the polygon shape. +-- @return #ZONE_POLYGON self +function ZONE_POLYGON:New( ZoneName, ZoneGroup ) + + local GroupPoints = ZoneGroup:GetTaskRoute() + + local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) ) + self:F( { ZoneName, ZoneGroup, self.Polygon } ) + + return self +end + +--- This module contains the DATABASE class, managing the database of mission objects. +-- +-- ==== +-- +-- 1) @{#DATABASE} class, extends @{Base#BASE} +-- =================================================== +-- Mission designers can use the DATABASE class to refer to: +-- +-- * UNITS +-- * GROUPS +-- * CLIENTS +-- * AIRPORTS +-- * PLAYERSJOINED +-- * PLAYERS +-- +-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor. +-- +-- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE. +-- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required. +-- +-- 1.1) DATABASE iterators +-- ----------------------- +-- You can iterate the database with the available iterator methods. +-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide. +-- The following iterator methods are currently available within the DATABASE: +-- +-- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE. +-- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE. +-- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE. +-- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE. +-- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE. +-- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE. +-- +-- === +-- +-- @module Database +-- @author FlightControl + +--- DATABASE class +-- @type DATABASE +-- @extends Core.Base#BASE +DATABASE = { + ClassName = "DATABASE", + Templates = { + Units = {}, + Groups = {}, + ClientsByName = {}, + ClientsByID = {}, + }, + UNITS = {}, + STATICS = {}, + GROUPS = {}, + PLAYERS = {}, + PLAYERSJOINED = {}, + CLIENTS = {}, + AIRBASES = {}, + COUNTRY_ID = {}, + COUNTRY_NAME = {}, + NavPoints = {}, +} + +local _DATABASECoalition = + { + [1] = "Red", + [2] = "Blue", + } + +local _DATABASECategory = + { + ["plane"] = Unit.Category.AIRPLANE, + ["helicopter"] = Unit.Category.HELICOPTER, + ["vehicle"] = Unit.Category.GROUND_UNIT, + ["ship"] = Unit.Category.SHIP, + ["static"] = Unit.Category.STRUCTURE, + } + + +--- Creates a new DATABASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. +-- @param #DATABASE self +-- @return #DATABASE +-- @usage +-- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. +-- DBObject = DATABASE:New() +function DATABASE:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) + + self:SetEventPriority( 1 ) + + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + + -- Follow alive players and clients + self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit ) + + self:_RegisterTemplates() + self:_RegisterGroupsAndUnits() + self:_RegisterClients() + self:_RegisterStatics() + self:_RegisterPlayers() + self:_RegisterAirbases() + + return self +end + +--- Finds a Unit based on the Unit Name. +-- @param #DATABASE self +-- @param #string UnitName +-- @return Wrapper.Unit#UNIT The found Unit. +function DATABASE:FindUnit( UnitName ) + + local UnitFound = self.UNITS[UnitName] + return UnitFound +end + + +--- Adds a Unit based on the Unit Name in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddUnit( DCSUnitName ) + + if not self.UNITS[DCSUnitName] then + local UnitRegister = UNIT:Register( DCSUnitName ) + self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) + end + + return self.UNITS[DCSUnitName] +end + + +--- Deletes a Unit from the DATABASE based on the Unit Name. +-- @param #DATABASE self +function DATABASE:DeleteUnit( DCSUnitName ) + + --self.UNITS[DCSUnitName] = nil +end + +--- Adds a Static based on the Static Name in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddStatic( DCSStaticName ) + + if not self.STATICS[DCSStaticName] then + self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName ) + end +end + + +--- Deletes a Static from the DATABASE based on the Static Name. +-- @param #DATABASE self +function DATABASE:DeleteStatic( DCSStaticName ) + + --self.STATICS[DCSStaticName] = nil +end + +--- Finds a STATIC based on the StaticName. +-- @param #DATABASE self +-- @param #string StaticName +-- @return Wrapper.Static#STATIC The found STATIC. +function DATABASE:FindStatic( StaticName ) + + local StaticFound = self.STATICS[StaticName] + return StaticFound +end + +--- Adds a Airbase based on the Airbase Name in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddAirbase( DCSAirbaseName ) + + if not self.AIRBASES[DCSAirbaseName] then + self.AIRBASES[DCSAirbaseName] = AIRBASE:Register( DCSAirbaseName ) + end +end + + +--- Deletes a Airbase from the DATABASE based on the Airbase Name. +-- @param #DATABASE self +function DATABASE:DeleteAirbase( DCSAirbaseName ) + + --self.AIRBASES[DCSAirbaseName] = nil +end + +--- Finds a AIRBASE based on the AirbaseName. +-- @param #DATABASE self +-- @param #string AirbaseName +-- @return Wrapper.Airbase#AIRBASE The found AIRBASE. +function DATABASE:FindAirbase( AirbaseName ) + + local AirbaseFound = self.AIRBASES[AirbaseName] + return AirbaseFound +end + + +--- Finds a CLIENT based on the ClientName. +-- @param #DATABASE self +-- @param #string ClientName +-- @return Wrapper.Client#CLIENT The found CLIENT. +function DATABASE:FindClient( ClientName ) + + local ClientFound = self.CLIENTS[ClientName] + return ClientFound +end + + +--- Adds a CLIENT based on the ClientName in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddClient( ClientName ) + + if not self.CLIENTS[ClientName] then + self.CLIENTS[ClientName] = CLIENT:Register( ClientName ) + end + + return self.CLIENTS[ClientName] +end + + +--- Finds a GROUP based on the GroupName. +-- @param #DATABASE self +-- @param #string GroupName +-- @return Wrapper.Group#GROUP The found GROUP. +function DATABASE:FindGroup( GroupName ) + + local GroupFound = self.GROUPS[GroupName] + return GroupFound +end + + +--- Adds a GROUP based on the GroupName in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddGroup( GroupName ) + + if not self.GROUPS[GroupName] then + self:E( { "Add GROUP:", GroupName } ) + self.GROUPS[GroupName] = GROUP:Register( GroupName ) + end + + return self.GROUPS[GroupName] +end + +--- Adds a player based on the Player Name in the DATABASE. +-- @param #DATABASE self +function DATABASE:AddPlayer( UnitName, PlayerName ) + + if PlayerName then + self:E( { "Add player for unit:", UnitName, PlayerName } ) + self.PLAYERS[PlayerName] = self:FindUnit( UnitName ) + self.PLAYERSJOINED[PlayerName] = PlayerName + end +end + +--- Deletes a player from the DATABASE based on the Player Name. +-- @param #DATABASE self +function DATABASE:DeletePlayer( PlayerName ) + + if PlayerName then + self:E( { "Clean player:", PlayerName } ) + self.PLAYERS[PlayerName] = nil + end +end + + +--- Instantiate new Groups within the DCSRTE. +-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined: +-- SpawnCountryID, SpawnCategoryID +-- This method is used by the SPAWN class. +-- @param #DATABASE self +-- @param #table SpawnTemplate +-- @return #DATABASE self +function DATABASE:Spawn( SpawnTemplate ) + self:F( SpawnTemplate.name ) + + self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) + + -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. + local SpawnCoalitionID = SpawnTemplate.CoalitionID + local SpawnCountryID = SpawnTemplate.CountryID + local SpawnCategoryID = SpawnTemplate.CategoryID + + -- Nullify + SpawnTemplate.CoalitionID = nil + SpawnTemplate.CountryID = nil + SpawnTemplate.CategoryID = nil + + self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) + + self:T3( SpawnTemplate ) + coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) + + -- Restore + SpawnTemplate.CoalitionID = SpawnCoalitionID + SpawnTemplate.CountryID = SpawnCountryID + SpawnTemplate.CategoryID = SpawnCategoryID + + local SpawnGroup = self:AddGroup( SpawnTemplate.name ) + return SpawnGroup +end + +--- Set a status to a Group within the Database, this to check crossing events for example. +function DATABASE:SetStatusGroup( GroupName, Status ) + self:F2( Status ) + + self.Templates.Groups[GroupName].Status = Status +end + +--- Get a status to a Group within the Database, this to check crossing events for example. +function DATABASE:GetStatusGroup( GroupName ) + self:F2( Status ) + + if self.Templates.Groups[GroupName] then + return self.Templates.Groups[GroupName].Status + else + return "" + end +end + +--- Private method that registers new Group Templates within the DATABASE Object. +-- @param #DATABASE self +-- @param #table GroupTemplate +-- @return #DATABASE self +function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID ) + + local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name) + + local TraceTable = {} + + if not self.Templates.Groups[GroupTemplateName] then + self.Templates.Groups[GroupTemplateName] = {} + self.Templates.Groups[GroupTemplateName].Status = nil + end + + -- Delete the spans from the route, it is not needed and takes memory. + if GroupTemplate.route and GroupTemplate.route.spans then + GroupTemplate.route.spans = nil + end + + GroupTemplate.CategoryID = CategoryID + GroupTemplate.CoalitionID = CoalitionID + GroupTemplate.CountryID = CountryID + + self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName + self.Templates.Groups[GroupTemplateName].Template = GroupTemplate + self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId + self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units + self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units + self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID + self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID + self.Templates.Groups[GroupTemplateName].CountryID = CountryID + + + TraceTable[#TraceTable+1] = "Group" + TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName + + TraceTable[#TraceTable+1] = "Coalition" + TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID + TraceTable[#TraceTable+1] = "Category" + TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID + TraceTable[#TraceTable+1] = "Country" + TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID + + TraceTable[#TraceTable+1] = "Units" + + for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do + + UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name) + + self.Templates.Units[UnitTemplate.name] = {} + self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name + self.Templates.Units[UnitTemplate.name].Template = UnitTemplate + self.Templates.Units[UnitTemplate.name].GroupName = GroupTemplateName + self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate + self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId + self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID + self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID + self.Templates.Units[UnitTemplate.name].CountryID = CountryID + + if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then + self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate + self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID + self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID + self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID + self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate + end + + TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName + end + + self:E( TraceTable ) +end + +function DATABASE:GetGroupTemplate( GroupName ) + local GroupTemplate = self.Templates.Groups[GroupName].Template + GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID + GroupTemplate.SpawnCategoryID = self.Templates.Groups[GroupName].CategoryID + GroupTemplate.SpawnCountryID = self.Templates.Groups[GroupName].CountryID + return GroupTemplate +end + +function DATABASE:GetGroupNameFromUnitName( UnitName ) + return self.Templates.Units[UnitName].GroupName +end + +function DATABASE:GetGroupTemplateFromUnitName( UnitName ) + return self.Templates.Units[UnitName].GroupTemplate +end + +function DATABASE:GetCoalitionFromClientTemplate( ClientName ) + return self.Templates.ClientsByName[ClientName].CoalitionID +end + +function DATABASE:GetCategoryFromClientTemplate( ClientName ) + return self.Templates.ClientsByName[ClientName].CategoryID +end + +function DATABASE:GetCountryFromClientTemplate( ClientName ) + return self.Templates.ClientsByName[ClientName].CountryID +end + +--- Airbase + +function DATABASE:GetCoalitionFromAirbase( AirbaseName ) + return self.AIRBASES[AirbaseName]:GetCoalition() +end + +function DATABASE:GetCategoryFromAirbase( AirbaseName ) + return self.AIRBASES[AirbaseName]:GetCategory() +end + + + +--- Private method that registers all alive players in the mission. +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:_RegisterPlayers() + + local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + for UnitId, UnitData in pairs( CoalitionData ) do + self:T3( { "UnitData:", UnitData } ) + if UnitData and UnitData:isExist() then + local UnitName = UnitData:getName() + local PlayerName = UnitData:getPlayerName() + if not self.PLAYERS[PlayerName] then + self:E( { "Add player for unit:", UnitName, PlayerName } ) + self:AddPlayer( UnitName, PlayerName ) + end + end + end + end + + return self +end + + +--- Private method that registers all Groups and Units within in the mission. +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:_RegisterGroupsAndUnits() + + local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + for DCSGroupId, DCSGroup in pairs( CoalitionData ) do + + if DCSGroup:isExist() then + local DCSGroupName = DCSGroup:getName() + + self:E( { "Register Group:", DCSGroupName } ) + self:AddGroup( DCSGroupName ) + + for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do + + local DCSUnitName = DCSUnit:getName() + self:E( { "Register Unit:", DCSUnitName } ) + self:AddUnit( DCSUnitName ) + end + else + self:E( { "Group does not exist: ", DCSGroup } ) + end + + end + end + + return self +end + +--- Private method that registers all Units of skill Client or Player within in the mission. +-- @param #DATABASE self +-- @return #DATABASE self +function DATABASE:_RegisterClients() + + for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do + self:E( { "Register Client:", ClientName } ) + self:AddClient( ClientName ) + end + + return self +end + +--- @param #DATABASE self +function DATABASE:_RegisterStatics() + + local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + for DCSStaticId, DCSStatic in pairs( CoalitionData ) do + + if DCSStatic:isExist() then + local DCSStaticName = DCSStatic:getName() + + self:E( { "Register Static:", DCSStaticName } ) + self:AddStatic( DCSStaticName ) + else + self:E( { "Static does not exist: ", DCSStatic } ) + end + end + end + + return self +end + +--- @param #DATABASE self +function DATABASE:_RegisterAirbases() + + local CoalitionsData = { AirbasesRed = coalition.getAirbases( coalition.side.RED ), AirbasesBlue = coalition.getAirbases( coalition.side.BLUE ), AirbasesNeutral = coalition.getAirbases( coalition.side.NEUTRAL ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + for DCSAirbaseId, DCSAirbase in pairs( CoalitionData ) do + + local DCSAirbaseName = DCSAirbase:getName() + + self:E( { "Register Airbase:", DCSAirbaseName } ) + self:AddAirbase( DCSAirbaseName ) + end + end + + return self +end + + +--- Events + +--- Handles the OnBirth event for the alive units set. +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA Event +function DATABASE:_EventOnBirth( Event ) + self:F2( { Event } ) + + if Event.IniDCSUnit then + if Event.IniObjectCategory == 3 then + self:AddStatic( Event.IniDCSUnitName ) + else + if Event.IniObjectCategory == 1 then + self:AddUnit( Event.IniDCSUnitName ) + self:AddGroup( Event.IniDCSGroupName ) + end + end + self:_EventOnPlayerEnterUnit( Event ) + end +end + + +--- Handles the OnDead or OnCrash event for alive units set. +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA Event +function DATABASE:_EventOnDeadOrCrash( Event ) + self:F2( { Event } ) + + if Event.IniDCSUnit then + if Event.IniObjectCategory == 3 then + if self.STATICS[Event.IniDCSUnitName] then + self:DeleteStatic( Event.IniDCSUnitName ) + end + else + if Event.IniObjectCategory == 1 then + if self.UNITS[Event.IniDCSUnitName] then + self:DeleteUnit( Event.IniDCSUnitName ) + end + end + end + end +end + + +--- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA Event +function DATABASE:_EventOnPlayerEnterUnit( Event ) + self:F2( { Event } ) + + if Event.IniUnit then + if Event.IniObjectCategory == 1 then + self:AddUnit( Event.IniDCSUnitName ) + self:AddGroup( Event.IniDCSGroupName ) + local PlayerName = Event.IniUnit:GetPlayerName() + if not self.PLAYERS[PlayerName] then + self:AddPlayer( Event.IniUnitName, PlayerName ) + end + end + end +end + + +--- Handles the OnPlayerLeaveUnit event to clean the active players table. +-- @param #DATABASE self +-- @param Core.Event#EVENTDATA Event +function DATABASE:_EventOnPlayerLeaveUnit( Event ) + self:F2( { Event } ) + + if Event.IniUnit then + if Event.IniObjectCategory == 1 then + local PlayerName = Event.IniUnit:GetPlayerName() + if self.PLAYERS[PlayerName] then + self:DeletePlayer( PlayerName ) + end + end + end +end + +--- Iterators + +--- Iterate the DATABASE and call an iterator function for the given set, providing the Object for each element within the set and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an alive player in the database. +-- @return #DATABASE self +function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set ) + self:F2( arg ) + + local function CoRoutine() + local Count = 0 + for ObjectID, Object in pairs( Set ) do + self:T2( Object ) + IteratorFunction( Object, unpack( arg ) ) + Count = Count + 1 +-- if Count % 100 == 0 then +-- coroutine.yield( false ) +-- end + end + return true + end + +-- local co = coroutine.create( CoRoutine ) + local co = CoRoutine + + local function Schedule() + +-- local status, res = coroutine.resume( co ) + local status, res = co() + self:T3( { status, res } ) + + if status == false then + error( res ) + end + if res == false then + return true -- resume next time the loop + end + if FinalizeFunction then + FinalizeFunction( unpack( arg ) ) + end + return false + end + + local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 ) + + return self +end + + +--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter. +-- @return #DATABASE self +function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS ) + + return self +end + +--- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter. +-- @return #DATABASE self +function DATABASE:ForEachGroup( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.GROUPS ) + + return self +end + + +--- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an player in the database. The function needs to accept the player name. +-- @return #DATABASE self +function DATABASE:ForEachPlayer( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.PLAYERS ) + + return self +end + + +--- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter. +-- @return #DATABASE self +function DATABASE:ForEachPlayerJoined( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.PLAYERSJOINED ) + + return self +end + +--- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters. +-- @param #DATABASE self +-- @param #function IteratorFunction The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter. +-- @return #DATABASE self +function DATABASE:ForEachClient( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.CLIENTS ) + + return self +end + + +function DATABASE:_RegisterTemplates() + self:F2() + + self.Navpoints = {} + self.UNITS = {} + --Build routines.db.units and self.Navpoints + for CoalitionName, coa_data in pairs(env.mission.coalition) do + + if (CoalitionName == 'red' or CoalitionName == 'blue') and type(coa_data) == 'table' then + --self.Units[coa_name] = {} + + local CoalitionSide = coalition.side[string.upper(CoalitionName)] + + ---------------------------------------------- + -- build nav points DB + self.Navpoints[CoalitionName] = {} + if coa_data.nav_points then --navpoints + for nav_ind, nav_data in pairs(coa_data.nav_points) do + + if type(nav_data) == 'table' then + self.Navpoints[CoalitionName][nav_ind] = routines.utils.deepCopy(nav_data) + + self.Navpoints[CoalitionName][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. + self.Navpoints[CoalitionName][nav_ind]['point'] = {} -- point is used by SSE, support it. + self.Navpoints[CoalitionName][nav_ind]['point']['x'] = nav_data.x + self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0 + self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y + end + end + end + ------------------------------------------------- + if coa_data.country then --there is a country table + for cntry_id, cntry_data in pairs(coa_data.country) do + + local CountryName = string.upper(cntry_data.name) + local CountryID = cntry_data.id + + self.COUNTRY_ID[CountryName] = CountryID + self.COUNTRY_NAME[CountryID] = CountryName + + --self.Units[coa_name][countryName] = {} + --self.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 CategoryName = 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! + + --self.Units[coa_name][countryName][category] = {} + + for group_num, GroupTemplate in pairs(obj_type_data.group) do + + if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group + self:_RegisterTemplate( + GroupTemplate, + CoalitionSide, + _DATABASECategory[string.lower(CategoryName)], + CountryID + ) + end --if GroupTemplate and GroupTemplate.units then + end --for group_num, GroupTemplate 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 + + return self +end + + + + +--- **Core** - SET_ classes define **collections** of objects to perform **bulk actions** and logically **group** objects. +-- +-- ![Banner Image](..\Presentations\SET\Dia1.JPG) +-- +-- === +-- +-- SET_ classes group objects of the same type into a collection, which is either: +-- +-- * Manually managed using the **:Add...()** or **:Remove...()** methods. The initial SET can be filtered with the **@{#SET_BASE.FilterOnce}()** method +-- * Dynamically updated when new objects are created or objects are destroyed using the **@{#SET_BASE.FilterStart}()** method. +-- +-- Various types of SET_ classes are available: +-- +-- * @{#SET_UNIT}: Defines a colleciton of @{Unit}s filtered by filter criteria. +-- * @{#SET_GROUP}: Defines a collection of @{Group}s filtered by filter criteria. +-- * @{#SET_CLIENT}: Defines a collection of @{Client}s filterd by filter criteria. +-- * @{#SET_AIRBASE}: Defines a collection of @{Airbase}s filtered by filter criteria. +-- +-- These classes are derived from @{#SET_BASE}, which contains the main methods to manage SETs. +-- +-- A multitude of other methods are available in SET_ classes that allow to: +-- +-- * Validate the presence of objects in the SET. +-- * Trigger events when objects in the SET change a zone presence. +-- +-- ### Authors: +-- +-- * FlightControl : Design & Programming +-- +-- ### Contributions: +-- +-- +-- @module Set + + +--- @type SET_BASE +-- @field #table Filter +-- @field #table Set +-- @field #table List +-- @field Core.Scheduler#SCHEDULER CallScheduler +-- @extends Core.Base#BASE + + +--- # 1) SET_BASE class, extends @{Base#BASE} +-- The @{Set#SET_BASE} class defines the core functions that define a collection of objects. +-- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. +-- In this way, large loops can be done while not blocking the simulator main processing loop. +-- The default **"yield interval"** is after 10 objects processed. +-- The default **"time interval"** is after 0.001 seconds. +-- +-- ## 1.1) Add or remove objects from the SET +-- +-- Some key core functions are @{Set#SET_BASE.Add} and @{Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. +-- +-- ## 1.2) Define the SET iterator **"yield interval"** and the **"time interval"** +-- +-- Modify the iterator intervals with the @{Set#SET_BASE.SetInteratorIntervals} method. +-- You can set the **"yield interval"**, and the **"time interval"**. (See above). +-- +-- @field #SET_BASE SET_BASE +SET_BASE = { + ClassName = "SET_BASE", + Filter = {}, + Set = {}, + List = {}, + Index = {}, +} + + +--- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. +-- @param #SET_BASE self +-- @return #SET_BASE +-- @usage +-- -- Define a new SET_BASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. +-- DBObject = SET_BASE:New() +function SET_BASE:New( Database ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE + + self.Database = Database + + self.YieldInterval = 10 + self.TimeInterval = 0.001 + + self.Set = {} + + self.List = {} + self.List.__index = self.List + self.List = setmetatable( { Count = 0 }, self.List ) + + self.Index = {} + + self.CallScheduler = SCHEDULER:New( self ) + + self:SetEventPriority( 2 ) + + return self +end + +--- Finds an @{Base#BASE} object based on the object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @return Core.Base#BASE The Object found. +function SET_BASE:_Find( ObjectName ) + + local ObjectFound = self.Set[ObjectName] + return ObjectFound +end + + +--- Gets the Set. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:GetSet() + self:F2() + + return self.Set +end + +--- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using a given ObjectName as the index. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @param Core.Base#BASE Object +-- @return Core.Base#BASE The added BASE Object. +function SET_BASE:Add( ObjectName, Object ) + self:F2( ObjectName ) + + local t = { _ = Object } + + if self.List.last then + self.List.last._next = t + t._prev = self.List.last + self.List.last = t + else + -- this is the first node + self.List.first = t + self.List.last = t + end + + self.List.Count = self.List.Count + 1 + + self.Set[ObjectName] = t._ + + table.insert( self.Index, ObjectName ) + +end + +--- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. +-- @param #SET_BASE self +-- @param Wrapper.Object#OBJECT Object +-- @return Core.Base#BASE The added BASE Object. +function SET_BASE:AddObject( Object ) + self:F2( Object.ObjectName ) + + self:T( Object.UnitName ) + self:T( Object.ObjectName ) + self:Add( Object.ObjectName, Object ) + +end + + + +--- Removes a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +function SET_BASE:Remove( ObjectName ) + self:F( ObjectName ) + + local t = self.Set[ObjectName] + + self:E( { ObjectName, t } ) + + if t then + if t._next then + if t._prev then + t._next._prev = t._prev + t._prev._next = t._next + else + -- this was the first node + t._next._prev = nil + self.List._first = t._next + end + elseif t._prev then + -- this was the last node + t._prev._next = nil + self.List._last = t._prev + else + -- this was the only node + self.List._first = nil + self.List._last = nil + end + + t._next = nil + t._prev = nil + self.List.Count = self.List.Count - 1 + + for Index, Key in ipairs( self.Index ) do + if Key == ObjectName then + table.remove( self.Index, Index ) + break + end + end + + self.Set[ObjectName] = nil + + end + +end + +--- Gets a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @return Core.Base#BASE +function SET_BASE:Get( ObjectName ) + self:F( ObjectName ) + + local t = self.Set[ObjectName] + + self:T3( { ObjectName, t } ) + + return t + +end + +--- Gets the first object from the @{Set#SET_BASE} and derived classes. +-- @param #SET_BASE self +-- @return Core.Base#BASE +function SET_BASE:GetFirst() + self:F() + + local ObjectName = self.Index[1] + local FirstObject = self.Set[ObjectName] + self:T3( { FirstObject } ) + return FirstObject +end + +--- Gets the last object from the @{Set#SET_BASE} and derived classes. +-- @param #SET_BASE self +-- @return Core.Base#BASE +function SET_BASE:GetLast() + self:F() + + local ObjectName = self.Index[#self.Index] + local LastObject = self.Set[ObjectName] + self:T3( { LastObject } ) + return LastObject +end + +--- Gets a random object from the @{Set#SET_BASE} and derived classes. +-- @param #SET_BASE self +-- @return Core.Base#BASE +function SET_BASE:GetRandom() + self:F() + + local RandomItem = self.Set[self.Index[math.random(#self.Index)]] + + self:T3( { RandomItem } ) + + return RandomItem +end + + +--- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes. +-- @param #SET_BASE self +-- @return #number Count +function SET_BASE:Count() + + return #self.Index or 0 +end + + + +--- Copies the Filter criteria from a given Set (for rebuilding a new Set based on an existing Set). +-- @param #SET_BASE self +-- @param #SET_BASE BaseSet +-- @return #SET_BASE +function SET_BASE:SetDatabase( BaseSet ) + + -- Copy the filter criteria of the BaseSet + local OtherFilter = routines.utils.deepCopy( BaseSet.Filter ) + self.Filter = OtherFilter + + -- Now base the new Set on the BaseSet + self.Database = BaseSet:GetSet() + return self +end + + + +--- Define the SET iterator **"yield interval"** and the **"time interval"**. +-- @param #SET_BASE self +-- @param #number YieldInterval Sets the frequency when the iterator loop will yield after the number of objects processed. The default frequency is 10 objects processed. +-- @param #number TimeInterval Sets the time in seconds when the main logic will resume the iterator loop. The default time is 0.001 seconds. +-- @return #SET_BASE self +function SET_BASE:SetIteratorIntervals( YieldInterval, TimeInterval ) + + self.YieldInterval = YieldInterval + self.TimeInterval = TimeInterval + + return self +end + + +--- Filters for the defined collection. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:FilterOnce() + + for ObjectName, Object in pairs( self.Database ) do + + if self:IsIncludeObject( Object ) then + self:Add( ObjectName, Object ) + end + end + + return self +end + +--- Starts the filtering for the defined collection. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:_FilterStart() + + for ObjectName, Object in pairs( self.Database ) do + + if self:IsIncludeObject( Object ) then + self:E( { "Adding Object:", ObjectName } ) + self:Add( ObjectName, Object ) + end + end + + self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + + -- Follow alive players and clients + self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit ) + + + return self +end + +--- Stops the filtering for the defined collection. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:FilterStop() + + self:UnHandleEvent( EVENTS.Birth ) + self:UnHandleEvent( EVENTS.Dead ) + self:UnHandleEvent( EVENTS.Crash ) + + return self +end + +--- Iterate the SET_BASE while identifying the nearest object from a @{Point#POINT_VEC2}. +-- @param #SET_BASE self +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest object in the set. +-- @return Core.Base#BASE The closest object. +function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ) + self:F2( PointVec2 ) + + local NearestObject = nil + local ClosestDistance = nil + + for ObjectID, ObjectData in pairs( self.Set ) do + if NearestObject == nil then + NearestObject = ObjectData + ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) + else + local Distance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) + if Distance < ClosestDistance then + NearestObject = ObjectData + ClosestDistance = Distance + end + end + end + + return NearestObject +end + + + +----- Private method that registers all alive players in the mission. +---- @param #SET_BASE self +---- @return #SET_BASE self +--function SET_BASE:_RegisterPlayers() +-- +-- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } +-- for CoalitionId, CoalitionData in pairs( CoalitionsData ) do +-- for UnitId, UnitData in pairs( CoalitionData ) do +-- self:T3( { "UnitData:", UnitData } ) +-- if UnitData and UnitData:isExist() then +-- local UnitName = UnitData:getName() +-- if not self.PlayersAlive[UnitName] then +-- self:E( { "Add player for unit:", UnitName, UnitData:getPlayerName() } ) +-- self.PlayersAlive[UnitName] = UnitData:getPlayerName() +-- end +-- end +-- end +-- end +-- +-- return self +--end + +--- Events + +--- Handles the OnBirth event for the Set. +-- @param #SET_BASE self +-- @param Core.Event#EVENTDATA Event +function SET_BASE:_EventOnBirth( Event ) + self:F3( { Event } ) + + if Event.IniDCSUnit then + local ObjectName, Object = self:AddInDatabase( Event ) + self:T3( ObjectName, Object ) + if Object and self:IsIncludeObject( Object ) then + self:Add( ObjectName, Object ) + --self:_EventOnPlayerEnterUnit( Event ) + end + end +end + +--- Handles the OnDead or OnCrash event for alive units set. +-- @param #SET_BASE self +-- @param Core.Event#EVENTDATA Event +function SET_BASE:_EventOnDeadOrCrash( Event ) + self:F3( { Event } ) + + if Event.IniDCSUnit then + local ObjectName, Object = self:FindInDatabase( Event ) + if ObjectName and Object ~= nil then + self:Remove( ObjectName ) + end + end +end + +--- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). +-- @param #SET_BASE self +-- @param Core.Event#EVENTDATA Event +function SET_BASE:_EventOnPlayerEnterUnit( Event ) + self:F3( { Event } ) + + if Event.IniDCSUnit then + local ObjectName, Object = self:AddInDatabase( Event ) + self:T3( ObjectName, Object ) + if self:IsIncludeObject( Object ) then + self:Add( ObjectName, Object ) + --self:_EventOnPlayerEnterUnit( Event ) + end + end +end + +--- Handles the OnPlayerLeaveUnit event to clean the active players table. +-- @param #SET_BASE self +-- @param Core.Event#EVENTDATA Event +function SET_BASE:_EventOnPlayerLeaveUnit( Event ) + self:F3( { Event } ) + + local ObjectName = Event.IniDCSUnit + if Event.IniDCSUnit then + if Event.IniDCSGroup then + local GroupUnits = Event.IniDCSGroup:getUnits() + local PlayerCount = 0 + for _, DCSUnit in pairs( GroupUnits ) do + if DCSUnit ~= Event.IniDCSUnit then + if DCSUnit:getPlayerName() ~= nil then + PlayerCount = PlayerCount + 1 + end + end + end + self:E(PlayerCount) + if PlayerCount == 0 then + self:Remove( Event.IniDCSGroupName ) + end + end + end +end + +-- Iterators + +--- Iterate the SET_BASE and derived classes and call an iterator function for the given SET_BASE, providing the Object for each element within the set and optional parameters. +-- @param #SET_BASE self +-- @param #function IteratorFunction The function that will be called. +-- @return #SET_BASE self +function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArguments ) + self:F3( arg ) + + Set = Set or self:GetSet() + arg = arg or {} + + local function CoRoutine() + local Count = 0 + for ObjectID, ObjectData in pairs( Set ) do + local Object = ObjectData + self:T3( Object ) + if Function then + if Function( unpack( FunctionArguments ), Object ) == true then + IteratorFunction( Object, unpack( arg ) ) + end + else + IteratorFunction( Object, unpack( arg ) ) + end + Count = Count + 1 +-- if Count % self.YieldInterval == 0 then +-- coroutine.yield( false ) +-- end + end + return true + end + +-- local co = coroutine.create( CoRoutine ) + local co = CoRoutine + + local function Schedule() + +-- local status, res = coroutine.resume( co ) + local status, res = co() + self:T3( { status, res } ) + + if status == false then + error( res ) + end + if res == false then + return true -- resume next time the loop + end + + return false + end + + --self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) + Schedule() + + return self +end + + +----- Iterate the SET_BASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. +---- @param #SET_BASE self +---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. +---- @return #SET_BASE self +--function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... ) +-- self:F3( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.DCSUnitsAlive ) +-- +-- return self +--end +-- +----- Iterate the SET_BASE and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. +---- @param #SET_BASE self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. +---- @return #SET_BASE self +--function SET_BASE:ForEachPlayer( IteratorFunction, ... ) +-- self:F3( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) +-- +-- return self +--end +-- +-- +----- Iterate the SET_BASE and call an interator function for each client, providing the Client to the function and optional parameters. +---- @param #SET_BASE self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. +---- @return #SET_BASE self +--function SET_BASE:ForEachClient( IteratorFunction, ... ) +-- self:F3( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.Clients ) +-- +-- return self +--end + + +--- Decides whether to include the Object +-- @param #SET_BASE self +-- @param #table Object +-- @return #SET_BASE self +function SET_BASE:IsIncludeObject( Object ) + self:F3( Object ) + + return true +end + +--- Flushes the current SET_BASE contents in the log ... (for debugging reasons). +-- @param #SET_BASE self +-- @return #string A string with the names of the objects. +function SET_BASE:Flush() + self:F3() + + local ObjectNames = "" + for ObjectName, Object in pairs( self.Set ) do + ObjectNames = ObjectNames .. ObjectName .. ", " + end + self:E( { "Objects in Set:", ObjectNames } ) + + return ObjectNames +end + + +--- @type SET_GROUP +-- @extends Core.Set#SET_BASE + +--- # 2) SET_GROUP class, extends @{Set#SET_BASE} +-- +-- Mission designers can use the @{Set#SET_GROUP} class to build sets of groups belonging to certain: +-- +-- * Coalitions +-- * Categories +-- * Countries +-- * Starting with certain prefix strings. +-- +-- ## 2.1) SET_GROUP constructor +-- +-- Create a new SET_GROUP object with the @{#SET_GROUP.New} method: +-- +-- * @{#SET_GROUP.New}: Creates a new SET_GROUP object. +-- +-- ## 2.2) Add or Remove GROUP(s) from SET_GROUP +-- +-- GROUPS can be added and removed using the @{Set#SET_GROUP.AddGroupsByName} and @{Set#SET_GROUP.RemoveGroupsByName} respectively. +-- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_GROUP. +-- +-- ## 2.3) SET_GROUP filter criteria +-- +-- You can set filter criteria to define the set of groups within the SET_GROUP. +-- Filter criteria are defined by: +-- +-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s). +-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies). +-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies). +-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s). +-- +-- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: +-- +-- * @{#SET_GROUP.FilterStart}: Starts the filtering of the groups within the SET_GROUP and add or remove GROUP objects **dynamically**. +-- +-- Planned filter criteria within development are (so these are not yet available): +-- +-- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Zone#ZONE}. +-- +-- ## 2.4) SET_GROUP iterators +-- +-- Once the filters have been defined and the SET_GROUP has been built, you can iterate the SET_GROUP with the available iterator methods. +-- The iterator methods will walk the SET_GROUP set, and call for each element within the set a function that you provide. +-- The following iterator methods are currently available within the SET_GROUP: +-- +-- * @{#SET_GROUP.ForEachGroup}: Calls a function for each alive group it finds within the SET_GROUP. +-- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- * @{#SET_GROUP.ForEachGroupPartlyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- +-- === +-- @field #SET_GROUP SET_GROUP +SET_GROUP = { + ClassName = "SET_GROUP", + Filter = { + Coalitions = nil, + Categories = nil, + Countries = nil, + GroupPrefixes = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + plane = Group.Category.AIRPLANE, + helicopter = Group.Category.HELICOPTER, + ground = Group.Category.GROUND_UNIT, + ship = Group.Category.SHIP, + structure = Group.Category.STRUCTURE, + }, + }, +} + + +--- Creates a new SET_GROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names. +-- @param #SET_GROUP self +-- @return #SET_GROUP +-- @usage +-- -- Define a new SET_GROUP Object. This DBObject will contain a reference to all alive GROUPS. +-- DBObject = SET_GROUP:New() +function SET_GROUP:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) + + return self +end + +--- Add GROUP(s) to SET_GROUP. +-- @param Core.Set#SET_GROUP self +-- @param #string AddGroupNames A single name or an array of GROUP names. +-- @return self +function SET_GROUP:AddGroupsByName( AddGroupNames ) + + local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames } + + for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do + self:Add( AddGroupName, GROUP:FindByName( AddGroupName ) ) + end + + return self +end + +--- Remove GROUP(s) from SET_GROUP. +-- @param Core.Set#SET_GROUP self +-- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names. +-- @return self +function SET_GROUP:RemoveGroupsByName( RemoveGroupNames ) + + local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames } + + for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do + self:Remove( RemoveGroupName.GroupName ) + end + + return self +end + + + + +--- Finds a Group based on the Group Name. +-- @param #SET_GROUP self +-- @param #string GroupName +-- @return Wrapper.Group#GROUP The found Group. +function SET_GROUP:FindGroup( GroupName ) + + local GroupFound = self.Set[GroupName] + return GroupFound +end + + + +--- Builds a set of groups of coalitions. +-- Possible current coalitions are red, blue and neutral. +-- @param #SET_GROUP self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #SET_GROUP self +function SET_GROUP:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end + + +--- Builds a set of groups out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #SET_GROUP self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #SET_GROUP self +function SET_GROUP:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end + +--- Builds a set of groups of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #SET_GROUP self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #SET_GROUP self +function SET_GROUP:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self +end + + +--- Builds a set of groups of defined GROUP prefixes. +-- All the groups starting with the given prefixes will be included within the set. +-- @param #SET_GROUP self +-- @param #string Prefixes The prefix of which the group name starts with. +-- @return #SET_GROUP self +function SET_GROUP:FilterPrefixes( Prefixes ) + if not self.Filter.GroupPrefixes then + self.Filter.GroupPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.GroupPrefixes[Prefix] = Prefix + end + return self +end + + +--- Starts the filtering. +-- @param #SET_GROUP self +-- @return #SET_GROUP self +function SET_GROUP:FilterStart() + + if _DATABASE then + self:_FilterStart() + end + + + + return self +end + +--- Handles the Database to check on an event (birth) that the Object was added in the Database. +-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! +-- @param #SET_GROUP self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the GROUP +-- @return #table The GROUP +function SET_GROUP:AddInDatabase( Event ) + self:F3( { Event } ) + + if Event.IniObjectCategory == 1 then + if not self.Database[Event.IniDCSGroupName] then + self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName ) + self:T3( self.Database[Event.IniDCSGroupName] ) + end + end + + return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] +end + +--- Handles the Database to check on any event that Object exists in the Database. +-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! +-- @param #SET_GROUP self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the GROUP +-- @return #table The GROUP +function SET_GROUP:FindInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] +end + +--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. +-- @param #SET_GROUP self +-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. +-- @return #SET_GROUP self +function SET_GROUP:ForEachGroup( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self +end + +--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- @param #SET_GROUP self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. +-- @return #SET_GROUP self +function SET_GROUP:ForEachGroupCompletelyInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Group#GROUP GroupObject + function( ZoneObject, GroupObject ) + if GroupObject:IsCompletelyInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- @param #SET_GROUP self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. +-- @return #SET_GROUP self +function SET_GROUP:ForEachGroupPartlyInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Group#GROUP GroupObject + function( ZoneObject, GroupObject ) + if GroupObject:IsPartlyInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- @param #SET_GROUP self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. +-- @return #SET_GROUP self +function SET_GROUP:ForEachGroupNotInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Group#GROUP GroupObject + function( ZoneObject, GroupObject ) + if GroupObject:IsNotInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + + +----- Iterate the SET_GROUP and call an interator function for each **alive** player, providing the Group of the player and optional parameters. +---- @param #SET_GROUP self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. +---- @return #SET_GROUP self +--function SET_GROUP:ForEachPlayer( IteratorFunction, ... ) +-- self:F2( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) +-- +-- return self +--end +-- +-- +----- Iterate the SET_GROUP and call an interator function for each client, providing the Client to the function and optional parameters. +---- @param #SET_GROUP self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. +---- @return #SET_GROUP self +--function SET_GROUP:ForEachClient( IteratorFunction, ... ) +-- self:F2( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.Clients ) +-- +-- return self +--end + + +--- +-- @param #SET_GROUP self +-- @param Wrapper.Group#GROUP MooseGroup +-- @return #SET_GROUP self +function SET_GROUP:IsIncludeObject( MooseGroup ) + self:F2( MooseGroup ) + local MooseGroupInclude = true + + if self.Filter.Coalitions then + local MooseGroupCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:T3( { "Coalition:", MooseGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MooseGroup:GetCoalition() then + MooseGroupCoalition = true + end + end + MooseGroupInclude = MooseGroupInclude and MooseGroupCoalition + end + + if self.Filter.Categories then + local MooseGroupCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T3( { "Category:", MooseGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MooseGroup:GetCategory() then + MooseGroupCategory = true + end + end + MooseGroupInclude = MooseGroupInclude and MooseGroupCategory + end + + if self.Filter.Countries then + local MooseGroupCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T3( { "Country:", MooseGroup:GetCountry(), CountryName } ) + if country.id[CountryName] == MooseGroup:GetCountry() then + MooseGroupCountry = true + end + end + MooseGroupInclude = MooseGroupInclude and MooseGroupCountry + end + + if self.Filter.GroupPrefixes then + local MooseGroupPrefix = false + for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do + self:T3( { "Prefix:", string.find( MooseGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) + if string.find( MooseGroup:GetName(), GroupPrefix, 1 ) then + MooseGroupPrefix = true + end + end + MooseGroupInclude = MooseGroupInclude and MooseGroupPrefix + end + + self:T2( MooseGroupInclude ) + return MooseGroupInclude +end + +--- @type SET_UNIT +-- @extends Core.Set#SET_BASE + +--- # 3) SET_UNIT class, extends @{Set#SET_BASE} +-- +-- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: +-- +-- * Coalitions +-- * Categories +-- * Countries +-- * Unit types +-- * Starting with certain prefix strings. +-- +-- ## 3.1) SET_UNIT constructor +-- +-- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: +-- +-- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. +-- +-- ## 3.2) Add or Remove UNIT(s) from SET_UNIT +-- +-- UNITs can be added and removed using the @{Set#SET_UNIT.AddUnitsByName} and @{Set#SET_UNIT.RemoveUnitsByName} respectively. +-- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. +-- +-- ## 3.3) SET_UNIT filter criteria +-- +-- You can set filter criteria to define the set of units within the SET_UNIT. +-- Filter criteria are defined by: +-- +-- * @{#SET_UNIT.FilterCoalitions}: Builds the SET_UNIT with the units belonging to the coalition(s). +-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). +-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). +-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). +-- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). +-- +-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: +-- +-- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. +-- +-- Planned filter criteria within development are (so these are not yet available): +-- +-- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Zone#ZONE}. +-- +-- ## 3.4) SET_UNIT iterators +-- +-- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. +-- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. +-- The following iterator methods are currently available within the SET_UNIT: +-- +-- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. +-- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. +-- +-- Planned iterators methods in development are (so these are not yet available): +-- +-- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. +-- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. +-- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. +-- +-- ## 3.5 ) SET_UNIT atomic methods +-- +-- Various methods exist for a SET_UNIT to perform actions or calculations and retrieve results from the SET_UNIT: +-- +-- * @{#SET_UNIT.GetTypeNames}(): Retrieve the type names of the @{Unit}s in the SET, delimited by a comma. +-- +-- === +-- @field #SET_UNIT SET_UNIT +SET_UNIT = { + ClassName = "SET_UNIT", + Units = {}, + Filter = { + Coalitions = nil, + Categories = nil, + Types = nil, + Countries = nil, + UnitPrefixes = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + plane = Unit.Category.AIRPLANE, + helicopter = Unit.Category.HELICOPTER, + ground = Unit.Category.GROUND_UNIT, + ship = Unit.Category.SHIP, + structure = Unit.Category.STRUCTURE, + }, + }, +} + + +--- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. +-- @param #SET_UNIT self +-- @return #SET_UNIT +-- @usage +-- -- Define a new SET_UNIT Object. This DBObject will contain a reference to all alive Units. +-- DBObject = SET_UNIT:New() +function SET_UNIT:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) + + return self +end + +--- Add UNIT(s) to SET_UNIT. +-- @param #SET_UNIT self +-- @param #string AddUnit A single UNIT. +-- @return #SET_UNIT self +function SET_UNIT:AddUnit( AddUnit ) + self:F2( AddUnit:GetName() ) + + self:Add( AddUnit:GetName(), AddUnit ) + + return self +end + + +--- Add UNIT(s) to SET_UNIT. +-- @param #SET_UNIT self +-- @param #string AddUnitNames A single name or an array of UNIT names. +-- @return #SET_UNIT self +function SET_UNIT:AddUnitsByName( AddUnitNames ) + + local AddUnitNamesArray = ( type( AddUnitNames ) == "table" ) and AddUnitNames or { AddUnitNames } + + self:T( AddUnitNamesArray ) + for AddUnitID, AddUnitName in pairs( AddUnitNamesArray ) do + self:Add( AddUnitName, UNIT:FindByName( AddUnitName ) ) + end + + return self +end + +--- Remove UNIT(s) from SET_UNIT. +-- @param Core.Set#SET_UNIT self +-- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names. +-- @return self +function SET_UNIT:RemoveUnitsByName( RemoveUnitNames ) + + local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames } + + for RemoveUnitID, RemoveUnitName in pairs( RemoveUnitNamesArray ) do + self:Remove( RemoveUnitName ) + end + + return self +end + + +--- Finds a Unit based on the Unit Name. +-- @param #SET_UNIT self +-- @param #string UnitName +-- @return Wrapper.Unit#UNIT The found Unit. +function SET_UNIT:FindUnit( UnitName ) + + local UnitFound = self.Set[UnitName] + return UnitFound +end + + + +--- Builds a set of units of coalitions. +-- Possible current coalitions are red, blue and neutral. +-- @param #SET_UNIT self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #SET_UNIT self +function SET_UNIT:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end + + +--- Builds a set of units out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #SET_UNIT self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #SET_UNIT self +function SET_UNIT:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end + + +--- Builds a set of units of defined unit types. +-- Possible current types are those types known within DCS world. +-- @param #SET_UNIT self +-- @param #string Types Can take those type strings known within DCS world. +-- @return #SET_UNIT self +function SET_UNIT:FilterTypes( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self +end + + +--- Builds a set of units of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #SET_UNIT self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #SET_UNIT self +function SET_UNIT:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self +end + + +--- Builds a set of units of defined unit prefixes. +-- All the units starting with the given prefixes will be included within the set. +-- @param #SET_UNIT self +-- @param #string Prefixes The prefix of which the unit name starts with. +-- @return #SET_UNIT self +function SET_UNIT:FilterPrefixes( Prefixes ) + if not self.Filter.UnitPrefixes then + self.Filter.UnitPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.UnitPrefixes[Prefix] = Prefix + end + return self +end + +--- Builds a set of units having a radar of give types. +-- All the units having a radar of a given type will be included within the set. +-- @param #SET_UNIT self +-- @param #table RadarTypes The radar types. +-- @return #SET_UNIT self +function SET_UNIT:FilterHasRadar( RadarTypes ) + + self.Filter.RadarTypes = self.Filter.RadarTypes or {} + if type( RadarTypes ) ~= "table" then + RadarTypes = { RadarTypes } + end + for RadarTypeID, RadarType in pairs( RadarTypes ) do + self.Filter.RadarTypes[RadarType] = RadarType + end + return self +end + +--- Builds a set of SEADable units. +-- @param #SET_UNIT self +-- @return #SET_UNIT self +function SET_UNIT:FilterHasSEAD() + + self.Filter.SEAD = true + return self +end + + + +--- Starts the filtering. +-- @param #SET_UNIT self +-- @return #SET_UNIT self +function SET_UNIT:FilterStart() + + if _DATABASE then + self:_FilterStart() + end + + return self +end + +--- Handles the Database to check on an event (birth) that the Object was added in the Database. +-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! +-- @param #SET_UNIT self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the UNIT +-- @return #table The UNIT +function SET_UNIT:AddInDatabase( Event ) + self:F3( { Event } ) + + if Event.IniObjectCategory == 1 then + if not self.Database[Event.IniDCSUnitName] then + self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) + self:T3( self.Database[Event.IniDCSUnitName] ) + end + end + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Handles the Database to check on any event that Object exists in the Database. +-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! +-- @param #SET_UNIT self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the UNIT +-- @return #table The UNIT +function SET_UNIT:FindInDatabase( Event ) + self:E( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } ) + + + return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName] +end + +--- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. +-- @param #SET_UNIT self +-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. +-- @return #SET_UNIT self +function SET_UNIT:ForEachUnit( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self +end + +--- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. +-- @param #SET_UNIT self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. +-- @return #SET_UNIT self +function SET_UNIT:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Unit#UNIT UnitObject + function( ZoneObject, UnitObject ) + if UnitObject:IsCompletelyInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. +-- @param #SET_UNIT self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. +-- @return #SET_UNIT self +function SET_UNIT:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Unit#UNIT UnitObject + function( ZoneObject, UnitObject ) + if UnitObject:IsNotInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- Returns map of unit types. +-- @param #SET_UNIT self +-- @return #map<#string,#number> A map of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. +function SET_UNIT:GetUnitTypes() + self:F2() + + local MT = {} -- Message Text + local UnitTypes = {} + + for UnitID, UnitData in pairs( self:GetSet() ) do + local TextUnit = UnitData -- Wrapper.Unit#UNIT + if TextUnit:IsAlive() then + local UnitType = TextUnit:GetTypeName() + + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + end + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + + return UnitTypes +end + + +--- Returns a comma separated string of the unit types with a count in the @{Set}. +-- @param #SET_UNIT self +-- @return #string The unit types string +function SET_UNIT:GetUnitTypesText() + self:F2() + + local MT = {} -- Message Text + local UnitTypes = self:GetUnitTypes() + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + + return table.concat( MT, ", " ) +end + +--- Returns map of unit threat levels. +-- @param #SET_UNIT self +-- @return #table. +function SET_UNIT:GetUnitThreatLevels() + self:F2() + + local UnitThreatLevels = {} + + for UnitID, UnitData in pairs( self:GetSet() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + if ThreatUnit:IsAlive() then + local UnitThreatLevel, UnitThreatLevelText = ThreatUnit:GetThreatLevel() + local ThreatUnitName = ThreatUnit:GetName() + + UnitThreatLevels[UnitThreatLevel] = UnitThreatLevels[UnitThreatLevel] or {} + UnitThreatLevels[UnitThreatLevel].UnitThreatLevelText = UnitThreatLevelText + UnitThreatLevels[UnitThreatLevel].Units = UnitThreatLevels[UnitThreatLevel].Units or {} + UnitThreatLevels[UnitThreatLevel].Units[ThreatUnitName] = ThreatUnit + end + end + + return UnitThreatLevels +end + +--- Calculate the maxium A2G threat level of the SET_UNIT. +-- @param #SET_UNIT self +function SET_UNIT:CalculateThreatLevelA2G() + + local MaxThreatLevelA2G = 0 + for UnitName, UnitData in pairs( self:GetSet() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + local ThreatLevelA2G = ThreatUnit:GetThreatLevel() + if ThreatLevelA2G > MaxThreatLevelA2G then + MaxThreatLevelA2G = ThreatLevelA2G + end + end + + self:T3( MaxThreatLevelA2G ) + return MaxThreatLevelA2G + +end + + +--- Returns if the @{Set} has targets having a radar (of a given type). +-- @param #SET_UNIT self +-- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType +-- @return #number The amount of radars in the Set with the given type +function SET_UNIT:HasRadar( RadarType ) + self:F2( RadarType ) + + local RadarCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitSensorTest = UnitData -- Wrapper.Unit#UNIT + local HasSensors + if RadarType then + HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType ) + else + HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR ) + end + self:T3(HasSensors) + if HasSensors then + RadarCount = RadarCount + 1 + end + end + + return RadarCount +end + +--- Returns if the @{Set} has targets that can be SEADed. +-- @param #SET_UNIT self +-- @return #number The amount of SEADable units in the Set +function SET_UNIT:HasSEAD() + self:F2() + + local SEADCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitSEAD = UnitData -- Wrapper.Unit#UNIT + if UnitSEAD:IsAlive() then + local UnitSEADAttributes = UnitSEAD:GetDesc().attributes + + local HasSEAD = UnitSEAD:HasSEAD() + + self:T3(HasSEAD) + if HasSEAD then + SEADCount = SEADCount + 1 + end + end + end + + return SEADCount +end + +--- Returns if the @{Set} has ground targets. +-- @param #SET_UNIT self +-- @return #number The amount of ground targets in the Set. +function SET_UNIT:HasGroundUnits() + self:F2() + + local GroundUnitCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitTest = UnitData -- Wrapper.Unit#UNIT + if UnitTest:IsGround() then + GroundUnitCount = GroundUnitCount + 1 + end + end + + return GroundUnitCount +end + +--- Returns if the @{Set} has friendly ground units. +-- @param #SET_UNIT self +-- @return #number The amount of ground targets in the Set. +function SET_UNIT:HasFriendlyUnits( FriendlyCoalition ) + self:F2() + + local FriendlyUnitCount = 0 + for UnitID, UnitData in pairs( self:GetSet()) do + local UnitTest = UnitData -- Wrapper.Unit#UNIT + if UnitTest:IsFriendly( FriendlyCoalition ) then + FriendlyUnitCount = FriendlyUnitCount + 1 + end + end + + return FriendlyUnitCount +end + + + +----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. +---- @param #SET_UNIT self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. +---- @return #SET_UNIT self +--function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) +-- self:F2( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) +-- +-- return self +--end +-- +-- +----- Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. +---- @param #SET_UNIT self +---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. +---- @return #SET_UNIT self +--function SET_UNIT:ForEachClient( IteratorFunction, ... ) +-- self:F2( arg ) +-- +-- self:ForEach( IteratorFunction, arg, self.Clients ) +-- +-- return self +--end + + +--- +-- @param #SET_UNIT self +-- @param Wrapper.Unit#UNIT MUnit +-- @return #SET_UNIT self +function SET_UNIT:IsIncludeObject( MUnit ) + self:F2( MUnit ) + local MUnitInclude = true + + if self.Filter.Coalitions then + local MUnitCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + self:T3( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then + MUnitCoalition = true + end + end + MUnitInclude = MUnitInclude and MUnitCoalition + end + + if self.Filter.Categories then + local MUnitCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then + MUnitCategory = true + end + end + MUnitInclude = MUnitInclude and MUnitCategory + end + + if self.Filter.Types then + local MUnitType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) + if TypeName == MUnit:GetTypeName() then + MUnitType = true + end + end + MUnitInclude = MUnitInclude and MUnitType + end + + if self.Filter.Countries then + local MUnitCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) + if country.id[CountryName] == MUnit:GetCountry() then + MUnitCountry = true + end + end + MUnitInclude = MUnitInclude and MUnitCountry + end + + if self.Filter.UnitPrefixes then + local MUnitPrefix = false + for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do + self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) + if string.find( MUnit:GetName(), UnitPrefix, 1 ) then + MUnitPrefix = true + end + end + MUnitInclude = MUnitInclude and MUnitPrefix + end + + if self.Filter.RadarTypes then + local MUnitRadar = false + for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do + self:T3( { "Radar:", RadarType } ) + if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then + if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability. + self:T3( "RADAR Found" ) + end + MUnitRadar = true + end + end + MUnitInclude = MUnitInclude and MUnitRadar + end + + if self.Filter.SEAD then + local MUnitSEAD = false + if MUnit:HasSEAD() == true then + self:T3( "SEAD Found" ) + MUnitSEAD = true + end + MUnitInclude = MUnitInclude and MUnitSEAD + end + + self:T2( MUnitInclude ) + return MUnitInclude +end + + +--- Retrieve the type names of the @{Unit}s in the SET, delimited by an optional delimiter. +-- @param #SET_UNIT self +-- @param #string Delimiter (optional) The delimiter, which is default a comma. +-- @return #string The types of the @{Unit}s delimited. +function SET_UNIT:GetTypeNames( Delimiter ) + + Delimiter = Delimiter or ", " + local TypeReport = REPORT:New() + local Types = {} + + for UnitName, UnitData in pairs( self:GetSet() ) do + + local Unit = UnitData -- Wrapper.Unit#UNIT + local UnitTypeName = Unit:GetTypeName() + + if not Types[UnitTypeName] then + Types[UnitTypeName] = UnitTypeName + TypeReport:Add( UnitTypeName ) + end + end + + return TypeReport:Text( Delimiter ) +end + + +--- SET_CLIENT + + +--- @type SET_CLIENT +-- @extends Core.Set#SET_BASE + + + +--- # 4) SET_CLIENT class, extends @{Set#SET_BASE} +-- +-- Mission designers can use the @{Set#SET_CLIENT} class to build sets of units belonging to certain: +-- +-- * Coalitions +-- * Categories +-- * Countries +-- * Client types +-- * Starting with certain prefix strings. +-- +-- ## 4.1) SET_CLIENT constructor +-- +-- Create a new SET_CLIENT object with the @{#SET_CLIENT.New} method: +-- +-- * @{#SET_CLIENT.New}: Creates a new SET_CLIENT object. +-- +-- ## 4.2) Add or Remove CLIENT(s) from SET_CLIENT +-- +-- CLIENTs can be added and removed using the @{Set#SET_CLIENT.AddClientsByName} and @{Set#SET_CLIENT.RemoveClientsByName} respectively. +-- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. +-- +-- ## 4.3) SET_CLIENT filter criteria +-- +-- You can set filter criteria to define the set of clients within the SET_CLIENT. +-- Filter criteria are defined by: +-- +-- * @{#SET_CLIENT.FilterCoalitions}: Builds the SET_CLIENT with the clients belonging to the coalition(s). +-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies). +-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s). +-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). +-- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s). +-- +-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: +-- +-- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients within the SET_CLIENT. +-- +-- Planned filter criteria within development are (so these are not yet available): +-- +-- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Zone#ZONE}. +-- +-- ## 4.4) SET_CLIENT iterators +-- +-- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. +-- The iterator methods will walk the SET_CLIENT set, and call for each element within the set a function that you provide. +-- The following iterator methods are currently available within the SET_CLIENT: +-- +-- * @{#SET_CLIENT.ForEachClient}: Calls a function for each alive client it finds within the SET_CLIENT. +-- +-- === +-- @field #SET_CLIENT SET_CLIENT +SET_CLIENT = { + ClassName = "SET_CLIENT", + Clients = {}, + Filter = { + Coalitions = nil, + Categories = nil, + Types = nil, + Countries = nil, + ClientPrefixes = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + plane = Unit.Category.AIRPLANE, + helicopter = Unit.Category.HELICOPTER, + ground = Unit.Category.GROUND_UNIT, + ship = Unit.Category.SHIP, + structure = Unit.Category.STRUCTURE, + }, + }, +} + + +--- Creates a new SET_CLIENT object, building a set of clients belonging to a coalitions, categories, countries, types or with defined prefix names. +-- @param #SET_CLIENT self +-- @return #SET_CLIENT +-- @usage +-- -- Define a new SET_CLIENT Object. This DBObject will contain a reference to all Clients. +-- DBObject = SET_CLIENT:New() +function SET_CLIENT:New() + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CLIENTS ) ) + + return self +end + +--- Add CLIENT(s) to SET_CLIENT. +-- @param Core.Set#SET_CLIENT self +-- @param #string AddClientNames A single name or an array of CLIENT names. +-- @return self +function SET_CLIENT:AddClientsByName( AddClientNames ) + + local AddClientNamesArray = ( type( AddClientNames ) == "table" ) and AddClientNames or { AddClientNames } + + for AddClientID, AddClientName in pairs( AddClientNamesArray ) do + self:Add( AddClientName, CLIENT:FindByName( AddClientName ) ) + end + + return self +end + +--- Remove CLIENT(s) from SET_CLIENT. +-- @param Core.Set#SET_CLIENT self +-- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names. +-- @return self +function SET_CLIENT:RemoveClientsByName( RemoveClientNames ) + + local RemoveClientNamesArray = ( type( RemoveClientNames ) == "table" ) and RemoveClientNames or { RemoveClientNames } + + for RemoveClientID, RemoveClientName in pairs( RemoveClientNamesArray ) do + self:Remove( RemoveClientName.ClientName ) + end + + return self +end + + +--- Finds a Client based on the Client Name. +-- @param #SET_CLIENT self +-- @param #string ClientName +-- @return Wrapper.Client#CLIENT The found Client. +function SET_CLIENT:FindClient( ClientName ) + + local ClientFound = self.Set[ClientName] + return ClientFound +end + + + +--- Builds a set of clients of coalitions. +-- Possible current coalitions are red, blue and neutral. +-- @param #SET_CLIENT self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #SET_CLIENT self +function SET_CLIENT:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end + + +--- Builds a set of clients out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #SET_CLIENT self +-- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". +-- @return #SET_CLIENT self +function SET_CLIENT:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end + + +--- Builds a set of clients of defined client types. +-- Possible current types are those types known within DCS world. +-- @param #SET_CLIENT self +-- @param #string Types Can take those type strings known within DCS world. +-- @return #SET_CLIENT self +function SET_CLIENT:FilterTypes( Types ) + if not self.Filter.Types then + self.Filter.Types = {} + end + if type( Types ) ~= "table" then + Types = { Types } + end + for TypeID, Type in pairs( Types ) do + self.Filter.Types[Type] = Type + end + return self +end + + +--- Builds a set of clients of defined countries. +-- Possible current countries are those known within DCS world. +-- @param #SET_CLIENT self +-- @param #string Countries Can take those country strings known within DCS world. +-- @return #SET_CLIENT self +function SET_CLIENT:FilterCountries( Countries ) + if not self.Filter.Countries then + self.Filter.Countries = {} + end + if type( Countries ) ~= "table" then + Countries = { Countries } + end + for CountryID, Country in pairs( Countries ) do + self.Filter.Countries[Country] = Country + end + return self +end + + +--- Builds a set of clients of defined client prefixes. +-- All the clients starting with the given prefixes will be included within the set. +-- @param #SET_CLIENT self +-- @param #string Prefixes The prefix of which the client name starts with. +-- @return #SET_CLIENT self +function SET_CLIENT:FilterPrefixes( Prefixes ) + if not self.Filter.ClientPrefixes then + self.Filter.ClientPrefixes = {} + end + if type( Prefixes ) ~= "table" then + Prefixes = { Prefixes } + end + for PrefixID, Prefix in pairs( Prefixes ) do + self.Filter.ClientPrefixes[Prefix] = Prefix + end + return self +end + + + + +--- Starts the filtering. +-- @param #SET_CLIENT self +-- @return #SET_CLIENT self +function SET_CLIENT:FilterStart() + + if _DATABASE then + self:_FilterStart() + end + + return self +end + +--- Handles the Database to check on an event (birth) that the Object was added in the Database. +-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! +-- @param #SET_CLIENT self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the CLIENT +-- @return #table The CLIENT +function SET_CLIENT:AddInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Handles the Database to check on any event that Object exists in the Database. +-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! +-- @param #SET_CLIENT self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the CLIENT +-- @return #table The CLIENT +function SET_CLIENT:FindInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Iterate the SET_CLIENT and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters. +-- @param #SET_CLIENT self +-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. +-- @return #SET_CLIENT self +function SET_CLIENT:ForEachClient( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self +end + +--- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence completely in a @{Zone}, providing the CLIENT and optional parameters to the called function. +-- @param #SET_CLIENT self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. +-- @return #SET_CLIENT self +function SET_CLIENT:ForEachClientInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Client#CLIENT ClientObject + function( ZoneObject, ClientObject ) + if ClientObject:IsInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence not in a @{Zone}, providing the CLIENT and optional parameters to the called function. +-- @param #SET_CLIENT self +-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. +-- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. +-- @return #SET_CLIENT self +function SET_CLIENT:ForEachClientNotInZone( ZoneObject, IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set, + --- @param Core.Zone#ZONE_BASE ZoneObject + -- @param Wrapper.Client#CLIENT ClientObject + function( ZoneObject, ClientObject ) + if ClientObject:IsNotInZone( ZoneObject ) then + return true + else + return false + end + end, { ZoneObject } ) + + return self +end + +--- +-- @param #SET_CLIENT self +-- @param Wrapper.Client#CLIENT MClient +-- @return #SET_CLIENT self +function SET_CLIENT:IsIncludeObject( MClient ) + self:F2( MClient ) + + local MClientInclude = true + + if MClient then + local MClientName = MClient.UnitName + + if self.Filter.Coalitions then + local MClientCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName ) + self:T3( { "Coalition:", ClientCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == ClientCoalitionID then + MClientCoalition = true + end + end + self:T( { "Evaluated Coalition", MClientCoalition } ) + MClientInclude = MClientInclude and MClientCoalition + end + + if self.Filter.Categories then + local MClientCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName ) + self:T3( { "Category:", ClientCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == ClientCategoryID then + MClientCategory = true + end + end + self:T( { "Evaluated Category", MClientCategory } ) + MClientInclude = MClientInclude and MClientCategory + end + + if self.Filter.Types then + local MClientType = false + for TypeID, TypeName in pairs( self.Filter.Types ) do + self:T3( { "Type:", MClient:GetTypeName(), TypeName } ) + if TypeName == MClient:GetTypeName() then + MClientType = true + end + end + self:T( { "Evaluated Type", MClientType } ) + MClientInclude = MClientInclude and MClientType + end + + if self.Filter.Countries then + local MClientCountry = false + for CountryID, CountryName in pairs( self.Filter.Countries ) do + local ClientCountryID = _DATABASE:GetCountryFromClientTemplate(MClientName) + self:T3( { "Country:", ClientCountryID, country.id[CountryName], CountryName } ) + if country.id[CountryName] and country.id[CountryName] == ClientCountryID then + MClientCountry = true + end + end + self:T( { "Evaluated Country", MClientCountry } ) + MClientInclude = MClientInclude and MClientCountry + end + + if self.Filter.ClientPrefixes then + local MClientPrefix = false + for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do + self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } ) + if string.find( MClient.UnitName, ClientPrefix, 1 ) then + MClientPrefix = true + end + end + self:T( { "Evaluated Prefix", MClientPrefix } ) + MClientInclude = MClientInclude and MClientPrefix + end + end + + self:T2( MClientInclude ) + return MClientInclude +end + +--- @type SET_AIRBASE +-- @extends Core.Set#SET_BASE + +--- # 5) SET_AIRBASE class, extends @{Set#SET_BASE} +-- +-- Mission designers can use the @{Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: +-- +-- * Coalitions +-- +-- ## 5.1) SET_AIRBASE constructor +-- +-- Create a new SET_AIRBASE object with the @{#SET_AIRBASE.New} method: +-- +-- * @{#SET_AIRBASE.New}: Creates a new SET_AIRBASE object. +-- +-- ## 5.2) Add or Remove AIRBASEs from SET_AIRBASE +-- +-- AIRBASEs can be added and removed using the @{Set#SET_AIRBASE.AddAirbasesByName} and @{Set#SET_AIRBASE.RemoveAirbasesByName} respectively. +-- These methods take a single AIRBASE name or an array of AIRBASE names to be added or removed from SET_AIRBASE. +-- +-- ## 5.3) SET_AIRBASE filter criteria +-- +-- You can set filter criteria to define the set of clients within the SET_AIRBASE. +-- Filter criteria are defined by: +-- +-- * @{#SET_AIRBASE.FilterCoalitions}: Builds the SET_AIRBASE with the airbases belonging to the coalition(s). +-- +-- Once the filter criteria have been set for the SET_AIRBASE, you can start filtering using: +-- +-- * @{#SET_AIRBASE.FilterStart}: Starts the filtering of the airbases within the SET_AIRBASE. +-- +-- ## 5.4) SET_AIRBASE iterators +-- +-- Once the filters have been defined and the SET_AIRBASE has been built, you can iterate the SET_AIRBASE with the available iterator methods. +-- The iterator methods will walk the SET_AIRBASE set, and call for each airbase within the set a function that you provide. +-- The following iterator methods are currently available within the SET_AIRBASE: +-- +-- * @{#SET_AIRBASE.ForEachAirbase}: Calls a function for each airbase it finds within the SET_AIRBASE. +-- +-- === +-- @field #SET_AIRBASE SET_AIRBASE +SET_AIRBASE = { + ClassName = "SET_AIRBASE", + Airbases = {}, + Filter = { + Coalitions = nil, + }, + FilterMeta = { + Coalitions = { + red = coalition.side.RED, + blue = coalition.side.BLUE, + neutral = coalition.side.NEUTRAL, + }, + Categories = { + airdrome = Airbase.Category.AIRDROME, + helipad = Airbase.Category.HELIPAD, + ship = Airbase.Category.SHIP, + }, + }, +} + + +--- Creates a new SET_AIRBASE object, building a set of airbases belonging to a coalitions and categories. +-- @param #SET_AIRBASE self +-- @return #SET_AIRBASE self +-- @usage +-- -- Define a new SET_AIRBASE Object. The DatabaseSet will contain a reference to all Airbases. +-- DatabaseSet = SET_AIRBASE:New() +function SET_AIRBASE:New() + -- Inherits from BASE + local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.AIRBASES ) ) + + return self +end + +--- Add AIRBASEs to SET_AIRBASE. +-- @param Core.Set#SET_AIRBASE self +-- @param #string AddAirbaseNames A single name or an array of AIRBASE names. +-- @return self +function SET_AIRBASE:AddAirbasesByName( AddAirbaseNames ) + + local AddAirbaseNamesArray = ( type( AddAirbaseNames ) == "table" ) and AddAirbaseNames or { AddAirbaseNames } + + for AddAirbaseID, AddAirbaseName in pairs( AddAirbaseNamesArray ) do + self:Add( AddAirbaseName, AIRBASE:FindByName( AddAirbaseName ) ) + end + + return self +end + +--- Remove AIRBASEs from SET_AIRBASE. +-- @param Core.Set#SET_AIRBASE self +-- @param Wrapper.Airbase#AIRBASE RemoveAirbaseNames A single name or an array of AIRBASE names. +-- @return self +function SET_AIRBASE:RemoveAirbasesByName( RemoveAirbaseNames ) + + local RemoveAirbaseNamesArray = ( type( RemoveAirbaseNames ) == "table" ) and RemoveAirbaseNames or { RemoveAirbaseNames } + + for RemoveAirbaseID, RemoveAirbaseName in pairs( RemoveAirbaseNamesArray ) do + self:Remove( RemoveAirbaseName.AirbaseName ) + end + + return self +end + + +--- Finds a Airbase based on the Airbase Name. +-- @param #SET_AIRBASE self +-- @param #string AirbaseName +-- @return Wrapper.Airbase#AIRBASE The found Airbase. +function SET_AIRBASE:FindAirbase( AirbaseName ) + + local AirbaseFound = self.Set[AirbaseName] + return AirbaseFound +end + + + +--- Builds a set of airbases of coalitions. +-- Possible current coalitions are red, blue and neutral. +-- @param #SET_AIRBASE self +-- @param #string Coalitions Can take the following values: "red", "blue", "neutral". +-- @return #SET_AIRBASE self +function SET_AIRBASE:FilterCoalitions( Coalitions ) + if not self.Filter.Coalitions then + self.Filter.Coalitions = {} + end + if type( Coalitions ) ~= "table" then + Coalitions = { Coalitions } + end + for CoalitionID, Coalition in pairs( Coalitions ) do + self.Filter.Coalitions[Coalition] = Coalition + end + return self +end + + +--- Builds a set of airbases out of categories. +-- Possible current categories are plane, helicopter, ground, ship. +-- @param #SET_AIRBASE self +-- @param #string Categories Can take the following values: "airdrome", "helipad", "ship". +-- @return #SET_AIRBASE self +function SET_AIRBASE:FilterCategories( Categories ) + if not self.Filter.Categories then + self.Filter.Categories = {} + end + if type( Categories ) ~= "table" then + Categories = { Categories } + end + for CategoryID, Category in pairs( Categories ) do + self.Filter.Categories[Category] = Category + end + return self +end + +--- Starts the filtering. +-- @param #SET_AIRBASE self +-- @return #SET_AIRBASE self +function SET_AIRBASE:FilterStart() + + if _DATABASE then + self:_FilterStart() + end + + return self +end + + +--- Handles the Database to check on an event (birth) that the Object was added in the Database. +-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! +-- @param #SET_AIRBASE self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the AIRBASE +-- @return #table The AIRBASE +function SET_AIRBASE:AddInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Handles the Database to check on any event that Object exists in the Database. +-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! +-- @param #SET_AIRBASE self +-- @param Core.Event#EVENTDATA Event +-- @return #string The name of the AIRBASE +-- @return #table The AIRBASE +function SET_AIRBASE:FindInDatabase( Event ) + self:F3( { Event } ) + + return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] +end + +--- Iterate the SET_AIRBASE and call an interator function for each AIRBASE, providing the AIRBASE and optional parameters. +-- @param #SET_AIRBASE self +-- @param #function IteratorFunction The function that will be called when there is an alive AIRBASE in the SET_AIRBASE. The function needs to accept a AIRBASE parameter. +-- @return #SET_AIRBASE self +function SET_AIRBASE:ForEachAirbase( IteratorFunction, ... ) + self:F2( arg ) + + self:ForEach( IteratorFunction, arg, self.Set ) + + return self +end + +--- Iterate the SET_AIRBASE while identifying the nearest @{Airbase#AIRBASE} from a @{Point#POINT_VEC2}. +-- @param #SET_AIRBASE self +-- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Airbase#AIRBASE}. +-- @return Wrapper.Airbase#AIRBASE The closest @{Airbase#AIRBASE}. +function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 ) + self:F2( PointVec2 ) + + local NearestAirbase = self:FindNearestObjectFromPointVec2( PointVec2 ) + return NearestAirbase +end + + + +--- +-- @param #SET_AIRBASE self +-- @param Wrapper.Airbase#AIRBASE MAirbase +-- @return #SET_AIRBASE self +function SET_AIRBASE:IsIncludeObject( MAirbase ) + self:F2( MAirbase ) + + local MAirbaseInclude = true + + if MAirbase then + local MAirbaseName = MAirbase:GetName() + + if self.Filter.Coalitions then + local MAirbaseCoalition = false + for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do + local AirbaseCoalitionID = _DATABASE:GetCoalitionFromAirbase( MAirbaseName ) + self:T3( { "Coalition:", AirbaseCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) + if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == AirbaseCoalitionID then + MAirbaseCoalition = true + end + end + self:T( { "Evaluated Coalition", MAirbaseCoalition } ) + MAirbaseInclude = MAirbaseInclude and MAirbaseCoalition + end + + if self.Filter.Categories then + local MAirbaseCategory = false + for CategoryID, CategoryName in pairs( self.Filter.Categories ) do + local AirbaseCategoryID = _DATABASE:GetCategoryFromAirbase( MAirbaseName ) + self:T3( { "Category:", AirbaseCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) + if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == AirbaseCategoryID then + MAirbaseCategory = true + end + end + self:T( { "Evaluated Category", MAirbaseCategory } ) + MAirbaseInclude = MAirbaseInclude and MAirbaseCategory + end + end + + self:T2( MAirbaseInclude ) + return MAirbaseInclude +end +--- **Core** - **POINT\_VEC** classes define an **extensive API** to **manage 3D points** in the simulation space. +-- +-- 1) @{Point#POINT_VEC3} class, extends @{Base#BASE} +-- ================================================== +-- The @{Point#POINT_VEC3} class defines a 3D point in the simulator. +-- +-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. +-- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums. +-- +-- ## 1.1) POINT_VEC3 constructor +-- +-- A new POINT_VEC3 instance can be created with: +-- +-- * @{Point#POINT_VEC3.New}(): a 3D point. +-- * @{Point#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}. +-- +-- ## 1.2) Manupulate the X, Y, Z coordinates of the point +-- +-- A POINT_VEC3 class works in 3D space. It contains internally an X, Y, Z coordinate. +-- Methods exist to manupulate these coordinates. +-- +-- The current X, Y, Z axis can be retrieved with the methods @{#POINT_VEC3.GetX}(), @{#POINT_VEC3.GetY}(), @{#POINT_VEC3.GetZ}() respectively. +-- The methods @{#POINT_VEC3.SetX}(), @{#POINT_VEC3.SetY}(), @{#POINT_VEC3.SetZ}() change the respective axis with a new value. +-- The current axis values can be changed by using the methods @{#POINT_VEC3.AddX}(), @{#POINT_VEC3.AddY}(), @{#POINT_VEC3.AddZ}() +-- to add or substract a value from the current respective axis value. +-- Note that the Set and Add methods return the current POINT_VEC3 object, so these manipulation methods can be chained... For example: +-- +-- local Vec3 = PointVec3:AddX( 100 ):AddZ( 150 ):GetVec3() +-- +-- ## 1.3) Create waypoints for routes +-- +-- A POINT_VEC3 can prepare waypoints for Ground, Air and Naval groups to be embedded into a Route. +-- +-- +-- ## 1.5) Smoke, flare, explode, illuminate +-- +-- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods: +-- +-- ### 1.5.1) Smoke +-- +-- * @{#POINT_VEC3.Smoke}(): To smoke the point in a certain color. +-- * @{#POINT_VEC3.SmokeBlue}(): To smoke the point in blue. +-- * @{#POINT_VEC3.SmokeRed}(): To smoke the point in red. +-- * @{#POINT_VEC3.SmokeOrange}(): To smoke the point in orange. +-- * @{#POINT_VEC3.SmokeWhite}(): To smoke the point in white. +-- * @{#POINT_VEC3.SmokeGreen}(): To smoke the point in green. +-- +-- ### 1.5.2) Flare +-- +-- * @{#POINT_VEC3.Flare}(): To flare the point in a certain color. +-- * @{#POINT_VEC3.FlareRed}(): To flare the point in red. +-- * @{#POINT_VEC3.FlareYellow}(): To flare the point in yellow. +-- * @{#POINT_VEC3.FlareWhite}(): To flare the point in white. +-- * @{#POINT_VEC3.FlareGreen}(): To flare the point in green. +-- +-- ### 1.5.3) Explode +-- +-- * @{#POINT_VEC3.Explosion}(): To explode the point with a certain intensity. +-- +-- ### 1.5.4) Illuminate +-- +-- * @{#POINT_VEC3.IlluminationBomb}(): To illuminate the point. +-- +-- +-- 2) @{Point#POINT_VEC2} class, extends @{Point#POINT_VEC3} +-- ========================================================= +-- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. +-- +-- 2.1) POINT_VEC2 constructor +-- --------------------------- +-- A new POINT_VEC2 instance can be created with: +-- +-- * @{Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. +-- * @{Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCSTypes#Vec2}. +-- +-- ## 1.2) Manupulate the X, Altitude, Y coordinates of the 2D point +-- +-- A POINT_VEC2 class works in 2D space, with an altitude setting. It contains internally an X, Altitude, Y coordinate. +-- Methods exist to manupulate these coordinates. +-- +-- The current X, Altitude, Y axis can be retrieved with the methods @{#POINT_VEC2.GetX}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetY}() respectively. +-- The methods @{#POINT_VEC2.SetX}(), @{#POINT_VEC2.SetAlt}(), @{#POINT_VEC2.SetY}() change the respective axis with a new value. +-- The current Lat(itude), Alt(itude), Lon(gitude) values can also be retrieved with the methods @{#POINT_VEC2.GetLat}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetLon}() respectively. +-- The current axis values can be changed by using the methods @{#POINT_VEC2.AddX}(), @{#POINT_VEC2.AddAlt}(), @{#POINT_VEC2.AddY}() +-- to add or substract a value from the current respective axis value. +-- Note that the Set and Add methods return the current POINT_VEC2 object, so these manipulation methods can be chained... For example: +-- +-- local Vec2 = PointVec2:AddX( 100 ):AddY( 2000 ):GetVec2() +-- +-- === +-- +-- **API CHANGE HISTORY** +-- ====================== +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-03-03: POINT\_VEC3:**Explosion( ExplosionIntensity )** added. +-- 2017-03-03: POINT\_VEC3:**IlluminationBomb()** added. +-- +-- 2017-02-18: POINT\_VEC3:**NewFromVec2( Vec2, LandHeightAdd )** added. +-- +-- 2016-08-12: POINT\_VEC3:**Translate( Distance, Angle )** added. +-- +-- 2016-08-06: Made PointVec3 and Vec3, PointVec2 and Vec2 terminology used in the code consistent. +-- +-- * Replaced method _Point_Vec3() to **Vec3**() where the code manages a Vec3. Replaced all references to the method. +-- * Replaced method _Point_Vec2() to **Vec2**() where the code manages a Vec2. Replaced all references to the method. +-- * Replaced method Random_Point_Vec3() to **RandomVec3**() where the code manages a Vec3. Replaced all references to the method. +-- . +-- === +-- +-- ### Authors: +-- +-- * FlightControl : Design & Programming +-- +-- ### Contributions: +-- +-- @module Point + +--- The POINT_VEC3 class +-- @type POINT_VEC3 +-- @field #number x The x coordinate in 3D space. +-- @field #number y The y coordinate in 3D space. +-- @field #number z The z coordiante in 3D space. +-- @field Utilities.Utils#SMOKECOLOR SmokeColor +-- @field Utilities.Utils#FLARECOLOR FlareColor +-- @field #POINT_VEC3.RoutePointAltType RoutePointAltType +-- @field #POINT_VEC3.RoutePointType RoutePointType +-- @field #POINT_VEC3.RoutePointAction RoutePointAction +-- @extends Core.Base#BASE +POINT_VEC3 = { + ClassName = "POINT_VEC3", + Metric = true, + RoutePointAltType = { + BARO = "BARO", + }, + RoutePointType = { + TakeOffParking = "TakeOffParking", + TurningPoint = "Turning Point", + }, + RoutePointAction = { + FromParkingArea = "From Parking Area", + TurningPoint = "Turning Point", + }, +} + +--- The POINT_VEC2 class +-- @type POINT_VEC2 +-- @field Dcs.DCSTypes#Distance x The x coordinate in meters. +-- @field Dcs.DCSTypes#Distance y the y coordinate in meters. +-- @extends Core.Point#POINT_VEC3 +POINT_VEC2 = { + ClassName = "POINT_VEC2", +} + + +do -- POINT_VEC3 + +--- RoutePoint AltTypes +-- @type POINT_VEC3.RoutePointAltType +-- @field BARO "BARO" + +--- RoutePoint Types +-- @type POINT_VEC3.RoutePointType +-- @field TakeOffParking "TakeOffParking" +-- @field TurningPoint "Turning Point" + +--- RoutePoint Actions +-- @type POINT_VEC3.RoutePointAction +-- @field FromParkingArea "From Parking Area" +-- @field TurningPoint "Turning Point" + +-- Constructor. + +--- Create a new POINT_VEC3 object. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. +-- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing Upwards. +-- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. +-- @return Core.Point#POINT_VEC3 self +function POINT_VEC3:New( x, y, z ) + + local self = BASE:Inherit( self, BASE:New() ) + self.x = x + self.y = y + self.z = z + + return self +end + +--- Create a new POINT_VEC3 object from Vec2 coordinates. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. +-- @return Core.Point#POINT_VEC3 self +function POINT_VEC3:NewFromVec2( Vec2, LandHeightAdd ) + + local LandHeight = land.getHeight( Vec2 ) + + LandHeightAdd = LandHeightAdd or 0 + LandHeight = LandHeight + LandHeightAdd + + self = self:New( Vec2.x, LandHeight, Vec2.y ) + + self:F2( self ) + + return self +end + +--- Create a new POINT_VEC3 object from Vec3 coordinates. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. +-- @return Core.Point#POINT_VEC3 self +function POINT_VEC3:NewFromVec3( Vec3 ) + + self = self:New( Vec3.x, Vec3.y, Vec3.z ) + self:F2( self ) + return self +end + + +--- Return the coordinates of the POINT_VEC3 in Vec3 format. +-- @param #POINT_VEC3 self +-- @return Dcs.DCSTypes#Vec3 The Vec3 coodinate. +function POINT_VEC3:GetVec3() + return { x = self.x, y = self.y, z = self.z } +end + +--- Return the coordinates of the POINT_VEC3 in Vec2 format. +-- @param #POINT_VEC3 self +-- @return Dcs.DCSTypes#Vec2 The Vec2 coodinate. +function POINT_VEC3:GetVec2() + return { x = self.x, y = self.z } +end + + +--- Return the x coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @return #number The x coodinate. +function POINT_VEC3:GetX() + return self.x +end + +--- Return the y coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @return #number The y coodinate. +function POINT_VEC3:GetY() + return self.y +end + +--- Return the z coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @return #number The z coodinate. +function POINT_VEC3:GetZ() + return self.z +end + +--- Set the x coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number x The x coordinate. +-- @return #POINT_VEC3 +function POINT_VEC3:SetX( x ) + self.x = x + return self +end + +--- Set the y coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number y The y coordinate. +-- @return #POINT_VEC3 +function POINT_VEC3:SetY( y ) + self.y = y + return self +end + +--- Set the z coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number z The z coordinate. +-- @return #POINT_VEC3 +function POINT_VEC3:SetZ( z ) + self.z = z + return self +end + +--- Add to the x coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number x The x coordinate value to add to the current x coodinate. +-- @return #POINT_VEC3 +function POINT_VEC3:AddX( x ) + self.x = self.x + x + return self +end + +--- Add to the y coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number y The y coordinate value to add to the current y coodinate. +-- @return #POINT_VEC3 +function POINT_VEC3:AddY( y ) + self.y = self.y + y + return self +end + +--- Add to the z coordinate of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #number z The z coordinate value to add to the current z coodinate. +-- @return #POINT_VEC3 +function POINT_VEC3:AddZ( z ) + self.z = self.z +z + return self +end + +--- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance OuterRadius +-- @param Dcs.DCSTypes#Distance InnerRadius +-- @return Dcs.DCSTypes#Vec2 Vec2 +function POINT_VEC3:GetRandomVec2InRadius( OuterRadius, InnerRadius ) + self:F2( { OuterRadius, InnerRadius } ) + + local Theta = 2 * math.pi * math.random() + local Radials = math.random() + math.random() + if Radials > 1 then + Radials = 2 - Radials + end + + local RadialMultiplier + if InnerRadius and InnerRadius <= OuterRadius then + RadialMultiplier = ( OuterRadius - InnerRadius ) * Radials + InnerRadius + else + RadialMultiplier = OuterRadius * Radials + end + + local RandomVec2 + if OuterRadius > 0 then + RandomVec2 = { x = math.cos( Theta ) * RadialMultiplier + self:GetX(), y = math.sin( Theta ) * RadialMultiplier + self:GetZ() } + else + RandomVec2 = { x = self:GetX(), y = self:GetZ() } + end + + return RandomVec2 +end + +--- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance OuterRadius +-- @param Dcs.DCSTypes#Distance InnerRadius +-- @return #POINT_VEC2 +function POINT_VEC3:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) + self:F2( { OuterRadius, InnerRadius } ) + + return POINT_VEC2:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) +end + +--- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance OuterRadius +-- @param Dcs.DCSTypes#Distance InnerRadius +-- @return Dcs.DCSTypes#Vec3 Vec3 +function POINT_VEC3:GetRandomVec3InRadius( OuterRadius, InnerRadius ) + + local RandomVec2 = self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) + local y = self:GetY() + math.random( InnerRadius, OuterRadius ) + local RandomVec3 = { x = RandomVec2.x, y = y, z = RandomVec2.y } + + return RandomVec3 +end + +--- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance OuterRadius +-- @param Dcs.DCSTypes#Distance InnerRadius +-- @return #POINT_VEC3 +function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) + + return POINT_VEC3:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) +end + + +--- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. +-- @return Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. +function POINT_VEC3:GetDirectionVec3( TargetPointVec3 ) + return { x = TargetPointVec3:GetX() - self:GetX(), y = TargetPointVec3:GetY() - self:GetY(), z = TargetPointVec3:GetZ() - self:GetZ() } +end + +--- Get a correction in radians of the real magnetic north of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @return #number CorrectionRadians The correction in radians. +function POINT_VEC3:GetNorthCorrectionRadians() + local TargetVec3 = self:GetVec3() + local lat, lon = coord.LOtoLL(TargetVec3) + local north_posit = coord.LLtoLO(lat + 1, lon) + return math.atan2( north_posit.z - TargetVec3.z, north_posit.x - TargetVec3.x ) +end + + +--- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. +-- @return #number DirectionRadians The direction in radians. +function POINT_VEC3:GetDirectionRadians( DirectionVec3 ) + local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x ) + --DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians() + if DirectionRadians < 0 then + DirectionRadians = DirectionRadians + 2 * math.pi -- put dir in range of 0 to 2*pi ( the full circle ) + end + return DirectionRadians +end + +--- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. +-- @return Dcs.DCSTypes#Distance Distance The distance in meters. +function POINT_VEC3:Get2DDistance( TargetPointVec3 ) + local TargetVec3 = TargetPointVec3:GetVec3() + local SourceVec3 = self:GetVec3() + return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 +end + +--- Return the 3D distance in meters between the target POINT_VEC3 and the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. +-- @return Dcs.DCSTypes#Distance Distance The distance in meters. +function POINT_VEC3:Get3DDistance( TargetPointVec3 ) + local TargetVec3 = TargetPointVec3:GetVec3() + local SourceVec3 = self:GetVec3() + return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 +end + +--- Provides a Bearing / Range string +-- @param #POINT_VEC3 self +-- @param #number AngleRadians The angle in randians +-- @param #number Distance The distance +-- @return #string The BR Text +function POINT_VEC3:ToStringBR( AngleRadians, Distance ) + + AngleRadians = UTILS.Round( UTILS.ToDegree( AngleRadians ), 0 ) + if self:IsMetric() then + Distance = UTILS.Round( Distance / 1000, 2 ) + else + Distance = UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) + end + + local s = string.format( '%03d', AngleRadians ) .. ' for ' .. Distance + + s = s .. self:GetAltitudeText() -- When the POINT is a VEC2, there will be no altitude shown. + + return s +end + +--- Provides a Bearing / Range string +-- @param #POINT_VEC3 self +-- @param #number AngleRadians The angle in randians +-- @param #number Distance The distance +-- @return #string The BR Text +function POINT_VEC3:ToStringLL( acc, DMS ) + + acc = acc or 3 + local lat, lon = coord.LOtoLL( self:GetVec3() ) + return UTILS.tostringLL(lat, lon, acc, DMS) +end + +--- Return the altitude text of the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @return #string Altitude text. +function POINT_VEC3:GetAltitudeText() + if self:IsMetric() then + return ' at ' .. UTILS.Round( self:GetY(), 0 ) + else + return ' at ' .. UTILS.Round( UTILS.MetersToFeet( self:GetY() ), 0 ) + end +end + +--- Return a BR string from a POINT_VEC3 to the POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. +-- @return #string The BR text. +function POINT_VEC3:GetBRText( TargetPointVec3 ) + local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 ) + local AngleRadians = self:GetDirectionRadians( DirectionVec3 ) + local Distance = self:Get2DDistance( TargetPointVec3 ) + return self:ToStringBR( AngleRadians, Distance ) +end + +--- Sets the POINT_VEC3 metric or NM. +-- @param #POINT_VEC3 self +-- @param #boolean Metric true means metric, false means NM. +function POINT_VEC3:SetMetric( Metric ) + self.Metric = Metric +end + +--- Gets if the POINT_VEC3 is metric or NM. +-- @param #POINT_VEC3 self +-- @return #boolean Metric true means metric, false means NM. +function POINT_VEC3:IsMetric() + return self.Metric +end + +--- Add a Distance in meters from the POINT_VEC3 horizontal plane, with the given angle, and calculate the new POINT_VEC3. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. +-- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. +-- @return #POINT_VEC3 The new calculated POINT_VEC3. +function POINT_VEC3:Translate( Distance, Angle ) + local SX = self:GetX() + local SZ = self:GetZ() + local Radians = Angle / 180 * math.pi + local TX = Distance * math.cos( Radians ) + SX + local TZ = Distance * math.sin( Radians ) + SZ + + return POINT_VEC3:New( TX, self:GetY(), TZ ) +end + + + +--- Build an air type route point. +-- @param #POINT_VEC3 self +-- @param #POINT_VEC3.RoutePointAltType AltType The altitude type. +-- @param #POINT_VEC3.RoutePointType Type The route point type. +-- @param #POINT_VEC3.RoutePointAction Action The route point action. +-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. +-- @param #boolean SpeedLocked true means the speed is locked. +-- @return #table The route point. +function POINT_VEC3:RoutePointAir( AltType, Type, Action, Speed, SpeedLocked ) + self:F2( { AltType, Type, Action, Speed, SpeedLocked } ) + + local RoutePoint = {} + RoutePoint.x = self.x + RoutePoint.y = self.z + RoutePoint.alt = self.y + RoutePoint.alt_type = AltType + + RoutePoint.type = Type + RoutePoint.action = Action + + RoutePoint.speed = Speed / 3.6 + RoutePoint.speed_locked = true + +-- ["task"] = +-- { +-- ["id"] = "ComboTask", +-- ["params"] = +-- { +-- ["tasks"] = +-- { +-- }, -- end of ["tasks"] +-- }, -- end of ["params"] +-- }, -- end of ["task"] + + + RoutePoint.task = {} + RoutePoint.task.id = "ComboTask" + RoutePoint.task.params = {} + RoutePoint.task.params.tasks = {} + + + return RoutePoint +end + +--- Build an ground type route point. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Speed Speed Speed in km/h. +-- @param #POINT_VEC3.RoutePointAction Formation The route point Formation. +-- @return #table The route point. +function POINT_VEC3:RoutePointGround( Speed, Formation ) + self:F2( { Formation, Speed } ) + + local RoutePoint = {} + RoutePoint.x = self.x + RoutePoint.y = self.z + + RoutePoint.action = Formation or "" + + + RoutePoint.speed = Speed / 3.6 + RoutePoint.speed_locked = true + +-- ["task"] = +-- { +-- ["id"] = "ComboTask", +-- ["params"] = +-- { +-- ["tasks"] = +-- { +-- }, -- end of ["tasks"] +-- }, -- end of ["params"] +-- }, -- end of ["task"] + + + RoutePoint.task = {} + RoutePoint.task.id = "ComboTask" + RoutePoint.task.params = {} + RoutePoint.task.params.tasks = {} + + + return RoutePoint +end + +--- Creates an explosion at the point of a certain intensity. +-- @param #POINT_VEC3 self +-- @param #number ExplosionIntensity +function POINT_VEC3:Explosion( ExplosionIntensity ) + self:F2( { ExplosionIntensity } ) + trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) +end + +--- Creates an illumination bomb at the point. +-- @param #POINT_VEC3 self +function POINT_VEC3:IlluminationBomb() + self:F2() + trigger.action.illuminationBomb( self:GetVec3() ) +end + + +--- Smokes the point in a color. +-- @param #POINT_VEC3 self +-- @param Utilities.Utils#SMOKECOLOR SmokeColor +function POINT_VEC3:Smoke( SmokeColor ) + self:F2( { SmokeColor } ) + trigger.action.smoke( self:GetVec3(), SmokeColor ) +end + +--- Smoke the POINT_VEC3 Green. +-- @param #POINT_VEC3 self +function POINT_VEC3:SmokeGreen() + self:F2() + self:Smoke( SMOKECOLOR.Green ) +end + +--- Smoke the POINT_VEC3 Red. +-- @param #POINT_VEC3 self +function POINT_VEC3:SmokeRed() + self:F2() + self:Smoke( SMOKECOLOR.Red ) +end + +--- Smoke the POINT_VEC3 White. +-- @param #POINT_VEC3 self +function POINT_VEC3:SmokeWhite() + self:F2() + self:Smoke( SMOKECOLOR.White ) +end + +--- Smoke the POINT_VEC3 Orange. +-- @param #POINT_VEC3 self +function POINT_VEC3:SmokeOrange() + self:F2() + self:Smoke( SMOKECOLOR.Orange ) +end + +--- Smoke the POINT_VEC3 Blue. +-- @param #POINT_VEC3 self +function POINT_VEC3:SmokeBlue() + self:F2() + self:Smoke( SMOKECOLOR.Blue ) +end + +--- Flares the point in a color. +-- @param #POINT_VEC3 self +-- @param Utilities.Utils#FLARECOLOR FlareColor +-- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. +function POINT_VEC3:Flare( FlareColor, Azimuth ) + self:F2( { FlareColor } ) + trigger.action.signalFlare( self:GetVec3(), FlareColor, Azimuth and Azimuth or 0 ) +end + +--- Flare the POINT_VEC3 White. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. +function POINT_VEC3:FlareWhite( Azimuth ) + self:F2( Azimuth ) + self:Flare( FLARECOLOR.White, Azimuth ) +end + +--- Flare the POINT_VEC3 Yellow. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. +function POINT_VEC3:FlareYellow( Azimuth ) + self:F2( Azimuth ) + self:Flare( FLARECOLOR.Yellow, Azimuth ) +end + +--- Flare the POINT_VEC3 Green. +-- @param #POINT_VEC3 self +-- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. +function POINT_VEC3:FlareGreen( Azimuth ) + self:F2( Azimuth ) + self:Flare( FLARECOLOR.Green, Azimuth ) +end + +--- Flare the POINT_VEC3 Red. +-- @param #POINT_VEC3 self +function POINT_VEC3:FlareRed( Azimuth ) + self:F2( Azimuth ) + self:Flare( FLARECOLOR.Red, Azimuth ) +end + +end + +do -- POINT_VEC2 + + + +--- POINT_VEC2 constructor. +-- @param #POINT_VEC2 self +-- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. +-- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. +-- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. +-- @return Core.Point#POINT_VEC2 +function POINT_VEC2:New( x, y, LandHeightAdd ) + + local LandHeight = land.getHeight( { ["x"] = x, ["y"] = y } ) + + LandHeightAdd = LandHeightAdd or 0 + LandHeight = LandHeight + LandHeightAdd + + self = BASE:Inherit( self, POINT_VEC3:New( x, LandHeight, y ) ) + self:F2( self ) + + return self +end + +--- Create a new POINT_VEC2 object from Vec2 coordinates. +-- @param #POINT_VEC2 self +-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. +-- @return Core.Point#POINT_VEC2 self +function POINT_VEC2:NewFromVec2( Vec2, LandHeightAdd ) + + local LandHeight = land.getHeight( Vec2 ) + + LandHeightAdd = LandHeightAdd or 0 + LandHeight = LandHeight + LandHeightAdd + + self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) + self:F2( self ) + + return self +end + +--- Create a new POINT_VEC2 object from Vec3 coordinates. +-- @param #POINT_VEC2 self +-- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. +-- @return Core.Point#POINT_VEC2 self +function POINT_VEC2:NewFromVec3( Vec3 ) + + local self = BASE:Inherit( self, BASE:New() ) + local Vec2 = { x = Vec3.x, y = Vec3.z } + + local LandHeight = land.getHeight( Vec2 ) + + self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) + self:F2( self ) + + return self +end + +--- Return the x coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @return #number The x coodinate. +function POINT_VEC2:GetX() + return self.x +end + +--- Return the y coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @return #number The y coodinate. +function POINT_VEC2:GetY() + return self.z +end + +--- Return the altitude (height) of the land at the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @return #number The land altitude. +function POINT_VEC2:GetAlt() + return land.getHeight( { x = self.x, y = self.z } ) +end + +--- Return Return the Lat(itude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.x). +-- @param #POINT_VEC2 self +-- @return #number The x coodinate. +function POINT_VEC2:GetLat() + return self.x +end + +--- Return the Lon(gitude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.z). +-- @param #POINT_VEC2 self +-- @return #number The y coodinate. +function POINT_VEC2:GetLon() + return self.z +end + +--- Set the x coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param #number x The x coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:SetX( x ) + self.x = x + return self +end + +--- Set the y coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param #number y The y coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:SetY( y ) + self.z = y + return self +end + +--- Set the Lat(itude) coordinate of the POINT_VEC2 (ie: POINT_VEC3.x). +-- @param #POINT_VEC2 self +-- @param #number x The x coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:SetLat( x ) + self.x = x + return self +end + +--- Set the altitude of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param #number Altitude The land altitude. If nothing (nil) is given, then the current land altitude is set. +-- @return #POINT_VEC2 +function POINT_VEC2:SetAlt( Altitude ) + self.y = Altitude or land.getHeight( { x = self.x, y = self.z } ) + return self +end + +--- Set the Lon(gitude) coordinate of the POINT_VEC2 (ie: POINT_VEC3.z). +-- @param #POINT_VEC2 self +-- @param #number y The y coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:SetLon( z ) + self.z = z + return self +end + +--- Add to the x coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param #number x The x coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:AddX( x ) + self.x = self.x + x + return self +end + +--- Add to the y coordinate of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param #number y The y coordinate. +-- @return #POINT_VEC2 +function POINT_VEC2:AddY( y ) + self.z = self.z + y + return self +end + +--- Add to the current land height an altitude. +-- @param #POINT_VEC2 self +-- @param #number Altitude The Altitude to add. If nothing (nil) is given, then the current land altitude is set. +-- @return #POINT_VEC2 +function POINT_VEC2:AddAlt( Altitude ) + self.y = land.getHeight( { x = self.x, y = self.z } ) + Altitude or 0 + return self +end + + + +--- Calculate the distance from a reference @{#POINT_VEC2}. +-- @param #POINT_VEC2 self +-- @param #POINT_VEC2 PointVec2Reference The reference @{#POINT_VEC2}. +-- @return Dcs.DCSTypes#Distance The distance from the reference @{#POINT_VEC2} in meters. +function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference ) + self:F2( PointVec2Reference ) + + local Distance = ( ( PointVec2Reference:GetX() - self:GetX() ) ^ 2 + ( PointVec2Reference:GetY() - self:GetY() ) ^2 ) ^0.5 + + self:T2( Distance ) + return Distance +end + +--- Calculate the distance from a reference @{DCSTypes#Vec2}. +-- @param #POINT_VEC2 self +-- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{DCSTypes#Vec2}. +-- @return Dcs.DCSTypes#Distance The distance from the reference @{DCSTypes#Vec2} in meters. +function POINT_VEC2:DistanceFromVec2( Vec2Reference ) + self:F2( Vec2Reference ) + + local Distance = ( ( Vec2Reference.x - self:GetX() ) ^ 2 + ( Vec2Reference.y - self:GetY() ) ^2 ) ^0.5 + + self:T2( Distance ) + return Distance +end + + +--- Return no text for the altitude of the POINT_VEC2. +-- @param #POINT_VEC2 self +-- @return #string Empty string. +function POINT_VEC2:GetAltitudeText() + return '' +end + +--- Add a Distance in meters from the POINT_VEC2 orthonormal plane, with the given angle, and calculate the new POINT_VEC2. +-- @param #POINT_VEC2 self +-- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. +-- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. +-- @return #POINT_VEC2 The new calculated POINT_VEC2. +function POINT_VEC2:Translate( Distance, Angle ) + local SX = self:GetX() + local SY = self:GetY() + local Radians = Angle / 180 * math.pi + local TX = Distance * math.cos( Radians ) + SX + local TY = Distance * math.sin( Radians ) + SY + + return POINT_VEC2:New( TX, TY ) +end + +end + + +--- **Core** - MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation. +-- +-- ![Banner Image](..\Presentations\MESSAGE\Dia1.JPG) +-- +-- === +-- +-- # 1) @{Message#MESSAGE} class, extends @{Base#BASE} +-- +-- Message System to display Messages to Clients, Coalitions or All. +-- Messages are shown on the display panel for an amount of seconds, and will then disappear. +-- Messages can contain a category which is indicating the category of the message. +-- +-- ## 1.1) MESSAGE construction +-- +-- Messages are created with @{Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet. +-- To send messages, you need to use the To functions. +-- +-- ## 1.2) Send messages to an audience +-- +-- Messages are sent: +-- +-- * To a @{Client} using @{Message#MESSAGE.ToClient}(). +-- * To a @{Group} using @{Message#MESSAGE.ToGroup}() +-- * To a coalition using @{Message#MESSAGE.ToCoalition}(). +-- * To the red coalition using @{Message#MESSAGE.ToRed}(). +-- * To the blue coalition using @{Message#MESSAGE.ToBlue}(). +-- * To all Players using @{Message#MESSAGE.ToAll}(). +-- +-- ## 1.3) Send conditionally to an audience +-- +-- Messages can be sent conditionally to an audience (when a condition is true): +-- +-- * To all players using @{Message#MESSAGE.ToAllIf}(). +-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}(). +-- +-- +-- @module Message + +--- The MESSAGE class +-- @type MESSAGE +-- @extends Core.Base#BASE +MESSAGE = { + ClassName = "MESSAGE", + MessageCategory = 0, + MessageID = 0, +} + + +--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. +-- @param self +-- @param #string MessageText is the text of the Message. +-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. +-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ". +-- @return #MESSAGE +-- @usage +-- -- Create a series of new Messages. +-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". +-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win". +-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". +-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". +-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" ) +-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" ) +-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ) +-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score") +function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( { MessageText, MessageDuration, MessageCategory } ) + + -- When no MessageCategory is given, we don't show it as a title... + if MessageCategory and MessageCategory ~= "" then + if MessageCategory:sub(-1) ~= "\n" then + self.MessageCategory = MessageCategory .. ": " + else + self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n" + end + else + self.MessageCategory = "" + end + + self.MessageDuration = MessageDuration or 5 + self.MessageTime = timer.getTime() + self.MessageText = MessageText + + self.MessageSent = false + self.MessageGroup = false + self.MessageCoalition = false + + return self +end + +--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player". +-- @param #MESSAGE self +-- @param Wrapper.Client#CLIENT Client is the Group of the Client. +-- @return #MESSAGE +-- @usage +-- -- Send the 2 messages created with the @{New} method to the Client Group. +-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1. +-- ClientGroup = Group.getByName( "ClientGroup" ) +-- +-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) +-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) +-- or +-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) +-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) +-- or +-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ) +-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) +-- MessageClient1:ToClient( ClientGroup ) +-- MessageClient2:ToClient( ClientGroup ) +function MESSAGE:ToClient( Client ) + self:F( Client ) + + if Client and Client:GetClientGroupID() then + + local ClientGroupID = Client:GetClientGroupID() + self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) + trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + end + + return self +end + +--- Sends a MESSAGE to a Group. +-- @param #MESSAGE self +-- @param Wrapper.Group#GROUP Group is the Group. +-- @return #MESSAGE +function MESSAGE:ToGroup( Group ) + self:F( Group.GroupName ) + + if Group then + + self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) + trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + end + + return self +end +--- Sends a MESSAGE to the Blue coalition. +-- @param #MESSAGE self +-- @return #MESSAGE +-- @usage +-- -- Send a message created with the @{New} method to the BLUE coalition. +-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() +-- or +-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() +-- or +-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) +-- MessageBLUE:ToBlue() +function MESSAGE:ToBlue() + self:F() + + self:ToCoalition( coalition.side.BLUE ) + + return self +end + +--- Sends a MESSAGE to the Red Coalition. +-- @param #MESSAGE self +-- @return #MESSAGE +-- @usage +-- -- Send a message created with the @{New} method to the RED coalition. +-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() +-- or +-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() +-- or +-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) +-- MessageRED:ToRed() +function MESSAGE:ToRed( ) + self:F() + + self:ToCoalition( coalition.side.RED ) + + return self +end + +--- Sends a MESSAGE to a Coalition. +-- @param #MESSAGE self +-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. +-- @return #MESSAGE +-- @usage +-- -- Send a message created with the @{New} method to the RED coalition. +-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) +-- or +-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) +-- or +-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) +-- MessageRED:ToCoalition( coalition.side.RED ) +function MESSAGE:ToCoalition( CoalitionSide ) + self:F( CoalitionSide ) + + if CoalitionSide then + self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) + trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) + end + + return self +end + +--- Sends a MESSAGE to a Coalition if the given Condition is true. +-- @param #MESSAGE self +-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. +-- @return #MESSAGE +function MESSAGE:ToCoalitionIf( CoalitionSide, Condition ) + self:F( CoalitionSide ) + + if Condition and Condition == true then + self:ToCoalition( CoalitionSide ) + end + + return self +end + +--- Sends a MESSAGE to all players. +-- @param #MESSAGE self +-- @return #MESSAGE +-- @usage +-- -- Send a message created to all players. +-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() +-- or +-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() +-- or +-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) +-- MessageAll:ToAll() +function MESSAGE:ToAll() + self:F() + + self:ToCoalition( coalition.side.RED ) + self:ToCoalition( coalition.side.BLUE ) + + return self +end + + +--- Sends a MESSAGE to all players if the given Condition is true. +-- @param #MESSAGE self +-- @return #MESSAGE +function MESSAGE:ToAllIf( Condition ) + + if Condition and Condition == true then + self:ToCoalition( coalition.side.RED ) + self:ToCoalition( coalition.side.BLUE ) + end + + return self +end +--- **Core** - The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes +-- are design patterns allowing efficient (long-lasting) processes and workflows. +-- +-- ![Banner Image](..\Presentations\FSM\Dia1.JPG) +-- +-- === +-- +-- A FSM can only be in one of a finite number of states. +-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. +-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. +-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. +-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. +-- +-- The FSM class supports a **hierarchical implementation of a Finite State Machine**, +-- that is, it allows to **embed existing FSM implementations in a master FSM**. +-- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. +-- +-- ![Workflow Example](..\Presentations\FSM\Dia2.JPG) +-- +-- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, +-- orders him to destroy x targets and account the results. +-- Other examples of ready made FSM could be: +-- +-- * route a plane to a zone flown by a human +-- * detect targets by an AI and report to humans +-- * account for destroyed targets by human players +-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle +-- * let an AI patrol a zone +-- +-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, +-- because **the goal of MOOSE is to simplify mission design complexity for mission building**. +-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. +-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, +-- and tailored** by mission designers through **the implementation of Transition Handlers**. +-- Each of these FSM implementation classes start either with: +-- +-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. +-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. +-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. +-- +-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. +-- +-- ##__Dislaimer:__ +-- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. +-- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) +-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. +-- Additionally, I've added extendability and created an API that allows seamless FSM implementation. +-- +-- The following derived classes are available in the MOOSE framework, that implement a specialised form of a FSM: +-- +-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s. +-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s. +-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s. +-- * @{#FSM_SET}: Models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here +-- for multiple objects or the position of the state machine in the process. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) +-- YYYY-MM-DD: CLASS:**NewFunction( Params )** added +-- +-- Hereby the change log: +-- +-- * 2016-12-18: Released. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements. +-- +-- ### Authors: +-- +-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. +-- +-- @module Fsm + +do -- FSM + + --- @type FSM + -- @extends Core.Base#BASE + + + --- # 1) FSM class, extends @{Base#BASE} + -- + -- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG) + -- + -- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. + -- The derived FSM\_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component. + -- + -- Finite State Machines have **Transition Rules**, **Transition Handlers** and **Event Triggers**. + -- + -- The **Transition Rules** define the "Process Flow Boundaries", that is, + -- the path that can be followed hopping from state to state upon triggered events. + -- If an event is triggered, and there is no valid path found for that event, + -- an error will be raised and the FSM will stop functioning. + -- + -- The **Transition Handlers** are special methods that can be defined by the mission designer, following a defined syntax. + -- If the FSM object finds a method of such a handler, then the method will be called by the FSM, passing specific parameters. + -- The method can then define its own custom logic to implement the FSM workflow, and to conduct other actions. + -- + -- The **Event Triggers** are methods that are defined by the FSM, which the mission designer can use to implement the workflow. + -- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. + -- + -- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. + -- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. + -- + -- ## 1.1) FSM Linear Transitions + -- + -- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. + -- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. + -- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. + -- + -- ### 1.1.1) FSM Transition Rules + -- + -- The FSM has transition rules that it follows and validates, as it walks the process. + -- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. + -- + -- The method @{#FSM.AddTransition}() specifies a new possible Transition Rule for the FSM. + -- + -- The initial state can be defined using the method @{#FSM.SetStartState}(). The default start state of an FSM is "None". + -- + -- Find below an example of a Linear Transition Rule definition for an FSM. + -- + -- local Fsm3Switch = FSM:New() -- #FsmDemo + -- FsmSwitch:SetStartState( "Off" ) + -- FsmSwitch:AddTransition( "Off", "SwitchOn", "On" ) + -- FsmSwitch:AddTransition( "Off", "SwitchMiddle", "Middle" ) + -- FsmSwitch:AddTransition( "On", "SwitchOff", "Off" ) + -- FsmSwitch:AddTransition( "Middle", "SwitchOff", "Off" ) + -- + -- The above code snippet models a 3-way switch Linear Transition: + -- + -- * It can be switched **On** by triggering event **SwitchOn**. + -- * It can be switched to the **Middle** position, by triggering event **SwitchMiddle**. + -- * It can be switched **Off** by triggering event **SwitchOff**. + -- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. + -- + -- ### Some additional comments: + -- + -- Note that Linear Transition Rules **can be declared in a few variations**: + -- + -- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. + -- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. + -- + -- The below code snippet shows how the two last lines can be rewritten and consensed. + -- + -- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) + -- + -- ### 1.1.2) Transition Handling + -- + -- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG) + -- + -- An FSM transitions in **4 moments** when an Event is being triggered and processed. + -- The mission designer can define for each moment specific logic within methods implementations following a defined API syntax. + -- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be triggered. + -- + -- * To handle **State** transition moments, create methods starting with OnLeave or OnEnter concatenated with the State name. + -- * To handle **Event** transition moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. + -- + -- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition!** + -- + -- Transition Handler methods need to follow the above specified naming convention, but are also passed parameters from the FSM. + -- These parameters are on the correct order: From, Event, To: + -- + -- * From = A string containing the From state. + -- * Event = A string containing the Event name that was triggered. + -- * To = A string containing the To state. + -- + -- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). + -- + -- ### 1.1.3) Event Triggers + -- + -- ![Event Triggers](..\Presentations\FSM\Dia5.JPG) + -- + -- The FSM creates for each Event two **Event Trigger methods**. + -- There are two modes how Events can be triggered, which is **synchronous** and **asynchronous**: + -- + -- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. + -- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. + -- + -- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. + -- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. + -- + -- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. + -- + -- function FSM:OnAfterEvent( From, Event, To, Amount ) + -- self:T( { Amount = Amount } ) + -- end + -- + -- local Amount = 1 + -- FSM:__Event( 5, Amount ) + -- + -- Amount = Amount + 1 + -- FSM:Event( Text, Amount ) + -- + -- In this example, the **:OnAfterEvent**() Transition Handler implementation will get called when **Event** is being triggered. + -- Before we go into more detail, let's look at the last 4 lines of the example. + -- The last line triggers synchronously the **Event**, and passes Amount as a parameter. + -- The 3rd last line of the example triggers asynchronously **Event**. + -- Event will be processed after 5 seconds, and Amount is given as a parameter. + -- + -- The output of this little code fragment will be: + -- + -- * Amount = 2 + -- * Amount = 2 + -- + -- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! + -- + -- ### 1.1.4) Linear Transition Example + -- + -- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) + -- + -- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare. + -- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build. + -- Have a look at the source code. The source code is also further explained below in this section. + -- + -- The example creates a new FsmDemo object from class FSM. + -- It will set the start state of FsmDemo to state **Green**. + -- Two Linear Transition Rules are created, where upon the event **Switch**, + -- the FsmDemo will transition from state **Green** to **Red** and from **Red** back to **Green**. + -- + -- ![Transition Example](..\Presentations\FSM\Dia6.JPG) + -- + -- local FsmDemo = FSM:New() -- #FsmDemo + -- FsmDemo:SetStartState( "Green" ) + -- FsmDemo:AddTransition( "Green", "Switch", "Red" ) + -- FsmDemo:AddTransition( "Red", "Switch", "Green" ) + -- + -- In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. + -- The next code implements this through the event handling method **OnAfterSwitch**. + -- + -- ![Transition Flow](..\Presentations\FSM\Dia7.JPG) + -- + -- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) + -- self:T( { From, Event, To, FsmUnit } ) + -- + -- if From == "Green" then + -- FsmUnit:Flare(FLARECOLOR.Green) + -- else + -- if From == "Red" then + -- FsmUnit:Flare(FLARECOLOR.Red) + -- end + -- end + -- self:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. + -- end + -- + -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds. + -- + -- The OnAfterSwitch implements a loop. The last line of the code fragment triggers the Switch Event within 5 seconds. + -- Upon the event execution (after 5 seconds), the OnAfterSwitch method is called of FsmDemo (cfr. the double point notation!!! ":"). + -- The OnAfterSwitch method receives from the FSM the 3 transition parameter details ( From, Event, To ), + -- and one additional parameter that was given when the event was triggered, which is in this case the Unit that is used within OnSwitchAfter. + -- + -- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) + -- + -- For debugging reasons the received parameters are traced within the DCS.log. + -- + -- self:T( { From, Event, To, FsmUnit } ) + -- + -- The method will check if the From state received is either "Green" or "Red" and will flare the respective color from the FsmUnit. + -- + -- if From == "Green" then + -- FsmUnit:Flare(FLARECOLOR.Green) + -- else + -- if From == "Red" then + -- FsmUnit:Flare(FLARECOLOR.Red) + -- end + -- end + -- + -- It is important that the Switch event is again triggered, otherwise, the FsmDemo would stop working after having the first Event being handled. + -- + -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. + -- + -- The below code fragment extends the FsmDemo, demonstrating multiple **From states declared as a table**, adding a **Linear Transition Rule**. + -- The new event **Stop** will cancel the Switching process. + -- The transition for event Stop can be executed if the current state of the FSM is either "Red" or "Green". + -- + -- local FsmDemo = FSM:New() -- #FsmDemo + -- FsmDemo:SetStartState( "Green" ) + -- FsmDemo:AddTransition( "Green", "Switch", "Red" ) + -- FsmDemo:AddTransition( "Red", "Switch", "Green" ) + -- FsmDemo:AddTransition( { "Red", "Green" }, "Stop", "Stopped" ) + -- + -- The transition for event Stop can also be simplified, as any current state of the FSM is valid. + -- + -- FsmDemo:AddTransition( "*", "Stop", "Stopped" ) + -- + -- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. + -- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. + -- + -- ## 1.5) FSM Hierarchical Transitions + -- + -- Hierarchical Transitions allow to re-use readily available and implemented FSMs. + -- This becomes in very useful for mission building, where mission designers build complex processes and workflows, + -- combining smaller FSMs to one single FSM. + -- + -- The FSM can embed **Sub-FSMs** that will execute and return **multiple possible Return (End) States**. + -- Depending upon **which state is returned**, the main FSM can continue the flow **triggering specific events**. + -- + -- The method @{#FSM.AddProcess}() adds a new Sub-FSM to the FSM. + -- + -- === + -- + -- @field #FSM FSM + -- + FSM = { + ClassName = "FSM", + } + + --- Creates a new FSM object. + -- @param #FSM self + -- @return #FSM + function FSM:New( FsmT ) + + -- Inherits from BASE + self = BASE:Inherit( self, BASE:New() ) + + self.options = options or {} + self.options.subs = self.options.subs or {} + self.current = self.options.initial or 'none' + self.Events = {} + self.subs = {} + self.endstates = {} + + self.Scores = {} + + self._StartState = "none" + self._Transitions = {} + self._Processes = {} + self._EndStates = {} + self._Scores = {} + self._EventSchedules = {} + + self.CallScheduler = SCHEDULER:New( self ) + + + return self + end + + + --- Sets the start state of the FSM. + -- @param #FSM self + -- @param #string State A string defining the start state. + function FSM:SetStartState( State ) + + self._StartState = State + self.current = State + end + + + --- Returns the start state of the FSM. + -- @param #FSM self + -- @return #string A string containing the start state. + function FSM:GetStartState() + + return self._StartState or {} + end + + --- Add a new transition rule to the FSM. + -- A transition rule defines when and if the FSM can transition from a state towards another state upon a triggered event. + -- @param #FSM self + -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. + -- @param #string Event The Event name. + -- @param #string To The To state. + function FSM:AddTransition( From, Event, To ) + + local Transition = {} + Transition.From = From + Transition.Event = Event + Transition.To = To + + self:T( Transition ) + + self._Transitions[Transition] = Transition + self:_eventmap( self.Events, Transition ) + end + + + --- Returns a table of the transition rules defined within the FSM. + -- @return #table + function FSM:GetTransitions() + + return self._Transitions or {} + end + + --- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task. + -- @param #FSM self + -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. + -- @param #string Event The Event name. + -- @param Core.Fsm#FSM_PROCESS Process An sub-process FSM. + -- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM. + -- @return Core.Fsm#FSM_PROCESS The SubFSM. + function FSM:AddProcess( From, Event, Process, ReturnEvents ) + self:T( { From, Event, Process, ReturnEvents } ) + + local Sub = {} + Sub.From = From + Sub.Event = Event + Sub.fsm = Process + Sub.StartEvent = "Start" + Sub.ReturnEvents = ReturnEvents + + self._Processes[Sub] = Sub + + self:_submap( self.subs, Sub, nil ) + + self:AddTransition( From, Event, From ) + + return Process + end + + + --- Returns a table of the SubFSM rules defined within the FSM. + -- @return #table + function FSM:GetProcesses() + + return self._Processes or {} + end + + function FSM:GetProcess( From, Event ) + + for ProcessID, Process in pairs( self:GetProcesses() ) do + if Process.From == From and Process.Event == Event then + return Process.fsm + end + end + + error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" ) + end + + --- Adds an End state. + function FSM:AddEndState( State ) + + self._EndStates[State] = State + self.endstates[State] = State + end + + --- Returns the End states. + function FSM:GetEndStates() + + return self._EndStates or {} + end + + + --- Adds a score for the FSM to be achieved. + -- @param #FSM self + -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). + -- @param #string ScoreText is a text describing the score that is given according the status. + -- @param #number Score is a number providing the score of the status. + -- @return #FSM self + function FSM:AddScore( State, ScoreText, Score ) + self:F( { State, ScoreText, Score } ) + + self._Scores[State] = self._Scores[State] or {} + self._Scores[State].ScoreText = ScoreText + self._Scores[State].Score = Score + + return self + end + + --- Adds a score for the FSM_PROCESS to be achieved. + -- @param #FSM self + -- @param #string From is the From State of the main process. + -- @param #string Event is the Event of the main process. + -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). + -- @param #string ScoreText is a text describing the score that is given according the status. + -- @param #number Score is a number providing the score of the status. + -- @return #FSM self + function FSM:AddScoreProcess( From, Event, State, ScoreText, Score ) + self:F( { From, Event, State, ScoreText, Score } ) + + local Process = self:GetProcess( From, Event ) + + Process._Scores[State] = Process._Scores[State] or {} + Process._Scores[State].ScoreText = ScoreText + Process._Scores[State].Score = Score + + self:T( Process._Scores ) + + return Process + end + + --- Returns a table with the scores defined. + function FSM:GetScores() + + return self._Scores or {} + end + + --- Returns a table with the Subs defined. + function FSM:GetSubs() + + return self.options.subs + end + + + function FSM:LoadCallBacks( CallBackTable ) + + for name, callback in pairs( CallBackTable or {} ) do + self[name] = callback + end + + end + + function FSM:_eventmap( Events, EventStructure ) + + local Event = EventStructure.Event + local __Event = "__" .. EventStructure.Event + self[Event] = self[Event] or self:_create_transition(Event) + self[__Event] = self[__Event] or self:_delayed_transition(Event) + self:T( "Added methods: " .. Event .. ", " .. __Event ) + Events[Event] = self.Events[Event] or { map = {} } + self:_add_to_map( Events[Event].map, EventStructure ) + + end + + function FSM:_submap( subs, sub, name ) + self:F( { sub = sub, name = name } ) + subs[sub.From] = subs[sub.From] or {} + subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {} + + -- Make the reference table weak. + -- setmetatable( subs[sub.From][sub.Event], { __mode = "k" } ) + + subs[sub.From][sub.Event][sub] = {} + subs[sub.From][sub.Event][sub].fsm = sub.fsm + subs[sub.From][sub.Event][sub].StartEvent = sub.StartEvent + subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop. + subs[sub.From][sub.Event][sub].name = name + subs[sub.From][sub.Event][sub].fsmparent = self + end + + + function FSM:_call_handler( handler, params, EventName ) + + local ErrorHandler = function( errmsg ) + + env.info( "Error in SCHEDULER function:" .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + + return errmsg + end + if self[handler] then + self:T( "Calling " .. handler ) + self._EventSchedules[EventName] = nil + local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) + return Value + end + end + + function FSM._handler( self, EventName, ... ) + + local Can, to = self:can( EventName ) + + if to == "*" then + to = self.current + end + + if Can then + local from = self.current + local params = { from, EventName, to, ... } + + if self.Controllable then + self:T( "FSM Transition for " .. self.Controllable.ControllableName .. " :" .. self.current .. " --> " .. EventName .. " --> " .. to ) + else + self:T( "FSM Transition:" .. self.current .. " --> " .. EventName .. " --> " .. to ) + end + + if ( self:_call_handler("onbefore" .. EventName, params, EventName ) == false ) + or ( self:_call_handler("OnBefore" .. EventName, params, EventName ) == false ) + or ( self:_call_handler("onleave" .. from, params, EventName ) == false ) + or ( self:_call_handler("OnLeave" .. from, params, EventName ) == false ) then + self:T( "Cancel Transition" ) + return false + end + + self.current = to + + local execute = true + + local subtable = self:_gosub( from, EventName ) + for _, sub in pairs( subtable ) do + --if sub.nextevent then + -- self:F2( "nextevent = " .. sub.nextevent ) + -- self[sub.nextevent]( self ) + --end + self:T( "calling sub start event: " .. sub.StartEvent ) + sub.fsm.fsmparent = self + sub.fsm.ReturnEvents = sub.ReturnEvents + sub.fsm[sub.StartEvent]( sub.fsm ) + execute = false + end + + local fsmparent, Event = self:_isendstate( to ) + if fsmparent and Event then + self:F2( { "end state: ", fsmparent, Event } ) + self:_call_handler("onenter" .. to, params, EventName ) + self:_call_handler("OnEnter" .. to, params, EventName ) + self:_call_handler("onafter" .. EventName, params, EventName ) + self:_call_handler("OnAfter" .. EventName, params, EventName ) + self:_call_handler("onstatechange", params, EventName ) + fsmparent[Event]( fsmparent ) + execute = false + end + + if execute then + -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! + --if from ~= to then + self:_call_handler("onenter" .. to, params, EventName ) + self:_call_handler("OnEnter" .. to, params, EventName ) + --end + + self:_call_handler("onafter" .. EventName, params, EventName ) + self:_call_handler("OnAfter" .. EventName, params, EventName ) + + self:_call_handler("onstatechange", params, EventName ) + end + else + self:T( "Cannot execute transition." ) + self:T( { From = self.current, Event = EventName, To = to, Can = Can } ) + end + + return nil + end + + function FSM:_delayed_transition( EventName ) + return function( self, DelaySeconds, ... ) + self:T2( "Delayed Event: " .. EventName ) + local CallID = 0 + if DelaySeconds ~= nil then + if DelaySeconds < 0 then -- Only call the event ONCE! + DelaySeconds = math.abs( DelaySeconds ) + if not self._EventSchedules[EventName] then + CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) + self._EventSchedules[EventName] = CallID + else + -- reschedule + end + else + CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) + end + else + error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." ) + end + self:T2( { CallID = CallID } ) + end + end + + function FSM:_create_transition( EventName ) + return function( self, ... ) return self._handler( self, EventName , ... ) end + end + + function FSM:_gosub( ParentFrom, ParentEvent ) + local fsmtable = {} + if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then + self:T( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } ) + return self.subs[ParentFrom][ParentEvent] + else + return {} + end + end + + function FSM:_isendstate( Current ) + local FSMParent = self.fsmparent + if FSMParent and self.endstates[Current] then + self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) + FSMParent.current = Current + local ParentFrom = FSMParent.current + self:T( ParentFrom ) + self:T( self.ReturnEvents ) + local Event = self.ReturnEvents[Current] + self:T( { ParentFrom, Event, self.ReturnEvents } ) + if Event then + return FSMParent, Event + else + self:T( { "Could not find parent event name for state ", ParentFrom } ) + end + end + + return nil + end + + function FSM:_add_to_map( Map, Event ) + self:F3( { Map, Event } ) + if type(Event.From) == 'string' then + Map[Event.From] = Event.To + else + for _, From in ipairs(Event.From) do + Map[From] = Event.To + end + end + self:T3( { Map, Event } ) + end + + function FSM:GetState() + return self.current + end + + + function FSM:Is( State ) + return self.current == State + end + + function FSM:is(state) + return self.current == state + end + + function FSM:can(e) + local Event = self.Events[e] + self:F3( { self.current, Event } ) + local To = Event and Event.map[self.current] or Event.map['*'] + return To ~= nil, To + end + + function FSM:cannot(e) + return not self:can(e) + end + +end + +do -- FSM_CONTROLLABLE + + --- @type FSM_CONTROLLABLE + -- @field Wrapper.Controllable#CONTROLLABLE Controllable + -- @extends Core.Fsm#FSM + + --- # FSM_CONTROLLABLE, extends @{#FSM} + -- + -- FSM_CONTROLLABLE class models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s. + -- + -- === + -- + -- @field #FSM_CONTROLLABLE FSM_CONTROLLABLE + -- + FSM_CONTROLLABLE = { + ClassName = "FSM_CONTROLLABLE", + } + + --- Creates a new FSM_CONTROLLABLE object. + -- @param #FSM_CONTROLLABLE self + -- @param #table FSMT Finite State Machine Table + -- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs. + -- @return #FSM_CONTROLLABLE + function FSM_CONTROLLABLE:New( FSMT, Controllable ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE + + if Controllable then + self:SetControllable( Controllable ) + end + + self:AddTransition( "*", "Stop", "Stopped" ) + + --- OnBefore Transition Handler for Event Stop. + -- @function [parent=#FSM_CONTROLLABLE] OnBeforeStop + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Stop. + -- @function [parent=#FSM_CONTROLLABLE] OnAfterStop + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Stop. + -- @function [parent=#FSM_CONTROLLABLE] Stop + -- @param #FSM_CONTROLLABLE self + + --- Asynchronous Event Trigger for Event Stop. + -- @function [parent=#FSM_CONTROLLABLE] __Stop + -- @param #FSM_CONTROLLABLE self + -- @param #number Delay The delay in seconds. + + --- OnLeave Transition Handler for State Stopped. + -- @function [parent=#FSM_CONTROLLABLE] OnLeaveStopped + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Stopped. + -- @function [parent=#FSM_CONTROLLABLE] OnEnterStopped + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + return self + end + + --- OnAfter Transition Handler for Event Stop. + -- @function [parent=#FSM_CONTROLLABLE] OnAfterStop + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + function FSM_CONTROLLABLE:OnAfterStop(Controllable,From,Event,To) + + -- Clear all pending schedules + self.CallScheduler:Clear() + end + + --- Sets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. + -- @param #FSM_CONTROLLABLE self + -- @param Wrapper.Controllable#CONTROLLABLE FSMControllable + -- @return #FSM_CONTROLLABLE + function FSM_CONTROLLABLE:SetControllable( FSMControllable ) + self:F( FSMControllable ) + self.Controllable = FSMControllable + end + + --- Gets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. + -- @param #FSM_CONTROLLABLE self + -- @return Wrapper.Controllable#CONTROLLABLE + function FSM_CONTROLLABLE:GetControllable() + return self.Controllable + end + + function FSM_CONTROLLABLE:_call_handler( handler, params, EventName ) + + local ErrorHandler = function( errmsg ) + + env.info( "Error in SCHEDULER function:" .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + + return errmsg + end + + if self[handler] then + self:F3( "Calling " .. handler ) + self._EventSchedules[EventName] = nil + local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) + return Value + --return self[handler]( self, self.Controllable, unpack( params ) ) + end + end + +end + +do -- FSM_PROCESS + + --- @type FSM_PROCESS + -- @field Tasking.Task#TASK Task + -- @extends Core.Fsm#FSM_CONTROLLABLE + + + --- # FSM_PROCESS, extends @{#FSM} + -- + -- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s. + -- + -- === + -- + -- @field #FSM_PROCESS FSM_PROCESS + -- + FSM_PROCESS = { + ClassName = "FSM_PROCESS", + } + + --- Creates a new FSM_PROCESS object. + -- @param #FSM_PROCESS self + -- @return #FSM_PROCESS + function FSM_PROCESS:New( Controllable, Task ) + + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS + + self:F( Controllable, Task ) + + self:Assign( Controllable, Task ) + + return self + end + + function FSM_PROCESS:Init( FsmProcess ) + self:T( "No Initialisation" ) + end + + function FSM_PROCESS:_call_handler( handler, params, EventName ) + + local ErrorHandler = function( errmsg ) + + env.info( "Error in FSM_PROCESS call handler:" .. errmsg ) + if debug ~= nil then + env.info( debug.traceback() ) + end + + return errmsg + end + + if self[handler] then + self:F3( "Calling " .. handler ) + self._EventSchedules[EventName] = nil + local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler ) + return Value + --return self[handler]( self, self.Controllable, unpack( params ) ) + end + end + + --- Creates a new FSM_PROCESS object based on this FSM_PROCESS. + -- @param #FSM_PROCESS self + -- @return #FSM_PROCESS + function FSM_PROCESS:Copy( Controllable, Task ) + self:T( { self:GetClassNameAndID() } ) + + + local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS + + NewFsm:Assign( Controllable, Task ) + + -- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS + NewFsm:Init( self ) + + -- Set Start State + NewFsm:SetStartState( self:GetStartState() ) + + -- Copy Transitions + for TransitionID, Transition in pairs( self:GetTransitions() ) do + NewFsm:AddTransition( Transition.From, Transition.Event, Transition.To ) + end + + -- Copy Processes + for ProcessID, Process in pairs( self:GetProcesses() ) do + self:E( { Process} ) + local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents ) + end + + -- Copy End States + for EndStateID, EndState in pairs( self:GetEndStates() ) do + self:T( EndState ) + NewFsm:AddEndState( EndState ) + end + + -- Copy the score tables + for ScoreID, Score in pairs( self:GetScores() ) do + self:T( Score ) + NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score ) + end + + return NewFsm + end + + --- Removes an FSM_PROCESS object. + -- @param #FSM_PROCESS self + -- @return #FSM_PROCESS + function FSM_PROCESS:Remove() + self:T( { self:GetClassNameAndID() } ) + + -- Copy Processes + for ProcessID, Process in pairs( self:GetProcesses() ) do + self:E( { Process} ) + Process.fsm:Remove() + Process.fsm = nil + end + + return self + end + + --- Sets the task of the process. + -- @param #FSM_PROCESS self + -- @param Tasking.Task#TASK Task + -- @return #FSM_PROCESS + function FSM_PROCESS:SetTask( Task ) + + self.Task = Task + + return self + end + + --- Gets the task of the process. + -- @param #FSM_PROCESS self + -- @return Tasking.Task#TASK + function FSM_PROCESS:GetTask() + + return self.Task + end + + --- Gets the mission of the process. + -- @param #FSM_PROCESS self + -- @return Tasking.Mission#MISSION + function FSM_PROCESS:GetMission() + + return self.Task.Mission + end + + --- Gets the mission of the process. + -- @param #FSM_PROCESS self + -- @return Tasking.CommandCenter#COMMANDCENTER + function FSM_PROCESS:GetCommandCenter() + + return self:GetTask():GetMission():GetCommandCenter() + end + +-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP. + + --- Send a message of the @{Task} to the Group of the Unit. +-- @param #FSM_PROCESS self +function FSM_PROCESS:Message( Message ) + self:F( { Message = Message } ) + + local CC = self:GetCommandCenter() + local TaskGroup = self.Controllable:GetGroup() + + local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit + PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets. + local Callsign = self.Controllable:GetCallsign() + local Prefix = Callsign and " @ " .. Callsign .. PlayerName or "" + + Message = Prefix .. ": " .. Message + CC:MessageToGroup( Message, TaskGroup ) +end + + + + + --- Assign the process to a @{Unit} and activate the process. + -- @param #FSM_PROCESS self + -- @param Task.Tasking#TASK Task + -- @param Wrapper.Unit#UNIT ProcessUnit + -- @return #FSM_PROCESS self + function FSM_PROCESS:Assign( ProcessUnit, Task ) + self:T( { Task, ProcessUnit } ) + + self:SetControllable( ProcessUnit ) + self:SetTask( Task ) + + --self.ProcessGroup = ProcessUnit:GetGroup() + + return self + end + + function FSM_PROCESS:onenterAssigned( ProcessUnit ) + self:T( "Assign" ) + + self.Task:Assign() + end + + function FSM_PROCESS:onenterFailed( ProcessUnit ) + self:T( "Failed" ) + + self.Task:Fail() + end + + function FSM_PROCESS:onenterSuccess( ProcessUnit ) + self:T( "Success" ) + + self.Task:Success() + end + + --- StateMachine callback function for a FSM_PROCESS + -- @param #FSM_PROCESS self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To, Dummy ) + self:T( { ProcessUnit, From, Event, To, Dummy, self:IsTrace() } ) + + if self:IsTrace() then + MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() + end + + self:T( { Scores = self._Scores, To = To } ) + -- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects... + if self._Scores[To] then + + local Task = self.Task + local Scoring = Task:GetScoring() + if Scoring then + Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self._Scores[To].ScoreText, self._Scores[To].Score ) + end + end + end + +end + +do -- FSM_TASK + + --- FSM_TASK class + -- @type FSM_TASK + -- @field Tasking.Task#TASK Task + -- @extends #FSM + + --- # FSM_TASK, extends @{#FSM} + -- + -- FSM_TASK class models Finite State Machines for @{Task}s. + -- + -- === + -- + -- @field #FSM_TASK FSM_TASK + -- + FSM_TASK = { + ClassName = "FSM_TASK", + } + + --- Creates a new FSM_TASK object. + -- @param #FSM_TASK self + -- @param #table FSMT + -- @param Tasking.Task#TASK Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #FSM_TASK + function FSM_TASK:New( FSMT ) + + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK + + self["onstatechange"] = self.OnStateChange + + return self + end + + function FSM_TASK:_call_handler( handler, params, EventName ) + if self[handler] then + self:T( "Calling " .. handler ) + self._EventSchedules[EventName] = nil + return self[handler]( self, unpack( params ) ) + end + end + +end -- FSM_TASK + +do -- FSM_SET + + --- FSM_SET class + -- @type FSM_SET + -- @field Core.Set#SET_BASE Set + -- @extends Core.Fsm#FSM + + + --- # FSM_SET, extends @{#FSM} + -- + -- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here + -- for multiple objects or the position of the state machine in the process. + -- + -- === + -- + -- @field #FSM_SET FSM_SET + -- + FSM_SET = { + ClassName = "FSM_SET", + } + + --- Creates a new FSM_SET object. + -- @param #FSM_SET self + -- @param #table FSMT Finite State Machine Table + -- @param Set_SET_BASE FSMSet (optional) The Set object that the FSM_SET governs. + -- @return #FSM_SET + function FSM_SET:New( FSMSet ) + + -- Inherits from BASE + self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET + + if FSMSet then + self:Set( FSMSet ) + end + + return self + end + + --- Sets the SET_BASE object that the FSM_SET governs. + -- @param #FSM_SET self + -- @param Core.Set#SET_BASE FSMSet + -- @return #FSM_SET + function FSM_SET:Set( FSMSet ) + self:F( FSMSet ) + self.Set = FSMSet + end + + --- Gets the SET_BASE object that the FSM_SET governs. + -- @param #FSM_SET self + -- @return Core.Set#SET_BASE + function FSM_SET:Get() + return self.Controllable + end + + function FSM_SET:_call_handler( handler, params, EventName ) + if self[handler] then + self:T( "Calling " .. handler ) + self._EventSchedules[EventName] = nil + return self[handler]( self, self.Set, unpack( params ) ) + end + end + +end -- FSM_SET + +--- **Core** - The RADIO class is responsible for **transmitting radio communications**. +-- +-- --- bitmap +-- +-- === +-- +-- What are radio communications in DCS ? +-- +-- * Radio transmissions consist of **sound files** that are broadcasted on a specific **frequency** (e.g. 115MHz) and **modulation** (e.g. AM), +-- * They can be **subtitled** for a specific **duration**, the **power** in Watts of the transmiter's antenna can be set, and the transmission can be **looped**. +-- +-- How to supply DCS my own Sound Files ? +-- +-- * Your sound files need to be encoded in **.ogg** or .wav, +-- * Your sound files should be **as tiny as possible**. It is suggested you encode in .ogg with low bitrate and sampling settings, +-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file), +-- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission. +-- +-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Group#GROUP} or by any other @{Positionable#POSITIONABLE} +-- +-- * If the transmitter is a @{Unit#UNIT} or a @{Group#GROUP}, DCS will set the power of the transmission automatically, +-- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped. +-- +-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft, +-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below). +-- If a FC3 airacraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. +-- +-- === +-- +-- ### Authors: Hugues "Grey_Echo" Bousquet +-- +-- @module Radio + +--- # 1) RADIO class, extends @{Base#BASE} +-- +-- ## 1.1) RADIO usage +-- +-- There are 3 steps to a successful radio transmission. +-- +-- * First, you need to **"add" a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function, +-- * Then, you will **set the relevant parameters** to the transmission (see below), +-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{Positionable#POSITIONABLE.Broadcast}() function. +-- +-- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE} +-- +-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"), +-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission, +-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission. +-- +-- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Group#GROUP} +-- +-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped, +-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration, +-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call +-- +-- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE} +-- +-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts +-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call +-- +-- What is this power thing ? +-- +-- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Group#GROUP}, you can set the power of the antenna, +-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit, +-- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**, +-- * This an automated DCS calculation you have no say on, +-- * For reference, a standard VOR station has a 100W antenna, a standard AA TACAN has a 120W antenna, and civilian ATC's antenna usually range between 300 and 500W, +-- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission. +-- +-- @type RADIO +-- @field Wrapper.Positionable#POSITIONABLE Positionable The transmiter +-- @field #string FileName Name of the sound file +-- @field #number Frequency Frequency of the transmission in Hz +-- @field #number Modulation Modulation of the transmission (either radio.modulation.AM or radio.modulation.FM) +-- @field #string Subtitle Subtitle of the transmission +-- @field #number SubtitleDuration Duration of the Subtitle in seconds +-- @field #number Power Power of the antenna is Watts +-- @field #boolean Loop +-- @extends Core.Base#BASE +RADIO = { + ClassName = "RADIO", + FileName = "", + Frequency = 0, + Modulation = radio.modulation.AM, + Subtitle = "", + SubtitleDuration = 0, + Power = 100, + Loop = 0, +} + +--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast +-- @param #RADIO self +-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities. +-- @return #RADIO Radio +-- @return #nil If Positionable is invalid +-- @usage +-- -- If you want to create a RADIO, you probably should use @{Positionable#POSITIONABLE.GetRadio}() instead +function RADIO:New(Positionable) + local self = BASE:Inherit( self, BASE:New() ) -- Core.Radio#RADIO + + self:F(Positionable) + + if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid + self.Positionable = Positionable + return self + end + + self:E({"The passed positionable is invalid, no RADIO created", Positionable}) + return nil +end + +--- Check validity of the filename passed and sets RADIO.FileName +-- @param #RADIO self +-- @param #string FileName File name of the sound file (i.e. "Noise.ogg") +-- @return #RADIO self +function RADIO:SetFileName(FileName) + self:F2(FileName) + + if type(FileName) == "string" then + if FileName:find(".ogg") or FileName:find(".wav") then + if not FileName:find("l10n/DEFAULT/") then + FileName = "l10n/DEFAULT/" .. FileName + end + self.FileName = FileName + return self + end + end + + self:E({"File name invalid. Maybe something wrong with the extension ?", self.FileName}) + return self +end + +--- Check validity of the frequency passed and sets RADIO.Frequency +-- @param #RADIO self +-- @param #number Frequency in MHz (Ranges allowed for radio transmissions in DCS : 30-88 / 108-152 / 225-400MHz) +-- @return #RADIO self +function RADIO:SetFrequency(Frequency) + self:F2(Frequency) + if type(Frequency) == "number" then + -- If frequency is in range + if (Frequency >= 30 and Frequency < 88) or (Frequency >= 108 and Frequency < 152) or (Frequency >= 225 and Frequency < 400) then + self.Frequency = Frequency * 1000000 -- Conversion in Hz + -- If the RADIO is attached to a UNIT or a GROUP, we need to send the DCS Command "SetFrequency" to change the UNIT or GROUP frequency + if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then + self.Positionable:SetCommand({ + id = "SetFrequency", + params = { + frequency = self.Frequency, + modulation = self.Modulation, + } + }) + end + return self + end + end + self:E({"Frequency is outside of DCS Frequency ranges (30-80, 108-152, 225-400). Frequency unchanged.", self.Frequency}) + return self +end + +--- Check validity of the frequency passed and sets RADIO.Modulation +-- @param #RADIO self +-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM +-- @return #RADIO self +function RADIO:SetModulation(Modulation) + self:F2(Modulation) + if type(Modulation) == "number" then + if Modulation == radio.modulation.AM or Modulation == radio.modulation.FM then --TODO Maybe make this future proof if ED decides to add an other modulation ? + self.Modulation = Modulation + return self + end + end + self:E({"Modulation is invalid. Use DCS's enum radio.modulation. Modulation unchanged.", self.Modulation}) + return self +end + +--- Check validity of the power passed and sets RADIO.Power +-- @param #RADIO self +-- @param #number Power in W +-- @return #RADIO self +function RADIO:SetPower(Power) + self:F2(Power) + if type(Power) == "number" then + self.Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that + return self + end + self:E({"Power is invalid. Power unchanged.", self.Power}) + return self +end + +--- Check validity of the loop passed and sets RADIO.Loop +-- @param #RADIO self +-- @param #boolean Loop +-- @return #RADIO self +-- @usage +function RADIO:SetLoop(Loop) + self:F2(Loop) + if type(Loop) == "boolean" then + self.Loop = Loop + return self + end + self:E({"Loop is invalid. Loop unchanged.", self.Loop}) + return self +end + +--- Check validity of the subtitle and the subtitleDuration passed and sets RADIO.subtitle and RADIO.subtitleDuration +-- @param #RADIO self +-- @param #string Subtitle +-- @param #number SubtitleDuration in s +-- @return #RADIO self +-- @usage +-- -- Both parameters are mandatory, since it wouldn't make much sense to change the Subtitle and not its duration +function RADIO:SetSubtitle(Subtitle, SubtitleDuration) + self:F2({Subtitle, SubtitleDuration}) + if type(Subtitle) == "string" then + self.Subtitle = Subtitle + else + self.Subtitle = "" + self:E({"Subtitle is invalid. Subtitle reset.", self.Subtitle}) + end + if type(SubtitleDuration) == "number" then + if math.floor(math.abs(SubtitleDuration)) == SubtitleDuration then + self.SubtitleDuration = SubtitleDuration + return self + end + end + self.SubtitleDuration = 0 + self:E({"SubtitleDuration is invalid. SubtitleDuration reset.", self.SubtitleDuration}) +end + +--- Create a new transmission, that is to say, populate the RADIO with relevant data +-- @param #RADIO self +-- @param #string FileName +-- @param #number Frequency in MHz +-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM +-- @param #number Power in W +-- @return #RADIO self +-- @usage +-- -- In this function the data is especially relevant if the broadcaster is anything but a UNIT or a GROUP, +-- but it will work with a UNIT or a GROUP anyway +-- -- Only the RADIO and the Filename are mandatory +function RADIO:NewGenericTransmission(FileName, Frequency, Modulation, Power) + self:F({FileName, Frequency, Modulation, Power}) + + self:SetFileName(FileName) + if Frequency then self:SetFrequency(Frequency) end + if Modulation then self:SetModulation(Modulation) end + if Power then self:SetPower(Power) end + + return self +end + + +--- Create a new transmission, that is to say, populate the RADIO with relevant data +-- @param #RADIO self +-- @param #string FileName +-- @param #string Subtitle +-- @param #number SubtitleDuration in s +-- @param #number Frequency in MHz +-- @param #number Modulation either radio.modulation.AM or radio.modulation.FM +-- @param #boolean Loop +-- @return #RADIO self +-- @usage +-- -- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP, +-- but it will work for any POSITIONABLE +-- -- Only the RADIO and the Filename are mandatory +function RADIO:NewUnitTransmission(FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop) + self:F({FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop}) + + self:SetFileName(FileName) + if Subtitle then self:SetSubtitle(Subtitle) end + if SubtitleDuration then self:SetSubtitleDuration(SubtitleDuration) end + if Frequency then self:SetFrequency(Frequency) end + if Modulation then self:SetModulation(Modulation) end + if Loop then self:SetLoop(Loop) end + + return self +end + +--- Actually Broadcast the transmission +-- @param #RADIO self +-- @return #RADIO self +-- @usage +-- -- The Radio has to be populated with the new transmission before broadcasting. +-- -- Please use RADIO setters or either @{Radio#RADIO.NewGenericTransmission} or @{Radio#RADIO.NewUnitTransmission} +-- -- This class is in fact pretty smart, it determines the right DCS function to use depending on the type of POSITIONABLE +-- -- If the POSITIONABLE is not a UNIT or a GROUP, we use the generic (but limited) trigger.action.radioTransmission() +-- -- If the POSITIONABLE is a UNIT or a GROUP, we use the "TransmitMessage" Command +-- -- If your POSITIONABLE is a UNIT or a GROUP, the Power is ignored. +-- -- If your POSITIONABLE is not a UNIT or a GROUP, the Subtitle, SubtitleDuration and Loop are ignored +function RADIO:Broadcast() + self:F() + -- If the POSITIONABLE is actually a UNIT or a GROUP, use the more complicated DCS command system + if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then + self:T2("Broadcasting from a UNIT or a GROUP") + self.Positionable:SetCommand({ + id = "TransmitMessage", + params = { + file = self.FileName, + duration = self.SubtitleDuration, + subtitle = self.Subtitle, + loop = self.Loop, + } + }) + else + -- If the POSITIONABLE is anything else, we revert to the general singleton function + self:T2("Broadcasting from a POSITIONABLE") + trigger.action.radioTransmission(self.FileName, self.Positionable:GetPositionVec3(), self.Modulation, false, self.Frequency, self.Power) + end + return self +end + +--- Stops a transmission +-- @param #RADIO self +-- @return #RADIO self +-- @usage +-- -- Especially usefull to stop the broadcast of looped transmissions +-- -- Only works with broadcasts from UNIT or GROUP +function RADIO:StopBroadcast() + self:F() + -- If the POSITIONABLE is a UNIT or a GROUP, stop the transmission with the DCS "StopTransmission" command + if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then + self.Positionable:SetCommand({ + id = "StopTransmission", + params = {} + }) + else + self:E("This broadcast can't be stopped. It's not looped either, so please wait for the end of the sound file playback") + end + return self +end--- This module contains the OBJECT class. +-- +-- 1) @{Object#OBJECT} class, extends @{Base#BASE} +-- =========================================================== +-- The @{Object#OBJECT} class is a wrapper class to handle the DCS Object objects: +-- +-- * Support all DCS Object APIs. +-- * Enhance with Object specific APIs not in the DCS Object API set. +-- * Manage the "state" of the DCS Object. +-- +-- 1.1) OBJECT constructor: +-- ------------------------------ +-- The OBJECT class provides the following functions to construct a OBJECT instance: +-- +-- * @{Object#OBJECT.New}(): Create a OBJECT instance. +-- +-- 1.2) OBJECT methods: +-- -------------------------- +-- The following methods can be used to identify an Object object: +-- +-- * @{Object#OBJECT.GetID}(): Returns the ID of the Object object. +-- +-- === +-- +-- @module Object + +--- The OBJECT class +-- @type OBJECT +-- @extends Core.Base#BASE +-- @field #string ObjectName The name of the Object. +OBJECT = { + ClassName = "OBJECT", + ObjectName = "", +} + +--- A DCSObject +-- @type DCSObject +-- @field id_ The ID of the controllable in DCS + +--- Create a new OBJECT from a DCSObject +-- @param #OBJECT self +-- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name +-- @return #OBJECT self +function OBJECT:New( ObjectName, Test ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( ObjectName ) + self.ObjectName = ObjectName + + return self +end + + +--- Returns the unit's unique identifier. +-- @param Wrapper.Object#OBJECT self +-- @return Dcs.DCSWrapper.Object#Object.ID ObjectID +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetID() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectID = DCSObject:getID() + return ObjectID + end + + return nil +end + +--- Destroys the OBJECT. +-- @param #OBJECT self +-- @return #nil The DCS Unit is not existing or alive. +function OBJECT:Destroy() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + + DCSObject:destroy() + end + + return nil +end + + + + +--- This module contains the IDENTIFIABLE class. +-- +-- 1) @{#IDENTIFIABLE} class, extends @{Object#OBJECT} +-- =============================================================== +-- The @{#IDENTIFIABLE} class is a wrapper class to handle the DCS Identifiable objects: +-- +-- * Support all DCS Identifiable APIs. +-- * Enhance with Identifiable specific APIs not in the DCS Identifiable API set. +-- * Manage the "state" of the DCS Identifiable. +-- +-- 1.1) IDENTIFIABLE constructor: +-- ------------------------------ +-- The IDENTIFIABLE class provides the following functions to construct a IDENTIFIABLE instance: +-- +-- * @{#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. +-- +-- 1.2) IDENTIFIABLE methods: +-- -------------------------- +-- The following methods can be used to identify an identifiable object: +-- +-- * @{#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. +-- * @{#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. +-- * @{#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. +-- * @{#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. +-- * @{#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. +-- * @{#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. +-- +-- +-- === +-- +-- @module Identifiable + +--- The IDENTIFIABLE class +-- @type IDENTIFIABLE +-- @extends Wrapper.Object#OBJECT +-- @field #string IdentifiableName The name of the identifiable. +IDENTIFIABLE = { + ClassName = "IDENTIFIABLE", + IdentifiableName = "", +} + +local _CategoryName = { + [Unit.Category.AIRPLANE] = "Airplane", + [Unit.Category.HELICOPTER] = "Helicoper", + [Unit.Category.GROUND_UNIT] = "Ground Identifiable", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } + +--- Create a new IDENTIFIABLE from a DCSIdentifiable +-- @param #IDENTIFIABLE self +-- @param Dcs.DCSWrapper.Identifiable#Identifiable IdentifiableName The DCS Identifiable name +-- @return #IDENTIFIABLE self +function IDENTIFIABLE:New( IdentifiableName ) + local self = BASE:Inherit( self, OBJECT:New( IdentifiableName ) ) + self:F2( IdentifiableName ) + self.IdentifiableName = IdentifiableName + return self +end + +--- Returns if the Identifiable is alive. +-- If the Identifiable is not alive, nil is returned. +-- If the Identifiable is alive, true is returned. +-- @param #IDENTIFIABLE self +-- @return #boolean true if Identifiable is alive. +-- @return #nil if the Identifiable is not existing or is not alive. +function IDENTIFIABLE:IsAlive() + self:F3( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() -- Dcs.DCSObject#Object + + if DCSIdentifiable then + local IdentifiableIsAlive = DCSIdentifiable:isExist() + return IdentifiableIsAlive + end + + return false +end + + + + +--- Returns DCS Identifiable object name. +-- The function provides access to non-activated objects too. +-- @param #IDENTIFIABLE self +-- @return #string The name of the DCS Identifiable. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:GetName() + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableName = self.IdentifiableName + return IdentifiableName + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + + +--- Returns the type name of the DCS Identifiable. +-- @param #IDENTIFIABLE self +-- @return #string The type name of the DCS Identifiable. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:GetTypeName() + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableTypeName = DCSIdentifiable:getTypeName() + self:T3( IdentifiableTypeName ) + return IdentifiableTypeName + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + + +--- Returns category of the DCS Identifiable. +-- @param #IDENTIFIABLE self +-- @return Dcs.DCSWrapper.Object#Object.Category The category ID +function IDENTIFIABLE:GetCategory() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + local ObjectCategory = DCSObject:getCategory() + self:T3( ObjectCategory ) + return ObjectCategory + end + + return nil +end + + +--- Returns the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. +-- @param #IDENTIFIABLE self +-- @return #string The DCS Identifiable Category Name +function IDENTIFIABLE:GetCategoryName() + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableCategoryName = _CategoryName[ self:GetDesc().category ] + return IdentifiableCategoryName + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + +--- Returns coalition of the Identifiable. +-- @param #IDENTIFIABLE self +-- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The side of the coalition. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:GetCoalition() + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableCoalition = DCSIdentifiable:getCoalition() + self:T3( IdentifiableCoalition ) + return IdentifiableCoalition + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + +--- Returns country of the Identifiable. +-- @param #IDENTIFIABLE self +-- @return Dcs.DCScountry#country.id The country identifier. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:GetCountry() + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableCountry = DCSIdentifiable:getCountry() + self:T3( IdentifiableCountry ) + return IdentifiableCountry + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + + + +--- Returns Identifiable descriptor. Descriptor type depends on Identifiable category. +-- @param #IDENTIFIABLE self +-- @return Dcs.DCSWrapper.Identifiable#Identifiable.Desc The Identifiable descriptor. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:GetDesc() + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableDesc = DCSIdentifiable:getDesc() + self:T2( IdentifiableDesc ) + return IdentifiableDesc + end + + self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + +--- Gets the CallSign of the IDENTIFIABLE, which is a blank by default. +-- @param #IDENTIFIABLE self +-- @return #string The CallSign of the IDENTIFIABLE. +function IDENTIFIABLE:GetCallsign() + return '' +end + + +function IDENTIFIABLE:GetThreatLevel() + + return 0, "Scenery" +end +--- This module contains the POSITIONABLE class. +-- +-- 1) @{Positionable#POSITIONABLE} class, extends @{Identifiable#IDENTIFIABLE} +-- =========================================================== +-- The @{Positionable#POSITIONABLE} class is a wrapper class to handle the POSITIONABLE objects: +-- +-- * Support all DCS APIs. +-- * Enhance with POSITIONABLE specific APIs not in the DCS API set. +-- * Manage the "state" of the POSITIONABLE. +-- +-- 1.1) POSITIONABLE constructor: +-- ------------------------------ +-- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: +-- +-- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- 1.2) POSITIONABLE methods: +-- -------------------------- +-- The following methods can be used to identify an measurable object: +-- +-- * @{Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. +-- * @{Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. +-- +-- === +-- +-- @module Positionable + +--- The POSITIONABLE class +-- @type POSITIONABLE +-- @extends Wrapper.Identifiable#IDENTIFIABLE +-- @field #string PositionableName The name of the measurable. +POSITIONABLE = { + ClassName = "POSITIONABLE", + PositionableName = "", +} + +--- A DCSPositionable +-- @type DCSPositionable +-- @field id_ The ID of the controllable in DCS + +--- Create a new POSITIONABLE from a DCSPositionable +-- @param #POSITIONABLE self +-- @param Dcs.DCSWrapper.Positionable#Positionable PositionableName The POSITIONABLE name +-- @return #POSITIONABLE self +function POSITIONABLE:New( PositionableName ) + local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) + + self.PositionableName = PositionableName + return self +end + +--- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetPositionVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePosition = DCSPositionable:getPosition().p + self:T3( PositionablePosition ) + return PositionablePosition + end + + return nil +end + +--- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Vec2 The 2D point vector of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetVec2() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableVec3 = DCSPositionable:getPosition().p + + local PositionableVec2 = {} + PositionableVec2.x = PositionableVec3.x + PositionableVec2.y = PositionableVec3.z + + self:T2( PositionableVec2 ) + return PositionableVec2 + end + + return nil +end + +--- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetPointVec2() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableVec3 = DCSPositionable:getPosition().p + + local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) + + self:T2( PositionablePointVec2 ) + return PositionablePointVec2 + end + + return nil +end + +--- Returns a POINT_VEC3 object indicating the point in 3D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetPointVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableVec3 = self:GetPositionVec3() + + local PositionablePointVec3 = POINT_VEC3:NewFromVec3( PositionableVec3 ) + + self:T2( PositionablePointVec3 ) + return PositionablePointVec3 + end + + return nil +end + + +--- Returns a random @{DCSTypes#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @param #number Radius +-- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +-- @usage +-- -- If Radius is ignored, returns the Dcs.DCSTypes#Vec3 of first UNIT of the GROUP +function POSITIONABLE:GetRandomVec3( Radius ) + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + + if Radius then + local PositionableRandomVec3 = {} + local angle = math.random() * math.pi*2; + PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius; + PositionableRandomVec3.y = PositionablePointVec3.y + PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius; + + self:T3( PositionableRandomVec3 ) + return PositionableRandomVec3 + else + self:E("Radius is nil, returning the PointVec3 of the POSITIONABLE", PositionablePointVec3) + return PositionablePointVec3 + end + end + + return nil +end + +--- Returns the @{DCSTypes#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableVec3 = DCSPositionable:getPosition().p + self:T3( PositionableVec3 ) + return PositionableVec3 + end + + return nil +end + +--- Returns the altitude of the POSITIONABLE. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Distance The altitude of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetAltitude() + self:F2() + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPoint() --Dcs.DCSTypes#Vec3 + return PositionablePointVec3.y + end + + return nil +end + +--- Returns if the Positionable is located above a runway. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return #boolean true if Positionable is above a runway. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:IsAboveRunway() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + + local Vec2 = self:GetVec2() + local SurfaceType = land.getSurfaceType( Vec2 ) + local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY + + self:T2( IsAboveRunway ) + return IsAboveRunway + end + + return nil +end + + + +--- Returns the POSITIONABLE heading in degrees. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return #number The POSTIONABLE heading +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetHeading() + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + + local PositionablePosition = DCSPositionable:getPosition() + if PositionablePosition then + local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x ) + if PositionableHeading < 0 then + PositionableHeading = PositionableHeading + 2 * math.pi + end + PositionableHeading = PositionableHeading * 180 / math.pi + self:T2( PositionableHeading ) + return PositionableHeading + end + end + + return nil +end + + +--- Returns true if the POSITIONABLE is in the air. +-- Polymorphic, is overridden in GROUP and UNIT. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return #boolean true if in the air. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:InAir() + self:F2( self.PositionableName ) + + return nil +end + + +--- Returns the POSITIONABLE velocity vector. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Vec3 The velocity vector +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetVelocity() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableVelocityVec3 = DCSPositionable:getVelocity() + self:T3( PositionableVelocityVec3 ) + return PositionableVelocityVec3 + end + + return nil +end + +--- Returns the POSITIONABLE velocity in km/h. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return #number The velocity in km/h +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetVelocityKMH() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local VelocityVec3 = self:GetVelocity() + local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec + local Velocity = Velocity * 3.6 -- now it is in km/h. + self:T3( Velocity ) + return Velocity + end + + return nil +end + +--- Returns a message with the callsign embedded (if there is one). +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +-- @return Core.Message#MESSAGE +function POSITIONABLE:GetMessage( Message, Duration, Name ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + Name = Name or self:GetTypeName() + return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. Name .. ")" ) + end + + return nil +end + +--- Send a message to all coalitions. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToAll( Message, Duration, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToAll() + end + + return nil +end + +--- Send a message to a coalition. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTYpes#Duration Duration The duration of the message. +-- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition ) + end + + return nil +end + + +--- Send a message to the red coalition. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTYpes#Duration Duration The duration of the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToRed( Message, Duration, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToRed() + end + + return nil +end + +--- Send a message to the blue coalition. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToBlue( Message, Duration, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToBlue() + end + + return nil +end + +--- Send a message to a client. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param Wrapper.Client#CLIENT Client The client object receiving the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToClient( Message, Duration, Client, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToClient( Client ) + end + + return nil +end + +--- Send a message to a @{Group}. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param Wrapper.Group#GROUP MessageGroup The GROUP object receiving the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + if DCSObject:isExist() then + self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup ) + end + end + + return nil +end + +--- Send a message to the players in the @{Group}. +-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. +-- @param #POSITIONABLE self +-- @param #string Message The message text +-- @param Dcs.DCSTypes#Duration Duration The duration of the message. +-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. +function POSITIONABLE:Message( Message, Duration, Name ) + self:F2( { Message, Duration } ) + + local DCSObject = self:GetDCSObject() + if DCSObject then + self:GetMessage( Message, Duration, Name ):ToGroup( self ) + end + + return nil +end + +--- Create a @{Radio#RADIO}, to allow radio transmission for this POSITIONABLE. +-- Set parameters with the methods provided, then use RADIO:Broadcast() to actually broadcast the message +-- @param #POSITIONABLE self +-- @return #RADIO Radio +function POSITIONABLE:GetRadio() + self:F2(self) + return RADIO:New(self) +end +--- This module contains the CONTROLLABLE class. +-- +-- 1) @{Controllable#CONTROLLABLE} class, extends @{Positionable#POSITIONABLE} +-- =========================================================== +-- The @{Controllable#CONTROLLABLE} class is a wrapper class to handle the DCS Controllable objects: +-- +-- * Support all DCS Controllable APIs. +-- * Enhance with Controllable specific APIs not in the DCS Controllable API set. +-- * Handle local Controllable Controller. +-- * Manage the "state" of the DCS Controllable. +-- +-- 1.1) CONTROLLABLE constructor +-- ----------------------------- +-- The CONTROLLABLE class provides the following functions to construct a CONTROLLABLE instance: +-- +-- * @{#CONTROLLABLE.New}(): Create a CONTROLLABLE instance. +-- +-- 1.2) CONTROLLABLE task methods +-- ------------------------------ +-- Several controllable task methods are available that help you to prepare tasks. +-- These methods return a string consisting of the task description, which can then be given to either a @{Controllable#CONTROLLABLE.PushTask} or @{Controllable#SetTask} method to assign the task to the CONTROLLABLE. +-- Tasks are specific for the category of the CONTROLLABLE, more specific, for AIR, GROUND or AIR and GROUND. +-- Each task description where applicable indicates for which controllable category the task is valid. +-- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. +-- +-- ### 1.2.1) Assigned task methods +-- +-- Assigned task methods make the controllable execute the task where the location of the (possible) targets of the task are known before being detected. +-- This is different from the EnRoute tasks, where the targets of the task need to be detected before the task can be executed. +-- +-- Find below a list of the **assigned task** methods: +-- +-- * @{#CONTROLLABLE.TaskAttackGroup}: (AIR) Attack a Controllable. +-- * @{#CONTROLLABLE.TaskAttackMapObject}: (AIR) Attacking the map object (building, structure, e.t.c). +-- * @{#CONTROLLABLE.TaskAttackUnit}: (AIR) Attack the Unit. +-- * @{#CONTROLLABLE.TaskBombing}: (AIR) Delivering weapon at the point on the ground. +-- * @{#CONTROLLABLE.TaskBombingRunway}: (AIR) Delivering weapon on the runway. +-- * @{#CONTROLLABLE.TaskEmbarking}: (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. +-- * @{#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location. +-- * @{#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne controllable. +-- * @{#CONTROLLABLE.TaskFAC_AttackGroup}: (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. +-- * @{#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire some or all ammunition at a VEC2 point. +-- * @{#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne controllable. +-- * @{#CONTROLLABLE.TaskHold}: (GROUND) Hold ground controllable from moving. +-- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable. +-- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. +-- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Zone#ZONE_RADIUS). +-- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. +-- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. +-- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. +-- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points. +-- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point. +-- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point. +-- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone. +-- * @{#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the controllable to an airbase. +-- +-- ### 1.2.2) EnRoute task methods +-- +-- EnRoute tasks require the targets of the task need to be detected by the controllable (using its sensors) before the task can be executed: +-- +-- * @{#CONTROLLABLE.EnRouteTaskAWACS}: (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. +-- * @{#CONTROLLABLE.EnRouteTaskEngageControllable}: (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. +-- * @{#CONTROLLABLE.EnRouteTaskEngageTargets}: (AIR) Engaging targets of defined types. +-- * @{#CONTROLLABLE.EnRouteTaskEWR}: (AIR) Attack the Unit. +-- * @{#CONTROLLABLE.EnRouteTaskFAC}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. +-- * @{#CONTROLLABLE.EnRouteTaskFAC_EngageControllable}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. +-- * @{#CONTROLLABLE.EnRouteTaskTanker}: (AIR) Aircraft will act as a tanker for friendly units. No parameters. +-- +-- ### 1.2.3) Preparation task methods +-- +-- There are certain task methods that allow to tailor the task behaviour: +-- +-- * @{#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command. +-- * @{#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks. +-- * @{#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task. +-- * @{#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition. +-- +-- ### 1.2.4) Obtain the mission from controllable templates +-- +-- Controllable templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a controllable and assign it to another: +-- +-- * @{#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. +-- +-- 1.3) CONTROLLABLE Command methods +-- -------------------------- +-- Controllable **command methods** prepare the execution of commands using the @{#CONTROLLABLE.SetCommand} method: +-- +-- * @{#CONTROLLABLE.CommandDoScript}: Do Script command. +-- * @{#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command. +-- +-- 1.4) CONTROLLABLE Option methods +-- ------------------------- +-- Controllable **Option methods** change the behaviour of the Controllable while being alive. +-- +-- ### 1.4.1) Rule of Engagement: +-- +-- * @{#CONTROLLABLE.OptionROEWeaponFree} +-- * @{#CONTROLLABLE.OptionROEOpenFire} +-- * @{#CONTROLLABLE.OptionROEReturnFire} +-- * @{#CONTROLLABLE.OptionROEEvadeFire} +-- +-- To check whether an ROE option is valid for a specific controllable, use: +-- +-- * @{#CONTROLLABLE.OptionROEWeaponFreePossible} +-- * @{#CONTROLLABLE.OptionROEOpenFirePossible} +-- * @{#CONTROLLABLE.OptionROEReturnFirePossible} +-- * @{#CONTROLLABLE.OptionROEEvadeFirePossible} +-- +-- ### 1.4.2) Rule on thread: +-- +-- * @{#CONTROLLABLE.OptionROTNoReaction} +-- * @{#CONTROLLABLE.OptionROTPassiveDefense} +-- * @{#CONTROLLABLE.OptionROTEvadeFire} +-- * @{#CONTROLLABLE.OptionROTVertical} +-- +-- To test whether an ROT option is valid for a specific controllable, use: +-- +-- * @{#CONTROLLABLE.OptionROTNoReactionPossible} +-- * @{#CONTROLLABLE.OptionROTPassiveDefensePossible} +-- * @{#CONTROLLABLE.OptionROTEvadeFirePossible} +-- * @{#CONTROLLABLE.OptionROTVerticalPossible} +-- +-- === +-- +-- @module Controllable + +--- The CONTROLLABLE class +-- @type CONTROLLABLE +-- @extends Wrapper.Positionable#POSITIONABLE +-- @field Dcs.DCSWrapper.Controllable#Controllable DCSControllable The DCS controllable class. +-- @field #string ControllableName The name of the controllable. +CONTROLLABLE = { + ClassName = "CONTROLLABLE", + ControllableName = "", + WayPointFunctions = {}, +} + +--- Create a new CONTROLLABLE from a DCSControllable +-- @param #CONTROLLABLE self +-- @param Dcs.DCSWrapper.Controllable#Controllable ControllableName The DCS Controllable name +-- @return #CONTROLLABLE self +function CONTROLLABLE:New( ControllableName ) + local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) + self:F2( ControllableName ) + self.ControllableName = ControllableName + + self.TaskScheduler = SCHEDULER:New( self ) + return self +end + +-- DCS Controllable methods support. + +--- Get the controller for the CONTROLLABLE. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSController#Controller +function CONTROLLABLE:_GetController() + self:F2( { self.ControllableName } ) + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local ControllableController = DCSControllable:getController() + self:T3( ControllableController ) + return ControllableController + end + + return nil +end + +-- Get methods + +--- Returns the UNITs wrappers of the DCS Units of the Controllable (default is a GROUP). +-- @param #CONTROLLABLE self +-- @return #list The UNITs wrappers. +function CONTROLLABLE:GetUnits() + self:F2( { self.ControllableName } ) + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local DCSUnits = DCSControllable:getUnits() + local Units = {} + for Index, UnitData in pairs( DCSUnits ) do + Units[#Units+1] = UNIT:Find( UnitData ) + end + self:T3( Units ) + return Units + end + + return nil +end + + +--- Returns the health. Dead controllables have health <= 1.0. +-- @param #CONTROLLABLE self +-- @return #number The controllable health value (unit or group average). +-- @return #nil The controllable is not existing or alive. +function CONTROLLABLE:GetLife() + self:F2( self.ControllableName ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local UnitLife = 0 + local Units = self:GetUnits() + if #Units == 1 then + local Unit = Units[1] -- Wrapper.Unit#UNIT + UnitLife = Unit:GetLife() + else + local UnitLifeTotal = 0 + for UnitID, Unit in pairs( Units ) do + local Unit = Unit -- Wrapper.Unit#UNIT + UnitLifeTotal = UnitLifeTotal + Unit:GetLife() + end + UnitLife = UnitLifeTotal / #Units + end + return UnitLife + end + + return nil +end + + + +-- Tasks + +--- Clear all tasks from the controllable. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE +function CONTROLLABLE:ClearTasks() + self:F2() + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Controller = self:_GetController() + Controller:resetTask() + return self + end + + return nil +end + + +--- Popping current Task from the controllable. +-- @param #CONTROLLABLE self +-- @return Wrapper.Controllable#CONTROLLABLE self +function CONTROLLABLE:PopCurrentTask() + self:F2() + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Controller = self:_GetController() + Controller:popTask() + return self + end + + return nil +end + +--- Pushing Task on the queue from the controllable. +-- @param #CONTROLLABLE self +-- @return Wrapper.Controllable#CONTROLLABLE self +function CONTROLLABLE:PushTask( DCSTask, WaitTime ) + self:F2() + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Controller = self:_GetController() + + -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. + -- Therefore we schedule the functions to set the mission and options for the Controllable. + -- Controller:pushTask( DCSTask ) + + if WaitTime then + self.TaskScheduler:Schedule( Controller, Controller.pushTask, { DCSTask }, WaitTime ) + else + Controller:pushTask( DCSTask ) + end + + return self + end + + return nil +end + +--- Clearing the Task Queue and Setting the Task on the queue from the controllable. +-- @param #CONTROLLABLE self +-- @return Wrapper.Controllable#CONTROLLABLE self +function CONTROLLABLE:SetTask( DCSTask, WaitTime ) + self:F2( { DCSTask } ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local Controller = self:_GetController() + self:T3( Controller ) + + -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. + -- Therefore we schedule the functions to set the mission and options for the Controllable. + -- Controller.setTask( Controller, DCSTask ) + + if not WaitTime then + Controller:setTask( DCSTask ) + else + self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime ) + end + + return self + end + + return nil +end + + +--- Return a condition section for a controlled task. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTime#Time time +-- @param #string userFlag +-- @param #boolean userFlagValue +-- @param #string condition +-- @param Dcs.DCSTime#Time duration +-- @param #number lastWayPoint +-- return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) + self:F2( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) + + local DCSStopCondition = {} + DCSStopCondition.time = time + DCSStopCondition.userFlag = userFlag + DCSStopCondition.userFlagValue = userFlagValue + DCSStopCondition.condition = condition + DCSStopCondition.duration = duration + DCSStopCondition.lastWayPoint = lastWayPoint + + self:T3( { DCSStopCondition } ) + return DCSStopCondition +end + +--- Return a Controlled Task taking a Task and a TaskCondition. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTasking.Task#Task DCSTask +-- @param #DCSStopCondition DCSStopCondition +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition ) + self:F2( { DCSTask, DCSStopCondition } ) + + local DCSTaskControlled + + DCSTaskControlled = { + id = 'ControlledTask', + params = { + task = DCSTask, + stopCondition = DCSStopCondition + } + } + + self:T3( { DCSTaskControlled } ) + return DCSTaskControlled +end + +--- Return a Combo Task taking an array of Tasks. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTasking.Task#TaskArray DCSTasks Array of @{DCSTasking.Task#Task} +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskCombo( DCSTasks ) + self:F2( { DCSTasks } ) + + local DCSTaskCombo + + DCSTaskCombo = { + id = 'ComboTask', + params = { + tasks = DCSTasks + } + } + + for TaskID, Task in ipairs( DCSTasks ) do + self:E( Task ) + end + + self:T3( { DCSTaskCombo } ) + return DCSTaskCombo +end + +--- Return a WrappedAction Task taking a Command. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSCommand#Command DCSCommand +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index ) + self:F2( { DCSCommand } ) + + local DCSTaskWrappedAction + + DCSTaskWrappedAction = { + id = "WrappedAction", + enabled = true, + number = Index, + auto = false, + params = { + action = DCSCommand, + }, + } + + self:T3( { DCSTaskWrappedAction } ) + return DCSTaskWrappedAction +end + +--- Executes a command action +-- @param #CONTROLLABLE self +-- @param Dcs.DCSCommand#Command DCSCommand +-- @return #CONTROLLABLE self +function CONTROLLABLE:SetCommand( DCSCommand ) + self:F2( DCSCommand ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Controller = self:_GetController() + Controller:setCommand( DCSCommand ) + return self + end + + return nil +end + +--- Perform a switch waypoint command +-- @param #CONTROLLABLE self +-- @param #number FromWayPoint +-- @param #number ToWayPoint +-- @return Dcs.DCSTasking.Task#Task +-- @usage +-- --- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class. +-- HeliGroup = GROUP:FindByName( "Helicopter" ) +-- +-- --- Route the helicopter back to the FARP after 60 seconds. +-- -- We use the SCHEDULER class to do this. +-- SCHEDULER:New( nil, +-- function( HeliGroup ) +-- local CommandRTB = HeliGroup:CommandSwitchWayPoint( 2, 8 ) +-- HeliGroup:SetCommand( CommandRTB ) +-- end, { HeliGroup }, 90 +-- ) +function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint ) + self:F2( { FromWayPoint, ToWayPoint } ) + + local CommandSwitchWayPoint = { + id = 'SwitchWaypoint', + params = { + fromWaypointIndex = FromWayPoint, + goToWaypointIndex = ToWayPoint, + }, + } + + self:T3( { CommandSwitchWayPoint } ) + return CommandSwitchWayPoint +end + +--- Create a stop route command, which returns a string containing the command. +-- Use the result in the method @{#CONTROLLABLE.SetCommand}(). +-- A value of true will make the ground group stop, a value of false will make it continue. +-- Note that this can only work on GROUP level, although individual UNITs can be commanded, the whole GROUP will react. +-- +-- Example missions: +-- +-- * GRP-310 +-- +-- @param #CONTROLLABLE self +-- @param #boolean StopRoute true if the ground unit needs to stop, false if it needs to continue to move. +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:CommandStopRoute( StopRoute ) + self:F2( { StopRoute } ) + + local CommandStopRoute = { + id = 'StopRoute', + params = { + value = StopRoute, + }, + } + + self:T3( { CommandStopRoute } ) + return CommandStopRoute +end + + +-- TASKS FOR AIR CONTROLLABLES + + +--- (AIR) Attack a Controllable. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. +-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- AttackGroup = { + -- id = 'AttackGroup', + -- params = { + -- groupId = Group.ID, + -- weaponType = number, + -- expend = enum AI.Task.WeaponExpend, + -- attackQty = number, + -- directionEnabled = boolean, + -- direction = Azimuth, + -- altitudeEnabled = boolean, + -- altitude = Distance, + -- attackQtyLimit = boolean, + -- } + -- } + + local DirectionEnabled = nil + if Direction then + DirectionEnabled = true + end + + local AltitudeEnabled = nil + if Altitude then + AltitudeEnabled = true + end + + local DCSTask + DCSTask = { id = 'AttackGroup', + params = { + groupId = AttackGroup:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + directionEnabled = DirectionEnabled, + direction = Direction, + altitudeEnabled = AltitudeEnabled, + altitude = Altitude, + attackQtyLimit = AttackQtyLimit, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (AIR) Attack the Unit. +-- @param #CONTROLLABLE self +-- @param Wrapper.Unit#UNIT AttackUnit The UNIT. +-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param #number Altitude (optional) The altitude from where to attack. +-- @param #boolean Visible (optional) not a clue. +-- @param #number WeaponType (optional) The WeaponType. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskAttackUnit( AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, WeaponType ) + self:F2( { self.ControllableName, AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, WeaponType } ) + + local DCSTask + DCSTask = { + id = 'AttackUnit', + params = { + unitId = AttackUnit:GetID(), + groupAttack = GroupAttack or false, + visible = Visible or false, + expend = WeaponExpend or "Auto", + directionEnabled = Direction and true or false, + direction = Direction, + altitudeEnabled = Altitude and true or false, + altitude = Altitude or 30, + attackQtyLimit = AttackQty and true or false, + attackQty = AttackQty, + weaponType = WeaponType + } + } + + self:E( DCSTask ) + + return DCSTask +end + + +--- (AIR) Delivering weapon at the point on the ground. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskBombing( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) + +-- Bombing = { +-- id = 'Bombing', +-- params = { +-- point = Vec2, +-- weaponType = number, +-- expend = enum AI.Task.WeaponExpend, +-- attackQty = number, +-- direction = Azimuth, +-- controllableAttack = boolean, +-- } +-- } + + local DCSTask + DCSTask = { id = 'Bombing', + params = { + point = Vec2, + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Point The point to hold the position. +-- @param #number Altitude The altitude to hold the position. +-- @param #number Speed The speed flying when holding the position. +-- @return #CONTROLLABLE self +function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) + self:F2( { self.ControllableName, Point, Altitude, Speed } ) + + -- pattern = enum AI.Task.OribtPattern, + -- point = Vec2, + -- point2 = Vec2, + -- speed = Distance, + -- altitude = Distance + + local LandHeight = land.getHeight( Point ) + + self:T3( { LandHeight } ) + + local DCSTask = { id = 'Orbit', + params = { pattern = AI.Task.OrbitPattern.CIRCLE, + point = Point, + speed = Speed, + altitude = Altitude + LandHeight + } + } + + + -- local AITask = { id = 'ControlledTask', + -- params = { task = { id = 'Orbit', + -- params = { pattern = AI.Task.OrbitPattern.CIRCLE, + -- point = Point, + -- speed = Speed, + -- altitude = Altitude + LandHeight + -- } + -- }, + -- stopCondition = { duration = Duration + -- } + -- } + -- } + -- ) + + return DCSTask +end + +--- (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. +-- @param #CONTROLLABLE self +-- @param #number Altitude The altitude to hold the position. +-- @param #number Speed The speed flying when holding the position. +-- @return #CONTROLLABLE self +function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed ) + self:F2( { self.ControllableName, Altitude, Speed } ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local ControllablePoint = self:GetVec2() + return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed ) + end + + return nil +end + + + +--- (AIR) Hold position at the current position of the first unit of the controllable. +-- @param #CONTROLLABLE self +-- @param #number Duration The maximum duration in seconds to hold the position. +-- @return #CONTROLLABLE self +function CONTROLLABLE:TaskHoldPosition() + self:F2( { self.ControllableName } ) + + return self:TaskOrbitCircle( 30, 10 ) +end + + + + +--- (AIR) Attacking the map object (building, structure, e.t.c). +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point the map object is closest to. The distance between the point and the map object must not be greater than 2000 meters. Object id is not used here because Mission Editor doesn't support map object identificators. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskAttackMapObject( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) + +-- AttackMapObject = { +-- id = 'AttackMapObject', +-- params = { +-- point = Vec2, +-- weaponType = number, +-- expend = enum AI.Task.WeaponExpend, +-- attackQty = number, +-- direction = Azimuth, +-- controllableAttack = boolean, +-- } +-- } + + local DCSTask + DCSTask = { id = 'AttackMapObject', + params = { + point = Vec2, + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Delivering weapon on the runway. +-- @param #CONTROLLABLE self +-- @param Wrapper.Airbase#AIRBASE Airbase Airbase to attack. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) + +-- BombingRunway = { +-- id = 'BombingRunway', +-- params = { +-- runwayId = AirdromeId, +-- weaponType = number, +-- expend = enum AI.Task.WeaponExpend, +-- attackQty = number, +-- direction = Azimuth, +-- controllableAttack = boolean, +-- } +-- } + + local DCSTask + DCSTask = { id = 'BombingRunway', + params = { + point = Airbase:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Refueling from the nearest tanker. No parameters. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskRefueling() + self:F2( { self.ControllableName } ) + +-- Refueling = { +-- id = 'Refueling', +-- params = {} +-- } + + local DCSTask + DCSTask = { id = 'Refueling', + params = { + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR HELICOPTER) Landing at the ground. For helicopters only. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Point The point where to land. +-- @param #number Duration The duration in seconds to stay on the ground. +-- @return #CONTROLLABLE self +function CONTROLLABLE:TaskLandAtVec2( Point, Duration ) + self:F2( { self.ControllableName, Point, Duration } ) + +-- Land = { +-- id= 'Land', +-- params = { +-- point = Vec2, +-- durationFlag = boolean, +-- duration = Time +-- } +-- } + + local DCSTask + if Duration and Duration > 0 then + DCSTask = { id = 'Land', + params = { + point = Point, + durationFlag = true, + duration = Duration, + }, + } + else + DCSTask = { id = 'Land', + params = { + point = Point, + durationFlag = false, + }, + } + end + + self:T3( DCSTask ) + return DCSTask +end + +--- (AIR) Land the controllable at a @{Zone#ZONE_RADIUS). +-- @param #CONTROLLABLE self +-- @param Core.Zone#ZONE Zone The zone where to land. +-- @param #number Duration The duration in seconds to stay on the ground. +-- @return #CONTROLLABLE self +function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint ) + self:F2( { self.ControllableName, Zone, Duration, RandomPoint } ) + + local Point + if RandomPoint then + Point = Zone:GetRandomVec2() + else + Point = Zone:GetVec2() + end + + local DCSTask = self:TaskLandAtVec2( Point, Duration ) + + self:T3( DCSTask ) + return DCSTask +end + + + +--- (AIR) Following another airborne controllable. +-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. +-- If another controllable is on land the unit / controllable will orbit around. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE FollowControllable The controllable to be followed. +-- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. +-- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex ) + self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex } ) + +-- Follow = { +-- id = 'Follow', +-- params = { +-- groupId = Group.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number +-- } +-- } + + local LastWaypointIndexFlag = false + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { + id = 'Follow', + params = { + groupId = FollowControllable:GetID(), + pos = Vec3, + lastWptIndexFlag = LastWaypointIndexFlag, + lastWptIndex = LastWaypointIndex + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Escort another airborne controllable. +-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. +-- The unit / controllable will also protect that controllable from threats of specified types. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. +-- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. +-- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. +-- @param #number EngagementDistanceMax Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. +-- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes ) + self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) + +-- Escort = { +-- id = 'Escort', +-- params = { +-- groupId = Group.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number, +-- engagementDistMax = Distance, +-- targetTypes = array of AttributeName, +-- } +-- } + + local LastWaypointIndexFlag = false + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Escort', + params = { + groupId = FollowControllable:GetID(), + pos = Vec3, + lastWptIndexFlag = LastWaypointIndexFlag, + lastWptIndex = LastWaypointIndex, + engagementDistMax = EngagementDistance, + targetTypes = TargetTypes, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +-- GROUND TASKS + +--- (GROUND) Fire at a VEC2 point until ammunition is finished. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Vec2 The point to fire at. +-- @param Dcs.DCSTypes#Distance Radius The radius of the zone to deploy the fire at. +-- @param #number AmmoCount (optional) Quantity of ammunition to expand (omit to fire until ammunition is depleted). +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount ) + self:F2( { self.ControllableName, Vec2, Radius, AmmoCount } ) + + -- FireAtPoint = { + -- id = 'FireAtPoint', + -- params = { + -- point = Vec2, + -- radius = Distance, + -- expendQty = number, + -- expendQtyEnabled = boolean, + -- } + -- } + + local DCSTask + DCSTask = { id = 'FireAtPoint', + params = { + point = Vec2, + radius = Radius, + expendQty = 100, -- dummy value + expendQtyEnabled = false, + } + } + + if AmmoCount then + DCSTask.params.expendQty = AmmoCount + DCSTask.params.expendQtyEnabled = true + end + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (GROUND) Hold ground controllable from moving. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskHold() + self:F2( { self.ControllableName } ) + +-- Hold = { +-- id = 'Hold', +-- params = { +-- } +-- } + + local DCSTask + DCSTask = { id = 'Hold', + params = { + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +-- TASKS FOR AIRBORNE AND GROUND UNITS/CONTROLLABLES + +--- (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. +-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. +-- If the task is assigned to the controllable lead unit will be a FAC. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. +-- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. +-- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackGroup, WeaponType, Designation, Datalink } ) + +-- FAC_AttackGroup = { +-- id = 'FAC_AttackGroup', +-- params = { +-- groupId = Group.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_AttackGroup', + params = { + groupId = AttackGroup:GetID(), + weaponType = WeaponType, + designation = Designation, + datalink = Datalink, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +-- EN-ACT_ROUTE TASKS FOR AIRBORNE CONTROLLABLES + +--- (AIR) Engaging targets of defined types. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. +-- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. +-- @param #number Priority All enroute tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) + self:F2( { self.ControllableName, Distance, TargetTypes, Priority } ) + +-- EngageTargets ={ +-- id = 'EngageTargets', +-- params = { +-- maxDist = Distance, +-- targetTypes = array of AttributeName, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'EngageTargets', + params = { + maxDist = Distance, + targetTypes = TargetTypes, + priority = Priority + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + + +--- (AIR) Engaging a targets of defined types at circle-shaped zone. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the zone. +-- @param Dcs.DCSTypes#Distance Radius Radius of the zone. +-- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. +-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageTargets( Vec2, Radius, TargetTypes, Priority ) + self:F2( { self.ControllableName, Vec2, Radius, TargetTypes, Priority } ) + +-- EngageTargetsInZone = { +-- id = 'EngageTargetsInZone', +-- params = { +-- point = Vec2, +-- zoneRadius = Distance, +-- targetTypes = array of AttributeName, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'EngageTargetsInZone', + params = { + point = Vec2, + zoneRadius = Radius, + targetTypes = TargetTypes, + priority = Priority + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. +-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. +-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- EngageControllable = { + -- id = 'EngageControllable ', + -- params = { + -- groupId = Group.ID, + -- weaponType = number, + -- expend = enum AI.Task.WeaponExpend, + -- attackQty = number, + -- directionEnabled = boolean, + -- direction = Azimuth, + -- altitudeEnabled = boolean, + -- altitude = Distance, + -- attackQtyLimit = boolean, + -- priority = number, + -- } + -- } + + local DirectionEnabled = nil + if Direction then + DirectionEnabled = true + end + + local AltitudeEnabled = nil + if Altitude then + AltitudeEnabled = true + end + + local DCSTask + DCSTask = { id = 'EngageControllable', + params = { + groupId = AttackGroup:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + directionEnabled = DirectionEnabled, + direction = Direction, + altitudeEnabled = AltitudeEnabled, + altitude = Altitude, + attackQtyLimit = AttackQtyLimit, + priority = Priority, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Search and attack the Unit. +-- @param #CONTROLLABLE self +-- @param Wrapper.Unit#UNIT EngageUnit The UNIT. +-- @param #number Priority (optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +-- @param Dcs.DCSTypes#Distance Altitude (optional) Desired altitude to perform the unit engagement. +-- @param #boolean Visible (optional) Unit must be visible. +-- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageUnit( EngageUnit, Priority, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, ControllableAttack ) + self:F2( { self.ControllableName, EngageUnit, Priority, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, Visible, ControllableAttack } ) + + -- EngageUnit = { + -- id = 'EngageUnit', + -- params = { + -- unitId = Unit.ID, + -- weaponType = number, + -- expend = enum AI.Task.WeaponExpend + -- attackQty = number, + -- direction = Azimuth, + -- attackQtyLimit = boolean, + -- controllableAttack = boolean, + -- priority = number, + -- } + -- } + + local DCSTask + DCSTask = { id = 'EngageUnit', + params = { + unitId = EngageUnit:GetID(), + priority = Priority or 1, + groupAttack = GroupAttack or false, + visible = Visible or false, + expend = WeaponExpend or "Auto", + directionEnabled = Direction and true or false, + direction = Direction, + altitudeEnabled = Altitude and true or false, + altitude = Altitude, + attackQtyLimit = AttackQty and true or false, + attackQty = AttackQty, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + + +--- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskAWACS( ) + self:F2( { self.ControllableName } ) + +-- AWACS = { +-- id = 'AWACS', +-- params = { +-- } +-- } + + local DCSTask + DCSTask = { id = 'AWACS', + params = { + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Aircraft will act as a tanker for friendly units. No parameters. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskTanker( ) + self:F2( { self.ControllableName } ) + +-- Tanker = { +-- id = 'Tanker', +-- params = { +-- } +-- } + + local DCSTask + DCSTask = { id = 'Tanker', + params = { + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +-- En-route tasks for ground units/controllables + +--- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. +-- @param #CONTROLLABLE self +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEWR( ) + self:F2( { self.ControllableName } ) + +-- EWR = { +-- id = 'EWR', +-- params = { +-- } +-- } + + local DCSTask + DCSTask = { id = 'EWR', + params = { + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +-- En-route tasks for airborne and ground units/controllables + +--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. +-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. +-- If the task is assigned to the controllable lead unit will be a FAC. +-- @param #CONTROLLABLE self +-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. +-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. +-- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) + +-- FAC_EngageControllable = { +-- id = 'FAC_EngageControllable', +-- params = { +-- groupId = Group.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean, +-- priority = number, +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_EngageControllable', + params = { + groupId = AttackGroup:GetID(), + weaponType = WeaponType, + designation = Designation, + datalink = Datalink, + priority = Priority, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. +-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. +-- If the task is assigned to the controllable lead unit will be a FAC. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Distance Radius The maximal distance from the FAC to a target. +-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority ) + self:F2( { self.ControllableName, Radius, Priority } ) + +-- FAC = { +-- id = 'FAC', +-- params = { +-- radius = Distance, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC', + params = { + radius = Radius, + priority = Priority + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + + + +--- (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Point The point where to wait. +-- @param #number Duration The duration in seconds to wait. +-- @param #CONTROLLABLE EmbarkingControllable The controllable to be embarked. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure +function CONTROLLABLE:TaskEmbarking( Point, Duration, EmbarkingControllable ) + self:F2( { self.ControllableName, Point, Duration, EmbarkingControllable.DCSControllable } ) + + local DCSTask + DCSTask = { id = 'Embarking', + params = { x = Point.x, + y = Point.y, + duration = Duration, + controllablesForEmbarking = { EmbarkingControllable.ControllableID }, + durationFlag = true, + distributionFlag = false, + distribution = {}, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (GROUND) Embark to a Transport landed at a location. + +--- Move to a defined Vec2 Point, and embark to a controllable when arrived within a defined Radius. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec2 Point The point where to wait. +-- @param #number Radius The radius of the embarking zone around the Point. +-- @return Dcs.DCSTasking.Task#Task The DCS task structure. +function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) + self:F2( { self.ControllableName, Point, Radius } ) + + local DCSTask --Dcs.DCSTasking.Task#Task + DCSTask = { id = 'EmbarkToTransport', + params = { x = Point.x, + y = Point.y, + zoneRadius = Radius, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + + + +--- (AIR + GROUND) Return a mission task from a mission template. +-- @param #CONTROLLABLE self +-- @param #table TaskMission A table containing the mission task. +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskMission( TaskMission ) + self:F2( Points ) + + local DCSTask + DCSTask = { id = 'Mission', params = { TaskMission, }, } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- Return a Misson task to follow a given route defined by Points. +-- @param #CONTROLLABLE self +-- @param #table Points A table of route points. +-- @return Dcs.DCSTasking.Task#Task +function CONTROLLABLE:TaskRoute( Points ) + self:F2( Points ) + + local DCSTask + DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (AIR + GROUND) Make the Controllable move to fly to a given point. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. +-- @param #number Speed The speed to travel. +-- @return #CONTROLLABLE self +function CONTROLLABLE:RouteToVec2( Point, Speed ) + self:F2( { Point, Speed } ) + + local ControllablePoint = self:GetUnit( 1 ):GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + + local PointTo = {} + PointTo.x = Point.x + PointTo.y = Point.y + PointTo.type = "Turning Point" + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self +end + +--- (AIR + GROUND) Make the Controllable move to a given point. +-- @param #CONTROLLABLE self +-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. +-- @param #number Speed The speed to travel. +-- @return #CONTROLLABLE self +function CONTROLLABLE:RouteToVec3( Point, Speed ) + self:F2( { Point, Speed } ) + + local ControllableVec3 = self:GetUnit( 1 ):GetVec3() + + local PointFrom = {} + PointFrom.x = ControllableVec3.x + PointFrom.y = ControllableVec3.z + PointFrom.alt = ControllableVec3.y + PointFrom.alt_type = "BARO" + PointFrom.type = "Turning Point" + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + + local PointTo = {} + PointTo.x = Point.x + PointTo.y = Point.z + PointTo.alt = Point.y + PointTo.alt_type = "BARO" + PointTo.type = "Turning Point" + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self +end + + + +--- Make the controllable to follow a given route. +-- @param #CONTROLLABLE self +-- @param #table GoPoints A table of Route Points. +-- @return #CONTROLLABLE self +function CONTROLLABLE:Route( GoPoints ) + self:F2( GoPoints ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Points = routines.utils.deepCopy( GoPoints ) + local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } + local Controller = self:_GetController() + --Controller.setTask( Controller, MissionTask ) + self.TaskScheduler:Schedule( Controller, Controller.setTask, { MissionTask }, 1 ) + return self + end + + return nil +end + + + +--- (AIR + GROUND) Route the controllable to a given zone. +-- The controllable final destination point can be randomized. +-- A speed can be given in km/h. +-- A given formation can be given. +-- @param #CONTROLLABLE self +-- @param Core.Zone#ZONE Zone The zone where to route to. +-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. +-- @param #number Speed The speed. +-- @param Base#FORMATION Formation The formation string. +function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) + self:F2( Zone ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local ControllablePoint = self:GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = Formation or "Cone" + PointFrom.speed = 20 / 1.6 + + + local PointTo = {} + local ZonePoint + + if Randomize then + ZonePoint = Zone:GetRandomVec2() + else + ZonePoint = Zone:GetVec2() + end + + PointTo.x = ZonePoint.x + PointTo.y = ZonePoint.y + PointTo.type = "Turning Point" + + if Formation then + PointTo.action = Formation + else + PointTo.action = "Cone" + end + + if Speed then + PointTo.speed = Speed + else + PointTo.speed = 20 / 1.6 + end + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self + end + + return nil +end + + +-- Commands + +--- Do Script command +-- @param #CONTROLLABLE self +-- @param #string DoScript +-- @return #DCSCommand +function CONTROLLABLE:CommandDoScript( DoScript ) + + local DCSDoScript = { + id = "Script", + params = { + command = DoScript, + }, + } + + self:T3( DCSDoScript ) + return DCSDoScript +end + + +--- Return the mission template of the controllable. +-- @param #CONTROLLABLE self +-- @return #table The MissionTemplate +-- TODO: Rework the method how to retrieve a template ... +function CONTROLLABLE:GetTaskMission() + self:F2( self.ControllableName ) + + return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template ) +end + +--- Return the mission route of the controllable. +-- @param #CONTROLLABLE self +-- @return #table The mission route defined by points. +function CONTROLLABLE:GetTaskRoute() + self:F2( self.ControllableName ) + + return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template.route.points ) +end + + + +--- Return the route of a controllable by using the @{Database#DATABASE} class. +-- @param #CONTROLLABLE self +-- @param #number Begin The route point from where the copy will start. The base route point is 0. +-- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. +-- @param #boolean Randomize Randomization of the route, when true. +-- @param #number Radius When randomization is on, the randomization is within the radius. +function CONTROLLABLE:CopyRoute( Begin, End, Randomize, Radius ) + self:F2( { Begin, End } ) + + local Points = {} + + -- Could be a Spawned Controllable + local ControllableName = string.match( self:GetName(), ".*#" ) + if ControllableName then + ControllableName = ControllableName:sub( 1, -2 ) + else + ControllableName = self:GetName() + end + + self:T3( { ControllableName } ) + + local Template = _DATABASE.Templates.Controllables[ControllableName].Template + + if Template then + if not Begin then + Begin = 0 + end + if not End then + End = 0 + end + + for TPointID = Begin + 1, #Template.route.points - End do + if Template.route.points[TPointID] then + Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) + if Randomize then + if not Radius then + Radius = 500 + end + Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) + Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) + end + end + end + return Points + else + error( "Template not found for Controllable : " .. ControllableName ) + end + + return nil +end + + +--- Return the detected targets of the controllable. +-- The optional parametes specify the detection methods that can be applied. +-- If no detection method is given, the detection will use all the available methods by default. +-- @param Wrapper.Controllable#CONTROLLABLE self +-- @param #boolean DetectVisual (optional) +-- @param #boolean DetectOptical (optional) +-- @param #boolean DetectRadar (optional) +-- @param #boolean DetectIRST (optional) +-- @param #boolean DetectRWR (optional) +-- @param #boolean DetectDLINK (optional) +-- @return #table DetectedTargets +function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) + self:F2( self.ControllableName ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local DetectionVisual = ( DetectVisual and DetectVisual == true ) and Controller.Detection.VISUAL or nil + local DetectionOptical = ( DetectOptical and DetectOptical == true ) and Controller.Detection.OPTICAL or nil + local DetectionRadar = ( DetectRadar and DetectRadar == true ) and Controller.Detection.RADAR or nil + local DetectionIRST = ( DetectIRST and DetectIRST == true ) and Controller.Detection.IRST or nil + local DetectionRWR = ( DetectRWR and DetectRWR == true ) and Controller.Detection.RWR or nil + local DetectionDLINK = ( DetectDLINK and DetectDLINK == true ) and Controller.Detection.DLINK or nil + + + return self:_GetController():getDetectedTargets( DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK ) + end + + return nil +end + +function CONTROLLABLE:IsTargetDetected( DCSObject ) + self:F2( self.ControllableName ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + + local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + = self:_GetController().isTargetDetected( self:_GetController(), DCSObject, + Controller.Detection.VISUAL, + Controller.Detection.OPTIC, + Controller.Detection.RADAR, + Controller.Detection.IRST, + Controller.Detection.RWR, + Controller.Detection.DLINK + ) + return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + end + + return nil +end + +-- Options + +--- Can the CONTROLLABLE hold their weapons? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROEHoldFirePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() or self:IsGround() or self:IsShip() then + return true + end + + return false + end + + return nil +end + +--- Holding weapons. +-- @param Wrapper.Controllable#CONTROLLABLE self +-- @return Wrapper.Controllable#CONTROLLABLE self +function CONTROLLABLE:OptionROEHoldFire() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) + elseif self:IsGround() then + Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.WEAPON_HOLD ) + elseif self:IsShip() then + Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.WEAPON_HOLD ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE attack returning on enemy fire? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROEReturnFirePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() or self:IsGround() or self:IsShip() then + return true + end + + return false + end + + return nil +end + +--- Return fire. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROEReturnFire() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) + elseif self:IsGround() then + Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.RETURN_FIRE ) + elseif self:IsShip() then + Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.RETURN_FIRE ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE attack designated targets? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROEOpenFirePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() or self:IsGround() or self:IsShip() then + return true + end + + return false + end + + return nil +end + +--- Openfire. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROEOpenFire() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) + elseif self:IsGround() then + Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.OPEN_FIRE ) + elseif self:IsShip() then + Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.OPEN_FIRE ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE attack targets of opportunity? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROEWeaponFreePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() then + return true + end + + return false + end + + return nil +end + +--- Weapon free. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROEWeaponFree() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE ignore enemy fire? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROTNoReactionPossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() then + return true + end + + return false + end + + return nil +end + + +--- No evasion on enemy threats. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROTNoReaction() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE evade using passive defenses? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROTPassiveDefensePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() then + return true + end + + return false + end + + return nil +end + +--- Evasion passive defense. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROTPassiveDefense() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENCE ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE evade on enemy fire? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROTEvadeFirePossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() then + return true + end + + return false + end + + return nil +end + + +--- Evade on fire. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROTEvadeFire() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) + end + + return self + end + + return nil +end + +--- Can the CONTROLLABLE evade on fire using vertical manoeuvres? +-- @param #CONTROLLABLE self +-- @return #boolean +function CONTROLLABLE:OptionROTVerticalPossible() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + if self:IsAir() then + return true + end + + return false + end + + return nil +end + + +--- Evade on fire using vertical manoeuvres. +-- @param #CONTROLLABLE self +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionROTVertical() + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) + end + + return self + end + + return nil +end + +--- Retrieve the controllable mission and allow to place function hooks within the mission waypoint plan. +-- Use the method @{Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. +-- Use the method @{Controllable@CONTROLLABLE:WayPointExecute) to start the execution of the new mission plan. +-- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED! +-- @param #CONTROLLABLE self +-- @param #table WayPoints If WayPoints is given, then use the route. +-- @return #CONTROLLABLE +function CONTROLLABLE:WayPointInitialize( WayPoints ) + self:F( { WayPoints } ) + + if WayPoints then + self.WayPoints = WayPoints + else + self.WayPoints = self:GetTaskRoute() + end + + return self +end + +--- Get the current WayPoints set with the WayPoint functions( Note that the WayPoints can be nil, although there ARE waypoints). +-- @param #CONTROLLABLE self +-- @return #table WayPoints If WayPoints is given, then return the WayPoints structure. +function CONTROLLABLE:GetWayPoints() + self:F( ) + + if self.WayPoints then + return self.WayPoints + end + + return nil +end + +--- Registers a waypoint function that will be executed when the controllable moves over the WayPoint. +-- @param #CONTROLLABLE self +-- @param #number WayPoint The waypoint number. Note that the start waypoint on the route is WayPoint 1! +-- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions. +-- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters. +-- @return #CONTROLLABLE +function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... ) + self:F2( { WayPoint, WayPointIndex, WayPointFunction } ) + + table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex ) + self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPoint, WayPointIndex, WayPointFunction, arg ) + return self +end + + +function CONTROLLABLE:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) + self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) + + local DCSTask + + local DCSScript = {} + DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) " + + if FunctionArguments and #FunctionArguments > 0 then + DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, " .. table.concat( FunctionArguments, "," ) .. ")" + else + DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )" + end + + DCSTask = self:TaskWrappedAction( + self:CommandDoScript( + table.concat( DCSScript ) + ), WayPointIndex + ) + + self:T3( DCSTask ) + + return DCSTask + +end + +--- Executes the WayPoint plan. +-- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint. +-- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1! +-- @param #CONTROLLABLE self +-- @param #number WayPoint The WayPoint from where to execute the mission. +-- @param #number WaitTime The amount seconds to wait before initiating the mission. +-- @return #CONTROLLABLE +function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime ) + self:F( { WayPoint, WaitTime } ) + + if not WayPoint then + WayPoint = 1 + end + + -- When starting the mission from a certain point, the TaskPoints need to be deleted before the given WayPoint. + for TaskPointID = 1, WayPoint - 1 do + table.remove( self.WayPoints, 1 ) + end + + self:T3( self.WayPoints ) + + self:SetTask( self:TaskRoute( self.WayPoints ), WaitTime ) + + return self +end + +-- Message APIs--- **Wrapper** -- GROUP is a wrapper class for the DCS Class Group. +-- +-- === +-- +-- The @{#GROUP} class is a wrapper class to handle the DCS Group objects: +-- +-- * Support all DCS Group APIs. +-- * Enhance with Group specific APIs not in the DCS Group API set. +-- * Handle local Group Controller. +-- * Manage the "state" of the DCS Group. +-- +-- **IMPORTANT: ONE SHOULD NEVER SANATIZE these GROUP OBJECT REFERENCES! (make the GROUP object references nil).** +-- +-- See the detailed documentation on the GROUP class. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-03-26: GROUP:**RouteRTB( RTBAirbase, Speed )** added. +-- +-- 2017-03-07: GROUP:**HandleEvent( Event, EventFunction )** added. +-- 2017-03-07: GROUP:**UnHandleEvent( Event )** added. +-- +-- 2017-01-24: GROUP:**SetAIOnOff( AIOnOff )** added. +-- +-- 2017-01-24: GROUP:**SetAIOn()** added. +-- +-- 2017-01-24: GROUP:**SetAIOff()** added. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * [**Entropy**](https://forums.eagle.ru/member.php?u=111471), **Afinegan**: Came up with the requirement for AIOnOff(). +-- +-- ### Authors: +-- +-- * **FlightControl**: Design & Programming +-- +-- @module Group +-- @author FlightControl + +--- @type GROUP +-- @extends Wrapper.Controllable#CONTROLLABLE +-- @field #string GroupName The name of the group. + +--- +-- # GROUP class, extends @{Controllable#CONTROLLABLE} +-- +-- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. +-- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). +-- +-- The GROUP class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference +-- using the DCS Group or the DCS GroupName. +-- +-- Another thing to know is that GROUP objects do not "contain" the DCS Group object. +-- The GROUP methods will reference the DCS Group object by name when it is needed during API execution. +-- If the DCS Group object does not exist or is nil, the GROUP methods will return nil and log an exception in the DCS.log file. +-- +-- The GROUP class provides the following functions to retrieve quickly the relevant GROUP instance: +-- +-- * @{#GROUP.Find}(): Find a GROUP instance from the _DATABASE object using a DCS Group object. +-- * @{#GROUP.FindByName}(): Find a GROUP instance from the _DATABASE object using a DCS Group name. +-- +-- ## GROUP task methods +-- +-- A GROUP is a @{Controllable}. See the @{Controllable} task methods section for a description of the task methods. +-- +-- ### Obtain the mission from group templates +-- +-- Group templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a group and assign it to another: +-- +-- * @{Controllable#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. +-- +-- ## GROUP Command methods +-- +-- A GROUP is a @{Controllable}. See the @{Controllable} command methods section for a description of the command methods. +-- +-- ## GROUP option methods +-- +-- A GROUP is a @{Controllable}. See the @{Controllable} option methods section for a description of the option methods. +-- +-- ## GROUP Zone validation methods +-- +-- The group can be validated whether it is completely, partly or not within a @{Zone}. +-- Use the following Zone validation methods on the group: +-- +-- * @{#GROUP.IsCompletelyInZone}: Returns true if all units of the group are within a @{Zone}. +-- * @{#GROUP.IsPartlyInZone}: Returns true if some units of the group are within a @{Zone}. +-- * @{#GROUP.IsNotInZone}: Returns true if none of the group units of the group are within a @{Zone}. +-- +-- The zone can be of any @{Zone} class derived from @{Zone#ZONE_BASE}. So, these methods are polymorphic to the zones tested on. +-- +-- ## GROUP AI methods +-- +-- A GROUP has AI methods to control the AI activation. +-- +-- * @{#GROUP.SetAIOnOff}(): Turns the GROUP AI On or Off. +-- * @{#GROUP.SetAIOn}(): Turns the GROUP AI On. +-- * @{#GROUP.SetAIOff}(): Turns the GROUP AI Off. +-- +-- @field #GROUP GROUP +GROUP = { + ClassName = "GROUP", +} + +--- Create a new GROUP from a DCSGroup +-- @param #GROUP self +-- @param Dcs.DCSWrapper.Group#Group GroupName The DCS Group name +-- @return #GROUP self +function GROUP:Register( GroupName ) + self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) + self:F2( GroupName ) + self.GroupName = GroupName + + self:SetEventPriority( 4 ) + return self +end + +-- Reference methods. + +--- Find the GROUP wrapper class instance using the DCS Group. +-- @param #GROUP self +-- @param Dcs.DCSWrapper.Group#Group DCSGroup The DCS Group. +-- @return #GROUP The GROUP. +function GROUP:Find( DCSGroup ) + + local GroupName = DCSGroup:getName() -- Wrapper.Group#GROUP + local GroupFound = _DATABASE:FindGroup( GroupName ) + return GroupFound +end + +--- Find the created GROUP using the DCS Group Name. +-- @param #GROUP self +-- @param #string GroupName The DCS Group Name. +-- @return #GROUP The GROUP. +function GROUP:FindByName( GroupName ) + + local GroupFound = _DATABASE:FindGroup( GroupName ) + return GroupFound +end + +-- DCS Group methods support. + +--- Returns the DCS Group. +-- @param #GROUP self +-- @return Dcs.DCSWrapper.Group#Group The DCS Group. +function GROUP:GetDCSObject() + local DCSGroup = Group.getByName( self.GroupName ) + + if DCSGroup then + return DCSGroup + end + + return nil +end + +--- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePosition = DCSPositionable:getUnits()[1]:getPosition().p + self:T3( PositionablePosition ) + return PositionablePosition + end + + return nil +end + +--- Returns if the Group is alive. +-- The Group must: +-- +-- * Exist at run-time. +-- * Has at least one unit. +-- +-- When the first @{Unit} of the Group is active, it will return true. +-- If the first @{Unit} of the Group is inactive, it will return false. +-- +-- @param #GROUP self +-- @return #boolean true if the Group is alive and active. +-- @return #boolean false if the Group is alive but inactive. +-- @return #nil if the group does not exist anymore. +function GROUP:IsAlive() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() -- Dcs.DCSGroup#Group + + if DCSGroup then + if DCSGroup:isExist() then + local DCSUnit = DCSGroup:getUnit(1) -- Dcs.DCSUnit#Unit + if DCSUnit then + local GroupIsAlive = DCSUnit:isActive() + self:T3( GroupIsAlive ) + return GroupIsAlive + end + end + end + + return nil +end + +--- Destroys the DCS Group and all of its DCS Units. +-- Note that this destroy method also raises a destroy event at run-time. +-- So all event listeners will catch the destroy event of this DCS Group. +-- @param #GROUP self +function GROUP:Destroy() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + self:CreateEventCrash( timer.getTime(), UnitData ) + end + DCSGroup:destroy() + DCSGroup = nil + end + + return nil +end + +--- Returns category of the DCS Group. +-- @param #GROUP self +-- @return Dcs.DCSWrapper.Group#Group.Category The category ID +function GROUP:GetCategory() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + if DCSGroup then + local GroupCategory = DCSGroup:getCategory() + self:T3( GroupCategory ) + return GroupCategory + end + + return nil +end + +--- Returns the category name of the #GROUP. +-- @param #GROUP self +-- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship +function GROUP:GetCategoryName() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + if DCSGroup then + local CategoryNames = { + [Group.Category.AIRPLANE] = "Airplane", + [Group.Category.HELICOPTER] = "Helicopter", + [Group.Category.GROUND] = "Ground Unit", + [Group.Category.SHIP] = "Ship", + } + local GroupCategory = DCSGroup:getCategory() + self:T3( GroupCategory ) + + return CategoryNames[GroupCategory] + end + + return nil +end + + +--- Returns the coalition of the DCS Group. +-- @param #GROUP self +-- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The coalition side of the DCS Group. +function GROUP:GetCoalition() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + if DCSGroup then + local GroupCoalition = DCSGroup:getCoalition() + self:T3( GroupCoalition ) + return GroupCoalition + end + + return nil +end + +--- Returns the country of the DCS Group. +-- @param #GROUP self +-- @return Dcs.DCScountry#country.id The country identifier. +-- @return #nil The DCS Group is not existing or alive. +function GROUP:GetCountry() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + if DCSGroup then + local GroupCountry = DCSGroup:getUnit(1):getCountry() + self:T3( GroupCountry ) + return GroupCountry + end + + return nil +end + +--- Returns the UNIT wrapper class with number UnitNumber. +-- If the underlying DCS Unit does not exist, the method will return nil. . +-- @param #GROUP self +-- @param #number UnitNumber The number of the UNIT wrapper class to be returned. +-- @return Wrapper.Unit#UNIT The UNIT wrapper class. +function GROUP:GetUnit( UnitNumber ) + self:F2( { self.GroupName, UnitNumber } ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) + self:T2( UnitFound ) + return UnitFound + end + + return nil +end + +--- Returns the DCS Unit with number UnitNumber. +-- If the underlying DCS Unit does not exist, the method will return nil. . +-- @param #GROUP self +-- @param #number UnitNumber The number of the DCS Unit to be returned. +-- @return Dcs.DCSWrapper.Unit#Unit The DCS Unit. +function GROUP:GetDCSUnit( UnitNumber ) + self:F2( { self.GroupName, UnitNumber } ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) + self:T3( DCSUnitFound ) + return DCSUnitFound + end + + return nil +end + +--- Returns current size of the DCS Group. +-- If some of the DCS Units of the DCS Group are destroyed the size of the DCS Group is changed. +-- @param #GROUP self +-- @return #number The DCS Group size. +function GROUP:GetSize() + self:F2( { self.GroupName } ) + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupSize = DCSGroup:getSize() + self:T3( GroupSize ) + return GroupSize + end + + return nil +end + +--- +--- Returns the initial size of the DCS Group. +-- If some of the DCS Units of the DCS Group are destroyed, the initial size of the DCS Group is unchanged. +-- @param #GROUP self +-- @return #number The DCS Group initial size. +function GROUP:GetInitialSize() + self:F2( { self.GroupName } ) + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupInitialSize = DCSGroup:getInitialSize() + self:T3( GroupInitialSize ) + return GroupInitialSize + end + + return nil +end + + +--- Returns the DCS Units of the DCS Group. +-- @param #GROUP self +-- @return #table The DCS Units. +function GROUP:GetDCSUnits() + self:F2( { self.GroupName } ) + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local DCSUnits = DCSGroup:getUnits() + self:T3( DCSUnits ) + return DCSUnits + end + + return nil +end + + +--- Activates a GROUP. +-- @param #GROUP self +function GROUP:Activate() + self:F2( { self.GroupName } ) + trigger.action.activateGroup( self:GetDCSObject() ) + return self:GetDCSObject() +end + + +--- Gets the type name of the group. +-- @param #GROUP self +-- @return #string The type name of the group. +function GROUP:GetTypeName() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupTypeName = DCSGroup:getUnit(1):getTypeName() + self:T3( GroupTypeName ) + return( GroupTypeName ) + end + + return nil +end + +--- Gets the CallSign of the first DCS Unit of the DCS Group. +-- @param #GROUP self +-- @return #string The CallSign of the first DCS Unit of the DCS Group. +function GROUP:GetCallsign() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupCallSign = DCSGroup:getUnit(1):getCallsign() + self:T3( GroupCallSign ) + return GroupCallSign + end + + return nil +end + +--- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. +-- @param #GROUP self +-- @return Dcs.DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. +function GROUP:GetVec2() + self:F2( self.GroupName ) + + local UnitPoint = self:GetUnit(1) + UnitPoint:GetVec2() + local GroupPointVec2 = UnitPoint:GetVec2() + self:T3( GroupPointVec2 ) + return GroupPointVec2 +end + +--- Returns the current Vec3 vector of the first DCS Unit in the GROUP. +-- @param #GROUP self +-- @return Dcs.DCSTypes#Vec3 Current Vec3 of the first DCS Unit of the GROUP. +function GROUP:GetVec3() + self:F2( self.GroupName ) + + local GroupVec3 = self:GetUnit(1):GetVec3() + self:T3( GroupVec3 ) + return GroupVec3 +end + +--- Returns a POINT_VEC2 object indicating the point in 2D of the first UNIT of the GROUP within the mission. +-- @param #GROUP self +-- @return Core.Point#POINT_VEC2 The 2D point vector of the first DCS Unit of the GROUP. +-- @return #nil The first UNIT is not existing or alive. +function GROUP:GetPointVec2() + self:F2(self.GroupName) + + local FirstUnit = self:GetUnit(1) + + if FirstUnit then + local FirstUnitPointVec2 = FirstUnit:GetPointVec2() + self:T3(FirstUnitPointVec2) + return FirstUnitPointVec2 + end + + return nil +end + +--- Returns a random @{DCSTypes#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP. +-- @param #GROUP self +-- @param #number Radius +-- @return Dcs.DCSTypes#Vec3 The random 3D point vector around the first UNIT of the GROUP. +-- @return #nil The GROUP is invalid or empty +-- @usage +-- -- If Radius is ignored, returns the Dcs.DCSTypes#Vec3 of first UNIT of the GROUP +function GROUP:GetRandomVec3(Radius) + self:F2(self.GroupName) + + local FirstUnit = self:GetUnit(1) + + if FirstUnit then + local FirstUnitRandomPointVec3 = FirstUnit:GetRandomVec3(Radius) + self:T3(FirstUnitRandomPointVec3) + return FirstUnitRandomPointVec3 + end + + return nil +end + +--- Returns the mean heading of every UNIT in the GROUP in degrees +-- @param #GROUP self +-- @return #number mean heading of the GROUP +-- @return #nil The first UNIT is not existing or alive. +function GROUP:GetHeading() + self:F2(self.GroupName) + + local GroupSize = self:GetSize() + local HeadingAccumulator = 0 + + if GroupSize then + for i = 1, GroupSize do + HeadingAccumulator = HeadingAccumulator + self:GetUnit(i):GetHeading() + end + return math.floor(HeadingAccumulator / GroupSize) + end + + return nil + +end + +do -- Is Zone methods + +--- Returns true if all units of the group are within a @{Zone}. +-- @param #GROUP self +-- @param Core.Zone#ZONE_BASE Zone The zone to test. +-- @return #boolean Returns true if the Group is completely within the @{Zone#ZONE_BASE} +function GROUP:IsCompletelyInZone( Zone ) + self:F2( { self.GroupName, Zone } ) + + for UnitID, UnitData in pairs( self:GetUnits() ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + if Zone:IsVec3InZone( Unit:GetVec3() ) then + else + return false + end + end + + return true +end + +--- Returns true if some units of the group are within a @{Zone}. +-- @param #GROUP self +-- @param Core.Zone#ZONE_BASE Zone The zone to test. +-- @return #boolean Returns true if the Group is partially within the @{Zone#ZONE_BASE} +function GROUP:IsPartlyInZone( Zone ) + self:F2( { self.GroupName, Zone } ) + + local PartlyInZone = false + + for UnitID, UnitData in pairs( self:GetUnits() ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + if Zone:IsVec3InZone( Unit:GetVec3() ) then + PartlyInZone = true + else + -- So, if there were groups in the zone found, and suddenly one NOT in the zone, + -- then the group is partialy in the zone :-) + if PartlyInZone == true then + return true + end + end + end + + return false +end + +--- Returns true if none of the group units of the group are within a @{Zone}. +-- @param #GROUP self +-- @param Core.Zone#ZONE_BASE Zone The zone to test. +-- @return #boolean Returns true if the Group is not within the @{Zone#ZONE_BASE} +function GROUP:IsNotInZone( Zone ) + self:F2( { self.GroupName, Zone } ) + + for UnitID, UnitData in pairs( self:GetUnits() ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + if Zone:IsVec3InZone( Unit:GetVec3() ) then + return false + end + end + + return true +end + +--- Returns if the group is of an air category. +-- If the group is a helicopter or a plane, then this method will return true, otherwise false. +-- @param #GROUP self +-- @return #boolean Air category evaluation result. +function GROUP:IsAir() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER + self:T3( IsAirResult ) + return IsAirResult + end + + return nil +end + +--- Returns if the DCS Group contains Helicopters. +-- @param #GROUP self +-- @return #boolean true if DCS Group contains Helicopters. +function GROUP:IsHelicopter() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupCategory = DCSGroup:getCategory() + self:T2( GroupCategory ) + return GroupCategory == Group.Category.HELICOPTER + end + + return nil +end + +--- Returns if the DCS Group contains AirPlanes. +-- @param #GROUP self +-- @return #boolean true if DCS Group contains AirPlanes. +function GROUP:IsAirPlane() + self:F2() + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupCategory = DCSGroup:getCategory() + self:T2( GroupCategory ) + return GroupCategory == Group.Category.AIRPLANE + end + + return nil +end + +--- Returns if the DCS Group contains Ground troops. +-- @param #GROUP self +-- @return #boolean true if DCS Group contains Ground troops. +function GROUP:IsGround() + self:F2() + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupCategory = DCSGroup:getCategory() + self:T2( GroupCategory ) + return GroupCategory == Group.Category.GROUND + end + + return nil +end + +--- Returns if the DCS Group contains Ships. +-- @param #GROUP self +-- @return #boolean true if DCS Group contains Ships. +function GROUP:IsShip() + self:F2() + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupCategory = DCSGroup:getCategory() + self:T2( GroupCategory ) + return GroupCategory == Group.Category.SHIP + end + + return nil +end + +--- Returns if all units of the group are on the ground or landed. +-- If all units of this group are on the ground, this function will return true, otherwise false. +-- @param #GROUP self +-- @return #boolean All units on the ground result. +function GROUP:AllOnGround() + self:F2() + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local AllOnGroundResult = true + + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + if UnitData:inAir() then + AllOnGroundResult = false + end + end + + self:T3( AllOnGroundResult ) + return AllOnGroundResult + end + + return nil +end + +end + +do -- AI methods + + --- Turns the AI On or Off for the GROUP. + -- @param #GROUP self + -- @param #boolean AIOnOff The value true turns the AI On, the value false turns the AI Off. + -- @return #GROUP The GROUP. + function GROUP:SetAIOnOff( AIOnOff ) + + local DCSGroup = self:GetDCSObject() -- Dcs.DCSGroup#Group + + if DCSGroup then + local DCSController = DCSGroup:getController() -- Dcs.DCSController#Controller + if DCSController then + DCSController:setOnOff( AIOnOff ) + return self + end + end + + return nil + end + + --- Turns the AI On for the GROUP. + -- @param #GROUP self + -- @return #GROUP The GROUP. + function GROUP:SetAIOn() + + return self:SetAIOnOff( true ) + end + + --- Turns the AI Off for the GROUP. + -- @param #GROUP self + -- @return #GROUP The GROUP. + function GROUP:SetAIOff() + + return self:SetAIOnOff( false ) + end + +end + + + +--- Returns the current maximum velocity of the group. +-- Each unit within the group gets evaluated, and the maximum velocity (= the unit which is going the fastest) is returned. +-- @param #GROUP self +-- @return #number Maximum velocity found. +function GROUP:GetMaxVelocity() + self:F2() + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local GroupVelocityMax = 0 + + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + + local UnitVelocityVec3 = UnitData:getVelocity() + local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) + + if UnitVelocity > GroupVelocityMax then + GroupVelocityMax = UnitVelocity + end + end + + return GroupVelocityMax + end + + return nil +end + +--- Returns the current minimum height of the group. +-- Each unit within the group gets evaluated, and the minimum height (= the unit which is the lowest elevated) is returned. +-- @param #GROUP self +-- @return #number Minimum height found. +function GROUP:GetMinHeight() + self:F2() + +end + +--- Returns the current maximum height of the group. +-- Each unit within the group gets evaluated, and the maximum height (= the unit which is the highest elevated) is returned. +-- @param #GROUP self +-- @return #number Maximum height found. +function GROUP:GetMaxHeight() + self:F2() + +end + +-- SPAWNING + +--- Respawn the @{GROUP} using a (tweaked) template of the Group. +-- The template must be retrieved with the @{Group#GROUP.GetTemplate}() function. +-- The template contains all the definitions as declared within the mission file. +-- To understand templates, do the following: +-- +-- * unpack your .miz file into a directory using 7-zip. +-- * browse in the directory created to the file **mission**. +-- * open the file and search for the country group definitions. +-- +-- Your group template will contain the fields as described within the mission file. +-- +-- This function will: +-- +-- * Get the current position and heading of the group. +-- * When the group is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. +-- * Then it will destroy the current alive group. +-- * And it will respawn the group using your new template definition. +-- @param Wrapper.Group#GROUP self +-- @param #table Template The template of the Group retrieved with GROUP:GetTemplate() +function GROUP:Respawn( Template ) + + local Vec3 = self:GetVec3() + Template.x = Vec3.x + Template.y = Vec3.z + --Template.x = nil + --Template.y = nil + + self:E( #Template.units ) + for UnitID, UnitData in pairs( self:GetUnits() ) do + local GroupUnit = UnitData -- Wrapper.Unit#UNIT + self:E( GroupUnit:GetName() ) + if GroupUnit:IsAlive() then + local GroupUnitVec3 = GroupUnit:GetVec3() + local GroupUnitHeading = GroupUnit:GetHeading() + Template.units[UnitID].alt = GroupUnitVec3.y + Template.units[UnitID].x = GroupUnitVec3.x + Template.units[UnitID].y = GroupUnitVec3.z + Template.units[UnitID].heading = GroupUnitHeading + self:E( { UnitID, Template.units[UnitID], Template.units[UnitID] } ) + end + end + + self:Destroy() + _DATABASE:Spawn( Template ) +end + +--- Returns the group template from the @{DATABASE} (_DATABASE object). +-- @param #GROUP self +-- @return #table +function GROUP:GetTemplate() + local GroupName = self:GetName() + self:E( GroupName ) + return _DATABASE:GetGroupTemplate( GroupName ) +end + +--- Sets the controlled status in a Template. +-- @param #GROUP self +-- @param #boolean Controlled true is controlled, false is uncontrolled. +-- @return #table +function GROUP:SetTemplateControlled( Template, Controlled ) + Template.uncontrolled = not Controlled + return Template +end + +--- Sets the CountryID of the group in a Template. +-- @param #GROUP self +-- @param Dcs.DCScountry#country.id CountryID The country ID. +-- @return #table +function GROUP:SetTemplateCountry( Template, CountryID ) + Template.CountryID = CountryID + return Template +end + +--- Sets the CoalitionID of the group in a Template. +-- @param #GROUP self +-- @param Dcs.DCSCoalitionWrapper.Object#coalition.side CoalitionID The coalition ID. +-- @return #table +function GROUP:SetTemplateCoalition( Template, CoalitionID ) + Template.CoalitionID = CoalitionID + return Template +end + + + + +--- Return the mission template of the group. +-- @param #GROUP self +-- @return #table The MissionTemplate +function GROUP:GetTaskMission() + self:F2( self.GroupName ) + + return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template ) +end + +--- Return the mission route of the group. +-- @param #GROUP self +-- @return #table The mission route defined by points. +function GROUP:GetTaskRoute() + self:F2( self.GroupName ) + + return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points ) +end + +--- Return the route of a group by using the @{Database#DATABASE} class. +-- @param #GROUP self +-- @param #number Begin The route point from where the copy will start. The base route point is 0. +-- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. +-- @param #boolean Randomize Randomization of the route, when true. +-- @param #number Radius When randomization is on, the randomization is within the radius. +function GROUP:CopyRoute( Begin, End, Randomize, Radius ) + self:F2( { Begin, End } ) + + local Points = {} + + -- Could be a Spawned Group + local GroupName = string.match( self:GetName(), ".*#" ) + if GroupName then + GroupName = GroupName:sub( 1, -2 ) + else + GroupName = self:GetName() + end + + self:T3( { GroupName } ) + + local Template = _DATABASE.Templates.Groups[GroupName].Template + + if Template then + if not Begin then + Begin = 0 + end + if not End then + End = 0 + end + + for TPointID = Begin + 1, #Template.route.points - End do + if Template.route.points[TPointID] then + Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) + if Randomize then + if not Radius then + Radius = 500 + end + Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) + Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) + end + end + end + return Points + else + error( "Template not found for Group : " .. GroupName ) + end + + return nil +end + +--- Calculate the maxium A2G threat level of the Group. +-- @param #GROUP self +function GROUP:CalculateThreatLevelA2G() + + local MaxThreatLevelA2G = 0 + for UnitName, UnitData in pairs( self:GetUnits() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + local ThreatLevelA2G = ThreatUnit:GetThreatLevel() + if ThreatLevelA2G > MaxThreatLevelA2G then + MaxThreatLevelA2G = ThreatLevelA2G + end + end + + self:T3( MaxThreatLevelA2G ) + return MaxThreatLevelA2G +end + +--- Returns true if the first unit of the GROUP is in the air. +-- @param Wrapper.Group#GROUP self +-- @return #boolean true if in the first unit of the group is in the air. +-- @return #nil The GROUP is not existing or not alive. +function GROUP:InAir() + self:F2( self.GroupName ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + local DCSUnit = DCSGroup:getUnit(1) + if DCSUnit then + local GroupInAir = DCSGroup:getUnit(1):inAir() + self:T3( GroupInAir ) + return GroupInAir + end + end + + return nil +end + +do -- Route methods + + --- (AIR) Return the Group to an @{Airbase#AIRBASE}. + -- The following things are to be taken into account: + -- + -- * The group is respawned to achieve the RTB, there may be side artefacts as a result of this. (Like weapons suddenly come back). + -- * A group consisting out of more than one unit, may rejoin formation when respawned. + -- * A speed can be given in km/h. If no speed is specified, the maximum speed of the first unit will be taken to return to base. + -- * When there is no @{Airbase} object specified, the group will return to the home base if the route of the group is pinned at take-off or at landing to a base. + -- * When there is no @{Airbase} object specified and the group route is not pinned to any airbase, it will return to the nearest airbase. + -- + -- @param #GROUP self + -- @param Wrapper.Airbase#AIRBASE RTBAirbase (optional) The @{Airbase} to return to. If blank, the controllable will return to the nearest friendly airbase. + -- @param #number Speed (optional) The Speed, if no Speed is given, the maximum Speed of the first unit is selected. + -- @return #GROUP + function GROUP:RouteRTB( RTBAirbase, Speed ) + self:F2( { RTBAirbase, Speed } ) + + local DCSGroup = self:GetDCSObject() + + if DCSGroup then + + if RTBAirbase then + + local GroupPoint = self:GetVec2() + local GroupVelocity = self:GetUnit(1):GetDesc().speedMax + + local PointFrom = {} + PointFrom.x = GroupPoint.x + PointFrom.y = GroupPoint.y + PointFrom.type = "Turning Point" + PointFrom.action = "Turning Point" + PointFrom.speed = GroupVelocity + + + local PointTo = {} + local AirbasePointVec2 = RTBAirbase:GetPointVec2() + local AirbaseAirPoint = AirbasePointVec2:RoutePointAir( + POINT_VEC3.RoutePointAltType.BARO, + "Land", + "Landing", + Speed or self:GetUnit(1):GetDesc().speedMax + ) + + AirbaseAirPoint["airdromeId"] = RTBAirbase:GetID() + AirbaseAirPoint["speed_locked"] = true, + + self:E(AirbaseAirPoint ) + + local Points = { PointFrom, AirbaseAirPoint } + + self:T3( Points ) + + local Template = self:GetTemplate() + Template.route.points = Points + self:Respawn( Template ) + + self:Route( Points ) + + self:Respawn(Template) + else + self:ClearTasks() + end + end + + return self + end + +end + +function GROUP:OnReSpawn( ReSpawnFunction ) + + self.ReSpawnFunction = ReSpawnFunction +end + +do -- Event Handling + + --- Subscribe to a DCS Event. + -- @param #GROUP self + -- @param Core.Event#EVENTS Event + -- @param #function EventFunction (optional) The function to be called when the event occurs for the GROUP. + -- @return #GROUP + function GROUP:HandleEvent( Event, EventFunction ) + + self:EventDispatcher():OnEventForGroup( self:GetName(), EventFunction, self, Event ) + + return self + end + + --- UnSubscribe to a DCS event. + -- @param #GROUP self + -- @param Core.Event#EVENTS Event + -- @return #GROUP + function GROUP:UnHandleEvent( Event ) + + self:EventDispatcher():RemoveForGroup( self:GetName(), self, Event ) + + return self + end + +end + +do -- Players + + --- Get player names + -- @param #GROUP self + -- @return #table The group has players, an array of player names is returned. + -- @return #nil The group has no players + function GROUP:GetPlayerNames() + + local PlayerNames = nil + + local Units = self:GetUnits() + for UnitID, UnitData in pairs( Units ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + local PlayerName = Unit:GetPlayerName() + if PlayerName and PlayerName ~= "" then + PlayerNames = PlayerNames or {} + table.insert( PlayerNames, PlayerName ) + end + end + + self:F( PlayerNames ) + return PlayerNames + end + +end--- **Wrapper** - UNIT is a wrapper class for the DCS Class Unit. +-- +-- === +-- +-- The @{#UNIT} class is a wrapper class to handle the DCS Unit objects: +-- +-- * Support all DCS Unit APIs. +-- * Enhance with Unit specific APIs not in the DCS Unit API set. +-- * Handle local Unit Controller. +-- * Manage the "state" of the DCS Unit. +-- +-- @module Unit + +--- @type UNIT +-- @extends Wrapper.Controllable#CONTROLLABLE + +--- +-- # UNIT class, extends @{Controllable#CONTROLLABLE} +-- +-- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. +-- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Unit objects are spawned (using the @{SPAWN} class). +-- +-- The UNIT class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference +-- using the DCS Unit or the DCS UnitName. +-- +-- Another thing to know is that UNIT objects do not "contain" the DCS Unit object. +-- The UNIT methods will reference the DCS Unit object by name when it is needed during API execution. +-- If the DCS Unit object does not exist or is nil, the UNIT methods will return nil and log an exception in the DCS.log file. +-- +-- The UNIT class provides the following functions to retrieve quickly the relevant UNIT instance: +-- +-- * @{#UNIT.Find}(): Find a UNIT instance from the _DATABASE object using a DCS Unit object. +-- * @{#UNIT.FindByName}(): Find a UNIT instance from the _DATABASE object using a DCS Unit name. +-- +-- IMPORTANT: ONE SHOULD NEVER SANATIZE these UNIT OBJECT REFERENCES! (make the UNIT object references nil). +-- +-- ## DCS UNIT APIs +-- +-- The DCS Unit APIs are used extensively within MOOSE. The UNIT class has for each DCS Unit API a corresponding method. +-- To be able to distinguish easily in your code the difference between a UNIT API call and a DCS Unit API call, +-- the first letter of the method is also capitalized. So, by example, the DCS Unit method @{DCSWrapper.Unit#Unit.getName}() +-- is implemented in the UNIT class as @{#UNIT.GetName}(). +-- +-- ## Smoke, Flare Units +-- +-- The UNIT class provides methods to smoke or flare units easily. +-- The @{#UNIT.SmokeBlue}(), @{#UNIT.SmokeGreen}(),@{#UNIT.SmokeOrange}(), @{#UNIT.SmokeRed}(), @{#UNIT.SmokeRed}() methods +-- will smoke the unit in the corresponding color. Note that smoking a unit is done at the current position of the DCS Unit. +-- When the DCS Unit moves for whatever reason, the smoking will still continue! +-- The @{#UNIT.FlareGreen}(), @{#UNIT.FlareRed}(), @{#UNIT.FlareWhite}(), @{#UNIT.FlareYellow}() +-- methods will fire off a flare in the air with the corresponding color. Note that a flare is a one-off shot and its effect is of very short duration. +-- +-- ## Location Position, Point +-- +-- The UNIT class provides methods to obtain the current point or position of the DCS Unit. +-- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively. +-- If you want to obtain the complete **3D position** including ori�ntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively. +-- +-- ## Test if alive +-- +-- The @{#UNIT.IsAlive}(), @{#UNIT.IsActive}() methods determines if the DCS Unit is alive, meaning, it is existing and active. +-- +-- ## Test for proximity +-- +-- The UNIT class contains methods to test the location or proximity against zones or other objects. +-- +-- ### Zones +-- +-- To test whether the Unit is within a **zone**, use the @{#UNIT.IsInZone}() or the @{#UNIT.IsNotInZone}() methods. Any zone can be tested on, but the zone must be derived from @{Zone#ZONE_BASE}. +-- +-- ### Units +-- +-- Test if another DCS Unit is within a given radius of the current DCS Unit, use the @{#UNIT.OtherUnitInRadius}() method. +-- +-- @field #UNIT UNIT +UNIT = { + ClassName="UNIT", +} + + +--- Unit.SensorType +-- @type Unit.SensorType +-- @field OPTIC +-- @field RADAR +-- @field IRST +-- @field RWR + + +-- Registration. + +--- Create a new UNIT from DCSUnit. +-- @param #UNIT self +-- @param #string UnitName The name of the DCS unit. +-- @return #UNIT +function UNIT:Register( UnitName ) + local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) + self.UnitName = UnitName + + self:SetEventPriority( 3 ) + return self +end + +-- Reference methods. + +--- Finds a UNIT from the _DATABASE using a DCSUnit object. +-- @param #UNIT self +-- @param Dcs.DCSWrapper.Unit#Unit DCSUnit An existing DCS Unit object reference. +-- @return #UNIT self +function UNIT:Find( DCSUnit ) + + local UnitName = DCSUnit:getName() + local UnitFound = _DATABASE:FindUnit( UnitName ) + return UnitFound +end + +--- Find a UNIT in the _DATABASE using the name of an existing DCS Unit. +-- @param #UNIT self +-- @param #string UnitName The Unit Name. +-- @return #UNIT self +function UNIT:FindByName( UnitName ) + + local UnitFound = _DATABASE:FindUnit( UnitName ) + return UnitFound +end + +--- Return the name of the UNIT. +-- @param #UNIT self +-- @return #string The UNIT name. +function UNIT:Name() + + return self.UnitName +end + + +--- @param #UNIT self +-- @return Dcs.DCSWrapper.Unit#Unit +function UNIT:GetDCSObject() + + local DCSUnit = Unit.getByName( self.UnitName ) + + if DCSUnit then + return DCSUnit + end + + return nil +end + +--- Respawn the @{Unit} using a (tweaked) template of the parent Group. +-- +-- This function will: +-- +-- * Get the current position and heading of the group. +-- * When the unit is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. +-- * Then it will respawn the re-modelled group. +-- +-- @param #UNIT self +-- @param Dcs.DCSTypes#Vec3 SpawnVec3 The position where to Spawn the new Unit at. +-- @param #number Heading The heading of the unit respawn. +function UNIT:ReSpawn( SpawnVec3, Heading ) + + local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) + self:T( SpawnGroupTemplate ) + + local SpawnGroup = self:GetGroup() + + if SpawnGroup then + + local Vec3 = SpawnGroup:GetVec3() + SpawnGroupTemplate.x = SpawnVec3.x + SpawnGroupTemplate.y = SpawnVec3.z + + self:E( #SpawnGroupTemplate.units ) + for UnitID, UnitData in pairs( SpawnGroup:GetUnits() ) do + local GroupUnit = UnitData -- #UNIT + self:E( GroupUnit:GetName() ) + if GroupUnit:IsAlive() then + local GroupUnitVec3 = GroupUnit:GetVec3() + local GroupUnitHeading = GroupUnit:GetHeading() + SpawnGroupTemplate.units[UnitID].alt = GroupUnitVec3.y + SpawnGroupTemplate.units[UnitID].x = GroupUnitVec3.x + SpawnGroupTemplate.units[UnitID].y = GroupUnitVec3.z + SpawnGroupTemplate.units[UnitID].heading = GroupUnitHeading + self:E( { UnitID, SpawnGroupTemplate.units[UnitID], SpawnGroupTemplate.units[UnitID] } ) + end + end + end + + for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do + self:T( UnitTemplateData.name ) + if UnitTemplateData.name == self:Name() then + self:T("Adjusting") + SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y + SpawnGroupTemplate.units[UnitTemplateID].x = SpawnVec3.x + SpawnGroupTemplate.units[UnitTemplateID].y = SpawnVec3.z + SpawnGroupTemplate.units[UnitTemplateID].heading = Heading + self:E( { UnitTemplateID, SpawnGroupTemplate.units[UnitTemplateID], SpawnGroupTemplate.units[UnitTemplateID] } ) + else + self:E( SpawnGroupTemplate.units[UnitTemplateID].name ) + local GroupUnit = UNIT:FindByName( SpawnGroupTemplate.units[UnitTemplateID].name ) -- #UNIT + if GroupUnit and GroupUnit:IsAlive() then + local GroupUnitVec3 = GroupUnit:GetVec3() + local GroupUnitHeading = GroupUnit:GetHeading() + UnitTemplateData.alt = GroupUnitVec3.y + UnitTemplateData.x = GroupUnitVec3.x + UnitTemplateData.y = GroupUnitVec3.z + UnitTemplateData.heading = GroupUnitHeading + else + if SpawnGroupTemplate.units[UnitTemplateID].name ~= self:Name() then + self:T("nilling") + SpawnGroupTemplate.units[UnitTemplateID].delete = true + end + end + end + end + + -- Remove obscolete units from the group structure + local i = 1 + while i <= #SpawnGroupTemplate.units do + + local UnitTemplateData = SpawnGroupTemplate.units[i] + self:T( UnitTemplateData.name ) + + if UnitTemplateData.delete then + table.remove( SpawnGroupTemplate.units, i ) + else + i = i + 1 + end + end + + _DATABASE:Spawn( SpawnGroupTemplate ) +end + + + +--- Returns if the unit is activated. +-- @param #UNIT self +-- @return #boolean true if Unit is activated. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:IsActive() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + + local UnitIsActive = DCSUnit:isActive() + return UnitIsActive + end + + return nil +end + +--- Returns if the Unit is alive. +-- If the Unit is not alive, nil is returned. +-- If the Unit is alive and active, true is returned. +-- If the Unit is alive but not active, false is returned. +-- @param #UNIT self +-- @return #boolean true if Unit is alive and active. +-- @return #boolean false if Unit is alive but not active. +-- @return #nil if the Unit is not existing or is not alive. +function UNIT:IsAlive() + self:F3( self.UnitName ) + + local DCSUnit = self:GetDCSObject() -- Dcs.DCSUnit#Unit + + if DCSUnit then + local UnitIsAlive = DCSUnit:isExist() and DCSUnit:isActive() + return UnitIsAlive + end + + return nil +end + + + +--- Returns the Unit's callsign - the localized string. +-- @param #UNIT self +-- @return #string The Callsign of the Unit. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetCallsign() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitCallSign = DCSUnit:getCallsign() + return UnitCallSign + end + + self:E( self.ClassName .. " " .. self.UnitName .. " not found!" ) + return nil +end + + +--- Returns name of the player that control the unit or nil if the unit is controlled by A.I. +-- @param #UNIT self +-- @return #string Player Name +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetPlayerName() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + + local PlayerName = DCSUnit:getPlayerName() + if PlayerName == nil then + PlayerName = "" + end + return PlayerName + end + + return nil +end + +--- Returns the unit's number in the group. +-- The number is the same number the unit has in ME. +-- It may not be changed during the mission. +-- If any unit in the group is destroyed, the numbers of another units will not be changed. +-- @param #UNIT self +-- @return #number The Unit number. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetNumber() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitNumber = DCSUnit:getNumber() + return UnitNumber + end + + return nil +end + +--- Returns the unit's group if it exist and nil otherwise. +-- @param Wrapper.Unit#UNIT self +-- @return Wrapper.Group#GROUP The Group of the Unit. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetGroup() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) + return UnitGroup + end + + return nil +end + + +-- Need to add here functions to check if radar is on and which object etc. + +--- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign. +-- DCS Units spawned with the @{SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name. +-- The spawn sequence number and unit number are contained within the name after the '#' sign. +-- @param #UNIT self +-- @return #string The name of the DCS Unit. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetPrefix() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) + self:T3( UnitPrefix ) + return UnitPrefix + end + + return nil +end + +--- Returns the Unit's ammunition. +-- @param #UNIT self +-- @return Dcs.DCSWrapper.Unit#Unit.Ammo +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetAmmo() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitAmmo = DCSUnit:getAmmo() + return UnitAmmo + end + + return nil +end + +--- Returns the unit sensors. +-- @param #UNIT self +-- @return Dcs.DCSWrapper.Unit#Unit.Sensors +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetSensors() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitSensors = DCSUnit:getSensors() + return UnitSensors + end + + return nil +end + +-- Need to add here a function per sensortype +-- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS) + +--- Returns if the unit has sensors of a certain type. +-- @param #UNIT self +-- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:HasSensors( ... ) + self:F2( arg ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local HasSensors = DCSUnit:hasSensors( unpack( arg ) ) + return HasSensors + end + + return nil +end + +--- Returns if the unit is SEADable. +-- @param #UNIT self +-- @return #boolean returns true if the unit is SEADable. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:HasSEAD() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitSEADAttributes = DCSUnit:getDesc().attributes + + local HasSEAD = false + if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or + UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true then + HasSEAD = true + end + return HasSEAD + end + + return nil +end + +--- Returns two values: +-- +-- * First value indicates if at least one of the unit's radar(s) is on. +-- * Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. +-- @param #UNIT self +-- @return #boolean Indicates if at least one of the unit's radar(s) is on. +-- @return Dcs.DCSWrapper.Object#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetRadar() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() + return UnitRadarOn, UnitRadarObject + end + + return nil, nil +end + +--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0. +-- @param #UNIT self +-- @return #number The relative amount of fuel (from 0.0 to 1.0). +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetFuel() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitFuel = DCSUnit:getFuel() + return UnitFuel + end + + return nil +end + +--- Returns the UNIT in a UNIT list of one element. +-- @param #UNIT self +-- @return #list The UNITs wrappers. +function UNIT:GetUnits() + self:F2( { self.UnitName } ) + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local DCSUnits = DCSUnit:getUnits() + local Units = {} + Units[1] = UNIT:Find( DCSUnit ) + self:T3( Units ) + return Units + end + + return nil +end + + +--- Returns the unit's health. Dead units has health <= 1.0. +-- @param #UNIT self +-- @return #number The Unit's health value. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetLife() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitLife = DCSUnit:getLife() + return UnitLife + end + + return nil +end + +--- Returns the Unit's initial health. +-- @param #UNIT self +-- @return #number The Unit's initial health value. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:GetLife0() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitLife0 = DCSUnit:getLife0() + return UnitLife0 + end + + return nil +end + +--- Returns the category name of the #UNIT. +-- @param #UNIT self +-- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship +function UNIT:GetCategoryName() + self:F3( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + if DCSUnit then + local CategoryNames = { + [Unit.Category.AIRPLANE] = "Airplane", + [Unit.Category.HELICOPTER] = "Helicopter", + [Unit.Category.GROUND_UNIT] = "Ground Unit", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } + local UnitCategory = DCSUnit:getDesc().category + self:T3( UnitCategory ) + + return CategoryNames[UnitCategory] + end + + return nil +end + + +--- Returns the Unit's A2G threat level on a scale from 1 to 10 ... +-- The following threat levels are foreseen: +-- +-- * Threat level 0: Unit is unarmed. +-- * Threat level 1: Unit is infantry. +-- * Threat level 2: Unit is an infantry vehicle. +-- * Threat level 3: Unit is ground artillery. +-- * Threat level 4: Unit is a tank. +-- * Threat level 5: Unit is a modern tank or ifv with ATGM. +-- * Threat level 6: Unit is a AAA. +-- * Threat level 7: Unit is a SAM or manpad, IR guided. +-- * Threat level 8: Unit is a Short Range SAM, radar guided. +-- * Threat level 9: Unit is a Medium Range SAM, radar guided. +-- * Threat level 10: Unit is a Long Range SAM, radar guided. +-- @param #UNIT self +function UNIT:GetThreatLevel() + + local Attributes = self:GetDesc().attributes + self:T( Attributes ) + + local ThreatLevel = 0 + local ThreatText = "" + + if self:IsGround() then + + self:T( "Ground" ) + + local ThreatLevels = { + "Unarmed", + "Infantry", + "Old Tanks & APCs", + "Tanks & IFVs without ATGM", + "Tanks & IFV with ATGM", + "Modern Tanks", + "AAA", + "IR Guided SAMs", + "SR SAMs", + "MR SAMs", + "LR SAMs" + } + + + if Attributes["LR SAM"] then ThreatLevel = 10 + elseif Attributes["MR SAM"] then ThreatLevel = 9 + elseif Attributes["SR SAM"] and + not Attributes["IR Guided SAM"] then ThreatLevel = 8 + elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and + Attributes["IR Guided SAM"] then ThreatLevel = 7 + elseif Attributes["AAA"] then ThreatLevel = 6 + elseif Attributes["Modern Tanks"] then ThreatLevel = 5 + elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and + Attributes["ATGM"] then ThreatLevel = 4 + elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and + not Attributes["ATGM"] then ThreatLevel = 3 + elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2 + elseif Attributes["Infantry"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] + end + + if self:IsAir() then + + self:T( "Air" ) + + local ThreatLevels = { + "Unarmed", + "Tanker", + "AWACS", + "Transport Helicpter", + "UAV", + "Bomber", + "Strategic Bomber", + "Attack Helicopter", + "Interceptor", + "Multirole Fighter", + "Fighter" + } + + + if Attributes["Fighters"] then ThreatLevel = 10 + elseif Attributes["Multirole fighters"] then ThreatLevel = 9 + elseif Attributes["Battleplanes"] then ThreatLevel = 8 + elseif Attributes["Attack helicopters"] then ThreatLevel = 7 + elseif Attributes["Strategic bombers"] then ThreatLevel = 6 + elseif Attributes["Bombers"] then ThreatLevel = 5 + elseif Attributes["UAVs"] then ThreatLevel = 4 + elseif Attributes["Transport helicopters"] then ThreatLevel = 3 + elseif Attributes["AWACS"] then ThreatLevel = 2 + elseif Attributes["Tankers"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] + end + + if self:IsShip() then + + self:T( "Ship" ) + +--["Aircraft Carriers"] = {"Heavy armed ships",}, +--["Cruisers"] = {"Heavy armed ships",}, +--["Destroyers"] = {"Heavy armed ships",}, +--["Frigates"] = {"Heavy armed ships",}, +--["Corvettes"] = {"Heavy armed ships",}, +--["Heavy armed ships"] = {"Armed ships", "Armed Air Defence", "HeavyArmoredUnits",}, +--["Light armed ships"] = {"Armed ships","NonArmoredUnits"}, +--["Armed ships"] = {"Ships"}, +--["Unarmed ships"] = {"Ships","HeavyArmoredUnits",}, + + local ThreatLevels = { + "Unarmed ship", + "Light armed ships", + "Corvettes", + "", + "Frigates", + "", + "Cruiser", + "", + "Destroyer", + "", + "Aircraft Carrier" + } + + + if Attributes["Aircraft Carriers"] then ThreatLevel = 10 + elseif Attributes["Destroyers"] then ThreatLevel = 8 + elseif Attributes["Cruisers"] then ThreatLevel = 6 + elseif Attributes["Frigates"] then ThreatLevel = 4 + elseif Attributes["Corvettes"] then ThreatLevel = 2 + elseif Attributes["Light armed ships"] then ThreatLevel = 1 + end + + ThreatText = ThreatLevels[ThreatLevel+1] + end + + self:T2( ThreatLevel ) + return ThreatLevel, ThreatText + +end + + +-- Is functions + +--- Returns true if the unit is within a @{Zone}. +-- @param #UNIT self +-- @param Core.Zone#ZONE_BASE Zone The zone to test. +-- @return #boolean Returns true if the unit is within the @{Zone#ZONE_BASE} +function UNIT:IsInZone( Zone ) + self:F2( { self.UnitName, Zone } ) + + if self:IsAlive() then + local IsInZone = Zone:IsVec3InZone( self:GetVec3() ) + + self:T( { IsInZone } ) + return IsInZone + end + + return false +end + +--- Returns true if the unit is not within a @{Zone}. +-- @param #UNIT self +-- @param Core.Zone#ZONE_BASE Zone The zone to test. +-- @return #boolean Returns true if the unit is not within the @{Zone#ZONE_BASE} +function UNIT:IsNotInZone( Zone ) + self:F2( { self.UnitName, Zone } ) + + if self:IsAlive() then + local IsInZone = not Zone:IsVec3InZone( self:GetVec3() ) + + self:T( { IsInZone } ) + return IsInZone + else + return false + end +end + + +--- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. +-- @param #UNIT self +-- @param #UNIT AwaitUnit The other UNIT wrapper object. +-- @param Radius The radius in meters with the DCS Unit in the centre. +-- @return true If the other DCS Unit is within the radius of the 2D point of the DCS Unit. +-- @return #nil The DCS Unit is not existing or alive. +function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) + self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitVec3 = self:GetVec3() + local AwaitUnitVec3 = AwaitUnit:GetVec3() + + if (((UnitVec3.x - AwaitUnitVec3.x)^2 + (UnitVec3.z - AwaitUnitVec3.z)^2)^0.5 <= Radius) then + self:T3( "true" ) + return true + else + self:T3( "false" ) + return false + end + end + + return nil +end + + + +--- Signal a flare at the position of the UNIT. +-- @param #UNIT self +-- @param Utilities.Utils#FLARECOLOR FlareColor +function UNIT:Flare( FlareColor ) + self:F2() + trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 ) +end + +--- Signal a white flare at the position of the UNIT. +-- @param #UNIT self +function UNIT:FlareWhite() + self:F2() + trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 ) +end + +--- Signal a yellow flare at the position of the UNIT. +-- @param #UNIT self +function UNIT:FlareYellow() + self:F2() + trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 ) +end + +--- Signal a green flare at the position of the UNIT. +-- @param #UNIT self +function UNIT:FlareGreen() + self:F2() + trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 ) +end + +--- Signal a red flare at the position of the UNIT. +-- @param #UNIT self +function UNIT:FlareRed() + self:F2() + local Vec3 = self:GetVec3() + if Vec3 then + trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 ) + end +end + +--- Smoke the UNIT. +-- @param #UNIT self +function UNIT:Smoke( SmokeColor, Range ) + self:F2() + if Range then + trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor ) + else + trigger.action.smoke( self:GetVec3(), SmokeColor ) + end + +end + +--- Smoke the UNIT Green. +-- @param #UNIT self +function UNIT:SmokeGreen() + self:F2() + trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green ) +end + +--- Smoke the UNIT Red. +-- @param #UNIT self +function UNIT:SmokeRed() + self:F2() + trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red ) +end + +--- Smoke the UNIT White. +-- @param #UNIT self +function UNIT:SmokeWhite() + self:F2() + trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White ) +end + +--- Smoke the UNIT Orange. +-- @param #UNIT self +function UNIT:SmokeOrange() + self:F2() + trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange ) +end + +--- Smoke the UNIT Blue. +-- @param #UNIT self +function UNIT:SmokeBlue() + self:F2() + trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue ) +end + +-- Is methods + +--- Returns if the unit is of an air category. +-- If the unit is a helicopter or a plane, then this method will return true, otherwise false. +-- @param #UNIT self +-- @return #boolean Air category evaluation result. +function UNIT:IsAir() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitDescriptor = DCSUnit:getDesc() + self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) + + local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) + + self:T3( IsAirResult ) + return IsAirResult + end + + return nil +end + +--- Returns if the unit is of an ground category. +-- If the unit is a ground vehicle or infantry, this method will return true, otherwise false. +-- @param #UNIT self +-- @return #boolean Ground category evaluation result. +function UNIT:IsGround() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitDescriptor = DCSUnit:getDesc() + self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) + + local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) + + self:T3( IsGroundResult ) + return IsGroundResult + end + + return nil +end + +--- Returns if the unit is a friendly unit. +-- @param #UNIT self +-- @return #boolean IsFriendly evaluation result. +function UNIT:IsFriendly( FriendlyCoalition ) + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitCoalition = DCSUnit:getCoalition() + self:T3( { UnitCoalition, FriendlyCoalition } ) + + local IsFriendlyResult = ( UnitCoalition == FriendlyCoalition ) + + self:E( IsFriendlyResult ) + return IsFriendlyResult + end + + return nil +end + +--- Returns if the unit is of a ship category. +-- If the unit is a ship, this method will return true, otherwise false. +-- @param #UNIT self +-- @return #boolean Ship category evaluation result. +function UNIT:IsShip() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitDescriptor = DCSUnit:getDesc() + self:T3( { UnitDescriptor.category, Unit.Category.SHIP } ) + + local IsShipResult = ( UnitDescriptor.category == Unit.Category.SHIP ) + + self:T3( IsShipResult ) + return IsShipResult + end + + return nil +end + +--- Returns true if the UNIT is in the air. +-- @param Wrapper.Positionable#UNIT self +-- @return #boolean true if in the air. +-- @return #nil The UNIT is not existing or alive. +function UNIT:InAir() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitInAir = DCSUnit:inAir() + self:T3( UnitInAir ) + return UnitInAir + end + + return nil +end + +do -- Event Handling + + --- Subscribe to a DCS Event. + -- @param #UNIT self + -- @param Core.Event#EVENTS Event + -- @param #function EventFunction (optional) The function to be called when the event occurs for the unit. + -- @return #UNIT + function UNIT:HandleEvent( Event, EventFunction ) + + self:EventDispatcher():OnEventForUnit( self:GetName(), EventFunction, self, Event ) + + return self + end + + --- UnSubscribe to a DCS event. + -- @param #UNIT self + -- @param Core.Event#EVENTS Event + -- @return #UNIT + function UNIT:UnHandleEvent( Event ) + + self:EventDispatcher():RemoveForUnit( self:GetName(), self, Event ) + + return self + end + +end--- This module contains the CLIENT class. +-- +-- 1) @{Client#CLIENT} class, extends @{Unit#UNIT} +-- =============================================== +-- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. +-- Note that clients are NOT the same as Units, they are NOT necessarily alive. +-- The @{Client#CLIENT} class is a wrapper class to handle the DCS Unit objects that have the skillset defined as __Client__ or __Player__: +-- +-- * Wraps the DCS Unit objects with skill level set to Player or Client. +-- * Support all DCS Unit APIs. +-- * Enhance with Unit specific APIs not in the DCS Group API set. +-- * When player joins Unit, execute alive init logic. +-- * Handles messages to players. +-- * Manage the "state" of the DCS Unit. +-- +-- Clients are being used by the @{MISSION} class to follow players and register their successes. +-- +-- 1.1) CLIENT reference methods +-- ----------------------------- +-- For each DCS Unit having skill level Player or Client, a CLIENT wrapper object (instance) will be created within the _@{DATABASE} object. +-- This is done at the beginning of the mission (when the mission starts). +-- +-- The CLIENT class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference +-- using the DCS Unit or the DCS UnitName. +-- +-- Another thing to know is that CLIENT objects do not "contain" the DCS Unit object. +-- The CLIENT methods will reference the DCS Unit object by name when it is needed during API execution. +-- If the DCS Unit object does not exist or is nil, the CLIENT methods will return nil and log an exception in the DCS.log file. +-- +-- The CLIENT class provides the following functions to retrieve quickly the relevant CLIENT instance: +-- +-- * @{#CLIENT.Find}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit object. +-- * @{#CLIENT.FindByName}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit name. +-- +-- IMPORTANT: ONE SHOULD NEVER SANATIZE these CLIENT OBJECT REFERENCES! (make the CLIENT object references nil). +-- +-- @module Client + +--- The CLIENT class +-- @type CLIENT +-- @extends Wrapper.Unit#UNIT +CLIENT = { + ONBOARDSIDE = { + NONE = 0, + LEFT = 1, + RIGHT = 2, + BACK = 3, + FRONT = 4 + }, + ClassName = "CLIENT", + ClientName = nil, + ClientAlive = false, + ClientTransport = false, + ClientBriefingShown = false, + _Menus = {}, + _Tasks = {}, + Messages = { + } +} + + +--- Finds a CLIENT from the _DATABASE using the relevant DCS Unit. +-- @param #CLIENT self +-- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. +-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. +-- @return #CLIENT +-- @usage +-- -- Create new Clients. +-- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) +-- Mission:AddGoal( DeploySA6TroopsGoal ) +-- +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) +function CLIENT:Find( DCSUnit, Error ) + local ClientName = DCSUnit:getName() + local ClientFound = _DATABASE:FindClient( ClientName ) + + if ClientFound then + ClientFound:F( ClientName ) + return ClientFound + end + + if not Error then + error( "CLIENT not found for: " .. ClientName ) + end +end + + +--- Finds a CLIENT from the _DATABASE using the relevant Client Unit Name. +-- As an optional parameter, a briefing text can be given also. +-- @param #CLIENT self +-- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. +-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. +-- @param #boolean Error A flag that indicates whether an error should be raised if the CLIENT cannot be found. By default an error will be raised. +-- @return #CLIENT +-- @usage +-- -- Create new Clients. +-- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) +-- Mission:AddGoal( DeploySA6TroopsGoal ) +-- +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) +-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) +function CLIENT:FindByName( ClientName, ClientBriefing, Error ) + local ClientFound = _DATABASE:FindClient( ClientName ) + + if ClientFound then + ClientFound:F( { ClientName, ClientBriefing } ) + ClientFound:AddBriefing( ClientBriefing ) + ClientFound.MessageSwitch = true + + return ClientFound + end + + if not Error then + error( "CLIENT not found for: " .. ClientName ) + end +end + +function CLIENT:Register( ClientName ) + local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) + + self:F( ClientName ) + self.ClientName = ClientName + self.MessageSwitch = true + self.ClientAlive2 = false + + --self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 ) + self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5 ) + + self:E( self ) + return self +end + + +--- Transport defines that the Client is a Transport. Transports show cargo. +-- @param #CLIENT self +-- @return #CLIENT +function CLIENT:Transport() + self:F() + + self.ClientTransport = true + return self +end + +--- AddBriefing adds a briefing to a CLIENT when a player joins a mission. +-- @param #CLIENT self +-- @param #string ClientBriefing is the text defining the Mission briefing. +-- @return #CLIENT self +function CLIENT:AddBriefing( ClientBriefing ) + self:F( ClientBriefing ) + self.ClientBriefing = ClientBriefing + self.ClientBriefingShown = false + + return self +end + +--- Show the briefing of a CLIENT. +-- @param #CLIENT self +-- @return #CLIENT self +function CLIENT:ShowBriefing() + self:F( { self.ClientName, self.ClientBriefingShown } ) + + if not self.ClientBriefingShown then + self.ClientBriefingShown = true + local Briefing = "" + if self.ClientBriefing then + Briefing = Briefing .. self.ClientBriefing + end + Briefing = Briefing .. " Press [LEFT ALT]+[B] to view the complete mission briefing." + self:Message( Briefing, 60, "Briefing" ) + end + + return self +end + +--- Show the mission briefing of a MISSION to the CLIENT. +-- @param #CLIENT self +-- @param #string MissionBriefing +-- @return #CLIENT self +function CLIENT:ShowMissionBriefing( MissionBriefing ) + self:F( { self.ClientName } ) + + if MissionBriefing then + self:Message( MissionBriefing, 60, "Mission Briefing" ) + end + + return self +end + + + +--- Resets a CLIENT. +-- @param #CLIENT self +-- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. +function CLIENT:Reset( ClientName ) + self:F() + self._Menus = {} +end + +-- Is Functions + +--- Checks if the CLIENT is a multi-seated UNIT. +-- @param #CLIENT self +-- @return #boolean true if multi-seated. +function CLIENT:IsMultiSeated() + self:F( self.ClientName ) + + local ClientMultiSeatedTypes = { + ["Mi-8MT"] = "Mi-8MT", + ["UH-1H"] = "UH-1H", + ["P-51B"] = "P-51B" + } + + if self:IsAlive() then + local ClientTypeName = self:GetClientGroupUnit():GetTypeName() + if ClientMultiSeatedTypes[ClientTypeName] then + return true + end + end + + return false +end + +--- Checks for a client alive event and calls a function on a continuous basis. +-- @param #CLIENT self +-- @param #function CallBackFunction Create a function that will be called when a player joins the slot. +-- @return #CLIENT +function CLIENT:Alive( CallBackFunction, ... ) + self:F() + + self.ClientCallBack = CallBackFunction + self.ClientParameters = arg + + return self +end + +--- @param #CLIENT self +function CLIENT:_AliveCheckScheduler( SchedulerName ) + self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } ) + + if self:IsAlive() then + if self.ClientAlive2 == false then + self:ShowBriefing() + if self.ClientCallBack then + self:T("Calling Callback function") + self.ClientCallBack( self, unpack( self.ClientParameters ) ) + end + self.ClientAlive2 = true + end + else + if self.ClientAlive2 == true then + self.ClientAlive2 = false + end + end + + return true +end + +--- Return the DCSGroup of a Client. +-- This function is modified to deal with a couple of bugs in DCS 1.5.3 +-- @param #CLIENT self +-- @return Dcs.DCSWrapper.Group#Group +function CLIENT:GetDCSGroup() + self:F3() + +-- local ClientData = Group.getByName( self.ClientName ) +-- if ClientData and ClientData:isExist() then +-- self:T( self.ClientName .. " : group found!" ) +-- return ClientData +-- else +-- return nil +-- end + + local ClientUnit = Unit.getByName( self.ClientName ) + + local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } + for CoalitionId, CoalitionData in pairs( CoalitionsData ) do + self:T3( { "CoalitionData:", CoalitionData } ) + for UnitId, UnitData in pairs( CoalitionData ) do + self:T3( { "UnitData:", UnitData } ) + if UnitData and UnitData:isExist() then + + --self:E(self.ClientName) + if ClientUnit then + local ClientGroup = ClientUnit:getGroup() + if ClientGroup then + self:T3( "ClientGroup = " .. self.ClientName ) + if ClientGroup:isExist() and UnitData:getGroup():isExist() then + if ClientGroup:getID() == UnitData:getGroup():getID() then + self:T3( "Normal logic" ) + self:T3( self.ClientName .. " : group found!" ) + self.ClientGroupID = ClientGroup:getID() + self.ClientGroupName = ClientGroup:getName() + return ClientGroup + end + else + -- Now we need to resolve the bugs in DCS 1.5 ... + -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) + self:T3( "Bug 1.5 logic" ) + local ClientGroupTemplate = _DATABASE.Templates.Units[self.ClientName].GroupTemplate + self.ClientGroupID = ClientGroupTemplate.groupId + self.ClientGroupName = _DATABASE.Templates.Units[self.ClientName].GroupName + self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) + return ClientGroup + end + -- else + -- error( "Client " .. self.ClientName .. " not found!" ) + end + else + --self:E( { "Client not found!", self.ClientName } ) + end + end + end + end + + -- For non player clients + if ClientUnit then + local ClientGroup = ClientUnit:getGroup() + if ClientGroup then + self:T3( "ClientGroup = " .. self.ClientName ) + if ClientGroup:isExist() then + self:T3( "Normal logic" ) + self:T3( self.ClientName .. " : group found!" ) + return ClientGroup + end + end + end + + self.ClientGroupID = nil + self.ClientGroupUnit = nil + + return nil +end + + +-- TODO: Check Dcs.DCSTypes#Group.ID +--- Get the group ID of the client. +-- @param #CLIENT self +-- @return Dcs.DCSTypes#Group.ID +function CLIENT:GetClientGroupID() + + local ClientGroup = self:GetDCSGroup() + + --self:E( self.ClientGroupID ) -- Determined in GetDCSGroup() + return self.ClientGroupID +end + + +--- Get the name of the group of the client. +-- @param #CLIENT self +-- @return #string +function CLIENT:GetClientGroupName() + + local ClientGroup = self:GetDCSGroup() + + self:T( self.ClientGroupName ) -- Determined in GetDCSGroup() + return self.ClientGroupName +end + +--- Returns the UNIT of the CLIENT. +-- @param #CLIENT self +-- @return Wrapper.Unit#UNIT +function CLIENT:GetClientGroupUnit() + self:F2() + + local ClientDCSUnit = Unit.getByName( self.ClientName ) + + self:T( self.ClientDCSUnit ) + if ClientDCSUnit and ClientDCSUnit:isExist() then + local ClientUnit = _DATABASE:FindUnit( self.ClientName ) + self:T2( ClientUnit ) + return ClientUnit + end +end + +--- Returns the DCSUnit of the CLIENT. +-- @param #CLIENT self +-- @return Dcs.DCSTypes#Unit +function CLIENT:GetClientGroupDCSUnit() + self:F2() + + local ClientDCSUnit = Unit.getByName( self.ClientName ) + + if ClientDCSUnit and ClientDCSUnit:isExist() then + self:T2( ClientDCSUnit ) + return ClientDCSUnit + end +end + + +--- Evaluates if the CLIENT is a transport. +-- @param #CLIENT self +-- @return #boolean true is a transport. +function CLIENT:IsTransport() + self:F() + return self.ClientTransport +end + +--- Shows the @{AI_Cargo#CARGO} contained within the CLIENT to the player as a message. +-- The @{AI_Cargo#CARGO} is shown using the @{Message#MESSAGE} distribution system. +-- @param #CLIENT self +function CLIENT:ShowCargo() + self:F() + + local CargoMsg = "" + + for CargoName, Cargo in pairs( CARGOS ) do + if self == Cargo:IsLoadedInClient() then + CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n" + end + end + + if CargoMsg == "" then + CargoMsg = "empty" + end + + self:Message( CargoMsg, 15, "Co-Pilot: Cargo Status", 30 ) + +end + +-- TODO (1) I urgently need to revise this. +--- A local function called by the DCS World Menu system to switch off messages. +function CLIENT.SwitchMessages( PrmTable ) + PrmTable[1].MessageSwitch = PrmTable[2] +end + +--- The main message driver for the CLIENT. +-- This function displays various messages to the Player logged into the CLIENT through the DCS World Messaging system. +-- @param #CLIENT self +-- @param #string Message is the text describing the message. +-- @param #number MessageDuration is the duration in seconds that the Message should be displayed. +-- @param #string MessageCategory is the category of the message (the title). +-- @param #number MessageInterval is the interval in seconds between the display of the @{Message#MESSAGE} when the CLIENT is in the air. +-- @param #string MessageID is the identifier of the message when displayed with intervals. +function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInterval, MessageID ) + self:F( { Message, MessageDuration, MessageCategory, MessageInterval } ) + + if self.MessageSwitch == true then + if MessageCategory == nil then + MessageCategory = "Messages" + end + if MessageID ~= nil then + if self.Messages[MessageID] == nil then + self.Messages[MessageID] = {} + self.Messages[MessageID].MessageId = MessageID + self.Messages[MessageID].MessageTime = timer.getTime() + self.Messages[MessageID].MessageDuration = MessageDuration + if MessageInterval == nil then + self.Messages[MessageID].MessageInterval = 600 + else + self.Messages[MessageID].MessageInterval = MessageInterval + end + MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) + else + if self:GetClientGroupDCSUnit() and not self:GetClientGroupDCSUnit():inAir() then + if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + 10 then + MESSAGE:New( Message, MessageDuration , MessageCategory):ToClient( self ) + self.Messages[MessageID].MessageTime = timer.getTime() + end + else + if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + self.Messages[MessageID].MessageInterval then + MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) + self.Messages[MessageID].MessageTime = timer.getTime() + end + end + end + else + MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) + end + end +end +--- This module contains the STATIC class. +-- +-- 1) @{Static#STATIC} class, extends @{Positionable#POSITIONABLE} +-- =============================================================== +-- Statics are **Static Units** defined within the Mission Editor. +-- Note that Statics are almost the same as Units, but they don't have a controller. +-- The @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: +-- +-- * Wraps the DCS Static objects. +-- * Support all DCS Static APIs. +-- * Enhance with Static specific APIs not in the DCS API set. +-- +-- 1.1) STATIC reference methods +-- ----------------------------- +-- For each DCS Static will have a STATIC wrapper object (instance) within the _@{DATABASE} object. +-- This is done at the beginning of the mission (when the mission starts). +-- +-- The STATIC class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference +-- using the Static Name. +-- +-- Another thing to know is that STATIC objects do not "contain" the DCS Static object. +-- The STATIc methods will reference the DCS Static object by name when it is needed during API execution. +-- If the DCS Static object does not exist or is nil, the STATIC methods will return nil and log an exception in the DCS.log file. +-- +-- The STATIc class provides the following functions to retrieve quickly the relevant STATIC instance: +-- +-- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name. +-- +-- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil). +-- +-- @module Static +-- @author FlightControl + + + + + + +--- The STATIC class +-- @type STATIC +-- @extends Wrapper.Positionable#POSITIONABLE +STATIC = { + ClassName = "STATIC", +} + + +--- Finds a STATIC from the _DATABASE using the relevant Static Name. +-- As an optional parameter, a briefing text can be given also. +-- @param #STATIC self +-- @param #string StaticName Name of the DCS **Static** as defined within the Mission Editor. +-- @param #boolean RaiseError Raise an error if not found. +-- @return #STATIC +function STATIC:FindByName( StaticName, RaiseError ) + local StaticFound = _DATABASE:FindStatic( StaticName ) + + self.StaticName = StaticName + + if StaticFound then + StaticFound:F3( { StaticName } ) + + return StaticFound + end + + if RaiseError == nil or RaiseError == true then + error( "STATIC not found for: " .. StaticName ) + end + + return nil +end + +function STATIC:Register( StaticName ) + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) + self.StaticName = StaticName + return self +end + + +function STATIC:GetDCSObject() + local DCSStatic = StaticObject.getByName( self.StaticName ) + + if DCSStatic then + return DCSStatic + end + + return nil +end + +function STATIC:GetThreatLevel() + + return 1, "Static" +end--- This module contains the AIRBASE classes. +-- +-- === +-- +-- 1) @{Airbase#AIRBASE} class, extends @{Positionable#POSITIONABLE} +-- ================================================================= +-- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: +-- +-- * Support all DCS Airbase APIs. +-- * Enhance with Airbase specific APIs not in the DCS Airbase API set. +-- +-- +-- 1.1) AIRBASE reference methods +-- ------------------------------ +-- For each DCS Airbase object alive within a running mission, a AIRBASE wrapper object (instance) will be created within the _@{DATABASE} object. +-- This is done at the beginning of the mission (when the mission starts). +-- +-- The AIRBASE class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference +-- using the DCS Airbase or the DCS AirbaseName. +-- +-- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object. +-- The AIRBASE methods will reference the DCS Airbase object by name when it is needed during API execution. +-- If the DCS Airbase object does not exist or is nil, the AIRBASE methods will return nil and log an exception in the DCS.log file. +-- +-- The AIRBASE class provides the following functions to retrieve quickly the relevant AIRBASE instance: +-- +-- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object. +-- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name. +-- +-- IMPORTANT: ONE SHOULD NEVER SANATIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil). +-- +-- 1.2) DCS AIRBASE APIs +-- --------------------- +-- The DCS Airbase APIs are used extensively within MOOSE. The AIRBASE class has for each DCS Airbase API a corresponding method. +-- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call, +-- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{DCSWrapper.Airbase#Airbase.getName}() +-- is implemented in the AIRBASE class as @{#AIRBASE.GetName}(). +-- +-- More functions will be added +-- ---------------------------- +-- During the MOOSE development, more functions will be added. +-- +-- @module Airbase +-- @author FlightControl + + + + + +--- The AIRBASE class +-- @type AIRBASE +-- @extends Wrapper.Positionable#POSITIONABLE +AIRBASE = { + ClassName="AIRBASE", + CategoryName = { + [Airbase.Category.AIRDROME] = "Airdrome", + [Airbase.Category.HELIPAD] = "Helipad", + [Airbase.Category.SHIP] = "Ship", + }, + } + +-- Registration. + +--- Create a new AIRBASE from DCSAirbase. +-- @param #AIRBASE self +-- @param #string AirbaseName The name of the airbase. +-- @return Wrapper.Airbase#AIRBASE +function AIRBASE:Register( AirbaseName ) + + local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) + self.AirbaseName = AirbaseName + return self +end + +-- Reference methods. + +--- Finds a AIRBASE from the _DATABASE using a DCSAirbase object. +-- @param #AIRBASE self +-- @param Dcs.DCSWrapper.Airbase#Airbase DCSAirbase An existing DCS Airbase object reference. +-- @return Wrapper.Airbase#AIRBASE self +function AIRBASE:Find( DCSAirbase ) + + local AirbaseName = DCSAirbase:getName() + local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) + return AirbaseFound +end + +--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase. +-- @param #AIRBASE self +-- @param #string AirbaseName The Airbase Name. +-- @return Wrapper.Airbase#AIRBASE self +function AIRBASE:FindByName( AirbaseName ) + + local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) + return AirbaseFound +end + +function AIRBASE:GetDCSObject() + local DCSAirbase = Airbase.getByName( self.AirbaseName ) + + if DCSAirbase then + return DCSAirbase + end + + return nil +end + + + +--- This module contains the SCENERY class. +-- +-- 1) @{Scenery#SCENERY} class, extends @{Positionable#POSITIONABLE} +-- =============================================================== +-- Scenery objects are defined on the map. +-- The @{Scenery#SCENERY} class is a wrapper class to handle the DCS Scenery objects: +-- +-- * Wraps the DCS Scenery objects. +-- * Support all DCS Scenery APIs. +-- * Enhance with Scenery specific APIs not in the DCS API set. +-- +-- @module Scenery +-- @author FlightControl + + + +--- The SCENERY class +-- @type SCENERY +-- @extends Wrapper.Positionable#POSITIONABLE +SCENERY = { + ClassName = "SCENERY", +} + + +function SCENERY:Register( SceneryName, SceneryObject ) + local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) ) + self.SceneryName = SceneryName + self.SceneryObject = SceneryObject + return self +end + +function SCENERY:GetDCSObject() + return self.SceneryObject +end + +function SCENERY:GetThreatLevel() + + return 0, "Scenery" +end +--- Single-Player:**Yes** / Multi-Player:**Yes** / Core:**Yes** -- **Administer the scoring of player achievements, +-- and create a CSV file logging the scoring events for use at team or squadron websites.** +-- +-- ![Banner Image](..\Presentations\SCORING\Dia1.JPG) +-- +-- === +-- +-- The @{#SCORING} class administers the scoring of player achievements, +-- and creates a CSV file logging the scoring events and results for use at team or squadron websites. +-- +-- SCORING automatically calculates the threat level of the objects hit and destroyed by players, +-- which can be @{Unit}, @{Static) and @{Scenery} objects. +-- +-- Positive score points are granted when enemy or neutral targets are destroyed. +-- Negative score points or penalties are given when a friendly target is hit or destroyed. +-- This brings a lot of dynamism in the scoring, where players need to take care to inflict damage on the right target. +-- By default, penalties weight heavier in the scoring, to ensure that players don't commit fratricide. +-- The total score of the player is calculated by **adding the scores minus the penalties**. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia4.JPG) +-- +-- The score value is calculated based on the **threat level of the player** and the **threat level of the target**. +-- A calculated score takes the threat level of the target divided by a balanced threat level of the player unit. +-- As such, if the threat level of the target is high, and the player threat level is low, a higher score will be given than +-- if the threat level of the player would be high too. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia5.JPG) +-- +-- When multiple players hit the same target, and finally succeed in destroying the target, then each player who contributed to the target +-- destruction, will receive a score. This is important for targets that require significant damage before it can be destroyed, like +-- ships or heavy planes. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia13.JPG) +-- +-- Optionally, the score values can be **scaled** by a **scale**. Specific scales can be set for positive cores or negative penalties. +-- The default range of the scores granted is a value between 0 and 10. The default range of penalties given is a value between 0 and 30. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia7.JPG) +-- +-- **Additional scores** can be granted to **specific objects**, when the player(s) destroy these objects. +-- +-- ![Banner Image](..\Presentations\SCORING\Dia9.JPG) +-- +-- Various @{Zone}s can be defined for which scores are also granted when objects in that @{Zone} are destroyed. +-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed. +-- +-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**. +-- These CSV files can be used to: +-- +-- * Upload scoring to a database or a BI tool to publish the scoring results to the player community. +-- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results. +-- * Share scoring amoung players after the mission to discuss mission results. +-- +-- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit. +-- Use the radio menu F10 to consult the scores while running the mission. +-- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission. +-- +-- # 1) @{Scoring#SCORING} class, extends @{Base#BASE} +-- +-- ## 1.1) Set the destroy score or penalty scale +-- +-- Score scales can be set for scores granted when enemies or friendlies are destroyed. +-- Use the method @{#SCORING.SetScaleDestroyScore}() to set the scale of enemy destroys (positive destroys). +-- Use the method @{#SCORING.SetScaleDestroyPenalty}() to set the scale of friendly destroys (negative destroys). +-- +-- local Scoring = SCORING:New( "Scoring File" ) +-- Scoring:SetScaleDestroyScore( 10 ) +-- Scoring:SetScaleDestroyPenalty( 40 ) +-- +-- The above sets the scale for valid scores to 10. So scores will be given in a scale from 0 to 10. +-- The penalties will be given in a scale from 0 to 40. +-- +-- ## 1.2) Define special targets that will give extra scores. +-- +-- Special targets can be set that will give extra scores to the players when these are destroyed. +-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Unit}s. +-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s. +-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Group}s. +-- +-- local Scoring = SCORING:New( "Scoring File" ) +-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 ) +-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 ) +-- +-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed. +-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over. +-- For example, this can be done as follows: +-- +-- Scoring:RemoveUnitScore( UNIT:FindByName( "Unit #001" ) ) +-- +-- ## 1.3) Define destruction zones that will give extra scores. +-- +-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points. +-- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring. +-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring. +-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Zone#ZONE_UNIT}, +-- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points. +-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone}, +-- just large enough around that building. +-- +-- ## 1.4) Add extra Goal scores upon an event or a condition. +-- +-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens. +-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission. +-- +-- ## 1.5) Configure fratricide level. +-- +-- When a player commits too much damage to friendlies, his penalty score will reach a certain level. +-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked. +-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. +-- +-- ## 1.6) Penalty score when a player changes the coalition. +-- +-- When a player changes the coalition, he can receive a penalty score. +-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition. +-- By default, the penalty for changing coalition is the default penalty scale. +-- +-- ## 1.8) Define output CSV files. +-- +-- The CSV file is given the name of the string given in the @{#SCORING.New}{} constructor, followed by the .csv extension. +-- The file is incrementally saved in the **\\Saved Games\\DCS\\Logs** folder, and has a time stamp indicating each mission run. +-- See the following example: +-- +-- local ScoringFirstMission = SCORING:New( "FirstMission" ) +-- local ScoringSecondMission = SCORING:New( "SecondMission" ) +-- +-- The above documents that 2 Scoring objects are created, ScoringFirstMission and ScoringSecondMission. +-- +-- ## 1.9) Configure messages. +-- +-- When players hit or destroy targets, messages are sent. +-- Various methods exist to configure: +-- +-- * Which messages are sent upon the event. +-- * Which audience receives the message. +-- +-- ### 1.9.1) Configure the messages sent upon the event. +-- +-- Use the following methods to configure when to send messages. By default, all messages are sent. +-- +-- * @{#SCORING.SetMessagesHit}(): Configure to send messages after a target has been hit. +-- * @{#SCORING.SetMessagesDestroy}(): Configure to send messages after a target has been destroyed. +-- * @{#SCORING.SetMessagesAddon}(): Configure to send messages for additional score, after a target has been destroyed. +-- * @{#SCORING.SetMessagesZone}(): Configure to send messages for additional score, after a target has been destroyed within a given zone. +-- +-- ### 1.9.2) Configure the audience of the messages. +-- +-- Use the following methods to configure the audience of the messages. By default, the messages are sent to all players in the mission. +-- +-- * @{#SCORING.SetMessagesToAll}(): Configure to send messages to all players. +-- * @{#SCORING.SetMessagesToCoalition}(): Configure to send messages to only those players within the same coalition as the player. +-- +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-02-26: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **Wingthor (TAW)**: Testing & Advice. +-- * **Dutch-Baron (TAW)**: Testing & Advice. +-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing and Advice. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module Scoring + + +--- The Scoring class +-- @type SCORING +-- @field Players A collection of the current players that have joined the game. +-- @extends Core.Base#BASE +SCORING = { + ClassName = "SCORING", + ClassID = 0, + Players = {}, +} + +local _SCORINGCoalition = + { + [1] = "Red", + [2] = "Blue", + } + +local _SCORINGCategory = + { + [Unit.Category.AIRPLANE] = "Plane", + [Unit.Category.HELICOPTER] = "Helicopter", + [Unit.Category.GROUND_UNIT] = "Vehicle", + [Unit.Category.SHIP] = "Ship", + [Unit.Category.STRUCTURE] = "Structure", + } + +--- Creates a new SCORING object to administer the scoring achieved by players. +-- @param #SCORING self +-- @param #string GameName The name of the game. This name is also logged in the CSV score file. +-- @return #SCORING self +-- @usage +-- -- Define a new scoring object for the mission Gori Valley. +-- ScoringObject = SCORING:New( "Gori Valley" ) +function SCORING:New( GameName ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) -- #SCORING + + if GameName then + self.GameName = GameName + else + error( "A game name must be given to register the scoring results" ) + end + + + -- Additional Object scores + self.ScoringObjects = {} + + -- Additional Zone scores. + self.ScoringZones = {} + + -- Configure Messages + self:SetMessagesToAll() + self:SetMessagesHit( true ) + self:SetMessagesDestroy( true ) + self:SetMessagesScore( true ) + self:SetMessagesZone( true ) + + -- Scales + self:SetScaleDestroyScore( 10 ) + self:SetScaleDestroyPenalty( 30 ) + + -- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked). + self:SetFratricide( self.ScaleDestroyPenalty * 3 ) + + -- Default penalty when a player changes coalition. + self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty ) + + -- Event handlers + self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Hit, self._EventOnHit ) + self:HandleEvent( EVENTS.PlayerEnterUnit ) + self:HandleEvent( EVENTS.PlayerLeaveUnit ) + + -- Create the CSV file. + self:OpenCSV( GameName ) + + return self + +end + +--- Set the scale for scoring valid destroys (enemy destroys). +-- A default calculated score is a value between 1 and 10. +-- The scale magnifies the scores given to the players. +-- @param #SCORING self +-- @param #number Scale The scale of the score given. +function SCORING:SetScaleDestroyScore( Scale ) + + self.ScaleDestroyScore = Scale + + return self +end + +--- Set the scale for scoring penalty destroys (friendly destroys). +-- A default calculated penalty is a value between 1 and 10. +-- The scale magnifies the scores given to the players. +-- @param #SCORING self +-- @param #number Scale The scale of the score given. +-- @return #SCORING +function SCORING:SetScaleDestroyPenalty( Scale ) + + self.ScaleDestroyPenalty = Scale + + return self +end + +--- Add a @{Unit} for additional scoring when the @{Unit} is destroyed. +-- Note that if there was already a @{Unit} declared within the scoring with the same name, +-- then the old @{Unit} will be replaced with the new @{Unit}. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddUnitScore( ScoreUnit, Score ) + + local UnitName = ScoreUnit:GetName() + + self.ScoringObjects[UnitName] = Score + + return self +end + +--- Removes a @{Unit} for additional scoring when the @{Unit} is destroyed. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given. +-- @return #SCORING +function SCORING:RemoveUnitScore( ScoreUnit ) + + local UnitName = ScoreUnit:GetName() + + self.ScoringObjects[UnitName] = nil + + return self +end + +--- Add a @{Static} for additional scoring when the @{Static} is destroyed. +-- Note that if there was already a @{Static} declared within the scoring with the same name, +-- then the old @{Static} will be replaced with the new @{Static}. +-- @param #SCORING self +-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddStaticScore( ScoreStatic, Score ) + + local StaticName = ScoreStatic:GetName() + + self.ScoringObjects[StaticName] = Score + + return self +end + +--- Removes a @{Static} for additional scoring when the @{Static} is destroyed. +-- @param #SCORING self +-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given. +-- @return #SCORING +function SCORING:RemoveStaticScore( ScoreStatic ) + + local StaticName = ScoreStatic:GetName() + + self.ScoringObjects[StaticName] = nil + + return self +end + + +--- Specify a special additional score for a @{Group}. +-- @param #SCORING self +-- @param Wrapper.Group#GROUP ScoreGroup The @{Group} for which each @{Unit} a Score is given. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddScoreGroup( ScoreGroup, Score ) + + local ScoreUnits = ScoreGroup:GetUnits() + + for ScoreUnitID, ScoreUnit in pairs( ScoreUnits ) do + local UnitName = ScoreUnit:GetName() + self.ScoringObjects[UnitName] = Score + end + + return self +end + +--- Add a @{Zone} to define additional scoring when any object is destroyed in that zone. +-- Note that if a @{Zone} with the same name is already within the scoring added, the @{Zone} (type) and Score will be replaced! +-- This allows for a dynamic destruction zone evolution within your mission. +-- @param #SCORING self +-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters. +-- Note that a zone can be a polygon or a moving zone. +-- @param #number Score The Score value. +-- @return #SCORING +function SCORING:AddZoneScore( ScoreZone, Score ) + + local ZoneName = ScoreZone:GetName() + + self.ScoringZones[ZoneName] = {} + self.ScoringZones[ZoneName].ScoreZone = ScoreZone + self.ScoringZones[ZoneName].Score = Score + + return self +end + +--- Remove a @{Zone} for additional scoring. +-- The scoring will search if any @{Zone} is added with the given name, and will remove that zone from the scoring. +-- This allows for a dynamic destruction zone evolution within your mission. +-- @param #SCORING self +-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters. +-- Note that a zone can be a polygon or a moving zone. +-- @return #SCORING +function SCORING:RemoveZoneScore( ScoreZone ) + + local ZoneName = ScoreZone:GetName() + + self.ScoringZones[ZoneName] = nil + + return self +end + + +--- Configure to send messages after a target has been hit. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesHit( OnOff ) + + self.MessagesHit = OnOff + return self +end + +--- If to send messages after a target has been hit. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesHit() + + return self.MessagesHit +end + +--- Configure to send messages after a target has been destroyed. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesDestroy( OnOff ) + + self.MessagesDestroy = OnOff + return self +end + +--- If to send messages after a target has been destroyed. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesDestroy() + + return self.MessagesDestroy +end + +--- Configure to send messages after a target has been destroyed and receives additional scores. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesScore( OnOff ) + + self.MessagesScore = OnOff + return self +end + +--- If to send messages after a target has been destroyed and receives additional scores. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesScore() + + return self.MessagesScore +end + +--- Configure to send messages after a target has been hit in a zone, and additional score is received. +-- @param #SCORING self +-- @param #boolean OnOff If true is given, the messages are sent. +-- @return #SCORING +function SCORING:SetMessagesZone( OnOff ) + + self.MessagesZone = OnOff + return self +end + +--- If to send messages after a target has been hit in a zone, and additional score is received. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesZone() + + return self.MessagesZone +end + +--- Configure to send messages to all players. +-- @param #SCORING self +-- @return #SCORING +function SCORING:SetMessagesToAll() + + self.MessagesAudience = 1 + return self +end + +--- If to send messages to all players. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesToAll() + + return self.MessagesAudience == 1 +end + +--- Configure to send messages to only those players within the same coalition as the player. +-- @param #SCORING self +-- @return #SCORING +function SCORING:SetMessagesToCoalition() + + self.MessagesAudience = 2 + return self +end + +--- If to send messages to only those players within the same coalition as the player. +-- @param #SCORING self +-- @return #boolean +function SCORING:IfMessagesToCoalition() + + return self.MessagesAudience == 2 +end + + +--- When a player commits too much damage to friendlies, his penalty score will reach a certain level. +-- Use this method to define the level when a player gets kicked. +-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score. +-- @param #SCORING self +-- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked. +-- @return #SCORING +function SCORING:SetFratricide( Fratricide ) + + self.Fratricide = Fratricide + return self +end + + +--- When a player changes the coalition, he can receive a penalty score. +-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition. +-- By default, the penalty for changing coalition is the default penalty scale. +-- @param #SCORING self +-- @param #number CoalitionChangePenalty The amount of penalty that is given. +-- @return #SCORING +function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty ) + + self.CoalitionChangePenalty = CoalitionChangePenalty + return self +end + + +--- Add a new player entering a Unit. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT UnitData +function SCORING:_AddPlayerFromUnit( UnitData ) + self:F( UnitData ) + + if UnitData:IsAlive() then + local UnitName = UnitData:GetName() + local PlayerName = UnitData:GetPlayerName() + local UnitDesc = UnitData:GetDesc() + local UnitCategory = UnitDesc.category + local UnitCoalition = UnitData:GetCoalition() + local UnitTypeName = UnitData:GetTypeName() + local UnitThreatLevel, UnitThreatType = UnitData:GetThreatLevel() + + self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } ) + + if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ... + self.Players[PlayerName] = {} + self.Players[PlayerName].Hit = {} + self.Players[PlayerName].Destroy = {} + self.Players[PlayerName].Goals = {} + self.Players[PlayerName].Mission = {} + + -- for CategoryID, CategoryName in pairs( SCORINGCategory ) do + -- self.Players[PlayerName].Hit[CategoryID] = {} + -- self.Players[PlayerName].Destroy[CategoryID] = {} + -- end + self.Players[PlayerName].HitPlayers = {} + self.Players[PlayerName].Score = 0 + self.Players[PlayerName].Penalty = 0 + self.Players[PlayerName].PenaltyCoalition = 0 + self.Players[PlayerName].PenaltyWarning = 0 + end + + if not self.Players[PlayerName].UnitCoalition then + self.Players[PlayerName].UnitCoalition = UnitCoalition + else + if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then + self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50 + self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1 + MESSAGE:New( "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. + "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", + 2 + ):ToAll() + self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, + UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() ) + end + end + self.Players[PlayerName].UnitName = UnitName + self.Players[PlayerName].UnitCoalition = UnitCoalition + self.Players[PlayerName].UnitCategory = UnitCategory + self.Players[PlayerName].UnitType = UnitTypeName + self.Players[PlayerName].UNIT = UnitData + self.Players[PlayerName].ThreatLevel = UnitThreatLevel + self.Players[PlayerName].ThreatType = UnitThreatType + + if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then + if self.Players[PlayerName].PenaltyWarning < 1 then + MESSAGE:New( "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, + 30 + ):ToAll() + self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 + end + end + + if self.Players[PlayerName].Penalty > self.Fratricide then + UnitData:Destroy() + MESSAGE:New( "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", + 10 + ):ToAll() + end + + end +end + + +--- Add a goal score for a player. +-- The method takes the PlayerUnit for which the Goal score needs to be set. +-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal. +-- A free text can be given that is shown to the players. +-- The Score can be both positive and negative. +-- @param #SCORING self +-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc. +-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel). +-- @param #string Text A free text that is shown to the players. +-- @param #number Score The score can be both positive or negative ( Penalty ). +function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score ) + + local PlayerName = PlayerUnit:GetPlayerName() + + self:E( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } ) + + -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. + if PlayerName then + local PlayerData = self.Players[PlayerName] + + PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 } + PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score + PlayerData.Score = PlayerData.Score + Score + + MESSAGE:New( Text, 30 ):ToAll() + + self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() ) + end +end + + +--- Registers Scores the players completing a Mission Task. +-- @param #SCORING self +-- @param Tasking.Mission#MISSION Mission +-- @param Wrapper.Unit#UNIT PlayerUnit +-- @param #string Text +-- @param #number Score +function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) + + local PlayerName = PlayerUnit:GetPlayerName() + local MissionName = Mission:GetName() + + self:E( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } ) + + -- PlayerName can be nil, if the Unit with the player crashed or due to another reason. + if PlayerName then + local PlayerData = self.Players[PlayerName] + + if not PlayerData.Mission[MissionName] then + PlayerData.Mission[MissionName] = {} + PlayerData.Mission[MissionName].ScoreTask = 0 + PlayerData.Mission[MissionName].ScoreMission = 0 + end + + self:T( PlayerName ) + self:T( PlayerData.Mission[MissionName] ) + + PlayerData.Score = self.Players[PlayerName].Score + Score + PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score + + MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. + Score .. " task score!", + 30 ):ToAll() + + self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) + end +end + + +--- Registers Mission Scores for possible multiple players that contributed in the Mission. +-- @param #SCORING self +-- @param Tasking.Mission#MISSION Mission +-- @param Wrapper.Unit#UNIT PlayerUnit +-- @param #string Text +-- @param #number Score +function SCORING:_AddMissionScore( Mission, Text, Score ) + + local MissionName = Mission:GetName() + + self:E( { Mission, Text, Score } ) + self:E( self.Players ) + + for PlayerName, PlayerData in pairs( self.Players ) do + + self:E( PlayerData ) + if PlayerData.Mission[MissionName] then + + PlayerData.Score = PlayerData.Score + Score + PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score + + MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. + Score .. " mission score!", + 60 ):ToAll() + + self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score ) + end + end +end + + +--- Handles the OnPlayerEnterUnit event for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:OnEventPlayerEnterUnit( Event ) + if Event.IniUnit then + self:_AddPlayerFromUnit( Event.IniUnit ) + local Menu = MENU_GROUP:New( Event.IniGroup, 'Scoring' ) + local ReportGroupSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, Event.IniGroup ) + local ReportGroupDetailed = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, Event.IniGroup ) + local ReportToAllSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, Event.IniGroup ) + self:SetState( Event.IniUnit, "ScoringMenu", Menu ) + end +end + +--- Handles the OnPlayerLeaveUnit event for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:OnEventPlayerLeaveUnit( Event ) + if Event.IniUnit then + local Menu = self:GetState( Event.IniUnit, "ScoringMenu" ) -- Core.Menu#MENU_GROUP + if Menu then + -- TODO: Check if this fixes #281. + --Menu:Remove() + end + end +end + + +--- Handles the OnHit event for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:_EventOnHit( Event ) + self:F( { Event } ) + + local InitUnit = nil + local InitUNIT = nil + local InitUnitName = "" + local InitGroup = nil + local InitGroupName = "" + local InitPlayerName = nil + + local InitCoalition = nil + local InitCategory = nil + local InitType = nil + local InitUnitCoalition = nil + local InitUnitCategory = nil + local InitUnitType = nil + + local TargetUnit = nil + local TargetUNIT = nil + local TargetUnitName = "" + local TargetGroup = nil + local TargetGroupName = "" + local TargetPlayerName = nil + + local TargetCoalition = nil + local TargetCategory = nil + local TargetType = nil + local TargetUnitCoalition = nil + local TargetUnitCategory = nil + local TargetUnitType = nil + + if Event.IniDCSUnit then + + InitUnit = Event.IniDCSUnit + InitUNIT = Event.IniUnit + InitUnitName = Event.IniDCSUnitName + InitGroup = Event.IniDCSGroup + InitGroupName = Event.IniDCSGroupName + InitPlayerName = Event.IniPlayerName + + InitCoalition = Event.IniCoalition + --TODO: Workaround Client DCS Bug + --InitCategory = InitUnit:getCategory() + --InitCategory = InitUnit:getDesc().category + InitCategory = Event.IniCategory + InitType = Event.IniTypeName + + InitUnitCoalition = _SCORINGCoalition[InitCoalition] + InitUnitCategory = _SCORINGCategory[InitCategory] + InitUnitType = InitType + + self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } ) + end + + + if Event.TgtDCSUnit then + + TargetUnit = Event.TgtDCSUnit + TargetUNIT = Event.TgtUnit + TargetUnitName = Event.TgtDCSUnitName + TargetGroup = Event.TgtDCSGroup + TargetGroupName = Event.TgtDCSGroupName + TargetPlayerName = Event.TgtPlayerName + + TargetCoalition = Event.TgtCoalition + --TODO: Workaround Client DCS Bug + --TargetCategory = TargetUnit:getCategory() + --TargetCategory = TargetUnit:getDesc().category + TargetCategory = Event.TgtCategory + TargetType = Event.TgtTypeName + + TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] + TargetUnitCategory = _SCORINGCategory[TargetCategory] + TargetUnitType = TargetType + + self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } ) + end + + if InitPlayerName ~= nil then -- It is a player that is hitting something + self:_AddPlayerFromUnit( InitUNIT ) + if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway. + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + self:_AddPlayerFromUnit( TargetUNIT ) + end + + self:T( "Hitting Something" ) + + -- What is he hitting? + if TargetCategory then + + -- A target got hit, score it. + -- Player contains the score data from self.Players[InitPlayerName] + local Player = self.Players[InitPlayerName] + + -- Ensure there is a hit table per TargetCategory and TargetUnitName. + Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {} + Player.Hit[TargetCategory][TargetUnitName] = Player.Hit[TargetCategory][TargetUnitName] or {} + + -- PlayerHit contains the score counters and data per unit that was hit. + local PlayerHit = Player.Hit[TargetCategory][TargetUnitName] + + PlayerHit.Score = PlayerHit.Score or 0 + PlayerHit.Penalty = PlayerHit.Penalty or 0 + PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0 + PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0 + PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT + PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() + + -- Only grant hit scores if there was more than one second between the last hit. + if timer.getTime() - PlayerHit.TimeStamp > 1 then + PlayerHit.TimeStamp = timer.getTime() + + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + + -- Ensure there is a Player to Player hit reference table. + Player.HitPlayers[TargetPlayerName] = true + end + + local Score = 0 + + if InitCoalition then -- A coalition object was hit. + if InitCoalition == TargetCoalition then + Player.Penalty = Player.Penalty + 10 + PlayerHit.Penalty = PlayerHit.Penalty + 10 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 + + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit a friendly target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + else + Player.Score = Player.Score + 1 + PlayerHit.Score = PlayerHit.Score + 1 + PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit an enemy target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + end + self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + end + else -- A scenery object was hit. + MESSAGE + :New( "Player '" .. InitPlayerName .. "' hit a scenery object.", + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) + end + end + end + end + elseif InitPlayerName == nil then -- It is an AI hitting a player??? + + end + + -- It is a weapon initiated by a player, that is hitting something + -- This seems to occur only with scenery and static objects. + if Event.WeaponPlayerName ~= nil then + self:_AddPlayerFromUnit( Event.WeaponUNIT ) + if self.Players[Event.WeaponPlayerName] then -- This should normally not happen, but i'll test it anyway. + if TargetPlayerName ~= nil then -- It is a player hitting another player ... + self:_AddPlayerFromUnit( TargetUNIT ) + end + + self:T( "Hitting Scenery" ) + + -- What is he hitting? + if TargetCategory then + + -- A scenery or static got hit, score it. + -- Player contains the score data from self.Players[WeaponPlayerName] + local Player = self.Players[Event.WeaponPlayerName] + + -- Ensure there is a hit table per TargetCategory and TargetUnitName. + Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {} + Player.Hit[TargetCategory][TargetUnitName] = Player.Hit[TargetCategory][TargetUnitName] or {} + + -- PlayerHit contains the score counters and data per unit that was hit. + local PlayerHit = Player.Hit[TargetCategory][TargetUnitName] + + PlayerHit.Score = PlayerHit.Score or 0 + PlayerHit.Penalty = PlayerHit.Penalty or 0 + PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0 + PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0 + PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT + PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() + + -- Only grant hit scores if there was more than one second between the last hit. + if timer.getTime() - PlayerHit.TimeStamp > 1 then + PlayerHit.TimeStamp = timer.getTime() + + local Score = 0 + + if InitCoalition then -- A coalition object was hit, probably a static. + if InitCoalition == TargetCoalition then + -- TODO: Penalty according scale + Player.Penalty = Player.Penalty + 10 + PlayerHit.Penalty = PlayerHit.Penalty + 10 + PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 + + MESSAGE + :New( "Player '" .. Event.WeaponPlayerName .. "' hit a friendly target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. + "Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + else + Player.Score = Player.Score + 1 + PlayerHit.Score = PlayerHit.Score + 1 + PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 + MESSAGE + :New( "Player '" .. Event.WeaponPlayerName .. "' hit an enemy target " .. + TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. + "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + end + else -- A scenery object was hit. + MESSAGE + :New( "Player '" .. Event.WeaponPlayerName .. "' hit a scenery object.", + 2 + ) + :ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) + self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType ) + end + end + end + end + end +end + +--- Track DEAD or CRASH events for the scoring. +-- @param #SCORING self +-- @param Core.Event#EVENTDATA Event +function SCORING:_EventOnDeadOrCrash( Event ) + self:F( { Event } ) + + local TargetUnit = nil + local TargetGroup = nil + local TargetUnitName = "" + local TargetGroupName = "" + local TargetPlayerName = "" + local TargetCoalition = nil + local TargetCategory = nil + local TargetType = nil + local TargetUnitCoalition = nil + local TargetUnitCategory = nil + local TargetUnitType = nil + + if Event.IniDCSUnit then + + TargetUnit = Event.IniUnit + TargetUnitName = Event.IniDCSUnitName + TargetGroup = Event.IniDCSGroup + TargetGroupName = Event.IniDCSGroupName + TargetPlayerName = Event.IniPlayerName + + TargetCoalition = Event.IniCoalition + --TargetCategory = TargetUnit:getCategory() + --TargetCategory = TargetUnit:getDesc().category -- Workaround + TargetCategory = Event.IniCategory + TargetType = Event.IniTypeName + + TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] + TargetUnitCategory = _SCORINGCategory[TargetCategory] + TargetUnitType = TargetType + + self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) + end + + -- Player contains the score and reference data for the player. + for PlayerName, Player in pairs( self.Players ) do + if Player then -- This should normally not happen, but i'll test it anyway. + self:T( "Something got destroyed" ) + + -- Some variables + local InitUnitName = Player.UnitName + local InitUnitType = Player.UnitType + local InitCoalition = Player.UnitCoalition + local InitCategory = Player.UnitCategory + local InitUnitCoalition = _SCORINGCoalition[InitCoalition] + local InitUnitCategory = _SCORINGCategory[InitCategory] + + self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) + + local Destroyed = false + + -- What is the player destroying? + if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 then -- Was there a hit for this unit for this player before registered??? + + local TargetThreatLevel = Player.Hit[TargetCategory][TargetUnitName].ThreatLevel + local TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType + + Player.Destroy[TargetCategory] = Player.Destroy[TargetCategory] or {} + Player.Destroy[TargetCategory][TargetType] = Player.Destroy[TargetCategory][TargetType] or {} + + -- PlayerDestroy contains the destroy score data per category and target type of the player. + local TargetDestroy = Player.Destroy[TargetCategory][TargetType] + TargetDestroy.Score = TargetDestroy.Score or 0 + TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy or 0 + TargetDestroy.Penalty = TargetDestroy.Penalty or 0 + TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy or 0 + + if TargetCoalition then + if InitCoalition == TargetCoalition then + local ThreatLevelTarget = TargetThreatLevel + local ThreatTypeTarget = TargetThreatType + local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 + local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 ) + self:E( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) + + Player.Penalty = Player.Penalty + ThreatPenalty + TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty + TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1 + + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " .. + "Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed a friendly target " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " .. + "Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + end + + Destroyed = true + self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + else + + local ThreatLevelTarget = TargetThreatLevel + local ThreatTypeTarget = TargetThreatType + local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1 + local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 ) + + self:E( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } ) + + Player.Score = Player.Score + ThreatScore + TargetDestroy.Score = TargetDestroy.Score + ThreatScore + TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1 + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " .. + "Score: " .. TargetDestroy.Score .. ". Score Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + else + MESSAGE + :New( "Player '" .. PlayerName .. "' destroyed an enemy " .. + TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " .. + "Score: " .. TargetDestroy.Score .. ". Total:" .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) + end + Destroyed = true + self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + + local UnitName = TargetUnit:GetName() + local Score = self.ScoringObjects[UnitName] + if Score then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() ) + self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + Destroyed = true + end + + -- Check if there are Zones where the destruction happened. + for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do + self:E( { ScoringZone = ScoreZoneData } ) + local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE + local Score = ScoreZoneData.Score + if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + "Total: " .. Player.Score - Player.Penalty, + 15 ) + :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) + self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + Destroyed = true + end + end + + end + else + -- Check if there are Zones where the destruction happened. + for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do + self:E( { ScoringZone = ScoreZoneData } ) + local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE + local Score = ScoreZoneData.Score + if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then + Player.Score = Player.Score + Score + TargetDestroy.Score = TargetDestroy.Score + Score + MESSAGE + :New( "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." .. + "Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. + "Total: " .. Player.Score - Player.Penalty, + 15 + ) + :ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() ) + :ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() ) + Destroyed = true + self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType ) + end + end + end + + -- Delete now the hit cache if the target was destroyed. + -- Otherwise points will be granted every time a target gets killed by the players that hit that target. + -- This is only relevant for player to player destroys. + if Destroyed then + Player.Hit[TargetCategory][TargetUnitName].TimeStamp = 0 + end + end + end + end +end + + +--- Produce detailed report of player hit scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerHits( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageHits = "" + for CategoryID, CategoryName in pairs( _SCORINGCategory ) do + self:T( CategoryName ) + if PlayerData.Hit[CategoryID] then + self:T( "Hit scores exist for player " .. PlayerName ) + local Score = 0 + local ScoreHit = 0 + local Penalty = 0 + local PenaltyHit = 0 + for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do + Score = Score + UnitData.Score + ScoreHit = ScoreHit + UnitData.ScoreHit + Penalty = Penalty + UnitData.Penalty + PenaltyHit = UnitData.PenaltyHit + end + local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) + self:T( ScoreMessageHit ) + ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit + PlayerScore = PlayerScore + Score + PlayerPenalty = PlayerPenalty + Penalty + else + --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) + end + end + if ScoreMessageHits ~= "" then + ScoreMessage = "Hits: " .. ScoreMessageHits + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + + +--- Produce detailed report of player destroy scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerDestroys( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageDestroys = "" + for CategoryID, CategoryName in pairs( _SCORINGCategory ) do + if PlayerData.Destroy[CategoryID] then + self:T( "Destroy scores exist for player " .. PlayerName ) + local Score = 0 + local ScoreDestroy = 0 + local Penalty = 0 + local PenaltyDestroy = 0 + + for UnitName, UnitData in pairs( PlayerData.Destroy[CategoryID] ) do + self:E( { UnitData = UnitData } ) + if UnitData ~= {} then + Score = Score + UnitData.Score + ScoreDestroy = ScoreDestroy + UnitData.ScoreDestroy + Penalty = Penalty + UnitData.Penalty + PenaltyDestroy = PenaltyDestroy + UnitData.PenaltyDestroy + end + end + + local ScoreMessageDestroy = string.format( " %s:%d ", CategoryName, Score - Penalty ) + self:T( ScoreMessageDestroy ) + ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy + + PlayerScore = PlayerScore + Score + PlayerPenalty = PlayerPenalty + Penalty + else + --ScoreMessageDestroys = ScoreMessageDestroys .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) + end + end + if ScoreMessageDestroys ~= "" then + ScoreMessage = "Destroys: " .. ScoreMessageDestroys + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player penalty scores because of changing the coalition. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerCoalitionChanges( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageCoalitionChangePenalties = "" + if PlayerData.PenaltyCoalition ~= 0 then + ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) + PlayerPenalty = PlayerPenalty + PlayerData.Penalty + end + if ScoreMessageCoalitionChangePenalties ~= "" then + ScoreMessage = ScoreMessage .. "Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player goal scores. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerGoals( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageGoal = "" + local ScoreGoal = 0 + local ScoreTask = 0 + for GoalName, GoalData in pairs( PlayerData.Goals ) do + ScoreGoal = ScoreGoal + GoalData.Score + ScoreMessageGoal = ScoreMessageGoal .. "'" .. GoalName .. "':" .. GoalData.Score .. "; " + end + PlayerScore = PlayerScore + ScoreGoal + + if ScoreMessageGoal ~= "" then + ScoreMessage = "Goals: " .. ScoreMessageGoal + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + +--- Produce detailed report of player penalty scores because of changing the coalition. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @return #string The report. +function SCORING:ReportDetailedPlayerMissions( PlayerName ) + + local ScoreMessage = "" + local PlayerScore = 0 + local PlayerPenalty = 0 + + local PlayerData = self.Players[PlayerName] + if PlayerData then -- This should normally not happen, but i'll test it anyway. + self:T( "Score Player: " .. PlayerName ) + + -- Some variables + local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] + local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] + local InitUnitType = PlayerData.UnitType + local InitUnitName = PlayerData.UnitName + + local ScoreMessageMission = "" + local ScoreMission = 0 + local ScoreTask = 0 + for MissionName, MissionData in pairs( PlayerData.Mission ) do + ScoreMission = ScoreMission + MissionData.ScoreMission + ScoreTask = ScoreTask + MissionData.ScoreTask + ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " + end + PlayerScore = PlayerScore + ScoreMission + ScoreTask + + if ScoreMessageMission ~= "" then + ScoreMessage = "Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")" + end + end + + return ScoreMessage, PlayerScore, PlayerPenalty +end + + +--- Report Group Score Summary +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreGroupSummary( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score Group Summary" ) + + local PlayerUnits = PlayerGroup:GetUnits() + for UnitID, PlayerUnit in pairs( PlayerUnits ) do + local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT + local PlayerName = PlayerUnit:GetPlayerName() + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + end + end + +end + +--- Report Group Score Detailed +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreGroupDetailed( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score Group Detailed" ) + + local PlayerUnits = PlayerGroup:GetUnits() + for UnitID, PlayerUnit in pairs( PlayerUnits ) do + local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT + local PlayerName = PlayerUnit:GetPlayerName() + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty, + ReportHits, + ReportDestroys, + ReportCoalitionChanges, + ReportGoals, + ReportMissions + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + end + end + +end + +--- Report all players score +-- @param #SCORING self +-- @param Wrapper.Group#GROUP PlayerGroup The player group. +function SCORING:ReportScoreAllSummary( PlayerGroup ) + + local PlayerMessage = "" + + self:T( "Report Score All Players" ) + + for PlayerName, PlayerData in pairs( self.Players ) do + + if PlayerName then + + local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName ) + ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits + self:E( { ReportHits, ScoreHits, PenaltyHits } ) + + local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName ) + ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys + self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } ) + + local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName ) + ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges + self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } ) + + local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName ) + ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals + self:E( { ReportGoals, ScoreGoals, PenaltyGoals } ) + + local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName ) + ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions + self:E( { ReportMissions, ScoreMissions, PenaltyMissions } ) + + local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions + local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions + + PlayerMessage = + string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )", + PlayerName, + PlayerScore - PlayerPenalty, + PlayerScore, + PlayerPenalty + ) + MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup ) + end + end + +end + + +function SCORING:SecondsToClock(sSeconds) + local nSeconds = sSeconds + if nSeconds == 0 then + --return nil; + return "00:00:00"; + else + nHours = string.format("%02.f", math.floor(nSeconds/3600)); + nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); + nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); + return nHours..":"..nMins..":"..nSecs + end +end + +--- Opens a score CSV file to log the scores. +-- @param #SCORING self +-- @param #string ScoringCSV +-- @return #SCORING self +-- @usage +-- -- Open a new CSV file to log the scores of the game Gori Valley. Let the name of the CSV file begin with "Player Scores". +-- ScoringObject = SCORING:New( "Gori Valley" ) +-- ScoringObject:OpenCSV( "Player Scores" ) +function SCORING:OpenCSV( ScoringCSV ) + self:F( ScoringCSV ) + + if lfs and io and os then + if ScoringCSV then + self.ScoringCSV = ScoringCSV + local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" + + self.CSVFile, self.err = io.open( fdir, "w+" ) + if not self.CSVFile then + error( "Error: Cannot open CSV file in " .. lfs.writedir() ) + end + + self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' ) + + self.RunTime = os.date("%y-%m-%d_%H-%M-%S") + else + error( "A string containing the CSV file name must be given." ) + end + else + self:E( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) + end + return self +end + + +--- Registers a score for a player. +-- @param #SCORING self +-- @param #string PlayerName The name of the player. +-- @param #string TargetPlayerName The name of the target player. +-- @param #string ScoreType The type of the score. +-- @param #string ScoreTimes The amount of scores achieved. +-- @param #string ScoreAmount The score given. +-- @param #string PlayerUnitName The unit name of the player. +-- @param #string PlayerUnitCoalition The coalition of the player unit. +-- @param #string PlayerUnitCategory The category of the player unit. +-- @param #string PlayerUnitType The type of the player unit. +-- @param #string TargetUnitName The name of the target unit. +-- @param #string TargetUnitCoalition The coalition of the target unit. +-- @param #string TargetUnitCategory The category of the target unit. +-- @param #string TargetUnitType The type of the target unit. +-- @return #SCORING self +function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) + --write statistic information to file + local ScoreTime = self:SecondsToClock( timer.getTime() ) + PlayerName = PlayerName:gsub( '"', '_' ) + + TargetPlayerName = TargetPlayerName or "" + TargetPlayerName = TargetPlayerName:gsub( '"', '_' ) + + if PlayerUnitName and PlayerUnitName ~= '' then + local PlayerUnit = Unit.getByName( PlayerUnitName ) + + if PlayerUnit then + if not PlayerUnitCategory then + --PlayerUnitCategory = SCORINGCategory[PlayerUnit:getCategory()] + PlayerUnitCategory = _SCORINGCategory[PlayerUnit:getDesc().category] + end + + if not PlayerUnitCoalition then + PlayerUnitCoalition = _SCORINGCoalition[PlayerUnit:getCoalition()] + end + + if not PlayerUnitType then + PlayerUnitType = PlayerUnit:getTypeName() + end + else + PlayerUnitName = '' + PlayerUnitCategory = '' + PlayerUnitCoalition = '' + PlayerUnitType = '' + end + else + PlayerUnitName = '' + PlayerUnitCategory = '' + PlayerUnitCoalition = '' + PlayerUnitType = '' + end + + TargetUnitCoalition = TargetUnitCoalition or "" + TargetUnitCategory = TargetUnitCategory or "" + TargetUnitType = TargetUnitType or "" + TargetUnitName = TargetUnitName or "" + + if lfs and io and os then + self.CSVFile:write( + '"' .. self.GameName .. '"' .. ',' .. + '"' .. self.RunTime .. '"' .. ',' .. + '' .. ScoreTime .. '' .. ',' .. + '"' .. PlayerName .. '"' .. ',' .. + '"' .. TargetPlayerName .. '"' .. ',' .. + '"' .. ScoreType .. '"' .. ',' .. + '"' .. PlayerUnitCoalition .. '"' .. ',' .. + '"' .. PlayerUnitCategory .. '"' .. ',' .. + '"' .. PlayerUnitType .. '"' .. ',' .. + '"' .. PlayerUnitName .. '"' .. ',' .. + '"' .. TargetUnitCoalition .. '"' .. ',' .. + '"' .. TargetUnitCategory .. '"' .. ',' .. + '"' .. TargetUnitType .. '"' .. ',' .. + '"' .. TargetUnitName .. '"' .. ',' .. + '' .. ScoreTimes .. '' .. ',' .. + '' .. ScoreAmount + ) + + self.CSVFile:write( "\n" ) + end +end + + +function SCORING:CloseCSV() + if lfs and io and os then + self.CSVFile:close() + end +end + +--- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area. +-- @module CleanUp +-- @author Flightcontrol + + + + + + + +--- The CLEANUP class. +-- @type CLEANUP +-- @extends Core.Base#BASE +CLEANUP = { + ClassName = "CLEANUP", + ZoneNames = {}, + TimeInterval = 300, + CleanUpList = {}, +} + +--- Creates the main object which is handling the cleaning of the debris within the given Zone Names. +-- @param #CLEANUP self +-- @param #table ZoneNames Is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name. +-- @param #number TimeInterval The interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes. +-- @return #CLEANUP +-- @usage +-- -- Clean these Zones. +-- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 ) +-- or +-- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) +-- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) +function CLEANUP:New( ZoneNames, TimeInterval ) + + local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP + self:F( { ZoneNames, TimeInterval } ) + + if type( ZoneNames ) == 'table' then + self.ZoneNames = ZoneNames + else + self.ZoneNames = { ZoneNames } + end + if TimeInterval then + self.TimeInterval = TimeInterval + end + + self:HandleEvent( EVENTS.Birth ) + + self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) + + return self +end + + +--- Destroys a group from the simulator, but checks first if it is still existing! +-- @param #CLEANUP self +-- @param Dcs.DCSWrapper.Group#Group GroupObject The object to be destroyed. +-- @param #string CleanUpGroupName The groupname... +function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) + self:F( { GroupObject, CleanUpGroupName } ) + + if GroupObject then -- and GroupObject:isExist() then + trigger.action.deactivateGroup(GroupObject) + self:T( { "GroupObject Destroyed", GroupObject } ) + end +end + +--- Destroys a @{DCSWrapper.Unit#Unit} from the simulator, but checks first if it is still existing! +-- @param #CLEANUP self +-- @param Dcs.DCSWrapper.Unit#Unit CleanUpUnit The object to be destroyed. +-- @param #string CleanUpUnitName The Unit name ... +function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName ) + self:F( { CleanUpUnit, CleanUpUnitName } ) + + if CleanUpUnit then + local CleanUpGroup = Unit.getGroup(CleanUpUnit) + -- TODO Client bug in 1.5.3 + if CleanUpGroup and CleanUpGroup:isExist() then + local CleanUpGroupUnits = CleanUpGroup:getUnits() + if #CleanUpGroupUnits == 1 then + local CleanUpGroupName = CleanUpGroup:getName() + --self:CreateEventCrash( timer.getTime(), CleanUpUnit ) + CleanUpGroup:destroy() + self:T( { "Destroyed Group:", CleanUpGroupName } ) + else + CleanUpUnit:destroy() + self:T( { "Destroyed Unit:", CleanUpUnitName } ) + end + self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list + CleanUpUnit = nil + end + end +end + +-- TODO check Dcs.DCSTypes#Weapon +--- Destroys a missile from the simulator, but checks first if it is still existing! +-- @param #CLEANUP self +-- @param Dcs.DCSTypes#Weapon MissileObject +function CLEANUP:_DestroyMissile( MissileObject ) + self:F( { MissileObject } ) + + if MissileObject and MissileObject:isExist() then + MissileObject:destroy() + self:T( "MissileObject Destroyed") + end +end + +--- @param #CLEANUP self +-- @param Core.Event#EVENTDATA EventData +function CLEANUP:_OnEventBirth( EventData ) + self:F( { EventData } ) + + self.CleanUpList[EventData.IniDCSUnitName] = {} + self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniDCSUnit + self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniDCSGroup + self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName + self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName + + EventData.IniUnit:HandleEvent( EVENTS.EngineShutdown , self._EventAddForCleanUp ) + EventData.IniUnit:HandleEvent( EVENTS.EngineStartup, self._EventAddForCleanUp ) + EventData.IniUnit:HandleEvent( EVENTS.Hit, self._EventAddForCleanUp ) + EventData.IniUnit:HandleEvent( EVENTS.PilotDead, self._EventCrash ) + EventData.IniUnit:HandleEvent( EVENTS.Dead, self._EventCrash ) + EventData.IniUnit:HandleEvent( EVENTS.Crash, self._EventCrash ) + EventData.IniUnit:HandleEvent( EVENTS.Shot, self._EventShot ) + +end + +--- Detects if a crash event occurs. +-- Crashed units go into a CleanUpList for removal. +-- @param #CLEANUP self +-- @param Dcs.DCSTypes#Event event +function CLEANUP:_EventCrash( Event ) + self:F( { Event } ) + + --TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed. + -- self:T("before getGroup") + -- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired + -- self:T("after getGroup") + -- _grp:destroy() + -- self:T("after deactivateGroup") + -- event.initiator:destroy() + + self.CleanUpList[Event.IniDCSUnitName] = {} + self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit + self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup + self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName + self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName + +end + +--- Detects if a unit shoots a missile. +-- If this occurs within one of the zones, then the weapon used must be destroyed. +-- @param #CLEANUP self +-- @param Dcs.DCSTypes#Event event +function CLEANUP:_EventShot( Event ) + self:F( { Event } ) + + -- Test if the missile was fired within one of the CLEANUP.ZoneNames. + local CurrentLandingZoneID = 0 + CurrentLandingZoneID = routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) + if ( CurrentLandingZoneID ) then + -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. + --_SEADmissile:destroy() + SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) + end +end + + +--- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. +-- @param #CLEANUP self +-- @param Dcs.DCSTypes#Event event +function CLEANUP:_EventHitCleanUp( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then + self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniDCSUnit:getLife(), "/", Event.IniDCSUnit:getLife0() } ) + if Event.IniDCSUnit:getLife() < Event.IniDCSUnit:getLife0() then + self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName ) + SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) + end + end + end + + if Event.TgtDCSUnit then + if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then + self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtDCSUnit:getLife(), "/", Event.TgtDCSUnit:getLife0() } ) + if Event.TgtDCSUnit:getLife() < Event.TgtDCSUnit:getLife0() then + self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName ) + SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) + end + end + end +end + +--- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp. +function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName ) + self:F( { CleanUpUnit, CleanUpUnitName } ) + + self.CleanUpList[CleanUpUnitName] = {} + self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit + self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName + self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit) + self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName() + self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime() + self.CleanUpList[CleanUpUnitName].CleanUpMoved = false + + self:T( { "CleanUp: Add to CleanUpList: ", Unit.getGroup(CleanUpUnit):getName(), CleanUpUnitName } ) + +end + +--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List. +-- @param #CLEANUP self +-- @param Dcs.DCSTypes#Event event +function CLEANUP:_EventAddForCleanUp( Event ) + + if Event.IniDCSUnit then + if self.CleanUpList[Event.IniDCSUnitName] == nil then + if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then + self:_AddForCleanUp( Event.IniDCSUnit, Event.IniDCSUnitName ) + end + end + end + + if Event.TgtDCSUnit then + if self.CleanUpList[Event.TgtDCSUnitName] == nil then + if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then + self:_AddForCleanUp( Event.TgtDCSUnit, Event.TgtDCSUnitName ) + end + end + end + +end + +local CleanUpSurfaceTypeText = { + "LAND", + "SHALLOW_WATER", + "WATER", + "ROAD", + "RUNWAY" + } + +--- At the defined time interval, CleanUp the Groups within the CleanUpList. +-- @param #CLEANUP self +function CLEANUP:_CleanUpScheduler() + self:F( { "CleanUp Scheduler" } ) + + local CleanUpCount = 0 + for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do + CleanUpCount = CleanUpCount + 1 + + self:T( { CleanUpUnitName, UnitData } ) + local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName) + local CleanUpGroupName = UnitData.CleanUpGroupName + local CleanUpUnitName = UnitData.CleanUpUnitName + if CleanUpUnit then + self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } ) + if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then + local CleanUpUnitVec3 = CleanUpUnit:getPoint() + --self:T( CleanUpUnitVec3 ) + local CleanUpUnitVec2 = {} + CleanUpUnitVec2.x = CleanUpUnitVec3.x + CleanUpUnitVec2.y = CleanUpUnitVec3.z + --self:T( CleanUpUnitVec2 ) + local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2) + --self:T( CleanUpSurfaceType ) + + if CleanUpUnit and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then + if CleanUpSurfaceType == land.SurfaceType.RUNWAY then + if CleanUpUnit:inAir() then + local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2) + local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight + self:T( { "CleanUp Scheduler", "Height = " .. CleanUpUnitHeight } ) + if CleanUpUnitHeight < 30 then + self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } ) + self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) + end + else + self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } ) + self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) + end + end + end + -- Clean Units which are waiting for a very long time in the CleanUpZone. + if CleanUpUnit then + local CleanUpUnitVelocity = CleanUpUnit:getVelocity() + local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z) + if CleanUpUnitVelocityTotal < 1 then + if UnitData.CleanUpMoved then + if UnitData.CleanUpTime + 180 <= timer.getTime() then + self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } ) + self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) + end + end + else + UnitData.CleanUpTime = timer.getTime() + UnitData.CleanUpMoved = true + end + end + + else + -- Do nothing ... + self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE + end + else + self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." ) + self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE + end + end + self:T(CleanUpCount) + + return true +end + +--- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- +-- **Spawn groups of units dynamically in your missions.** +-- +-- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) +-- +-- === +-- +-- # 1) @{#SPAWN} class, extends @{Base#BASE} +-- +-- The @{#SPAWN} class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned. +-- For each group to be spawned, within the mission editor, a group has to be created with the "late activation flag" set. We call this group the *"Spawn Template"* of the SPAWN object. +-- A reference to this Spawn Template needs to be provided when constructing the SPAWN object, by indicating the name of the group within the mission editor in the constructor methods. +-- +-- Within the SPAWN object, there is an internal index that keeps track of which group from the internal group list was spawned. +-- When new groups get spawned by using the SPAWN methods (see below), it will be validated whether the Limits (@{#SPAWN.Limit}) of the SPAWN object are not reached. +-- When all is valid, a new group will be created by the spawning methods, and the internal index will be increased with 1. +-- +-- Regarding the name of new spawned groups, a _SpawnPrefix_ will be assigned for each new group created. +-- If you want to have the Spawn Template name to be used as the _SpawnPrefix_ name, use the @{#SPAWN.New} constructor. +-- However, when the @{#SPAWN.NewWithAlias} constructor was used, the Alias name will define the _SpawnPrefix_ name. +-- Groups will follow the following naming structure when spawned at run-time: +-- +-- 1. Spawned groups will have the name _SpawnPrefix_#ggg, where ggg is a counter from 0 to 999. +-- 2. Spawned units will have the name _SpawnPrefix_#ggg-uu, where uu is a counter from 0 to 99 for each new spawned unit belonging to the group. +-- +-- Some additional notes that need to be remembered: +-- +-- * Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the @{#SPAWN} module. +-- * It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. +-- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. +-- +-- ## 1.1) SPAWN construction methods +-- +-- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: +-- +-- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition). +-- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned @{Group} an different name. +-- +-- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. +-- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. +-- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. +-- +-- ## 1.2) SPAWN initialization methods +-- +-- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix: +-- +-- * @{#SPAWN.InitKeepUnitNames}(): Keeps the unit names as defined within the mission editor, but note that anything after a # mark is ignored, and any spaces before and after the resulting name are removed. IMPORTANT! This method MUST be the first used after :New !!! +-- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. +-- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height. +-- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. +-- * @{#SPAWN.InitUnControlled}(): Spawn plane groups uncontrolled. +-- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array. +-- * @{#SPAWN.InitRepeat}(): Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}. +-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. +-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. +-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. +-- * @{#SPAWN.InitAIOn}(): Turns the AI On when spawning the new @{Group} object. +-- * @{#SPAWN.InitAIOff}(): Turns the AI Off when spawning the new @{Group} object. +-- * @{#SPAWN.InitAIOnOff}(): Turns the AI On or Off when spawning the new @{Group} object. +-- +-- ## 1.3) SPAWN spawning methods +-- +-- Groups can be spawned at different times and methods: +-- +-- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index. +-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index. +-- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart}() and @{#SPAWN.SpawnScheduleStop}() to start and stop the schedule respectively. +-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). +-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). +-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. +-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. +-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. +-- +-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. +-- You can use the @{GROUP} object to do further actions with the DCSGroup. +-- +-- ## 1.4) Retrieve alive GROUPs spawned by the SPAWN object +-- +-- The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. +-- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. +-- SPAWN provides methods to iterate through that internal GROUP object reference table: +-- +-- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found. +-- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found. +-- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found. +-- +-- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. +-- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive... +-- +-- ## 1.5) SPAWN object cleaning +-- +-- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. +-- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, +-- and it may occur that no new groups are or can be spawned as limits are reached. +-- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group. +-- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. +-- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... +-- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. +-- This models AI that has succesfully returned to their airbase, to restart their combat activities. +-- Check the @{#SPAWN.InitCleanUp}() for further info. +-- +-- ## 1.6) Catch the @{Group} spawn event in a callback function! +-- +-- When using the SpawnScheduled method, new @{Group}s are created following the schedule timing parameters. +-- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. +-- To SPAWN class supports this functionality through the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method, which takes a function as a parameter that you can define locally. +-- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. +-- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. +-- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-03-14: SPAWN:**InitKeepUnitNames()** added. +-- 2017-03-14: SPAWN:**InitRandomizePosition( RandomizePosition, OuterRadious, InnerRadius )** added. +-- +-- 2017-02-04: SPAWN:InitUnControlled( **UnControlled** ) replaces SPAWN:InitUnControlled(). +-- +-- 2017-01-24: SPAWN:**InitAIOnOff( AIOnOff )** added. +-- +-- 2017-01-24: SPAWN:**InitAIOn()** added. +-- +-- 2017-01-24: SPAWN:**InitAIOff()** added. +-- +-- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ). +-- +-- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones )** added. +-- +-- 2016-08-14: SPAWN:**OnSpawnGroup**( SpawnCallBackFunction, ... ) replaces SPAWN:_SpawnFunction_( SpawnCallBackFunction, ... ). +-- +-- 2016-08-14: SPAWN.SpawnInZone( Zone, __RandomizeGroup__, SpawnIndex ) replaces SpawnInZone( Zone, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- +-- 2016-08-14: SPAWN.SpawnFromVec3( Vec3, SpawnIndex ) replaces SpawnFromVec3( Vec3, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): +-- +-- 2016-08-14: SPAWN.SpawnFromVec2( Vec2, SpawnIndex ) replaces SpawnFromVec2( Vec2, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): +-- +-- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromUnit( SpawnUnit, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): +-- +-- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromStatic( SpawnStatic, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): +-- +-- 2016-08-14: SPAWN.**InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius )** added: +-- +-- 2016-08-14: SPAWN.**Init**Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) replaces SPAWN._Limit_( SpawnMaxUnitsAlive, SpawnMaxGroups ): +-- +-- 2016-08-14: SPAWN.**Init**Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) replaces SPAWN._Array_( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ). +-- +-- 2016-08-14: SPAWN.**Init**RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) replaces SPAWN._RandomizeRoute_( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ). +-- +-- 2016-08-14: SPAWN.**Init**RandomizeTemplate( SpawnTemplatePrefixTable ) replaces SPAWN._RandomizeTemplate_( SpawnTemplatePrefixTable ). +-- +-- 2016-08-14: SPAWN.**Init**UnControlled() replaces SPAWN._UnControlled_(). +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **Aaron**: Posed the idea for Group position randomization at SpawnInZone and make the Unit randomization separate from the Group randomization. +-- * [**Entropy**](https://forums.eagle.ru/member.php?u=111471), **Afinegan**: Came up with the requirement for AIOnOff(). +-- +-- ### Authors: +-- +-- * **FlightControl**: Design & Programming +-- +-- @module Spawn + + + +--- SPAWN Class +-- @type SPAWN +-- @extends Core.Base#BASE +-- @field ClassName +-- @field #string SpawnTemplatePrefix +-- @field #string SpawnAliasPrefix +-- @field #number AliveUnits +-- @field #number MaxAliveUnits +-- @field #number SpawnIndex +-- @field #number MaxAliveGroups +-- @field #SPAWN.SpawnZoneTable SpawnZoneTable +SPAWN = { + ClassName = "SPAWN", + SpawnTemplatePrefix = nil, + SpawnAliasPrefix = nil, +} + + +--- @type SPAWN.SpawnZoneTable +-- @list SpawnZone + + +--- Creates the main object to spawn a @{Group} defined in the DCS ME. +-- @param #SPAWN self +-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. +-- @return #SPAWN +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ) +-- @usage local Plane = SPAWN:New( "Plane" ) -- Creates a new local variable that can initiate new planes with the name "Plane#ddd" using the template "Plane" as defined within the ME. +function SPAWN:New( SpawnTemplatePrefix ) + local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN + self:F( { SpawnTemplatePrefix } ) + + local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) + if TemplateGroup then + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.SpawnIndex = 0 + self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. + self.SpawnUnControlled = false + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + + self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. + else + error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + + return self +end + +--- Creates a new SPAWN instance to create new groups based on the defined template and using a new alias for each new group. +-- @param #SPAWN self +-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. +-- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime. +-- @return #SPAWN +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) +-- @usage local PlaneWithAlias = SPAWN:NewWithAlias( "Plane", "Bomber" ) -- Creates a new local variable that can instantiate new planes with the name "Bomber#ddd" using the template "Plane" as defined within the ME. +function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } ) + + local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) + if TemplateGroup then + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.SpawnAliasPrefix = SpawnAliasPrefix + self.SpawnIndex = 0 + self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. + self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! + self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. + self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. + self.SpawnInitLimit = false -- By default, no InitLimit + self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. + self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. + self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. + self.AIOnOff = true -- The AI is on by default when spawning a group. + self.SpawnUnControlled = false + self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + + self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. + else + error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + + return self +end + + +--- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. +-- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. +-- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... +-- When a @{#SPAWN.New} is executed and the limit of the amount of units alive is reached, then no new spawn will happen of the group, until some of these units of the spawn object will be destroyed. +-- @param #SPAWN self +-- @param #number SpawnMaxUnitsAlive The maximum amount of units that can be alive at runtime. +-- @param #number SpawnMaxGroups The maximum amount of groups that can be spawned. When the limit is reached, then no more actual spawns will happen of the group. +-- This parameter is useful to define a maximum amount of airplanes, ground troops, helicopters, ships etc within a supply area. +-- This parameter accepts the value 0, which defines that there are no maximum group limits, but there are limits on the maximum of units that can be alive at the same time. +-- @return #SPAWN self +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- -- This helicopter group consists of one Unit. So, this group will SPAWN maximum 2 groups simultaneously within the DCSRTE. +-- -- There will be maximum 24 groups spawned during the whole mission lifetime. +-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitLimit( 2, 24 ) +function SPAWN:InitLimit( SpawnMaxUnitsAlive, SpawnMaxGroups ) + self:F( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) + + self.SpawnInitLimit = true + self.SpawnMaxUnitsAlive = SpawnMaxUnitsAlive -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. + self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned. + + for SpawnGroupID = 1, self.SpawnMaxGroups do + self:_InitializeSpawnGroups( SpawnGroupID ) + end + + return self +end + +--- Keeps the unit names as defined within the mission editor, +-- but note that anything after a # mark is ignored, +-- and any spaces before and after the resulting name are removed. +-- IMPORTANT! This method MUST be the first used after :New !!! +-- @param #SPAWN self +-- @return #SPAWN self +function SPAWN:InitKeepUnitNames() + self:F( ) + + self.SpawnInitKeepUnitNames = true + + return self +end + + +--- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. +-- @param #SPAWN self +-- @param #number SpawnStartPoint is the waypoint where the randomization begins. +-- Note that the StartPoint = 0 equaling the point where the group is spawned. +-- @param #number SpawnEndPoint is the waypoint where the randomization ends counting backwards. +-- This parameter is useful to avoid randomization to end at a waypoint earlier than the last waypoint on the route. +-- @param #number SpawnRadius is the radius in meters in which the randomization of the new waypoints, with the original waypoint of the original template located in the middle ... +-- @param #number SpawnHeight (optional) Specifies the **additional** height in meters that can be added to the base height specified at each waypoint in the ME. +-- @return #SPAWN +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). +-- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. +-- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. +-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) +function SPAWN:InitRandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) + self:F( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight } ) + + self.SpawnRandomizeRoute = true + self.SpawnRandomizeRouteStartPoint = SpawnStartPoint + self.SpawnRandomizeRouteEndPoint = SpawnEndPoint + self.SpawnRandomizeRouteRadius = SpawnRadius + self.SpawnRandomizeRouteHeight = SpawnHeight + + for GroupID = 1, self.SpawnMaxGroups do + self:_RandomizeRoute( GroupID ) + end + + return self +end + +--- Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. +-- @param #SPAWN self +-- @param #boolean RandomizePosition If true, SPAWN will perform the randomization of the @{Group}s position between a given outer and inner radius. +-- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. +-- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. +-- @return #SPAWN +function SPAWN:InitRandomizePosition( RandomizePosition, OuterRadius, InnerRadius ) + self:F( { self.SpawnTemplatePrefix, RandomizePosition, OuterRadius, InnerRadius } ) + + self.SpawnRandomizePosition = RandomizePosition or false + self.SpawnRandomizePositionOuterRadius = OuterRadius or 0 + self.SpawnRandomizePositionInnerRadius = InnerRadius or 0 + + for GroupID = 1, self.SpawnMaxGroups do + self:_RandomizeRoute( GroupID ) + end + + return self +end + + +--- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius. +-- @param #SPAWN self +-- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius. +-- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. +-- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. +-- @return #SPAWN +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). +-- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. +-- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. +-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) +function SPAWN:InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius ) + self:F( { self.SpawnTemplatePrefix, RandomizeUnits, OuterRadius, InnerRadius } ) + + self.SpawnRandomizeUnits = RandomizeUnits or false + self.SpawnOuterRadius = OuterRadius or 0 + self.SpawnInnerRadius = InnerRadius or 0 + + for GroupID = 1, self.SpawnMaxGroups do + self:_RandomizeRoute( GroupID ) + end + + return self +end + +--- This method is rather complicated to understand. But I'll try to explain. +-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor, +-- but they will all follow the same Template route and have the same prefix name. +-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group. +-- @param #SPAWN self +-- @param #string SpawnTemplatePrefixTable A table with the names of the groups defined within the mission editor, from which one will be choosen when a new group will be spawned. +-- @return #SPAWN +-- @usage +-- -- NATO Tank Platoons invading Gori. +-- -- Choose between 13 different 'US Tank Platoon' configurations for each new SPAWN the Group to be spawned for the +-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SpawnTemplatePrefixes. +-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and +-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission. +-- Spawn_US_Platoon = { 'US Tank Platoon 1', 'US Tank Platoon 2', 'US Tank Platoon 3', 'US Tank Platoon 4', 'US Tank Platoon 5', +-- 'US Tank Platoon 6', 'US Tank Platoon 7', 'US Tank Platoon 8', 'US Tank Platoon 9', 'US Tank Platoon 10', +-- 'US Tank Platoon 11', 'US Tank Platoon 12', 'US Tank Platoon 13' } +-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) +-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) +-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) +function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable ) + self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) + + self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable + self.SpawnRandomizeTemplate = true + + for SpawnGroupID = 1, self.SpawnMaxGroups do + self:_RandomizeTemplate( SpawnGroupID ) + end + + return self +end + +--TODO: Add example. +--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. +-- @param #SPAWN self +-- @param #table SpawnZoneTable A table with @{Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Zone}s objects. +-- @return #SPAWN +-- @usage +-- -- NATO Tank Platoons invading Gori. +-- -- Choose between 3 different zones for each new SPAWN the Group to be executed, regardless of the zone type. +function SPAWN:InitRandomizeZones( SpawnZoneTable ) + self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } ) + + self.SpawnZoneTable = SpawnZoneTable + self.SpawnRandomizeZones = true + + for SpawnGroupID = 1, self.SpawnMaxGroups do + self:_RandomizeZones( SpawnGroupID ) + end + + return self +end + + + + + +--- For planes and helicopters, when these groups go home and land on their home airbases and farps, they normally would taxi to the parking spot, shut-down their engines and wait forever until the Group is removed by the runtime environment. +-- This method is used to re-spawn automatically (so no extra call is needed anymore) the same group after it has landed. +-- This will enable a spawned group to be re-spawned after it lands, until it is destroyed... +-- Note: When the group is respawned, it will re-spawn from the original airbase where it took off. +-- So ensure that the routes for groups that respawn, always return to the original airbase, or players may get confused ... +-- @param #SPAWN self +-- @return #SPAWN self +-- @usage +-- -- RU Su-34 - AI Ship Attack +-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically. +-- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():InitRandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown() +function SPAWN:InitRepeat() + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) + + self.Repeat = true + self.RepeatOnEngineShutDown = false + self.RepeatOnLanding = true + + return self +end + +--- Respawn group after landing. +-- @param #SPAWN self +-- @return #SPAWN self +function SPAWN:InitRepeatOnLanding() + self:F( { self.SpawnTemplatePrefix } ) + + self:InitRepeat() + self.RepeatOnEngineShutDown = false + self.RepeatOnLanding = true + + return self +end + + +--- Respawn after landing when its engines have shut down. +-- @param #SPAWN self +-- @return #SPAWN self +function SPAWN:InitRepeatOnEngineShutDown() + self:F( { self.SpawnTemplatePrefix } ) + + self:InitRepeat() + self.RepeatOnEngineShutDown = true + self.RepeatOnLanding = false + + return self +end + + +--- CleanUp groups when they are still alive, but inactive. +-- When groups are still alive and have become inactive due to damage and are unable to contribute anything, then this group will be removed at defined intervals in seconds. +-- @param #SPAWN self +-- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds. +-- @return #SPAWN self +-- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive. +function SPAWN:InitCleanUp( SpawnCleanUpInterval ) + self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) + + self.SpawnCleanUpInterval = SpawnCleanUpInterval + self.SpawnCleanUpTimeStamps = {} + + local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() + self:T( { "CleanUp Scheduler:", SpawnGroup } ) + + --self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, SpawnCleanUpInterval ) + self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 ) + return self +end + + + +--- Makes the groups visible before start (like a batallion). +-- The method will take the position of the group as the first position in the array. +-- @param #SPAWN self +-- @param #number SpawnAngle The angle in degrees how the groups and each unit of the group will be positioned. +-- @param #number SpawnWidth The amount of Groups that will be positioned on the X axis. +-- @param #number SpawnDeltaX The space between each Group on the X-axis. +-- @param #number SpawnDeltaY The space between each Group on the Y-axis. +-- @return #SPAWN self +-- @usage +-- -- Define an array of Groups. +-- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):InitLimit( 2, 24 ):InitArray( 90, "Diamond", 10, 100, 50 ) +function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) + self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) + + self.SpawnVisible = true -- When the first Spawn executes, all the Groups need to be made visible before start. + + local SpawnX = 0 + local SpawnY = 0 + local SpawnXIndex = 0 + local SpawnYIndex = 0 + + for SpawnGroupID = 1, self.SpawnMaxGroups do + self:T( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } ) + + self.SpawnGroups[SpawnGroupID].Visible = true + self.SpawnGroups[SpawnGroupID].Spawned = false + + SpawnXIndex = SpawnXIndex + 1 + if SpawnWidth and SpawnWidth ~= 0 then + if SpawnXIndex >= SpawnWidth then + SpawnXIndex = 0 + SpawnYIndex = SpawnYIndex + 1 + end + end + + local SpawnRootX = self.SpawnGroups[SpawnGroupID].SpawnTemplate.x + local SpawnRootY = self.SpawnGroups[SpawnGroupID].SpawnTemplate.y + + self:_TranslateRotate( SpawnGroupID, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) + + self.SpawnGroups[SpawnGroupID].SpawnTemplate.lateActivation = true + self.SpawnGroups[SpawnGroupID].SpawnTemplate.visible = true + + self.SpawnGroups[SpawnGroupID].Visible = true + + self:HandleEvent( EVENTS.Birth, self._OnBirth ) + self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._OnDeadOrCrash ) + if self.Repeat then + self:HandleEvent( EVENTS.Takeoff, self._OnTakeOff ) + self:HandleEvent( EVENTS.Land, self._OnLand ) + end + if self.RepeatOnEngineShutDown then + self:HandleEvent( EVENTS.EngineShutdown, self._OnEngineShutDown ) + end + + self.SpawnGroups[SpawnGroupID].Group = _DATABASE:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) + + SpawnX = SpawnXIndex * SpawnDeltaX + SpawnY = SpawnYIndex * SpawnDeltaY + end + + return self +end + +do -- AI methods + --- Turns the AI On or Off for the @{Group} when spawning. + -- @param #SPAWN self + -- @param #boolean AIOnOff A value of true sets the AI On, a value of false sets the AI Off. + -- @return #SPAWN The SPAWN object + function SPAWN:InitAIOnOff( AIOnOff ) + + self.AIOnOff = AIOnOff + return self + end + + --- Turns the AI On for the @{Group} when spawning. + -- @param #SPAWN self + -- @return #SPAWN The SPAWN object + function SPAWN:InitAIOn() + + return self:InitAIOnOff( true ) + end + + --- Turns the AI Off for the @{Group} when spawning. + -- @param #SPAWN self + -- @return #SPAWN The SPAWN object + function SPAWN:InitAIOff() + + return self:InitAIOnOff( false ) + end + +end -- AI methods + +--- Will spawn a group based on the internal index. +-- Note: Uses @{DATABASE} module defined in MOOSE. +-- @param #SPAWN self +-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. +function SPAWN:Spawn() + self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, self.AliveUnits } ) + + return self:SpawnWithIndex( self.SpawnIndex + 1 ) +end + +--- Will re-spawn a group based on a given index. +-- Note: Uses @{DATABASE} module defined in MOOSE. +-- @param #SPAWN self +-- @param #string SpawnIndex The index of the group to be spawned. +-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. +function SPAWN:ReSpawn( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + if not SpawnIndex then + SpawnIndex = 1 + end + +-- TODO: This logic makes DCS crash and i don't know why (yet). + local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) + local WayPoints = SpawnGroup and SpawnGroup.WayPoints or nil + if SpawnGroup then + local SpawnDCSGroup = SpawnGroup:GetDCSObject() + if SpawnDCSGroup then + SpawnGroup:Destroy() + end + end + + local SpawnGroup = self:SpawnWithIndex( SpawnIndex ) + if SpawnGroup and WayPoints then + -- If there were WayPoints set, then Re-Execute those WayPoints! + SpawnGroup:WayPointInitialize( WayPoints ) + SpawnGroup:WayPointExecute( 1, 5 ) + end + + if SpawnGroup.ReSpawnFunction then + SpawnGroup:ReSpawnFunction() + end + + return SpawnGroup +end + +--- Will spawn a group with a specified index number. +-- Uses @{DATABASE} global object defined in MOOSE. +-- @param #SPAWN self +-- @param #string SpawnIndex The index of the group to be spawned. +-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. +function SPAWN:SpawnWithIndex( SpawnIndex ) + self:F2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } ) + + if self:_GetSpawnIndex( SpawnIndex ) then + + if self.SpawnGroups[self.SpawnIndex].Visible then + self.SpawnGroups[self.SpawnIndex].Group:Activate() + else + + local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate + self:T( SpawnTemplate.name ) + + if SpawnTemplate then + + local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y ) + self:T( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } ) + + -- If RandomizePosition, then Randomize the formation in the zone band, keeping the template. + if self.SpawnRandomizePosition then + local RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnRandomizePositionOuterRadius, self.SpawnRandomizePositionInnerRadius ) + local CurrentX = SpawnTemplate.units[1].x + local CurrentY = SpawnTemplate.units[1].y + SpawnTemplate.x = RandomVec2.x + SpawnTemplate.y = RandomVec2.y + for UnitID = 1, #SpawnTemplate.units do + SpawnTemplate.units[UnitID].x = SpawnTemplate.units[UnitID].x + ( RandomVec2.x - CurrentX ) + SpawnTemplate.units[UnitID].y = SpawnTemplate.units[UnitID].y + ( RandomVec2.y - CurrentY ) + self:T( 'SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + end + end + + -- If RandomizeUnits, then Randomize the formation at the start point. + if self.SpawnRandomizeUnits then + for UnitID = 1, #SpawnTemplate.units do + local RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius ) + SpawnTemplate.units[UnitID].x = RandomVec2.x + SpawnTemplate.units[UnitID].y = RandomVec2.y + self:T( 'SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + end + end + + if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then + if SpawnTemplate.route.points[1].type == "TakeOffParking" then + SpawnTemplate.uncontrolled = self.SpawnUnControlled + end + end + end + + self:HandleEvent( EVENTS.Birth, self._OnBirth ) + self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash ) + self:HandleEvent( EVENTS.Crash, self._OnDeadOrCrash ) + if self.Repeat then + self:HandleEvent( EVENTS.Takeoff, self._OnTakeOff ) + self:HandleEvent( EVENTS.Land, self._OnLand ) + end + if self.RepeatOnEngineShutDown then + self:HandleEvent( EVENTS.EngineShutdown, self._OnEngineShutDown ) + end + + self.SpawnGroups[self.SpawnIndex].Group = _DATABASE:Spawn( SpawnTemplate ) + + local SpawnGroup = self.SpawnGroups[self.SpawnIndex].Group -- Wrapper.Group#GROUP + + --TODO: Need to check if this function doesn't need to be scheduled, as the group may not be immediately there! + if SpawnGroup then + + SpawnGroup:SetAIOnOff( self.AIOnOff ) + end + + self:T3( SpawnTemplate.name ) + + -- If there is a SpawnFunction hook defined, call it. + if self.SpawnFunctionHook then + self.SpawnFunctionHook( self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments ) ) + end + -- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats. + --if self.Repeat then + -- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) + --end + end + + self.SpawnGroups[self.SpawnIndex].Spawned = true + return self.SpawnGroups[self.SpawnIndex].Group + else + --self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } ) + end + + return nil +end + +--- Spawns new groups at varying time intervals. +-- This is useful if you want to have continuity within your missions of certain (AI) groups to be present (alive) within your missions. +-- @param #SPAWN self +-- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups. +-- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn. +-- The variation is a number between 0 and 1, representing the %-tage of variation to be applied on the time interval. +-- @return #SPAWN self +-- @usage +-- -- NATO helicopters engaging in the battle field. +-- -- The time interval is set to SPAWN new helicopters between each 600 seconds, with a time variation of 50%. +-- -- The time variation in this case will be between 450 seconds and 750 seconds. +-- -- This is calculated as follows: +-- -- Low limit: 600 * ( 1 - 0.5 / 2 ) = 450 +-- -- High limit: 600 * ( 1 + 0.5 / 2 ) = 750 +-- -- Between these two values, a random amount of seconds will be choosen for each new spawn of the helicopters. +-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) +function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) + self:F( { SpawnTime, SpawnTimeVariation } ) + + if SpawnTime ~= nil and SpawnTimeVariation ~= nil then + self.SpawnScheduler = SCHEDULER:New( self, self._Scheduler, {}, 1, SpawnTime, SpawnTimeVariation ) + end + + return self +end + +--- Will re-start the spawning scheduler. +-- Note: This method is only required to be called when the schedule was stopped. +function SPAWN:SpawnScheduleStart() + self:F( { self.SpawnTemplatePrefix } ) + + self.SpawnScheduler:Start() +end + +--- Will stop the scheduled spawning scheduler. +function SPAWN:SpawnScheduleStop() + self:F( { self.SpawnTemplatePrefix } ) + + self.SpawnScheduler:Stop() +end + + +--- Allows to place a CallFunction hook when a new group spawns. +-- The provided method will be called when a new group is spawned, including its given parameters. +-- The first parameter of the SpawnFunction is the @{Group#GROUP} that was spawned. +-- @param #SPAWN self +-- @param #function SpawnCallBackFunction The function to be called when a group spawns. +-- @param SpawnFunctionArguments A random amount of arguments to be provided to the function when the group spawns. +-- @return #SPAWN +-- @usage +-- -- Declare SpawnObject and call a function when a new Group is spawned. +-- local SpawnObject = SPAWN +-- :New( "SpawnObject" ) +-- :InitLimit( 2, 10 ) +-- :OnSpawnGroup( +-- function( SpawnGroup ) +-- SpawnGroup:E( "I am spawned" ) +-- end +-- ) +-- :SpawnScheduled( 300, 0.3 ) +function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... ) + self:F( "OnSpawnGroup" ) + + self.SpawnFunctionHook = SpawnCallBackFunction + self.SpawnFunctionArguments = {} + if arg then + self.SpawnFunctionArguments = arg + end + + return self +end + + +--- Will spawn a group from a Vec3 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } ) + + local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) + self:T2(PointVec3) + + if SpawnIndex then + else + SpawnIndex = self.SpawnIndex + 1 + end + + if self:_GetSpawnIndex( SpawnIndex ) then + + local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate + + if SpawnTemplate then + + self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) + + -- Translate the position of the Group Template to the Vec3. + for UnitID = 1, #SpawnTemplate.units do + self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + local UnitTemplate = SpawnTemplate.units[UnitID] + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = Vec3.x + ( SX - BX ) + local TY = Vec3.z + ( SY - BY ) + SpawnTemplate.units[UnitID].x = TX + SpawnTemplate.units[UnitID].y = TY + SpawnTemplate.units[UnitID].alt = Vec3.y + self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + end + + SpawnTemplate.route.points[1].x = Vec3.x + SpawnTemplate.route.points[1].y = Vec3.z + SpawnTemplate.route.points[1].alt = Vec3.y + + SpawnTemplate.x = Vec3.x + SpawnTemplate.y = Vec3.z + + return self:SpawnWithIndex( self.SpawnIndex ) + end + end + + return nil +end + +--- Will spawn a group from a Vec2 in 3D space. +-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromVec2( Vec2, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } ) + + local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 ) + return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex ) +end + + +--- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } ) + + if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then + return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex ) + end + + return nil +end + +--- Will spawn a group from a hosting static. This method is mostly advisable to be used if you want to simulate spawning from buldings and structures (static buildings). +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } ) + + if HostStatic and HostStatic:IsAlive() then + return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex ) + end + + return nil +end + +--- Will spawn a Group within a given @{Zone}. +-- The @{Zone} can be of any type derived from @{Zone#ZONE_BASE}. +-- Once the @{Group} is spawned within the zone, the @{Group} will continue on its route. +-- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates. +-- @param #SPAWN self +-- @param Core.Zone#ZONE Zone The zone where the group is to be spawned. +-- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone. +-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil when nothing was spawned. +function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } ) + + if Zone then + if RandomizeGroup then + return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex ) + else + return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex ) + end + end + + return nil +end + +--- (**AIR**) Will spawn a plane group in UnControlled or Controlled mode... +-- This will be similar to the uncontrolled flag setting in the ME. +-- You can use UnControlled mode to simulate planes startup and ready for take-off but aren't moving (yet). +-- ReSpawn the plane in Controlled mode, and the plane will move... +-- @param #SPAWN self +-- @param #boolean UnControlled true if UnControlled, false if Controlled. +-- @return #SPAWN self +function SPAWN:InitUnControlled( UnControlled ) + self:F2( { self.SpawnTemplatePrefix, UnControlled } ) + + self.SpawnUnControlled = UnControlled + + for SpawnGroupID = 1, self.SpawnMaxGroups do + self.SpawnGroups[SpawnGroupID].UnControlled = UnControlled + end + + return self +end + + + +--- Will return the SpawnGroupName either with with a specific count number or without any count. +-- @param #SPAWN self +-- @param #number SpawnIndex Is the number of the Group that is to be spawned. +-- @return #string SpawnGroupName +function SPAWN:SpawnGroupName( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) + + local SpawnPrefix = self.SpawnTemplatePrefix + if self.SpawnAliasPrefix then + SpawnPrefix = self.SpawnAliasPrefix + end + + if SpawnIndex then + local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex ) + self:T( SpawnName ) + return SpawnName + else + self:T( SpawnPrefix ) + return SpawnPrefix + end + +end + +--- Will find the first alive @{Group} it has spawned, and return the alive @{Group} object and the first Index where the first alive @{Group} object has been found. +-- @param #SPAWN self +-- @return Wrapper.Group#GROUP, #number The @{Group} object found, the new Index where the group was found. +-- @return #nil, #nil When no group is found, #nil is returned. +-- @usage +-- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() +-- while GroupPlane ~= nil do +-- -- Do actions with the GroupPlane object. +-- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) +-- end +function SPAWN:GetFirstAliveGroup() + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + + for SpawnIndex = 1, self.SpawnCount do + local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) + if SpawnGroup and SpawnGroup:IsAlive() then + return SpawnGroup, SpawnIndex + end + end + + return nil, nil +end + + +--- Will find the next alive @{Group} object from a given Index, and return a reference to the alive @{Group} object and the next Index where the alive @{Group} has been found. +-- @param #SPAWN self +-- @param #number SpawnIndexStart A Index holding the start position to search from. This method can also be used to find the first alive @{Group} object from the given Index. +-- @return Wrapper.Group#GROUP, #number The next alive @{Group} object found, the next Index where the next alive @{Group} object was found. +-- @return #nil, #nil When no alive @{Group} object is found from the start Index position, #nil is returned. +-- @usage +-- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() +-- while GroupPlane ~= nil do +-- -- Do actions with the GroupPlane object. +-- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) +-- end +function SPAWN:GetNextAliveGroup( SpawnIndexStart ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndexStart } ) + + SpawnIndexStart = SpawnIndexStart + 1 + for SpawnIndex = SpawnIndexStart, self.SpawnCount do + local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) + if SpawnGroup and SpawnGroup:IsAlive() then + return SpawnGroup, SpawnIndex + end + end + + return nil, nil +end + +--- Will find the last alive @{Group} object, and will return a reference to the last live @{Group} object and the last Index where the last alive @{Group} object has been found. +-- @param #SPAWN self +-- @return Wrapper.Group#GROUP, #number The last alive @{Group} object found, the last Index where the last alive @{Group} object was found. +-- @return #nil, #nil When no alive @{Group} object is found, #nil is returned. +-- @usage +-- -- Find the last alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. +-- local GroupPlane, Index = SpawnPlanes:GetLastAliveGroup() +-- if GroupPlane then -- GroupPlane can be nil!!! +-- -- Do actions with the GroupPlane object. +-- end +function SPAWN:GetLastAliveGroup() + self:F( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) + + self.SpawnIndex = self:_GetLastIndex() + for SpawnIndex = self.SpawnIndex, 1, -1 do + local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) + if SpawnGroup and SpawnGroup:IsAlive() then + self.SpawnIndex = SpawnIndex + return SpawnGroup + end + end + + self.SpawnIndex = nil + return nil +end + + + +--- Get the group from an index. +-- Returns the group from the SpawnGroups list. +-- If no index is given, it will return the first group in the list. +-- @param #SPAWN self +-- @param #number SpawnIndex The index of the group to return. +-- @return Wrapper.Group#GROUP self +function SPAWN:GetGroupFromIndex( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + + if not SpawnIndex then + SpawnIndex = 1 + end + + if self.SpawnGroups and self.SpawnGroups[SpawnIndex] then + local SpawnGroup = self.SpawnGroups[SpawnIndex].Group + return SpawnGroup + else + return nil + end +end + + +--- Return the prefix of a SpawnUnit. +-- The method will search for a #-mark, and will return the text before the #-mark. +-- It will return nil of no prefix was found. +-- @param #SPAWN self +-- @param Dcs.DCSWrapper.Unit#UNIT DCSUnit The @{DCSUnit} to be searched. +-- @return #string The prefix +-- @return #nil Nothing found +function SPAWN:_GetPrefixFromGroup( SpawnGroup ) + self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) + + local GroupName = SpawnGroup:GetName() + if GroupName then + local SpawnPrefix = string.match( GroupName, ".*#" ) + if SpawnPrefix then + SpawnPrefix = SpawnPrefix:sub( 1, -2 ) + end + return SpawnPrefix + end + + return nil +end + + +--- Get the index from a given group. +-- The function will search the name of the group for a #, and will return the number behind the #-mark. +function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) + + local IndexString = string.match( SpawnGroup:GetName(), "#(%d*)$" ):sub( 2 ) + local Index = tonumber( IndexString ) + + self:T3( IndexString, Index ) + return Index + +end + +--- Return the last maximum index that can be used. +function SPAWN:_GetLastIndex() + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + + return self.SpawnMaxGroups +end + +--- Initalize the SpawnGroups collection. +-- @param #SPAWN self +function SPAWN:_InitializeSpawnGroups( SpawnIndex ) + self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) + + if not self.SpawnGroups[SpawnIndex] then + self.SpawnGroups[SpawnIndex] = {} + self.SpawnGroups[SpawnIndex].Visible = false + self.SpawnGroups[SpawnIndex].Spawned = false + self.SpawnGroups[SpawnIndex].UnControlled = false + self.SpawnGroups[SpawnIndex].SpawnTime = 0 + + self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefix + self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) + end + + self:_RandomizeTemplate( SpawnIndex ) + self:_RandomizeRoute( SpawnIndex ) + --self:_TranslateRotate( SpawnIndex ) + + return self.SpawnGroups[SpawnIndex] +end + + + +--- Gets the CategoryID of the Group with the given SpawnPrefix +function SPAWN:_GetGroupCategoryID( SpawnPrefix ) + local TemplateGroup = Group.getByName( SpawnPrefix ) + + if TemplateGroup then + return TemplateGroup:getCategory() + else + return nil + end +end + +--- Gets the CoalitionID of the Group with the given SpawnPrefix +function SPAWN:_GetGroupCoalitionID( SpawnPrefix ) + local TemplateGroup = Group.getByName( SpawnPrefix ) + + if TemplateGroup then + return TemplateGroup:getCoalition() + else + return nil + end +end + +--- Gets the CountryID of the Group with the given SpawnPrefix +function SPAWN:_GetGroupCountryID( SpawnPrefix ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) + + local TemplateGroup = Group.getByName( SpawnPrefix ) + + if TemplateGroup then + local TemplateUnits = TemplateGroup:getUnits() + return TemplateUnits[1]:getCountry() + else + return nil + end +end + +--- Gets the Group Template from the ME environment definition. +-- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE. +-- @param #SPAWN self +-- @param #string SpawnTemplatePrefix +-- @return @SPAWN self +function SPAWN:_GetTemplate( SpawnTemplatePrefix ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) + + local SpawnTemplate = nil + + SpawnTemplate = routines.utils.deepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template ) + + if SpawnTemplate == nil then + error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) + end + + --SpawnTemplate.SpawnCoalitionID = self:_GetGroupCoalitionID( SpawnTemplatePrefix ) + --SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnTemplatePrefix ) + --SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnTemplatePrefix ) + + self:T3( { SpawnTemplate } ) + return SpawnTemplate +end + +--- Prepares the new Group Template. +-- @param #SPAWN self +-- @param #string SpawnTemplatePrefix +-- @param #number SpawnIndex +-- @return #SPAWN self +function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) + + local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) + SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) + + SpawnTemplate.groupId = nil + --SpawnTemplate.lateActivation = false + SpawnTemplate.lateActivation = false + + if SpawnTemplate.CategoryID == Group.Category.GROUND then + self:T3( "For ground units, visible needs to be false..." ) + SpawnTemplate.visible = false + end + + if self.SpawnInitKeepUnitNames == false then + for UnitID = 1, #SpawnTemplate.units do + SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID ) + SpawnTemplate.units[UnitID].unitId = nil + end + else + for UnitID = 1, #SpawnTemplate.units do + local UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" ) + self:T( { UnitPrefix, Rest } ) + + SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID ) + SpawnTemplate.units[UnitID].unitId = nil + end + end + + self:T3( { "Template:", SpawnTemplate } ) + return SpawnTemplate + +end + +--- Private method randomizing the routes. +-- @param #SPAWN self +-- @param #number SpawnIndex The index of the group to be spawned. +-- @return #SPAWN +function SPAWN:_RandomizeRoute( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) + + if self.SpawnRandomizeRoute then + local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate + local RouteCount = #SpawnTemplate.route.points + + for t = self.SpawnRandomizeRouteStartPoint + 1, ( RouteCount - self.SpawnRandomizeRouteEndPoint ) do + + SpawnTemplate.route.points[t].x = SpawnTemplate.route.points[t].x + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) + SpawnTemplate.route.points[t].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) + + -- Manage randomization of altitude for airborne units ... + if SpawnTemplate.CategoryID == Group.Category.AIRPLANE or SpawnTemplate.CategoryID == Group.Category.HELICOPTER then + if SpawnTemplate.route.points[t].alt and self.SpawnRandomizeRouteHeight then + SpawnTemplate.route.points[t].alt = SpawnTemplate.route.points[t].alt + math.random( 1, self.SpawnRandomizeRouteHeight ) + end + else + SpawnTemplate.route.points[t].alt = nil + end + + self:T( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y ) + end + end + + self:_RandomizeZones( SpawnIndex ) + + return self +end + +--- Private method that randomizes the template of the group. +-- @param #SPAWN self +-- @param #number SpawnIndex +-- @return #SPAWN self +function SPAWN:_RandomizeTemplate( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeTemplate } ) + + if self.SpawnRandomizeTemplate then + self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] + self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.route = routines.utils.deepCopy( self.SpawnTemplate.route ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x + self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y + self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time + local OldX = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[1].x + local OldY = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[1].y + for UnitID = 1, #self.SpawnGroups[SpawnIndex].SpawnTemplate.units do + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].heading = self.SpawnTemplate.units[1].heading + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x = self.SpawnTemplate.units[1].x + ( self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x - OldX ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y = self.SpawnTemplate.units[1].y + ( self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y - OldY ) + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].alt = self.SpawnTemplate.units[1].alt + end + end + + self:_RandomizeRoute( SpawnIndex ) + + return self +end + +--- Private method that randomizes the @{Zone}s where the Group will be spawned. +-- @param #SPAWN self +-- @param #number SpawnIndex +-- @return #SPAWN self +function SPAWN:_RandomizeZones( SpawnIndex ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } ) + + if self.SpawnRandomizeZones then + local SpawnZone = nil -- Core.Zone#ZONE_BASE + while not SpawnZone do + self:T( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } ) + local ZoneID = math.random( #self.SpawnZoneTable ) + self:T( ZoneID ) + SpawnZone = self.SpawnZoneTable[ ZoneID ]:GetZoneMaybe() + end + + self:T( "Preparing Spawn in Zone", SpawnZone:GetName() ) + + local SpawnVec2 = SpawnZone:GetRandomVec2() + + self:T( { SpawnVec2 = SpawnVec2 } ) + + local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate + + self:T( { Route = SpawnTemplate.route } ) + + for UnitID = 1, #SpawnTemplate.units do + local UnitTemplate = SpawnTemplate.units[UnitID] + self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = SpawnVec2.x + ( SX - BX ) + local TY = SpawnVec2.y + ( SY - BY ) + UnitTemplate.x = TX + UnitTemplate.y = TY + -- TODO: Manage altitude based on landheight... + --SpawnTemplate.units[UnitID].alt = SpawnVec2: + self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) + end + SpawnTemplate.x = SpawnVec2.x + SpawnTemplate.y = SpawnVec2.y + SpawnTemplate.route.points[1].x = SpawnVec2.x + SpawnTemplate.route.points[1].y = SpawnVec2.y + end + + return self + +end + +function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) + self:F( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) + + -- Translate + local TranslatedX = SpawnX + local TranslatedY = SpawnY + + -- Rotate + -- From Wikipedia: https://en.wikipedia.org/wiki/Rotation_matrix#Common_rotations + -- x' = x \cos \theta - y \sin \theta\ + -- y' = x \sin \theta + y \cos \theta\ + local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) + + TranslatedY * math.sin( math.rad( SpawnAngle ) ) + local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) + + TranslatedY * math.cos( math.rad( SpawnAngle ) ) + + -- Assign + self.SpawnGroups[SpawnIndex].SpawnTemplate.x = SpawnRootX - RotatedX + self.SpawnGroups[SpawnIndex].SpawnTemplate.y = SpawnRootY + RotatedY + + + local SpawnUnitCount = table.getn( self.SpawnGroups[SpawnIndex].SpawnTemplate.units ) + for u = 1, SpawnUnitCount do + + -- Translate + local TranslatedX = SpawnX + local TranslatedY = SpawnY - 10 * ( u - 1 ) + + -- Rotate + local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) + + TranslatedY * math.sin( math.rad( SpawnAngle ) ) + local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) + + TranslatedY * math.cos( math.rad( SpawnAngle ) ) + + -- Assign + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].x = SpawnRootX - RotatedX + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].y = SpawnRootY + RotatedY + self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading + math.rad( SpawnAngle ) + end + + return self +end + +--- Get the next index of the groups to be spawned. This method is complicated, as it is used at several spaces. +function SPAWN:_GetSpawnIndex( SpawnIndex ) + self:F2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) + + if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then + if ( self.SpawnMaxUnitsAlive == 0 ) or ( self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive ) or self.UnControlled == true then + if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then + self.SpawnCount = self.SpawnCount + 1 + SpawnIndex = self.SpawnCount + end + self.SpawnIndex = SpawnIndex + if not self.SpawnGroups[self.SpawnIndex] then + self:_InitializeSpawnGroups( self.SpawnIndex ) + end + else + return nil + end + else + return nil + end + + return self.SpawnIndex +end + + +-- TODO Need to delete this... _DATABASE does this now ... + +--- @param #SPAWN self +-- @param Core.Event#EVENTDATA EventData +function SPAWN:_OnBirth( EventData ) + self:F( self.SpawnTemplatePrefix ) + + local SpawnGroup = EventData.IniGroup + + if SpawnGroup then + local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) + self:T( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self.AliveUnits = self.AliveUnits + 1 + self:T( "Alive Units: " .. self.AliveUnits ) + end + end + +end + +--- Obscolete +-- @todo Need to delete this... _DATABASE does this now ... + +--- @param #SPAWN self +-- @param Core.Event#EVENTDATA EventData +function SPAWN:_OnDeadOrCrash( EventData ) + self:F( self.SpawnTemplatePrefix ) + + local SpawnGroup = EventData.IniGroup + + if SpawnGroup then + local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) + self:T( { "Dead event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self.AliveUnits = self.AliveUnits - 1 + self:T( "Alive Units: " .. self.AliveUnits ) + end + end +end + +--- Will detect AIR Units taking off... When the event takes place, the spawned Group is registered as airborne... +-- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups. +-- @param #SPAWN self +-- @param Core.Event#EVENTDATA EventData +function SPAWN:_OnTakeOff( EventData ) + self:F( self.SpawnTemplatePrefix ) + + local SpawnGroup = EventData.IniGroup + if SpawnGroup then + local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) + self:T( { "TakeOff event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self:T( "self.Landed = false" ) + SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false ) + end + end +end + +--- Will detect AIR Units landing... When the event takes place, the spawned Group is registered as landed. +-- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups. +-- @param #SPAWN self +-- @param Core.Event#EVENTDATA EventData +function SPAWN:_OnLand( EventData ) + self:F( self.SpawnTemplatePrefix ) + + local SpawnGroup = EventData.IniGroup + if SpawnGroup then + local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) + self:T( { "Land event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + -- TODO: Check if this is the last unit of the group that lands. + SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true ) + if self.RepeatOnLanding then + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) + self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) + self:ReSpawn( SpawnGroupIndex ) + end + end + end +end + +--- Will detect AIR Units shutting down their engines ... +-- When the event takes place, and the method @{RepeatOnEngineShutDown} was called, the spawned Group will Re-SPAWN. +-- But only when the Unit was registered to have landed. +-- @param #SPAWN self +-- @param Core.Event#EVENTDATA EventData +function SPAWN:_OnEngineShutDown( EventData ) + self:F( self.SpawnTemplatePrefix ) + + local SpawnGroup = EventData.IniGroup + if SpawnGroup then + local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) + self:T( { "EngineShutdown event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + -- todo: test if on the runway + local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" ) + if Landed and self.RepeatOnEngineShutDown then + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) + self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) + self:ReSpawn( SpawnGroupIndex ) + end + end + end +end + +--- This function is called automatically by the Spawning scheduler. +-- It is the internal worker method SPAWNing new Groups on the defined time intervals. +function SPAWN:_Scheduler() + self:F2( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) + + -- Validate if there are still groups left in the batch... + self:Spawn() + + return true +end + +--- Schedules the CleanUp of Groups +-- @param #SPAWN self +-- @return #boolean True = Continue Scheduler +function SPAWN:_SpawnCleanUpScheduler() + self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) + + local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() + self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) + + while SpawnGroup do + + local SpawnUnits = SpawnGroup:GetUnits() + + for UnitID, UnitData in pairs( SpawnUnits ) do + + local SpawnUnit = UnitData -- Wrapper.Unit#UNIT + local SpawnUnitName = SpawnUnit:GetName() + + + self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {} + local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] + self:T( { SpawnUnitName, Stamp } ) + + if Stamp.Vec2 then + if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then + local NewVec2 = SpawnUnit:GetVec2() + if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then + -- If the plane is not moving, and is on the ground, assign it with a timestamp... + if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then + self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) + self:ReSpawn( SpawnCursor ) + Stamp.Vec2 = nil + Stamp.Time = nil + end + else + Stamp.Time = timer.getTime() + Stamp.Vec2 = SpawnUnit:GetVec2() + end + else + Stamp.Vec2 = nil + Stamp.Time = nil + end + else + if SpawnUnit:InAir() == false then + Stamp.Vec2 = SpawnUnit:GetVec2() + if SpawnUnit:GetVelocityKMH() < 1 then + Stamp.Time = timer.getTime() + end + else + Stamp.Time = nil + Stamp.Vec2 = nil + end + end + end + + SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor ) + + self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) + + end + + return true -- Repeat + +end +--- Limit the simultaneous movement of Groups within a running Mission. +-- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles. +-- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if +-- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units +-- on defined intervals (currently every minute). +-- @module Movement + +--- the MOVEMENT class +-- @type MOVEMENT +-- @extends Core.Base#BASE +MOVEMENT = { + ClassName = "MOVEMENT", +} + +--- Creates the main object which is handling the GROUND forces movement. +-- @param table{string,...}|string MovePrefixes is a table of the Prefixes (names) of the GROUND Groups that need to be controlled by the MOVEMENT Object. +-- @param number MoveMaximum is a number that defines the maximum amount of GROUND Units to be moving during one minute. +-- @return MOVEMENT +-- @usage +-- -- Limit the amount of simultaneous moving units on the ground to prevent lag. +-- Movement_US_Platoons = MOVEMENT:New( { 'US Tank Platoon Left', 'US Tank Platoon Middle', 'US Tank Platoon Right', 'US CH-47D Troops' }, 15 ) + +function MOVEMENT:New( MovePrefixes, MoveMaximum ) + local self = BASE:Inherit( self, BASE:New() ) -- #MOVEMENT + self:F( { MovePrefixes, MoveMaximum } ) + + if type( MovePrefixes ) == 'table' then + self.MovePrefixes = MovePrefixes + else + self.MovePrefixes = { MovePrefixes } + end + self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart. + self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move... + self.AliveUnits = 0 -- Contains the counter how many units are currently alive + self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not. + + self:HandleEvent( EVENTS.Birth ) + +-- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth ) +-- +-- self:EnableEvents() + + self:ScheduleStart() + + return self +end + +--- Call this function to start the MOVEMENT scheduling. +function MOVEMENT:ScheduleStart() + self:F() + --self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) + self.MoveFunction = SCHEDULER:New( self, self._Scheduler, {}, 1, 120 ) +end + +--- Call this function to stop the MOVEMENT scheduling. +-- @todo need to implement it ... Forgot. +function MOVEMENT:ScheduleStop() + self:F() + +end + +--- Captures the birth events when new Units were spawned. +-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. +-- @param #MOVEMENT self +-- @param Core.Event#EVENTDATA self +function MOVEMENT:OnEventBirth( EventData ) + self:F( { EventData } ) + + if 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 + if EventData.IniDCSUnit then + self:T( "Birth object : " .. EventData.IniDCSUnitName ) + if EventData.IniDCSGroup and EventData.IniDCSGroup:isExist() then + for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do + if string.find( EventData.IniDCSUnitName, MovePrefix, 1, true ) then + self.AliveUnits = self.AliveUnits + 1 + self.MoveUnits[EventData.IniDCSUnitName] = EventData.IniDCSGroupName + self:T( self.AliveUnits ) + end + end + end + end + + EventData.IniUnit:HandleEvent( EVENTS.DEAD, self.OnDeadOrCrash ) + end + +end + +--- Captures the Dead or Crash events when Units crash or are destroyed. +-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. +function MOVEMENT:OnDeadOrCrash( Event ) + self:F( { Event } ) + + if Event.IniDCSUnit then + self:T( "Dead object : " .. Event.IniDCSUnitName ) + for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do + if string.find( Event.IniDCSUnitName, MovePrefix, 1, true ) then + self.AliveUnits = self.AliveUnits - 1 + self.MoveUnits[Event.IniDCSUnitName] = nil + self:T( self.AliveUnits ) + end + end + end +end + +--- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true. +function MOVEMENT:_Scheduler() + self:F( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) + + if self.AliveUnits > 0 then + local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits + self:T( 'Move Probability = ' .. MoveProbability ) + + for MovementUnitName, MovementGroupName in pairs( self.MoveUnits ) do + local MovementGroup = Group.getByName( MovementGroupName ) + if MovementGroup and MovementGroup:isExist() then + local MoveOrStop = math.random( 1, 100 ) + self:T( 'MoveOrStop = ' .. MoveOrStop ) + if MoveOrStop <= MoveProbability then + self:T( 'Group continues moving = ' .. MovementGroupName ) + trigger.action.groupContinueMoving( MovementGroup ) + else + self:T( 'Group stops moving = ' .. MovementGroupName ) + trigger.action.groupStopMoving( MovementGroup ) + end + else + self.MoveUnits[MovementUnitName] = nil + end + end + end + return true +end +--- Provides defensive behaviour to a set of SAM sites within a running Mission. +-- @module Sead +-- @author to be searched on the forum +-- @author (co) Flightcontrol (Modified and enriched with functionality) + +--- The SEAD class +-- @type SEAD +-- @extends Core.Base#BASE +SEAD = { + ClassName = "SEAD", + TargetSkill = { + Average = { Evade = 50, DelayOff = { 10, 25 }, DelayOn = { 10, 30 } } , + Good = { Evade = 30, DelayOff = { 8, 20 }, DelayOn = { 20, 40 } } , + High = { Evade = 15, DelayOff = { 5, 17 }, DelayOn = { 30, 50 } } , + Excellent = { Evade = 10, DelayOff = { 3, 10 }, DelayOn = { 30, 60 } } + }, + SEADGroupPrefixes = {} +} + +--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. +-- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions... +-- Chances are big that the missile will miss. +-- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCSRTE on which evasive actions need to be taken. +-- @return SEAD +-- @usage +-- -- CCCP SEAD Defenses +-- -- Defends the Russian SA installations from SEAD attacks. +-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) +function SEAD:New( SEADGroupPrefixes ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( SEADGroupPrefixes ) + if type( SEADGroupPrefixes ) == 'table' then + for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do + self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix + end + else + self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes + end + + self:HandleEvent( EVENTS.Shot ) + + return self +end + +--- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. +-- @see SEAD +-- @param #SEAD +-- @param Core.Event#EVENTDATA EventData +function SEAD:OnEventShot( EventData ) + self:F( { EventData } ) + + local SEADUnit = EventData.IniDCSUnit + local SEADUnitName = EventData.IniDCSUnitName + local SEADWeapon = EventData.Weapon -- Identify the weapon fired + local SEADWeaponName = EventData.WeaponName -- return weapon type + -- Start of the 2nd loop + self:T( "Missile Launched = " .. SEADWeaponName ) + if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD + local _evade = math.random (1,100) -- random number for chance of evading action + local _targetMim = EventData.Weapon:getTarget() -- Identify target + local _targetMimname = Unit.getName(_targetMim) + local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) + local _targetMimgroupName = _targetMimgroup:getName() + local _targetMimcont= _targetMimgroup:getController() + local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill + self:T( self.SEADGroupPrefixes ) + self:T( _targetMimgroupName ) + local SEADGroupFound = false + for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do + if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then + SEADGroupFound = true + self:T( 'Group Found' ) + break + end + end + if SEADGroupFound == true then + if _targetskill == "Random" then -- when skill is random, choose a skill + local Skills = { "Average", "Good", "High", "Excellent" } + _targetskill = Skills[ math.random(1,4) ] + end + self:T( _targetskill ) + if self.TargetSkill[_targetskill] then + if (_evade > self.TargetSkill[_targetskill].Evade) then + self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) + local _targetMim = Weapon.getTarget(SEADWeapon) + local _targetMimname = Unit.getName(_targetMim) + local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) + local _targetMimcont= _targetMimgroup:getController() + routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly + local SuppressedGroups1 = {} -- unit suppressed radar off for a random time + local function SuppressionEnd1(id) + id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) + SuppressedGroups1[id.groupName] = nil + end + local id = { + groupName = _targetMimgroup, + ctrl = _targetMimcont + } + local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2]) + if SuppressedGroups1[id.groupName] == nil then + SuppressedGroups1[id.groupName] = { + SuppressionEndTime1 = timer.getTime() + delay1, + SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function + } + Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) + timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function + --trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20) + end + + local SuppressedGroups = {} + local function SuppressionEnd(id) + id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) + SuppressedGroups[id.groupName] = nil + end + local id = { + groupName = _targetMimgroup, + ctrl = _targetMimcont + } + local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) + if SuppressedGroups[id.groupName] == nil then + SuppressedGroups[id.groupName] = { + SuppressionEndTime = timer.getTime() + delay, + SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function + } + timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function + --trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20) + end + end + end + end + end +end +--- Taking the lead of AI escorting your flight. +-- +-- @{#ESCORT} class +-- ================ +-- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead. +-- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). +-- +-- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. +-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. +-- +-- RADIO MENUs that can be created: +-- ================================ +-- Find a summary below of the current available commands: +-- +-- Navigation ...: +-- --------------- +-- Escort group navigation functions: +-- +-- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. +-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. +-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. +-- +-- Hold position ...: +-- ------------------ +-- Escort group navigation functions: +-- +-- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. +-- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. +-- +-- Report targets ...: +-- ------------------- +-- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). +-- +-- * **"Report now":** Will report the current detected targets. +-- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. +-- * **"Report targets off":** Will stop detecting targets. +-- +-- Scan targets ...: +-- ----------------- +-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. +-- +-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. +-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. +-- +-- Attack targets ...: +-- ------------------- +-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. +-- +-- Request assistance from ...: +-- ---------------------------- +-- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. +-- This menu item allows to request attack support from other escorts supporting the current client group. +-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. +-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. +-- +-- ROE ...: +-- -------- +-- Sets the Rules of Engagement (ROE) of the escort group when in flight. +-- +-- * **"Hold Fire":** The escort group will hold fire. +-- * **"Return Fire":** The escort group will return fire. +-- * **"Open Fire":** The escort group will open fire on designated targets. +-- * **"Weapon Free":** The escort group will engage with any target. +-- +-- Evasion ...: +-- ------------ +-- Will define the evasion techniques that the escort group will perform during flight or combat. +-- +-- * **"Fight until death":** The escort group will have no reaction to threats. +-- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed. +-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. +-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. +-- +-- Resume Mission ...: +-- ------------------- +-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. +-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. +-- +-- ESCORT construction methods. +-- ============================ +-- Create a new SPAWN object with the @{#ESCORT.New} method: +-- +-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text. +-- +-- ESCORT initialization methods. +-- ============================== +-- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player: +-- +-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client. +-- * @{#ESCORT.MenuHoldAtEscortPosition}: Creates a menu to hold the escort at its current position. +-- * @{#ESCORT.MenuHoldAtLeaderPosition}: Creates a menu to hold the escort at the client position. +-- * @{#ESCORT.MenuScanForTargets}: Creates a menu so that the escort scans targets. +-- * @{#ESCORT.MenuFlare}: Creates a menu to disperse flares. +-- * @{#ESCORT.MenuSmoke}: Creates a menu to disparse smoke. +-- * @{#ESCORT.MenuReportTargets}: Creates a menu so that the escort reports targets. +-- * @{#ESCORT.MenuReportPosition}: Creates a menu so that the escort reports its current position from bullseye. +-- * @{#ESCORT.MenuAssistedAttack: Creates a menu so that the escort supportes assisted attack from other escorts with the client. +-- * @{#ESCORT.MenuROE: Creates a menu structure to set the rules of engagement of the escort. +-- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat. +-- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint. +-- +-- +-- @usage +-- -- Declare a new EscortPlanes object as follows: +-- +-- -- First find the GROUP object and the CLIENT object. +-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. +-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. +-- +-- -- Now use these 2 objects to construct the new EscortPlanes object. +-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +-- +-- +-- +-- @module Escort +-- @author FlightControl + +--- ESCORT class +-- @type ESCORT +-- @extends Core.Base#BASE +-- @field Wrapper.Client#CLIENT EscortClient +-- @field Wrapper.Group#GROUP EscortGroup +-- @field #string EscortName +-- @field #ESCORT.MODE EscortMode The mode the escort is in. +-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. +-- @field #number FollowDistance The current follow distance. +-- @field #boolean ReportTargets If true, nearby targets are reported. +-- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. +-- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. +-- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission +-- @field Functional.Detection#DETECTION_BASE Detection +ESCORT = { + ClassName = "ESCORT", + EscortName = nil, -- The Escort Name + EscortClient = nil, + EscortGroup = nil, + EscortMode = 1, + MODE = { + FOLLOW = 1, + MISSION = 2, + }, + Targets = {}, -- The identified targets + FollowScheduler = nil, + ReportTargets = true, + OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, + OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, + SmokeDirectionVector = false, + TaskPoints = {} +} + +--- ESCORT.Mode class +-- @type ESCORT.MODE +-- @field #number FOLLOW +-- @field #number MISSION + +--- MENUPARAM type +-- @type MENUPARAM +-- @field #ESCORT ParamSelf +-- @field #Distance ParamDistance +-- @field #function ParamFunction +-- @field #string ParamMessage + +--- ESCORT class constructor for an AI group +-- @param #ESCORT self +-- @param Wrapper.Client#CLIENT EscortClient The client escorted by the EscortGroup. +-- @param Wrapper.Group#GROUP EscortGroup The group AI escorting the EscortClient. +-- @param #string EscortName Name of the escort. +-- @param #string EscortBriefing A text showing the ESCORT briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. +-- @return #ESCORT self +-- @usage +-- -- Declare a new EscortPlanes object as follows: +-- +-- -- First find the GROUP object and the CLIENT object. +-- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. +-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. +-- +-- -- Now use these 2 objects to construct the new EscortPlanes object. +-- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing ) + + local self = BASE:Inherit( self, BASE:New() ) -- #ESCORT + self:F( { EscortClient, EscortGroup, EscortName } ) + + self.EscortClient = EscortClient -- Wrapper.Client#CLIENT + self.EscortGroup = EscortGroup -- Wrapper.Group#GROUP + self.EscortName = EscortName + self.EscortBriefing = EscortBriefing + + self.EscortSetGroup = SET_GROUP:New() + self.EscortSetGroup:AddObject( self.EscortGroup ) + self.EscortSetGroup:Flush() + self.Detection = DETECTION_UNITS:New( self.EscortSetGroup, 15000 ) + + self.EscortGroup.Detection = self.Detection + + -- Set EscortGroup known at EscortClient. + if not self.EscortClient._EscortGroups then + self.EscortClient._EscortGroups = {} + end + + if not self.EscortClient._EscortGroups[EscortGroup:GetName()] then + self.EscortClient._EscortGroups[EscortGroup:GetName()] = {} + self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup + self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName + self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection = self.EscortGroup.Detection + end + + self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName ) + + self.EscortGroup:WayPointInitialize(1) + + self.EscortGroup:OptionROTVertical() + self.EscortGroup:OptionROEOpenFire() + + if not EscortBriefing then + EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. + "We're escorting your flight. " .. + "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n", + 60, EscortClient + ) + else + EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") " .. EscortBriefing, + 60, EscortClient + ) + end + + self.FollowDistance = 100 + self.CT1 = 0 + self.GT1 = 0 + + self.FollowScheduler, self.FollowSchedule = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 ) + self.FollowScheduler:Stop( self.FollowSchedule ) + + self.EscortMode = ESCORT.MODE.MISSION + + + return self +end + +--- Set a Detection method for the EscortClient to be reported upon. +-- Detection methods are based on the derived classes from DETECTION_BASE. +-- @param #ESCORT self +-- @param Function.Detection#DETECTION_BASE Detection +function ESCORT:SetDetection( Detection ) + + self.Detection = Detection + self.EscortGroup.Detection = self.Detection + self.EscortClient._EscortGroups[self.EscortGroup:GetName()].Detection = self.EscortGroup.Detection + + Detection:__Start( 1 ) + +end + +--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to. +-- This allows to visualize where the escort is flying to. +-- @param #ESCORT self +-- @param #boolean SmokeDirection If true, then the direction vector will be smoked. +function ESCORT:TestSmokeDirectionVector( SmokeDirection ) + self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false +end + + +--- Defines the default menus +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:Menus() + self:F() + + self:MenuFollowAt( 100 ) + self:MenuFollowAt( 200 ) + self:MenuFollowAt( 300 ) + self:MenuFollowAt( 400 ) + + self:MenuScanForTargets( 100, 60 ) + + self:MenuHoldAtEscortPosition( 30 ) + self:MenuHoldAtLeaderPosition( 30 ) + + self:MenuFlare() + self:MenuSmoke() + + self:MenuReportTargets( 60 ) + self:MenuAssistedAttack() + self:MenuROE() + self:MenuEvasion() + self:MenuResumeMission() + + + return self +end + + + +--- Defines a menu slot to let the escort Join and Follow you at a certain distance. +-- This menu will appear under **Navigation**. +-- @param #ESCORT self +-- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client. +-- @return #ESCORT +function ESCORT:MenuFollowAt( Distance ) + self:F(Distance) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + if not self.EscortMenuJoinUpAndFollow then + self.EscortMenuJoinUpAndFollow = {} + end + + self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance ) + + self.EscortMode = ESCORT.MODE.FOLLOW + end + + return self +end + +--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. +-- This menu will appear under **Hold position**. +-- @param #ESCORT self +-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. +function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + + if not self.EscortMenuHold then + self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) + end + + if not Height then + Height = 30 + end + + if not Seconds then + Seconds = 0 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "Hold at %d meter", Height ) + else + MenuText = string.format( "Hold at %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuHoldPosition then + self.EscortMenuHoldPosition = {} + end + + self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuHold, + ESCORT._HoldPosition, + self, + self.EscortGroup, + Height, + Seconds + ) + end + + return self +end + + +--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. +-- This menu will appear under **Navigation**. +-- @param #ESCORT self +-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. +function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + + if not self.EscortMenuHold then + self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) + end + + if not Height then + Height = 30 + end + + if not Seconds then + Seconds = 0 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "Rejoin and hold at %d meter", Height ) + else + MenuText = string.format( "Rejoin and hold at %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuHoldAtLeaderPosition then + self.EscortMenuHoldAtLeaderPosition = {} + end + + self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuHold, + ESCORT._HoldPosition, + { ParamSelf = self, + ParamOrbitGroup = self.EscortClient, + ParamHeight = Height, + ParamSeconds = Seconds + } + ) + end + + return self +end + +--- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds. +-- This menu will appear under **Scan targets**. +-- @param #ESCORT self +-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. +-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) + self:F( { Height, Seconds, MenuTextFormat } ) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuScan then + self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu ) + end + + if not Height then + Height = 100 + end + + if not Seconds then + Seconds = 30 + end + + local MenuText = "" + if not MenuTextFormat then + if Seconds == 0 then + MenuText = string.format( "At %d meter", Height ) + else + MenuText = string.format( "At %d meter for %d seconds", Height, Seconds ) + end + else + if Seconds == 0 then + MenuText = string.format( MenuTextFormat, Height ) + else + MenuText = string.format( MenuTextFormat, Height, Seconds ) + end + end + + if not self.EscortMenuScanForTargets then + self.EscortMenuScanForTargets = {} + end + + self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND + :New( + self.EscortClient, + MenuText, + self.EscortMenuScan, + ESCORT._ScanTargets, + self, + 30 + ) + end + + return self +end + + + +--- Defines a menu slot to let the escort disperse a flare in a certain color. +-- This menu will appear under **Navigation**. +-- The flare will be fired from the first unit in the group. +-- @param #ESCORT self +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuFlare( MenuTextFormat ) + self:F() + + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Flare" + else + MenuText = MenuTextFormat + end + + if not self.EscortMenuFlare then + self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self ) + self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" ) + self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" ) + self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" ) + self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" ) + end + + return self +end + +--- Defines a menu slot to let the escort disperse a smoke in a certain color. +-- This menu will appear under **Navigation**. +-- Note that smoke menu options will only be displayed for ships and ground units. Not for air units. +-- The smoke will be fired from the first unit in the group. +-- @param #ESCORT self +-- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. +-- @return #ESCORT +function ESCORT:MenuSmoke( MenuTextFormat ) + self:F() + + if not self.EscortGroup:IsAir() then + if not self.EscortMenuReportNavigation then + self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) + end + + local MenuText = "" + if not MenuTextFormat then + MenuText = "Smoke" + else + MenuText = MenuTextFormat + end + + if not self.EscortMenuSmoke then + self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self ) + self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" ) + self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" ) + self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" ) + self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" ) + self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" ) + end + end + + return self +end + +--- Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds. +-- This menu will appear under **Report targets**. +-- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. +-- @param #ESCORT self +-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. +-- @return #ESCORT +function ESCORT:MenuReportTargets( Seconds ) + self:F( { Seconds } ) + + if not self.EscortMenuReportNearbyTargets then + self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) + end + + if not Seconds then + Seconds = 30 + end + + -- Report Targets + self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self ) + self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true ) + self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false ) + + -- Attack Targets + self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) + + + self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) + + return self +end + +--- Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client. +-- This menu will appear under **Request assistance from**. +-- Note that this method needs to be preceded with the method MenuReportTargets. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuAssistedAttack() + self:F() + + -- Request assistance from other escorts. + -- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane... + self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu ) + + return self +end + +--- Defines a menu to let the escort set its rules of engagement. +-- All rules of engagement will appear under the menu **ROE**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuROE( MenuTextFormat ) + self:F( MenuTextFormat ) + + if not self.EscortMenuROE then + -- Rules of Engagement + self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) + if self.EscortGroup:OptionROEHoldFirePossible() then + self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" ) + end + if self.EscortGroup:OptionROEReturnFirePossible() then + self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" ) + end + if self.EscortGroup:OptionROEOpenFirePossible() then + self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" ) + end + if self.EscortGroup:OptionROEWeaponFreePossible() then + self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" ) + end + end + + return self +end + + +--- Defines a menu to let the escort set its evasion when under threat. +-- All rules of engagement will appear under the menu **Evasion**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuEvasion( MenuTextFormat ) + self:F( MenuTextFormat ) + + if self.EscortGroup:IsAir() then + if not self.EscortMenuEvasion then + -- Reaction to Threats + self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) + if self.EscortGroup:OptionROTNoReactionPossible() then + self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" ) + end + if self.EscortGroup:OptionROTPassiveDefensePossible() then + self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" ) + end + if self.EscortGroup:OptionROTEvadeFirePossible() then + self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" ) + end + if self.EscortGroup:OptionROTVerticalPossible() then + self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" ) + end + end + end + + return self +end + +--- Defines a menu to let the escort resume its mission from a waypoint on its route. +-- All rules of engagement will appear under the menu **Resume mission from**. +-- @param #ESCORT self +-- @return #ESCORT +function ESCORT:MenuResumeMission() + self:F() + + if not self.EscortMenuResumeMission then + -- Mission Resume Menu Root + self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu ) + end + + return self +end + + +--- @param #MENUPARAM MenuParam +function ESCORT:_HoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + local OrbitUnit = OrbitGroup:GetUnit(1) -- Wrapper.Unit#UNIT + + self.FollowScheduler:Stop( self.FollowSchedule ) + + local PointFrom = {} + local GroupVec3 = EscortGroup:GetUnit(1):GetVec3() + PointFrom = {} + PointFrom.x = GroupVec3.x + PointFrom.y = GroupVec3.z + PointFrom.speed = 250 + PointFrom.type = AI.Task.WaypointType.TURNING_POINT + PointFrom.alt = GroupVec3.y + PointFrom.alt_type = AI.Task.AltitudeType.BARO + + local OrbitPoint = OrbitUnit:GetVec2() + local PointTo = {} + PointTo.x = OrbitPoint.x + PointTo.y = OrbitPoint.y + PointTo.speed = 250 + PointTo.type = AI.Task.WaypointType.TURNING_POINT + PointTo.alt = OrbitHeight + PointTo.alt_type = AI.Task.AltitudeType.BARO + PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( OrbitPoint, OrbitHeight, 0 ) + + local Points = { PointFrom, PointTo } + + EscortGroup:OptionROEHoldFire() + EscortGroup:OptionROTPassiveDefense() + + EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) ) + EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient ) + +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_JoinUpAndFollow( Distance ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self.Distance = Distance + + self:JoinUpAndFollow( EscortGroup, EscortClient, self.Distance ) +end + +--- JoinsUp and Follows a CLIENT. +-- @param Functional.Escort#ESCORT self +-- @param Wrapper.Group#GROUP EscortGroup +-- @param Wrapper.Client#CLIENT EscortClient +-- @param Dcs.DCSTypes#Distance Distance +function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) + self:F( { EscortGroup, EscortClient, Distance } ) + + self.FollowScheduler:Stop( self.FollowSchedule ) + + EscortGroup:OptionROEHoldFire() + EscortGroup:OptionROTPassiveDefense() + + self.EscortMode = ESCORT.MODE.FOLLOW + + self.CT1 = 0 + self.GT1 = 0 + self.FollowScheduler:Start( self.FollowSchedule ) + + EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_Flare( Color, Message ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + EscortGroup:GetUnit(1):Flare( Color ) + EscortGroup:MessageToClient( Message, 10, EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_Smoke( Color, Message ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + EscortGroup:GetUnit(1):Smoke( Color ) + EscortGroup:MessageToClient( Message, 10, EscortClient ) +end + + +--- @param #MENUPARAM MenuParam +function ESCORT:_ReportNearbyTargetsNow() + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self:_ReportTargetsScheduler() + +end + +function ESCORT:_SwitchReportNearbyTargets( ReportTargets ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self.ReportTargets = ReportTargets + + if self.ReportTargets then + if not self.ReportTargetsScheduler then + self.ReportTargetsScheduler:Schedule( self, self._ReportTargetsScheduler, {}, 1, 30 ) + end + else + routines.removeFunction( self.ReportTargetsScheduler ) + self.ReportTargetsScheduler = nil + end +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_ScanTargets( ScanDuration ) + + local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP + local EscortClient = self.EscortClient + + self.FollowScheduler:Stop( self.FollowSchedule ) + + if EscortGroup:IsHelicopter() then + EscortGroup:PushTask( + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 200, 20 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) + ), 1 ) + elseif EscortGroup:IsAirPlane() then + EscortGroup:PushTask( + EscortGroup:TaskControlled( + EscortGroup:TaskOrbitCircle( 1000, 500 ), + EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) + ), 1 ) + end + + EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient ) + + if self.EscortMode == ESCORT.MODE.FOLLOW then + self.FollowScheduler:Start( self.FollowSchedule ) + end + +end + +--- @param Wrapper.Group#GROUP EscortGroup +function _Resume( EscortGroup ) + env.info( '_Resume' ) + + local Escort = EscortGroup:GetState( EscortGroup, "Escort" ) + env.info( "EscortMode = " .. Escort.EscortMode ) + if Escort.EscortMode == ESCORT.MODE.FOLLOW then + Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance ) + end + +end + +--- @param #ESCORT self +-- @param #number DetectedItemID +function ESCORT:_AttackTarget( DetectedItemID ) + + local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP + self:E( EscortGroup ) + + local EscortClient = self.EscortClient + + self.FollowScheduler:Stop( self.FollowSchedule ) + + if EscortGroup:IsAir() then + EscortGroup:OptionROEOpenFire() + EscortGroup:OptionROTPassiveDefense() + EscortGroup:SetState( EscortGroup, "Escort", self ) + + local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID ) + + local Tasks = {} + + DetectedSet:ForEachUnit( + --- @param Wrapper.Unit#UNIT DetectedUnit + function( DetectedUnit, Tasks ) + if DetectedUnit:IsAlive() then + Tasks[#Tasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit ) + end + end, Tasks + ) + + Tasks[#Tasks+1] = EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } ) + + EscortGroup:SetTask( + EscortGroup:TaskCombo( + Tasks + ), 1 + ) + + else + + local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID ) + + local Tasks = {} + + DetectedSet:ForEachUnit( + --- @param Wrapper.Unit#UNIT DetectedUnit + function( DetectedUnit, Tasks ) + if DetectedUnit:IsAlive() then + Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 ) + end + end, Tasks + ) + + EscortGroup:SetTask( + EscortGroup:TaskCombo( + Tasks + ), 1 + ) + + end + + EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient ) + +end + +--- +-- @param #number DetectedItemID +function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self.FollowScheduler:Stop( self.FollowSchedule ) + + if EscortGroupAttack:IsAir() then + EscortGroupAttack:OptionROEOpenFire() + EscortGroupAttack:OptionROTVertical() + + local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID ) + + local Tasks = {} + + DetectedSet:ForEachUnit( + --- @param Wrapper.Unit#UNIT DetectedUnit + function( DetectedUnit, Tasks ) + if DetectedUnit:IsAlive() then + Tasks[#Tasks+1] = EscortGroupAttack:TaskAttackUnit( DetectedUnit ) + end + end, Tasks + ) + + Tasks[#Tasks+1] = EscortGroupAttack:TaskOrbitCircle( 500, 350 ) + + EscortGroupAttack:SetTask( + EscortGroupAttack:TaskCombo( + Tasks + ), 1 + ) + + else + local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID ) + + local Tasks = {} + + DetectedSet:ForEachUnit( + --- @param Wrapper.Unit#UNIT DetectedUnit + function( DetectedUnit, Tasks ) + if DetectedUnit:IsAlive() then + Tasks[#Tasks+1] = EscortGroupAttack:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 ) + end + end, Tasks + ) + + EscortGroupAttack:SetTask( + EscortGroupAttack:TaskCombo( + Tasks + ), 1 + ) + + end + + EscortGroupAttack:MessageToClient( "Assisting with the destroying the enemy unit!", 10, EscortClient ) + +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_ROE( EscortROEFunction, EscortROEMessage ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + pcall( function() EscortROEFunction() end ) + EscortGroup:MessageToClient( EscortROEMessage, 10, EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_ROT( EscortROTFunction, EscortROTMessage ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + pcall( function() EscortROTFunction() end ) + EscortGroup:MessageToClient( EscortROTMessage, 10, EscortClient ) +end + +--- @param #MENUPARAM MenuParam +function ESCORT:_ResumeMission( WayPoint ) + + local EscortGroup = self.EscortGroup + local EscortClient = self.EscortClient + + self.FollowScheduler:Stop( self.FollowSchedule ) + + local WayPoints = EscortGroup:GetTaskRoute() + self:T( WayPoint, WayPoints ) + + for WayPointIgnore = 1, WayPoint do + table.remove( WayPoints, 1 ) + end + + SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) + + EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) +end + +--- Registers the waypoints +-- @param #ESCORT self +-- @return #table +function ESCORT:RegisterRoute() + self:F() + + local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP + + local TaskPoints = EscortGroup:GetTaskRoute() + + self:T( TaskPoints ) + + return TaskPoints +end + +--- @param Functional.Escort#ESCORT self +function ESCORT:_FollowScheduler() + self:F( { self.FollowDistance } ) + + self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } ) + if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then + + local ClientUnit = self.EscortClient:GetClientGroupUnit() + local GroupUnit = self.EscortGroup:GetUnit( 1 ) + local FollowDistance = self.FollowDistance + + self:T( {ClientUnit.UnitName, GroupUnit.UnitName } ) + + if self.CT1 == 0 and self.GT1 == 0 then + self.CV1 = ClientUnit:GetVec3() + self:T( { "self.CV1", self.CV1 } ) + self.CT1 = timer.getTime() + self.GV1 = GroupUnit:GetVec3() + self.GT1 = timer.getTime() + else + local CT1 = self.CT1 + local CT2 = timer.getTime() + local CV1 = self.CV1 + local CV2 = ClientUnit:GetVec3() + self.CT1 = CT2 + self.CV1 = CV2 + + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 + local CT = CT2 - CT1 + + local CS = ( 3600 / CT ) * ( CD / 1000 ) + + self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + + local GT1 = self.GT1 + local GT2 = timer.getTime() + local GV1 = self.GV1 + local GV2 = GroupUnit:GetVec3() + self.GT1 = GT2 + self.GV1 = GV2 + + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 + local GT = GT2 - GT1 + + local GS = ( 3600 / GT ) * ( GD / 1000 ) + + self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + + -- Calculate the group direction vector + local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } + + -- Calculate GH2, GH2 with the same height as CV2. + local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } + + -- Calculate the angle of GV to the orthonormal plane + local alpha = math.atan2( GV.z, GV.x ) + + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) + local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + y = GH2.y, + z = CV2.z + FollowDistance * math.sin(alpha), + } + + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. + local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } + + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. + -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. + -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... + local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } + + -- Now we can calculate the group destination vector GDV. + local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } + + if self.SmokeDirectionVector == true then + trigger.action.smoke( GDV, trigger.smokeColor.Red ) + end + + self:T2( { "CV2:", CV2 } ) + self:T2( { "CVI:", CVI } ) + self:T2( { "GDV:", GDV } ) + + -- Measure distance between client and group + local CatchUpDistance = ( ( GDV.x - GV2.x )^2 + ( GDV.y - GV2.y )^2 + ( GDV.z - GV2.z )^2 ) ^ 0.5 + + -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome + -- the requested Distance). + local Time = 10 + local CatchUpSpeed = ( CatchUpDistance - ( CS * 8.4 ) ) / Time + + local Speed = CS + CatchUpSpeed + if Speed < 0 then + Speed = 0 + end + + self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } ) + + -- Now route the escort to the desired point with the desired speed. + self.EscortGroup:RouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) + end + + return true + end + + return false +end + + +--- Report Targets Scheduler. +-- @param #ESCORT self +function ESCORT:_ReportTargetsScheduler() + self:F( self.EscortGroup:GetName() ) + + if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then + + if true then + + local EscortGroupName = self.EscortGroup:GetName() + + self.EscortMenuAttackNearbyTargets:RemoveSubMenus() + + if self.EscortMenuTargetAssistance then + self.EscortMenuTargetAssistance:RemoveSubMenus() + end + + local DetectedItems = self.Detection:GetDetectedItems() + self:E( DetectedItems ) + + local DetectedTargets = false + + local DetectedMsgs = {} + + for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do + + local ClientEscortTargets = EscortGroupData.Detection + + for DetectedItemID, DetectedItem in ipairs( DetectedItems ) do + self:E( { DetectedItemID, DetectedItem } ) + -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup. + + local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID ) + + if ClientEscortGroupName == EscortGroupName then + + DetectedMsgs[#DetectedMsgs+1] = DetectedItemReportSummary + + MENU_CLIENT_COMMAND:New( self.EscortClient, + DetectedItemReportSummary, + self.EscortMenuAttackNearbyTargets, + ESCORT._AttackTarget, + self, + DetectedItemID + ) + else + if self.EscortMenuTargetAssistance then + + self:T( DetectedItemReportSummary ) + local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) + MENU_CLIENT_COMMAND:New( self.EscortClient, + DetectedItemReportSummary, + MenuTargetAssistance, + ESCORT._AssistTarget, + self, + EscortGroupData.EscortGroup, + DetectedItemID + ) + end + end + + DetectedTargets = true + + end + end + self:E( DetectedMsgs ) + if DetectedTargets then + self.EscortGroup:MessageToClient( "Detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient ) + else + self.EscortGroup:MessageToClient( "No targets detected.", 10, self.EscortClient ) + end + + return true + else +-- local EscortGroupName = self.EscortGroup:GetName() +-- local EscortTargets = self.EscortGroup:GetDetectedTargets() +-- +-- local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets +-- +-- local EscortTargetMessages = "" +-- for EscortTargetID, EscortTarget in pairs( EscortTargets ) do +-- local EscortObject = EscortTarget.object +-- self:T( EscortObject ) +-- if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then +-- +-- local EscortTargetUnit = UNIT:Find( EscortObject ) +-- local EscortTargetUnitName = EscortTargetUnit:GetName() +-- +-- +-- +-- -- local EscortTargetIsDetected, +-- -- EscortTargetIsVisible, +-- -- EscortTargetLastTime, +-- -- EscortTargetKnowType, +-- -- EscortTargetKnowDistance, +-- -- EscortTargetLastPos, +-- -- EscortTargetLastVelocity +-- -- = self.EscortGroup:IsTargetDetected( EscortObject ) +-- -- +-- -- self:T( { EscortTargetIsDetected, +-- -- EscortTargetIsVisible, +-- -- EscortTargetLastTime, +-- -- EscortTargetKnowType, +-- -- EscortTargetKnowDistance, +-- -- EscortTargetLastPos, +-- -- EscortTargetLastVelocity } ) +-- +-- +-- local EscortTargetUnitVec3 = EscortTargetUnit:GetVec3() +-- local EscortVec3 = self.EscortGroup:GetVec3() +-- local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + +-- ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + +-- ( EscortTargetUnitVec3.z - EscortVec3.z )^2 +-- ) ^ 0.5 / 1000 +-- +-- self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } ) +-- +-- if Distance <= 15 then +-- +-- if not ClientEscortTargets[EscortTargetUnitName] then +-- ClientEscortTargets[EscortTargetUnitName] = {} +-- end +-- ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit +-- ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible +-- ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type +-- ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance +-- else +-- if ClientEscortTargets[EscortTargetUnitName] then +-- ClientEscortTargets[EscortTargetUnitName] = nil +-- end +-- end +-- end +-- end +-- +-- self:T( { "Sorting Targets Table:", ClientEscortTargets } ) +-- table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end ) +-- self:T( { "Sorted Targets Table:", ClientEscortTargets } ) +-- +-- -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup. +-- self.EscortMenuAttackNearbyTargets:RemoveSubMenus() +-- +-- if self.EscortMenuTargetAssistance then +-- self.EscortMenuTargetAssistance:RemoveSubMenus() +-- end +-- +-- --for MenuIndex = 1, #self.EscortMenuAttackTargets do +-- -- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) +-- -- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() +-- --end +-- +-- +-- if ClientEscortTargets then +-- for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do +-- +-- for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do +-- +-- if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then +-- +-- local EscortTargetMessage = "" +-- local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName() +-- local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName() +-- if ClientEscortTargetData.type then +-- EscortTargetMessage = EscortTargetMessage .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at " +-- else +-- EscortTargetMessage = EscortTargetMessage .. "Unknown target at " +-- end +-- +-- local EscortTargetUnitVec3 = ClientEscortTargetData.AttackUnit:GetVec3() +-- local EscortVec3 = self.EscortGroup:GetVec3() +-- local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + +-- ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + +-- ( EscortTargetUnitVec3.z - EscortVec3.z )^2 +-- ) ^ 0.5 / 1000 +-- +-- self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } ) +-- if ClientEscortTargetData.visible == false then +-- EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km" +-- else +-- EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" +-- end +-- +-- if ClientEscortTargetData.visible then +-- EscortTargetMessage = EscortTargetMessage .. ", visual" +-- end +-- +-- if ClientEscortGroupName == EscortGroupName then +-- +-- MENU_CLIENT_COMMAND:New( self.EscortClient, +-- EscortTargetMessage, +-- self.EscortMenuAttackNearbyTargets, +-- ESCORT._AttackTarget, +-- { ParamSelf = self, +-- ParamUnit = ClientEscortTargetData.AttackUnit +-- } +-- ) +-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage +-- else +-- if self.EscortMenuTargetAssistance then +-- local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) +-- MENU_CLIENT_COMMAND:New( self.EscortClient, +-- EscortTargetMessage, +-- MenuTargetAssistance, +-- ESCORT._AssistTarget, +-- self, +-- EscortGroupData.EscortGroup, +-- ClientEscortTargetData.AttackUnit +-- ) +-- end +-- end +-- else +-- ClientEscortTargetData = nil +-- end +-- end +-- end +-- +-- if EscortTargetMessages ~= "" and self.ReportTargets == true then +-- self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient ) +-- else +-- self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient ) +-- end +-- end +-- +-- if self.EscortMenuResumeMission then +-- self.EscortMenuResumeMission:RemoveSubMenus() +-- +-- -- if self.EscortMenuResumeWayPoints then +-- -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do +-- -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } ) +-- -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove() +-- -- end +-- -- end +-- +-- local TaskPoints = self:RegisterRoute() +-- for WayPointID, WayPoint in pairs( TaskPoints ) do +-- local EscortVec3 = self.EscortGroup:GetVec3() +-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + +-- ( WayPoint.y - EscortVec3.z )^2 +-- ) ^ 0.5 / 1000 +-- MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) +-- end +-- end +-- +-- return true + end + end + + return false +end +--- This module contains the MISSILETRAINER class. +-- +-- === +-- +-- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Base#BASE} +-- =============================================================== +-- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft, +-- the class will destroy the missile within a certain range, to avoid damage to your aircraft. +-- It suports the following functionality: +-- +-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes. +-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range � +-- * Provide alerts when a missile would have killed your aircraft. +-- * Provide alerts when the missile self destructs. +-- * Enable / Disable and Configure the Missile Trainer using the various menu options. +-- +-- When running a mission where MISSILETRAINER is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players: +-- +-- * **Messages**: Menu to configure all messages. +-- * **Messages On**: Show all messages. +-- * **Messages Off**: Disable all messages. +-- * **Tracking**: Menu to configure missile tracking messages. +-- * **To All**: Shows missile tracking messages to all players. +-- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at. +-- * **Tracking On**: Show missile tracking messages. +-- * **Tracking Off**: Disable missile tracking messages. +-- * **Frequency Increase**: Increases the missile tracking message frequency with one second. +-- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second. +-- * **Alerts**: Menu to configure alert messages. +-- * **To All**: Shows alert messages to all players. +-- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at. +-- * **Hits On**: Show missile hit alert messages. +-- * **Hits Off**: Disable missile hit alert messages. +-- * **Launches On**: Show missile launch messages. +-- * **Launches Off**: Disable missile launch messages. +-- * **Details**: Menu to configure message details. +-- * **Range On**: Shows range information when a missile is fired to a target. +-- * **Range Off**: Disable range information when a missile is fired to a target. +-- * **Bearing On**: Shows bearing information when a missile is fired to a target. +-- * **Bearing Off**: Disable bearing information when a missile is fired to a target. +-- * **Distance**: Menu to configure the distance when a missile needs to be destroyed when near to a player, during tracking. This will improve/influence hit calculation accuracy, but has the risk of damaging the aircraft when the missile reaches the aircraft before the distance is measured. +-- * **50 meter**: Destroys the missile when the distance to the aircraft is below or equal to 50 meter. +-- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter. +-- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter. +-- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter. +-- +-- +-- 1.1) MISSILETRAINER construction methods: +-- ----------------------------------------- +-- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method: +-- +-- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed. +-- +-- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those. +-- +-- 1.2) MISSILETRAINER initialization methods: +-- ------------------------------------------- +-- A MISSILETRAINER object will behave differently based on the usage of initialization methods: +-- +-- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF. +-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you. +-- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF. +-- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. +-- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you. +-- * @{#MISSILETRAINER.InitAlertsHitsOnOff}: Sets by default the display of hit alerts ON or OFF. +-- * @{#MISSILETRAINER.InitAlertsLaunchesOnOff}: Sets by default the display of launch alerts ON or OFF. +-- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF. +-- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF. +-- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu. +-- +-- === +-- +-- CREDITS +-- ======= +-- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums. +-- Working together with Danny has resulted in the MISSILETRAINER class. +-- Danny has shared his ideas and together we made a design. +-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback! +-- +-- @module MissileTrainer +-- @author FlightControl + + +--- The MISSILETRAINER class +-- @type MISSILETRAINER +-- @field Core.Set#SET_CLIENT DBClients +-- @extends Core.Base#BASE +MISSILETRAINER = { + ClassName = "MISSILETRAINER", + TrackingMissiles = {}, +} + +function MISSILETRAINER._Alive( Client, self ) + + if self.Briefing then + Client:Message( self.Briefing, 15, "Trainer" ) + end + + if self.MenusOnOff == true then + Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" ) + + Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT + + Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu ) + Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } ) + Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } ) + + Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu ) + Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } ) + Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } ) + Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } ) + Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } ) + Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } ) + Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } ) + + Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu ) + Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } ) + Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } ) + Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } ) + Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } ) + Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } ) + Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } ) + + Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu ) + Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } ) + Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } ) + Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } ) + Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } ) + + Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu ) + Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } ) + Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } ) + Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } ) + Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } ) + else + if Client.MainMenu then + Client.MainMenu:Remove() + end + end + + local ClientID = Client:GetID() + self:T( ClientID ) + if not self.TrackingMissiles[ClientID] then + self.TrackingMissiles[ClientID] = {} + end + self.TrackingMissiles[ClientID].Client = Client + if not self.TrackingMissiles[ClientID].MissileData then + self.TrackingMissiles[ClientID].MissileData = {} + end +end + +--- Creates the main object which is handling missile tracking. +-- When a missile is fired a SCHEDULER is set off that follows the missile. When near a certain a client player, the missile will be destroyed. +-- @param #MISSILETRAINER self +-- @param #number Distance The distance in meters when a tracked missile needs to be destroyed when close to a player. +-- @param #string Briefing (Optional) Will show a text to the players when starting their mission. Can be used for briefing purposes. +-- @return #MISSILETRAINER +function MISSILETRAINER:New( Distance, Briefing ) + local self = BASE:Inherit( self, BASE:New() ) + self:F( Distance ) + + if Briefing then + self.Briefing = Briefing + end + + self.Schedulers = {} + self.SchedulerID = 0 + + self.MessageInterval = 2 + self.MessageLastTime = timer.getTime() + + self.Distance = Distance / 1000 + + self:HandleEvent( EVENTS.Shot ) + + self.DBClients = SET_CLIENT:New():FilterStart() + + +-- for ClientID, Client in pairs( self.DBClients.Database ) do +-- self:E( "ForEach:" .. Client.UnitName ) +-- Client:Alive( self._Alive, self ) +-- end +-- + self.DBClients:ForEachClient( + function( Client ) + self:E( "ForEach:" .. Client.UnitName ) + Client:Alive( self._Alive, self ) + end + ) + + + +-- self.DB:ForEachClient( +-- --- @param Wrapper.Client#CLIENT Client +-- function( Client ) +-- +-- ... actions ... +-- +-- end +-- ) + + self.MessagesOnOff = true + + self.TrackingToAll = false + self.TrackingOnOff = true + self.TrackingFrequency = 3 + + self.AlertsToAll = true + self.AlertsHitsOnOff = true + self.AlertsLaunchesOnOff = true + + self.DetailsRangeOnOff = true + self.DetailsBearingOnOff = true + + self.MenusOnOff = true + + self.TrackingMissiles = {} + + self.TrackingScheduler = SCHEDULER:New( self, self._TrackMissiles, {}, 0.5, 0.05, 0 ) + + return self +end + +-- Initialization methods. + + + +--- Sets by default the display of any message to be ON or OFF. +-- @param #MISSILETRAINER self +-- @param #boolean MessagesOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff ) + self:F( MessagesOnOff ) + + self.MessagesOnOff = MessagesOnOff + if self.MessagesOnOff == true then + MESSAGE:New( "Messages ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Messages OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the missile tracking report for all players or only for those missiles targetted to you. +-- @param #MISSILETRAINER self +-- @param #boolean TrackingToAll true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitTrackingToAll( TrackingToAll ) + self:F( TrackingToAll ) + + self.TrackingToAll = TrackingToAll + if self.TrackingToAll == true then + MESSAGE:New( "Missile tracking to all players ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Missile tracking to all players OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of missile tracking report to be ON or OFF. +-- @param #MISSILETRAINER self +-- @param #boolean TrackingOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitTrackingOnOff( TrackingOnOff ) + self:F( TrackingOnOff ) + + self.TrackingOnOff = TrackingOnOff + if self.TrackingOnOff == true then + MESSAGE:New( "Missile tracking ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Missile tracking OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. +-- The default frequency is a 3 second interval, so the Tracking Frequency parameter specifies the increase or decrease from the default 3 seconds or the last frequency update. +-- @param #MISSILETRAINER self +-- @param #number TrackingFrequency Provide a negative or positive value in seconds to incraese or decrease the display frequency. +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitTrackingFrequency( TrackingFrequency ) + self:F( TrackingFrequency ) + + self.TrackingFrequency = self.TrackingFrequency + TrackingFrequency + if self.TrackingFrequency < 0.5 then + self.TrackingFrequency = 0.5 + end + if self.TrackingFrequency then + MESSAGE:New( "Missile tracking frequency is " .. self.TrackingFrequency .. " seconds.", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of alerts to be shown to all players or only to you. +-- @param #MISSILETRAINER self +-- @param #boolean AlertsToAll true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitAlertsToAll( AlertsToAll ) + self:F( AlertsToAll ) + + self.AlertsToAll = AlertsToAll + if self.AlertsToAll == true then + MESSAGE:New( "Alerts to all players ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Alerts to all players OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of hit alerts ON or OFF. +-- @param #MISSILETRAINER self +-- @param #boolean AlertsHitsOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitAlertsHitsOnOff( AlertsHitsOnOff ) + self:F( AlertsHitsOnOff ) + + self.AlertsHitsOnOff = AlertsHitsOnOff + if self.AlertsHitsOnOff == true then + MESSAGE:New( "Alerts Hits ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Alerts Hits OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of launch alerts ON or OFF. +-- @param #MISSILETRAINER self +-- @param #boolean AlertsLaunchesOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitAlertsLaunchesOnOff( AlertsLaunchesOnOff ) + self:F( AlertsLaunchesOnOff ) + + self.AlertsLaunchesOnOff = AlertsLaunchesOnOff + if self.AlertsLaunchesOnOff == true then + MESSAGE:New( "Alerts Launches ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Alerts Launches OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of range information of missiles ON of OFF. +-- @param #MISSILETRAINER self +-- @param #boolean DetailsRangeOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitRangeOnOff( DetailsRangeOnOff ) + self:F( DetailsRangeOnOff ) + + self.DetailsRangeOnOff = DetailsRangeOnOff + if self.DetailsRangeOnOff == true then + MESSAGE:New( "Range display ON", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Range display OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Sets by default the display of bearing information of missiles ON of OFF. +-- @param #MISSILETRAINER self +-- @param #boolean DetailsBearingOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitBearingOnOff( DetailsBearingOnOff ) + self:F( DetailsBearingOnOff ) + + self.DetailsBearingOnOff = DetailsBearingOnOff + if self.DetailsBearingOnOff == true then + MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() + end + + return self +end + +--- Enables / Disables the menus. +-- @param #MISSILETRAINER self +-- @param #boolean MenusOnOff true or false +-- @return #MISSILETRAINER self +function MISSILETRAINER:InitMenusOnOff( MenusOnOff ) + self:F( MenusOnOff ) + + self.MenusOnOff = MenusOnOff + if self.MenusOnOff == true then + MESSAGE:New( "Menus are ENABLED (only when a player rejoins a slot)", 15, "Menu" ):ToAll() + else + MESSAGE:New( "Menus are DISABLED", 15, "Menu" ):ToAll() + end + + return self +end + + +-- Menu functions + +function MISSILETRAINER._MenuMessages( MenuParameters ) + + local self = MenuParameters.MenuSelf + + if MenuParameters.MessagesOnOff ~= nil then + self:InitMessagesOnOff( MenuParameters.MessagesOnOff ) + end + + if MenuParameters.TrackingToAll ~= nil then + self:InitTrackingToAll( MenuParameters.TrackingToAll ) + end + + if MenuParameters.TrackingOnOff ~= nil then + self:InitTrackingOnOff( MenuParameters.TrackingOnOff ) + end + + if MenuParameters.TrackingFrequency ~= nil then + self:InitTrackingFrequency( MenuParameters.TrackingFrequency ) + end + + if MenuParameters.AlertsToAll ~= nil then + self:InitAlertsToAll( MenuParameters.AlertsToAll ) + end + + if MenuParameters.AlertsHitsOnOff ~= nil then + self:InitAlertsHitsOnOff( MenuParameters.AlertsHitsOnOff ) + end + + if MenuParameters.AlertsLaunchesOnOff ~= nil then + self:InitAlertsLaunchesOnOff( MenuParameters.AlertsLaunchesOnOff ) + end + + if MenuParameters.DetailsRangeOnOff ~= nil then + self:InitRangeOnOff( MenuParameters.DetailsRangeOnOff ) + end + + if MenuParameters.DetailsBearingOnOff ~= nil then + self:InitBearingOnOff( MenuParameters.DetailsBearingOnOff ) + end + + if MenuParameters.Distance ~= nil then + self.Distance = MenuParameters.Distance + MESSAGE:New( "Hit detection distance set to " .. self.Distance .. " meters", 15, "Menu" ):ToAll() + end + +end + +--- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. +-- @param #MISSILETRAINER self +-- @param Core.Event#EVENTDATA EventData +function MISSILETRAINER:OnEventShot( EVentData ) + self:F( { EVentData } ) + + local TrainerSourceDCSUnit = EVentData.IniDCSUnit + local TrainerSourceDCSUnitName = EVentData.IniDCSUnitName + local TrainerWeapon = EVentData.Weapon -- Identify the weapon fired + local TrainerWeaponName = EVentData.WeaponName -- return weapon type + + self:T( "Missile Launched = " .. TrainerWeaponName ) + + local TrainerTargetDCSUnit = TrainerWeapon:getTarget() -- Identify target + if TrainerTargetDCSUnit then + local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit ) + local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill + + self:T(TrainerTargetDCSUnitName ) + + local Client = self.DBClients:FindClient( TrainerTargetDCSUnitName ) + if Client then + + local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit ) + local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit ) + + if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then + + local Message = MESSAGE:New( + string.format( "%s launched a %s", + TrainerSourceUnit:GetTypeName(), + TrainerWeaponName + ) .. self:_AddRange( Client, TrainerWeapon ) .. self:_AddBearing( Client, TrainerWeapon ), 5, "Launch Alert" ) + + if self.AlertsToAll then + Message:ToAll() + else + Message:ToClient( Client ) + end + end + + local ClientID = Client:GetID() + self:T( ClientID ) + local MissileData = {} + MissileData.TrainerSourceUnit = TrainerSourceUnit + MissileData.TrainerWeapon = TrainerWeapon + MissileData.TrainerTargetUnit = TrainerTargetUnit + MissileData.TrainerWeaponTypeName = TrainerWeapon:getTypeName() + MissileData.TrainerWeaponLaunched = true + table.insert( self.TrackingMissiles[ClientID].MissileData, MissileData ) + --self:T( self.TrackingMissiles ) + end + else + -- TODO: some weapons don't know the target unit... Need to develop a workaround for this. + if ( TrainerWeapon:getTypeName() == "9M311" ) then + SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 1 ) + else + end + end +end + +function MISSILETRAINER:_AddRange( Client, TrainerWeapon ) + + local RangeText = "" + + if self.DetailsRangeOnOff then + + local PositionMissile = TrainerWeapon:getPoint() + local TargetVec3 = Client:GetVec3() + + local Range = ( ( PositionMissile.x - TargetVec3.x )^2 + + ( PositionMissile.y - TargetVec3.y )^2 + + ( PositionMissile.z - TargetVec3.z )^2 + ) ^ 0.5 / 1000 + + RangeText = string.format( ", at %4.2fkm", Range ) + end + + return RangeText +end + +function MISSILETRAINER:_AddBearing( Client, TrainerWeapon ) + + local BearingText = "" + + if self.DetailsBearingOnOff then + + local PositionMissile = TrainerWeapon:getPoint() + local TargetVec3 = Client:GetVec3() + + self:T2( { TargetVec3, PositionMissile }) + + local DirectionVector = { x = PositionMissile.x - TargetVec3.x, y = PositionMissile.y - TargetVec3.y, z = PositionMissile.z - TargetVec3.z } + local DirectionRadians = math.atan2( DirectionVector.z, DirectionVector.x ) + --DirectionRadians = DirectionRadians + routines.getNorthCorrection( PositionTarget ) + if DirectionRadians < 0 then + DirectionRadians = DirectionRadians + 2 * math.pi + end + local DirectionDegrees = DirectionRadians * 180 / math.pi + + BearingText = string.format( ", %d degrees", DirectionDegrees ) + end + + return BearingText +end + + +function MISSILETRAINER:_TrackMissiles() + self:F2() + + + local ShowMessages = false + if self.MessagesOnOff and self.MessageLastTime + self.TrackingFrequency <= timer.getTime() then + self.MessageLastTime = timer.getTime() + ShowMessages = true + end + + -- ALERTS PART + + -- Loop for all Player Clients to check the alerts and deletion of missiles. + for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do + + local Client = ClientData.Client + self:T2( { Client:GetName() } ) + + for MissileDataID, MissileData in pairs( ClientData.MissileData ) do + self:T3( MissileDataID ) + + local TrainerSourceUnit = MissileData.TrainerSourceUnit + local TrainerWeapon = MissileData.TrainerWeapon + local TrainerTargetUnit = MissileData.TrainerTargetUnit + local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName + local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched + + if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then + local PositionMissile = TrainerWeapon:getPosition().p + local TargetVec3 = Client:GetVec3() + + local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 + + ( PositionMissile.y - TargetVec3.y )^2 + + ( PositionMissile.z - TargetVec3.z )^2 + ) ^ 0.5 / 1000 + + if Distance <= self.Distance then + -- Hit alert + TrainerWeapon:destroy() + if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then + + self:T( "killed" ) + + local Message = MESSAGE:New( + string.format( "%s launched by %s killed %s", + TrainerWeapon:getTypeName(), + TrainerSourceUnit:GetTypeName(), + TrainerTargetUnit:GetPlayerName() + ), 15, "Hit Alert" ) + + if self.AlertsToAll == true then + Message:ToAll() + else + Message:ToClient( Client ) + end + + MissileData = nil + table.remove( ClientData.MissileData, MissileDataID ) + self:T(ClientData.MissileData) + end + end + else + if not ( TrainerWeapon and TrainerWeapon:isExist() ) then + if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then + -- Weapon does not exist anymore. Delete from Table + local Message = MESSAGE:New( + string.format( "%s launched by %s self destructed!", + TrainerWeaponTypeName, + TrainerSourceUnit:GetTypeName() + ), 5, "Tracking" ) + + if self.AlertsToAll == true then + Message:ToAll() + else + Message:ToClient( Client ) + end + end + MissileData = nil + table.remove( ClientData.MissileData, MissileDataID ) + self:T( ClientData.MissileData ) + end + end + end + end + + if ShowMessages == true and self.MessagesOnOff == true and self.TrackingOnOff == true then -- Only do this when tracking information needs to be displayed. + + -- TRACKING PART + + -- For the current client, the missile range and bearing details are displayed To the Player Client. + -- For the other clients, the missile range and bearing details are displayed To the other Player Clients. + -- To achieve this, a cross loop is done for each Player Client <-> Other Player Client missile information. + + -- Main Player Client loop + for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do + + local Client = ClientData.Client + self:T2( { Client:GetName() } ) + + + ClientData.MessageToClient = "" + ClientData.MessageToAll = "" + + -- Other Players Client loop + for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do + + for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do + self:T3( MissileDataID ) + + local TrainerSourceUnit = MissileData.TrainerSourceUnit + local TrainerWeapon = MissileData.TrainerWeapon + local TrainerTargetUnit = MissileData.TrainerTargetUnit + local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName + local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched + + if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then + + if ShowMessages == true then + local TrackingTo + TrackingTo = string.format( " -> %s", + TrainerWeaponTypeName + ) + + if ClientDataID == TrackingDataID then + if ClientData.MessageToClient == "" then + ClientData.MessageToClient = "Missiles to You:\n" + end + ClientData.MessageToClient = ClientData.MessageToClient .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. "\n" + else + if self.TrackingToAll == true then + if ClientData.MessageToAll == "" then + ClientData.MessageToAll = "Missiles to other Players:\n" + end + ClientData.MessageToAll = ClientData.MessageToAll .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. " ( " .. TrainerTargetUnit:GetPlayerName() .. " )\n" + end + end + end + end + end + end + + -- Once the Player Client and the Other Player Client tracking messages are prepared, show them. + if ClientData.MessageToClient ~= "" or ClientData.MessageToAll ~= "" then + local Message = MESSAGE:New( ClientData.MessageToClient .. ClientData.MessageToAll, 1, "Tracking" ):ToClient( Client ) + end + end + end + + return true +end +--- This module contains the AIRBASEPOLICE classes. +-- +-- === +-- +-- 1) @{AirbasePolice#AIRBASEPOLICE_BASE} class, extends @{Base#BASE} +-- ================================================================== +-- The @{AirbasePolice#AIRBASEPOLICE_BASE} class provides the main methods to monitor CLIENT behaviour at airbases. +-- CLIENTS should not be allowed to: +-- +-- * Don't taxi faster than 40 km/h. +-- * Don't take-off on taxiways. +-- * Avoid to hit other planes on the airbase. +-- * Obey ground control orders. +-- +-- 2) @{AirbasePolice#AIRBASEPOLICE_CAUCASUS} class, extends @{AirbasePolice#AIRBASEPOLICE_BASE} +-- ============================================================================================= +-- All the airbases on the caucasus map can be monitored using this class. +-- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. +-- The following names can be given: +-- * AnapaVityazevo +-- * Batumi +-- * Beslan +-- * Gelendzhik +-- * Gudauta +-- * Kobuleti +-- * KrasnodarCenter +-- * KrasnodarPashkovsky +-- * Krymsk +-- * Kutaisi +-- * MaykopKhanskaya +-- * MineralnyeVody +-- * Mozdok +-- * Nalchik +-- * Novorossiysk +-- * SenakiKolkhi +-- * SochiAdler +-- * Soganlug +-- * SukhumiBabushara +-- * TbilisiLochini +-- * Vaziani +-- +-- 3) @{AirbasePolice#AIRBASEPOLICE_NEVADA} class, extends @{AirbasePolice#AIRBASEPOLICE_BASE} +-- ============================================================================================= +-- All the airbases on the NEVADA map can be monitored using this class. +-- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. +-- The following names can be given: +-- * Nellis +-- * McCarran +-- * Creech +-- * Groom Lake +-- +-- ### Contributions: Dutch Baron - Concept & Testing +-- ### Author: FlightControl - Framework Design & Programming +-- +-- @module AirbasePolice + + + + + +--- @type AIRBASEPOLICE_BASE +-- @field Core.Set#SET_CLIENT SetClient +-- @extends Core.Base#BASE + +AIRBASEPOLICE_BASE = { + ClassName = "AIRBASEPOLICE_BASE", + SetClient = nil, + Airbases = nil, + AirbaseNames = nil, +} + + +--- Creates a new AIRBASEPOLICE_BASE object. +-- @param #AIRBASEPOLICE_BASE self +-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. +-- @param Airbases A table of Airbase Names. +-- @return #AIRBASEPOLICE_BASE self +function AIRBASEPOLICE_BASE:New( SetClient, Airbases ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) + self:E( { self.ClassName, SetClient, Airbases } ) + + self.SetClient = SetClient + self.Airbases = Airbases + + for AirbaseID, Airbase in pairs( self.Airbases ) do + Airbase.ZoneBoundary = ZONE_POLYGON_BASE:New( "Boundary", Airbase.PointsBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + for PointsRunwayID, PointsRunway in pairs( Airbase.PointsRunways ) do + Airbase.ZoneRunways[PointsRunwayID] = ZONE_POLYGON_BASE:New( "Runway " .. PointsRunwayID, PointsRunway ):SmokeZone(SMOKECOLOR.Red):Flush() + end + end + +-- -- Template +-- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) +-- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() +-- +-- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) +-- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + + self.SetClient:ForEachClient( + --- @param Wrapper.Client#CLIENT Client + function( Client ) + Client:SetState( self, "Speeding", false ) + Client:SetState( self, "Warnings", 0) + Client:SetState( self, "Taxi", false ) + end + ) + + self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, {}, 0, 2, 0.05 ) + + return self +end + +--- @type AIRBASEPOLICE_BASE.AirbaseNames +-- @list <#string> + +--- Monitor a table of airbase names. +-- @param #AIRBASEPOLICE_BASE self +-- @param #AIRBASEPOLICE_BASE.AirbaseNames AirbaseNames A list of AirbaseNames to monitor. If this parameters is nil, then all airbases will be monitored. +-- @return #AIRBASEPOLICE_BASE self +function AIRBASEPOLICE_BASE:Monitor( AirbaseNames ) + + if AirbaseNames then + if type( AirbaseNames ) == "table" then + self.AirbaseNames = AirbaseNames + else + self.AirbaseNames = { AirbaseNames } + end + end +end + +--- @param #AIRBASEPOLICE_BASE self +function AIRBASEPOLICE_BASE:_AirbaseMonitor() + + for AirbaseID, Airbase in pairs( self.Airbases ) do + + if not self.AirbaseNames or self.AirbaseNames[AirbaseID] then + + self:E( AirbaseID ) + + self.SetClient:ForEachClientInZone( Airbase.ZoneBoundary, + + --- @param Wrapper.Client#CLIENT Client + function( Client ) + + self:E( Client.UnitName ) + if Client:IsAlive() then + local NotInRunwayZone = true + for ZoneRunwayID, ZoneRunway in pairs( Airbase.ZoneRunways ) do + NotInRunwayZone = ( Client:IsNotInZone( ZoneRunway ) == true ) and NotInRunwayZone or false + end + + if NotInRunwayZone then + local Taxi = self:GetState( self, "Taxi" ) + self:E( Taxi ) + if Taxi == false then + Client:Message( "Welcome at " .. AirbaseID .. ". The maximum taxiing speed is " .. Airbase.MaximumSpeed " km/h.", 20, "ATC" ) + self:SetState( self, "Taxi", true ) + end + + -- TODO: GetVelocityKMH function usage + local VelocityVec3 = Client:GetVelocity() + local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec + local Velocity = Velocity * 3.6 -- now it is in km/h. + -- MESSAGE:New( "Velocity = " .. Velocity, 1 ):ToAll() + local IsAboveRunway = Client:IsAboveRunway() + local IsOnGround = Client:InAir() == false + self:T( IsAboveRunway, IsOnGround ) + + if IsAboveRunway and IsOnGround then + + if Velocity > Airbase.MaximumSpeed then + local IsSpeeding = Client:GetState( self, "Speeding" ) + + if IsSpeeding == true then + local SpeedingWarnings = Client:GetState( self, "Warnings" ) + self:T( SpeedingWarnings ) + + if SpeedingWarnings <= 3 then + Client:Message( "You are speeding on the taxiway! Slow down or you will be removed from this airbase! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Warning " .. SpeedingWarnings .. " / 3" ) + Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) + else + MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() + Client:Destroy() + trigger.action.setUserFlag( "AIRCRAFT_"..Client:GetID(), 100) + Client:SetState( self, "Speeding", false ) + Client:SetState( self, "Warnings", 0 ) + end + + else + Client:Message( "You are speeding on the taxiway, slow down now! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Attention! " ) + Client:SetState( self, "Speeding", true ) + Client:SetState( self, "Warnings", 1 ) + end + + else + Client:SetState( self, "Speeding", false ) + Client:SetState( self, "Warnings", 0 ) + end + end + + else + Client:SetState( self, "Speeding", false ) + Client:SetState( self, "Warnings", 0 ) + local Taxi = self:GetState( self, "Taxi" ) + if Taxi == true then + Client:Message( "You have progressed to the runway ... Await take-off clearance ...", 20, "ATC" ) + self:SetState( self, "Taxi", false ) + end + end + end + end + ) + end + end + + return true +end + + +--- @type AIRBASEPOLICE_CAUCASUS +-- @field Core.Set#SET_CLIENT SetClient +-- @extends #AIRBASEPOLICE_BASE + +AIRBASEPOLICE_CAUCASUS = { + ClassName = "AIRBASEPOLICE_CAUCASUS", + Airbases = { + AnapaVityazevo = { + PointsBoundary = { + [1]={["y"]=242234.85714287,["x"]=-6616.5714285726,}, + [2]={["y"]=241060.57142858,["x"]=-5585.142857144,}, + [3]={["y"]=243806.2857143,["x"]=-3962.2857142868,}, + [4]={["y"]=245240.57142858,["x"]=-4816.5714285726,}, + [5]={["y"]=244783.42857144,["x"]=-5630.8571428583,}, + [6]={["y"]=243800.57142858,["x"]=-5065.142857144,}, + [7]={["y"]=242232.00000001,["x"]=-6622.2857142868,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=242140.57142858,["x"]=-6478.8571428583,}, + [2]={["y"]=242188.57142858,["x"]=-6522.0000000011,}, + [3]={["y"]=244124.2857143,["x"]=-4344.0000000011,}, + [4]={["y"]=244068.2857143,["x"]=-4296.5714285726,}, + [5]={["y"]=242140.57142858,["x"]=-6480.0000000011,} + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Batumi = { + PointsBoundary = { + [1]={["y"]=617567.14285714,["x"]=-355313.14285715,}, + [2]={["y"]=616181.42857142,["x"]=-354800.28571429,}, + [3]={["y"]=616007.14285714,["x"]=-355128.85714286,}, + [4]={["y"]=618230,["x"]=-356914.57142858,}, + [5]={["y"]=618727.14285714,["x"]=-356166,}, + [6]={["y"]=617572.85714285,["x"]=-355308.85714286,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=616442.28571429,["x"]=-355090.28571429,}, + [2]={["y"]=618450.57142857,["x"]=-356522,}, + [3]={["y"]=618407.71428571,["x"]=-356584.85714286,}, + [4]={["y"]=618361.99999999,["x"]=-356554.85714286,}, + [5]={["y"]=618324.85714285,["x"]=-356599.14285715,}, + [6]={["y"]=618250.57142856,["x"]=-356543.42857143,}, + [7]={["y"]=618257.7142857,["x"]=-356496.28571429,}, + [8]={["y"]=618237.7142857,["x"]=-356459.14285715,}, + [9]={["y"]=616555.71428571,["x"]=-355258.85714286,}, + [10]={["y"]=616486.28571428,["x"]=-355280.57142858,}, + [11]={["y"]=616410.57142856,["x"]=-355227.71428572,}, + [12]={["y"]=616441.99999999,["x"]=-355179.14285715,}, + [13]={["y"]=616401.99999999,["x"]=-355147.71428572,}, + [14]={["y"]=616441.42857142,["x"]=-355092.57142858,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Beslan = { + PointsBoundary = { + [1]={["y"]=842082.57142857,["x"]=-148445.14285715,}, + [2]={["y"]=845237.71428572,["x"]=-148639.71428572,}, + [3]={["y"]=845232,["x"]=-148765.42857143,}, + [4]={["y"]=844220.57142857,["x"]=-149168.28571429,}, + [5]={["y"]=843274.85714286,["x"]=-149125.42857143,}, + [6]={["y"]=842077.71428572,["x"]=-148554,}, + [7]={["y"]=842083.42857143,["x"]=-148445.42857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=842104.57142857,["x"]=-148460.57142857,}, + [2]={["y"]=845225.71428572,["x"]=-148656,}, + [3]={["y"]=845220.57142858,["x"]=-148750,}, + [4]={["y"]=842098.85714286,["x"]=-148556.28571429,}, + [5]={["y"]=842104,["x"]=-148460.28571429,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Gelendzhik = { + PointsBoundary = { + [1]={["y"]=297856.00000001,["x"]=-51151.428571429,}, + [2]={["y"]=299044.57142858,["x"]=-49720.000000001,}, + [3]={["y"]=298861.71428572,["x"]=-49580.000000001,}, + [4]={["y"]=298198.85714286,["x"]=-49842.857142858,}, + [5]={["y"]=297990.28571429,["x"]=-50151.428571429,}, + [6]={["y"]=297696.00000001,["x"]=-51054.285714286,}, + [7]={["y"]=297850.28571429,["x"]=-51160.000000001,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=297834.00000001,["x"]=-51107.428571429,}, + [2]={["y"]=297786.57142858,["x"]=-51068.857142858,}, + [3]={["y"]=298946.57142858,["x"]=-49686.000000001,}, + [4]={["y"]=298993.14285715,["x"]=-49725.714285715,}, + [5]={["y"]=297835.14285715,["x"]=-51107.714285715,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Gudauta = { + PointsBoundary = { + [1]={["y"]=517246.57142857,["x"]=-197850.28571429,}, + [2]={["y"]=516749.42857142,["x"]=-198070.28571429,}, + [3]={["y"]=515755.14285714,["x"]=-197598.85714286,}, + [4]={["y"]=515369.42857142,["x"]=-196538.85714286,}, + [5]={["y"]=515623.71428571,["x"]=-195618.85714286,}, + [6]={["y"]=515946.57142857,["x"]=-195510.28571429,}, + [7]={["y"]=517243.71428571,["x"]=-197858.85714286,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=517096.57142857,["x"]=-197804.57142857,}, + [2]={["y"]=515880.85714285,["x"]=-195590.28571429,}, + [3]={["y"]=515812.28571428,["x"]=-195628.85714286,}, + [4]={["y"]=517036.57142857,["x"]=-197834.57142857,}, + [5]={["y"]=517097.99999999,["x"]=-197807.42857143,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Kobuleti = { + PointsBoundary = { + [1]={["y"]=634427.71428571,["x"]=-318290.28571429,}, + [2]={["y"]=635033.42857143,["x"]=-317550.2857143,}, + [3]={["y"]=635864.85714286,["x"]=-317333.14285715,}, + [4]={["y"]=636967.71428571,["x"]=-317261.71428572,}, + [5]={["y"]=637144.85714286,["x"]=-317913.14285715,}, + [6]={["y"]=634630.57142857,["x"]=-318687.42857144,}, + [7]={["y"]=634424.85714286,["x"]=-318290.2857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=634509.71428571,["x"]=-318339.42857144,}, + [2]={["y"]=636767.42857143,["x"]=-317516.57142858,}, + [3]={["y"]=636790,["x"]=-317575.71428572,}, + [4]={["y"]=634531.42857143,["x"]=-318398.00000001,}, + [5]={["y"]=634510.28571429,["x"]=-318339.71428572,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + KrasnodarCenter = { + PointsBoundary = { + [1]={["y"]=366680.28571429,["x"]=11699.142857142,}, + [2]={["y"]=366654.28571429,["x"]=11225.142857142,}, + [3]={["y"]=367497.14285715,["x"]=11082.285714285,}, + [4]={["y"]=368025.71428572,["x"]=10396.57142857,}, + [5]={["y"]=369854.28571429,["x"]=11367.999999999,}, + [6]={["y"]=369840.00000001,["x"]=11910.857142856,}, + [7]={["y"]=366682.57142858,["x"]=11697.999999999,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=369205.42857144,["x"]=11789.142857142,}, + [2]={["y"]=369209.71428572,["x"]=11714.857142856,}, + [3]={["y"]=366699.71428572,["x"]=11581.714285713,}, + [4]={["y"]=366698.28571429,["x"]=11659.142857142,}, + [5]={["y"]=369208.85714286,["x"]=11788.57142857,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + KrasnodarPashkovsky = { + PointsBoundary = { + [1]={["y"]=386754,["x"]=6476.5714285703,}, + [2]={["y"]=389182.57142858,["x"]=8722.2857142846,}, + [3]={["y"]=388832.57142858,["x"]=9086.5714285703,}, + [4]={["y"]=386961.14285715,["x"]=7707.9999999989,}, + [5]={["y"]=385404,["x"]=9179.4285714274,}, + [6]={["y"]=383239.71428572,["x"]=7386.5714285703,}, + [7]={["y"]=383954,["x"]=6486.5714285703,}, + [8]={["y"]=385775.42857143,["x"]=8097.9999999989,}, + [9]={["y"]=386804,["x"]=7319.4285714274,}, + [10]={["y"]=386375.42857143,["x"]=6797.9999999989,}, + [11]={["y"]=386746.85714286,["x"]=6472.2857142846,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=385891.14285715,["x"]=8416.5714285703,}, + [2]={["y"]=385842.28571429,["x"]=8467.9999999989,}, + [3]={["y"]=384180.85714286,["x"]=6917.1428571417,}, + [4]={["y"]=384228.57142858,["x"]=6867.7142857132,}, + [5]={["y"]=385891.14285715,["x"]=8416.5714285703,}, + }, + [2] = { + [1]={["y"]=386714.85714286,["x"]=6674.857142856,}, + [2]={["y"]=386757.71428572,["x"]=6627.7142857132,}, + [3]={["y"]=389028.57142858,["x"]=8741.4285714275,}, + [4]={["y"]=388981.71428572,["x"]=8790.5714285703,}, + [5]={["y"]=386714.57142858,["x"]=6674.5714285703,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Krymsk = { + PointsBoundary = { + [1]={["y"]=293338.00000001,["x"]=-7575.4285714297,}, + [2]={["y"]=295199.42857144,["x"]=-5434.0000000011,}, + [3]={["y"]=295595.14285715,["x"]=-6239.7142857154,}, + [4]={["y"]=294152.2857143,["x"]=-8325.4285714297,}, + [5]={["y"]=293345.14285715,["x"]=-7596.8571428582,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=293522.00000001,["x"]=-7567.4285714297,}, + [2]={["y"]=293578.57142858,["x"]=-7616.0000000011,}, + [3]={["y"]=295246.00000001,["x"]=-5591.142857144,}, + [4]={["y"]=295187.71428573,["x"]=-5546.0000000011,}, + [5]={["y"]=293523.14285715,["x"]=-7568.2857142868,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Kutaisi = { + PointsBoundary = { + [1]={["y"]=682087.42857143,["x"]=-284512.85714286,}, + [2]={["y"]=685387.42857143,["x"]=-283662.85714286,}, + [3]={["y"]=685294.57142857,["x"]=-284977.14285715,}, + [4]={["y"]=682744.57142857,["x"]=-286505.71428572,}, + [5]={["y"]=682094.57142857,["x"]=-284527.14285715,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=682638,["x"]=-285202.28571429,}, + [2]={["y"]=685050.28571429,["x"]=-284507.42857144,}, + [3]={["y"]=685068.85714286,["x"]=-284578.85714286,}, + [4]={["y"]=682657.42857143,["x"]=-285264.28571429,}, + [5]={["y"]=682638.28571429,["x"]=-285202.85714286,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + MaykopKhanskaya = { + PointsBoundary = { + [1]={["y"]=456876.28571429,["x"]=-27665.42857143,}, + [2]={["y"]=457800,["x"]=-28392.857142858,}, + [3]={["y"]=459368.57142857,["x"]=-26378.571428573,}, + [4]={["y"]=459425.71428572,["x"]=-25242.857142858,}, + [5]={["y"]=458961.42857143,["x"]=-24964.285714287,}, + [6]={["y"]=456878.57142857,["x"]=-27667.714285715,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=457005.42857143,["x"]=-27668.000000001,}, + [2]={["y"]=459028.85714286,["x"]=-25168.857142858,}, + [3]={["y"]=459082.57142857,["x"]=-25216.857142858,}, + [4]={["y"]=457060,["x"]=-27714.285714287,}, + [5]={["y"]=457004.57142857,["x"]=-27669.714285715,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + MineralnyeVody = { + PointsBoundary = { + [1]={["y"]=703857.14285714,["x"]=-50226.000000002,}, + [2]={["y"]=707385.71428571,["x"]=-51911.714285716,}, + [3]={["y"]=707595.71428571,["x"]=-51434.857142859,}, + [4]={["y"]=707900,["x"]=-51568.857142859,}, + [5]={["y"]=707542.85714286,["x"]=-52326.000000002,}, + [6]={["y"]=706628.57142857,["x"]=-52568.857142859,}, + [7]={["y"]=705142.85714286,["x"]=-51790.285714288,}, + [8]={["y"]=703678.57142857,["x"]=-50611.714285716,}, + [9]={["y"]=703857.42857143,["x"]=-50226.857142859,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=703904,["x"]=-50352.571428573,}, + [2]={["y"]=707596.28571429,["x"]=-52094.571428573,}, + [3]={["y"]=707560.57142858,["x"]=-52161.714285716,}, + [4]={["y"]=703871.71428572,["x"]=-50420.571428573,}, + [5]={["y"]=703902,["x"]=-50352.000000002,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Mozdok = { + PointsBoundary = { + [1]={["y"]=832123.42857143,["x"]=-83608.571428573,}, + [2]={["y"]=835916.28571429,["x"]=-83144.285714288,}, + [3]={["y"]=835474.28571429,["x"]=-84170.571428573,}, + [4]={["y"]=832911.42857143,["x"]=-84470.571428573,}, + [5]={["y"]=832487.71428572,["x"]=-85565.714285716,}, + [6]={["y"]=831573.42857143,["x"]=-85351.42857143,}, + [7]={["y"]=832123.71428572,["x"]=-83610.285714288,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=832201.14285715,["x"]=-83699.428571431,}, + [2]={["y"]=832212.57142857,["x"]=-83780.571428574,}, + [3]={["y"]=835730.28571429,["x"]=-83335.714285717,}, + [4]={["y"]=835718.85714286,["x"]=-83246.571428574,}, + [5]={["y"]=832200.57142857,["x"]=-83700.000000002,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Nalchik = { + PointsBoundary = { + [1]={["y"]=759370,["x"]=-125502.85714286,}, + [2]={["y"]=761384.28571429,["x"]=-124177.14285714,}, + [3]={["y"]=761472.85714286,["x"]=-124325.71428572,}, + [4]={["y"]=761092.85714286,["x"]=-125048.57142857,}, + [5]={["y"]=760295.71428572,["x"]=-125685.71428572,}, + [6]={["y"]=759444.28571429,["x"]=-125734.28571429,}, + [7]={["y"]=759375.71428572,["x"]=-125511.42857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=759454.28571429,["x"]=-125551.42857143,}, + [2]={["y"]=759492.85714286,["x"]=-125610.85714286,}, + [3]={["y"]=761406.28571429,["x"]=-124304.28571429,}, + [4]={["y"]=761361.14285714,["x"]=-124239.71428572,}, + [5]={["y"]=759456,["x"]=-125552.57142857,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Novorossiysk = { + PointsBoundary = { + [1]={["y"]=278677.71428573,["x"]=-41656.571428572,}, + [2]={["y"]=278446.2857143,["x"]=-41453.714285715,}, + [3]={["y"]=278989.14285716,["x"]=-40188.000000001,}, + [4]={["y"]=279717.71428573,["x"]=-39968.000000001,}, + [5]={["y"]=280020.57142859,["x"]=-40208.000000001,}, + [6]={["y"]=278674.85714287,["x"]=-41660.857142858,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=278673.14285716,["x"]=-41615.142857144,}, + [2]={["y"]=278625.42857144,["x"]=-41570.571428572,}, + [3]={["y"]=279835.42857144,["x"]=-40226.000000001,}, + [4]={["y"]=279882.2857143,["x"]=-40270.000000001,}, + [5]={["y"]=278672.00000001,["x"]=-41614.857142858,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + SenakiKolkhi = { + PointsBoundary = { + [1]={["y"]=646036.57142857,["x"]=-281778.85714286,}, + [2]={["y"]=646045.14285714,["x"]=-281191.71428571,}, + [3]={["y"]=647032.28571429,["x"]=-280598.85714285,}, + [4]={["y"]=647669.42857143,["x"]=-281273.14285714,}, + [5]={["y"]=648323.71428571,["x"]=-281370.28571428,}, + [6]={["y"]=648520.85714286,["x"]=-281978.85714285,}, + [7]={["y"]=646039.42857143,["x"]=-281783.14285714,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=646060.85714285,["x"]=-281736,}, + [2]={["y"]=646056.57142857,["x"]=-281631.71428571,}, + [3]={["y"]=648442.28571428,["x"]=-281840.28571428,}, + [4]={["y"]=648432.28571428,["x"]=-281918.85714286,}, + [5]={["y"]=646063.71428571,["x"]=-281738.85714286,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + SochiAdler = { + PointsBoundary = { + [1]={["y"]=460642.28571428,["x"]=-164861.71428571,}, + [2]={["y"]=462820.85714285,["x"]=-163368.85714286,}, + [3]={["y"]=463649.42857142,["x"]=-163340.28571429,}, + [4]={["y"]=463835.14285714,["x"]=-164040.28571429,}, + [5]={["y"]=462535.14285714,["x"]=-165654.57142857,}, + [6]={["y"]=460678,["x"]=-165247.42857143,}, + [7]={["y"]=460635.14285714,["x"]=-164876,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=460831.42857143,["x"]=-165180,}, + [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, + [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, + [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, + [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, + }, + [2] = { + [1]={["y"]=460831.42857143,["x"]=-165180,}, + [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, + [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, + [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, + [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Soganlug = { + PointsBoundary = { + [1]={["y"]=894530.85714286,["x"]=-316928.28571428,}, + [2]={["y"]=896422.28571428,["x"]=-318622.57142857,}, + [3]={["y"]=896090.85714286,["x"]=-318934,}, + [4]={["y"]=894019.42857143,["x"]=-317119.71428571,}, + [5]={["y"]=894533.71428571,["x"]=-316925.42857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=894525.71428571,["x"]=-316964,}, + [2]={["y"]=896363.14285714,["x"]=-318634.28571428,}, + [3]={["y"]=896299.14285714,["x"]=-318702.85714286,}, + [4]={["y"]=894464,["x"]=-317031.71428571,}, + [5]={["y"]=894524.57142857,["x"]=-316963.71428571,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + SukhumiBabushara = { + PointsBoundary = { + [1]={["y"]=562541.14285714,["x"]=-219852.28571429,}, + [2]={["y"]=562691.14285714,["x"]=-219395.14285714,}, + [3]={["y"]=564326.85714286,["x"]=-219523.71428571,}, + [4]={["y"]=566262.57142857,["x"]=-221166.57142857,}, + [5]={["y"]=566069.71428571,["x"]=-221580.85714286,}, + [6]={["y"]=562534,["x"]=-219873.71428571,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=562684,["x"]=-219779.71428571,}, + [2]={["y"]=562717.71428571,["x"]=-219718,}, + [3]={["y"]=566046.85714286,["x"]=-221376.57142857,}, + [4]={["y"]=566012.28571428,["x"]=-221446.57142857,}, + [5]={["y"]=562684.57142857,["x"]=-219782.57142857,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + TbilisiLochini = { + PointsBoundary = { + [1]={["y"]=895172.85714286,["x"]=-314667.42857143,}, + [2]={["y"]=895337.42857143,["x"]=-314143.14285714,}, + [3]={["y"]=895990.28571429,["x"]=-314036,}, + [4]={["y"]=897730.28571429,["x"]=-315284.57142857,}, + [5]={["y"]=897901.71428571,["x"]=-316284.57142857,}, + [6]={["y"]=897684.57142857,["x"]=-316618.85714286,}, + [7]={["y"]=895173.14285714,["x"]=-314667.42857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=895261.14285715,["x"]=-314652.28571428,}, + [2]={["y"]=897654.57142857,["x"]=-316523.14285714,}, + [3]={["y"]=897711.71428571,["x"]=-316450.28571429,}, + [4]={["y"]=895327.42857143,["x"]=-314568.85714286,}, + [5]={["y"]=895261.71428572,["x"]=-314656,}, + }, + [2] = { + [1]={["y"]=895605.71428572,["x"]=-314724.57142857,}, + [2]={["y"]=897639.71428572,["x"]=-316148,}, + [3]={["y"]=897683.42857143,["x"]=-316087.14285714,}, + [4]={["y"]=895650,["x"]=-314660,}, + [5]={["y"]=895606,["x"]=-314724.85714286,} + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Vaziani = { + PointsBoundary = { + [1]={["y"]=902122,["x"]=-318163.71428572,}, + [2]={["y"]=902678.57142857,["x"]=-317594,}, + [3]={["y"]=903275.71428571,["x"]=-317405.42857143,}, + [4]={["y"]=903418.57142857,["x"]=-317891.14285714,}, + [5]={["y"]=904292.85714286,["x"]=-318748.28571429,}, + [6]={["y"]=904542,["x"]=-319740.85714286,}, + [7]={["y"]=904042,["x"]=-320166.57142857,}, + [8]={["y"]=902121.42857143,["x"]=-318164.85714286,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=902239.14285714,["x"]=-318190.85714286,}, + [2]={["y"]=904014.28571428,["x"]=-319994.57142857,}, + [3]={["y"]=904064.85714285,["x"]=-319945.14285715,}, + [4]={["y"]=902294.57142857,["x"]=-318146,}, + [5]={["y"]=902247.71428571,["x"]=-318190.85714286,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + }, +} + +--- Creates a new AIRBASEPOLICE_CAUCASUS object. +-- @param #AIRBASEPOLICE_CAUCASUS self +-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. +-- @return #AIRBASEPOLICE_CAUCASUS self +function AIRBASEPOLICE_CAUCASUS:New( SetClient ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) + + -- -- AnapaVityazevo + -- local AnapaVityazevoBoundary = GROUP:FindByName( "AnapaVityazevo Boundary" ) + -- self.Airbases.AnapaVityazevo.ZoneBoundary = ZONE_POLYGON:New( "AnapaVityazevo Boundary", AnapaVityazevoBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local AnapaVityazevoRunway1 = GROUP:FindByName( "AnapaVityazevo Runway 1" ) + -- self.Airbases.AnapaVityazevo.ZoneRunways[1] = ZONE_POLYGON:New( "AnapaVityazevo Runway 1", AnapaVityazevoRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Batumi + -- local BatumiBoundary = GROUP:FindByName( "Batumi Boundary" ) + -- self.Airbases.Batumi.ZoneBoundary = ZONE_POLYGON:New( "Batumi Boundary", BatumiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local BatumiRunway1 = GROUP:FindByName( "Batumi Runway 1" ) + -- self.Airbases.Batumi.ZoneRunways[1] = ZONE_POLYGON:New( "Batumi Runway 1", BatumiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Beslan + -- local BeslanBoundary = GROUP:FindByName( "Beslan Boundary" ) + -- self.Airbases.Beslan.ZoneBoundary = ZONE_POLYGON:New( "Beslan Boundary", BeslanBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local BeslanRunway1 = GROUP:FindByName( "Beslan Runway 1" ) + -- self.Airbases.Beslan.ZoneRunways[1] = ZONE_POLYGON:New( "Beslan Runway 1", BeslanRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Gelendzhik + -- local GelendzhikBoundary = GROUP:FindByName( "Gelendzhik Boundary" ) + -- self.Airbases.Gelendzhik.ZoneBoundary = ZONE_POLYGON:New( "Gelendzhik Boundary", GelendzhikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local GelendzhikRunway1 = GROUP:FindByName( "Gelendzhik Runway 1" ) + -- self.Airbases.Gelendzhik.ZoneRunways[1] = ZONE_POLYGON:New( "Gelendzhik Runway 1", GelendzhikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Gudauta + -- local GudautaBoundary = GROUP:FindByName( "Gudauta Boundary" ) + -- self.Airbases.Gudauta.ZoneBoundary = ZONE_POLYGON:New( "Gudauta Boundary", GudautaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local GudautaRunway1 = GROUP:FindByName( "Gudauta Runway 1" ) + -- self.Airbases.Gudauta.ZoneRunways[1] = ZONE_POLYGON:New( "Gudauta Runway 1", GudautaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Kobuleti + -- local KobuletiBoundary = GROUP:FindByName( "Kobuleti Boundary" ) + -- self.Airbases.Kobuleti.ZoneBoundary = ZONE_POLYGON:New( "Kobuleti Boundary", KobuletiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local KobuletiRunway1 = GROUP:FindByName( "Kobuleti Runway 1" ) + -- self.Airbases.Kobuleti.ZoneRunways[1] = ZONE_POLYGON:New( "Kobuleti Runway 1", KobuletiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- KrasnodarCenter + -- local KrasnodarCenterBoundary = GROUP:FindByName( "KrasnodarCenter Boundary" ) + -- self.Airbases.KrasnodarCenter.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarCenter Boundary", KrasnodarCenterBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local KrasnodarCenterRunway1 = GROUP:FindByName( "KrasnodarCenter Runway 1" ) + -- self.Airbases.KrasnodarCenter.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarCenter Runway 1", KrasnodarCenterRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- KrasnodarPashkovsky + -- local KrasnodarPashkovskyBoundary = GROUP:FindByName( "KrasnodarPashkovsky Boundary" ) + -- self.Airbases.KrasnodarPashkovsky.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarPashkovsky Boundary", KrasnodarPashkovskyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local KrasnodarPashkovskyRunway1 = GROUP:FindByName( "KrasnodarPashkovsky Runway 1" ) + -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 1", KrasnodarPashkovskyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- local KrasnodarPashkovskyRunway2 = GROUP:FindByName( "KrasnodarPashkovsky Runway 2" ) + -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[2] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 2", KrasnodarPashkovskyRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Krymsk + -- local KrymskBoundary = GROUP:FindByName( "Krymsk Boundary" ) + -- self.Airbases.Krymsk.ZoneBoundary = ZONE_POLYGON:New( "Krymsk Boundary", KrymskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local KrymskRunway1 = GROUP:FindByName( "Krymsk Runway 1" ) + -- self.Airbases.Krymsk.ZoneRunways[1] = ZONE_POLYGON:New( "Krymsk Runway 1", KrymskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Kutaisi + -- local KutaisiBoundary = GROUP:FindByName( "Kutaisi Boundary" ) + -- self.Airbases.Kutaisi.ZoneBoundary = ZONE_POLYGON:New( "Kutaisi Boundary", KutaisiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local KutaisiRunway1 = GROUP:FindByName( "Kutaisi Runway 1" ) + -- self.Airbases.Kutaisi.ZoneRunways[1] = ZONE_POLYGON:New( "Kutaisi Runway 1", KutaisiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- MaykopKhanskaya + -- local MaykopKhanskayaBoundary = GROUP:FindByName( "MaykopKhanskaya Boundary" ) + -- self.Airbases.MaykopKhanskaya.ZoneBoundary = ZONE_POLYGON:New( "MaykopKhanskaya Boundary", MaykopKhanskayaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local MaykopKhanskayaRunway1 = GROUP:FindByName( "MaykopKhanskaya Runway 1" ) + -- self.Airbases.MaykopKhanskaya.ZoneRunways[1] = ZONE_POLYGON:New( "MaykopKhanskaya Runway 1", MaykopKhanskayaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- MineralnyeVody + -- local MineralnyeVodyBoundary = GROUP:FindByName( "MineralnyeVody Boundary" ) + -- self.Airbases.MineralnyeVody.ZoneBoundary = ZONE_POLYGON:New( "MineralnyeVody Boundary", MineralnyeVodyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local MineralnyeVodyRunway1 = GROUP:FindByName( "MineralnyeVody Runway 1" ) + -- self.Airbases.MineralnyeVody.ZoneRunways[1] = ZONE_POLYGON:New( "MineralnyeVody Runway 1", MineralnyeVodyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Mozdok + -- local MozdokBoundary = GROUP:FindByName( "Mozdok Boundary" ) + -- self.Airbases.Mozdok.ZoneBoundary = ZONE_POLYGON:New( "Mozdok Boundary", MozdokBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local MozdokRunway1 = GROUP:FindByName( "Mozdok Runway 1" ) + -- self.Airbases.Mozdok.ZoneRunways[1] = ZONE_POLYGON:New( "Mozdok Runway 1", MozdokRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Nalchik + -- local NalchikBoundary = GROUP:FindByName( "Nalchik Boundary" ) + -- self.Airbases.Nalchik.ZoneBoundary = ZONE_POLYGON:New( "Nalchik Boundary", NalchikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local NalchikRunway1 = GROUP:FindByName( "Nalchik Runway 1" ) + -- self.Airbases.Nalchik.ZoneRunways[1] = ZONE_POLYGON:New( "Nalchik Runway 1", NalchikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Novorossiysk + -- local NovorossiyskBoundary = GROUP:FindByName( "Novorossiysk Boundary" ) + -- self.Airbases.Novorossiysk.ZoneBoundary = ZONE_POLYGON:New( "Novorossiysk Boundary", NovorossiyskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local NovorossiyskRunway1 = GROUP:FindByName( "Novorossiysk Runway 1" ) + -- self.Airbases.Novorossiysk.ZoneRunways[1] = ZONE_POLYGON:New( "Novorossiysk Runway 1", NovorossiyskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- SenakiKolkhi + -- local SenakiKolkhiBoundary = GROUP:FindByName( "SenakiKolkhi Boundary" ) + -- self.Airbases.SenakiKolkhi.ZoneBoundary = ZONE_POLYGON:New( "SenakiKolkhi Boundary", SenakiKolkhiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local SenakiKolkhiRunway1 = GROUP:FindByName( "SenakiKolkhi Runway 1" ) + -- self.Airbases.SenakiKolkhi.ZoneRunways[1] = ZONE_POLYGON:New( "SenakiKolkhi Runway 1", SenakiKolkhiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- SochiAdler + -- local SochiAdlerBoundary = GROUP:FindByName( "SochiAdler Boundary" ) + -- self.Airbases.SochiAdler.ZoneBoundary = ZONE_POLYGON:New( "SochiAdler Boundary", SochiAdlerBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local SochiAdlerRunway1 = GROUP:FindByName( "SochiAdler Runway 1" ) + -- self.Airbases.SochiAdler.ZoneRunways[1] = ZONE_POLYGON:New( "SochiAdler Runway 1", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- local SochiAdlerRunway2 = GROUP:FindByName( "SochiAdler Runway 2" ) + -- self.Airbases.SochiAdler.ZoneRunways[2] = ZONE_POLYGON:New( "SochiAdler Runway 2", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Soganlug + -- local SoganlugBoundary = GROUP:FindByName( "Soganlug Boundary" ) + -- self.Airbases.Soganlug.ZoneBoundary = ZONE_POLYGON:New( "Soganlug Boundary", SoganlugBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local SoganlugRunway1 = GROUP:FindByName( "Soganlug Runway 1" ) + -- self.Airbases.Soganlug.ZoneRunways[1] = ZONE_POLYGON:New( "Soganlug Runway 1", SoganlugRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- SukhumiBabushara + -- local SukhumiBabusharaBoundary = GROUP:FindByName( "SukhumiBabushara Boundary" ) + -- self.Airbases.SukhumiBabushara.ZoneBoundary = ZONE_POLYGON:New( "SukhumiBabushara Boundary", SukhumiBabusharaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local SukhumiBabusharaRunway1 = GROUP:FindByName( "SukhumiBabushara Runway 1" ) + -- self.Airbases.SukhumiBabushara.ZoneRunways[1] = ZONE_POLYGON:New( "SukhumiBabushara Runway 1", SukhumiBabusharaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- TbilisiLochini + -- local TbilisiLochiniBoundary = GROUP:FindByName( "TbilisiLochini Boundary" ) + -- self.Airbases.TbilisiLochini.ZoneBoundary = ZONE_POLYGON:New( "TbilisiLochini Boundary", TbilisiLochiniBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local TbilisiLochiniRunway1 = GROUP:FindByName( "TbilisiLochini Runway 1" ) + -- self.Airbases.TbilisiLochini.ZoneRunways[1] = ZONE_POLYGON:New( "TbilisiLochini Runway 1", TbilisiLochiniRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- local TbilisiLochiniRunway2 = GROUP:FindByName( "TbilisiLochini Runway 2" ) + -- self.Airbases.TbilisiLochini.ZoneRunways[2] = ZONE_POLYGON:New( "TbilisiLochini Runway 2", TbilisiLochiniRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + -- -- Vaziani + -- local VazianiBoundary = GROUP:FindByName( "Vaziani Boundary" ) + -- self.Airbases.Vaziani.ZoneBoundary = ZONE_POLYGON:New( "Vaziani Boundary", VazianiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local VazianiRunway1 = GROUP:FindByName( "Vaziani Runway 1" ) + -- self.Airbases.Vaziani.ZoneRunways[1] = ZONE_POLYGON:New( "Vaziani Runway 1", VazianiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + -- + -- + -- + + + -- Template + -- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) + -- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() + -- + -- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) + -- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() + + return self + +end + + + + +--- @type AIRBASEPOLICE_NEVADA +-- @extends Functional.AirbasePolice#AIRBASEPOLICE_BASE +AIRBASEPOLICE_NEVADA = { + ClassName = "AIRBASEPOLICE_NEVADA", + Airbases = { + Nellis = { + PointsBoundary = { + [1]={["y"]=-17814.714285714,["x"]=-399823.14285714,}, + [2]={["y"]=-16875.857142857,["x"]=-398763.14285714,}, + [3]={["y"]=-16251.571428571,["x"]=-398988.85714286,}, + [4]={["y"]=-16163,["x"]=-398693.14285714,}, + [5]={["y"]=-16328.714285714,["x"]=-398034.57142857,}, + [6]={["y"]=-15943,["x"]=-397571.71428571,}, + [7]={["y"]=-15711.571428571,["x"]=-397551.71428571,}, + [8]={["y"]=-15748.714285714,["x"]=-396806,}, + [9]={["y"]=-16288.714285714,["x"]=-396517.42857143,}, + [10]={["y"]=-16751.571428571,["x"]=-396308.85714286,}, + [11]={["y"]=-17263,["x"]=-396234.57142857,}, + [12]={["y"]=-17577.285714286,["x"]=-396640.28571429,}, + [13]={["y"]=-17614.428571429,["x"]=-397400.28571429,}, + [14]={["y"]=-19405.857142857,["x"]=-399428.85714286,}, + [15]={["y"]=-19234.428571429,["x"]=-399683.14285714,}, + [16]={["y"]=-18708.714285714,["x"]=-399408.85714286,}, + [17]={["y"]=-18397.285714286,["x"]=-399657.42857143,}, + [18]={["y"]=-17814.428571429,["x"]=-399823.42857143,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=-18687,["x"]=-399380.28571429,}, + [2]={["y"]=-18620.714285714,["x"]=-399436.85714286,}, + [3]={["y"]=-16217.857142857,["x"]=-396596.85714286,}, + [4]={["y"]=-16300.142857143,["x"]=-396530,}, + [5]={["y"]=-18687,["x"]=-399380.85714286,}, + }, + [2] = { + [1]={["y"]=-18451.571428572,["x"]=-399580.57142857,}, + [2]={["y"]=-18392.142857143,["x"]=-399628.57142857,}, + [3]={["y"]=-16011,["x"]=-396806.85714286,}, + [4]={["y"]=-16074.714285714,["x"]=-396751.71428572,}, + [5]={["y"]=-18451.571428572,["x"]=-399580.85714285,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + McCarran = { + PointsBoundary = { + [1]={["y"]=-29455.285714286,["x"]=-416277.42857142,}, + [2]={["y"]=-28860.142857143,["x"]=-416492,}, + [3]={["y"]=-25044.428571429,["x"]=-416344.85714285,}, + [4]={["y"]=-24580.142857143,["x"]=-415959.14285714,}, + [5]={["y"]=-25073,["x"]=-415630.57142857,}, + [6]={["y"]=-25087.285714286,["x"]=-415130.57142857,}, + [7]={["y"]=-25830.142857143,["x"]=-414866.28571428,}, + [8]={["y"]=-26658.714285715,["x"]=-414880.57142857,}, + [9]={["y"]=-26973,["x"]=-415273.42857142,}, + [10]={["y"]=-27380.142857143,["x"]=-415187.71428571,}, + [11]={["y"]=-27715.857142857,["x"]=-414144.85714285,}, + [12]={["y"]=-27551.571428572,["x"]=-413473.42857142,}, + [13]={["y"]=-28630.142857143,["x"]=-413201.99999999,}, + [14]={["y"]=-29494.428571429,["x"]=-415437.71428571,}, + [15]={["y"]=-29455.571428572,["x"]=-416277.71428571,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=-29408.428571429,["x"]=-416016.28571428,}, + [2]={["y"]=-29408.142857144,["x"]=-416105.42857142,}, + [3]={["y"]=-24680.714285715,["x"]=-416003.14285713,}, + [4]={["y"]=-24681.857142858,["x"]=-415926.57142856,}, + [5]={["y"]=-29408.42857143,["x"]=-416016.57142856,}, + }, + [2] = { + [1]={["y"]=-28575.571428572,["x"]=-416303.14285713,}, + [2]={["y"]=-28575.571428572,["x"]=-416382.57142856,}, + [3]={["y"]=-25111.000000001,["x"]=-416309.7142857,}, + [4]={["y"]=-25111.000000001,["x"]=-416249.14285713,}, + [5]={["y"]=-28575.571428572,["x"]=-416303.7142857,}, + }, + [3] = { + [1]={["y"]=-29331.000000001,["x"]=-416275.42857141,}, + [2]={["y"]=-29259.000000001,["x"]=-416306.85714284,}, + [3]={["y"]=-28005.571428572,["x"]=-413449.7142857,}, + [4]={["y"]=-28068.714285715,["x"]=-413422.85714284,}, + [5]={["y"]=-29331.000000001,["x"]=-416275.7142857,}, + }, + [4] = { + [1]={["y"]=-29073.285714286,["x"]=-416386.57142856,}, + [2]={["y"]=-28997.285714286,["x"]=-416417.42857141,}, + [3]={["y"]=-27697.571428572,["x"]=-413464.57142856,}, + [4]={["y"]=-27767.857142858,["x"]=-413434.28571427,}, + [5]={["y"]=-29073.000000001,["x"]=-416386.85714284,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + Creech = { + PointsBoundary = { + [1]={["y"]=-74522.714285715,["x"]=-360887.99999998,}, + [2]={["y"]=-74197,["x"]=-360556.57142855,}, + [3]={["y"]=-74402.714285715,["x"]=-359639.42857141,}, + [4]={["y"]=-74637,["x"]=-359279.42857141,}, + [5]={["y"]=-75759.857142857,["x"]=-359005.14285712,}, + [6]={["y"]=-75834.142857143,["x"]=-359045.14285712,}, + [7]={["y"]=-75902.714285714,["x"]=-359782.28571427,}, + [8]={["y"]=-76099.857142857,["x"]=-360399.42857141,}, + [9]={["y"]=-77314.142857143,["x"]=-360219.42857141,}, + [10]={["y"]=-77728.428571429,["x"]=-360445.14285713,}, + [11]={["y"]=-77585.571428571,["x"]=-360585.14285713,}, + [12]={["y"]=-76471.285714286,["x"]=-360819.42857141,}, + [13]={["y"]=-76325.571428571,["x"]=-360942.28571427,}, + [14]={["y"]=-74671.857142857,["x"]=-360927.7142857,}, + [15]={["y"]=-74522.714285714,["x"]=-360888.85714284,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=-74237.571428571,["x"]=-360591.7142857,}, + [2]={["y"]=-74234.428571429,["x"]=-360493.71428571,}, + [3]={["y"]=-77605.285714286,["x"]=-360399.14285713,}, + [4]={["y"]=-77608.714285715,["x"]=-360498.85714285,}, + [5]={["y"]=-74237.857142857,["x"]=-360591.7142857,}, + }, + [2] = { + [1]={["y"]=-75807.571428572,["x"]=-359073.42857142,}, + [2]={["y"]=-74770.142857144,["x"]=-360581.71428571,}, + [3]={["y"]=-74641.285714287,["x"]=-360585.42857142,}, + [4]={["y"]=-75734.142857144,["x"]=-359023.14285714,}, + [5]={["y"]=-75807.285714287,["x"]=-359073.42857142,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + GroomLake = { + PointsBoundary = { + [1]={["y"]=-88916.714285714,["x"]=-289102.28571425,}, + [2]={["y"]=-87023.571428572,["x"]=-290388.57142857,}, + [3]={["y"]=-85916.428571429,["x"]=-290674.28571428,}, + [4]={["y"]=-87645.000000001,["x"]=-286567.14285714,}, + [5]={["y"]=-88380.714285715,["x"]=-286388.57142857,}, + [6]={["y"]=-89670.714285715,["x"]=-283524.28571428,}, + [7]={["y"]=-89797.857142858,["x"]=-283567.14285714,}, + [8]={["y"]=-88635.000000001,["x"]=-286749.99999999,}, + [9]={["y"]=-89177.857142858,["x"]=-287207.14285714,}, + [10]={["y"]=-89092.142857144,["x"]=-288892.85714285,}, + [11]={["y"]=-88917.000000001,["x"]=-289102.85714285,}, + }, + PointsRunways = { + [1] = { + [1]={["y"]=-86039.000000001,["x"]=-290606.28571428,}, + [2]={["y"]=-85965.285714287,["x"]=-290573.99999999,}, + [3]={["y"]=-87692.714285715,["x"]=-286634.85714285,}, + [4]={["y"]=-87756.714285715,["x"]=-286663.99999999,}, + [5]={["y"]=-86038.714285715,["x"]=-290606.85714285,}, + }, + [2] = { + [1]={["y"]=-86808.428571429,["x"]=-290375.7142857,}, + [2]={["y"]=-86732.714285715,["x"]=-290344.28571427,}, + [3]={["y"]=-89672.714285714,["x"]=-283546.57142855,}, + [4]={["y"]=-89772.142857143,["x"]=-283587.71428569,}, + [5]={["y"]=-86808.142857143,["x"]=-290375.7142857,}, + }, + }, + ZoneBoundary = {}, + ZoneRunways = {}, + MaximumSpeed = 50, + }, + }, +} + +--- Creates a new AIRBASEPOLICE_NEVADA object. +-- @param #AIRBASEPOLICE_NEVADA self +-- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. +-- @return #AIRBASEPOLICE_NEVADA self +function AIRBASEPOLICE_NEVADA:New( SetClient ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) + +-- -- Nellis +-- local NellisBoundary = GROUP:FindByName( "Nellis Boundary" ) +-- self.Airbases.Nellis.ZoneBoundary = ZONE_POLYGON:New( "Nellis Boundary", NellisBoundary ):SmokeZone(SMOKECOLOR.White):Flush() +-- +-- local NellisRunway1 = GROUP:FindByName( "Nellis Runway 1" ) +-- self.Airbases.Nellis.ZoneRunways[1] = ZONE_POLYGON:New( "Nellis Runway 1", NellisRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local NellisRunway2 = GROUP:FindByName( "Nellis Runway 2" ) +-- self.Airbases.Nellis.ZoneRunways[2] = ZONE_POLYGON:New( "Nellis Runway 2", NellisRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- -- McCarran +-- local McCarranBoundary = GROUP:FindByName( "McCarran Boundary" ) +-- self.Airbases.McCarran.ZoneBoundary = ZONE_POLYGON:New( "McCarran Boundary", McCarranBoundary ):SmokeZone(SMOKECOLOR.White):Flush() +-- +-- local McCarranRunway1 = GROUP:FindByName( "McCarran Runway 1" ) +-- self.Airbases.McCarran.ZoneRunways[1] = ZONE_POLYGON:New( "McCarran Runway 1", McCarranRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local McCarranRunway2 = GROUP:FindByName( "McCarran Runway 2" ) +-- self.Airbases.McCarran.ZoneRunways[2] = ZONE_POLYGON:New( "McCarran Runway 2", McCarranRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local McCarranRunway3 = GROUP:FindByName( "McCarran Runway 3" ) +-- self.Airbases.McCarran.ZoneRunways[3] = ZONE_POLYGON:New( "McCarran Runway 3", McCarranRunway3 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local McCarranRunway4 = GROUP:FindByName( "McCarran Runway 4" ) +-- self.Airbases.McCarran.ZoneRunways[4] = ZONE_POLYGON:New( "McCarran Runway 4", McCarranRunway4 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- -- Creech +-- local CreechBoundary = GROUP:FindByName( "Creech Boundary" ) +-- self.Airbases.Creech.ZoneBoundary = ZONE_POLYGON:New( "Creech Boundary", CreechBoundary ):SmokeZone(SMOKECOLOR.White):Flush() +-- +-- local CreechRunway1 = GROUP:FindByName( "Creech Runway 1" ) +-- self.Airbases.Creech.ZoneRunways[1] = ZONE_POLYGON:New( "Creech Runway 1", CreechRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local CreechRunway2 = GROUP:FindByName( "Creech Runway 2" ) +-- self.Airbases.Creech.ZoneRunways[2] = ZONE_POLYGON:New( "Creech Runway 2", CreechRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- -- Groom Lake +-- local GroomLakeBoundary = GROUP:FindByName( "GroomLake Boundary" ) +-- self.Airbases.GroomLake.ZoneBoundary = ZONE_POLYGON:New( "GroomLake Boundary", GroomLakeBoundary ):SmokeZone(SMOKECOLOR.White):Flush() +-- +-- local GroomLakeRunway1 = GROUP:FindByName( "GroomLake Runway 1" ) +-- self.Airbases.GroomLake.ZoneRunways[1] = ZONE_POLYGON:New( "GroomLake Runway 1", GroomLakeRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() +-- +-- local GroomLakeRunway2 = GROUP:FindByName( "GroomLake Runway 2" ) +-- self.Airbases.GroomLake.ZoneRunways[2] = ZONE_POLYGON:New( "GroomLake Runway 2", GroomLakeRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() + +end + + + + + + --- **Functional** - DETECTION_ classes model the detection of enemy units by FACs or RECCEs and group them according various methods. +-- +-- ![Banner Image](..\Presentations\DETECTION\Dia1.JPG) +-- +-- === +-- +-- DETECTION classes facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units). +-- DETECTION uses the in-built detection capabilities of DCS World, but adds new functionalities. +-- +-- Please watch this [youtube video](https://youtu.be/C7p81dUwP-E) that explains the detection concepts. +-- +-- +-- ### Contributions: +-- +-- * Mechanist : Early concept of DETECTION_AREAS. +-- +-- ### Authors: +-- +-- * FlightControl : Analysis, Design, Programming, Testing +-- +-- @module Detection + + +do -- DETECTION_BASE + + --- # 1) DETECTION_BASE class, extends @{Fsm#FSM} + -- + -- The DETECTION_BASE class defines the core functions to administer detected objects. + -- The DETECTION_BASE class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s). + -- + -- ## 1.1) DETECTION_BASE constructor + -- + -- Construct a new DETECTION_BASE instance using the @{#DETECTION_BASE.New}() method. + -- + -- ## 1.2) DETECTION_BASE initialization + -- + -- By default, detection will return detected objects with all the detection sensors available. + -- However, you can ask how the objects were found with specific detection methods. + -- If you use one of the below methods, the detection will work with the detection method specified. + -- You can specify to apply multiple detection methods. + -- + -- Use the following functions to report the objects it detected using the methods Visual, Optical, Radar, IRST, RWR, DLINK: + -- + -- * @{#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. + -- * @{#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. + -- * @{#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. + -- * @{#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. + -- * @{#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. + -- * @{#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. + -- + -- ## 1.3) DETECTION_BASE derived classes group the detected units into a DetectedItems[] list + -- + -- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later + -- of grouping of detected units. Each DetectedItem within the DetectedItems[] list contains + -- a SET_UNIT object that contains the detected units that belong to that group. + -- + -- Derived classes will apply different methods to group the detected units. + -- Examples are per area, per quadrant, per distance, per type. + -- See further the derived DETECTION classes on which grouping methods are currently supported. + -- + -- Various methods exist how to retrieve the grouped items from a DETECTION_BASE derived class: + -- + -- * The method @{Detection#DETECTION_BASE.GetDetectedItems}() retrieves the DetectedItems[] list. + -- * A DetectedItem from the DetectedItems[] list can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedItem}( DetectedItemIndex ). + -- Note that this method returns a DetectedItem element from the list, that contains a Set variable and further information + -- about the DetectedItem that is set by the DETECTION_BASE derived classes, used to group the DetectedItem. + -- * A DetectedSet from the DetectedItems[] list can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSet}( DetectedItemIndex ). + -- This method retrieves the Set from a DetectedItem element from the DetectedItem list (DetectedItems[ DetectedItemIndex ].Set ). + -- + -- ## 1.4) Apply additional Filters to fine-tune the detected objects + -- + -- By default, DCS World will return any object that is in LOS and within "visual reach", or detectable through one of the electronic detection means. + -- That being said, the DCS World detection algorithm can sometimes be unrealistic. + -- Especially for a visual detection, DCS World is able to report within 1 second a detailed detection of a group of 20 units (including types of the units) that are 10 kilometers away, using only visual capabilities. + -- Additionally, trees and other obstacles are not accounted during the DCS World detection. + -- + -- Therefore, an additional (optional) filtering has been built into the DETECTION_BASE class, that can be set for visual detected units. + -- For electronic detection, this filtering is not applied, only for visually detected targets. + -- + -- The following additional filtering can be applied for visual filtering: + -- + -- * A probability factor per kilometer distance. + -- * A probability factor based on the alpha angle between the detected object and the unit detecting. + -- A detection from a higher altitude allows for better detection than when on the ground. + -- * Define a probability factor for "cloudy zones", which are zones where forests or villages are located. In these zones, detection will be much more difficult. + -- The mission designer needs to define these cloudy zones within the mission, and needs to register these zones in the DETECTION_ objects additing a probability factor per zone. + -- + -- I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters. + -- Only when you experience unrealistic behaviour in your missions, these filters could be applied. + -- + -- ### 1.4.1 ) Distance visual detection probability + -- + -- Upon a **visual** detection, the further away a detected object is, the less likely it is to be detected properly. + -- Also, the speed of accurate detection plays a role. + -- + -- A distance probability factor between 0 and 1 can be given, that will model a linear extrapolated probability over 10 km distance. + -- + -- For example, if a probability factor of 0.6 (60%) is given, the extrapolated probabilities over 15 kilometers would like like: + -- 1 km: 96%, 2 km: 92%, 3 km: 88%, 4 km: 84%, 5 km: 80%, 6 km: 76%, 7 km: 72%, 8 km: 68%, 9 km: 64%, 10 km: 60%, 11 km: 56%, 12 km: 52%, 13 km: 48%, 14 km: 44%, 15 km: 40%. + -- + -- Note that based on this probability factor, not only the detection but also the **type** of the unit will be applied! + -- + -- Use the method @{Detection#DETECTION_BASE.SetDistanceProbability}() to set the probability factor upon a 10 km distance. + -- + -- ### 1.4.2 ) Alpha Angle visual detection probability + -- + -- Upon a **visual** detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly. + -- A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct. + -- + -- A probability factor between 0 and 1 can be given, that will model a progressive extrapolated probability if the target would be detected at a 0° angle. + -- + -- For example, if a alpha angle probability factor of 0.7 is given, the extrapolated probabilities of the different angles would look like: + -- 0°: 70%, 10°: 75,21%, 20°: 80,26%, 30°: 85%, 40°: 89,28%, 50°: 92,98%, 60°: 95,98%, 70°: 98,19%, 80°: 99,54%, 90°: 100% + -- + -- Use the method @{Detection#DETECTION_BASE.SetAlphaAngleProbability}() to set the probability factor if 0°. + -- + -- ### 1.4.3 ) Cloudy Zones detection probability + -- + -- Upon a **visual** detection, the more a detected unit is within a cloudy zone, the less likely the detected unit is to be detected successfully. + -- The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission + -- zones that reflect cloudy areas where detected units may not be so easily visually detected. + -- + -- Use the method @{Detection#DETECTION_BASE.SetZoneProbability}() to set for a defined number of zones, the probability factors. + -- + -- Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take + -- from the DETECTION_BASE to calculate the presence of the detected unit within each zone. + -- Expecially for ZONE_POLYGON, try to limit the amount of nodes of the polygon! + -- + -- Typically, this kind of filter would be applied for very specific areas were a detection needs to be very realisting for + -- AI not to detect so easily targets within a forrest or village rich area. + -- + -- ## 1.5 ) Accept / Reject detected units + -- + -- DETECTION_BASE can accept or reject successful detections based on the location of the detected object, + -- if it is located in range or located inside or outside of specific zones. + -- + -- ### 1.5.1 ) Detection acceptance of within range limit + -- + -- A range can be set that will limit a successful detection for a unit. + -- Use the method @{Detection#DETECTION_BASE.SetAcceptRange}() to apply a range in meters till where detected units will be accepted. + -- + -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. + -- + -- -- Build a detect object. + -- local Detection = DETECTION_BASE:New( SetGroup ) + -- + -- -- This will accept detected units if the range is below 5000 meters. + -- Detection:SetAcceptRange( 5000 ) + -- + -- -- Start the Detection. + -- Detection:Start() + -- + -- + -- ### 1.5.2 ) Detection acceptance if within zone(s). + -- + -- Specific ZONE_BASE object(s) can be given as a parameter, which will only accept a detection if the unit is within the specified ZONE_BASE object(s). + -- Use the method @{Detection#DETECTION_BASE.SetAcceptZones}() will accept detected units if they are within the specified zones. + -- + -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. + -- + -- -- Search fo the zones where units are to be accepted. + -- local ZoneAccept1 = ZONE:New( "AcceptZone1" ) + -- local ZoneAccept2 = ZONE:New( "AcceptZone2" ) + -- + -- -- Build a detect object. + -- local Detection = DETECTION_BASE:New( SetGroup ) + -- + -- -- This will accept detected units by Detection when the unit is within ZoneAccept1 OR ZoneAccept2. + -- Detection:SetAcceptZones( { ZoneAccept1, ZoneAccept2 } ) + -- + -- -- Start the Detection. + -- Detection:Start() + -- + -- ### 1.5.3 ) Detection rejectance if within zone(s). + -- + -- Specific ZONE_BASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONE_BASE object(s). + -- Use the method @{Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones. + -- An example of how to use the method is shown below. + -- + -- local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers. + -- + -- -- Search fo the zones where units are to be rejected. + -- local ZoneReject1 = ZONE:New( "RejectZone1" ) + -- local ZoneReject2 = ZONE:New( "RejectZone2" ) + -- + -- -- Build a detect object. + -- local Detection = DETECTION_BASE:New( SetGroup ) + -- + -- -- This will reject detected units by Detection when the unit is within ZoneReject1 OR ZoneReject2. + -- Detection:SetRejectZones( { ZoneReject1, ZoneReject2 } ) + -- + -- -- Start the Detection. + -- Detection:Start() + -- + -- ## 1.6) DETECTION_BASE is a Finite State Machine + -- + -- Various Events and State Transitions can be tailored using DETECTION_BASE. + -- + -- ### 1.6.1) DETECTION_BASE States + -- + -- * **Detecting**: The detection is running. + -- * **Stopped**: The detection is stopped. + -- + -- ### 1.6.2) DETECTION_BASE Events + -- + -- * **Start**: Start the detection process. + -- * **Detect**: Detect new units. + -- * **Detected**: New units have been detected. + -- * **Stop**: Stop the detection process. + -- + -- @type DETECTION_BASE + -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. + -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. + -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. + -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. + -- @field #number DetectionRun + -- @extends Core.Fsm#FSM + DETECTION_BASE = { + ClassName = "DETECTION_BASE", + DetectionSetGroup = nil, + DetectionRange = nil, + DetectedObjects = {}, + DetectionRun = 0, + DetectedObjectsIdentified = {}, + DetectedItems = {}, + } + + --- @type DETECTION_BASE.DetectedObjects + -- @list <#DETECTION_BASE.DetectedObject> + + --- @type DETECTION_BASE.DetectedObject + -- @field #string Name + -- @field #boolean Visible + -- @field #string Type + -- @field #number Distance + -- @field #boolean Identified + + --- @type DETECTION_BASE.DetectedItems + -- @list <#DETECTION_BASE.DetectedItem> + + --- @type DETECTION_BASE.DetectedItem + -- @field Core.Set#SET_UNIT Set + -- @field Core.Set#SET_UNIT Set -- The Set of Units in the detected area. + -- @field Core.Zone#ZONE_UNIT Zone -- The Zone of the detected area. + -- @field #boolean Changed Documents if the detected area has changes. + -- @field #table Changes A list of the changes reported on the detected area. (It is up to the user of the detected area to consume those changes). + -- @field #number ItemID -- The identifier of the detected area. + -- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area. + -- @field Wrapper.Unit#UNIT NearestFAC The nearest FAC near the Area. + + + --- DETECTION constructor. + -- @param #DETECTION_BASE self + -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. + -- @return #DETECTION_BASE self + function DETECTION_BASE:New( DetectionSetGroup ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New() ) -- #DETECTION_BASE + + self.DetectedItemCount = 0 + self.DetectedItemMax = 0 + self.DetectedItems = {} + + self.DetectionSetGroup = DetectionSetGroup + + self.DetectionInterval = 30 + + self:InitDetectVisual( true ) + self:InitDetectOptical( false ) + self:InitDetectRadar( false ) + self:InitDetectRWR( false ) + self:InitDetectIRST( false ) + self:InitDetectDLINK( false ) + + -- Create FSM transitions. + + self:SetStartState( "Stopped" ) + self.CountryID = DetectionSetGroup:GetFirst():GetCountry() + + self:AddTransition( "Stopped", "Start", "Detecting") + + --- OnLeave Transition Handler for State Stopped. + -- @function [parent=#DETECTION_BASE] OnLeaveStopped + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Stopped. + -- @function [parent=#DETECTION_BASE] OnEnterStopped + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnBefore Transition Handler for Event Start. + -- @function [parent=#DETECTION_BASE] OnBeforeStart + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Start. + -- @function [parent=#DETECTION_BASE] OnAfterStart + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Start. + -- @function [parent=#DETECTION_BASE] Start + -- @param #DETECTION_BASE self + + --- Asynchronous Event Trigger for Event Start. + -- @function [parent=#DETECTION_BASE] __Start + -- @param #DETECTION_BASE self + -- @param #number Delay The delay in seconds. + + --- OnLeave Transition Handler for State Detecting. + -- @function [parent=#DETECTION_BASE] OnLeaveDetecting + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Detecting. + -- @function [parent=#DETECTION_BASE] OnEnterDetecting + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + self:AddTransition( "Detecting", "Detect", "Detecting" ) + self:AddTransition( "Detecting", "DetectionGroup", "Detecting" ) + + --- OnBefore Transition Handler for Event Detect. + -- @function [parent=#DETECTION_BASE] OnBeforeDetect + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Detect. + -- @function [parent=#DETECTION_BASE] OnAfterDetect + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Detect. + -- @function [parent=#DETECTION_BASE] Detect + -- @param #DETECTION_BASE self + + --- Asynchronous Event Trigger for Event Detect. + -- @function [parent=#DETECTION_BASE] __Detect + -- @param #DETECTION_BASE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Detecting", "Detected", "Detecting" ) + + --- OnBefore Transition Handler for Event Detected. + -- @function [parent=#DETECTION_BASE] OnBeforeDetected + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Detected. + -- @function [parent=#DETECTION_BASE] OnAfterDetected + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Detected. + -- @function [parent=#DETECTION_BASE] Detected + -- @param #DETECTION_BASE self + + --- Asynchronous Event Trigger for Event Detected. + -- @function [parent=#DETECTION_BASE] __Detected + -- @param #DETECTION_BASE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "*", "Stop", "Stopped" ) + + --- OnBefore Transition Handler for Event Stop. + -- @function [parent=#DETECTION_BASE] OnBeforeStop + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Stop. + -- @function [parent=#DETECTION_BASE] OnAfterStop + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Stop. + -- @function [parent=#DETECTION_BASE] Stop + -- @param #DETECTION_BASE self + + --- Asynchronous Event Trigger for Event Stop. + -- @function [parent=#DETECTION_BASE] __Stop + -- @param #DETECTION_BASE self + -- @param #number Delay The delay in seconds. + + --- OnLeave Transition Handler for State Stopped. + -- @function [parent=#DETECTION_BASE] OnLeaveStopped + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Stopped. + -- @function [parent=#DETECTION_BASE] OnEnterStopped + -- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + return self + end + + do -- State Transition Handling + + --- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + function DETECTION_BASE:onafterStart(From,Event,To) + self:__Detect(0.1) + end + + --- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + function DETECTION_BASE:onafterDetect(From,Event,To) + self:E( {From,Event,To}) + + local DetectDelay = 0.1 + self.DetectionCount = 0 + self.DetectionRun = 0 + self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table + + self.DetectionSetGroup:Flush() + + for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do + self:E( {DetectionGroupData}) + self:__DetectionGroup( DetectDelay, DetectionGroupData ) -- Process each detection asynchronously. + self.DetectionCount = self.DetectionCount + 1 + DetectDelay = DetectDelay + 0.1 + end + end + + --- @param #DETECTION_BASE self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Wrapper.Group#GROUP DetectionGroup The Group detecting. + function DETECTION_BASE:onafterDetectionGroup( From, Event, To, DetectionGroup ) + self:E( {From,Event,To}) + + self.DetectionRun = self.DetectionRun + 1 + + local HasDetectedObjects = false + + if DetectionGroup:IsAlive() then + + self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } ) + + local DetectionGroupName = DetectionGroup:GetName() + + local DetectedUnits = {} + + local DetectedTargets = DetectionGroup:GetDetectedTargets( + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) + + self:T( DetectedTargets ) + + for DetectionObjectID, Detection in pairs( DetectedTargets ) do + local DetectedObject = Detection.object -- Dcs.DCSWrapper.Object#Object + self:T2( DetectedObject ) + + if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then + + local DetectionAccepted = true + + local DetectedObjectName = DetectedObject:getName() + + local DetectedObjectVec3 = DetectedObject:getPoint() + local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z } + local DetectionGroupVec3 = DetectionGroup:GetVec3() + local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z } + + local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 + + ( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 + + ( DetectedObjectVec3.z - DetectionGroupVec3.z )^2 + ) ^ 0.5 / 1000 + + self:T( { "Detected Target", DetectionGroupName, DetectedObjectName, Distance } ) + + -- Calculate Acceptance + + if self.AcceptRange and Distance > self.AcceptRange then + DetectionAccepted = false + end + + if self.AcceptZones then + for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do + local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE + if AcceptZone:IsPointVec2InZone( DetectedObjectVec2 ) == false then + DetectionAccepted = false + end + end + end + + if self.RejectZones then + for RejectZoneID, RejectZone in pairs( self.RejectZones ) do + local RejectZone = RejectZone -- Core.Zone#ZONE_BASE + if RejectZone:IsPointVec2InZone( DetectedObjectVec2 ) == true then + DetectionAccepted = false + end + end + end + + -- Calculate additional probabilities + + if not self.DetectedObjects[DetectedObjectName] and Detection.visible and self.DistanceProbability then + local DistanceFactor = Distance / 4 + local DistanceProbabilityReversed = ( 1 - self.DistanceProbability ) * DistanceFactor + local DistanceProbability = 1 - DistanceProbabilityReversed + DistanceProbability = DistanceProbability * 30 / 300 + local Probability = math.random() -- Selects a number between 0 and 1 + self:T( { Probability, DistanceProbability } ) + if Probability > DistanceProbability then + DetectionAccepted = false + end + end + + if not self.DetectedObjects[DetectedObjectName] and Detection.visible and self.AlphaAngleProbability then + local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y } + local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x ) + local Sinus = math.sin( AlphaAngle ) + local AlphaAngleProbabilityReversed = ( 1 - self.AlphaAngleProbability ) * ( 1 - Sinus ) + local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed + + AlphaAngleProbability = AlphaAngleProbability * 30 / 300 + + local Probability = math.random() -- Selects a number between 0 and 1 + self:T( { Probability, AlphaAngleProbability } ) + if Probability > AlphaAngleProbability then + DetectionAccepted = false + end + + end + + if not self.DetectedObjects[DetectedObjectName] and Detection.visible and self.ZoneProbability then + + for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do + self:E({ZoneData}) + local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE + local ZoneProbability = ZoneData[2] -- #number + ZoneProbability = ZoneProbability * 30 / 300 + + if ZoneObject:IsPointVec2InZone( DetectedObjectVec2 ) == true then + local Probability = math.random() -- Selects a number between 0 and 1 + self:T( { Probability, ZoneProbability } ) + if Probability > ZoneProbability then + DetectionAccepted = false + break + end + end + end + end + + if DetectionAccepted then + + HasDetectedObjects = true + + if not self.DetectedObjects[DetectedObjectName] then + self.DetectedObjects[DetectedObjectName] = {} + end + self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName + self.DetectedObjects[DetectedObjectName].Visible = Detection.visible + self.DetectedObjects[DetectedObjectName].Type = Detection.type + self.DetectedObjects[DetectedObjectName].Distance = Distance + + local DetectedUnit = UNIT:FindByName( DetectedObjectName ) + + DetectedUnits[DetectedObjectName] = DetectedUnit + else + -- if beyond the DetectionRange then nullify... + if self.DetectedObjects[DetectedObjectName] then + self.DetectedObjects[DetectedObjectName] = nil + end + end + end + + self:T2( self.DetectedObjects ) + end + + if HasDetectedObjects then + self:__Detected( 0.1, DetectedUnits ) + end + + end + + if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then + self:__Detect( self.DetectionInterval ) + + self:T( "--> Create Detection Sets" ) + self:CreateDetectionSets() + end + + end + + + end + + do -- Initialization methods + + --- Detect Visual. + -- @param #DETECTION_BASE self + -- @param #boolean DetectVisual + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectVisual( DetectVisual ) + + self.DetectVisual = DetectVisual + end + + --- Detect Optical. + -- @param #DETECTION_BASE self + -- @param #boolean DetectOptical + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectOptical( DetectOptical ) + self:F2() + + self.DetectOptical = DetectOptical + end + + --- Detect Radar. + -- @param #DETECTION_BASE self + -- @param #boolean DetectRadar + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectRadar( DetectRadar ) + self:F2() + + self.DetectRadar = DetectRadar + end + + --- Detect IRST. + -- @param #DETECTION_BASE self + -- @param #boolean DetectIRST + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectIRST( DetectIRST ) + self:F2() + + self.DetectIRST = DetectIRST + end + + --- Detect RWR. + -- @param #DETECTION_BASE self + -- @param #boolean DetectRWR + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectRWR( DetectRWR ) + self:F2() + + self.DetectRWR = DetectRWR + end + + --- Detect DLINK. + -- @param #DETECTION_BASE self + -- @param #boolean DetectDLINK + -- @return #DETECTION_BASE self + function DETECTION_BASE:InitDetectDLINK( DetectDLINK ) + self:F2() + + self.DetectDLINK = DetectDLINK + end + + end + + do + + --- Set the detection interval time in seconds. + -- @param #DETECTION_BASE self + -- @param #number DetectionInterval Interval in seconds. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetDetectionInterval( DetectionInterval ) + self:F2() + + self.DetectionInterval = DetectionInterval + + return self + end + + end + + do -- Accept / Reject detected units + + --- Accept detections if within a range in meters. + -- @param #DETECTION_BASE self + -- @param #number AcceptRange Accept a detection if the unit is within the AcceptRange in meters. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetAcceptRange( AcceptRange ) + self:F2() + + self.AcceptRange = AcceptRange + + return self + end + + --- Accept detections if within the specified zone(s). + -- @param #DETECTION_BASE self + -- @param AcceptZones Can be a list or ZONE_BASE objects, or a single ZONE_BASE object. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetAcceptZones( AcceptZones ) + self:F2() + + if type( AcceptZones ) == "table" then + self.AcceptZones = AcceptZones + else + self.AcceptZones = { AcceptZones } + end + + return self + end + + --- Reject detections if within the specified zone(s). + -- @param #DETECTION_BASE self + -- @param RejectZones Can be a list or ZONE_BASE objects, or a single ZONE_BASE object. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetRejectZones( RejectZones ) + self:F2() + + if type( RejectZones ) == "table" then + self.RejectZones = RejectZones + else + self.RejectZones = { RejectZones } + end + + return self + end + + end + + do -- Probability methods + + --- Upon a **visual** detection, the further away a detected object is, the less likely it is to be detected properly. + -- Also, the speed of accurate detection plays a role. + -- A distance probability factor between 0 and 1 can be given, that will model a linear extrapolated probability over 10 km distance. + -- For example, if a probability factor of 0.6 (60%) is given, the extrapolated probabilities over 15 kilometers would like like: + -- 1 km: 96%, 2 km: 92%, 3 km: 88%, 4 km: 84%, 5 km: 80%, 6 km: 76%, 7 km: 72%, 8 km: 68%, 9 km: 64%, 10 km: 60%, 11 km: 56%, 12 km: 52%, 13 km: 48%, 14 km: 44%, 15 km: 40%. + -- @param #DETECTION_BASE self + -- @param DistanceProbability The probability factor. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetDistanceProbability( DistanceProbability ) + self:F2() + + self.DistanceProbability = DistanceProbability + + return self + end + + + --- Upon a **visual** detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly. + -- A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct. + -- + -- A probability factor between 0 and 1 can be given, that will model a progressive extrapolated probability if the target would be detected at a 0° angle. + -- + -- For example, if a alpha angle probability factor of 0.7 is given, the extrapolated probabilities of the different angles would look like: + -- 0°: 70%, 10°: 75,21%, 20°: 80,26%, 30°: 85%, 40°: 89,28%, 50°: 92,98%, 60°: 95,98%, 70°: 98,19%, 80°: 99,54%, 90°: 100% + -- @param #DETECTION_BASE self + -- @param AlphaAngleProbability The probability factor. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetAlphaAngleProbability( AlphaAngleProbability ) + self:F2() + + self.AlphaAngleProbability = AlphaAngleProbability + + return self + end + + --- Upon a **visual** detection, the more a detected unit is within a cloudy zone, the less likely the detected unit is to be detected successfully. + -- The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission + -- zones that reflect cloudy areas where detected units may not be so easily visually detected. + -- @param #DETECTION_BASE self + -- @param ZoneArray Aray of a The ZONE_BASE object and a ZoneProbability pair.. + -- @return #DETECTION_BASE self + function DETECTION_BASE:SetZoneProbability( ZoneArray ) + self:F2() + + self.ZoneProbability = ZoneArray + + return self + end + + + end + + do -- Change processing + + --- Accepts changes from the detected item. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @return #DETECTION_BASE self + function DETECTION_BASE:AcceptChanges( DetectedItem ) + + DetectedItem.Changed = false + DetectedItem.Changes = {} + + return self + end + + --- Add a change to the detected zone. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @param #string ChangeCode + -- @return #DETECTION_BASE self + function DETECTION_BASE:AddChangeItem( DetectedItem, ChangeCode, ItemUnitType ) + + DetectedItem.Changed = true + local ItemID = DetectedItem.ItemID + + DetectedItem.Changes = DetectedItem.Changes or {} + DetectedItem.Changes[ChangeCode] = DetectedItem.Changes[ChangeCode] or {} + DetectedItem.Changes[ChangeCode].ItemID = ItemID + DetectedItem.Changes[ChangeCode].ItemUnitType = ItemUnitType + + self:T( { "Change on Detection Item:", DetectedItem.ItemID, ChangeCode, ItemUnitType } ) + + return self + end + + + --- Add a change to the detected zone. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @param #string ChangeCode + -- @param #string ChangeUnitType + -- @return #DETECTION_BASE self + function DETECTION_BASE:AddChangeUnit( DetectedItem, ChangeCode, ChangeUnitType ) + + DetectedItem.Changed = true + local ItemID = DetectedItem.ItemID + + DetectedItem.Changes = DetectedItem.Changes or {} + DetectedItem.Changes[ChangeCode] = DetectedItem.Changes[ChangeCode] or {} + DetectedItem.Changes[ChangeCode][ChangeUnitType] = DetectedItem.Changes[ChangeCode][ChangeUnitType] or 0 + DetectedItem.Changes[ChangeCode][ChangeUnitType] = DetectedItem.Changes[ChangeCode][ChangeUnitType] + 1 + DetectedItem.Changes[ChangeCode].ItemID = ItemID + + self:T( { "Change on Detection Item:", DetectedItem.ItemID, ChangeCode, ChangeUnitType } ) + + return self + end + + + end + + do -- Threat + + --- Returns if there are friendlies nearby the FAC units ... + -- @param #DETECTION_BASE self + -- @return #boolean trhe if there are friendlies nearby + function DETECTION_BASE:IsFriendliesNearBy( DetectedItem ) + + self:T3( DetectedItem.FriendliesNearBy ) + return DetectedItem.FriendliesNearBy or false + end + + --- Background worker function to determine if there are friendlies nearby ... + -- @param #DETECTION_BASE self + function DETECTION_BASE:ReportFriendliesNearBy( ReportGroupData ) + self:F2() + + local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = ReportGroupData.DetectedItem.Set + local DetectedUnit = DetectedSet:GetFirst() + + DetectedItem.FriendliesNearBy = false + + if DetectedUnit then + + + local SphereSearch = { + id = world.VolumeType.SPHERE, + params = { + point = DetectedUnit:GetVec3(), + radius = 6000, + } + + } + + --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit + -- @param Wrapper.Group#GROUP ReportGroup + -- @param Set#SET_GROUP ReportSetGroup + local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) + + local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = ReportGroupData.DetectedItem.Set + local DetectedUnit = DetectedSet:GetFirst() -- Wrapper.Unit#UNIT + local ReportSetGroup = ReportGroupData.ReportSetGroup + + local EnemyCoalition = DetectedUnit:GetCoalition() + + local FoundUnitCoalition = FoundDCSUnit:getCoalition() + local FoundUnitName = FoundDCSUnit:getName() + local FoundUnitGroupName = FoundDCSUnit:getGroup():getName() + local EnemyUnitName = DetectedUnit:GetName() + local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil + + self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) + + if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then + DetectedItem.FriendliesNearBy = true + return false + end + + return true + end + + world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData ) + end + end + + end + + --- Determines if a detected object has already been identified during detection processing. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedObject DetectedObject + -- @return #boolean true if already identified. + function DETECTION_BASE:IsDetectedObjectIdentified( DetectedObject ) + self:F3( DetectedObject.Name ) + + local DetectedObjectName = DetectedObject.Name + local DetectedObjectIdentified = self.DetectedObjectsIdentified[DetectedObjectName] == true + self:T3( DetectedObjectIdentified ) + return DetectedObjectIdentified + end + + --- Identifies a detected object during detection processing. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedObject DetectedObject + function DETECTION_BASE:IdentifyDetectedObject( DetectedObject ) + self:F( { "Identified:", DetectedObject.Name } ) + + local DetectedObjectName = DetectedObject.Name + self.DetectedObjectsIdentified[DetectedObjectName] = true + end + + --- UnIdentify a detected object during detection processing. + -- @param #DETECTION_BASE self + -- @param #DETECTION_BASE.DetectedObject DetectedObject + function DETECTION_BASE:UnIdentifyDetectedObject( DetectedObject ) + + local DetectedObjectName = DetectedObject.Name + self.DetectedObjectsIdentified[DetectedObjectName] = false + end + + --- UnIdentify all detected objects during detection processing. + -- @param #DETECTION_BASE self + function DETECTION_BASE:UnIdentifyAllDetectedObjects() + + self.DetectedObjectsIdentified = {} -- Table will be garbage collected. + end + + --- Gets a detected object with a given name. + -- @param #DETECTION_BASE self + -- @param #string ObjectName + -- @return #DETECTION_BASE.DetectedObject + function DETECTION_BASE:GetDetectedObject( ObjectName ) + self:F( ObjectName ) + + if ObjectName then + local DetectedObject = self.DetectedObjects[ObjectName] + + -- Only return detected objects that are alive! + local DetectedUnit = UNIT:FindByName( ObjectName ) + if DetectedUnit and DetectedUnit:IsAlive() then + if self:IsDetectedObjectIdentified( DetectedObject ) == false then + return DetectedObject + end + end + end + + return nil + end + + + --- Adds a new DetectedItem to the DetectedItems list. + -- The DetectedItem is a table and contains a SET_UNIT in the field Set. + -- @param #DETECTION_BASE self + -- @param #string DetectedItemIndex The index of the DetectedItem. + -- @param Core.Set#SET_UNIT Set (optional) The Set of Units to be added. + -- @return #DETECTION_BASE.DetectedItem + function DETECTION_BASE:AddDetectedItem( DetectedItemIndex, Set ) + + local DetectedItem = {} + self.DetectedItemCount = self.DetectedItemCount + 1 + self.DetectedItemMax = self.DetectedItemMax + 1 + + if DetectedItemIndex then + self.DetectedItems[DetectedItemIndex] = DetectedItem + else + self.DetectedItems[self.DetectedItemCount] = DetectedItem + end + + DetectedItem.Set = Set or SET_UNIT:New() + DetectedItem.ItemID = self.DetectedItemMax + DetectedItem.Removed = false + + return DetectedItem + end + + --- Adds a new DetectedItem to the DetectedItems list. + -- The DetectedItem is a table and contains a SET_UNIT in the field Set. + -- @param #DETECTION_BASE self + -- @param #string DetectedItemIndex The index of the DetectedItem. + -- @param Core.Set#SET_UNIT Set (optional) The Set of Units to be added. + -- @param Core.Zone#ZONE_UNIT Zone (optional) The Zone to be added where the Units are located. + -- @return #DETECTION_BASE.DetectedItem + function DETECTION_BASE:AddDetectedItemZone( DetectedItemIndex, Set, Zone ) + + local DetectedItem = self:AddDetectedItem( DetectedItemIndex, Set ) + + DetectedItem.Zone = Zone + + return DetectedItem + end + + --- Removes an existing DetectedItem from the DetectedItems list. + -- The DetectedItem is a table and contains a SET_UNIT in the field Set. + -- @param #DETECTION_BASE self + -- @param #number DetectedItemIndex The index or position in the DetectedItems list where the item needs to be removed. + function DETECTION_BASE:RemoveDetectedItem( DetectedItemIndex ) + + self.DetectedItemCount = self.DetectedItemCount - 1 + self.DetectedItems[DetectedItemIndex] = nil + end + + + --- Get the detected @{Set#SET_BASE}s. + -- @param #DETECTION_BASE self + -- @return #DETECTION_BASE.DetectedItems + function DETECTION_BASE:GetDetectedItems() + + return self.DetectedItems + end + + --- Get the amount of SETs with detected objects. + -- @param #DETECTION_BASE self + -- @return #number Count + function DETECTION_BASE:GetDetectedItemsCount() + + local DetectedCount = self.DetectedItemCount + return DetectedCount + end + + --- Get a detected item using a given numeric index. + -- @param #DETECTION_BASE self + -- @param #number Index + -- @return #DETECTION_BASE.DetectedItem + function DETECTION_BASE:GetDetectedItem( Index ) + + local DetectedItem = self.DetectedItems[Index] + if DetectedItem then + return DetectedItem + end + + return nil + end + + --- Get the @{Set#SET_UNIT} of a detecttion area using a given numeric index. + -- @param #DETECTION_BASE self + -- @param #number Index + -- @return Core.Set#SET_UNIT DetectedSet + function DETECTION_BASE:GetDetectedSet( Index ) + + local DetectedItem = self:GetDetectedItem( Index ) + local DetectedSetUnit = DetectedItem.Set + if DetectedSetUnit then + return DetectedSetUnit + end + + return nil + end + + do -- Zones + + --- Get the @{Zone#ZONE_UNIT} of a detection area using a given numeric index. + -- @param #DETECTION_BASE self + -- @param #number Index + -- @return Core.Zone#ZONE_UNIT DetectedZone + function DETECTION_BASE:GetDetectedZone( Index ) + + local DetectedZone = self.DetectedItems[Index].Zone + if DetectedZone then + return DetectedZone + end + + return nil + end + + end + + + --- Report summary of a detected item using a given numeric index. + -- @param #DETECTION_BASE self + -- @param Index + -- @return #string + function DETECTION_BASE:DetectedItemReportSummary( Index ) + self:F( Index ) + return nil + end + + --- Report detailed of a detectedion result. + -- @param #DETECTION_BASE self + -- @return #string + function DETECTION_BASE:DetectedReportDetailed() + self:F() + return nil + end + + --- Get the detection Groups. + -- @param #DETECTION_BASE self + -- @return Wrapper.Group#GROUP + function DETECTION_BASE:GetDetectionSetGroup() + + local DetectionSetGroup = self.DetectionSetGroup + return DetectionSetGroup + end + + --- Make a DetectionSet table. This function will be overridden in the derived clsses. + -- @param #DETECTION_BASE self + -- @return #DETECTION_BASE self + function DETECTION_BASE:CreateDetectionSets() + self:F2() + + self:E( "Error, in DETECTION_BASE class..." ) + + end + + + --- Schedule the DETECTION construction. + -- @param #DETECTION_BASE self + -- @param #number DelayTime The delay in seconds to wait the reporting. + -- @param #number RepeatInterval The repeat interval in seconds for the reporting to happen repeatedly. + -- @return #DETECTION_BASE self + function DETECTION_BASE:Schedule( DelayTime, RepeatInterval ) + self:F2() + + self.ScheduleDelayTime = DelayTime + self.ScheduleRepeatInterval = RepeatInterval + + self.DetectionScheduler = SCHEDULER:New( self, self._DetectionScheduler, { self, "Detection" }, DelayTime, RepeatInterval ) + return self + end + +end + +do -- DETECTION_UNITS + + --- # 2) DETECTION_UNITS class, extends @{Detection#DETECTION_BASE} + -- + -- The DETECTION_UNITS class will detect units within the battle zone. + -- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Set#SET_UNIT} containing ONE @{UNIT} object reference. + -- Beware that when the amount of units detected is large, the DetectedItems list will be large also. + -- + -- @type DETECTION_UNITS + -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are detected. + -- @extends #DETECTION_BASE + DETECTION_UNITS = { + ClassName = "DETECTION_UNITS", + DetectionRange = nil, + } + + --- DETECTION_UNITS constructor. + -- @param Functional.Detection#DETECTION_UNITS self + -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. + -- @return Functional.Detection#DETECTION_UNITS self + function DETECTION_UNITS:New( DetectionSetGroup ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) ) -- #DETECTION_UNITS + + self._SmokeDetectedUnits = false + self._FlareDetectedUnits = false + self._SmokeDetectedZones = false + self._FlareDetectedZones = false + self._BoundDetectedZones = false + + return self + end + + --- Make text documenting the changes of the detected zone. + -- @param #DETECTION_UNITS self + -- @param #DETECTION_UNITS.DetectedItem DetectedItem + -- @return #string The Changes text + function DETECTION_UNITS:GetChangeText( DetectedItem ) + self:F( DetectedItem ) + + local MT = {} + + for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do + + if ChangeCode == "AU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " New target(s) detected: " .. table.concat( MTUT, ", " ) .. "." + end + + if ChangeCode == "RU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " Invisible or destroyed target(s): " .. table.concat( MTUT, ", " ) .. "." + end + + end + + return table.concat( MT, "\n" ) + + end + + + --- Create the DetectedItems list from the DetectedObjects table. + -- For each DetectedItem, a one field array is created containing the Unit detected. + -- @param #DETECTION_UNITS self + -- @return #DETECTION_UNITS self + function DETECTION_UNITS:CreateDetectionSets() + self:F2( #self.DetectedObjects ) + + -- Loop the current detected items, and check if each object still exists and is detected. + + for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do + + local DetectedItemSet = DetectedItem.Set -- Core.Set#SET_UNIT + local DetectedTypeName = DetectedItem.Type + + for DetectedUnitName, DetectedUnitData in pairs( DetectedItemSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + + local DetectedObject = nil + self:E( DetectedUnit ) + if DetectedUnit:IsAlive() then + --self:E(DetectedUnit:GetName()) + DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) + end + if DetectedObject then + + -- Yes, the DetectedUnit is still detected or exists. Flag as identified. + self:IdentifyDetectedObject( DetectedObject ) + else + -- There was no DetectedObject, remove DetectedUnit from the Set. + self:AddChangeUnit( DetectedItem, "RU", DetectedUnitName ) + DetectedItemSet:Remove( DetectedUnitName ) + end + end + end + + + -- Now we need to loop through the unidentified detected units and add these... These are all new items. + for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do + + local DetectedObject = self:GetDetectedObject( DetectedUnitName ) + if DetectedObject then + self:T( { "Detected Unit #", DetectedUnitName } ) + + local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT + + if DetectedUnit then + local DetectedTypeName = DetectedUnit:GetTypeName() + local DetectedItem = self:GetDetectedItem( DetectedUnitName ) + if not DetectedItem then + self:T( "Added new DetectedItem" ) + DetectedItem = self:AddDetectedItem( DetectedUnitName ) + DetectedItem.Type = DetectedUnit:GetTypeName() + DetectedItem.Name = DetectedObjectData.Name + DetectedItem.Visible = DetectedObjectData.Visible + DetectedItem.Distance = DetectedObjectData.Distance + end + + DetectedItem.Set:AddUnit( DetectedUnit ) + self:AddChangeUnit( DetectedItem, "AU", DetectedTypeName ) + end + end + end + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set + + self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table + --self:NearestFAC( DetectedItem ) + end + + end + + --- Report summary of a DetectedItem using a given numeric index. + -- @param #DETECTION_UNITS self + -- @param Index + -- @return #string + function DETECTION_UNITS:DetectedItemReportSummary( Index ) + self:F( Index ) + + local DetectedItem = self:GetDetectedItem( Index ) + local DetectedSet = self:GetDetectedSet( Index ) + + self:T( DetectedSet ) + if DetectedSet then + local ReportSummary = "" + local UnitDistanceText = "" + local UnitCategoryText = "" + + local DetectedItemUnit = DetectedSet:GetFirst() -- Wrapper.Unit#UNIT + + if DetectedItemUnit and DetectedItemUnit:IsAlive() then + self:T(DetectedItemUnit) + + local UnitCategoryName = DetectedItemUnit:GetCategoryName() or "" + local UnitCategoryType = DetectedItemUnit:GetTypeName() or "" + + if DetectedItem.Type and UnitCategoryName and UnitCategoryType then + UnitCategoryText = UnitCategoryName .. " (" .. UnitCategoryType .. ") at " + else + UnitCategoryText = "Unknown target at " + end + + if DetectedItem.Visible == false then + UnitDistanceText = string.format( "%.2f", DetectedItem.Distance ) .. " estimated km" + else + UnitDistanceText = string.format( "%.2f", DetectedItem.Distance ) .. " km, visual contact" + end + + local DetectedItemPointVec3 = DetectedItemUnit:GetPointVec3() + local DetectedItemPointLL = DetectedItemPointVec3:ToStringLL( 3, true ) + + local ThreatLevelA2G = DetectedItemUnit:GetThreatLevel( DetectedItem ) + + ReportSummary = string.format( + "%s - Threat [%s] (%2d) - %s%s", + DetectedItemPointLL, + string.rep( "■", ThreatLevelA2G ), + ThreatLevelA2G, + UnitCategoryText, + UnitDistanceText + ) + end + + self:T( ReportSummary ) + + return ReportSummary + end + end + + --- Report detailed of a detection result. + -- @param #DETECTION_UNITS self + -- @return #string + function DETECTION_UNITS:DetectedReportDetailed() + self:F() + + local Report = REPORT:New( "Detected units:" ) + for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do + local DetectedItem = DetectedItem -- #DETECTION_BASE.DetectedItem + local ReportSummary = self:DetectedItemReportSummary( DetectedItemID ) + Report:Add( ReportSummary ) + end + + local ReportText = Report:Text() + + return ReportText + end + +end + +do -- DETECTION_TYPES + + --- # 3) DETECTION_TYPES class, extends @{Detection#DETECTION_BASE} + -- + -- The DETECTION_TYPES class will detect units within the battle zone. + -- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected. + -- Each DetectedItem will contain a field Set, which contains a @{Set#SET_UNIT} containing ONE @{UNIT} object reference. + -- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also. + -- + -- @type DETECTION_TYPES + -- @extends #DETECTION_BASE + DETECTION_TYPES = { + ClassName = "DETECTION_TYPES", + DetectionRange = nil, + } + + --- DETECTION_TYPES constructor. + -- @param Functional.Detection#DETECTION_TYPES self + -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Recce role. + -- @return Functional.Detection#DETECTION_TYPES self + function DETECTION_TYPES:New( DetectionSetGroup ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) ) -- #DETECTION_TYPES + + self._SmokeDetectedUnits = false + self._FlareDetectedUnits = false + self._SmokeDetectedZones = false + self._FlareDetectedZones = false + self._BoundDetectedZones = false + + return self + end + + --- Make text documenting the changes of the detected zone. + -- @param #DETECTION_TYPES self + -- @param #DETECTION_TYPES.DetectedItem DetectedItem + -- @return #string The Changes text + function DETECTION_TYPES:GetChangeText( DetectedItem ) + self:F( DetectedItem ) + + local MT = {} + + for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do + + if ChangeCode == "AU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " New target(s) detected: " .. table.concat( MTUT, ", " ) .. "." + end + + if ChangeCode == "RU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = " Invisible or destroyed target(s): " .. table.concat( MTUT, ", " ) .. "." + end + + end + + return table.concat( MT, "\n" ) + + end + + + --- Create the DetectedItems list from the DetectedObjects table. + -- For each DetectedItem, a one field array is created containing the Unit detected. + -- @param #DETECTION_TYPES self + -- @return #DETECTION_TYPES self + function DETECTION_TYPES:CreateDetectionSets() + self:F2( #self.DetectedObjects ) + + -- Loop the current detected items, and check if each object still exists and is detected. + + for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do + + local DetectedItemSet = DetectedItem.Set -- Core.Set#SET_UNIT + local DetectedTypeName = DetectedItem.Type + + for DetectedUnitName, DetectedUnitData in pairs( DetectedItemSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + + local DetectedObject = nil + if DetectedUnit:IsAlive() then + --self:E(DetectedUnit:GetName()) + DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) + end + if DetectedObject then + + -- Yes, the DetectedUnit is still detected or exists. Flag as identified. + self:IdentifyDetectedObject( DetectedObject ) + else + -- There was no DetectedObject, remove DetectedUnit from the Set. + self:AddChangeUnit( DetectedItem, "RU", DetectedUnitName ) + DetectedItemSet:Remove( DetectedUnitName ) + end + end + end + + + -- Now we need to loop through the unidentified detected units and add these... These are all new items. + for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do + + local DetectedObject = self:GetDetectedObject( DetectedUnitName ) + if DetectedObject then + self:T( { "Detected Unit #", DetectedUnitName } ) + + local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT + + if DetectedUnit then + local DetectedTypeName = DetectedUnit:GetTypeName() + local DetectedItem = self:GetDetectedItem( DetectedTypeName ) + if not DetectedItem then + DetectedItem = self:AddDetectedItem( DetectedTypeName ) + DetectedItem.Type = DetectedUnit:GetTypeName() + end + + DetectedItem.Set:AddUnit( DetectedUnit ) + self:AddChangeUnit( DetectedItem, "AU", DetectedTypeName ) + end + end + end + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set + + self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table + --self:NearestFAC( DetectedItem ) + end + + end + + --- Report summary of a DetectedItem using a given numeric index. + -- @param #DETECTION_TYPES self + -- @param Index + -- @return #string + function DETECTION_TYPES:DetectedItemReportSummary( DetectedTypeName ) + self:F( DetectedTypeName ) + + local DetectedItem = self:GetDetectedItem( DetectedTypeName ) + local DetectedSet = self:GetDetectedSet( DetectedTypeName ) + + self:T( DetectedItem ) + if DetectedItem then + + local ThreatLevelA2G = DetectedSet:CalculateThreatLevelA2G() + local DetectedItemsCount = DetectedSet:Count() + local DetectedItemType = DetectedItem.Type + + local ReportSummary = string.format( + "Threat [%s] (%2d) - %2d of %s", + string.rep( "■", ThreatLevelA2G ), + ThreatLevelA2G, + DetectedItemsCount, + DetectedItemType + ) + self:T( ReportSummary ) + + return ReportSummary + end + end + + --- Report detailed of a detection result. + -- @param #DETECTION_TYPES self + -- @return #string + function DETECTION_TYPES:DetectedReportDetailed() + self:F() + + local Report = REPORT:New( "Detected types:" ) + for DetectedItemTypeName, DetectedItem in pairs( self.DetectedItems ) do + local DetectedItem = DetectedItem -- #DETECTION_BASE.DetectedItem + local ReportSummary = self:DetectedItemReportSummary( DetectedItemTypeName ) + Report:Add( ReportSummary ) + end + + local ReportText = Report:Text() + + return ReportText + end + +end + + +do -- DETECTION_AREAS + + --- # 4) DETECTION_AREAS class, extends @{Detection#DETECTION_BASE} + -- + -- The DETECTION_AREAS class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s), + -- and will build a list (table) of @{Set#SET_UNIT}s containing the @{Unit#UNIT}s detected. + -- The class is group the detected units within zones given a DetectedZoneRange parameter. + -- A set with multiple detected zones will be created as there are groups of units detected. + -- + -- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones + -- + -- The methods to manage the DetectedItems[].Set(s) are implemented in @{Detection#DECTECTION_BASE} and + -- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Detection#DETECTION_AREAS}. + -- + -- Retrieve the DetectedItems[].Set with the method @{Detection#DETECTION_BASE.GetDetectedSet}(). A @{Set#SET_UNIT} object will be returned. + -- + -- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Detection#DETECTION_BASE.GetDetectionZones}(). + -- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). + -- If you want to obtain a specific zone from the DetectedZones, use the method @{Detection#DETECTION_BASE.GetDetectionZone}() with a given index. + -- + -- ## 4.4) Flare or Smoke detected units + -- + -- Use the methods @{Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place. + -- + -- ## 4.5) Flare or Smoke or Bound detected zones + -- + -- Use the methods: + -- + -- * @{Detection#DETECTION_AREAS.FlareDetectedZones}() to flare in a color + -- * @{Detection#DETECTION_AREAS.SmokeDetectedZones}() to smoke in a color + -- * @{Detection#DETECTION_AREAS.SmokeDetectedZones}() to bound with a tire with a white flag + -- + -- the detected zones when a new detection has taken place. + -- + -- @type DETECTION_AREAS + -- @field Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. + -- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. + -- @extends #DETECTION_BASE + DETECTION_AREAS = { + ClassName = "DETECTION_AREAS", + DetectionZoneRange = nil, + } + + + --- DETECTION_AREAS constructor. + -- @param #DETECTION_AREAS self + -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. + -- @param Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. + -- @return #DETECTION_AREAS + function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) ) + + self.DetectionZoneRange = DetectionZoneRange + + self._SmokeDetectedUnits = false + self._FlareDetectedUnits = false + self._SmokeDetectedZones = false + self._FlareDetectedZones = false + self._BoundDetectedZones = false + + return self + end + + --- Report summary of a detected item using a given numeric index. + -- @param #DETECTION_AREAS self + -- @param Index + -- @return #string + function DETECTION_AREAS:DetectedItemReportSummary( Index ) + self:F( Index ) + + local DetectedItem = self:GetDetectedItem( Index ) + if DetectedItem then + local DetectedSet = self:GetDetectedSet( Index ) + local ReportSummaryItem + + local DetectedZone = self:GetDetectedZone( Index ) + local DetectedItemPointVec3 = DetectedZone:GetPointVec3() + local DetectedItemPointLL = DetectedItemPointVec3:ToStringLL( 3, true ) + + local ThreatLevelA2G = self:GetTreatLevelA2G( DetectedItem ) + local DetectedItemsCount = DetectedSet:Count() + local DetectedItemsTypes = DetectedSet:GetTypeNames() + + local ReportSummary = string.format( + "%s - Threat [%s] (%2d) - %2d of %s", + DetectedItemPointLL, + string.rep( "■", ThreatLevelA2G ), + ThreatLevelA2G, + DetectedItemsCount, + DetectedItemsTypes + ) + + return ReportSummary + end + + return nil + end + + + --- Returns if there are friendlies nearby the FAC units ... + -- @param #DETECTION_AREAS self + -- @return #boolean trhe if there are friendlies nearby + function DETECTION_AREAS:IsFriendliesNearBy( DetectedItem ) + + self:T3( DetectedItem.FriendliesNearBy ) + return DetectedItem.FriendliesNearBy or false + end + + --- Calculate the maxium A2G threat level of the DetectedItem. + -- @param #DETECTION_AREAS self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + function DETECTION_AREAS:CalculateThreatLevelA2G( DetectedItem ) + + local MaxThreatLevelA2G = 0 + for UnitName, UnitData in pairs( DetectedItem.Set:GetSet() ) do + local ThreatUnit = UnitData -- Wrapper.Unit#UNIT + local ThreatLevelA2G = ThreatUnit:GetThreatLevel() + if ThreatLevelA2G > MaxThreatLevelA2G then + MaxThreatLevelA2G = ThreatLevelA2G + end + end + + self:T3( MaxThreatLevelA2G ) + DetectedItem.MaxThreatLevelA2G = MaxThreatLevelA2G + + end + + --- Find the nearest FAC of the DetectedItem. + -- @param #DETECTION_AREAS self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @return Wrapper.Unit#UNIT The nearest FAC unit + function DETECTION_AREAS:NearestFAC( DetectedItem ) + + local NearestFAC = nil + local MinDistance = 1000000000 -- Units are not further than 1000000 km away from an area :-) + + for FACGroupName, FACGroupData in pairs( self.DetectionSetGroup:GetSet() ) do + for FACUnit, FACUnitData in pairs( FACGroupData:GetUnits() ) do + local FACUnit = FACUnitData -- Wrapper.Unit#UNIT + if FACUnit:IsActive() then + local Vec3 = FACUnit:GetVec3() + local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) + local Distance = PointVec3:Get2DDistance(POINT_VEC3:NewFromVec3( FACUnit:GetVec3() ) ) + if Distance < MinDistance then + MinDistance = Distance + NearestFAC = FACUnit + end + end + end + end + + DetectedItem.NearestFAC = NearestFAC + + end + + --- Returns the A2G threat level of the units in the DetectedItem + -- @param #DETECTION_AREAS self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @return #number a scale from 0 to 10. + function DETECTION_AREAS:GetTreatLevelA2G( DetectedItem ) + + self:T3( DetectedItem.MaxThreatLevelA2G ) + return DetectedItem.MaxThreatLevelA2G + end + + + + --- Smoke the detected units + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:SmokeDetectedUnits() + self:F2() + + self._SmokeDetectedUnits = true + return self + end + + --- Flare the detected units + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:FlareDetectedUnits() + self:F2() + + self._FlareDetectedUnits = true + return self + end + + --- Smoke the detected zones + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:SmokeDetectedZones() + self:F2() + + self._SmokeDetectedZones = true + return self + end + + --- Flare the detected zones + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:FlareDetectedZones() + self:F2() + + self._FlareDetectedZones = true + return self + end + + --- Bound the detected zones + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:BoundDetectedZones() + self:F2() + + self._BoundDetectedZones = true + return self + end + + --- Make text documenting the changes of the detected zone. + -- @param #DETECTION_AREAS self + -- @param #DETECTION_BASE.DetectedItem DetectedItem + -- @return #string The Changes text + function DETECTION_AREAS:GetChangeText( DetectedItem ) + self:F( DetectedItem ) + + local MT = {} + + for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do + + if ChangeCode == "AA" then + MT[#MT+1] = "Detected new area " .. ChangeData.ItemID .. ". The center target is a " .. ChangeData.ItemUnitType .. "." + end + + if ChangeCode == "RAU" then + MT[#MT+1] = "Changed area " .. ChangeData.ItemID .. ". Removed the center target." + end + + if ChangeCode == "AAU" then + MT[#MT+1] = "Changed area " .. ChangeData.ItemID .. ". The new center target is a " .. ChangeData.ItemUnitType .. "." + end + + if ChangeCode == "RA" then + MT[#MT+1] = "Removed old area " .. ChangeData.ItemID .. ". No more targets in this area." + end + + if ChangeCode == "AU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = "Detected for area " .. ChangeData.ItemID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "." + end + + if ChangeCode == "RU" then + local MTUT = {} + for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do + if ChangeUnitType ~= "ItemID" then + MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType + end + end + MT[#MT+1] = "Removed for area " .. ChangeData.ItemID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "." + end + + end + + return table.concat( MT, "\n" ) + + end + + + --- Make a DetectionSet table. This function will be overridden in the derived clsses. + -- @param #DETECTION_AREAS self + -- @return #DETECTION_AREAS self + function DETECTION_AREAS:CreateDetectionSets() + self:F2() + + + self:T( "Checking Detected Items for new Detected Units ..." ) + -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. + -- Regroup when needed, split groups when needed. + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + if DetectedItem then + + self:T( { "Detected Item ID:", DetectedItemID } ) + + + local DetectedSet = DetectedItem.Set + + local AreaExists = false -- This flag will determine of the detected area is still existing. + + -- First test if the center unit is detected in the detection area. + self:T3( { "Zone Center Unit:", DetectedItem.Zone.ZoneUNIT.UnitName } ) + local DetectedZoneObject = self:GetDetectedObject( DetectedItem.Zone.ZoneUNIT.UnitName ) + self:T3( { "Detected Zone Object:", DetectedItem.Zone:GetName(), DetectedZoneObject } ) + + if DetectedZoneObject then + + --self:IdentifyDetectedObject( DetectedZoneObject ) + AreaExists = true + + + + else + -- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area. + -- First remove the center unit from the set. + DetectedSet:RemoveUnitsByName( DetectedItem.Zone.ZoneUNIT.UnitName ) + + self:AddChangeItem( DetectedItem, 'RAU', "Dummy" ) + + -- Then search for a new center area unit within the set. Note that the new area unit candidate must be within the area range. + for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do + + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName ) + + -- The DetectedObject can be nil when the DetectedUnit is not alive anymore or it is not in the DetectedObjects map. + -- If the DetectedUnit was already identified, DetectedObject will be nil. + if DetectedObject then + self:IdentifyDetectedObject( DetectedObject ) + AreaExists = true + + DetectedItem.Zone:BoundZone( 12, self.CountryID, true) + + -- Assign the Unit as the new center unit of the detected area. + DetectedItem.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange ) + + self:AddChangeItem( DetectedItem, "AAU", DetectedItem.Zone.ZoneUNIT:GetTypeName() ) + + -- We don't need to add the DetectedObject to the area set, because it is already there ... + break + end + end + end + + -- Now we've determined the center unit of the area, now we can iterate the units in the detected area. + -- Note that the position of the area may have moved due to the center unit repositioning. + -- If no center unit was identified, then the detected area does not exist anymore and should be deleted, as there are no valid units that can be the center unit. + if AreaExists then + + -- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ... + -- Those units within the zone are flagged as Identified. + -- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets. + for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do + + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + local DetectedObject = nil + if DetectedUnit:IsAlive() then + --self:E(DetectedUnit:GetName()) + DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) + end + if DetectedObject then + + -- Check if the DetectedUnit is within the DetectedItem.Zone + if DetectedUnit:IsInZone( DetectedItem.Zone ) then + + -- Yes, the DetectedUnit is within the DetectedItem.Zone, no changes, DetectedUnit can be kept within the Set. + self:IdentifyDetectedObject( DetectedObject ) + + else + -- No, the DetectedUnit is not within the DetectedItem.Zone, remove DetectedUnit from the Set. + DetectedSet:Remove( DetectedUnitName ) + self:AddChangeUnit( DetectedItem, "RU", DetectedUnit:GetTypeName() ) + end + + else + -- There was no DetectedObject, remove DetectedUnit from the Set. + self:AddChangeUnit( DetectedItem, "RU", "destroyed target" ) + DetectedSet:Remove( DetectedUnitName ) + + -- The DetectedObject has been identified, because it does not exist ... + -- self:IdentifyDetectedObject( DetectedObject ) + end + end + else + DetectedItem.Zone:BoundZone( 12, self.CountryID, true) + self:RemoveDetectedItem( DetectedItemID ) + self:AddChangeItem( DetectedItem, "RA" ) + end + end + end + + -- We iterated through the existing detection areas and: + -- - We checked which units are still detected in each detection area. Those units were flagged as Identified. + -- - We recentered the detection area to new center units where it was needed. + -- + -- Now we need to loop through the unidentified detected units and see where they belong: + -- - They can be added to a new detection area and become the new center unit. + -- - They can be added to a new detection area. + for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do + + local DetectedObject = self:GetDetectedObject( DetectedUnitName ) + + if DetectedObject then + + -- We found an unidentified unit outside of any existing detection area. + local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT + + local AddedToDetectionArea = false + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + if DetectedItem then + self:T( "Detection Area #" .. DetectedItem.ItemID ) + local DetectedSet = DetectedItem.Set + if not self:IsDetectedObjectIdentified( DetectedObject ) and DetectedUnit:IsInZone( DetectedItem.Zone ) then + self:IdentifyDetectedObject( DetectedObject ) + DetectedSet:AddUnit( DetectedUnit ) + AddedToDetectionArea = true + self:AddChangeUnit( DetectedItem, "AU", DetectedUnit:GetTypeName() ) + end + end + end + + if AddedToDetectionArea == false then + + -- New detection area + local DetectedItem = self:AddDetectedItemZone( nil, + SET_UNIT:New(), + ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + ) + --self:E( DetectedItem.Zone.ZoneUNIT.UnitName ) + DetectedItem.Set:AddUnit( DetectedUnit ) + self:AddChangeItem( DetectedItem, "AA", DetectedUnit:GetTypeName() ) + end + end + end + + -- Now all the tests should have been build, now make some smoke and flares... + -- We also report here the friendlies within the detected areas. + + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set + local DetectedZone = DetectedItem.Zone + + self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table + self:CalculateThreatLevelA2G( DetectedItem ) -- Calculate A2G threat level + self:NearestFAC( DetectedItem ) + + if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then + DetectedZone.ZoneUNIT:SmokeRed() + end + DetectedSet:ForEachUnit( + --- @param Wrapper.Unit#UNIT DetectedUnit + function( DetectedUnit ) + if DetectedUnit:IsAlive() then + self:T( "Detected Set #" .. DetectedItem.ItemID .. ":" .. DetectedUnit:GetName() ) + if DETECTION_AREAS._FlareDetectedUnits or self._FlareDetectedUnits then + DetectedUnit:FlareGreen() + end + if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then + DetectedUnit:SmokeGreen() + end + end + end + ) + if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then + DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) ) + end + if DETECTION_AREAS._SmokeDetectedZones or self._SmokeDetectedZones then + DetectedZone:SmokeZone( SMOKECOLOR.White, 30 ) + end + + if DETECTION_AREAS._BoundDetectedZones or self._BoundDetectedZones then + DetectedZone:BoundZone( 12, self.CountryID ) + end + end + + end + +end +--- Single-Player:**No** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- **AI Balancing will replace in multi player missions +-- non-occupied human slots with AI groups, in order to provide an engaging simulation environment, +-- even when there are hardly any players in the mission.** +-- +-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) +-- +-- === +-- +-- # 1) @{AI_Balancer#AI_BALANCER} class, extends @{Fsm#FSM_SET} +-- +-- The @{AI_Balancer#AI_BALANCER} class monitors and manages as many replacement AI groups as there are +-- CLIENTS in a SET_CLIENT collection, which are not occupied by human players. +-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. +-- +-- The parent class @{Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). +-- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods. +-- An explanation about state and event transition methods can be found in the @{FSM} module documentation. +-- +-- The mission designer can tailor the AI_BALANCER behaviour, by implementing a state or event handling method for the following: +-- +-- * **@{#AI_BALANCER.OnAfterSpawned}**( AISet, From, Event, To, AIGroup ): Define to add extra logic when an AI is spawned. +-- +-- ## 1.1) AI_BALANCER construction +-- +-- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: +-- +-- ## 1.2) AI_BALANCER is a FSM +-- +-- ![Process](..\Presentations\AI_Balancer\Dia13.JPG) +-- +-- ### 1.2.1) AI_BALANCER States +-- +-- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. +-- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. +-- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. +-- +-- ### 1.2.2) AI_BALANCER Events +-- +-- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. +-- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. +-- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. +-- +-- ## 1.3) AI_BALANCER spawn interval for replacement AI +-- +-- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. +-- +-- ## 1.4) AI_BALANCER returns AI to Airbases +-- +-- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. +-- However, there are 2 additional options that you can use to customize the destroy behaviour. +-- When a human player joins a slot, you can configure to let the AI return to: +-- +-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Airbase#AIRBASE}. +-- +-- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return, +-- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed. +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-01-17: There is still a problem with AI being destroyed, but not respawned. Need to check further upon that. +-- +-- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. +-- +-- ### Authors: +-- +-- * FlightControl: Framework Design & Programming and Documentation. +-- +-- @module AI_Balancer + +--- AI_BALANCER class +-- @type AI_BALANCER +-- @field Core.Set#SET_CLIENT SetClient +-- @field Functional.Spawn#SPAWN SpawnAI +-- @field Wrapper.Group#GROUP Test +-- @extends Core.Fsm#FSM_SET +AI_BALANCER = { + ClassName = "AI_BALANCER", + PatrolZones = {}, + AIGroups = {}, + Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. + Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. +} + + + +--- Creates a new AI_BALANCER object +-- @param #AI_BALANCER self +-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). +-- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. +-- @return #AI_BALANCER +function AI_BALANCER:New( SetClient, SpawnAI ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER + + -- TODO: Define the OnAfterSpawned event + self:SetStartState( "None" ) + self:AddTransition( "*", "Monitor", "Monitoring" ) + self:AddTransition( "*", "Spawn", "Spawning" ) + self:AddTransition( "Spawning", "Spawned", "Spawned" ) + self:AddTransition( "*", "Destroy", "Destroying" ) + self:AddTransition( "*", "Return", "Returning" ) + + self.SetClient = SetClient + self.SetClient:FilterOnce() + self.SpawnAI = SpawnAI + + self.SpawnQueue = {} + + self.ToNearestAirbase = false + self.ToHomeAirbase = false + + self:__Monitor( 1 ) + + return self +end + +--- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. +-- Provide 2 identical seconds if the interval should be a fixed amount of seconds. +-- @param #AI_BALANCER self +-- @param #number Earliest The earliest a new AI can be spawned in seconds. +-- @param #number Latest The latest a new AI can be spawned in seconds. +-- @return self +function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) + + self.Earliest = Earliest + self.Latest = Latest + + return self +end + +--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- @param #AI_BALANCER self +-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. +function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) + + self.ToNearestAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange + self.ReturnAirbaseSet = ReturnAirbaseSet +end + +--- Returns the AI to the home @{Airbase#AIRBASE}. +-- @param #AI_BALANCER self +-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) + + self.ToHomeAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange +end + +--- @param #AI_BALANCER self +-- @param Core.Set#SET_GROUP SetGroup +-- @param #string ClientName +-- @param Wrapper.Group#GROUP AIGroup +function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) + + -- OK, Spawn a new group from the default SpawnAI object provided. + local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP + if AIGroup then + AIGroup:E( "Spawning new AIGroup" ) + --TODO: need to rework UnitName thing ... + + SetGroup:Add( ClientName, AIGroup ) + self.SpawnQueue[ClientName] = nil + + -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. + -- Mission designers can catch this event to bind further actions to the AIGroup. + self:Spawned( AIGroup ) + end +end + +--- @param #AI_BALANCER self +-- @param Core.Set#SET_GROUP SetGroup +-- @param Wrapper.Group#GROUP AIGroup +function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) + + AIGroup:Destroy() + SetGroup:Flush() + SetGroup:Remove( ClientName ) + SetGroup:Flush() +end + +--- @param #AI_BALANCER self +-- @param Core.Set#SET_GROUP SetGroup +-- @param Wrapper.Group#GROUP AIGroup +function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup ) + + local AIGroupTemplate = AIGroup:GetTemplate() + if self.ToHomeAirbase == true then + local WayPointCount = #AIGroupTemplate.route.points + local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) + AIGroup:SetCommand( SwitchWayPointCommand ) + AIGroup:MessageToRed( "Returning to home base ...", 30 ) + else + -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. + --TODO: i need to rework the POINT_VEC2 thing. + local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) + local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) + self:T( ClosestAirbase.AirbaseName ) + AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) + local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) + AIGroupTemplate.route = RTBRoute + AIGroup:Respawn( AIGroupTemplate ) + end + +end + + +--- @param #AI_BALANCER self +function AI_BALANCER:onenterMonitoring( SetGroup ) + + self:T2( { self.SetClient:Count() } ) + --self.SetClient:Flush() + + self.SetClient:ForEachClient( + --- @param Wrapper.Client#CLIENT Client + function( Client ) + self:T3(Client.ClientName) + + local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP + if Client:IsAlive() then + + if AIGroup and AIGroup:IsAlive() == true then + + if self.ToNearestAirbase == false and self.ToHomeAirbase == false then + self:Destroy( Client.UnitName, AIGroup ) + else + -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. + -- If there is a CLIENT, the AI stays engaged and will not return. + -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. + + local PlayerInRange = { Value = false } + local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) + + self:T2( RangeZone ) + + _DATABASE:ForEachPlayer( + --- @param Wrapper.Unit#UNIT RangeTestUnit + function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) + self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) + if RangeTestUnit:IsInZone( RangeZone ) == true then + self:T2( "in zone" ) + if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then + self:T2( "in range" ) + PlayerInRange.Value = true + end + end + end, + + --- @param Core.Zone#ZONE_RADIUS RangeZone + -- @param Wrapper.Group#GROUP AIGroup + function( RangeZone, AIGroup, PlayerInRange ) + if PlayerInRange.Value == false then + self:Return( AIGroup ) + end + end + , RangeZone, AIGroup, PlayerInRange + ) + + end + self.Set:Remove( Client.UnitName ) + end + else + if not AIGroup or not AIGroup:IsAlive() == true then + self:T( "Client " .. Client.UnitName .. " not alive." ) + if not self.SpawnQueue[Client.UnitName] then + -- Spawn a new AI taking into account the spawn interval Earliest, Latest + self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) + self.SpawnQueue[Client.UnitName] = true + self:E( "New AI Spawned for Client " .. Client.UnitName ) + end + end + end + return true + end + ) + + self:__Monitor( 10 ) +end + + + +--- **AI** -- **Air Patrolling or Staging.** +-- +-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG) +-- +-- === +-- +-- AI PATROL classes makes AI Controllables execute an Patrol. +-- +-- There are the following types of PATROL classes defined: +-- +-- * @{#AI_PATROL_ZONE}: Perform a PATROL in a zone. +-- +-- ==== +-- +-- # **OPEN ISSUES** +-- +-- 2017-01-17: When Spawned AI is located at an airbase, it will be routed first back to the airbase after take-off. +-- +-- 2016-01-17: +-- -- Fixed problem with AI returning to base too early and unexpected. +-- -- ReSpawning of AI will reset the AI_PATROL and derived classes. +-- -- Checked the correct workings of SCHEDULER, and it DOES work correctly. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-01-17: Rename of class: **AI\_PATROL\_ZONE** is the new name for the old _AI\_PATROLZONE_. +-- +-- 2017-01-15: Complete revision. AI_PATROL_ZONE is the base class for other AI_PATROL like classes. +-- +-- 2016-09-01: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review. +-- +-- ### Authors: +-- +-- * **FlightControl**: Design & Programming. +-- +-- @module AI_Patrol + +--- AI_PATROL_ZONE class +-- @type AI_PATROL_ZONE +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @field Functional.Spawn#SPAWN CoordTest +-- @extends Core.Fsm#FSM_CONTROLLABLE + +--- # 1) @{#AI_PATROL_ZONE} class, extends @{Fsm#FSM_CONTROLLABLE} +-- +-- The @{#AI_PATROL_ZONE} class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) +-- +-- The AI_PATROL_ZONE is assigned a @{Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia4.JPG) +-- +-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. +-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia9.JPG) +-- +---- Note that the enemy is not engaged! To model enemy engagement, either tailor the **Detected** event, or +-- use derived AI_ classes to model AI offensive or defensive behaviour. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia10.JPG) +-- +-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. +-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia11.JPG) +-- +-- ## 1.1) AI_PATROL_ZONE constructor +-- +-- * @{#AI_PATROL_ZONE.New}(): Creates a new AI_PATROL_ZONE object. +-- +-- ## 1.2) AI_PATROL_ZONE is a FSM +-- +-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG) +-- +-- ### 1.2.1) AI_PATROL_ZONE States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Returning** ( Group ): The AI is returning to Base. +-- * **Stopped** ( Group ): The process is stopped. +-- * **Crashed** ( Group ): The AI has crashed or is dead. +-- +-- ### 1.2.2) AI_PATROL_ZONE Events +-- +-- * **Start** ( Group ): Start the process. +-- * **Stop** ( Group ): Stop the process. +-- * **Route** ( Group ): Route the AI to a new random 3D point within the Patrol Zone. +-- * **RTB** ( Group ): Route the AI to the home base. +-- * **Detect** ( Group ): The AI is detecting targets. +-- * **Detected** ( Group ): The AI has detected new targets. +-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- ## 1.3) Set or Get the AI controllable +-- +-- * @{#AI_PATROL_ZONE.SetControllable}(): Set the AIControllable. +-- * @{#AI_PATROL_ZONE.GetControllable}(): Get the AIControllable. +-- +-- ## 1.4) Set the Speed and Altitude boundaries of the AI controllable +-- +-- * @{#AI_PATROL_ZONE.SetSpeed}(): Set the patrol speed boundaries of the AI, for the next patrol. +-- * @{#AI_PATROL_ZONE.SetAltitude}(): Set altitude boundaries of the AI, for the next patrol. +-- +-- ## 1.5) Manage the detection process of the AI controllable +-- +-- The detection process of the AI controllable can be manipulated. +-- Detection requires an amount of CPU power, which has an impact on your mission performance. +-- Only put detection on when absolutely necessary, and the frequency of the detection can also be set. +-- +-- * @{#AI_PATROL_ZONE.SetDetectionOn}(): Set the detection on. The AI will detect for targets. +-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased. +-- +-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection. +-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI. +-- +-- The detection can be filtered to potential targets in a specific zone. +-- Use the method @{#AI_PATROL_ZONE.SetDetectionZone}() to set the zone where targets need to be detected. +-- Note that when the zone is too far away, or the AI is not heading towards the zone, or the AI is too high, no targets may be detected +-- according the weather conditions. +-- +-- ## 1.6) Manage the "out of fuel" in the AI_PATROL_ZONE +-- +-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. +-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, +-- while a new AI is targetted to the AI_PATROL_ZONE. +-- Once the time is finished, the old AI will return to the base. +-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place. +-- +-- ## 1.7) Manage "damage" behaviour of the AI in the AI_PATROL_ZONE +-- +-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on. +-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB). +-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place. +-- +-- === +-- +-- @field #AI_PATROL_ZONE AI_PATROL_ZONE +-- +AI_PATROL_ZONE = { + ClassName = "AI_PATROL_ZONE", +} + +--- Creates a new AI_PATROL_ZONE object +-- @param #AI_PATROL_ZONE self +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_PATROL_ZONE self +-- @usage +-- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. +-- PatrolZone = ZONE:New( 'PatrolZone' ) +-- PatrolSpawn = SPAWN:New( 'Patrol Group' ) +-- PatrolArea = AI_PATROL_ZONE:New( PatrolZone, 3000, 6000, 600, 900 ) +function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE + + + self.PatrolZone = PatrolZone + self.PatrolFloorAltitude = PatrolFloorAltitude + self.PatrolCeilingAltitude = PatrolCeilingAltitude + self.PatrolMinSpeed = PatrolMinSpeed + self.PatrolMaxSpeed = PatrolMaxSpeed + + -- defafult PatrolAltType to "RADIO" if not specified + self.PatrolAltType = PatrolAltType or "RADIO" + + self:SetDetectionInterval( 30 ) + + self.CheckStatus = true + + self:ManageFuel( .2, 60 ) + self:ManageDamage( 1 ) + + + self.DetectedUnits = {} -- This table contains the targets detected during patrol. + + self:SetStartState( "None" ) + + self:AddTransition( "*", "Stop", "Stopped" ) + +--- OnLeave Transition Handler for State Stopped. +-- @function [parent=#AI_PATROL_ZONE] OnLeaveStopped +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Stopped. +-- @function [parent=#AI_PATROL_ZONE] OnEnterStopped +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- OnBefore Transition Handler for Event Stop. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeStop +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Stop. +-- @function [parent=#AI_PATROL_ZONE] OnAfterStop +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Stop. +-- @function [parent=#AI_PATROL_ZONE] Stop +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Stop. +-- @function [parent=#AI_PATROL_ZONE] __Stop +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "None", "Start", "Patrolling" ) + +--- OnBefore Transition Handler for Event Start. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeStart +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Start. +-- @function [parent=#AI_PATROL_ZONE] OnAfterStart +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Start. +-- @function [parent=#AI_PATROL_ZONE] Start +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Start. +-- @function [parent=#AI_PATROL_ZONE] __Start +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Patrolling. +-- @function [parent=#AI_PATROL_ZONE] OnLeavePatrolling +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Patrolling. +-- @function [parent=#AI_PATROL_ZONE] OnEnterPatrolling +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Patrolling", "Route", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + +--- OnBefore Transition Handler for Event Route. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeRoute +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Route. +-- @function [parent=#AI_PATROL_ZONE] OnAfterRoute +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Route. +-- @function [parent=#AI_PATROL_ZONE] Route +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Route. +-- @function [parent=#AI_PATROL_ZONE] __Route +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Status", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + +--- OnBefore Transition Handler for Event Status. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeStatus +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Status. +-- @function [parent=#AI_PATROL_ZONE] OnAfterStatus +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Status. +-- @function [parent=#AI_PATROL_ZONE] Status +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Status. +-- @function [parent=#AI_PATROL_ZONE] __Status +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Detect", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + +--- OnBefore Transition Handler for Event Detect. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeDetect +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Detect. +-- @function [parent=#AI_PATROL_ZONE] OnAfterDetect +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Detect. +-- @function [parent=#AI_PATROL_ZONE] Detect +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Detect. +-- @function [parent=#AI_PATROL_ZONE] __Detect +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Detected", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + +--- OnBefore Transition Handler for Event Detected. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeDetected +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Detected. +-- @function [parent=#AI_PATROL_ZONE] OnAfterDetected +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event Detected. +-- @function [parent=#AI_PATROL_ZONE] Detected +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event Detected. +-- @function [parent=#AI_PATROL_ZONE] __Detected +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "RTB", "Returning" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + +--- OnBefore Transition Handler for Event RTB. +-- @function [parent=#AI_PATROL_ZONE] OnBeforeRTB +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event RTB. +-- @function [parent=#AI_PATROL_ZONE] OnAfterRTB +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + +--- Synchronous Event Trigger for Event RTB. +-- @function [parent=#AI_PATROL_ZONE] RTB +-- @param #AI_PATROL_ZONE self + +--- Asynchronous Event Trigger for Event RTB. +-- @function [parent=#AI_PATROL_ZONE] __RTB +-- @param #AI_PATROL_ZONE self +-- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Returning. +-- @function [parent=#AI_PATROL_ZONE] OnLeaveReturning +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Returning. +-- @function [parent=#AI_PATROL_ZONE] OnEnterReturning +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE. + + self:AddTransition( "*", "Eject", "*" ) + self:AddTransition( "*", "Crash", "Crashed" ) + self:AddTransition( "*", "PilotDead", "*" ) + + return self +end + + + + +--- Sets (modifies) the minimum and maximum speed of the patrol. +-- @param #AI_PATROL_ZONE self +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) + self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) + + self.PatrolMinSpeed = PatrolMinSpeed + self.PatrolMaxSpeed = PatrolMaxSpeed +end + + + +--- Sets the floor and ceiling altitude of the patrol. +-- @param #AI_PATROL_ZONE self +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) + self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) + + self.PatrolFloorAltitude = PatrolFloorAltitude + self.PatrolCeilingAltitude = PatrolCeilingAltitude +end + +-- * @{#AI_PATROL_ZONE.SetDetectionOn}(): Set the detection on. The AI will detect for targets. +-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased. + +--- Set the detection on. The AI will detect for targets. +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionOn() + self:F2() + + self.DetectOn = true +end + +--- Set the detection off. The AI will NOT detect for targets. +-- However, the list of already detected targets will be kept and can be enquired! +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionOff() + self:F2() + + self.DetectOn = false +end + +--- Set the status checking off. +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetStatusOff() + self:F2() + + self.CheckStatus = false +end + +--- Activate the detection. The AI will detect for targets if the Detection is switched On. +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionActivated() + self:F2() + + self:ClearDetectedUnits() + self.DetectActivated = true + self:__Detect( -self.DetectInterval ) +end + +--- Deactivate the detection. The AI will NOT detect for targets. +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionDeactivated() + self:F2() + + self:ClearDetectedUnits() + self.DetectActivated = false +end + +--- Set the interval in seconds between each detection executed by the AI. +-- The list of already detected targets will be kept and updated. +-- Newly detected targets will be added, but already detected targets that were +-- not detected in this cycle, will NOT be removed! +-- The default interval is 30 seconds. +-- @param #AI_PATROL_ZONE self +-- @param #number Seconds The interval in seconds. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionInterval( Seconds ) + self:F2() + + if Seconds then + self.DetectInterval = Seconds + else + self.DetectInterval = 30 + end +end + +--- Set the detection zone where the AI is detecting targets. +-- @param #AI_PATROL_ZONE self +-- @param Core.Zone#ZONE DetectionZone The zone where to detect targets. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:SetDetectionZone( DetectionZone ) + self:F2() + + if DetectionZone then + self.DetectZone = DetectionZone + else + self.DetectZone = nil + end +end + +--- Gets a list of @{Unit#UNIT}s that were detected by the AI. +-- No filtering is applied, so, ANY detected UNIT can be in this list. +-- It is up to the mission designer to use the @{Unit} class and methods to filter the targets. +-- @param #AI_PATROL_ZONE self +-- @return #table The list of @{Unit#UNIT}s +function AI_PATROL_ZONE:GetDetectedUnits() + self:F2() + + return self.DetectedUnits +end + +--- Clears the list of @{Unit#UNIT}s that were detected by the AI. +-- @param #AI_PATROL_ZONE self +function AI_PATROL_ZONE:ClearDetectedUnits() + self:F2() + self.DetectedUnits = {} +end + +--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. +-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE. +-- Once the time is finished, the old AI will return to the base. +-- @param #AI_PATROL_ZONE self +-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. +-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime ) + + self.PatrolManageFuel = true + self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage + self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime + + return self +end + +--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base. +-- However, damage cannot be foreseen early on. +-- Therefore, when the damage treshold is reached, +-- the AI will return immediately to the home base (RTB). +-- Note that for groups, the average damage of the complete group will be calculated. +-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25. +-- @param #AI_PATROL_ZONE self +-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged. +-- @return #AI_PATROL_ZONE self +function AI_PATROL_ZONE:ManageDamage( PatrolDamageTreshold ) + + self.PatrolManageDamage = true + self.PatrolDamageTreshold = PatrolDamageTreshold + + return self +end + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_PATROL_ZONE self +-- @return #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To ) + self:F2() + + self:__Route( 1 ) -- Route to the patrol point. The asynchronous trigger is important, because a spawned group and units takes at least one second to come live. + self:__Status( 60 ) -- Check status status every 30 seconds. + self:SetDetectionActivated() + + self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead ) + self:HandleEvent( EVENTS.Crash, self.OnCrash ) + self:HandleEvent( EVENTS.Ejection, self.OnEjection ) + + Controllable:OptionROEHoldFire() + Controllable:OptionROTVertical() + + self.Controllable:OnReSpawn( + function( PatrolGroup ) + self:E( "ReSpawn" ) + self:__Reset( 1 ) + self:__Route( 5 ) + end + ) + + self:SetDetectionOn() + +end + + +--- @param #AI_PATROL_ZONE self +--- @param Wrapper.Controllable#CONTROLLABLE Controllable +function AI_PATROL_ZONE:onbeforeDetect( Controllable, From, Event, To ) + + return self.DetectOn and self.DetectActivated +end + +--- @param #AI_PATROL_ZONE self +--- @param Wrapper.Controllable#CONTROLLABLE Controllable +function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To ) + + local Detected = false + + local DetectedTargets = Controllable:GetDetectedTargets() + for TargetID, Target in pairs( DetectedTargets or {} ) do + local TargetObject = Target.object + + if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then + + local TargetUnit = UNIT:Find( TargetObject ) + local TargetUnitName = TargetUnit:GetName() + + if self.DetectionZone then + if TargetUnit:IsInZone( self.DetectionZone ) then + self:T( {"Detected ", TargetUnit } ) + if self.DetectedUnits[TargetUnit] == nil then + self.DetectedUnits[TargetUnit] = true + end + Detected = true + end + else + if self.DetectedUnits[TargetUnit] == nil then + self.DetectedUnits[TargetUnit] = true + end + Detected = true + end + end + end + + self:__Detect( -self.DetectInterval ) + + if Detected == true then + self:__Detected( 1.5 ) + end + +end + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable. +-- Note that this method is required, as triggers the next route when patrolling for the Controllable. +function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable ) + + local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolCore.Zone#AI_PATROL_ZONE + PatrolZone:__Route( 1 ) +end + + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_PATROL_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To ) + + self:F2() + + -- When RTB, don't allow anymore the routing. + if From == "RTB" then + return + end + + + if self.Controllable:IsAlive() then + -- Determine if the AIControllable is within the PatrolZone. + -- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point. + + local PatrolRoute = {} + + -- Calculate the current route point of the controllable as the start point of the route. + -- However, when the controllable is not in the air, + -- the controllable current waypoint is probably the airbase... + -- Thus, if we would take the current waypoint as the startpoint, upon take-off, the controllable flies + -- immediately back to the airbase, and this is not correct. + -- Therefore, when on a runway, get as the current route point a random point within the PatrolZone. + -- This will make the plane fly immediately to the patrol zone. + + if self.Controllable:InAir() == false then + self:E( "Not in the air, finding route path within PatrolZone" ) + local CurrentVec2 = self.Controllable:GetVec2() + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToPatrolZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TakeOffParking, + POINT_VEC3.RoutePointAction.FromParkingArea, + ToPatrolZoneSpeed, + true + ) + PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint + else + self:E( "In the air, finding route path within PatrolZone" ) + local CurrentVec2 = self.Controllable:GetVec2() + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToPatrolZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToPatrolZoneSpeed, + true + ) + PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint + end + + + --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. + + --- Find a random 2D point in PatrolZone. + local ToTargetVec2 = self.PatrolZone:GetRandomVec2() + self:T2( ToTargetVec2 ) + + --- Define Speed and Altitude. + local ToTargetAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) + local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) + self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) + + --- Obtain a 3D @{Point} from the 2D point + altitude. + local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) + + --- Create a route point of type air. + local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + --self.CoordTest:SpawnFromVec3( ToTargetPointVec3:GetVec3() ) + + --ToTargetPointVec3:SmokeRed() + + PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + self.Controllable:WayPointInitialize( PatrolRoute ) + + --- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ... + self.Controllable:SetState( self.Controllable, "PatrolZone", self ) + self.Controllable:WayPointFunction( #PatrolRoute, 1, "AI_PATROL_ZONE:_NewPatrolRoute" ) + + --- NOW ROUTE THE GROUP! + self.Controllable:WayPointExecute( 1, 2 ) + end + +end + +--- @param #AI_PATROL_ZONE self +function AI_PATROL_ZONE:onbeforeStatus() + + return self.CheckStatus +end + +--- @param #AI_PATROL_ZONE self +function AI_PATROL_ZONE:onafterStatus() + self:F2() + + if self.Controllable and self.Controllable:IsAlive() then + + local RTB = false + + local Fuel = self.Controllable:GetUnit(1):GetFuel() + if Fuel < self.PatrolFuelTresholdPercentage then + self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" ) + local OldAIControllable = self.Controllable + local AIControllableTemplate = self.Controllable:GetTemplate() + + local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) + local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) ) + OldAIControllable:SetTask( TimedOrbitTask, 10 ) + + RTB = true + else + end + + -- TODO: Check GROUP damage function. + local Damage = self.Controllable:GetLife() + if Damage <= self.PatrolDamageTreshold then + self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" ) + RTB = true + end + + if RTB == true then + self:RTB() + else + self:__Status( 60 ) -- Execute the Patrol event after 30 seconds. + end + end +end + +--- @param #AI_PATROL_ZONE self +function AI_PATROL_ZONE:onafterRTB() + self:F2() + + if self.Controllable and self.Controllable:IsAlive() then + + self:SetDetectionOff() + self.CheckStatus = false + + local PatrolRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToPatrolZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToPatrolZoneSpeed, + true + ) + + PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + self.Controllable:WayPointInitialize( PatrolRoute ) + + --- NOW ROUTE THE GROUP! + self.Controllable:WayPointExecute( 1, 1 ) + + end + +end + +--- @param #AI_PATROL_ZONE self +function AI_PATROL_ZONE:onafterDead() + self:SetDetectionOff() + self:SetStatusOff() +end + +--- @param #AI_PATROL_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_PATROL_ZONE:OnCrash( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:E( self.Controllable:GetUnits() ) + if #self.Controllable:GetUnits() == 1 then + self:__Crash( 1, EventData ) + end + end +end + +--- @param #AI_PATROL_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_PATROL_ZONE:OnEjection( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:__Eject( 1, EventData ) + end +end + +--- @param #AI_PATROL_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_PATROL_ZONE:OnPilotDead( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:__PilotDead( 1, EventData ) + end +end +--- **AI** - **Execute Combat Air Patrol (CAP).** +-- +-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG) +-- +-- === +-- +-- AI CAP classes makes AI Controllables execute a Combat Air Patrol. +-- +-- There are the following types of CAP classes defined: +-- +-- * @{#AI_CAP_ZONE}: Perform a CAP in a zone. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-01-15: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing. +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing. +-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision. +-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing. +-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module AI_Cap + + +--- @type AI_CAP_ZONE +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. +-- @extends AI.AI_Patrol#AI_PATROL_ZONE + + +--- # 1) @{#AI_CAP_ZONE} class, extends @{AI_CAP#AI_PATROL_ZONE} +-- +-- The @{#AI_CAP_ZONE} class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group} +-- and automatically engage any airborne enemies that are within a certain range or within a certain zone. +-- +-- ![Process](..\Presentations\AI_CAP\Dia3.JPG) +-- +-- The AI_CAP_ZONE is assigned a @{Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia4.JPG) +-- +-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. +-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. +-- +-- ![Process](..\Presentations\AI_CAP\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_CAP\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia9.JPG) +-- +-- When enemies are detected, the AI will automatically engage the enemy. +-- +-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) +-- +-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. +-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. +-- +-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) +-- +-- ## 1.1) AI_CAP_ZONE constructor +-- +-- * @{#AI_CAP_ZONE.New}(): Creates a new AI_CAP_ZONE object. +-- +-- ## 1.2) AI_CAP_ZONE is a FSM +-- +-- ![Process](..\Presentations\AI_CAP\Dia2.JPG) +-- +-- ### 1.2.1) AI_CAP_ZONE States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Engaging** ( Group ): The AI is engaging the bogeys. +-- * **Returning** ( Group ): The AI is returning to Base.. +-- +-- ### 1.2.2) AI_CAP_ZONE Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys. +-- * **@{#AI_CAP_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Unit}. +-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task. +-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- ## 1.3) Set the Range of Engagement +-- +-- ![Range](..\Presentations\AI_CAP\Dia11.JPG) +-- +-- An optional range can be set in meters, +-- that will define when the AI will engage with the detected airborne enemy targets. +-- The range can be beyond or smaller than the range of the Patrol Zone. +-- The range is applied at the position of the AI. +-- Use the method @{AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range. +-- +-- ## 1.4) Set the Zone of Engagement +-- +-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG) +-- +-- An optional @{Zone} can be set, +-- that will define when the AI will engage with the detected airborne enemy targets. +-- Use the method @{AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone. +-- +-- === +-- +-- @field #AI_CAP_ZONE AI_CAP_ZONE +-- +AI_CAP_ZONE = { + ClassName = "AI_CAP_ZONE", +} + + + +--- Creates a new AI_CAP_ZONE object +-- @param #AI_CAP_ZONE self +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_CAP_ZONE + + self.Accomplished = false + self.Engaging = false + + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_CAP_ZONE] OnBeforeEngage + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Engage. + -- @function [parent=#AI_CAP_ZONE] OnAfterEngage + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAP_ZONE] Engage + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAP_ZONE] __Engage + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_CAP_ZONE] OnLeaveEngaging +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Engaging. +-- @function [parent=#AI_CAP_ZONE] OnEnterEngaging +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_CAP_ZONE] OnBeforeFired + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Fired. + -- @function [parent=#AI_CAP_ZONE] OnAfterFired + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAP_ZONE] Fired + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAP_ZONE] __Fired + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] OnBeforeDestroy + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] OnAfterDestroy + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] Destroy + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] __Destroy + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_CAP_ZONE] OnBeforeAbort + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Abort. + -- @function [parent=#AI_CAP_ZONE] OnAfterAbort + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Abort. + -- @function [parent=#AI_CAP_ZONE] Abort + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_CAP_ZONE] __Abort + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] OnBeforeAccomplish + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] OnAfterAccomplish + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] Accomplish + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] __Accomplish + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- Set the Engage Zone which defines where the AI will engage bogies. +-- @param #AI_CAP_ZONE self +-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP. +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE:SetEngageZone( EngageZone ) + self:F2() + + if EngageZone then + self.EngageZone = EngageZone + else + self.EngageZone = nil + end +end + +--- Set the Engage Range when the AI will engage with airborne enemies. +-- @param #AI_CAP_ZONE self +-- @param #number EngageRange The Engage Range. +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE:SetEngageRange( EngageRange ) + self:F2() + + if EngageRange then + self.EngageRange = EngageRange + else + self.EngageRange = nil + end +end + +--- onafter State Transition for Event Start. +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To ) + + -- Call the parent Start event handler + self:GetParent(self).onafterStart( self, Controllable, From, Event, To ) + self:HandleEvent( EVENTS.Dead ) + +end + +-- todo: need to fix this global function + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +function _NewEngageCapRoute( AIControllable ) + + AIControllable:T( "NewEngageRoute" ) + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE + EngageZone:__Engage( 1 ) +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onbeforeEngage( Controllable, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To ) + + if From ~= "Engaging" then + + local Engage = false + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( DetectedUnit ) + if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then + Engage = true + break + end + end + + if Engage == true then + self:E( 'Detected -> Engaging' ) + self:__Engage( 1 ) + end + end +end + + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onafterAbort( Controllable, From, Event, To ) + Controllable:ClearTasks() + self:__Route( 1 ) +end + + + + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To ) + + if Controllable:IsAlive() then + + local EngageRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToEngageZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToEngageZoneSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = CurrentRoutePoint + + + --- Find a random 2D point in PatrolZone. + local ToTargetVec2 = self.PatrolZone:GetRandomVec2() + self:T2( ToTargetVec2 ) + + --- Define Speed and Altitude. + local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) + local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) + self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) + + --- Obtain a 3D @{Point} from the 2D point + altitude. + local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) + + --- Create a route point of type air. + local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint + + Controllable:OptionROEOpenFire() + Controllable:OptionROTPassiveDefense() + + local AttackTasks = {} + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( { DetectedUnit, DetectedUnit:IsAlive(), DetectedUnit:IsAir() } ) + if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then + if self.EngageZone then + if DetectedUnit:IsInZone( self.EngageZone ) then + self:E( {"Within Zone and Engaging ", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + else + if self.EngageRange then + if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then + self:E( {"Within Range and Engaging", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + else + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + self.Controllable:WayPointInitialize( EngageRoute ) + + + if #AttackTasks == 0 then + self:E("No targets found -> Going back to Patrolling") + self:__Abort( 1 ) + self:__Route( 1 ) + self:SetDetectionActivated() + else + EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + self.Controllable:SetState( self.Controllable, "EngageZone", self ) + + self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" ) + + self:SetDetectionDeactivated() + end + + --- NOW ROUTE THE GROUP! + self.Controllable:WayPointExecute( 1, 2 ) + + end +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAP_ZONE:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self:SetDetectionOff() +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @param Core.Event#EVENTDATA EventData +function AI_CAP_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) + + if EventData.IniUnit then + self.DetectedUnits[EventData.IniUnit] = nil + end +end + +--- @param #AI_CAP_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_CAP_ZONE:OnEventDead( EventData ) + self:F( { "EventDead", EventData } ) + + if EventData.IniDCSUnit then + if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit] then + self:__Destroy( 1, EventData ) + end + end +end +--- **AI** -- **Provide Close Air Support to friendly ground troops.** +-- +-- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG) +-- +-- === +-- +-- AI CAS classes makes AI Controllables execute a Close Air Support. +-- +-- There are the following types of CAS classes defined: +-- +-- * @{#AI_CAS_ZONE}: Perform a CAS in a zone. +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-01-15: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing. +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing. +-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module AI_Cas + + +--- AI_CAS_ZONE class +-- @type AI_CAS_ZONE +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. +-- @extends AI.AI_Patrol#AI_PATROL_ZONE + +--- # 1) @{#AI_CAS_ZONE} class, extends @{AI_Patrol#AI_PATROL_ZONE} +-- +-- @{#AI_CAS_ZONE} derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +-- +-- The @{#AI_CAS_ZONE} class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. +-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. +-- +-- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG) +-- +-- The AI_CAS_ZONE is assigned a @{Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event. +-- +-- ![Start Event](..\Presentations\AI_CAS\Dia4.JPG) +-- +-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone, +-- using a random speed within the given altitude and speed limits. +-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. +-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. +-- +-- ![Route Event](..\Presentations\AI_CAS\Dia5.JPG) +-- +-- When the AI is commanded to provide Close Air Support (through the event **Engage**), the AI will fly towards the Engage Zone. +-- Any target that is detected in the Engage Zone will be reported and will be destroyed by the AI. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia6.JPG) +-- +-- The AI will detect the targets and will only destroy the targets within the Engage Zone. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia7.JPG) +-- +-- Every target that is destroyed, is reported< by the AI. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia8.JPG) +-- +-- Note that the AI does not know when the Engage Zone is cleared, and therefore will keep circling in the zone. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia9.JPG) +-- +-- Until it is notified through the event **Accomplish**, which is to be triggered by an observing party: +-- +-- * a FAC +-- * a timed event +-- * a menu option selected by a human +-- * a condition +-- * others ... +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia10.JPG) +-- +-- When the AI has accomplished the CAS, it will fly back to the Patrol Zone. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia11.JPG) +-- +-- It will keep patrolling there, until it is notified to RTB or move to another CAS Zone. +-- It can be notified to go RTB through the **RTB** event. +-- +-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. +-- +-- ![Engage Event](..\Presentations\AI_CAS\Dia12.JPG) +-- +-- # 1.1) AI_CAS_ZONE constructor +-- +-- * @{#AI_CAS_ZONE.New}(): Creates a new AI_CAS_ZONE object. +-- +-- ## 1.2) AI_CAS_ZONE is a FSM +-- +-- ![Process](..\Presentations\AI_CAS\Dia2.JPG) +-- +-- ### 1.2.1) AI_CAS_ZONE States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Engaging** ( Group ): The AI is engaging the targets in the Engage Zone, executing CAS. +-- * **Returning** ( Group ): The AI is returning to Base.. +-- +-- ### 1.2.2) AI_CAS_ZONE Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_CAS_ZONE.Engage}**: Engage the AI to provide CAS in the Engage Zone, destroying any target it finds. +-- * **@{#AI_CAS_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. +-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the CAS task. +-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- === +-- +-- @field #AI_CAS_ZONE AI_CAS_ZONE +-- +AI_CAS_ZONE = { + ClassName = "AI_CAS_ZONE", +} + + + +--- Creates a new AI_CAS_ZONE object +-- @param #AI_CAS_ZONE self +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_CAS_ZONE self +function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_CAS_ZONE + + self.EngageZone = EngageZone + self.Accomplished = false + + self:SetDetectionZone( self.EngageZone ) + + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_CAS_ZONE] OnBeforeEngage + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Engage. + -- @function [parent=#AI_CAS_ZONE] OnAfterEngage + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAS_ZONE] Engage + -- @param #AI_CAS_ZONE self + -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. + -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- If parameter is not defined the unit / controllable will choose expend on its own discretion. + -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. + -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAS_ZONE] __Engage + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. + -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. + -- If parameter is not defined the unit / controllable will choose expend on its own discretion. + -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. + -- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging +-- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Engaging. +-- @function [parent=#AI_CAS_ZONE] OnEnterEngaging +-- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Engaging", "Target", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_CAS_ZONE] OnBeforeFired + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Fired. + -- @function [parent=#AI_CAS_ZONE] OnAfterFired + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAS_ZONE] Fired + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAS_ZONE] __Fired + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] OnBeforeDestroy + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] OnAfterDestroy + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] Destroy + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] __Destroy + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_CAS_ZONE] OnBeforeAbort + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Abort. + -- @function [parent=#AI_CAS_ZONE] OnAfterAbort + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Abort. + -- @function [parent=#AI_CAS_ZONE] Abort + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_CAS_ZONE] __Abort + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] OnBeforeAccomplish + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] OnAfterAccomplish + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] Accomplish + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] __Accomplish + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- Set the Engage Zone where the AI is performing CAS. Note that if the EngageZone is changed, the AI needs to re-detect targets. +-- @param #AI_CAS_ZONE self +-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAS. +-- @return #AI_CAS_ZONE self +function AI_CAS_ZONE:SetEngageZone( EngageZone ) + self:F2() + + if EngageZone then + self.EngageZone = EngageZone + else + self.EngageZone = nil + end +end + + + +--- onafter State Transition for Event Start. +-- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To ) + + -- Call the parent Start event handler + self:GetParent(self).onafterStart( self, Controllable, From, Event, To ) + self:HandleEvent( EVENTS.Dead ) + + self:SetDetectionDeactivated() -- When not engaging, set the detection off. +end + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +function _NewEngageRoute( AIControllable ) + + AIControllable:T( "NewEngageRoute" ) + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_CAS_ZONE + EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection ) +end + + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onbeforeEngage( Controllable, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To ) + self:E("onafterTarget") + + if Controllable:IsAlive() then + + local AttackTasks = {} + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + if DetectedUnit:IsAlive() then + if DetectedUnit:IsInZone( self.EngageZone ) then + if Detected == true then + self:E( {"Target: ", DetectedUnit } ) + self.DetectedUnits[DetectedUnit] = false + local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil ) + self.Controllable:PushTask( AttackTask, 1 ) + end + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + self:__Target( -10 ) + + end +end + + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterAbort( Controllable, From, Event, To ) + Controllable:ClearTasks() + self:__Route( 1 ) +end + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. +-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. +-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. +function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To, + EngageSpeed, + EngageAltitude, + EngageWeaponExpend, + EngageAttackQty, + EngageDirection ) + self:F("onafterEngage") + + self.EngageSpeed = EngageSpeed or 400 + self.EngageAltitude = EngageAltitude or 2000 + self.EngageWeaponExpend = EngageWeaponExpend + self.EngageAttackQty = EngageAttackQty + self.EngageDirection = EngageDirection + + if Controllable:IsAlive() then + + local EngageRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToEngageZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + self.EngageSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = CurrentRoutePoint + + local AttackTasks = {} + + for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( DetectedUnit ) + if DetectedUnit:IsAlive() then + if DetectedUnit:IsInZone( self.EngageZone ) then + self:E( {"Engaging ", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit, + true, + EngageWeaponExpend, + EngageAttackQty, + EngageDirection + ) + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) + + --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. + + --- Find a random 2D point in EngageZone. + local ToTargetVec2 = self.EngageZone:GetRandomVec2() + self:T2( ToTargetVec2 ) + + --- Obtain a 3D @{Point} from the 2D point + altitude. + local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y ) + + --- Create a route point of type air. + local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + self.EngageSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = ToTargetRoutePoint + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Controllable:WayPointInitialize( EngageRoute ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + Controllable:SetState( Controllable, "EngageZone", self ) + + Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) + + --- NOW ROUTE THE GROUP! + Controllable:WayPointExecute( 1 ) + + Controllable:OptionROEOpenFire() + Controllable:OptionROTVertical() + + self:SetDetectionInterval( 2 ) + self:SetDetectionActivated() + self:__Target( -2 ) -- Start Targetting + end +end + + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self:SetDetectionDeactivated() +end + + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @param Core.Event#EVENTDATA EventData +function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) + + if EventData.IniUnit then + self.DetectedUnits[EventData.IniUnit] = nil + end +end + + +--- @param #AI_CAS_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_CAS_ZONE:OnEventDead( EventData ) + self:F( { "EventDead", EventData } ) + + if EventData.IniDCSUnit then + if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit] then + self:__Destroy( 1, EventData ) + end + end +end + + +---Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**Ground** -- +-- **Management of logical cargo objects, that can be transported from and to transportation carriers.** +-- +-- ![Banner Image](..\Presentations\AI_CARGO\CARGO.JPG) +-- +-- === +-- +-- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): +-- +-- * AI_CARGO_UNIT, represented by a @{Unit} in a @{Group}: Cargo can be represented by a Unit in a Group. Destruction of the Unit will mean that the cargo is lost. +-- * CARGO_STATIC, represented by a @{Static}: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost. +-- * AI_CARGO_PACKAGE, contained in a @{Unit} of a @{Group}: Cargo can be contained within a Unit of a Group. The cargo can be **delivered** by the @{Unit}. If the Unit is destroyed, the cargo will be destroyed also. +-- * AI_CARGO_PACKAGE, Contained in a @{Static}: Cargo can be contained within a Static. The cargo can be **collected** from the @Static. If the @{Static} is destroyed, the cargo will be destroyed. +-- * CARGO_SLINGLOAD, represented by a @{Cargo} that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost. +-- +-- * AI_CARGO_GROUPED, represented by a Group of CARGO_UNITs. +-- +-- # 1) @{#AI_CARGO} class, extends @{Fsm#FSM_PROCESS} +-- +-- The @{#AI_CARGO} class defines the core functions that defines a cargo object within MOOSE. +-- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. +-- +-- The AI_CARGO is a state machine: it manages the different events and states of the cargo. +-- All derived classes from AI_CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. +-- +-- ## 1.2.1) AI_CARGO Events: +-- +-- * @{#AI_CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. +-- * @{#AI_CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. +-- * @{#AI_CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. +-- * @{#AI_CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. +-- * @{#AI_CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. +-- +-- ## 1.2.2) AI_CARGO States: +-- +-- * **UnLoaded**: The cargo is unloaded from a carrier. +-- * **Boarding**: The cargo is currently boarding (= running) into a carrier. +-- * **Loaded**: The cargo is loaded into a carrier. +-- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. +-- * **Dead**: The cargo is dead ... +-- * **End**: The process has come to an end. +-- +-- ## 1.2.3) AI_CARGO state transition methods: +-- +-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. +-- There are 2 moments when state transition methods will be called by the state machine: +-- +-- * **Leaving** the state. +-- The state transition method needs to start with the name **OnLeave + the name of the state**. +-- If the state transition method returns false, then the processing of the state transition will not be done! +-- If you want to change the behaviour of the AIControllable at this event, return false, +-- but then you'll need to specify your own logic using the AIControllable! +-- +-- * **Entering** the state. +-- The state transition method needs to start with the name **OnEnter + the name of the state**. +-- These state transition methods need to provide a return value, which is specified at the function description. +-- +-- # 2) #AI_CARGO_UNIT class +-- +-- The AI_CARGO_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. +-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. +-- +-- # 5) #AI_CARGO_GROUPED class +-- +-- The AI_CARGO_GROUPED class defines a cargo that is represented by a group of UNIT objects within the simulator, and can be transported by a carrier. +-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. +-- +-- This module is still under construction, but is described above works already, and will keep working ... +-- +-- @module Cargo + +-- Events + +-- Board + +--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#AI_CARGO] Board +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + +--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#AI_CARGO] __Board +-- @param #AI_CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + + +-- UnBoard + +--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#AI_CARGO] UnBoard +-- @param #AI_CARGO self +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. + +--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#AI_CARGO] __UnBoard +-- @param #AI_CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. + + +-- Load + +--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#AI_CARGO] Load +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + +--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **UnLoaded** state. +-- @function [parent=#AI_CARGO] __Load +-- @param #AI_CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. + + +-- UnLoad + +--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#AI_CARGO] UnLoad +-- @param #AI_CARGO self +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. + +--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. +-- The cargo must be in the **Loaded** state. +-- @function [parent=#AI_CARGO] __UnLoad +-- @param #AI_CARGO self +-- @param #number DelaySeconds The amount of seconds to delay the action. +-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. + +-- State Transition Functions + +-- UnLoaded + +--- @function [parent=#AI_CARGO] OnLeaveUnLoaded +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#AI_CARGO] OnEnterUnLoaded +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + +-- Loaded + +--- @function [parent=#AI_CARGO] OnLeaveLoaded +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#AI_CARGO] OnEnterLoaded +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + +-- Boarding + +--- @function [parent=#AI_CARGO] OnLeaveBoarding +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#AI_CARGO] OnEnterBoarding +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + +-- UnBoarding + +--- @function [parent=#AI_CARGO] OnLeaveUnBoarding +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable +-- @return #boolean + +--- @function [parent=#AI_CARGO] OnEnterUnBoarding +-- @param #AI_CARGO self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable + + +-- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. + +CARGOS = {} + +do -- AI_CARGO + + --- @type AI_CARGO + -- @extends Core.Fsm#FSM_PROCESS + -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. + -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. + -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. + -- @field #number ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier. + -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. + -- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... + -- @field Wrapper.Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... + -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. + -- @field #boolean Moveable This flag defines if the cargo is moveable. + -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. + -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. + AI_CARGO = { + ClassName = "AI_CARGO", + Type = nil, + Name = nil, + Weight = nil, + CargoObject = nil, + CargoCarrier = nil, + Representable = false, + Slingloadable = false, + Moveable = false, + Containable = false, + } + +--- @type AI_CARGO.CargoObjects +-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. + + +--- AI_CARGO Constructor. This class is an abstract class and should not be instantiated. +-- @param #AI_CARGO self +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO +function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) + + local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self:SetStartState( "UnLoaded" ) + self:AddTransition( "UnLoaded", "Board", "Boarding" ) + self:AddTransition( "Boarding", "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "Load", "Loaded" ) + self:AddTransition( "UnLoaded", "Load", "Loaded" ) + self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) + self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) + self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) + + + self.Type = Type + self.Name = Name + self.Weight = Weight + self.ReportRadius = ReportRadius + self.NearRadius = NearRadius + self.CargoObject = nil + self.CargoCarrier = nil + self.Representable = false + self.Slingloadable = false + self.Moveable = false + self.Containable = false + + + self.CargoScheduler = SCHEDULER:New() + + CARGOS[self.Name] = self + + return self +end + + +--- Template method to spawn a new representation of the AI_CARGO in the simulator. +-- @param #AI_CARGO self +-- @return #AI_CARGO +function AI_CARGO:Spawn( PointVec2 ) + self:F() + +end + + +--- Check if CargoCarrier is near the Cargo to be Loaded. +-- @param #AI_CARGO self +-- @param Core.Point#POINT_VEC2 PointVec2 +-- @return #boolean +function AI_CARGO:IsNear( PointVec2 ) + self:F( { PointVec2 } ) + + local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + self:T( Distance ) + + if Distance <= self.NearRadius then + return true + else + return false + end +end + +end + +do -- AI_CARGO_REPRESENTABLE + + --- @type AI_CARGO_REPRESENTABLE + -- @extends #AI_CARGO + AI_CARGO_REPRESENTABLE = { + ClassName = "AI_CARGO_REPRESENTABLE" + } + +--- AI_CARGO_REPRESENTABLE Constructor. +-- @param #AI_CARGO_REPRESENTABLE self +-- @param Wrapper.Controllable#Controllable CargoObject +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO_REPRESENTABLE +function AI_CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + return self +end + +--- Route a cargo unit to a PointVec2. +-- @param #AI_CARGO_REPRESENTABLE self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #number Speed +-- @return #AI_CARGO_REPRESENTABLE +function AI_CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) + self:F2( ToPointVec2 ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) + Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + return self +end + +end -- AI_CARGO + +do -- AI_CARGO_UNIT + + --- @type AI_CARGO_UNIT + -- @extends #AI_CARGO_REPRESENTABLE + AI_CARGO_UNIT = { + ClassName = "AI_CARGO_UNIT" + } + +--- AI_CARGO_UNIT Constructor. +-- @param #AI_CARGO_UNIT self +-- @param Wrapper.Unit#UNIT CargoUnit +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO_UNIT +function AI_CARGO_UNIT:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_UNIT + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self:T( CargoUnit ) + self.CargoObject = CargoUnit + + self:T( self.ClassName ) + + return self +end + +--- Enter UnBoarding State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Core.Point#POINT_VEC2 ToPointVec2 +function AI_CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2 ) + self:F() + + local Angle = 180 + local Speed = 10 + local DeployDistance = 5 + local RouteDistance = 60 + + if From == "Loaded" then + + local CargoCarrierPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, CargoDeployHeading ) + local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) + + -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 + ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 + + local FromPointVec2 = CargoCarrierPointVec2 + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) + self.CargoCarrier = nil + + local Points = {} + Points[#Points+1] = FromPointVec2:RoutePointGround( Speed ) + Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 1 ) + + self:__UnBoarding( 1, ToPointVec2 ) + end + end + +end + +--- Leave UnBoarding State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Core.Point#POINT_VEC2 ToPointVec2 +function AI_CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + if self:IsNear( ToPointVec2 ) then + return true + else + self:__UnBoarding( 1, ToPointVec2 ) + end + return false + end + +end + +--- UnBoard Event. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Core.Point#POINT_VEC2 ToPointVec2 +function AI_CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + self.CargoInAir = self.CargoObject:InAir() + + self:T( self.CargoInAir ) + + -- Only unboard the cargo when the carrier is not in the air. + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + + end + + self:__UnLoad( 1, ToPointVec2 ) + +end + + + +--- Enter UnLoaded State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Core.Point#POINT_VEC2 +function AI_CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "Loaded" then + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) + + ToPointVec2 = ToPointVec2 or POINT_VEC2:New( CargoDeployPointVec2:GetX(), CargoDeployPointVec2:GetY() ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) + self.CargoCarrier = nil + end + + end + + if self.OnUnLoadedCallBack then + self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) + self.OnUnLoadedCallBack = nil + end + +end + + + +--- Enter Boarding State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local Speed = 10 + local Angle = 180 + local Distance = 5 + + if From == "UnLoaded" then + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 2 ) + end + +end + +--- Leave Boarding State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + if self:IsNear( CargoCarrier:GetPointVec2() ) then + self:__Load( 1, CargoCarrier ) + return true + else + self:__Boarding( 1, CargoCarrier ) + end + return false +end + +--- Loaded State. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) + self:F() + + self.CargoCarrier = CargoCarrier + + -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). + if self.CargoObject then + self:T("Destroying") + self.CargoObject:Destroy() + end +end + + +--- Board Event. +-- @param #AI_CARGO_UNIT self +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier ) + self:F() + + self.CargoInAir = self.CargoObject:InAir() + + self:T( self.CargoInAir ) + + -- Only move the group to the carrier when the cargo is not in the air + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + self:Load( CargoCarrier ) + end + +end + +end + +do -- AI_CARGO_PACKAGE + + --- @type AI_CARGO_PACKAGE + -- @extends #AI_CARGO_REPRESENTABLE + AI_CARGO_PACKAGE = { + ClassName = "AI_CARGO_PACKAGE" + } + +--- AI_CARGO_PACKAGE Constructor. +-- @param #AI_CARGO_PACKAGE self +-- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO_PACKAGE +function AI_CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_PACKAGE + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + self:T( CargoCarrier ) + self.CargoCarrier = CargoCarrier + + return self +end + +--- Board Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed +-- @param #number BoardDistance +-- @param #number Angle +function AI_CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + self:F() + + self.CargoInAir = self.CargoCarrier:InAir() + + self:T( self.CargoInAir ) + + -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. + if not self.CargoInAir then + + local Points = {} + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) + + Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + end + + self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + +end + +--- Check if CargoCarrier is near the Cargo to be Loaded. +-- @param #AI_CARGO_PACKAGE self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @return #boolean +function AI_CARGO_PACKAGE:IsNear( CargoCarrier ) + self:F() + + local CargoCarrierPoint = CargoCarrier:GetPointVec2() + + local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + self:T( Distance ) + + if Distance <= self.NearRadius then + return true + else + return false + end +end + +--- Boarded Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + self:F() + + if self:IsNear( CargoCarrier ) then + self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) + else + self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) + end +end + +--- UnBoard Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param #number Speed +-- @param #number UnLoadDistance +-- @param #number UnBoardDistance +-- @param #number Radius +-- @param #number Angle +function AI_CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) + self:F() + + self.CargoInAir = self.CargoCarrier:InAir() + + self:T( self.CargoInAir ) + + -- Only unboard the cargo when the carrier is not in the air. + -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). + if not self.CargoInAir then + + self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) + + local Points = {} + + local StartPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) + + Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = CargoCarrier:TaskRoute( Points ) + CargoCarrier:SetTask( TaskRoute, 1 ) + end + + self:__UnBoarded( 1 , CargoCarrier, Speed ) + +end + +--- UnBoarded Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +function AI_CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) + self:F() + + if self:IsNear( CargoCarrier ) then + self:__UnLoad( 1, CargoCarrier, Speed ) + else + self:__UnBoarded( 1, CargoCarrier, Speed ) + end +end + +--- Load Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed +-- @param #number LoadDistance +-- @param #number Angle +function AI_CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) + self:F() + + self.CargoCarrier = CargoCarrier + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) + + local Points = {} + Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + +end + +--- UnLoad Event. +-- @param #AI_CARGO_PACKAGE self +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param #number Distance +-- @param #number Angle +function AI_CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) + self:F() + + local StartPointVec2 = self.CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) + + self.CargoCarrier = CargoCarrier + + local Points = {} + Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoCarrier:TaskRoute( Points ) + self.CargoCarrier:SetTask( TaskRoute, 1 ) + +end + + +end + +do -- AI_CARGO_GROUP + + --- @type AI_CARGO_GROUP + -- @extends AI.AI_Cargo#AI_CARGO + -- @field Set#SET_BASE CargoSet A set of cargo objects. + -- @field #string Name A string defining the name of the cargo group. The name is the unique identifier of the cargo. + AI_CARGO_GROUP = { + ClassName = "AI_CARGO_GROUP", + } + +--- AI_CARGO_GROUP constructor. +-- @param #AI_CARGO_GROUP self +-- @param Core.Set#Set_BASE CargoSet +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO_GROUP +function AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, 0, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUP + self:F( { Type, Name, ReportRadius, NearRadius } ) + + self.CargoSet = CargoSet + + + return self +end + +end -- AI_CARGO_GROUP + +do -- AI_CARGO_GROUPED + + --- @type AI_CARGO_GROUPED + -- @extends AI.AI_Cargo#AI_CARGO_GROUP + AI_CARGO_GROUPED = { + ClassName = "AI_CARGO_GROUPED", + } + +--- AI_CARGO_GROUPED constructor. +-- @param #AI_CARGO_GROUPED self +-- @param Core.Set#Set_BASE CargoSet +-- @param #string Type +-- @param #string Name +-- @param #number Weight +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #AI_CARGO_GROUPED +function AI_CARGO_GROUPED:New( CargoSet, Type, Name, ReportRadius, NearRadius ) + local self = BASE:Inherit( self, AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUPED + self:F( { Type, Name, ReportRadius, NearRadius } ) + + return self +end + +--- Enter Boarding State. +-- @param #AI_CARGO_GROUPED self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onenterBoarding( From, Event, To, CargoCarrier ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + if From == "UnLoaded" then + + -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + Cargo:__Board( 1, CargoCarrier ) + end + ) + + self:__Boarding( 1, CargoCarrier ) + end + +end + +--- Enter Loaded State. +-- @param #AI_CARGO_GROUPED self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onenterLoaded( From, Event, To, CargoCarrier ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + if From == "UnLoaded" then + -- For each Cargo object within the AI_CARGO_GROUPED, load each cargo to the CargoCarrier. + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + Cargo:Load( CargoCarrier ) + end + end +end + +--- Leave Boarding State. +-- @param #AI_CARGO_GROUPED self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onleaveBoarding( From, Event, To, CargoCarrier ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local Boarded = true + + -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( Cargo.current ) + if not Cargo:is( "Loaded" ) then + Boarded = false + end + end + + if not Boarded then + self:__Boarding( 1, CargoCarrier ) + else + self:__Load( 1, CargoCarrier ) + end + return Boarded +end + +--- Enter UnBoarding State. +-- @param #AI_CARGO_GROUPED self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onenterUnBoarding( From, Event, To, ToPointVec2 ) + self:F() + + local Timer = 1 + + if From == "Loaded" then + + -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + Cargo:__UnBoard( Timer, ToPointVec2 ) + Timer = Timer + 10 + end + ) + + self:__UnBoarding( 1, ToPointVec2 ) + end + +end + +--- Leave UnBoarding State. +-- @param #AI_CARGO_GROUPED self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + local UnBoarded = true + + -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( Cargo.current ) + if not Cargo:is( "UnLoaded" ) then + UnBoarded = false + end + end + + if UnBoarded then + return true + else + self:__UnBoarding( 1, ToPointVec2 ) + end + + return false + end + +end + +--- UnBoard Event. +-- @param #AI_CARGO_GROUPED self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onafterUnBoarding( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + self:__UnLoad( 1, ToPointVec2 ) +end + + + +--- Enter UnLoaded State. +-- @param #AI_CARGO_GROUPED self +-- @param Core.Point#POINT_VEC2 +-- @param #string Event +-- @param #string From +-- @param #string To +function AI_CARGO_GROUPED:onenterUnLoaded( From, Event, To, ToPointVec2 ) + self:F( { ToPointVec2, From, Event, To } ) + + if From == "Loaded" then + + -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + Cargo:UnLoad( ToPointVec2 ) + end + ) + + end + +end + +end -- AI_CARGO_GROUPED + + + +--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments. +-- +-- === +-- +-- # @{#ACT_ASSIGN} FSM template class, extends @{Fsm#FSM_PROCESS} +-- +-- ## ACT_ASSIGN state machine: +-- +-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. +-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. +-- Each derived class follows exactly the same process, using the same events and following the same state transitions, +-- but will have **different implementation behaviour** upon each event or state transition. +-- +-- ### ACT_ASSIGN **Events**: +-- +-- These are the events defined in this class: +-- +-- * **Start**: Start the tasking acceptance process. +-- * **Assign**: Assign the task. +-- * **Reject**: Reject the task.. +-- +-- ### ACT_ASSIGN **Event methods**: +-- +-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. +-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: +-- +-- * **Immediate**: The event method has exactly the name of the event. +-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. +-- +-- ### ACT_ASSIGN **States**: +-- +-- * **UnAssigned**: The player has not accepted the task. +-- * **Assigned (*)**: The player has accepted the task. +-- * **Rejected (*)**: The player has not accepted the task. +-- * **Waiting**: The process is awaiting player feedback. +-- * **Failed (*)**: The process has failed. +-- +-- (*) End states of the process. +-- +-- ### ACT_ASSIGN state transition methods: +-- +-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. +-- There are 2 moments when state transition methods will be called by the state machine: +-- +-- * **Before** the state transition. +-- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- If the state transition method returns false, then the processing of the state transition will not be done! +-- If you want to change the behaviour of the AIControllable at this event, return false, +-- but then you'll need to specify your own logic using the AIControllable! +-- +-- * **After** the state transition. +-- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- These state transition methods need to provide a return value, which is specified at the function description. +-- +-- === +-- +-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} +-- +-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task. +-- +-- ## 1.1) ACT_ASSIGN_ACCEPT constructor: +-- +-- * @{#ACT_ASSIGN_ACCEPT.New}(): Creates a new ACT_ASSIGN_ACCEPT object. +-- +-- === +-- +-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} +-- +-- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option. +-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task. +-- The assignment type also allows to reject the task. +-- +-- ## 2.1) ACT_ASSIGN_MENU_ACCEPT constructor: +-- ----------------------------------------- +-- +-- * @{#ACT_ASSIGN_MENU_ACCEPT.New}(): Creates a new ACT_ASSIGN_MENU_ACCEPT object. +-- +-- === +-- +-- @module Assign + + +do -- ACT_ASSIGN + + --- ACT_ASSIGN class + -- @type ACT_ASSIGN + -- @field Tasking.Task#TASK Task + -- @field Wrapper.Unit#UNIT ProcessUnit + -- @field Core.Zone#ZONE_BASE TargetZone + -- @extends Core.Fsm#FSM_PROCESS + ACT_ASSIGN = { + ClassName = "ACT_ASSIGN", + } + + + --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. + -- @param #ACT_ASSIGN self + -- @return #ACT_ASSIGN The task acceptance process. + function ACT_ASSIGN:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIGN" ) ) -- Core.Fsm#FSM_PROCESS + + self:AddTransition( "UnAssigned", "Start", "Waiting" ) + self:AddTransition( "Waiting", "Assign", "Assigned" ) + self:AddTransition( "Waiting", "Reject", "Rejected" ) + self:AddTransition( "*", "Fail", "Failed" ) + + self:AddEndState( "Assigned" ) + self:AddEndState( "Rejected" ) + self:AddEndState( "Failed" ) + + self:SetStartState( "UnAssigned" ) + + return self + end + +end -- ACT_ASSIGN + + + +do -- ACT_ASSIGN_ACCEPT + + --- ACT_ASSIGN_ACCEPT class + -- @type ACT_ASSIGN_ACCEPT + -- @field Tasking.Task#TASK Task + -- @field Wrapper.Unit#UNIT ProcessUnit + -- @field Core.Zone#ZONE_BASE TargetZone + -- @extends #ACT_ASSIGN + ACT_ASSIGN_ACCEPT = { + ClassName = "ACT_ASSIGN_ACCEPT", + } + + + --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. + -- @param #ACT_ASSIGN_ACCEPT self + -- @param #string TaskBriefing + function ACT_ASSIGN_ACCEPT:New( TaskBriefing ) + + local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_ACCEPT + + self.TaskBriefing = TaskBriefing + + return self + end + + function ACT_ASSIGN_ACCEPT:Init( FsmAssign ) + + self.TaskBriefing = FsmAssign.TaskBriefing + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_ACCEPT self + -- @param Wrapper.Unit#UNIT ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) + self:E( { ProcessUnit, From, Event, To } ) + + self:__Assign( 1 ) + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_ACCEPT self + -- @param Wrapper.Unit#UNIT ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To ) + env.info( "in here" ) + self:E( { ProcessUnit, From, Event, To } ) + + local ProcessGroup = ProcessUnit:GetGroup() + + self:Message( "You are assigned to the task " .. self.Task:GetName() ) + + self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() ) + end + +end -- ACT_ASSIGN_ACCEPT + + +do -- ACT_ASSIGN_MENU_ACCEPT + + --- ACT_ASSIGN_MENU_ACCEPT class + -- @type ACT_ASSIGN_MENU_ACCEPT + -- @field Tasking.Task#TASK Task + -- @field Wrapper.Unit#UNIT ProcessUnit + -- @field Core.Zone#ZONE_BASE TargetZone + -- @extends #ACT_ASSIGN + ACT_ASSIGN_MENU_ACCEPT = { + ClassName = "ACT_ASSIGN_MENU_ACCEPT", + } + + --- Init. + -- @param #ACT_ASSIGN_MENU_ACCEPT self + -- @param #string TaskName + -- @param #string TaskBriefing + -- @return #ACT_ASSIGN_MENU_ACCEPT self + function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing ) + + -- Inherits from BASE + local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT + + self.TaskName = TaskName + self.TaskBriefing = TaskBriefing + + return self + end + + function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign ) + + self.TaskName = FsmAssign.TaskName + self.TaskBriefing = FsmAssign.TaskBriefing + end + + + --- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. + -- @param #ACT_ASSIGN_MENU_ACCEPT self + -- @param #string TaskName + -- @param #string TaskBriefing + -- @return #ACT_ASSIGN_MENU_ACCEPT self + function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing ) + + self.TaskBriefing = TaskBriefing + self.TaskName = TaskName + + return self + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_MENU_ACCEPT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) + self:E( { ProcessUnit, From, Event, To } ) + + self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." ) + + local ProcessGroup = ProcessUnit:GetGroup() + + self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" ) + self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self ) + self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self ) + end + + --- Menu function. + -- @param #ACT_ASSIGN_MENU_ACCEPT self + function ACT_ASSIGN_MENU_ACCEPT:MenuAssign() + self:E( ) + + self:__Assign( 1 ) + end + + --- Menu function. + -- @param #ACT_ASSIGN_MENU_ACCEPT self + function ACT_ASSIGN_MENU_ACCEPT:MenuReject() + self:E( ) + + self:__Reject( 1 ) + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_MENU_ACCEPT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To ) + self:E( { ProcessUnit.UnitNameFrom, Event, To } ) + + self.Menu:Remove() + end + + --- StateMachine callback function + -- @param #ACT_ASSIGN_MENU_ACCEPT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To ) + self:E( { ProcessUnit.UnitName, From, Event, To } ) + + self.Menu:Remove() + --TODO: need to resolve this problem ... it has to do with the events ... + --self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event + ProcessUnit:Destroy() + end + +end -- ACT_ASSIGN_MENU_ACCEPT +--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. +-- +-- === +-- +-- # @{#ACT_ROUTE} FSM class, extends @{Fsm#FSM_PROCESS} +-- +-- ## ACT_ROUTE state machine: +-- +-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. +-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. +-- Each derived class follows exactly the same process, using the same events and following the same state transitions, +-- but will have **different implementation behaviour** upon each event or state transition. +-- +-- ### ACT_ROUTE **Events**: +-- +-- These are the events defined in this class: +-- +-- * **Start**: The process is started. The process will go into the Report state. +-- * **Report**: The process is reporting to the player the route to be followed. +-- * **Route**: The process is routing the controllable. +-- * **Pause**: The process is pausing the route of the controllable. +-- * **Arrive**: The controllable has arrived at a route point. +-- * **More**: There are more route points that need to be followed. The process will go back into the Report state. +-- * **NoMore**: There are no more route points that need to be followed. The process will go into the Success state. +-- +-- ### ACT_ROUTE **Event methods**: +-- +-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. +-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: +-- +-- * **Immediate**: The event method has exactly the name of the event. +-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. +-- +-- ### ACT_ROUTE **States**: +-- +-- * **None**: The controllable did not receive route commands. +-- * **Arrived (*)**: The controllable has arrived at a route point. +-- * **Aborted (*)**: The controllable has aborted the route path. +-- * **Routing**: The controllable is understay to the route point. +-- * **Pausing**: The process is pausing the routing. AI air will go into hover, AI ground will stop moving. Players can fly around. +-- * **Success (*)**: All route points were reached. +-- * **Failed (*)**: The process has failed. +-- +-- (*) End states of the process. +-- +-- ### ACT_ROUTE state transition methods: +-- +-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. +-- There are 2 moments when state transition methods will be called by the state machine: +-- +-- * **Before** the state transition. +-- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- If the state transition method returns false, then the processing of the state transition will not be done! +-- If you want to change the behaviour of the AIControllable at this event, return false, +-- but then you'll need to specify your own logic using the AIControllable! +-- +-- * **After** the state transition. +-- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- These state transition methods need to provide a return value, which is specified at the function description. +-- +-- === +-- +-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE} +-- +-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}. +-- The player receives on perioding times messages with the coordinates of the route to follow. +-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended. +-- +-- # 1.1) ACT_ROUTE_ZONE constructor: +-- +-- * @{#ACT_ROUTE_ZONE.New}(): Creates a new ACT_ROUTE_ZONE object. +-- +-- === +-- +-- @module Route + + +do -- ACT_ROUTE + + --- ACT_ROUTE class + -- @type ACT_ROUTE + -- @field Tasking.Task#TASK TASK + -- @field Wrapper.Unit#UNIT ProcessUnit + -- @field Core.Zone#ZONE_BASE Zone + -- @extends Core.Fsm#FSM_PROCESS + ACT_ROUTE = { + ClassName = "ACT_ROUTE", + } + + + --- Creates a new routing state machine. The process will route a CLIENT to a ZONE until the CLIENT is within that ZONE. + -- @param #ACT_ROUTE self + -- @return #ACT_ROUTE self + function ACT_ROUTE:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ROUTE" ) ) -- Core.Fsm#FSM_PROCESS + + self:AddTransition( "None", "Start", "Routing" ) + self:AddTransition( "*", "Report", "Reporting" ) + self:AddTransition( "*", "Route", "Routing" ) + self:AddTransition( "Routing", "Pause", "Pausing" ) + self:AddTransition( "*", "Abort", "Aborted" ) + self:AddTransition( "Routing", "Arrive", "Arrived" ) + self:AddTransition( "Arrived", "Success", "Success" ) + self:AddTransition( "*", "Fail", "Failed" ) + self:AddTransition( "", "", "" ) + self:AddTransition( "", "", "" ) + + self:AddEndState( "Arrived" ) + self:AddEndState( "Failed" ) + + self:SetStartState( "None" ) + + return self + end + + --- Task Events + + --- StateMachine callback function + -- @param #ACT_ROUTE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ROUTE:onafterStart( ProcessUnit, From, Event, To ) + + + self:__Route( 1 ) + end + + --- Check if the controllable has arrived. + -- @param #ACT_ROUTE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @return #boolean + function ACT_ROUTE:onfuncHasArrived( ProcessUnit ) + return false + end + + --- StateMachine callback function + -- @param #ACT_ROUTE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To ) + self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } ) + + if ProcessUnit:IsAlive() then + self:F( "BeforeRoute 2" ) + local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic + if self.DisplayCount >= self.DisplayInterval then + self:T( { HasArrived = HasArrived } ) + if not HasArrived then + self:Report() + end + self.DisplayCount = 1 + else + self.DisplayCount = self.DisplayCount + 1 + end + + self:T( { DisplayCount = self.DisplayCount } ) + + if HasArrived then + self:__Arrive( 1 ) + else + self:__Route( 1 ) + end + + return HasArrived -- if false, then the event will not be executed... + end + + return false + + end + +end -- ACT_ROUTE + + +do -- ACT_ROUTE_POINT + + --- ACT_ROUTE_POINT class + -- @type ACT_ROUTE_POINT + -- @field Tasking.Task#TASK TASK + -- @extends #ACT_ROUTE + ACT_ROUTE_POINT = { + ClassName = "ACT_ROUTE_POINT", + } + + + --- Creates a new routing state machine. + -- The task will route a controllable to a PointVec2 until the controllable is within the Range. + -- @param #ACT_ROUTE_POINT self + -- @param Core.Point#POINT_VEC2 The PointVec2 to Target. + -- @param #number Range The Distance to Target. + -- @param Core.Zone#ZONE_BASE Zone + function ACT_ROUTE_POINT:New( PointVec2, Range ) + local self = BASE:Inherit( self, ACT_ROUTE:New() ) -- #ACT_ROUTE_POINT + + self.PointVec2 = PointVec2 + self.Range = Range or 0 + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + + return self + end + + function ACT_ROUTE_POINT:Init( FsmRoute ) + + self.PointVec2 = FsmRoute.PointVec2 + self.Range = FsmRoute.Range or 0 + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + end + + --- Set PointVec2 + -- @param #ACT_ROUTE_POINT self + -- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to route to. + function ACT_ROUTE_POINT:SetPointVec2( PointVec2 ) + self:F2( { PointVec2 } ) + self.PointVec2 = PointVec2 + end + + --- Get PointVec2 + -- @param #ACT_ROUTE_POINT self + -- @return Core.Point#POINT_VEC2 PointVec2 The PointVec2 to route to. + function ACT_ROUTE_POINT:GetPointVec2() + self:F2( { self.PointVec2 } ) + return self.PointVec2 + end + + --- Set Range around PointVec2 + -- @param #ACT_ROUTE_POINT self + -- @param #number Range The Range to consider the arrival. Default is 10000 meters. + function ACT_ROUTE_POINT:SetRange( Range ) + self:F2( { self.Range } ) + self.Range = Range or 10000 + end + + --- Get Range around PointVec2 + -- @param #ACT_ROUTE_POINT self + -- @return #number The Range to consider the arrival. Default is 10000 meters. + function ACT_ROUTE_POINT:GetRange() + return self.Range + end + + --- Method override to check if the controllable has arrived. + -- @param #ACT_ROUTE_POINT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @return #boolean + function ACT_ROUTE_POINT:onfuncHasArrived( ProcessUnit ) + + if ProcessUnit:IsAlive() then + local Distance = self.PointVec2:Get2DDistance( ProcessUnit:GetPointVec2() ) + + if Distance <= self.Range then + local RouteText = "You have arrived." + self:Message( RouteText ) + return true + end + end + + return false + end + + --- Task Events + + --- StateMachine callback function + -- @param #ACT_ROUTE_POINT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ROUTE_POINT:onenterReporting( ProcessUnit, From, Event, To ) + + local TaskUnitPointVec2 = ProcessUnit:GetPointVec2() + local RouteText = "Route to " .. TaskUnitPointVec2:GetBRText( self.PointVec2 ) .. " km." + self:Message( RouteText ) + end + +end -- ACT_ROUTE_POINT + + +do -- ACT_ROUTE_ZONE + + --- ACT_ROUTE_ZONE class + -- @type ACT_ROUTE_ZONE + -- @field Tasking.Task#TASK TASK + -- @field Wrapper.Unit#UNIT ProcessUnit + -- @field Core.Zone#ZONE_BASE Zone + -- @extends #ACT_ROUTE + ACT_ROUTE_ZONE = { + ClassName = "ACT_ROUTE_ZONE", + } + + + --- Creates a new routing state machine. The task will route a controllable to a ZONE until the controllable is within that ZONE. + -- @param #ACT_ROUTE_ZONE self + -- @param Core.Zone#ZONE_BASE Zone + function ACT_ROUTE_ZONE:New( Zone ) + local self = BASE:Inherit( self, ACT_ROUTE:New() ) -- #ACT_ROUTE_ZONE + + self.Zone = Zone + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + + return self + end + + function ACT_ROUTE_ZONE:Init( FsmRoute ) + + self.Zone = FsmRoute.Zone + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + end + + --- Set Zone + -- @param #ACT_ROUTE_ZONE self + -- @param Core.Zone#ZONE_BASE Zone The Zone object where to route to. + function ACT_ROUTE_ZONE:SetZone( Zone ) + self.Zone = Zone + end + + --- Get Zone + -- @param #ACT_ROUTE_ZONE self + -- @return Core.Zone#ZONE_BASE Zone The Zone object where to route to. + function ACT_ROUTE_ZONE:GetZone() + return self.Zone + end + + --- Method override to check if the controllable has arrived. + -- @param #ACT_ROUTE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @return #boolean + function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit ) + + if ProcessUnit:IsInZone( self.Zone ) then + local RouteText = "You have arrived within the zone." + self:Message( RouteText ) + end + + return ProcessUnit:IsInZone( self.Zone ) + end + + --- Task Events + + --- StateMachine callback function + -- @param #ACT_ROUTE_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ROUTE_ZONE:onenterReporting( ProcessUnit, From, Event, To ) + + local ZoneVec2 = self.Zone:GetVec2() + local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y ) + local TaskUnitVec2 = ProcessUnit:GetVec2() + local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y ) + local RouteText = "Route to " .. TaskUnitPointVec2:GetBRText( ZonePointVec2 ) .. " km." + self:Message( RouteText ) + end + +end -- ACT_ROUTE_ZONE +--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Unit}s. +-- +-- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG) +-- +-- === +-- +-- @module Account + + +do -- ACT_ACCOUNT + + --- # @{#ACT_ACCOUNT} FSM class, extends @{Fsm#FSM_PROCESS} + -- + -- ## ACT_ACCOUNT state machine: + -- + -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. + -- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. + -- Each derived class follows exactly the same process, using the same events and following the same state transitions, + -- but will have **different implementation behaviour** upon each event or state transition. + -- + -- ### ACT_ACCOUNT States + -- + -- * **Asigned**: The player is assigned. + -- * **Waiting**: Waiting for an event. + -- * **Report**: Reporting. + -- * **Account**: Account for an event. + -- * **Accounted**: All events have been accounted for, end of the process. + -- * **Failed**: Failed the process. + -- + -- ### ACT_ACCOUNT Events + -- + -- * **Start**: Start the process. + -- * **Wait**: Wait for an event. + -- * **Report**: Report the status of the accounting. + -- * **Event**: An event happened, process the event. + -- * **More**: More targets. + -- * **NoMore (*)**: No more targets. + -- * **Fail (*)**: The action process has failed. + -- + -- (*) End states of the process. + -- + -- ### ACT_ACCOUNT state transition methods: + -- + -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. + -- There are 2 moments when state transition methods will be called by the state machine: + -- + -- * **Before** the state transition. + -- The state transition method needs to start with the name **OnBefore + the name of the state**. + -- If the state transition method returns false, then the processing of the state transition will not be done! + -- If you want to change the behaviour of the AIControllable at this event, return false, + -- but then you'll need to specify your own logic using the AIControllable! + -- + -- * **After** the state transition. + -- The state transition method needs to start with the name **OnAfter + the name of the state**. + -- These state transition methods need to provide a return value, which is specified at the function description. + -- + -- @type ACT_ACCOUNT + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Core.Fsm#FSM_PROCESS + ACT_ACCOUNT = { + ClassName = "ACT_ACCOUNT", + TargetSetUnit = nil, + } + + --- Creates a new DESTROY process. + -- @param #ACT_ACCOUNT self + -- @return #ACT_ACCOUNT + function ACT_ACCOUNT:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_PROCESS:New() ) -- Core.Fsm#FSM_PROCESS + + self:AddTransition( "Assigned", "Start", "Waiting") + self:AddTransition( "*", "Wait", "Waiting") + self:AddTransition( "*", "Report", "Report") + self:AddTransition( "*", "Event", "Account") + self:AddTransition( "Account", "More", "Wait") + self:AddTransition( "Account", "NoMore", "Accounted") + self:AddTransition( "*", "Fail", "Failed") + + self:AddEndState( "Accounted" ) + self:AddEndState( "Failed" ) + + self:SetStartState( "Assigned" ) + + return self + end + + --- Process Events + + --- StateMachine callback function + -- @param #ACT_ACCOUNT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT:onafterStart( ProcessUnit, From, Event, To ) + + self:HandleEvent( EVENTS.Dead, self.onfuncEventDead ) + + self:__Wait( 1 ) + end + + + --- StateMachine callback function + -- @param #ACT_ACCOUNT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT:onenterWaiting( ProcessUnit, From, Event, To ) + + if self.DisplayCount >= self.DisplayInterval then + self:Report() + self.DisplayCount = 1 + else + self.DisplayCount = self.DisplayCount + 1 + end + + return true -- Process always the event. + end + + --- StateMachine callback function + -- @param #ACT_ACCOUNT self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event ) + + self:__NoMore( 1 ) + end + +end -- ACT_ACCOUNT + +do -- ACT_ACCOUNT_DEADS + + --- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT} + -- + -- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units. + -- The process is given a @{Set} of units that will be tracked upon successful destruction. + -- The process will end after each target has been successfully destroyed. + -- Each successful dead will trigger an Account state transition that can be scored, modified or administered. + -- + -- + -- ## ACT_ACCOUNT_DEADS constructor: + -- + -- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object. + -- + -- @type ACT_ACCOUNT_DEADS + -- @field Set#SET_UNIT TargetSetUnit + -- @extends #ACT_ACCOUNT + ACT_ACCOUNT_DEADS = { + ClassName = "ACT_ACCOUNT_DEADS", + TargetSetUnit = nil, + } + + + --- Creates a new DESTROY process. + -- @param #ACT_ACCOUNT_DEADS self + -- @param Set#SET_UNIT TargetSetUnit + -- @param #string TaskName + function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName ) + -- Inherits from BASE + local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS + + self.TargetSetUnit = TargetSetUnit + self.TaskName = TaskName + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + self.DisplayCategory = "HQ" -- Targets is the default display category + + return self + end + + function ACT_ACCOUNT_DEADS:Init( FsmAccount ) + + self.TargetSetUnit = FsmAccount.TargetSetUnit + self.TaskName = FsmAccount.TaskName + end + + --- Process Events + + --- StateMachine callback function + -- @param #ACT_ACCOUNT_DEADS self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To ) + self:E( { ProcessUnit, From, Event, To } ) + + self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." ) + end + + + --- StateMachine callback function + -- @param #ACT_ACCOUNT_DEADS self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT_DEADS:onenterAccount( ProcessUnit, Task, From, Event, To, EventData ) + self:T( { ProcessUnit, EventData, From, Event, To } ) + + self:T({self.Controllable}) + + self.TargetSetUnit:Flush() + + self:T( { "Before sending Message", EventData.IniUnitName, self.TargetSetUnit:FindUnit( EventData.IniUnitName ) } ) + if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then + self:T( "Sending Message" ) + local TaskGroup = ProcessUnit:GetGroup() + self.TargetSetUnit:Remove( EventData.IniUnitName ) + self:Message( "You hit a target. Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." ) + end + self:T( { "After sending Message" } ) + end + + --- StateMachine callback function + -- @param #ACT_ACCOUNT_DEADS self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Task, From, Event, To ) + + if self.TargetSetUnit:Count() > 0 then + self:__More( 1 ) + else + self:__NoMore( 1 ) + end + end + + --- DCS Events + + --- @param #ACT_ACCOUNT_DEADS self + -- @param Event#EVENTDATA EventData + function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData ) + self:T( { "EventDead", EventData } ) + + if EventData.IniDCSUnit then + self:Event( EventData ) + end + end + +end -- ACT_ACCOUNT DEADS +--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. +-- +-- === +-- +-- # @{#ACT_ASSIST} FSM class, extends @{Fsm#FSM_PROCESS} +-- +-- ## ACT_ASSIST state machine: +-- +-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. +-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. +-- Each derived class follows exactly the same process, using the same events and following the same state transitions, +-- but will have **different implementation behaviour** upon each event or state transition. +-- +-- ### ACT_ASSIST **Events**: +-- +-- These are the events defined in this class: +-- +-- * **Start**: The process is started. +-- * **Next**: The process is smoking the targets in the given zone. +-- +-- ### ACT_ASSIST **Event methods**: +-- +-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. +-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: +-- +-- * **Immediate**: The event method has exactly the name of the event. +-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. +-- +-- ### ACT_ASSIST **States**: +-- +-- * **None**: The controllable did not receive route commands. +-- * **AwaitSmoke (*)**: The process is awaiting to smoke the targets in the zone. +-- * **Smoking (*)**: The process is smoking the targets in the zone. +-- * **Failed (*)**: The process has failed. +-- +-- (*) End states of the process. +-- +-- ### ACT_ASSIST state transition methods: +-- +-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. +-- There are 2 moments when state transition methods will be called by the state machine: +-- +-- * **Before** the state transition. +-- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- If the state transition method returns false, then the processing of the state transition will not be done! +-- If you want to change the behaviour of the AIControllable at this event, return false, +-- but then you'll need to specify your own logic using the AIControllable! +-- +-- * **After** the state transition. +-- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- These state transition methods need to provide a return value, which is specified at the function description. +-- +-- === +-- +-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST} +-- +-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}. +-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour. +-- At random intervals, a new target is smoked. +-- +-- # 1.1) ACT_ASSIST_SMOKE_TARGETS_ZONE constructor: +-- +-- * @{#ACT_ASSIST_SMOKE_TARGETS_ZONE.New}(): Creates a new ACT_ASSIST_SMOKE_TARGETS_ZONE object. +-- +-- === +-- +-- @module Smoke + +do -- ACT_ASSIST + + --- ACT_ASSIST class + -- @type ACT_ASSIST + -- @extends Core.Fsm#FSM_PROCESS + ACT_ASSIST = { + ClassName = "ACT_ASSIST", + } + + --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. + -- @param #ACT_ASSIST self + -- @return #ACT_ASSIST + function ACT_ASSIST:New() + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIST" ) ) -- Core.Fsm#FSM_PROCESS + + self:AddTransition( "None", "Start", "AwaitSmoke" ) + self:AddTransition( "AwaitSmoke", "Next", "Smoking" ) + self:AddTransition( "Smoking", "Next", "AwaitSmoke" ) + self:AddTransition( "*", "Stop", "Success" ) + self:AddTransition( "*", "Fail", "Failed" ) + + self:AddEndState( "Failed" ) + self:AddEndState( "Success" ) + + self:SetStartState( "None" ) + + return self + end + + --- Task Events + + --- StateMachine callback function + -- @param #ACT_ASSIST self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIST:onafterStart( ProcessUnit, From, Event, To ) + + local ProcessGroup = ProcessUnit:GetGroup() + local MissionMenu = self:GetMission():GetMenu( ProcessGroup ) + + local function MenuSmoke( MenuParam ) + self:E( MenuParam ) + local self = MenuParam.self + local SmokeColor = MenuParam.SmokeColor + self.SmokeColor = SmokeColor + self:__Next( 1 ) + end + + self.Menu = MENU_GROUP:New( ProcessGroup, "Target acquisition", MissionMenu ) + self.MenuSmokeBlue = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop blue smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Blue } ) + self.MenuSmokeGreen = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop green smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Green } ) + self.MenuSmokeOrange = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Orange smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Orange } ) + self.MenuSmokeRed = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Red smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Red } ) + self.MenuSmokeWhite = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop White smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.White } ) + end + + --- StateMachine callback function + -- @param #ACT_ASSIST self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIST:onafterStop( ProcessUnit, From, Event, To ) + + self.Menu:Remove() -- When stopped, remove the menus + end + +end + +do -- ACT_ASSIST_SMOKE_TARGETS_ZONE + + --- ACT_ASSIST_SMOKE_TARGETS_ZONE class + -- @type ACT_ASSIST_SMOKE_TARGETS_ZONE + -- @field Set#SET_UNIT TargetSetUnit + -- @field Core.Zone#ZONE_BASE TargetZone + -- @extends #ACT_ASSIST + ACT_ASSIST_SMOKE_TARGETS_ZONE = { + ClassName = "ACT_ASSIST_SMOKE_TARGETS_ZONE", + } + +-- function ACT_ASSIST_SMOKE_TARGETS_ZONE:_Destructor() +-- self:E("_Destructor") +-- +-- self.Menu:Remove() +-- self:EventRemoveAll() +-- end + + --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. + -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self + -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Zone#ZONE_BASE TargetZone + function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone ) + local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST + + self.TargetSetUnit = TargetSetUnit + self.TargetZone = TargetZone + + return self + end + + function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( FsmSmoke ) + + self.TargetSetUnit = FsmSmoke.TargetSetUnit + self.TargetZone = FsmSmoke.TargetZone + end + + --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. + -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self + -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Zone#ZONE_BASE TargetZone + -- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self + function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone ) + + self.TargetSetUnit = TargetSetUnit + self.TargetZone = TargetZone + + return self + end + + --- StateMachine callback function + -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit + -- @param #string Event + -- @param #string From + -- @param #string To + function ACT_ASSIST_SMOKE_TARGETS_ZONE:onenterSmoking( ProcessUnit, From, Event, To ) + + self.TargetSetUnit:ForEachUnit( + --- @param Wrapper.Unit#UNIT SmokeUnit + function( SmokeUnit ) + if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then + SCHEDULER:New( self, + function() + if SmokeUnit:IsAlive() then + SmokeUnit:Smoke( self.SmokeColor, 150 ) + end + end, {}, math.random( 10, 60 ) + ) + end + end + ) + + end + +end--- A COMMANDCENTER is the owner of multiple missions within MOOSE. +-- A COMMANDCENTER governs multiple missions, the tasking and the reporting. +-- @module CommandCenter + + + +--- The REPORT class +-- @type REPORT +-- @extends Core.Base#BASE +REPORT = { + ClassName = "REPORT", +} + +--- Create a new REPORT. +-- @param #REPORT self +-- @param #string Title +-- @return #REPORT +function REPORT:New( Title ) + + local self = BASE:Inherit( self, BASE:New() ) + + self.Report = {} + if Title then + self.Report[#self.Report+1] = Title + end + + return self +end + +--- Add a new line to a REPORT. +-- @param #REPORT self +-- @param #string Text +-- @return #REPORT +function REPORT:Add( Text ) + self.Report[#self.Report+1] = Text + return self.Report[#self.Report] +end + +--- Produces the text of the report, taking into account an optional delimeter, which is \n by default. +-- @param #REPORT self +-- @param #string Delimiter (optional) A delimiter text. +-- @return #string The report text. +function REPORT:Text( Delimiter ) + Delimiter = Delimiter or "\n" + local ReportText = table.concat( self.Report, Delimiter ) or "" + return ReportText +end + +--- The COMMANDCENTER class +-- @type COMMANDCENTER +-- @field Wrapper.Group#GROUP HQ +-- @field Dcs.DCSCoalitionWrapper.Object#coalition CommandCenterCoalition +-- @list Missions +-- @extends Core.Base#BASE +COMMANDCENTER = { + ClassName = "COMMANDCENTER", + CommandCenterName = "", + CommandCenterCoalition = nil, + CommandCenterPositionable = nil, + Name = "", +} +--- The constructor takes an IDENTIFIABLE as the HQ command center. +-- @param #COMMANDCENTER self +-- @param Wrapper.Positionable#POSITIONABLE CommandCenterPositionable +-- @param #string CommandCenterName +-- @return #COMMANDCENTER +function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) + + local self = BASE:Inherit( self, BASE:New() ) + + self.CommandCenterPositionable = CommandCenterPositionable + self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName() + self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition() + + self.Missions = {} + + self:HandleEvent( EVENTS.Birth, + --- @param #COMMANDCENTER self + -- @param Core.Event#EVENTDATA EventData + function( self, EventData ) + if EventData.IniObjectCategory == 1 then + local EventGroup = GROUP:Find( EventData.IniDCSGroup ) + if EventGroup and self:HasGroup( EventGroup ) then + local MenuReporting = MENU_GROUP:New( EventGroup, "Reporting", self.CommandCenterMenu ) + local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Summary Report", MenuReporting, self.ReportSummary, self, EventGroup ) + local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Details Report", MenuReporting, self.ReportDetails, self, EventGroup ) + self:ReportSummary( EventGroup ) + end + local PlayerUnit = EventData.IniUnit + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled! + Mission:JoinUnit( PlayerUnit, PlayerGroup ) + Mission:ReportDetails() + end + end + + end + ) + + -- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do. + -- For these elements, it will= + -- - Set the correct menu. + -- - Assign the PlayerUnit to the Task if required. + -- - Send a message to the other players in the group that this player has joined. + self:HandleEvent( EVENTS.PlayerEnterUnit, + --- @param #COMMANDCENTER self + -- @param Core.Event#EVENTDATA EventData + function( self, EventData ) + local PlayerUnit = EventData.IniUnit + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled! + Mission:JoinUnit( PlayerUnit, PlayerGroup ) + Mission:ReportDetails() + end + end + ) + + -- Handle when a player leaves a slot and goes back to spectators ... + -- The PlayerUnit will be UnAssigned from the Task. + -- When there is no Unit left running the Task, the Task goes into Abort... + self:HandleEvent( EVENTS.PlayerLeaveUnit, + --- @param #TASK self + -- @param Core.Event#EVENTDATA EventData + function( self, EventData ) + local PlayerUnit = EventData.IniUnit + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + Mission:AbortUnit( PlayerUnit ) + end + end + ) + + -- Handle when a player leaves a slot and goes back to spectators ... + -- The PlayerUnit will be UnAssigned from the Task. + -- When there is no Unit left running the Task, the Task goes into Abort... + self:HandleEvent( EVENTS.Crash, + --- @param #TASK self + -- @param Core.Event#EVENTDATA EventData + function( self, EventData ) + local PlayerUnit = EventData.IniUnit + for MissionID, Mission in pairs( self:GetMissions() ) do + Mission:CrashUnit( PlayerUnit ) + end + end + ) + + return self +end + +--- Gets the name of the HQ command center. +-- @param #COMMANDCENTER self +-- @return #string +function COMMANDCENTER:GetName() + + return self.CommandCenterName +end + +--- Gets the POSITIONABLE of the HQ command center. +-- @param #COMMANDCENTER self +-- @return Wrapper.Positionable#POSITIONABLE +function COMMANDCENTER:GetPositionable() + return self.CommandCenterPositionable +end + +--- Get the Missions governed by the HQ command center. +-- @param #COMMANDCENTER self +-- @return #list +function COMMANDCENTER:GetMissions() + + return self.Missions +end + +--- Add a MISSION to be governed by the HQ command center. +-- @param #COMMANDCENTER self +-- @param Tasking.Mission#MISSION Mission +-- @return Tasking.Mission#MISSION +function COMMANDCENTER:AddMission( Mission ) + + self.Missions[Mission] = Mission + + return Mission +end + +--- Removes a MISSION to be governed by the HQ command center. +-- The given Mission is not nilified. +-- @param #COMMANDCENTER self +-- @param Tasking.Mission#MISSION Mission +-- @return Tasking.Mission#MISSION +function COMMANDCENTER:RemoveMission( Mission ) + + self.Missions[Mission] = nil + + return Mission +end + +--- Sets the menu structure of the Missions governed by the HQ command center. +-- @param #COMMANDCENTER self +function COMMANDCENTER:SetMenu() + self:F() + + self.CommandCenterMenu = self.CommandCenterMenu or MENU_COALITION:New( self.CommandCenterCoalition, "Command Center (" .. self:GetName() .. ")" ) + + local MenuTime = timer.getTime() + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + Mission:SetMenu( MenuTime ) + end + + for MissionID, Mission in pairs( self:GetMissions() ) do + local Mission = Mission -- Tasking.Mission#MISSION + Mission:RemoveMenu( MenuTime ) + end + +end + +--- Gets the commandcenter menu structure governed by the HQ command center. +-- @param #COMMANDCENTER self +-- @return Core.Menu#MENU_COALITION +function COMMANDCENTER:GetMenu() + self:F() + return self.CommandCenterMenu +end + +--- Checks of the COMMANDCENTER has a GROUP. +-- @param #COMMANDCENTER self +-- @param Wrapper.Group#GROUP +-- @return #boolean +function COMMANDCENTER:HasGroup( MissionGroup ) + + local Has = false + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + if Mission:HasGroup( MissionGroup ) then + Has = true + break + end + end + + return Has +end + +--- Send a CC message to the coalition of the CC. +-- @param #COMMANDCENTER self +function COMMANDCENTER:MessageToAll( Message ) + + self:GetPositionable():MessageToAll( Message, 20, self:GetName() ) + +end + +--- Send a CC message to a GROUP. +-- @param #COMMANDCENTER self +-- @param #string Message +-- @param Wrapper.Group#GROUP TaskGroup +-- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. +function COMMANDCENTER:MessageToGroup( Message, TaskGroup, Name ) + + local Prefix = "@ Group" + Prefix = Prefix .. ( Name and " (" .. Name .. "): " or '' ) + Message = Prefix .. Message + self:GetPositionable():MessageToGroup( Message , 20, TaskGroup, self:GetName() ) + +end + +--- Send a CC message to the coalition of the CC. +-- @param #COMMANDCENTER self +function COMMANDCENTER:MessageToCoalition( Message ) + + local CCCoalition = self:GetPositionable():GetCoalition() + --TODO: Fix coalition bug! + self:GetPositionable():MessageToCoalition( Message, 20, CCCoalition, self:GetName() ) + +end + + +--- Report the status of all MISSIONs to a GROUP. +-- Each Mission is listed, with an indication how many Tasks are still to be completed. +-- @param #COMMANDCENTER self +function COMMANDCENTER:ReportSummary( ReportGroup ) + self:E( ReportGroup ) + + local Report = REPORT:New() + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + Report:Add( " - " .. Mission:ReportOverview() ) + end + + self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) + +end + +--- Report the status of a Task to a Group. +-- Report the details of a Mission, listing the Mission, and all the Task details. +-- @param #COMMANDCENTER self +function COMMANDCENTER:ReportDetails( ReportGroup, Task ) + self:E( ReportGroup ) + + local Report = REPORT:New() + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + Report:Add( " - " .. Mission:ReportDetails() ) + end + + self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) +end + +--- A MISSION is the main owner of a Mission orchestration within MOOSE . The Mission framework orchestrates @{CLIENT}s, @{TASK}s, @{STAGE}s etc. +-- A @{CLIENT} needs to be registered within the @{MISSION} through the function @{AddClient}. A @{TASK} needs to be registered within the @{MISSION} through the function @{AddTask}. +-- @module Mission + +--- The MISSION class +-- @type MISSION +-- @field #MISSION.Clients _Clients +-- @field Core.Menu#MENU_COALITION MissionMenu +-- @field #string MissionBriefing +-- @extends Core.Fsm#FSM +MISSION = { + ClassName = "MISSION", + Name = "", + MissionStatus = "PENDING", +} + +--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. +-- @param #MISSION self +-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter +-- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. +-- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. +-- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. +-- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... +-- @return #MISSION self +function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) + + local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM + + self:SetStartState( "Idle" ) + + self:AddTransition( "Idle", "Start", "Ongoing" ) + + --- OnLeave Transition Handler for State Idle. + -- @function [parent=#MISSION] OnLeaveIdle + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Idle. + -- @function [parent=#MISSION] OnEnterIdle + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnLeave Transition Handler for State Ongoing. + -- @function [parent=#MISSION] OnLeaveOngoing + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Ongoing. + -- @function [parent=#MISSION] OnEnterOngoing + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnBefore Transition Handler for Event Start. + -- @function [parent=#MISSION] OnBeforeStart + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Start. + -- @function [parent=#MISSION] OnAfterStart + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Start. + -- @function [parent=#MISSION] Start + -- @param #MISSION self + + --- Asynchronous Event Trigger for Event Start. + -- @function [parent=#MISSION] __Start + -- @param #MISSION self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Ongoing", "Stop", "Idle" ) + + --- OnLeave Transition Handler for State Idle. + -- @function [parent=#MISSION] OnLeaveIdle + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Idle. + -- @function [parent=#MISSION] OnEnterIdle + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnBefore Transition Handler for Event Stop. + -- @function [parent=#MISSION] OnBeforeStop + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Stop. + -- @function [parent=#MISSION] OnAfterStop + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Stop. + -- @function [parent=#MISSION] Stop + -- @param #MISSION self + + --- Asynchronous Event Trigger for Event Stop. + -- @function [parent=#MISSION] __Stop + -- @param #MISSION self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Ongoing", "Complete", "Completed" ) + + --- OnLeave Transition Handler for State Completed. + -- @function [parent=#MISSION] OnLeaveCompleted + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Completed. + -- @function [parent=#MISSION] OnEnterCompleted + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnBefore Transition Handler for Event Complete. + -- @function [parent=#MISSION] OnBeforeComplete + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Complete. + -- @function [parent=#MISSION] OnAfterComplete + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Complete. + -- @function [parent=#MISSION] Complete + -- @param #MISSION self + + --- Asynchronous Event Trigger for Event Complete. + -- @function [parent=#MISSION] __Complete + -- @param #MISSION self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Fail", "Failed" ) + + --- OnLeave Transition Handler for State Failed. + -- @function [parent=#MISSION] OnLeaveFailed + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnEnter Transition Handler for State Failed. + -- @function [parent=#MISSION] OnEnterFailed + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- OnBefore Transition Handler for Event Fail. + -- @function [parent=#MISSION] OnBeforeFail + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Fail. + -- @function [parent=#MISSION] OnAfterFail + -- @param #MISSION self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Fail. + -- @function [parent=#MISSION] Fail + -- @param #MISSION self + + --- Asynchronous Event Trigger for Event Fail. + -- @function [parent=#MISSION] __Fail + -- @param #MISSION self + -- @param #number Delay The delay in seconds. + + self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } ) + + self.CommandCenter = CommandCenter + CommandCenter:AddMission( self ) + + self.Name = MissionName + self.MissionPriority = MissionPriority + self.MissionBriefing = MissionBriefing + self.MissionCoalition = MissionCoalition + + self.Tasks = {} + + -- Private implementations + + + + return self +end + +-- FSM function for a MISSION +-- @param #MISSION self +-- @param #string From +-- @param #string Event +-- @param #string To +function MISSION:onbeforeComplete( From, Event, To ) + + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if not Task:IsStateSuccess() and not Task:IsStateFailed() and not Task:IsStateAborted() and not Task:IsStateCancelled() then + return false -- Mission cannot be completed. Other Tasks are still active. + end + end + return true -- Allow Mission completion. +end + +-- FSM function for a MISSION +-- @param #MISSION self +-- @param #string From +-- @param #string Event +-- @param #string To +function MISSION:onenterCompleted( From, Event, To ) + + self:GetCommandCenter():MessageToCoalition( "Mission " .. self:GetName() .. " has been completed! Good job guys!" ) +end + +--- Gets the mission name. +-- @param #MISSION self +-- @return #MISSION self +function MISSION:GetName() + return self.Name +end + +--- Add a Unit to join the Mission. +-- For each Task within the Mission, the Unit is joined with the Task. +-- If the Unit was not part of a Task in the Mission, false is returned. +-- If the Unit is part of a Task in the Mission, true is returned. +-- @param #MISSION self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. +-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission. +-- @return #boolean true if Unit is part of a Task in the Mission. +function MISSION:JoinUnit( PlayerUnit, PlayerGroup ) + self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } ) + + local PlayerUnitAdded = false + + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if Task:JoinUnit( PlayerUnit, PlayerGroup ) then + PlayerUnitAdded = true + end + end + + return PlayerUnitAdded +end + +--- Aborts a PlayerUnit from the Mission. +-- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. +-- If the Unit was not part of a Task in the Mission, false is returned. +-- If the Unit is part of a Task in the Mission, true is returned. +-- @param #MISSION self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. +-- @return #boolean true if Unit is part of a Task in the Mission. +function MISSION:AbortUnit( PlayerUnit ) + self:F( { PlayerUnit = PlayerUnit } ) + + local PlayerUnitRemoved = false + + for TaskID, Task in pairs( self:GetTasks() ) do + if Task:AbortUnit( PlayerUnit ) then + PlayerUnitRemoved = true + end + end + + return PlayerUnitRemoved +end + +--- Handles a crash of a PlayerUnit from the Mission. +-- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. +-- If the Unit was not part of a Task in the Mission, false is returned. +-- If the Unit is part of a Task in the Mission, true is returned. +-- @param #MISSION self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player crashing. +-- @return #boolean true if Unit is part of a Task in the Mission. +function MISSION:CrashUnit( PlayerUnit ) + self:F( { PlayerUnit = PlayerUnit } ) + + local PlayerUnitRemoved = false + + for TaskID, Task in pairs( self:GetTasks() ) do + if Task:CrashUnit( PlayerUnit ) then + PlayerUnitRemoved = true + end + end + + return PlayerUnitRemoved +end + +--- Add a scoring to the mission. +-- @param #MISSION self +-- @return #MISSION self +function MISSION:AddScoring( Scoring ) + self.Scoring = Scoring + return self +end + +--- Get the scoring object of a mission. +-- @param #MISSION self +-- @return #SCORING Scoring +function MISSION:GetScoring() + return self.Scoring +end + +--- Get the groups for which TASKS are given in the mission +-- @param #MISSION self +-- @return Core.Set#SET_GROUP +function MISSION:GetGroups() + + local SetGroup = SET_GROUP:New() + + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + local GroupSet = Task:GetGroups() + GroupSet:ForEachGroup( + function( TaskGroup ) + SetGroup:Add( TaskGroup, TaskGroup ) + end + ) + end + + return SetGroup + +end + + +--- Sets the Planned Task menu. +-- @param #MISSION self +-- @param #number MenuTime +function MISSION:SetMenu( MenuTime ) + self:F() + + for _, TaskData in pairs( self:GetTasks() ) do + local Task = TaskData -- Tasking.Task#TASK + Task:SetMenu( MenuTime ) + end +end + +--- Removes the Planned Task menu. +-- @param #MISSION self +-- @param #number MenuTime +function MISSION:RemoveMenu( MenuTime ) + self:F() + + for _, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + Task:RemoveMenu( MenuTime ) + end +end + + +--- Gets the COMMANDCENTER. +-- @param #MISSION self +-- @return Tasking.CommandCenter#COMMANDCENTER +function MISSION:GetCommandCenter() + return self.CommandCenter +end + + +--- Removes a Task menu. +-- @param #MISSION self +-- @param Tasking.Task#TASK Task +-- @return #MISSION self +function MISSION:RemoveTaskMenu( Task ) + + Task:RemoveMenu() +end + + +--- Gets the mission menu for the coalition. +-- @param #MISSION self +-- @param Wrapper.Group#GROUP TaskGroup +-- @return Core.Menu#MENU_COALITION self +function MISSION:GetMenu( TaskGroup ) + + local CommandCenter = self:GetCommandCenter() + local CommandCenterMenu = CommandCenter:GetMenu() + + local MissionName = self:GetName() + local MissionMenu = CommandCenterMenu:GetMenu( MissionName ) + + return MissionMenu +end + + +--- Get the TASK identified by the TaskNumber from the Mission. This function is useful in GoalFunctions. +-- @param #string TaskName The Name of the @{Task} within the @{Mission}. +-- @return Tasking.Task#TASK The Task +-- @return #nil Returns nil if no task was found. +function MISSION:GetTask( TaskName ) + self:F( { TaskName } ) + + return self.Tasks[TaskName] +end + + +--- Register a @{Task} to be completed within the @{Mission}. +-- Note that there can be multiple @{Task}s registered to be completed. +-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. +-- @param #MISSION self +-- @param Tasking.Task#TASK Task is the @{Task} object. +-- @return Tasking.Task#TASK The task added. +function MISSION:AddTask( Task ) + + local TaskName = Task:GetTaskName() + self:F( TaskName ) + + self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } + + self.Tasks[TaskName] = Task + + self:GetCommandCenter():SetMenu() + + return Task +end + +--- Removes a @{Task} to be completed within the @{Mission}. +-- Note that there can be multiple @{Task}s registered to be completed. +-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. +-- @param #MISSION self +-- @param Tasking.Task#TASK Task is the @{Task} object. +-- @return #nil The cleaned Task reference. +function MISSION:RemoveTask( Task ) + + local TaskName = Task:GetTaskName() + + self:F( TaskName ) + self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } + + -- Ensure everything gets garbarge collected. + self.Tasks[TaskName] = nil + Task = nil + + collectgarbage() + + self:GetCommandCenter():SetMenu() + + return nil +end + +--- Return the next @{Task} ID to be completed within the @{Mission}. +-- @param #MISSION self +-- @param Tasking.Task#TASK Task is the @{Task} object. +-- @return Tasking.Task#TASK The task added. +function MISSION:GetNextTaskID( Task ) + + local TaskName = Task:GetTaskName() + self:F( TaskName ) + self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } + + self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1 + + return self.Tasks[TaskName].n +end + +--- Is the @{Mission} **Completed**. +-- @param #MISSION self +-- @return #boolean +function MISSION:IsCompleted() + return self:Is( "Completed" ) +end + +--- Is the @{Mission} **Idle**. +-- @param #MISSION self +-- @return #boolean +function MISSION:IsIdle() + return self:Is( "Idle" ) +end + +--- Is the @{Mission} **Ongoing**. +-- @param #MISSION self +-- @return #boolean +function MISSION:IsOngoing() + return self:Is( "Ongoing" ) +end + +--- Is the @{Mission} **Failed**. +-- @param #MISSION self +-- @return #boolean +function MISSION:IsFailed() + return self:Is( "Failed" ) +end + +--- Is the @{Mission} **Hold**. +-- @param #MISSION self +-- @return #boolean +function MISSION:IsHold() + return self:Is( "Hold" ) +end + +--- Validates if the Mission has a Group +-- @param #MISSION +-- @return #boolean true if the Mission has a Group. +function MISSION:HasGroup( TaskGroup ) + local Has = false + + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if Task:HasGroup( TaskGroup ) then + Has = true + break + end + end + + return Has +end + +--- Create a summary report of the Mission (one line). +-- @param #MISSION self +-- @return #string +function MISSION:ReportSummary() + + local Report = REPORT:New() + + -- List the name of the mission. + local Name = self:GetName() + + -- Determine the status of the mission. + local Status = self:GetState() + + -- Determine how many tasks are remaining. + local TasksRemaining = 0 + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if Task:IsStateSuccess() or Task:IsStateFailed() then + else + TasksRemaining = TasksRemaining + 1 + end + end + + Report:Add( "Mission " .. Name .. " - " .. Status .. " - " .. TasksRemaining .. " tasks remaining." ) + + return Report:Text() +end + +--- Create a overview report of the Mission (multiple lines). +-- @param #MISSION self +-- @return #string +function MISSION:ReportOverview() + + local Report = REPORT:New() + + -- List the name of the mission. + local Name = self:GetName() + + -- Determine the status of the mission. + local Status = self:GetState() + + Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) + + -- Determine how many tasks are remaining. + local TasksRemaining = 0 + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + Report:Add( "- " .. Task:ReportSummary() ) + end + + return Report:Text() +end + +--- Create a detailed report of the Mission, listing all the details of the Task. +-- @param #MISSION self +-- @return #string +function MISSION:ReportDetails() + + local Report = REPORT:New() + + -- List the name of the mission. + local Name = self:GetName() + + -- Determine the status of the mission. + local Status = self:GetState() + + Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) + + -- Determine how many tasks are remaining. + local TasksRemaining = 0 + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + Report:Add( Task:ReportDetails() ) + end + + return Report:Text() +end + +--- Get all the TASKs from the Mission. This function is useful in GoalFunctions. +-- @return {TASK,...} Structure of TASKS with the @{TASK} number as the key. +-- @usage +-- -- Get Tasks from the Mission. +-- Tasks = Mission:GetTasks() +-- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) +function MISSION:GetTasks() + self:F() + + return self.Tasks +end + + +--- **Tasking** -- This module contains the TASK class. +-- +-- === +-- +-- +-- === +-- +-- ### Authors: FlightControl - Design and Programming +-- +-- @module Task + +--- @type TASK +-- @field Core.Scheduler#SCHEDULER TaskScheduler +-- @field Tasking.Mission#MISSION Mission +-- @field Core.Set#SET_GROUP SetGroup The Set of Groups assigned to the Task +-- @field Core.Fsm#FSM_PROCESS FsmTemplate +-- @field Tasking.Mission#MISSION Mission +-- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter +-- @extends Core.Fsm#FSM_TASK + +--- +-- # TASK class, extends @{Base#BASE} +-- +-- ## The TASK class implements the methods for task orchestration within MOOSE. +-- +-- The class provides a couple of methods to: +-- +-- * @{#TASK.AssignToGroup}():Assign a task to a group (of players). +-- * @{#TASK.AddProcess}():Add a @{Process} to a task. +-- * @{#TASK.RemoveProcesses}():Remove a running @{Process} from a running task. +-- * @{#TASK.SetStateMachine}():Set a @{Fsm} to a task. +-- * @{#TASK.RemoveStateMachine}():Remove @{Fsm} from a task. +-- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Fsm} +-- * @{#TASK.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK}. +-- * @{#TASK.UnAssignFromUnit}(): Unassign the task from a unit. +-- * @{#TASK.SetTimeOut}(): Set timer in seconds before task gets cancelled if not assigned. +-- +-- ## 1.2) Set and enquire task status (beyond the task state machine processing). +-- +-- A task needs to implement as a minimum the following task states: +-- +-- * **Success**: Expresses the successful execution and finalization of the task. +-- * **Failed**: Expresses the failure of a task. +-- * **Planned**: Expresses that the task is created, but not yet in execution and is not assigned yet. +-- * **Assigned**: Expresses that the task is assigned to a Group of players, and that the task is in execution mode. +-- +-- A task may also implement the following task states: +-- +-- * **Rejected**: Expresses that the task is rejected by a player, who was requested to accept the task. +-- * **Cancelled**: Expresses that the task is cancelled by HQ or through a logical situation where a cancellation of the task is required. +-- +-- A task can implement more statusses than the ones outlined above. Please consult the documentation of the specific tasks to understand the different status modelled. +-- +-- The status of tasks can be set by the methods **State** followed by the task status. An example is `StateAssigned()`. +-- The status of tasks can be enquired by the methods **IsState** followed by the task status name. An example is `if IsStateAssigned() then`. +-- +-- ## 1.3) Add scoring when reaching a certain task status: +-- +-- Upon reaching a certain task status in a task, additional scoring can be given. If the Mission has a scoring system attached, the scores will be added to the mission scoring. +-- Use the method @{#TASK.AddScore}() to add scores when a status is reached. +-- +-- ## 1.4) Task briefing: +-- +-- A task briefing can be given that is shown to the player when he is assigned to the task. +-- +-- @field #TASK TASK +-- +TASK = { + ClassName = "TASK", + TaskScheduler = nil, + ProcessClasses = {}, -- The container of the Process classes that will be used to create and assign new processes for the task to ProcessUnits. + Processes = {}, -- The container of actual process objects instantiated and assigned to ProcessUnits. + Players = nil, + Scores = {}, + Menu = {}, + SetGroup = nil, + FsmTemplate = nil, + Mission = nil, + CommandCenter = nil, + TimeOut = 0, +} + +--- FSM PlayerAborted event handler prototype for TASK. +-- @function [parent=#TASK] OnAfterPlayerAborted +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he went back to spectators or left the mission. +-- @param #string PlayerName The name of the Player. + +--- FSM PlayerCrashed event handler prototype for TASK. +-- @function [parent=#TASK] OnAfterPlayerCrashed +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he crashed in the mission. +-- @param #string PlayerName The name of the Player. + +--- FSM PlayerDead event handler prototype for TASK. +-- @function [parent=#TASK] OnAfterPlayerDead +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he died in the mission. +-- @param #string PlayerName The name of the Player. + +--- FSM Fail synchronous event function for TASK. +-- Use this event to Fail the Task. +-- @function [parent=#TASK] Fail +-- @param #TASK self + +--- FSM Fail asynchronous event function for TASK. +-- Use this event to Fail the Task. +-- @function [parent=#TASK] __Fail +-- @param #TASK self + +--- FSM Abort synchronous event function for TASK. +-- Use this event to Abort the Task. +-- @function [parent=#TASK] Abort +-- @param #TASK self + +--- FSM Abort asynchronous event function for TASK. +-- Use this event to Abort the Task. +-- @function [parent=#TASK] __Abort +-- @param #TASK self + +--- FSM Success synchronous event function for TASK. +-- Use this event to make the Task a Success. +-- @function [parent=#TASK] Success +-- @param #TASK self + +--- FSM Success asynchronous event function for TASK. +-- Use this event to make the Task a Success. +-- @function [parent=#TASK] __Success +-- @param #TASK self + +--- FSM Cancel synchronous event function for TASK. +-- Use this event to Cancel the Task. +-- @function [parent=#TASK] Cancel +-- @param #TASK self + +--- FSM Cancel asynchronous event function for TASK. +-- Use this event to Cancel the Task. +-- @function [parent=#TASK] __Cancel +-- @param #TASK self + +--- FSM Replan synchronous event function for TASK. +-- Use this event to Replan the Task. +-- @function [parent=#TASK] Replan +-- @param #TASK self + +--- FSM Replan asynchronous event function for TASK. +-- Use this event to Replan the Task. +-- @function [parent=#TASK] __Replan +-- @param #TASK self + + +--- Instantiates a new TASK. Should never be used. Interface Class. +-- @param #TASK self +-- @param Tasking.Mission#MISSION Mission The mission wherein the Task is registered. +-- @param Core.Set#SET_GROUP SetGroupAssign The set of groups for which the Task can be assigned. +-- @param #string TaskName The name of the Task +-- @param #string TaskType The type of the Task +-- @return #TASK self +function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) + + local self = BASE:Inherit( self, FSM_TASK:New() ) -- Core.Fsm#FSM_TASK + + self:SetStartState( "Planned" ) + self:AddTransition( "Planned", "Assign", "Assigned" ) + self:AddTransition( "Assigned", "AssignUnit", "Assigned" ) + self:AddTransition( "Assigned", "Success", "Success" ) + self:AddTransition( "Assigned", "Fail", "Failed" ) + self:AddTransition( "Assigned", "Abort", "Aborted" ) + self:AddTransition( "Assigned", "Cancel", "Cancelled" ) + self:AddTransition( "*", "PlayerCrashed", "*" ) + self:AddTransition( "*", "PlayerAborted", "*" ) + self:AddTransition( "*", "PlayerDead", "*" ) + self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" ) + self:AddTransition( "*", "TimeOut", "Cancelled" ) + + self:E( "New TASK " .. TaskName ) + + self.Processes = {} + self.Fsm = {} + + self.Mission = Mission + self.CommandCenter = Mission:GetCommandCenter() + + self.SetGroup = SetGroupAssign + + self:SetType( TaskType ) + self:SetName( TaskName ) + self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences .. + + self.TaskBriefing = "You are invited for the task: " .. self.TaskName .. "." + + self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() + + + return self +end + +--- Get the Task FSM Process Template +-- @param #TASK self +-- @return Core.Fsm#FSM_PROCESS +function TASK:GetUnitProcess( TaskUnit ) + + if TaskUnit then + return self:GetStateMachine( TaskUnit ) + else + return self.FsmTemplate + end +end + +--- Sets the Task FSM Process Template +-- @param #TASK self +-- @param Core.Fsm#FSM_PROCESS +function TASK:SetUnitProcess( FsmTemplate ) + + self.FsmTemplate = FsmTemplate +end + +--- Add a PlayerUnit to join the Task. +-- For each Group within the Task, the Unit is check if it can join the Task. +-- If the Unit was not part of the Task, false is returned. +-- If the Unit is part of the Task, true is returned. +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. +-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission. +-- @return #boolean true if Unit is part of the Task. +function TASK:JoinUnit( PlayerUnit, PlayerGroup ) + self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } ) + + local PlayerUnitAdded = false + + local PlayerGroups = self:GetGroups() + + -- Is the PlayerGroup part of the PlayerGroups? + if PlayerGroups:IsIncludeObject( PlayerGroup ) then + + -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task. + -- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader. + if self:IsStatePlanned() or self:IsStateReplanned() then + self:SetMenuForGroup( PlayerGroup ) + --self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() ) + end + if self:IsStateAssigned() then + local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) + self:E( { IsAssignedToGroup = IsAssignedToGroup } ) + if IsAssignedToGroup then + self:AssignToUnit( PlayerUnit ) + self:MessageToGroups( PlayerUnit:GetPlayerName() .. " joined Task " .. self:GetName() ) + end + end + end + + return PlayerUnitAdded +end + +--- Abort a PlayerUnit from a Task. +-- If the Unit was not part of the Task, false is returned. +-- If the Unit is part of the Task, true is returned. +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. +-- @return #boolean true if Unit is part of the Task. +function TASK:AbortUnit( PlayerUnit ) + self:F( { PlayerUnit = PlayerUnit } ) + + local PlayerUnitAborted = false + + local PlayerGroups = self:GetGroups() + local PlayerGroup = PlayerUnit:GetGroup() + + -- Is the PlayerGroup part of the PlayerGroups? + if PlayerGroups:IsIncludeObject( PlayerGroup ) then + + -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. + -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. + if self:IsStateAssigned() then + local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) + self:E( { IsAssignedToGroup = IsAssignedToGroup } ) + if IsAssignedToGroup then + self:UnAssignFromUnit( PlayerUnit ) + self:MessageToGroups( PlayerUnit:GetPlayerName() .. " aborted Task " .. self:GetName() ) + self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) + if #PlayerGroup:GetUnits() == 1 then + self:UnAssignFromGroup( PlayerGroup ) + PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) + self:RemoveMenuForGroup( PlayerGroup ) + end + self:Abort() + end + end + end + + return PlayerUnitAborted +end + +--- A PlayerUnit crashed in a Task. Abort the Player. +-- If the Unit was not part of the Task, false is returned. +-- If the Unit is part of the Task, true is returned. +-- @param #TASK self +-- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. +-- @return #boolean true if Unit is part of the Task. +function TASK:CrashUnit( PlayerUnit ) + self:F( { PlayerUnit = PlayerUnit } ) + + local PlayerUnitCrashed = false + + local PlayerGroups = self:GetGroups() + local PlayerGroup = PlayerUnit:GetGroup() + + -- Is the PlayerGroup part of the PlayerGroups? + if PlayerGroups:IsIncludeObject( PlayerGroup ) then + + -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. + -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. + if self:IsStateAssigned() then + local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) + self:E( { IsAssignedToGroup = IsAssignedToGroup } ) + if IsAssignedToGroup then + self:UnAssignFromUnit( PlayerUnit ) + self:MessageToGroups( PlayerUnit:GetPlayerName() .. " crashed in Task " .. self:GetName() ) + self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) + if #PlayerGroup:GetUnits() == 1 then + PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) + self:RemoveMenuForGroup( PlayerGroup ) + end + self:PlayerCrashed( PlayerUnit ) + end + end + end + + return PlayerUnitCrashed +end + + + +--- Gets the Mission to where the TASK belongs. +-- @param #TASK self +-- @return Tasking.Mission#MISSION +function TASK:GetMission() + + return self.Mission +end + + +--- Gets the SET_GROUP assigned to the TASK. +-- @param #TASK self +-- @return Core.Set#SET_GROUP +function TASK:GetGroups() + return self.SetGroup +end + + + +--- Assign the @{Task} to a @{Group}. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @return #TASK +function TASK:AssignToGroup( TaskGroup ) + self:F2( TaskGroup:GetName() ) + + local TaskGroupName = TaskGroup:GetName() + + TaskGroup:SetState( TaskGroup, "Assigned", self ) + + local Mission = self:GetMission() + local MissionMenu = Mission:GetMenu( TaskGroup ) + MissionMenu:RemoveSubMenus() + + --self:RemoveMenuForGroup( TaskGroup ) + self:SetAssignedMenuForGroup( TaskGroup ) + + local TaskUnits = TaskGroup:GetUnits() + for UnitID, UnitData in pairs( TaskUnits ) do + local TaskUnit = UnitData -- Wrapper.Unit#UNIT + local PlayerName = TaskUnit:GetPlayerName() + self:E(PlayerName) + if PlayerName ~= nil or PlayerName ~= "" then + self:AssignToUnit( TaskUnit ) + end + end + + return self +end + +--- +-- @param #TASK self +-- @param Wrapper.Group#GROUP FindGroup +-- @return #boolean +function TASK:HasGroup( FindGroup ) + + return self:GetGroups():IsIncludeObject( FindGroup ) + +end + +--- Assign the @{Task} to an alive @{Unit}. +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @return #TASK self +function TASK:AssignToUnit( TaskUnit ) + self:F( TaskUnit:GetName() ) + + local FsmTemplate = self:GetUnitProcess() + + -- Assign a new FsmUnit to TaskUnit. + local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Core.Fsm#FSM_PROCESS + self:E({"Address FsmUnit", tostring( FsmUnit ) } ) + + FsmUnit:SetStartState( "Planned" ) + + FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow. + + return self +end + +--- UnAssign the @{Task} from an alive @{Unit}. +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @return #TASK self +function TASK:UnAssignFromUnit( TaskUnit ) + self:F( TaskUnit:GetName() ) + + self:RemoveStateMachine( TaskUnit ) + + return self +end + +--- Sets the TimeOut for the @{Task}. If @{Task} stayed planned for longer than TimeOut, it gets into Cancelled status. +-- @param #TASK self +-- @param #integer Timer in seconds +-- @return #TASK self +function TASK:SetTimeOut ( Timer ) + self:F( Timer ) + self.TimeOut = Timer + self:__TimeOut( self.TimeOut ) + return self +end + +--- Send a message of the @{Task} to the assigned @{Group}s. +-- @param #TASK self +function TASK:MessageToGroups( Message ) + self:F( { Message = Message } ) + + local Mission = self:GetMission() + local CC = Mission:GetCommandCenter() + + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + local TaskGroup = TaskGroup -- Wrapper.Group#GROUP + CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() ) + end +end + + +--- Send the briefng message of the @{Task} to the assigned @{Group}s. +-- @param #TASK self +function TASK:SendBriefingToAssignedGroups() + self:F2() + + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + + if self:IsAssignedToGroup( TaskGroup ) then + TaskGroup:Message( self.TaskBriefing, 60 ) + end + end +end + + +--- UnAssign the @{Task} from the @{Group}s. +-- @param #TASK self +function TASK:UnAssignFromGroups() + self:F2() + + for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do + self:UnAssignFromGroup( TaskGroup ) + end +end + +--- UnAssign the @{Task} from a @{Group}. +-- @param #TASK self +function TASK:UnAssignFromGroup( TaskGroup ) + self:F2( { TaskGroup } ) + + TaskGroup:SetState( TaskGroup, "Assigned", nil ) + + self:RemoveAssignedMenuForGroup( TaskGroup ) + + local TaskUnits = TaskGroup:GetUnits() + for UnitID, UnitData in pairs( TaskUnits ) do + local TaskUnit = UnitData -- Wrapper.Unit#UNIT + local PlayerName = TaskUnit:GetPlayerName() + if PlayerName ~= nil or PlayerName ~= "" then + self:UnAssignFromUnit( TaskUnit ) + end + end +end + + + +--- Returns if the @{Task} is assigned to the Group. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @return #boolean +function TASK:IsAssignedToGroup( TaskGroup ) + + local TaskGroupName = TaskGroup:GetName() + + if self:IsStateAssigned() then + if TaskGroup:GetState( TaskGroup, "Assigned" ) == self then + self:T( { "Task is assigned to:", TaskGroup:GetName() } ) + return true + end + end + + self:T( { "Task is not assigned to:", TaskGroup:GetName() } ) + return false +end + +--- Returns if the @{Task} has still alive and assigned Units. +-- @param #TASK self +-- @return #boolean +function TASK:HasAliveUnits() + self:F() + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if self:IsStateAssigned() then + if self:IsAssignedToGroup( TaskGroup ) then + for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do + if TaskUnit:IsAlive() then + self:T( { HasAliveUnits = true } ) + return true + end + end + end + end + end + + self:T( { HasAliveUnits = false } ) + return false +end + +--- Set the menu options of the @{Task} to all the groups in the SetGroup. +-- @param #TASK self +-- @param #number MenuTime +-- @return #TASK +function TASK:SetMenu( MenuTime ) + self:F() + + self.SetGroup:Flush() + for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetSet() ) do + local TaskGroup = TaskGroupData -- Wrapper.Group#GROUP + if TaskGroup:IsAlive() and TaskGroup:GetPlayerNames() then + if self:IsStatePlanned() or self:IsStateReplanned() then + self:SetMenuForGroup( TaskGroup, MenuTime ) + end + end + end +end + + + +--- Set the Menu for a Group +-- @param #TASK self +-- @param #number MenuTime +-- @return #TASK +function TASK:SetMenuForGroup( TaskGroup, MenuTime ) + + if not TaskGroup:GetState( TaskGroup, "Assigned" ) then + self:SetPlannedMenuForGroup( TaskGroup, self:GetTaskName(), MenuTime ) + else + if not self:IsAssignedToGroup( TaskGroup ) then + self:SetAssignedMenuForGroup( TaskGroup, MenuTime ) + end + end +end + + +--- Set the planned menu option of the @{Task}. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @param #string MenuText The menu text. +-- @param #number MenuTime +-- @return #TASK self +function TASK:SetPlannedMenuForGroup( TaskGroup, MenuText, MenuTime ) + self:E( TaskGroup:GetName() ) + + local Mission = self:GetMission() + local MissionName = Mission:GetName() + local CommandCenter = Mission:GetCommandCenter() + local CommandCenterMenu = CommandCenter:GetMenu() + + local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime ) + + + local MissionMenu = Mission:GetMenu( TaskGroup ) + + local TaskType = self:GetType() + local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, MissionMenu ):SetTime( MenuTime ) + local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, MenuText, TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ):SetTime( MenuTime ):SetRemoveParent( true ) + + return self +end + +--- Set the assigned menu options of the @{Task}. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @param #number MenuTime +-- @return #TASK self +function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) + self:E( TaskGroup:GetName() ) + + local Mission = self:GetMission() + local MissionMenu = Mission:GetMenu( TaskGroup ) + + self:E( { MissionMenu = MissionMenu } ) + + local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Task Status", MissionMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ) + local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Abort Task", MissionMenu, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ) + + return self +end + +--- Remove the menu options of the @{Task} to all the groups in the SetGroup. +-- @param #TASK self +-- @param #number MenuTime +-- @return #TASK +function TASK:RemoveMenu( MenuTime ) + self:F() + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + local TaskGroup = TaskGroup -- Wrapper.Group#GROUP + if TaskGroup:IsAlive() and TaskGroup:GetPlayerNames() then + if not self:IsAssignedToGroup( TaskGroup ) then + self:RemovePlannedMenuForGroup( TaskGroup, MenuTime ) + end + end + end +end + + +--- Remove the menu option of the @{Task} for a @{Group}. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @param #number MenuTime +-- @return #TASK self +function TASK:RemovePlannedMenuForGroup( TaskGroup, MenuTime ) + self:F() + + local Mission = self:GetMission() + local MissionName = Mission:GetName() + + local MissionMenu = Mission:GetMenu( TaskGroup ) + + if MissionMenu then + local TaskType = self:GetType() + local TypeMenu = MissionMenu:GetMenu( TaskType ) + + if TypeMenu then + local TaskMenu = TypeMenu:GetMenu( self:GetTaskName() ) + if TaskMenu then + TaskMenu:Remove( MenuTime ) + end + end + end + +end + +--- Remove the assigned menu option of the @{Task} for a @{Group}. +-- @param #TASK self +-- @param Wrapper.Group#GROUP TaskGroup +-- @param #number MenuTime +-- @return #TASK self +function TASK:RemoveAssignedMenuForGroup( TaskGroup ) + self:F() + + local Mission = self:GetMission() + local MissionName = Mission:GetName() + + local MissionMenu = Mission:GetMenu( TaskGroup ) + + if MissionMenu then + MissionMenu:RemoveSubMenus() + end + +end + +function TASK.MenuAssignToGroup( MenuParam ) + + local self = MenuParam.self + local TaskGroup = MenuParam.TaskGroup + + self:E( "Assigned menu selected") + + self:AssignToGroup( TaskGroup ) +end + +--- Report the task status. +-- @param #TASK self +function TASK:MenuTaskStatus( TaskGroup ) + + local ReportText = self:ReportDetails() + + self:T( ReportText ) + self:GetMission():GetCommandCenter():MessageToGroup( ReportText, TaskGroup ) + +end + +--- Report the task status. +-- @param #TASK self +function TASK:MenuTaskAbort( TaskGroup ) + + self:Abort() +end + + + +--- Returns the @{Task} name. +-- @param #TASK self +-- @return #string TaskName +function TASK:GetTaskName() + return self.TaskName +end + + + + +--- Get the default or currently assigned @{Process} template with key ProcessName. +-- @param #TASK self +-- @param #string ProcessName +-- @return Core.Fsm#FSM_PROCESS +function TASK:GetProcessTemplate( ProcessName ) + + local ProcessTemplate = self.ProcessClasses[ProcessName] + + return ProcessTemplate +end + + + +-- TODO: Obscolete? +--- Fail processes from @{Task} with key @{Unit} +-- @param #TASK self +-- @param #string TaskUnitName +-- @return #TASK self +function TASK:FailProcesses( TaskUnitName ) + + for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do + local Process = ProcessData + Process.Fsm:Fail() + end +end + +--- Add a FiniteStateMachine to @{Task} with key Task@{Unit} +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @param Core.Fsm#FSM_PROCESS Fsm +-- @return #TASK self +function TASK:SetStateMachine( TaskUnit, Fsm ) + self:F2( { TaskUnit, self.Fsm[TaskUnit] ~= nil, Fsm:GetClassNameAndID() } ) + + self.Fsm[TaskUnit] = Fsm + + return Fsm +end + +--- Gets the FiniteStateMachine of @{Task} with key Task@{Unit} +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @return Core.Fsm#FSM_PROCESS +function TASK:GetStateMachine( TaskUnit ) + self:F2( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) + + return self.Fsm[TaskUnit] +end + +--- Remove FiniteStateMachines from @{Task} with key Task@{Unit} +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @return #TASK self +function TASK:RemoveStateMachine( TaskUnit ) + self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) + + self:E( self.Fsm ) + for TaskUnitT, Fsm in pairs( self.Fsm ) do + self:E( TaskUnitT ) + end + + self.Fsm[TaskUnit] = nil + + collectgarbage() + self:E( "Garbage Collected, Processes should be finalized now ...") +end + +--- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task} +-- @param #TASK self +-- @param Wrapper.Unit#UNIT TaskUnit +-- @return #TASK self +function TASK:HasStateMachine( TaskUnit ) + self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) + + return ( self.Fsm[TaskUnit] ~= nil ) +end + + +--- Gets the Scoring of the task +-- @param #TASK self +-- @return Functional.Scoring#SCORING Scoring +function TASK:GetScoring() + return self.Mission:GetScoring() +end + + +--- Gets the Task Index, which is a combination of the Task type, the Task name. +-- @param #TASK self +-- @return #string The Task ID +function TASK:GetTaskIndex() + + local TaskType = self:GetType() + local TaskName = self:GetName() + + return TaskType .. "." .. TaskName +end + +--- Sets the Name of the Task +-- @param #TASK self +-- @param #string TaskName +function TASK:SetName( TaskName ) + self.TaskName = TaskName +end + +--- Gets the Name of the Task +-- @param #TASK self +-- @return #string The Task Name +function TASK:GetName() + return self.TaskName +end + +--- Sets the Type of the Task +-- @param #TASK self +-- @param #string TaskType +function TASK:SetType( TaskType ) + self.TaskType = TaskType +end + +--- Gets the Type of the Task +-- @param #TASK self +-- @return #string TaskType +function TASK:GetType() + return self.TaskType +end + +--- Sets the ID of the Task +-- @param #TASK self +-- @param #string TaskID +function TASK:SetID( TaskID ) + self.TaskID = TaskID +end + +--- Gets the ID of the Task +-- @param #TASK self +-- @return #string TaskID +function TASK:GetID() + return self.TaskID +end + + +--- Sets a @{Task} to status **Success**. +-- @param #TASK self +function TASK:StateSuccess() + self:SetState( self, "State", "Success" ) + return self +end + +--- Is the @{Task} status **Success**. +-- @param #TASK self +function TASK:IsStateSuccess() + return self:Is( "Success" ) +end + +--- Sets a @{Task} to status **Failed**. +-- @param #TASK self +function TASK:StateFailed() + self:SetState( self, "State", "Failed" ) + return self +end + +--- Is the @{Task} status **Failed**. +-- @param #TASK self +function TASK:IsStateFailed() + return self:Is( "Failed" ) +end + +--- Sets a @{Task} to status **Planned**. +-- @param #TASK self +function TASK:StatePlanned() + self:SetState( self, "State", "Planned" ) + return self +end + +--- Is the @{Task} status **Planned**. +-- @param #TASK self +function TASK:IsStatePlanned() + return self:Is( "Planned" ) +end + +--- Sets a @{Task} to status **Aborted**. +-- @param #TASK self +function TASK:StateAborted() + self:SetState( self, "State", "Aborted" ) + return self +end + +--- Is the @{Task} status **Aborted**. +-- @param #TASK self +function TASK:IsStateAborted() + return self:Is( "Aborted" ) +end + +--- Sets a @{Task} to status **Cancelled**. +-- @param #TASK self +function TASK:StateCancelled() + self:SetState( self, "State", "Cancelled" ) + return self +end + +--- Is the @{Task} status **Cancelled**. +-- @param #TASK self +function TASK:IsStateCancelled() + return self:Is( "Cancelled" ) +end + +--- Sets a @{Task} to status **Assigned**. +-- @param #TASK self +function TASK:StateAssigned() + self:SetState( self, "State", "Assigned" ) + return self +end + +--- Is the @{Task} status **Assigned**. +-- @param #TASK self +function TASK:IsStateAssigned() + return self:Is( "Assigned" ) +end + +--- Sets a @{Task} to status **Hold**. +-- @param #TASK self +function TASK:StateHold() + self:SetState( self, "State", "Hold" ) + return self +end + +--- Is the @{Task} status **Hold**. +-- @param #TASK self +function TASK:IsStateHold() + return self:Is( "Hold" ) +end + +--- Sets a @{Task} to status **Replanned**. +-- @param #TASK self +function TASK:StateReplanned() + self:SetState( self, "State", "Replanned" ) + return self +end + +--- Is the @{Task} status **Replanned**. +-- @param #TASK self +function TASK:IsStateReplanned() + return self:Is( "Replanned" ) +end + +--- Gets the @{Task} status. +-- @param #TASK self +function TASK:GetStateString() + return self:GetState( self, "State" ) +end + +--- Sets a @{Task} briefing. +-- @param #TASK self +-- @param #string TaskBriefing +-- @return #TASK self +function TASK:SetBriefing( TaskBriefing ) + self.TaskBriefing = TaskBriefing + return self +end + + + + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName ) + + self:E( { "Task Assigned", self.Dispatcher } ) + + self:MessageToGroups( "Task " .. self:GetName() .. " has been assigned to your group." ) + + if self.Dispatcher then + self:E( "Firing Assign event " ) + self.Dispatcher:Assign( self, PlayerUnit, PlayerName ) + end + + self:GetMission():__Start( 1 ) +end + + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onenterSuccess( From, Event, To ) + + self:E( "Task Success" ) + + self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is successful! Good job!" ) + self:UnAssignFromGroups() + + self:GetMission():__Complete( 1 ) + +end + + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string From +-- @param #string Event +-- @param #string To +function TASK:onenterAborted( From, Event, To ) + + self:E( "Task Aborted" ) + + self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been aborted! Task may be replanned." ) + + self:UnAssignFromGroups() + + self:__Replan( 5 ) +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string From +-- @param #string Event +-- @param #string To +function TASK:onafterReplan( From, Event, To ) + + self:E( "Task Replanned" ) + + self:GetMission():GetCommandCenter():MessageToCoalition( "Replanning Task " .. self:GetName() .. "." ) + + self:SetMenu() + +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string From +-- @param #string Event +-- @param #string To +function TASK:onenterFailed( From, Event, To ) + + self:E( "Task Failed" ) + + self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has failed!" ) + + self:UnAssignFromGroups() +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onstatechange( From, Event, To ) + + if self:IsTrace() then + MESSAGE:New( "@ Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() + end + + if self.Scores[To] then + local Scoring = self:GetScoring() + if Scoring then + self:E( { self.Scores[To].ScoreText, self.Scores[To].Score } ) + Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score ) + end + end + +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onenterPlanned( From, Event, To) + if not self.TimeOut == 0 then + self.__TimeOut( self.TimeOut ) + end +end + +--- FSM function for a TASK +-- @param #TASK self +-- @param #string Event +-- @param #string From +-- @param #string To +function TASK:onbeforeTimeOut( From, Event, To ) + if From == "Planned" then + self:RemoveMenu() + return true + end + return false +end + +do -- Dispatcher + + --- Set dispatcher of a task + -- @param #TASK self + -- @param Tasking.DetectionManager#DETECTION_MANAGER Dispatcher + -- @return #TASK + function TASK:SetDispatcher( Dispatcher ) + self.Dispatcher = Dispatcher + end + +end + +do -- Reporting + +--- Create a summary report of the Task. +-- List the Task Name and Status +-- @param #TASK self +-- @return #string +function TASK:ReportSummary() + + local Report = REPORT:New() + + -- List the name of the Task. + local Name = self:GetName() + + -- Determine the status of the Task. + local State = self:GetState() + + Report:Add( "Task " .. Name .. " - State '" .. State ) + + return Report:Text() +end + + +--- Create a detailed report of the Task. +-- List the Task Status, and the Players assigned to the Task. +-- @param #TASK self +-- @return #string +function TASK:ReportDetails() + + local Report = REPORT:New() + + -- List the name of the Task. + local Name = self:GetName() + + -- Determine the status of the Task. + local State = self:GetState() + + -- Loop each Unit active in the Task, and find Player Names. + local PlayerNames = {} + local PlayerReport = REPORT:New( " - Players:" ) + for PlayerGroupID, PlayerGroupData in pairs( self:GetGroups():GetSet() ) do + local PlayerGroup = PlayerGroupData -- Wrapper.Group#GROUP + PlayerNames = PlayerGroup:GetPlayerNames() + if PlayerNames then + PlayerReport:Add( " -- Group " .. PlayerGroup:GetCallsign() .. ": " .. table.concat( PlayerNames, ", " ) ) + end + end + + -- Loop each Process in the Task, and find Reporting Details. + Report:Add( string.format( " - Task %s\n -- State '%s'\n%s", Name, State, PlayerReport:Text() ) ) + return Report:Text() +end + + +end -- Reporting +--- This module contains the DETECTION_MANAGER class and derived classes. +-- +-- === +-- +-- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Fsm#FSM} +-- ==================================================================== +-- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. +-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. +-- +-- 1.1) DETECTION_MANAGER constructor: +-- ----------------------------------- +-- * @{DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. +-- +-- 1.2) DETECTION_MANAGER reporting: +-- --------------------------------- +-- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetReportInterval}(). +-- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Reporting can be started and stopped using the methods @{DetectionManager#DETECTION_MANAGER.StartReporting}() and @{DetectionManager#DETECTION_MANAGER.StopReporting}() respectively. +-- If an ad-hoc report is requested, use the method @{DetectionManager#DETECTION_MANAGER#ReportNow}(). +-- +-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. +-- +-- === +-- +-- 2) @{DetectionManager#DETECTION_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER} +-- ========================================================================================= +-- The @{DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class. +-- +-- 2.1) DETECTION_REPORTING constructor: +-- ------------------------------- +-- The @{DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance. +-- +-- +-- === +-- +-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing +-- ### Author: FlightControl - Framework Design & Programming +-- +-- @module DetectionManager + +do -- DETECTION MANAGER + + --- DETECTION_MANAGER class. + -- @type DETECTION_MANAGER + -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. + -- @extends Core.Fsm#FSM + DETECTION_MANAGER = { + ClassName = "DETECTION_MANAGER", + SetGroup = nil, + Detection = nil, + } + + --- FAC constructor. + -- @param #DETECTION_MANAGER self + -- @param Set#SET_GROUP SetGroup + -- @param Functional.Detection#DETECTION_BASE Detection + -- @return #DETECTION_MANAGER self + function DETECTION_MANAGER:New( SetGroup, Detection ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM:New() ) -- #DETECTION_MANAGER + + self.SetGroup = SetGroup + self.Detection = Detection + + self:SetStartState( "Stopped" ) + self:AddTransition( "Stopped", "Start", "Started" ) + self:AddTransition( "Started", "Stop", "Stopped" ) + self:AddTransition( "Started", "Report", "Started" ) + + self:SetReportInterval( 30 ) + self:SetReportDisplayTime( 25 ) + + Detection:__Start( 1 ) + + return self + end + + function DETECTION_MANAGER:onafterStart( From, Event, To ) + self:Report() + end + + function DETECTION_MANAGER:onafterReport( From, Event, To ) + + self:E( "onafterReport" ) + + self:__Report( -self._ReportInterval ) + + self:ProcessDetected( self.Detection ) + end + + --- Set the reporting time interval. + -- @param #DETECTION_MANAGER self + -- @param #number ReportInterval The interval in seconds when a report needs to be done. + -- @return #DETECTION_MANAGER self + function DETECTION_MANAGER:SetReportInterval( ReportInterval ) + self:F2() + + self._ReportInterval = ReportInterval + end + + + --- Set the reporting message display time. + -- @param #DETECTION_MANAGER self + -- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. + -- @return #DETECTION_MANAGER self + function DETECTION_MANAGER:SetReportDisplayTime( ReportDisplayTime ) + self:F2() + + self._ReportDisplayTime = ReportDisplayTime + end + + --- Get the reporting message display time. + -- @param #DETECTION_MANAGER self + -- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. + function DETECTION_MANAGER:GetReportDisplayTime() + self:F2() + + return self._ReportDisplayTime + end + + --- Reports the detected items to the @{Set#SET_GROUP}. + -- @param #DETECTION_MANAGER self + -- @param Functional.Detection#DETECTION_BASE Detection + -- @return #DETECTION_MANAGER self + function DETECTION_MANAGER:ProcessDetected( Detection ) + self:E() + + end + +end + + +do -- DETECTION_REPORTING + + --- DETECTION_REPORTING class. + -- @type DETECTION_REPORTING + -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. + -- @extends #DETECTION_MANAGER + DETECTION_REPORTING = { + ClassName = "DETECTION_REPORTING", + } + + + --- DETECTION_REPORTING constructor. + -- @param #DETECTION_REPORTING self + -- @param Set#SET_GROUP SetGroup + -- @param Functional.Detection#DETECTION_AREAS Detection + -- @return #DETECTION_REPORTING self + function DETECTION_REPORTING:New( SetGroup, Detection ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_REPORTING + + self:Schedule( 1, 30 ) + return self + end + + --- Creates a string of the detected items in a @{Detection}. + -- @param #DETECTION_MANAGER self + -- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object. + -- @return #DETECTION_MANAGER self + function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet ) + self:F2() + + local MT = {} -- Message Text + local UnitTypes = {} + + for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT + if DetectedUnit:IsAlive() then + local UnitType = DetectedUnit:GetTypeName() + + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + end + + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + + return table.concat( MT, ", " ) + end + + + + --- Reports the detected items to the @{Set#SET_GROUP}. + -- @param #DETECTION_REPORTING self + -- @param Wrapper.Group#GROUP Group The @{Group} object to where the report needs to go. + -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_BASE} object. + -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. + function DETECTION_REPORTING:ProcessDetected( Group, Detection ) + self:F2( Group ) + + self:E( Group ) + local DetectedMsg = {} + for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do + local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea + DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set ) + end + local FACGroup = Detection:GetDetectionGroups() + FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group ) + + return true + end + +end + +--- **Tasking** - The TASK_A2G_DISPATCHER creates and manages player TASK_A2G tasks based on detected targets. +-- +-- === +-- +-- # 1) @{#TASK_A2G_DISPATCHER} class, extends @{#DETECTION_MANAGER} +-- +-- The @{#TASK_A2G_DISPATCHER} class implements the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of FAC (groups). +-- The FAC will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. +-- Find a summary below describing for which situation a task type is created: +-- +-- * **CAS Task**: Is created when there are enemy ground units within range of the FAC, while there are friendly units in the FAC perimeter. +-- * **BAI Task**: Is created when there are enemy ground units within range of the FAC, while there are NO other friendly units within the FAC perimeter. +-- * **SEAD Task**: Is created when there are enemy ground units wihtin range of the FAC, with air search radars. +-- +-- Other task types will follow... +-- +-- 3.1) TASK_A2G_DISPATCHER constructor: +-- -------------------------------------- +-- The @{#TASK_A2G_DISPATCHER.New}() method creates a new TASK_A2G_DISPATCHER instance. +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-03-09: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module Task_A2G_Dispatcher + +do -- TASK_A2G_DISPATCHER + + --- TASK_A2G_DISPATCHER class. + -- @type TASK_A2G_DISPATCHER + -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. + -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. + -- @field Tasking.Mission#MISSION Mission + -- @extends Tasking.DetectionManager#DETECTION_MANAGER + TASK_A2G_DISPATCHER = { + ClassName = "TASK_A2G_DISPATCHER", + Mission = nil, + Detection = nil, + } + + + --- TASK_A2G_DISPATCHER constructor. + -- @param #TASK_A2G_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done. + -- @param Set#SET_GROUP SetGroup The set of groups that can join the tasks within the mission. + -- @param Functional.Detection#DETECTION_BASE Detection The detection results that are used to dynamically assign new tasks to human players. + -- @return #TASK_A2G_DISPATCHER self + function TASK_A2G_DISPATCHER:New( Mission, SetGroup, Detection ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #TASK_A2G_DISPATCHER + + self.Detection = Detection + self.Mission = Mission + + self:AddTransition( "Started", "Assign", "Started" ) + + --- OnAfter Transition Handler for Event Assign. + -- @function [parent=#TASK_A2G_DISPATCHER] OnAfterAssign + -- @param #TASK_A2G_DISPATCHER self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Tasking.Task_A2G#TASK_A2G Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string PlayerName + + self:__Start( 5 ) + + return self + end + + + --- Creates a SEAD task when there are targets for it. + -- @param #TASK_A2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem + -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return #nil If there are no targets to be set. + function TASK_A2G_DISPATCHER:EvaluateSEAD( DetectedItem ) + self:F( { DetectedItem.ItemID } ) + + local DetectedSet = DetectedItem.Set + local DetectedZone = DetectedItem.Zone + + -- Determine if the set has radar targets. If it does, construct a SEAD task. + local RadarCount = DetectedSet:HasSEAD() + + if RadarCount > 0 then + + -- Here we're doing something advanced... We're copying the DetectedSet, but making a new Set only with SEADable Radar units in it. + local TargetSetUnit = SET_UNIT:New() + TargetSetUnit:SetDatabase( DetectedSet ) + TargetSetUnit:FilterHasSEAD() + TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. + + return TargetSetUnit + end + + return nil + end + + --- Creates a CAS task when there are targets for it. + -- @param #TASK_A2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem + -- @return Tasking.Task#TASK + function TASK_A2G_DISPATCHER:EvaluateCAS( DetectedItem ) + self:F( { DetectedItem.ItemID } ) + + local DetectedSet = DetectedItem.Set + local DetectedZone = DetectedItem.Zone + + + -- Determine if the set has radar targets. If it does, construct a SEAD task. + local GroundUnitCount = DetectedSet:HasGroundUnits() + local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedItem ) + + if GroundUnitCount > 0 and FriendliesNearBy == true then + + -- Copy the Set + local TargetSetUnit = SET_UNIT:New() + TargetSetUnit:SetDatabase( DetectedSet ) + TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. + + return TargetSetUnit + end + + return nil + end + + --- Creates a BAI task when there are targets for it. + -- @param #TASK_A2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem + -- @return Tasking.Task#TASK + function TASK_A2G_DISPATCHER:EvaluateBAI( DetectedItem, FriendlyCoalition ) + self:F( { DetectedItem.ItemID } ) + + local DetectedSet = DetectedItem.Set + local DetectedZone = DetectedItem.Zone + + + -- Determine if the set has radar targets. If it does, construct a SEAD task. + local GroundUnitCount = DetectedSet:HasGroundUnits() + local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedItem ) + + if GroundUnitCount > 0 and FriendliesNearBy == false then + + -- Copy the Set + local TargetSetUnit = SET_UNIT:New() + TargetSetUnit:SetDatabase( DetectedSet ) + TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. + + return TargetSetUnit + end + + return nil + end + + --- Evaluates the removal of the Task from the Mission. + -- Can only occur when the DetectedItem is Changed AND the state of the Task is "Planned". + -- @param #TASK_A2G_DISPATCHER self + -- @param Tasking.Mission#MISSION Mission + -- @param Tasking.Task#TASK Task + -- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem + -- @return Tasking.Task#TASK + function TASK_A2G_DISPATCHER:EvaluateRemoveTask( Mission, Task, DetectedItem ) + + if Task then + if Task:IsStatePlanned() and DetectedItem.Changed == true then + self:E( "Removing Tasking: " .. Task:GetTaskName() ) + Task = Mission:RemoveTask( Task ) + end + end + + return Task + end + + + --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. + -- @param #TASK_A2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function TASK_A2G_DISPATCHER:ProcessDetected( Detection ) + self:E() + + local AreaMsg = {} + local TaskMsg = {} + local ChangeMsg = {} + + local Mission = self.Mission + local ReportSEAD = REPORT:New( "- SEAD Tasks:") + local ReportCAS = REPORT:New( "- CAS Tasks:") + local ReportBAI = REPORT:New( "- BAI Tasks:") + local ReportChanges = REPORT:New( " - Changes:" ) + + --- First we need to the detected targets. + for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do + + local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set -- Functional.Detection#DETECTION_BASE.DetectedSet + local DetectedZone = DetectedItem.Zone + self:E( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } ) + DetectedSet:Flush() + + local ItemID = DetectedItem.ItemID + + -- Evaluate SEAD Tasking + local SEADTask = Mission:GetTask( string.format( "SEAD.%03d", ItemID ) ) + SEADTask = self:EvaluateRemoveTask( Mission, SEADTask, DetectedItem ) + if not SEADTask then + local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed... + if TargetSetUnit then + local Task = TASK_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", ItemID ), TargetSetUnit ) + Task:SetTargetZone( DetectedZone ) + Task:SetDispatcher( self ) + SEADTask = Mission:AddTask( Task ) + end + end + if SEADTask and SEADTask:IsStatePlanned() then + ReportSEAD:Add( string.format( " - %s.%02d - %s", "SEAD", ItemID, Detection:DetectedItemReportSummary(DetectedItemID) ) ) + end + + -- Evaluate CAS Tasking + local CASTask = Mission:GetTask( string.format( "CAS.%03d", ItemID ) ) + CASTask = self:EvaluateRemoveTask( Mission, CASTask, DetectedItem ) + if not CASTask then + local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed... + if TargetSetUnit then + local Task = TASK_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", ItemID ), TargetSetUnit ) + Task:SetTargetZone( DetectedZone ) + Task:SetDispatcher( self ) + CASTask = Mission:AddTask( Task ) + end + end + if CASTask and CASTask:IsStatePlanned() then + ReportCAS:Add( string.format( " - %s.%02d - %s", "CAS", ItemID, Detection:DetectedItemReportSummary(DetectedItemID) ) ) + end + + -- Evaluate BAI Tasking + local BAITask = Mission:GetTask( string.format( "BAI.%03d", ItemID ) ) + BAITask = self:EvaluateRemoveTask( Mission, BAITask, DetectedItem ) + if not BAITask then + local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be SEADed... + if TargetSetUnit then + local Task = TASK_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", ItemID ), TargetSetUnit ) + Task:SetTargetZone( DetectedZone ) + Task:SetDispatcher( self ) + BAITask = Mission:AddTask( Task ) + end + end + if BAITask and BAITask:IsStatePlanned() then + ReportBAI:Add( string.format( " - %s.%02d - %s", "BAI", ItemID, Detection:DetectedItemReportSummary(DetectedItemID) ) ) + end + + + -- Loop through the changes ... + local ChangeText = Detection:GetChangeText( DetectedItem ) + ReportChanges:Add( ChangeText ) + + + -- OK, so the tasking has been done, now delete the changes reported for the area. + Detection:AcceptChanges( DetectedItem ) + + end + + -- TODO set menus using the HQ coordinator + Mission:GetCommandCenter():SetMenu() + + for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do + if not TaskGroup:GetState( TaskGroup, "Assigned" ) then + Mission:GetCommandCenter():MessageToGroup( + string.format( "HQ Reporting - Planned tasks for mission '%s':\n%s\n", + self.Mission:GetName(), + string.format( "%s\n\n%s\n\n%s\n\n%s", ReportSEAD:Text(), ReportCAS:Text(), ReportBAI:Text(), ReportChanges:Text() + ) + ), TaskGroup + ) + end + end + + return true + end + +end--- **Tasking** - The TASK_A2G models tasks for players in Air to Ground engagements. +-- +-- ![Banner Image](..\Presentations\TASK_A2G\Dia1.JPG) +-- +-- +-- # 1) @{Task_A2G#TASK_A2G} class, extends @{Task#TASK} +-- +-- The @{#TASK_A2G} class defines Air To Ground tasks for a @{Set} of Target Units, +-- based on the tasking capabilities defined in @{Task#TASK}. +-- The TASK_A2G is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: +-- +-- * **None**: Start of the process +-- * **Planned**: The A2G task is planned. +-- * **Assigned**: The A2G task is assigned to a @{Group#GROUP}. +-- * **Success**: The A2G task is successfully completed. +-- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. +-- +-- # 1.1) Set the scoring of achievements in an A2G attack. +-- +-- Scoring or penalties can be given in the following circumstances: +-- +-- * @{#TASK_A2G.SetScoreOnDestroy}(): Set a score when a target in scope of the A2G attack, has been destroyed. +-- * @{#TASK_A2G.SetScoreOnSuccess}(): Set a score when all the targets in scope of the A2G attack, have been destroyed. +-- * @{#TASK_A2G.SetPenaltyOnFailed}(): Set a penalty when the A2G attack has failed. +-- +-- # 2) @{Task_A2G#TASK_SEAD} class, extends @{Task_A2G#TASK_A2G} +-- +-- The @{#TASK_SEAD} class defines a SEAD task for a @{Set} of Target Units. +-- +-- === +-- +-- # 3) @{Task_A2G#TASK_CAS} class, extends @{Task_A2G#TASK_A2G} +-- +-- The @{#TASK_CAS} class defines a CAS task for a @{Set} of Target Units. +-- +-- === +-- +-- # 4) @{Task_A2G#TASK_BAI} class, extends @{Task_A2G#TASK_A2G} +-- +-- The @{#TASK_BAI} class defines a BAI task for a @{Set} of Target Units. +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-03-09: Revised version. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[WingThor]**: Concept, Advice & Testing. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module Task_A2G + +do -- TASK_A2G + + --- The TASK_A2G class + -- @type TASK_A2G + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Tasking.Task#TASK + TASK_A2G = { + ClassName = "TASK_A2G", + } + + --- Instantiates a new TASK_A2G. + -- @param #TASK_A2G self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Set#SET_UNIT UnitSetTargets + -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. + -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. + -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. + -- @return #TASK_A2G self + function TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskType ) + local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) -- Tasking.Task#TASK_A2G + self:F() + + self.TargetSetUnit = TargetSetUnit + self.TaskType = TaskType + + Mission:AddTask( self ) + + local Fsm = self:GetUnitProcess() + + + Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "RouteToRendezVous", Rejected = "Reject" } ) + + Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" ) + Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } ) + Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } ) + + Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" ) + + Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" ) + Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" ) + + Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, self.TaskType ), { Accounted = "Success" } ) + Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" ) + Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} ) + Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} ) + Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" ) + + Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" ) + Fsm:AddTransition( "Accounted", "Success", "Success" ) + Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) + Fsm:AddTransition( "Failed", "Fail", "Failed" ) + + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_A2G#TASK_A2G Task + function Fsm:onafterRouteToRendezVous( TaskUnit, Task ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- Determine the first Unit from the self.RendezVousSetUnit + + if Task:GetRendezVousZone( TaskUnit ) then + self:__RouteToRendezVousZone( 0.1 ) + else + if Task:GetRendezVousPointVec2( TaskUnit ) then + self:__RouteToRendezVousPoint( 0.1 ) + else + self:__ArriveAtRendezVous( 0.1 ) + end + end + end + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task#TASK_A2G Task + function Fsm:OnAfterArriveAtRendezVous( TaskUnit, Task ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- Determine the first Unit from the self.TargetSetUnit + + self:__Engage( 0.1 ) + end + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task#TASK_A2G Task + function Fsm:onafterEngage( TaskUnit, Task ) + self:E( { self } ) + self:__Account( 0.1 ) + self:__RouteToTarget(0.1 ) + self:__RouteToTargets( -10 ) + end + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_A2G#TASK_A2G Task + function Fsm:onafterRouteToTarget( TaskUnit, Task ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- Determine the first Unit from the self.TargetSetUnit + + if Task:GetTargetZone( TaskUnit ) then + self:__RouteToTargetZone( 0.1 ) + else + local TargetUnit = Task.TargetSetUnit:GetFirst() -- Wrapper.Unit#UNIT + if TargetUnit then + local PointVec2 = TargetUnit:GetPointVec2() + self:T( { TargetPointVec2 = PointVec2, PointVec2:GetX(), PointVec2:GetAlt(), PointVec2:GetZ() } ) + Task:SetTargetPointVec2( TargetUnit:GetPointVec2(), TaskUnit ) + end + self:__RouteToTargetPoint( 0.1 ) + end + end + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_A2G#TASK_A2G Task + function Fsm:onafterRouteToTargets( TaskUnit, Task ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + local TargetUnit = Task.TargetSetUnit:GetFirst() -- Wrapper.Unit#UNIT + if TargetUnit then + Task:SetTargetPointVec2( TargetUnit:GetPointVec2(), TaskUnit ) + end + self:__RouteToTargets( -10 ) + end + + return self + + end + + --- @param #TASK_A2G self + function TASK_A2G:GetPlannedMenuText() + return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" + end + + --- @param #TASK_A2G self + -- @param Core.Point#POINT_VEC2 RendezVousPointVec2 The PointVec2 object referencing to the 2D point where the RendezVous point is located on the map. + -- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point. + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_A2G:SetRendezVousPointVec2( RendezVousPointVec2, RendezVousRange, TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteRendezVous = ProcessUnit:GetProcess( "RoutingToRendezVous", "RouteToRendezVousPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT + ActRouteRendezVous:SetPointVec2( RendezVousPointVec2 ) + ActRouteRendezVous:SetRange( RendezVousRange ) + end + + --- @param #TASK_A2G self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return Core.Point#POINT_VEC2 The PointVec2 object referencing to the 2D point where the RendezVous point is located on the map. + -- @return #number The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point. + function TASK_A2G:GetRendezVousPointVec2( TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteRendezVous = ProcessUnit:GetProcess( "RoutingToRendezVous", "RouteToRendezVousPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT + return ActRouteRendezVous:GetPointVec2(), ActRouteRendezVous:GetRange() + end + + + + --- @param #TASK_A2G self + -- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map. + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_A2G:SetRendezVousZone( RendezVousZone, TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteRendezVous = ProcessUnit:GetProcess( "RoutingToRendezVous", "RouteToRendezVousZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + ActRouteRendezVous:SetZone( RendezVousZone ) + end + + --- @param #TASK_A2G self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return Core.Zone#ZONE_BASE The Zone object where the RendezVous is located on the map. + function TASK_A2G:GetRendezVousZone( TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteRendezVous = ProcessUnit:GetProcess( "RoutingToRendezVous", "RouteToRendezVousZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + return ActRouteRendezVous:GetZone() + end + + --- @param #TASK_A2G self + -- @param Core.Point#POINT_VEC2 TargetPointVec2 The PointVec2 object where the Target is located on the map. + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_A2G:SetTargetPointVec2( TargetPointVec2, TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteTarget = ProcessUnit:GetProcess( "Engaging", "RouteToTargetPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT + ActRouteTarget:SetPointVec2( TargetPointVec2 ) + end + + + --- @param #TASK_A2G self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return Core.Point#POINT_VEC2 The PointVec2 object where the Target is located on the map. + function TASK_A2G:GetTargetPointVec2( TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteTarget = ProcessUnit:GetProcess( "Engaging", "RouteToTargetPoint" ) -- Actions.Act_Route#ACT_ROUTE_POINT + return ActRouteTarget:GetPointVec2() + end + + + --- @param #TASK_A2G self + -- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map. + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_A2G:SetTargetZone( TargetZone, TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteTarget = ProcessUnit:GetProcess( "Engaging", "RouteToTargetZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + ActRouteTarget:SetZone( TargetZone ) + end + + + --- @param #TASK_A2G self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map. + function TASK_A2G:GetTargetZone( TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteTarget = ProcessUnit:GetProcess( "Engaging", "RouteToTargetZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + return ActRouteTarget:GetZone() + end + + --- Set a score when a target in scope of the A2G attack, has been destroyed . + -- @param #TASK_A2G self + -- @param #string Text The text to display to the player, when the target has been destroyed. + -- @param #number Score The score in points. + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_A2G + function TASK_A2G:SetScoreOnDestroy( Text, Score, TaskUnit ) + self:F( { Text, Score, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + ProcessUnit:AddScoreProcess( "Engaging", "Account", "Account", Text, Score ) + + return self + end + + --- Set a score when all the targets in scope of the A2G attack, have been destroyed. + -- @param #TASK_A2G self + -- @param #string Text The text to display to the player, when all targets hav been destroyed. + -- @param #number Score The score in points. + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_A2G + function TASK_A2G:SetScoreOnSuccess( Text, Score, TaskUnit ) + self:F( { Text, Score, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + ProcessUnit:AddScore( "Success", Text, Score ) + + return self + end + + --- Set a penalty when the A2G attack has failed. + -- @param #TASK_A2G self + -- @param #string Text The text to display to the player, when the A2G attack has failed. + -- @param #number Penalty The penalty in points. + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_A2G + function TASK_A2G:SetPenaltyOnFailed( Text, Penalty, TaskUnit ) + self:F( { Text, Score, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + ProcessUnit:AddScore( "Failed", Text, Penalty ) + + return self + end + + +end + + +do -- TASK_SEAD + + --- The TASK_SEAD class + -- @type TASK_SEAD + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Tasking.Task#TASK + TASK_SEAD = { + ClassName = "TASK_SEAD", + } + + --- Instantiates a new TASK_SEAD. + -- @param #TASK_SEAD self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Set#SET_UNIT TargetSetUnit + -- @return #TASK_SEAD self + function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD" ) ) -- #TASK_SEAD + self:F() + + return self + end + +end + +do -- TASK_BAI + + --- The TASK_BAI class + -- @type TASK_BAI + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Tasking.Task#TASK + TASK_BAI = { + ClassName = "TASK_BAI", + } + + --- Instantiates a new TASK_BAI. + -- @param #TASK_BAI self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Set#SET_UNIT UnitSetTargets + -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. + -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. + -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. + -- @return #TASK_BAI self + function TASK_BAI:New( Mission, SetGroup, TaskName, TargetSetUnit ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "BAI" ) ) -- #TASK_BAI + self:F() + + return self + end + +end + +do -- TASK_CAS + + --- The TASK_CAS class + -- @type TASK_CAS + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Tasking.Task#TASK + TASK_CAS = { + ClassName = "TASK_CAS", + } + + --- Instantiates a new TASK_CAS. + -- @param #TASK_CAS self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Set#SET_UNIT UnitSetTargets + -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. + -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. + -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. + -- @return #TASK_CAS self + function TASK_CAS:New( Mission, SetGroup, TaskName, TargetSetUnit ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "CAS" ) ) -- #TASK_CAS + self:F() + + return self + end + +end +-- The order of the declarations is important here. Don't touch it. + +--- Declare the event dispatcher based on the EVENT class +_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT + +--- Declare the timer dispatcher based on the SCHEDULEDISPATCHER class +_SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER + +--- Declare the main database object, which is used internally by the MOOSE classes. +_DATABASE = DATABASE:New() -- Database#DATABASE + + + +BASE:TraceOnOff( false ) env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Utils/7-Zip/7-zip.chm b/Utils/7-Zip/7-zip.chm new file mode 100644 index 000000000..1dd03b8e3 Binary files /dev/null and b/Utils/7-Zip/7-zip.chm differ diff --git a/Utils/7-Zip/7-zip.dll b/Utils/7-Zip/7-zip.dll new file mode 100644 index 000000000..c06074bc5 Binary files /dev/null and b/Utils/7-Zip/7-zip.dll differ diff --git a/Utils/7-Zip/7-zip32.dll b/Utils/7-Zip/7-zip32.dll new file mode 100644 index 000000000..c5d427fc5 Binary files /dev/null and b/Utils/7-Zip/7-zip32.dll differ diff --git a/Utils/7-Zip/7z.dll b/Utils/7-Zip/7z.dll new file mode 100644 index 000000000..042cbf1d4 Binary files /dev/null and b/Utils/7-Zip/7z.dll differ diff --git a/Utils/7-Zip/7z.exe b/Utils/7-Zip/7z.exe new file mode 100644 index 000000000..c8feeddf8 Binary files /dev/null and b/Utils/7-Zip/7z.exe differ diff --git a/Utils/7-Zip/7z.sfx b/Utils/7-Zip/7z.sfx new file mode 100644 index 000000000..5a8b5f662 Binary files /dev/null and b/Utils/7-Zip/7z.sfx differ diff --git a/Utils/7-Zip/7zCon.sfx b/Utils/7-Zip/7zCon.sfx new file mode 100644 index 000000000..308663917 Binary files /dev/null and b/Utils/7-Zip/7zCon.sfx differ diff --git a/Utils/7-Zip/7zFM.exe b/Utils/7-Zip/7zFM.exe new file mode 100644 index 000000000..237e97eae Binary files /dev/null and b/Utils/7-Zip/7zFM.exe differ diff --git a/Utils/7-Zip/7zG.exe b/Utils/7-Zip/7zG.exe new file mode 100644 index 000000000..0442d42e3 Binary files /dev/null and b/Utils/7-Zip/7zG.exe differ diff --git a/Moose Mission Setup/Moose Mission Update/History.txt b/Utils/7-Zip/History.txt similarity index 99% rename from Moose Mission Setup/Moose Mission Update/History.txt rename to Utils/7-Zip/History.txt index 677d35b55..89702db1f 100644 --- a/Moose Mission Setup/Moose Mission Update/History.txt +++ b/Utils/7-Zip/History.txt @@ -1,6 +1,19 @@ HISTORY of the 7-Zip -------------------- +16.04 2016-10-04 +------------------------- +- The bug was fixed: 7-Zip 16.03 exe installer under Vista didn't create + links in Start / Programs menu. +- Some bugs were fixed in RAR code. + + +16.03 2016-09-28 +------------------------- +- Installer and SFX modules now use some protection against DLL preloading attack. +- Some bugs were fixed in 7z, NSIS, SquashFS, RAR5 and another code. + + 16.02 2016-05-21 ------------------------- - 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip). diff --git a/Utils/7-Zip/Lang/af.txt b/Utils/7-Zip/Lang/af.txt new file mode 100644 index 000000000..c578d4530 --- /dev/null +++ b/Utils/7-Zip/Lang/af.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.09 : Petri Jooste +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Afrikaans +Afrikaans +401 +OK +Kanselleer + + + +&Ja +&Nee +A&fsluit +Hulp + +&Gaan voort +440 +Ja vir &almal +Nee vir a&lmal +Stop +Herbegin +&Agtergrond +&Voorgrond +&Wag +Wagtend +Is u seker dat u wil kanselleer? +500 +&Lêer +R&edigeer +&Vertoon +G&unstelinge +&Gereedskap +&Hulp +540 +&Open +Open &Binne +Open B&uite +&Wys +R&edigeer +Her&noem +&Kopieer na... +&Verskuif na... +Ve&rwyder +Ver&deel lêer... +Kom&bineer lêers... +E&ienskappe +Komme&ntaar + + +Maak gids +Maak lêer +A&fsluit +600 +Selekteer &alles +Deselekteer a&lles +Keer &seleksie om +Selekteer... +Deselekteer... +Selekteer op Soort +Deselekteer op Soort +700 +&Groot ikone +&Klein ikone +&Lys +&Detail +730 +Ongesorteer + +&2 Panele +&Nutsbalke +Maak wortelgids oop +Een vlak hoër +Gidse geskiedenis... +&Verfris +750 +Argiveernutsbalk +Standaardnutsbalk +Groot knoppies +Wys teks op knoppies +800 +Voeg gids by gunstelinge &as +Boekmerk +900 +&Opsies... +&Normtoetsing +960 +&Inhoud... +&Aangaande 7-Zip... +1003 +Pad +Naam +Uitgang +Gids +Grootte +Ingepakte grootte +Kenmerke +Gemaak +Laatste toegang +Gewysig +Kompak +Kommentaar +Versleuteld +Verdeel Voor +Verdeel Na +Woordeboek +CRC +Tipe +Anti +Metode +Gasheer BS +Lêersstelsel +Gebruiker +Groep +Blok +Kommentaar +Posisie + + + + + + + + + + + + + + + + + + + + + + + + + +Fout +Totale grootte +Vrye ruimte +Klustergrootte +Etiket +Plaaslike naam +Verskaffer +2100 +Opsies +Taal +Taal: +Redigeerder +R&edigeerder: + +2200 +Stelsel +Assosieer 7-Zip met: +2301 +Integreer 7-Zip in kontekskeuselys. +Trapsgewyse kontekskeuselys +Kontekskeuselysitems: +2320 + + +Open +Pak lêers uit... +Voeg by argief... +Toets argief +Pak hier uit +Pak uit in {0} +Voeg by {0} +Saampers en e-pos... +Pers saam in {0} en e-pos +2400 +Gidse +&Werkgids +&TEMP-gids van het stelsel +&Huidige gids +&Gespesifiseerde gids: +Gebruik slegs vir verwisselbare media. +Spesifiseer die stoorplek vir tydelyke argieflêers. +2500 +Instellings +Wys ".." &item +Wys &ware lêerikone +Wys &stelselkeuselys +Wys seleksie oor &hele ry(e) +Wys &roosterlyne + + + +2900 +Aangaande 7-Zip +7-Zip is gratis programmatuur. Indien u egter so baie van 7-Zip hou dat u die verdere ontwikkeling wil ondersteun, registreer dan asb. met 'n geldelike donasie aan die 7-Zip Projek. +3000 + +Daar is geen foute nie +{0} objekt(e) is geselekteer +Kan gids '{0}' nie maak nie +Bywerk-funksie word vir hierdie argief nie ondersteun nie. + + + + +Lêer '{0}' is gewysig.\nWil u dit bywerk in die argief? +Kan lêer\n'{0}' nie bywerk nie +Redigeerder nie aan die gang gesit word nie. + + + + +Te veel items +3300 +Besig om uit te pak +Besig met saampersing +Besig om te toets +Besig om oop te maak... + +3400 +&Uitpak +U&itpak in: +Gee 'n bestemming vir uitgepakte lêers. +3410 +Pad-metode +Volledige padname +Geen padname +3420 +Vervang lêers +Vervang slegs met bevestiging +Vervang sonder bevestiging +Slaan bestaande lêers oor +Hernoem outomaties +Hernoem bestaande lêers outomaties +3500 +Bevestig lêeroorskrywing +Doelgids bevat alreeds 'n lêer met hierdie naam. +Wil u die bestaande lêer vervang +deur hierdie lêer ? +{0} grepe +O&utomaties hernoem +3700 +Nie-ondersteunde saampersmetode vir '{0}'. +Datafout in '{0}'. Lêer is beskadig. +CRC het misluk in '{0}'. Lêer is beskadig. + + +3800 +Tik wagwoord in +Tik wagwoord in: + +&Wys wagwoord + + + +&Wagwoord +3900 +Tydsduur sovêr: +Oorblywende tyd: +Grootte: +Spoed: + + +Foute: + +4000 +Voeg by argief +&Argief: +&Bywerkwyse: +Argie&fformaat: +Saampersingv&lak: +&Saampersmetode: +&Woordeboekgrootte: +&Woordgrootte: + + +Pa&rameters: +Opsies +Maak SF&X argief + + + +Enkripteer lêer&name +Geheuegebruik vir saampersing: +Geheuegebruik vir uitpakking: +4050 +Stoor +Vinnigste +Vinnig +Normaal +Maksimum +Ultra +4060 +Lêers byvoeg en vervang +Lêers bywerk en byvoeg +Verfris bestaande lêers +Sinkroniseer lêers +4070 +Blaai +Alle lêers + + +6000 +Kopieer +Verskuif +Kopieer na: +Verskuif na: +Besig met kopiëring... +Besig met verskuiwing... +Besig met hernoeming... + +Bewerking word nie ondersteun nie. +Fout by hernoeming van lêer of gids + + +6100 +Bevestig lêerverwydering +Bevestig gidsverwydering +Bevestig verwydering van meerdere lêers +Is u seker dat u '{0}' wil verwyder? +Is u seker dat u gids '{0}' asook die inhoud daarvan wil verwyder? +Is u seker dat u hierdie {0} items wil verwyder? +Besig met verwydering... +Fout by verwydering van lêer of gids + +6300 +Maak gids +Maak lêer +Naam van die gids: +Lêernaam: +Nuwe gids +Nuwe lêer +Fout by maak van gids +Fout by maak van nuwe lêer +6400 + + +Selekteer +Deselekteer +Masker: +6600 + +Gidse-geskiedenis +Diagnostiese boodskappe +Boodskap +7100 +Rekenaar +Network + +Stelsel +7200 +Voeg by +Pak uit +Toets +Kopiëer +Skuif +Vee uit +Intigting +7300 +Verdeel lêer +&Verdeel na: +Verdeel in &volumes, aantal grepe: +Besig met verdeling... + + + + + +7400 +Kombineer lêers +&Kombineer na: +Besig met kombinering... + + + +7500 + + + + +7600 +Meet +Geheuegebruik: +Inpakking +Uitpakking +Gradering +Totale gradering +Huidige +Resultaat + + +Lopies: diff --git a/Utils/7-Zip/Lang/an.txt b/Utils/7-Zip/Lang/an.txt new file mode 100644 index 000000000..6264849e9 --- /dev/null +++ b/Utils/7-Zip/Lang/an.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Feliciano Martínez Tur +; 9.07 : Juan Pablo Martínez +; +; +; +; +; +; +; +; +; +0 +7-Zip +Aragonese +Aragonés +401 +Acceptar +Cancelar + + + +&Sí +&No +&Zarrar +Aduya + +&Continar +440 +Sí a &tot +No a t&ot +Aturar +Tornar a empecipiar +Se&gundo plano +P&rimer plano +&Pausa +Aturau +Yes seguro que quiers cancelar? +500 +&Fichero +&Editar +&Veyer +&Favoritos +&Ferramientas +Ad&uya +540 +&Ubrir +Ubrir &adintro +Ubrir &difuera +&Veyer +&Editar +Re&nombrar +&Copiar en... +&Mover ta... +&Borrar +Di&vidir o fichero... +C&ombinar os fichers... +&Propiedatz +Comen&tario +Calcular a suma de comprebación +Diff +Creyar carpeta +Creyar fichero +&Salir +600 +Seleccionar-lo &tot +Deseleccionar-lo tot +&Invertir selección +Seleccionar... +Deseleccionar... +Seleccionar por tipo +Deseleccionar por tipo +700 +Iconos g&rans +&Iconos chicotz +&Lista +&Detalles +730 +Desordenau +Anvista plana +&2 panels +&Barras de ferramientas +Ubrir a carpeta radiz +Carpeta mai +Historial de carpetas... +&Esviellar +750 +Barra de ferramientas d'archivo +Barras de ferramientas estandard +Botons grans +Amostrar texto en os botons +800 +&Adhibir carpeta a favoritos como +Adhibir a favoritos +900 +&Opcions... +&Prebas de referencia (benchmark) +960 +&Conteniu... +A&rredol de 7-Zip... +1003 +Rota +Nombre +Tipo de fichero +Carpeta +Grandaria +Grandaria comprimida +Atributos +Creyau +Zaguer acceso +Zaguera modificación +Compacto +Comentario +Zifrau +Expandiu antis +Expandiu dimpués +Diccionario +CRC +Tipo +Anti +Metodo +SO d'orichen +Sistema de fichers +Usuario +Grupo +Bloque +Comentario +Posición +Prefixo de rota +Carpeta +Fichers +Versión +Fragmento +Multiframento +Desplazamiento +Vinclos +Bloques +Fragmentos + +64-bit +Big-endian +CPU +Grandaria fisica +Grandaria d'as cabeceras +Suma de comprebación +Caracteristicas +Adreza virtual +ID +Nombre curto +Aplicación creyadera +Grandaria de sector +Modo +Vinclo +Error +Espacio total +Espacio libre +Grandaria de sector +Etiqueta +Nombre local +Proveyedor +2100 +Opcions +Luenga +Luenga: +Editor +&Editor: +&Diff: +2200 +Sistema +Asociar 7-Zip con: +2301 +Integrar 7-Zip en o menú contextual de Windows +Menú contextual en cascada +Elementos d'o menú contextual: +2320 + + +Ubrir archivo +Extrayer-ne os fichers... +Adhibir a l'archivo... +Comprebar l'archivo +Extrayer aquí +Extrayer en {0} +Adhibir a {0} +Comprimir y ninviar por correu... +Comprimir en {0} y ninviar por correu +2400 +Carpeta +Carpeta de &treballo +Carpeta temporal d'o &sistema +Carpeta &actual +&Especificar una carpeta: +No emplegar que ta dispositivos extrayibles +Especificar una carpeta ta archivos temporals. +2500 +Propiedatz +Amostrar l'elemento ".." +Amostrar iconos propios +Amostrar o menú d'o sistema +&Seleccionar ringlera(s) completa(s) +Amostrar as linias d'a &quadricla +Clicar una vegada ta ubrir elemento +Modo de selección &alternativo +Emplegar pachinas de memoria &grans +2900 +Arredol de 7-Zip +7-Zip ye un programa libre y gratuito. Si quiers, puetz colaborar en o desembolique de 7-Zip rechistrando-te ta contribuyir a amillorar o programa. +3000 +O sistema no ha puesto asignar a cantidat necesaria de memoria +No i hai errors +{0} elemento(s) seleccionau(s) +No se puet creyar a carpeta '{0}' +Ista mena d'archivo no permite actualización. +No se puet ubrir o fichero '{0}' como archivo comprimiu +No se puet ubrir l'archivo zifrau '{0}'. Comprebe si a clau ye incorrecta. +Tipo d'archivo no admeso +O fichero {0} ya existe +O fichero '{0}' s'ha modificau.\nQuiers esviellar-lo en l'archivo? +No se puet esviellar o fichero\n'{0}' +No se puet executar l'editor. +O fichero pareix un virus (o nombre d'o fichero contiene espacios largos). +No se puet execitar ista operación dende una carpeta que tienga una rota larga. +Has de seleccionar un fichero +Has de seleccionar un u más fichers +Masiaus elementos +3300 +Extrayendo +comprimindo +Prebando +Ubrindo... +Buscando... +3400 +Extrayer +E&xtrayer a: +Selecciona un destín ta os fichers extrayius. +3410 +Modo de rota +Rotas completas +Sin rotas +3420 +Modo de sobrescritura +Con confirmación +Sin confirmación +Conservar os fichers ya existents +Renombrar automaticament +Renombrar automaticament os fichers ya existents +3500 +Confirmar a substitución de fichers +A carpeta de destín ya contiene un fichero con o mesmo nombre. +Quiers substituyir o fichero existent +por iste atro? +{0} bytes +Renombrar a&utomaticament +3700 +Metodo de compresión no valido ta '{0}'. +Error de datos en '{0}'. O fichero ye corrompiu. +O CRC ha fallau en '{0}'. O fichero ye corrompiu. +Error de datos en o fichero zifrau '{0}'. Verifica a clau. +Error de CRC en o fichero zifrau '{0}'. Verifica a clau. +3800 +Escribe a clau +Escribe a clau: +Torne a escribir a clau: +&Amostrar a clau +As claus son diferents. Por favor, torne a escribir-la. +Emplega en a clau nomás as letras de l'alfabeto anglés, numeros y caracters especials (!, #, $, ...) +A clau ye masiau larga. +Contrasenya +3900 +Tiempo transcorriu: +Tiempo pendient: +Grandaria: +Velocidat: +Procesau: +Razón de compresión: +Errors: +Archivos: +4000 +Adhibir a l'archivo +&Archivo: +M&odo d'actualización: +&Formato d'archivo: +&Libel de compresión: +&Metodo de compresión: +Grandaria de &diccionario: +Granda&ria d'a parola: +Grandaria de bloque compacto: +Numero de filos d'a CPU: +&Parametros: +Opcions +Creyar archivo SF&X (autoextrayible) +Comprimir fichers compartius +Encriptación +Metodo d'e &zifrau: +Zifrar &nombres de fichero +Memoria emplegada ta comprimir: +Memoria emplegada ta descomprimir: +4050 +Sin compresión +A mas rapida +Rapida +Normal +Maxima +Ultra +4060 +Adhibir y substituyir fichers +Esviellar y adhibir-ie fichers +Esviellar fichers ya presents +Sincronizar fichers +4070 +Explorar +Totz os fichers +No compacto +Compacto +6000 +Copiar +Mover +Copiar en: +Mover ta: +Copiando... +Movendo... +Renombrando... +Selecciona a carpeta de destín +Operación no permitida. +Error en enombrar un fichero u carpeta +Confirmar a copia d'o fichero +Yes seguro de que quiers copiar os fichers en l'archivo +6100 +Confirmar borrau de fichero +Confirmar borrau de carpeta +Confirmar borrau multiple fichers +Yes seguro que quiers borrar '{0}'? +Yes seguro que quiers borrar a carpeta '{0}' y tot o suyo conteniu? +Yes seguro que quiers borrar istos {0} elementos? +Borrando... +Error borrando fichero u carpeta +O sistema no puet mover un fichero con rota larga ta la Papelera de Reciclache +6300 +Creyar carpeta +Creyar fichero +Nombre de'a carpeta: +Nombre de'o fichero: +Carpeta nueva +Fichero nuevo +Error en creyar carpeta +Error en creyar o fichero: +6400 +Comentario +&Comentario: +Seleccionar +Deseleccionar +Patrón: +6600 +Propiedatz +Historial de carpetas +Mensaches de diagnostico +Mensache +7100 +O mío ordinador +Entorno de ret +Documentos +Sistema +7200 +Adhibir +Extrayer +Prebar +Copiar +Mover +Borrar +Información +7300 +Dividir fichero +Di&vidir a: +Dividir en fra&gmentos (bytes): +Dividindo... +Confirmar a división +Yes seguro que quiers dividir o fichero en {0} fragmentos? +A grandaria d'os fragmentos ha d'estar menor que a d'o fichero orichinal +Grandaria de fragmento incorrecta +Grandaria de fragmento especificada: {0} bytes.\nYe seguro que quiere dividir o fichero en fragmentos d'ixa grandaria? +7400 +Combinar fichers +&Combinar en: +Combinando... +Selecciona només o primer fichero +No s'ha puesto detectar o fichero como parti d'un fichero por fragmentos +No s'ha puesto trobar que un fragmento d'o fichero por fragmentos +7500 +Calculando a suma de verificación... +Suma de verificación (CRC) +CRC d'os datos: +CRC d'os datos y os nombres: +7600 +Prebas de referencia (benchmark) +Emplego de memoria: +Compresión +Descompresión +Taxa +Taxa total +Actual +Resultant +Emplego de CPU +Taxa / Emplego +Pasadas: diff --git a/Utils/7-Zip/Lang/ar.txt b/Utils/7-Zip/Lang/ar.txt new file mode 100644 index 000000000..f62e23c62 --- /dev/null +++ b/Utils/7-Zip/Lang/ar.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 9.07 :ترجمةالاستاذ:عوض ال-عائض الغامدي +; 9.07 : Awadh A Al-Ghaamdi +; +; 15.00 : 2016-08-28 : تعديل وتصحيح الترجمة: سيف حسام الاسدي +; 15.00 : 2016-08-28 : Saif H Al-asadi (edited and corrected) +; +; +; +; +; +; +0 +7-Zip +Arabic +عربي +401 +حسنا +إلغاء الأمر + + + +&نعم +&لا +&إغلاق +المساعدة + +&استمرار +440 +نعم للكل +لا للكل +إيقاف +إعادة تشغيل +&بالخلفية +&بالمقدمة +&إيقاف مؤقت +متوقف مؤقتا +هل أنت متأكد من الإلغاء؟ +500 +&الملف +&التعديل +&العرض +التف&ضيلات +&ألادوات +&المساعدة +540 +&فتح +&افتح بالداخل +&افتح للخارج +&عرض +&تعديل +إعادة التسمية +..نسخ إلى +..نقل إلى +&حذف +&تقسيم الملف... +دم&ج الملفات... +الخ&صائص +تعليق& +حساب قيمة التدقيق +فرق +إنشاء مجلد +إنشاء ملف +خروج +الربط +&الجداول البديلة +600 +تحديد الكل +عدم تحديد الكل +عكس التحديد +تحديد... +عدم تحديد... +تحديد حسب النوع +عدم تحديد حسب النوع +700 +رموز كبيرة +رموز صغيرة +&القائمة +&التفاصيل +730 +غير مرتب +العرض الافقي +&مجموعتين +&أشرطة الأدوات +فتح المجلد الرئيسي +للأعلى بمستوى واحد +...محفوظات المجلدات +&تحديث +تحديث تلقائي +750 +شريط أدوات الأرشفة +شريط ألادوات قياسي +أزرار كبيرة +إظهار تسميات الازرار +800 +&إضافة المجلد للمفضلة باسم +العلامات المرجعية +900 +...&الخيارات +&معالج الاداء +960 +..&المحتويات +7-Zip &حول... +1003 +المسار +الإسم +الإمتداد +المجلد +الحجم +الحجم المضغوط +الخواص +تم انشاءه +تم الدخول +تم تعديله +ثابت +تم التعيلق +مشفر +التقسيم قبل +التقسيم بعد +القاموس + +النوع +متعدد +الطريقة +نظام التشغيل +ملفات النظام +المستخدم +المجموعة +التكتل +التعليق +الموقع +بادئة المسار +المجلدات +الملفات +الإصدار +وحدة التخزين +وحدة تخزين متعددة +التعويض +روابط +كتل +وحدات تخزين + +64-بت +Big-endian +CPU +الحجم الطبيعي +حجم المقدمات +قيمة التحقق +المميزات +العنوان الظاهري +الهوية +إسم قصير +برنامج الانشاء +حجم القطاع +الوضع +الرابط الرمزي +خطأ +الحجم الكلي +المساحة الحرة +حجم الجزء +العلامة +الإسم المحلي +المجهز +NT أمان +الجداول البديلة +Aux +تم حذفة +التفرعات + + +خطأ في النوع +اخطاء +اخطاء +تحذيرات +تحذير +الجداول +الجداول البديلة +حجم الجداول البديلة +الحجم الظاهري +حجم الاخراج +الحجم الطبيعي الكلي +دليل الحجم +النوع الفرعي +تعليق قصير +رمز الصفحة + + + +حجم التذييل +حجم العقبات المضمن +الارتباط +الارتباط الصعب +iNode + +للقراءة-فقط +2100 +الخيارات +اللغة +ترجمةالأستاذ عوض الغامدي -التعديل سيف الاسدي +المحرر +&المحرر: +ال&فرق: +2200 +النظام +تكامل البرنامج مع : +جميع المستخدمين +2301 +الإندماج مع قائمة الزر الايمن +تتالي قائمة الزر الايمن +عناصر قائمة الزر الايمن : +الايقونات في قائمة الزر الايمن +2320 +<مجلد> +<إرشيف> +فتح ارشيف +استخراج الملفات... +إضافة إلى الإرشيف... +فحص الإرشيف +إستخرج هنا +إستخرج إلى {0}ـ +إضافة إلى {0}ـ +ضغط ثم إرسال... +ضغط إلى {0} ثم إرسال +2400 +مجلدات +&مجلد العمل +&مجلد النظام المؤقت +&الحالي +&محدد: +الإستخدام فقط للأقراص المتحركة +تحديد موضع للإرشيف المؤقت للملفات +2500 +الاعدادات +".." إظهار عنصر +إظهار أيقونات الملف الفعلية +إظهار قائمة النظام +&تحديد الصف بالكامل +إظهار خطوط الشبكة +نقرة واحدة لفتح أي مادة +&نظام تحديد بديل +إستعمال &صفحات ذاكرة كبيرة +2900 +حول البرنامج +7-Zip البرنامج مجاني +3000 +لا يمكن للنظام تخصيص الكمية المطلوبة للذاكرة +لا يوجد أخطاء +تم تحديد {0} عنصر +'{0}' لا يمكن إنشاء المجلد +تحديث العمليات غير مدعوم لهذا الإرشيف +كأرشيف '{0}' لا يمكن فتح الملف +كلمة المرور خطأ ؟ . '{0}' تعذر فتح الأرشيف المشفر +نوع أرشيف غير معتمد +موجود مسبقا {0} الملف +أتريد تحديثه في الإرشيف ؟\nالملف '{0}' تم تعديله +لا يمكن تحديث الملف\n'{0}' +لا يمكن بدء المحرر +(الملف يشبه فيروس (إسم الملف يحتوي على مسافات طويلة +لا يمكن إستدعاء العملية من مجلد له مسار طويل +يجب تحديد ملف واحد +يجب تحديد ملف واحد أو أكثر +عناصر كثيرة جداً +لايمكن فتح الملف {0} كأرشيف +الملف مفتوح {0} كأرشيف +ان الارشيف مفتوح بطريقة الطباعة بالاوفسيت +3300 +استخراج +الضغط +فحص +...فـتـح... +...يتم التفحص +تتم الازالة +3320 +يتم الاضافة +يتم التحديث +يتم التحليل +يتم التكرار +يتم اعادة الضغط +يتم التجاهل +يتم الحذف +يتم انشاء المقدمة +3400 +استخراج +استخراج إلى: +تحديد الموضع للملفات المستخرجة +3410 +حالة المسار +اسم المسار بالكامل +بدون اسم المسار +اسم المسار المطلق +اسم المسار النسبي +3420 +حالة إعادة الكتابة +السؤال قبل إعادة الكتابة +إعادة الكتابة بدون تنبيه +تجاوز الملفات المتوفرة +تسمية تلقائية +تسمية الملفات الموجودة تلقائياً +3430 +ازالة تكرارات المجلد الرئيسي +استعادة ملف الامان +3500 +تأكيد استبدال الملف +المجلد الهدف يحوي مسبقاً الملف +أتريد استبدال الملف الموجود؟ +بهذا الملف؟ +{0} بايت +إعادة تسمية تلقائية +3700 +'{0}'طريقة ضغط غير معتمدة لـ +'{0}'خطأ بيانات في. الملف تالف +'{0}' خطأ بصمة في . الملف تالف +خطأ بيانات في الملف المشفر '{0}' . كلمة المرور غير صحيحة ؟ +فشل الفحص الدوري في الملف المشفر '{0}' . كلمة المرور غير صحيحة ؟ +3710 +كلمة مرور خاطئة? +3721 +طريقة ضغط غير مدعومة +بيانات خطأ +CRC فشل +بيانات غير متاحة +النهاية المفاجئة للبيانات +هناك بعض البيانات بعد نهاية بيانات الحمولة +ليس ارشيفاً +مقدمات خطأ +كلمة مرور خاطئة +3763 +البداية غير متوفرة للارشيف +البداية غير مؤكدة للارشيف + + + +ميزة غير مدعومة +3800 +أدخل كلمة المرور +أدخل كلمة المرور: +إعادة كلمة المرور : +&إظهار كلمة المرور +كلمتا المرور غير متطابقتان +أستخدم فقط حروف إنجليزية و أرقام و علامات خاصة (!,#,,$ ...) لكلمة المرور +كلمة المرور طويلة جدا +كلمة المرور +3900 +الزمن المنقضي: +الزمن المتبقي: +الحجم الكلي: +السرعة: +المعالج: +نسبة الضغط: +الأخطاء: +ملفات الإرشيف: +4000 +إضافة للإرشيف +&الإرشيف: +&حالة التحديث: +صيغة الإرشيف: +مستوى الضغط&: +طريقة الضغط: +&حجم المعجم: +&حجم الكلمة: +حجم الكتلة الخاصة : +CPU عدد مؤشرات الـ : +&أوامر إضافية: +الخيارات +إنشاء إرشيف ذاتي الإستخراج +ضغط الملفات المشاركة +التشفير +طريقة التشفير : +تشفير أسماء ال&ملفات +إستهلاك الذاكرة للضغط : +إستهلاك الذاكرة لإلغاء الضغط : +حذف الملفات بعد الضغط +4040 +خزن الاتباطات الرمزية +خزن الارتباطات الصعبة +خزن جداول البيانات البديلة +خزن ملف الامان +4050 +للخزن +ألاسرع +السريع +الطبيعي +المرتفع +ألاقصى +4060 +إضافة واستبدال الملفات +تحديث و إضافة الملفات +تجديد الملفات المتوفرة فقط +مزامنة الملفات +4070 +إستعراض +كافة الملفات +غير خالص +خالص +6000 +نسخ +نقل +نسخ إلى: +نقل إلى: +...نـسـخ... +...نـقـل... +إعادة تسمية... +تحديد مجلد الوجهة +العملية غير معتمدة +حدوث خطأ لدي إعادة تسمية الملف أو المجلد +تأكيد نسخ الملف +هل أنت متأكد من نسخ الملفات للإرشيف؟ +6100 +تأكيد الحذف للملف +تأكيد الحذف للمجلد +تأكيد الحذف للملفات +'؟ {0}'هل أنت متأكد من حذف +هل أنت متأكد من حذف المجلد '{0}' و كافة محتوياته ؟ +؟ {0} هل أنت متأكد من حذف العناصر التالية +حذف... +حدوث خطأ لدي حذف الملف أو المجلد +لا يمكن للنظام نقل ملف له مسار طويل إلى سلة المحذوفات +6300 +إنشاء مجلد +إنشاء ملف +اسم المجلد: +اسم الملف: +مجلد جديد +ملف جديد +حدوث خطأ لدي إنشاء المجلد +حدوث خطأ لدي إنشاء الملف +6400 +تعليق +&تعليق: +تحديد +عدم تحديد +إخفاء: +6600 +خصائص +محفوظات المجلدات +رسائل الفاحص +رسالة +7100 +جهاز الكمبيوتر +الشبكة +المستندات +النظام +7200 +إضافة +إستخراج +فحص +نسخ +نقل +حذف +معلومات +7300 +تقسيم الملف +&التقسيم إلى: +التقسيم لكتل أو بايتات: +تقسيم... +تأكيد التقسيم +هل تريد فعلا تقسيم الملف إلى {0} كتلة ؟ +يجب أن يكون حجم الكتلة أصغر من حجم الملف الأصلي +كتلة الحجم غير صحيحة +حجم الكتلة المعين : {0} بايت\nهل تريد فعلا تقسيم الأرشيف إلى مثل هذه الكتل ؟ +7400 +دمج الملفات +&دمج إلى: +دمج... +حدد فقط الجزء الأول من ملف التقسيم +لا يمكن إكتشاف الملف كجزء من ملف التقسيم +لا يمكن العثور على أكثر من جزء واحد من ملف التقسيم +7500 +...يتم حساب مجموعة الإختبار +معلومات مجموعة الإختبار +للبيانات CRC مجموعة الإختبار: +للبيانات و للأسماء CRC مجموعة الإختبار: +7600 +تقييم الأداء +إستخدام الذاكرة: +ضغط +فك ضغط +المعدل +المعدل الكلي +الحالي +الناتج +CPU إستهلاك الـ +التقدير / الإستهلاك +العمليات: +7700 +الرابط +الارتباط +ربط من: +ربط الى: +7710 +نوع الربط +ربط قوي +ربط الملف الرمزي +ربط القاموس الرمزي +قاموس الربط diff --git a/Utils/7-Zip/Lang/ast.txt b/Utils/7-Zip/Lang/ast.txt new file mode 100644 index 000000000..623ac9063 --- /dev/null +++ b/Utils/7-Zip/Lang/ast.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.07 : Dinamiteru +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Asturian +Asturianu +401 +Val +Torgar + + + +&Si +&Non +&Zarrar +Axuda + +&Siguir +440 +Si a &Too +Non a T&oo +Parar +Reentamar +&De fondu +&En primer planu +&Posar +Posao +¿Tas fixu que quies paralo? +500 +F&icheru +&Remanar +&Ver +F&avoritos +&Ferramientes +A&xuda +540 +&Abrir +Abrir &Dientro +Abrir F&uera +&Ver +&Remanar +Reno&mar +&Copiar a... +&Mover a... +&Borrar +&Partir ficheru... +Com&binar ficheros... +P&ropiedaes +Come&ntariu + + +Crear carpeta +Crear ficheru +Co&lar +600 +Seleicionar &Too +Deseleicionar too +&Invertir seleición +Seleicionar... +Deseleicionar... +Seleicionar por Tipu +Deseleicionar por Tipu +700 +Miniatures &Grandes +&Miniatures Pequeñes +&Llista +&Detalles +730 +Ensín Ordenar + +&2 Paneles +&Barres de Ferramientes +Abrir Carpeta Raiz +Xubir Un Nivel +Hestorial de Carpetes... +Actualiza&r +750 +Barra Ferramientes d´Archivu +Barra Ferramientes Normal +Botones Grandes +Amosar Testu nos Botones +800 +&Añedir carpeta a Favoritos como +Marca +900 +&Opciones... +&Bancu de Pruebes +960 +&Conteníos... +&Al rodiu 7-Zip... +1003 +Ruta +Nome +Estensión +Carpeta +Tamañu +Tamañu comprimío +Atributos +Creao +Accedío +Cambiao +Sólidu +Comentao +Cifrao +Partir antes +Partir dempués +Diccionariu +CRC +Tipu +Anti +Métodu +S.O. d´Acoyida +Sistema de ficheros +Usuariu +Grupu +Bloque +Comentariu +Posición + + + + + + + + + + + + + + + + + + + + + + + + + +Error +Tamañu total +Espaciu llibre +Tamañu del clúster +Etiqueta +Nome llocal +Suministrador +2100 +Opciones +Llingua +Llingua: +Remanaor +&Remanaor: + +2200 +Sistema +Asociar 7-Zip con: +2301 +Integrar 7-Zip nel menú contestual +Menú contestual en ´cascada´ +Artículos del menú contestual: +2320 + + +Abrir archivu +Estrayer ficheros... +Añedir al archivu... +Probar archivu +Estrayer equí +Estrayer a {0} +Añedir a {0} +Comprimir y mandar per correu... +Comprimir en {0} y mandar per correu +2400 +Carpetes +&Carpeta de trabayu +Carpeta &temporal de sistema +&Actual +&Especificar: +Usar sólo pa dispositivos estrayibles +Especificar llocalización pa ficheros d´archivos temporales. +2500 +Igües +Amosar ".." artículu +Amosar les miniatures reales del ficheru +Amosar menú del sistema +Seleicionar tola &fila +Amosar les llinies de la &cuadrícula + + + +2900 +Al rodiu 7-Zip +7-Zip ye software llibre. De toos moos, tú pues sofitar el desendolcu de 7-Zip rexistrándote. +3000 + +Ensín errores +{0} oxetu(os) seleicionaos +Nun se puede crear la carpeta '{0}' +Esti archivu nun permite les operaciones d´actualización. + + + + +El ficheru '{0}' foi modificáu.\nDo ¿Quies actualizalu nel archivu? +Nun se pudo actualizar l´archivu\n'{0}' +Nun se pudo entamar el Remanaor. + + + + +Demasiaos artículos +3300 +Estrayendo +Comprimiendo +Probando +Abriendo... + +3400 +Estrayer +E&strayer a: +Especificar llocalización pa ficheros estrayíos. +3410 +Mou de ruta +Nomes de ruta completos +Ensín nomes de ruta +3420 +Mou de sobreescritura +Entrugar enantes de sobreescribir +Sobreescribir ensín confirmación +Dexar ficheros esistentes +Auto renomar +Auto renomar ficheros esistentes +3500 +Confirmar sustitución de ficheros +La carpeta destín yá tien el ficheru procesáu. +¿Quiés sustituyir el ficheru esistente +con esti otru? +{0} bytes +A&uto Renomar +3700 +Métodu de compresión nun permitíu pa '{0}'. +Error de datos en '{0}'. El ficheru ta rotu. +El CRC falló en '{0}'. El ficheru ta rotu. + + +3800 +Introduz clave +Introduz clave: + +Amo&sar clave + + + +Clave +3900 +Tiempu trescurríu: +Tiempu pa finar: +Tamañu: +Velocidá: + + +Errores: + +4000 +Añedir al archivu +&Archivu: +Mo&u d´actualización: +&Formatu del archivu: +Nive&l de compresión: +&Métodu de compresión: +Tamañu del &Diccionariu: +Tamañu de la pa&llabra: + + +&Parámetros: +Opciones +Crear archivu SF&X + + + +Cifrar &nomes de ficheru +Usu de memoria pa la compresión: +Usu de memoria pa la descompresión: +4050 +Nenguna +Más rápida +Rápida +Normal +Másima +Ultra +4060 +Añedir y sustituyir ficheros +Actualizar y añedir ficheros +Actualizar ficheros esistentes +Sincronizar ficheros +4070 +Agüeyar +Tolos ficheros + + +6000 +Copiar +Mover +Copiar a: +Mover a: +Copiando... +Moviendo... +Renomando... + +La operación nun tá permitía. +Error al renomar el ficheru o carpeta + + +6100 +Confirmar Borráu de Ficheru +Confirmar Borráu de Carpeta +Confirmar Borráu Múltiple de Ficheros +¿Tas fixu que quies borrar '{0}'? +¿Tas fixu que quies borrar la carpeta '{0}' y tolos sos conteníos? +¿Tas fixu que quies borrar estos {0} artículos? +Borrando... +Error al borrar el ficheru o carpeta + +6300 +Crear Carpeta +Crear ficheru +Nome de la carpeta: +Nome del ficheru: +Nueva carpeta +Nuevu ficheru +Error al crear la carpeta +Error al crear el ficheru +6400 +Comentariu +&Comentariu: +Seleicionar +Deseleicionar +Mazcarita: +6600 + +Hestorial de carpetes +Mensaxes de diagnósticu +Mensax +7100 +Ordenador +Rede de Trabayu + +Sistema +7200 +Añedir +Estrayer +Probar +Copiar +Mover +Borrar +Información +7300 +Partir Ficheru +&Partir a: +Partir en &cachos, bytes: +Partiendo... + + + + + +7400 +Combinar Ficheros +&Combinar a: +Combinando... + + + +7500 + + + + +7600 +Bancu de Pruebes +Usu de memoria: +Comprimiendo +Descomprimiendo +Valoración +Valoración total +Actual +Resultáu + + +Correutos: diff --git a/Utils/7-Zip/Lang/az.txt b/Utils/7-Zip/Lang/az.txt new file mode 100644 index 000000000..712b82833 --- /dev/null +++ b/Utils/7-Zip/Lang/az.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 9.07 : F@rhad +; 15.02 : 22/05/2015 : Г. Гасымов +; +; +; +; +; +; +; +; +; +0 +7-Zip +Azerbaijani +Azərbaycanca +401 +OLDU +İmtina + + + +&Bəli +&Xeyr +&Bağla +Kömək + +&Davam +440 +&Hamısına Bəli +Ha&mısına Xeyr +Dayan +Yenidən başla +&Arxa planda +Ö&ndə +F&asilə +Fasilədə +Həqiqətən əməliyyatı dayandırmaq istəyirsiniz? +500 +&Fayl +&Düzəliş +&Görünüş +S&eçilmişlər +&Vasitələr +&Arayış +540 +&Aç +&Daxildə Aç +B&ayırda aç +&Baxış +&Düzəliş +Ye&nidən Adlandır +&Nüsxələ... +&Köçür... +&Sil +Faylı &Böl... +Faylları B&irləşdir... +X&üsusiyyətlər +Şər&h... +Yoxlama Cəmi +Müqayisə +Qovluq Yarat +Fayl Yarat +Ç&ıxış +İstinad +&Əvəzedici Axınlar +600 +&Hamısını Seç +Seçimi Ləğv Et +&Seçimi Çevir +Seç... +Seçimi Ləğv Et... +Növünə Görə Seç +Növünə Görə Seçimi Ləğv Et +700 +&Böyük İşarələr +K&içik İşarələr +&Siyahı +&Cədvəl +730 +Çeşidsiz +Müstəvi Görünüş +&2 Lövhə +&Alətlər Lövhələri +Kök Qovluğu Aç +Bir Səviyyə Yuxarı +Qovluqlar Tarixçəsi... +&Yenilə +Bilavasitə Yeniləmə +750 +Arxivləyicinin Düymələr Lövhəsi +Sadə Düymələr Lövhəsi +Böyük Düymələr +Düymələr Üzərində Mətnlər +800 +&Qovluğu Seçilmişlərə Fərqli Əlavə Et +Əlfəcin +900 +Tənzimləmələr... +Səmərə Sınağı +960 +&Başlıq... +7-Zip &Haqqında... +1003 +İstiqamət +Ad +Genişləmə +Qovluq +Ölçü +Sıxılmış +Rəmzlər +Yaranıb +Açıq +Dəyişilib +Aramsız +Şərh +Şifrələnib +Əvvəlki parça +Sonrakı parça +Lüğət + +Növ +Əleyhinə +Sıxılma Üsulu +Quruluş +Fayl Quruluşu +İstifadəçi +Dəstə +Bölmə +Şərh +Mövqe +İstiqamət +Qovluq +Fayl +Buraxılış +Cild +Çox Cildli +Uzlaşma +İstinad +Bölmə +Cild + + + +Prosessor +Fiziki Ölçü +Başlıqlar Ölçüsü +Yoxlama Cəmi +Xassələr +Xəyali Ünvan + +Qısa Ad +Yaradıcı +Sahə Ölçüsü +Vəziyyət +Rəmzi İstinad +Xəta +Cəmi Həcm +Azad Həcm +Toplam Həcm +Nişan +Qısa Ad +Təchizatcı +NT Təhlükəsizlik +Əvəzedici Axın + +Silinmiş +Ağac + + +Xəta Növü +Xətalar +Xətalar +Xəbərdarlıqlar +Xəbərdarlıq +Axınlar +Əvəzedici Axınlar +Əvəzedici Axınlar Ölçüsü +Xəyali Ölçü +Ceşidli Ölçü +Ümumi Fiziki Ölçü +Cild Nömrəsi +Növaltı +Qısa Şərh +Şifrələnmiş Səhifə + + + +Qalıq Ölçüsü +Tətbiq Olunmuş Bölmə Ölçüsü +İstinad +Sərt İstinad +iNode + +Yalnız Oxumaq Üçün +2100 +Tənzimləmələr +Dil +Dil: +Düzəliş +&Düzəliş: +&Müqayisə: +2200 +Quruluş +7-Zip Fayllarla Əlaqələnsin +Bütün İstifadəçilər +2301 +7-Zip əhatə təklifinə tətbiq edilsin +Zəncirvari əhatə təklifi +Ünsürlü əhatə təklifi: +Əhatə təklifində nişanlar +2320 + +<Аrxiv> +Arxivi Aç +Çeşidlə +Arxivə Əlavə Et... +Sınaq +Burda Çeşidlə +{0} Çeşidlə +{0} Əlavə Et +Sıx Və E-Poçtla Göndər... +{0} Sıx Və E-Poçtla Göndər +2400 +Qovluqlar +&İş Qovluğu +&Müvəqqəti Quruluş Qovluğu +&Cari +&Təyin Et: +Yalnız dəyişkən daşıyıcılar üçün istifadə +Müvəqqəti arxivlər üçün yer göstər. +2500 +Tənzimləmələr +".." ünsürünü göstər +Həqiqi fayl işarələri göstər +Quruluş təklifini göstər +Ox bütün sətir üzrə +Ayrıcıları Göstər +Bir Toxunuşla Aç +Əvəzedici vəziyyət işarələnməsi +Böyük yaddaş səhifələri istifadəsi +2900 +7-Zip Haqqında +7-Zip Sərbəst Yayılan Proqramdır +3000 +Kifayət qədər boş yaddaş yoxdur +Səhvlər tapılmadı +{0} Ayrılmış hədəf +'{0}' Qovluğunu yaratmaq mümkün olmadı +Bu arxiv üçün dəyişiklik əməliyatı dəstəklənmir +'{0}' Faylını arxiv kimi açmaq alınmadı +Şifrələnmiş '{0}' arxivini açmaq alınmadı. Yanlış şifrə? +Dəstəklənməyən arxiv +{0} faylı artıq mövcuddur +'{0}' faylına dəyişiklik edildi.\nSiz onu arxivdə yeniləmək istəyirsiz? +\n'{0}' faylını yeniləmək alınmadı +Redaktəni işə salmaq alınmadı +Fayl zərərvericiyə oxşayır (faylın adı uzun boşluq ardıcıllığı təşkil edir). +Əməliyyat uzun yol təşkil edən qovluqdan icra oluna bilmir. +Siz bir fayl seçməlisiniz +Siz bir və ya bir neçə fayl seçməlisiniz +Həddən çox ünsür +Faylı, '{0}' arxivi kimi açmaq alınmadı +Fayl, {0} arxivi kimi açıldı +Arxiv əvəzlənərək açıldı +3300 +Çeşidlənmə +Sıxılma +Sınaq +Açılma... +Yoxlama... +Silinmə +3320 +Əlavə Etmək +Yenilənmə +Təhlil +Nüsxələnmə +Yenidən Çeşidlənmə +Keçmə İcazəsi +Silinmə +Başlıqlar Yaradılması +3400 +Ayır +Ç&eçidlə: +Ayrılan faylların yerini göstərin. +3410 +Fayllara istiqamət: +Tam istiqamətlər +İstiqamətsiz +Mütləq istiqamətlər +Nisbi istiqamətlər +3420 +Yenidən yazılma: +Təsdiqli +Təsdiqsiz +Ötürmək +Birbaşa yenidən adlandır +Mövcud olanları yenidən adlandır +3430 +Kök qovluqla bənzərliyi aradan qaldır +Faylın təhlükəsizlik bərpası +3500 +Faylın əvəzlənmə təsdiqi +Qovluq artıq emal olunan fayl təşkil edir. +Mövcud faylı əvəzlə +növbəti faylla? +{0} bayt +Birbaşa yenidən adlandır +3700 +'{0}' faylının dəstəklənməyən sıxılma üsulu. +'{0}' məlumatlarında xəta. Fayl korlanıb. +'{0}' CRC xətası. Fayl korlanıb. +'{0}' şifrəli fayl məlumatlarında xəta. Yanlış şifrə? +'{0}' şifrəli faylı üçün CRC xətası. Yanlış şifrə? +3710 +Yanlış şifrə? +3721 +Dəstəklənməyən sıxılma üsulu +Dəlillərdə xəta +CRC xətası +Mövcud olmayan dəlillər +Dəlillərin gözlənilməz sonu +Bölmənin sonunda faydalı dəlillər olduğuna dəlillər var +Arxiv deyil +Başlıqlarda Xəta +Yanlış şifrə +3763 +Arxivin əvvəli mövcud deyil +Təsdiqsiz arxiv əvvəli + + + +Dəstəklənməyən xüsusiyyət +3800 +Şifrə daxil etmə +&Şifrə daxil edin: +Şifrəni təkrarlayın: +&Şifrəni göstər +Şifrələr uyğun deyil +Şifrə üçün yalnız latın hərfləri, rəqəmlər və xüsusi rəmzlər istifadə edin (!, #, $, ...) +Şifrə şox uzundur +&Şifrə +3900 +Keçdi: +Qalıb: +Cəmi: +Sürət: +Ölçü: +Sıxılma dərəcəsi: +Xəta: +Arxiv: +4000 +Arxivə əlavə etmək +&Arxiv: +&Dəyişmə vəziyyəti: +Arxiv &qismi: +Sıxılma &dərəcəsi: +Sıxılma &üsulu: +&Lüğət ölçüsü: +&Söz ölçüsü: +Bölmə ölçüsü: +Axın sayı: +&Nizamlar: +&Seçimlər +SF&X arxiv yarat +Yazılış üçün açıq faylları sıx +Şifrələmə +Şifrələmə üsulu: +Fayl adlarını &şifrələ +Qablaşdırma üçün yaddaş həcmi: +Çeşidləmə üçün yaddaş həcmi: +Sıxılmadan sonra faylları sil +4040 +Rəmzli keçidləri saxla +Sərt keçidləri saxla +Əvəzedici axınları saxla +Giriş hüququnu saxla +4050 +Sıxılmasız +Sürətli +Cəld +Məqbul +Yüksək +Daha Yüksək (Ultra) +4060 +Əlavə et və əvəzlə +Yenilə və əlavə et +Yenilə +Eyniləşdir (Sinxron) +4070 +Vərəqlə +Bütün Fayllar +Fayl ölçüsünə görə +Aramsız +6000 +Nüsxələ +Köçür +Nüsxələ: +Köçür: +Nüsxələlənmə... +Köçürülmə... +Yenidən adlandırılma... +Qovluğu göstərin. +Əməliyyat bu qovluq üçün dəstəklənmir. +Fayl və ya Qovluğun Yenidən Adlandırılması Zamanı Xəta +Faylların Nüsxələlənmə Təsdiqi +Siz həqiqətən bu faylları arxivə nüsxələmək istəyirsiz +6100 +Fayl silinmə təsdiqi +Qovluq silinmə təsdiqi +Fayllar dəstəsinin silinmə təsdiqi +Siz həqiqətən "{0}" silmək istəyirsiz? +Siz həqiqətən "{0}" qovluğunu və onun bütün məzmununu silmək istəyirsiz? +Siz həqiqətən {0} hədəfi silmək istəyirsiz? +Silinmə... +Fayl və ya Qovluq Silinməsi Zamanı Xəta +Quruluş uzun yollu faylların səbətə silinməsi əməliyyatını dəstəkləmir +6300 +Qovluq Yarat +Fayl Yarat +Qovluq Adı: +Fayl Adı: +Yeni Qovluq +Yeni Fayl +Qovluq Yaradılması Zamanı Zəta +Fayl Yaradılması Zamanı Zəta +6400 +Şərh +&Şərh: +Seçin +Seçimi Ləğv Edin +Üzlük (Maska): +6600 +Xassələr +Qovluqlar Tarixçəsi +İsmarıclar +İsmarıc +7100 +Kompüter +Şəbəkə +Sənədlər +Quruluş +7200 +Əlavə Et +Ayır +Sınaq +Nüsxələ +Köçür +Sil +Məlumat +7300 +Fayl Bölmək +&Bölmək: +Cildlərə &bölmək, (bayt) ölçüdə: +Bölünmə... +Bölünmə Təsdiqi +Siz həqiqətən faylı {0} hissəyə bölmək istəyirsiz? +Cild ölçüsü ilkin fayl ölçüsündən kiçik olmalıdır +Cildlərin ölçü təyin etmə sahəsində xəta +Təyin edilmiş cild ölçüsü: {0} bayt.\nSiz həqiqətən arxivi belə cildlərə bölmək istəyirsiniz? +7400 +Faylları Birləşdir +&Birləşdirmək: +Birləşmə... +Bölünmüş faylın yalnız birinci hissəsini seçmək lazımdır +Bölünmüş faylın tanınması mümkün olmadı +Bölünmüş faylın birdən çox hissəsini tapmaq mümkün olmadı +7500 +Yoxlanma cəminin hesablanması... +Yoxlanma cəmi +Dəlillər üçün CRC yoxlanma cəmi: +Dəlillər və adlar üçün CRC yoxlanma cəmi: +7600 +Səmərə Sinağı +Yaddaş Həcmi: +Qablaşdırma +Çeşidlənmə +Dərəcə +Ümumi Dərəcə +Cari +Nəticə +Yüklənmə +Yüklənmə Dərəcəsi +Keçid: +7700 +İstinad +Əlaqələndir +Mənbə: +Məqsəd: +7710 +İstinad Qismi +Sərt İstinad +Rəmzi İstinad (Fayl) +Rəmzi İstinad (Qovluq) +Bağlantı Nöqtəsi (Qovşaq) diff --git a/Utils/7-Zip/Lang/ba.txt b/Utils/7-Zip/Lang/ba.txt new file mode 100644 index 000000000..947d4a808 --- /dev/null +++ b/Utils/7-Zip/Lang/ba.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.20 : Haqmar : www.bashqort.com +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Bashkir +Башҡортса +401 +Тамам +Кире ал + + + +&Эйе +&Юҡ +&Яп +Ярҙам + +&Дауам +440 +Бөтәһенә лә Э&йе +Бө&тәһенә лә Юҡ +Туҡта +Яңынан башла +&Артҡы планда +А&лғы планда +&Туҡтатып тор +Паузала +Был эште ысынлап та өҙөргә теләйһегеҙме? +500 +&Файл +Һа&йлау +&Күренеш +Һ&айланмалар +&Сервис +&Белешмә +540 +&Асырға +&Эсендә асырға +&Тышта асырға +Ҡа&рау +&Мөхәррирләргә +&Исемен алыштырырға +&Күбәйтергә... +Кү&серергә... +&Юйырға +Файлды &бүл... +Файлдар бер&ләштереү... +Мәғ&лүмәт +Тас&уирлама +Тикшереү һаны +Diff +Яңы папка... +Яңы &файл... +С&ығырға +600 +&Бөтәһен дә һайларға +Һай&лауҙы кире алырға +Бил&дәләнгәндәрҙе кире әйләндерергә +Маска менән һайларға... +Һайлауҙы ябырға... +Төр буйынса һайларға +Төр буйынса һайлауҙы ябырға +700 +&Эре тамғалар +&Бәләкәй тамғалар +&Исемлек +&Ентекле +730 +Тәртип булмаһын +Барыһын да күрһәт +&2 Панель +&Ҡоралдар панеле +Төп папканы ас +Бер кимәл юғары +Папкалар тарихы... +&Яңырт +750 +&Архивлау төймәләре +Стандарт төймәләр +Эре төймәләр +Төймәләр аңлатмалы +800 +Ғәмәлдәге папканы һайланғандарға өҫтәргә: +Урын +900 +&Көйләү... +&Етештереүсәнлекте үлсәү +960 +&Эстәлек... +7-Zip &тураhында... +1003 +Юл +Исем +Киңәйеүе +Папка +Күләм +Архивдағы күләме +Атрибуттар +Яһалған +Асылған +Үҙгәртелгән +Өҙөлмәгән +Аңлатма +Серләнгән +Алдағы киҫәк +Киләһе киҫәк +Һүҙлек +CRC +Төр +Анти +Ысул +Система +Файл системаһы +Ҡулланыусы +Tөркөм +Блок +Тасуирлама +Урын +Юл префиксы +Папкалар +Файлдар +Версия +Том +Күп томлы +Шылыу +Һылтанмалар +Блоктар +Томдар + +64-bit +Big-endian +Процессор +Физик күләме +Башлыҡтар күләме +Тикшереү суммаһы +Характеристикалар +Виртуаль адрес +ID +Ҡыҫҡа исем +Яһаусы +Сектор күләме +Режим +Һылтанма +Хата +Бар күләм +Буш урын +Кластер күләме +Билдә +Урындағы Исем +Провайдер +2100 +Көйләүҙәр +Тел һайлау +Тел: +Мөхәррирләүсе +&Мөхәррирләүсе: +&Diff: +2200 +Система +7-Zip менән килештер: +2301 +Контекст менюла 7-Zip-ты күрһәтергә +Каскадлы контекст меню +Контекст меню элементтары: +2320 +<Папка> +<Архив> +Архивты асырға +Файлдар сығарыу... +Архивғ өҫтәргә... +Архивты һынарға +Бында сығарырға +{0} папкаһына сығарырға +{0} итеп архивла +Архивлап, e-mail менән ебәрергә... +{0} итеп архивларға һәм e-mail менән ебәрергә +2400 +Папкалар +&Эш папкаһы +&Ваҡытлыса система папкаһы +&Ағымдағы +&Билдәләргә: +Алмаш ташығыстар өсөн генә ҡулланырға +Ваҡытлыса архивтар өсөн урын күрһәтегеҙ. +2500 +Көйләүҙәр +".." элементы күренһен +Файлдарҙың ысын тамғалары күренһен +Система менюһы күренһен +Бөтә юл һайланһын +Һыҙыҡтар күренһен +Бер сиртеү менән асырға +Альтернатив һайлау ысулы +Ҙур хәтер биттәрен ҡуллан +2900 +7-Zip тураhында +7-Zip – ирекле таратылған программа. +3000 +Буш хәтер етмәй +Хата табылманы +{0} объект һайланған +{0} папкаһын яһап булмай +Был архивды үҙгәртеү ғәмәлен үтәп булмай. +'{0}' файлын архив һымаҡ асып булмай +Шифрланған '{0}' файлын асып булманы. Хаталы пароль? +Терәкләнмәгән архив төрө +{0} файлы бар +'{0}' файлы мөхәррирләнде.\nБыл файл архивда яңыртылһынмы? +Файлды яңыртып булманы\n'{0}' +Мөхәррирләүсене асып булманы. +Файл вирусҡа оҡшаған (файл исемендә бер-бер артлы килгән күп бушлыҡтар бар). +Ғәмәлде бындай оҙон юллы папканан үтәп булмай. +Бер файлды һайлау кәрәк +Бер йәки күберәк файлды һайлау кәрәк +Бик күп элемент +3300 +Сығарыу бара... +Ҡыҫыу бара... +Һынау +Асыла... +Тарау бара... +3400 +Сығар +Бында &сығар: +Сығарыласаҡ файлдар өсөн урын һайлағыҙ. +3410 +Юл исемдәре +&Тулы юл исемдәре +Юл исемдәре булмаһын +3420 +Өҫтөнә яҙыу +&Өҫтөнә яҙыу алдынан һора +&Өҫтөнә яҙыу алдынан һорама +Булған файлдарҙы үтеп кит +Яңы исем ҡуш +Булған файлдарға яңы исем ҡуш +3500 +Файл алмаштырыуҙы раҫлағыҙ +Сығарыласаҡ папкала эшкәртелгән файл бар. +Булған +файлын киләһе менән алыштырырғамы? +{0} байт +&Яңы исем ҡушылһын +3700 +'{0}' файлын ҡыҫыу ысулын табып булманы. +'{0}' файлында мәғлүмәт хатаһы бар. Файл боҙоҡ. +'{0}' файлында CRC хатаһы бар. Файл боҙоҡ. +Шифрланған '{0}' файлы мәғлүмәттәрендә хата. Хаталы пароль? +Шифрланған '{0}' файлында CRC хатаһы. Хаталы пароль? +3800 +Пароль керетеү +&Паролде керетегеҙ: +Па&ролде яңынан керетегеҙ: +П&ароль күренһен +Паролдәр тап килмәй +Пароль өсөн тик латин хәрефтәрен, һандарҙы һәм махсус символдарҙы (!, #, $, ...) ҡулланығыҙ +Пароль бик оҙон +Пароль +3900 +Үткән ваҡыт: +Ҡалған ваҡыт: +Барыһы: +Тиҙлек: +Күләм: +Ҡыҫыу нисбәте: +Хаталар: +Архив: +4000 +Архивлау +&Архив: +&Яңыртыу ысулы: +А&рхив төрө: +Ҡыҫыу &дәрәжәһе: +Ҡ&ыҫыу ысулы: +Һүҙ&лек күләме: +Һүҙ күлә&ме: +Блоктар күләме: +Ағымдар һаны: +&Параметрҙар: +&Көйләү +SFX ар&хивын яһау +Яҙыуға асыҡ файлдарҙы ҡыҫырға +Шифрлау +Шифрлау методы: +&Файл исемдәрен шифрла +Ҡыҫҡанда хәтер ҡулланыу: +Сығарғанда хәтер ҡулланыу: +4050 +Ҡыҫыуһыҙ +Бик тиҙ +Тиҙ +Ғәҙәти +Максимум +Ультра +4060 +Өҫтәргә һәм алмаштырырға +Яңыртырға һәм өҫтәргә +Яңыртырға +Синхронларға +4070 +Ҡарау +Бар файлдар +Файл күләме буйынса +Өҙөлмәгән +6000 +Копияһын ал +Күсер +Копия ҡуйыласаҡ урын: +Күсереләсәк урын: +Копияһын алыу... +Күсереү... +Яңынан исемләү бара... +Папканы күрһәтегеҙ. +Ғәмәлде үтәп булмай +Файлға йәки папкаға яңы исем биреү хатаһы +Файлдарҙы күбәйтеүҙе раҫлау +Был файлдар архивға ҡуйылһынмы? +6100 +Файл юйыуҙы раҫлау +Папка юйыуҙы раҫлау +Берҙән күп файл юйыуҙы раҫлау +'{0}' юйылһынмы? +'{0}' папкаһы һәм эсендәгеләр юйылһынмы? +{0} есеме юйылһынмы? +Юйыу бара... +Файл йәки папка юйыу хатаһы +Оҙон юллы файлдарҙы кәрзингә юйыуҙы система терәкләмәй +6300 +Папка яhа +Файл яhа +Папка исеме: +Файл исеме: +Яңы папка +Яңы файл +Папка яһау хатаһы +Файл яһау хатаһы +6400 +Тасуирлама +&Асыҡлама: +hайла +Һайлауҙы кире ал +Маска: +6600 +Үҙенсәлектәр +Папкалар тарихы +Белдереүҙәр +Белдереү +7100 +Компьютер +Селтәр +Документтар +Система +7200 +Өҫтәргә +Сығарырға +Һынарға +Копияһын алырға +Күсерергә +Юйырға +Мәғлүмәт +7300 +Файлды бүл +&Ошо папкаға бүл: +Киҫәк/&байт итеп бүл: +Бүлеү бара... +Бүлеүҙе раҫлау +Был файлды {0} киҫәккә бүлеүҙе раҫлайһығыҙмы? +Том күләме сығанак файлдан бәләкәй булырға тейеш +Хаталы том күләме +Том күләме : {0} байт.\nФайлды бындай томдарға бүлеүҙе раҫлайһығыҙмы? +7400 +Файлдарҙы берләштер +&Ошо папкала берләштер: +Берләштереү бара... +Бүленгән файлдың беренсе киҫәген генә һайлағыҙ +Бүленгән файлды танып булманы +Бүленгән файлдың берҙән күп киҫәген табып булманы +7500 +Тикшереү һанын иҫәпләү бара... +Тикшереү һаны +Мәғлүмәттәр өсөн CRC тикшереү һаны: +Мәғлүмәттәр һәм исемдәр өсөн CRC тикшереү һаны: +7600 +Етештереүсәнлекте тикшереү +Хәтер ҡулланыу: +Ҡыҫыу +Сығарыу +Рейтинг +Дөйөм рейтинг +Хәҙерге +Һөҙөмтә +Процессор ҡулланыу +Рейтинг / Проц. ҡулл. +Үтеүҙәр: diff --git a/Utils/7-Zip/Lang/be.txt b/Utils/7-Zip/Lang/be.txt new file mode 100644 index 000000000..5a16ebdc9 --- /dev/null +++ b/Utils/7-Zip/Lang/be.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Kirill Gulyakevitch +; 9.07 : 2011-03-15 : Drive DRKA +; +; +; +; +; +; +; +; +; +0 +7-Zip +Belarusian +Беларуская +401 +OK +Адмена + + + +&Так +&Не +&Зачыніць +Дапамога + +&Працягнуць +440 +Так для &усіх +Не для ў&сіх +Стоп +Перазапуск +&Фонам +&На пярэдні план +&Паўза +На паўзе +Вы сапраўды жадаеце перапыніць аперацыю? +500 +&Файл +&Праўка +&Выгляд +&Абранае +С&ервіс +&Даведка +540 +&Адкрыць +Адкрыць &усярэдзіне +Адкрыць з&вонку +Прагляд +&Рэдагаваць +Пера&назваць +&Капіяваць у... +&Перамясціць у... +&Выдаліць +Ра&збіць файл... +А&б'яднаць файлы... +Сво&йства +Коме&нтар +Кантрольная сума +Diff +&Стварыць папку +Ств&арыць Файл +В&ыхад +600 +Вылучыць у&сё +Прыбраць вылучэнне +&Звярнуць в&ыдзяленне +Вылучыць... +Прыбраць вылучэнне... +Вылучыць па тыпе +Прыбраць вылучэнне па тыпе +700 +&Буйныя значкі +&Дробныя значкі +Спі&с +&Табліца +730 +Без сартавання +Плоскі рэжым +&2 Панэлі +&Панэлі прылад +Адкрыць каранёвую папку +Пераход на адзін узровень уверх +Гісторыя папак... +А&бнавіць +750 +Панэль кнопак архіватара +Стандартная панэль кнопак +Вялікія кнопкі +Надпісы на кнопках +800 +Дадаць папку ў &абранае як +Закладка +900 +Налады... +Тэставанне прадукцыйнасці +960 +&Змест... +Аб &праграме... +1003 +Шлях +Імя +Пашырэнне +Папка +Памер +Сціснуты +Атрыбуты +Створаны +Адчынены +Зменены +Бесперапынны +Каментар +Зашыфраваны +Пабіты Да +Пабіты Пасля +Слоўнік +CRC +Тып +Анты +Метад +Сістэма +Файлавая Сістэма +Карыстальнік +Група +Блок +Каментар +Пазіцыя +Шлях +Папак +Файлаў +Версія +Тым +Шматтомны +Зрушэнне +Спасылак +Блокаў +Тамоў + +64-bit +Big-endian +Працэсар +Фізічны Памер +Памер Загалоўкаў +Кантрольная Сума +Характарыстыкі +Віртуальны Адрас +ID +Кароткае Iмя +Создатель +Памер Сектара +Рэжiм +Ссылка +Памылка +Ёмістасць +Вольна +Памер кластара +Пазнака +Лакальнае імя +Правайдэр +2100 +Налады +Мова +Мова: +Рэдактар +&Рэдактар: +&Diff: +2200 +Сістэма +Асацыяваць 7-Zip з файламі: +2301 +Убудаваць 7-Zip у кантэкстнае меню абалонкі +Каскаднае кантэкстнае меню +Элементы кантэкстнага меню: +2320 +<Папка> +<Архіў> +Адкрыць архіў +Распакаваць +Дадаць да архіва... +Тэставаць +Распакаваць тут +Распакаваць у {0} +Дадаць да {0} +Сціснуць і адправіць па email... +Сціснуць у {0} і адправіць па email +2400 +Папкі +&Працоўная Папка +&Сістэмная часавая Папка +&Бягучая +&Задаць: +Выкарыстаць толькі для зменных носьбітаў +Пакажыце становішча для часавых архіваў. +2500 +Налады +Паказваць элемент ".." +Паказваць рэальныя абразкі файлаў +Паказваць сістэмнае меню +Курсор на ўвесь радок +Паказваць падзельнікі +Адчыняць элемент адным клiкам +Альтэрнатыўны рэжым пазнакі +Выкарыстаць вялікія старонкі памяці +2900 +Аб праграме 7-Zip +7-Zip з'яўляецца вольна распаўсюджваемай праграмай. Аднак калі вы жадаеце падтрымаць распрацоўку 7-Zip, вы можаце зарэгістраваць праграму.Праграма перакладена Drive DRKA.Мая электронная скрыня: drka2003@mail.ru.Пераклад зроблен у верасні 2007 года. +3000 +Нядосыць вольнай памяці +Памылак не знойдзена +Вылучана аб'ектаў: {0} +Не атрымалася стварыць папку '{0}' +Аперацыі змены не падтрымліваюцца для гэтага архіва. +Не атрымалася адкрыць файл '{0}' як архіў +Не атрымалася адкрыць зашыфраваны архіў '{0}'. Няслушны пароль? +Непадтрымоўваны тып архіва +Файл {0} ужо існуе +Файл '{0}' быў зменены.\nВы жадаеце абнавіць яго ў архіве? +Не атрымалася абнавіць файл\n'{0}' +Не атрымалася запусціць рэдактар +Файл падобны на вірус (імя файла ўтрымоўвае доўгую паслядоўнасць прабелаў). +Аперацыя не можа быць выкананая з папкі, якая мае доўгі шлях. +Вы павінны вылучыць адзін файл +Вы павінны вылучыць адзін або некалькі файлаў +Занадта шмат элементаў +3300 +Распакаванне +Кампрэсія +Тэставанне +Адкрыццё... +Сканаванне... +3400 +Выняць +&Распакаваць у: +Пакажыце становішча для вымаемых файлаў. +3410 +Шляхі +По&ўные шляхі +&Без шляхоў +3420 +Перазапіс +&З пацверджаннем +Бы&ез пацверджанні +Прап&ускаць +Пераназваць аўтам. +Переім. аўтам. істот. +3500 +Пацверджанне замены файла +Папка ўжо ўтрымоўвае апрацоўваемы файл. +Замяніць наяўны файл +наступным файлам? +{0} байтаў +Пераназваць аўтам. +3700 +Непадтрымоўваны метад сціску для файла '{0}'. +Памылка ў дадзеных у '{0}'. Файл сапсаваны. +Памылка CRC у '{0}'. Файл сапсаваны. +Памылка ў дадзеных зашыфраванага файла '{0}'. Няслушны пароль? +Памылка CRC для зашыфраванага файла '{0}'. Няслушны пароль? +3800 +Увод пароля +&Увядзіце пароль: +&Паўтарыце пароль: +&Паказаць пароль +Паралі не супадаюць +Для пароля выкарыстайце толькі знакі лацінскага алфавіту, лічбы і адмысловыя знакі (!, #, $, ...) +Пароль занадта доўгі +&Пароль +3900 +Мінула: +Засталося: +Усяго: +Хуткасць: +Памер: +Ступень сціску: +Памылак: +Архіваў: +4000 +Дадаць да архіва +&Архіў: +&Рэжым змены: +&Фармат архіва: +&Узровень сціску: +&Метад сціску: +Памер &слоўніка: +Памер з&лоўлі: +Памер блока: +Лік струменяў: +&Параметры: +&Опцыі +Стварыць SF&X-архіў +Сціскаць адчыненыя для запісу файлы +Шыфраванне +Метад шыфравання: +&Шыфраваць імёны файлаў +Аб'ём памяці для пакавання: +Аб'ём памяці для распакавання: +4050 +Без сціску +Хуткасны +Хуткі +Нармалёвы +Максімальны +Ультра +4060 +Дадаць і замяніць +Абнавіць і дадаць +Абнавіць +Сінхранізаваць +4070 +Прагартаць +Усе файлы +Па памеры файла +Бесперапынны +6000 +Капіяваць +Перамясціць +Капіяваць у: +Перамясціць у: +Капіяванне... +Перамяшчэнне... +Пераназванне... +Пакажыце папку. +Аперацыя не падтрымліваецца для гэтай папкі. +Памылка пры пераназванні файла або папкі +Пацверджанне капіявання файлаў +Вы сапраўды жадаеце скапіяваць гэтыя файлы ў архіў +6100 +Пацверджанне выдалення файла +Пацверджанне выдалення папкі +Пацверджанне выдалення групы файлаў +Вы сапраўды жадаеце выдаліць "{0}"? +Вы сапраўды жадаеце выдаліць папку "{0}" і ўсё яе змесціва? +Вы сапраўды жадаеце выдаліць гэтыя аб'екты ({0} шт.)? +Выдаленне... +Памылка пры выдаленні файла або папкі +Сістэма не падтрымлівае аперацыю выдалення файлаў з доўгімі шляхамі ў кошык +6300 +Стварыць папку +Стварыць файл +Імя папкі: +Імя файла: +Новая Папка +Новы файл +Памылка пры стварэнні папкі +Памылка пры стварэнні файла +6400 +Каментар +&Каментар: +Вылучыць +Прыбраць вылучэнне +Маска: +6600 +Уласцівасці +Гісторыя папак +Паведамленні +Паведамленне +7100 +Кампутар +Сетка +Дакументы +Сістэма +7200 +Дадаць +Выняць +Тэставаць +Капіяваць +Перамясціць +Выдаліць +Інфармацыя +7300 +Разбіць файл +&Разбіць у: +Разбіць на &тамы памерам (у байтах): +Разбіццё... +Пацверджанне разбіцця +Вы сапраўды жадаеце разбіць файл на {0} частак? +Памер тома павінен быць менш памеру зыходнага файла +Памылка ў поле для задання памеру тамоў +Усталяваны памер тома: {0} байтаў.\nВы сапраўды жадаеце разбіць архіў на такія тамы? +7400 +Аб'яднаць файлы +&Аб'яднаць у: +Аб'яднанне... +Неабходна вылучыць толькі першую частку пабітага файла +Не атрымалася распазнаць пабіты файл +Не атрымалася знайсці больш адной часткі пабітага файла +7500 +Вылічэнне кантрольнай сумы... +Кантрольная сума +Кантрольная сума CRC для дадзеных: +Кантрольная сума CRC для дадзеных і імёнаў: +7600 +Тэставанне прадукцыйнасці +Аб'ём памяці: +Пакаванне +Распакаванне +Рэйтынг +Агульны рэйтынг +Бягучы +Выніковы +Нагрузка +Рэйтынг / Нагр. +Праходаў: diff --git a/Utils/7-Zip/Lang/bg.txt b/Utils/7-Zip/Lang/bg.txt new file mode 100644 index 000000000..4346f1660 --- /dev/null +++ b/Utils/7-Zip/Lang/bg.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : chavv +; : icobgr +; 4.65 : Vassia Atanassova +; +; +; +; +; +; +; +; +0 +7-Zip +Bulgarian +Български +401 +OK +Отказ + + + +&Да +&Не +&Затваряне +Помощ + +Пр&одължаване +440 +Да за &всички +Не за &всички +Стоп +От начало +&Фонов режим +&Нормален режим +&Пауза +В пауза +Наистина ли желаете да прекратите? +500 +&Файл +&Редактиране +&Показване +&Любими +&Инструменти +&Помощ +540 +&Отваряне +Отваряне &в +Отваряне &извън +&Показване +&Редактиране +Преи&менуване +&Копиране в... +Пре&местване в... +Из&триване +Р&азделяне на файл... +О&бединяване на файлове... +&Свойства +Ком&ентар +Изчисляване на контролна сума + +Създаване на директория +Създаване на файл +Из&ход +600 +&Маркиране на всички +&Размаркиране на всички +&Обръщане на избора +Маркиране... +Размаркиране... +Маркиране по тип +Размаркиране по тип +700 +&Големи икони +&Малки икони +&Списък +&Детайли +730 +Несортиран +Плосък изглед +&2 панела +&Ленти с инструменти +Отваряне на главната директория +Едно ниво нагоре +История на директориите... +&Опресняване +750 +Лента на архива +Стандартна лента +Големи бутони +Показване на текст под бутоните +800 +&Добавяне на директорията като любима: +Отметка +900 +&Настройки... +&Статистика +960 +&Съдържание... +&За 7-zip... +1003 +Път +Име +Разширение +Директория +Размер +Компресиран размер +Атрибути +Създаден +Отварян +Изменен +Солиден +Коментар +Зашифрован +Разделен до +Разделен след +Речник +CRC +Тип +Анти +Метод +Операционна система +Файлова система +Потребител +Група +Блок +Коментар +Позиция +Префикс на пътя +Директории +Файлове +Версия +Том +Multivolume +Offset +Links +Blocks +Томове + +64-битов +Big-endian +CPU +Физически размер +Размер на заглавната част +Контролна сума +Характеристики +Виртуален адрес + + + + + + +Грешка +Пълен размер +Свободно пространство +Размер на клъстер +Етикет +Локално име +Доставчик +2100 +Настройки +Език +Език: +Редактор +&Редактор: + +2200 +Система +Асоцииране на 7-Zip с: +2301 +Интегриране на 7-Zip в контекстното меню на шела +Каскадно контекстно меню +Елементи на контекстното меню: +2320 +<Директория> +<Архив> +Отваряне на архив +Разархивиране на файловете... +Добавяне към архив... +Проверка на архива +Разархивиране тук +Разархивиране в {0} +Добавяне в {0} +Архивиране и изпращане... +Архивиране в {0} и изпращане +2400 +Директории +&Работна директория +&Системната TEMP директория +&Текущата +&Друга: +Използване само за преносими носители +Указване на място за временните архиви. +2500 +Настройки +Показване на обекта ".." +Показване на истинските икони на файловете +Показване на системното меню +&Избор на цял ред +Показване на помощни &линии + +&Алтернативен режим на избор +Използване на &големи страници от паметта +2900 +Информация +7-Zip се разпространява като свободен софтуер. Все пак, можете да подпомогнете разработката на 7-zip, като се регистрирате. +3000 +Системата не може да задели необходимото количество памет. +Няма грешки в архива +{0} обект(и) избрани +Не може да бъде създадена директория '{0}' +Този архив не поддържа операции за изменение. +Файлът '{0}' не може да се отвори като архив +Криптираният архив '{0}' не може да се отвори. Грешка в паролата? +Архив от тип, който не се поддържа +Файлът {0} вече съществува +Файлът '{0}' е бил променен.\nИскате ли да обновите копието му в архива? +Не може да бъде обновен файл \n'{0}' +Не може да бъде стартиран редактора. +Файлът прилича на вирус (името му съдържа дълги поредици интервали). +Операцията не може да бъде извикана от директория с толкова дълъг път. +Трябва да се избере един файл +Трябва да се изберат един или повече файлове +Твърде много обекти +3300 +Разархивиране +Компресия +Проверка +Отваряне... +Претърсване... +3400 +Разархивиране +&Разархивиране в: +Избор на място за разархивираните файлове. +3410 +Режим за пътищата +Пълни пътища +Без пътища +3420 +Режим за презаписване +Потвърждение преди презаписване +Презаписване без потвърждение +Пропускане на съществуващите файлове +Автоматично преименуване +Автоматично преименуване на съществуващите файлове +3500 +Подтвърдете замяната на файла +Директорията вече съдържа файл с такова име. +Желаете ли да замените съществуващия файл +с този файл? +{0} байта +&Автоматично преименуване +3700 +Неподдържан метод за компресия във файл '{0}'. +Грешка в данните в '{0}'. Файлът е повреден. +Проверката на цикличния остатък даде грешка в '{0}'. Файлът е повреден. +Грешка в данните в криптирания файл '{0}'. Грешка в паролата? +Проверката на цикличния остатък даде грешка в криптирания файл '{0}'. Грешка в паролата? +3800 +Въведете парола +Въведете парола: +Въведете повторно парола: +&Показване на паролата +Двете пароли не съвпадат +За паролата си използвайте само латински букви, цифри и специални символи (!, #, $, ...) +Паролата е твърде дълга +&Парола +3900 +Изминало време: +Оставащо време: +Размер: +Скорост: +Обработени: +Коефициент на компресия: +Грешки: +Архиви: +4000 +Добавяне към архив +&Архив: +Режим за изменение: +Формат на архива: +&Ниво на компресия: +Метод за компресия: +Размер на &речника: +Размер на &думата: +Размер на непрекъснат блок: +Брой процесорни нишки: +&Параметри: +&Опции +Самора&зархивиращ се архив +Компресирани споделени файлове +Криптиране +Метод за криптиране: +Криптиране на файловите &имена +Използвана памет за архивиране: +Използвана памет за разархивиране: +4050 +Без компресия +Най-бърза +Бърза +Нормална +Максимална +Ултра +4060 +Добавяне и замяна на файлове +Обновяване и добавяне на файлове +Опресняване на съществуващите файлове +Синхронизиране на файловете +4070 +Разглеждане +Всички файлове +Non-solid +Непрекъсната (solid) компресия +6000 +Копиране +Преместване +Копиране в: +Преместване в: +Копиране... +Местене... +Преименуване... +Избор на целева директория. +Операцията не се поддържа за тази директория. +Грешка при преименуването на файл или директория +Потвърждение за копирането на файл +Сигурни ли сте, че искате да копирате файлове към архива? +6100 +Потвърждение за изтриването на файл +Потвърждение за изтриването на директория +Потвърждение за изтриването на множество файлове +Сигурни ли сте, че искате да изтриете '{0}'? +Сигурни ли сте, че искате да изтриете диркеторията '{0}' с цялото й съдържание? +Сигурни ли сте, че искате да изтриете тези {0} обекта? +Изтриване... +Грешка при изтриване на файл или директория +Системата не може да изтрие файл с толкова дълъг път +6300 +Създаване на директория +Създаване на файл +Име на директория: +Име на файл: +Нова директория +Нов файл +Грешка при създаване на директория +Грешка при създаване на файл +6400 +Коментар +&Коментар: +Маркиране +Размаркиране +Маска: +6600 +Свойства +История на директориите +Диагностични съобщения +Съобщение +7100 +Компютър +Мрежа +Документи +Система +7200 +Добавяне +Извличане +Тестване +Копиране +Преместване +Изтриване +Информация +7300 +Разделяне на файл +&Разделяне на: +Разделяне на &томове, байтове: +Разделяне... +Потвърждение на разделянето +Сигурни ли сте, че искате да разделите файла на {0} тома? +Размерът на том трябва да бъде по-малък от размера на оригиналния файл +Невалиден размер на том +Указан размер на том: {0} байта.\nСигурни ли сте, че искате да разделите архива на томове с такъв размер? +7400 +Обединяване на файлове +&Обединяване в: +Обединяване... +Избиране само на първата част от разделения файл +Файлът не се разпознава като част от разделен оригинален файл +Не се открива повече от една част от разделения файл +7500 +Изчисляване на контролната сума... +Информация за контролната сума +CRC контролна сума за данни: +CRC контролна сума за данни и имена: +7600 +Статистика +Използвана памет: +Архивиране +Разархивиране +Оценка +Обща оценка +Текущо +Резултат + + +Успешно преминали: diff --git a/Utils/7-Zip/Lang/bn.txt b/Utils/7-Zip/Lang/bn.txt new file mode 100644 index 000000000..3e1865694 --- /dev/null +++ b/Utils/7-Zip/Lang/bn.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.46 : Team Oruddho (Fahad Mohammad Shaon, Mahmud Hassan) : http://www.oruddho.com +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Bangla +বাংলা +401 +ঠিক আছে +বাতিল + + + +&হ্যাঁ +&না +&বন্ধ করা +সাহায্য + +&চালিয়ে যাওয়া +440 +&সবগুলোর জন্য হ্যাঁ +স&বগুলোর জন্য না +বন্ধ +আবার শুরু +&পটভূমি +& সামনে +&বিরতি +বিরতিতে অবস্থানরত +আপনি বাতিল করতে ইচ্ছুক? +500 +&ফাইল +&পরিবর্তন +প্রদর্শন& +&প্রিয় +&দরকারি +&সহায়তা +540 +&উন্মুক্ত করা +7-zip-এ উন্মুক্ত করা +বাহিরে উন্মুক্ত করা +&প্রদর্শন +&পরিবর্তন +নাম পরিবর্তন +&অনুলিপি হবে... +প্রতিস্থাপন হবে... +&মুছে ফেলা +&ফাইল খন্ডায়ন... +ফাইল সংযোজন... +বৈশিষ্টাবলি +মন্তব্য +Checksum গননা করা + +ফোল্ডার সৃষ্টি +ফাইল সৃষ্টি +বাহির +600 +সব নির্বাচন +নির্বাচন রদ করা +উল্টো নির্বাচন +নির্বাচন... +নির্বাচন রদ করা... +ধরণ অনুযায়ী নির্বাচন +ধরণ অনুযায়ী নির্বাচন রদ করা +700 +বৃহৎ প্রতিক +ছোট্ট প্রতিক +&তালিকা +&বিবরণ +730 +অসজ্জিত +সমতল সজ্জা +&ব্যবস্থাপক দ্বিখন্ডন +&দরকারিখুটি +মূল ফোল্ডার উন্মুক্ত করা +এক পর্যায় উপরে ... +ফোল্ডারের অতীত বিবরণ... +&সতেজতা +750 +সংকোচোন ব্যবস্থাপক খুটি +সাধারণ খুটি +বৃহৎ বোতাম +বোতামের শিরোনাম প্রদর্শন +800 +&প্রিয় ফোল্ডার হিসাবে সংযোজন ... +পছন্দের তালিকা +900 +&পছন্দগুলো... +&বেঞ্চমার্ক +960 +&সাহায্য... +&7-Zip সর্ম্পকে... +1003 +অবস্থান +নাম +পরিচয় +ফোল্ডার +আকার +সংকুচিত আকার +বৈশিষ্ট +সৃষ্টি হয়েছে +ব্যবহার হয়েছে +পরিবর্ধন হয়েছে +দৃঢ় +Commented +আটকানো +খন্ডনের পূর্বে +খন্ডনের পরে +অভিধান +CRC +ধরন +বিরোধী +পদ্ধতি +চলতি অপারেটিং সিস্টেম +ফাইল ব্যবস্থা +ব্যবহারকারী +দল +বাধা +মন্তব্য +অবস্থান +পথের বিশেষায়ণ (Path Prefix) + + + + + + + + + + + + + + + + + + + + + + + + +ত্রুটি +সম্পূর্ণ আকার +অবশিষ্ট জায়গা +ক্লাস্টারের আকার +শিরোনাম +স্থানীয় নাম +বিতরণকারী +2100 +পছন্দগুলো +ভাষা +ভাষা: +সম্পাদক +বর্তমান সম্পাদক : + +2200 +বর্তমান অবস্থা +7-Zip-এর সাথে সম্পর্কিত : +2301 +সাহায্যকারী তালিকায় 7-Zip সংযোজন +সাহায্যকারী তালিকায় একের ভিতর সব গুটিয়ে ফেলা +সাহায্যকারী তালিকার বিষয়সমূহ: +2320 +<ফোল্ডার> +<সংকুচিত ফাইল> +সংকুচিত ফাইল চালু করা +ফাইল সম্প্রসারণ... +সংকুচিত ফাইলে সংযোজন... +সংকুচিত ফাইল নিরীক্ষণ +এখানেই সম্প্রসারণ +সম্প্রসারণ করা হবে {0} +সযোজন করা হবে {0} +সংকোচন এবং ই-মেইল... +সংকোচন - {0} এবং ই-মেইল +2400 +ফোল্ডার +&কার্যরত ফোল্ডার +&অস্থায়ী ফোল্ডার +&প্রচলিত +&নির্দিষ্ট: +অস্থায়ী অংশের জন্য ব্যবহার করা +অস্থায়ী ফোল্ডার নির্বাচন করুন। +2500 +পছন্দগুলো +".." ফাইল প্রদর্শন +ফাইলের আসল প্রতিক দেখানো +কম্পিউটার চালকের তালিকা দেখানো +পূর্ণ পর্যায় প্রদর্শন +ছকের লাইন প্রদর্শন + +পরিপূরক নিবাচনের পদ্ধতি +বেশি স্মৃতির ব্যবহার +2900 +7-Zip সম্পর্কে +7-Zip একটি মুক্ত প্রোগ্রাম কিন্তু এটি 7-Zip এর কতৃপক্ষের কাচে নিবন্ধনের মাধ্যমে আপনি উন্নত সেবা পেতে পারেন +3000 + +কোন ত্রুটি নেই +{0} ফাইল(সমূহ) নির্বাচিত +'{0}' ফোল্ডার সৃষ্টি করা সম্ভব হচ্ছেনা +এই সংকোচনের ক্ষেত্রে এই সেবা প্রদান করা সম্ভব হচ্ছে না। +'{0}' -কে সংকুচিত ফাইল হিসেবে চালু করা সম্ভব হচ্ছেনা +'{0}' বদ্ধ সংকুচিত ফাইল চালু করা সম্ভব হচ্ছেনা. ভুল পাসওয়ার্ড? + + +ফাইলটি '{0}' পরিমার্জিত.\nআপনি সংকুচিত ফাইলটি ও পরিমার্জন করতে চান? +পরিমার্জন করা সম্ভব হয়নি\n'{0}' +সম্পাদক চালু করা সম্ভব নয় + + + + +অনেক বেশী ফাইল +3300 +সম্প্রসারণ করা হচ্ছে +সংকোচায়ন প্রক্রিয়াধীন +নিরক্ষণ করছে ... +উন্মুক্ত করা হচ্ছে... +তথ্য সংগ্রহ চলছে... (Scanning...) +3400 +সম্প্রসারণ +&সম্প্রসারণ করা হবে: +ফাইল সম্প্রসারনের ঠিকানা +3410 +ঠিকানা নির্বাচন পদ্ধতি +পূর্ণ ঠিকানাসমূহ +ঠিকানাবিহীন +3420 +প্রতিস্থাপন পদ্ধতি +প্রতিস্থাপনের পূর্বাভাস +আভাসবিহীন প্রতিস্থাপন +একই পরিচয় প্রাপ্ত ফাইল এড়িয়ে চলা +স্বয়ংক্রিয় পুঃনামকরণ +একই পরিচয় প্রাপ্ত ফাইলের নাম পরিবর্ত্ন +3500 +ফাইল প্রতিস্থাপন নিশ্চিত করণ +নির্ধারিত ফোল্ডারে ফাইলটি আগেথেকেই আছে +আপনিকি বর্তমান ফাইলটি প্রতিস্থাপন করতে চান? +এইটির সাথে? +{0} bytesবাইট +স্বয়ংক্রিয় পুঃনামকরণ +3700 +অসমর্থিত সংকোচন পদ্ধতি -'{0}'. +'{0}' ফাইলে ত্রুটিপূর্ণ তথ্য. ফাইলটি খন্ডিত +'{0}' ফাইলে CRC ব্যর্থ. ফাইলটি খন্ডিত +'{0}' বদ্ধ ফাইলে তথ্যে ত্রুটি. ভুল পাসওয়ার্ড? +'{0}' বদ্ধ ফাইলে CRC ব্যর্থ. ভুল পাসওয়ার্ড? +3800 +পাসওয়ার্ডটি প্রবেশ করুনঃ +পাসওয়ার্ডটি প্রবেশ করুনঃ +আবার পাসওয়ার্ড প্রবেশ করুনঃ +&পাসওয়ার্ড প্রদর্শন +পাসওয়ার্ড দুটি একই নয় +শুধু ইংলিশ বর্ণ, সংখ্যা এবং বিশেষ বর্ণ (!, #, $, ...) পাসওয়ার্ড হিসেবে ব্যবহার করুন +পাসওয়ার্ডটি খুব বেশী বড় হয়েছে +পাসওর্য়াড +3900 +অতিবাহিত সময়ঃ +সময় বাকি আছেঃ +আকার: +গতি: + + +বিফলতা : + +4000 +সংকোচনে সংযোজন +&সংকোচন +&পরিমার্জন পদ্ধতি: +সংকোচনের & পরিচয়: +সংকোচনের &পর্যায়: +সংকোচন &পদ্ধতি: +&Dictionary size: +&Word size: +Solid block size: +CPU-এর thread-এর সংখ্যা: +&Parameters: +পছন্দনীয় +স্বয়ংক্রিয় সংকোচন প্রোগ্রাম তৈরি +বিনিময়যোগ্য ফাইল সংকোচন +বদ্ধ করা +বদ্ধ করার পদ্ধতি: +ফাইলের নাম &আটকে ফেলা +সংকোচনের জন্য স্মৃতির ব্যবহার: +সম্প্রসারনের জন্য স্মৃতির ব্যবহার: +4050 +অতি সংকোচায়ন +অতি দ্রুত +দ্রুত +সাধারন +সর্ব্বোচ্চ +পলকের গতি +4060 +সংকোচন ও ফাইল প্রতিস্থাপন +পরিমার্জন ও ফাইল প্রতিস্থাপন +উল্লেখিত ফাইলে সতেজতা প্রদান +ফাইল সাজিয়ে রাখা +4070 +বিচরণ +সকল ফাইল +Non-solid +Solid +6000 +অনুলিপি গ্রহন +অনুলিপি গ্রহন এবং মুছে ফেলা +অনুলিপি করা হবে: +প্রতিস্থাপিত হবে: +অনুলিপি করা হচ্ছে... +প্রতিস্থাপিত হচ্ছে... +নাম পরিবর্তন... +গন্তব্য ফোল্ডার নির্বাচন. +কার্যটি সম্ভব নয় +ফাইল বা ফোল্ডারের নাম পরিবর্তনে সম্ভব নয় +ফাইল অনুলিপি নিশ্চিতকরণ +আপনি কি ফাইলগুলোকে সংকুচিত ফাইলে অনুলিপি গ্রহণ করতে চান। +6100 +ফাইলটি মুছে ফেলতে কি আপনি নিশ্চিত +ফোল্ডারটি মুছে ফেলতে কি আপনি নিশ্চিত +ফাইলটি মুছে ফেলতে কি আপনি নিশ্চিত +মুছে ফেলতে আপনি কি নিশ্চিত - '{0}'? +'{0}' ফোল্ডার এবং এর সব ফাইল আপনি কি মুছে ফেলতে নিশ্চিত? +নির্বাচিত {0} টি ফাইল আপনি কি মুছে ফেলতে নিশ্চিত? +মুছে ফেলা হচ্ছে... +ফাইল বা ফোল্ডার মুছে ফেলাতে সমস্যা হচ্ছে + +6300 +ফোল্ডার সৃষ্টি +ফাইল সৃষ্টি +ফোল্ডারের নাম: +ফাইল নাম: +নতুন ফোল্ডার +নতুন ধারক +ফোল্ডার সৃষ্টিতে সমস্যা +ফাইল সৃষ্টিতে সমস্যা +6400 +মন্তব্য +&মন্তব্য: +নির্বাচন +নির্বাচন রদ করা +আড়াল করা: +6600 + +ফোল্ডারের অতিত বিবরন +সমস্যা নিরাময় আভাস +আভাস +7100 +কম্পিউটার +আন্তঃ সম্পর্ক + +কম্পিউটার চালক +7200 +সংজোযন +সম্প্রসারন +নিরীক্ষণ +অনুলিপি গ্রহন +প্রতিস্থাপন +মুছে ফেলা +তথ্য +7300 +ফাইল খন্ডায়ন +&ফাইল খন্ডায়িত হবে: +volumes(খন্ডে), bytes(বাইটস)-এ খন্ডায়নঃ +ফাইল খন্ডায়ন চলছে... +ফাইল খন্ডায়ন নিশ্চিতকরণ +আপনি কি সংকুচিত ফাইলটিকে {0} খন্ডে খন্ডায়ন করতে চান? +খন্ডের আকার অবশ্যই মূল ফাইলের চেয়ে ছোট হতে হবে +খন্ডের আকারে ভুল +উল্লেক্ষিত খন্ডের আকার : {0} bytes.\nআপনি কি সংকোচিত ফাইলটিকে এ ভাবেই খন্ডে খন্ডায়ন করতে চান? +7400 +ফাইল একীভূতি করণ +&একীভূতি করা হবে: +একীভূতি চলছে... +শুধু প্রথম ফাইলটি নির্বাচন করুন + + +7500 +Checksum গননা চলছে... +Checksum তথ্য +তথ্যের জন্য CRC checksum: +তথ্য এবং নামের জন্য CRC checksum: +7600 +বেঞ্চমার্ক +ব্যবহৃত স্মৃতি : +সংকোচায়ন ... +সম্প্রসারণ ... +রেটিং +মোট রেটিং +চলতি +ফলাফল +CPU ব্যবহার করছে +Rating / ব্যবহার করছে +সফলতা : diff --git a/Utils/7-Zip/Lang/br.txt b/Utils/7-Zip/Lang/br.txt new file mode 100644 index 000000000..f7f7fa3b8 --- /dev/null +++ b/Utils/7-Zip/Lang/br.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 3.12 : KAD-Korvigelloù An Drouizig (drouizig.org). +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Breton +Brezhoneg +401 +Mat eo +Nullañ + + + +&Ya +&Ket +&Serriñ +Skoazell + +&Kenderc'hel +440 +Ya be&pred +Ket &bepred +Paouez +Adloc'hañ +&Drekleur +&Rakleur +&Ehan +Ehanet +Ha fellout a ra deoc'h nullañ ? +500 +&Restr +&Aozañ +&Gwelout +Di&baboù +&Ostilhoù +&Skoazell +540 +&Digeriñ +Digeriñ a-zia&barzh +Digeriñ a-zia&vaez +&Gwelout +&Aozañ +Adenv&el +&Kopiañ diwar... +&Dilec'hiañ diwar... +D&ilemel +&Troc'hañ restr... +&Kendeuziñ restroù... +P&erzhioù +Evezhia&denn + + +Sevel un teul +Sevel ur restr +&Kuitaat +600 +Diuz pep &tra +Diziuz pe tra +Lakaat an &diuzad war an tu gin +Diuz... +Diziuz... +Diuz diouzh ar rizh +Diziuz diouzh ar rizh +700 +Arlunioù &bras +Arlunioù &bihan +&Roll +&Munudoù +730 +Dirummet + +&2 brenestr +&Barrennoù ostilhoù +Digeriñ an teul gwrizienn +Teul kerent +Roll istor an teul... +Fresk&aat +750 +Barrenn ziell +Barrenn skouerek +Meudellioù bras +Diskouez an destenn +800 +&Ouzhpennañ ar c'havlec'h d'ar sinedoù +Sined +900 +&Dibaboù... +&Amprouiñ +960 +&Roll ar pennadoù... +A-&zivout 7-Zip... +1003 +Treug +Anv +Astenn +Teul +Ment +Gwasket +Doareennoù +Savet d'ar +Stoket d'ar +Kemmet d'ar +Solut +Evezhiadenn +Ennodet +Rannañ a-raok +Rannañ war-lerc'h +Geriadur +CRC +Rizh +Enep +Hentenn +OS ostiz +Reizhiad restroù +Implijour +Strollad +Bloc'h +Evezhiadenn +Lec'hiadur + + + + + + + + + + + + + + + + + + + + + + + + + +Fazi +Ment en holl +Egor vak +Ment ar c'hleusteurioù +Skritellig +Anv lec'hel +Pourchaser +2100 +Dibaboù +Yezh +Yezh : +Embanner +&Embanner : + +2200 +Reizhiad +Kenstagañ 7-Zip ouzh : +2301 +Lakaat 7-Zip el lañser kemperzhel +Lañser kemperzhel a-steud +Elfennoù al lañser kemperzhel : +2320 + + +Digeriñ +Eztennañ ar restroù... +Ouzhpennañ d'an diell... +Gwiriañ an diell +Eztennañ amañ +Eztennañ diwar {0} +Ouzhpennañ da {0} +Gwaskañ ha kas dre postel... +Gwaskañ diwar {0} ha kas dre postel. +2400 +Teulioù +Teulioù &labour +Teul dibadelus ar &reizhiad +Teul &red +Teul &spisaet : +Implijout nemet evit ar mediaoù dilec'hus +Spisait un teul evit lakaat ar restroù diell dibadelus. +2500 +Perzhioù +Diskouez an elfenn ".." +Diskouez arlunioù gwirion ar restroù +Diskouez al lañser reizhiad +&Diuz ar bannoù a-bezh +Diskouez al &linennoù kael + + + +2900 +Keloù +Digoust eo ar meziant 7-Zip. Mar plij deoc'h 7-zip ha mar fell deoc'h skoazellañ ar raktres-mañ e c'hellit donezoniñ argant da 7-Zip. +3000 + +N'eus fazi ebet +{0} elfenn ziuzet +N'haller ket sevel ar restr '{0}' +N'haller ket ober gant an oberiadennoù nevesaat evti an diell-mañ. + + + + +Kemmet ez eo bet ar restr '{0}'.\nHa fellout a ra deoc'h he nevesaat en diell ? +N'haller ket nevesaat\n'{0}' +N'haller ket loc'hañ an embanner. + + + + +Re a elfennoù +3300 +Eztennañ +O waskañ +Gwiriañ +O tigeriñ... + +3400 +Eztennañ +E&ztennañ diwar : +Dibabit un teul evit eztennañ an restroù. +3410 +Treugoù +Treugoù klok +Treug ebet +3420 +Mod erlec'hiañ +Goulenn a-raok erlec'hiañ +Erlec'hiañ hep goulenn +Lakaat ar restroù a zo anezho a-gostez +Adenvel ent-emgefre ar restroù a zo anezho + +3500 +Kadarnaat a-raok erlec'hiañ ur restr +Emañ dija ur restr gant ar memes anv en teul bukenn. +Ha fellout a ra deoc'h lakaat e-lec'h +ar restr da heul ? +{0} eizhtet +Adenvel ent-&emgefre +3700 +Hentenn waskañ direizh evit '{0}'. +Stlenn faziet e-barzh '{0}'. Gwastet eo ar restr. +Fazi ar reoliñ CRC evit '{0}'. Gwastet eo ar restr. + + +3800 +Roit ar ger-tremen +Roit ar ger-tremen : + +&Diskouez ar ger-tremen + + + +Ger-tremen +3900 +Amzer dremenet : +Amzer o chom : +Ment : +Tizh : + + +Fazioù : + +4000 +Ouzhpennañ d'an diell +&Diell : +&Mod nevesaat : +&Mentrezh an diell : +L&ive gwaskañ : +Rizh &gwaskañ: +&Ment ar geriadur : +Me&nt ar gerioù : + + +&Perzhioù: +&Dibaboù +Sevel un diell SF&X + + + +Ennodiñ an &anvioù restroù +Memor evit ar waskerezh : +Memor evit an diwaskerezh : +4050 +Gwaskañ ebet +Primañ +Prim +Reizh +Uhelañ +Gour +4060 +Ouzhpennañ hag erlec'hiañ ar restroù +Nevesaat hag ouzhpennañ ar restroù +Freskaat ar restroù a zo anezho +Goubredañ ar restroù +4070 +Furchal +An holl restroù + + +6000 +Kopiañ +Dilec'hiañ +Kopiañ e-barzh : +Dilec'hiañ diwar : +O kopiañ... +O tilec'hiañ... +Oc'h adenvel... + +N'haller ket ober an oberiadenn-mañ. +Fazi oc'h adenvel ar restr pe an teul + + +6100 +Kadarnañ a-raok dilemel ar restr +Kadarnañ a-raok dilemel an teul +Kadarnañ a-raok dilemel an holl restroù +Ha fellout a ra deoc'h dilemel '{0}' ? +Ha fellout a ra deoc'h dilemel an teul '{0}' ha pep tra a zo e-barzh ? +Ha fellout a ra deoc'h dilemel ar {0} elfenn-mañ ? +O tilemel... +Fazo o tilemel ar restr pe an teul + +6300 +Sevel un teul +Sevel ur restr +Anv an teul : +Anv restr : +Teul nevez +Restr nevez +Fazi o sevel an teul +Fazi o sevel ar restr +6400 +Evezhiadenn +&Evezhiadenn : +Diuz +Diziuz +Kuzh : +6600 + +Roll istor an teulioù +Kemennoù yalc'h +Kemenn +7100 +Urzhiataer +Rouedad + +Reizhiad +7200 +Ouzhpennañ +Eztennañ +Amprouiñ +Kopiañ +Dilec'hiañ +Dilemel +Keloù +7300 +Troc'hañ restr +&Troc'hañ da : +Troc'hañ e &levrennoù, eizhtetoù : +O troc'hañ... + + + + + +7400 +Kendeuziñ restroù +&Kendeuziñ da : +O kendeuziñ... + + + +7500 + + + + +7600 +Amprouiñ +Implij ar vemor : +Gwaskerezh +Diwaskerezh +Feur +Feur en holl +Red +Da heul + + +Tremenioù : diff --git a/Utils/7-Zip/Lang/ca.txt b/Utils/7-Zip/Lang/ca.txt new file mode 100644 index 000000000..767d93521 --- /dev/null +++ b/Utils/7-Zip/Lang/ca.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Josep Casals, Marc Folch +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Catalan +Català +401 +D'acord +Cancel.la + + + +&Sí +&No +Tan&ca +Ajuda + +&Continua +440 +Sí a &tot +No a t&ot +Atura +Reinicia +Rerefons +Primer pla +&Pausa +Aturat +Esteu segur que voleu cancel.lar? +500 +&Fitxer +&Edita +&Visualitza +&Preferits +E&ines +Aj&uda +540 +&Obre +Obre d&ins +Obre fora +&Visualitza +&Edita +Renom&ena +&Copia a... +&Moure a... +Suprimeix +&Divideix el fitxer... +Com&bina el fitxer... +P&ropietats +Come&ntari +Calcula el checksum +Diff +Crea carpeta +Crea fitxer +Surt +600 +Seleccion&a-ho tot +Deselecciona-ho tot +&Inverteix selecció +Selecciona... +Deselecciona... +Selecciona per tipus +Deselecciona per tipus +700 +Icones g&rans +Icones petites +&Llista +&Detalls +730 +No ordenat +Vista plana +&2 Taules +&Barres d'eines +Obre carpeta arrel +Carpeta pare +Historial de carpetes... +&Actualitza +750 +Barra d'eines afegeix/extreu +Barra d'eines estàndard +Botons grans +Mostra botons amb text +800 +&Afegeix la carpeta als Preferits com +Personal +900 +Opcions... +&Test de referència +960 +&Contingut... +Quant a 7-Zip... +1003 +Adreça +Nom +Tipus de fitxer +Carpeta +Mida +Mida comprimit +Atributs +Creat +Darrer accés +Darrera modificació +Compacte +Comentari +Xifrat +Expandit abans +Expandit després +Diccionari +CRC +Tipus +Anti +Mètode +SO orígen +Sistema de fitxers +Usuari +Grup +Bloc +Comentari +Posició +Path Prefix +Carpetes +Fitxers +Versió +Volum +Multivolum +Desplaçament +Enllaços +Blocs +Volums + +64-bits +Big-endian +CPU +Mida física +Mida capçaleres +Suma de verificació +Característiques +Adreça virtual +ID +Nom curt +Aplicació creadora +Mida del sector +Mode +Enllaç +Error +Mida total +Espai lliure +Mida sector +Etiqueta +Nom local +Proveïdor +2100 +Opcions +Llengua +Llengua: +Editor +&Editor: +&Diff: +2200 +Sistema +Associa 7-Zip amb: +2301 +Integra 7-Zip dins el menú contextual de Windows +Menú contextual en cascada +Objectes del menú contextual: +2320 + + +Obre +Extreu fitxers... +Afegeix al fitxer... +Comprova el fitxer +Extreu a aquesta carpeta +Extreu a {0} +Afegeix a {0} +Comprimeix i envia per correu electrònic... +Comprimeix a {0} i envia per correu electrònic +2400 +Carpetes +Carpeta de &treball +Carpeta temporal del &sistema +Carpeta a&ctual +E&specifica una carpeta: +Utilitza únicament per a discs extraïbles +Especifica una carpeta pels fitxers temporals. +2500 +Selecció +Mostra l'element ".." +Mostra icones reals dels fitxers +Mostra el menú de sistema +&Selecció de columna completa +Mostra les línies de &graella +Obre amb un sol clic els elements +Mode de selecció &alternatiu +Usa pàgines de memòria &grans +2900 +Informació sobre 7-Zip +7-Zip és programari lliure. De totes maneres, podeu col.laborar en el seu desenvolupament registrant el programa. +3000 +El sistema no pot assignar la quantitat de memòria requerida +No hi ha errors +{0} objecte(s) seleccionat(s) +No es pot crear la carpeta '{0}' +Aquest tipus de fitxer no permet actualització. +No es pot obrir el fitxe '{0}' com a arxiu +No es pot obrir el fitxer xifrat '{0}'. La contrasenya és incorrecta? +Tipus d'arxiu no admès +El fitxer {0} ja existeix +El fitxer '{0}' ha estat modificat.\nVoleu actualitzar-lo a l'arxiu? +No pot actualitzar-se el fitxer\n'{0}' +No pot executar-se l'editor. +El fitxer sembla un virus (el nom del fitxer conté espais molt llargs al nom). +L'operació no es pot cridar des d'una carpeta amb una ruta llarga. +Heu de seleccionar un fitxer +Heu de seleccionar un o més fitxers +Massa objectes +3300 +Extraient +Comprimint +Provant +Obrint... +Scanning... +3400 +Extreu +E&xtreu a: +Seleccioneu una destinació pels fitxers extrets. +3410 +Mode d'adreça +Adreça completa +Sense adreça +3420 +Sobreescriure +Amb confirmació +Sense confirmació +Conserva els fitxers ja existents +Reanomena automàticament +Auto-reanomena fitxers existents +3500 +Confirmeu substitució de fitxers +La carpeta de destí conté un fitxer amb el mateix nom. +Voleu substituir el fitxer existent +per aquest altre? +{0} bytes +Renomena a&utomàticament +3700 +Mètode de compressió no vàlid per a '{0}'. +Error de dades en '{0}'. El fitxer és corrupte. +CRC ha fallat en '{0}'. El fitxer és corrupte. +Error de dades al fitxer xifrat '{0}'. Contrasenya errònia? +CRC ha fallat al fitxer xifrat '{0}'. Contrasenya errònia? +3800 +Introduïu la contrasenya +Introduïu la contrasenya: +Torneu a introduir la contrasenya: +Mo&stra la contrasenya +Les contrasenyes no coincideixen +Utilitza només lletres (sense accents), números i caràcters especials (!, #, $, ...) a la contrasenya +La contrasenya és massa llarga +Contrasenya +3900 +Temps transcorregut: +Temps restant: +Mida: +Taxa: +Processat: +Ràtio de compressió: +Errors: +Arxius: +4000 +Afegir al fitxer +&Fitxer: +Mode d'act&ualització: +&Format del fitxer: +Nivell de &compressió: +&Tipus de compressió: +Mida del &diccionari: +Mida de la paraula: +Mida de bloc sòlid: +Nombre de fils de la CPU: +&Paràmetres: +Opcions +Crea fitxer SF&X +Comprimeix fitxers compartits +Xifrat +Mètode de xifrat: +Xifra el nom dels fitxers +Ús de memòria per comprimir: +Ús de memòria per descomprimir: +4050 +Sense compressió +Ràpida + +Normal +Màxima +Ultra +4060 +Afegeix i substitueix fitxers +Actualitza i afegeix fitxers +Actualitza fitxers ja presents +Sincronitza fitxers +4070 +Visualitza +Tots els fitxers +No sòlid +Sòlid +6000 +Copia +Mou +Copia a: +Mou a: +Copiant... +Movent... +Renomenant... +Seleccioneu una carpeta de destí. +Operació no permesa. +Error renomenant fitxer o carpeta +Confirmeu la còpia del fitxer +Esteu segur que voleu copiar els fitxers a l'arxiu +6100 +Confirmeu la supressió del fitxer +Confirmeu la supressió de la carpeta +Confirmeu supressió múltiple de fitxers +Esteu segur que voleu suprimir '{0}'? +Esteu segur que voleu suprimir la carpeta '{0}' i tot el seu contingut? +Esteu segur que voleu esborrar aquests {0} elements? +Suprimint... +Error esborrant fitxer o carpeta +El sistema no pot moure un fitxer amb una ruta llarga a la paperea de reciclatge +6300 +Crea carpeta +Crea arxiu +Nom de carpeta: +Nom d'arxiu: +Carpeta nova +Fitxer nou +Error creant carpeta +Error creant el fitxer +6400 +Comentari +&Comentari: +Selecciona +No selecciona +Màscara: +6600 +Properties +Historial de carpetes +Missatges de diagnosi +Missatge +7100 +El meu ordinador +Entorn de xarxa +Documents +Sistema +7200 +Afegeix +Extreu +Prova +Copia +Mou +Suprimeix +Info +7300 +Divideix fitxer +&Divideix a: +Divideix en &volums, bytes: +Dividint... +Confirmació de la divisió +Esteu segur que voleu dividir el fitxer en {0} volums? +La mida del volum ha de ser més petita que la mida del fitxer original +Mida del volum incorrecte +Mida de volum especificada: {0} bytes.\nEsteu segur que voleu dividir el fitxer en aquests volums? +7400 +Combina fitxers +&Combina a: +Combinant... +Seleccioneu només el primer fitxer +No es pot detectar un fitxer com a una part del fitxer dividit +No es pot trobar més d'una part del fitxer dividit +7500 +Calculant el checksum... +Informació del checksum +CRC checksum per les dades: +CRC checksum per les dades i els noms: +7600 +Test de referència +Ús de la memòria: +Comprimint +Decomprimint +Taxa +Taxa total +Actual +Resultant +Ús de la CPU +Taxa / Ús +Passades: diff --git a/Utils/7-Zip/Lang/co.txt b/Utils/7-Zip/Lang/co.txt new file mode 100644 index 000000000..4b05003b6 --- /dev/null +++ b/Utils/7-Zip/Lang/co.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.00 : Patriccollu di Santa Maria è Sichè +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Corsican +Corsu +401 +OK +Abbandunà + + + +&Iè +I&nnò +&Chjode +Aiutu + +&Cuntinuà +440 +Iè per &Tutti +Innò per T&utti +Piantà +Riavvià +&Arci pianu +P&rimu pianu +&Pausa +In pausa +Site sicuru di vulè abbandunà ? +500 +&Schedariu +&Mudificà +&Affissà +&Favuriti +A&ttrezzi +A&iutu +540 +&Apre +Apre Den&tru +Apre F&ora +A&ffissà +&Mudificà +&Rinumà +&Cupià Ver Di... +&Dispiazzà Ver Di... +S&quassà +&Sparte u schedariu... +&Unisce i schedarii... +&Pruprietà +Cumme&ntu... +Calculà a somma di cuntrollu +Paragunà e sfarenze +Creà un Cartulare +Creà un Schedariu +&Esce +Leia +Flussi A<ernativi +600 +Selezziunà &Tuttu +Ùn selezziunà &Nunda +&Arritrusà a Selezzione +&Selezziunà... +Ùn selezziunà &micca... +Selezziunà da u Tipu +Ùn Selezziunà da u Tipu +700 +Icone &Maiò +Icone &Chjuche +&Lista +&Detaglii +730 +Non &Ordinatu +&Vista Sparta +&2 Finestre +&Barre d'Attrezzi +Apre u Cartulare di &Radica +Livellu &Superiore +Crunulugia di i Cartulari... +&Attualizà +Attualisazione Autumatica +750 +Barra d'Attrezzi d'Archiviu +Barra d'Attrezzi Classica +Buttoni Maiò +Affissà u Testu di i Buttoni +800 +&Aghjunghje u cartulare à i Favuriti cum'è +Indetta +900 +&Ozzioni... +&Sperimentu di pussibilità +960 +&Cuntenutu (in inglese)... +&Apprupositu di 7-Zip... +1003 +Passeghju +Nome +Estensione +Cartulare +Dimensione +Dimensione Cumpressa +Attributi +Creatu u +Accessu u +Mudificatu u +Solidu +Cummentatu +Cifratu +Frazziunà Nanzu +Frazziunà Dopu +Dizziunariu + +Tipu +Anti +Metoda +OS ospite +Sistema di Schedariu +Utilizatore +Gruppu +Bloccu +Cummentu +Pusizione +Prefissu di Passeghju +Cartulari +Schedarii +Versione +Vulume +Multi-Vulume +Offset +Leie +Blocchi +Vulumi + +64-bit +Big-endian +CPU +Dimensione Fisica +Dimensione di l'Intestature +Somma di cuntrollu +Caratteristiche +Indirizzu Virtuale +ID +Nome Cortu +Appiecazione d'Urigine +Dimensione di Settore +Modu +Leia Simbolica +Sbagliu +Dimensione Tutale +Spaziu Liberu +Dimensione di Cluster +Nome di Vulume +Nome Lucale +Furnidore +Sicurità NT +Flussu Alternativu +Ausiliaru +Squassatu +In Arburu + + +Tipu di Sbagliu +Sbaglii +Sbaglii +Avertimenti +Avertimentu +Flussi +Flussi Alternativi +Dimensione di i Flussi Alternativi +Dimensione Virtuale +Dimensione Senza Compressione +Dimensione Fisica Tutale +Indice di Vulume +SottuTipu +Cummentu Cortu +Pagina di Codice + + + +Dimensione di a Coda +Dimensione di u Mozzicone Incurpuratu +Leia +Leia Solida +iNode + +Lettura sola +2100 +Ozzioni +Lingua +Lingua : +Editore +&Editore : +Paragunà e sfarenze : +2200 +Sistema +Assucià 7-Zip cù : +Tutti l'utilizatori +2301 +Integrà 7-Zip à l'interfaccia cuntestuale +Interfaccia cuntestuale in cascata +Elementi di l'interfaccia cuntestuale : +Icone in l'interfaccia cuntestuale +2320 + + +Apre l'archiviu +Estrae i schedarii... +Aghjunghje à l'archiviu... +Verificà l'archiviu +Estrae Quì +Estrae ver di {0} +Aghjunghje à {0} +Cumprime è mandà da email... +Cumprime ver di {0} è mandà da email. +2400 +Cartulari +Cartulare di &travagliu +Cartulare timpurariu di &sistema +&Currente +&Specificatu : +Impiegà solu per i dischi amuvibili +Specificate un cartulare per i schedarii timpurarii d'archiviu. +2500 +Preferenze +Affissà l'elementu ".." +Affissà e vere icone di i schedarii +Affissà l'interfaccia sistema +Selezziunà tutta a linea +Affissà linee &quadrittate +Cliccu unicu per apre un elementu +Modu di selezzione &alternativa +Impiegà pagine maiò di memoria +2900 +Apprupositu di 7-Zip +7-Zip hè un prugramma liberu.\n\nTraduttu in lingua corsa da Patriccollu di Santa Maria è Sichè. +3000 +U sistema ùn pò micca attribuisce a quantità richiesta di memoria +Ùn ci hè micca sbagliu +{0} ughjettu(i) selezziunatu(i) +U cartulare '{0}' ùn pò micca esse creatu +L'azzioni di mudificazione ùn sò micca pussibule per quessu archiviu. +U schedariu '{0}' ùn pò micca esse apertu cum'è un archiviu +L'archiviu cifratu '{0}' ùn pò micca esse apertu. Parolla d'intrata falsa ? +Stu tipu d'archiviu ùn hè micca accettatu +U schedariu {0} esiste dighjà +U schedariu '{0}' hè statu mudificatu.\nVulete cambiallu in l'archiviu ? +Ùn hè micca pussibule di cambià u schedariu\n'{0}' +Ùn hè micca pussibule d'avvià l'editore. +U schedariu hè podasse infettatu da un virus (u so nome cuntene spazii numerosi). +St'azzione ùn pò micca fassi dapoi un cartulare cù u nome di passeghju cusì longu. +Ci vole à selezziunà un schedariu +Ci vole à selezziunà al menu un schedariu +Troppu elementi +Ùn hè micca pussibule d'apre u schedariu cum'è un archiviu {0} +U schedariu hè apertu cum'è un archiviu {0} +L'archiviu hè apertu cù offset +3300 +Estrazzione +Cumpressione +Verificazione +Apertura... +Esplurazione... +Cacciatura +3320 +Aghjuntu +Mudificazione +Analisa +Riproduzzione +Rimballasgiu +Tralasciamentu +Squassatura +Creazione di l'intestatura in corsu +3400 +Estrae +E&strae ver di : +Sciglite un cartulare per l'estrazzione di i schedarii. +3410 +Modu di passeghju : +Nomi cumpletti di passeghju +Alcunu nome di passeghju +Nomi assuluti di passeghju +Nomi relativi di passeghju +3420 +Modu di rimpiazzamentu : +Cunfirmà nanzu di rimpiazzà +Rimpiazzà senza dumandà +Ignurà i schedarii esistenti +Rinumà autumaticamente +Rinumà autumaticamente i schedarii esistenti +3430 +Ùn cupià micca u cartulare di radica +Risturà a sicurità di i schedarii +3500 +Cunfirmà u Rimpiazzamentu di Schedariu +U cartulare di distinazione cuntene dighjà un schedariu cù stu nome. +Vulete rimpiazzà u schedariu esistentu +cù quessu ? +{0} ottetti +Rinumà &Autumaticamente +3700 +Metoda di cumpressione micca accettatu per '{0}'. +Sbagliu di dati in '{0}'. U schedariu hè alteratu. +Fiascu di l'ispezzione CRC per u schedariu '{0}'. U schedariu hè alteratu. +Sbagliu di dati in u schedariu cifratu '{0}'. Parolla d'intrata falsa ? +Fiascu di l'ispezzione CRC per u schedariu cifratu '{0}'. Parolla d'intrata falsa ? +3710 +Parolla d'intrata falsa ? +3721 +Metoda di compressione micca accettatu +Sbagliu di dati +Fiascu di CRC +Dati micca dispunibule +Fine inaspettata di dati +Ci hè d'altri dati dopu à a fine di i dati ghjuvevule +Ùn hè un archiviu +Sbagliu d'Intestature +Parolla d'intrata falsa +3763 +Principiu di l'archiviu micca dispunibule +Principiu di l'archiviu micca confirmatu + + + +Funzione micca accettata +3800 +Scrivite a parolla d'intrata +Scrivite a parolla d'intrata : +Scrivite torna a parolla d'intrata : +&Affissà a parolla d'intrata +E parolle d'intrata sò sfarente +Per a parolla d'intrata, pudete impiegà solu : lettere senza aletta, cifri è segni particulari (!, #, $, ...) +A parolla d'intrata hè troppu longa +Parolla d'intrata +3900 +Tempu passatu : +Tempu rimanentu : +Dimensione tutale : +Celerità : +Prucessu : +Reditu di cumpressione : +Sbaglii : +Archivii : +4000 +Aghjunghje à l'archiviu +&Archiviu : +Modu di m&udificazione : +&Forma d'archiviu : +&Livellu de cumpressione : +&Metoda di cumpressione : +&Dimensione di u dizziunariu : +Dimensione di &e parolle : +Dimensione di u bloccu solidu : +Numeru di flussi CPU : +&Parametri : +Ozzioni +Creà un archiviu SF&X +Cumprime schedarii sparti +Cifratura +Metoda di cifratura : +Cifrà i &nomi di schedariu +Memoria impiegata da a Cumpressione : +Memoria impiegata da a Scumpressione : +Squassà i schedarii dopu à a cumpressione +4040 +Cunservà e leie simboliche +Cunservà e leie solide +Cunservà i flussi di dati alternativi +Cunservà a sicurità di i schedarii +4050 +Alcuna +A più rapida +Rapida +Nurmale +Massima +Ultra +4060 +Aghjunghje è rimpiazzà i schedarii +Mudificà è aghjunghje i schedarii +Attualizà i schedarii esistenti +Sincrunizà i schedarii +4070 +Sfuglià +Tutti i Schedarii +Non-solidu +Solidu +6000 +Cupià +Dispiazzà +Cupià ver di : +Dispiazzà ver di : +Copia in corsu... +Dispiazzamentu in corsu... +Cambiamentu di nome in corsu... +Selezziunà u cartulare di distinazione. +St'azzione ùn hè micca accettata per stu cartulare. +Sbagliu durante u Cambiu di Nome di Schedariu o di Cartulare +Cunfirmazione di a Copia di Schedariu +Site sicuru di vulè cupià u(i) schedariu(i) ver di l'archiviu +6100 +Cunfirmà a Squassatura di u Schedariu +Cunfirmà a Squassatura di u Cartulare +Cunfirmà a Squassatura di Schedarii Multiplice +Site sicuru di vulè squassà '{0}' ? +Site sicuru di vulè squassà u cartulare '{0}' è tuttu u so cuntenutu ? +Site sicuru di vulè squassà sti {0} elementi ? +Squassatura in corsu... +Sbagliu durante a Squassatura di Schedariu o di Cartulare +U sistema ùn pò micca mette à a Rumenzula un schedariu cù u nome di passeghju cusì longu +6300 +Creà un Cartulare +Creà un Schedariu +Nome di cartulare : +Nome di schedariu : +Novu Cartulare +Novu Schedariu +Sbagliu durante a Creazione di Cartulare +Sbagliu durante a Creazione di Schedariu +6400 +Cummentu +&Cummentu : +Selezziunà +Ùn Selezziunà +Filtru : +6600 +Pruprietà +Crunulugia di i Cartulari +Messaghji di diagnosticu +Messaghju +7100 +Urdinatore +Reta +Ducumenti +Sistema +7200 +Aghjunghje +Estrae +Verificà +Cupià +Dispiazzà +Squassà +Infurmazione +7300 +Sparte u schedariu +&Sparte in : +Sparte in &vulumi, ottetti : +Spartimentu... +Cunfirmà u Spartimentu +Site sicuru di vulè sparte u schedariu in {0} vulumi ? +A dimensione di u vulume deve esse più chjucu chì u schedariu d'urighjine +Dimensione di vulume falsa +Dimensione di vulume specificata : {0} ottetti.\nSite sicuru di vulè taglià l'archiviu in tali vulumi ? +7400 +Unisce i Schedarii +&Unisce in : +Unione... +Selezziunà solu a prima parte di l'archiviu spartutu +Ùn si trova alcuna parte d'archiviu spartutu +Ùn si trova micca più d'una parte d'archiviu spartutu +7500 +Calculu di a somma di cuntrollu... +Infurmazione nant'à a somma di cuntrollu +Somma di cuntrollu CRC per i dati : +Somma di cuntrollu CRC per i dati è i nomi : +7600 +Sperimentu di pussibilità +Memoria impiegata : +Cumpressione +Scumpressione +Percentuale +Percentuale tutale +Attuale +Risultante +Impiegu CPU +Estimatu / Impiegatu +Passagi : +7700 +Leia +Ligà +Leia d'urigine : +Leia di distinazione : +7710 +Tipu di Leia +Leia Solida +Leia Simbolica di Schedariu +Leia Simbolica di Cartulare +Unione di Cartulare diff --git a/Utils/7-Zip/Lang/cs.txt b/Utils/7-Zip/Lang/cs.txt new file mode 100644 index 000000000..8eb5a2a3d --- /dev/null +++ b/Utils/7-Zip/Lang/cs.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.30 : Milan Hrubý +; 4.33 : Michal Molhanec +; 9.07 : Jiří Malák +; +; +; +; +; +; +; +; +0 +7-Zip +Czech +Čeština +401 +OK +Storno + + + +&Ano +&Ne +Zavří&t +Nápověda + +Po&kračovat +440 +Ano na &všechno +N&e na všechno +Zastavit +Spustit znovu +&Pozadí +P&opředí +Po&zastavit +Pozastaveno +Jste si jistí, že to chcete stornovat? +500 +&Soubor +Úpr&avy +&Zobrazení +&Oblíbené +&Nástroje +Nápo&věda +540 +&Otevřít +Otevřít u&vnitř +Otevřít &mimo +&Zobrazit +&Upravit +&Přejmenovat +Kopírovat &do... +Př&esunout do... +Vymaza&t +&Rozdělit soubor... +&Sloučit soubory... +Vlast&nosti +Poznámk&a +Vypočítat kontrolní součet +Porovnat soubory +Vytvořit složku +Vytvořit soubor +&Konec +600 +Vybrat &vše +Zrušit výběr vše +&Invertovat výběr +Vybrat... +Zrušit výběr... +Vybrat podle typu +Zrušit výběr podle typu +700 +&Velké ikony +&Malé ikony +&Seznam +&Podrobnosti +730 +&Bez třídění +"Ploché" zobrazení +&2 panely +Nástrojové lišty +Otevřít kořenovou složku +O úroveň výš +Historie složek... +&Obnovit +750 +Archivační lišta +Standardní lišta +Velká tlačítka +Zobrazovat text tlačítek +800 +&Přidat složku do oblíbených jako +Záložka +900 +&Možnosti... +&Zkouška výkonu +960 +&Obsah... +O progr&amu 7-Zip... +1003 +Cesta +Název +Přípona +Složka +Velikost +Komprimovaná velikost +Atributy +Vytvořen +Použit +Změněn +Pevný +S poznámkou +Zakódovaný +Rozdělen do +Rozdělen od +Slovník +CRC +Typ +Anti +Metoda +Hostitelský OS +Souborový systém +Uživatel +Skupina +Blok +Poznámka +Pozice +Cesta +Složky +Soubory +Verze +Díl +Vícedílný +Offset +Odkazy +Bloků +Dílů + +64-bit +Big-endian +Pocesor +Fyzická velikost +Velikost hlaviček +Kontrolní součet +Charakteristiky +Virtuální adresa +ID +Krátké jméno +Autor +Velikost sektoru +Režim +Odkaz +Chyba +Celková velikost +Volné místo +Velikost clusteru +Označení +Místní název +Poskytovatel +2100 +Možnosti +Jazyk +Jazyk: +Editor +&Editor: +Program pro &porovnání souborů: +2200 +Systém +Asociovat 7-Zip s: +2301 +&Integrovat 7-Zip do kontextového menu +S&tupňovité kontextové menu +&Položky kontextového menu: +2320 + + +Otevřít +Rozbalit soubory... +Přidat do archivu... +Zkontrolovat archiv +Rozbalit zde +Rozbalit do {0} +Přidat do {0} +Zkomprimovat a odeslat poštou... +Zkomprimovat do {0} a odeslat poštou +2400 +Složky +Pracovní složka +&Systémová složka pro dočasné soubory +&Aktuální +S&ložka: +&Používat pouze pro vyjímatelné disky +Vyberte umístění pro dočasné komprimované soubory. +2500 +Nastavení +Zobrazovat položku ".." +Zobrazovat skutečnou ikonu souboru +Zobrazovat systémové menu +&Vybírat celý řádek +Zobrazovat &mřížku +Otevřít položku jedním kliknutím +&Alternativní způsob výběru +&Používat velké stránky paměti +2900 +O programu 7-Zip +7-Zip je svobodný software. Nicméně můžete podpořit jeho vývoj registrací. +3000 +Systém nemůže přidělit požadovanou velikost paměti +Nedošlo k žádným chybám +vybráno {0} objekt(ů) +Nelze vytvořit složku '{0}' +Aktualizace není podporována pro tento archiv. +Soubor '{0}' nelze otevřít jako archiv +Zakódovaný archiv '{0}' nelze otevřít. Špatné heslo? +Nepodporovaný typ archivu +Soubor {0} již existuje +Soubor '{0}' byl změněn.\nChcete ho aktualizovat v archivu? +Nelze aktualizovat soubor\n'{0}' +Editor nelze spustit. +Soubor se jeví jako virus (ve jménu souboru jsou dlouhé mezery). +Operace nemůže být provedena ze složky s dlouhou cestou. +Musíte vybrat jeden soubor +Musíte vybrat jeden nebo více souborů +Příliš mnoho položek +3300 +Rozbalování +Komprimování +Konrola +Otevírání... +Prohledávání... +3400 +Rozbalit +&Rozbalit do: +Vyberte umístění pro rozbalené soubory. +3410 +Cesty +Plné cesty +Bez cesty +3420 +Způsob přepisování +Zeptat se před přepisem +Přepsat bez výzvy +Přeskočit existující soubory +Automatické přejmenování +Automatické přejmenování existujících souborů +3500 +Potvrzení nahrazení souboru +Cílová složka již obsahuje zpracovaný soubor. +Chcete nahradit existující soubor +tímto? +{0} bajtů +A&utomaticky přejmenovat +3700 +Nepodporovaná komprimační metoda pro '{0}'. +Chyba dat v '{0}'. Soubor je poškozený. +Chyba CRC v '{0}'. Soubor je poškozený. +Chyba dat v zakódovaném souboru '{0}'. Chybné heslo? +Chyba CRC v zakódovaném souboru '{0}'. Chybné heslo? +3800 +Vložit heslo +Vložit heslo: +Potvrzení hesla: +Zobrazit he&slo +Heslo nesouhlasí +Pro heslo použíjte pouze anglická písmena, číslice a speciální znaky (!, #, $, ...) +Heslo je příliš dlouhé +Heslo +3900 +Uplynulý čas: +Zbývající čas: +Celková velikost: +Rychlost: +Zpracováno: +Komprimační poměr: +Chyb: +Archívy: +4000 +Přidat do archivu +&Archiv: +Způsob aktualizace: +&Formát archivu: +Ú&roveň komprese: +&Komprimační metoda: +Ve&likost slovníku: +V&elikost slova: +Velikost bloku: +Počet vláken procesoru: +&Parametry: +Možnosti +Vytvořit SF&X archiv +Zkomprimovat otevřené soubory +Zakódování +Metoda zakódování: +Zakódovat &názvy souborů +Spotřeba paměti pro zabalení: +Spotřeba paměti pro rozbalení: +4050 +Skladovací +Nejrychlejší +Rychlá +Normální +Maximální +Ultra +4060 +Přidat a nahradit soubory +Aktualizovat a přidat soubory +Aktualizovat existující soubory +Synchronizovat soubory +4070 +Procházet +Všechny soubory +Podle velikosti souboru +Pevný +6000 +Kopírovat +Přesunout +Kopírovat do: +Přesunout do: +Kopírování... +Přesouvání... +Přejmenování... +Vyberte cílovou složku. +Operace není podporována. +Chyba při přejmenování souboru nebo složky +Potvrzení kopírování souborů +Jste si jistí, že chcete zkopírovat soubory do archivu +6100 +Potvrdit vymazání souboru +Potvrdit vymazání složky +Potvrdit mnohonásobné vymazání souboru +Jste si jistí, že chcete vymazat '{0}'? +Jste si jistí, že chcete vymazat složku '{0}' a všechno co obsahuje? +Jste si jistí, že chcete vymazat tyto {0} položky? +Mazání... +Chyba při mazání souboru nebo složky +Systém nepodporuje přesun soubor s dlouhou cestou do Odpadkového koše +6300 +Vytvořit složku +Vytvořit soubor +Název složky: +Název souboru: +Nová složka +Nový soubor +Chyba při vytváření složky +Chyba při vytváření souboru +6400 +Poznámka +&Poznámka: +Vybrat +Zrušit výběr +Maska: +6600 +Vlastnosti +Historie složek +Diagnostické zprávy +Zpráva +7100 +Počítač +Síť +Dokumenty +Systém +7200 +Přidat +Rozbalit +Zkontrolovat +Kopírovat +Přesunout +Vymazat +Informace +7300 +Rozdělit soubor +Rozdělit do: +Rozdělit na díly, bajtů: +Rozdělování... +Potvrdit rozdělování +Jste si jistí, že chcete rozdělit soubor na {0} dílů? +Velikost dílu musí být menší než velikost původního souboru +Nesprávná velikost dílu +Zadaná velikost dílu: {0} bytů.\nJste si jistí, že chcete rozdělit archiv do takových dílů? +7400 +Sloučit soubory +Sloučit do: +Slučování... +Musí se vybrat pouze první díl rozděleného soubor +Nepodařilo se rozpoznat rozdělený soubor +Nepodařilo se nalézt více než jeden díl rozděleného souboru +7500 +Vypočítávání kontrolního součtu... +Informace o kontrolním součtu +CRC kontrolní součet pro data: +CRC kontrolní součet pro data a jména: +7600 +Zkouška výkonu +Spotřeba paměti: +Komprimování +Rozbalování +Výkon +Celkový výkon +Aktuální +Výsledné +Využití procesoru +Výkon / Využití +Průchodů: diff --git a/Utils/7-Zip/Lang/cy.txt b/Utils/7-Zip/Lang/cy.txt new file mode 100644 index 000000000..38be91b3b --- /dev/null +++ b/Utils/7-Zip/Lang/cy.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.37 : Owain Lewis +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Welsh +Cymraeg +401 +Iawn +Canslo + + + +&Iawn +&Na +&Cau +Cymorth + +P&arhau +440 +Iawn i'r &Cwbwl +Na i'r C&wbwl +Stopio +Ailgychwyn +&Cefndir +&Blaendir +&Pwyllo +Pwyllo +Ydych chi am canslo? +500 +&Ffeil +&Golygu +Gwe&ld +Ff&efrynnau +&Offer +&Cymorth +540 +&Agor +Agor tu &Mewn +Agor tu &Fas +Gwe&ld +&Golygu +A&ilenwi +&Copïo i... +&Symud i... +&Dileu +&Hollti ffeil... +Cy&funo ffeilau... +&Priodweddau +Syl&wad +Cyfrifo swm-gwirio + +Creu Ffolder +Creu Ffeil +Alla&n +600 +Dewis y C&yfan +Dad-ddewis y Cyfan +Gwrt&hdroi'r Dewis +Dewis... +Dad-ddewis... +Dewis trwy Math +Dad-ddewis trwy Math +700 +Eiconau &Mawr +Eiconau &Bach +&Rhestr +Ma&nylion +730 +Dad-dosbarthu +Golwg Flat +&2 Paneli +Bariau &Offer +Agor Ffolder Gwraidd +Lan Un Lefel +Hanes Ffolderi... +&Adnewyddu +750 +Bar Offer Archif +Bar Offer Arferol +Botwmau Fawr +Dangos Testun Botwmau +800 +&Ychwanegu ffolder i Ffefrynnau fel +Llyfrnod +900 +&Dewisiadau... +&Meincnod +960 +&Cynnwys... +&Manylion 7-Zip... +1003 +Llwybr +Enw +Estyniad +Ffolder +Maint +Maint wedi'i Cywasgu +Priodweddau +Crëwyd +Cyrchwyd +Addaswyd +Solet +Sylwad +Amgryptio +Hollti Cyn +Hollti ar Ôl +Geiriadur +CRC +Math +Anti +Dull +SW Cynnal +System Ffeiliau +Ddefnyddiwr +Grŵp +Bloc +Sylwad +Safle +Rhagddodiad y Llwybr + + + + + + + + + + + + + + + + + + + + + + + + +Gwall +Cyfanswm Maint +Lle Rhydd +Maint Clwstwr +Label +Enw Lleol +Darparwr +2100 +Dewisiadau +Iaith +Iaith: +Golygydd +&Golygydd: + +2200 +System +Cysylltu 7-Zip gyda: +2301 +Cyfuno 7-Zip mewn i dewislen cyd-destun y cribyn +Dewislen cyd-destun wedi'i rhaeadru +Eitemau dewislen cyd-destun: +2320 + + +Agor archif +Echdynnu ffeiliau... +Ychwanegu i'r archif... +Profi archif +Echdynnu Yma +Echdynnu i {0} +Ychwanegu i {0} +Cywasgu ac e-bostio... +Cywasgu i {0} ac e-bostio +2400 +Ffolderi +Ffolder &gweithio +Ffolder tymor byr y &system +&Cyfredol +&Penodol: +Defnyddiwch am gyriant symudadwy yn unig +Nodwch lleoliad am ffeiliau archif tymor byr. +2500 +Gosodiadau +Dangos eitem ".." +Dangos eicon ffeil go iawn +Dangos dewislen y system +Dethol &holl rhes +Dangos llinellau &grid + +Modd dethol &arallddewisiol +Defnyddiwch tudalenau cof &mawr +2900 +Manylion 7-Zip +Mae 7-Zip yn meddalwedd am ddim. Ond, gallwch cefnogi y \ndatblygiad o 7-Zip trwy cofrestru. +3000 + +Mae na ddim wallau +{0} gwrthrych(au) dethol +Ddim yn gallu creu y ffolder '{0}' +Mae gweithrediadau diweddaru ddim yn ateg am yr archif hyn. + + + + +Roedd ffeil '{0}' wedi'i addasu.\nWyt ti moen ei diweddaru yn yr \narchif? +Ddim yn gallu diweddaru ffeil\n'{0}' +Ddim yn gallu dechrau golygydd. + + + + +Gormod o eitemau +3300 +Echdynnu +Cywasgu +Ymbrofi +Agor... +Sganio... +3400 +Echdynnu +E&chdynnu i: +Nodwch lleoliad am echdynnu ffeiliau. +3410 +Modd llwybr +Enwau llwybr llawn +Dim enwau llwybr +3420 +Modd disodli +Gofyn cyn disodli +Disodli heb awgrymeb +Crychneidio ffeiliau presennol +Ailenwu yn awtomatig +Ailenwu ffeiliau presennol yn awtomatig +3500 +Cadarnhau Disodli Ffeil +Mae'r ffolder hon eisioes yn cynnwys y ffeil cyrchfan. +Hoffech chi ddisodli'r ffeil sy'n bodoli eisioes +Gyda hon? +{0} beit +Ailenwi A&wtomatig +3700 +Modd cywasgu ddim yn dilys am '{0}'. +Gwall data mewn '{0}'. Ffeil wedi'i torri. +CRC wedi'i methu mewn '{0}'. Ffeil wedi'i torri. + + +3800 +Mewnbynnwch cyfrinair +Mewnbynnwch cyfrinair: + +&Dangos cyfrinair + + + +Cyfrinair +3900 +Wedi treiglo: +Amser a'r ôl: +Maint: +Cyflymder: + + +Gwallau: + +4000 +Ychwanegu i'r archif +&Archif: +Modd &diweddaru: +&Fformat yr archif: +&Lefel cywasgu: +Dull &cywasgu: +Maint &geiriadur: +Maint geiria&u: + + +&Paramedrau: +Dewisiadau +Creu archif SF&X + + + +Amgryptio &enwau ffeiliau +Defnydd cof am Cywasgu: +Defnydd cof am Datgywasgu: +4050 +Storio +Cyflymach +Cyflum +Arferol +Uchafswm +Ultra +4060 +Ychwanegu ac amnewid ffeiliau +Diweddaru ac ychwanegu ffeiliau +Adnewyddu y ffeiliau presennol +Cyfamseru ffeiliau +4070 +Pori +Pob Ffeil + + +6000 +Copïo +Symud +Copïo i: +Symud i: +Copïo... +Symud... +Ailenwi... + +Mae'r gweithrediad ddim wedi'i ategu. +Gwall wrth Ailenwi Ffeil neu Ffolder +Cadarnhau Copi Ffeil +Ydych chi'n siŵr eich bod am copïo'r ffeiliau i'r archif +6100 +Cadarnhau Dileu Ffeil +Cadarnhau Dileu Ffolder +Cadarnhau Dileu Ffeiliau Amryfal +Ydych chi'n siŵr eich bod am dileu '{0}'? +Ydych chi'n siŵr eich bod am dileu y ffolder '{0}' ac ei holl \ncynnwys? +Ydych chi'n siŵr eich bod am dileu yr eitemau hyn {0}? +Dileu... +Gwall Dileu Ffeil neu Ffolder + +6300 +Creu Ffolder +Creu Ffeil +Enw Ffolder: +Enw Ffeil: +Ffolder Newydd +Ffeil Newydd +Gwall wrth Creu Ffolder +Gwall wrth Creu Ffeil +6400 +Sylwad +&Sylwad: +Dewis +Dad-ddewis +Mwgwd: +6600 + +Hanes Ffolderi +Neges diagnostig +Neges +7100 +Cyfrifiadur +Rhyngrwyd + +System +7200 +Ychwanegu +Echdynnu +Profi +Copïo +Symud +Dileu +Gwybodaeth +7300 +Hollti Ffeil +&Hollti i: +Hollti i &cyfeintiau, beitiau: +Hollti... + + + + + +7400 +Cyfuno Ffeiliau +&Cyfuno i: +Cyfuno... + + + +7500 +Cyfrifo swm-gwirio... +Gwybodaeth swm-gwirio +Swm-gwirio CRC am data: +Swm-gwirio CRC am data ac enwau: +7600 +Meincnod +Defnyddiad cof: +Cywasgu +Datgywasgu +Amcangyfrif +Amcangyfrif llwyr +Presennol +Canlyniad + + +Pasio: diff --git a/Utils/7-Zip/Lang/da.txt b/Utils/7-Zip/Lang/da.txt new file mode 100644 index 000000000..563b1978a --- /dev/null +++ b/Utils/7-Zip/Lang/da.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Jakob Schmidt +; 9.07 : Kian Andersen, Jørgen Rasmussen +; 15.00 : 2016-08-19 : scootergrisen +; +; +; +; +; +; +; +; +0 +7-Zip +Danish +Dansk +401 +OK +Annuller + + + +&Ja +&Nej +&Luk +Hjælp + +&Fortsæt +440 +Ja til &alle +Nej til a&lle +Stop +Genstart +&Baggrund +&Forgrund +&Pause +Pauset +Er du sikker på, at du vil annullere? +500 +&Filer +R&ediger +&Vis +F&avoritter +Funk&tioner +&Hjælp +540 +&Åbn +Åbn &inden i +Åbn &uden for +&Vis +&Rediger +O&mdøb +&Kopier til... +&Flyt til... +S&let +&Opdel fil... +Kom&biner filer... +&Egenskaber +Komme&ntar... +Udregn checksum +Sammenlign +Opret mappe +Opret fil +&Afslut +Opret/rediger henvisning +&Alternative strømme +600 +Vælg &alle +Fravælg alle +&Omvendt markering +Vælg... +Fravælg... +Vælg efter type +Fravælg efter type +700 +Sto&re ikoner +S&må ikoner +&Liste +&Detaljer +730 +Usorteret +Flad visning +&2 paneler +&Værktøjslinjer +Åbn rodmappe +Et niveau op +Mappehistorik... +&Opdater +Opdater automatisk +750 +Arkivlinje +Standardlinje +Store knapper +Vis knappernes tekst +800 +&Føj mappe til Favoritter som +Bogmærke +900 +&Funktioner... +&Benchmark +960 +&Indhold... +&Om 7-Zip... +1003 +Sti +Navn +Filtype +Mappe +Størrelse +Pakket størrelse +Attributter +Oprettet +Åbnet +Ændret +Solid +Kommenteret +Krypteret +Opdel før +Opdel efter +Leksikon + +Type +Anti +Metode +Vært OS +Filsystem +Bruger +Gruppe +Blok +Kommentar +Placering +Sti præfiks +Mapper +Filer +Version +Bind +Flerbindsarkiv +Forskydning +Henvisning +Blokke +Bind + +64-bit +Big-endian +CPU +Fysisk størrelse +Hovedernes størrelse +Checksum +Karakteristika +Virtuel adresse +ID +Kort navn +Oprettende program +Sektorstørrelse +Tilstand +Symbolsk henvisning +Fejl +Samlet størrelse +Fri plads +Klyngestørrelse +Etiket +Lokalt navn +Udbyder +NT Security +Alternativ strøm +Aux +Slettet +Er træ + + +Fejltype +Fejl +Fejl +Advarsler +Advarsel +Strømme +Alternative strømme +Størrelse på alternative strømme +Virtuel størrelse +Udpakket størrelse +Samlet fysiske størrelse +Bind-indeks +Undertype +Kort kommentar +Tegnsæt + + + +Halestørrelse +Indlejret stumpstørrelse +Henvisning +Fast henvisning +iNode + +Skrivebeskyttet +2100 +Funktioner +Sprog +Sprog: +Redigering +&Rediger: +&Sammenlign: +2200 +System +Knyt 7-Zip til: +Alle brugere +2301 +Vis i Windows genvejsmenu +Brug undermenu +Punkter i genvejsmenu: +Ikoner i genvejsmenu +2320 + + +Åbn arkiv +Udpak filer... +Føj til arkiv... +Test arkiv +Udpak her +Udpak til {0} +Føj til {0} +Komprimer og vedhæft i e-mail... +Komprimer til {0} og vedhæft i e-mail +2400 +Mapper +&Arbejdsmappe +&Systemets midlertidige mappe +&Aktuelle +&Brugerdefineret: +Brug kun til flytbare drev +Angiv en placering til midlertidige arkivfiler. +2500 +Indstillinger +Vis ".."-element +Vis rigtige filikoner +Vis systemmenu +&Marker hele rækken +Vis &gitter +Åbn element med ét klik +&Alternativ markeringsmetode +Brug &store hukommelsessider +2900 +Om 7-Zip +7-Zip er fri software +3000 +Systemet kan ikke tildele den nødvendige mængde hukommelse +Der er ingen fejl +{0} markerede element(er) +Kan ikke oprette mappen "{0}" +Arkivet understøtter ikke opdateringshandlinger. +Kan ikke åbne filen "{0}" som arkiv +Kan ikke åbne det krypterede arkiv "{0}". Forkert adgangskode? +Arkivtypen er ikke understøttet +Filen {0} findes allerede +Filen "{0}" er blevet ændret.\nVil du opdatere den i arkivet? +Kan ikke opdatere filen\n"{0}" +Kan ikke starte redigering. +Filen ligner en virus (filnavnet indeholder lange mellemrum i navn). +Handlingen kan ikke kaldes fra en mappe som har en lang sti. +Du skal vælge en fil +Du skal vælge en eller flere filer +For mange elementer +Kan ikke åbne filen som {0}-arkiv +Filen er åbnet som {0}-arkiv +Arkivet er åbnet med forskydning +3300 +Udpakker +Komprimerer +Tester +Åbner... +Skanner... +Fjerner +3320 +Tilføjer +Opdaterer +Analyserer +Replikerer +Ompakker +Springer over +Sletter +Opretter hovede +3400 +Udpak +U&dpak til: +Angiv en placering til udpakkede filer. +3410 +Stitilstand: +Fulde stinavne +Ingen stinavne +Absolutte stinavne +Relative stinavne +3420 +Overskrivningstilstand: +Spørg før overskrivning +Overskriv uden at spørge +Spring eksisterende filer over +Automatisk omdøbning +Automatisk omdøbning af eksisterende filer +3430 +Forhindr duplikering af rodmappe +Genskab filsikkerhed +3500 +Bekræft filerstatning +Destinationsmappen indeholder allerede behandlet fil. +Vil du erstatte den eksisterende fil +med denne? +{0} byte +A&utomatisk omdøbning +3700 +Komprimeringsmetode for "{0}" er ikke understøttet. +Datafejl i "{0}". Filen er ødelagt. +CRC mislykkedes i "{0}". Filen er ødelagt. +Datafejl i den krypterede fil "{0}". Forkert adgangskode? +CRC mislykkedes i den krypterede fil "{0}". Forkert adgangskode? +3710 +Forkert adgangskode? +3721 +Komprimeringsmetoden er ikke understøttet +Datafejl +CRC mislykkedes +Utilgængelig data +Uventet slutning på data +Der er data efter slutningen af nyttedataene +Ikke et arkiv +Fejl i hoveder +Forkert adgangskode +3763 +Utilgængelig begyndelse på arkiv +Ubekræftet begyndelse på arkiv + + + +Faciliteten understøttes ikke +3800 +Indtast adgangskode +Indtast adgangskode: +Indtast adgangskode igen: +&Vis adgangskode +Adgangskoderne er ikke ens +Brug kun engelske bogstaver, numre og specialtegn (!, #, $, ...) til adgangskoden +Adgangskoden er for lang +Adgangskode +3900 +Forløbet tid: +Resterende tid: +Samlet størrelse: +Hastighed: +Behandlet: +Komprimeringsforhold: +Fejl: +Arkiver: +4000 +Føj til arkiv +&Arkiv: +O&pdateringstilstand: +Arkiv&format: +Komprimerings&niveau: +Komprimerings&metode: +Størrelse på or&dbog: +Størrelse på &ord: +Størrelse på solid blok: +Antal CPU-tråde: +Pa&rametre: +Funktioner +Opret SF&X-arkiv +Komprimer delte filer +Kryptering +Krypteringsmetode: +Kr&ypter filnavne +Hukommelsesforbrug ved komprimering: +Hukommelsesforbrug ved udpakning: +Slet filer efter komprimering +4040 +Gem symbolske henvisninger +Gem hårde henvisninger +Gem alternative datastrømme +Gem filsikkerhed +4050 +Gem +Hurtigst +Hurtig +Normal +Maksimum +Ultra +4060 +Tilføj og erstat filer +Opdater og tilføj filer +Opdater eksisterende filer +Synkroniser filer +4070 +Gennemse +Alle filer +Ikke-solid +Solid +6000 +Kopier +Flyt +Kopier til: +Flyt til: +Kopierer... +Flytter... +Omdøber... +Vælg destinationsmappen. +Handlingen understøttes ikke af denne mappe. +Fejl under omdøbning af fil eller mappe +Bekræft kopiering af fil +Er du sikker på, at du vil kopiere filer til arkiv +6100 +Bekræft sletning af fil +Bekræft sletning af mappe +Bekræft sletning af flere filer +Er du sikker på, at du vil slette "{0}"? +Er du sikker på, at du vil slette mappen "{0}" og alt dens indhold? +Er du sikker på, at du vil slette disse {0} elementer? +Sletter... +Fejl under sletning af fil eller mappe +Systemet kan ikke flytte en fil med lang sti til Papirkurven +6300 +Opret mappe +Opret fil +Mappenavn: +Filnavn: +Ny mappe +Ny fil +Fejl under oprettelse af mappe +Fejl under oprettelse af fil +6400 +Kommentar +&Kommentar: +Vælg +Fravælg +Maske: +6600 +Egenskaber +Mappers historik +Diagnostiske meddelelser +Meddelelse +7100 +Computer +Netværk +Dokumenter +System +7200 +Tilføj +Udpak +Test +Kopier +Flyt +Slet +Info +7300 +Opdel fil +&Opdel til: +Opd&el i bind, byte: +Opdeler... +Bekræft opdeling +Er du sikker på, at du vil opdele filen i {0} bind? +Størrelsen på bind skal være mindre end størrelsen på den oprindelige fil +Forkert størrelse på bind +Angivet størrelse på bind: {0} byte.\nEr du sikker på, at du vil opdele arkivet i disse bind? +7400 +Kombiner filer +&Kombiner til: +Kombinerer... +Vælg kun første del af opdelt fil +Kan ikke genkende fil, som del af opdelt fil +Kan ikke finde mere end én del af opdelt fil +7500 +Beregner checksum... +Checksum information +CRC-checksum for data: +CRC-checksum for data og navne: +7600 +Benchmark +Hukommelsesforbrug: +Komprimering +Udpakning +Vurdering +Samlet vurdering +Aktuelt +Resultat +CPU forbrug +Vurdering/forbrug +Gennemløb: +7700 +Opret/rediger henvisning +Opret/rediger henvisning +Henvisning fra: +Henvisning til: +7710 +Henvisningstype +Fast henvisning +Fil symbolsk henvisning +Mappe symbolsk henvisning +Mappe forbindelsespunkt diff --git a/Utils/7-Zip/Lang/de.txt b/Utils/7-Zip/Lang/de.txt new file mode 100644 index 000000000..828dd17d6 --- /dev/null +++ b/Utils/7-Zip/Lang/de.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 2.30 : Soeren Finster +; 4.07 : JAK-Software.DE +; 9.07 : Joachim Henke +; +; +; +; +; +; +; +; +0 +7-Zip +German +Deutsch +401 +OK +Abbrechen + + + +&Ja +&Nein +&Schließen +Hilfe + +&Fortsetzen +440 +Ja für &alle +Nein für a&lle +Stopp +Neustart +&Hintergrund +&Vordergrund +&Pause +Pause +Möchten Sie wirklich abbrechen? +500 +&Datei +&Bearbeiten +&Ansicht +&Favoriten +&Extras +&Hilfe +540 +Ö&ffnen +I&ntern öffnen +E&xtern öffnen +&Ansehen +&Bearbeiten +&Umbenennen +&Kopieren nach... +&Verschieben nach... +&Löschen +Datei auf&splitten... +Dateien &zusammenfügen... +E&igenschaften +K&ommentieren +&Prüfsumme berechnen +Ver&gleichen +Ordner erstellen +Datei erstellen +Be&enden +Verknüpfung... +&Alternative Datenströme +600 +Alles &markieren +Alles abwählen +Markierung &umkehren +Auswählen... +Auswahl aufheben... +Nach Typ auswählen +Nach Typ abwählen +700 +&Große Symbole +&Kleine Symbole +&Liste +&Details +730 +Unsortiert +Alles in einer &Ebene +&Zweigeteiltes Fenster +&Symbolleisten +Wurzelverzeichnis +Übergeordneter Ordner +Ordnerverlauf... +&Aktualisieren +Auto-Aktualisierung +750 +Archivfunktionen +Standardfunktionen +Große Schaltflächen +Schaltflächenbeschriftung +800 +&Ordner hinzufügen als +Favorit +900 +&Optionen... +&Benchmark +960 +&Hilfethemen +Ü&ber 7-Zip... +1003 +Pfad +Name +Erweiterung +Ordner +Größe +Gepackte Größe +Attribute +Erstellt am +Letzter Zugriff +Geändert am +Kompakt (solid) +Kommentiert +Verschlüsselt +Vorher geteilt +Danach geteilt +Wörterbuch +CRC +Typ +Anti +Verfahren +Herkunft +Dateisystem +Besitzer +Gruppe +Block +Kommentar +Position +Pfad +Ordner +Dateien +Version +Teilarchiv +Mehrteiliges Archiv +Offset +Verknüpfungen +Blöcke +Teilarchive + +64 Bit +Big-Endian +CPU +Gesamtgröße +Header-Größe +Prüfsumme +Kenndaten +Virtuelle Adresse +ID +Kurzname +Erstellt durch +Sektorgröße +Zugriffsrechte +Link +Fehler +Gesamtgröße +Freier Speicherplatz +Cluster-Größe +Name +Lokaler Name +Provider +NT-Sicherheit +Alternativer Datenstrom +Aux +Gelöscht +Ist Baum + + +Fehlertyp +Fehler +Fehler +Warnungen +Warnung +Datenströme +Alternative Datenströme +Größe der alternativen Datenströme +Virtuelle Größe +Entpackte Größe +Gesamte physikalische Größe +Teilstück Index +Untertyp +Kurzkommentar +Code-Seite + + + +Endungsgröße +integrierte Stub-Größe +Verknüpfung +Harte Verknüpfung +iNode + +Schreibgeschützt +2100 +Optionen +Sprache +Sprache: +Editor +&Editor: +Programm zum &Vergleichen: +2200 +System +7-Zip verknüpfen mit: +alle Benutzer +2301 +7-Zip in Kontextmenü integrieren +Kontextmenü kaskadieren +Einträge im Kontextmenü: +Symbole im Kontextmenü +2320 + + +Öffnen +Dateien entpacken... +Zu einem Archiv hinzufügen... +Archiv überprüfen +Hier entpacken +Entpacken nach {0} +Hinzufügen zu {0} +Archivieren und versenden... +Archivieren in {0} und versenden +2400 +Ordner +&Arbeitsverzeichnis +&TEMP-Ordner des Systems +Aktueller &Ordner +&Benutzerdefiniert: +Nur bei &Wechselmedien benutzen +Wählen Sie einen Ordner für temporäre Archivdateien: +2500 +Einstellungen +&Verzeichniseintrag ".." anzeigen +Symbole aus &Dateien laden und anzeigen +System-Kontext&menü im Dateimenü anzeigen +Dateiauswahl markiert ganze &Zeile +&Gitternetzlinien anzeigen +Einfacher &Klick zum Öffnen +&Alternativer Dateiauswahl-Modus +Große &Speicherseiten verwenden +2900 +Info über 7-Zip +7-Zip ist freie Software. Sie können jedoch das Projekt durch eine Registrierung unterstützen. +3000 +Das System kann die benötigte Speichermenge nicht bereit stellen. +Es sind keine Fehler aufgetreten. +{0} Objekt(e) markiert +Kann den Ordner "{0}" nicht erstellen. +Aktualisierungen werden für dieses Archiv nicht unterstützt. +Die Datei "{0}" kann nicht als Archiv geöffnet werden. +Das verschlüsselte Archiv "{0}" kann nicht geöffnet werden. Falsches Passwort? +Typ des Archives wird nicht unterstützt +Die Datei {0} existiert bereits. +Die Datei "{0}" wurde geändert.\nSoll sie im Archiv aktualisiert werden? +Die Datei konnte nicht aktualisiert werden.\n"{0}" +Kann Editor nicht starten +Die Datei scheint ein Virus zu sein (Dateiname enthält lange Reihen von Leerzeichen). +Die Operation kann nicht aus einem Ordner mit langem Pfad aufgerufen werden. +Bitte genau eine Datei auswählen. +Bitte mindestens eine Datei auswählen. +Zu viele Objekte +Die Datei kann nicht als {0}-Archiv geöffnet werden. +Die Datei wurde als {0}-Archiv geöffnet. +Die Datei wurde mit einem Offset geöffnet. +3300 +Entpacken +Komprimiere +Überprüfen +Öffne... +Durchsuche... +Entferne +3320 +Hinzufügen +Aktualisieren +Analysieren +Replizieren +Neu Packen +Überspringen +Löschen +Header erstellen +3400 +Entpacken +&Entpacken nach: +Wählen Sie einen Ordner für die entpackten Dateien: +3410 +Verzeichnisstruktur wiederherstellen +Komplette Pfadangaben +Keine Pfadangaben +Absolute Pfadangaben +Relative Pfadangaben +3420 +Dateien überschreiben +Nur mit Bestätigung +Ohne Bestätigung +Vorhandene Dateien überspringen +Automatisch umbenennen +Vorhandene Dateien umbenennen +3430 +Verdoppelung des Wurzelordners vermeiden +Dateirechte wiederherstellen +3500 +Überschreiben bestätigen +Der Zielordner beinhaltet bereits eine Datei diesen Namens. +Wollen Sie diese Datei +durch diese ersetzen? +{0} Bytes +A&utomatisch umbenennen +3700 +Das Kompressionsverfahren in "{0}" wird nicht unterstützt. +Datenfehler in "{0}". Die Datei ist beschädigt. +CRC-Prüfsummenfehler. Die Datei "{0}" ist beschädigt. +Datenfehler in der verschlüsselten Datei "{0}". Falsches Passwort? +CRC-Prüfsummenfehler bei verschlüsselter Datei "{0}". Falsches Passwort? +3710 +Falsches Passwort? +3721 +Nicht unterstützte Kompressionsmethode +Datenfehler +CRC-Fehler +Daten stehen nicht zur Verfügung +Unerwartetes Datenende +Es gibt noch Daten hinter den Hauptdaten +Ist kein Archiv +Headers-Fehler +Falsches Passwort +3763 +Anfang des Archivs fehlt +Anfang des Archivs nicht bestätigt + + + +Nicht unterstützte Funktion +3800 +Kennworteingabe +Passwort eingeben: +Passwort bestätigen: +Passwort an&zeigen +Die Passwörter stimmen nicht überein. +Bitte nur Buchstaben des englischen Alphabets, Ziffern und Sonderzeichen (!, #, $, ...) im Passwort verwenden! +Das Passwort ist zu lang. +Passwort +3900 +Verstrichene Zeit: +Verbleibende Zeit: +Gesamtdatenmenge: +Geschwindigkeit: +Verarbeitet: +Kompressionsrate: +Fehler: +Archive: +4000 +Zu Archiv hinzufügen +&Archiv: +Art der Akt&ualisierung: +Archiv&format: +&Kompressionsstärke: +Kompressions&verfahren: +Wörter&buchgröße: +&Wortgröße: +Größe &solider Blöcke: +Anzahl &CPU-Threads: +&Parameter: +Optionen +Selbstentpackendes Archiv (SF&X) erstellen +Zum Schreiben &geöffnete Dateien einbeziehen +Verschlüsselung +Verfahren: +Datei&namen verschlüsseln +Speicherbedarf beim Komprimieren: +Speicherbedarf beim Entpacken: +Dateien nach Komprimierung löschen +4040 +Symbolische Verknüpfungen speichern +Harte Verknüpfungen speichern +Alternative Datenströme speichern +Dateirechte speichern +4050 +Speichern +Schnellste +Schnell +Normal +Maximum +Ultra +4060 +Hinzufügen und Ersetzen +Aktualisieren und Hinzufügen +Vorhandene Dateien aktualisieren +Synchronisieren +4070 +Durchsuchen +Alle Dateien +Nicht solide +Solide +6000 +Kopieren +Verschieben +Kopieren nach: +Verschieben nach: +Kopiere... +Verschiebe... +Umbenennen... +Zielordner auswählen +Die Operation wird für diesen Ordner nicht unterstützt. +Fehler beim Umbenennen von Datei oder Ordner +Kopieren bestätigen +Sollen die Dateien wirklich in dieses Archiv kopiert werden: +6100 +Löschen von Datei bestätigen +Löschen von Ordner bestätigen +Löschen von mehreren Dateien bestätigen +Soll "{0}" wirklich gelöscht werden? +Soll der Ordner "{0}" und sein gesamter Inhalt wirklich gelöscht werden? +Sollen diese {0} Objekte wirklich gelöscht werden? +Lösche... +Fehler beim Löschen von Datei oder Ordner +Das System kann Dateien mit langem Pfad nicht in den Papierkorb verschieben. +6300 +Ordner erstellen +Datei erstellen +Ordnername: +Dateiname: +Neuer Ordner +Neue Datei +Fehler beim Erstellen des Ordners +Fehler beim Erstellen der Datei +6400 +Kommentar +&Kommentar: +Auswählen +Auswahl aufheben +Filter: +6600 +Eigenschaften +Ordnerverlauf +Diagnosemeldungen +Meldung +7100 +Arbeitsplatz +Netzwerk +Dokumente +System +7200 +Hinzufügen +Entpacken +Überprüfen +Kopieren +Verschieben +Löschen +Eigenschaften +7300 +Datei aufsplitten +Teildateien &nach: +In &Teildateien aufsplitten (Bytes): +Aufsplitten... +Aufsplitten bestätigen +Sind Sie sicher, die Datei in {0} Teildateien aufsplitten zu wollen? +Die Größe der Teildateien muss kleiner sein als die der ursprünglichen Datei. +Ungültiger Wert für Dateigrößen +Angegebene Größe für Teildateien: {0} Bytes.\nSind Sie sicher, dass das Archiv dementsprechend aufgesplittet werden soll? +7400 +Dateien zusammenfügen +Zieldatei &nach: +Zusammenfügen... +Bitte nur den ersten Teil der Datei auswählen. +Datei nicht als Teil einer aufgesplitteten Datei erkannt +Kann nicht mehr als eine Teildatei finden. +7500 +Berechne Prüfsumme... +Prüfsummen-Information +CRC-Prüfsumme über die Daten: +Prüfsumme über Daten und Namen: +7600 +Benchmark +Speichernutzung: +Komprimierung +Dekomprimierung +Bewertung +Gesamtwertung +Aktuell +Ergebnis +CPU-Nutzung +Bewert./Nutzung +Durchläufe: +7700 +Verknüpfung +Verknüpfung +Verknüpfung von: +Verknüpfung zu: +7710 +Verknüpfungsart +Harte Verknüpfung +Datei Symbolische Verknüpfung +Ordner Symbolische Verknüpfung +Ordner Verbindung diff --git a/Utils/7-Zip/Lang/el.txt b/Utils/7-Zip/Lang/el.txt new file mode 100644 index 000000000..faa7b3650 --- /dev/null +++ b/Utils/7-Zip/Lang/el.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Vasileios Karakoidas, Jacaranda Bill, Vasilis Kosmidis +; 9.07 : SkyHi [HDManiacs Team] +; 15.00 : 2015-05-07: Pete D +; +; +; +; +; +; +; +; +0 +7-Zip +Greek +Ελληνικά +401 +OK +Άκυρο + + + +&Ναι +Ό&χι +&Κλείσιμο +Βοήθεια + +&Συνέχεια +440 +Ναι σε &όλα +Όχι σε ό&λα +&Παύση +Επανεκκίνηση +Στο &παρασκήνιο +Στο &προσκήνιο +&Παύση +Παύθηκε +Είστε σίγουροι ότι θέλετε να ακυρώσετε; +500 +&Αρχείο +&Επεξεργασία +Π&ροβολή +Αγα&πημένα +Εργα&λεία +&Βοήθεια +540 +Άν&οιγμα +Άνοιγμα στο &ίδιο παράθυρο +Άνοιγμα σε &νέο παράθυρο +Π&ροβολή +Επε&ξεργασία +Με&τονομασία +Αντι&γραφή... +Μετα&κίνηση... +Διαγρα&φή +&Τεμαχισμός αρχείου... +&Συνένωση αρχείων... +&Ιδιότητες +Σχόλιο +Υπολογισμός αθροίσματος ελέγχου +Diff +Δημιουργία φακέλου +Δημιουργία αρχείου +Έ&ξοδος +Σύνδεσμος +&Alternate Streams +600 +Ε&πιλογή όλων +Αποεπιλογή όλων +Αντιστροφή επιλογής +Επιλογή... +Αποεπιλογή... +Επιλογή σύμφωνα με τον τύπο αρχείου +Αποεπιλογή σύμφωνα με τον τύπο αρχείου +700 +Μεγάλα εικονί&δια +&Μικρά εικονίδια +&Λίστα +Λε&πτομέρειες +730 +Χωρίς ταξινόμηση +Επίπεδη προβολή +2 πάνελ +&Γραμμές εργαλείων +Άνοιγμα κεντρικού φακέλου +Μετάβαση ένα επίπεδο πάνω +&Ιστορικό φακέλων... +Α&νανέωση +Αυτόματη ανανέωση +750 +Συμπίεσης +Βασική +Μεγάλα εικονίδια +Εμφάνιση κειμένου +800 +&Προσθήκη καταλόγου στα Αγαπημένα ως +Σελιδοδείκτης +900 +&Ρυθμίσεις... +&Ελεγχος επιδόσεων +960 +&Περιεχόμενα... +Π&ερί του 7-Zip... +1003 +Θέση +Όνομα +Τύπος +Φάκελος +Μέγεθος +Συμπιεσμένο μέγεθος +Ιδιότητες +Δημιουργήθηκε +Προσπελάστηκε +Τροποποιήθηκε +Συμπαγές +Σχόλιο +Κωδικοποιημένο +Τεμαχισμός πριν +Τεμαχισμός μετά +Λεξικό + +Τύπος +Αντί +Μέθοδος +Λειτουργικό +Σύστημα αρχείων +Χρήστης +Ομάδα +Μπλοκ +Σχόλιο +Θέση +Προκαθορισμένη διαδρομή +Φάκελοι +Αρχεία +Έκδοση +Τόμος +Πολυτόμος +Offset +Σύνδεσμοι +Μπλοκ +Τόμοι + +64-bit +Big-endian +CPU +Φυσικό μέγεθος +Μέγεθος headers +Άθροισμα ελέγχου +Χαρακτηριστικά +Εικονική διεύθυνση +ID +Σύντομο όνομα +Εφαρμογή δημιουργίας +Μέγεθος τομέα +Κατάσταση λειτουργίας +Σύνδεσμος +Σφάλμα +Συνολικό μέγεθος +Ελεύθερος χώρος +Μέγεθος συμπλέγματος +Ετικέτα +Τοπικό όνομα +Παροχέας +NT Security +Alternate Stream +Aux +Deleted +Is Tree + + +Τύπος λάθους +Λάθη +Λάθη +Προειδοποιήσεις +Προειδοποίηση +Streams +Alternate Streams +Alternate Streams Size +Εικονικό μέγεθος +Αποσυμπιεσμένο μέγεθος +Συνολικό φυσικό μέγεθος +Ευρετήριο τόμου +SubType +Σύντομο σχόλιο +Κωδικοσελίδα + + + +Tail Size +Embedded Stub Size +Σύνδεσμος +Σταθερός σύνδεσμος +iNode + +Ανάγνωση-Μόνο +2100 +Ρυθμίσεις +Γλώσσα +Γλώσσα: +Πρόγραμμα επεξεργασίας +&Πρόγραμμα επεξεργασίας: +&Diff: +2200 +Σύστημα +Συσχέτιση του 7-Zip με τα αρχεία: +Ολοι οι χρήστες +2301 +Ενσωμάτωση του 7-Zip στο λειτουργικό +Με ομαδοποίηση των επιλογών +Στοιχεία του αναδυόμενου μενού: +Εικονίδια στο αναδυόμενο μενού +2320 +<Φάκελος> +<Αρχείο Συμπίεσης> +Άνοιγμα +Αποσυμπίεση αρχείων... +Προσθήκη σε αρχείο συμπίεσης... +Έλεγχος αρχείου συμπίεσης +Αποσυμπίεση εδώ +Αποσυμπίεση στο φάκελο {0} +Προσθήκη στο {0} +Συμπίεση και αποστολή με e-mail... +Συμπίεση στο {0} και αποστολή με e-mail +2400 +Φάκελοι +&Φάκελος εργασίας +&Προσωρινός φάκελος συστήματος +&Τρέχων φάκελος +&Καθορισμένος: +Χρήση μόνο για αφαιρούμενες μονάδες δίσκου +Καθορίστε μια τοποθεσία για τα προσωρινά αρχεία συμπίεσης. +2500 +Επιλογές +Εμφάνιση αντικειμένου ".." +Εμφάνιση των κανονικών εικονιδίων των αρχείων +Εμφάνιση μενού συστήματος +&Επιλογή ολόκληρης διαδρομής +Εμφάνιση γραμμών πλέγματος +Άνοιγμα αντικειμένου με μονό κλικ +Εναλλακτική κατάσταση επιλογής +Χρήση μεγάλων &σελίδων μνήμης +2900 +Πληροφορίες για το 7-Zip +Το 7-Zip είναι ελεύθερο λογισμικό. Ωστόσο μπορείτε να υποστηρίξετε την περαιτέρω ανάπτυξη του με την εγγραφή σας. +3000 +Το σύστημα δεν μπορεί να διαθέσει την απαιτούμενη ποσότητα μνήμης. +Δεν υπάρχουν σφάλματα +{0} επιλεγμένα στοιχεία +Αδύνατη η δημιουργία του φακέλου '{0}' +Οι λειτουργίες ενημέρωσης δεν είναι διαθέσιμες για αυτόν τον τύπο συμπιεσμένου αρχείου. +Δεν μπορεί να ανοιχθεί το αρχείο '{0}' σαν αρχείο συμπίεσης +Δεν μπορεί να ανοιχθεί το κρυπτογραφημένο αρχείο '{0}'. Λάθος κωδικός; +Μη υποστηριζόμενο αρχείο συμπίεσης. +Το αρχείο {0} ήδη υπάρχει. +Το αρχείο '{0}' τροποποιήθηκε.\nΘέλετε να ενημερώσετε το αρχείο συμπίεσης; +Αδυνατή η ενημέρωση του αρχείου\n'{0}' +Δεν είναι δυνατή η εκκίνηση του προγράμματος επεξεργασίας. +Το αρχείο μοιάζει με ιό (το όνομα του περιέχει μεγάλα κενά). +Η λειτουργία δεν μπορεί να κληθεί από ένα φάκελο που έχει μεγάλη διαδρομή. +Πρέπει να επιλέξετε ένα αρχείο. +Πρέπει να επιλέξετε ένα ή περισσότερα αρχεία. +Πάρα πολλά στοιχεία +Αδυναμία ανοίγματος του αρχείου ως {0} συμπιεσμένο +Το αρχείο είναι ανοιχτό ως {0} συμπιεσμένο +Το συμπιεσμένο αρχείο είναι ανοιχτό με offset +3300 +Αποσυμπίεση +Συμπίεση +Έλεγχος +Άνοιγμα... +Σάρωση... +Διαγραφή... +3320 +Προσθήκη.. +Ενημέρωση.. +Ανάλυση.. +Αντιγραφή.. +Επανασυμπίεση.. +Παράλειψη.. +Διαγραφή.. +Δημιουργία κεφαλίδας.. +3400 +Αποσυμπίεση +&Αποσυμπίεση στο φάκελο: +Καθορίστε τον φάκελο αποσυμπίεσης. +3410 +Επιλογές διαδρομών φακέλων +Πλήρεις διαδρομές φακέλων +Χωρίς διαδρομές φακέλων +Απόλυτες διαδρομές φακέλων +Σχετικές διαδρομές φακέλων +3420 +Επιλογές αντικατάστασης αρχείων +Αντικατάσταση με ερώτηση +Αντικατάσταση χωρίς ερώτηση +Παράβλεψη των υπαρχόντων αρχείων +Αυτόματη μετονομασία +Αυτόματη μετονομασία των υπαρχόντων αρχείων +3430 +Απαλοιφή ριζικού καταλόγου +Επαναφορά ασφάλειας αρχείου +3500 +Επιβεβαίωση αντικατάστασης του αρχείου +Ο φάκελος προορισμού περιέχει ήδη ένα αρχείο με το ίδιο όνομα. +Θέλετε να αντικαταστήσετε το υπάρχον αρχείο +με αυτό; +{0} bytes +Αυτόματη &μετονομασία +3700 +Μη υποστηριζόμενη μέθοδος συμπίεσης για το '{0}'. +Λάθος δεδομένων στο {0}. Το αρχείο είναι φθαρμένο. +Ο έλεγχος CRC απέτυχε στο '{0}'. Το αρχείο είναι φθαρμένο. +Λάθος δεδομένων στο κρυπτογραφημένο αρχείο '{0}'. Λάθος κωδικός; +Ο έλεγχος CRC απέτυχε στο κρυπτογραφημένο αρχείο '{0}'. Λάθος κωδικός; +3710 +Λάθος κωδικός; +3721 +Μη υποστηριζόμενη μέθοδος συμπίεσης +Λάθος δεδομένων +Ο έλεγχος CRC απέτυχε +Μη διαθέσιμα δεδομένα +Απρόβλεπτο τελείωμα δεδομένων +Υπάρχουν μερικα δεδομένα στο τέλος των χρήσιμων δεδομένων +Δεν είναι συμπιεσμένο αρχείο +Λάθος επικεφαλίδων +Λάθος κωδικός +3763 +Μη διαθέσιμη αρχή του συμπιεσμένου αρχείου +Ανεπιβεβαίωτη αρχή του συμπιεσμένου αρχείου + + + +Μη υποστηριζόμενη λειτουργία +3800 +Εισαγωγή κωδικού πρόσβασης +Κωδικός πρόσβασης: +Επανεισάγετε τον κωδικό πρόσβασης: +&Εμφάνιση κωδικού +Οι κωδικοί δεν ταιριάζουν. +Χρησιμοποιήστε μόνο Αγγλικά γράμματα, αριθμούς και ειδικούς χαρακτήρες (!, #, ...) για κωδικό. +Ο κωδικός είναι πολύ μεγάλος. +Κωδικός πρόσβασης +3900 +Διανύθηκε: +Απομένει: +Μέγεθος: +Ταχύτητα: +Επεξεργάσθηκαν: +Αναλογία συμπίεσης +Σφάλματα: +Αρχεία συμπίεσης: +4000 +Προσθήκη σε συμπιεσμένο αρχείο +&Όνομα αρχείου συμπίεσης: +&Τρόπος ενημέρωσης: +Συμπίεση στη μορ&φή: +Επίπεδο συμπίεσης: +&Μέθοδος συμπίεσης: +Μέγεθος &λεξικού: +Μέγεθος &λέξης: +Μέγεθος συμπαγούς μπλοκ: +Αριθμός νημάτων CPU +&Παράμετροι: +Επιλογές συμπίεσης +Με αυτόματη αποσυμπίεση (SF&X) +Συμπίεση κοινών αρχείων +Κρυπτογράφηση +Μέθοδος κρυπτογράφησης +Κρυπτογράφηση των &ονομάτων +Χρήση μνήμης για συμπίεση: +Χρήση μνήμης για αποσυμπίεση: +Διαγραφή αρχείων μετά τη συμπίεση +4040 +Αποθήκευση συμβολικών συνδέσμων +Αποθήκευση σταθερών συνδέσμων +Αποθήκευση ενναλλακτικών ροών δεδομένων +Αποθήκευση ασφάλειας αρχείου +4050 +Αποθήκευση +Πολύ γρήγορη +Γρήγορη +Κανονική +Μέγιστη +Υπερσυμπίεση +4060 +Προσθήκη και αντικατάσταση αρχείων +Προσθήκη και ενημέρωση αρχείων +Ενημέρωση των υπαρχόντων αρχείων +Συγχρονισμός αρχείων +4070 +Αναζήτηση +Όλα τα αρχεία +Μη-συμπαγές +Συμπαγές +6000 +Αντιγραφή +Μετακίνηση +Αντιγραφή στο: +Μετακίνηση στο: +Αντιγραφή... +Μετακίνηση... +Μετονομασία... +Επιλέξτε φάκελο προορισμού. +Η λειτουργία δεν υποστηρίζεται. +Παρουσιάστηκε σφάλμα κατά τη μετονομασία. +Επιβεβαίωση αντιγραφής αρχείων +Είστε βέβαιος ότι θέλετε να αντιγράψετε τα αρχεία στο αρχείο συμπίεσης; +6100 +Επιβεβαίωση διαγραφής του αρχείου +Επιβεβαίωση διαγραφής του φακέλου +Επιβεβαίωση διαγραφής πολλών αρχείων +Είστε βέβαιοι ότι θέλετε να διαγράψετε το '{0}' ; +Είστε βέβαιοι ότι θέλετε να διαγράψετε το φάκελο '{0}' και όλα τα περιεχόμενα του; +Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτά τα {0} στοιχεία; +Διαγραφή... +Παρουσιάστηκε σφάλμα κατά τη διαγραφή. +Το σύστημα δεν μπορεί να μετακινήσει ένα αρχείο με μεγάλη διαδρομή στον Κάδο Ανακύκλωσης. +6300 +Δημιουργία φακέλου +Δημιουργία αρχείου +Όνομα φακέλου: +Όνομα αρχείου: +Νέος φάκελος +Νέο αρχείο +Σφάλμα κατά την δημιουργία φακέλου. +Σφάλμα κατά την δημιουργία αρχείου. +6400 +Σχόλιο +&Σχόλιο: +Επιλογή +Αποεπιλογή +Με όνομα: +6600 +Ιδιότητες +Ιστορικό φακέλων +Διαγνωστικά μηνύματα +Μήνυμα +7100 +Υπολογιστής +Δικτύο +Έγγραφα +Σύστημα +7200 +Προσθήκη +Αποσυμπίεση +Έλεγχος +Αντιγραφή +Μετακίνηση +Διαγραφή +Πληροφορίες +7300 +Τεμαχισμός αρχείου +&Τεμαχισμός σε: +Τεμαχισμός σε τόμους: +Τεμαχισμός... +Επιβεβαίωση τεμαχισμού +Είστε βέβαιος ότι θέλετε να τεμαχίσετε το αρχείο σε {0} τόμους; +Το μέγεθος του τόμου πρέπει να είναι μικρότερο από αυτό του αρχικού αρχείου. +Λάθος μέγεθος τόμου +Καθορισμένο μέγεθος τόμου: {0} bytes.\nΕίστε σίγουρος ότι θέλετε να χωρίσετε το αρχείο σε τέτοιους τόμους; +7400 +Συνένωση αρχείων +&Συνένωση σε: +Συνένωση... +Επιλέξτε μόνο το πρώτο αρχείο +Το αρχείο δεν μπορεί να ανιχνευθεί ως μέρος τεμαχισμένου αρχείου. +Δεν μπορούν να βρεθούν πάνω από ένα μέρη τεμαχισμένου αρχείου. +7500 +Υπολογισμός αθροίσματος ελέγχου... +Πληροφορίες αθροίσματος ελέγχου +Άθροισμα ελέγχου CRC για δεδομένα: +Άθροισμα ελέγχου CRC για δεδομένα και ονόματα: +7600 +Αξιολόγηση επιδόσεων +Χρήση μνήμης: +Συμπίεση +Αποσυμπίεση +Εκτίμηση +Συνολ. εκτίμηση +Τρέχων πέρασμα +Αποτέλεσμα +Χρήση CPU +Ταξ/μιση/Χρήση +Περάσματα: +7700 +Σύνδεσμος +Σύνδεσμος +Σύνδεσμος από: +Σύνδεσμος έως: +7710 +Τύπος συνδέσμου +Σταθερός σύνδεσμος +Συμβολικός σύνδεσμος αρχείου +Συμβολικός σύνδεσμος καταλόγου +Συνένωση καταλόγου diff --git a/Utils/7-Zip/Lang/en.ttt b/Utils/7-Zip/Lang/en.ttt new file mode 100644 index 000000000..d94df3816 --- /dev/null +++ b/Utils/7-Zip/Lang/en.ttt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.00 : 2015-03-29 : Igor Pavlov +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +English +English +401 +OK +Cancel + + + +&Yes +&No +&Close +Help + +&Continue +440 +Yes to &All +No to A&ll +Stop +Restart +&Background +&Foreground +&Pause +Paused +Are you sure you want to cancel? +500 +&File +&Edit +&View +F&avorites +&Tools +&Help +540 +&Open +Open &Inside +Open O&utside +&View +&Edit +Rena&me +&Copy To... +&Move To... +&Delete +&Split file... +Com&bine files... +P&roperties +Comme&nt... +Calculate checksum +Diff +Create Folder +Create File +E&xit +Link +&Alternate Streams +600 +Select &All +Deselect All +&Invert Selection +Select... +Deselect... +Select by Type +Deselect by Type +700 +Lar&ge Icons +S&mall Icons +&List +&Details +730 +Unsorted +Flat View +&2 Panels +&Toolbars +Open Root Folder +Up One Level +Folders History... +&Refresh +Auto Refresh +750 +Archive Toolbar +Standard Toolbar +Large Buttons +Show Buttons Text +800 +&Add folder to Favorites as +Bookmark +900 +&Options... +&Benchmark +960 +&Contents... +&About 7-Zip... +1003 +Path +Name +Extension +Folder +Size +Packed Size +Attributes +Created +Accessed +Modified +Solid +Commented +Encrypted +Split Before +Split After +Dictionary + +Type +Anti +Method +Host OS +File System +User +Group +Block +Comment +Position +Path Prefix +Folders +Files +Version +Volume +Multivolume +Offset +Links +Blocks +Volumes + +64-bit +Big-endian +CPU +Physical Size +Headers Size +Checksum +Characteristics +Virtual Address +ID +Short Name +Creator Application +Sector Size +Mode +Symbolic Link +Error +Total Size +Free Space +Cluster Size +Label +Local Name +Provider +NT Security +Alternate Stream +Aux +Deleted +Is Tree + + +Error Type +Errors +Errors +Warnings +Warning +Streams +Alternate Streams +Alternate Streams Size +Virtual Size +Unpack Size +Total Physical Size +Volume Index +SubType +Short Comment +Code Page + + + +Tail Size +Embedded Stub Size +Link +Hard Link +iNode + +Read-only +2100 +Options +Language +Language: +Editor +&Editor: +&Diff: +2200 +System +Associate 7-Zip with: +All users +2301 +Integrate 7-Zip to shell context menu +Cascaded context menu +Context menu items: +Icons in context menu +2320 + + +Open archive +Extract files... +Add to archive... +Test archive +Extract Here +Extract to {0} +Add to {0} +Compress and email... +Compress to {0} and email +2400 +Folders +&Working folder +&System temp folder +&Current +&Specified: +Use for removable drives only +Specify a location for temporary archive files. +2500 +Settings +Show ".." item +Show real file icons +Show system menu +&Full row select +Show &grid lines +Single-click to open an item +&Alternative selection mode +Use &large memory pages +2900 +About 7-Zip +7-Zip is free software +3000 +The system cannot allocate the required amount of memory +There are no errors +{0} object(s) selected +Cannot create folder '{0}' +Update operations are not supported for this archive. +Can not open file '{0}' as archive +Can not open encrypted archive '{0}'. Wrong password? +Unsupported archive type +File {0} is already exist +File '{0}' was modified.\nDo you want to update it in the archive? +Can not update file\n'{0}' +Cannot start editor. +The file looks like a virus (the file name contains long spaces in name). +The operation cannot be called from a folder that has a long path. +You must select one file +You must select one or more files +Too many items +Can not open the file as {0} archive +The file is open as {0} archive +The archive is open with offset +3300 +Extracting +Compressing +Testing +Opening... +Scanning... +Removing +3320 +Adding +Updating +Analyzing +Replicating +Repacking +Skipping +Deleting +Header creating +3400 +Extract +E&xtract to: +Specify a location for extracted files. +3410 +Path mode: +Full pathnames +No pathnames +Absolute pathnames +Relative pathnames +3420 +Overwrite mode: +Ask before overwrite +Overwrite without prompt +Skip existing files +Auto rename +Auto rename existing files +3430 +Eliminate duplication of root folder +Restore file security +3500 +Confirm File Replace +Destination folder already contains processed file. +Would you like to replace the existing file +with this one? +{0} bytes +A&uto Rename +3700 +Unsupported compression method for '{0}'. +Data error in '{0}'. File is broken. +CRC failed in '{0}'. File is broken. +Data error in encrypted file '{0}'. Wrong password? +CRC failed in encrypted file '{0}'. Wrong password? +3710 +Wrong password? +3721 +Unsupported compression method +Data error +CRC failed +Unavailable data +Unexpected end of data +There are some data after the end of the payload data +Is not archive +Headers Error +Wrong password +3763 +Unavailable start of archive +Unconfirmed start of archive + + + +Unsupported feature +3800 +Enter password +Enter password: +Reenter password: +&Show password +Passwords do not match +Use only English letters, numbers and special characters (!, #, $, ...) for password +Password is too long +Password +3900 +Elapsed time: +Remaining time: +Total size: +Speed: +Processed: +Compression ratio: +Errors: +Archives: +4000 +Add to archive +&Archive: +&Update mode: +Archive &format: +Compression &level: +Compression &method: +&Dictionary size: +&Word size: +Solid block size: +Number of CPU threads: +&Parameters: +Options +Create SF&X archive +Compress shared files +Encryption +Encryption method: +Encrypt file &names +Memory usage for Compressing: +Memory usage for Decompressing: +Delete files after compression +4040 +Store symbolic links +Store hard links +Store alternate data streams +Store file security +4050 +Store +Fastest +Fast +Normal +Maximum +Ultra +4060 +Add and replace files +Update and add files +Freshen existing files +Synchronize files +4070 +Browse +All Files +Non-solid +Solid +6000 +Copy +Move +Copy to: +Move to: +Copying... +Moving... +Renaming... +Select destination folder. +The operation is not supported for this folder. +Error Renaming File or Folder +Confirm File Copy +Are you sure you want to copy files to archive +6100 +Confirm File Delete +Confirm Folder Delete +Confirm Multiple File Delete +Are you sure you want to delete '{0}'? +Are you sure you want to delete the folder '{0}' and all its contents? +Are you sure you want to delete these {0} items? +Deleting... +Error Deleting File or Folder +The system cannot move a file with long path to the Recycle Bin +6300 +Create Folder +Create File +Folder name: +File Name: +New Folder +New File +Error Creating Folder +Error Creating File +6400 +Comment +&Comment: +Select +Deselect +Mask: +6600 +Properties +Folders History +Diagnostic messages +Message +7100 +Computer +Network +Documents +System +7200 +Add +Extract +Test +Copy +Move +Delete +Info +7300 +Split File +&Split to: +Split to &volumes, bytes: +Splitting... +Confirm Splitting +Are you sure you want to split file into {0} volumes? +Volume size must be smaller than size of original file +Incorrect volume size +Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes? +7400 +Combine Files +&Combine to: +Combining... +Select only first part of split file +Can not detect file as part of split file +Can not find more than one part of split file +7500 +Checksum calculating... +Checksum information +CRC checksum for data: +CRC checksum for data and names: +7600 +Benchmark +Memory usage: +Compressing +Decompressing +Rating +Total Rating +Current +Resulting +CPU Usage +Rating / Usage +Passes: +7700 +Link +Link +Link from: +Link to: +7710 +Link Type +Hard Link +File Symbolic Link +Directory Symbolic Link +Directory Junction diff --git a/Utils/7-Zip/Lang/eo.txt b/Utils/7-Zip/Lang/eo.txt new file mode 100644 index 000000000..45261353a --- /dev/null +++ b/Utils/7-Zip/Lang/eo.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.37 : Dmitri Gabinski +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Esperanto +Esperanto +401 +B&one +Nuligu + + + +&Jes +&Ne +&Fermu +Helpo + +&Daŭrigu +440 +Jes por ĉ&iuj +Ne por ĉi&uj +&Haltu +Restartigu +&Fono +&Malfono +&Paŭzo +Paŭzita +Ĉu vi vere volas nuligi? +500 +&Dosiero +&Redakto +&Vido +&Favoritaj +&Agordoj +&Helpo +540 +&Malfermu +Malfermu &ene +Malfermu ek&stere +&Vidigu +&Redaktu +Ŝ&anĝu nomon +&Kopiu en... +M&ovu en... +&Forigu +&Erigu dosierojn... +Komb&inu dosierojn... +A&tributoj +Ko&mentu +Kalkulu kontrolsumon + +Kreu &dosierujon +Kre&u dos&ieron +E&liru +600 +M&arku ĉiun +Ma&lmarku ĉiun +&Inversigu markon +Marku... +Malmarku... +Marku laŭ tipo +Malmarku laŭ tipo +700 +&Grandaj bildetoj +&Malgrandaj bildetoj +&Listo +&Detale +730 +&Neordigite +Ununivela vido +&2 paneloj +&Ilobretoj +Malfermu radikan dosierujon +Supren je unu nivelo +Dosierujhistorio... +Ĝ&isdatigu +750 +Arĥivo-ilobreto +Norma ilobreto +Grandaj bildetoj +Montru butontekston +800 +&Aldonu dosierujon al favorataj kiel +Legosigno +900 +&Agordoj... +&Etalono +960 +&Enhavo... +&Pri 7-Zip... +1003 +Dosierindiko +Nomo +Dosiernoma sufikso +Dosierujo +Grando +Enarĥiva grando +Atributoj +Kreita +Malfermita +Ŝanĝita +Solida +Komento +Ĉifra +Disigita antaŭ +Disigita post +Vortaro +CRC +Tipo +Kontraŭ +Metodo +Gastiga operaciumo +Dosiersistemo +Uzulo +Grupo +Bloko +Komento +Pozicio +Vojprefikso + + + + + + + + + + + + + + + + + + + + + + + + +Eraro +Kapacito +Libera +Faskogrando +Marko +Loka nomo +Provizanto +2100 +Agordoj +Lingvo +Lingvo: +Redaktilo +&Redaktilo: + +2200 +Sistemo +Asociu 7-Zip-on kun dosieroj: +2301 +Metu 7-Zip'on en kuntekstan menuon de ŝelo +Kaskada kunteksta menuo +Punktoj de kunteksta menuo: +2320 + + +Malfermu +Elarĥivigu dosierojn... +Enarĥivigu... +Testu arĥivon +Elarĥivigu ĉi-tien +Elarĥivigu en {0} +Aldonu al {0} +Enarĥivigu kaj enretpoŝtigu... +Enarĥivigu en {0} kaj enretpoŝtigu... +2400 +Dosierujoj +&Kuranta dosierujo +&Sistema labora dosierujo +&Ĉi tiu +&Specifu: +&Uzi nur por demeteblaj datumportiloj +Specifu ujon por laboraj dosieroj. +2500 +Agordoj +Montru ".."-elementon +Montru realajn dosierbildetojn +Montru sisteman menuon +Marku &tutan linion +Montru &kradliniojn + +&Alternativa markreĝimo +Uzu &grandajn memorpaĝojn +2900 +Informo +7-Zip estas senpaga programo. Tamen, vi povas subteni evoluadon de 7-Zip per enregistriĝo. +3000 + +Eraroj ne trovitaj +{0} objekto(j) markita(j) +Fiaskis krei dosierujon '{0}' +Ĝisdatigoperacioj ne estas subtenataj por ĉi-tiu arĥivo. + + + + +Dosiero '{0}' ŝanĝiĝis.\nĈu vi volas ĝistadigi ĝin enraĥive? +Fiaskis ĝisdatigi dosieron\n'{0}'' +Fiaskis startigi redaktilon. + + + + +Troaj elementoj +3300 +Elarĥivigo +Densigo +Testado +Malfermo... +Analizante... +3400 +&Elarĥivigu +E&larĥivigu en: +Specifu ujon por elarĥivendaj dosieroj. +3410 +Dosierindikoj +&Absolutaj dosierindikoj +&Sen dosierindikoj +3420 +Anstataŭiga skribreĝimo +&Kun konfirmo +&Sen konfirmo +&Preterlasu estantaj dosieroj +Aŭtonomŝanĝo +Aŭtonomŝanĝo de ekzistantaj dosieroj +3500 +Konfirmo de nomŝanĝo +Dosierujo jam enhavas prilaboratan dosieron. +Anstataŭigu estantan dosieron +per ĉi-tiu? +{0} bajtoj +&Aŭtonomŝanĝo. +3700 +Ne estas subtenata densigmetodo por dosiero '{0}'. +Datumeraro en '{0}'. Difektiĝinta dosiero. +CRC-eraro en '{0}'. Difektiĝinta dosiero. + + +3800 +Pasvorto +Enigu pasvorton: + +&Montru pasvorton + + + +&Pasvorto +3900 +Pasinta tempo: +Restanta tempo: +Grando: +Rapideco: + + +Eraroj: + +4000 +Enarĥivigu +&Arĥivo: +A&nstataŭigreĝimo: +A&rĥivformato: +Densigo&nivelo +&Densigmetodo: +&Vortarogrando: +Vo&rtogrando: + + +&Parametroj: +Agordoj +Kreu SF&X-arĥivon + + + +Ĉifru dosier&nomojn +Memoruzo por densigo: +Memoruzo por maldensigo: +4050 +Sen densigo +Plej rapide +Rapide +Normala densigo +Maksimuma densigo +Ultra +4060 +Aldonu kaj anstataŭigu dosierojn +Ĝisdatigu kaj aldonu dosierojn +Refreŝigu estantajn dosierojn +Sinkronigu dosierojn +4070 +Foliumu +Ĉiuj dosieroj + + +6000 +Kopiu +Movu +Kopiu en: +Movu en: +Kopio... +Movo... +Nomŝanĝo... + +Operacio ne estas subtenata. +Eraro dum nomŝanĝo de dosiero aŭ dosierujo +Konfirmu dosierkopion +Ĉu vere kopii dosierojn enarĥiven +6100 +Konfirmo de forigo de dosiero +Konfirmo de forigo de dosierujo +Konfirmo de forigo de dosieraro +Ĉu vi vere volas forigi '{0}'? +Ĉu vi vere volas forigi dosierujon "{0}" kaj tutan ĝian enhavon? +Ĉu vi vere volas forigi ĉi tiajn {0} objektojn? +Forigo... +Eraro dum forigo de dosiero aŭ dosierujo + +6300 +Kreu dosierujon +Kreu dosieron +Dosierujnomo: +Dosiernomo: +Nova dosierujo +Nova dosiero +Eraro dum dosierujkreo +Eraro dum dosierkreo +6400 +Komento +&Komento: +Marku +Malmarku +Masko: +6600 + +Dosierujhistorio +Diagnozaj mesaĝoj +Mesaĝo +7100 +Komputilo +Reto + +Sistemo +7200 +Enarĥivigu +Elarĥivigu +Testu +Kopiu +Movu +Forigu +Informo +7300 +Erigu dosieron +&Erigu en: +&Plurvolumigu, bajtoj: +Erigo... + + + + + +7400 +Kombinu dosierojn +&Kombinu en: +Kombino... + + + +7500 +Kalkulante kontrolsumon... +Informo pri kontrolsumo +CRC-kontrolsumo por datumoj: +CRC-kontrolsumo por datumoj kaj nomoj: +7600 +Etalono +Memoruzo: +Densigo +Maldensigo +Takso +Tuta takso +Kuranta +Rezulta + + +Pasoj: diff --git a/Utils/7-Zip/Lang/es.txt b/Utils/7-Zip/Lang/es.txt new file mode 100644 index 000000000..15b17071d --- /dev/null +++ b/Utils/7-Zip/Lang/es.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Pablo Rodriguez +; : Jbc25 +; : 2007-09-05 : Guillermo Gabrielli +; 9.07 : 2010-06-10 : Purgossu +; 2010-10-23 : Sergi Medina (corrected) +; +; +; +; +; +; +0 +7-Zip +Spanish +Español +401 +Aceptar +Cancelar + + + +&Sí +&No +&Cerrar +Ayuda + +&Continuar +440 +Sí a &todo +No a t&odo +Parar +Volver a empezar +Se&gundo plano +P&rimer plano +&Pausa +Pausado +¿Estás seguro de que deseas cancelar? +500 +&Archivo +&Editar +&Ver +&Favoritos +&Herramientas +Ay&uda +540 +&Abrir +Abrir &dentro +Abrir &fuera +&Ver +&Editar +Re&nombrar +&Copiar a... +&Mover a... +&Borrar +Di&vidir archivo... +C&ombinar archivos... +&Propiedades +Comen&tario +Suma de verificación +Diff +Crear carpeta +Crear archivo +&Salir +600 +Seleccionar &todo +Deseleccionar todo +&Invertir selección +Seleccionar... +Deseleccionar... +Seleccionar por tipo +Deseleccionar por tipo +700 +Iconos g&randes +&Iconos pequeños +&Lista +&Detalles +730 +Desordenado +Vista plana (flat view) +&2 paneles +&Barras de herramientas +Abrir directorio raíz +Subir un directorio +Historia de carpetas... +&Actualizar +750 +Barra de herramientas Archivo +Barras de herramientas estándar +Botones grandes +Mostrar texto en los botones +800 +&Añadir carpeta a favoritos como +Agregar a favoritos +900 +&Opciones... +&Pruebas (benchmark) +960 +&Contenido... +&Acerca de 7-Zip... +1003 +Ruta +Nombre +Tipo de archivo +Directorio +Tamaño +Tamaño comprimido +Atributos +Creado +Acceso +Modificado +Compacto +Comentado +Encriptado +expandido antes +expandido después +Diccionario +CRC +Tipo +Anti +Método +SO de origen +Sistema de archivos +Usuario +Grupo +Bloque +Comentario +Posición +Ruta +Directorios +Ficheros +Versión +Volumen +Multivolumen +Desplazamiento +Vínculos +Bloques +Volúmenes + +64-bit +Big-endian +CPU +Tamaño físico +Tamaño de las cabeceras +Verificación de suma +Características +Dirección virtual +ID +Nombre corto +Aplicación de creación +Tamaño de sector +Modo +Enlace +Error +Espacio total +Espacio libre +Tamaño de clúster +Etiqueta +Nombre local +Proveedor +2100 +Opciones +Lengua +Lengua: +Editor +&Editor: +&Diff: +2200 +Sistema +Asociar 7-Zip con: +2301 +Integrar 7-Zip en el menú contextual de Windows +Menú contextual en cascada +Elementos en el menú contextual: +2320 + + +Abrir comprimido +Extraer ficheros... +Añadir al archivo... +Comprobar archivo +Extraer aquí +Extraer en {0} +Añadir a {0} +Comprimir y enviar por correo... +Comprimir a {0} y enviar por correo +2400 +Directorios +Directorio de &trabajo +Directorio temporal del &sistema +Directorio &actual +&Especificar directorio: +Usar solo para dispositivos extraíbles +Especificar un directorio para archivos temporales. +2500 +Propiedades +Mostrar el elemento ".." +Mostrar iconos propios +Mostrar menú del sistema +&Seleccionar fila(s) entera(s) +Mostrar &cuadrícula +Clicar una vez para abrir elemento +Modo de selección &alternativo +Usar páginas &grandes de memoria +2900 +Acerca de 7-Zip +7-Zip es un programa excelente; además, es libre y gratuito. Tú puedes apoyar el desarrollo de 7-Zip registrándote para contribuir a mejorar el programa. +3000 +El sistema no ha podido asignar la cantidad necesaria de memoria +No hay errores +{0} elemento(s) seleccionado(s) +No se puede crear el directorio '{0}' +Este tipo de archivo no permite actualización. +No se puede abrir '{0}' como un archivo comprimido +No se puede abrir el archivo encriptado '{0}'. Verifique la contraseña. +Tipo de archivo no soportado +El fichero {0} ya existe +El fichero '{0}' ha sido modificado.\n¿Quieres actualizarlo en el archivo? +No puede actualizarse el fichero\n'{0}' +No puede ejecutarse el editor. +El fichero parece un virus (el nombre del fichero contiene espacios largos). +No puede realizarse la operación desde una carpeta que tenga una ruta larga. +Debes seleccionar un fichero +Debes seleccionar uno o más ficheros +Demasiados elementos +3300 +extrayendo +comprimiendo +probando +abriendo... +Buscando... +3400 +Extraer +E&xtraer a: +Selecciona destino para los archivos extraídos. +3410 +Modo de directorio +Directorio completo +Sin directorio +3420 +Sobreescribir +Con confirmación +Sin confirmación +Conservar archivos existentes +Renombrar automáticamente +Autorrenombrar archivos existentes +3500 +Confirmar sustitución de archivos +El directorio ya contiene un archivo con el mismo nombre. +¿Deseas sustituir el archivo existente +por este otro? +{0} bytes +Renombrar a&utomáticamente +3700 +Método de compresión no válido para '{0}'. +Error de datos en '{0}'. El archivo está corrupto. +CRC ha fallado en '{0}'. El archivo está corrupto. +Error de datos en el archivo encriptado '{0}'. Verifica la contraseña. +Fallo de CRC en el archivo encriptado '{0}'. Verifica la contraseña. +3800 +Introduce la contraseña +E&scribe la contraseña: +Escribe nue&vamente la contraseña: +&Mostrar la contraseña +Las contraseñas son diferentes. Por favor, vuelve a escribirlas. +Usa en la contraseña solamente letras del alfabeto inglés, números y caracteres especiales (!, #, $, ...) +La contraseña es demasiado larga. +Contraseña +3900 +Tiempo transcurrido: +Tiempo pendiente: +Tamaño: +Velocidad: +Procesado: +Razón de compresión: +Errores: +Archivos: +4000 +Añadir al archivo +&Archivo: +M&odo de actualización: +&Formato de archivo: +Nive&l de compresión: +&Tipo de compresión: +Tamaño de &diccionario: +Tama&ño de la palabra: +Tamaño de bloque compacto: +Número de hilos de la CPU: +&Parámetros: +Opciones +Crear archivo SF&X (autoextraíble) +Comprimir archivos abiertos para escritura +Encriptación +Método de &encriptación: +Encriptar &nombres de fichero +Memoria usada para comprimir: +Memoria usada para descomprimir: +4050 +Sin compresión +La más rápida +Rápida +Normal +Máxima +Ultra +4060 +Añadir y sustituir archivos +Actualizar y añadir archivos +Solo actualizar archivos +Sincronizar archivos +4070 +Explorar +Todos los archivos +No compacto +Sin límite +6000 +Copiar +Mover +Copiar a: +Mover a: +copiado... +movido... +Renombrando... +Selecciona la carpeta de destino +Operación no permitida. +Error renombrando fichero o carpeta +Confirmar copia de ficheros +¿Estás seguro de que deseas copiar los ficheros al archivo +6100 +Confirmar borrado de archivo +Confirmar borrado de carpeta +Confirmar borrado de numerosos ficheros +¿Estás seguro de querer borrar '{0}'? +¿Estás seguro de querer borrar la carpeta '{0}' y todo su contenido? +¿Estás seguro de querer borrar estos {0} elementos? +Borrando... +Error borrando fichero o carpeta +El sistema no puede mover un fichero con ruta larga a la Papelera de Reciclaje +6300 +Crear carpeta +Crear archivo +Nombre de carpeta: +Nombre de archivo: +Carpeta nueva +Archivo nuevo +Error creando carpeta +Error creando archivo +6400 +Comentario +&Comentario: +Seleccionar +Deseleccionar +Máscara: +6600 +Propiedades +Historial de carpetas +Mensajes de diagnóstico +Mensaje +7100 +Mi PC +Entorno de red +Documentos +Sistema +7200 +Agregar +Extraer +Probar +Copiar +Mover +Borrar +Información +7300 +Dividir archivo +Di&vidir a: +Dividir en fra&gmentos (bytes): +Dividiendo... +Confirmar división +¿Estás seguro de que deseas dividir el archivo en {0} partes? +El tamaño de los fragmentos debe ser menor que el del archivo original +Tamaño de fragmento incorrecto +Tamaño de fragmento especificado: {0} bytes.\n¿Estás seguro de que deseas dividir el archivo en fragmentos de ese tamaño? +7400 +Combinar archivos +&Combinar a: +Combinando... +Selecciona solamente el primer archivo +No se ha podido detectar el fichero como parte de un fichero por volúmenes +No se ha podido encontrar más que un fragmento del fichero por volúmenes +7500 +Calculando suma de verificación... +Suma de verificación (CRC) +CRC de los datos: +CRC de los datos y nombres: +7600 +Pruebas (benchmark) +Uso de memoria: +Compresión +Descompresión +Tasa +Tasa total +Actual +Resultante +Uso de CPU +Resultante/uso +Pasos: diff --git a/Utils/7-Zip/Lang/et.txt b/Utils/7-Zip/Lang/et.txt new file mode 100644 index 000000000..de2282f23 --- /dev/null +++ b/Utils/7-Zip/Lang/et.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 3.09 : Kaupo Suviste +; 9.07 : Mihkel Tõnnov +; +; +; +; +; +; +; +; +; +0 +7-Zip +Estonian +eesti keel +401 +OK +Loobu + + + +&Jah +&Ei +&Sulge +Abi + +&Jätka +440 +Kõigile j&ah +Kõigile e&i +Seiska +Restardi +&Taustal +&Esiplaanile +&Paus +Pausiks peatatud +Kas soovite kindlasti loobuda? +500 +&Fail +&Redigeeri +&Vaade +&Lemmikud +&Tööriistad +&Abi +540 +&Ava +Ava s&ees +Ava väljasp&ool +Vaat&ur +&Redigeeri +&Nimeta ümber +&Kopeeri asukohta... +&Teisalda asukohta... +Ku&stuta +Tükel&da fail... +Ü&henda failid... +Atri&buudid +Ko&mmentaar... +Arvuta kontrollsumma +Võrdle +Loo kaust +Loo fail +&Välju +600 +V&ali kõik +Tühista kõik valikud +&Pööra valik +Vali... +Tühista valik... +Vali tüübi järgi +Tühista tüübi järgi valik +700 +&Suured ikoonid +Väik&esed ikoonid +&Loend +Üksikasja&d +730 +Sortimata +Lame vaade +&Kaks paani +&Tööriistaribad +Ava juurkaust +Taseme võrra üles +Kaustaajalugu... +&Värskenda +750 +Arhiiviriistariba +Standardnupuriba +Suured nupud +Kuva nupusildid +800 +&Lisa kaust lemmikute hulka järjehoidjana +Järjehoidja +900 +&Häälestus... +&Jõudlustest +960 +&Sisukord... +&Teave 7-Zipi kohta... +1003 +Tee +Nimi +Laiend +Kaust +Maht +Maht tihendatult +Atribuudid +Loodud +Avatud +Muudetud +Ühtne +Kommenteeritud +Krüptitud +Tükeldatud enne +Tükeldatud pärast +Sõnastik +CRC +Tüüp +Anti +Meetod +Opsüsteem +Failisüsteem +Kasutaja +Rühm +Plokk +Kommentaar +Koht +Tee prefiks +Kaustu +Faile +Versioon +Köide +Mitmeköiteline +Nihe +Linke +Plokke +Köiteid + +64-bitine +Big-Endian +Protsessor +Füüsiline maht +Päiste maht +Kontrollsumma +Karakteristikud +Virtuaalaadress +ID +Lühinimi +Loomisrakendus +Sektori maht +Režiim +Link +Tõrge +Kogumaht +Vaba ruum +Klastri suurus +Silt +Kohalik nimi +Teenusepakkuja +2100 +Häälestus +Keel +Keel: +Redaktor +&Redaktor: +&Võrdlusprogramm: +2200 +Süsteem +Seosta 7-Zip laienditega: +2301 +Integreeri 7-Zip kesta hüpikmenüüsse +Kaskaad-hüpikmenüü +Hüpikmenüü käsud: +2320 + + +Ava arhiiv +Eralda failid... +Lisa arhiivi... +Testi arhiivi +Eralda siia +Eralda kausta {0} +Lisa arhiivi {0} +Tihenda ja meili... +Tihenda arhiiviks {0} ja meili +2400 +Kaustad +&Töökaust +&Süsteemi ajutiste failide kaust +&Praegune kaust +&Kasutaja määratud: +Kasuta ainult irddraivide puhul +Määrake ajutiste arhiivifailide asukoht. +2500 +Sätted +Kuva element ".." +Kuva tegelikud failiikoonid +Kuva süsteemimenüü +&Vali terve rida +Kuva &ruudujooned +Ava üksus ühe klõpsuga +&Alternatiivne valikurežiim +Kasuta &suuri mälulehekülgi +2900 +Teave 7-Zipi kohta +7-Zip on vaba tarkvara. Kuid kui soovite toetada 7-Zipi arendamist, siis saate programmi registreerida.\n\n7-Zipi Eesti koduleht:\nhttp://www.hot.ee/somberg/7zip.html +3000 +Süsteem ei saa eraldada nõutavat mälumahtu. +Vigu ei leitud. +{0} üksus(t) valitud +Ei saa luua kausta {0} +Selle arhiivi värskendamistoiminguid ei toetata. +Ei saa avada faili {0} arhiivina. +Ei saa avada krüptitud arhiivi {0}. Kas vale parool? +Toetamata arhiivitüüp. +Fail {0} on juba olemas. +Faili {0} on muudetud.\nKas soovite selle arhiivis värskendada? +Ei saa värskendada faili\n{0} +Ei saa käivitada redaktorit. +See fail sarnaneb viirusega (faili nimi sisaldab pikka tühikute jada). +Toimingut ei saa käivitada kaustast, millel on pikk tee. +Te peate valima ühe faili. +Te peate valima ühe või mitu faili. +Liiga palju üksusi. +3300 +välja eraldatud +tihendatud +Testimine +Avamine... +Läbivaatamine... +3400 +Väljaeraldamine +&Eralda välja kausta: +Määrake väljaeraldatud failide asukoht. +3410 +Teed +&Täielikud teenimed +Teenime&deta +3420 +Ülekirjutus +Küsi e&nne ülekirjutamist +Ki&rjuta küsimata üle +&Jäta olemasolevad failid vahele +Nimeta a&utomaatselt ümber +Nimeta &olemasolevad f. autom. ümber +3500 +Failiasenduse kinnitamine +Sihtkaust juba sisaldab töödeldavat faili. +Kas soovite asendada olemasoleva faili +selle failiga? +{0} baiti +Nimeta a&utomaatselt ümber +3700 +Toetuseta tihendusmeetod failile {0}. +Andmeviga failis {0}. Fail on rikutud. +Tsükkelkoodkontroll (CRC) failis {0} nurjus. Fail on rikutud. +Andmeviga krüptitud failis {0}. Kas vale parool? +Tsükkelkoodkontroll (CRC) krüptitud failis {0} nurjus. Kas vale parool? +3800 +Parooli sisestamine +Sisestage parool: +Parooli kordus: +&Kuva parool +Paroolid ei kattu. +Kasutage paroolis ainult inglise keele tähti, numbreid ja erimärke (!, #, $, ...). +Parool on liiga pikk. +&Parool +3900 +Kulunud aeg: +Järelejäänud aeg: +Kogumaht: +Kiirus: +Töödeldud: +Tihendussuhe: +Vigu: +Arhiive: +4000 +Arhiivi lisamine +&Arhiiv: +Värskend&usrežiim: +Arhiivi&vorming: +&Tihendusaste: +Tihendus&meetod: +Sõnaraamatu ma&ht: +&Sõna maht: +Ühtse ploki maht: +Protsessorilõimede arv: +Pa&rameetrid: +Suvandid +Loo is&eavanev arhiiv +Tihenda kirjutuseks avatud failid +Krüptimine +Krüptimismeetod: +Krüpti faili&nimed +Mälu hõivatus tihendamisel: +Mälu hõivatus hõrendamisel: +4050 +Tihenduseta +Kiireim tihendus +Kiirtihendus +Normaaltihendus +Maksimaaltihendus +Ultratihendus +4060 +Lisa ja asenda failid +Värskenda ja lisa failid +Värskenda olemasolevad failid +Sünkrooni failid +4070 +Sirvi +Kõik failid +Mitteühtne +Ühtne +6000 +Kopeerimine +Teisaldamine +Kopeeri asukohta: +Teisalda asukohta: +Kopeerimine... +Teisaldamine... +Ümbernimetamine... +Valige sihtkaust. +See toiming pole selles kaustas toetatud. +Tõrge faili või kausta ümbernimetamisel +Failikopeerimise kinnitamine +Kas soovite kindlasti kopeerida arhiivi järgmised failid: +6100 +Failikustutuse kinnitamine +Kaustakustutuse kinnitamine +Mitme faili kustutamise kinnitamine +Kas soovite kindlasti kustutada faili {0}? +Kas soovite kindlasti kustutada kausta {0} ja kogu selle sisu? +Kas soovite kindlasti kustutada need {0} üksust? +Kustutamine... +Tõrge faili või kausta kustutamisel +Süsteem ei saa teisaldada prügikasti pika teega faili. +6300 +Kausta loomine +Faili loomine +Kausta nimi: +Faili nimi: +Uus kaust +Uus fail +Tõrge kausta loomisel +Tõrge faili loomisel +6400 +- kommentaar +&Kommentaar: +Valimine +Valiku tühistamine +Mask: +6600 +Atribuudid +Kaustaajalugu +Diagnostikateated +Teade +7100 +Arvuti +Võrk +Dokumendid +Süsteem +7200 +Lisa +Eralda välja +Testi +Kopeeri +Teisalda +Kustuta +Teave +7300 +Faili tükeldamine: +&Tükelda asukohta: +&Tükelda köideteks (baitides): +Tükeldamine... +Tükeldamise kinnitamine +Kas soovite kindlasti tükeldada faili {0} köiteks? +Köite maht peab olema algfaili mahust väiksem. +Sobimatu köitemaht. +Määratud köitemaht: {0} baiti.\nKas soovite kindlasti tükeldada arhiivi niisugusteks köideteks? +7400 +Failide ühendamine: +Ü&henda asukohta: +Ühendamine... +Valige ainult tükeldatud faili esimene osa. +Ei õnnestu tuvastada, et see fail oleks tükeldatud faili osa. +Ei leia rohkem kui ühte tükeldatud faili osa. +7500 +Kontrollsumma arvutamine... +Kontrollsumma +Andmete CRC-kontrollsumma: +Andmete ja nimede CRC-kontrollsumma: +7600 +Jõudlustest +Mälu hõivatus: +Tihendamine +Hõrendamine +Hinnang +Üldine jõudlushinnang +Praegune: +Lõpptulemus: +CPU hõivatus +Hinnang/hõivatus +Töötiire: diff --git a/Utils/7-Zip/Lang/eu.txt b/Utils/7-Zip/Lang/eu.txt new file mode 100644 index 000000000..e9be78746 --- /dev/null +++ b/Utils/7-Zip/Lang/eu.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.12 : 2015-12-04 : Xabier Aramendi +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Basque +Euskara +401 +&Ongi +E&zeztatu + + + +&Bai +&Ez +It&xi +&Laguntza + +&Jarraitu +440 +Bai &Guztiari +Ez G&uztiari +Gelditu +Berrabiarazi +Ba&rrenean +&Gainean +&Pausatu +Pausatuta +Zihur zaude ezeztatzea nahi duzula? +500 +&Agiria +&Editatu +&Ikusi +&Gogokoenak +&Tresnak +&Laguntza +540 +&Ireki +Ireki &Barnean +Ireki &Kanpoan +Ik&usi +&Editatu +Berrize&ndatu +Kopiatu &Hona... +&Mugitu Hona... +E&zabatu +Banan&du agiria... +Nahas&tu agiriak... +Ezau&garriak +&Aipamena... +Ka&lkulatu egiaztapen-batura +Ezber +Sortu Agiritegia +S&ortu Agiria +I&rten +Lotura +&Aldikatu Jarioak +600 +Hautatu &Guztiak +Deshatutau G&uztiak +&Alderantzizkatu Hautapena +&Hautatu... +&Deshautatu... +Hautatu &Motaz +Deshautatu M&otaz +700 +Ikur &Handiak +Ikur Txi&kiak +&Zerrenda +&Xehetasunak +730 +Ant&olatugabe +Ik&uspegi Laua +&2 Panel +&Tresnabarrak +Ireki &Erro Agiritegia +Maila Bat &Gora +Agiritegi &Historia... +&Berritu +Be&rez Berritu +750 +Artxibo Tresnabarra +Tresnabarra Estandarra +Botoi Handiak +Erakutsi Botoien Idazkia +800 +&Gehitu agiritegia Gogokoenetara honela +Lastermarka +900 +A&ukerak... +&Benchmark +960 +&Edukiak... +&7-Zip Buruz... +1003 +Helburua +Izena +Luzapena +Agiritegia +Neurria +Pakete Neurria +Ezaugarriak +Sortua +Sartua +Aldatua +Solidoa +Aipatua +Enkriptatua +Banandu Aurretik +Banandu Ondoren +Hiztegia + +Mota +Anti +Metodoa +Hostalari SE +Agiri Sistema +Erabiltzailea +Taldea +Blokea +Aipamena +Kokapena +Helburu Aurrizkia +Agiritegiak +Agiriak +Bertsioa +Bolumena +Bolumen-anitz +Oreka +Loturak +Blokeak +Bolumenak + +64-bit +Big-endian +CPU +Neurri Fisikoa +Idazburu Neurria +Egiaztapen-batura +Ezaugarriak +Helbide Birtuala +ID-a +Izen Laburra +Aplikazio Sortzailea +Sektore Neurria +Modua +Lotura Sinbolikoa +Akatsa +Neurria Guztira +Toki Askea +Kluster Neurria +Etiketa +Tokiko Izena +Hornitzailea +NT Segurtasuna +Aldikatu Jarioa +Aux +Ezabatuta +Zuhaitza da + + +Akats Mota +Akatsak +Akatsak +Ohartarazpenak +Ohartarazpena +Jarioak +Aldikatu Jarioak +Aldikatu Jario Neurriak +Neurri Birtuala +Despaketatu Neurria +Neurri Fisikoa Guztira +Bolumen Aurkibidea +AzpiMota +Aipamen Labura +Kode Orrialdea + + + +Isats Neurria +Barneratutako Stub Neurria +Lotura +Lotura Gogorra +iNode + +Irakurtzeko-bakarrik +2100 +Aukerak +Hizkuntza +Hizkuntza: +Editatzailea +&Editatzailea: +E&zberdintasunak: +2200 +Sistema +Elkartu 7-Zip hauekin: +Erabiltzaile guztiak +2301 +&Bateratu 7-Zip shell hitzinguru menura +&Urjauzi hitzinguru menua +Hitzinguru menuko gaiak: +&Ikurrak hitzinguru menuan +2320 + + +Ireki artxiboa +Atera agiriak... +Gehitu &artxibora... +Aztertu artxiboa +Atera Hemen +Atera hona: {0} +Gehitu hona: {0} +Konprimitu eta &bidali post@z... +Konprimitu hona {0} eta bidali post@z +2400 +Agiritegiak +&Lan agiritegia +&Sistemaren aldibaterako agiritegia +&Oraingoa +A&dierazia: +&Erabili gidagailu kengarrientzat bakarrik +Adierazi aldibaterako artxibo agirientzako kokalekua +2500 +Ezarpenak +&Erakutsi ".." gai +E&rakutsi egizko agiriaren ikurrak +Erakutsi siste&maren menua +&Lerro osoko hautapena +Erakutsi &saretxo lerroak +&Klik-bakarra gai bat irekitzeko +A&ukerazko hautapen modua +Erabili &oroimen handiko orrialdeak +2900 +7-Zip buruz +7-Zip software askea da +3000 +Sistemak ezin du beharrezko oroimen kopurua esleitu +Ez dago akatsik +{0} objetu hautaturik +Ezin da '{0}' agiritegia sortu +Eguneratze eragiketak ez daude sostengaturik artxibo honentzat. +Ezinezkoa '{0}' agiria artxibo bezala irekitzea +Ezinezkoa '{0}' artxibo enkriptatua ireki. Sarhitz okerra? +Artxibo mota ez dago sostengatua +{0} agiria badago jadanik +'{0}' agiria aldatu egin da.\nArtxioboan eguneratzea nahi duzu? +Ezinezkoa agiria eguneratzea\n'{0}' +Ezin da editatzailea abiarazi. +Agiriak birus bat ematen du (agiri izenak tarte luzeak ditu izenean). +Eragiketa ezin da helburu luze bat duen agiritegi batetik deitu +Agiri bat hautatu behar duzu +Agiri bat edo gehiago hautatu behar dituzu +Gai gehiegi +Ezin da agiria {0} artxibo bezala ireki +Agiria {0} artxibo bezala dago irekita +Artxiboa orekaz irekita dago +3300 +Ateratzen +Konprimitzen +Aztertzen +Atzeratzen... +Mihatzen... +Kentzen +3320 +Gehitzen +Eguneratzen +Aztertzen +Erreplikatzen +Berpaketatzen +Jauzten +Ezabatzen +Idazburua sortzen +3400 +&Atera +Atera &hona: +A&dierazi ateratako agirientzako kokaleku bat. +3410 +Helburu mo&dua: +Helburu-izen osoak +Helburu-izenik ez +Helburu-izen absolutoak +Helburu-izen erlatiboak +3420 +Gainidazketa modua: +Galdetu gainidatzi aurretik +Gainidazi galdetu gabe +Jauzi dauden agiriak +Berez berrizendatu +Berez berrizendatu dauden agiriak +3430 +Ezabatu erro agiritegi bikoizketa +Leheneratu agiri segurtasuna +3500 +Baieztatu Agiri Ordeztea +Helmuga agiritegiak jadanik badu prozesatutako agiria. +Dagoen agiria ordeztea nahi duzu +beste honekin? +{0} byte +&Berez Berrizendatu +3700 +Konpresio metodo sostengatu gabea '{0}'-rako. +Datu akatsa '{0}'. Agiria hautsita dago. +CRC hutsegitea '{0}'. Agiria hautsita dago. +Datu akatsa '{0}' enkriptaturiko agirian. Sarhitz okerra? +CRC hutsegitea '{0}' enkriptaturiko agirian. Sarhitz okerra? +3710 +Sarhitz okerra? +3721 +Konpresio metodoa ez dago sostengatua +Datu akatsa +CRC hutsegitea +Datu eskuraezinak +Ustekabeko datu amaiera +Zenbait akats daude gertaketa amaieraren ondoren +Ez da artxiboa +Idazburu Akatsa +Sarhitz okerra +3763 +Artxibo hasiera eskuraezina +Artxibo hasiera baieztatugabe + + + +Ezaugarri sostengu gabea +3800 +Sartu sarhitza +Sartu sarhitza: +Bersartu sarhitza: +&Erakutsi sarhitza +Sarhitzak ez datoz bat +Erabili bakarrik Ingelerazko hizkiak, zenbakiak eta hizki bereziak (!, #, $, ...) sarhitzarentzat +Sarhitza luzeegia da +Sarhitza +3900 +Igarotako denbora: +Gelditzen den denbora: +Neurria guztira: +Abiadura: +Prozesatuta: +Konpresio maila: +Akatsak: +Artxiboak: +4000 +Gehitu artxibora +&Artxiboa: +Egu&neraketa modua: +Artxibo he&uskarria: +Konpre&sio maila: +Konpresio &metodoa: +&Hiztegi neurria: +Hi&tz neurria: +&Bloke solidoaren neurria: +&CPU hari zenbatekoa: +&Parametroak: +Aukerak +Sortu SF&X artxiboa +&Konprimitu elkarbanaturiko agiriak +Enkriptaketa +Enkriptaketa metodoa: +Enkriptatu agiri &izenak +Oroimen erabilera Konprimitzeko: +Oroimen erabilera Deskonprimitzeko: +Ezabatu agi&riak konprimitu ondoren +4040 +Biltegiratu lotura sinbolikoak +Biltegiratu lotura gogorrak +Biltegiratu aldikatu datu jarioak +Biltegiratu agiri segurtasuna +4050 +Biltegia +Azkarrena +Azkarra +Arrunta +Gehiena +Ultra +4060 +Gehitu eta ordeztu agiriak +Eguneratu eta gehitu agiriak +Berritu dauden agiriak +Aldiberetu agiriak +4070 +Bilatu +Agiri Denak +Ez-solidoa +Solidoa +6000 +Kopiatu +Mugitu +Kopiatu hona: +Mugitu hona: +Kopiatzen... +Mugitzen... +Berrizendatzen... +Hautatu helmuga agiritegia. +Eragiketa hau ez dago sostengatua agiritegi honentzat. +Akatsa Agiria edo Agiritegia Berrizendatzerakoan +Baieztatu Agiri Kopiatzea +Zihur zaude agiriak artxibora kopiatzea nahi dituzula +6100 +Baieztatu Agiri Ezabapena +Baieztatu Agiritegi Ezabapena +Baieztatu Agiri Anitz Ezabapena +Zihur zaude '{0}' ezabatzea nahi duzula? +Zihur zaude '{0}' agiritegia eta bere eduki guztiak ezabatzea nahi dituzula? +Zihur zaude {0} gai hauek ezabatzea nahi dituzula? +Ezabatzen... +Akatsa Agiria edo Agiritegia Ezabatzerakoan +Sistemak ezin du helburu luzeko agiria Birziklapen Ontzira mugitu +6300 +Sortu Agiritegia +Sortu Agiria +Agiritegi izena: +Agiri Izena: +Agiritegi Berria +Agiri Berria +Akatsa Agiritegia Sortzerakoan +Akatsa Agiria Sortzerakoan +6400 +Aipamena +&Aipamena: +Hautatu +Deshautatu +Mozorroa: +6600 +Ezaugarriak +Agiritegi Historia +Azterketa mezuak +Mezuak +7100 +Ordenagailua +Sarea +Agiriak +Sistema +7200 +Gehitu +Atera +Aztertu +Kopiatu +Mugitu +Ezabatu +Argibideak +7300 +Banandu Agiria +Banandu &hona: +Banandu &bolumenetan, byte: +Banantzen... +Baieztatu Banantzea +Zihur zaude agiria {0} bolumenetan banantzea nahi duzula? +Bolumen neurria jatorrizko agiriaren neurria baino txikiagoa izan behar da +Bolumen neurri okerra +Adierazitako bolumen neurria: {0} byte.\nZihur zaude artxiboa bolumenetan banantzea nahi duzula? +7400 +Nahastu Agiriak +&Nahastu hona: +Nahasten... +Hautatu bakarrik banantzeko agiriaren lehen atala +Ezin da agiria atzeman banandutako agiriaren atal bezala +Ezin da aurkitu banandutako agiriaren atal bat baino gehiago +7500 +Egiaztapen-batura kalkulatzen... +Egiaztapen-batura argibideak +CRC Egiaztapen-batura datuentzat: +CRC Egiaztapen-batura datu eta izenentzat: +7600 +Benchmark +Oroimen erabilpena: +Konprimitzen +Deskonprimitzen +Mailaketa +Mailaketa Guztira +Oraingoa +Emaitza +CPU Erabilpena +Mailaketa / Erabilpena +Pasaldiak: +7700 +Lotura +Lotura +Lotura hemendik: +Lotura hona: +7710 +Lotura Mota +Lotura Gogorra +Agiri Lotura Sinbolikoa +Zuzenbide Lotura Sinbolikoa +Zuzenbide Elkargunea diff --git a/Utils/7-Zip/Lang/ext.txt b/Utils/7-Zip/Lang/ext.txt new file mode 100644 index 000000000..469cd18f4 --- /dev/null +++ b/Utils/7-Zip/Lang/ext.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Miguel Angel +; 9.07 : Purgossu +; +; +; +; +; +; +; +; +; +0 +7-Zip +Extremaduran +Estremeñu +401 +Acetal +Cancelal + + + +&Sí +&Nu +&Fechal +Ayua + +A&continal +440 +Sí &a tó +Nu a &tó +Paral +Reinicial +Se&gundu pranu +&Primel pranu +&Paral +Parau +De siguru que quieri cancelal la operación? +500 +&Archivu +&Eital +&Vel +A&tihus +&Herramientas +A&yua +540 +&Abril +Abril &dentru +Abril &huera +&Vel +&Eital +Renom&bral +&Copial a... +&Movel pa... +&Eliminal +De&sapartal ficheru... +Com&binal ficherus... +P&ropieais +Come&ntariu +Calculal suma e verificación +Diff +Creal diretóriu +Creal ficheru +&Salil +600 +Selecional &tó +Deselecional tó +&Invertil seleción +Selecional... +Deselecional... +Selecional pol tipu +Deselecional pol tipu +700 +Iconus g&randis +Iconus caquerus +&Listau +&Detallis +730 +Nu soportau +Vista prana +&2 panelis +Barra e herramien&tas +Abril diretóriu raí +Subil un nivel +Estorial de diretórius... +&Atualizal +750 +Barra e herramientas 'archivu' +Barra e herramientas estándal +Botonis grandis +Muestral testu enus botonis +800 +&Añíl diretóriu a Atihus comu +Atihu +900 +&Ocionis... +&Prebas ('benchmark') +960 +&Contenius... +&Al tentu 7-Zip... +1003 +Ruta +Nombri +Estensión +Diretóriu +Tamañu +Tamañu comprimiu +Atributus +Creau'l +Úrtimu acesu +Escambiau'l +Sóliu +Comentau +Encrihtau +Desapartau enantis +Desapartau endispués +Izionáriu +CRC +Tipu +Anti +Métou +S.O. orihin +Sistema d'archivus +Usuariu +Grupu +Broqui +Comentariu +Posición +Prefihu la ruta +Diretórius +Ficherus +Velsión +Volumin +Murtivolumin +Desprazamientu +Enlacis +Broquis +Volúmenis + +64-bit +Big-endian +UCP +Tamañu físicu +Tamañu las cabiceras +Suma e cumprebación +Caraterísticas +Direción virtual +ID +Nombri cortu +Apricación criaora +Tamañu el setol +Mou +Enlaci +Yerru +Tamañu total +Espaciu dispunibri +Tamañu el 'cluster' +Etiqueta +Nombri local +Proveol +2100 +Ocionis +Palra +Palra: +Eitol +&Eitol: +&Diff: +2200 +Sistema +Asocial 7-Zip a hormatus: +2301 +Integral 7-Zip nel menú contestual +Menú contestual en cascá +Elementus del menú contestual: +2320 + + +Abril archivu +Estrayel ficherus... +Añíl al archivu... +Comprebal archivu +Estrayel aquina +Estrayel en {0} +Añiil a {0} +Comprimil i envial pol correu-e... +Comprimil en {0} i envial pol correu +2400 +Diretórius +Diretóriu e labu&tu +Diretóriu temporal del &sistema +Diretóriu &ahtual +&Especifical: +Usal sólu pa dispositivus estrayíbris +Especifical ruta pa ficherus d'archivus temporalis. +2500 +Configuración +Muestral l'elementu \.." +Muestral icunus propius del ficheru +Muestral menú el sistema +&Selecional fila(s) enteriza(s) +Muestral línias e la &cuairícula +'Click' únicu p'abril un elementu +Móu e seleción &alternativu +Usa&l páhinas de memoria grandis +2900 +About 7-Zip +7-Zip es una apricación libri i a gastus pagus. Peru puei apoyal el desarrollu e 7-Zip meyanti'l rehistru el pograma. +3000 +El sistema nu á síu escapás d'asinal la cantiá prehisa de memoria +Sin yerrus +{0} elementu(s) selecionaus +Nu s'á puiu crial el diretóriu '{0}' +Nu se puei atualizal esti tipu d'archivu. +Nu s'á puiu abril '{0}' comu archivu +Nu s'a puiu abril l'archivu encritau '{0}'. Conseña yerronia? +Tipu archivu nu suportau +File {0} is already exist +El ficheru '{0}' á síu moificau.\nAtualizalu nel archivu? +Nu s'á puíu atualizal l'archivu\n'{0}' +Nu s'á puíu ehecutal el eitol. +El ficheru pahi un virus (el nombri'l ficheru contieni espacius largus nel nombri). +Nu puei realizasi la operación dendi un diretóriu que tenga una ruta larga. +You must select one file +You must select one or more files +Ai elementus en demasía +3300 +Estrayendu +Comprimiendu +Comprebandu +Abriendu... +Escaneandu... +3400 +Estrayel +E&strayel a: +Especifical destinu palus ficherus estrayíus. +3410 +Mou e ruta +Ruta compreta +Sin ruta +3420 +Mou e sobrescrebil +Preguntal enantis +Sobrescrebil sin preguntal +Conserval ficherus esistentis +Renombral de horma automática +Autu-renombral ficherus esistentis +3500 +Confirmal remprazu de ficherus +El diretóriu ya contieni un ficheru el mesmu nombri. +Escambial el ficheru esistenti +pol esti otru? +{0} bytes +Escambial nombri a&utomáticamenti +3700 +Métou e compresión nu soportau pa '{0}'. +Yerru datus en '{0}'. El ficheru está changarrau. +Yerru e CRC '{0}'. El ficheru está changarrau. +Yerru e datus nel ficheru encritau '{0}'. Conseña yerrónia? +Yerru e CRC nel ficheru encritau '{0}'. Conseña yerrónia? +3800 +Introuzil conseña +Introuzil conseña: +Repitil conseña: +Mue&stral conseña +Las cunseñas nu coinciín +Usi sólu letras ingresas, númirus i caráteris especialis (!, #, $, ...) pala conseña +La conseña tieni largura'n demasía +Conseña +3900 +Tiempu trascurríu: +Tiempu restanti: +Tamañu total: +Velociá: +Procesau: +Tasa e compresión: +Yerrus: +Archivus: +4000 +Añiil a archivu +&Archivu: +&Mou d'atualización: +&Hormatu d'archivu: +Nive&l de compresión: +Mé&tou e compresión: +Tamañu el i&zionariu: +Tama&ñu e parabra: +Tamañu el bloqui sóliu: +Númiru hilus e la UCP: +&Parámetrus: +Ocionis +Creal archivu 'SF&X' +Comprimil ficherus compartíus +Encritación +Métou encritación: +Encrital &nombris de ficheru +Usu e memoria pa compresión: +Usu e memoria pa decompresión: +4050 +Almacenal +La más respahila +Respahila +Normal +Másima +Ultra +4060 +Añiil i remprazal ficherus +Atualizal i añiil ficherus +Atualizal sólu ficherus esistentis +Sincronizal ficherus +4070 +Esproral +Tolos ficherus +Nu sóliu +Sóliu +6000 +Copial +Movel +Copial a: +Movel pa: +Copiandu... +Moviendu... +Renombrandu... +Selecional diretóriu destinu. +Operación nu soportá. +S'alcuentrau'n yerru al renombral el ficheru u diretóriu +Confirmal copia el ficheru +De siguru que quieri copiar estus ficherus al archivu? +6100 +Confirmal eliminación del ficheru +Confirmal eliminación del direhtoriu +Confirmal eliminación de varius ficherus +De siguru que quieri eliminal '{0}'? +De siguru que quieri eliminal el diretóriu '{0}' i tol su conteniu? +De siguru que quieri eliminal estus {0} elementus? +Eliminandu... +S'alcuentrau'n yerru al eliminal el ficheru u diretóriu +El sistema nu puei movel un ficheru con ruta larga a la Papelera Recicrahi +6300 +Creal diretóriu +Creal ficheru +Nombri e diretóriu: +Nombri el ficheru: +Nuevu diretóriu +Nuevu ficheru +S'alcuentrau'n yerru al creal el diretóriu +S'alcuentrau'n yerru al creal el ficheru +6400 +Comentáriu +&Comentáriu: +Selecional +Deselecional +Máscara: +6600 +Propieais +Estorial de diretórius +Mensahis de dianósticu +Mensahi +7100 +Mi PC +Entorno de red +Documentos +Sistema +7200 +Añiil +Estrayel +Comprebal +Copial +Movel +Eliminal +Inhormazión +7300 +Desapartal ficheru +&Desapartal a: +Desapartal en &balandronis, 'bytes': +Desapartandu... +Confirmal desapartamientu +De siguru que quieri desapartal el ficheru'n {0} volúmenis? +El tamañu lus volúmenis debi sel mas caqueru que'l del ficheru orihinal +Tamañu el volumin nu váliu +Introuza'l tamañu el volumin: {0} 'bytes'.\nDe siguru que quieri desapartal l'archivu'n tantus volúmenis? +7400 +Uñil ficherus +&Uñil en: +Uñiendu... +Selecional sólu'l primel ficheru +Nu s'á puíu detetal el ficheru comu parti d'un ficheru desapartau +Nu s'á puíu alcuentral más d'un balandrón del ficheru desapartau +7500 +Calculandu la suma e verificación... +Inhormazión de suma e verificación +Suma e verificación de 'CRC' pala inhormazión: +Suma e verificación de 'CRC' pala inhormazión i lus nombris: +7600 +Prebas ('benchmark') +Usu e memoria: +Comprimiendu +Comprimiendu +Razón +Razón total +Atual +Resurtau +Usu e CPU +Razón / Usu +Pasis: diff --git a/Utils/7-Zip/Lang/fa.txt b/Utils/7-Zip/Lang/fa.txt new file mode 100644 index 000000000..c524ed468 --- /dev/null +++ b/Utils/7-Zip/Lang/fa.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 3.12 : Edris Naderan +; 4.53 : Mehdi Farhadi +; 9.22 : Hessam Mohamadi +; +; +; +; +; +; +; +; +0 +7-Zip +Farsi +فارسی +401 +تایید +لغو + + + +بله&ه +&خیر +بستن +راهنما + +ادامه +440 +بله روی همه +نه روی همه +توقف +ریستارت +پس زمینه +پیش زمینه +وقفه +متوقف +آیا میخواهید عملکرد را لغو میکنید؟ +500 +فایل +ویرایش +مشاهده +موردعلاقه ها +ابزارها +راهنما +540 +بازکردن +بازکردن از داخل +بازکردن از خارج +مشاهده +ویرایش +تغییرنام +کپی به... +انتقال به... +حذف +تقسیم فایل... +ادغام فایل.. +مشخصات +توضيح.. +محاسبه مجموع مقابله ای +مقایسه گر +ایجاد پوشه +ایجاد فایل +خروج +600 +انتخاب همه +لغو انتخاب‌ همه +انتخاب معکوس +انتخاب... +لغو انتخاب... +انتخاب بر حسب نوع +لغو انتخاب بر حسب نوع +700 +آیکون‌ بزرگ +آیکون‌ کوچک +لیست +جزئیات +730 +نامرتب +مشاهده یکنواخت +2 پانل +نوارابزارها +بازکردن ریشه پوشه +یک مرحله به بالا +تاریخچه پوشه ها.. +تازه کردن +750 +نوارابزار آرشیو +نوارابزار استاندارد +دکمه بزرگ +نمایش متن دکمه ها +800 +افزودن پوشه به مورد علاقه بعنوان +بوکمارک +900 +گزینه ها.. +سنجش +960 +محتویات.. +درباره برنامه.. +1003 +مسیر +نام +پسوند +پوشه +حجم +حجم فشرده شده +صفات +ساخته شده +دستیابی شده +تغییر یافته +یکدست +توضیح دار +رمزگذاری شده +تقسیم قبل از +تقسیم بعد از +لغت نامه +سی آر سی +نوع +Anti +روش +سیستم میزبان +فایل سیستمی +کاربر +گروه +بلوک +توضيح‌ +موقعیت +مسیر پیشوند +پوشه ها +فایل ها +نسخه +بخش +چند بخشی +آفست +لینک +بلوک ها +بخش ها + +64 بیت +Big-endian +پردازنده +حجم فیزیکی +حجم سرساز ها +مجموع مقابله ای +خصوصیات +آدرس مجازی +شناسه +نام کوتاه +سازنده برنامه +حجم قطاع +حالت +لینک +خطا +مجموع حجم +فضای خالی +حجم کلاستر +برچسب +نام محلی +ارائه دهنده +2100 +گزینه ها +زبان +زبان: +ویرایشگر +ویرایشگر: +مقایسه گر: +2200 +سیستم +وابسته سازی برنامه با: +2301 +افزودن منوی برنامه به منوی ویندوز +منوها به صورت آبشاری در یک منو +آیتم های منوی برنامه: +2320 +<پوشه> +<آرشیو> +بازکردن آرشیو +استخراج فایل‌ها... +افزودن به آرشیو... +تست آرشیو +استخراج در اینجا +استخراج به {0} +افزودن به {0} +فشرده سازی و ارسال با ایمیل... +فشرده‌سازی در {0} و ارسال با ایمیل +2400 +پوشه ها +پوشه در حال کار +پوشه موقت سیستم +فعلی +مشخص کنید: +فقط برای درایوهای پرتابل استفاده شود +یک مکان برای فایل های موقتی آرشیو مشخص کنید +2500 +تنظیمات +نمایش آیتم ".." +نمایش آیکون واقعی فایل +نمایش منوی سیستم +انتخاب سطر به طور کامل +نمایش خطوط توری +تک کلیک برای بازکردن یک آیتم +حالت انتخاب جايگزين +استفاده از صفحات حافظه حجیم +2900 +درباره برنامه +برنامه‌ای که در پیش رو دارید یک برنامه رایگان است، اما شما می توانید با پرداخت مبلغی جزئی به توسعه این نرم‌افزار کمک کنید. +3000 +سیستم مقدار حافظه موردنیاز را نمیتواند اختصاص دهد +خطایی وجود ندارد +{0} آیتم انتخاب شده +ایجاد پوشه '{0}' ممکن نیست +عملکرد بروزرسانی برای این آرشیو بروزرسانی نمیشود +فایل '{0}' را بعنوان یک آرشیو نمیتوان باز کرد +آرشیو رمزگذاری شده '{0}' را نمیتوان باز کرد.رمزعبور اشتباه است؟ +نوع آرشیو پشتیبانی نشده +فایل {0} از قبل موجود است +فایل '{0}' تغییر کرده است.\n آیا میخواهید این فایل در آرشیو بروزرسانی شود؟ +این فایل قابل بروزرسانی نمی‌باشد\n'{0}' +ویرایشگر را نمیتوان اجرا کرد +فایل شبیه ویروس است (نام فایل حاوی فضای بلندی در نام هست). +عملکرد نمیتواند از پوشه ای که مسیر بلند دارد فراخوانی شود +شما باید یک فایل انتخاب کنید +شما باید یک یا تعداد بیشتری فایل انتخاب کنید +تعداد آیتم ها بسیار زیاد است +3300 +در حال استخراج +فشرده سازی +تست +درحال بازکردن.. +در حال اسکن.. +3400 +استخراج +استخراج به: +یک مکان برای فایل های استخراج شده تعیین کنید +3410 +نوع مسیر +نام مسیر کامل +بدون نام مسیر +3420 +حالت جایگزینی +پرسش قبل از جایگزینی +جایگزینی بدون اخطار +چشمپوشی فایل‌های موجود +تغییرنام خودکار +تغییرنام خودکار فایل های موجود +3500 +تایید جایگزینی فایل +پوشه مقصد از قبل حاوی فایل در حال پردازش هست +آیا میخواهید فایل موجود با +این یکی جایگزین شود؟ +{0} بایت +تغییرنام خودکار +3700 +روش فشرده سازی برای '{0}' پشتیبانی نشذه است +خطای داده در '{0}'. اين فايل شکسته هست +سی آر سی در '{0}' موفق نشد.فایل شکسته هست +خطای داده در فايل رمزگذارى شده '{0}'. رمزعبور اشتباه است؟ +سی آر سی در فایل رمزگذاری شده '{0}' موفق نشد.رمزعبور اشتباه است +3800 +رمزعبور +رمزعبور: +تكرار رمزعبور: +نمایش رمزعبور +رمزعبورها یکسان نیست +فقط از حروف انگليسى، اعداد و علامت‌هاى خاص (!، #، $، ...) در رمزعبور استفاده كنيد +رمزعبور خیلی بلند است +رمزعبور +3900 +زمان سپری شده: +زمان باقیمانده: +مجموع حجم: +سرعت: +پردازش شده: +نسبت فشرده سازی: +خطاها: +آرشیو‌: +4000 +افزودن به آرشیو +آرشیو: +حالت بروزرسانی: +فرمت آرشیو: +ميزان فشرده‌سازی: +روش فشرده سازی: +حجم لغت نامه: +اندازه لغت: +حجم بلوک یکدست: +تعداد هسته پردازنده +پارامترها: +گزینه ها +ایجاد ارشیو خوداستخراجگر +فشرده سازی فایل های مشترک درسایر برنامه ها +رمزگذاری +روش رمزگذاری: +رمزگذاری نام فایل ها +حافظه مصرفی برای فشرده سازی: +حافظه مصرفی برای استخراج: +4050 +ذخیره +سریعترین +سریع +عادی +حداکثر +مافوق +4060 +افزودن و جایگزینی فایل ها +بروزرسانی و افزودن فایل ها +تازه کردن فایل های موجود +همگامسازی فایل ها +4070 +جستجو +همه فایل ها +غیر-یکدست +یکدست +6000 +کپی +انتقال +کپی به: +انتقال به: +در حال کپی... +در حال انتقال... +تغییرنام... +پوشه مقصد را انتخاب كنيد +عملکرد برای این پوشه پشتیبانی نمیشود +خطای تغییر نام فایل یا پوشه +تایید کپی فایل +آیا میخواهید فایل ها را به ارشیو کپی کنید +6100 +تایید حذف فایل +تایید حذف پوشه +تایید حذف فایل ها +آیا میخواهید '{0}' را حذف کنید؟ +آیا میخواهید پوشه '{0}' و همه محتویات آن را حذف کنید؟ +آیا میخواهید این {0} آیتم را حذف کنید؟ +در حال حذف... +خطای حذف فایل یا پوشه +سیستم فایل با مسیر بلند را نمیتواند به سطل زباله انتقال دهد +6300 +ایجاد پوشه +ایجاد فایل +نام پوشه: +نام فایل: +پوشه جدید +فایل جدید +خطای ایجاد پوشه +خطای ایجاد فایل +6400 +توضيح +توضيح: +انتخاب +لغو انتخاب +ماسك: +6600 +مشخصات +تاریخچه پوشه‌ها +پیغام‌های تشخيصی +پیام +7100 +رایانه +شبکه +اسناد +سیستم +7200 +افزودن +استخراج +تست +کپی +انتقال +حذف +اطلاعات +7300 +تقسیم فایل +تقسیم در: +تقسیم به چندین بخش،برحسب بایت: +در حال تقسیم... +تاييد تقسیم فایل +آیا میخواهید اين فايل را به {0} بخش تقسيم كنيد؟ +حجم بخش ها باید کوچکتر از اندازه فایل اصلی باشد +حجم بخش نادرست است +حجم بخش های مشخص شده: {0} بايت.\nآیا میخواهید آرشيو را به بخش هایی به اين اندازه تقسيم كنيد؟ +7400 +ادغام فایل ها +ادغام در: +در حال ادغام... +فقط اولین بخش فایل را انتخاب کنید +فایل را نمی تواند بعنوان فایل تقسیمی تشخیص دهد +بیشتر از یک بخش از فایل تقسیمی را نمیتواند پیدا کند +7500 +محاسبه مجموع مقابله ای.. +اطلاعات مجموع مقابله ای +مجموع مقابله ای سی آر سی برای داده: +مجموع مقابله ای سی آر سی برای داده و نام: +7600 +سنجش +حافظه مصرفی: +فشرده سازی +استخراج +رتبه بندی +رتبه بندی کلی: +فعلی +دستاورد +مصرف پردازنده +رتبه بندی / مصرف +تعداد عبور: diff --git a/Utils/7-Zip/Lang/fi.txt b/Utils/7-Zip/Lang/fi.txt new file mode 100644 index 000000000..c40152594 --- /dev/null +++ b/Utils/7-Zip/Lang/fi.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 3.08 : Ari Ryynanen +; 4.30 : Jarko P. +; 4.42 : Juhani Valtasalmi +; 9.35b : T.Sakkara +; 15.05 : 2015-08-07 : Lauri Kenttä +; +; +; +; +; +; +0 +7-Zip +Finnish +Suomi +401 +OK +Peruuta + + + +&Kyllä +&Ei +&Sulje +Ohje + +&Jatka +440 +Kyllä k&aikkiin +E&i kaikkiin +Pysäytä +Aloita uudelleen +&Tausta-ajona +&Normaali prioriteetti +&Pysäytä +Pysäytetty +Keskeytetäänkö toiminto? +500 +&Tiedosto +&Muokkaa +&Näytä +&Suosikit +Työ&kalut +&Ohje +540 +&Avaa +Avaa s&isäisesti +Avaa ulkoisesti +&Näytä +&Muokkaa +Nimeä &uudelleen +&Kopioi... +&Siirrä... +&Poista +&Jaa osiin... +&Yhdistä jaetut... +&Ominaisuudet +Ku&vaus +Laske tarkiste +Erot +Luo kansio +Luo tiedosto +&Lopeta +Linkitä +Vaihtoehtoiset tietovirrat +600 +V&alitse kaikki +Poista &valinnat +&Käänteinen valinta +Valitse... +Poista valinta... +Valitse lajeittain +Poista valinta lajeittain +700 +Suu&ret kuvakkeet +&Pienet kuvakkeet +&Luettelo +&Tiedot +730 +Alkuperäinen järjestys +Kansioiden sisältö luetteloituna +&Kaksi panelia +&Työkalupalkki +Avaa pääkansio +Avaa yläkansio +Kansiohistoria... +P&äivitä +Automaattipäivitys +750 +Pakettipalkki +Vakiopalkki +Suuret painikkeet +Näytä painiketekstit +800 +&Lisää kansio Suosikkeihin +Kirjanmerkki +900 +&Asetukset... +&Nopeustesti +960 +&Sisältö... +&Tietoja ohjelmasta... +1003 +Polku +Nimi +Pääte +Kansio +Koko +Pakattu koko +Määritteet +Luotu +Käytetty +Muokattu +Kiinteä +Kuvailtu +Suojaus +Jaa ennen +Jaa jälkeen +Sanakirja +Tarkiste +Laji +Vastakohta +Menetelmä +Isäntäjärjestelmä +Tiedostojärjestelmä +Käyttäjä +Ryhmä +Lohkoja +Kuvaus +Kohta +Polun etuliite +Kansioita +Tiedostoja +Versio +Nimi +Jaettu osiin +Siirtymä +Linkit +Lohkot +Nimet + +64-bittinen +Big-endian +Suoritin +Fyysinen koko +Otsikon koko +Tarkiste +Ominaisuudet +Näennäisosoite +ID +Lyhyt nimi +Luontisovellus +Sektorikoko +Tila +Symbolinen linkki +Virhe +Aseman koko +Vapaata tilaa +Varausyksikön koko +Nimi +Paikallinen nimi +Palveluntarjoja +NT-suojaukset +Vaihtoehtoinen tietovirta +Muu +Poistettu +On kansiorakenne + + +Virhelaji +Virheet +Virheet +Varoitukset +Varoitus +Tietovirrat +Vaihtoehtoiset tietovirrat +Vaihtoehtoisten tietovirtojen koko +Näennäiskoko +Pakkaamaton koko +Fyysinen koko +Aseman indeksi +Alilaji +Kuvaus +Koodisivu + + + +Loppupään koko +Upotetun segmentin koko +Linkki +Kiinteä linkki +iNode + +Vain luku +2100 +Asetukset +Kieli +Kieli: +Muokkausohjelmat +&Tekstieditori: +&Erojen etsintä: +2200 +Järjestelmäliitännät +Liitä 7-Zip seuraaviin tiedostotyypeihin: +Kaikki käyttäjät +2301 +Liitä 7-Zip järjestelmän valikoihin. +Ryhmitetty järjestelmävalikko +Järjestelmävalikon sisältö: +Näytä järjestelmävalikon kuvakkeet +2320 + + +Avaa +Pura... +Lisää pakettiin... +Eheystarkastus +Pura tänne +Pura kansioon {0} +Lisää pakettiin {0} +Pakkaa tiedostot ja lähetä... +Lisää pakettiin {0} ja lähetä +2400 +Kansiot +&Työkansio +&Järjestelmän väliaikaiskansio +&Nykyinen kansio +&Valittu kansio: +Käytä vain siirrettäville tietovälineille +Määritä väliaikaistiedostojen sijainti. +2500 +Tiedostoikkuna +Näytä &yläkansion symboli +Näytä &aidot tiedostokuvakkeet +Näytä &järjestelmävalikko +&Valitse koko rivi +Näytä &ruudukko +Avaa &kertanapsautuksella +Vaihtoehtoinen valintojen &esitystapa +Käytä &suuria muistisivuja +2900 +Tietoja +7-Zip on ilmaisohjelmisto. +3000 +Ei riittävästi muistia toimintoa varten +Ei virheitä. +{0} tiedosto(a) valittu +Ei voida luoda kansioita '{0}.' +Tätä pakettia ei voi päivittää. +Tiedoston '{0}' pakkausta ei voi purkaa. +Ei voi avata suojattua pakettia '{0}'. Väärä salasana? +Pakkaustapaa ei tueta +Tiedosto {0} on jo olemassa +Tiedostoa '{0}' on muutettu.\nHaluatko päivittää paketin? +Ei voida päivittää tiedostoa \n'{0}'. +Editoria ei voida käynnistää. +Tiedosto vaikuttaa haittaohjelmalta, sillä sen nimi sisältää peräkkäisiä välilyöntejä. +Toimintoa ei voi suorittaa kansiosta, jonka nimi on pitkä. +Valitse yksi tiedosto +Valitse vähintään yksi tiedosto +Liian monta kohdetta. +Ei voida avata tiedostoa {0}-pakettina +Tiedosto on avattu {0}-pakettina +Paketti on auki eri alkukohdasta (offset) +3300 +Puretaan paketti +Lisätään pakettiin +Eheystarkistus +Avataan... +Etsitään... +Poistetaan +3320 +Lisätään +Päivitetään +Analysoidaan +Kopioidaan +Pakataan uudestaan +Ohitetaan +Poistetaan +Luodaan otsikkoa +3400 +Pura +&Pura kansioon +Määritä puretuille tiedostoille sijainti. +3410 +Polut: +Täydet polut +Ei polkuja (vain nimi) +Absoluuttiset polut +Suhteelliset polut +3420 +Samannimiset tiedostot: +Kysy tapauskohtaisesti +Korvaa +Ohita +Uudelleennimeä automaattisesti +Uudelleennimeä entiset automaattisesti +3430 +Estä pääkansion kahdennus +Palauta tiedostojen suojaukset +3500 +Vahvista tiedoston korvaus +Kansiossa on jo samanniminen tiedosto. +Korvataanko aiempi tiedosto +tällä tiedostolla? +{0} tavua +&Uudelleennimeä automaattisesti +3700 +Tiedoston '{0}' pakkaustapaa ei tueta. +Sisältövirhe tiedostossa '{0}'. Tiedosto on viottunut. +Tiedoston '{0}' eheystarkistus epäonnistui. Tiedosto on vioittunut. +Virhe avattaessa suojattua tiedostoa '{0}'. Väärä salasana? +Tarkistevirhe avattaessa suojattua tiedostoa '{0}'. Väärä salasana? +3710 +Väärä salasana? +3721 +Pakkaustapaa ei tueta +Sisältövirhe +Tarkistevirhe +Sisältö ei ole käytettävissä +Sisällön ennenaikainen loppuminen +Varsinaisen tietosisällön jälkeen on ylimääräistä sisältöä +Tiedosto ei ole pakattu +Otsikkovirhe +Väärä salasana +3763 +Pakkauksen alku ei käytettävissä +Pakkauksen alkua ei vahvistettu + + + +Toiminto ei tuettu +3800 +Syötä salasana +Syötä salasana: +Toista salasana: +Näytä &salasana +Salasanat eivät täsmää +Salasanassa voi käyttää numeroita ja erikoismerkkejä, mutta EI skandinaavisia kirjaimia. +Liian pitkä salasana +Salasana +3900 +Aikaa kulunut: +Aikaa jäljellä: +Koko: +Nopeus: +Käsitelty: +Pakkaussuhde: +Virheitä: +Paketteja: +4000 +Lisää pakettiin +&Paketti: +&Päivitystapa: +Pakkaus&: +Pakkauksen &taso: +Pakkaus&menetelmä: +&Sanakirjan koko: +&Sanan koko: +Lohkokoko +Prosessorisäikeet: +&Parametrit: +Lisäasetukset +Luo itsepurkautuva paketti +Pakkaa yhteiset tiedostot +Suojaus +Salausalgoritmi +Tiedosto&nimien suojaus +Pakkaamiseen käytettävä muisti: +Purkamiseen käytettävä muisti: +Poista pakkauksen jälkeen +4040 +Tallenna symboliset linkit +Tallenna kiinteät linkit +Tallenna vaihtoehtoiset tietovirrat +Tallenna tiedostojen suojaukset +4050 +Ei pakkausta +Nopein +Nopea +Normaali +Maksimi +Ultra +4060 +Lisää ja korvaa +Päivitä ja lisää +Päivitä +Synkronoi +4070 +Selaa +Kaikki tiedostot +Muuttuva +Kiinteä +6000 +Kopioi +Siirrä +Kopioi kansioon: +Siirrä kansioon: +Kopioidaan... +Siirretään... +Nimetään uudelleen... +Valitse kohdekansio. +Toiminto ei ole tuettu. +Virhe uudelleennimettäessä tiedostoa tai kansiota +Vahvista tiedoston kopioiminen +Kopioidaanko tiedostot pakettiin +6100 +Vahvista tiedoston poisto +Vahvista kansion poisto +Vahvista useiden kohteiden poisto +Poistetaanko tiedosto '{0}'? +Poistetaanko kansio '{0}' ja kaikki sen sisältö? +Poistetaanko nämä {0} kohdetta? +Poistetaan... +Virhe poistettaessa tiedostoa tai kansiota +Roskakoriin ei voida siirtää tiedostoa, jolla on pitkä nimi +6300 +Luo uusi kansio +Luo uusi tiedosto +Kansion nimi: +Tiedostonimi: +Uusi kansio +Uusi tiedosto +Virhe luotaessa kansiota +Virhe luotaessa tiedostoa +6400 +Kuvaus +&Kuvaus: +Valitse +Poista valinta +Maski: +6600 +Ominaisuudet +Kansiohistoria +Tietoja +Viesti +7100 +Tietokone +Verkko +Dokumentit +Järjestelmä +7200 +Lisää +Pura +Eheystarkistus +Kopioi +Siirrä +Poista +Ominaisuudet +7300 +Jaa tiedosto osiin +&Jaa kansioon: +&Osien koko jaettaessa: +Jaetaan osiin... +Vahvista jakaminen. +Jaetaanko tiedosto {0} osaan? +Jaetun osan koon pitää olla alkuperäistä pienempi. +Jaetun osan koko ei kelpaa +Jaettavien osien koko: {0} tavua.\nJaetaanko tiedosto sen kokoisiin osiin? +7400 +Yhdistä jaetut tiedostot +&Yhdistä kansioon: +Yhdistetään... +Valitse jaetusta tiedostosta vain ensimmäinen osa +Tiedosto ei ole jaetun tiedoston osa +Jaetun tiedoston osista löydettiin vain yksi +7500 +Lasketaan tarkiste... +Tarkisteet +Sisällön tarkiste: +Sisällön ja tiedostonimien tarkiste: +7600 +Nopeustesti +Muistin käyttö: +Pakkaaminen +Purkaminen +Luokitus +Kokonaisluokitus +Nykyinen +Tulos +Suoritinkäyttö +Luokitus / käyttö +Läpäisty: +7700 +Linkitys +Linkitä +Linkitys kohteesta: +Linkitys kohteeseen: +7710 +Linkkilaji +Kiinteä linkki +Symbolinen tiedostolinkki +Symbolinen kansiolinkki +Kansioliitos diff --git a/Utils/7-Zip/Lang/fr.txt b/Utils/7-Zip/Lang/fr.txt new file mode 100644 index 000000000..fa661c7a0 --- /dev/null +++ b/Utils/7-Zip/Lang/fr.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 4.07 : Nicolas Sierro +; 9.07 : Philippe Berthault +; 15.14 : Sylvain St-Amand (SSTSylvain) +; +; +; +; +; +; +; +; +0 +7-Zip +French +Français +401 +OK +Annuler + + + +&Oui +&Non +&Fermer +Aide + +&Continuer +440 +Oui pour &Tous +Non pour T&ous +Arrêter +Redémarrer +&Arrière-plan +P&remier plan +&Pause +En pause +Êtes-vous sur de vouloir annuler ? +500 +&Fichier +&Édition +Affic&hage +Fa&voris +&Outils +&Aide +540 +&Ouvrir +Ouvrir à l'&intérieur +Ouvrir à l'e&xtérieur +&Voir +&Édition +Reno&mmer +&Copier vers... +&Déplacer vers... +S&upprimer +Diviser le &fichier... +Combiner les fic&hiers... +P&ropriétés +Comme&ntaire... +Somme de contrôle +Diff +Créer un dossier +Créer un fichier +&Quitter +Lien +Flux &Alternatif +600 +Sélectionner &Tout +Désélectionner Tout +&Inverser la Sélection +Sélectionner... +Désélectionner... +Sélectionner par Sorte +Désélectionner par Sorte +700 +&Grandes Icônes +&Petites Icônes +&Liste +&Détails +730 +Non trié +Vue à plat +&2 Fenêtres +&Barres d'outils +Ouvrir le dossier racine +Dossier parent +Historique des dossiers... +Actualis&er +Actualiser Automatiquement +750 +Barre d'Archive +Barre Standard +Grands Boutons +Montrer le texte des Boutons +800 +&Ajouter le répertoire aux Favoris +Signet +900 +&Options... +&Test de performance +960 +&Contenu... +À &propos de 7-Zip... +1003 +Chemin +Nom +Extension +Dossier +Taille +Compressé +Attributs +Créé le +Accédé le +Modifié le +Solide +Commentaire +Chiffrer +Diviser Avant +Diviser Après +Dictionnaire + +Sorte +Anti +Méthode +OS hôte +Système de Fichiers +Utilisateur +Groupe +Bloc +Commentaire +Position +Préfixe +Dossiers +Fichiers +Version +Volume +Multivolume +Offset +Liens +Blocs +Volumes + +64 bits +Big-endian +CPU +Taille physique +Taille des en-têtes +Somme de contrôle +Caractéristiques +Adresse virtuelle +ID +Nom court +Application créatrice +Taille de secteur +Mode +Lien Symbolique +Erreur +Taille Totale +Espace Libre +Taille des clusters +Nom de volume +Nom local +Fournisseur +Sécurité NT +Flux alternatif +Aux +Effacer +En Arbre + + +Type d'erreur +Erreurs +Erreurs +Avertissements +Avertissement +Flux +Flux Alterné +Grosseur du Flux Alterné +Grosseur Virtuel +Grosseur Décompressé +Grosseur Physique Totale +Indexe du Volume +Sous-Type +Commentaire Bref +Code Page + + + +Grosseur Tail +Grosseur Embedded Stub +Lien +Lien Solide +iNode + +Lecture-seulement +2100 +Options +Langue +Langue : +Éditeur +&Éditeur : +&Diff : +2200 +Système +Associer avec 7-Zip : +Tous les utilisateurs +2301 +Intégrer 7-Zip au menu contextuel +Menu contextuel en cascade +Éléments du menu contextuel : +Icônes dans le menu contextuel +2320 + + +Ouvrir archive +Extraire les fichiers... +Ajouter à l'archive... +Contrôler l'archive +Extraire Ici +Extraire vers {0} +Ajouter à {0} +Compresser et envoyer par courriel... +Compresser vers {0} et envoyer par courriel +2400 +Dossiers +Dossier de &travail +Dossier temporaire du &système +&Courant +S&pécifié : +N'utiliser que pour les médias amovibles +Spécifiez un dossier pour les fichiers d'archive temporaires. +2500 +Paramètres +Afficher l'élément ".." +Afficher les icônes réelles des fichiers +Afficher le menu système +&Sélectionner toute la ligne +Afficher la &grille +Simple clic pour ouvrir un item +Utiliser la sélection &alternative +Utiliser des &grosses pages mémoire +2900 +A propos de 7-Zip +7-Zip est un logiciel libre +3000 +Le système ne peut allouer la quantité de mémoire nécessaire +Il n'y a pas d'erreurs +{0} objet(s) sélectionné(s) +Le dossier '{0}' ne peut pas être créé +Les opérations de mise à jour ne sont pas disponibles pour cette archive. +Le fichier '{0}' ne peut être ouvert comme une archive +L'archive cryptée '{0}' ne peut être ouverte. Mauvais mot de passe ? +Ce type d'archive n'est pas supporté +Le fichier {0} existe déjà +Le fichier '{0}' a été modifié.\nVoulez-vous le mettre à jour dans l'archive ? +Impossible de mettre à jour\n'{0}' +Impossible de démarrer l'éditeur. +Le fichier est peut-être un virus (le nom contient des grands espacements pour masquer l'extension). +Cette opération ne peut être effectuée depuis un dossier ayant un trop long chemin d'accès. +Vous devez sélectionner un fichier +Vous devez sélectionner un ou plusieurs fichiers +Trop d'objets +Ne peut ouvrir les fichiers {0} comme une archive +Le fichier {0} est ouvert comme une archive +L'archive est ouverte avec un décalage +3300 +Extraction +Compression +Contrôle +Ouverture... +Exploration... +Enlever +3320 +Ajoute +Modifie +Analyse +Réplique +Remballage +Passe +Efface +Création d'un en-tête +3400 +Extraire +E&xtraire vers : +Choisissez un dossier pour l'extraction des fichiers. +3410 +Mode de chemin : +Nom de chemin complet +Pas de nom de chemin +Nom de chemin absolu +Nom de chemin relatif +3420 +Mode de remplacement : +Confirmer avant de remplacer +Remplacer sans demander +Ignorer les fichiers existants +Renommer automatiquement +Renommer les fichiers existants +3430 +Élimine la duplication du répertoire racine +Restauration du fichier de sécurité +3500 +Confirmer le remplacement de fichier +Le dossier de destination contient déjà un fichier avec ce nom. +Voulez-vous remplacer le fichier existant +par celui-ci ? +{0} octets +Renommer &automatiquement +3700 +Méthode de compression non valide pour '{0}'. +Donnée erronée dans le fichier '{0}'. Le fichier est corrompu. +Échec du contrôle CRC dans le fichier '{0}'. Le fichier est corrompu. +Donnée erronée dans le fichier crypté '{0}'. Mauvais mot de passe ? +Échec du contrôle CRC dans le fichier crypté '{0}'. Mauvais mot de passe ? +3710 +Pas le bon mot de passe ? +3721 +Méthode de compression non supportée +Erreur de donnée +Échec de CRC +Donnée non disponible +Fin de données inattendues +Il y a des données après la fin des données utiles +N'est pas une archive +Erreur en-têtes +Mauvais mot de passe +3763 +Démarrage non disponible d'une archive +Démarrage non confirmé d'une archive + + + +Option non supportée +3800 +Entrez le mot de passe +Entrez le mot de passe : +Entrez le mot de passe à nouveau : +&Afficher le mot de passe +Les mots de passe ne correspondent pas +Pour le mot de passe, n'utilisez que des lettres non accentuées, des chiffres et des caractères spéciaux (!, #, $, ...) +Le mot de passe est trop long +Mot de passe +3900 +Temps écoulé : +Temps restant : +Taille totale : +Vitesse : +Traité : +Taux de compression : +Erreurs : +Archive : +4000 +Ajouter à l'archive +&Archive : +&Mode de mise à jour : +&Format de l'archive : +N&iveau de compression : +Méthode de &compression : +&Taille du dictionnaire : +Tai&lle des mots : +Taille de bloc solide : +Nombre de threads CPU : +&Paramètres : +Options +Créer une archive SF&X +Compresser des fichiers partagés +Chiffrement +Méthode de chiffrement : +Chiffre les &noms de fichiers +Mémoire pour la compression : +Mémoire pour la décompression : +Effacer les fichiers après compression +4040 +Emmagasine liens symboliques +Emmagasine liens solides +Emmagasine flux de données alternatifs +Emmagasine fichier de sécurité +4050 +Aucune +Le plus rapide +Rapide +Normale +Maximum +Ultra +4060 +Ajouter et remplacer les fichiers +Mettre à jour et ajouter les fichiers +Rafraîchir les fichiers existants +Synchroniser les fichiers +4070 +Choisir +Tous les fichiers +Non-solide +Solide +6000 +Copier +Déplacer +Copier dans : +Déplacer vers : +Copie... +Déplacement... +Renommage... +Sélectionnez le dossier de destination. +L'opération n'est pas possible pour ce dossier. +Erreur durant le Renommage du Fichier ou du Dossier +Confirmation de la Copie de(s) Fichier(s) +Confirmer la copie de(s) fichier(s) à archiver +6100 +Confirmer la Suppression du Fichier +Confirmer la Suppression du Dossier +Confirmer la Suppression de Multiple Fichiers +Êtes-vous sûr de vouloir supprimer '{0}' ? +Êtes-vous sûr de vouloir supprimer le dossier '{0}' et tout ce qu'il contient ? +Êtes-vous sûr de vouloir supprimer ces {0} objets ? +Suppression... +Erreur durant la suppression du fichier ou du dossier +Le système ne peut mettre à la Corbeille un fichier avec un trop long chemin d'accès +6300 +Créer un Dossier +Créer un Fichier +Nom du dossier : +Nom du fichier : +Nouveau dossier +Nouveau fichier +Erreur durant la création du dossier +Erreur durant la création du fichier +6400 +Commentaire +&Commentaire : +Sélectionner +Désélectionner +Masquer : +6600 +Propriétés +Historique des dossiers +Messages de diagnostic +Message +7100 +Ordinateur +Réseau +Documents +Système +7200 +Ajouter +Extraire +Tester +Copier +Déplacer +Supprimer +Informations +7300 +Diviser le fichier +&Diviser en : +Diviser en &volumes, octets : +Découper... +Confirmez le découpage +Êtes-vous sûr de vouloir découper le fichier en {0} volumes ? +La taille de volume doit être inférieure à la taille du fichier d'origine +Taille de volume incorrecte +Taille de volume spécifiée : {0} octets.\nÊtes-vous sûr de vouloir découper l'archive dans de tels volumes ? +7400 +Combiner les fichiers +&Combiner en : +Combinaison... +Ne sélectionnez que le premier fichier +Ne trouve aucun fichier faisant partie d'une archive divisée +Ne trouve qu'un seul fichier faisant partie d'une archive divisée +7500 +Calcul de la somme de contrôle... +Informations sur la somme de contrôle +Somme de contrôle des données : +Somme de contrôle des données et des noms : +7600 +Test de performance +Utilisation de la mémoire : +Compression +Décompression +Taux +Taux total +Actuel +Résultant +Utilisation CPU +Estimé / Usage +Passe : +7700 +Lien +Lien +Lien depuis : +Lien ver : +7710 +Sorte de lien +Lien solide +Lien symbolique de fichier +Lien symbolique de répertoire +Jonction de répertoire diff --git a/Utils/7-Zip/Lang/fur.txt b/Utils/7-Zip/Lang/fur.txt new file mode 100644 index 000000000..ef4ae0dbe --- /dev/null +++ b/Utils/7-Zip/Lang/fur.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.60 : Andrea Decorte (Klenje) : http://softfurlan.altervista.org : secont l'ortografie uficiâl de Provincie di Udin +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Friulian +Furlan +401 +Va ben +Scancele + + + +&Sì +&No +&Siare +&Jutori + +&Continue +440 +Sì &a ducj +No a &ducj +Ferme +Torne a inviâ +&Sfont +P&rin plan +&Pause +In pause +Sêstu sigûr di volê scancelâ? +500 +&File +&Modifiche +&Viodude +&Preferîts +&Imprescj +&Jutori +540 +&Viarç +Viarç dentri 7-&Zip +V&iarç fûr di 7-Zip +&Mostre +M&odifiche +Gambie &non +&Copie in... +Mô&f in... +&Elimine +&Divît file... +Torne a &unî files... +P&ropietâts +Comen&t +Calcole so&me di control + +Cree cartele +Cree file +V&a fûr +600 +Selezione d&ut +&Deselezione dut +&Invertìs selezion +Selezione... +Deselezione... +Selezione par gjenar +Deselezione par gjenar +700 +Iconis &grandis +Iconis &piçulis +&Liste +&Detais +730 +Cence ordin +Viodude plane +&2 panei +Sbaris dai impresc&j +Viarç cartele principâl +Parsore di un nivel +Storic des cartelis... +&Atualize +750 +Sbare dai imprescj par l'archivi +Sbare dai imprescj standard +Botons larcs +Mostre test dai botons +800 +&Zonte cartele ai Preferîts sicu +Preferît +900 +&Opzions... +&Banc di prove +960 +&Argoments... +&Informazions su 7-Zip... +1003 +Percors +Non +Estension +Cartele +Dimension +Dimension comprimude +Atribûts +Creât +Ultin acès +Modificât +Solit +Comentât +Cifrât +Divît prin di +Divît daspò di +Dizionari +CRC +Gjenar +Anti +Metodi +SO di origjin +Sisteme dai files +Utent +Grup +Bloc +Coment +Posizion +Prefìs dal troi +Cartelis +Files +Version +Volum +Multivolum +Offset +Leams +Blocs +Volums + +64-bit +Big-endian +CPU +Dimension fisiche +Dimension intestazions +Some di control +Caracteristichis +Direzion virtuâl + + + + + + +Erôr +Dimension totâl +Puest libar +Dimension setôr +Etichete +Non locâl +Furnidôr +2100 +Opzions +Lenghe +Lenghe: +Editôr +&Editôr: + +2200 +Sisteme +Associe 7-Zip cun: +2301 +Integre 7-Zip intal menù contestuâl de shell +Menù contestuâl in discjadude +Elements dal menù contestuâl: +2320 + + +Viarç archivi +Tire fûr files... +Zonte a un archivi... +Prove archivi +Tire fûr ca +Tire fûr in {0} +Zonte a {0} +Comprim e mande par email... +Comprim in {0} e mande par email +2400 +Cartelis +Cartele di &vore +Cartele &provisorie dal sisteme +&Corinte +&Specificade: +Dopre dome pai drives che si puedin gjavâ +Specifiche une posizion pai files provisoris di un archivi. +2500 +Configurazion +Mostre l'element ".." +Mostre lis veris iconis dai files +Mostre il menù dal sisteme +&Selezione la rie intire +Mostre les liniis de &gridele sot + +Mût di selezion &alternatîf +Dopre pagjinis di memorie &largjis +2900 +Informazions su 7-Zip +7-Zip al è un program libar. Purpûr, tu puedis supuartâ il disvilup di 7-Zip cu la regjistrazion. I utents regjistrâts a podaran otignî supuart tecnic. +3000 +Il sisteme nol rive a cjoli la cuantitât di memorie che e covente +Nissun erôr cjatât +{0} ogjet(s) selezionât(s) +No si pues creâ la cartele '{0}' +Lis operazions di atualizazion no son supuartadis par chest archivi. +No si pues viarzi il file '{0}' come archivi +No si pues viarzi l'archivi cifrât '{0}'. Ise sbaliade la peraule clâf? +Gjenar di archivi no supuartât +Il file {0} al esist za +Il file '{0}' al è stât modificât.\nVuelistu atualizâlu intal archivi? +No si pues atualizâ il file\n'{0}' +No si pues inviâ l'editôr. +Il file al samee un virus (il non al à dentri un grum di spazis). +Cheste operazion no pues jessi clamade di une cartele cuntun troi lunc. +Tu scugnis sielzi un file +Tu scugnis sielzi un o plui files +Masse elements +3300 +Daûr a tirâ fûr... +Daûr a comprimi +Daûr a provâ +Daûr a viarzi... +Daûr a scandaiâ... +3400 +Tire fûr +Tir&e fûr in: +Specifiche une posizion pai files tirâts fûr. +3410 +Struture des cartelis +Percors intîrs +Nissun percors +3420 +Sore scriture +Domande prin di scrivi parsore +Scrîf parsore cence domandâ +Salte i files che esistin +Gambie nons in automatic +Gambie nons in automatic se a esistin +3500 +Conferme de sostituzion dal file +Inte cartele di destinazion al è za il file processât. +Vuelistu sostituî il file esistint +cun chest file? +{0} bytes +&Gambie non in automatic +3700 +Il metodi di compression nol è supuartât par '{0}'. +Erôr di dâts in '{0}'. Il file al è corot. +CRC falît in '{0}'. Il file al è corot. +Erôr di dâts tal file cifrât '{0}'. Peraule clâf sbaliade? +CRC falît tal file cifrât '{0}'. Peraule clâf sbaliade? +3800 +Scrîf peraule clâf +Scrîf la peraule clâf: +Torne a inserî la peraule clâf: +&Mostre la peraule clâf +Lis peraulis clâfs no son compagnis +Dopre dome lis letaris inglesis (no acentadis), i numars e i caratars speciâi (!, #, $, ...) inte peraule clâf +La peraule clâf e je masse lungje +Peraule clâf +3900 +Timp passât: +Timp restant: +Dimension: +Sveltece: +Elaborât: +Tas di compression: +Erôrs: +Archivis: +4000 +Zonte a un archivi +&Archivi: +Mût di at&ualizazion: +&Formât archivi: +Nive&l di compression: +&Metodi di compression: +&Dimension dizionari: +Dimension &peraule: +Dimension bloc solit: +Numar di threads de CPU: +&Parametris: +Opzions +Cree archivi SF&X +Comprim i files condividûts +Ciframent +Metodi di ciframent: +Cifre i &nons dai files +Utilizazion memorie comprimint: +Utilizazion memorie decomprimint: +4050 +Cence compression +Il pi svelt +Svelt +Normâl +Massim +Super +4060 +Zonte e sostituìs files +Atualize e zonte files +Atualize i files che esistin +Sincronize i files +4070 +Sgarfe +Ducj i files +No-solit +Solit +6000 +Copie +Môf +Copie in: +Môf in: +Daûr a copiâ... +Daûr a movi... +Daûr a gambiâ non... +Sielç la cartele di destinazion. +L'operazion no je supuartade. +Erôr gambiant non a un file o une cartele +Conferme de copie dai files +Sêstu sigûr di volê copiâ i files tal archivi +6100 +Conferme de eliminazion dal file +Conferme de eliminazion de cartele +Conferme de eliminazion di plui files +Sêstu sigûr di volê eliminâ '{0}'? +Sêstu sigûr di volê eliminâ la cartele '{0}' e dut ce ch'al è lì dentri? +Sêstu sigûr di volê eliminâ chescj {0} elements? +Daûr a eliminâ... +Erôr eliminant un file o une cartele +Il sisteme nol pues movi un file cuntun troi lunc te Scovacere +6300 +Cree cartele +Cree file +Non de cartele: +Non dal file: +Gnove cartele +Gnûf file +Erôr inte creazion de cartele +Erôr inte creazion dal file +6400 +Coment +&Coment: +Selezione +Deselezione +Filtri: +6600 +Propietâts +Storic des cartelis +Messaçs diagnostics +Messaç +7100 +Ordenadôr +Rêt +Documents +Sisteme +7200 +Zonte +Tire fûr +Prove +Copie +Môf +Elimine +Info +7300 +Divît file +&Divît in: +Divît in &volums, grandece in bytes: +Daûr a dividi... +Conferme de division +Sêstu sigûr di volê dividi il file in {0} tocs? +La dimension di un volum e à di jessi plui piçule di chê dal file origjinâl +Dimension dai volums sbaliade +Dimension dai volums volude: {0} bytes.\nSêstu sigûr di volê dividi l'archivi in tocs di cheste dimension? +7400 +Torne a unî files +&Torne a unî in: +Daûr a tornâ a unî... +Sielç dome il prin file +No si pues rilevâ il file come toc di un file dividût +No son stâts cjatâts plui tocs di file dividûts +7500 +Daûr a calcolâ la some di control... +Informazions su la some di control +Some di control CRC pai dâts: +Some di control CRC pai dâts e i nons: +7600 +Banc di prove +Utilizazion memorie: +Comprimint +Decomprimint +Valutazion +Valutazion totâl +Corint +Risultant +Utilizazion CPU +Judizi / Utilizazion +Passaçs: diff --git a/Utils/7-Zip/Lang/fy.txt b/Utils/7-Zip/Lang/fy.txt new file mode 100644 index 000000000..aed26dfb4 --- /dev/null +++ b/Utils/7-Zip/Lang/fy.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.53 : Berend Ytsma +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Frisian +Frysk +401 +Okee +Ofbrekke + + + +&Jawis +&Nee +&Slute +Help + +&Ferfetsje +440 +Jawis foar &Alles +Nee foar A&lles +Stopje +Opnij begjinne +&Eftergrûn +&Foargrûn +&Skoftsje +Skoft +Binne jo wis dat jo ôfbrekke wolle? +500 +&Triem +&Bewurkje +&Byld +B&lêdwizers +&Ark +&Help +540 +&Iepenje +Iepenje &yn +Iepenje bû&ten +&Byld +&Bewurkje +Omne&ame +&Kopiearje nei... +&Ferpleats nei... +&Wiskje +Triemmen &spjalte... +Triemmen Kom&binearje... +E&igenskippen +Komme&ntaar +Kontrôlesom berekenje + +Map meitsje +Triem meitsje +U&tgong +600 +&Alles selektearje +Alles net selektearje +&Seleksje omdraaien +Selektearje... +Net selektearje... +Selektearje neffens type +Net selektearje neffens type +700 +Gru&tte Ikoanen +L&ytse Ikoanen +&List +&Details +730 +Net Sortearre +Platte werjefte +&2 Panielen +&Arkbalke +Haadmap iepenje +Ien nivo omheech +Maphistoarje... +&Ferfarskje +750 +Argyf arkbalke +Standert arkbalke +Grutte knoppen +Knoptekst sjen litte +800 +Map oan blêdwizers &taheakje as +Blêdwizer meitsje +900 +&Opsjes... +&Ykpunt +960 +&Ynhâld... +&7-Zip it hoe en het... +1003 +Paad +Namme +Taheaksel +Map +Grutte +Ynpakte grutte +Skaaimerk +Makke +Lêste tagong +Feroare +Kompakt +Kommentaar +Fersifere +Spjalt foar +Spjalt efter +Wurdboek +CRC +Type +Anty +Metoade +Host OS +Triemsysteem +Brûker +Keppel +Blok +Kommentaar +Posysje +Paad foarheaksel +Mappen +Triemmen +Ferzje +Folume +Multifolume +Offset +Links +Blokken +Folumes + + + + + + + + + + + + + + + +Flater +Totale grutte +Frije romte +Kluster grutte +Kaartsje +Lokale namme +Ferskaffer +2100 +Opsjes +Taal +Taal: +Bewurker +&Bewurker: + +2200 +Systeem +Ferbyn 7-Zip Mei: +2301 +Yntegraasje fan 7-Zip yn ferbânmenu +Ferbânmenu yn trepfoarm +Ferbânmenu-items: +2320 + + +Argyf iepenje +Triemmen útpakke... +Oan argyf taheakje... +Argyf teste +Hjir útpakke +Utpakke yn {0} +Oan {0} taheakje +komprimearje en ferstjoere... +Komprimearje nei {0} en poste +2400 +Mappen +&Wurkmap +&Tydlikesysteemmap +&Aktive +&Oantsjutte: +Allinnich brûke foar útnimbere skiven +ynfiere fan de lokaasje foar tydlike argyftriemmen. +2500 +Ynstellings +".." item sjen litte +Echte triem ikoanen sjen litte +Systeemmenu sjen litte +&Folsleine rige selektearje +&Roaster sjen litte + +&Alternative seleksje modus +Brûk &grut ûnthâld siden +2900 +7-Zip it hoe en het +7-Zip is fergees. Mar, jo kinne de ûntwikkeling stypje troch jo te registrearjen. +3000 + +Der binne gjin flaters +{0} objekt(en) selektearre +Kin map '{0}' net meitsje +Bywurk operaasje waard net stipe troch dit argyf. +Kin triem '{0} net as argyf iepenje +Kin fersifere argyf '{0}' net iepenje. Ferkeard wachtwurd? + + +Triem '{0}' is wizige.\nWolle jo it bywurkje yn it argyf? +Kin triem '{0}'\nnet bywurkje +Kin bewurker net starte. + + + + +Tefolle items +3300 +Utpakke +Oan it komprimearjen +Oan it Testen +Oan it iepenjen... +Oan it skennen... +3400 +Utpakke +U&tpakke nei: +De lokaasje om nei út te pakken oantsjutte. +3410 +Paad modus +Folsleine paadnammen +Gjin paadnammen +3420 +Oerskriuw modus +Freegje foardat jo oerskriuwe +Oerskriuwe sûnder pront +Besteande triemmen oerslaan +Automatysk omneame +Automatysk ek by besteande triemmen +3500 +It ferfangen fan de triem befêstigje +Bestimmingsmap befettet al in triem mei dizze namme. +Wolle jo de triem ferfange +Mei dizze? +{0} bytes +A&utomatysk omneame +3700 +Net stipe kompresjemetoade foar '{0}'. +Data flater yn '{0}'. Triem is beskeadige. +CRC mislearre yn '{0}'. Triem is beskeadige. +Data flater yn fersifere triem '{0}'. Ferkeard wachtwurd? +CRC mislearre yn fersifere triem '{0}'. Ferkeard wachtwurd? +3800 +Wachtwurd ynfiere +Wachtwurd ynfiere: +Wachwurd opnij ynfiere: +Wachtwurd &sjen litte +Wachtwurden komme net oerien +Brûk allinne ingelske letters, nûmers en spesjale karakters (!, #, $, ...) foar it wachtwurd +Wachtwurd is te lang +Wachtwurd +3900 +Ferstrutsen tiid: +Tiid noch te gean: +Totale grutte: +Fluggens: +Ferwurke: +Kompresje nivo: +Flaters: +Argiven: +4000 +Oan argyf taheakje +&Argyf: +&Bywurkmodus: +Argyf &formaat: +Kompresje&nivo: +Kompresje&metoade: +&Wurdboekgrutte: +&Wurdgrutte: +Kompakte blokgrutte: +Tal CPU trieden: +&Parameters: +Opsjes +Meitsje SF&X-argyf +Dielde triemmen komprimearje +Fersifering +Fersiferingmetoade: +Fersiferje triem&nammen +Unthâld gebrûk by komprimearjen: +Unthâld gebrûk by ûntkomprimearjen: +4050 +Bewarje +Fluchst +Fluch +Normaal +Maksimum +Ultra +4060 +Triemmen taheakje en ferfange +Triemmen taheakje en bywurkje +Besteande triemmen ferfarskje +Triemmen lyk rinne litte +4070 +Blêdzje +Alle triemmen +net-kompakt +Kompakt +6000 +Kopiearje +Ferpleatse +Kopiearje nei: +Ferpleats nei: +Oan it kopiearren... +Oan it ferpleatsen... +Omneame... +Bestimmingsmap selektearje. +Operaasje wurdt net stipe. +Flater by it omneamen fan triem of map +Triem kopiearje befêstigje +Binne jo wis dat jo de triemmen nei it argyf kopiearje wolle? +6100 +It wiskjen fan de triem befêstigje +It wiskjen fan de map befêstigje +It wiskjen fan meardere triemmen befêstigje +Binne jo wis dat jo '{0}' wiskje wolle? +Binne jo wis dat jo de map '{0}' en al syn ynhâld wiskje wolle? +Binne jo wis dat jo {0} items wiskje wolle? +Oan it wiskjen +Flater by it wiskjen fan triem of map + +6300 +Map meitsje +Triem meitsje +Mapnamme: +Triem namme: +Nije map +Nije triem +Flater by it meitsjen fan map +Flater by’t meitsjen fan triem +6400 +Kommentaar +&Kommentaar: +Selektearje +Net Selektearje +Masker: +6600 +Eigenskippen +Maphistoarje +Diagnostyk berjocht +Berjocht +7100 +Kompjûter +Netwurk + +Systeem +7200 +Taheakje +Utpakke +Test +Kopiearje +Ferpleatse +Wiskje +Ynformaasje +7300 +Triem spjalte +&Spjalt nei: +Spjalte nei &folumes, bytes: +Oan it Spjalten... +Spjalte befêstigje +Wolle jo de triem spjalte yn {0} dielen? +Folumegrutte moat lytser wêze dan de grutte fan it orizjineel +Net juste folumegrutte +Oantsjutte folumegrutte: {0} bytes.\nWolle jo it argyf yn sokke folumes spjalte? +7400 +Triemmen kombinearje +&Kombinearje nei: +Oan it kombinearjen... +Allinne earste triem selektearje + + +7500 +Kontrôlesom oan it berekenjen... +Kontrôlesom ynformaasje +CRC kontrôlesom foar data: +CRC kontrôlesom foar data en nammen: +7600 +Benchmark +Unthâld gebrûk: +Oan it komprimearren +Oan it ûntkomprimearren +Wurdearring +Totale Wurdearring +Hjoeddeiske +Resultaat +CPU brûkens +Beoardieling / Brûkens +Kear foarbei: diff --git a/Utils/7-Zip/Lang/ga.txt b/Utils/7-Zip/Lang/ga.txt new file mode 100644 index 000000000..0c5a8a966 --- /dev/null +++ b/Utils/7-Zip/Lang/ga.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Seanán Ó Coistín +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Irish +Gaeilge +401 +Tá go maith +Cealaigh + + + +&Tá +&Níl +&Dún +Cabhair + +&Lean ar aghaidh +440 +Tá do gach ceann +Níl go gach ceann +Stad +Atosaigh +&Cúlra +&Tulra +&Cuir ar sos +Ar sos +An bhfuil tú cinnte gur mian leat é a chealú? +500 +&Comhad +&Leagan +Am&harc +Ceanáin +&Uirlisí +&Cabhair +540 +&Oscail +Oscail &istigh +Oscail &lasamuigh +&Amharc +&Eagar +Athainmnigh +&Macasamhlaigh go... +&Bog go... +S&crios +Scar an comhad... +Cumascaigh na comhaid... +Airíonna +Nóta tráchta +Ríomh an tsuim sheiceála +Diff +Cruthaigh fillteán +Cruthaigh comhad +&Scoir +600 +Roghnaigh &uile +Díroghnaigh uile +&Aisiompaigh an roghnúchán +Roghnaigh... +Díroghnaigh... +Roghnaigh de réir cineál +Díroghnaigh de réir cineál +700 +&Deilbhíní móra +&Deilbhíní beaga +&Liosta +&Sonraí +730 +Neamhaicmithe +Gach rud in aon chiseal +&2 fhuinneog +&Barraí na n-uirlisí +Oscail an fréamhfhillteán +Suas fillteán amháin +Oireas na bhfillteán... +Athnuaigh +750 +Barra cartlanna +Barra na n-uirlisí caighdeánacha +Cnaipí móra +Taispeáin an téacs ar na cnaipí +800 +&Cuir an fillteán leis na Ceanáin +Leabharmharc +900 +&Roghanna... +Tástáil fheidhmíochta +960 +&Inneachair... +Maidir le 7-Zip... +1003 +Conair +Ainm +Breiseán +Fillteán +Méid +Comhbhrúite +Tréithe +Cruthaithe an +Rochtain faighte ar an +Mionathraithe ar an +Fothúil +Trácht +Criptithe +Roinn roimh +Roinn i ndiaidh +Foclóir +CRC +Cineál +Frith +Modh +Óstach an CO +Córas na gcomhad +Úsáideoir +Aicme +Ceap +Nóta tráchta +Suíomh +Réimír na conaire +Fillteáin +Comhaid +Leagan +Imleabhar +Il-imleabhair +Fritháirigh +Naisc +Ceapa +Imleabhair + +64 bheart +Foirceann mór +LAP +Méid aiceanta +Méid na gceanntásc +Suim seiceála +Tréithe +Seoladh fíorúil +ID +Ainm gearr +Feidhmchlár a chruthaigh í +Méid na hearnála +Modh +Nasc +Botún +Méid iomlán +Slí atá saor +Méid na braisle +Lipéad +Ainm logánta +Soláthraí +2100 +Roghanna +Teanga +Teanga: +Eagarthóir +&Eagarthóir: +&Diff: +2200 +Córas +Comhthiomsaigh 7-Zip le: +2301 +Comhtháthaigh 7-Zip sa roghchlár comhthéacs +Roghchlár comhthéacs ag titim +Nithe an roghchláir chomhthéacs: +2320 + + +Oscail +Asbhain na comhaid... +Cuir leis an gcartlann... +Tástáil an chartlann +Asbhain anseo +Bain go {0} +Cuir le {0} +Comhbhrúigh agus seol i ríomphost iad... +Comhbhrúigh go {0} agus seol i ríomhphost iad +2400 +Fillteáin +Fillteán oibre +Fillteán sealadach an chórai&s +An comhad reatha +Fillteán &sonraithe: +Bain feidhm as do thiomántáin inaistrithe amháin +Sonraigh suíomh i gcomhair comhaid chartlainne sealadacha. +2500 +Socruithe +Taispeáin an ní ".." +Taispeáin fíordheilbhíní an chomhaid +Taispeáin roghchlár an chórais +Roghnaigh an tsraith ar fad +Taispeáin línte na greille +Brúigh uair amháin chun ní a oscailt +Bain feidhm as modh roghnaithe malartach +Bain feidhm as leathanaigh chuimhne mhóra +2900 +Maidir le 7-Zip +Is saorearra é 7-Zip. Is féidir tacaíocht a thabhairt dá fhorbairt amach anseo, áfach, trí chlárú. +3000 +Ní féidir leis an gcóras an méid cuimhne atá de dhíth a leathdháileadh dó +Níl aon bhotún ann +{0} ní/nithe roghnaithe +Ní féidir an fillteán '{0}' a chruthú +Ní féidir an chartlann seo a nuashonrú. +Ní féidir an comhad '{0}' a oscailt mar chartlann +Ní féidir an chartlann chriptithe '{0}' a oscailt. An bhfuil an focal faire mícheart? +Ní thugtar tacaíocht don chineál comhad seo +Tá an comhad {0} ann cheana +Mionathraíodh an comhad '{0}'.\nAr mhaith leat é a nuashonrú sa chartlann? +Ní féidir an comhad a leanas a nuashonrú\n'{0}' +Ní féidir an t-eagarthóir a thosú. +B'fhéidir gur aicíd é an comhad (tá bearnaí móra in ainm an chomhaid). +Ní féidir an oibríocht seo a chur i bhfeidhm ó fhillteán a bhfuil conair fhada aige. +Caithfear comhad amháin a roghnú +Caithfear comhad amháin nó níos mó a roghnú +An iomarca nithe +3300 +Asbhaint +Ag comhbhrú +Ag tástáil +Ag oscailt... +Ag taiscéal... +3400 +Bain +Bain go: +Roghnaigh fillteán do na comhaid asbhainte. +3410 +Conairí +Conairí iomlána +Níl conair ann +3420 +Modh forscríofa +Deimhnigh sular forscríobhtar +Forscríobh gan iarraidh +Déan neamhaird de na comhaid atá ann cheana +Athainmnigh go huathoibríoch +Athainmnigh na comhaid atá ann cheana +3500 +Deimhnigh ionadú comhaid +Tá comhad leis an ainm seo sa spriocfhillteán cheana féin. +Ar mhaith leat an comhad atá ann cheana a ionadú +leis an gceann seo? +{0} bearta +Athainmnigh go huathoibríoch +3700 +Níl an bealach comhbhrúite bailí i gcomhair '{0}'. +Botún sna sonraí sa chomhad '{0}'. Tá an comhad briste. +Theip ar CRC sa chomhad '{0}'. Tá an comhad briste. +Sonra mícheart sa chomhad criptithe '{0}'. Focal faire mícheart? +Theip ar CRC sa chomhad chriptithe '{0}'. Focal faire mícheart? +3800 +Cuir isteach an focal faire +Cuir an focal faire isteach: +Cuir an focal faire isteach arís: +&Taispeáin an focal faire +Ní hionann an dá fhocal faire +Bain feidhm as litreacha gan síntí fada, uimhreacha agus carachtair shainiúla (!, #, $, ...) +Tá an focal faire rófhada +Focal faire +3900 +Am caite: +Am fágtha: +Méid iomlán: +Luas: +Déanta: +Luas an chomhbhrúite: +Botúin: +Cartlanna: +4000 +Cuir leis an gcartlann +&Cartlann: +&Modh nuashonraithe: +&Formáid na cartlainne: +Méid comhbhrúite: +Modh comhbhrúite: +&Méid an fhoclóra: +Méid na bhfocal: +Méid an chip fhothúla: +Líon na snáitheanna LAP: +&Teorainneacha: +Roghanna +Cruthaigh cartlann SF&X +Comhbhrúigh na comhaid a roinneadh +Criptiú +Modh criptiúcháin: +Criptigh ainmneacha na gcomhad +Cuimhne don chomhbhrúigh: +Cuimhne don dhíchomhbhrúigh: +4050 +Taisc +Is gasta +Gasta +Gnáth +Uasmhéid +Fíorghasta +4060 +Cuir comhaid leis agus ionadaigh +Nuashonraigh na comhaid agus cuir leo +Athnuaigh comhaid atá ann cheana +Comhionannaigh na comhaid +4070 +Siortaigh +Gach comhad +Neamhfhothúil +Fothúil +6000 +Macasamhlaigh +Bog +Macasamhlaigh chuig: +Bog chuig: +Ag acasamhlú... +Ag bogadh... +Ag athainmniú... +Roghnaigh an spriocfhillteán. +Ní féidir sin a dhéanamh. +Tharla botún ag athainmniú an comhad nó an fillteán +Deimhnigh macasamhlú an chomhaid +An bhfuil tú cinnte gur mian leat na comhaid a mhacasamhlú go dtí an chartlann? +6100 +Deimhnigh scriosadh an chomhaid +Deimhnigh scriosadh an chomhaid +Deimhnigh scriosadh iliomad comhad +An bhfuil tú cinnte gur mian leat '{0}' a scriosadh? +An bhfuil tú cinnte gur mian leat an fillteán '{0}' agus gach rud ann a scriosadh? +An bhfuil tú cinnte gur mian leat na {0} nithe seo a scriosadh? +Ag scriosadh... +Tharla botún ag scriosadh an comhad nó an fillteán +Ní thig leis an gcóras comhad le conair fhada a bhogadh go dtí an bosca athchúrsála +6300 +Cruthaigh comhad +Cruthaigh comhad +Ainm an chomhaid: +Ainm an chomhaid: +Comhad nua +Comhad nua +Tharla botún fad is a bhí an comhad á chruthú +Tharla botún fad is a bhí an comhad á chruthú +6400 +Trácht +&Trácht: +Roghnaigh +Díroghnaigh +Folaigh: +6600 +Airíonna +Oireas na bhfillteán +Teachtaireachtaí diagnóiseach +Teachtaireacht +7100 +Ríomhaire +Líonra +Cáipéisí +Córas +7200 +Cuir leis +Asbhain +Tástáil +Macasamhlaigh +Bog +Scrios +Faisnéis +7300 +Roinn an comhad +&Roinn chuig: +Roinn in imleabhair, bearta: +Ag roinnt... +Deimhnigh an roinnt +An bhfuil tú cinnte go dteastaíonn uait an comhad a roinnt i {0} imleabhair? +Ní mór do mhéid an imleabhair a bheith níos lú ná méid an chomhaid bhunaidh +Tá méid an cholúin mícheart +Méid an cholúin sonraithe: {0} bearta.\nAn bhfuil tú cinnte gur mian leat an chartlann a roinnt in imleabhair? +7400 +Cumaisc comhaid +&Cumaisc go: +Ag cumasc... +Ná roghnaigh an chéad chomhad +Ní féidir an comhad a bhraith mar chuid de chomhad scoilte +Ní féidir níos mó ná aon chuid amháin den chomhad scoilte a aimsiú +7500 +Ag ríomh na suime seiceála... +Faisnéis maidir leis an suim sheiceála +Suim sheiceála do shonraí: +Suim sheiceála do shonraí agus d'ainmneacha +7600 +Tástáil fheidhmíochta +Gnáthaíocht na cuimhne: +Ag comhbhrú +Ag díchomhbhrú +Measúnú +Measúnú iomlán +Reatha +Toradh +Gnáthaíocht an LAP +Measúnú / Gnáthaíocht +Bealaí: diff --git a/Utils/7-Zip/Lang/gl.txt b/Utils/7-Zip/Lang/gl.txt new file mode 100644 index 000000000..46c4ff908 --- /dev/null +++ b/Utils/7-Zip/Lang/gl.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.00 : 2016-02-01 : enfeitizador +; +; 9.20 : 2014-11-26 : enfeitizador +; +; 3.12 : 2007-11-22 : Xosé Calvo +; +; +; +; +; +; +0 +7-Zip +Galician +Galego +401 +De acordo +Cancelar + + + +&Si +&Non +Pe&char +Axuda + +&Continuar +440 +Si &a todo +Non a &todo +Parar +Reiniciar +Poñer por de&baixo +Traer ao &fronte +&Pausa +Pausado +Ten a certeza de querer cancelar? +500 +&Ficheiro +&Editar +&Ver +F&avoritos +Ferramen&tas +A&xuda +540 +&Abrir +Abrir &dentro +Abrir &fora +&Ver +&Editar +Rena&me +&Copiar a... +&Mover a... +&Eliminar +&Dividir ficheiro... +Com&binar ficheiros... +P&ropiedades +Come&ntario... +Calcular suma de verificación +Diferenzas +Crear cartafol +Crear ficheiro +Sa&ír +Ligazón +&Alternar fluxos +600 +Seleccion&ar todo +Desmarcar todo +&Inverter selección +Seleccionar... +Desmarcar... +Seleccionar por tipo +Desmarcar por tipo +700 +Iconas lon&gas +Iconas &miúdas +&Lista +&Detalles +730 +Sen orde +Vista plana +&2 paneis +Barras de ferramen&tas +Abrir cartafol raíz +Subir un nivel +Históricos de cartafoles... +&Recargar +Recargar auto. +750 +Barra de ferramentas de arquivos +Barra de ferramentas normal +Botóns grandes +Amosar texto dos botóns +800 +Eng&adir cartafol a favoritos como +Marcador +900 +&Opcións... +&Rendemento +960 +&Contidos... +&Acerca de 7-Zip... +1003 +Camiño +Nome +Extensión +Cartafol +Tamaño +Tamaño comprimido +Atributos +Creado +Último acceso +Modificado +Sólido +Comentado +Cifrado +Partir antes +Partir despois +Dicionario +CRC +Tipo +Anti +Método +SO servidor +Sistema de ficheiros +Usuario +Grupo +Bloque +Comentario +Posición +Prefixo do camiño +Cartafoles +Ficheiros +Versión +Volume +Varios volumes +Desprazamento +Ligazóns +Bloques +Volumes + +64-bit +Big-Endian +Procesador +Tamaño físico +Tamaño cabeceiras +Suma de verificación +Características +Enderezo virtual +ID +Nome curto +Aplicación orixinal +Tamaño sector +Modo +Ligazón simbólica +Erro +Tamaño total +Tamaño libre +Tamaño do clúster +Etiqueta +Nome local +Fornecedor +Seguridade NT +Fluxos alternos +Aux !BUSCA +Eliminado +Is Tree !BUSCA + + +Tipo de error +Erros +Erros +Avisos +Aviso +Fluxos +Fluxos alternos +Tamaño fluxos alternos +Tamaño virtual +Tamaño sen comprimir +Total tamaño físico +Indexar volume +SubTipo +Comentario curto +Código de páxina + + + +Tamaño de cola +Tamaño temporal inserido +Ligazón +Ligazón forte +iNode + +Só lectura +2100 +Opcións +Idioma +Idioma: +Editor +&Editor: +&Diferenza: +2200 +Sistema +Asociar 7-Zip con: +Todos os usuarios +2301 +Integrar 7-Zip no menú de contexto +Menú do contexto en cascada +Elementos do menú do contexto: +Iconas no menú de contexto +2320 + + +Abrir arquivo +Extraer ficheiros... +Engadir ao arquivo... +Comprobar arquivo +Extraer aquí +Extraer a {0} +Engadir a {0} +Comprimir e enviar por correo... +Comprimir a {0} e enviar por correo +2400 +Cartafoles +Cartafol en &uso +Cartafol temporal do &sistema +Cartafol a&ctual +E&specificar: +Usar só en unidades extraíbles +Especificar unha localización para os arquivos temporais. +2500 +Axustes +Amosar o elemento ".." +Amosar iconas reais do ficheiro +Amosar menú do sistema +Seleccionar &fila completa +Amosar liñas de &grella +Clic simple para abrir un elemento +Modo de selección &alternativo +Usar memoria &longa de páxinas +2900 +Acerca de 7-Zip +7-Zip é un programa gratuíto +3000 +O sistema non puido atribuír a memoria requirida +Non se produciron erros +{0} obxecto(s) seleccionados +Non se pode crear o cartafol '{0}' +Este tipo de arquivo non permite actualizacións. +Non se pode abrir o ficheiro '{0}' como arquivo +Non se pode abrir o ficheiro cifrado '{0}'. Contrasinal incorrecto? +Tipo de arquivo non admitido +O ficheiro {0} xa existe +Modificouse o ficheiro '{0}'.\nQuéreo actualizar no arquivo? +Non se pode actualizar o ficheiro\n'{0}' +Non se pode iniciar o editor. +O ficheiro parécese a un virus (o nome do ficheiro contén espazos longos). +A operación non pode responder dende un cartafol cun camiño longo. +Tes que seleccionar un ficheiro +Tes que seleccionar un ou máis ficheiros +Demasiados elementos +Non se pode abrir o ficheiro como arquivo {0} +O ficheiro está aberto como arquivo {0} +O arquivo está aberto con desprazamento +3300 +Extraendo +Comprimindo +Probando +Abrindo... +Escaneando... +Eliminando +3320 +Engadindo +Actualizando +Analizando +Replicando +Volvendo comprimir +Omitindo +Eliminando +Creando cabeceira +3400 +Extraer +E&xtraer a: +Especificar unha localización para os ficheiros extraídos. +3410 +Modo camiño: +Nomes de camiño completos +Sen nomes de camiño +Nomes de camiño absoluto +Nomes de camiño relativo +3420 +Modo sobrescribir: +Preguntar antes de sobrescribir +Sobrescribir sen preguntar +Omitir ficheiros existentes +Renomeo automático +Renomeo automático de ficheiros existentes +3430 +Eliminar duplicidade do cartafol raíz +Restaurar seguridade do ficheiro +3500 +Confirmar a substitución de ficheiro +O cartafol destino xa ten un ficheiro co mesmo nome. +Desexa substituír o ficheiro existente +con estoutro? +{0} bytes +Renomeo a&utomático +3700 +Método de compresión non admitido para '{0}'. +Erro de datos en '{0}'. O ficheiro está danado. +Fallou a verificación CRC en '{0}'. O ficheiro está danado. +Erro de datos no ficheiro cifrado '{0}'. Contrasinal incorrecto? +Fallou a verificación CRC no ficheiro cifrado '{0}'. Contrasinal incorrecto? +3710 +Contrasinal incorrecto? +3721 +Método de compresión non admitido +Erro de datos +Fallou a verificación CRC +Datos non dispoñibles +Remate de datos inesperado +Hai certos datos despois do remate dos datos cargados +Non é arquivo +Erro de cabeceiras +Contrasinal incorrecto +3763 +Inicio de arquivo non dispoñible +Inicio de arquivo non confirmado + + + +Característica non admitida +3800 +Insira contrasinal +Insira contrasinal: +Insírao de novo: +Amo&sar contrasinal +Os contrasinais non coinciden +Use só letras latinas, números e caracteres especiais (!, #, $, ...) para o contrasinal +O contrasinal é moi longo +Contrasinal +3900 +Tempo transcorrido: +Tempo restante: +Tamaño total: +Velocidade: +Procesado: +Proporción de compresión: +Erros: +Arquivos: +4000 +Engadir ao arquivo +&Arquivo: +Función act&ualizar: +&Formato de arquivo: +Nive&l de compresión: +&Método de compresión: +Tamaño do &dicionario: +Tamaño de &palabra: +Tamaño de bloque sólido: +Número de procesos da CPU: +&Parámetros: +Opcións +Crear ficheiro SF&X +Comprimir ficheiros compartidos +Cifrado +Método de cifrado: +Cifrar &nomes de ficheiro +Uso de memoria para compresión: +Uso de memoria para extracción: +Eliminar ficheiros despois de comprimir +4040 +Arquivar ligazóns simbólicas +Arquivar ligazóns fortes +Arquivar fluxo de datos alternos +Arquivar seguridade de ficheiro +4050 +Arquivar +Máis rápida +Rápida +Normal +Máxima +Ultra +4060 +Engadir e substituír ficheiros +Actualizar e engadir ficheiros +Só actualizar ficheiros existentes +Sincronizar ficheiros +4070 +Navegar +Todos os ficheiros +Non sólido +Sólido +6000 +Copiar +Mover +Copiar a: +Mover a: +Copiando... +Movendo... +Renomeando... +Seleccione cartafol destino. +A operación non é admitida para este cartafol. +Erro ao renomear ficheiro ou cartafol +Confirmar copia de ficheiro +Desexa copiar os ficheiros ao arquivo +6100 +Confirmar eliminar ficheiro +Confirmar eliminar cartafol +Confirmar eliminar ficheiro múltiplo +Ten a certeza de eliminar '{0}'? +Ten a certeza de eliminar o cartafol '{0}' e todo o que contén? +Ten a certeza de eliminar estes {0} elementos? +Eliminando... +Erro ao eliminar ficheiro ou cartafol +O sistema non pode mover un ficheiro cun nome tan longo á papeleira +6300 +Crear cartafol +Crear ficheiro +Nome do cartafol: +Nome do ficheiro: +Novo cartafol +Novo ficheiro +Erro ao crear cartafol +Erro ao crear ficheiro +6400 +Comentario +&Comentario: +Seleccionar +Desmarcar +Máscara: +6600 +Propiedades +Histórico de cartafoles +Mensaxes de diagnose +Mensaxe +7100 +Computador +Rede +Documentos +Sistema +7200 +Engadir +Extraer +Probar +Copiar +Mover +Eliminar +Información +7300 +Dividir ficheiro +&Dividir a: +Dividir en &volumes, bytes: +Dividindo... +Confirmar división +Ten a certeza de dividir o ficheiro en {0} volumes? +O tamaño do volume ten que ser menor que o tamaño do ficheiro orixinal +Tamaño de volume incorrecto +Tamaño de volume especificado: {0} bytes.\nTen a certeza de dividir o arquivo nestes volumes? +7400 +Combinar ficheiros +&Combinar a: +Combinando... +Seleccionar só a primeira parte do ficheiro dividido +Non se detecta o ficheiro como parte dun ficheiro dividido +Non se atopan máis ca unha parte do ficheiro dividido +7500 +Calculando suma de verificación... +Información da suma de verificación +Verificación CRC para datos: +Verificación CRC para datos e nomes: +7600 +Rendemento +Uso de memoria: +Comprimindo +Extraendo +Proporción +Proporción total +Actual +Resultante +Uso de CPU +Proporción / Uso +Pases: +7700 +Ligazón +Ligazón +Ligazón desde: +Ligazón a: +7710 +Tipo de ligazón +Ligazón forte +Ligazón simbólica de ficheiro +Directorio ligazón simbólica +Directorio nexo diff --git a/Utils/7-Zip/Lang/gu.txt b/Utils/7-Zip/Lang/gu.txt new file mode 100644 index 000000000..abcedc727 --- /dev/null +++ b/Utils/7-Zip/Lang/gu.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Vinayy Sharrma : વિનય શર્મા દ્વારા અનુવાદિત મેહનત કરેલી છે તો પોતાનું નામ લખવામાં કાંઇ બુરાઈ નથી. હિન્દ પર ગર્વ કરો, જય હિન્દ ! જય હિન્દી ! જય ગરવી ગુજરાત ! જય ગુજરાતી +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Gujarati, Indian, હિન્દુસ્તાન +ગુજરાતી +401 +સારું +રદ્દ + + + +&હાઁ +&ના +&બંદ કરો +મદદ + +&જારી રાખો +440 +&બધા માટે હાઁ +&બધા માટે ના +રૂકો +પુનઃ શુરુ કરો +&પૄષ્ઠ્ભૂમિ +&અગ્રભૂમિ(ડેસ્ક્ટોપ) +&વિશ્રામ +થોભેલું +તુમે રદ્દ કરવા ચાહો છો. શું તમને યકીન છે? +500 +&ફ઼ાઇલ +&સંપાદન +&દર્શન +&મનપસંદ +&ઔજાર +&મદદ +540 +&ખોલો +&અંદર ખોલો +&બાહર ખોલો +&દૃશ્ય +&સંપાદન +&પુન: નામકરણ +&માં નકલ બનાવો... +&માં લઇ જાઓ... +&મિટાવો +&ફ઼ાઇલનો વિભાજન કરો... +&ફ઼ાઇલનો સંયોજન કરો... +&સંપત્તિયાઁ યા ગુણ +&ટિપ્પણી +&જાઁચ યોગની ગણના કરો +&અન્તર +&ફ઼ોલ્ડર તૈયાર કરો +&ફ઼ાઇલ તૈયાર કરો +&નિર્ગમન +600 +&બધા ચયન કરો +&બધા અચયનિત કરો +&ચયન ઊંધું કરો +ચયન કરો... +અચયન કરો... +પ્રકાર દ્વારા ચયન +પ્રકાર દ્વારા અચયન +700 +મોટાં પ્રતીક +લઘુ પ્રતીક +&સૂચી +&વર્ણન +730 +અવિતરિત +ચૌડ઼ા દૃશ્ય +&૨ ફ઼લક +&ઔજાર પટ્ટીઓ +મૂલ ફ઼ોલ્ડર ખોલો +એક સ્તર ઊપર ચઢ઼ો +ફ઼ોલ્ડરો નો ઇતિહાસ... +&તાજા કરો +750 +સંગ્રહ ઔજાર પટ્ટી +માનક ઔજાર પટ્ટી +મોટા ખટકા(બટન) +ખટકા(બટન)ના શબ્દ દિખાવો +800 +&ફ઼ોલ્ડર મનપસંદમાં એવી રીતે જોડો... +પુસ્તચિન્હ +900 +&વિકલ્પ... +&બેઞ્ચમાર્ક(પ્રામાણિક તુલના) +960 +&સામગ્રી... +૭-જિપ ના વિશેમાં... +1003 +માર્ગ +નામ +વિસ્તાર +ફ઼ોલ્ડર +આકાર +કુલ આકાર +વિશેષતા યા ગુણધર્મ +સર્જિત +ચલાવેલી +પરિવર્ધિત +ઠોસ +ટિપ્પણી +ગુપ્તિકૃત +ના પૂર્વે વિભાજન(ટુકડે) કરો +ના બાદ વિભાજન(ટુકડે) કરો +શબ્દકોશ +સીઆરસી +પ્રકાર +વિરોધી +પદ્ધતિ +યજમાન આજ્ઞાવલી(ઓપરેટિંગ સિસ્ટમ) +ફ઼ાઇલ પ્રણાલી +પ્રયોગકર્તા +સમૂહ +રોક કે ટુકડાઓ +પ્રતિક્રિયા +સ્થાન +માર્ગ પ્રત્યય +ફોલ્ડરસ +ફાઇલ્સ +સંસ્કરણ +જત્થા +અનેક જત્થાઓ +ઓફસેટ +કડિયાઁ +ટુકડ઼ે +જત્થે + +૬૪-બિટ +મોટું-એન્ડિયન +સીપીયૂ +ભૌતિક આકાર +શીર્ષકોંના આકાર +જાઁચયોગ +ચરિત્રતાઓ +આભાસી પત્તો +આઈડી +સંક્ષિપ્ત નામ +સર્જક અનુપ્રયોગ +સેક્ટરનો આકાર +સ્થિતિ +કડ઼ી +ત્રુટિ +કુલ આકાર +સ્વતન્ત્ર રિક્તસ્થાન(ખાલી જગહ) +ક્લસ્ટર(સમૂહ) આકાર +ધ્યાનાકર્ષક(લેબલ) +સ્થાનિક નામ +પ્રદાયક +2100 +વિકલ્પ +ભાષા +ભાષા: +સંપાદક +&સંપાદક: +&અન્તર: +2200 +પ્રણાલી કે તંત્ર +સંબધિત કરો ૭-જિપ ના સાથે: +2301 +૭-જિપ ના શેલ (કવચ) પ્રસંગ મેનુ માં જોડો +સોપાનીકૃત(કેસ્કેડેડ) પ્રસંગ મેનુ +પ્રસંગ(કોન્ટેક્સ્ટ) મેનુ વસ્તુએઁ: +2320 +<ફોલ્ડર> +<સંગ્રહ(આર્ચિવ)> +સંગ્રહ ખોલો +ફ઼ાઇલ્સ બાહર કાઢો... +સંગ્રહમાં જોડો... +સંગ્રહની જાઁચ કરો +અહિયાં બાહર કાઢો +{0} માં બાહર કાઢો +{0} માં જોડો +દબાવો(સંકુચન) અને ઇમેલ કરો... +{0} માં દબાવો અને ઈમેલ કરો +2400 +ફોલ્ડર્સ +&કાર્યરત ફોલ્ડર +&પ્રણાલીનું અસ્થાયી(ટેમ્પરરી) ફોલ્ડર +&ચાલુ +&નિર્દિષ્ટ: +ફક્ત હટાવવા યોગ્ય(રિમૂવેબલ) ડ્રાઈવ માટે જ પ્રયોગ કરો +અસ્થાયી સંગ્રહ ફાઇલ માટે સ્થાન નિર્દિષ્ટ કરો(બતાવો). +2500 +વ્યવસ્થાઓ +દિખાવો ".."વસ્તુ +વાસ્તવિક ફ઼ાઇલ પ્રતીક બતાવો +તંત્ર નો મેનુ બતાવો +&આખી પન્ક્તિનું ચયન +&ગ્રિડ(જાલ) રેખા દિખાવો +વસ્તુ ખોલવા માટે એક જ(સિંગલ)-ક્લિક +&વૈકલ્પિક ચયન સ્થિતિ +&મોટા સ્મૃતિ પૃષ્ઠનો પ્રયોગ કરો +2900 +7-જિપ ના વિશે +7-જિપ એ નિઃશુલ્ક સૉફ઼્ટવેયર છે. તો પણ, આપ પંજીકૃત(રજિસ્ટર્ડ) થઈને ૭-જ઼િપ ના વિકાસમાં સહયોગ કરી શકો છો. +3000 +તંત્ર જરૂરી માત્રામાં મેમોરી(સ્મૃતિ) વિતરિત નથી કરી શકતું +આમાં કોઈ પણ ત્રુટિ નથી +{0} ચયનિત વસ્તુ(ઓ) +'{0}' ફ઼ોલ્ડર સર્જિત નથી કરી શકતું +આ સંગ્રહ માટે અદ્યતનીકૃત સંચાલન સમર્થિત નથી. +'{0}' ફાઇલને સંગ્રહનાં રૂપમાં નથી ખોલી શકતું +'{0}' ગુપ્તિકૃત સંગ્રહને નથી ખોલી શકતુ. ગલત કૂટશબ્દ? +અસમર્થિત સંગ્રહ પ્રકાર +ફાઇલ {0} પહેલાથી હયાત છે +'{0}' ફ઼ાઇલ પરિવર્ધિત થઈ છે.\nશું તમે સંગ્રહમાં આને અદ્યતનીકૃત કરવા માગો છો? +ફ઼ાઇલ ને અદ્યતનીકૃત નથી કરી શકતું\n'{0}' +સંપાદકને શરૂ નથી કરી શકતું. +આ ફાઇલ એક વિષાણુ(વાયરસ) જેવી લાગે છે (ફાઇલ નામ લાંબી ખાલી જગહ નામમાં રાખતો છે). +જે ફોલ્ડરનો લાંબો માર્ગ છે તેનાથી સઞ્ચાલન ક્રિયા બોલાવી નથી શકાતી. +તમારે એક ફાઇલનો ચયન તો કરવો જ પડશે +તમારે એક કે જ્યાદા ફાઇલોંનો ચયન તો કરવો જ પડશે +બહુ વધારે વસ્તુઓ +3300 +બાહર કાઢી રહ્યું છે +સંકુચન કરી રહ્યું છે +પરીક્ષણ +ખોલી રહ્યુ છે... +તલાશી(સ્કૈનિંગ) કરી રહ્યુ છે... +3400 +બાહર કાઢો +&બાહર કાઢો: +બાહર કાઢેલી ફ઼ાઇલોં માટે સ્થાન નિર્દિષ્ટ કરો. +3410 +માર્ગ સ્થિતિ +આખો માર્ગનામ +કોઈ માર્ગ નામ નથી +3420 +અધિલેખન રીત +અધિલેખન કરતાં પહલાં પૂછો +વગર પૂછે અધિલેખન(જુનું મટાવવું) કરો +પહેલાથી હયાત ફ઼ાઇલસને છોડો +સ્વચાલિત પુન: નામકરણ +પહેલાથી હયાત ફ઼ાઇલસનો સ્વચાલિત(ઓટોમેટિક) પુન: નામકરણ કરો +3500 +ફ઼ાઇલ પ્રતિસ્થાપન ને પાક્કુ કરો +ગન્તવ્ય ફોલ્ડરમાં પહેલાથી જ પ્રક્રિયા થએલી ફ઼ાઇલ છે. +શું આપ પહેલાથી હયાત ફ઼ાઇલ ને બદલવું પસંદ કરશો? +આની જોડે? +{0} બાઇટ્સ +સ્વચાલિત પુન: નામકરણ +3700 +'{0}' ના માટે અસહાયક દબાવાવાની પદ્ધતિ. +ડેટા ત્રુટિ’{0}' માં. ફ઼ાઇલ તૂટેલી છે. +'{0}' માં સીઆરસી અસફલ. ફ઼ાઇલ તૂટેલી છે. +'{0}' ગુપ્તિકૃત(એનક્રિપ્ટેડ) ફાઇલ માં ડેટા ત્રુટિ. ગલત કૂટશબ્દ? +'{0}' ગુપ્તિકૃત(એનક્રિપ્ટેડ) ફાઇલ માં સીઆરસી અસફલ. ગલત કૂટશબ્દ? +3800 +કૂટશબ્દ(પાસવર્ડ) ડાલે +કૂટશબ્દ(પાસવર્ડ) ડાલે: +કૂટશબ્દ પુનઃ નાખો: +&કૂટશબ્દ(પાસવર્ડ) દિખાવો +કૂટશબ્દ સહેજેલાંથી જુદૂં છે +કૂટશબ્દ માટે ફક્ત ઇંગ્લિશ વર્ણમાલા, અંકો અને વિશેષ અક્ષરોં (!, #, $, ...) નો જ ઉપયોગ કરો +કૂટશબ્દ ખૂબ જ મોટું છે +કૂટશબ્દ(પાસવર્ડ) +3900 +વ્યતીત સમય: +શેષ બચેલું સમય: +કુલ આકાર: +ગતિ: +પ્રક્રિયા કરેલું: +દબાવાનું(આકાર છોટા કરવાનું)અનુપાત: +ત્રુટિયાઁ: +સંગ્રહ: +4000 +સંગ્રહમાં જોડો +&સંગ્રહ: +&અદ્યતનીકરણ સ્થિતિ(મોડ): +સંગ્રહ &ઢાઁચા: +&સંકુચન સ્તર: +&સંકુચન વિધિ: +&શબ્દકોશ આકાર: +&શબ્દ આકાર: +ઠોસ ટુકડાનો આકાર: +સીપીયૂ સૂત્ર સંખ્યા: +&પરિમાપ: +વિકલ્પ +&એસએફ઼એક્સ(SFX) સંગ્રહ તૈયાર કરો +સાઝી ફાઇલો સંકુચિત કરો +ગુપ્તિકરણ +ગુપ્તિકરણ પદ્ધતિ: +ફ઼ાઇલ &નામ ગુપ્તિકરણ કરો +સંકુચન માટે સ્મૃતિ પ્રયોગ: +પ્રસારણ માટે સ્મૃતિ પ્રયોગ: +4050 +ભંડારણ +સર્વાધિક તેજ +તેજ +સાધારણ +અધિકતમ +અત્યન્ત +4060 +ફ઼ાઇલેં જોડો અને પ્રતિસ્થાપિત કરો +ફાઇલો અદ્યતનીકૃત કરો અને જોડો +અવસ્થિત ફાઇલોં તાજા કરો +ફાઇલોં સમક્રમણ(સિંક્રોનાઈજ઼) કરો +4070 +બ્રાઉજ યા ઘૂમો +બધા ફાઇલોં +અ-ઠોસ +ઠોસ +6000 +નકલ +લઇ જાઓ +માં નકલ: +માં લઇ જાઓ: +નકલ... +લઇ જાઇ રહ્યુ છે... +પુનઃ નામકરણ... +ગન્તવ્ય ફોલ્ડર ચયનિત કરો. +આ ફોલ્ડર માટે આ સઞ્ચાલન ક્રિયા સમર્થિત નથી. +ફ઼ાઇલ કે ફ઼ોલ્ડરના પુનઃ નામકરણ માં ત્રુટિ +ફ઼ાઇલની નકલ કરવુ પાક્કું કરો +તમે સંગ્રહમાં ફાઇલ ની પ્રતિલિપિ કરવા ચાહો છો શું તમને યકીન છે +6100 +ફ઼ાઇલ મિટાવો આ પાક્કું કરો +ફ઼ોલ્ડર મિટાવો પાક્કું કરો +અનેક ફ઼ાઇલ મિટાવો પાક્કું કરો +શું તમને યકીન છે કે તમે મેટવવા ચાહો છો '{0}'? +શું તમને યકીન છે કે તમે ફ઼ોલ્ડર મિટાવવા માંગો છો ’{0}' અને આની બધી સામગ્રી પણ? +શું તમને યકીન છે કે તમે મિટાવવા માંગો છો આ {0} વસ્તુઓં ને? +મેટવી રહ્યુ છે... +ફ઼ાઇલ કિંવા ફ઼ોલ્ડર મિટાવામાં ત્રુટિ +તંત્ર લાંબા માર્ગ વાલી ફાઇલને પુનઃચક્રણ પેટી(રિસાઈકલ બિન)માં નથી લઇ જાઇ શકતુ. +6300 +ફ઼ોલ્ડર તૈયાર કરો +ફ઼ાઇલ તૈયાર કરો +ફ઼ોલ્ડર નામ: +ફ઼ાઇલ નામ: +નવુ ફ઼ોલ્ડર +નવી ફ઼ાઇલ +ફ઼ોલ્ડર તૈયાર કરવામાં ત્રુટિ +ફ઼ાઇલ તૈયાર કરવામાં ત્રુટિ +6400 +ટિપ્પણી +&ટિપ્પણી: +ચયન +ચયન રદ્દ +મુખૌટો: +6600 +ગુણ યા સંપત્તિયાઁ +ફ઼ોલ્ડરોંનો ઇતિહાસ +નિદાનાત્મક સંદેશ +સંદેશ +7100 +સંગણક +સઞ્જાલ +દસ્તાવેજ +પ્રણાલી +7200 +જોડો +બાહર કાઢો +પરીક્ષણ +નકલ +લઈ જાઓ +મિટાવો +સૂચના +7300 +ફ઼ાઇલનું વિભાજન કરો +&માં વિભાજન: +જત્થાઓમાં વિભાજન, બાઇટ્સ: +વિભાજન કરી રહ્યુ છે... +વિભાજન કરવાનું પાક્કું કરો +શું તમને યકીન છે કે તમે ફાઇલ ને {0} જત્થાઓમાં વિભાજિત કરવા માગો છો? +મૂલ ફાઇલના આકારની તુલનામાં જત્થાનું આકાર નાનો જ હોવો જોઇએ +જત્થાનો આકાર ખોટું છે +નિર્દેશિત જત્થા આકાર: {0} બાઇટસ.\n આપ સંગ્રહને એવા જત્થાઓમાં વિભાજિત કરવા ચાહો છો, શું તમને યકીન છે? +7400 +ફાઇલો સંયોજિત કરો +&માં સંયોજન કરો: +સંયોજન થઇ રહ્યુ છે... +વિભાજિત ફાઇલનો ફક્ત પ્રથમ ભાગ જ ચયનિત કરો +ફાઇલ ને વિભાજિત ફાઇલના ભાગના રૂપમાં ઓળખી નથી શકતુ +વિભાજિત ફાઇલના એક થી વધારે ભાગ શોધી નથી શકતુ +7500 +જાઁચયોગ(ચેકસમ)ની ગણના કરી રહ્યુ છે... +જાઁચયોગ(ચેકસમ) માહિતી +સીઆરસી જાઁચયોગ(ચેકસમ) આઁકડ઼ોં માટે : +સીઆરસી જાઁચયોગ(ચેકસમ) આઁકડ઼ોં અને નામોં માટે : +7600 +(કસૌટી ચિન્હ)બેઞ્ચમાર્ક +સ્મૃતિ ઉપયોગ: +સંકુચન કરી રહ્યું છે +પ્રસારણ કરી રહ્યું છે +ક્રમાંકન +કુલ ક્રમાંકન +વર્તમાન +પરિણામ +સીપીયૂ ઉપયોગ +ક્રમાંકન / ઉપયોગ +પાસ: diff --git a/Utils/7-Zip/Lang/he.txt b/Utils/7-Zip/Lang/he.txt new file mode 100644 index 000000000..c4e9d39d9 --- /dev/null +++ b/Utils/7-Zip/Lang/he.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : peterg +; : Gal Brill +; 9.13 : 2010-04-30 : Jonathan Lahav +; +; +; +; +; +; +; +; +0 +7-Zip +Hebrew +עברית +401 +אישור +ביטול + + + +&כן +&לא +&סגור +עזרה + +ה&משך +440 +כן ל&הכל +ל&א להכל +עצור +התחל מחדש +&רקע +&קדמה +ה&שהה +מושהה +?האם את/ה בטוח/ה שברצונך לבטל +500 +&קובץ +&עריכה +&תצוגה +&מועדפים +&כלים +ע&זרה +540 +&פתח +פתח ב&תוכנה +פתח ב&חלון +&הצג +&ערוך +&שנה שם +...העתק ל& +...העבר ל& +&מחק +...פצל קובץ& +...מזג קבצים& +מ&אפיינים +הערה +חשב סיכום ביקורת +הבדל +צור תיקייה +צור קובץ +י&ציאה +600 +בח&ר הכל +בטל בחירה +ה&פוך בחירה +...בחר +...בטל בחירה +בחר לפי סוג +בטל בחירה לפי סוג +700 +סמלים &גדולים +סמלים &קטנים +&רשימה +&פרטים +730 +לא מסודר +תצוגה בפריסה מלאה +&שני חלונות +&סרגלי כלים +פתח תיקיית שורש +חזור שלב אחד +...היסטוריית תיקיות +ר&ענן +750 +סרגל ארכיון +סרגל רגיל +כפתורים גדולים +הצג את פעולת הכפתור מתחתיו +800 +&הוסף תיקייה למועדפים כ +סימנייה +900 +&...אפשרויות +&מבחן ביצועים +960 +&...תוכן +&...7-Zip אודות +1003 +נתיב +שם +סיומת +תיקייה +גודל +גודל מכווץ +תכונות +נוצר +נצפה +השתנה +רצוף +נרשמה הערה +הוצפן +פצל לפני +פצל אחרי +מילון +CRC +סוג +אנטי +שיטה +מערכת הפעלה +מערכת קבצים +משתמש +קבוצה +קטע +הערה +מיקום +תחילית נתיב +תיקיות +קבצים +גירסה +חלק +ריבוי חלקים +קיזוז +קישורים +קטעים +חלקים + +64ביט +אחסון בסדר חשיבות יורד +משאבי מערכת/מעבד +גודל פיזי +גודל כותרת עליונה +בדיקת סיכום +מאפיינים +כתובת וירטואלית +מס' זיהוי +שם קצר +תוכנה יוצרת +גודל סקטור +מצב +קישור +שגיאה +גודל כללי +שטח פנוי +גודל קלסטר/יחידת אחסון +תווית +שם מקומי +ספק +2100 +אפשרויות +Language / שפה +Language / שפה: +עורך +&עורך: +&הבדל: +2200 +מערכת +7-Zip שייך ל : +2301 +שלב את התוכנה בתפריט-ההקשר הכללי +תפריט מדורג +פריטי תפריט: +2320 +<תיקייה> +<ארכיון> +פתח ארכיון +...חלץ קבצים +...הוסף לארכיון +בדוק ארכיון +חלץ לכאן +{0} -חלץ ל +{0} -הוסף ל +כווץ ושלח בדואר אלקטרוני +כווץ ל- {0} ושלח בדואר אלקטרוני +2400 +תיקיות +&תיקיית עבודה +של המ&ערכת "Temp" תיקיית ה +&נוכחית +&בחר תיקייה: +השתמש בהגדרות אלו עבור כוננים ניידים בלבד +.בחר מיקום לקבצי ארכיון זמניים +2500 +הגדרות +".." הצג את הפריט +הצג סמלי קבצים אמיתיים +הצג את תפריט המערכת +בחר את כל ה&שורה +הצג קווי &טבלה +לחיצה אחת לפתיחת פריט +שיטת &בחירה חלופית +השתמש בקטעי זיכרון &גדולים יותר +2900 +7-Zip אודות +זו היא תוכנה חופשית. עם זאת, ביכולתך לתמוך בפיתוח התוכנה על ידי הרשמה +3000 +המערכת אינה יכולה להקצוות את כמות הזיכרון הדרושה +אין שגיאות +(נבחרו {0} פריט(ים +'{0}' אין אפשרות ליצור את התיקייה +.פעולות עדכון לא נתמכות עבור ארכיון זה +'לא היה ניתן לפתוח את הקובץ '{0}' כארכיון +'?לא היה ניתן לפתוח את הארכיון המקודד '{0}'. סיסמא שגוייה +סוג ארכיון אינו נתמך +הקובץ {0} כבר קיים +?האם ברצונך לעדכן אותו בארכיון\n.הקובץ '{0}' שונה +'{0}'\nאין אפשרות לעדכן את הקובץ +.אין אפשרות להפעיל את העורך +(ייתכן והקובץ היינו וירוס (ישנם רווחים גדולים בשם הקובץ +.הפעולה אינה יכולה להתבצע מתיקייה בעלת נתיב ארוך +הינך חייב/ת לבחור קובץ אחד +הינך חייב לבחור קובץ אחד או יותר +יותר מדי פריטים +3300 +מחלץ +מכווץ +בודק +...פותח +...סורק +3400 +חלץ +&חלץ ל: +.ציין יעד לחילוץ הקבצים +3410 +שיטת הנתיבים +נתיבים מלאים +ללא נתיבים +3420 +מצב שכתוב קבצים +שאל לפני שכתוב +שכתב בלי לשאול +דלג על קבצים קיימים +שינוי שם אוטומטי +שינוי שם אוטומטי לקבצים קיימים +3500 +אשר החלפת קובץ +.תיקיית היעד מכילה כבר קובץ בשם זה +האם ברצונך להחליף את הקובץ הקיים +?בקובץ הזה +{בתים: {0 +שינוי שם &אוטומטי +3700 +.'{0}' שיטת הדחיסה אינה נתמכת עבור +.שגיאת מידע ב '{0}'. הקובץ אינו תקין +.בדיקת סכום הנתונים נכשלה ב '{0}'. הקובץ אינו תקין +'?שגיאת נתון בקובץ המקודד '{0}'. סיסמא שגוייה +'?שגיאה בבדיקת סכום הנתונים בקובץ המקודד '{0}'. סיסמא שגוייה +3800 +הכנס סיסמא +הכנס סיסמא: +הכנס שנית את הסיסמא: +&הצג סיסמא +הסיסמאות אינן תואמות +(!, #, $, ...) ליצירת הסיסמא השתמש רק באותיות אנגליות, מספרים או תווים מיוחדים +הסיסמא ארוכה מידי +סיסמא +3900 +הזמן שעבר: +הזמן שנותר: +גודל כולל: +מהירות: +התקדמות: +יחס כיווץ: +שגיאות: +ארכיונים: +4000 +הוסף לארכיון +&ארכיון: +מצב &עדכון: +&פורמט הארכיון: +רמת &דחיסה: +&שיטת דחיסה: +גודל מי&לון: +גודל &מילה: +גודל קטע רצוף: +כמות הליכי מעבד/מערכת: +&פרמטרים: +אפשרויות +צור ארכיון &חילוץ-עצמי +דחוס קבצים שבשיתוף +הצפנה +שיטת הצפנה: +&קדד שמות קבצים +זיכרון הדרוש לדחיסה: +זיכרון הדרוש לחילוץ: +4050 +אחסון +הכי מהירה +מהירה +רגילה +מקסימאלית +אולטרה +4060 +הוסף והחלף קבצים +עדכן והוסף קבצים +רענן קבצים קיימים +סנכרן קבצים +4070 +עיון +כל הקבצים +לא רצוף +רצוף +6000 +העתק +העבר +העתק ל: +העבר ל: +...מעתיק +...מעביר +...משנה שם +בחר תיקיית יעד. +הפעולה אינה נתמכת עבור תיקייה זו +אירעה שגיאה בשינוי שם של קובץ או תיקייה +אשר העתקת קובץ +?האם את/ה בטוח/ה שברצונך להעתיק קבצים לארכיון +6100 +אשר מחיקת קובץ +אשר מחיקת תיקייה +אשר מחיקת מספר קבצים +?'{0}' האם את/ה בטוח/ה שברצונך למחוק את +?האם את/ה בטוח/ה שברצונך למחוק את התיקייה '{0}' ואת כל תוכנה +?האם את/ה בטוח/ה שברצונך למחוק את {0} הפריטים האלה +...מוחק +אירעה שגיאה במהלך מחיקת קובץ או תיקייה +המערכת אינה יכולה להעביר קובץ עם נתיב ארוך לפח המחזור +6300 +צור תיקייה +צור קובץ +שם התיקייה: +שם הקובץ: +תיקייה חדשה +קובץ חדש +שגיאה ביצירת תיקייה +שגיאה ביצירת קובץ +6400 +הערה +&הערה: +בחר +בטל בחירה +מיסוך: +6600 +מאפיינים +היסטוריית תיקיות +הודעות איבחון +הודעה +7100 +מחשב +רשת +מסמכים +מערכת +7200 +הוסף +חלץ +בדוק +העתק +העבר +מחק +מידע +7300 +פצל קובץ +&פצל ל: +פצל לחלקים, בתים: +...מפצל +אשר פיצול +? האם את/ה בטוח/ה שברצונך לפצל את הקובץ ל{0} חלקים +גודל החלק חייב להיות קטן יותר מהקובץ המקורי +גודל חלק שגוי +?האם את/ה בטוח/ה שברצונך לפצל את הארכיון לחלקים אלה\nגודל החלק המוגדר: {0} בתים +7400 +מזג קבצים +&מזג ל: +...מבצע מיזוג +בחר רק את החלק הראשון של הקובץ המפוצל +לא היה ניתן למצוא קובץ שהוא חלק מהקובץ המפוצל +לא ניתן למצוא יותר מחלק אחד של הקובץ המפוצל +7500 +...מחשב סיכום ביקורת +תוצאות סיכום ביקורת +עבור הנתונים CRC בדיקת סיכום ביקורת : +עבור הנתונים ושמות CRC בדיקת סיכום ביקורת : +7600 +מבחן ביצועים +זיכרון בשימוש: +מכווץ +מחלץ +קצב +סיכום הקצב +נוכחי +סופי +משאבי מערכת/מעבד +קצב / שימוש +הצלחות: diff --git a/Utils/7-Zip/Lang/hi.txt b/Utils/7-Zip/Lang/hi.txt new file mode 100644 index 000000000..03a75a199 --- /dev/null +++ b/Utils/7-Zip/Lang/hi.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Vinayy Sharrma : अनुवाद विनय शर्मा मेहनत की है तो अपना नाम लिखने मे कोई बुराई तो है नही. हिन्दी पर गर्व करो, जय हिन्द ! जय हिन्दी ! +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Hindi, Indian, हिन्दुस्तान +हिन्दी +401 +ठीक है +रद्द + + + +&हाँ +&नहीं +&बंद करो +मदद + +&जारी रखे +440 +&सभी के लिये हाँ +&सभी के लिये नहीं +रूको +पुनः शुरु करें +&पॄष्ठ्भूमि +&अग्रभूमि(डेस्क्टोप) +&विश्राम +विश्रामित +तुम रद्द करना चाहते हो. तुम्हें यकीन है क्या? +500 +&फ़ाइल +&संपादन +&दर्शन +&मनपसंद +&औजार +&मदद +540 +&खोले +&अंदर खोले +&बाहर खोले +&दृश्य +&संपादन +&पुन: नामकरण +&में नकल बनाये... +&में ले जायें... +&मिटायें +&फ़ाइल का विभाजन करें... +&फ़ाइल का संयोजन करें... +&संपत्तियाँ या गुण +&टिप्पणी +&जाँच योग की गणना करें +&अन्तर +&फ़ोल्डर तैयार करें +&फ़ाइल तैयार करें +&निर्गमन +600 +&सभी चयन करे +&सभी अचयनित करें +&चयन उलटा करें +चयन करें... +अचयन करे... +प्रकार द्वारा चयन +प्रकार द्वारा अचयन +700 +बड़ी प्रतीक +लघु प्रतीक +&सूची +&वर्णन +730 +अवितरित +चौड़ा दृश्य +&२ फ़लक +&औजार पट्टीयाँ +मूल फ़ोल्डर खोले +एक स्तर ऊपर चढ़े +फ़ोल्डरो का इतिहास... +&ताजा करें +750 +संग्रह उपकरणपट्टी +मानक औजार पट्टी +बड़े खटके(बटन) +खटके(बटन) के शब्द दिखायें +800 +&फ़ोल्डर मनपसंद में ऎसे जोड़े... +पुस्तचिन्ह +900 +&विकल्प... +&बेञ्चमार्क(प्रामाणिक तुलना) +960 +&सामग्री... +7-जिप के बारे में... +1003 +मार्ग +नाम +विस्तार +फ़ोल्डर +आकार +कुल आकार +विशेषता या गुणधर्म +सर्जित +चलायी गई +परिवर्धित +ठोस +टिप्पणी +गुप्तिकृत +के पूर्व विभाजन(टुकडे) करें +के बाद विभाजन(टुकडे) करें +शब्दकोश +सीआरसी +प्रकार +विरोधी +पद्धति +यजमान आज्ञावली(ओपरेटिंग सिस्टम) +फ़ाइल प्रणाली +प्रयोगकर्ता +समूह +रोक या टुकड़े +प्रतिक्रिया +स्थान +मार्ग प्रत्यय +फोल्डर्स +फाइल्स +संस्करण +जत्था +अनेक जत्थे +ओफसेट +कडियाँ +टुकड़े +जत्थे + +64-बिट +बड़ा-एन्डियन +सीपीयू +भौतिक आकार +शीर्षकों के आकार +जाँचयोग +चरित्रताऎं +आभासी पता +आईडी +संक्षिप्त नाम +सर्जक अनुप्रयोग +सेक्टर का आकार +स्थिति +कड़ी +त्रुटि +कुल आकार +स्वतन्त्र रिक्तस्थान(खाली जगह) +क्लस्टर(समूह) आकार +ध्यानाकर्षक(लेबल) +स्थानिय नाम +प्रदायक +2100 +विकल्प +भाषा +भाषा: +संपादक +&संपादक: +&अन्तर: +2200 +प्रणाली या तंत्र +संबधित करें 7-जिप के साथ: +2301 +7-जिप के शेल (कवच) प्रसंग मेनु में जोडें +सोपानीकृत(केस्केडेड) प्रसंग मेनु +प्रसंग(कोन्टेक्स्ट) मेनु वस्तुएँ: +2320 +<फोल्डर> +<संग्रह(आर्चिव)> +संग्रह खोले +फ़ाइल्स बाहर निकाले... +संग्रह में जोड़े... +संग्रह की जाँच करे +यहीं बाहर निकाले +{0} में बाहर निकाले +{0} में जोड़े +दबायें(संकुचन) ओर इमेल करें... +{0} में दबायें ओर ईमेल करें +2400 +फ़ोल्डर्स +&कार्यरत फ़ोल्डर +&प्रणाली का अस्थायी(टेम्पररी) फोल्डर +&चालू +&निर्दिष्ट: +सिर्फ हटाने योग्य(रिमूवेबल) ड्राईव के लिये ही प्रयोग करें +अस्थायी संग्रह फाइल के लिये स्थान निर्दिष्ट करें(बतायें). +2500 +व्यवस्थाएँ +दिखाओ ".."वस्तु +वास्तविक फ़ाइल प्रतिमायें दिखाओ +तंत्र का मेनु दिखाओ +&पूरी पन्क्ति का चयन +&ग्रिड(जाल) रेखा दिखाओ +वस्तु खोलने के लिये एक ही(सिंगल)-क्लिक +&वैकल्पिक चयन स्थिति +&बड़े स्मृति पृष्ठ का प्रयोग करे +2900 +7-जिप के बारे में +7-जिप यह निःशुल्क सॉफ़्टवेयर है. फिर भी, आप पंजीकृत(रजिस्टर्ड) होकर७-ज़िप के विकास में सहयोग कर सकते हैं. +3000 +तंत्र जरूरी मात्रा में मेमोरी(स्मृति) वितरित नही कर सकता है +इनमे कोई भी त्रुटि नहीं है +{0} चयनित वस्तु(एँ) +'{0}' फ़ोल्डर सर्जित नहीं कर सकता +इस संग्रह के लिये अद्यतनीकृत संचालन समर्थित नहीं हैं. +'{0}' फाइल को संग्रह के रूप में नही खोल सकता +'{0}' गुप्तिकृत संग्रह को नही खोल सकता. गलत कूटशब्द? +असमर्थित संग्रह प्रकार +फाइल {0} पहले से मौजूद है +'{0}' फ़ाइल परिवर्धित हुई है.\nक्या तुम संग्रह में इसे अद्यतनीकृत करना चाहते हो? +फ़ाइल को अद्यतनीकृत नही कर सकता\n'{0}' +संपादक को शुरू नही कर सकता. +यह फाइल एक विषाणु(वायरस) जैसी लगती है(फाइल नाम लंबी खाली जगह नाम में रखता है). +जिस फोल्डर का लंबा मार्ग है उससे सञ्चालन क्रिया नही बुलाई जा सकती. +तुम्हे एक फाइल का चयन तो करना ही होगा +तुम्हे एक या ज्यादा फाइलों को चुनना ही होगा +बहुत ज्यादा वस्तुएँ +3300 +बाहर निकाल रहा है +संकुचन कर रहा है +परीक्षण +खोल रहा है... +तलाशी(स्कैनिंग) कर रहा है... +3400 +बाहर निकाले +&बाहर निकाले: +बाहर निकाली हुई फ़ाइलों के लिये स्थान निर्दिष्ट करें. +3410 +मार्ग स्थिति +पूरा मार्गनाम +कोई मार्ग नाम नहीं है +3420 +अधिलेखन रीत +अधिलेखन करने से पहले पूछे +बिना पूछे अधिलेखन(पुराने को मिटाना) करें +पहले से मौजूद फ़ाइलस को छोड़े +स्वचालित पुन: नामकरण +पहले से मौजूद फ़ाइलस का स्वचालित(ओटोमेटिक) पुन: नामकरण करे +3500 +फ़ाइल प्रतिस्थापन को पक्का करें +गन्तव्य फोल्डर में पहले से ही प्रक्रिया हुई फ़ाइल है. +क्या आप पहले से मौजूद फ़ाइल को बदलना पसंद करेंगे? +इसके साथ? +{0} बाइट्स +स्वचालित पुन: नामकरण +3700 +'{0}' के लिए असहायक दबाने की पद्धति. +डेटा त्रुटि'{0}' में. फ़ाइल टूटी हुई है. +'{0}' में सीआरसी असफल. फ़ाइल टूटी हुई है. +'{0}' गुप्तिकृत(एनक्रिप्टेड) फाइल में डेटा त्रुटि. गलत कूटशब्द? +'{0}'गुप्तिकृत(एनक्रिप्टेड) फाइल में सीआरसी असफल. गलत कूटशब्द? +3800 +कूटशब्द(पासवर्ड) डाले +कूटशब्द(पासवर्ड) डाले: +कूटशब्द पुनः डाले: +&कूटशब्द(पासवर्ड) दिखाओ +कूटशब्द सहेजे हुए से अलग है +कूटशब्द के लिये सिर्फ़ इंग्लिश वर्णमाला, अंको और विशेष अक्षरों (!, #, $, ...) का ही उपयोग करें +कूटशब्द बहुत ज्यादा बड़ा है +कूटशब्द(पासवर्ड) +3900 +व्यतीत समय: +बाकी बचा समय: +कुल आकार: +गति: +प्रक्रिया किया हुआ: +दबाने(आकार छोटा करने) का अनुपात: +त्रुटियाँ: +संग्रह: +4000 +संग्रह में जोड़े +&संग्रह: +&अद्यतनीकरण स्थिति(मोड): +संग्रह &ढाँचा: +&संकुचन स्तर: +&संकुचन विधि: +&शब्दकोश आकार: +&शब्द आकार: +ठोस टुकडे का आकार: +सीपीयू सूत्र संख्या: +&परिमाप: +विकल्प +&एसएफ़एक्स(SFX) संग्रह तैयार करें +साझी फाइलें संकुचित करें +गुप्तिकरण +गुप्तिकरण पद्धति: +फ़ाइल &नाम गुप्तिकरण करें +संकुचन के लिये स्मृति प्रयोग: +प्रसारण के लिये स्मृति प्रयोग: +4050 +भण्डारण +सर्वाधिक तेज +तेज +साधारण +अधिकतम +अत्यन्त +4060 +फ़ाइलें जोड़े और प्रतिस्थापित करे +फ़ाइले अद्यतनीकृत करें और जोड़े +अवस्थित फ़ाइलें ताजा करें +फाइलें समक्रमण(सिंक्रोनाईज़) करें +4070 +ब्राउज या घूमे +सभी फ़ाइलें +अ-ठोस +ठोस +6000 +नकल +ले जायें +में नकल: +में ले जायें: +नकल... +ले जा रहा है... +पुन: नामकरण... +गन्तव्य फोल्डर चयनित करें. +इस फोल्डर के लिये यह सञ्चालन क्रिया समर्थित नहीं है. +फ़ाइल या फ़ोल्डर के पुन: नामकरण में त्रुटि +फ़ाइल की नकल करना पक्का करो +तुम संग्रह में फाइल की प्रतिलिपि करना चाहते हो क्या तुम्हे यकीन है +6100 +फ़ाइल मिटाये यह पक्का करो +फ़ोल्डर मिटायें पक्का करो +अनेक फ़ाइल मिटायें पक्का करो +क्या तुम्हे यकीन है कि तुम मिटाना चाहते हो '{0}'? +क्या तुम्हे यकीन है कि तुम फ़ोल्डर मिटाना चाहते हो '{0}' और इसकी सब सामग्री भी? +क्या तुम्हे यकीन है कि तुम मिटाना चाहते हो इन {0} वस्तुओं को? +मिटा रहा है... +फ़ाइल किंवा फ़ोल्डर मिटाने में त्रुटि +तंत्र लंबे मार्ग वाली फाइल को पुनःचक्रण पेटी(रिसाईकल बिन) में नही ले जा सकता है. +6300 +फ़ॊल्डर तैयार करें +फ़ाइल तैयार करें +फ़ोल्डर नाम: +फ़ाइल नाम: +नया फ़ॊल्डर +नया फ़ाइल +फ़ोल्डर तैयार करने में त्रुटि +फ़ाइल तैयार करने में त्रुटि +6400 +टिप्पणी +&टिप्पणी: +चयन +चयन रद्द +मुखौटा: +6600 +गुण या संपत्तियाँ +फ़ोल्डरों का इतिहास +निदानात्मक संदेश +संदेश +7100 +संगणक +सञ्जाल +दस्तावेज +प्रणाली +7200 +जोड़े +बाहर निकाले +परीक्षण +नकल +ले जायें +मिटायें +सूचना +7300 +फ़ाइल का विभाजन करें +&में विभाजन: +जत्थों में विभाजन, बाइट्स: +विभाजन कर रहा है... +विभाजन करना पक्का करे +क्या तुम्हे यकीन है कि तुम फाइल को {0} जत्थों में विभाजित करना चाहते हो? +मूल फाइल के आकार की तुलना में जत्थे का आकार छोटा ही होना चाहिए +जत्थे का आकार गलत है +निर्देशित जत्था आकार: {0} बाइटस.\n आप संग्रह को ऎसे जत्थों में विभाजित करना चाहते है, क्या आपको यकीन है? +7400 +फ़ाइले संयोजित करें +&मेंसंयोजन करे: +संयोजन हो रहा है... +विभाजित फाइल का सिर्फ़ प्रथम भाग ही चयनित करे +फाइल को विभाजित फाइल के भाग के रूप में पहचान नही सकता +विभाजित फाइल का एक से ज्यादा भाग नही ढूँढ सकता +7500 +जाँचयोग(चेकसम) की गणना कर रहा है... +जाँचयोग(चेकसम) माहिती +सीआरसी जाँचयोग(चेकसम) आँकड़ों के लिये : +सीआरसी जाँचयोग(चेकसम) आँकड़ों और नामों के लिये : +7600 +(कसौटी चिन्ह)बेञ्चमार्क +स्मृति उपयोग: +संकुचन कर रहा है +प्रसारण हो रहा है +क्रमांकन +कुल क्रमांकन +वर्तमान +परिणाम +सीपीयू उपयोग +क्रमांकन / उपयोग +पास: diff --git a/Utils/7-Zip/Lang/hr.txt b/Utils/7-Zip/Lang/hr.txt new file mode 100644 index 000000000..dd61b97a1 --- /dev/null +++ b/Utils/7-Zip/Lang/hr.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 3.12 : Alan Šimek +; 4.53 : Hasan Osmanagić +; 9.07 : +; 15.05 : 2015-06-15 : Stjepan Treger +; +; +; +; +; +; +; +0 +7-Zip +Croatian +Hrvatski +401 +U redu +Odustani + + + +&Da +&Ne +&Zatvori +Pomoć + +Nastavi +440 +Da za &Sve +Ne za Sv&e +&Stani +Ponovi +U pozadini +U prvom planu +&Pauza +Pauzirano +Poništiti? +500 +&Datoteke +&Uređivanje +&Izgled +Omiljene mape +&Alati +&Pomoć +540 +&Otvori +Ot&vori mapu +Otvori u &sustavu +Iz&gled +&Uređivanje +Prei&menuj +&Kopiraj u... +Premje&sti u... +O&briši +Podije&li datoteku... +Spo&ji datoteke... +Svojs&tva +Komentar +Izračun kontrolnog zbroja +Uspoređivanje +Stvo&ri mapu +Stvori &datoteku +&Izlaz +Poveznica +&Alternativni tokovi +600 +Odaberi &sve +Poništi odabir +&Obrni odabir +Odaberi... +Poništi odabir... +Odabir po tipu +Poništi odabir tipa +700 +&Velike ikone +&Male ikone +&Popis +&Detalji +730 +Neso&rtirano +Sadržaj mapa +&2 okna +Alatne &trake +&Korijen +&Nadmapa +Proš&le mape... +O&svježi +Automatski osvježi +750 +Alatna traka arhiva +Standardna alatna traka +Velike tipke +Prikaži tekst +800 +Dod&aj u popis omiljenih kao +Zabilješka +900 +&Mogućnosti... +M&jerenje +960 +&7-Zip pomoć... +&O programu... +1003 +Putanja +Prema nazivu +Tip +Mapa +Prema veličini +Sažeta veličina +Atributi +Kreirano +Pristupano +Prema mijenjanju +Zbijeno +Komentar +Enkripcija +Podjeli prije +Podjeli poslije +Rječnik + +Prema tipu +Anti +Način +Glavni OS +Sustav datoteka +Korisnik +Grupa +Zbijeno +Komentar +Pozicija +U datoteci +Mape +Datoteke +Inačica +Dio +Višedijelni +Razmak +Veza +Blokovi +Dijelova + +64-bitno +Big-endian +CPU +Fizička veličina +Veličina zaglavlja +Kontrolni zbroj +Karakteristike +Virtualna adresa +Jedinstvena oznaka +Kratko ime +Aplikacija stvaranja +Veličina sektora +Način +Poveznica +Greška +Ukupni kapacitet +Slobodni prostor +Veličina klastera +Naziv +Lokalni naziv +Pružatelj +NT sigurnost +Alternativni tok +Dodatno +Obrisano +Je stablo + + +Tip greške +Greške +Greške +Upozorenja +Upozorenje +Tokovi +Alternativni tokovi +Veličina alternativnih tokova +Virtualna veličina +Veličina raspakiranog +Ukupna fizička veličina +Indeks dijela +Podtip +Kratki komentar +Kodna stranica + + + +Veličina repa +Veličina ugrađenog odsječka +Poveznica +Čvrsta poveznica +iNode + +Samo za čitanje +2100 +Mogućnosti +Jezik +Jezik: +Uređivač +&Program za uređivanje: +Program za uspoređivanje: +2200 +Sustav +Poveži 7-Zip sa: +Svi korisnici +2301 +Integriraj 7-Zip u padajući kontekstni izbornik +Padajući kontekstni izbornik +Stavke kontekstnog izbornika: +Ikone kontekstnog izbornika +2320 + + +Otvori arhiv +Raspakiraj datoteke... +Dodaj u arhiv... +Testiraj arhiv +Raspakiraj ovdje +Raspakiraj u {0} +Dodaj u {0} +Sažimanje i slanje e-poštom +Sažimanje u {0} i slanje e-poštom +2400 +Mape +&Radna mapa +&Privremena sistemska mapa +&Trenutna +&Navedena: +Koristi samo za izmjenjive diskove +Lokaciju za smještaj privremenih datoteka. +2500 +Postavke +Nadmapa ".." +Prikaži prave ikone datoteka +Prikaži sistemski izbornik +&Označi cijeli redak +Prikaži &linije mreže +Jedan klik za otvaranje stavke +Drugi n&ačin označavanja +Koristi raspo&loživu memoriju +2900 +O 7-Zip-u +7-Zip je besplatan softver. +3000 +Sustav ne može pripremiti potrebnu količinu memorije +Nema grešaka +{0} objekt(a) izabrano +Ne mogu kreirati mapu '{0}' +Obnova nije podržana za ovaj arhiv. +Nemoguće otvoriti datoteku '{0}' kao arhiv +Nemoguće otvoriti kriptiranu arhivu '{0}'. Kriva lozinka? +Tip arhive nije podržan +Datoteka {0} već postoji +Datoteka '{0}' je izmijenjena.\nObnoviti arhiv? +Nije moguće obnoviti datoteku\n'{0}' +Nije moguće započeti uređivanje. +Datoteka izgleda kao virus (naziv datoteke sadrži dugačke razmake). +Operaciju nemoguće pozvati iz mape koja ima dugačku putanju. +Morate obilježiti jednu datoteku +Morate obilježiti jednu ili više datoteka +Previše stavki +Nemoguće otvoriti datoteku kao {0} arhivu +Datoteka je otvorena kao {0} arhiva +Arhiva je otvorena sa pomakom +3300 +Raspakiranje +Sažimanje u arhiv +Testiranje +Otvaranje u tijeku... +Skeniram... +Uklanjanje +3320 +Dodavanje +Ažuriranje +Analiziranje +Replikiranje +Repakiranje +Preskakanje +Brisanje +Stvaranje zaglavlja +3400 +Raspakiraj +&Raspakiraj u: +Lokacija za raspakiranje datoteka. +3410 +Putanja mapa: +Potpune putanje +Bez putanja +Apsolutne putanje +Relativne putanje +3420 +Natpiši postojeće +Pitaj prije natpisivanja postojećeg +Natpiši postojeće bez upozorenja +Preskoči postojeće datoteke +Automatska promjena naziva +Automatska promjena naziva postojećih datoteka +3430 +Eliminiraj dupliranje korijenske mape +Vrati sigurnost datoteka +3500 +Potvrdite zamjenu datoteka +Ciljana mapa već sadrži datoteku koja se trenutno obrađuje. +Zamijeniti postojeću +datoteku s ovom? +{0} bajte +A&utomatska promjena naziva +3700 +Nije podržan način sažimanja za '{0}'. +Podatkovna greška u '{0}'. Datoteka je neispravna. +CRC greška u '{0}'. Datoteka je neispravna. +Greška u kriptiranoj datoteci '{0}'. Kriva lozinka? +CRC greška u kriptiranoj datoteci '{0}'. Kriva lozinka? +3710 +Kriva lozinka? +3721 +Nepodržana metoda kompresije +Greška podataka +CRC neuspješan +Nedostupni podaci +Neočekivan kraj podataka +Postoji još podataka nakon glavnih podataka +Nije arhiva +Greška zaglavlja +Kriva lozinka +3763 +Neočekivan početak arhive +Nepotvrđen početak arhive + + + +Nepodržano svojstvo +3800 +Unesite lozinku +Unesite lozinku: +Ponovite lozinku: +&Prikaži lozinku +Lozinka nije jednaka +Koristite samo engleska slova, brojeve i specijalne znake (!, #, $, ...) za lozinku +Lozinka je preduga +&Lozinka +3900 +Utrošeno vrijeme: +Preostalo vrijeme: +Veličina: +Brzina: +Obrađeno: +Omjer kompresije: +Greške: +Arhive: +4000 +Dodaj u arhiv +&Arhiv: +&Način obnove: +&Format arhiva: +Stupanj sažimanja +&Metoda sažimanja: +Veličina &rječnika: +&Veličina riječi: +Veličina bloka u zbijenom: +Broj niti u CPU: +&Parametri: +&Mogućnosti +Kreiraj E&XE arhiv +Sažmi dijeljene datoteke +Kriptiranje +Metoda kriptiranja: +Enkripcija naziva datoteka +Korištenje memorije za sažimanje: +Korištenje memorije za raspakiranje: +Obriši datoteke nakon kompresije +4040 +Spremi simbolične poveznice +Spremi čvrste poveznice +Spremi alternativne tokove podataka +Spremi sigurnost datoteka +4050 +Bez sažimanja +Vrlo brzo +Brzo +Uobičajeno +Najjače +Ultra +4060 +Dodaj i zamjeni datoteke +Obnovi i dodaj datoteke +Osvježi postojeće datoteke +Sinkroniziraj datoteke +4070 +Traži +Sve datoteke +Bez-zbijanja +Zbijeno +6000 +Kopiraj +Premjesti +Kopiraj u: +Premjesti u: +Kopiranje u tijeku... +Premještanje u tijeku... +Preimenovanje u tijeku... +Odabir odredišne mape. +Operacija nije podržana. +Greška pri preimenovanju datoteke ili mape +Potvrdite kopiranje datoteka +Kopiranje datoteka u arhiv? +6100 +Potvrdite brisanje datoteke +Potvrdite brisanje mape +Potvrdite višestruko brisanje datoteka +Obrisati '{0}'? +Obrisati mapu '{0}' i sav njezin sadržaj? +Obrisati ove {0} podatke? +Brisanje u tijeku... +Greška pri brisanju datoteke ili mape +Sustav ne može premjestiti datoteku sa dugačkom putanjom u Kantu za recikliranje +6300 +Kreiraj mapu +Kreiraj datoteku +Naziv mape: +Naziv datoteke: +Nova mapa +Nova datoteka +Greška pri kreiranju mape +Greška pri kreiranju datoteka +6400 +Komentar +&Komentar: +Odaberi +Poništi odabir +Maska: +6600 +Svojstva +Kronologija mapa +Dijagnostičke poruke +Poruka +7100 +Računalo +Mreža +Dokumenti +Sustav +7200 +Dodaj +Raspakiraj +Testiraj +Kopiraj +Premjesti +Obriši +Svojstva +7300 +Podijeli datoteku +&Podijeli u: +Razdvajanje na dijelove, bajta: +Dioba... +Potvrdite diobu +Podijeliti datoteku u {0} dijelova? +Veličina diobenog dijela mora biti manja od izvorne datoteke +Netočna veličina bloka +Veličina bloka: {0} bajtova.\nJeste li sigurni da želite podijeliti u takve dijelove? +7400 +Spoji datoteke +&Spoji u: +Spajanje... +Označite samo prvu datoteku +Nije pronađena datoteka koja je dio razdijeljenih datoteka +Pronađena samo jedna datoteka od razdijeljenih datoteka +7500 +Izračunavanje kontrolnog zbroja... +Info kontrolni zbroj +CRC kontrolni zbroj za podatke: +CRC kontrolni zbroj za podatke i nazive: +7600 +Mjerenje +Korištenje memorije: +Sažimanje +Raspakiranje +Ocjena +Ukupna ocjena +Trenutno +Rezultat +CPU zauzeće +Ocjena / Zauzeće +Prolazi: +7700 +Poveznica +Poveznica +Veza od: +Veza do: +7710 +Tip poveznice +Čvrsta poveznica +Simbolična poveznica datoteka +Simbolična poveznica mapa +Mapa čvorišta diff --git a/Utils/7-Zip/Lang/hu.txt b/Utils/7-Zip/Lang/hu.txt new file mode 100644 index 000000000..b7b40ba94 --- /dev/null +++ b/Utils/7-Zip/Lang/hu.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Jozsef Tamas Herczeg +; 9.16 : Nyilas MISY +; +; +; +; +; +; +; +; +; +0 +7-Zip +Hungarian +Magyar +401 +OK +Mégsem + + + +&Igen +&Nem +&Bezárás +Súgó + +&Folytatás +440 +I&gen, mindre +N&em, mindre +Leállítás +Újraindítás +&Háttérben +&Előtérben +&Szünet +Szünet +Biztos, hogy megszakítja a folyamatot? +500 +&Fájl +S&zerkesztés +&Nézet +Ked&vencek +&Eszközök +&Súgó +540 +M&egnyitás +Megnyitás &belül +Megnyitás kí&vül +&Nézet +S&zerkesztés +Átn&evezés +Más&olás mappába... +Át&helyezés mappába... +&Törlés +Fájl&darabolás... +Fájl&egyesítés... +T&ulajdonságok +&Megjegyzés +Checksum számolása +Különbség +Mappa létrehozása +Fájl létrehozása +&Kilépés +600 +Min&d kijelölése +Kijelölés megszüntetése +Kijelölés &megfordítása +Kijelölés... +Megszüntetés... +Kijelölés típus alapján +Megszüntetés típus alapján +700 +&Nagy ikonok +&Kis ikonok +&Lista +&Részletek +730 +Rendezetlen +Lapos ikonok +&2 panel +&Eszköztárak +Gyökérmappa megnyitása +Egy szinttel feljebb +Mappa előzmények... +&Frissítés +750 +Archiválás eszköztár +Szokásos eszköztár +Nagy gombok +Szövegcímkék megjelenítése +800 +Mappa &hozzáadása a Kedvencekhez mint +Könyvjelző +900 +&Beállítások... +&Teljesítménymérés +960 +&Tartalomjegyzék... +7-Zip &névjegye... +1003 +Útvonal +Név +Kiterjesztés +Mappa +Méret +Tömörített méret +Attribútumok +Létrehozva +Hozzáférés +Módosítva +Tömör +Megjegyzés +Titkosított +Feldarabolás előtt +Feldarabolás után +Szótár +CRC +Típus +Anti +Módszer +Gazda OS +Fájlrendszer +Felhasználó +Csoport +Blokk +Megjegyzés +Pozíció +Útvonal előtag +Mappák +Fájlok +Verzió +Kötet +Többkötet +Eltolás +Linkek +Blokkok +Kötetek + +64-bit +Big-endian +CPU +Fizikai méret +Fejlécek mérete +Checksum +Karakterisztika +Virtuális cím +ID +Név rendezése +Alkalmazás készítője +Szakasz mérete +Mód +Link +Hiba +Teljes méret +Szabad terület +Kluszterméret +Címke +Helyi név +Szolgáltató +2100 +Beállítások +Nyelv +Nyelv: +Szerkesztő +&Szerkesztő: +&Különbség: +2200 +Rendszer +7-Zip társítása: +2301 +7-Zip hozzáadása a parancsértelmező helyi menüjéhez +Lépcsőzetes helyi menü +Helyi menü elemek: +2320 + + +Archívum megnyitása +Fájlok kibontása... +Hozzáad az archívumhoz... +Archívum tesztelése +Kibontás ide +Kibontás ide: {0} +Hozzáadás: {0} +Tömörítés és küldés... +Tömörítés {0} archívumba és küldés +2400 +Mappák +&Munkamappa +A &rendszer ideiglenes mappája +&Jelenlegi +&Meghatározott: +Csak cserélhető meghajtókhoz +Válassza ki az ideiglenes archív fájlok mappáját. +2500 +Beállítások +A ".." elem látható +Az eredeti fájlikonok láthatók +Látható a rendszermenü +&Teljes soros kijelölés +&Rácsvonalak kijelzése +Elem megnyitása egyszeres kattintással +&Alternativ kiválasztási mód +&Nagy memória haszálata +2900 +A 7-Zip névjegye +A 7-Zip ingyenes szoftver. Ha elnyerte a tetszését, s mégis szeretné támogatni a további fejlesztését, regisztrálja 20 USD áron, fizethet hitelkártyával vagy más módon. +3000 +A rendszer nem tudja lefoglalni a szükséges memóriát +Az archívum hibamentes +{0} objektum kijelölve +A(z) '{0}' mappát nem lehet létrehozni +Az aktualizálás ennél az archívumtípusnál nem támogatott. +A(z) '{0}' fájl nem nyitható meg archívként +A(z) '{0}' titkosított archívum nem megnyitható. Hibás a jelszó? +Nem támogatott archívum típus +A(z) {0} fájl már létezik +'{0}'\nA fájl tartalma megváltozott.\nKívánja aktualizálni az archívumban? +A fájl nem aktualizálható:\n'{0}' +A szerkesztő nem indítható. +A fájl vírusnak néz ki (a fájlnév hosszú szóközt tartalmaz a nevében). +A művelet nem hívható meg abból a mappából amelynek hosszú az elérési útvonala. +Egy fájlt ki kell jelölnie! +Egy vagy több fájlt ki kell jelölnie +Túl sok elem +3300 +Kibontás +Tömörítés +Tesztelés +Megnyitás... +Vizsgálat... +3400 +Kibontás +&Kibontás ide: +Határozza meg a kibontott fájlok tárolómappáját. +3410 +Útvonal +Teljes útvonal +Nincs útvonal +3420 +Felülírás +Rákérdezés felülírás előtt +Felülírás rákérdezés nélkül +A létező fájlok kihagyása +Automatikus átnevezés +A létező fájlok automatikus átnevezése +3500 +Fájlcsere megerősítése +A célmappa már tartalmazza a feldolgozott fájlt. +Kívánja lecserélni a létező fájlt +ezzel a fájllal? +{0} bájt +A&utomatikus átnevezés +3700 +A(z) '{0}' tömörítési módja nem támogatott. +Adathiba a következőben: '{0}'. A fájl sérült. +CRC-hiba a következőben: '{0}'. A fájl sérült. +Adathiba a titkosított fájlban: '{0}'. Hibás a jelszó? +CRC-hiba a titkosított fájlban: '{0}'. Hibás a jelszó? +3800 +Jelszó beírása +Írja be a jelszót: +Jelszó újbóli beírása: +A &jelszó megjelenítése +Jelszavak nem egyeznek +Csak ékezetmentes karaktereket, számokat és speciális karaktereket (!, #, $, ...) használjon a jelszavaknak +A jelszó túl hosszú +Jelszó +3900 +Eltelt idő: +Hátralévő idő: +Méret: +Sebesség: +Feldolgozott: +Tömörítési arány: +Hibák: +Archívumok: +4000 +Behelyezés archívumba +&Archívum: +Akt&ualizálás módja: +Arcíhvum &formátuma: +Tömörítés &foka: +Tömörítés &módja: +&Címtár mérete: +&Szó mérete: +Tömör blokk méret: +CPU számok: +&Tulajdonságok: +Beállítások +SF&X archívum létrehozása +Megosztott fájlok tömörítése +Titkosítás +Titkosítási eljárás: +Fájlnevek &titkosítása +A tömörítés memóriahasználata: +A kitömörítés memóriahasználata: +4050 +Raktár +Leggyorsabb +Gyors +Normál +Legnagyobb +Ultra +4060 +Fájlok behelyezése és cseréje +Fájlok aktualizálása és behelyezése +Létező fájlok frissítése +Fájlok szinkronizálása +4070 +Tallózás +Minden fájl +Nem tömör +Tömör +6000 +Másolás +Áthelyezés +Másolás ide: +Áthelyezés ide: +Másolás... +Áthelyezés... +Átnevezés... +Válassza ki a cél mappát. +A művelet nem támogatott. +Hiba történt a fájl vagy a mappa átnevezésekor +Fájl másolásának megerősítése +Biztos, hogy fájl(oka)t akar másolni az archívumba? +6100 +Fájltörlés megerősítése +Mappatörlés megerősítése +Több fájltörlés megerősítése +Biztos, hogy törölni akarja a következőt: '{0}'? +Biztos, hogy törölni akarja a(z) '{0}' mappát és annak teljes tartalmát? +Biztos, hogy törölni akarja ezt a(z) {0} elemet? +Törlés... +Hiba történt a fájl vagy a mappa törlésekor +A rendszer nembírja mozgatni a fájlt a hosszú útvonallal a Lomtárba +6300 +Mappa létrehozása +Fájl létrehozása +Mappa neve: +Fájlnév: +Új mappa +Új fájl +Hiba történt a mappa létrehozásakor +Hiba történt a fájl létrehozásakor +6400 +Megjegyzés +&Megjegyzés: +Kijelölés +Megszüntetés +Maszk: +6600 +Tulajdonságok +Mappa előzmények +Diagnosztikai üzenetek +Üzenet +7100 +Sajátgép +Hálózati helyek +Dokumentumok +Rendszer +7200 +Hozzáadás +Kibontás +Teszt +Másolás +Áthelyezés +Törlés +Tulajdonságok +7300 +Fájldarabolás +&Darabolás ide: +Darabolás &kötetekre, bájt: +Darabolás... +Darabolás megerősítése +Biztos szét akarja darabolni a fájlt {0} kötetre? +Kötet méretének kissebbnek kell lennie, mint az eredeti fájl mérete +Hibás kötet méret +A megadott kötet mérete: {0} byte.\nBiztos fel akarja darabolni az archívumot ilyen kötetre? +7400 +Fájlegyesítés +&Egyesítés ide: +Egyesítés... +Csak az első rész kiválasztása a darabolt fájlból +Nem ismeri fel a fájlt, mint darabolt fájl része +Nem talál egynél több részt a darabolt fájlból +7500 +Leírás számolása... +Leírás információ +CRC leírás az adathoz: +CRC leírás az adathoz és névhez: +7600 +Teljesítménymérés +Memóriahasználat: +Tömörítés +Kitömörítés +Értékelés +Összértékelés +Jelenlegi +Eredmény +CPU használata +Becslés / Használat +Menetek: diff --git a/Utils/7-Zip/Lang/hy.txt b/Utils/7-Zip/Lang/hy.txt new file mode 100644 index 000000000..343d0284a --- /dev/null +++ b/Utils/7-Zip/Lang/hy.txt @@ -0,0 +1,501 @@ +;!@Lang2@!UTF-8! +; : Gevorg Papikyan +; 15.00 : Hrant Ohanyan : http://haysoft.org +; +; +; +; +; +; +; +; +; +0 +7-Zip +Armenian +Հայերեն +401 +ԼԱՎ +Չեղարկել + + + +&Այո +&Ոչ +&Փակել +Օգնություն + +&Շարունակել +440 +Այո բոլորի &համար +Ոչ բոլորի &համար +Կանգնեցնել +Վերսկսել +&Խորապատկերում +&Առջևում +&Դադար +Դադարի մեջ է +Ընդհատե՞լ +500 +&Ֆայլ +&Խմբագրել +&Տեսք +&Ընտրյալներ +Գ&ործիքներ +&Օգնություն +540 +&Բացել +Բացել &ներսում +Բացել դրս&ում +Ընտրել +&Խմբագրել +Վեր&անվանել +&Պատճենել... +&Տեղափոխել... +&Ջնջել +Տրոհել& ֆայլը... +Հ&ամակցել ֆայլը... +Հատկու&թյուններ +Մեկնաբա&նություններ +Հանրագումար +Համեմատել +&Ստեղծել թղթապանակ +Ստեղ&ծել ֆայլ +Փակ&ել +Հղում +&Այլընտրանքային հոսքեր +600 +Նշել &բոլորը +Ապանշել +&Ետարկել ն&շումը +Նշել... +Ապանշել... +Նշել ըստ տեսակի +Ապանշել ըստ տեսակի +700 +&Մեծ պատկերակներով +&Փոքր պատկերակներով +Ցուց&ակ +&Աղյուսակ +730 +Առանց դասավորելու +Հարթ եղանակ +&2 վահանակ +&Գործիքների վահանակ +Բացել արմատային թղթապանակը +Մեկ մակարդակ վերև +Թղթապանակների պատմությունը... +Թ&արմացնել +Ինքնաթարմացում +750 +Ծրագրի կոճակների վահանակ +Կոճակների ստանդարտ վահանակ +Մեծ կոճակներով +Կոճակների անունը +800 +Ավելացնել թղթապանակը &ընտրյալներին որպես +Էջանիշ +900 +Կարգավորումներ... +Արտադրողականության թեստ +960 +&Բովանդակություն... +Ծրագրի &մասին... +1003 +Ուղի +Անուն +Ընդլայնում +Թղթապանակ +Չափ +Սեղմած +Հատկություններ +Ստեղծվել է +Մուտք +Փոփոխվել է +Անընդհատ +Մեկնաբանություններ +Կոդավորված է +Տրոհված է մինչ +Տրոհված է հետո +Բառարան + +Տեսակ +Հակա +Մեթոդ +Համակարգ +Ֆայլային համակարգ +Օգտվող +Խումբ +Կողպում +Մեկնաբանություններ +Դիրք +Ուղի +Թղթապանակներ +Ֆայլեր +Տարբերակ +Հատոր +Բազմահատոր +Շեղում +Հղումներ +Հատվածներ +Հատորներ + + + +CPU +Ֆիզիկական չափը +Գլխագրերի չափը +Արդյունքը +Բնութագրություններ +Վիրտուալ հասցե + +Կարճ անուն +Ստեղծող +Հատվածի չափ +Եղանակ +Նշանային հղում +Սխալ +Ծավալ +Ազատ է +Կլաստերի չափ +Տառ +Տեղային անուն +Մատակարար +Անվտանգություն +Այլընտրանքային հոսք + +Հեռակա +Ծառ + + +Սխալի տեսակ +Սխալներ +Սխալներ +Զգուշացում +Զգուշացումներ +Հոսքեր +Այլընտրանքային հոսքեր +Այլընտրանքային հոսքերի չափ +Վիրտուալ չափը +Բացված չափը +Ընդհանուր ֆիզիկական չափը +Հատորի համարը +Ենթատեսակ +Կարճ մեկնաբանություն +Կոդային էջ + + + +Մնացորդի չափը +Ներկառուցված հատվածի չափը +Հղում +Կոշտ հղում +iNode + +Միայն կարդալու + + + + + + +2100 +Կարգավորումներ +Լեզուն +Լեզուն. +Խմբագիր +&Խմբագիր +&Համեմատելու ծրագիր. +2200 +Համակարգը +Ասոցիացնել 7-Zip-ը հետևյալ ֆայլերի հետ՝ +Բոլոր օգտվողները +2301 +Ներդնել 7-Zip-ը համատեքստային ցանկում +Կասկադային ցանկ +Համատեքստային ցանկի բաղադրիչները +Պատկերակներ համատեքստային ցանկում +2320 +«Թղթապանակ» +«Արխիվ» +Բացել արխիվը +Դուրս բերել +Ավելացնել արխիվի... +Թեստավորել +Դուրս բերել այստեղ +Դուրս բերել{0}-ում +Ավելացնել {0}-ին +Սեղմել և ուղարկել էլ. փոստով... +Սեղմել {0}-ում և ուղարկել էլ. փոստով +2400 +Թղթապանակներ +&Աշխատանքային թղթապանակ +&Համակարգային ժամանակավոր թղթապանակ +&Ընթացիկ +&Նշանակել. +Օգտագործել միայն շարժական կրիչների համար +Նշեք ժամանակավոր արխիվների համար տեղ +2500 +Կարգավորումներ +Ցուցադրել բաղադրիչը ".." +Ցուցադրել ֆայլերի իրական պատկերները +Ցուցադրել համակարգային ցանկը +Կուրսորը ամբողջ տողով +Ցուցադրել բաժանարարներ +Բացել մեկ սեղմամբ +Նշելու այլընտրանքային եղանակ +Օգտագործել հիշողության մեծ ծավալներ +2900 +7-Zip-ի մասին +7-Zip-ը ազատ տարածվող ծրագիր է: +3000 +Չկա ազատ տեղ +Սխալներ չկան +Ընտրված են {0} ֆայլեր +Հնարավոր չէ ստեղծել '{0}' թղթապանակը: +Փոփոխման գործողությունը այս արխիվը չի աջակցում: +Հնարավոր չէ բացել '{0}' ֆայլը որպես արխիվ +Հնարավոր չէ բացել '{0}' կողփած արխիվը: Մուտքագրեք գաղտնաբառը: +Արխիվի տեսակը չի աջակցվում +{0} ֆայլը արդեն գոյություն ունի +'{0}' ֆայլը փոփոխվել է:\n Թարմացնե՞լ այն արխիվում: +Հնարավոր չէ թարմացնել ֆայլը \n'{0}' +Հնարավոր չէ բացել խմբագիրը: +Ֆայլը նման է վիրուսի: +Գործողությունը չի կարող կատարվել այն թղթապանակից, որը ունի երկար ճանապարհ: +Ընտրեք գոնե մեկ ֆայլ +Ընտրեք գոնե մեկ կամ մի քանի ֆայլեր +Բաղադրիչները շատ են +Հնարավոր չեղավ բացել ֆայլը որպես {0} արխիվ +Ֆայլը բացվել է որպես {0} արխիվ +Ֆայլը բացվել է շեղումով +3300 +Դուրս է բերվում +Սեղմվում է +Թեստավորվում է +Բացվում է... +Տեսածրում... +Ջնջում +3320 +Ավելացվում է +Թարմացվում է +Վերլուծում +Պատճենվում է +Վերափաթեթավորում +Բաց է թողնվում +Ջնջում +Գլխագրերի ստեղծում +3400 +Դուրս բերել +&Դուրս բերել՝ +Նշեք հանվող ֆայլերի տեղադրությունը: +3410 +Ֆայլերի ուղին. +Ամբողջական& ուղիներ +&Առանց ուղիների +Բացարձակ ուղիներ +Հարաբերական ուղիներ +3420 +Վերագրանցում +Հաստատումով +Առանց հաստատման +Բաց թողնել +Վերանվանել +Վերանվանել գոյություն ունեցողները +3430 +Վերացնել արմատային թղթ. կրկնօրինակումը +Վերացնել մուտքի թույլտվությունը +3500 +Հաստատեք ֆայլի փոխարինումը +Թղթապանակում արդեն կա մշակված ֆայլ: +Փոխարինե՞լ առկա ֆայլը +տվյալ ֆայլով: +{0} բայթ +Վերանվանել ինք. +3700 +'{0}' ֆայլը սեղմելու եղանակը չի աջակցվում +Տվյալների սխալ'{0}'-ում: Ֆայլը վնասված է: +CRC սխալ'{0}'-ում: Ֆայլը վնասված է: +Սխալ՝ '{0}' ֆայլի կոդավորման տվյալներում: Գաղտնաբառը սխա՞լ է: +CRC սխալ '{0}' կոդավորված ֆայլի համար: Գաղտնաբառը սխա՞լ է: +3710 +Գաղտնաբառը սխա՞լ է +3721 +Սեղմելու չաջակցվող եղանակ +Սխալ տվյալներում +CRC սխալ +Անհասանելի տվյալներ +Տվյալների անսպասելի ավարտ +Կան տվյալներ՝ օգտակար տվյալների հատվածի վերջում +Արխիվ չէ +Սխալ գլխագրերում +Գաղտնաբառը սխալ է +3763 +Արխիվի անընդունելի սկիզբ +Արխիվի չհաստատված սկիզբ + + + +Չաջակցվող յուրահատկություն +3800 +Մուտքագրել գաղտնաբառ +&Մուտքագրել գաղտնաբառ. +Կրկնել գաղտնաբառը. +&Ցուցադրել գաղտնաբառը +Գաղտնաբառը չի համապատասխանում +Գաղտնաբառի համար օգտագործեք միայն լատիներեն տառեր, թվեր և հատուկ նշաններ (!, #, $, ...) +Գաղտնաբառը չափազանց երկար է +&Գաղտնաբառը. +3900 +Անցել է. +Մնացել է. +Չափ. +Արագություն. +Ընթացք. +Սեղմելու աստիճան +Սխալներ. +Արխիվներ. +4000 +Ավելացնել արխիվի +&Արխիվ. +&Փոփոխման կարգը. +&Արխիվի տեսակը. +&Սեղմելու աստիճանը. +&Սեղմելու մեթոդը. +Բառարանի &չափը. +Բառի չ&ափը. +Հատվածի չափը. +CPU հոսքերի քանակը. +&Ցուցիչներ. +&Ընտրանքներ +Ստեղծել SF&X արխիվ +Սեղմել համաօգտագործվող ֆայլերը +Կոդավորում +Կոդավորման եղանակ. +&Կոդավորել ֆայլերի անունները +Հիշող. ծավալը սեղմելու համար. +Հիշող. ծավալը դուրս բերելու համար. +Սեղմելուց հետո ջնջել ֆայլերը +4040 +Պահպանել նշանային հղումները +Պահպանել կոշտ հղումները +Պահպանել այլընտրանքային հոսքերը +Պահպանել մուտքի իրավունքը +4050 +Առանց սեղմելու +Արագընթաց +Արագ +Նորմալ +Առավելագույն +Ուլտրա +4060 +Ավելացնել և փոխարինել +Թարմացնել և ավելացնել +Թարմացնել +Համաժամեցնել +4070 +Թերթել +Բոլոր ֆայլերը +Ֆայլի չափով +Անդադար +6000 +Պատճենել +Տեղափոխել +Պատճենել՝ +Տեղափոխել՝ +Պատճենվում է... +Տեղափոխվում է... +Վերանվանվում է... +Ընտրել թղթապանակ +Գործողությունը չի աջակցվում +Սխալ` ֆայլը կամ թղթապանակը անվանափոխելիս: +Հաստատեք ֆայլերի պատճենումը +Պատճենե՞լ այս ֆայլերը արխիվի մեջ: +6100 +Հաստատել ֆայլի ջնջումը +Հաստատել թղթապանակի ջնջումը +Հաստատել ֆայլերի ջնջումը +Իրո՞ք ցանկանում եք ջնջել "{0}"-ը: +Իրո՞ք ցանկանում եք ջնջել "{0}" թղթապանակը և նրա պարունակությունը: +Իրո՞ք ցանկանում եք ջնջել ({0} հատ) ֆայլերը: +Ջնջում է... +Սխալ` ֆայլը կամ թղթապանակը ջնջելիս: +Հնարավոր չէ Աղբարկղ տեղափոխել երկար անուններով ֆայլեր: +6300 +Ստեղծել թղթապանակ +Ստեղծել ֆայլ +Թղթապանակի անունը. +Ֆայլի անունը. +Նոր թղթապանակ +Նոր ֆայլ +Սխալ` թղթապանակ ստեղծելիս +Սխալ` ֆայլ ստեղծելիս +6400 +Մեկնաբանություններ +&Մեկնաբանություններ +Նշել +Ապանշել +Դիմակ. +6600 +Հատկություններ +Թղթապանակների պատմությունը +Հաղորդագրություն +Հաղորդագրություն +7100 +Համակարգիչ +Ցանց +Փաստաթղթեր +Համակարգ +7200 +Ավելացնել +Դուրս բերել +Թեստավորել +Պատճենել +Տեղափոխել +Ջնջել +Տեղեկություն +7300 +Տրոհել ֆայլը +&Տրոհել՝ +Տրոհել &մասերի (բայթերով)` +Տրոհում... +Հաստատեք տրոհումը +Իրո˚ք տրոհել ֆայլը {0} հատորների +Հատորի չափը պետք է փոքր լինի ընթացիկ ֆայլի չափից +Գործողության սխալ +Հատորի նշված չափը. {0} բայթ:\nՏրոհե˚լ արխիվը հատորների: +7400 +Համակցել ֆայլը +&Համակցել. +Համակցում... +Ընտրել տրոհված ֆայլի միայն առաջին մասը +Հնարավոր չեղավ ճանաչել տրոհված ֆայլը +Հնարավոր չեղավ գտնել տրոհված ֆայլի մասերը +7500 +Checksum-ի որոշում... +Checksum +CRC checksum ֆայլերի համար. +CRC checksum ֆայլերի և անունների համար. +7600 +Արտադրողականության թեստ +Հիշողության ծավալը. +Սեղմել +Դուրս բերել +Վարկանիշ +Ընդհանուր վարկանիշը +Ընթացիկը +Ավարտուն արդյունքը +CPU-ի օգտ-ը +Վարկ./Օգտ. +Անցումներ. +7700 +Հղում +Կապել +Աղբյուր. +Նպատակ. +7710 +Հղման տեսակ +Կոշտ հղում +Նշանային հղում (ֆայլ) +Նշանային հղում (թղթապանակ) +Միացման կետ (Junction) diff --git a/Utils/7-Zip/Lang/id.txt b/Utils/7-Zip/Lang/id.txt new file mode 100644 index 000000000..c4fc1b78b --- /dev/null +++ b/Utils/7-Zip/Lang/id.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.14 : 02/01/2016 : Frans Liando +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Indonesian +Bahasa Indonesia +401 +Oke +Batal + + + +&Ya +&Tidak +&Tutup +Bantuan + +&Lanjut +440 +Ya untuk &semua +Tidak untuk s&emua +Henti +Mulai Ulang +Latar Bela&kang +Latar &Depan +&Jeda +Terjeda +Anda yakin ingin batal? +500 +&Berkas +&Edit +Tam&pilan +&Kesukaan +Pera&latan +Ban&tuan +540 +&Buka +Buka Sisi &Dalam +Buka Sisi L&uar +&Tampilkan +&Edit +&Nama Ulang +&Salin Ke... +P&indahkan Ke... +&Hapus +Be&lah Berkas... +Gabun&g Berkas... +P&roperti +K&omentari +Hitung ceksum +Beda +Buat Direktori +Buat Berkas +&Keluar +Tautan +Alternati&f Aliran +600 +Pi&lih Semua +Batal Pilih Semua +Pilih Sebal&iknya +Pilih... +Batal Pilih... +Pilih Berdasarkan Tipe +Batal Pilih Berdasarkan Tipe +700 +Ikon &Besar +Ikon &Kecil +&Daftar +&Rincian +730 +Tidak Berurutan +Tampilan Datar +&2 Panel +Bilah Ala&t +Buka Akar Direktori +Naik Satu Tingkat +Riwayat Direktori... +&Segarkan +Segarkan Otomatis +750 +Bilah Alat Arsip +Bilah Ala&t Standar +Tombol Besar +Perlihatkan Teks Tombol +800 +Tambah direktori ke Favorit sebagai +Markah +900 +&Pilihan... +&Tolok Ukur +960 +Petun&juk... +Mengen&ai 7-Zip... +1003 +Lintasan +Nama +Ekstensi +Direktori +Ukuran +Ukuran dipak +Atribut +Dibuat +Diakses +Dimodifikasi +Padat +Dikomentari +Dienkripsi +Belah Sebelum +Belah Setelah +Kamus + +Tipe +Anti +Metode +SO Host +Sistem Berkas +Pengguna +Grup +Blok +Komentar +Posisi +Awalan Lintasan +Direktori +Berkas +Versi +Volume +Multivolume +Gelinciran +Tautan +Blok +Volume + +64-bit +Big-endian +CPU +Ukuran Fisik +Ukuran Tajuk +Ceksum +Karakteristik +Alamat Maya +ID +Nama Singkat +Aplikasi Pembuat +Ukuran Sektor +Ragam +Tautan Simbolik +Kesalahan +Ukuran Total +Ruang Kosong +Ukuran Gugus +Label +Nama Lokal +Penyelenggara +Keamanan NT +Alternatif ALiran +Aux +Dihapus +Apakah Pohon + + +Tipe Kesalahan +Kesalahan +Kesalahan +Peringatan +Peringatan +Aliran +Alternatif Aliran +Ukuran Alternatif Aliran +Ukuran Maya +Ukuran Terbongkar +Jumlah Ukuran Fisik +Indeks Volume +SubTipe +Komentar Singkat +Laman Kode + + + +Ukuran Ujung +Ukuran Rintisan Tertanam +Tautan +Tautan Keras +iNode + +Hanya-baca +2100 +Pilihan +Bahasa +Bahasa: +Editor +&Editor: +Be&da: +2200 +Sistem +Asosiasikan 7-Zip dengan: +Semua pengguna +2301 +Integrasikan 7-Zip ke cangkang menu konteks +Menu konteks dikaskade +Butir-butir menu konteks: +Ikon-ikon di menu konteks +2320 + + +Buka arsip +Ekstrak berkas... +Tambah ke arsip... +Uji arsip +Ekstrak di sini +Ekstrak ke {0} +Tambah ke {0} +Mampat dan surat kawat... +Mampat ke {0} dan surat kawat +2400 +Direktori +&Direktori kerja +Direktori temporer &sistem +S&ekarang +&Ditentukan: +Hanya untuk kandar yang dapat dilepas +Tetapkan lokasi untuk berkas arsip sementara. +2500 +Pengaturan +Perlihatkan butir ".." +Perlihatkan ikon asli berkas +Perlihatkan menu sistem +&Memilih baris penuh +Perlihatkan &garis kisi-kisi +Klik-tunggal untuk membuka +Ragam pemilihan &alternatif +Gunakan halaman memori &besar +2900 +Mengenai 7-Zip +7-Zip merupakan perangkat lunak gratis.\n\nTerjemahan oleh Frans Liando. +3000 +Sistem tidak bisa mengalokasikan jumlah memori yang diperlukan +Tidak ada kesalahan +{0} objek terpilih +Tidak bisa membuat Direktori '{0}' +Operasi pembaruan tidaklah didukung untuk arsip ini. +Tidak bisa membuka berkas arsip '{0}' +Tidak bisa membuka arsip terenkripsi '{0}'. Salah kata sandi? +Tipe arsip tidak didukung +Berkas {0} telah ada +Berkas '{0}' telah termodifikasi.\nApakah Anda ingin perbarui berkas dalam arsip? +Tidak bisa perbarui berkas\n'{0}' +Tidak bisa memulai editor. +Berkas ini tampaknya seperti virus (pada nama berkas berisi spasi yang panjang). +Pengoperasian tidak bisa dipanggil dari direktori yang berlintasan panjang. +Anda harus pilih satu berkas +Anda harus pilih satu berkas atau lebih +Terlalu banyak butir +Tidak bisa buka berkas sebagai arsip {0} +Berkas dibuka sebagai arsip {0} +Berkas dibuka dengan gelinciran +3300 +Mengekstrak +Pemampatan +Pengujian +Membuka... +Memindai... +Memindah +3320 +Menambah +Memperbarui +Menganalisa +Mereplikasi +Pak ulang +Melewatkan +Menghapus +Membuat tajuk +3400 +Ekstrak +E&kstrak ke: +Tetapkan lokasi untuk berkas yang diekstrak. +3410 +Ragam lintasan: +Nama lengkap lintasan +Tidak ada nama lintasan +Nama lintasan absolut +Nama lintasan relatif +3420 +Ragam tulis timpa: +Konfirmasikan sebelum tulis timpa +Tulis timpa tanpa konfirmasi +Lewati berkas yang ada +Penamaan ulang automatis +Penamaan ulang automatis terhadap berkas yang ada +3430 +Hilangkan duplikasi direktori akar +Pulihkan keamanan berkas +3500 +Konfirmasi Penggantian Berkas +Direktori tujuan telah berisi berkas yang terproses. +Maukah Anda mengganti berkas yang ada +dengan yang satu ini? +{0} bita +Nama &Ulang Automatis +3700 +Metode mampat untuk '{0}' tidak didukung. +Kesalahan data di '{0}'. Berkas ini rusak. +CRC gagal di '{0}'. Berkas ini rusak. +Kesalahan data di berkas terenkripsi '{0}'. Salah kata sandi? +CRC gagal di berkas terenkripsi '{0}'. Salah kata sandi? +3710 +Salah kata sandi? +3721 +Metode mampat tidak didukung +Kesalahan data +CRC gagal +Data tidak tersedia +Akhir data tidak terduga +Terdapat suatu data setelah akhir muatan data +Bukan arsip +Kesalahan Tajuk +Salah kata sandi +3763 +Awal arsip belum tersedia +Awal arsip belum dikonfirmasi + + + +Fitur tidak didukung +3800 +Masukkan kata sandi +Masukkan kata sandi: +Konfirmasi kata sandi: +&Perlihatkan kata sandi +Kata sandi tidak cocok +Gunakanlah hanya huruf bahasa Indonesia, nomor dan karakter khusus (!, #, $, ...) untuk kata sandi +Kata sandi terlalu panjang +Kata sandi +3900 +Waktu terpakai: +Sisa waktu: +Jumlah ukuran: +Kecepatan: +Terproses: +Rasio mampat: +Kesalahan: +Arsip: +4000 +Tambah ke arsip +&Arsip: +Ragam perbar&u: +&Format arsip: +&Level mampat: +&Metode mampat: +Ukuran &kamus: +Ukuran ka&ta: +Ukuran blok padat: +Jumlah CPU: +&Parameter: +Pilihan +Buat arsip SF&X +Kompres berkas bersama +Enkripsi +Metode enkripsi: +Enkripsi &nama berkas +Pemakaian memori untuk Pemampatan: +Pemakaian memori untuk Pengawamampatan: +Hapus berkas setelah dimampatkan +4040 +Simpan tautan simbolik +Simpan tautan keras +Simpan alternatif aliran data +Simpan keamanan berkas +4050 +Simpan +Tercepat +Cepat +Normal +Maksimum +Ultra +4060 +Tambah dan ganti berkas +Perbarui dan tambah berkas +Segarkan ulang berkas yang ada +Sinkronisasikan berkas +4070 +Ramban +Semua Berkas +Non-padat +Padat +6000 +Salin +Pindah +Salin ke: +Pindah ke: +Menyalin... +Memindah... +Penamaan Ulang... +Pilih direktori tujuan. +Pengoperasian tidak didukung untuk direktori demikian. +Kesalahan Penamaan Ulang Berkas atau Direktori +Konfirmasi Salin Berkas +Anda yakin ingin menyalin berkas ke arsip? +6100 +Konfirmasi Hapus Berkas +Konfirmasi Hapus Direktori +Konfirmasi Hapus Berkas-berkas +Anda yakin ingin hapus '{0}'? +Anda yakin ingin hapus direktori '{0}' dan semua isinya? +Anda yakin ingin hapus {0} butir? +Menghapus... +Kesalahan Penghapusan Berkas atau Direktori +Sistem tidak bisa memindah suatu berkas yang berlintasan panjang ke Recycle Bin +6300 +Buat Direktori +Buat Berkas +Nama Direktori: +Nama berkas: +Direktori Baru +Berkas Baru +Kesalahan Membuat Direktori +Kesalahan Pembuatan Berkas +6400 +Komentar +&Komentari: +Pilih +Tidak Memilih +Masker: +6600 +Properti +Riwayat Direktori +Pesan Diagnosa +Pesan +7100 +Komputer +Jaringan +Dokumen +Sistem +7200 +Tambah +Ekstrak +Uji +Salin +Pindah +Hapus +Info +7300 +Belah Berkas +&Belah ke: +Belah ke &volume, bita: +Membelah... +Konfirmasi Membelah +Anda yakin ingin membelah berkas menjadi {0} volume? +Ukuran volume seharusnya lebih kecil dari pada ukuran asli berkas +Ukuran volume salah +Tentukan ukuran volume: {0} bita.\nAnda Yakin ingin membelah arsip menjadi volume demikian? +7400 +Gabung Berkas +&Gabung ke: +Menggabung... +Pilih bagian pertama saja dari berkas belahan +Tidak bisa mendeteksi berkas sebagai bagian berkas belahan +Tidak bisa menemukan lebih dari satu bagian berkas belahan +7500 +Hitung ceksum... +Informasi ceksum +Ceksum CRC untuk data: +Ceksum CRC untuk data dan nama: +7600 +Tolok Ukur +Pemakaian memori: +Pemampatan +Pengawamampatan +Penilaian +Jumlah Penilaian +Sekarang +Hasil +Pemakaian CPU +Penilaian/Pemakaian +Lulus: +7700 +Tautan +Tautan +Tautan dari: +Tautan ke: +7710 +Tipe Tautan +Tautan Keras +Berkas Tautan Simbolik +Direktori Tautan Simbolik +Cabang Direktori diff --git a/Utils/7-Zip/Lang/io.txt b/Utils/7-Zip/Lang/io.txt new file mode 100644 index 000000000..ccc4f6c91 --- /dev/null +++ b/Utils/7-Zip/Lang/io.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.08 : iZoom +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Ido +Ido +401 +B&one +Abandonar + + + +&Yes +&No +&Klozez +Helpo + +&Durez +440 +Yes por &omni +No por o&mni +Haltez +Ristartez +&Fono +&Avanajo +&Pauzo +Pauzita +Kad vu ya volas abortar? +500 +&Dosiero +&Redakto +&Aspekto +&Favoraji +&Utensili +&Helpo +540 +&Apertigar +Apertigar int&erne +Apertigar e&xter +&Vidigar +&Redaktar +Ch&anjar nomo +Ko&piar aden... +Transp&ozar aden... +E&facar +F&endar dosiero... +Komb&inar dosieri... +In&heraji +Ko&mentar + + +Krear &dosieruyo +Krear dos&iero +E&kirar +600 +Merk&ar omno +Des&merkar omno +&Inversigar merko +Merkar... +Desmerkar... +Merkar segun tipo +Desmerkar segun tipo +700 +&Granda ikoneti +&Mikra ikoneti +&Listo +&Tabelo +730 +&Nearanjite + +&2 paneli +Utens&ila paneli +Apertigar radika dosieruyo +Ad-supre ye un nivelo +Dosieruya historio... +R&inovigar +750 +Utensila panelo di arkivo +Norma utensila panelo +Granda ikoneti +Videbla butontexto +800 +&Adjuntar dosieruyo ad la favorata quale +Lektomerkajo +900 +&Ajusti... +&Experienco dil rapideso +960 +&Konteno... +&Pri 7-Zip... +1003 +Dosiervoyo +Nomo +Dosiernoma sufixo +Dosieruyo +Grandeso +Enarkiva grandeso +Atributi +Kreita +Acesita +Chanjita +Solida +Komentita +Chifrita +Fendita ante +Fendita pos +Vortaro +CRC +Tipo +Kontre +Metodo +Operacala sistemo +Dosiersistemo +Uzero +Grupo +Bloko +Komenturo +Poziciono + + + + + + + + + + + + + + + + + + + + + + + + + +Eroro +Tota kapacivo +Vakanta +Faskogrando +Etiketo +Lokala nomo +Provizanto +2100 +Ajusti +Linguo +Linguo: +Redaktilo +&Redaktilo: + +2200 +Sistemo +Asociar 7-Zip-o kun dosieru: +2301 +Pozar 7-Zip'o en kuntexta menuo di shelo +Kaskada kuntexta menuo +Elementi di kuntexta menuo: +2320 + + +Apertar +Extraktar dosieri... +Adjuntar ad arkivo... +Verifikar arkivo +Extraktez hike +Extraktez aden {0} +Adjuntar ad {0} +Enarkivigar ed sendar elk-posto... +Enarkivigar aden {0} e sendar elk-posto... +2400 +Dosieruyi +&Laborala dosieruyo +&Sistemala provizora dosieruyo +&Nuna +&Definez: +&Uzar nur por deprenebla datumportili +Definar loko por provizora arkiva dosieri. +2500 +Ajusti +Montrar ".."-elemento +Montrar reala dosier-ikoneti +Montrar sistemala menuo +Merkar &tota lineo +Montrar &streki separanta + + + +2900 +Pri progamo... +7-Zip esas gratuita programo. Tamen, vu povas mantenar developado di 7-Zip per enregistrigesar. +3000 + +Erori ne es trovita +{0} objekt(o|i) merkita +Krear dosieruyo '{0}' neposiblesis +Rinovigo ne suportesas por ica arkivo. + + + + +Dosiero '{0}' chanjesis.\nKa vu volas rinovigar lu enarkive? +Rinovigo dil dosiero\n'{0}' faliis +Startigo dil redaktilo. + + + + +Tro multa objekti +3300 +Extrakto +Kompreso +Probado +Aperto... + +3400 +&Extraktar +E&xtraktar aden: +Definez loko por dosieri extraktenda. +3410 +Dosiervoyi +&Absoluta dosiervoyi +&Sen dosiervoyi +3420 +Remplasala skribmodo +&Kun konfirmo +&Sen konfirmo +&Omisar existanta dosieri +Automata nomchanjo +Automata nomchanjo de existanta dosieri +3500 +Konfirmo di nomchanjo +Dosieruyo ja kontenas operacata dosiero. +Kad remplasor esanta dosiero +per la ica? +{0} bayti* +&Automata nomchanjo. +3700 +Kompresmetodo ne esas suportata por dosiero '{0}'. +Datumeroro en '{0}'. Dosiero es fushita. +CRC-eroro en '{0}'. Dosiero es fushita. + + +3800 +Pasovorto +Sugestez pasovorto: + +&Montrar pasovorto + + + +&Pasovorto +3900 +Pasinta tempo: +Restanta tempo: +Grandeso: +Rapideso: + + +Erori: + +4000 +Adjuntar aden arkivo +&Arkivo: +R&emplasomodo: +A&rkiva formato: +Kompreso&grado +&Kompresometodo: +&Vortarograndeso: +Vo&rtograndeso: + + +&Parametri: +Ajustaji +Krear SF&X-arkivo + + + +Chifrar dosier&nomi +Memoruzo por kompresar: +Memoruzo por extraktar: +4050 +Sen kompresar +Maxim rapide +Rapide +Normala kompreso +Maxim granda kompreso +Extreme +4060 +Adjuntar e remplasar dosieri +Rinovigar e adjuntar dosieri +Rifreshigar existanta dosieri +Sinkronizar dosieri +4070 +Inspektar +Omna dosieri + + +6000 +Kopiar +Transpozar +Kopiez aden: +Transpozez aden: +Kopio... +Transpozo... +Nomchanjo... + +Operaco ne suportesas. +Eroro dum nomchanjo di dosiero o dosieruyo + + +6100 +Konfirmo dil efaco di dosiero +Konfirmo dil efaco di dosieruyo +Konfirmo dil efaco di dosieraro +Ka vu ya volas efacar '{0}'? +Ka vu ya volas efacar dosieruyo "{0}" e omna lua kontenaji? +Ka vu ya volas efacar ita {0} objekti? +Efaco... +Eroro dum efacar di dosiero o dosieruyo + +6300 +Krear dosieruyo +Krear dosiero +Dosieruynomo: +Dosiernomo: +Nova dosieruyo +Nova dosiero +Eroro dum dosieruykreo +Eroro dum dosierkreo +6400 +Komento +&Komento: +Merkar +Desmerkar +Masko: +6600 + +Dosieruyhistorio +Diagnozala mesaji +Mesajo +7100 +Komputilo +Reto + +Sistemo +7200 +Adjuntar +Extraktar +Verifikar +Kopiar +Transpozar +Efacar +Informo +7300 +Fendar dosiero +&Fendez aden: +&Fendar por volumini, bayti: +Fendo... + + + + + +7400 +Kombinar dosieri +&Kombinar aden: +Kombino... + + + +7500 + + + + +7600 +Experienco dil rapideso +Memoruzo: +Kompresado +Extraktado +Aprecuro +Tota aprecuro +Kuranta +Rezulta + + +Pasi: diff --git a/Utils/7-Zip/Lang/is.txt b/Utils/7-Zip/Lang/is.txt new file mode 100644 index 000000000..f324c6e94 --- /dev/null +++ b/Utils/7-Zip/Lang/is.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.14 : 2016-04-23 : Stefán Örvar Sigmundsson +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Icelandic +Íslenska +401 +Í lagi +Viðhætta + + + +&Já +&Nei +&Loka +Hjálp + +&Halda áfram +440 +&Já við öllu +&Nei við öllu +Stöðva +Endurræsa +&Bakgrunnur +&Forgrunnur +&Gera hlé +Í hléi +Ert þú viss um að þú viljir viðhætta? +500 +&Skrá +&Breyta +S&koða +&Uppáhald +&Verkfæri +&Hjálp +540 +&Opna +Opna að &innanverðu +Opna að &utanverðu +S&koða +&Breyta +&Endurnefna +&Afrita í… +&Færa í… +E&yða +K&ljúfa skrá +S&ameina skrár +E&iginleikar +&Gera athugasemd +Reikna samtölu +Mismunur +Skapa &möppu +Skapa &skrá +&Hætta +&Tengill +&Víxlstraumar +600 +&Velja allt +&Afvelja allt +&Umsnúa vali +&Velja +&Afvelja +&Velja eftir tegund +&Afvelja eftir tegund +700 +&Stórar táknmyndir +S&máar táknmyndir +&Listi +Sm&áatriði +730 +Óflokkað +&Flatsýn +&2 spjöld +&Verkfærastikur +&Opna rótarmöppu +&Upp um eitt stig +M&öppusaga +&Endurglæða +S&jálfendurglæðun +750 +Safnverkfærastika +Stöðluð verkfærastika +Stórir takkar +Sýna takkatexta +800 +&Viðbæta möppu í uppáhald sem +Bókamerki +900 +&Valmöguleikar +&Afkastaprófa +960 +&Efnisyfirlit +&Um 7-Zip +1003 +Slóð +Nafn +Framlenging +Mappa +Stærð +Þjöppuð stærð +Eiginleikar +Skapað +Aðkomið +Dagsetning +Þétt +Athugasemd +Dulkóðað +Kljúfa fyrir +Kljúfa eftir +Orðasafn + +Tegund +And +Aðferð +Stýrikerfi hýsils +Skráakerfi +Notandi +Hópur +Bálkur +Athugasemd +Staðsetning +Slóðarforskeyti +Möppur +Skrár +Útgáfa +Bindi +Fjölbinda +Afsetning +Tenglar +Bálkar +Bindi + +64-bita +Háenda +Gjörvi +Efnisleg stærð +Höfðastærð +Samtala +Einkenni +Sýndarvistfang +Auðkenni +Stutt nafn +Skaparahugbúnaður +Geirastærð +Hamur +Mjúktengill +Villa +Heildarstærð +Laust pláss +Klasastærð +Merki +Staðarnafn +Veitandi +NT-öryggi +Víxlstraumur +Aðstoðar- +Eytt +Er tré + + +Villutegund +Villur +Villur +Viðvaranir +Viðvörun +Straumar +Víxlstraumar +Víxlstraumastærð +Sýndarstærð +Afþjöppuð stærð +Efnisleg heildarstærð +Bindaskrá +Undirtegund +Stutt athugasemd +Kóðasíða + + + +Halastærð +Innfallin stubbastærð +Tengill +Harðtengill +Skráhnútur + +Einungis lesanlegt +2100 +Valmöguleikar +Tungumál +Tungumál: +Ritill +&Ritill: +&Mismunur: +2200 +Kerfi +Tengja 7-Zip við: +Allir notendur +2301 +&Innleiða 7-Zip í samhengisvalmynd skeljar +&Þrepaskipt samhengisvalmynd +Samhengisvalmyndaratriði: +&Táknmyndir í samhengisvalmynd +2320 + + +Opna safn +Afþjappa skrár +Viðbæta í safn +Prófa safn +Afþjappa hér +Afþjappa í „{0}“ +Viðbæta í „{0}“ +Þjappa og senda í rafpósti +Þjappa í „{0}“ og senda í rafpósti +2400 +Möppur +Vinnslumappa +&Tímabundin mappa kerfis +&Núverandi +Til&greind: +N&ota einungis fyrir fjarlægjanleg drif +Tilgreina staðsetningu fyrir tímabundnar safnskrár. +2500 +Stillingar +Sýna „..“ &atriði +Sýna &raunverulegar skráartáknmyndir +Sýna &kerfisvalmynd +&Fullraðaval +Sýna &töflulínur +&Einsmella til að opna atriði +Annars konar &valhamur +Nota stórar &minnissíður +2900 +Um 7-Zip +7-Zip er frjáls hugbúnaður +3000 +Kerfið getur ekki ráðstafað nauðsynlega magninu af minninu +Það eru engar villur +„{0}“ hlutir valdir +Getur ekki skapað möppuna „{0}“ +Uppfærsluaðgerðir eru ekki studdar fyrir þetta safn. +Getur ekki opnað skrána „{0}“ sem safn +Getur ekki opnað dulkóðaða safnið „{0}“. Rangt aðgangsorð? +Óstudd safntegund +Skráin „{0}“ er nú þegar til +Skránni „{0}“ var breytt.\nVilt þú uppfæra hana í safninu? +Getur ekki uppfært skrána\n„{0}“ +Getur ekki ræst ritilinn. +Skráin lítur út eins og veira (skráarnafnið inniheldur löng bil). +Aðgerðina er ekki hægt að kalla í frá möppu sem hefur langa slóð. +Þú verður að velja eina skrá +Þú verður að velja eina eða fleiri skrár +Of mörg atriði +Getur ekki opnað skrána sem „{0}“-safn +Skráin er opin sem „{0}“-safn +Safnið er opið með afsetningu +3300 +Afþjappar +Þjappar +Prófar +Opnar +Skimar +Fjarlægir +3320 +Viðbætir +Uppfærir +Greinir +Endurtekur +Endurpakkar +Sleppir +Eyðir +Skapar höfuð +3400 +Afþjappa +Afþjappa í: +Tilgreindu staðsetningu fyrir afþjöppuðu skrárnar. +3410 +Slóðarhamur: +Full slóðarnöfn +Engin slóðarnöfn +Algild slóðarnöfn +Afstæð slóðarnöfn +3420 +Yfirritunarhamur: +Spyrja áður en yfirritað er +Yfirrita án kvaðningar +Sleppa gildandi skrám +Sjálfendurnefnun +Sjálfendurnefnun gildandi skráa +3430 +Útrýma afritinu af rótarmöppunni +Endurheimta skráaröryggi +3500 +Staðfesta skráaryfirritun +Áfangastaðsmappan inniheldur nú þegar meðhöndluðu skrána. +Vilt þú yfirrita gildandi skrána +með þessari? +{0} bæti +Sjálfendurnefnun +3700 +Óstudd þjöppunaraðferð fyrir „{0}“. +Gagnavilla í „{0}“. Skráin er brotin +CRC mistókst í „{0}“. Skráin er brotin. +Gagnavilla í dulkóðuðu „{0}“. Rangt aðgangsorð? +CRC mistókst í dulkóðuðu skránni „{0}“. Rangt aðgangsorð? +3710 +Rangt aðgangsorð? +3721 +Óstudd þjöppunaraðferð +Gagnavilla +CRC mistókst +Ótiltæk gögn +Óvæntur endir gagna +Það eru gögn eftir endanum á aðalgögnunum +Er ekki safn +Höfðavillur +Rangt aðgangsorð +3763 +Ótiltækt upphaf safns +Óstaðfest upphaf safns + + + +Óstuddur eiginleiki +3800 +Ritaðu aðgangsorðið +Ritaðu aðgangsorðið: +Endurritaðu aðgangsorðið: +Sýna aðgangsorðið +Aðgangsorðin samsvarast ekki +Notaðu einungis enska stafi, tölur og sérstök rittákn (!, #, $, o.s.frv.) í aðgangsorðunum +Aðgangsorðið er of langt +Aðgangsorð +3900 +Liðinn tími: +Tími eftir: +Heildarstærð: +Hraði: +Meðhöndlað: +Þjöppunarhlutfall: +Villur: +Söfn: +4000 +Viðbæta safni +Safn: +Uppfærsluhamur: +Safnsnið: +Þjöppunarsnið: +Þjöppunaraðferð: +Orðasafnsstærð: +Orðastærð: +Þéttbálkstærð: +Fjöldi gjörvaþráða: +Færibreytur: +Valmöguleikar +Skapa SFX-safn +Þjappa sameiginlegum skrám +Dulkóðun +Dulkóðunaraðferð: +Dulkóða skráarnöfn +Minnisnotkun fyrir þjöppun: +Minnisnotkun fyrir afþjöppun: +Eyða skrám eftir þjöppun +4040 +Geyma mjúktengla +Geyma harðtengla +Geyma víxlgagnastrauma +Geyma skráaröryggi +4050 +Geyma +Hraðast +Hratt +Venjulegt +Hámarks +Öfga- +4060 +Viðbæta og yfirrita skrár +Uppfæra og viðbæta skrám +Hressa við gildandi skrám +Samstilla skrár +4070 +Vafra +Allar skrár +Óþétt +Þétt +6000 +Afrita +Færa +Afrita í: +Færa í: +Afritar +Færir +Endurnefnir +Veldu móttökumöppu. +Aðferðin er ekki stutt fyrir þessa möppu. +Villa við endurnefnun skráar eða möppu +Staðfesta skráarafritun +Ert þú viss um að þú viljir afrita skrárnar í safnið +6100 +Staðfesta skráareyðingu +Staðfesta möppueyðingu +Staðfesta fjölskráaeyðingu +Ert þú viss um að þú viljir eyða „{0}“? +Ert þú viss um að þú viljir eyða möppunni „{0}“ og öllu innihaldinu hennar? +Ert þú viss um að þú viljir eyða þessum {0} atriðum? +Eyðir +Villa við eyðingu skráar eða möppu +Kerfið getur ekki fært skrá með langri slóð í Recycle Bin +6300 +Skapa möppu +Skapa skrá +Möppunafn: +Skráarnafn: +Ný mappa +Ný skrá +Villa við sköpun möppunnar +Villa við sköpun skráarinnar +6400 +Athugasemd +Athugasemd: +Velja +Afvelja +Mát: +6600 +Eiginleikar +Möppusaga +Greiningarskilaboð +Skilaboð +7100 +Tölva +Net +Skjöl +Kerfi +7200 +Viðbæta +Afþjappa +Prófa +Afrita +Færa +Eyða +Upplýsingar +7300 +Kljúfa skrá +Kljúfa í: +Kljúfa í bindi, bæti: +Klýfur +Staðfesta klofning +Ert þú viss um að þú viljir kjúfa skrána í {0} bindi? +Bindisstærð verður að vera minni en stærðin á upprunalegu skránni +Röng bindisstærð +Tilgreindu bindisstærð: {0} bæti.\nErt þú viss um að þú viljir kljúfa safnið í slík bindi? +7400 +Sameina skrár +Sameina í: +Sameinar +Veldu einungis fyrsta hlutann af klofningsskránni +Get ekki greint skrána sem hluta af klofningsskránni +Get ekki fundið meira en einn hluta af klofningsskránni +7500 +Reiknar samtölu +Samtöluupplýsingar +CRC-samtala fyrir gögn: +CRC-samtala fyrir gögn og nöfn: +7600 +Afkastapróf +Minnisnotkun: +Þjöppun +Afþjöppun +Niðurstaða +Heildarniðurstaða +Núverandi +Útkoma +Gjörvanotkun +Niðurstaða / Notkun +Yfirferðir: +7700 +Tengill +Tengill +Tengill frá: +Tengill til: +7710 +Tengiltegund +Harðtengill +Skráarmjúktengill +Skráasafnsmjúktengill +Skráasafnstenging \ No newline at end of file diff --git a/Utils/7-Zip/Lang/it.txt b/Utils/7-Zip/Lang/it.txt new file mode 100644 index 000000000..ee4e3b1cf --- /dev/null +++ b/Utils/7-Zip/Lang/it.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 4.07 : Leandro Spagnol +; : Vincenzo Reale (some corrections) +; 15.05 : 2015-06-17 : TJL73 : http://tjl73.altervista.org/ +; +; +; +; +; +; +; +; +0 +7-Zip +Italian +Italiano +401 +OK +Annulla + + + +&Sì +&No +&Chiudi +Aiuto + +&Riprendi +440 +Sì per &tutti +No per t&utti +Ferma +Riavvia +&In background +&In primo piano +&Pausa +In pausa +Sei sicuro di voler annullare? +500 +&File +&Modifica +&Visualizza +&Preferiti +&Strumenti +&Aiuto +540 +&Apri +Apri in &7-Zip File Manager +Apri in E&xplorer +&Visualizza +Apri con l'&editor predefinito +Rino&mina +&Copia in... +&Sposta in... +&Elimina +&Dividi il file... +&Unisci i file... +&Proprietà +Comme&nto... +Calcola chec&ksum +Comparazione differenze (Diff) +Crea cartella +Crea file +E&sci +Collegamento +&Alternate Data Streams +600 +&Seleziona tutto +&Deseleziona tutto +In&verti selezione +Seleziona... +Deseleziona... +Seleziona per tipo +Deseleziona per tipo +700 +Icone &grandi +Icone &piccole +&Elenco +&Dettagli +730 +Nessun ordine +Vista non strutturata +Interfaccia a &2 pannelli +Barre degli &strumenti +Apri cartella principale +Livello superiore +Cronologia... +&Aggiorna +Aggiornamento automatico +750 +Barra archivio +Barra standard +Icone grandi +Mostra etichette di testo +800 +&Aggiungi la cartella ai Preferiti come +Collegamento +900 +&Opzioni... +&Benchmark +960 +&Guida... +&Informazioni su 7-Zip... +1003 +Percorso +Nome +Estensione +Cartella +Dimensione +Dimensione compressa +Attributi +Creato +Ultimo accesso +Ultima modifica +Solido +Commentato +Cifrato +Dividi prima +Dividi dopo +Dizionario + +Tipo +Estensione +Metodo +OS destinatario +File system +Utente +Gruppo +Blocco +Commento +Posizione +Percorso completo +Cartelle +File +Versione +Unità +Unità multiple +Offset +Collegamenti +Blocchi +Unità + +64-bit +Big-endian +CPU +Dimensione fisica +Dimensione intestazioni +Checksum +Caratteristiche +Indirizzo virtuale +ID +Nome breve +Applicativo origine +Dimensione settore +Modalità +Collegamento simbolico +Errore +Capacità +Disponibili +Dimensione dei cluster +Etichetta +Nome locale +Rete +Sicurezza NT +Flusso alternato +Ausiliario +Eliminato +Ad albero + + +Tipo di errori +Errori +Errori +Avvertimenti +Avvertimento +Flussi +Flussi alternati +Dimensione dei flussi alternati +Dimensione virtuale +Dimensione decompressione +Dimensione fisica totale +Indice del volume +Sottotipo +Commento breve +Pagina dei codici + + + +Dimensione della coda +Dimensione della matrice integrato +Collegamento +Collegamento statico +iNode + +Sola lettura +2100 +Opzioni +Lingua +Lingua: +Editor +&Editor predefinito: +Comparatore &differenze (Diff): +2200 +Sistema +Associa 7-Zip a: +Tutti gli utenti +2301 +Integra 7-Zip nel menu contestuale della shell +Menu contestuale a cascata +Elementi del menu contestuale: +Icone nel menu contestuale +2320 + + +Apri +Estrai i file... +Aggiungi all'archivio... +Verifica l'archivio +Estrai qui +Estrai in {0} +Aggiungi a {0} +Comprimi ed invia per email... +Comprimi in {0} ed invia per email +2400 +Cartelle +Cartella di lavoro +Cartella &TEMP di sistema +&Corrente +&Specificata: +&Utilizza solo per dischi rimovibili +Specifica una cartella per i file temporanei. +2500 +Impostazioni +Mostra l'elemento ".." +Mostra le icone dei file +Mostra le icone di sistema +Selezione a &riga intera +Mostra &griglia +Click singolo per aprire una voce +Modalità di selezione &alternativa +Utilizza pagine &larghe di memoria +2900 +Informazioni +7-Zip è un software libero.\n\nLocalizzazione italiana a cura di:\nTJL73 +3000 +Non è possibile allocare la quantità di memoria richiesta +Nessun errore. +Oggetti selezionati: {0} +Impossibile creare la cartella '{0}' +Non è possibile effettuare aggiornamenti su questo archivio. +Impossibile aprire il file '{0}' come archivio. +Impossibile aprire l'archivio cifrato '{0}'. Password errata? +Archivio non supportato +Il file {0} è già presente +Il file '{0}' è stato modificato.\nVuoi aggiornare l'archivio? +Impossibile aggiornare il file\n'{0}' +Impossibile avviare l'editor. +Il file sembra essere un virus (contiene molti spazi nel nome). +L'operazione non può essere richiamata da una cartella con percorso lungo. +Devi selezionare un file +Devi selezionare almeno un file +Troppi elementi +Impossibile aprire il file come archivio {0} +Il file è aperto come archivio {0} +L'archivio è aperto con offset +3300 +Estrazione in corso +Compressione in corso +Verifica archivio +Apertura in corso... +Scansione... +Rimozione +3320 +Aggiunta +Aggiornamento +Analisi +Replica +Ripacchettizzazione +Salto +Eliminazione +Creazione intestazione +3400 +Estrai +E&strai in: +Specifica una cartella in cui estrarre i file. +3410 +Struttura delle cartelle: +Percorsi completi +Nessun percorso +Percorsi assoluti +Percorsi relativi +3420 +Sovrascrittura: +Chiedi prima di sovrascrivere +Sovrascrivi senza chiedere +Non sovrascrivere i file esistenti +Rinomina automaticamente +Rinomina autom. i file esistenti +3430 +Elimina la duplicazione della radice +Ripristina sicurezza dei file +3500 +Conferma la sovrascrittura del file +File già esistente nella cartella di destinazione. +Vuoi sostituire il file esistente +con questo? +{0} byte +&Rinomina automaticamente +3700 +Metodo di compressione non supportato per '{0}'. +Errore nei dati in '{0}'. Il file è danneggiato. +CRC non corretto in '{0}'. Il file è danneggiato. +Errore nel file cifrato '{0}'. Password errata? +CRC errato nel file cifrato '{0}'. Password errata? +3710 +Password errata? +3721 +Metodo di compressione non supportata +Errore dei dati +CRC errato +Dati non disponibili +Fine dei dati inattesa +Sono presenti dati oltre la fine del blocco utile +Non è un archivio +Errore intestazioni +Password errata +3763 +Inizio dell'archivio non disponibile +Inizio dell'archivio non confermato + + + +Funzionalità non supportata +3800 +Inserisci password +&Inserisci password: +&Reinserisci password: +Mostra pass&word +Password differenti +Per la password, utilizzare solo lettere ASCII, numeri e caratteri speciali (!, #, $, ...) +La password è troppo lunga +Password +3900 +Tempo trascorso: +Tempo rimanente: +Dimensione totale: +Velocità: +Elaborato: +Rapporto compressione: +Errori: +Archivi: +4000 +Aggiungi all'archivio +Nome &archivio: +Modalità a&ggiornamento: +&Formato dell'archivio: +&Livello di compressione: +&Metodo di compressione: +Dimensione &Dizionario: +Dimensioni &Parola: +Dimensione del &blocco solido: +N&umero di flussi (thread) CPU: +Parametri &opzionali: +Opzioni +Crea archivio auto-&estraente +Comprimi file condivisi +Cifratura +Metodo &cifratura: +Cifra anche il &nome dei file +Quantità memoria per compressione: +Quantità memoria per decompressione: +Elimina i file dopo la compressione +4040 +Memorizza collegamenti simbolici +Memorizza collegamenti statici +Memorizza flussi dati alternati +Memorizza sicurezza dei file +4050 +Nessuna +Velocissima +Veloce +Normale +Massima +Ultra +4060 +Aggiungi e sostituisci i file +Aggiorna e aggiungi i file +Aggiorna i file esistenti +Sincronizza i file +4070 +Sfoglia +Tutti i file +Non-solido +Solido +6000 +Copia +Sposta +Copia in: +Sposta in: +Copia in corso... +Spostamento in corso... +Rinomina in corso... +Selezionare la cartella di destinazione. +Operazione non supportata per questa cartella. +Errore nella rinomina del file o cartella +Conferma copia +Sei sicuro di voler copiare questi file nell'archivio +6100 +Conferma l'eliminazione del file +Conferma l'eliminazione della cartella +Conferma l'eliminazione di più elementi +Sei certo di voler eliminare '{0}'? +Sei certo di voler eliminare la cartella '{0}' e tutto il suo contenuto? +Sei certo di voler eliminare questi {0} elementi? +Eliminazione in corso... +Errore nell'eliminazione del file o della cartella +Impossibile spostare un file con percorso lungo nel Cestino +6300 +Crea cartella +Crea file +Nome cartella: +Nome file: +Nuova cartella +Nuovo file +Errore nella creazione della cartella +Errore nella creazione del file +6400 +Commento +&Commento: +Seleziona +Deseleziona +Filtro: +6600 +Proprietà +Cronologia +Messaggi di diagnostica +Messaggio +7100 +Computer +Rete +Documenti +Sistema +7200 +Aggiungi +Estrai +Verifica +Copia +Sposta +Elimina +Proprietà +7300 +Dividi file +&Dividi in: +Di&vidi in più file (dimensione in byte): +Dividi in... +Conferma divisione +Sicuro di voler dividere l'archivio in {0} porzioni? +La dimensione di ciascuna porzione deve essere più piccola della dimensione totale dell'archivio originale +Dimensione non corretta +Dimensione specificata: {0} byte.\nSicuro di voler dividere l'archivio in questo modo? +7400 +Unisci i file +&Unisci in: +Unisci... +Seleziona solo la prima parte del file diviso +Impossibile riconoscere il file come archivio diviso +Impossibile trovare più di una parte dell'archivio diviso +7500 +Calcolo del checksum... +Informazioni sul checksum +CRC checksum sui dati: +CRC checksum su dati e nomi: +7600 +Benchmark +Utilizzo memoria: +Compressione in corso +Decompressione in corso +Valutazione +Valutazione totale +Attuale +Risultante +Utilizzo CPU +Stima / Utilizzo +Passaggi: +7700 +Collegamento +Collega +Origine collegamento: +Destinazione collegamento: +7710 +Tipo di collegamento +Collegamento statico +Collegamento simbolico al file +Collegamento simbolico alla cartella +Giunzione cartella diff --git a/Utils/7-Zip/Lang/ja.txt b/Utils/7-Zip/Lang/ja.txt new file mode 100644 index 000000000..c475e03a0 --- /dev/null +++ b/Utils/7-Zip/Lang/ja.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Komuro, Mick, 2chBBS-software +; : Crus Mitsuaki +; 9.07 : Stepanushkin Dmitry +; 9.23 : 2011-06-22 : Stepanushkin Dmitry, nabeshin +; 9.33 : 2014-06-17 : Stepanushkin Dmitry +; 15.00 : 2015-04-30 : Stepanushkin Dmitry +; +; +; +; +; +0 +7-Zip +Japanese +日本語 +401 +OK +キャンセル + + + +はい(&Y) +いいえ(&N) +閉じる(&C) +ヘルプ + +続行(&C) +440 +すべてに はい(&A) +すべてに いいえ(&L) +停止 +再開 +バックグラウンド(&B) +フォアグラウンド(&F) +一時停止(&P) +一時停止 +本当に圧縮を取りやめますか? +500 +ファイル(&F) +編集(&E) +表示(&V) +お気に入り(&A) +ツール(&T) +ヘルプ(&H) +540 +開く(&O) +7-Zipで閲覧(&I) +関連付けで開く(&U) +表示(&V) +編集(&E) +名前の変更(&M) +コピー(&C)... +移動(&M)... +削除(&D) +ファイル分割(&S)... +ファイル結合(&B)... +プロパティ(&R) +コメント(&N) +チェックサムの計算 +比較 +フォルダ作成 +ファイル作成 +閉じる(&X) +リンク作成 +代替データストリーム(&A) +600 +全て選択(&A) +全て選択解除 +反転選択(&I) +選択... +選択解除... +同一形式選択 +同一形式選択解除 +700 +大きいアイコン(&G) +小さいアイコン(&M) +一覧(&L) +詳細(&D) +730 +並べ替え解除 +フラットビュー +&2分割画面 +ツールバー(&T) +ルートフォルダを開く +1つ上の階層へ +フォルダ履歴... +最新の情報に更新(&R) +自動更新 +750 +書庫ツールバー +標準ツールバー +大きなボタン +ボタンのテキスト表示 +800 +フォルダをお気に入りに追加(&A) +ブックマーク +900 +オプション(&O)... +ベンチマーク(&B) +960 +ヘルプの表示(&C)... +7-Zipについて(&A)... +1003 +パス +名前 +拡張子 +フォルダ +サイズ +圧縮後サイズ +属性 +作成日時 +アクセス日時 +更新日時 +ソリッド +コメント済み +暗号化 +分割前 +分割後 +辞書 + +種類 +逆 +圧縮方法 +ホストOS +ファイルシステム +ユーザー +グループ +ブロック +コメント +ポジション +パスプレフィックス +フォルダ数 +ファイル数 +バージョン +ボリューム +多重ボリューム書庫 +オフセット +リンク数 +使用ブロック数 +ボリューム数 + +64ビット +ビッグエンディアン +CPU +物理サイズ +ヘッダーサイズ +チェックサム +特性 +仮想アドレス +ID +省略名 +作成アプリケーション +セクターサイズ +モード +リンク +エラー +合計サイズ +空き領域 +クラスタサイズ +ラベル +ローカル名 +プロバイダ +NTセキュリティ +代替データストリーム +補助 +削除済み +はツリー + + +エラー種類 +エラー +エラー +警告 +警告 +ストリーム +代替データストリーム +代替データストリームサイズ +仮想サイズ +解凍後サイズ +物理サイズ合計 +ボリュームインデックス +亜類型 +コメント +コードページ + + + +テイルのサイズ +組み込みスタブのサイズ +リンク +ハードリンク +iノード + +読み取り専用 +2100 +オプション +言語 +言語設定: +外部ツール +編集(&E): +比較(diff)(&D): +2200 +システム +7-Zipに関連付けるファイル: +全てのユーザー +2301 +シェルコンテキスト(右クリック)メニューに7-Zipを登録 +7-Zipをサブメニュー化する +メニュー項目: +コンテキストメニューにアイコンを表示 +2320 +<フォルダ> +<書庫> +開く +展開... +圧縮... +書庫をテスト +ここに展開 +{0}に展開 +{0}に圧縮 +圧縮して電子メール送信... +{0}に圧縮して電子メール送信 +2400 +フォルダ +作業フォルダ(&W) +システム一時フォルダ(&S) +カレントフォルダ(&C) +フォルダ指定(&P): +リムーバブルドライブのみ使用する +一時ファイルのための場所を指定してください +2500 +設定 +'..'を表示する +各ファイルの実際のアイコンを表示する +システム(エクスプローラ)のメニューも表示する +行単位(列アイテムを一括)で選択する(&F) +グリッド線を表示する(&G) +シングルクリックで開く +カーソル移動で選択が自動解除されないモード(&A) +大きなメモリページを使用する(&L) +2900 +7-Zipについて +7-Zipはフリーソフトウェアです +3000 +要求された量のメモリを割り当てることができません +正常です +{0}個のオブジェクトを選択 +'{0}'フォルダが作成できません +この書庫は更新機能がサポートされていません +ファイル'{0}'は書庫として開くことができません +暗号化された書庫'{0}'を開くことができません。パスワードが間違っていませんか? +未対応の書庫形式です +{0}ファイルは既に存在しています +'{0}'ファイルが変更されました。\n書庫を更新しますか? +ファイルを更新できません。\n'{0}' +エディタを起動できません。 +このファイルは、ウイルスのように見えます(ファイル名に大量のスペースを含んでいる)。 +パスが長いフォルダではこの操作を実行できません。 +1つのファイルを選択してください +1つ以上のファイルを選択してください +アイテムが多過ぎます +ファイルを{0}書庫として開くことができません +ファイルが{0}書庫として開かれています +書庫がオフセットを使用して開かれています +3300 +展開中 +圧縮中 +テスト中 +開いています... +スキャン中... +削除中 +3320 +追加中 +更新中 +解析中 +複製中 +再圧縮中 +スキップ中 +削除中 +ヘッダーの作成中 +3400 +展開 +展開先(&X): +展開先指定 +3410 +パス名出力方法: +フルパス +パスなし +絶対パス +相対パス +3420 +上書き方法 +上書きするときは確認する +常に上書き +ファイルが存在するときはスキップ +自動的にリネーム +ファイルが存在するときは自動リネーム +3430 +ルートフォルダーの重複を回避 +ファイルのセキュリティ属性を復元 +3500 +ファイル上書き確認 +出力先のフォルダには既に以下の同じファイルが存在します +現在のファイル +に次の新しいファイルを上書きしますか? +{0}バイト +自動的にリネーム(&U) +3700 +'{0}'はサポートされていない圧縮方式です +'{0}'でデータエラーが発生しました。ファイルは壊れています +'{0}'のCRCが違います。ファイルは壊れています +暗号化されたファイル'{0}'でデータエラーが発生しました。パスワードが間違っていませんか? +暗号化されたファイル'{0}'のCRCが違います。パスワードが間違っていませんか? +3710 +パスワードが間違っていませんか? +3721 +非対応圧縮方法 +データエラー +CRCが違います +データ取得失敗 +データ不足 +データのペイロード後にデータが存在します +書庫ではありません +ヘッダーエラー +パスワードが間違っています +3763 +書庫先頭の取得失敗 +無効な書庫先頭 + + + +非対応機能 +3800 +パスワード入力 +パスワード入力: +パスワード再入力: +パスワードを表示する(&S) +パスワードが一致しません +パスワードには半角英数記号(!, #, $, ...)のみを使用してください。 +パスワードがあまりに長過ぎます +パスワード +3900 +経過時間: +残り時間: +サイズ合計: +速度: +処理済み: +圧縮率: +エラー: +書庫数: +4000 +ファイル圧縮 +圧縮先(&A): +更新方法(&U): +書庫形式(&F): +圧縮レベル(&L): +圧縮方式(&M): +辞書サイズ(&D): +ワードサイズ(&W): +ソリッドブロックサイズ: +CPUスレッド数: +パラメータ(&P): +オプション +自己展開書庫作成(&X) +共有(編集中の)ファイルも圧縮 +暗号化 +暗号化方式: +ファイル名を暗号化(&N) +圧縮に必要なメモリ: +展開に必要なメモリ: +圧縮後に元のファイルを削除 +4040 +シンボリックリンクを保存 +ハードリンクを保存 +代替データストリームを保存 +ファイルのセキュリティ属性を保存 +4050 +無圧縮 +最速 +高速 +標準 +最高 +超圧縮 +4060 +すべてのファイル上書き +ファイル追加と更新 +変更したファイルのみ更新 +ファイルを同期させる +4070 +閲覧 +すべてのファイル +ソリッドなし +無制限 +6000 +コピー +移動 +フォルダへコピー: +フォルダへ移動: +コピーしています... +移動しています... +リネームしています... +対象のフォルダを選択してください。 +このフォルダでは、その操作はサポートされていません。 +ファイルまたはフォルダのリネームエラー +ファイルコピーの確認 +本当にファイルを書庫に追加しますか? +6100 +ファイル削除の確認 +フォルダ削除の確認 +複数ファイル削除の確認 +'{0}'を本当に削除しますか? +'{0}'フォルダとその中身のすべてを削除しますか? +これらの{0}個の項目を本当に削除しますか? +削除中... +ファイルまたはフォルダの削除エラー +ファイルのパスが長すぎるため、ファイルをごみ箱に移動できません +6300 +フォルダ作成 +ファイル作成 +フォルダ名: +ファイル名: +新しいフォルダ +新しいファイル +フォルダ作成エラー +ファイル作成エラー +6400 +コメント +コメント(&C): +選択 +選択解除 +マスク: +6600 +プロパティ +フォルダ履歴 +診断結果 +メッセージ +7100 +コンピュータ +ネットワーク +ドキュメント +システム +7200 +追加 +展開 +テスト +コピー +移動 +削除 +情報 +7300 +ファイル分割 +分割先(&S): +書庫をサイズで分割(&V): +分割中... +分割の確認 +{0}個にファイルを分割してもよろしいですか? +分割後のサイズは元のファイルサイズより小さいサイズを指定してください +不正なボリュームサイズ +選択されたボリュームサイズ:{0}バイト\nこのサイズに書庫を分割しますか? +7400 +ファイル結合 +結合先(&C): +結合中... +分割ファイルの先頭のファイルだけ選択してください +分割ファイルが見つかりません +分割ファイルの一部しか見つかりません +7500 +チェックサム計算中... +チェックサム情報 +データのCRCチェックサム: +データと名前のCRCチェックサム: +7600 +ベンチマーク +必要メモリ: +圧縮中 +展開中 +評価 +総合評価 +現在 +結果 +CPU使用率 +評価 / 使用率 +テスト回数: +7700 +リンク +リンク作成 +リンク元: +リンク先: +7710 +リンク種類 +ハードリンク +ファイルのシンボリックリンク +ディレクトリのシンボリックリンク +ディレクトリのジャンクション diff --git a/Utils/7-Zip/Lang/ka.txt b/Utils/7-Zip/Lang/ka.txt new file mode 100644 index 000000000..a920e7318 --- /dev/null +++ b/Utils/7-Zip/Lang/ka.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.23 : 2011-09-25 : Translated by Giorgi Maghlakelidze, original translation by Dimitri Gogelia, +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Georgian +ქართული +401 +OK +გაუქმება + + + +&დიახ +&არა +&დახურვა +დახმარება + +&გაგრძელება +440 +დიახ &ყველასათვის +არა ყვე&ლასათვის +შეწყვეტა +ხელახლა +&ფონურად +&წინა პლანზე +&შეჩერება +&შეჩერებული +ნამდვილად გსურთ მოქმედების შეწყვეტა? +500 +&ფაილი +&დამუშავება +&ხედი +რ&ჩეულები +&ხელსაწყოები +&დახმარება +540 +&გახსნა +გახსნა &შიგნით +გახსნა გა&რეთ +და&თვალიერება +და&მუშავება +გადა&რქმევა +&ასლის მოთავსება... +&გადატანა... +&წაშლა +&ფაილის დაყოფა... +&ფაილების გაერთიანება... +თ&ვისებები +კომენ&ტარი +საკონტროლო ჯამის დათვლა +Diff +საქაღალდის შექმნა +ფაილის შექმნა +გ&ამოსვლა +600 +&ყველაფრის მონიშვნა +მონიშვნის გაუქმება +მონიშვნის შებრუნება +მოინიშნოს... +მოიხსნას მონიშვნა... +მონიშვნა ტიპის მიხედვით +მონიშვნის მოხსნა ტიპის მიხედვით +700 +&დიდი ხატულები +&პატარა ხატულები +&სია +&დაწვრილებით +730 +დაულაგებელი +ბრტყელი ხედი +&2 პანელი +&ხელსაწყოთა ზოლი +ძირეული საქაღალდის გახსნა +საქაღალდიდან გასვლა +საქაღალდეების ისტორია... +&განახლება +750 +დაარქივების ზოლი +ძირითადი ზოლი +დიდი ღილაკები +წარწერები ღილაკებზე +800 +&საქაღალდის რჩეულებში დამატება როგორც +სანიშნე +900 +&გამართვა... +&წარმადობის შემოწმება +960 +სარჩევი... +7-Zip-ის შესახებ... +1003 +მდებარეობა +სახელი +გაფართოება +საქაღალდე +ზომა +შეკუმშულის ზომა +ატრიბუტები +შექმნილია +გახსნილია +შეცვლილია +უწყვეტი +კომენტარი +დაშიფრულია +დაყოფა სანამ +დაყოფა შემდეგ +ლექსიკონი +CRC +ტიპი +ანტი +მეთოდი +სისტემა +ფაილური სისტემა +მომხმარებელი +ჯგუფი +ბლოკი +კომენტარი +მდებარეობა +მდებარეობის თავსართი +საქაღალდეები +ფაილები +ვერსია +ტომი +მრავალტომიანი +წანაცვლება +ბმულები +ბლოკები +ტომები + +64 ბიტი +Big-endian +CPU +ფიზიკური ზომა +სათაურების ზომა +საკონტროლო ჯამი +თვისებები +ვირტუალური მისამართი +ID +მოკლე სახელი +შემქმნელი პროგრამა +სექტორის ზომა +რეჟიმი +ბმული +შეცდომა +სრული მოცულობა +თავისუფალი სივრცე +კლასტერის ზომა +წარწერა +ადგილობრივი სახელი +მომწოდებელი +2100 +გამართვა +ენები +ენა: +რედაქტორი +რედაქტორი: +&Diff: +2200 +სისტემა +ასოცირება 7-Zip-თან: +2301 +7-Zip-ის გარსის კონტექსტურ მენიუში ჩადგმა +კასკადური კონტექსტური მენიუ +კონტექსტური მენიუს შემადგენლობა: +2320 +<საქაღალდე> +<არქივი> +არქივის გახსნა +ფაილების ამოღება... +არქივში ჩამატება... +არქივის შემოწმება +ამოღება აქ +ამოღება {0}-ში +{0}-ში ჩამატება +შეკუმშვა და ელფოსტით გაგზავნა... +{0}-ში შეკუმშვა და ელფოსტით გაგზავნა +2400 +საქაღალდეები +&მუშაობის საქაღალდე +&სისტემური დროებითი საქაღალდე +&მიმდინარე +&მითითებული: +გამოიყენება ცვლადი მეხსიერების მოწყობილობებისთვის +მიუთითეთ მდებარეობა დროებითი არქივებისათვის. +2500 +გამართვა +".." ელემენტის ჩვენება +ფაილთა ნამდვილი ხატულების ჩვენება +სისტემური მენიუს ჩვენება +კურსორი &მთელ სტრიქონზე +ჩვენება &ცხრილის სახით +ელემენტთა გახსნა ერთი წკაპით +მონიშნვის &ალტერნატიული რეჟიმი +&დიდი მეხსიერების ბლოკების გამოყენება +2900 +7-Zip-ის შესახებ +7-Zip არის თავისუფლად გავრცელებადი პროგრამული უზრუნველყოფა. +3000 +შეუძლებელია საჭირო ზომის მეხსიერების გამოყოფა +შეცდომები არ მოიძებნა +მონიშნულია {0} ობიექტი +ვერ მოხერხდა '{0}' საქაღალდეს შექმნა +ამ ტიპის არქივისათვის ცვლილების ოპერაცია ხელმიუწვდომელია. +'{0}' ფაილის არქივად გახსნა ვერ მოხერხდა +'{0}' დაშიფრული არქივის გახსნა ვერ მოხერხდა. არასწორი პაროლი? +არქივთა ამ სახეობის გახსნა შეუძლებელია +ფაილი '{0}' უკვე არსებობს +ფაილი '{0}' შეიცვალა.\nგნებავთ მისი არქივში განახლება? +შეუძლებელია \n'{0}'-ის განახლება +შეუძლებელია რედაქტორის გაშვება. +ფაილი შესაძლოა აღმოჩნდეს ვირუსი (სახელი შეიცავს ძალიან ბევრ თავმოყრილ ჰარს). +შეუძლებელია გრძელ-სახელიანი საქაღალდიდან ქმედების შესრულება +უნდა აირჩიოთ ერთი ფაილი +უნდა აირჩიოთ ერთი ან მეტი ფაილი +მეტისმეტად ბევრი ელემენტი +3300 +მიმდინარეობს ამოღება +მიმდინარეობს შეკუმშვა +მიმდინარეობს შემოწმება +მიმდინარეობს გახსნა... +მიმდინარეობს ამოკითხვა... +3400 +ამოღება +ა&მოღება: +მიუთითეთ ადგილი ამოსაღები ფაილებისათვის. +3410 +მდებარეობა +სრული მდებარეობა +მდებარეობის გარეშე +3420 +ზედგადაწერა +ზედგადაწერის დასტური +ზედგადაწერა დასრურის გარეშე +არსებული ფაილების გამოტოვება +ავტო-გადარქმევა +არსებული ფაილების ავტო-გადარქმევა +3500 +ფაილის ზედგადაწერის დასტური +საქაღალდე უკვე შეიცავს დამუშავებულ ფაილს. +გსურთ ჩაანაცვლოთ არსებული ფაილი +ახალი ფაილით? +{0} ბაიტი +ა&ვტო-გადარქმევა +3700 +შეკუმშვის შეუთავსებადი მეთოდი '{0}'-თვის. +მონაცემების შეცდომა '{0}'-ში. ფაილი დაზიანებულია. +CRC-ის შეცდომა '{0}'-ში. ფაილი დაზიანებულია. +მონაცემების შეცდომა დაშიფრულ ფაილში '{0}'. არასწორი პაროლი? +CRC ჩაიშალა დაშიფრულ ფაილში '{0}'. არასწორი პაროლი? +3800 +პაროლის შეყვანა +შეიყვანეთ პაროლი: +პაროლი ხელახლა: +პაროლის &ჩვენება +პაროლები არ დაემთხვა +პაროლად შეიყვანეთ მხოლოდ ლათინური ასოები, ციფრები და განსაკუთერებული სიმბოლოები (!, #, $, ...) +პაროლი მეტისმეტად გრძელია +პაროლი +3900 +გასული დრო: +დარჩენილი დრო: +ჯამური ზომა: +სიჩქარე: +დამუშავებული: +შეკუმშვის დონე: +შეცდომა: +არქივები: +4000 +არქივში ჩამატება +&არქივი: +&განახლების რეჟიმი: +არქივის &ფორმატი: +შეკუმშვის &დონე: +შეკუმშვის &მეთოდი: +&ლექსიკონის ზომა: +&სიტყვის ზომა: +უწყვეტი ბლოკის ზომა: +CPU ნაკადების ოდენობა: +&პარამეტრები: +დამატებითი +შეიქმნას SF&X არქივი +გაზიარებული ფაილების შეკუმშვა +დაშიფრვა +დაშიფრვის მეთოდი: +ფაილთა &სახელების დაშიფრვა +მეხსიერება შეკუმშვისათვის: +მეხსიერება ამოღებისათვის: +4050 +შეკუმშვის გარეშე +უსწრაფესი +სწრაფი +ჩვეულებრივი +მაღალი +უმაღლესი +4060 +ფაილთა დამატება და შეცვლა +ფაილთა განახლება და დამატება +ფაილთა განახლება +ფაილთა სინქრონიზება +4070 +დათვალიერება +ყველა ფაილი +წყვეტილი +უწყვეტი +6000 +ასლის აღება +გადატანა +ასლის მოთავსება: +გადატანა: +ასლის აღება... +გადატანა... +გადარქმევა... +აირჩიეთ დანიშნულების საქაღალდე. +ქმედება შუთავსებელია მიმდინარე საქაღალდესთან. +ფაილის ან საქაღალდის გადარქმევის შეცდომა +ფაილის ასლის შექმნის დასტური +ნადმვილად გსურთ ფაილების არქივში ჩამატება +6100 +ფაილის წაშლის თანხმობა +საქაღალდის წაშლის თანხმობა +რამდენიმე ფაილის წაშლის თანხმობა +დარწმუნებული ხართ, რომ გინდათ წაშალოთ '{0}'? +დარწმუნებული ხართ, რომ გინდათ წაშალოთ '{0}' საქაღალდე და მთელი მისი შიგთავსი? +დარწმუნებული ხართ, რომ გინდათ წაშალოთ {0} ელემენტები? +იშლება... +ფაილის ან საქაღალდის წაშლის შეცდომა +სისტემას არ შეუძლია გადაიტანოს სანაგვე ყუთში ფაილი მეტისმეტად გრძელი მისამართით. +6300 +საქაღალდის შექმნა +ფაილის შექმნა +საქაღალდის სახელი: +ფაილის სახელი: +ახალი საქაღალდე +ახალი ფაილი +შეცდომა საქაღალდის შექმნისას +შეცდომა ფაილის შექმნისას +6400 +კომენტარი +&კომენტარი: +მონიშვნა +მონიშვნის გაუქმება +ნიღაბი: +6600 +თვისებები +საქაღალდეთა ისტორია +დიაგნოსტიკური შეტყობინება +შეტყობინება +7100 +კომპიუტერი +ქსელი +დოკუმენტები +სისტემა +7200 +დამატება +ამოღება +შემოწმება +ასლი +გადატანა +წაშლა +ცნობები +7300 +ფაილის დაყოფა +&დაიყოფა: +დაიყოს &ტომებად, ზომით (ბაიტებში): +დაყოფა... +დაყოფის დასტური +ნამდვილად გსურთ ფაილის დაყოფა {0} ნაწილად? +ნაწილის ზომა უნდა იყოს საწყისი ფაილის ზომაზე ნაკლები +ნაწილის ზომა მიუღებელია +მითითებული ნაწილის ზომა: {0} ბაიტი.\nნამდვილად გსურთ ასეთი ზომის ნაწილებას დაყოთ ფაილი? +7400 +ფაილების შეერთება +&შეერთება: +შეერთება... +მონიშნეთ დაყოფილი ფაილის მხოლოდ პირველი ნაწილი +როგორც ჩანს, ფაილი არ წარმოადგენს დაყოფილი ფაილის ნაწილს +ვერ მოიზებნა დაყოფილი ფაილის ერთზე მეტი ნაწილი +7500 +საკონტროლო ჯამის დათვლა... +საკონტრლო ჯამის შესახებ +CRC ჯამი მონაცემთათვის: +CRC ჯამი სახელთა და მონაცემთათვის: +7600 +წარმადობის შემოწმება +გამოყენებული მეხსიერება: +შეკუმშვა +გაშლა +შეფასება +საერთო შეფასება +მიმდინარე +შემაჯამებელი +CPU დატვირთვა +შეფას./დატვირთვა +გატარება: diff --git a/Utils/7-Zip/Lang/kaa.txt b/Utils/7-Zip/Lang/kaa.txt new file mode 100644 index 000000000..0ac118e38 --- /dev/null +++ b/Utils/7-Zip/Lang/kaa.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Atabek Murtazaev +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Karakalpak - Latin +Qaraqalpaqsha - Latın +401 +OK +Biykar etiw + + + +&Awa +&Yaq +&Jabıw +Ja'rdem + +&Dawam etiw +440 +&Barlıg'ına awa +Ba&rlıg'ına yaq +Toqtatıw +Qaytadan baslaw +&Artqı fong'a +Aldıng'ı &fong'a +&Pauza +Pauza qılıng'an +Anıq biykar etiwdi qa'leysizbe? +500 +&Fayl +&Du'zetiw +&Ko'rinis +&Saylandılar +A's&baplar +&Ja'rdem +540 +&Ashıw +&İshinde ashıw +&Sırtında ashıw +&Ko'riw +&Du'zetiw +Atın o'&zgertiw +Bul jerge &nusqasın alıw... +Bul jerge ko'shiriw... +O'shiriw +&Fayldı bo'liw... +Fayllardı &biriktiriw... +Sazlawla&r +Kom&mentariy... +Qadag'alaw summası +Diff +Papka jaratıw +Fayl jaratıw +Sh&ıg'ıw +600 +Barlıg'ın &saylaw +Saylawdı alıp taslaw +Saylawdı &teris awdarıw +Saylaw... +Saylawdı alıp taslaw... +Tu'ri boyınsha saylaw +Tu'ri boyınsha saylawdı alıp taslaw +700 +U'&lken ikonalar +Kishi &ikonalar +&Dizim +&Keste +730 +Ta'rtipsiz +Tegis ko'rinis +&2 panel +&A'sbaplar paneli +Derek papkasın ashıw +Bir da'reje joqarıg'a ko'teriliw +Papkalar tariyxı... +&Jan'alaw +750 +Arxivator knopkalar paneli +Standart knopkalar paneli +U'lken knopkalar +Knopkalar tekstin ko'rsetiw +800 +&Papkanı saylandılarg'a qosıw +Belgi +900 +&Sazlawlar... +&O'nimlilikti tekseriw +960 +&Mazmunı... +&7-Zip haqqında... +1003 +Jol +Atı +Ken'eytpe +Papka +Ko'lemi +Qısılg'andag'ı ko'lemi +Attributları +Jaratılg'an +Ashılg'an +O'zgertilgen +U'ziliksiz +Kommentariy berilgen +Shifrlengen +deyin bo'lingen +keyin bo'lingen +So'zlik +CRC +Tu'ri +Anti +Usıl +Basqarıwshı OS +Fayl sisteması +Paydalanıwshı +Topar +Blok +Kommentariy +Ornı +Jol prefiksi +Papkalar +Fayllar +Versiya +Tom +Ko'p tomlı +Jıljıw +Siltewler +Bloklar +Tomlar + +64-bit +Big-endian +Protsessor +Fizikalıq ko'lemi +Baslama ko'lemi +Qadag'alaw summası +Xarakteristika +Virtual adresi +ID +Qısqa atı +Jaratıwshı bag'darlama +Sektor ko'lemi +Rejim +Siltew +Qa'te +Ulıwma ko'lem +Bos orın +Klaster ko'lemi +Belgi +Jergilikli atı +Provayder +2100 +Sazlawlar +Til +Til: +Redaktor +&Redaktor: +&Diff: +2200 +Sistema +To'mendegi fayllardı 7-Zip penen baylanıstırıw: +2301 +7-Zip ti qabıq kontekst menyuine qosıw +Kaskadlı kontekst menyu +Kontekst menyu elementleri: +2320 + + +Arxivti ashıw +Fayllardı shıg'arıp alıw... +Arxivke qosıw... +Arxivti sınaw +Usı jerge shıg'arıw +Mına jerge shıg'arıw: {0} +Mınag'an qosıw: {0} +Qısıw ha'm email arqalı jiberiw... +Mınag'an qısıw: {0} ha'm email arqalı jiberiw +2400 +Papkalar +&İslewshi papka +&Sistemanın' waqtınshalıq papkası +Ha'zirgi &papka +&Ko'rsetilgen: +Tek alınbalı tasıg'ıshlar ushın paydalanıw +Waqtınshalıq arxiv fayllardın' ornın ko'rsetin'. +2500 +Sazlawlar +".." elementti ko'rsetiw +Fayldın' haqıyqıy ikonaların ko'rsetiw +Sistema menyuin ko'rsetiw +&Tolıq joldı saylaw +Tor &sızıqların ko'rsetiw +Elementti bir basıwdan ashıw +Saylawdın' &alternativ usılı +U'lken &yad betlerin paydalanıw +2900 +7-Zip haqqında +7-Zip bul biypul bag'darlama +3000 +Sistema kerekli bolg'an yad mug'darın ajırata almadı +Qa'te tabılmadı +{0} obekt saylang'an +'{0}' papkasın jaratıw iske aspadı +Bul arxiv ushın jan'alaw operatsiyaları qollanılmaydı. +'{0}' faylın arxiv sıpatında ashıw iske aspadı +Shifrlang'an '{0}' arxivin ashıw iske aspadı. Parol qa'te emespe? +Qollanbaytug'ın arxiv tu'ri +{0} faylı a'lle qashan bar (jaratılg'an) +'{0}' faylı o'zgertilgen.\nOnı arxiv ishinde jan'alawdı qa'leysizbe? +Mına fayldı jan'alaw iske aspadı\n'{0}' +Redaktordı ashıw iske aspadı. +Fayl virusqa uqsaydı (fayl atında uzın bos orınlar qollanılg'an). +Operatsiya uzun jollı papkadan ju'klene almaydı. +Siz bir fayl saylawın'ız kerek +Siz bir yamasa onnan ko'p fayllardı saylawın'ız kerek +Elementler sanı dım ko'p +3300 +Shıg'arılmaqta +Qısılmaqta +Sınaw +Ashılmaqta... +Skanerlenbekte... +3400 +Shıg'arıw +&Bul jerge shıg'arıw: +Shıg'arılatug'ın fayllar ushın orın ko'rsetin'. +3410 +Jol usılı +Tolıq jol atları +Jolsız +3420 +U'stinen jazıw usılı +U'stine jazıwdan aldın soraw +Soramastan u'stine jazıw +Aldınnan bar fayllardı o'tkizip jiberiw +Avtomat ta'rizde qayta at beriw +Aldınnan bar fayllarg'a avtomat ta'rizde qayta at beriw +3500 +Fayldın' u'stinen jazıwdı tastıyqlaw +Tayınlang'an papka a'lle qashan islengen fayldı o'z ishine alg'an. +Siz bar fayldı +mına fayl menen almastırıwdı qa'leysizbe? +{0} bayt +A&vtomat ta'rizde qayta at beriw +3700 +'{0}' faylı ushın tanıs bolmag'an qısıw usılı. +'{0}' faylında mag'lıwmat qa'tesi tabıldı. Fayl buzılg'an. +'{0}' faylında CRC qa'tesi tabıldı. Fayl buzılg'an. +'{0}' shifrlang'an faylında mag'lıwmat qa'tesi tabıldı. Parol qa'te emespe? +'{0}' shifrlang'an faylında CRC qa'tesi tabıldı. Parol qa'te emespe? +3800 +Paroldi kiritiw +Paroldi kiritin': +Paroldi qayta kiritin': +Paroldi &ko'rsetiw +Paroller sa'ykes kelmedi +Parol ushın tek latın a'lipbesi ha'riplerin, sanlar ha'm arnawlı simvollardı (!, #, $, ...) paydalanın' +Parol dım uzın +Parol +3900 +O'tken waqıt: +Qalg'an waqıt: +Tolıq ko'lem: +Tezlik: +İslengen ko'lem: +Qısıw da'rejesi: +Qa'teler: +Arxivler: +4000 +Arxivke qosıw +&Arxiv: +&Jan'alaw usılı: +Arxiv &formatı: +Qısıw &da'rejesi: +Qısıw &usılı: +&So'zlik ko'lemi: +So'z &ko'lemi: +Blok ko'lemi: +CPU ag'ımlar sanı: +&Parametrler: +Sazlawlar +SF&X arxivin jaratıw +Jazıw ushın ashılg'an fayllardı qısıw +Shifrlaw +Shifrlaw usılı: +Fayl a&tların shifrlaw +Qısıwg'a arnalg'an yad: +Ajıratıwg'a arnalg'an yad: +4050 +Qısıwsız +En' tez +Tez +Qa'dimgi +En' joqarı +Ultra +4060 +Fayllardı qosıw ha'm almastırıw +Fayllardı jan'alaw ha'm qosıw +Bar fayllardı jan'alaw +Fayllardı sinxronlastırıw +4070 +Belgilew +Barlıq fayllar +Fayl ko'lemi boyınsha +U'ziliksiz +6000 +Nusqasın alıw +Ko'shiriw +Mına papkag'a nusqasın alıw: +Mına papkag'a ko'shiriw: +Nusqa alınbaqta... +Ko'shirilmekte... +Qayta at berilmekte... +Papkanı saylan'. +Ko'rsetilgen operatsiya bul papka ushın qollanılmaydı. +Fayl yaki papkag'a qayta at beriwde qa'te ju'z berdi +Fayldın' nusqasın alıwdı tastıyqlan' +Siz bul fayllardı anıq arxivke ko'shiriwdi qa'leysizbe +6100 +Fayl o'shiriliwin tastıyqlaw +Papka o'shiriliwin tastıyqlaw +Fayllar toparının' o'shiriliwin tastıyqlaw +'{0}' degendi anıq o'shiriwdi qa'leysizbe? +'{0}' papkası ha'm onın' ishindegilerdi anıq o'shiriwdi qa'leysizbe? +Bul obektlerdi ({0} dana) anıq o'shiriwdi qa'leysizbe? +O'shirilmekte... +Fayl yaki papkanı o'shiriwde qa'te ju'z berdi +Sistema uzın jollı fayllardı sebetke ko'shire almaydı +6300 +Papka jaratıw +Fayl jaratıw +Papka atı: +Fayl atı: +Jan'a papka +Jan'a fayl +Papkanı jaratıwda qa'te ju'z berdi +Fayldı jaratıwda qa'te ju'z berdi +6400 +Kommentariy +&Kommentariy: +Saylaw +Saylawdı alıp taslaw +Maska: +6600 +Sazlawlar +Papkalar tariyxı +Diagnostik xabarlar +Xabar +7100 +Kompyuter +Tarmaq +Hu'jjetler +Sistema +7200 +Qosıw +Shıg'arıw +Sınaw +Nusqa alıw +Ko'shiriw +O'shiriw +Mag'lıwmat +7300 +Fayldı bo'liw +&Mınag'an bo'liw: +Tomlarg'a &bo'liw (baytlarda): +Bo'linbekte... +Bo'liwdi tastıyqlan' +Siz fayldı {0} bo'lekke anıq bo'liwdi qa'leysizbe? +Bo'lek ko'lemi original fayl ko'leminen kishi bolıwı kerek +Tom ko'lemi natuwrı berilgen +Tomnın' ko'rsetilgen ko'lemi: {0} bayt.\nArxivti bunday tomlarg'a anıq bo'liwdi qa'leysizbe? +7400 +Fayllardı biriktiriw +&Mınag'an biriktiriw: +Biriktirilmekte... +Bo'lingen fayldın' tek birinshi bo'legin saylaw kerek +Fayl bo'lingen fayldın' bo'legi retinde tanılmadı +Bo'lingen fayldın' birden ko'p bo'legi tabılmadı +7500 +Qadag'alaw summasın esaplaw... +Qadag'alaw summası mag'lıwmatı +Mag'lıwmatlar ushın CRC qadag'alaw summası: +Mag'lıwmatlar ha'm atamalar ushın CRC qadag'alaw summası: +7600 +O'nimlilikti tekseriw +Yad ko'lemi: +Qısıw +Ajıratıw +Reyting +Ulıwma reyting +Ha'zirgi +Ja'mi +Awırlıq +Reyting / Awır. +O'tkenler: diff --git a/Utils/7-Zip/Lang/kk.txt b/Utils/7-Zip/Lang/kk.txt new file mode 100644 index 000000000..0db20e07a --- /dev/null +++ b/Utils/7-Zip/Lang/kk.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Arslan Beisenov, Arman Beisenov +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Kazakh +Қазақша +401 +Жарайды +Болдырмау + + + +&Иә +&Жоқ +&Жабу +Анықтама + +&Жалғастыру +440 +Бәріне &ия +Бәріне &жоқ +Тоқтату +Қайта іске қосу +&Фонды +&Алдыңғы жоспарға +&Үізілс +Үзілісте +Операцияны тоқтату керек пе? +500 +&Файл +&Өңдеу +&Көрініс +&Таңдаулы +С&ервис +&Анықтама +540 +&Ашу +Ішінен &ашу +Сыртынан ашу +Қарау +&Өңдеу +Қайта атау +&Көшіру... +&Жылжыту... +&Жою +Файлды бөлшектеу... +Файлды біріктіру... +Сипаттар +Комме&нтарий... +Бақылау сомасы +Diff +&Қалта жасау +Файл жасау +Шығу +600 +Бәрін ерекшелеу +Ерекшелеуді аластау +&Ерекшелеуді көрсету +Ерекшелеу... +Ерекшедеужі аластау... +Түрі б-ша ерекшелеу +Түрі б-ша ерекшелеуді аластау +700 +&Үлкен таңбаша +&Кішк. таңбаша +Тізім +&Кесте +730 +Сұрыптаусыз +Жалпақ режим +&2 тақта +&Құралдар тақтасы +Негізгі қалтады ашу +Бір деңгей жоғары өту +Қалта тарихы... +Жаңарту +750 +Мұрағаттауыш батырма тақтасы +Батырманың кәдімгі тақтасы +Үлкен батырмалар +Батырмада жазулар +800 +Қалтаны таңдаулыға басқаша үстеу +Таңдаулы +900 +Баптау... +Өнімді тестілеу +960 +&Басты... +Бағдарламада... +1003 +Жол +Аты +Кеңейтімі +Қалта +Көлем +Сығылған +Атрибут +Жасалған +Ашылған +Өзгерген +Үзіліссіз +Комментарий +Шифрланған +дейін бөлінген +кейін бөлінген +Сөздік +CRC +Түрі +Анти +Тәсіл +Жүйе +Файлдық жүйе +Пайдаланушы +Топ +Блок +Комментарий +Орны +Жолы +Қалта +Файл +Нұсқа +Том +Көп томды +Жылжу +Сілтеме +Блок +Том + +64-bit +Big-endian +Процессор +Физикалық көлемі +Тақырып көлемі +Бақылау сомасы +Характеристика +Виртуальды мекен-жай +ID +Қысқа аты +Жасаушы +Сектор көлемі +Режим +Сілтеме +Қателік +Сыйымы +Бос +Кластер көлемі +Белгі +Жергілікті аты +Провайдер +2100 +Баптау +Тіл +Тіл: +Өңдегіш +&Өңдегіш: +&Diff: +2200 +Жүйе +7-Zip файлмен ассорциялау: +2301 +Мұқабаның мәтінміндің мәзіріне 7-Zip қою +Каскадты мәтінмәндік мәзір +Мәтінміндік мәзірдің элементтері: +2320 +<Қалта> +<Мұрағат> +Мұрағат ашу +Бумадан шешу +Мұрағатқа үстеу... +Тестілеу +Мұнда шешу +{0} дегенде шешу +{0} дегенге үстеу +Сығып э-поштамен жіберу... +{0} дегенде сығып, э-поштамен жіберу +2400 +Қалта +&Жұмыс қалтасы +&Жүйелік уақытша қалта +&Ағымдық +&Сұрау: +Тек алмалы тасығыштарға ғана пайдалану +Уақытша мұрағаттардың орнын нұсқаңыз. +2500 +Баптау +".." элементті көрсету +Файлдың шынайы таңбашасын көрсету +Жүйелік мәзірді көрсету +Барлық жолаққа меңзер +Бөлгіштерді көрсету +Бір шерткеннен ашу +Белгілеудің альтернативті режимі +Жадтың үлкен беттерін пайдалану +2900 +7-Zip туралы +7-Zip - тегін таратылатын бағдарлама. +3000 +Бос жад жоқ +Қателік табылған жоқ +Ерекшеленген нысан: {0} +'{0}' қалтасын жасау мүмкін емес +Көтермейтін мұрағат үшін операция өзгертіледі. +'{0}' файлды мұрағат ретінде ашу мүмкін емес +Шифрланған '{0}' мұрағатты ашу мүмкін емес. Кілтсөз дұрыс емес пе? +Көтермейтін мұрағат түрі +{0} деген файл бар +'{0}' файлы өзгерді.\nОны мұрағатта жаңарту керек пе? +\n'{0}' файлды жаңарту мүмкін емес +Өңдегішті ашу мүмкін емес +Файл вирусқа ұқсайды (файл аты ұзақ жолды мәселені құрайды). +Операция қалтаға жолдың ұзақтығынан орындалмайды +Сізге бір файл таңдау керек +Сізге бір не бірнеше файл таңдау керек +Өте көп элемент +3300 +Шешу +Компрессия +Тестілеу +Ашылу... +Сканерлеу... +3400 +Шығару +&Мұнда шешу: +Шығарылатын файл орнын нұсқаңыз. +3410 +Жолдар +&Толық жол +&Жолсыз +3420 +Қайта жазу +&Растаумен +&Растаусыз +Өткізіп &жіберу +Автоматты қайта атау. +Бар файлды автом. қайта атау +3500 +Файлды ауыстыру растау +Қалтада іс жүргізілетін файл бар. +Файлды ауыстыру +келесі файлмен ба? +{0} байт +Автоматты қайта атау +3700 +'{0}' файлы үшін сығу әдісін көтермейді. +'{0}' мәліметінде қателік. Файл зақымдалған. +'{0}' CRC қателік. Файл зақымдалған. +Шифрланған '{0}' файлында мәліміт қате. Кілтсөз дұрыс емес пе? +Шифрланған '{0}' файлында CRС қате. Кілтсөз дұрыс емес пе? +3800 +Кілтсөзді енгізу +&Кілтсөзді енгізіңіз: +&Кілтсөзді қайталаңыз: +&Кілтсөзді көрсету +Кілтсөздер сәйкес емес +Кілтсөзге тек ағылшын әліпбиін пайдаланыңыз, сандар және арнайы нышандар (!, #, $, ...) +Кілтсөз өте ұзақ +&Кілтсөз +3900 +Өтті: +Қалды: +Барлығы: +Жылд.: +Көлем: +Сығу дәрежесі: +Қате: +Мұрағат: +4000 +Мұрағатқа үстеу +&Мұрағат: +&Өзгерту режимі: +&Мұрағат пішімі: +&Сығу деңгейі: +&Сығу тәсілі: +Сөздік &көлемі: +Сөз &көлемі: +Блог көлемі: +Ағым саны: +&Параметр: +&Баптау +SF&X-мұрағат жасау +Ашылған файд жазу үшін сығу +Шифрлау +Шифрлау тәсілі: +&Файлдың атын шифрлау +Бууға арналған көлем: +Шешуге арналған көлем: +4050 +Сығусыз +Жылдам +Шапшаң +Кәдімгі +Ең жоғарғы +Ультра +4060 +Үстеу, ауыстыру +Жаңарту, үстеу +Жаңату +Теңестіру +4070 +Сапыру +Барлық файл +Файл көлемі б-ша +Үзіліссіз +6000 +Көшіру +Жылжыту +Мұнда көшіру: +Мұнда жылжыту: +Көшіру... +Жылжыту... +Атын өзгерту... +Қалтаны нұсқаңыз +Бұл қалтаға операция көтермейді. +Файл не қалтаның атын өзгерту мүмкін емес +Файлды көшіруді растау +Мына файлдарды мұрағатқа көшіру керек пе +6100 +Файлды жоюды растау +Қалтаны жоюды растау +Бірнеше файлды жоюды растау +"{0}" дегенді жою керек пе? +"{0}" қалтасын және оның ішіндегілерін жою керек пе? +({0} дана) нысандарды жою керек пе? +Жойылу... +Файл не қалтаны жою қате +Ұзақ жолды файлдарды себетке жоюды жүйе көтермейді +6300 +Қалта жасау +Файл жасау +Қалта аты: +Файл аты: +Жаңа қалта +Жаңа файл +Қалтаны жасау қате +Файлды жасау кезінде қателік болды +6400 +Комментарий +&Комментарий: +Ерекшелеу +Аластау +Маска: +6600 +Сипаттар +Қалта тарихы +Хабарлама +Хабарлама +7100 +Компьютер +Желі +Құжаттар +Жүйе +7200 +Үстеу +Шығару +Тестілеу +Көшіру +Жылжыту +Жою +Ақпарат +7300 +Файлды бөлшектеу +&Бөлшектеу: +Томға бөлшектеу (байтқа): +Бөлшектеу... +Бөлшектеуді растау +Файлд {0} бөлікке бөлшектеу керек пе? +Том көлемі файлдың кіріс көлемінен аз болу керек +Томның көлемін енгізу қате +Томның орнатылған көлемі: {0} байт.\nМұрағатты томға бөлшектеу керек пе? +7400 +Файлдарды біріктіру +&Мұнда біріктіру: +Біріктіру... +Бөлшектенген файлдың бірінші бөлігін таңдау керек +Бөлшектенген файлды тану мүмкін емес +Бөлшектенген файлдың бөліктерін табу мүмкін емес +7500 +Бақылау сомасын есептеу... +Бақылау сомасы +Мәлімет үшін CRC бақылау сомасы: +Мәлімет және атау үшін CRC бақылау сомасы: +7600 +Өнімділікке тестілеу +Жад көлемі: +Буу +Шешу +Рейтинг +Жалпы рейтинг +Ағымдық +Нәтижесі +Ауырлық +Рейтинг / Жеңіс. +Өтулер: diff --git a/Utils/7-Zip/Lang/ko.txt b/Utils/7-Zip/Lang/ko.txt new file mode 100644 index 000000000..5e9644d58 --- /dev/null +++ b/Utils/7-Zip/Lang/ko.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : ZannyLim (임재형) +; : bzImage +; 4.52 : Hyeong il Kim (kurt Sawyer) +; 9.07 : Dong-yoon Han (한동윤) +; 15.12 : Winterscenery (Ji-yong BAE) +; 16.02 : Add translation and Modify Typos by Winterscenery (Ji-yong BAE) +; +; +; +; +; +0 +7-Zip +Korean +한국어 +401 +확인 +취소 + + + +예(&Y) +아니오(&N) +닫기(&C) +도움말 + +계속(&C) +440 +모두 예(&A) +모두 아니오(&L) +중지 +다시 시작 +낮은 순위로(&B) +우선 순위로(&F) +일시정지(&P) +일시정지 됨 +정말로 취소하시겠습니까? +500 +파일(&F) +편집(&E) +보기(&V) +즐겨찾기(&A) +도구(&T) +도움말(&H) +540 +열기(&O) +내부 열기(&I) +외부 열기(&U) +파일 뷰어(&V) +편집(&E) +새 이름(&M) +복사(&C)... +이동(&M)... +삭제(&D) +파일 나누기(&S)... +파일 합치기(&B)... +속성(&R) +설명(&N)... +체크섬 계산 +파일 비교 +폴더 만들기 +파일 만들기 +끝내기(&X) +연결 +대체 데이터 스트림(&A) +600 +모두 선택(&A) +모두 선택 취소 +선택 항목 반전(&I) +선택... +선택 취소... +파일 형식으로 선택 +파일 형식으로 선택 취소 +700 +큰 아이콘(&G) +작은 아이콘(&M) +목록(&L) +자세히(&S) +730 +정렬 안함 +펼쳐 보기 +2 패널(&2) +도구 모음(&T) +최상위 폴더 열기 +한단계 위로 +폴더 히스토리... +새로 고침(&R) +자동 새로 고침 +750 +압축 도구 모음 +표준 도구 모음 +큰 버튼 +버튼 텍스트 보기 +800 +즐겨찾기에 추가(&A) +북마크 +900 +옵션(&P)... +벤치마크(&B) +960 +도움말 항목(&C)... +7-Zip 정보(&A)... +1003 +경로 +이름 +확장자 +폴더 +크기 +압축된 크기 +속성 +만든 날짜 +액세스한 날짜 +수정한 날짜 +솔리드 +설명 +암호화 +나누기 이전 +나누기 후 +사전 +CRC +형식 +안티 +압축 방식 +생성한 OS +파일 시스템 +사용자 +그룹 +블럭 +설명 +위치 +경로 접두 +폴더 +파일 +버전 +볼륨 +다중볼륨 +오프셋 +연결 +블록 +볼륨 + +64-bit +Big-endian +CPU +물리적 크기 +해더 크기 +체크섬 +특성 +가상 주소 +ID +짧은 이름 +생성 응용프로그램 +섹터 크기 +모드 +기호 연결 +오류 +전체 크기 +여유 공간 +클러스터 크기 +라벨 +로컬 이름 +제공자 +NT 보안 +대체 데이터 스트림 +보조 +삭제 +Is Tree + + +오류 유형 +오류 +오류 +경고 +경고 +스트림 +대체 데이터 스트림 +대체 데이터 스트림 크기 +가상 크기 +압축 해제 후 크기 +용량 실제 크기 +볼륨 인덱스 +보조형식 +주석 +코드 페이지 + + + +테일 크기 +임베디드 스텁 크기 +연결 +하드 연결 +i노드 + +읽기 전용 +2100 +옵션 +언어 +언어: +편집기 +파일 편집기(&E): +파일 비교(&D): +2200 +시스템 +7-Zip 으로 연결: +모든 사용자 +2301 +7-Zip 탐색기 메뉴 사용 +탐색기 메뉴 계단식 보기 +탐색기 메뉴 항목: +탐색기 메뉴 아이콘 보기 +2320 +<폴더> +<압축파일> +압축파일 열기 +압축 풀기... +압축파일에 추가... +압축파일 테스트 +여기에 압축 풀기 +{0}에 풀기 +{0}에 추가 +압축해서 이메일 보내기 +{0}로 압축해서 이메일 보내기 +2400 +폴더 +작업 폴더(&W) +시스템 임시 폴더(&S) +현재 폴더(&C) +지정 폴더(&S): +이동식 드라이브에서만 사용 +압축에 관계된 파일이 임시적으로 사용할 위치 지정. +2500 +설정 +상위 폴더 ".." 항목 보기 +실제 파일 아이콘 보기 +시스템 메뉴 보기 +행 전체 선택(&F) +눈금선 보기(&G) +한 번 클릭으로 항목 열기 +우선 선택적 선택 모드 +큰 메모리 페이지 사용 +2900 +7-Zip 정보 +7-Zip 은 무료 소프트웨어입니다. +3000 +시스템이 필요한 양의 메모리를 할당할 수 없음 +오류 없음 +{0} 항목이 선택됨 +'{0}' 폴더를 생성할 수 없음 +업데이트 작업이 이 압축파일에서는 지원되지 않습니다. +파일 '{0}'을(를) 압축파일로 열 수 없음 +암호화된 압축파일 '{0}'을(를) 열 수 없습니다. 잘못 입력된 암호? +지원되지 않는 압축파일 유형 +{0} 파일은 이미 존재함 +파일 '{0}'이 수정되었습니다.\n압축파일에 업데이트 하시겠습니까? +'{0}' 파일을 업데이트 할 수 없습니다. +편집기를 시작할 수 없습니다. +해당 파일이 바이러스 같습니다 (파일 이름에 길다란 공백이 들어있음). +긴 경로로된 폴더에서 해당 작업을 호출할 수 없습니다. +반드시 한 개의 파일을 선택해야함 +반드시 한 개 이상의 파일을 선택해야 함 +항목이 너무 많음 +{0} 압축파일로 파일을 열 수 없습니다 +{0} 압축파일로 파일이 열리고 있습니다 +압축파일 오프셋을 사용하여 열려 있습니다 +3300 +압축 푸는 중 +압축하는 중 +검사 중 +여는 중... +검색 중... +삭제 중 +3320 +추가 중 +업데이트 중 +분석 중 +덮어 쓰는 중 +다시 압축 중 +건너뛰는 중 +삭제 중 +헤더 작성 중 +3400 +압축 풀기 +압축 풀기(&X): +압축 풀린 파일의 위치를 지정합니다. +3410 +경로 모드 +전체 경로명 +경로명 없음 +절대 경로명 +상대 경로명 +3420 +덮어쓰기 모드 +덮어쓰기 전에 확인 +물어보지 않고 덮어쓰기 +존재하는 파일 건너뛰기 +자동으로 이름 바꾸기 +존재하는 파일 이름 바꾸기 +3430 +최상위 폴더의 중복을 방지 +파일 보안 속성을 복원 +3500 +파일 덮어쓰기 확인 +대상 폴더에 이미 파일이 존재합니다. +존재하는 파일을 +이것으로 덮어쓰기 하시겠습니까? +{0} 바이트 +자동으로 이름 바꾸기(&U) +3700 +'{0}'은 지원하지 않는 압축 방식입니다. +'{0}'에 데이터 오류가 있습니다. 파일이 손상되었습니다. +'{0}'의 CRC 검사를 실패했습니다. 파일이 손상되었습니다. +암호화 파일 '{0}'에 데이터 오류가 있습니다. 암호가 틀리나요? +암호화 파일 '{0}'의 CRC 검사를 실패했습니다. 암호가 틀리나요? +3710 +잘못 입력된 암호? +3721 +지원하지 않는 압축 방법 +데이터 오류 +CRC가 다릅니다 +사용할 수없는 데이터 +데이터의 예기치 않은 종료 +페이로드 데이터의 종료 후에 일부 데이터가있다. +압축되지 않습니다. +헤더 오류 +암호가 잘못되었습니다. +3763 +사용할 수 없는 시작의 압축파일 +확인되지 않는 시작의 압축파일 + + + +지원하지 않는 기능 +3800 +암호 입력 +암호 입력: +암호 다시 입력: +암호 보기(&S) +암호가 일치하지 않음 +암호로는 영문자, 숫자 그리고 특수 문자 (!, #, $, ...)만 사용 +암호가 너무 깁니다. +암호 +3900 +경과 시간: +남은 시간: +전체 크기: +속도: +처리됨: +압축 효율: +오류: +압축파일: +4000 +압축파일에 추가 +압축파일(&A): +업데이트 모드(&U): +압축파일 형식(&F): +압축 레벨(&L): +압축 방식(&M): +사전 크기(&D): +단어(word) 크기(&W): +솔리드 블록 크기: +CPU 스레드 수: +매개변수(&P): +옵션 +자동(SFX) 압축파일 생성(&X) +공유하고있는 파일 압축 +암호화 +암호화 방식: +파일 이름 암호화(&N) +압축시 사용 메모리: +압축 풀기시 사용 메모리: +압축 후 원본 파일을 삭제 +4040 +심볼릭 연결을 저장 +하드 연결을 저장 +대체 데이터 스트림을 저장 +파일 보안 속성을 저장 +4050 +저장 +가장 빠름 +빠름 +보통 +최고 +가장 느림 +4060 +파일을 추가하고 덮어쓰기 +파일을 업데이트하고 추가 +존재하는 파일만 새롭게 하기 +압축파일 내용을 동기화 +4070 +찾아보기 +모든 파일 +솔리드 사용 않함 +솔리드 +6000 +복사 +이동 +폴더로 복사: +폴더로 이동: +복사 중... +이동 중... +이름 바꾸는 중... +대상 폴더를 선택하세요. +지원되지 않는 작업입니다. +파일 또는 폴더 이름 바꾸기 실패 +파일 복사 확인 +파일을 압축파일로 복사 하시겠습니까? +6100 +파일 삭제 확인 +폴더 삭제 확인 +여러 파일 지우기 확인 +'{0}'을(를) 삭제하시겠습니까? +폴더 '{0}'와 그 모든 내용을 삭제하시겠습니까? +이 {0} 항목들을 삭제하시겠습니까? +삭제 중... +파일 또는 폴더 삭제 실패 +시스템이 긴 경로의 파일을 휴지통으로 이동할 수 없음 +6300 +폴더 만들기 +파일 만들기 +폴더 이름: +파일 이름: +새 폴더 +새 파일 +폴더 만들기 오류 +파일 만들기 오류 +6400 +설명 +설명(&C): +선택 +선택 취소 +마스크: +6600 +속성 +폴더 히스토리 +진단 메시지 +메시지 +7100 +컴퓨터 +네트워크 +문서 +시스템 +7200 +추가 +압축 풀기 +테스트 +복사 +이동 +삭제 +속성 +7300 +파일 분할하기 +분할하기(&S): +볼륨 나누기, 바이트(&V): +분할하는 중... +분할 확인 +정말 {0} 볼륨들로 분할 하시겠습니까? +볼륨 크기가 원본 파일보다 작아야만 합니다. +볼륨 크기가 부적절합니다. +지정된 볼륨 크기: {0} 바이트.\n이 볼륨 크기로 분할 하시겠습니까? +7400 +파일 합치기 +합치기(&B): +파일 합치는 중... +첫번째 파일만 선택하시오 +분할한 파일의 한 부분으로 인식할 수 없음 +분할 파일의 한 부분 이상을 찾을 수 없음 +7500 +체크섬 계산중... +체크섬 정보 +데이터 CRC 체크섬: +데이터와 이름 CRC 체크섬: +7600 +벤치마크 +메모리 사용량: +압축 중 +압축 푸는 중 +평가 +전체 평가 +현재 +결과 +CPU 사용량 +평가 / 사용량 +통과: +7700 +연결 +연결 만들기 +원본: +연결: +7710 +연결 유형 +하드 연결 +파일의 심볼릭 연결 +디렉토리의 심볼릭 연결 +디렉토리 접합 diff --git a/Utils/7-Zip/Lang/ku-ckb.txt b/Utils/7-Zip/Lang/ku-ckb.txt new file mode 100644 index 000000000..a6b52cea5 --- /dev/null +++ b/Utils/7-Zip/Lang/ku-ckb.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Ara Bakhtiar +; 4.66 : Ara Qadir : http://www.chawg.org +; +; +; +; +; +; +; +; +; +0 +7-Zip +Kurdish - Sorani +کوردی +401 +باشە +پاشگەزبوونەوە + + + +&بەڵێ +&نەخێر +&داخستن +یارمەتی + +&بەردەوامبوون +440 +بەڵێ بۆ &هەموو +نەخێر بۆ هە&موو +وەستاندن +دەستپێکردنەوە +&پاشەبنەما +پ&ێشەبنەما +&ڕاگرتن +ڕاگیردرا +دڵنیایت لە پاشگەزبوونەوە؟ +500 +&فایل +&دەستکاری +&بینین +د&ڵخوازەکان +&ئامڕازەکان +&یارمەتی +540 +&کردنەوە +کردنەوە لە&ناو خۆدا +کردنەوە لە &دەرەوە +&بینین +&دەستکاری +&ناوگۆڕین +&لەبەرگرتنەوە بۆ... +&گواستنەوە بۆ... +&سڕینەوە +&لەتکردنی پەڕگە... +&پێکەوە لکاندنی پەڕگەکان... +&تایبەتمەندییەکان +ل&ێدوان +ژماردنی checksum + +دروستکردنی بوخچە +دروستکردنی پەڕگە +دەر&چوون +600 +هەمووی دیاری بکە +هەموو دیاریکراوەکان لاببە +%پێچەوانەکردنەوەی دیاریکراو +دیاری بکە... +دیاری مەکە... +بە پێی جۆر دیاری بکە +لابردنی دیاریکراوەکان بەپێ جۆر +700 +ئایکۆنی &گەورە +ئایکۆنی &بچوک +&لیست +&وردەکاری +730 +ڕیزنەکراو +بینین بەشێوەی فلات +&2 پانێڵ +&جێ ئامڕاز +کردنەوەی بوخچەی ڕەگ +یەک ئاست بۆ سەرەوە +مێژووی بوخچەکان... +&بووژاندنەوە +750 +جێ ئامڕازی ئەرشیڤ +جی ئامڕازی بنچینە +دوگمەی گەورە +پیشاندانی دەقی دوگمەکان +800 +&زیادکردنی بوخچە بۆ دڵخوازەکان وەک +دڵخوازی +900 +&هەڵبژاردنەکان +&نیشانەی پێوان +960 +&ناوەڕۆکەکان... +&دەربارەی 7-Zip... +1003 +ڕێڕەو +ناو +پاشگر +بوخچە +قەبارە +قەبارەی پێچراو +تایبەتمەندی +دروستکراوە +بینراوە +دەستکاریکراوە +ڕەق +لێدوانی لەسەر دراوە +پارێزراو +لەتکردن پێش +لەتکردن پاش +فەرهەنگ +CRC +جۆر +دژ +ڕێباز +سیستەمی خانەخوێ +سیستەمی پەڕگە +بەکارهێنەر +گوروپ +بلۆک +لێدوان +جێگە +ـی ڕێڕەو Prefix +بوخچەکان +پەڕگەکان +وەشان +قەبارەکان +فرە قەبارە +Offset +بەستەرەکان +بلۆکەکان +قەبارەکان + +٦٤-بت +Big-endian +CPU +قەبارەی فیزیکی +قەبارەی سەر +کۆپشکنین +تایبەتمەندی +ناونیشانی ڕاستی + + + + + + +هەڵە +سەرجەمی قەبارە +بۆشایی بەتاڵ +قەبارەی کۆمەڵەکە +نیشان +ناوی ناوخۆیی +دابینکەر +2100 +ەەڵبژاردنەکان +زمان +زمان: +دەستکاریکەر +&دەستکاریکەر: + +2200 +سیستەم +7-Zip پەیوەست بکە بە: +2301 +7-Zip بکە نێو لیستەی مێنیوەوە +مێنیو بکە بە یەک هاوپۆل +کەرەستەکانی نێو مێنیو: +2320 +<بوخچە> +<ئەرشیڤ> +کردنەوەی ئەشیڤ +دەرکێشانی پەڕگەکان +زیادکردن بۆ ئەرشیڤ +تاقیکردنەوەی ئەرشیڤ +لێرە دەریبکێشە +دەرکێشان بۆ {0} +زیادکردنی بۆ {0} +پەستاندن و پەیامی ئەلیکترۆنی... +بیپەستێنە بۆ {0} و بە پەیامی ئەلیکترۆنی بینێرە +2400 +بوخچەکان +بوخچەی &کارکردن +بوخچەی کاتی &سیستەم +&ئێستایی +&دیاریکراو: +تەنها بۆ ئەو وەگەڕخەرانە بەکاری بهێنە کە توانای لابردنیان هەیە (removable disk) +شوێنێک دیاری بکە بۆ پەڕگە کاتییەکانی ئەرشیڤ. +2500 +ڕێکخستەکان +شتەکانی ".." پیشانبدە +ئایکۆنی ڕاستەقینەی پەڕگەکان پیشانبدە +مێنیوی سیستەم پیشانبدە +دیاریکردنی هەموو &ڕیزەکە +پیشاندانی هێڵە &grid ـەکان + +جۆری دیاریکردنی &جێگرەوە/ ئەڵتەرناتیڤ +پەڕەی بیرگەی &گەورە بەکارببە +2900 +7-Zip دەربارەی +7-Zip پڕۆگرامێکی خۆڕایە. لەگەڵ ئەوەشدا، ئەتوانی پاڵپشت بیت لە پەرەپێدانی 7-Zip. +3000 +سیستەم ناتوانێت بڕی پێویست لە بیرگە دابین بکات +هیچ هەڵەیەک نییە +{0} شت دیاریکراوە +ناتوانرێ بوخچەی '{0}' دروستبکرێت. +کارپێکردنی نوێکاری پاڵپشت نەکراوە بۆ ئەم ئەرشیڤە. +ناتوانرێت پەڕگەی '{0}' بکرێتەوە وەک ئەرشیڤ. +ناتوانرێت ئەرشیڤی پارێزراوی '{0}' بکرێتەوە. ئایا تێپەڕەوشە هەڵەیە؟ +جۆری ئەرشیڤ پاڵپشتی نەکراوە +پەڕگەی {0} پێشتر ەەیە +پەڕگەی '{0}' دەستکاریکراوە. ئەتەوێت لە ئەرشیڤەکەدا نوێی بکەیتەوە؟ +ناتوانرێ پەڕگەی \n'{0}' نوێبکرێتەوە +ناتوانرێ دەستکاریکەر دەستپێبکرێت. +پەڕگەکە لە ڤایرۆس دەچێت (ناوی پەڕگەکە بۆشایی زۆری تیادایە). +ناتوانرێت ئەو کردارە بانگبکرێت لە بوخچەیەکەوە کە ڕێڕەوێکی درێژی ەەیە. +پێویستە پەڕگەیەک دیاریبکەیت +پێویستە پەڕگەیەک یان زیاتر دیاریبکەیت +شتی(item) زۆر هەن +3300 +دەری دەکێشێ +دەی پەستێنێ... +تاقیدەکاتەوە +دەیکاتەوە... +دەی پشکنێت... +3400 +دەرکێشان +&دەرکێشان بۆ: +شوێنێک دیاری بکە بۆ پەڕگە دەرکێشراوەکان +3410 +جۆری ڕێڕەو +ناوی ڕێڕەوی تەواوەتی +ناوی ڕێڕەو نییە +3420 +جۆری بەسەردا نووسینەوە +بپرسە پێش بەسەردا نووسینەوە +بەسەردا بنووسەوە بەبێ ڕەزامەندی +پەڕگە هەبووەکان بپەڕێنە +خۆکار ناوگۆڕین +خۆکار ناوگۆڕینی پەڕگە هەبووەکان +3500 +دڵنیابە لە جێگرتنەوەی پەڕگە +بوخچەی مەبەست پەڕگەیەکی تیادایە بە هەمان ناو. +ئەتەوێت پەڕگە هەبووەکان جێبگیردرێتەوە؟ +لەگەڵ ئەم دانەیە؟ +{0} بایت +ناوگۆڕینی &خۆکار +3700 +ڕێبازێکی پاڵپشتی نەکراوی پەستاندن بۆ '{0}'. +زانیاری '{0}' هەڵەیە. پەڕگە تێکشکاوە. +CRC سەرکەوتوو نەبوو. پەڕگە تێکشکاوە. +زانیاری هەڵەیە لە پەڕگەی پارێزراودا '{0}'. ئایا تێپەڕەوشە هەڵەیە؟ +CRC هەڵەیە لە پەڕگەی پارێزراودا '{0}'. ئایا تێپەڕەوشە هەڵەیە؟ +3800 +نووسینی تێپەڕەوشە: +تێپەڕەوشە بنووسە: +تێپەڕەوشە بنووسەوە: +&پیشاندانی تێپەڕەوشە +تێپەڕەوشەکان وەک یەک نین +تەنها پیتە ئینگلیزییەکان، ژمارە و نووسە تیبەتییەکان ($، %، #) بۆ تێپەڕەوشە بەکاربهێنە +تێپەڕەوشە زۆر درێژە +تێپەڕەوشە +3900 +ک. دەستپێکردوو: +کاتی ماوە: +سەرجەمی قەبارە: +خێرایی: +جێبەجێکراوە: +ڕێژەی پەستاندن: +هەڵەکان: +ئەرشیڤەکان: +4000 +زیادکردن بۆ ئەرشیڤ +&ئەرشیڤ: +&جۆری نوێکاری: +&فۆڕماتی ئەرشیڤ: +&ئاستی پەستاندن: +&ڕێبازی پەستاندن: +قەبارەی &فەرەەنگ: +قەبارەی &وشە: +قەبارەی بلۆکی ڕەق: +ژمارەی دەزووەکانی CPU: +&هاوکۆڵکەکان: +هەڵبژاردنەکان +دروستکردنی ئەرشیڤی SF&X +پەستاندنی پەڕگە ئاڵوگۆڕکراوەکان +پاراستن +ڕێبازی پاراستن +&ناوی پەڕگەکان بپارێزە (encrypt) +ڕێژەی بەکارهێنانی بیرگە بۆ پەستاندان: +ڕێژەی بەکارهێنانی بیرگە بۆ کردنەوەی پەستێنراو: +4050 +پاشەکەوت +خێراترین +خێرا +ئاسایی +زۆرترین +سەروو +4060 +زیادکردن و جێگرتنەوەی پەڕگەکان +نوێکردنەوە و زیادکردنی پەڕگە +بووژاندنەوەی پەڕگە هەبووەکان +ـکردنی پەڕگەکان Synchronize +4070 +هەڵدەوە/ Browse +هەموو پەڕگەکان +نا-ڕەق +ڕەق +6000 +لەبەرگرتنەوە +گواستنەوە +لەبەرگتنەوە بۆ: +گواستنەوە بۆ: +لەبەری دەگرێتەوە... +دەیگوازێتەوە بۆ... +ناوی دەگۆڕێ... +بوخچەی مەبەست دیاری بکە. +ئەو کارە پاڵپشتی نەکراوە +هەڵە هەیە لە ناو گۆڕینی پەڕگە یان بوخچەکان. +دڵنیابە لە لەبەرگرتنەوەی پەڕگە +دڵنیایت لە لەبەرگرتنەوەی پەڕگەکان بۆ ئەرشیڤ؟ +6100 +دڵنیابە لە سڕینەوەی پەڕگە +دڵنیابە لە سڕینەوەی بوخچە +دڵنیابە لە سڕینەوەی هەموو پەڕگەکان +دڵنیایت لە سڕینەوەی '{0}'؟ +دڵنیایت لە سڕینەوەی بوخچەی '{0}' و هەموو ناوەڕۆکەکانی؟ +دڵنیایت لە سڕینەوەی ئەم {0} شتە؟ +دەی سڕێتەوە... +هەڵە هەیە لە سڕینەوەی پەڕگەکان یا بوخچەکان +سیستەم ناتوانێت پەڕگەیەک بگوێزێتەوە بۆ تەنەکەی خۆڵ بە ڕێڕەوی درێژەوە +6300 +دروستکردنی بوخچە +دروستکردنی پەڕگە +ناوی بوخچە: +ناوی پەڕگە: +بەخچەی نوێ +پەڕگەی نوێ +هەڵە هەیە لە دروستکردنی بوخچە +هەڵە هەیە لە دروستکردنی پەڕگەدا +6400 +لێدوان +&لێدوان: +دیاری بکە +دیاری مەکە +دەمامک: +6600 +تایبەتمەندییەکان +مێژووی بوخچەکان +پەیامی لێکۆڵینەوە/ پشکنین +پەیام +7100 +کۆمپیوتەر +ڕایەڵە +بەڵگەنامەکان +سیستەم +7200 +زیادکردن +دەرکێشان +تاقیکردنەوە +لەبەرگرتنەوە +گواستنەوە +سڕینەوە +زانیاری +7300 +لەتکردنی پەڕگە +&لەتی بکە بۆ: +لەتی بکە بۆ &قەبارە و بایت:‌ +لەتی دەکات... +دڵنیابە لە لەتکردن +دڵنیایت لە لەتکردنی پەڕگەی {0} بۆ دوو قەبارە؟ +پێویستە قەبارەی هەر یەک لە لەتەکان بچوکتربێت لە قەبارەی پەڕگە لەتکراوەکە +قەبارەی لەتکراوەکە هەڵەیە +قەبارەی دیاریکراوی لەتکراوەکە: {0} بایت.\nدڵنیایت لە لەتکردنی ئەرشیڤەکە بۆ ئەو قەبارانە؟ +7400 +پێکەوەلکاندنی پەڕگەکان +%پێکەوەی بلکێنە بۆ: +پێکەوەی دەلکێنێت... +تەنها پەڕگەی یەکەم دیاری بکە +ناتوانێت پەڕگە بدۆزێتەوە وەک بەشێک لە پەڕگە لەتکراوەکە +ناتوانێت لە بەشێک زیاتر بدۆزێتەوە لە پەڕگە لەتکراوەکە +7500 +ژماردنی کۆپشکنین... +زانیاری کۆپشکنین +کۆپشکنینی CRC بۆ دراوە: +کۆپشکنینی CRC بۆ دراوە و ناوەکان: +7600 +نیشانەی پێوان +ڕێژەی بەکارهێنراوی بیرگە: +پەستاندن +کردنەوەی پەستێنراو +هەڵسەنگاندن +سەرجەمی هەڵسەنگاندن +ئێستایی +ئەنجام +CPU ڕێژەی بەکارهێنراوی +ڕێژەی بەکارەێنراو / هەڵسەنگاندن +دەرچوونەکان: diff --git a/Utils/7-Zip/Lang/ku.txt b/Utils/7-Zip/Lang/ku.txt new file mode 100644 index 000000000..e5fb38f53 --- /dev/null +++ b/Utils/7-Zip/Lang/ku.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.37 : Rizoyê Xerzî +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Kurdish +Kurdî +401 +Temam +Betal + + + +&Erê +&Na +Bi&gire +Alîkarî + +Bi&domîne +440 +&Ji Bo Hemûyî Erê +Ji &Bo Hemûyî Na +Raweste +Dîsa Destpêke +L%i Pişt +Li &Pêş +&Rawestîne +Rawestiya - +Ma bila betal bibe? +500 +&Dosya +&Bipergalîne +&Nîşan Bide +Bi&jare +&Amûr +A&lîkarî +540 +&Veke +&Di Panelê De Veke +Di &Paceyê De Veke +&Nîşan Bide +&Sererast bike +&Navekî Nû Bidê +&Ji Ber Bigire +B&ar Bike +Jê B&ibe +Parçe Bi&ke... +Bike &Yek... +&Taybetî +Da&xuyanî +checksum heseb bike + +Pe&ldankeke Nû +Do&siyeke Nû +De&rkeve +600 +&Hemûyî hilbijêre +He&mû hilijartinê rake +Be&revajî wê hilbijêre +&Hilbijêre... +Hilbijarti&nê Rake... +Vî cureyî hilbijêre +Hilbijartina cure rake +700 +&Dawêrên Mezin +D&awêrên Biçûk +&Lîste +&Hûragahî +730 +Bê Dor +xuyakirina sade +&2 Panelan veke +Da&rikê amûran +Peldanka Kok Veke +Astekê Berjor +Dîroka Peldankê... +&Nû Bike +750 +Darikê arşîvê +Darikê standart +Bişkojkên mezin +Bila nivîsa bişkojkan bixuye +800 +Pe&ldanka derbasdar veke +Cih +900 +&Vebijêrk... +&Pîvana Çalakbûnê +960 +&Naverok... +D&er barê 7-Zip de... +1003 +Rê +Nav +Cure +Peldank +Mezinahî +Mezinahiya di arşîvê de +Taybetiyên xweser +Çêbûyî +Gihaştî +Guhertî +Hişk +Daxuyankirî +Şîfrekirî +Parçeyê borî +Parçeyê piştre +Ferheng +CRC +Cure +Dij +Awayê şidandinê +Platform +Pergala Dosiyê +Bikarhêner +Kom +Stûn +Daxuyanî +Cih +Path Prefix + + + + + + + + + + + + + + + + + + + + + + + + +Çewtî +Hemû Mezinahî +Cihê Vala +Mezinahiya telpikî +Etîket +Navê Herêmî +Derfetkar +2100 +Vebijêrk +Ziman +Ziman: +Per&galker +Pergalkerê De&qê: + +2200 +Pergal +Bi 7-Zip re têkildar bike: +2301 +Bila di pêşekên naverokê de 7-Zip bixuye +Pêşeka naverokê ya sûlavî +Hêmanên peşeka naverokê: +2320 + + +Arşîvê veke +Dosiyan derxe... +Bike Arşîv... +Arşîvê bihêçîne +Valake vir +Peldanka {0} derxe +Wekî {0} bike arşîv +Bişidîne û bişîne... +Wekî {0} bişidîne û bişîne +2400 +Peldank +Peldanka &Xebatê +&Peldanka TEMP a Pergalê +P&eldanka Derbasdar +Pe&ldanka Navborî: +Bi tenê ji bo ajokarên derketî bi kar bîne +Ji bo dosiyên demdemî yên arşîvê cih belî bike. +2500 +Mîheng +Bila hêmana ".." xuya bike +Bila dawêrên dosiyên rastî xuya bikin +Bila pêşeka pergalê xuya bike +Bila &hemû rêzikê bibore +Bila &xêzên tabloyê xuya bike + +&Kipa hilbijartina alternatîf +bîra berfireh bikar bîne +2900 +Der barê 7-Zip de +7-Zip nivîsbariyeke azad e. Lê, tu dikarî wekî tomarkirin desteka pêşxistina 7-zip bibî. +3000 + +Çewtî nîn e. +{0} heb hêman hilbijartî ne +Peldanka '{0}' nayê çêkirin +Tu nikarî vê arşîvê rojane bikî. + + + + +Dosiya '{0}' hatiye guhartin.\nMa bila di arşîvê bête rojanekirin? +Dosiya '{0}' nehate rojanekirin +Pergalkerê deqê nehate destpêkirin. + + + + +Hêman zêde ne +3300 +Tên derxistin +tên şidandin +tê hêçandin +vedibe... +Tê raguhestin +3400 +Derxe +&Cihê Dê Derkevê: +Ji bo dosya derkevinê cihekî belî bike. +3410 +Navê Rê +Navê tevahî yên rê +Bila navên rê tune bin +3420 +Dosiyên heyî +Ji bo li ser binivîse bipirse +Bê pirs li ser binivîse +Derxistin +Navekî nû li yên di arşîvê de bike +Navekî nû li yên heyî bike +3500 +Rewla Lisernivîsandinê +Di dosiya armanckirî de bi vî navî dosiyek heye. Bila li ser bête nivîsîn? +Dosiya heyî: +Dosiya tê derxistin: +{0} bayt +Na&vekî nû lê bike +3700 +Ji bo '{0}' awayê şidandinê nehate nasîn. +'{0}' xerabe ye. (Çewtiya daneyê) +'{0}' xerabe ye. (Çewtiya CRC) + + +3800 +Têketina Şîfreyê +Şîfreyê binivîse: + +Bi&la şîfre bixuye + + + +Şîfre +3900 +Dema borî: +Dema mayî: +Mezinahî: +Lez: + + +Çewt: + +4000 +Bike Arşîv +&Arşîv: +A&wayê rojanekirinê: +Awa&yê arşîvê: +A&sta şidandinê: +Awayê şi&dandinê: +Me&zinahiya ferhengê: +M&ezinahiya bêjeyê: + + +&Parametre: +Vebijêrk +Bila ew bixwe derxe (SFX) + + + +Navên dosiyê bike şîfre +Bikaranîna bîrê (Şidandin): +Bikaranîna bîrê (Vekirin): +4050 +Bêyî şidandin +Leztirîn +Bi Lez +Asayî +Herî Pir +Ultra +4060 +Dosiyan têxê, yên heyî derxe +Dosiyan têxê, yên kevin rojane bike +Bi tenê yên kevin rojane bike +Dosiyan bike wekî hev +4070 +Bibîne +Hemû dosya + + +6000 +Ji Ber Bigire +Bar Bike +Cihê Dê Were Jibergirtin: +Cihê Dê Were Barkirin: +tê jibergirtin... +tê barkirin... +navekî nû tê lêkirin... + +Kirin ne pêkan e. +Çewtiya Navlêkirinê +Erêkirina Jibergirtinê +Ma bila dosî ji bo arşîvê bên jibergirtin +6100 +Erêkirina jêbirina dosiyê +Erêkirina jêbirina peldankê +Erêkirina jêbirina gelek dosiyan +Ma bila dosiya '{0}' bête jêbirin? +Ma bila peldanka '{0}' û yên tê de bên jêbirin? +Ma bila hêmana {0} bête jêbirin? +tê jêbirin... +Çewtiya Jêbirinê + +6300 +Peldankeke nû +Dosiyeke Nû +Navê peldankê: +Navê Dosiyê: +Peldankeke Nû +Dosiyeke Nû +Çewtiya Çêkirina peldankê +Çewtiya çêkirina Dosiyê +6400 +Daxuyanî +&Daxuyanî: +Hilbijêre +Hilbijartinê rake +Derbirîna hilbijartinê: +6600 + +Rabirdûya Peldankê +Peyamên haydariyê +Peyam +7100 +Komputer +Tor + +Pergal +7200 +Bike Arşîv +Derxe +Bihêçîne +Ji Ber Bigire +Bar Bike +Jê Bibe +Agahî +7300 +Bike Parçe +Di &vê peldankê de parçe bike: +Wekî Bayt/&cilt bike parçe: +tê parçekirin... + + + + + +7400 +Bike Yek +Di vê &peldankê de bike yek: +tê yekirin... + + + +7500 +Hesabê sererastkirî... +Agahiyên hesabê sererast +CRC hesabê sererast bo data: +CRC hesabê sererast bo data û nav: +7600 +Çalakiya komputerê +Bikaranîna birê: +Şidandin +Vekirin +Puan +bi guloverî puanan +Carî +Encam + + +Serkeftî: diff --git a/Utils/7-Zip/Lang/ky.txt b/Utils/7-Zip/Lang/ky.txt new file mode 100644 index 000000000..3fff8815b --- /dev/null +++ b/Utils/7-Zip/Lang/ky.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.20 : Kalil uulu Bolot +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Kyrgyz +Кыргызча +401 +OK +Айнуу + + + +&Ооба +&Жок +&Жабуу +Жардам + +&Улантуу +440 +Ооба &баарына +Жок б&аарына эмес +Токто +Кайта иштетүү +&Фоном +&Алдыңкы планга +&Тыныгуу +Тыныгууда +Сиз чын эле операцияны токтоткуңуз келип жатабы? +500 +&Файл +&Оңдоо +&Кейп +&Тандалган +С&ервис +&Жардам +540 +&Ачуу +Ичи&нен ачуу +Сырты&нан ачуу +Көрүү +&Редактирлөө +Атын& өзгөртүү +&Буга көчүрүү... +&Буга ордун которуу... +&Өчүрүү +Фа&лды бөлүштүрүү... +Ф&айлдарды кошуу... +Кас&иети +Комме&нтарий +Контролдук жыйынтык +Diff +&Баштык жаратуу +Фай&л жаратуу +Ч&ыгуу +600 +Баарын б&өлүү +Бөлүнгөндү алуу +&Бөлүүнү к&аратуу +Бөлүү... +Бөлүнгөндү алуу... +Түзү менен бөлүү +Түзү менен бөлүнгөндү алуу +700 +&Чоң белгилер +&Кичине белгилер +Тиз&ме +&Таблица +730 +Иргөөсүз +Түз түзүлүш +&2 Панель +&Аспап панелдери +Түпкү баштыкты ачуу +Бир деңгээлге өйдө өтүү +Баштыктардын тарыхы... +Ж&аңыртуу +750 +Архиватордун баскычтарынын панели +Стандарттык баскыч панели +Чоң баскычтар +Баскычтагы жазуулар +800 +Кантип тандалганга& баштыкты кошуу +Чөп кат +900 +Оңдоп-түздөмөлөр... +Өндүрүмдүүлүктү тестирлөө +960 +&Мазмуну... +Программа &жөнүндө... +1003 +Жол +Ат +Кенейтүү +Баштык +Көлөм +Кысылган +Атрибуттар +Жаралган +Ачылган +Өзгөртүлгөн +Үзгүлтүксүз +Комментарий +Шифрланган +Чейин бөлүнгөн +Кийин Бөлүнгөн +Сөздүк +CRC +Түр +Анти +Амал +Система +Файлдык система +Колдонуучу +Топ +Блок +Комментарий +Ээлеген ахывал +Жол +Баштыктар +Файлдар +Версиясы +Том +Көптомдуу +Жылдыруу +Сүрүштүрүү +Блоктор +Томдор + +64-bit +Big-endian +Процессор +Физикалык көлөм +Баш аттардын көлөмү +Текшерүү жыйынтык +Мүнөздөмөлөр +Виртуалдык дарек +ID +Кыска ат +Жараткан +Сектордун көлөмү +Түзүлүш +Сүрүштүрүү +Ката +Сыйдыргычтык +Бош +Размер кластера +Белги +Локалдык ат +Провайдер +2100 +Оңдоп-түздөмөлөр +Тил +Тил: +Редактор +&Редактор: +&Diff: +2200 +Система +7-Zip менен файлдарды бириктирүү: +2301 +7-Zipти менюнун контексттик кыртышына жайгаштыруу +Каскадттык контексттик меню +Контексттик менюнун элементтери: +2320 +<Баштык> +<Архив> +Архивди ачуу +Таңгагын чечүү +Архивке кошуу... +Тестирлөө +Мында таңгагын чечүү +Буга таңгагын чечүү {0} +Буга кошуу {0} +Кысып жана аны email менен жиберүү... +Буга кысып {0} жана email менен жиберүү +2400 +Баштыктар +&Иштөө баштык +&Убактылуу системалык баштык +&Учурдагы +&Тапшыруу: +Котормолуу алып жүрүүчүлөргө гана колдонуу +Убактылуу архивтерге турган ордун көрсөтүңүз. +2500 +Оңдоп-түздөмөлөр +".." элементин көрсөтүү +Файлдардын реалдуу иконкаларын көрсөтүү +Системалык менюну көрсөтүү +Курсор жалпы сапка +Бөлгүчтөрдү көрсөтүү +Бир басуу менен ачуу +Белгинин алтернативалык режими +Эстин чоң барактарын колдонуу +2900 +7-Zip программа жөнүндө +7-Zip эркин таратылуучу программа.Бирок сиз 7-Zipтин иштетүүсүн колдогуңуз келсе,сиз программаны каттатып койсоңуз болот. +3000 +Эркин эске тутуу жетишсиз +Ката табылган жок +{0} Нерселер бөлүнгөн +'{0}' баштыкты жаратуу ишке ашкан жок +Бул архив үчүн өзгөртүү операциялары колдолбойт. +'{0}' архивтей кылып ачуу ишке ашкан жок +Шифрленген архивди ачуу ишке ашкан жок '{0}'. Купуя-белги туура эмес? +Архивдин колдоо кылынбаган түрлөрү +{0} деген файл бар +'{0}' файлы өзгөртүлгөн.\nСиз аны архивде жаңырткыңыз келип жатабы? +\n'{0}' файлын жаңыртуу ишке ашкан жок +Редакторду иштетүү, ишке ашкан жок +Файл вируска окшош (файлдын аты ырааттуу бош жерди камтыйт). +Баштыктын ичинен операция аткарылбайт, жолдун узактыгынан. +Сиз бир фалды бөлүшүңүз керек +Сиз бир нече файлды бөлүшүңүз керек +Өтө көп элементтерди камтыйт +3300 +Таңгагын чечүү +Компрессиялоо +Тестирлөө +Ачуу... +Сканирлөө... +3400 +Чыгаруу +& Буга таңгагын чечүү: +Чыгарып жаткан файлдар үчүн ордун көрсөтүңүз. +3410 +Жолдор +То&лук жолдор +&Жолсуз +3420 +Кайта жазуу +&Далилдөө менен +Д&алилдөөсүз +Өткө&рүү +Автоматтык түрдө атын өзгөртүү. +Бар файлдардын аттарын автоматтык түрдө өзгөртүү. +3500 +Файлды алмаштырууну далилдөө +Баштык иштеп чыгарылган файлды камтыйт. +Бар файлдарды алмаштыруу +кийинки файл менен? +{0} байт +Автоматтык түрдө атын өзгөртүү. +3700 +'{0}' файлдагы колдобоочу кысуу амалы. +'{0}' берилүүсүндөгү ката.файл бузук. +'{0}' CRCте ката.файл бузук. +'{0}' шифрленген файлда ката. Туура эмес купуя-белги? +'{0}' шифрленген файл үчүн CRCте ката. Туура эмес купуя-белги? +3800 +Купуя-белгини киргизүү +&Купуя-белгини киргизиңиз: +&Купуя-белгини кайталаңыз: +&Купуя-белгини көрсөтүү +Купуя-белгилер бири-бирине туура келбейт +Купуя-белги үчүн латын алфавитиндеги символдорду гана колдонуңуз,сандарды жана атайын (!, #, $, ...) символдорун +Купуя-белги өтө узун +&Купуя-белги +3900 +Өттү: +Калды: +Баары: +Ылдамдык: +Көлөм: +Кысуунун даражасы: +Каталар: +Архивтер: +4000 +Архивке кошуу +&Архив: +&Өзгөртүүнүн режими: +&Архивдин форматы: +&Кысуунун деңгээли: +&Кысуунун амалы: +Сөздүктүн &көлөмү: +Сөздүн к&өлөмү: +Блоктун көлөмү: +Агымдардын саны: +&Параметрлер: +&Оңдоп-түздөмөлөр +SF&X-архивди жаратуу +Файлдарды жаздыруу үчүн ачууну кысуу +Шифрлөө +Шифрлөөнүн амалы: +&Файлдардын атын шифрлөө +Салып бекитүү үчүн эстин көлөмү: +Таңгагын чечүү үчүн эстин көломү: +4050 +Кысуусуз +Ылдамдуу +Бат +Кадимкидей +Ээң жогорку +Ультра +4060 +Кошуп жана алмаштыруу +Жаңыртып жана кошуу +Жаңыртуу +Калптандыруу +4070 +Барактоо +Баардык файлдар +Файлдын көлөмүндөй +Үзгүлтүксүз +6000 +Көчүрүү +Которуштуруу +Буга көчүрүү: +Буга которуштуруу: +Көчүрүү... +Ордун которуу... +Атын өзгөртүү... +Баштыкты көрсөтүңүз. +Операция бул баштык үчүн колдолбойт. +Баштыктын же файлдын атын өзгөртүүдө ката +Файлдарды көчүрүүнү аныктоо +Сиз бул файлдарды архивке көчүрүүнү чын эле каалап жатасызбы +6100 +Файлдын өчүрүүсүн аныктоо +Баштыктын өчүрүүсүн аныктоо +Файлдын тобун өчүрүүсүн аныктоо +Сиз "{0}" өчүрүүнү чын эле каалап жатасызбы? +Сиз "{0}" баштыктын ичиндегилери менен өчүрүүнү чын эле каалап жатасызбы? +({0} даана.) нерселерди өчүрүүнү чын эле каалап жатасызбы? +Өчүрүү... +Баштыкты же файлды өчүрүүдө ката +Система узун жолдуу файлдарды өчүрүүбаштыкка өчүрүү операциясын колдобойт +6300 +Баштык жаратуу +Файл жаратуу +Баштыктын аты: +Файлдын аты: +Жаңы баштык +Жаңы файл +Баштык жаратуудан ката +Файл жаратуудан ката +6400 +Комментарий +&Комментарий: +Бөлүү +Бөлүнгөндү алып салуу +Маска: +6600 +Касиет +Баштыктардын тарыхы +Билдирүү +Билдирүү +7100 +Компьютер +Желе +Иш кагаздар +Система +7200 +Кошуу +Чыгаруу +Тестирлөө +Көчүрүү +Ордун которуу +Өчүрүү +Маалымат +7300 +Файлды бөлүштүрүү +&Буга бөлүштүрүү: +(байт ) көлөмү менен томдорго бөлүштүрүү: +Бөлүштүрүү... +Бөлүштүрүүнү аныктоо +Сиз файлды {0} бөлүккө бөлгүңүз келип жатабы? +Томдун көлөмү баштапкы файлдын көлөмүнөн кичине болушу керек +Томдордун көлөмүн берүүдө ката +Отургузулган томдун көлөмү: {0} байт.\nСиз чын эле архивди ушундай томдорго бөлгүңүз келип жатабы? +7400 +Файлдарды бириктирүү +&Буга бириктирүү: +Биригүү... +Бөлүштүрүлгөн файлдын биринчи бөлүгүн гана бөлүү керек +Бөлүштүрүлгөн файлды таану ишке ашкан жок +Бөлүштүрүлгөн файлдын бир бөлүгүн дагы табуу ишке ашкан жок +7500 +Текшерүүнүн жыйынтыгын эсептөө... +Текшерүүнүн жыйынтыгы +Маалымат үчүн CRC текшерүү жыйынтыгы: +Маалымат жана аттар үчүн CRC текшерүү жыйынтыгы: +7600 +Өндүрүмдүүлүктү тестирлөө +Эстин көлөмү: +Салып бекитүү +Таңгагын чечүү +Рейтинг +Жалпы рейтинг +Учурдагы +Жыйынтыгы +Жүк +Рейтинг / Жүк. +Өтүүлөр: diff --git a/Utils/7-Zip/Lang/lij.txt b/Utils/7-Zip/Lang/lij.txt new file mode 100644 index 000000000..bf31dacee --- /dev/null +++ b/Utils/7-Zip/Lang/lij.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : GENOVES.com.ar +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Ligurian +Zeneize +401 +D'acòrdio +Anulla + + + +&Sci +&No +Sæ&ra +Agiutto + +&Continoa +440 +Sci pe &Tutti +No pe T&utti +Ferma +Inandia torna +Into &sfondo +&In primmo cian +&Paoza +In paoza +Ti ê seguo de voei anulâ? +500 +&Archivio +&Modifica +&Vixoalizza +&Preferii +&Strumenti +A&giutto +540 +&Arvi +Arvi into Manezatô d'archivi 7-Zip +Arvi inte Explorer +&Vixoalizza +&Modifica +Ri&nomina +&Còpia inte... +&Spòsta inte... +Scancel&la +&Dividi l'archivio... +&Unisci i archivi... +P&ropietæ +Comen&ta... +Calcola somma de contròllo +Dif +Crea cartella +Crea archivio +Sc&iòrti +600 +Seleçionn-a &tutto +Deseleçionn-a tutto +In&verti seleçion +Seleçionn-a... +Deseleçionn-a... +Seleçionn-a pe tipo +Deseleçionn-a pe tipo +700 +Figue &grende +Figue picinn-e +&Listin +&Dæti +730 +Nisciun ordine +Vista ciatta +&2 barcoîn +Bare di &Strumenti +Arvi cartella prinçipâ +Livello supeiô +Cronologia... +&Agiorna +750 +Bara di strumenti Archivio +Bara di strumenti Normali +Figue grende +Mostra etichette de tèsto +800 +&Azonzi a cartella a-i Preferii comme +Colegamento +900 +&Òpsioin... +&Ponto de riferimento +960 +&Goidda... +&Informaçioin in sce de 7-Zip... +1003 +Percorso +Nomme +Estension +Cartella +Mezua +Mezua Conpressa +Atributi +Creou +Urtimo acesso +Urtima modifica +Sòlido +Comentou +Criptou +Dividi primma +Dividi dòppo +Diçionaio +CRC +Tipo +Anti +Metodo +OS destinaçion +Archivio do scistemma +Utente +Gruppo +Blòcco +Comento +Poxiçion +Prefisso da destinaçion +Cartelle +Archivi +Verscion +Volumme +Multivolumme +Offset +Colegamenti +Blòcchi +Volummi + +64-bit +Big-endian +CPU +Mezua fixica +Mezua de titoli +Somma de contròllo +Carateristiche +Indirisso Virtoale +ID +Nomme curto +Aplicaçion de creaçion +Mezua da seçion +Mòddo +Colegamento +Erô +Capaçitæ totale +Spaçio disponibile +Mezua de particole (cluster) +Etichetta +Nomme locale +Proveditô +2100 +Òpsioin +Lengoa +Lengoa: +Editô +&Editô: +&Dif: +2200 +Scistemma +Asòccia 7-Zip a: +2301 +Integra 7-Zip into menù contestoale +Menù contestoale a cascaa +Elementi do menù contestoale: +2320 + + +Arvi +Estranni i archivi... +Azonzi a l'archivio... +Contròlla l'archivio +Estranni chi. +Estranni inte {0} +Azonzi a {0} +Conprimmi e invia pe email... +Conprimmi in {0} e invia pe email +2400 +Cartelle +Cartella de tra&vaggio +Cartella &Temp de Scistemma +&Corente +&Specificâ: +Deuvia solo pe dischi estraibili +Specifica unna cartella pe-i archivi tenporanni. +2500 +Inpostaçioin +Mostra l'elemento ".." +Mostra e icöne di archivi +Mostra e icöne do scistemma +Seleçionn-a a &riga intrega +Mostra &grixella +Sciacâ unna vòtta sola pe arvî un elemento +&Mòddo de seleçion alternativo +Deuvia grende &pagine de memöia +2900 +Dæti +7-Zip o l'é un programa libero e de badda. +3000 +O scistemma o no peu separâ a quantitæ de memöia necesaia +Nisciun erô +{0} ògetti seleçionæ +Inposcibile creâ a cartella '{0}' +No l'é poscibile efetoâ agiornamenti in sce quest'archivio. +Inposcibile arvî l'archivio '{0}' comme conpilaçion +Inposcibile arvî a conpilaçion criptâ '{0}'. Scoretta a paròlla d'ordine? +Tipo de conpilaçion no consentia +L'archivio {0} za o l'existe +L'archivio '{0}' o l'é stæto modificou.\nTi veu agiornâ l'archivio? +Inposcibile agiornâ l'archivio\n'{0}' +Inposcibile inandiâ l'editô. +L'archivio o pâ d'ese un virus (o seu nomme o gh'à di spaççi longhi). +L'òperaçion a no peu conpletase da unna cartella da percorso longo. +Ti devi seleçionâ un archivio +Ti devi seleçionâ ùn ò ciù archivi +Tròppi elementi +3300 +Estraçion in corso... +Conprescion in corso... +Contròllo in corso... +Avertua in corso... +Controlemmo... +3400 +Estranni +&Estranni inte: +Specifica unna cartella dove estrae i archivi. +3410 +Strutua de cartelle +Percorsci conpleti +Nisciun percorso +3420 +Sorvescritua +Domanda primma de sorvescrive +Sorvescrivi sensa domandâ +No sorvescrive i archivi existenti +Rinomina outomaticamente +Rinomina outomaticamente i archivi existenti +3500 +Conferma a sostitoçion de l'archivio +A cartella destinaçion a contegne za l'archivio fæto. +Ti voriesci sostitoî l'archivio +con questo? +{0} byte +Rinomina &outomaticamente +3700 +Metodo de conprescion no consentio pe '{0}'. +Erô di dæti inte '{0}'. L'archivio o l'é danezou. +CRC no coretto inte '{0}'. L'archivio o l'é danezou. +Erô di dæti inte l'archivio criptou '{0}'. Scoretta a paròlla d'ordine? +CRC falio inte l'archivio criptou '{0}'. Scoretta a paròlla d'ordine? +3800 +Introduxi paròlla d'ordine +Introduxi paròlla d'ordine: +Ripeti a paròlla d'ordine: +&Mostra paròlla d'ordine +E paròlle d'ordine no coincidan +Deuvia solo segni de l'ingleize, numeri e carateri speciali (!, #, $, ...) pe-a paròlla d'ordine +Paròlla d'ordine tròppo longa +Paròlla d'ordine +3900 +Tenpo trascorso: +Tenpo rimanente: +Mezua: +Velocitæ: +Procesou: +Tascia de conprescion: +Eroî: +Conpilaçion: +4000 +Azonzi a l'archivio +&Archivio: +Modalitæ d'a&giornamento: +&Formato de l'archivio: +&Livello de conprescion: +&Metodo de conprescion: +Mezua &Diçionaio: +Mezue da Pa&ròlla: +Mezua do blòcco sòlido: +Numero de thread CPU: +&Parametri: +Òpsioin +Crea archivio outo-estraente +Conprimmi archivi condivixi +Critografia +Mòddo de criptâ: +Cripta o &nomme di archivi +Utilizzo da memöia pe conprescion: +Utilizzo da memöia pe deconprescion: +4050 +Nisciunn-a +Velociscima +Veloce +Normale +Mascima +Ultra +4060 +Azonzi e sostitoisci i archivi +Agiorna e azonzi i archivi +Agiorna i archivi existenti +Sincronizza i archivi +4070 +Sfeuggia +Tutti i archivi +No-sòlido +Sòlido +6000 +Còpia +Spòsta +Còpia inte: +Spòsta verso: +Còpia in corso... +Spostamento in corso... +Rinominaçion in corso... +Çerni cartella de destinaçion. +L'òperaçion a no l'é consentia. +Erô into rinominâ l'archivio ò a cartella +Conferma a còpia d'archivi +Ti ê seguo de voei copiâ di archivi a unna conpilaçion? +6100 +Conferma l'eliminaçion de l'archivio +Conferma l'eliminaçion da cartella +Conferma l'eliminaçion de ciù elementi +Ti ê seguo de voei eliminâ '{0}'? +Ti ê seguo de voei eliminâ a cartella '{0}' e tutto o seu contegnuo? +Ti ê seguo de voei eliminâ questi {0} elementi? +Eliminaçion in corso... +Erô inte l'eliminaçion de l'archivio ò da cartella +O scistemma o no peu caciâ via un archivio da percorso longo +6300 +Crea Cartella +Crea archivio +Nomme da cartella: +Nomme d'archivio: +Neuva cartella +Neuvo archivio +Erô inta creaçion da cartella +Erô inta creaçion de l'archivio +6400 +Comento +&Comento: +Seleçionn-a +Deseleçionn-a +Filtro: +6600 +Propietæ +Cronologia +Mesaggi diagnòstichi +Mesaggio +7100 +Calcolatô +Ræ +Documenti +Scistemma +7200 +Azonzi +Estranni +Contròlla +Còpia +Spòsta +Cancella +Propietæ +7300 +Dividi Archivio +&Dividi inte: +Di&vidi in ciù archivi, mezua in byte: +Dividimmo... +Conferma a divixon +Ti ê seguo de voei separâ l'archivio inte {0} volummi? +A mezua de volumme a deve ese ciù picinn-a de quella de l'òriginale +Scoretta a mezua do volumme +Mezua de volumme specificâ: {0} byte.\nTi ê seguo de voei separâ l'archivio inte quelli volummi? +7400 +Unisci i archivi +&Unisci inte: +Unimmo... +Seleçionn-a solo a primma parte de l'archivio divizo +No se gh'atreuva un archivio comme parte d'un archivio divizo +No se gh'atreuva ciù d'unna parte d'un archivio divizo +7500 +Calcolemmo a somma de contròllo... +Dæti da somma de contròllo +Somma de contròllo CRC pe dæti: +Somma de contròllo CRC pe dæti e nommi: +7600 +Ponto de riferimento +Utilizzo da memöia: +Conprescion in corso +Deconprescion in corso +Valutaçion +Valutaçion totale +Atoale +Derivou +Utilizzo de CPU +Rating / Utilizzo +Pasaggi: diff --git a/Utils/7-Zip/Lang/lt.txt b/Utils/7-Zip/Lang/lt.txt new file mode 100644 index 000000000..7f8fb71e9 --- /dev/null +++ b/Utils/7-Zip/Lang/lt.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 2.30 : Marius Navickas : http://www.teisininkas.lt/ivairus/7-zip: +; 4.57 : Domas Jokubauskis +; 15.05 : Vaidas777 (terminų šaltinis: www.raštija.lt) +; +; +; +; +; +; +; +; +0 +7-Zip +Lithuanian +Lietuvių +401 +Gerai +Atšaukti + + + +&Taip +&Ne +&Uždaryti +Elektroninis žinynas + +&Tęsti +440 +T&aip Visiems +Ne v&isiems +Sustabdyti +Iš naujo +&Fone +&Pirminis procesas +&Laikinai sustabdyti +Laikinai sustabdyta +Ar jūs esate tikri, kad norite atšaukti? +500 +&Failas +K&eisti +&Rodyti +Mėgi&amiausi +Įran&kiai +&Elektroninis žinynas +540 +&Atverti +Atverti v&iduje +Atverti iš&orėje +&Rodyti +K&eisti +Pervadi&nti +&Kopijuoti į... +&Perkelti į... +Šalin&ti +&Skaidyti failą... +Jungti &failus... +Savy&bės +Kome&ntuoti +Skaičiuoti kontrolinę sumą +Sulyginti +Sukurti aplanką +Sukurti failą +Išei&ti +Nuoroda +&Alternatyvūs srautai +600 +Pažymėti &viską +Nužymėti viską +Atv&irkštinis žymėjimas +Parinkti... +Atžymėti... +Pasirinkti pagal tipą +Atžymėti pagal tipą +700 +Did&elės piktogramos +&Mažos piktogramos +&Sąrašas +&Išsamiai +730 +Nerūšiuotos +Nepaisyti aplankų +&2 skydeliai +&Mygtukų juostos +Atverti šakninį aplanką +Lygiu aukščiau +Aplankų istorija... +&Atnaujinti +Automatiškai atnaujinti +750 +Archyvo mygtukų juosta +Standartinė mygtukų juosta +Dideli mygtukai +Rodyti užrašus ant mygtukų +800 +&Pridėti aplanką prie mėgiamiausiųjų kaip +Mėgiamiausias +900 +&Nuostatos... +&Spartos bandymas +960 +&Turinys... +&Apie 7-Zip... +1003 +Kelias +Pavadinimas +Plėtinys +Aplankas +Dydis +Dydis archyve +Atributai +Sukurta +Naudota +Pakeista +Vientisas +Komentaras +Šifruotas +Perskyra prieš +Perskyra paskui +Žodynas + +Tipas +Anti +Būdas +Kompiuterio OS +Bylų sistema +Naudotojas +Grupė +Blokas +Komentaras +Pozicija +Kelio priešdėlis +Aplankai +Failai +Versija +Tomas +Daugiatomis +Poslinkis +Nuorodos +Blokai +Tomai + +64-bit +Mažėjantys baitai +Procesorius +Fizinis dysis +Antraštės dydis +Kontrolinė suma +Charakteristikos +Virtualus adresas +ID +Trumpas pavadinimas +Kūrėjo programa +Sektoriaus dydis +Moda +Simbolinė nuoroda +Klaida +Visas dydis +Laisva vieta +Blokinio dydis +Žymė +Vietinis pavadinimas +Teikėjas +NT saugumas +Alternatyvus srautas +Pagalbinis +Ištrintas +Medis + + +Klaidos tipas +Klaidos +Klaidos +Perspėjimai +Perspėjimas +Srautai +Alternatyvūs srautai +Alternatyvių srautų dydis +Virtualus dydis +Išpakuoto dydis +Visas fizinis dydis +Tomo numeris +Subtipas +Trumpas komentaras +Kodų lentelė + + + +Pabaigos dydis +Įterpto bloko dydis +Nuoroda +Patvarioji nuoroda +iNode + +Tik skaityti +2100 +Nustatymai +Kalba +Kalba: +Redaktorius +R&edaktorius: +&Sulyginimas: +2200 +Sistema +Susieti 7-Zip su: +Visi vartotojai +2301 +Integruoti 7-Zip į kontekstinį meniu +Pakopinis kontekstinis meniu +Kontekstinio meniu įrašai: +Piktogramos kontekstiniame meniu +2320 + + +Atverti archyvą +Išskleisti failus... +Įtraukti į archyvą... +Patikrinti archyvą +Išskleisti čia +Išskleisti į {0} +Įtraukti į {0} +Suglaudinti ir išsiųsti el. paštu... +Suglaudinti į {0} ir išsiųsti el. paštu +2400 +Aplankai +&Darbinis aplankas +&Sisteminis laikinas aplankas +D&abartinis +Nurodyta&s: +Naudoti tik išimamiems diskams +Nurodyti vietą laikiniems archyviniams failams. +2500 +Nustatos +Rodyti „..“ failų sąraše +Rodyti tikras failų piktogramas +Rodyti sisteminį meniu +&Žymėti visą eilutę +Rodyti tinklelio linija&s +Atverti vienu spustelėjimu +&Kitoks žymėjimo būdas +Naudoti didžiu&lius atmintinės puslapius +2900 +Apie 7-Zip +7-Zip yra nemokama programa. +3000 +Sistema begali skirti reikalingo atminties kiekio +Klaidų nerasta +Pasirinkta {0} objektų: +Negalima sukurti aplanko „{0}“ +Šio archyvo negalima atnaujinti. +Negalima atverti „{0}“ failo kaip archyvo +Negalima atverti šifruoto archyvo „{0}“. Neteisingas slaptažodis? +Nepalaikomas archyvo tipas +Failas pavadinimu {0} yra +Failas „{0}“ buvo pakeistas.\nAr norite jį atnaujinti archyve? +Negalima atnaujinti failo\n„{0}“ +Negalima paleisti redaktoriaus. +Šis failas panašus į virusą (failo pavadinime yra pasikartojančių tarpų) +Šis veiksmas negali būti vykdomas iš aplanko, kuris turi ilgą kelią +Jūs privalote pažymėti vieną failą +Jūs privalote pažymėti bent vieną failą +Per daug elementų +Negalima atverti failo kaip {0} archyvo +Failas yra atvertas kaip {0} archyvas +Archyvas yra atvertas su ofsetu +3300 +Išskleidžiama +Glaudinama +Tikrinama +Atidaroma... +Skenuojama... +Šalinama +3320 +Glaudinama +Atnaujinama +Analizuojama +Dubliuojama +Glaudinama iš naujo +Praleidžiama +Šalinama +Kuriama antraštė +3400 +Išskleisti +Iš&skleisti į: +Nurodyti vietą išskleidžiamiesiems failams. +3410 +Kelio moda: +Pilni keliai +Jokių kelių +Absoliutūs keliai +Santykiniai keliai +3420 +Perrašymo režimas +Paklausti prieš perrašant +Perrašyti neįspėjant +Praleisti esančius failus +Automatiškai pervadinti +Automatiškai pervadinti esančius failus +3430 +Pašalinti šakninio aplanko pasikartojimą +Atstatyti failų saugumo nuostatas +3500 +Failų pakeitimo patvirtinimas +Paskirtame aplanke jau yra apdorojamas failas. +Ar norėtumėte pakeisti esančią failą +šiuo failu? +{0} baitų +A&utomatinis pervadinimas +3700 +Nepalaikomas suglaudinimo metodas failui „{0}“. +Duomenų klaida „{0}“. Failas pažeistas. +CRC klaida „{0}“. Failas pažeistas. +Duomenų klaida šifruotame faile „{0}“. Neteisingas slaptažodis? +CRC neatitikimas šifruotame faile „{0}“. Neteisingas slaptažodis? +3710 +Neteisingas slaptažodis? +3721 +Nepalaikomas suglaudinimo metodas +Duomenų klaida +CRC neatitikimas +Nepasiekiami duomenys +Netikėta duomenų pabaiga +Yra papildomi duomenys po naudingų duomenų +Tai nėra archyvas +Klaida antraštėse +Klaidingas slaptažodis +3763 +Nepasiekiama archyvo pradžia +Nepatvirtinta archyvo pradžia + + + +Nepalaikoma ypatybė +3800 +Slaptažodžio įvedimas +Įveskite slaptažodį: +Pakartokite slaptažodį: +&Rodyti slaptažodį +Slaptažodžiai nesutampa +Slaptažodžiui naudokite tik lotyniškas raides, numerius bei specialiuosius simbolius (!, #, $, ...) +Slaptažodis yra per ilgas +Slaptažodis +3900 +Praėjęs laikas: +Likęs laikas: +Dydis: +Sparta: +Apdorota: +Suglaudinimo laipsnis: +Klaidos: +Archyvai: +4000 +Įtraukti į archyvą +&Archyvas: +Atna&ujinimo režimas: +Archyvo &formatas: +Suglaudinimo &lygis: +Glaudini&mo būdas: +Žo&dyno dydis: +Ž&odžio dydis: +Vientiso bloko dydis: +CPU gijų skaičius: +&Parametrai: +Nuostatos +Sukurti iš&sipakuojantį archyvą +Glaudinti atvertus įrašymui failus +Šifravimas +Šifravimo metodas: +Už&šifruoti failų pavadinimus +Atmintinės naudojimas suglaudinimui: +Atmintinės naudojimas išskleidimui: +Ištrinti failus suglaudinus +4040 +Įsiminti simbolines nuorodas +Įsiminti patvariasias nuorodas +Įsiminti alternatyvius duomenų srautus +Įsiminti failų saugumo nuostatas +4050 +Mažiausias +Greitesnis +Greitas +Normalus +Didžiausias +Smarkiausias +4060 +Įtraukti ir pakeisti failus +Atnaujinti ir įtraukti failus +Atnaujinti esančius failus +Sinchronizuoti failus +4070 +Naršyti +Visus failus +Ne vientisas +Vientisas archyvas +6000 +Kopijuoti +Perkelti +Kopijuoti į: +Perkelti į: +Kopijuojama... +Perkeliama... +Pervadinama... +Pasirinkite paskirties aplanką. +Šiam aplankui veiksmas nepalaikomas. +Klaida pervadinant failą ar aplanką +Failų kopijavimo patvirtinimas +Ar jūs esate įsitikinę, jog norite kopijuoti failus į archyvą? +6100 +Patvirtinkite failo šalinimą +Patvirtinkite aplanko šalinimą +Patvirtinkite kelių failų šalinimą +Ar esate įsitikinę, jog norite pašalinti „{0}“? +Ar esate įsitikinę, jog norite pašalinti „{0}“ aplanką ir visą jo turinį? +Ar esate įsitikinę, jog norite pašalinti šiuos {0} elementus? +Šalinama... +Klaida trinant failą ar aplanką +Sistema negali perkelti failo į šiukšlinę, kadangi per ilgas kelias +6300 +Sukurti aplanką +Sukurti failą +Aplanko pavadinimas: +Failo pavadinimas: +Naujas aplankas +Naujas failas +Klaida kuriant aplanką +Klaida kuriant failą +6400 +Komentaras +&Komentaras: +Pažymėti +Panaikinti žymėjimą +Šablonas: +6600 +Nuostatos +Aplankų istorija +Diagnostiniai pranešimai +Pranešimas +7100 +Kompiuteris +Tinklas +Dokumentai +Sistema +7200 +Glaudinti +Išskleisti +Bandyti +Kopijuoti +Perkelti +Šalinti +Informacija +7300 +Skaidyti failą +&Skaidyti į: +Skaidyti į dalis bai&tais: +Skaidoma... +Skaidymo patvirtinimas +Ar jūs esate įsitikinę, jog norite failą skaidyti į {0} dalis? +Dalies dydis privalo būti mažesnis už dalijamo failo dydį +Neteisingas dalies dydis +Nurodytas dalies dydis: {0} baitai.\nAr jūs esate įsitikinę, jog norite archyvą skaidyti į tokias dalis? +7400 +Sujungti failus +&Sujungti į: +Sujungiami failai... +Pažymėkite tik pirmą suskaidyto archyvo failą +Nepavyko atpažinti suskaldyto failo +Nepavyko surasti daugiau nei vienos suskaldymo failo dalies +7500 +Skaičiuojama kontrolinė suma... +Kontrolinės sumos informacija +Duomenų CRC kontrolinė suma: +Duomenų ir failų pavadinimų CRC kontrolinė suma: +7600 +Spartos bandymas +Atmintinės naudojimas: +Suglaudinama +Išskleidžiama +Įvertis +Galutinis įvertis +Dabartinis +Galutinis +CPU naudojimas +Įvertis/naudojimas +Kartai: +7700 +Nuoroda +Sujungti +Šaltinis: +Tikslas: +7710 +Nuorodos tipas +Patvarioji nuoroda +Failo simbolinė nuoroda +Aplanko simbolinė nuoroda +Sujungimo taškas (Junction) diff --git a/Utils/7-Zip/Lang/lv.txt b/Utils/7-Zip/Lang/lv.txt new file mode 100644 index 000000000..85e4a1555 --- /dev/null +++ b/Utils/7-Zip/Lang/lv.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.10 : Armands Radzuška +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Latvian +Latviešu +401 +&Labi +&Atcelt + + + +&Jā +&Nē +Aiz&vērt +&Rokasgrāmata + +&Turpināt +440 +Jā &visiem +Nē v&isiem +Stop +Pārstartēt +&Fonā +&Priekšplānā +Pa&uze +Pauzēts +Vai piekrītat pārtraukt šo darbību? +500 +&Fails +&Labošana +&Izskats +Ie&cienītās +&Rīki +&Palīdzība +540 +&Atvērt +Atvērt &iekšpusē +Atvērt ārp&usē +Ap&skate +&Labot +Pā&rdēvēt +&Kopēt uz... +Pār&vietot uz... +&Dzēst +&Sadalīt failu... +Ap&vienot failus... +Īpašī&bas +&Piezīmes + + +Izveidot &mapi +Izveidot &failu +&Beigt +600 +Iezīmēt &visu +Atcelt vis&u +I&nvertēt iezīmējumu +Ie&zīmēt... +&Atcelt... +I&ezīmēt pēc tipa +A&tcelt pēc tipa +700 +&Lielas ikonas +&Mazas ikonas +&Saraksts +Sī&kāk +730 +&Nešķirot + +&2 paneļi +&Rīku joslas +&Atvērt saknes mapi +Līmeni &uz augšu +Mapju &vēsture... +&Pārlasīt +750 +Arhīva rīku josla +Standarta rīku josla +Lielas pogas +Parādīt pogu tekstu +800 +&Pievienot mapi iecienītajām kā +Iecienītās +900 +&Uzstādījumi... +&Darbspējas pārbaude +960 +&Rokasgrāmatas saturs... +&Par 7-Zip... +1003 +Ceļš +Nosaukums +Paplašinājums +Mape +Lielums +Saspiests +Atribūti +Izveidots +Atvērts +Pārveidots +Blīvs +Piezīmes +Šifrēts +Dalīts pirms +Dalīts pēc +Vārdnīca +CRC +Veids +Anti +Paņēmiens +Sistēma +Failu sistēma +Lietotājs +Grupa +Bloks +Piezīmes +Pozīcija + + + + + + + + + + + + + + + + + + + + + + + + + +Kļūda +Tilpums +Brīvā vieta +Klāstera lielums +Nosaukums +Lokālais nosaukums +Provaiders +2100 +Uzstādījumi +Valoda +Valoda: +Labošana +&Labošanas programma: + +2200 +Sistēma +Piesaistīt 7-Zip pie: +2301 +&Integrēt 7-Zip Windows vides kontekstizvēlē +&Kaskādveida kontekstizvēle +Kontekstizvēles elementi: +2320 + + +Atvērt arhīvu +Izvilkt failus... +Ielikt arhīvā... +Pārbaudīt arhīvu +Izvilkt šeit +Izvilkt {0} mapē +Ielikt {0} +Saspiest, sūtīt pa e-pastu... +Saspiest {0}, sūtīt pa e-pastu +2400 +Mapes +&Darba mape +&Sistēmas pagaidfailu mape +&Tekošā +&Noteikt: +&Izmantot tikai maināmajiem nesējiem +Norādiet vietu arhīvu pagaidfailiem. +2500 +Uzstādījumi +Parādīt ".." &vienību +Parādīt īstās &failu ikonas +Parādīt &sistēmas izvēli +&Pilnas rindas iezīmēšana +Parādīt at&dalošās līnijas + + + +2900 +Par 7-Zip +7-Zip ir bezmaksas programma, tomēr, reģistrējoties jūs varat 7-Zip izstrādāšanu atbalstīt. +3000 + +Kļūdu nav. +Iezīmēts(i) {0} objekts(i) +Mapi '{0}' neizdevās izveidot. +Šis arhīvs neatbalsta pārveidošanu. + + + + +Fails '{0}' ir pārveidots.\nVai vēlaties to atjaunināt arī arhīvā? +Failu nav iespējams uzlabot\n'{0}' +Nav iespējams palaist labošanas programmu. + + + + +Par daudz vienību. +3300 +Izvilkšana +saspiešana +Pārbaude +Atvēršana... + +3400 +Izvilkšana +&Izvilkt uz: +Norādiet vietu izvelkamiem failiem. +3410 +Ceļi +Pilni &ceļu nosaukumi +&Bez ceļu nosaukumiem +3420 +Pārrakstīšana +&Jautāt pirms pārrakstīšanas +Pārra&kstīt bez jautāšanas +I&zlaist esošos failus +A&utopārdēvēšana +Automātiski pārdēvēt esošos failu +3500 +Apstipriniet faila aizvietošanu +Mērķa mape jau satur apstrādājamo failu. +Vai vēlaties aizvietot esošo failu +ar šo? +{0} baiti +Autopārdēvēšana +3700 +Neatbalstīts saspiešanas paņēmiens '{0}' failam. +Datu kļūda '{0}'. Fails ir bojāts. +CRC kļūda '{0}'. Fails ir bojāts. + + +3800 +Paroles ievadīšana +Ievadiet paroli: + +Par&ole redzama + + + +&Parole +3900 +Pagājušais laiks: +Atlikušais laiks: +Lielums: +Ātrums: + + +Kļūdas: + +4000 +Pievienošana arhīvam +Ar&hīvs: +Pār&veidošanas režīms: +Arhīva &formāts: +&Saspiešanas līmenis: +&Saspiešanas paņēmiens: +&Vārdnīcas lielums: +Vār&da lielums: + + +Parame&tri: +&Uzstādījumi +Izveidot SF&X arhīvu + + + +Šifrēt failu &nosaukumus +Atmiņa arhivēšanai: +Atmiņa atarhivēšanai: +4050 +Uzkrāšana nesaspiežot +Ātrākais +Ātrais +Parastais +Maksimālā saspiešana +Ultra +4060 +Pievienot un aizvietot failus +Atjaunināt un pievienot failus +Atjaunināt esošos failus +Sinhronizēt failus +4070 +Pārlūkošana +Visi faili + + +6000 +Kopēt +Pārvietot +Kopēt uz: +Pārvietot uz: +Kopēšana... +Pārvietošana... +Pārdēvēšana... + +Darbība nav atbalstīta. +Faila vai mapes pārdēvēšanas kļūda + + +6100 +Faila dzēšanas apstiprinājums +Mapes dzēšanas apstiprinājums +Vairāku failu dzēšanas apstiprinājums +Vai piekrītat '{0}' dzēšanai? +Vai piekrītat mapes '{0}' un visa tās satura dzēšanai? +Vai piekrītat šo {0} vienību dzēšanai? +Dzēšana... +Faila vai mapes dzēšanas kļūda + +6300 +Mapes izveidošana +Faila izveidošana +Mapes nosaukums: +Faila nosaukums: +Jauna mape +Jauns fails +Mapes izveidošanas kļūda +Faila izveidošanas kļūda +6400 +Piezīmes +&Piezīmes: +Iezīmēšana +Iezīmējuma atcelšana +Šablons: +6600 + +Mapju vēsture +Diagnostikas paziņojumi +Paziņojums +7100 +Dators +Tīkls + +Sistēma +7200 +Ievietot +Izvilkt +Pārbaude +Kopēt +Pārvietot +Dzēst +Info +7300 +Sadalīt failu +&Dalīt uz: +&Dalīt sējumos, baitos: +Dalīšana... + + + + + +7400 +Apvienot failus +&Apvienot uz: +Apvienošana... + + + +7500 + + + + +7600 +Darpspējības pārbaude +Atmiņas pielietojums: +Arhivēšana +Atarhivēšana +Vērtējums +Kopējais vērtējums +Patreizējais +Rezultējošais + + +Izdošanās: diff --git a/Utils/7-Zip/Lang/mk.txt b/Utils/7-Zip/Lang/mk.txt new file mode 100644 index 000000000..f2d7a0b92 --- /dev/null +++ b/Utils/7-Zip/Lang/mk.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.09 : Gabriel Stojanoski +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Macedonian +Македонски +401 +Ок +Откажи + + + +&Да +&Не +&Затвори +Помош + +П&родолжи +440 +Да &Сите +Не Н&иедна +Стоп +Рестартирај +По&задина +&Напред +&Пауза +Паузирано +Дали сигурно сакате да откажете? +500 +&Датотека +&Уреди +&Изглед +&Омилени +&Алатки +&Помош +540 +&Отвори +Отвори &Внатре +Отвори &Надвор +&Поглед +&Уреди +&Преименувај +&Копирај Во... +&Премести Во... +&Избриши +&Подели датотека... +Ком&бинирај датотеки... +&Карактеристики +К&оментар + + +Креирај Директориум +Креирај Датотека +&Излези +600 +Селектирај &Се +Деселектирај Се +&Обратна Селекција +Селектирај... +Деселектирај... +Селектирај по Тип +Деселектирај по Тип +700 +&Големи Икони +&Мали Икони +&Листа +&Детали +730 +Неподредени + +&2 Панели +&Алатници +Отвори го основниот директориум +Едно Ниво Нагоре +Историја на Директориумите... +&Обнови +750 +Алатница на Архивата +Стандардна Алатница +Големи Копчиња +Текст На Копчињата +800 +&Додади го директориумот во Омилени +Забелешки +900 +&Опции... +&Тест +960 +&Содржина... +&За 7-Zip... +1003 +Патека +Име +Екстензија +Директориум +Големина +Пакувана Големина +Атрибути +Креирано +Пристапено +Променето +Целосна +Објаснета +Енкриптирана +Подели Пред +Подели После +Речник +CRC +Тип +Анти +Метод +Оперативен Систем +Датотечен Систем +Корисник +Група +Блок +Коментар +Позиција + + + + + + + + + + + + + + + + + + + + + + + + + +Грешка +Вкупна Големина +Слободен Простор +Голем на Кластерите +Етикета +Име +Провајдер +2100 +Опции +Јазик +Јазик: +Едитор +&Едитор: + +2200 +Систем +Придружи го 7-Zip со: +2301 +Интегрирај го 7-Zip во додатно мени +Каскадно додатно мени +Во додатното мени: +2320 +<Директориум> +<Архива> +Отвори архива +Отпакувај датотеки... +Додади во Архива... +Тестирај архива +Отпакувај овде +Отпакувај во {0} +Додади во {0} +Компресирај и прати на e-mail... +Компресирај во {0} и испрати +2400 +Директориуми +&Работен директориум +&Системски привремен директориум +&Моментален +&Одреди: +Само за преносни уреди +Одреди локација за привремените архивски датотеки. +2500 +Подесувања +Прикажи ".." предмет +Прикажи вистински икони +Прикажи системско мени +&Селектирај &цел ред +Прикажи &мрежа + + + +2900 +За 7-Zip +7-Zip е бесплатен архивер. Меѓутоа, вие можете да дадете поддршка на понатамошното развивање на 7-Zip со вашето регистрирање. +3000 + +Нема грешки +{0} објект(и) избрано +Не е можно креирање на директориумот '{0}' +Оваа операција не е поддржана за овој тип на архива. + + + + +Датотеката '{0}' е модифицирана.\nДали сакате да ја обновите во архивата? +Не е можно обновување на датотеката\n'{0}' +Грешка при стартување на Едиторот. + + + + +Премногу објекти +3300 +Отпакување +Компресирање +Тестирање +Отворање... + +3400 +Отпакувај +Отпакувај &во: +Одреди локација за отпакуваните датотеки. +3410 +Патеки +Целосна патека +Без патека +3420 +Презапишување +Прашај пред да презапишеш +Презапиши без прашување +Изостави постоечки датотеки +Автоматски преименувај +Автоматски преименувај постоечки датотеки +3500 +Потврди Замена на Датотеки +Конечниот директориум веќе ја содржи датотеката. +Дали сакате да ја замените постоечката датотека +со оваа? +{0} бајти +&Автоматски преименувај +3700 +Неподдржан метод за компресија за '{0}'. +Грешка во податоците во '{0}'. Датотеката е оштетена. +CRC грешка во '{0}'. Датотеката е оштетена. + + +3800 +Внеси лозинка +Внеси лозинка: + +&Прикажи ја лозинката + + + +Лозинка +3900 +Поминато време: +Преостанато време: +Големина: +Брзина: + + +Грешки: + +4000 +Додади во архива +&Архива: +&Додавање: +&Формат на Архива: +&Ниво на компресија: +&Метод на компресија: +Големина на &речникот: +Големина на &зборот: + + +&Параметри: +Опции +Креирај SFX ар&хива + + + +&Енкриптирај ги имињата +Искорист мемор за компрес: +Искорист мемор за декомпрес: +4050 +Спакувај +Најбрзо +Брзо +Нормално +Максимално +Ултра +4060 +Додади и замени датотеки +Обнови и додади датотеки +Обнови ги постоечките датотеки +Синхронизирај ги датотеките +4070 +Барај +Сите Датотеки + + +6000 +Копирај +Премести +Копирај Во: +Премести Во: +Копирање... +Преместување... +Преименување... + +Постапката не е поддржана. +Грешка при преименувањето на Датотеката или Директориумот + + +6100 +Потврдете го Бришењето на Датотеката +Потврдете го Бришењето на Директориумот +Потврдете го бришењето на повеќе датотеки +Дали сте сигурни за бришењето на '{0}'? +Дали сте сигурни за бришењето на директориумот '{0}' и неговата содржина? +Дали сте сигурни за бришењето на овие {0} датотеки? +Бришење... +Грешка при бришењето на Датотеката или Директориумот + +6300 +Креирај Директориум +Креирај датотека +Име на Директориумот: +Име на Датотеката: +Нов Директориум +Нова датотека +Грешка при креирањето на Директориумот +Грешка при креирањето на датотеката +6400 +Коментар +&Коментар: +Селектирај +Деселектитај +Маскирај: +6600 + +Историја на Директориумите +Дијагноза +Порака +7100 +Компјутер +Мрежа + +Систем +7200 +Додади +Отпакувај +Тестирај +Копирај +Премести +Избриши +Инфо +7300 +Подели датотека +&Подели на: +&Подели на делови, бајти: +Делење... + + + + + +7400 +Состави Датотеки +&Состави на: +Составување... + + + +7500 + + + + +7600 +Тест +Искорист Меморија: +Компресирање +Декомпресирање +Проценка +Вкупна Проценка +Моментално +Резултат + + +Поминато: diff --git a/Utils/7-Zip/Lang/mn.txt b/Utils/7-Zip/Lang/mn.txt new file mode 100644 index 000000000..9ab889ebf --- /dev/null +++ b/Utils/7-Zip/Lang/mn.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 3.12 : Bayar +; : Bayarsaikhan +; +; +; +; +; +; +; +; +; +0 +7-Zip +Mongolian +Монгол хэл +401 +За +Болих + + + +&Тийм +&Үгүй +&Хаах +Тусламж + +&Үргэлжлүүл +440 +Бүг&д тийм +Бүгд ү&гүй +Зогс +Дахин ачаалла +&Ар талд +&Өмнө тал +&Түр зогс +Түр зогслоо +Та үнэхээр болих гэж байна уу? +500 +&Файл +&Засах +&Үзүүлэх +Д&уртай зүйл +&Хэрэгслүүд +&Тусламж +540 +&Нээх +Дотор &нээх +Гадна &нээх +&Харах +&Засварлах +Нэр с&олих +...рүү &Хуулах... +...руу &Зөөх... +&Устгах +&Файл хуваах... +Файлуудыг нэгтгэх... +&Мэдээлэл үзэх +Тай&лбар + + +Хавтас үүсгэх +Файл үүсгэх +Га&рах +600 +Бүгдийг со&нгох +Сонгохоо болих +&Сонголтоо эргүүл +Сонгох... +Сонгохгүй... +Төрлөөр нь сонгох +Төрлөөр нь сонгохгүй +700 +Том& дүрсүүд +Жи&жиг дүрсүүд +&Жагсаалт +&Дэлгэрэнгүй +730 +Ангилаагүй + +&2 самбарууд +&Багажны самбар +Гол хавтсыг нээх +Нэг төвшин дээш +Хавтасны түүх... +&Сэргээ +750 +Aрхив багажны самбар +Стандарт багажны самбар +Том товчлуурууд +Товчлуурын текстийг үзүүл +800 +&Хавтсыг дуртайдаа нэмэх үү +Хавчуурга +900 +&Сонголтууд... +&Бэнчмарк +960 +&Агуулгууд... +&7-Зип-ийн тухай... +1003 +Зам +Нэр +Өргөтгөл +Хавтас +Хэмжээ +Багцалсан хэмжээ +Чанар +Үүсгэсэн +Хандсан +Өөрчилсөн +Баталгаатай +Тайлбар хийгдсэн +Нууцлагдсан +Өмнө хуваасан +Дараа хуваасан +Толь бичиг +CRC +Төрөл +Эсрэг +Арга +Хост ҮС +Файл систем +Хэрэглэгч +Бүлэг +Түгжих +Тайлбар +Байрлал + + + + + + + + + + + + + + + + + + + + + + + + + +Алдаа +Нийт хэмжээ +Хоосон зай +Кластерын зай +Нэр +Локаль Нэр +Хангагч +2100 +Сонголтууд +Хэл +Хэл: +Засварлагч +&Засварлагч: + +2200 +Систем +7-Зипийг дараахтай нэгтгэх: +2301 +7-Зип-ийг шелл контекст цэстэй нийлүүлэх +Контекст цэсийг цувуулан харуул +Контекст цэсийн төрлүүд: +2320 +<Хавтас> + +Архив нээх +Файлуудыг задал... +Архивт нэм... +Архивийн шалгалт +Энд задал +{0} руу задал +{0} рүү нэм +Шахах ба Шуудандах... +{0} рүү шахах ба Шууданд +2400 +Хавтсууд +&Ажлын хавтас +&Систем\завсрын хавтас +&Одоогийн +&Тодорхойлсон: +Зөвхөн зөөврийн төхөөрөмж хэрэглэх +Завсрын архив файл үүсгэх байрлалыг тодорхойл. +2500 +Тохируулгууд +Зүйл ".." үзүүлэх +Жинхэнэ файл дүрсийг харуулах +Системийн цэс харуул +&Бүтэн мөр сонгох +&Мөрийн дундах зураас харуулах + +&Сайжруулсан Сонгох горим +&Том санах ойн хуудас хэрэглэх +2900 +7-Zip-ийн тухай +7-Zip бол үнэгүй програм. Гэлээ ч та 7-Зип-д бүртгүүлэн хөгжүүлэгчдийг дэмжиж болно. Бүртгүүлсэн хэрэглэгчид техникийн дэмжлэг авах болно. +3000 + +Алдаа алга байна +{0} зүйл(үүд) сонгогдсон байна +Хавтас үүсгэж чадахгүй '{0}' +Дэмжигдээгүй архивийг задлах шинэчлэлт хийх. + + + + +Файл '{0}' өөрчлөгдлөө.\nТа архивт шинэчлэлт хиймээр байна уу? +Файлыг шинэчилж чадсангүй\n'{0} +Засварлагчийг нээж чадсангүй. + + + + +Дэндүү их юм байна +3300 +Задалж байна... +Шахаж байна +Шалгаж байна +Нээж байна... + +3400 +Задал +З&адлах газар: +Задалсан файлуудын байрлалыг тодорхойл. +3410 +Замын горим +Бүтэн замын нэр +Параметр алга +3420 +Давхарлаж бичих горим +Давхарлаж бичхээсээ өмнө асуух +Асуултгүй давхарлаж бичих +Байгаа файлыг алгасах +Автоматаар нэр солих +Байвал нэрийг нь солих +3500 +Файл дахин байрлуулахыг батлах +Хавтас файлыг агуулсан байна. +Байгаа файлуудыг дахин байрлуулах уу +Энүүнтэй юу? +{0} битүүд +A&втомат нэр солих +3700 +Дараах файлд шахалтын арга дэмжигдээгүй байна '{0}'. +'{0}'өгөгдлийн алдаа. Файл эвдэрсэн байна. +'{0}'CRC бүтсэнгүй. Файл эвдэрсэн байна. + + +3800 +Нууц үгээ оруулах +Нууц үгээ оруулах: + +&Нууц үг харуулах + + + +Нууц үг +3900 +Өнгөрсөн хугацаа: +Үлдсэн хугацаа: +Хэмжээ: +Хурд: + + +Алдаанууд: + +4000 +Архивт нэм +&Aрхив: +&Шинэчлэх горим: +Архив &өргөтгөл: +Шахалтын &төвшин: +Шахах &арга: +&Толь бичгийн хэмжээ: +&Үгийн хэмжээ: + + +&Параметерүүд: +Сонголтууд +SF&X архив үүсгэх + + + +&Файлын нэрүүдийг нууцал +Шахаж байгаа санах ойн хэрэглээ: +Задалж байгаа санах ойн хэрэглээ: +4050 +Хадгалах +Дээд хурданаар +Хурдан +Энгийн +Дээд хэмжээгээр +Ултра +4060 +Нэмэх ба дахин байрлуулах +Шинэчлэх ба дахин байрлуулах +Байгаа файлуудыг дахин унших +Файлуудыг тааруулах +4070 +Нэгжих +Бүх файлууд + + +6000 +Хуулах +Зөөх +хуулахдаа: +Зөөхдөө: +Хуулж байна... +Зөөж байна... +Нэр солиж байна... + +Үйлдэл дэмжигдээгүй байна. +Файл болон хавтсын нэрийг солиход алдаатай +Файл хуулахыг магадлах +Та үнэхээр файлуудыг архив руу хуулахыг хүсэж байна уу +6100 +Файл устгахыг батал +Хавтас устгахыг батал +Олон файл устгахыг батал +Та'{0}'-ийг устгах гэж байна уу? +'{0}' хавтас болон бүх агуулгыг устгах гэж байна уу? +{0} зүйлүүдийг устгах гэж байна уу? +Устгаж байна... +Файл болон хавтсыг устгахад алдаатай + +6300 +Хавтас үүсгэх +Файл үүсгэх +Хавтас нэр: +Файл нэр: +Шинэ хавтас +Шинэ файл +Хавтас үүсгэхэд алдаа гарав +Файл үүсгэхэд алдаа гарав +6400 +Тайлбар +&Тайлбар: +Сонгох +Сонгохгүй +Maск: +6600 + +Хавтсын түүх +Шинжилгээний зурвас +Зурвас +7100 +Компьютер +Сүлжээ + +Систем +7200 +Нэм +Задал +Шалгах +Хуулах +Зөөх +Устгах +Шинж... +7300 +Хуваах файл: +&Файл хуваах газар: +Эзлэхүүн рүү хуваах, битүүд: +Хувааж байна... + + + + + +7400 +Нэгтгэх файлууд: +&Нэгтгэх газар: +Нэгтгэж байна... + + + +7500 + + + + +7600 +Бэнчмарк +Санах ойн хэрэглээ: +Шахаж байна +Задалж байна +Үнэлж байна +Нийт үнэлгээ +Одоогийн +Хариуг гаргаж байна + + +Өнгөрсөн: diff --git a/Utils/7-Zip/Lang/mng.txt b/Utils/7-Zip/Lang/mng.txt new file mode 100644 index 000000000..f0c0859df --- /dev/null +++ b/Utils/7-Zip/Lang/mng.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 7-Zip 9.20 +; Saqirilatu Mongolqileb +; QQ:136087084 Email:saqirilatu@126.com +; Mongol soft QQ bulug Ⅰ: 39338772 Ⅱ:38803882 +; Toli Mongolian IME +; http://hi.baidu.com/saqirilatuu/item/9438213716f316ebe7bb7a8d +;last updated: 2014-1-1 +; +; +; +; +0 +7-Zip +Mongolian (Unicode) +ᠮᠤᠩᠭᠤᠯ ᠬᠡᠯᠡ +401 +ᠲᠡᠭᠡ +ᠤᠰᠠᠳᠬᠠᠬᠤ + + + +ᠲᠡᠭᠡ (&Y) +ᠪᠣᠯᠢ (&N) +ᠬᠠᠭᠠᠬᠤ (&C) +ᠬᠠᠪᠰᠤᠷᠤᠮᠵᠢ + +ᠵᠠᠯᠭᠠᠭᠠᠳ (&C) +440 +ᠪᠦᠭᠦᠳᠡ ᠲᠡᠭᠡ (&A) +ᠪᠦᠭᠦᠳᠡ ᠪᠣᠯᠢ (&L) +ᠵᠣᠭᠰᠣᠭᠠᠬᠤ +ᠳᠠᠬᠢᠨ ᠡᠬᠢᠯᠡᠬᠦ +ᠠᠷᠤ ᠲᠠᠯ᠎ᠠ (&B) +ᠡᠮᠦᠨ᠎ᠡ ᠲᠠᠯ᠎ᠠ (&F) +ᠵᠣᠭᠰᠣᠭᠠᠬᠤ (&P) +ᠨᠢᠭᠡᠨᠲᠡ ᠵᠣᠭᠰᠣᠪᠠ +ᠲᠠ ᠦᠨᠡᠬᠡᠷ ᠤᠰᠠᠳᠬᠠᠬᠤ ᠦᠦ ︖ +500 +ᠹᠠᠶᠢᠯ (&F) +ᠨᠠᠶᠢᠷᠠᠭᠤᠯᠬᠤ (&E) +ᠦᠵᠡᠬᠦ (&V) +ᠬᠠᠳᠠᠭᠠᠯᠠᠬᠤ (&A) +ᠪᠠᠭᠠᠵᠢ (&T) +ᠬᠠᠪᠰᠤᠷᠤᠮᠵᠢ (&H) +540 +ᠨᠡᠭᠡᠭᠡᠬᠦ (&O) +ᠣᠳᠣᠬᠢ ᠴᠣᠩᠬᠣ  ᠶᠢ ᠨᠡᠭᠡᠭᠡᠬᠦ (&I) +ᠰᠢᠨ᠎ᠡ ᠴᠣᠩᠬᠣ ᠪᠠᠶᠢᠭᠤᠯᠤᠭᠠᠳ ᠨᠡᠭᠡᠭᠡᠬᠦ (&U) +ᠵᠢᠷᠤᠭ ᠦᠵᠡᠬᠦ (&V) +ᠨᠠᠶᠢᠷᠠᠭᠤᠯᠬᠤ (&E) +ᠲᠠᠬᠢᠨ ᠨᠡᠷᠡᠯᠡᠬᠦ (&M) +ᠬᠣᠣᠰᠯᠠᠬᠤ (&C) +ᠰᠢᠯᠵᠢᠭᠦᠯᠬᠦ (&M) +ᠤᠰᠠᠳᠬᠠᠬᠤ (&D) +ᠹᠠᠶᠢᠯ ᠬᠤᠪᠢᠶᠠᠬᠤ (&S)... +ᠹᠠᠶᠢᠯ  ᠢ ᠨᠡᠶᠢᠯᠡᠭᠦᠯᠬᠦ (&B)... +ᠰᠢᠨᠵᠢ ᠴᠢᠨᠠᠷ (&R) +ᠲᠠᠶᠢᠯᠪᠤᠷᠢ (&N) +ᠹᠠᠶᠢᠯ ᠰᠢᠯᠭᠠᠬᠤ +ᠹᠠᠶᠢᠯ ᠠᠳᠠᠯᠢᠳᠬᠠᠬᠤ +ᠰᠢᠨ᠎ᠡ ᠬᠠᠪᠲᠠᠰᠤ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠹᠠᠶᠢᠯ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠭᠠᠷᠬᠤ (&X) +600 +ᠪᠦᠬᠦᠨ  ᠢ ᠰᠣᠩᠭᠣᠬᠤ (&A) +ᠪᠦᠬᠦᠨ  ᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠡᠰᠡᠷᠭᠦ ᠰᠣᠩᠭᠣᠬᠤ (&I) +ᠰᠣᠩᠭᠣᠬᠤ ... +ᠤᠰᠠᠳᠬᠠᠬᠤ ᠪᠠᠨ ᠰᠣᠩᠭᠣᠬᠤ ... +ᠠᠳᠠᠯᠢ ᠬᠡᠯᠪᠡᠷᠢ  ᠶᠢᠨ ᠹᠠᠶᠢᠯ  ᠢ ᠰᠣᠩᠭᠣᠬᠤ +ᠠᠳᠠᠯᠢ ᠬᠡᠯᠪᠡᠷᠢ  ᠶᠢᠨ ᠹᠠᠶᠢᠯ  ᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ +700 +ᠶᠡᠬᠡ ᠵᠢᠷᠤᠭ (&G) +ᠪᠠᠭ᠎ᠠ ᠵᠢᠷᠤᠭ (&M) +ᠵᠢᠭᠰᠠᠭᠠᠬᠤ (&L) +ᠨᠠᠷᠢᠨ ᠠᠭᠤᠯᠭ᠎ᠠ (&D) +730 +ᠮᠥᠷᠯᠡᠬᠦ ᠦᠭᠡᠢ +ᠲᠡᠭᠰᠢ ᠬᠡᠪ +ᠬᠣᠣᠰ ᠨᠢᠭᠤᠷ (&2) +ᠪᠠᠭᠠᠵᠢ  ᠶᠢᠨ ᠰᠠᠮᠪᠠᠷ᠎ᠠ (&T) +ᠦᠨᠳᠦᠰᠦ ᠬᠠᠪᠲᠠᠰᠤ ᠨᠡᠭᠡᠭᠡᠬᠦ +ᠳᠡᠭᠡᠭᠰᠢ +ᠬᠠᠪᠲᠠᠰᠤᠨ ‍ᠣ ᠲᠡᠦᠬᠡ ... +ᠰᠢᠨᠡᠳᠬᠡᠬᠦ (&R) +750 +ᠳᠠᠩᠰᠠᠨ ‍ᠣ ᠪᠠᠭᠠᠵᠢ  ᠶᠢᠨ ᠰᠠᠮᠪᠠᠷ᠎ᠠ +ᠪᠠᠷᠢᠮᠵᠢᠶ᠎ᠠ ᠪᠠᠭᠠᠵᠢ  ᠶᠢᠨ ᠰᠠᠮᠪᠠᠷ᠎ᠠ +ᠶᠡᠬᠡ ᠳᠠᠷᠤᠪᠴᠢ +ᠳᠠᠷᠤᠪᠴᠢ  ᠶᠢᠨ ᠦᠰᠦᠭ ᠢᠯᠡᠷᠡᠬᠦ +800 +ᠬᠠᠳᠠᠭᠠᠯᠠᠮᠵᠢ ᠲᠠᠭᠠᠨ ᠨᠡᠮᠡᠬᠦ (&A) +ᠱᠣᠰᠢᠭ᠎ᠠ +900 +ᠰᠣᠩᠭᠣᠯᠲᠠ (&O) +ᠥᠭᠭᠦᠭᠳᠡᠯ ᠰᠢᠯᠭᠠᠯᠲᠠ (&B) +960 +ᠬᠠᠪᠰᠤᠷᠤᠮᠵᠢ ᠦᠵᠡᠬᠦ (&C) +7-Zip ‍ᠣ ᠲᠤᠬᠠᠢ (&A) +1003 +ᠵᠠᠮ +ᠨᠡᠷᠡᠶᠢᠳᠦᠯ +ᠥᠷᠭᠡᠳᠭᠡᠭᠰᠡᠨ ᠨᠡᠷ᠎ᠡ +ᠬᠠᠪᠲᠠᠰᠤ +ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠠᠪᠴᠢᠶᠠᠭᠰᠠᠨ ‍ᠣ ᠳᠠᠷᠠᠭᠠᠬᠢ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠰᠢᠨᠵᠢ ᠴᠢᠨᠠᠷ +ᠪᠠᠶᠢᠭᠤᠯᠤᠭᠰᠠᠨ ᠴᠠᠭ +ᠦᠵᠡᠭᠰᠡᠨ ᠴᠠᠭ +ᠵᠠᠰᠠᠭᠰᠠᠨ ᠴᠠᠭ +ᠬᠠᠳᠠᠭᠤᠷ +ᠲᠠᠶᠢᠯᠪᠤᠷᠢ +ᠪᠠᠲᠤᠵᠢᠭᠤᠯᠬᠤ +ᠡᠮᠦᠨ᠎ᠡ ᠨᠢ ᠬᠤᠪᠢᠶᠠᠬᠤ +ᠰᠡᠭᠦᠯᠡᠷ ᠨᠢ ᠬᠤᠪᠢᠶᠠᠬᠤ +ᠲᠣᠯᠢ ᠪᠢᠴᠢᠭ  ᠦᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +CRC +ᠲᠥᠷᠥᠯ +ᠠᠷᠢᠯᠭᠠᠬᠤ ᠵᠦᠢᠯ +ᠲᠣᠭᠠᠴᠠᠬᠤ ᠠᠷᠭ᠎ᠠ +ᠭᠣᠣᠯ ᠠᠵᠢᠯᠯᠠᠬᠤ ᠰᠢᠰᠲ᠋ᠧᠮ +ᠹᠠᠶᠢᠯ  ᠤᠨ ᠰᠢᠰᠲ᠋ᠧᠮ +ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ +ᠪᠦᠯᠦᠭ +ᠥᠰᠦᠭ  ᠦᠨ ᠬᠡᠰᠡᠭ +ᠲᠠᠶᠢᠯᠪᠤᠷᠢ +ᠣᠷᠣᠨ ᠲᠣᠭᠲᠠᠭᠠᠬᠤ +ᠵᠠᠮ  ᠤᠨ ᠡᠮᠦᠨ᠎ᠡ ᠬᠡᠰᠡᠭ +ᠬᠠᠪᠲᠠᠰᠤ +ᠹᠠᠶᠢᠯ +ᠬᠡᠪ +ᠡᠪᠬᠡᠮᠡᠯ +ᠣᠯᠠᠨ ᠡᠪᠬᠡᠮᠡᠯ ᠠᠪᠴᠢᠭᠤᠯᠬᠤ +ᠬᠠᠵᠠᠭᠠᠢ ᠰᠢᠯᠵᠢᠭᠦᠯᠬᠦ +ᠵᠠᠯᠭᠠᠬᠤ +ᠥᠰᠦᠭ  ᠦᠨ ᠬᠡᠰᠡᠭ +ᠡᠪᠬᠡᠮᠡᠯ ᠬᠤᠪᠢᠶᠠᠬᠤ + +64 ᠣᠷᠣᠨ +ᠶᠡᠬᠡ ᠦᠰᠦᠭ  ᠦᠨ ᠬᠡᠰᠡᠭ  ᠦᠨ ᠳᠠᠷᠠᠭᠠᠯᠠᠯ +CPU +ᠹᠢᠽᠢᠺ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠹᠠᠶᠢᠯ  ᠤᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠨᠡᠶᠢᠯᠡᠪᠦᠷᠢ  ᠶᠢ ᠰᠢᠯᠭᠠᠬᠤ +ᠣᠨᠴᠠᠯᠢᠭ +ᠬᠡᠶᠢᠰᠪᠦᠷᠢ ᠬᠠᠶ᠋ᠢᠭ +ID +ᠵᠢᠭᠠᠬᠠᠨ ᠹᠠᠶᠢᠯ  ᠤᠨ ᠨᠡᠷ᠎ᠡ +ᠫᠷᠦᠭᠷᠡᠮ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠳᠡᠪᠢᠭᠦᠷ  ᠦᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠬᠡᠪ ᠵᠠᠭᠪᠤᠷ +ᠵᠠᠯᠭᠠᠬᠤ +ᠪᠤᠷᠤᠭᠤ +ᠶᠡᠷᠤᠩᠬᠡᠢ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠬᠡᠷᠡᠭᠯᠡᠭᠰᠡᠨ ᠣᠷᠣᠨ ᠵᠠᠢ +ᠪᠠᠭᠴᠠ  ᠶᠢᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠡᠪᠬᠡᠮᠡᠯ  ᠦᠨ ᠲᠡᠮᠳᠡᠭ +ᠲᠤᠰ ᠭᠠᠵᠠᠷ  ᠤᠨ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ +ᠬᠠᠩᠭᠠᠭᠴᠢ +2100 +ᠰᠣᠩᠭᠣᠯᠲᠠ +ᠬᠡᠯᠡ +ᠬᠡᠯᠡ ᠰᠣᠩᠭᠣᠬᠤ᠄ +ᠨᠠᠶᠢᠷᠠᠭᠤᠯᠤᠭᠴᠢ +ᠲᠣᠭᠲᠠᠭᠰᠠᠨ ᠨᠠᠶᠢᠷᠠᠭᠤᠯᠤᠭᠴᠢ (&E): +ᠲᠣᠭᠲᠠᠭᠰᠠᠨ ᠹᠠᠶᠢᠯ  ᠢ ᠠᠳᠠᠯᠢᠳᠬᠠᠬᠤ (&D): +2200 +ᠰᠢᠰᠲ᠋ᠧᠮ +7-Zip ᠪᠠᠷ ᠹᠠᠶᠢᠯ  ᠤᠨ ᠲᠥᠷᠥᠯ  ᠢ ᠬᠣᠯᠪᠣᠭᠳᠠᠭᠤᠯᠬᠤ ᠄ +2301 +7-Zip ᠶ᠋ᠢ ᠪᠠᠷᠠᠭᠤᠨ ᠳᠠᠷᠤᠪᠴᠢ ᠳ᠋ᠥ ᠨᠡᠮᠡᠬᠦ +ᠪᠠᠷᠠᠭᠤᠨ ᠳᠠᠷᠤᠪᠴᠢ ᠳ᠋ᠥ ᠳᠠᠪᠬᠤᠴᠠᠭᠤᠯᠬᠤ +ᠪᠠᠷᠠᠭᠤᠨ ᠳᠠᠷᠤᠪᠴᠢ ᠳ᠋ᠥ ᠢᠯᠡᠷᠡᠬᠦ ᠺᠣᠳ᠋  ᠢ ᠰᠣᠩᠭᠣᠬᠤ +2320 +<ᠬᠠᠪᠲᠠᠰᠤ > +< ᠡᠪᠬᠡᠮᠡᠯ > +ᠠᠪᠴᠢᠮᠠᠯ  ᠢ ᠨᠡᠭᠡᠭᠡᠬᠦ +ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ  ᠢ ᠭᠠᠷᠭᠠᠨ ᠠᠪᠬᠤ ... +ᠠᠪᠴᠢᠮᠠᠯ ᠳ᠋ᠥ ᠨᠡᠮᠡᠬᠦ ... +ᠠᠪᠴᠢᠮᠠᠯ  ᠢ ᠰᠢᠯᠭᠠᠬᠤ +ᠳᠣᠣᠷᠠᠬᠢ ᠭᠠᠷᠴᠠᠭ ᠳ᠋ᠥ ᠭᠠᠷᠭᠠᠨ ᠠᠪᠬᠤ +{0}ᠤᠷᠤᠭᠤ ᠵᠠᠳᠠᠯᠬᠤ +{0} ᠳ᠋ᠥ ᠨᠡᠮᠡᠬᠦ +ᠠᠪᠴᠢᠶᠠᠭᠠᠳ ᠢᠮᠸᠯ ᠶᠠᠪᠤᠭᠤᠯᠬᠤ ... +ᠠᠪᠴᠢᠶᠠᠭᠠᠳ {0}ᠶ᠋ᠢ ᠢᠯᠡᠭᠡᠬᠦ +2400 +ᠬᠠᠪᠲᠠᠰᠤ +ᠠᠵᠢᠯ  ᠤᠨ ᠬᠠᠪᠲᠠᠰᠤ (&W) +ᠰᠢᠰᠲ᠋ᠧᠮ \ ᠵᠠᠰᠠᠪᠤᠷᠢ  ᠶᠢᠨ ᠬᠠᠪᠲᠠᠰᠤ (&S) +ᠣᠳᠣ  ᠶᠢᠨ ᠬᠠᠪᠲᠠᠰᠤ (&C) +ᠲᠣᠭᠲᠠᠮᠠᠯ ᠪᠠᠶᠢᠷᠢ (&S) +ᠵᠥᠪᠬᠡᠨ ᠵᠥᠭᠡᠭᠡᠪᠦᠷᠢ  ᠶᠢᠨ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠳ᠋ᠥ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ +ᠲᠦᠷ ᠴᠠᠭ  ᠤᠨ ᠠᠪᠴᠢᠮᠠᠯ ᠹᠠᠶᠢᠯ ᠡᠭᠦᠰᠬᠡᠬᠦ ᠪᠠᠶᠢᠷᠢᠯᠠᠯ  ᠢ ᠲᠣᠳᠣᠷᠬᠠᠶᠢᠯᠠᠯ +2500 +ᠢᠯᠡᠷᠡᠬᠦ +ᠢᠯᠡᠷᠡᠬᠦ “..” ᠵᠦᠢᠯ ( ᠳᠡᠭᠡᠭᠰᠢ ᠬᠣᠣᠰ ᠲᠣᠪᠴᠢᠳᠠᠭᠠᠳ ) +ᠦᠨᠡᠨ ᠵᠢᠷᠤᠭ ᠨᠢ ᠢᠯᠡᠷᠡᠬᠦ +ᠰᠢᠰᠲ᠋ᠧᠮ  ᠦᠨ ᠲᠣᠪᠶᠣᠭ ᠨᠢ ᠢᠯᠡᠷᠡᠬᠦ +ᠪᠦᠬᠦ ᠮᠥᠷ  ᠢ ᠰᠣᠩᠭᠣᠬᠤ (&F) +ᠰᠦᠯᠵᠢᠶᠡᠨ ᠤᠲᠠᠰᠤ ᠢᠯᠡᠷᠡᠬᠦ (&G) +ᠲᠣᠪᠴᠢᠳᠠᠭᠠᠳ ᠨᠡᠭᠡᠭᠡᠬᠦ +7-Zip ᠤᠯᠠᠮᠵᠢᠯᠠᠯᠲᠤ ᠬᠡᠪ  ᠢ ᠰᠣᠩᠭᠣᠬᠤ (&A) +ᠶᠡᠬᠡ ᠷᠠᠮ  ᠤᠨ ᠨᠢᠭᠤᠷ  ᠢ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ (&L) +2900 +7-Zip  ᠶᠢᠨ ᠲᠤᠬᠠᠢ +7-Zip ᠪᠣᠯ ᠲᠥᠯᠥᠪᠦᠷᠢ ᠦᠭᠡᠢ ᠰᠣᠹᠲ ᠂ ᠲᠠ ᠬᠠᠨᠳᠢᠪ  ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ ᠪᠠᠷ 7 -zip ᠶ᠋ᠢ ᠳᠡᠮᠵᠢᠵᠦ ᠪᠣᠯᠣᠨ᠎ᠠ ᠂ ᠮᠣᠩᠭᠣᠯ ᠰᠣᠹᠲ  ᠤᠨ ᠪᠦᠯᠦᠭ ᠨᠢᠭᠡ 39338772 ᠬᠣᠶᠠᠷ 38803882 ᠵᠢᠨ ᠰᠠᠴᠤᠷᠠᠯᠲᠤ ᠮᠣᠩᠭᠣᠯᠴᠢᠯᠠᠪᠠ ᠂ QQ 136087084 Email: saqirilatu@126.com +3000 +ᠰᠢᠰᠲ᠋ᠧᠮ ᠷᠠᠮ  ᠢ ᠨᠢ ᠬᠤᠪᠢᠶᠠᠵᠤ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠪᠤᠷᠤᠭᠤ ᠦᠭᠡᠢ +{0}  ᠢ ᠰᠣᠩᠭᠣᠬᠤ +{0}” ᠬᠠᠪᠲᠠᠰᠤ ᠪᠠᠶᠢᠭᠤᠯᠵᠤ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠲᠣᠰ ᠠᠪᠴᠢᠮᠠᠯ  ᠤᠨ ᠰᠢᠨᠡᠳᠬᠡᠬᠦ  ᠶᠢ ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ +ᠠᠪᠴᠢᠮᠠᠯ ᠨᠡᠭᠡᠭᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ {0}” +ᠪᠠᠲᠤ ᠠᠪᠴᠢᠮᠠᠯ ᠨᠡᠭᠡᠭᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ “{0}” ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠪᠤᠷᠤᠭᠤ +ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ ᠠᠪᠴᠢᠮᠠᠯ  ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ +{0} ᠹᠠᠶᠢᠯ ᠨᠢᠭᠡᠨᠲᠡ ᠪᠠᠶᠢᠨ᠎ᠠ +ᠹᠠᠶᠢᠯ“{0}”ᠥᠭᠡᠷᠡᠴᠢᠯᠡᠭᠳᠡᠪᠡ \nᠲᠠ ᠠᠪᠴᠢᠮᠠᠯ  ᠳᠠᠬᠢ ᠹᠠᠶᠢᠯ  ᠢᠶᠠᠨ ᠰᠢᠨᠡᠳᠬᠡᠬᠦ ᠦᠦ ? +ᠹᠠᠶᠢᠯ  ᠢ ᠰᠢᠨᠡᠳᠬᠡᠵᠦ ᠳᠡᠶᠢᠯᠦᠭᠰᠡᠨ ᠦᠭᠡᠢ \n“{0}”ᠲᠤᠰ ᠠᠪᠴᠢᠮᠠᠯ ᠪᠤᠷᠤᠭᠤ ᠭᠠᠷᠴᠠᠢ +ᠭᠠᠳᠠᠨᠠᠬᠢ ᠨᠠᠶᠢᠷᠠᠭᠤᠯᠭ᠎ᠠ  ᠶᠢ ᠠᠵᠢᠯᠯᠠᠭᠤᠯᠵᠤ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠲᠤᠰ ᠹᠠᠶᠢᠯ ᠬᠣᠣᠷ ᠲᠠᠢ ( ᠹᠠᠶᠢᠯ  ᠤᠨ ᠨᠡᠷ᠎ᠡ ᠳ᠋ᠥ ᠣᠯᠠᠨ ᠬᠣᠭᠣᠰᠤᠨ ᠵᠠᠢ ᠪᠠᠶᠢᠨ᠎ᠠ )。 +ᠬᠡᠲᠦᠷᠬᠡᠢ ᠤᠷᠲᠤ ᠂ ᠠᠵᠢᠯᠯᠠᠭᠤᠯᠵᠤ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠲᠠ ᠵᠢᠭᠠᠪᠠᠯ ᠨᠢᠭᠡ ᠹᠠᠶᠢᠯ ᠰᠣᠩᠭᠣᠨ᠎ᠠ +ᠲᠠ ᠬᠠᠮᠤᠭ ᠪᠠᠭ᠎ᠠ  ᠳᠠᠭᠠᠨ ᠨᠢᠭᠡ ᠹᠠᠶᠢᠯ ᠰᠣᠩᠭᠣᠨ᠎ᠠ +ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠬᠡᠲᠦᠷᠬᠡᠢ ᠣᠯᠠᠨ +3300 +ᠶᠠᠭ ᠭᠠᠷᠭᠠᠨ ᠠᠪᠴᠤ ᠪᠠᠶᠢᠨ᠎ᠠ .... +ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠰᠢᠯᠭᠠᠬᠤ +ᠶᠡᠬ ᠨᠡᠭᠡᠭᠡᠵᠦ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠬᠠᠶᠢᠵᠤ ᠪᠠᠶᠢᠨ᠎ᠠ ... +3400 +ᠭᠠᠷᠭᠠᠨ ᠠᠪᠬᠤ +(&X)  ᠠᠴᠠ ᠭᠠᠷᠭᠠᠨ ᠠᠪᠬᠤ : +ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ  ᠢ ᠭᠠᠷᠭᠠᠨ ᠠᠪᠤᠭᠰᠠᠨ ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢᠨ ᠪᠠᠶᠢᠷᠢ +3410 +ᠵᠠᠮ  ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ +ᠪᠦᠷᠢᠨ ᠵᠠᠮ +ᠵᠠᠮ ᠦᠭᠡᠢ +3420 +ᠰᠣᠯᠢᠬᠤ ᠬᠡᠯᠪᠡᠷᠢ +ᠰᠣᠯᠢᠬᠤ  ᠠᠴᠠ ᠡᠮᠦᠨ᠎ᠡ ᠠᠰᠠᠭᠤᠨ᠎ᠠ +ᠰᠠᠨᠠᠭᠤᠯᠬᠤ ᠦᠭᠡᠢ ᠰᠢᠭᠤᠳ ᠰᠣᠯᠢᠬᠤ +ᠪᠠᠶᠢᠬᠤ ᠹᠠᠶᠢᠯ  ᠢ ᠥᠰᠦᠷᠬᠡᠶᠢᠯᠨᠨ ᠭᠠᠷᠬᠤ +ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠵᠢᠨᠷ ᠨᠡᠷᠡᠯᠡᠬᠦ +ᠣᠳᠣᠬᠢ ᠹᠠᠶᠢᠯ  ᠢᠶᠠᠨ ᠨᠡᠷᠡᠯᠡᠬᠦ +3500 +ᠹᠠᠶᠢᠯ  ᠢ ᠰᠣᠯᠢᠨ᠎ᠠ +ᠲᠣᠰ ᠬᠠᠪᠲᠠᠰᠤ ᠳ᠋ᠥ ᠠᠳᠠᠯᠢ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ ᠲᠠᠢ ᠹᠠᠶᠢᠯ ᠪᠠᠶᠢᠨ᠎ᠠ +ᠣᠳᠣ ᠪᠠᠶᠢᠬᠤ ᠹᠠᠶᠢᠯ  ᠢᠶᠠᠨ +ᠰᠣᠯᠢᠬᠤ +{0}ᠦᠰᠦᠭ  ᠦᠨ ᠰᠢᠷᠬᠡᠭ +ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠰᠢᠨ᠎ᠡ ᠨᠡᠷᠡᠯᠡᠬᠦ (&U) +3700 +ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ ᠠᠪᠴᠢᠮᠠᠯ ᠲᠤᠭᠠᠴᠢᠯᠳᠠ “{0}”。 +ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ “{0}” ᠪᠤᠷᠤᠭᠤ ᠭᠠᠷᠴᠠᠢ ᠂ ᠹᠠᠶᠢᠯ ᠡᠪᠳᠡᠷᠡᠭᠰᠡᠨ ᠡ +CRC ᠰᠢᠯᠭᠠᠭᠠᠳ“{0}”ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠹᠠᠶᠢᠯ ᠡᠪᠳᠡᠷᠡᠭᠰᠡᠨ ᠡ +ᠪᠠᠲᠤ ᠹᠠᠶᠢᠯ “{0}”  ᠤᠨ ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ ᠨᠢ ᠪᠤᠷᠤᠭᠤ ᠂ ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠪᠤᠷᠤᠭᠤ +ᠪᠠᠲᠤ ᠹᠠᠶᠢᠯ “{0}” CRC  ᠵᠢᠨ ᠰᠢᠯᠭᠠᠭᠰᠠᠨ ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ ᠨᠢ ᠪᠤᠷᠤᠭᠤ ᠂ ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠪᠤᠷᠤᠭᠤ +3800 +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠣᠷᠣᠭᠤᠯᠬᠤ +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠣᠷᠣᠭᠤᠯᠬᠤ ᠄ +ᠳᠠᠬᠢᠨ ᠣᠷᠣᠭᠤᠯᠬᠤ +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠢᠯᠡᠷᠡᠬᠦ (&S) +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠪᠤᠷᠤᠭᠤ +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠵᠥᠪᠬᠡᠨ ᠠᠩᠭ᠍ᠯᠢ ᠬᠡᠯᠡ ᠪᠣᠯᠣᠨ ᠲᠣᠭ᠎ᠠ ᠬᠢᠭᠡᠳ ᠣᠨᠴᠠᠭᠠᠢ ᠲᠡᠮᠳᠡᠭ (!、#、$...) +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠨᠢ ᠬᠡᠲᠦᠷᠬᠡᠢ ᠤᠷᠲᠤ +ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ +3900 +ᠬᠡᠷᠡᠭᠰᠡᠭᠰᠡᠨ ᠴᠠᠭ ᠄ +ᠦᠯᠡᠳᠡᠭᠰᠡᠨ ᠴᠠᠭ ᠄ +ᠶᠡᠷᠤᠩᠬᠡᠢ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +ᠬᠤᠷᠳᠤᠴᠠ ᠄ +ᠨᠢᠭᠡᠨᠲᠡ ᠰᠢᠢᠳᠪᠦᠷᠢᠯᠡᠭᠰᠡᠨ ᠨᠢ ᠄ +ᠠᠪᠴᠢᠶᠠᠭᠰᠠᠨ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠄ +ᠪᠤᠷᠤᠭᠤ ᠭᠠᠷᠴᠠᠢ ᠄ +ᠠᠪᠴᠢᠮᠠᠯ ᠄ +4000 +ᠠᠪᠴᠢᠮᠠᠯ ᠳ᠋ᠥ ᠨᠡᠮᠡᠬᠦ +ᠠᠪᠴᠢᠮᠠᠯ (&A): +ᠰᠢᠨᠡᠳᠬᠡᠬᠦ ᠬᠡᠯᠪᠡᠷᠢ (&U): +ᠠᠪᠴᠢᠮᠠᠯ  ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ (&F): +ᠠᠪᠴᠢᠶᠠᠬᠤ ᠳᠡᠰ (&L): +ᠠᠪᠴᠢᠶᠠᠬᠤ ᠠᠷᠭ᠎ᠠ (&M): +ᠲᠣᠯᠢ  ᠶᠢᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ (&D): +ᠳᠠᠩ ᠦᠭᠡᠰ  ᠦᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ (&W): +ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ  ᠶᠢᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ +CPU ᠬᠡᠷᠡᠭᠯᠡᠭᠰᠡᠨ ᠬᠡᠮᠵᠢᠶ᠎ᠡ +ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ (&P): +ᠰᠣᠩᠭᠣᠯᠲᠠ +ᠥᠪᠡᠷᠲᠡᠭᠡᠨ ᠠᠴᠢᠶᠠᠯᠠᠭᠴᠢ ᠫᠷᠦᠭᠷᠡᠮ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ (&X) +ᠠᠪᠴᠢᠮᠠᠯ ᠹᠠᠶᠢᠯ  ᠢᠶᠠᠨ ᠬᠤᠪᠢᠶᠠᠯᠴᠠᠬᠤ +ᠪᠠᠲᠤᠵᠢᠭᠤᠯᠬᠤ +ᠪᠠᠲᠤᠵᠢᠭᠤᠯᠬᠤ ᠲᠣᠭᠠᠴᠠᠬᠤ ᠠᠷᠭ᠎ᠠ +ᠪᠠᠲᠤ ᠹᠠᠶᠢᠯ  ᠤᠨ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ (&N) +ᠠᠪᠴᠢᠶᠠᠯᠠᠬᠤ ᠳ᠋ᠥ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠷᠠᠮ +ᠵᠠᠳᠠᠯᠬᠤ ᠳ᠋ᠥ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠷᠠᠮ +4050 +ᠵᠥᠪᠬᠡᠨ ᠬᠠᠳᠠᠭᠠᠯᠠᠬᠤ +ᠣᠨᠴᠠ ᠬᠤᠷᠳᠤᠨ ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠬᠤᠷᠳᠤᠨ ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠪᠠᠷᠢᠮᠵᠢᠶ᠎ᠠ ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠬᠠᠮᠤᠭ ᠶᠡᠬᠡ ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠴᠢᠨᠠᠷᠯᠠᠩᠭᠤᠢ ᠠᠪᠴᠢᠶᠠᠬᠤ +4060 +ᠹᠠᠶᠢᠯ ᠨᠡᠮᠡᠭᠡᠳ ᠰᠣᠯᠢᠬᠤ +ᠹᠠᠶᠢᠯ  ᠢ ᠰᠢᠨᠡᠳᠬᠡᠭᠡᠳ ᠨᠡᠮᠡᠬᠦ +ᠪᠠᠶᠢᠬᠤ ᠹᠠᠶᠢᠯ  ᠢ ᠰᠢᠨᠡᠳᠬᠡᠬᠦ +ᠠᠪᠴᠢᠮᠠᠯ  ᠤᠨ ᠠᠭᠤᠯᠭ᠎ᠠ  ᠶᠢ ᠵᠡᠷᠭᠡᠴᠡᠭᠦᠯᠬᠦ +4070 +ᠦᠵᠡᠬᠦ ... +ᠪᠦᠬᠦ ᠹᠠᠶᠢᠯ +ᠲᠡᠭᠡ +ᠪᠤᠯᠢ +6000 +ᠬᠣᠣᠰᠯᠠᠬᠤ +ᠰᠢᠯᠵᠢᠭᠦᠯᠬᠦ +ᠬᠣᠣᠰᠯᠠᠭᠤᠯᠤᠨ ᠄ +ᠰᠢᠯᠵᠢᠭᠦᠯᠦᠨ +ᠬᠣᠣᠰᠯᠠᠵᠤ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠰᠢᠯᠵᠢᠭᠦᠯᠵᠦ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠶᠠᠭ ᠰᠢᠨ᠎ᠡ ᠨᠡᠷᠡᠶᠢᠳᠴᠦ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠬᠠᠪᠲᠠᠰᠤ ᠰᠣᠩᠭᠣᠬᠤ +ᠣᠳᠣᠬᠢ ᠠᠵᠢᠯᠯᠠᠭ᠎ᠠ  ᠶᠢ ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ +ᠹᠠᠶᠢᠯ ᠪᠠ ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢ ᠲᠠᠬᠢᠨ ᠨᠡᠷᠡᠶᠢᠳᠴᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠹᠠᠶᠢᠯ  ᠢ ᠬᠣᠣᠰᠯᠠᠬᠤ ᠦᠦ ︖ +ᠹᠠᠶᠢᠯ  ᠢ ᠠᠪᠴᠢᠮᠠᠯ ᠳ᠋ᠥ ᠬᠣᠣᠰᠯᠠᠬᠤ ᠦᠦ ︖ +6100 +ᠹᠠᠶᠢᠯ ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠣᠯᠠᠨ ᠹᠠᠶᠢᠯ  ᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠦᠨᠡᠬᠡᠷ“{0}” ᠶᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ ᠦᠦ ? +ᠦᠨᠡᠬᠡᠷ“{0}”ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢᠨ ᠪᠦᠬᠦ ᠠᠭᠤᠯᠭ᠎ᠠ  ᠶᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ ᠦᠦ ? +ᠦᠨᠡᠬᠡᠷ {0} ᠵᠢ ᠤᠰᠠᠳᠬᠠᠬᠤ ᠦᠦ ? +ᠤᠰᠠᠳᠬᠠᠵᠤ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠹᠠᠶᠢᠯ ᠪᠠ ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢ ᠤᠰᠠᠳᠬᠠᠵᠤ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +ᠰᠢᠰᠲ᠋ᠧᠮ ᠬᠡᠲᠦᠷᠬᠡᠢ ᠤᠷᠲᠤ ᠵᠠᠮ ᠲᠠᠢ ᠹᠠᠶᠢᠯ  ᠢ ᠬᠣᠭ ᠬᠤᠷᠢᠶᠠᠭᠴᠢ ᠳ᠋ᠥ ᠰᠢᠯᠵᠢᠭᠦᠯᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ +6300 +ᠰᠢᠨ᠎ᠡ ᠬᠠᠪᠲᠠᠰᠤ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠰᠢᠨ᠎ᠡ ᠹᠠᠶᠢᠯ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢᠨ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ ᠄ +ᠹᠠᠶᠢᠯ  ᠤᠨ ᠨᠡᠷ᠎ᠡ +ᠰᠢᠨ᠎ᠡ ᠬᠠᠪᠲᠠᠰᠤ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ +ᠰᠢᠨ᠎ᠡ ᠹᠠᠶᠢᠯ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ .txt +ᠬᠠᠪᠲᠠᠰᠤ ᠪᠠᠶᠢᠭᠤᠯᠵᠤ ᠳᠡᠶᠢᠯᠦᠭᠰᠡᠨ ᠦᠭᠡᠢ +ᠰᠢᠨ᠎ᠡ ᠹᠠᠶᠢᠯ ᠪᠠᠶᠢᠭᠤᠯᠵᠤ ᠳᠡᠶᠢᠯᠦᠭᠰᠡᠨ ᠦᠭᠡᠢ +6400 +ᠲᠠᠶᠢᠯᠪᠤᠷᠢ +ᠲᠠᠶᠢᠯᠪᠤᠷᠢ (&C): +ᠰᠣᠩᠭᠣᠬᠤ +ᠰᠣᠩᠭᠣᠭᠰᠠᠨ  ᠢᠶᠠᠨ ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠨᠣᠮᠧᠷ ᠄ +6600 +ᠰᠢᠨᠵᠢ ᠴᠢᠨᠠᠷ +ᠬᠠᠪᠲᠠᠰᠤ  ᠶᠢᠨ ᠲᠡᠦᠬᠡ +ᠣᠨᠣᠰᠢᠯᠠᠭᠰᠠᠨ ᠰᠤᠷᠠᠭ +ᠰᠤᠷᠠᠭ +7100 +ᠮᠢᠨᠤ ᠺᠣᠮᠫᠢᠦ᠋ᠲ᠋ᠧᠷ +ᠰᠦᠯᠵᠢᠶᠡᠨ ‍ᠣ ᠬᠠᠨᠢ +ᠮᠢᠨᠤ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ +ᠰᠢᠰᠲ᠋ᠧᠮ +7200 +ᠨᠡᠮᠡᠬᠦ +ᠭᠠᠷᠭᠠᠨ ᠠᠪᠬᠤ +ᠰᠢᠯᠭᠠᠬᠤ +ᠬᠣᠣᠰᠯᠠᠬᠤ +ᠰᠢᠯᠵᠢᠭᠦᠯᠬᠦ +ᠤᠰᠠᠳᠬᠠᠬᠤ +ᠰᠤᠷᠠᠭ +7300 +ᠹᠠᠶᠢᠯ ᠰᠢᠯᠭᠠᠬᠤ +ᠹᠠᠶᠢᠯ  ᠢ (&S) ᠵᠦᠭ ᠰᠠᠯᠭᠠᠬᠤ᠄ +ᠡᠪᠬᠡᠮᠡᠯ ᠬᠤᠪᠢᠶᠠᠬᠤ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ (&V): +ᠰᠠᠯᠭᠠᠵᠤ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠰᠠᠯᠭᠠᠬᠤ ᠦᠦ +ᠲᠠ ᠹᠠᠶᠢᠯ  ᠢᠶᠠᠨ {0} ᠬᠡᠰᠡᠭ ᠬᠤᠪᠢᠶᠠᠬᠤ ᠦᠦ ︖ +ᠡᠪᠬᠡᠮᠡᠯ ᠬᠤᠪᠢᠶᠠᠭᠰᠠᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ ᠨᠢ ᠤᠭ ᠹᠠᠶᠢᠯ  ᠠᠴᠠ ᠪᠠᠭ᠎ᠠ ᠪᠠᠶᠢᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠢ +ᠡᠪᠬᠡᠮᠡᠯ ᠬᠤᠪᠢᠶᠠᠬᠤ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ ᠨᠢ ᠪᠤᠷᠤᠭᠤ +ᠡᠪᠬᠡᠮᠡᠯ ᠬᠤᠪᠢᠶᠠᠬᠤ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ  ᠶᠢ ᠲᠣᠭᠲᠠᠭᠠᠬᠤ {0} ᠦᠰᠦᠭ  ᠦᠨ ᠰᠢᠷᠬᠡᠭ \nᠲᠠ ᠳᠣᠣᠷᠠᠬᠢ ᠹᠠᠶᠢᠯ  ᠢ ᠬᠤᠪᠢᠶᠠᠬᠤ ᠦᠦ ? +7400 +ᠹᠠᠶᠢᠯ ᠨᠡᠶᠢᠯᠡᠭᠦᠯᠬᠦ +ᠹᠠᠶᠢᠯ  ᠢ (&S) ᠳ᠋ᠥ ᠨᠡᠶᠢᠯᠡᠭᠦᠯᠬᠦ +ᠨᠡᠶᠢᠯᠡᠭᠦᠯᠵᠦ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠬᠤᠪᠢᠷᠢ ᠡᠪᠬᠡᠮᠡᠯ  ᠦᠨ ᠲᠦᠷᠦᠭᠦᠦ ᠹᠠᠶᠢᠯ  ᠢ ᠰᠣᠩᠭᠣᠭᠠᠷᠠᠢ +ᠬᠤᠪᠢᠷᠢ ᠡᠪᠬᠡᠮᠡᠯ  ᠢ ᠲᠠᠨᠢᠬᠤ ᠦᠭᠡᠢ +ᠪᠤᠰᠤᠳ ᠬᠤᠪᠢᠷᠢ ᠡᠪᠬᠡᠮᠡᠯ ᠬᠠᠶᠢᠵᠤ ᠣᠯᠣᠭᠰᠠᠨ ᠦᠭᠡᠢ +7500 +ᠰᠢᠯᠭᠠᠵᠤ ᠪᠠᠶᠢᠨ᠎ᠠ ... +ᠰᠢᠯᠭᠠᠭᠰᠠᠨ ᠰᠤᠷᠠᠭ +CRC ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ ᠰᠢᠯᠭᠠᠬᠤ +CRC ᠲᠣᠭ᠎ᠠ ᠪᠠᠷᠢᠮᠲᠠ ᠪᠠ ᠹᠠᠶᠢᠯ  ᠤᠨ ᠨᠡᠷ᠎ᠡ  ᠶᠢ ᠰᠢᠯᠭᠠᠬᠤ : +7600 +ᠥᠭᠭᠦᠭᠳᠡᠯ ᠰᠢᠯᠭᠠᠯᠲᠠ +ᠷᠠᠮ ᠬᠡᠷᠡᠭᠯᠡᠯᠲᠡ ᠄ +ᠠᠪᠴᠢᠶᠠᠬᠤ +ᠵᠠᠳᠠᠯᠬᠤ +ᠣᠨᠣᠭ᠎ᠠ ᠥᠭᠬᠦ +ᠶᠡᠷᠤᠩᠬᠡᠢ ᠣᠨᠣᠭ᠎ᠠ +ᠣᠳᠣᠬᠢ +ᠦᠷ᠎ᠡ ᠳ᠋ᠦᠩ +CPUᠬᠡᠷᠡᠭᠯᠡᠭᠰᠡᠨ ᠬᠡᠮᠵᠢᠶ᠎ᠡ +ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ  ᠶᠢᠨ ᠣᠨᠣᠭ᠎ᠠ +ᠪᠠᠲᠤᠯᠠᠭᠳᠠᠭᠰᠠᠨ ᠡ ᠄ diff --git a/Utils/7-Zip/Lang/mng2.txt b/Utils/7-Zip/Lang/mng2.txt new file mode 100644 index 000000000..ad99c235e --- /dev/null +++ b/Utils/7-Zip/Lang/mng2.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 7-Zip 9.20 +; Saqirilatu Mongolqileb +; QQ:136087084 Email:saqirilatu@126.com +; Mongol soft QQ bulug Ⅰ: 39338772 Ⅱ:38803882 +; Toli Mongolian IME +; http://hi.baidu.com/saqirilatuu/item/9438213716f316ebe7bb7a8d +;last updated: 2013-12-11 +; Update and Spelling corrected Bayarsaikhan +; +; +; +0 +7-Zip +Mongolian (MenkCode) +  +401 + + + + + + (&Y) + (&N) + (&C) + + + (&C) +440 +  (&A) +  (&L) + +  +  (&B) +  (&F) + (&P) +  +    ? +500 + (&F) + (&E) + (&V) + (&A) + (&T) + (&H) +540 + (&O) +    (&I) +    (&U) +  (&V) + (&E) +  (&M) + (&C) + (&M) + (&D) +  (&S)... +   (&B)... +  (&R) + (&N) +  +  +   +  + (&X) +600 +   (&A) +   +  (&I) + ... +   ... +      +      +700 +  (&G) +  (&M) + (&L) +  (&D) +730 +  +  +  (&2) +   (&T) +   + +   ... + (&R) +750 +     +    +  +    +800 +   (&A) + +900 + (&O) +  (&B) +960 +  (&C) +7-Zip   (&A) +1003 + + +  + +  +     +  +  +  +  + + + +   +   +     +CRC + +  +  +   +   + + +   + +  +    + + + + +   +  + +   +  + +64  +      +CPU +   +    +   + +  +ID +    +  +    +  + + +   +   +    +   +    + +2100 + + +  : + +  (&E): +    (&D): +2200 + +7-Zip       : +2301 +7-Zip      +    +       +2320 +< > +<  > +   +    ... +   ... +   +     +{0}  +{0}   +   ... + {0}   +2400 + +   (&W) + \  (&S) +   (&C) +  (&S) +      +         +2500 + + “..” (   ) +    +     +    (&F) +   (&G) +  +7-Zip     (&A) +      (&L) +2900 +7-Zip   +7-Zip           7-Zip        Ⅰ39338772 Ⅱ 38803882      QQ 136087084 Email: saqirilatu@126.com +3000 +       +  +{0}   +{0}”     +       +   “{0}” +     “{0}”    ? +     +{0}    + “{0}” \n       ? +     \n“{0}”,    +      +    (         )。 +     +     +       +   +3300 +    .... + + +   ... +  ... +3400 +  +(&X)   : +       +3410 +   +  +  +3420 +  +    +    +     +   +    +3500 +   +        +    + +{0}    +    (&U) +3700 +    “{0}”。 +  “{0}”  ,   +CRC  “{0}”,   +  “{0}”     ,    ? +  “{0}”CRC       ,    ? +3800 +    +    : +  : +   (&S) +    +           (!、#、$...) +    +  +3900 +  : +  : +   : + : +   : +  : + : +: +4000 +   + (&A): +  (&U): +   (&F): +  (&L): +  (&M): +    (&D): +     (&W): +     : +CPU  : +  (&P): + +    (&X) +    + +   : +    (&N) +    : +   : +4050 +  +   +  +  +   +  +4060 +   +    +    +     +4070 + ... +  + + +6000 + + +: +: +  ... +  ... +    ... +  +     +        +    +     +6100 +  +   +    +“{0}”  ? +“{0}”       ? + {0}  ? +  ... +       . +             +6300 +   +   +   : +  : +   +   .txt +    +     +6400 + + (&C): + +   +: +6600 +  +   +  + +7100 +  +   +  + +7200 + +  + + + + + +7300 +  +  (&S)   : +    (&V): +  ... +  +   {0}    ? +           +      +      :{0}    。\n      ? +7400 +  +  (&S)  : +  ... +       +     +      +7500 +  ... +  +CRC   : +CRC       : +7600 +  +  : + + +  +  + +  +CPU   +   +  : diff --git a/Utils/7-Zip/Lang/mr.txt b/Utils/7-Zip/Lang/mr.txt new file mode 100644 index 000000000..0a4e5eb9e --- /dev/null +++ b/Utils/7-Zip/Lang/mr.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.42 : अनुवाद सुबोध गायकवाड (Subodh Gaikwad) +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Marathi +मराठी +401 +ठीक +रद्द + + + +&हो +&नाही +&बंद +मदत + +&सुरु +440 +&सर्व ला हो +&सर्व ला नाही +थांबा +पुन्हा सुरु करा +&मागे लपवा +&समोर आणा +&विश्राम +विश्राम +तुम्हाला रद्द करण्याबाबत खात्री आहे का? +500 +&फ़ाइल +&संपादन +&दर्शन +आ&वडते +&अवजार +&मदत +540 +&उघडा +&अंदर उघडा +&बाहेर उघडा +&दृश्य +&संपादक +नाव बदल +&प्रतिलिपी... +&हलवा... +&मिटवा +&फ़ाइल तुकडे करा... +फ़ाइल जोडा... +लक्षणं +प्रतिक्रिया + + +फ़ोल्डर तयार करा +फ़ाइल तयार करा +गमन +600 +सर्व निवडा +सर्वांना अनिवडित करा +&निवड उलटी करा +निवडा... +अनिवडा... +प्रकारेद्वारा निवडा +प्रकारेद्वारे अनिवडा +700 +मोठे Icons +लहान Icons +&सुची +&माहिती +730 +अव्यवस्थित +Flat दृश्य +&२ फ़लक +&अवजार कप्पाs +Root फ़ोल्डर उघडा +एक वरती चढा +फ़ोल्डर इतिहास... +&टवटवीत करा +750 +दफ़तर अवजार कप्पा +प्रमाण अवजार कप्पा +मोठे कळ +कळ शब्द दाखवा +800 +&फ़ोल्डर आवडते मध्ये टाका... +पृष्ठ +900 +&पर्याय... +&Benchmark +960 +&माहिती... +7-Zip बद्दल... +1003 +मार्ग +नाव +शेपुट +फ़ोल्डर +आकार +दबलेला आकार +गुणधर्म +तयार +वापर +बदल +ठोस +भाष्य +बंधिस्त +या पुर्व तुकडे करा +या नंतर तुकडे करा +शब्दावली +CRC +प्रकार +विरुद्ध +पद्धत +यजमान आज्ञावली +फ़ाइल प्रणाली +उपयोगकर्ता +गट +गठ्ठा +प्रतिक्रिया +स्थिती +मार्गाची सुरुवात + + + + + + + + + + + + + + + + + + + + + + + + +चुक +एकूण आकार +खाली जागा +क्लस्टर आकार +शिर्षक +लोकल नाव +देणारा +2100 +पर्याय +भाषा +भाषा: +संपादक +&संपादक: + +2200 +प्रणाली +7-Zip संबधित करा: +2301 +7-Zip ला shell context मेनुशी जोडा +Cascaded context menu +Context मेनु वस्तू: +2320 + + +दफ़तर उघडा +फ़ाइल्स बाहेर काढा... +दफ़तरात टाका... +दफ़तर तपासा +येथे बाहेर काढा +बाहेर {0} +{0} येथे टाका +दाबा आणि इमेल करा... +{0} येथे दाबा आणि इमेल करा +2400 +फ़ोल्डर +&चलित फ़ोल्डर +&प्रणालीचे तात्पुरते फ़ोल्डर +&सध्या +&नमुद: +फक्त काढता येणाय्रा ड्रॉईव्हकरता वापरा +तात्पुरत्या दफ़तर करिता मार्ग दर्शवा. +2500 +स्थिती +वस्तू ".." दाखवा +फ़ाइलचे खरे icon दाखवा +प्रणालीचे मेनु दाखवा +&सर्व ओळ निवडा +&grid रेघा दाखवा + +&अतिरिक्त निवड पद्धती +मोठे स्मरणशक्ती पृष्ठ वापरा +2900 +7-Zip बद्दल माहिती +7-Zip हे मोफ़त सॉफ़्टवेअर आहे. तरिही, तुम्ही नोंद करुन याच्या प्रगतीला सहाय्य करू शकता. +3000 + +येथे एकही चूक नाही +निवडलेल्या वस्तू{0} +'{0}' फ़ोल्डर तयार होऊ शकले नाही +या दफ़तरासाठी नुतनीकरण शक्य नाही. + + + + +'{0}' ही फ़ाइल बदलली आहे.\nतुम्हाला हे दफ़तरात नुतन करायचे आहे का? +फ़ाइल नुतन करता येत नाही\n'{0}' +संपादक सुरु होत नाही. + + + + +खूपच जास्त वस्तू +3300 +बाहेर +दाब +तपासणी +उघडत आहे... +बारकाईने पाहत आहे... +3400 +बाहेर +&बाहेर: +फ़ाइल बाहेर काढण्यासाठी मार्ग नमूद करा. +3410 +मार्ग रित +पूर्ण पत्ता +पत्ता नाही +3420 +Overwrite रीत +overwrite करण्यापुर्वी विचारा +Overwrite न विचारता करा +अस्तित्वात असलेल्या फ़ाइल सोडा +स्वयंचलित नाव बदलवा +अस्तित्वात असलेल्या फ़ाइलचे आपोआप नाव बदलवा +3500 +फ़ाइल बदलवीणे खात्री +त्या फ़ोल्डरमध्ये अगोदरच कार्यान्वीत फ़ाइल आहे. +अस्तित्वात असलेली फ़ाइल बदलवायची आहे का? +यानी? +{0} बाइट्स +स्वयंचलित नाव बदलवा +3700 +असहाय्यक दाब पद्धत'{0}'. +डेटा चूक'{0}'. फ़ाइल तुटलेली आहे. +CRC अयशस्वी '{0}'. फ़ाइल तुटलेली आहे. + + +3800 +परवलिचा शब्द टाका +परवलिचा शब्द टाका: + +परवलिचा शब्द दाखवा + + + +परवलिचा शब्द +3900 +झालेला वेळ: +निघुन गेलेला वॆळ: +आकार: +वेग: + + +चूक: + +4000 +दफ़तरात टाका +&दफ़तर: +&नुतनीकरन रित: +दफ़तर &प्रकार: +दाब &level: +दाब &पद्धत: +&शब्द्कोश आकार: +&शब्द आकार: + + +&Parameters: +पर्याय +SF&X दफ़तर तयार करा + + + +फ़ाइल &नाव बंधिस्त करा +दाबण्यासाठी स्मरणशक्तीचा वापर: +प्रसरण पावण्यासाठी स्मरणशक्तीचा वापर: +4050 +साठा +अतिशय वेगवान +वेगवान +साधारण +जास्तीत जास्त +एकदमच +4060 +फ़ाइल टाका आणि ठेवा +फ़ाइल टाका आणि नुतन करा +अस्तित्वातील फ़ाइल ताजे करा +Synchronize फ़ाइल +4070 +ब्राउझ +सर्व फ़ाइल + + +6000 +प्रतिलिपी +हलवा +प्रतिलिपी: +हलवा: +प्रतिलिपी... +हलवल्या जात आहे... +नविन नाव दिल्या जात आहे... + +क्रिया करता येणार नाही. +फ़ाइल किंवा फ़ोल्डरला नविन नाव देता येत नाही आहे +फ़ाइलची प्रतिलिपी करण्यास तुमची खात्री आहे का +दफ़्तरात फ़ाइलची प्रतिलिपी करण्यास तुमची खात्री आहे का +6100 +फ़ाइल मिटवायची खात्री +फ़ोल्डर मिटवायची खात्री +अनेक फ़ाइल मिटवायची खात्री +तुम्हाला '{0}' मिटवायची खात्री आहे का? +तुम्हाला '{0}' फ़ोल्डर आणि त्यातील सर्व वस्तु मिटवायची खात्री आहे का? +तुम्हाला {0} वस्तु मिटवायची खात्री आहे का? +मिटत आहे... +फ़ाइल किंवा फ़ोल्डर मिटवता येत नाही आहे + +6300 +फ़ॊल्डर तयार करा +फ़ाइल तयार करा +फ़ोल्डर नाव: +फ़ाइलचे नाव: +नविन फ़ॊल्डर +नविन फ़ाइल +फ़ोल्डर तयार करता येत नाही आहे +फ़ाइल तयार करता येत नाही आहे +6400 +प्रतिक्रिया +&प्रतिक्रिया: +निवडा +निवड रद्द +मुखवटा: +6600 + +फ़ोल्डरचा इतिहास +उपचार संदेश +संदेश +7100 +संगणक +नेटवर्क + +प्रणाली +7200 +टाका +बाहेर +तपासा +प्रतिलिपी +हलवा +मिटवा +माहिती +7300 +फ़ाइलचे तुकडे करा +&येथे तुकडे: +तुकडे, बाइट्स: +तुकडे होत आहे... + + + + + +7400 +फ़ाइल जोडा +&येथे फ़ाइल जोडा: +फ़ाइल जुडत आहे... + + + +7500 +Checksum मोजत आहे... +Checksum माहिती +डेटाकरिता CRC checksum : +नाव आणि डेटाकरिता CRC checksum : +7600 +Benchmark +स्मरणशक्ती वापर: +दाबत आहे +प्रसरण होत आहे +क्रमांकन +एकुण क्रमांकन +सध्या +परिणाम + + +Passes: diff --git a/Utils/7-Zip/Lang/ms.txt b/Utils/7-Zip/Lang/ms.txt new file mode 100644 index 000000000..19285ca43 --- /dev/null +++ b/Utils/7-Zip/Lang/ms.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.30 : Khairul Ridhwan Bin Omar +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Malay +Bahasa Melayu +401 +OK +Batal + + + +&Ya +&Tidak +&Tutup +Bantuan + +&Teruskan +440 +Ya untuk Semua +Tidak untuk Semua +Henti +Mula Semula +&Latar belakang +&Latar depan +&Berehat +Berehat +Anda yakin untuk membatalkannya? +500 +&Fail +&Edit +&Paparan +K&egemaran +&Alat +&Bantuan +540 +&Buka +Buka di D&alam +Buka di L&uar +&Paparan +&Edit +Nam&akan semula +&Salin ke... +&Pindahkan ke... +Hapus +&Bahagi/belah Fail... +Gab&ung Fail... +P&roperti +Kom&en + + +Buat Folder +Buat Fail +K&eluar +600 +Pilih &Semua +Jangan Pilih Semua +&Sonsangkan Pilihan +Pilih... +Tidak Memilih... +Pilih Berdasarkan Jenis +Tidak Memilih Berdasarkan Jenis +700 +Ikon B&esar +Ikon K&ecil +&Senarai +&Butiran +730 +Tidak Tersusun + +&2 Panel +&Toolbar +Buka Root Folder +Ke atas Satu Aras +Folder Sejarah... +&Segarkan Semula +750 +Toolbar Arkib +Toolbar Standard +Bebutang Besar +Perlihatkan Teks Bebutang +800 +&Tambah folder pada Kegemaran sebagai +Penanda Buku +900 +&Opsyen... +&Tanda Aras +960 +&Kandungan... +&Perihal 7-Zip... +1003 +Bahagian +Nama +Sambungan +Folder +Saiz +Saiz Paket +Atribut +Dibuat +Diakses +Diubah Suai +Solid +Komen +Terenkripsi +Terpisah Sebelum +Terpisah Selepas +Kamus +CRC +Jenis +Anti +Kaedah +Sistem Operasi +Sistem Fail +Pengguna +Kumpulan +Blok +Komen +Posisi + + + + + + + + + + + + + + + + + + + + + + + + + +Ralat +Saiz Keseluruhan +Ruang Kosong +Saiz Kluster +Label +Nama Tempatan +Penyedia +2100 +Opsyen +Bahasa +Bahasa: +Editor +&Editor: + +2200 +Sistem +Kongsikan 7-Zip dengan: +2301 +Integrasikan 7-Zip ke shell konteks menu +Cascaded konteks menu +Item pada konteks menu: +2320 + + +Buka arkib +Ekstrak fail... +Tambahkan ke arkib... +Uji arkib +Ekstrak di sini +Ekstrak ke {0} +Tambahkan ke {0} +Padatkan dan kirimkan melalui email... +Padatkan ke {0} dan kirimkan melalui email +2400 +Folder +&Folder kerja +&Folder sementara sistem +&Sekarang +&Ditentukan: +Hanya untuk pemacu mudah alih +Tentukan lokasi untuk arkib fail sementara. +2500 +Seting +Perlihatkan ".." item +Perlihatkan ikon asli dari fail +Perlihatkan menu sistem +&Pilih barisan penuh +Perlihatkan garisan grid + +&Mod Pilihan Alternatif +Gunakan muka surat memori yang &besar +2900 +Perihal 7-Zip +7-Zip adalah perisian percuma. Sokong pembangunan 7-Zip dengan melakukan pendaftaran. +3000 + +Tidak ada ralat +{0} buah objek telah terpilih +Tidak dapat membuat folder '{0}' +Tidak menyokong pengemaskinian untuk arkib ini. + + + + +Fail '{0}' telah terubah suai.\nApakah anda ingin mengemaskininya pada arkib? +Tidak dapat mengemaskini fail\n'{0}' +Tidak dapat membuka editor. + + + + +Terlalu banyak item +3300 +Sedang mengekstrak +Memampatkan +Pengujian +Membuka... + +3400 +Ekstrak +Ekstrak ke: +Tentukan lokasi untuk pengekstrakan fail. +3410 +Mod laluan +Laluan nama penuh +Tidak pakai nama laluan +3420 +Mod tulis semula +Tanya sebelum menulis semula +Tulis semula tanpa perlu diberitahu +Abaikan fail yang ada +Namakan semula automatik +Namakan automatik fail yang ada +3500 +Pastikan penggantian fail +Folder tujuan telah berisi fail yang telah terproses. +Mahukah anda menggantikan fail yang ada +dengan yang ini? +{0} baits +N&amakan semula Automatik +3700 +Kaedah pemampatan untuk '{0}' tidak disokong. +Data ralat di '{0}'. Fail ini rosak. +CRC gagal di '{0}'. Fail ini rosak. + + +3800 +Masukkan kata laluan +Masukkan kata laluan: + +&Perlihatkan kata laluan + + + +Kata laluan +3900 +Telah berlalu: +Selesai dalam: +Saiz: +Kecepatan: + + +Ralat: + +4000 +Tambahkan ke arkib +&Arkib: +&Mod kemaskini: +Format arkib: +Aras &mampatan: +Kaedah mampatan: +&Saiz kamus: +&Saiz perkataan: + + +&Parameter: +Opsyen +Buat arkib SF&X + + + +Enkripsi nama &fail +Penggunaan memori untuk Memampatkan: +Penggunaan memori untuk Menyah-mampatkan: +4050 +Untuk Penyimpanan +Lebih cepat +Cepat +Normal +Maksimum +Ultra +4060 +Tambah dan gantikan fail +Kemaskini dan tambahkan fail +Perbaharui fail yang ada +Menyesuaikan fail +4070 +Selusur... +Semua Fail + + +6000 +Salin +Pindah +Salin ke: +Pindah ke: +Sedang menyalin... +Sedang memindah... +Namakan semula... + +Operasi tidak disokong. +Ralat, ketika namakan semula Fail atau Folder +Pasti salinkan fail +Anda yakin untuk menyalinkan fail kepada arkib +6100 +Pasti penghapusan fail +Pasti penghapusan folder +Pasti penghapusan fail-fail +Anda yakin untuk menghapus '{0}'? +Anda yakin untuk menghapus folder '{0}' dan semua isi kandungannya? +Anda yakin untuk menghapus item {0}? +Penghapusan... +Ralat ketika menghapuskan Fail atau Folder + +6300 +Buat Folder +Buat Fail +Nama Folder: +Nama Fail: +Folder Baru +Fail Baru +Ralat, tidak dapat Membuat Folder +Ralat, tidak dapat Membuat Fail +6400 +Komen +&Komen: +Pilih +Tidak Memilih +Topeng: +6600 + +Folder Sejarah +Mesej diagnostik +Mesej +7100 +Komputer +Rangkaian + +Sistem +7200 +Tambah +Ekstrak +Uji +Salin +Pindah +Hapus +Maklumat +7300 +Pisahkan Fail +&Pisahkan ke: +Bahagi/belah ke &nilai, baits: +Pembelahan ... + + + + + +7400 +Gabungan Fail +&Gabung ke: +Penggabungan ... + + + +7500 + + + + +7600 +Tanda Aras +Penggunaan memori: +Pemampatan +Penyah-mampatan +Rating +Total Rating +Sekarang +Keputusan + + +Lulus: diff --git a/Utils/7-Zip/Lang/nb.txt b/Utils/7-Zip/Lang/nb.txt new file mode 100644 index 000000000..c90522a41 --- /dev/null +++ b/Utils/7-Zip/Lang/nb.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.45 : Jostein Christoffer Andersen +; : Kjetil Hjartnes +; : Robert Grønning +; +; +; +; +; +; +; +; +0 +7-Zip +Norwegian Bokmal +Norsk Bokmål +401 +OK +Avbryt + + + +&Ja +&Nei +&Lukk +Hjelp + +&Fortsett +440 +Ja til &alt +Nei til a< +Stopp +Start på nytt +&Bakgrunn +&Forgrunn +&Stopp +Stoppet +Vil du avbryte? +500 +&Fil +&Rediger +&Vis +&Bokmerker +Verk&tøy +&Hjelp +540 +&Åpne +Åpne &internt +Åpne &eksternt +&Vis +&Rediger +Gi nytt &navn +&Kopier til … +&Flytt til … +S&lett +&Del opp arkiv … +&Sett sammen arkiv … +E&genskaper +&Kommentar … +Beregn sjekksum + +Ny &mappe … +Ny f&il … +&Avslutt +600 +Merk &alle +Merk i&ngen +Merk &omvendt +Merk … +Merk &ikke … +Merk &valgt type +Merk i&kke valgt type +700 +&Store ikoner +S&må ikoner +&Liste +&Detaljer +730 +Usortert +&Flat visning +&To felt +&Verktøylinjer +Rotmappe +Gå opp et nivå +Mappelogg … +&Oppdater +750 +Arkivverktøylinje +Standardverktøylinje +Store knapper +Knappetekst +800 +&Bokmerk denne mappen som +Bokmerke +900 +&Innstillinger … +&Yteprøve … +960 +&Innhold +&Om 7-Zip +1003 +Plassering +Navn +Filetternavn +Mappe +Størrelse +Komprimert størrelse +Attributter +Opprettet +Åpnet +Endret +Kompakt +Kommentert +Kryptert +Oppdeling før +Oppdeling etter +Ordbok +CRC +Type +Anti +Metode +Vert-OS +Filsystem +Bruker +Gruppe +Blokk +Kommentar +Posisjon +Stiprefiks + + + + + + + + + + + + + + + + + + + + + + + + +Feil +Total plass +Ledig plass +Sektorgruppestørrelse +Etikett +Lokalt navn +Forsyner +2100 +Innstillinger +Språk +Språk: +Redigering +&Redigeringsprogram: + +2200 +System +Assosier 7-Zip med: +2301 +Integrer 7-Zip i programmenyen +Forgrenet programmeny +Valg i programmenyen: +2320 + + +Åpne arkiv +Pakk ut … +Legg til arkiv … +Test arkiv +Pakk ut internt +Pakk ut til {0} +Legg til {0} +Komprimer og send med e-post … +Komprimer til {0} og send med e-post +2400 +Mapper +&Arbeidsmappe +Systemets &midlertidige mappe +&Nåværende +&Egendefinert: +Kun for flyttbare stasjoner +Angi plassering for midlertidige filer. +2500 +Innstillinger +Vis element for å gå opp et &nivå +Vis egentlige fil&ikoner +Vis system&meny +Merk &hele rader +Vis &rutenett + +&Alternativ merking +Bruk &store minnesider +2900 +Om 7-Zip +7-Zip er gratis programvare, men du kan støtte utviklingen av 7-Zip ved å registrere deg. +3000 + +Fant ingen feil. +{0} element(er) merket +Klarte ikke opprette mappen «{0}» +Oppdateringsfunksjoner støttes ikke for dette arkivet. +Kan ikke åpne filen «{0}» som arkiv +Kan ikke åpne det krypterte arkivet «{0}». Sjekk at du har riktig passord. + + +Filen «{0}» har blitt endret.\nVil du oppdatere den i arkivet? +Klarte ikke oppdatere filen\n«{0}» +Klarte ikke starte redigeringsprogram. + + + + +For mange elementer +3300 +Pakker ut +Komprimerer +Testing +Åpner … +Skanner … +3400 +Pakk ut +&Pakk ut til: +Angi plassering for filer som skal pakkes ut. +3410 +Filstier +Fullstendige filstier +Ingen filstier +3420 +Overskrivelse +Bekreft før overskrivelse +Overskriv uten bekreftelse +Hopp over filer som finnes allerede +Navngi nye filer automatisk +Navngi filer som finnes automatisk +3500 +Bekreft filoverskrivelse +Den behandlede filen finnes i målmappen allerede. +Vil du overskrive filen +med denne? +{0} byte +Navngi a&utomatisk +3700 +Komprimeringsmetoden støttes ikke for «{0}». +Datafeil i «{0}». Filen er ødelagt. +CRC-feil i «{0}». Filen er ødelagt. +Datafeil i den krypterte filen «{0}». Sjekk at du har riktig passord. +CRC feilet i den krypterte filen «{0}». Sjekk at du har riktig passord. +3800 +Angi passord +Angi passord: +Bekreft passord: +&Vis passord +Passordene er ikke like +Du kan bare bruke engelske bokstaver, tall eller spesialtegn (!, #, $, …) i passordet +Passordet er for langt +Passord +3900 +Tidsforbruk: +Gjenværende tid: +Størrelse: +Hastighet: + + +Feilet: + +4000 +Legg til arkiv +Filn&avn: +&Oppdateringsmetode: +&Format: +Komprimerings&nivå: +Komprimerings&metode: +Ord&bokstørrelse: +&Ordstørrelse: +Solid blokk størrelse: +Antall CPU tråder: +&Parametre: +&Innstillinger +Selvutpakkende arkiv («SF&X») + +Kryptering +Krypteringsmetode: +Kr&ypter filnavn +Minnebruk ved komprimering: +Minnebruk ved dekomprimering: +4050 +Ukomprimert +Raskest +Rask +Normal +Maksimum +Ultra +4060 +Legg til og overskriv filer +Oppdater og legg til filer +Oppdater filer +Synkroniser filer +4070 +Bla gjennom +Alle filer +Ikkje-solid +Solid +6000 +Kopier +Flytt +Kopier til: +Flytt til: +Kopierer … +Flytter … +Navngir … +Velg målmappe. +Operasjonen støttes ikke. +Det oppstod en feil da filen eller mappen skulle navngis +Bekreft at fil skal kopieres +Vil du kopiere filene til arkivet +6100 +Bekreft at fil skal slettes +Bekreft at mappe skal slettes +Bekreft at flere filer skal slettes +Vil du slette «{0}»? +Vil du slette mappen «{0}» med alt innhold? +Vil du slette disse {0} elementene? +Sletter … +Det oppstod en feil da filen eller mappen skulle slettes + +6300 +Ny mappe +Ny fil +Mappenavn: +Filnavn: +Ny mappe +Ny fil +Det oppstod en feil da mappen skulle opprettes +Det oppstod en feil da filen skulle opprettes +6400 +kommentar +&Kommentar: +Merk +Merk ikke +Filter: +6600 + +Mappelogg +Diagnosemeldinger +Melding +7100 +Datamaskin +Nettverk + +System +7200 +Legg til +Pakk ut +Prøv +Kopier +Flytt +Slett +Egenskaper +7300 +Del opp arkiv +&Del opp som: +&Del opp til flere delarkiv i størrelsen: +Deler opp … +Bekreft deling +Er du sikker på at du vil dele arkivet i {0} delarkiv? +Delarkivene må være mindre enn originalarkivet +Ugyldig delarkivstørrelse +Valgt delarkivstørrelse: {0} byte.\nEr du sikker på at du vil dele arkivet med denne størrelsen? +7400 +Sett sammen arkiv +&Sett sammen som: +Setter sammen … +Velg bare det første delarkivet + + +7500 +Beregner sjekksum … +Sjekksuminformasjon +CRC-sjekksum for data: +CRC-sjekksum for data og filnavn: +7600 +Yteprøve +Minnebruk: +Komprimering +Dekomprimering +Ytelse +Samlet ytelse +Nåværende +Resultat +CPU bruk +Ytelse / Bruk +Bestått: diff --git a/Utils/7-Zip/Lang/ne.txt b/Utils/7-Zip/Lang/ne.txt new file mode 100644 index 000000000..7c3f29cb8 --- /dev/null +++ b/Utils/7-Zip/Lang/ne.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.37 : Shiva Pokharel, Mahesh Subedi +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Nepali +नेपाली +401 +ठीक छ +रद्द गर्नुहोस् + + + +&हो +&होइन +&बन्द गर्नुहोस् +मद्दत + +&जारी राख्नुहोस् +440 +&सबैलाई हो +&कसैलाई होइन +रोक्नुहोस् +पुन: सुरु गर्नुहोस् +&पृष्ठभुमि +&अग्रभुमि +&पज गर्नुहोस् +पज गरिएको +तपाईँ रद्द गर्न यकिन हुनुहुन्छ ? +500 +&फाइल +&सम्पादन गर्नुहोस् +&हेर्नुहोस् +&रुचाइएको +&उपकरण +&मद्दत +540 +&खोल्नुहोस् +भित्रपट्टि खोल्नुहोस् +बाहरिपट्टि खोल्नुहोस् +&हेर्नुहोस् +&सम्पादन गर्नुहोस् +पुन: नामकरण गर्नुहोस् +&यसमा प्रतिलिपि बनाउनुहोस्... +&यसमा सार्नुहोस्... +&मेट्नुहोस् +&फाइल विभाजन गर्नुहोस्... +फाइलहरू संयोजन गर्नुहोस्... +&गुण +टिप्पणी +checksum गणना गर्नुहोस् + +फोल्डर सिर्जना गर्नुहोस् +फाइल सिर्जना गर्नुहोस् +निस्कनुहोस् +600 +सबै चयन गर्नुहोस् +सबै मेट्नुहोस् +&चयन उल्टाउनुहोस् +चयन गर्नुहोस्... +चयन हटाउनुहोस्... +प्रकार अनुसार चयन गर्नुहोस् +प्रकार अनुसार चयन हटाउनुहोस् +700 +ठूलो प्रतिमा +सानो प्रतिमा +&सूची +&वर्णन +730 +क्रमबद्ध नगरिएको +फ्ल्याट दृश्य +&२ प्यानल +&उपकरणपट्टी +प्रमूल फोल्डर खोल्नुहोस् +एक स्तर माथि +फोल्डरको इतिहार... +&ताजा गर्नुहोस् +750 +सङ्ग्रह उपकरणपट्टी +मानक उपकरणपट्टी +ठूलो बटन +बटनको पाठ देखाउनुहोस् +800 +&यस रूपमा रूचाइएकोमा फोल्डर थप्नुहोस् +पुस्तकचिनो +900 +&विकल्प... +&बेञ्चमार्क +960 +&सामग्री... +&7-जिपका बारेमा... +1003 +मार्ग +नाम +विस्तार +फोल्डर +साइज +प्याक गरिएको साइज +विशेषता +सिर्जित +पहुँच +परिमार्जित +ठोस +टिप्पणी +गुप्तिकृत +यस पहिले विभाजन गर्नुहोस् +यस पछि विभाजन गर्नुहोस् +शब्दकोश +CRC +प्रकार +बिरोधि +विधि +होस्ट OS +फाइल प्रणाली +प्रयोगकर्ता +समूह +रोक +टिप्पणी +स्थान +मार्ग प्रत्यय + + + + + + + + + + + + + + + + + + + + + + + + +त्रुटि +जम्मा साइज +स्वतन्त्र रिक्तस्थान +समूह साइज +लेबुल +स्थानिय नाम +प्रदायक +2100 +विकल्प +भाषा +भाषा: +सम्पादक +&सम्पादक: + +2200 +प्रणाली +यससँग 7-जिप सम्बन्धित: +2301 +शेल प्रसङ्ग मेनुमा 7-जिप लाई सम्मिलन गर्नुहोस् +सोपानी प्रसङ्ग मेनु +प्रसङ्ग मेनु वस्तु: +2320 + + +सङ्ग्रह खोल्नुहोस् +फाइलहरू निकाल्नुहोस्... +सङ्ग्रहमा थप्नुहोस्... +सङ्ग्रह जाँच्नुहोस् +यहाँ निकाल्नुहोस् +{0} मा निकाल्नुहोस् +{0} मा थप्नुहोस् +सङ्कुचन गरेर इमेल गर्नुहोस्... +{0} मा सङ्कुचन गर्नुहोस् र इमेल गर्नुहोस् +2400 +फोल्डर +&कार्य फोल्डर +&प्रणाली टेम्प(अस्थायी) फोल्डर +&चालू +&निर्दिष्ट: +हटाउन योग्य ड्राइभहरूका लागि मात्र प्रयोग गर्नुहोस् +अस्थायी सङ्ग्रह फाइलका लागि स्थान तोक्नुहोस् । +2500 +सेटिङ +".." वस्तु देखाउनुहोस् +वास्तविक फाइल प्रतिमा देखाउनुहोस् +प्रणाली मेनु देखाउनुहोस् +&पूरा पङ्क्ति चयन +ग्रिड रेखा देखाउनुहोस् + +&वैकल्पिक चयन मोड +ठूलो स्मृति पृष्ठ प्रयोग गर्नुहोस् +2900 +7-जिपका बारेमा +7-जिप निशुल्क सफ्टवेयर हो। यद्यपी,तपाईँले दर्ता गरेर 7-जिपलाई सहयोग गर्न सक्नुहुन्छ । +3000 + +त्यहाँ त्रुटि छैन +{0} वस्तु(हरू) चयन गरियो +'{0}'फोल्डर सिर्जना गर्न सकिदैन +यो सङ्ग्रहका लागि अद्यावधिक सञ्चालन समर्थन गर्दैन + + + + +'{0}'फाइल परिमार्जन गरिएको छ ।\nतपाईँले यसलाई सङ्ग्रहमा अद्यावधिक गर्न चाहनुहुन्छ ? +फाइल अद्यावधिक गर्न सकिदैन\n'{0}' +सम्पादक सुरु गर्न सकिदैन + + + + +धेरै वस्तु +3300 +निकाल्दैछ +सङ्कुचन +परीक्षण +खोल्दैछ... +स्क्यानिङ... +3400 +निकाल्नुहोस् +यसलाई निकाल्नुहोस्: +निकालिएको फाइलका लागि स्थान निर्दिष्ट गर्नुहोस् +3410 +मार्ग मोड +पूरा मार्गनाम +मार्गनामहरू छैन +3420 +अधिलेखन मोड +अधिलेखन गर्नु अगाडि सोध्नुहोस् +प्रोम्टबिना अधिलेखन गर्नुहोस् +अवस्थित फाइलहरू फड्काउनुहोस् +स्वचालित पुन: नामकरण +स्वचालित पुन: नामकरण अवस्थित फाइलहरू +3500 +फाइल प्रतिस्थापन यकिन गर्नुहोस् +गन्तव्य फोल्डरले पहिले नै प्रक्रिया गरिएको फाइल समावेश गर्दछ +अवस्थित फाइलमा प्रतिस्थापन गर्न चाहनुहुन्छ +योसँग? +{0} बाइट +स्वचालित पुन: नामकरण +3700 +'{0}'का लागि असमर्थित सङ्कुचन विधि +'{0}'लगत त्रुटि । फाइल बिग्रेको छ +'{0}' मा CRC असफल । फाइल बिग्रेको छ + + +3800 +पासवर्ड प्रविष्ट गर्नुहोस् +पासवर्ड प्रविष्ट गर्नुहोस्: + +&पासवर्ड देखाउनुहोस् + + + +पासवर्ड +3900 +व्यतीत समय: +पुन: नामकरण समय: +साइज: +गति: + + +त्रुटि: + +4000 +सङ्ग्रहमा थप्नुहोस् +&सङ्ग्रह: +&अद्यावधिक मोड: +सङ्ग्रह ढाँचा: +सङ्कुचन स्तर: +सङ्कुचन विधि: +&शब्दकोश साइज: +&शब्द साइज: + + +&परिमिति: +विकल्प +SF&X सङ्ग्रह सिर्जना गर्नुहोस् + + + +फाइलनाम गुप्तिकरण गर्नुहोस् +सङ्कुचनका लागि स्मृति प्रयोग: +असङ्कुचनका लागि स्मृति प्रयोग: +4050 +भण्डार गर्नुहोस् +सब भन्दा छिटो +छिटो +साधारण +अधिकतम +अत्यन्त +4060 +फाइल थपेर प्रतिस्थापन गर्नुहोस् +फाइलहरू अद्यावधिक गरेर थप्नुहोस् +अवस्थित फाइल ताजा गर्नुहोस् +फाइल समक्रमण गर्नुहोस् +4070 +ब्राउज गर्नुहोस् +सबै फाइल + + +6000 +प्रतिलिपि गर्नुहोस् +सार्नुहोस् +यसमा प्रतिलिपि गर्नुहोस्: +यसमा सार्नुहोस्: +प्रतिलिपि गर्दैछ... +सार्दैछ... +पुन: नामकरण... + +सञ्चालन समर्थन गर्दैन +फाइल वा फोल्डर पुन: नामकरण गर्दा त्रुटि +फाइल प्रतिलिपि गर्न यकिन गर्नुहोस् +तपाईँ फाइलहरू सङ्ग्रहमा प्रतिलिपि गर्न निश्चित हुनुहुन्छ +6100 +फाइल मेट्न यकिन गर्नुहोस् +फोल्ड मेट्न यकिन गर्नुहोस् +बहुविध फाइल मेट्न यकिन गर्नुहोस् +तपाईँ '{0}'मेट्न निश्चित हुनुहुन्छ ? +तपाईँ '{0}' फोल्डर यसको सबै सामग्री मेट्न निश्चित हुनुहुन्छ ? +तपाईँ {0} वस्तुहरू मेट्न निश्चित हुनुहुन्छ ? +मेट्दैछ... +फाइल वा फोल्डर मेट्दा त्रुटि + +6300 +फोल्डर सिर्जना गर्नुहोस् +फाइल सिर्जना गर्नुहोस् +फोल्डर नाम: +फाइल नाम: +नयाँ फोल्डर +नयाँ फाइल +फोल्डर सिर्जना गर्दा त्रुटि +फाइल सिर्जना गर्दा त्रुटि +6400 +टिप्पणी +&टिप्पणी: +चयन गर्नुहोस् +चयन हटाउनुहोस् +मास्क: +6600 + +फोल्डर इतिहार +निदानात्मक सन्देश +सन्देश +7100 +कम्प्युटर +सञ्जाल + +प्रणाली +7200 +थप्नुहोस् +निकाल्नुहोस् +परीक्षण गर्नुहोस् +प्रतिलिपि गर्नुहोस् +सार्नुहोस् +मेट्नुहोस् +सूचना +7300 +फाइल विभाजन गर्नुहोस् +&यसमा विभाजन गर्नुहोस्: +भोल्युम, बाइटमा विभाजन गर्नुहोस्: +विभाजन गर्दैछ... + + + + + +7400 +फाइल संयोजन गर्नुहोस् +&यसमा संयोजन गर्नुहोस्: +संयोजन गर्दैछ... + + + +7500 +Checksum गणना गर्दैछ... +Checksum सूचना +लगतका लागि CRC checksum: +लगत र नामहरूका लागि CRC checksum: +7600 +बेञ्चमार्क +स्मृति उपयोग: +सङ्कुचन +असङ्कुचन +दर +जम्मा दर +हालको +नतिजा + + +पास: diff --git a/Utils/7-Zip/Lang/nl.txt b/Utils/7-Zip/Lang/nl.txt new file mode 100644 index 000000000..c91ecdffa --- /dev/null +++ b/Utils/7-Zip/Lang/nl.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Bert van Velsen +; 4.26 : Jeroen van der Weijde. +; : Harm Hilvers +; 9.07 : Jeroen Tulp +; 15.00 : Jeroen Tulp +; +; +; +; +; +; +0 +7-Zip +Dutch +Nederlands +401 +OK +Annuleren + + + +&Ja +&Nee +A&fsluiten +Help + +&Hervatten +440 +Ja op &alles +Nee op a&lles +Stop +Herstarten +&Achtergrond +&Voorgrond +&Pauzeren +Gepauzeerd +Weet u zeker dat u wilt annuleren? +500 +&Bestand +Be&werken +Bee&ld +&Favorieten +E&xtra +&Help +540 +&Openen +Open B&innen +Open B&uiten +Bee&ld +&Bewerken +&Hernoemen +&Kopiëren naar... +&Verplaatsen naar... +Verwij&deren +Bestand &opsplitsen... +Bestanden &samenvoegen... +&Eigenschappen +O&pmerking +&Checksum berekenen +Ver&gelijken +Nieuwe &map +&Nieuw bestand +&Sluiten +Koppe&ling +&Alternate Streams +600 +&Alles selecteren +A&lles de-selecteren +Selectie &omkeren +&Selecteer... +&De-selecteer... +Selecteer op &type +De-selecteer op t&ype +700 +&Grote pictogrammen +&Kleine pictogrammen +&Lijst +&Details +730 +&Ongesorteerd +&Platte weergave +&2 Panelen +&Werkbalken +&Root map openen +Één &niveau omhoog +&Mappen Geschiedenis... +&Verversen +&Automatisch verversen +750 +&Archief werkbalk +&Standaard werkbalk +Grote kn&oppen +Knop&tekst weergeven +800 +&Map toevoegen aan Favorieten +Favoriet maken +900 +&Opties... +&Benchmark +960 +&Inhoud... +&Over 7-Zip... +1003 +Pad +Naam +Extensie +Map +Grootte +Ingepakte grootte +Kenmerken +Aangemaakt +Laatst geopend +Gewijzigd +Compact +Commentaar +Gecodeerd +Gesplitst voor +Gesplitst na +Woordenboek + +Type +Anti +Methode +Gastheer OS +Bestandssysteem +Gebruiker +Groep +Blok +Commentaar +Positie +Pad Prefix +Mappen +Bestanden +Versie +Volume +Multivolume +Offset +Koppelingen +Blokken +Volumes + +64-bit +Big-endian +CPU +Fysieke grootte +Kop grootte +Checksum +Karakteristieken +Virtueel Adres +ID +Korte Naam +Aanmaak Applicatie +Sector Grootte +Modus +Symbolische Kpoppeling +Fout +Capaciteit +Beschikbaar +Clustergrootte +Label +Lokale naam +Provider +NT Beveiliging +Alternate Stream +Aux +Verwijderd +Is Structuur + + +Error Type +Errors +Errors +Waarschuwingen +Waarschuwing +Streams +Alternate Streams +Alternate Streams Grootte +Virtuele Grootte +Uitgepakte Grootte +Totale Fysieke Grootte +Volume Index +SubType +Kort Commentaar +Tekstcodering + + + +Tail Grootte +Embedded Stub Grootte +Koppeling +Harde Koppeling +iNode + +Alleen-lezen +2100 +Opties +Taal +Taal: +Editor +&Editor: +&Vergelijken: +2200 +Systeem +Associeer 7-Zip met: +All users +2301 +7-Zip in het contextmenu integreren. +Trapsgewijs contextmenu +Contextmenu items: +Pictogrammen in contexmenu +2320 + + +Open archief +Bestanden uitpakken... +Toevoegen aan archief... +Testen archief +Uitpakken (hier) +Uitpakken naar {0} +Toevoegen aan {0} +Comprimeer en verstuur... +Comprimeer naar {0} en verstuur +2400 +Mappen +&Werkmap +&Tijdelijke systeemmap +&Huidige +&Gespecificeerd: +Alleen voor verwisselbare schijven gebruiken. +Specificeer een locatie voor tijdelijke archiefbestanden. +2500 +Instellingen +Toon ".." &item +Toon &echte bestandspictogrammen +Toon &systeem contextmenu +&Selecteer gehele rij +Toon &rasterlijnen +Enkele klik om een item te openen +&Alternatieve selectiemodus +&Gebruik grote geheugenpagina's +2900 +Over 7-Zip +7-Zip is gratis software. Echter, u kunt de ontwikkeling van 7-Zip ondersteunen door u te registreren. +3000 +Het systeem kan de benodigde hoeveelheid geheugen niet alloceren +Er zijn geen fouten. +{0} item(s) geselecteerd +Kan map '{0}' niet aanmaken. +Bijwerkfuncties niet ondersteund voor dit archief. +Kan bestand '{0}' niet openen als archief. +Kan het gecodeerde archief '{0}' niet openen. Verkeerd wachtwoord? +Niet ondersteund archief type +Bestand {0} bestaat reeds +Bestand '{0}' is gewijzigd.\nWilt u het bijwerken in het archief? +Kan bestand\n'{0}' niet bijwerken. +Kan de editor niet starten. +Het bestand lijkt op een virus (het bevat veel opeenvolgende spaties in de naam). +De actie kan niet worden uitgevoerd vanuit een folder met een dermate lang pad. +U moet 1 bestand selecteren +U moet 1 of meerdere bestanden selecteren +Te veel items +Kan het bestand niet openen als {0} archief +Het bestand is geopend als {0} archief +Het archiefis geopend met een offset +3300 +Uitpakken +Comprimeren +Testen +Openen... +Scannen... +Verwijderen +3320 +Toevoegen +Bijwerken +Analyseren +Repliceren +Opnieuw inpakken +Overslaan +Verwijderen +Kop aanmaken +3400 +&Uitpakken +U&itpakken naar: +Specificeer een locatie voor de uitgepakte bestanden. +3410 +Padmethode +Volledige padnamen +Geen padnamen +Absolute padnamen +Relatieve padnamen +3420 +Overschrijfmethode +Vraag voor overschrijven +Overschrijven zonder bevestiging +Bestaande bestanden overslaan +Automatisch hernoemen +Automatisch hernoemen van bestaande bestanden +3430 +Verwijder duplicaat van de hoofdmap +Herstellen bestandsbeveiliging +3500 +Bevestig vervangen bestand +Doelmap bevat reeds het verwerkte bestand. +Wilt u het bestaande bestand vervangen +door dit bestand? +{0} bytes +A&utomatisch hernoemen +3700 +Niet ondersteunde compressiemethode voor '{0}'. +Gegevensfout in '{0}'. Bestand is beschadigd. +CRC mislukt in '{0}'. Bestand is beschadigd. +Gegevensfout in het gecodeerde bestand '{0}'. Verkeerd wachtwoord? +CRC mislukt in het gecodeerde bestand '{0}'. Verkeerd wachtwoord? +3710 +Verkeerd wachtwoord? +3721 +Niet ondersteunde compresssiemethode +Gegevens fout +CRC mislukt +Data niet beschikbaar +Data eindigd onverwachts +Er is nog wat data na het einde van de payload data +Is geen archief +Kop Error +Verkeerd wachtwoord +3763 +Start van archief is niet beschikbaar +Start van archief is niet bevestigd + + + +Niet ondersteunde functie +3800 +Wachtwoord ingeven +Wachtwoord &ingeven: +Wachtwoord bevestigen: +Wachtwoord &tonen +Wachtwoorden komen niet overeen. +Gebruik alleen alfanumerieke en speciale karakters (!, #, $, ...) voor het wachtwoord +Wachtwoord is te lang. +&Wachtwoord +3900 +Verstreken tijd: +Overgebleven tijd: +Grootte: +Snelheid: +Verwerkt: +Compressie verhouding: +Fouten: +Archieven: +4000 +Toevoegen aan archief +&Archief: +&Bijwerkmethode: +Archief &formaat: +Compressie&niveau: +Compressie&methode: +&Woordenboekgrootte: +W&oordgrootte: +Compacte b&lokgrootte: +Aantal CP&U-threads: +&Parameters: +Opties +SF&X archief maken +Comprimeer &gedeelde bestanden +Codering +Cod&eermethode: +Codee&r bestandsnamen +Geheugengebruik bij het inpakken: +Geheugengebruik bij het uitpakken: +Verwijder bestanden na inpakken +4040 +Symboische koppelingen opslaan +Harde koppelingen opslaan +Alternate data streams opslaan +Bestandsbeveiliging opslaan +4050 +Opslaan +Snelst +Snel +Normaal +Maximum +Ultra +4060 +Bestanden toevoegen en vervangen +Bestanden bijwerken en toevoegen +Bestaande bestanden opfrissen +Bestanden synchroniseren +4070 +Bladeren +Alle bestanden +Niet compact +Compact +6000 +Kopiëren +Verplaatsen +Kopiëren naar: +Verplaatsen naar: +Bezig met kopiëren... +Bezig met verplaatsen... +Bezig met hernoemen... +Selecteer een doelmap. +Functie wordt niet ondersteund. +Fout bij het hernoemen van een bestand of map +Bevestig kopiëren van bestand +Weet u zeker dat u deze bestanden naar het archief wilt kopiëren +6100 +Verwijdering bestand bevestigen +Verwijdering map bevestigen +Verwijdering van meerdere bestanden bevestigen +Weet u zeker dat u '{0}' wilt verwijderen? +Weet u zeker dat u de map '{0}' en alle onderliggende items wilt verwijderen? +Weet u zeker dat u deze {0} items wilt verwijderen? +Bezig met verwijderen... +Fout bij het verwijderen van een bestand of map +Het systeem kan een bestand met een lang pad niet verplaatsen naar de Prullenbak +6300 +Map maken +Bestand maken +Naam van de map: +Bestandsnaam: +Nieuwe map +Nieuw bestand +Fout bij het maken van de map +Fout bij het maken van het bestand. +6400 +Opmerking +&Opmerking: +Selecteren +De-selecteren +Masker: +6600 +Eigenschappen +Mappen Geschiedenis +Diagnostische berichten +Bericht +7100 +Computer +Netwerk +Documenten +Systeem +7200 +Toevoegen +Uitpakken +Testen +Kopiëren +Verplaatsen +Verwijderen +Info +7300 +Opsplitsen bestand +&Opsplitsen naar: +Opsplitsen in &volumes (grootte in bytes): +Bezig met opsplitsen... +Bevestigen opsplitsen +Weet u zeker dat u het bestand wilt opsplitsen in {0} volumes? +De volumegrootte moet kleiner zijn dan de grootte van het oorspronkelijke bestand. +Verkeerde volumegrootte +Gespecificeerde volumegrootte: {0} bytes.\nWeet u zeker dat u het archief zo wilt splitsen? +7400 +Bestanden samenvoegen +&Samenvoegen naar: +Bezig met samenvoegen... +Selecteer alleen het eerste bestand. +Kan het bestand niet herkennen als onderdeel van een gesplitst bestand +Kan niet meer dan 1 deel van een gesplitst bestand +7500 +Bezig met checksum berekenen... +Checksum informatie +CRC checksum voor gegevens: +CRC checksum voor gegevens en namen: +7600 +Benchmark +Geheugengebruik: +Inpakken +Uitpakken +Waarde +Totale waarde +Huidig +Resultaat +CPU-gebruik +Waarde / gebruik +Doorgangen: +7700 +Koppeling +Koppeling +Koppeling van: +Koppeling naar: +7710 +Koppeling Type +Harde Koppeling +Bestand Symbolische Koppeling +Map Symbolische Koppeling +Mapsplitsing diff --git a/Utils/7-Zip/Lang/nn.txt b/Utils/7-Zip/Lang/nn.txt new file mode 100644 index 000000000..bcd7fc8ab --- /dev/null +++ b/Utils/7-Zip/Lang/nn.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.45 : Robert Grønning +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Norwegian Nynorsk +Norsk Nynorsk +401 +OK +Avbryt + + + +&Ja +&Nei +&Lukke +Hjelp + +&Hald fram +440 +Ja til &alt +N&ei til alt +Stopp +Start på nytt +&Bakgrunn +&Forgrunn +&Pause +Sett på pause +Er du sikker på du vil avbryte? +500 +&Fil +&Redigere +&Vis +F&avorittar +Verk&tøy +&Hjelp +540 +&Opna +Opna &Inni +Opna &Utanfor +&Vis +&Redigere +Endra &namn +&Kopiere til... +&Flytt til... +&Slett +&Del opp fil... +Set saman filer... +&Eigenskapar +Ko&mmentar +Rekna ut kontrollnummer + +Opprett mappe +Opprett fil +&Avslutta +600 +&Merk alle +Fjern alle markeringar +&Omvendt markering +Marker... +Fjern markering... +Merk etter type +Fjern markering etter type +700 +S&tore ikon +S&må ikon +&Lista +&Detaljar +730 +Assortert +Flat vising +&2 felt +&Verktøylinjer +Opna kjeldemappa +Opp eit nivå +Mappelogg... +&Oppdatere +750 +Arkiv verktøylinje +Standard verktøylinjer +Store knappar +Vis knappetekst +800 +&Legg mappe til i favorittar som +Bokmerke +900 +&Val... +&Yting test +960 +&Innhold... +&Om 7-Zip... +1003 +Bane +Namn +Fil etternamn +Mappe +Størrelse +Komprimert Størrelse +Eigenskapar +Oppretta +Opna +Endra +Solid +Kommentert +Kryptert +Delt før +Delt etter +Ordbok +CRC +Type +Anti +Metode +Vert OS +Filsystem +Brukar +Gruppe +Blokkering +Kommentar +Posisjon +Bane prefiks + + + + + + + + + + + + + + + + + + + + + + + + +Feil +Total størrelse +Ledig plass +Klyngje størrelse +Etikett +Lokalt namn +Leverandør +2100 +Val +Språk +Språk: +Redigeringsprogram +&Redigeringsprogram: + +2200 +System +Forbind 7-Zip med: +2301 +Legg inn 7-Zip i programmenyen +Forgreina programmeny +Programmeny val: +2320 + + +Opna arkiv +Pakk ut filer... +Legg til i arkiv... +Test arkiv +Pakk ut her +Pakk ut til {0} +Legg til i {0} +Komprimere og send som epost... +Komprimere til {0} og send som epost +2400 +Mapper +&Arbeidsmappe +&Midlertidig mappe +&Noverande +&Eigendefinert: +Berre for flyttbare stasjonar +Oppgje plassering for midlertidige arkiv filer. +2500 +Innstillingar +Vis ".." element +Vis dei ordentlege fil ikona +Vis system meny +&Merk heile rader +Vis &rutenett + +&Alternativ markerings modus +Bruk &store minnesider +2900 +Om 7-Zip +7-Zip er fri programvare. Du kan støtta utviklinga av 7-Zip ved å registrere deg. +3000 + +Ingen feil +{0} objekt(ar) valt +Kan ikkje oppretta mappe '{0}' +Dette arkivet manglar støtte for å kunne oppdaterast. +Kan ikkje opna fila '{0}' som eit arkiv +Kan ikkje opna det krypterte arkivet '{0}'. Feil passord? + + +Fila '{0}' blei endra.\nVil du oppdatere den i arkivet? +Kan ikkje oppdatere fil\n'{0}' +Kan ikkje starta redigeringsprogram. + + + + +For mange gonger +3300 +Pakkar ut +Komprimerer +Testing +Opnar... +Undersøkjer... +3400 +Pakk ut +Pakk ut &til: +Vel ei mappe for ut-pakka filer. +3410 +Bane modus +Fulstendig banenamn +Ingen banenamn +3420 +Overskriving modus +Bekrefta før overskriving +Skriv over utan bekrefting +Hopp over eksisterande filer +Endra filnamn automatisk +Endra filnamn automatisk for eksisterande filer +3500 +Bekrefta overskriving av fil +Målmappa inneheld allereie ei behandla fil. +Vil du overskriva den eksisterande fila +med denne? +{0} byte +&Skift filnamn automatisk +3700 +Kompresjonsmetoden er ikkje støtta for '{0}'. +Data feil i '{0}'. Fila er øydelagt. +CRC feila på '{0}'. Fila er øydelagt. +Data feil i den krypterte fila '{0}'. Feil passord? +CRC feila i den krypterte fila '{0}'. Feil passord? +3800 +Skriv inn passord +Skriv inn passord: +Skriv inn passordet på nytt: +&Vis passord +Passorda er ikkje like +Bruk berre Engelske bokstavar, tal og spesielle teikn (!, #, $, ...) i passordet +Passordet er for langt +Passord +3900 +Tid brukt: +Tid gjenstår: +Størrelse: +Fart: + + +Feil: + +4000 +Legg til i arkiv +&Arkiv: +&Oppdaterings modus: +Arkiv &format: +Kompresjons &nivå: +Kompresjons &metode: +O&rdbok størrelse: +Or&d størrelse: +Solid blokk størrelse: +Anntal CPU tråder: +&Parameter: +Val +Opprett SF&X arkiv + +Krypter +Krypter metode: +&Krypter filnamn +Minnebruk ved kompresjon: +Minnebruk ved ut-pakking: +4050 +Lagre +Raskast +Rask +Normal +Maksimum +Ekstrem +4060 +Legg til og skriv over filer +Oppdatere og legg til filer +Frisk opp eksisterande filer +Synkroniser filer +4070 +Bla igjennom +Alle filer +Ikkje-solid +Solid +6000 +Kopiere +Flytt +Kopiere til: +Flytt til: +Kopierer... +Flyttar... +Endrar namn... +Vel målmappe. +Støttar ikkje handlinga. +Feil ved endring av namn på fil eller mappe +Godkjenne filkopiering +Er du sikker på at du vil kopiere filer til arkiv +6100 +Godkjenne sletting av fil +Godkjenne sletting av mappe +Godkjenne sletting av fleire filer +Er du sikker på at du vil sletta '{0}'? +Er du sikker på at du vil sletta mappa '{0}' og alt innhold i den? +Er du sikker på at du vil sletta desse {0} elementa? +Slettar... +Feil ved sletting av fil eller mappe + +6300 +Opprett mappe +Opprett fil +Mappe namn: +Filnamn: +Ny mappe +Ny fil +Feil ved oppretting av mappe +Feil ved oppretting av fil +6400 +Kommentar +&Kommentar: +Marker +Fjern markering +Maske: +6600 + +Mappe logg +Diagnose meldingar +Melding +7100 +Datamaskin +Nettverk + +System +7200 +Legg til +Pakk ut +Test +Kopiere +Flytt +Slett +Informasjon +7300 +Del opp fil +&Del opp til: +Splitt opp i deler, byte: +Delar opp... +Godkjenne oppdeling +Er du sikker på at du vil dele opp fila i {0} delar? +Størrelsen på delane må vera mindre enn størrelsen på originalfila +Feil del-størrelse +Oppgitt del-størrelse: {0} byte.\nEr du sikker på du vil dele arkivet opp i slike deler? +7400 +Slå saman filer +&Slå saman til: +Slår saman... +Berre vel den første fila + + +7500 +Reknar ut kontrollnummer... +Informasjon om kontrollnummer +CRC kontrollnummer for data: +CRC kontrollnummer for data og namn: +7600 +Yting test +Minnebruk: +Kompresjon +Ut-pakking +Yting +Total yting +Noverande +Resultat +CPU bruk +Yting / Bruk +Gonger: diff --git a/Utils/7-Zip/Lang/pa-in.txt b/Utils/7-Zip/Lang/pa-in.txt new file mode 100644 index 000000000..8633ed4fb --- /dev/null +++ b/Utils/7-Zip/Lang/pa-in.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.53 : Gurmeet Singh Kochar +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Punjabi, Indian +ਪੰਜਾਬੀ +401 +ਠੀਕ ਹੈ +ਰੱਦ ਕਰੋ + + + +ਹਾਂ (&Y) +ਨਹੀਂ (&N) +ਬੰਦ ਕਰੋ (&C) +ਮੱਦਦ + +ਜਾਰੀ ਕਰੋ (&C) +440 +ਸਾਰਿਆਂ ਲਈ ਹਾਂ (&A) +ਸਾਰਿਆਂ ਲਈ ਨਹੀਂ (&l) +ਰੁਕੋ +ਮੁੜ ਚਾਲੂ ਕਰੋ +ਬੈਕਗਰਾਉਂਡ (&B) +ਫੋਰਗਰਾਉਂਡ (&F) +ਪੋਜ਼ (&P) +ਪੋਜ਼ ਹੋਇਆ +ਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਹੀ ਰੱਦ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? +500 +ਫਾਇਲ (&F) +ਸੋਧ (&E) +ਵੇਖੋ (&V) +ਪਸੰਦੀਦਾ (&a) +ਸੰਧ (&T) +ਮੱਦਦ (&H) +540 +ਖੋਲੋ (&O) +ਅੰਦਰ ਖੋਲੋ (&I) +ਬਾਹਰ ਖੋਲੋ (&u) +ਵਿਖਾਓ (&V) +ਸੋਧ ਕਰੋ (&E) +ਨਾਂ ਬਦਲੋ (&m) +ਨਵੇਂ ਟਿਕਾਣੇ ਤੇ ਨਕਲ ਉਤਾਰੋ (&C)... +ਨਵੇਂ ਟਿਕਾਣੇ ਤੇ ਭੇਜੋ (&M)... +ਹਟਾਓ (&D) +ਫਾਇਲ ਹਿੱਸਿਆਂ ਵਿੱਚ ਵੰਡੋ (&S)... +ਫਾਇਲ ਦੇ ਹਿੱਸੇ ਜੋੜੋ (&b)... +ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ (&r) +ਟਿੱਪਣੀ (&n) +ਚੈਕਸੱਮ ਗਣਨਾ ਕਰੋ + +ਫੋਲਡਰ ਬਣਾਓ +ਫਾਇਲ ਬਣਾਓ +ਬਾਹਰ ਨਿਕਲੋ (&x) +600 +ਸਭ ਚੁਣੋ (&A) +ਸਭ ਚੋਣ ਰੱਦ ਕਰੋ +ਉਲਟ ਚੋਣ ਕਰੋ (&I) +ਚੁਣੋ... +ਚੋਣ ਰੱਦ ਕਰੋ... +ਕਿਸਮ ਨਾਲ ਚੁਣੋ ਕਰੋ +ਕਿਸਮ ਨਾਲ ਚੋਣ ਰੱਦ ਕਰੋ +700 +ਵੱਡੇ ਆਈਕਾਨ (&g) +ਛੋਟੇ ਆਈਕਾਨ (&m) +ਸੂਚੀ (&L) +ਵੇਰਵੇ ਸਹਿਤ (&D) +730 +ਨਾ ਕ੍ਰਮ-ਬੱਧ +ਫਲੈਟ ਦ੍ਰਿਸ਼ +&2 ਪੈਨਲ +ਟੂਲਬਾਰ (&T) +ਰੂਟ ਫੋਲਡਰ ਖੋਲੋ +ਇੱਕ ਪੱਧਰ ਉੱਤੇ +ਫੋਲਡਰ ਅਤੀਤ... +ਤਾਜ਼ਾ ਕਰੋ(&R) +750 +ਆਕਾਈਵ ਟੂਲਬਾਰ +ਸਧਾਰਨ ਟੂਲਬਾਰ +ਵੱਡੇ ਬਟਨ +ਬਟਨ ਟੈਕਸਟ ਵਿਖਾਓ +800 +ਫੋਲਡਰ ਪਸੰਦੀਦਾ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ (&A) +ਬੁੱਕਮਾਰਕ +900 +ਚੋਣਾਂ (&O)... +ਬੈਂਚਮਾਰਕ (&B) +960 +ਵਿਸ਼ਾ ਸੂਚੀ (&C)... +7-ਜ਼ਿੱਪ ਬਾਰੇ (&A)... +1003 +ਮਾਰਗ +ਨਾਂ +ਐਕਸਟੈਂਸ਼ਨ +ਫੋਲਡਰ +ਸਾਈਜ਼ +ਪੈਕਡ ਸਾਈਜ਼ +ਲੱਛਨ +ਬਣਤਰ ਸਮਾਂ +ਪਹੁੰਚ ਸਮਾਂ +ਸੋਧ ਸਮਾਂ +ਠੋਸ +ਟਿੱਪਣੀ +ਐਨਕ੍ਰਿਪਟਡ +Split Before +Split After +ਡਿਕਸ਼ਨਰੀ +ਸੀ-ਆਰ-ਸੀ (CRC) +ਕਿਸਮ +ਐਂਟੀ (Anti) +ਢੰਗ +ਮੇਜ਼ਬਾਨ ਔ-ਐੱਸ +ਫਾਇਲ ਸਿਸਟਮ +ਯੂਜ਼ਰ +ਸਮੂਹ +ਬਲੋਕ +ਟਿੱਪਣੀ +ਸਥਿੱਤੀ +ਮਾਰਗ ਅਗੇਤਰ +ਫੋਲਡਰ +ਫਾਇਲਾਂ +ਵਰਜਨ +ਵੋਲੁੱਮ +ਮਲਟੀਵੋਲੁੱਮ +ਔਫ਼ਸੈਟ +ਲਿੰਕ +ਬਲੋਕ +ਵੋਲੁੱਮ + + + + + + + + + + + + + + + +ਸਮੱਸਿਆ +ਕੁੱਲ ਸਾਈਜ਼ +ਖ਼ਾਲੀ ਥਾਂ +ਕਲੱਸਟਰ ਸਾਈਜ਼ +ਲੇਬਲ +ਸਥਾਨਕ ਨਾਂ +ਉਪਲੱਬਧ ਕਰਤਾ +2100 +ਚੋਣਾਂ +ਭਾਸ਼ਾ +ਭਾਸ਼ਾ: +ਐਡੀਟਰ +ਟੈਕਸਟ ਐਡੀਟਰ (&E): + +2200 +ਸਿਸਟਮ +7-ਜ਼ਿੱਪ ਨਾਲ ਹੇਠਾਂ ਦਿੱਤੇ ਫਾਇਲ ਐਕਸਟੈਂਸ਼ਨ ਜੋੜੋ: +2301 +ਸ਼ੈੱਲ ਕੰਨਟੈਕਸਟ ਮੇਨੂੰ ਨਾਲ 7-ਜ਼ਿੱਪ ਨੂੰ ਏਕੀਕਿਰਤ ਕਰੋ +ਕੈਸਕੇਡਡ ਕੰਨਟੈਕਸਟ ਮੇਨੂੰ +ਕੰਨਟੈਕਸਟ ਮੇਨੂੰ ਆਈਟਮਾਂ: +2320 +<ਫੋਲਡਰ> +<ਆਕਾਈਵ> +ਆਕਾਈਵ ਖੋਲੋ +ਫਾਇਲਾਂ ਕੱਡੋ... +ਆਕਾਈਵ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ... +ਆਕਾਈਵ ਪਰਖੋ +ਫਾਇਲਾਂ ਇੱਥੇ ਕੱਡੋ +{0} ਵਿੱਚ ਕੱਡੋ +{0} ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ +ਨਪੀੜੋ ਅਤੇ ਈਮੇਲ ਕਰੋ... +{0} ਵਿੱਚ ਨਪੀੜੋ ਅਤੇ ਈਮੇਲ ਕਰੋ +2400 +ਫੋਲਡਰ +ਵਰਕਿੰਗ ਫੋਲਡਰ (&W) +ਸਿਸਟਮ ਆਰਜ਼ੀ (temp) ਫੋਲਡਰ (&S) +ਇਸ ਸਮੇਂ ਚੁਣਿਆ (&C) +ਹੇਠਾਂ ਦਿੱਤਾ ਗਿਆ (&S): +ਸਿਰਫ਼ ਹਟਾਈ ਜਾ ਸੱਕਨ ਵਾਲੀਆਂ ਡਰਾਈਵ ਲਈ ਵਰਤੋਂ ਕਰੋ +ਆਰਜ਼ੀ ਆਕਾਈਵ ਫਾਇਲਾਂ ਲਈ ਟਿਕਾਣਾ ਦੱਸੋ। +2500 +ਸੈਟਿੰਗ +".." ਆਈਟਮ ਵਿਖਾਓ +ਅਸਲੀ ਫਾਇਲ ਆਈਕਾਨ ਵਿਖਾਓ +ਸਿਸਟਮ ਮੇਨੂੰ ਵਿਖਾਓ +ਪੂਰੀ ਕਤਾਰ ਚੁਣੋ (&F) +ਗ੍ਰਿਡ ਲਾਈਨਾਂ ਵਿਖਾਓ (&g) + +ਵਿਕਲਪਕ ਚੁਣਾਓ ਢੰਗ (&A) +ਵੱਡੇ ਮੈਮੋਰੀ ਪੇਜ ਵਰਤੋ (&l) +2900 +7-ਜ਼ਿੱਪ ਬਾਰੇ +7-ਜ਼ਿੱਪ ਇੱਕ ਮੁਫ਼ਤ ਸਾਫ਼ਟਵੇਅਰ ਹੈ। ਪਰ ਫੇਰ ਵੀ, ਤੁਸੀਂ ਰਜਿਸਟਰ ਕਰਕੇ 7-ਜ਼ਿੱਪ ਦੇ ਵਿਕਾਸ ਵਿੱਚ ਸਮਰਥਨ ਪਾ ਸੱਕਦੇ ਹੋ।\n\nਪੰਜਾਬੀ ਵਿੱਚ ਅਨੁਵਾਦ ਕੀਤਾ (Translation Done By):\nGurmeet Singh Kochar (ਗੁਰਮੀਤ ਸਿੰਘ ਕੋਚਰ)\n +3000 + +ਕੋਈ ਸਮੱਸਿਆਵਾਂ ਨਹੀਂ ਹਨ +ਚੁਣੇ ਪਦਾਰਥ: {0} +'{0}' ਫੋਲਡਰ ਨਹੀਂ ਬਣਾਇਆ ਜਾ ਸੱਕਿਆ +ਅੱਪਡੇਟ ਔਪਰੇਸ਼ਨ ਇਸ ਆਕਾਈਵ ਲਈ ਸਹਿਯੋਗੀ ਨਹੀਂ ਹਨ। +'{0}' ਫਾਇਲ ਨੂੰ ਆਕਾਈਵ ਤਰ੍ਹਾਂ ਨਹੀਂ ਖੋਲਿਆ ਜਾ ਸੱਕਿਆ +'{0}' ਐਨਕ੍ਰਿਪਟਡ ਆਕਾਈਵ ਨਹੀਂ ਖੋਲਿਆ ਜਾ ਸੱਕਿਆ। ਗਲ਼ਤ ਪਾਸਵਰਡ? + + +'{0}' ਫਾਇਲ ਸੋਧ ਦਿੱਤੀ ਗਈ ਹੈ।\nਕੀ ਤੁਸੀਂ ਉਸਨੂੰ ਆਕਾਈਵ ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? +ਫਾਇਲ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸੱਕੀ\n'{0}' +ਐਡੀਟਰ ਚਾਲੂ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸੱਕਿਆ। + + + + +ਬਹੁੱਤ ਸਾਰੀਆਂ ਆਈਟਮਾਂ +3300 +ਕੱਡੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ +ਨਪੀੜਨ ਕਾਰਜ ਚੱਲ ਰਿਹਾ ਹੈ +ਪਰਖ ਚੱਲ ਰਹੀ ਹੈ +ਖੋਲੀ ਜਾ ਰਹੀ ਹੈ... +ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ... +3400 +ਕੱਡੋ +ਇੱਥੇ ਕੱਡੋ (&x): +ਕੱਡੀਆਂ ਜਾਉਣ ਵਾਲੀਆਂ ਫਾਇਲਾਂ ਲਈ ਟਿਕਾਣਾ ਦੱਸੋ। +3410 +ਮਾਰਗ ਢੰਗ +ਪੂਰੇ ਮਾਰਗ ਨਾਂ +ਕੋਈ ਮਾਰਗ ਨਾਂ ਨਹੀਂ +3420 +ਉਪਰੀਲੇਖਨ ਢੰਗ +ਉਪਰੀਲੇਖਨ ਤੋਂ ਪਹਿਲਾਂ ਤਸਦੀਕ +ਬਿਨ੍ਹਾਂ ਤਸਦੀਕ ਉਪਰੀਲੇਖਨ +ਮੌਜੂਦਾ ਫਾਇਲਾਂ ਨਾਂ ਕੱਡੋ +ਆਪੇ ਨਾਂ ਬਦਲ ਦਿਓ +ਮੌਜੂਦਾ ਫਾਇਲਾਂ ਦਾ ਆਪੇ ਨਾਂ ਬਦਲ ਦਿਓ +3500 +ਫਾਇਲ ਬਦਲਨ ਦੀ ਤਸਦੀਕ +ਕਾਰਵਾਈ ਕੀਤੀ ਜਾਉਂਦੀ ਫਾਇਲ ਨਿਯਤ ਫੋਲਡਰ ਵਿੱਚ ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ। +ਕੀ ਤੁਸੀਂ ਮੌਜੂਦਾ ਫਾਇਲ ਨੂੰ +ਇਸ ਫਾਇਲ ਨਾਲ ਬਦਲਨਾ ਚਾਹੋਗੇ? +{0} ਬਾਈਟ +ਆਪੇ ਨਾਂ ਬਦਲੀ ਕਰੋ (&u) +3700 +'{0}' ਲਈ ਨਪੀੜਨ ਢੰਗ ਸਹਿਯੋਗੀ ਨਹੀਂ। +'{0}' ਵਿੱਚ ਡਾਟਾ ਸਮੱਸਿਆ। ਫਾਇਲ ਟੁੱਟੀ ਹੋਈ ਹੈ। +'{0}' ਵਿੱਚ ਸੀ-ਆਰ-ਸੀ ਅਸਫ਼ਲ ਰਿਹਾ। ਫਾਇਲ ਟੁੱਟੀ ਹੋਈ ਹੈ। +'{0}' ਐਨਕ੍ਰਿਪਟਡ ਫਾਇਲ ਵਿੱਚ ਡਾਟਾ ਸਮੱਸਿਆ। ਗਲ਼ਤ ਪਾਸਵਰਡ? +'{0}' ਐਨਕ੍ਰਿਪਟਡ ਫਾਇਲ ਵਿੱਚ ਸੀ-ਆਰ-ਸੀ ਅਸਫ਼ਲ ਰਿਹਾ। ਗਲ਼ਤ ਪਾਸਵਰਡ? +3800 +ਪਾਸਵਰਡ ਭਰੋ +ਪਾਸਵਰਡ ਭਰੋ: +ਪਾਸਵਰਡ ਮੁੜ ਭਰੋ: +ਪਾਸਵਰਡ ਵਿਖਾਓ (&S) +ਪਾਸਵਰਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ +ਪਾਸਵਰਡ ਲਈ ਸਿਰਫ਼ ਅੰਗ੍ਰੇਜ਼ੀ ਅੱਖਰ, ਅੰਕ, ਅਤੇ ਖ਼ਾਸ ਅੱਖਰਾਂ (!, #, $, ...) ਦੀ ਹੀ ਵਰਤੋਂ ਕਰੋ +ਪਾਸਵਰਡ ਬਹੁੱਤ ਲੰਬਾ ਹੈ +ਪਾਸਵਰਡ +3900 +ਬੀਤਿਆ ਸਮਾਂ: +ਰਹਿੰਦਾ ਸਮਾਂ: +ਕੁੱਲ ਸਾਈਜ਼: +ਗਤੀ: +ਨਿਬੇੜੀਆਂ ਬਾਈਟ: +ਨਪੀੜਨ ਅਨੁਪਾਤ: +ਸਮੱਸਿਆਵਾਂ: +ਆਕਾਈਵਾਂ: +4000 +ਆਕਾਈਵ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ +ਆਕਾਈਵ (&A): +ਅੱਪਡੇਟ ਢੰਗ (&U): +ਆਕਾਈਵ ਫੌਰਮੈਟ (&f): +ਨਪੀੜਨ ਪੱਧਰ (&l): +ਨਪੀੜਨ ਢੰਗ (&m): +ਡਿਕਸ਼ਨਰੀ ਸਾਈਜ਼ (&D): +ਵਰਡ ਸਾਈਜ਼(&W): +ਠੋਸ ਬਲੋਕ ਸਾਈਜ਼: +ਸੀ-ਪੀ-ਯੂ ਥਰੈੱਡ ਗਿਣਤੀ: +ਪੈਰਾਮੀਟਰ (&P): +ਚੋਣਾਂ +SF&X ਆਕਾਈਵ ਬਣਾਓ +ਵਰਤੀਆਂ ਜਾਉਂਦੀਆਂ ਫਾਇਲਾਂ ਨੂੰ ਵੀ ਨਪੀੜੋ +ਐਨਕ੍ਰਿਪਸ਼ਨ +ਐਨਕ੍ਰਿਪਸ਼ਨ ਢੰਗ: +ਫਾਇਲਾਂ ਦੇ ਨਾਂ ਐਨਕ੍ਰਿਪਟ ਕਰੋ (&n) +ਨਪੀੜਨ ਲਈ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ: +ਆਕਾਈਵ ਖੋਲਨ ਲਈ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ: +4050 +ਸਿਰਫ਼ ਇਕੱਤਰਤਾ +ਬਹੁੱਤ ਤੇਜ਼ +ਤੇਜ਼ +ਆਮ +ਵੱਧੋਂ ਵੱਧ +ਸਭ ਤੋਂ ਵੱਧ +4060 +ਫਾਇਲਾਂ ਸ਼ਾਮਲ ਕਰੋ ਅਤੇ ਬਦਲੋ +ਫਾਇਲਾਂ ਸ਼ਾਮਲ ਅਤੇ ਅੱਪਡੇਟ ਕਰੋ +ਮੌਜੂਦਾ ਫਾਇਲਾਂ ਤਾਜ਼ਾ ਕਰੋ +ਫਾਇਲਾਂ ਸਮਕਾਲਵਰਤੀ ਕਰੋ +4070 +ਬਰਾਊਜ਼ +ਸਾਰੀਆਂ ਫਾਇਲਾਂ +ਨਾ-ਠੋਸ +ਠੋਸ +6000 +ਨਵੇਂ ਟਿਕਾਣੇ ਤੇ ਨਕਲ ਉਤਾਰੋ +ਨਵੇਂ ਟਿਕਾਣੇ ਤੇ ਭੇਜੋ +ਹੇਠਾਂ ਦਿੱਤੇ ਟਿਕਾਣੇ ਤੇ ਨਕਲ ਉਤਾਰੋ: +ਹੇਠਾਂ ਦਿੱਤੇ ਟਿਕਾਣੇ ਤੇ ਭੇਜੋ: +ਨਕਲ ਉਤਾਰੀ ਜਾ ਰਹੀ ਹੈ... +ਭੇਜਿਆ ਜਾ ਰਿਹਾ ਹੈ... +ਨਾਂ ਬਦਲਿਆ ਜਾ ਰਿਹਾ ਹੈ... +ਨਿਯਤ ਫੋਲਡਰ ਚੁਣੋ +ਕਾਰਵਾਈ ਸਹਿਯੋਗੀ ਨਹੀਂ ਹੈ। +ਫਾਇਲ ਜਾਂ ਫੋਲਡਰ ਦਾ ਨਾਂ ਬਦਲਣ ਵਿੱਚ ਸਮੱਸਿਆ +ਫਾਇਲ ਦੀ ਨਕਲ ਉਤਾਰਣ ਦੀ ਤਸਦੀਕ +ਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਫਾਇਲਾਂ ਦੀ ਆਕਾਈਵ ਵਿੱਚ ਨਕਲ ਉਤਾਰਨਾ ਚਾਹੁੰਦੇ ਹੋ +6100 +ਫਾਇਲ ਹਟਾਉਣ ਦੀ ਤਸਦੀਕ +ਫੋਲਡਰ ਹਟਾਉਣ ਦੀ ਤਸਦੀਕ +ਬਹੁ-ਫਾਈਲਾਂ ਹਟਾਉਣ ਦੀ ਤਸਦੀਕ +'{0}' ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? +ਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਫੋਲਡਰ '{0}' ਅਤੇ ਉਸਦੇ ਵਿੱਚਲੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? +ਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਇਨ੍ਹਾਂ {0} ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? +ਹਟਾਉਣ ਦੀ ਕਾਰਵਾਈ ਚੱਲ ਰਹੀ ਹੈ... +ਫਾਇਲ ਜਾਂ ਫੋਲਡਰ ਹਟਾਉਣ ਵਿੱਚ ਸਮੱਸਿਆ + +6300 +ਫੋਲਡਰ ਬਣਾਓ +ਫਾਇਲ ਬਣਾਓ +ਫੋਲਡਰ ਨਾਂ: +ਫਾਇਲ ਨਾਂ: +ਨਵਾਂ ਫੋਲਡਰ +ਨਵੀਂ ਫਾਇਲ +ਫੋਲਡਰ ਬਨਾਉਣ ਵਿੱਚ ਸਮੱਸਿਆ +ਫਾਇਲ ਬਨਾਉਣ ਵਿੱਚ ਸਮੱਸਿਆ +6400 +ਟਿੱਪਣੀ +ਟਿੱਪਣੀ (&C): +ਚੁਣੋ +ਚੋਣ ਰੱਦ ਕਰੋ +ਮਾਸਕ: +6600 +ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ +ਫੋਲਡਰ ਅਤੀਤ +ਡਾਈਗਨੋਸਟਿੱਕ ਸੰਦੇਸ਼ +ਸੰਦੇਸ਼ +7100 +ਕੰਪਿਊਟਰ +ਨੈੱਟਵਰਕ + +ਸਿਸਟਮ +7200 +ਸ਼ਾਮਲ ਕਰੋ +ਕੱਡੋ +ਪਰਖ ਕਰੋ +ਨਕਲ ਉਤਾਰੋ +ਨਵੇਂ ਟਿਕਾਣੇ ਤੇ ਭੇਜੋ +ਹਟਾਓ +ਜਾਣਕਾਰੀ +7300 +ਫਾਇਲ ਹਿੱਸਿਆਂ ਵਿੱਚ ਵੰਡੋ +ਹੇਠਾਂ ਦਿੱਤੇ ਟਿਕਾਣੇ ਉੱਤੇ ਹਿੱਸੇ ਕਰੋ (&S): +ਵੋਲੁੱਮਾਂ ਵਿੱਚ ਵੰਡੋ, ਬਾਈਟ (&v): +ਫਾਇਲ ਹਿੱਸਿਆਂ ਵਿੱਚ ਵੰਡੀ ਜਾ ਰਹੀ ਹੈ... +ਹਿੱਸੇ ਕਰਨ ਦੀ ਤਸਦੀਕ +ਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਫਾਇਲ ਦੇ {0} ਵੋਲੁੱਮਾਂ ਵਿੱਚ ਹਿੱਸੇ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? +ਵੋਲੁੱਮ ਸਾਈਜ਼ ਅਸਲੀ ਫਾਇਲ ਦੇ ਸਾਈਜ਼ ਤੋਂ ਛੋਟਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ +ਵੋਲੁੱਮ ਸਾਈਜ਼ ਗਲ਼ਤ ਹੈ +ਦਿੱਤਾ ਗਿਆ ਵੋਲੁੱਮ ਸਾਈਜ਼: {0} ਬਾਈਟ।\nਕੀ ਤੁਸੀਂ ਨਿਸ਼ਚਿੱਤ ਆਕਾਈਵ ਨੂੰ ਦਿੱਤੇ ਗਏ ਵੋਲੁੱਮਾਂ ਵਿੱਚ ਵੰਡਣਾ ਚਾਹੁੰਦੇ ਹੋ? +7400 +ਫਾਇਲ ਦੇ ਹਿੱਸੇ ਜੋੜੋ +ਹੇਠਾਂ ਦਿੱਤੇ ਟਿਕਾਣੇ ਉੱਤੇ ਹਿੱਸੇ ਜੋੜੋ(&C): +ਹਿੱਸੇ ਜੋੜੇ ਜਾ ਰਹੇ ਹਨ... +ਸਿਰਫ਼ ਪਹਿਲੀ ਫਾਇਲ ਚੁਣੋ + + +7500 +ਚੈਕਸੱਮ ਗਣਨਾ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ... +ਚੈਕਸੱਮ ਜਾਣਕਾਰੀ +ਡਾਟਾ ਲਈ ਸੀ-ਆਰ-ਸੀ ਚੈਕਸੱਮ: +ਡਾਟਾ ਅਤੇ ਨਾਮਾਂ ਲਈ ਸੀ-ਆਰ-ਸੀ ਚੈਕਸੱਮ: +7600 +ਬੈਂਚਮਾਰਕ +ਮੈਮੋਰੀ ਵਰਤੋਂ: +ਨਪੀੜਨ ਕਾਰਜ +ਖੋਲਣ ਕਾਰਜ +ਦਰਜ਼ਾ +ਕੁੱਲ ਦਰਜ਼ਾ +ਇਸ ਸਮੇਂ +ਰੀਸੱਲਟਿੰਗ +ਸੀ-ਪੀ-ਯੂ ਵਰਤੋਂ +ਦਰਜ਼ਾ / ਵਰਤੋਂ +ਪਾਸ: diff --git a/Utils/7-Zip/Lang/pl.txt b/Utils/7-Zip/Lang/pl.txt new file mode 100644 index 000000000..e8d20b880 --- /dev/null +++ b/Utils/7-Zip/Lang/pl.txt @@ -0,0 +1,477 @@ +;!@Lang2@!UTF-8! +; : cienislaw +; : pixel +; 9.07 : F1xat +; 9.33 : Łukasz Maria P. Pastuszczak +; +; +; +; +; +; +; +0 +7-Zip +Polish +Polski +401 +OK +Anuluj + + + +&Tak +&Nie +&Zamknij +Pomoc + +&Kontynuuj +440 +Ta&k na wszystkie +Ni&e na wszystkie +Zatrzymaj +Ponów +&Tło +&Pierwszy plan +&Wstrzymaj +Wstrzymano +Czy na pewno chcesz anulować? +500 +&Plik +&Edycja +&Widok +&Ulubione +&Narzędzia +Pomo&c +540 +&Otwórz +Otwórz &wewnątrz +Otwórz na &zewnątrz +Pod&gląd +&Edytuj +Zmień &nazwę +Kopiuj &do... +&Przenieś do... +&Usuń +Podzie&l plik... +Złą&cz pliki... +Wł&aściwości +Ko&mentarz +Oblicz sumę kontrolną +Diff +Utwórz &folder +U&twórz plik +Za&kończ +Dow&iązanie +600 +Z&aznacz wszystko +&Odznacz wszystko +Odwróć &zaznaczenie +Zaznacz... +Odznacz... +Zaznacz według typu +Odznacz według typu +700 +&Duże ikony +&Małe ikony +&Lista +&Szczegóły +730 +Nieposortowane +Widok płaski +&2 panele +&Paski narzędzi +Otwórz folder główny +Do góry o jeden poziom +Historia folderów... +&Odśwież +Automatyczne odświeżanie +750 +Pasek archiwum +Pasek standardowy +Duże przyciski +Pokaż etykiety tekstowe +800 +&Dodaj folder do ulubionych jako +Zakładka +900 +&Opcje... +&Test wydajności +960 +&Zawartość +7-Zip - i&nformacje +1003 +Ścieżka +Nazwa +Rozszerzenie +Folder +Rozmiar +Rozmiar po spakowaniu +Atrybuty +Utworzony +Ostatnio otwarty +Zmodyfikowany +Ciągły +Z komentarzem +Zaszyfrowany +Podzielony przed +Podzielony po +Słownik + +Typ +Anty +Metoda +Pochodzenie +System plików +Użytkownik +Grupa +Blok +Komentarz +Pozycja +Prefiks ścieżki +Foldery +Pliki +Wersja +Wolumin +Wielowoluminowy +Przesunięcie +Dowiązania +Bloki +Woluminy + +64-bitowy +Big-endian +Procesor +Rozmiar fizyczny +Rozmiar nagłówków +Suma kontrolna +Charakterystyki +Adres wirtualny +Numer seryjny woluminu +Krótka nazwa +Generator +Rozmiar sektora +Tryb +Dowiązanie symboliczne +Błąd +Całkowity rozmiar +Wolne miejsce +Rozmiar klastra +Etykieta +Nazwa lokalna +Dostawca +Zabezpieczenia NT +Alternatywny strumień + +Usunięty +Drzewo + + +Rodzaj błędu +Błędy +Błędy +Ostrzeżenia +Ostrzeżenie +Strumienie +Alternatywne strumienie +Rozmiar alternatywnych strumieni +Rozmiar wirtualny +Rozmiar po rozpakowaniu +Całkowity rozmiar fizyczny +Numer woluminu +Podtyp +Krótki komentarz +Strona kodowa + + + + + +Dowiązanie +Dowiązanie twarde +I-węzeł +2100 +Opcje +Język +Język: +Edytor +&Edytor: +&Diff: +2200 +System +Skojarz program 7-Zip z: +2301 +Zintegruj program 7-Zip z menu kontekstowym powłoki +Kaskadowe menu kontekstowe +Elementy menu kontekstowego: +Ikony w menu kontekstowym +2320 + + +Otwórz archiwum +Wypakuj pliki... +Dodaj do archiwum... +Testuj archiwum +Wypakuj tutaj +Wypakuj do {0} +Dodaj do {0} +Skompresuj i wyślij e-mailem... +Skompresuj do {0} i wyślij e-mailem +2400 +Foldery +Folder roboczy +&Systemowy folder tymczasowy +&Bieżący +&Wskazany: +Użyj tylko dla dysków wymiennych +Wskaż lokalizację dla tymczasowych plików archiwów. +2500 +Ustawienia +Pokaż element „..” +Pokaż prawdziwe ikony plików +Pokaż menu systemowe +Zaznaczaj &cały rząd +&Pokaż linie siatki +Pojedyncze kliknięcie otwiera element +&Alternatywny tryb zaznaczania +&Użyj dużych stron pamięci +2900 +7-Zip - informacje +7-Zip jest programem darmowym. +3000 +System nie może przydzielić wymaganej ilości pamięci +Nie wykryto błędów +Zaznaczono {0} obiekt(ów) +Nie można utworzyć folderu „{0}” +Operacje aktualizacji nie są obsługiwane dla tego archiwum. +Nie można otworzyć pliku „{0}” jako archiwum +Nie można otworzyć zaszyfrowanego archiwum „{0}”. Nieprawidłowe hasło? +Nieobsługiwany typ archiwum +Plik {0} już istnieje +Plik „{0}” został zmodyfikowany.\nCzy chcesz zaktualizować go w archiwum? +Nie można zaktualizować pliku\n„{0}” +Nie można uruchomić edytora. +Plik wygląda na wirusa (nazwa pliku zawiera długi ciąg spacji). +Operacja nie może być wywołana z folderu, który ma długą ścieżkę. +Musisz zaznaczyć jeden plik +Musisz zaznaczyć jeden lub więcej plików +Zbyt dużo elementów +3300 +Wypakowywanie +Kompresowanie +Testowanie +Otwieranie... +Skanowanie... +3400 +Wypakuj +&Wypakuj do: +Wskaż lokalizację dla wypakowanych plików. +3410 +Tryb ścieżek: +Pełne ścieżki +Bez ścieżek +Bezwzględne ścieżki +Względne ścieżki +3420 +Tryb nadpisywania: +Monituj przed nadpisaniem +Nadpisuj bez monitowania +Pomiń istniejące pliki +Automatycznie zmień nazwy +Automatycznie zmień nazwy istniejących plików +3430 +Wyeliminuj podwojenie folderu głównego +Przywróć zabezpieczenia plików +3500 +Potwierdź zamianę pliku +Folder docelowy zawiera już przetwarzany plik. +Czy chcesz zamienić istniejący plik +na następujący? +{0} bajtów +Automatycznie &zmień nazwy +3700 +Nieobsługiwana metoda kompresji pliku „{0}”. +Błąd danych w „{0}”. Plik jest uszkodzony. +CRC nie powiodła się dla „{0}”. Plik jest uszkodzony. +Błąd danych w zaszyfrowanym pliku „{0}”. Nieprawidłowe hasło? +CRC nie powiodła się dla zaszyfrowanego pliku „{0}”. Nieprawidłowe hasło? +3710 +Nieprawidłowe hasło? +3721 +Nieobsługiwana metoda kompresji +Błąd danych +CRC nie powiodła się +Niedostępne dane +Nieoczekiwany koniec danych +Pewne dane znajdują się za końcem bloku użytecznych danych +Nie rozpoznano archiwum +Błąd nagłówków +3763 +Niedostępny początek archiwum +Niepotwierdzony początek archiwum + + + +Nieobsługiwana funkcja +3800 +Wprowadź hasło +Wprowadź hasło: +Wprowadź ponownie hasło: +Pokaż &hasło +Hasła nie zgadzają się +W haśle używaj tylko liter alfabetu angielskiego, cyfr i znaków specjalnych (!, #, $, ...) +Hasło jest zbyt długie +Hasło +3900 +Upłynęło czasu: +Pozostało czasu: +Całkowity rozmiar: +Szybkość: +Przetworzono: +Współczynnik kompresji: +Błędy: +Archiwów: +4000 +Dodaj do archiwum +&Archiwum: +&Tryb aktualizacji: +&Format archiwum: +Stopień &kompresji: +&Metoda kompresji: +&Rozmiar słownika: +Rozmiar &słowa: +Rozmiar bloku ciągłego: +Liczba wątków: +&Parametry: +Opcje +&Utwórz archiwum SFX +Kompresuj pliki współdzielone +Szyfrowanie +Metoda szyfrowania: +&Zaszyfruj nazwy plików +Użycie pamięci dla kompresji: +Użycie pamięci dla dekompresji: +Usuń pliki po skompresowaniu +4040 +Zachowaj dowiązania symboliczne +Zachowaj dowiązania twarde +Zachowaj alternatywne strumienie danych +Zachowaj zabezpieczenia plików +4050 +Bez kompresji +Najszybsza +Szybka +Normalna +Maksymalna +Ultra +4060 +Dodaj i zamień pliki +Aktualizuj i dodaj pliki +Odśwież istniejące pliki +Synchronizuj pliki +4070 +Przeglądaj +Wszystkie pliki +Nieciągły +Ciągły +6000 +Kopiuj +Przenieś +Kopiuj do: +Przenieś do: +Kopiowanie... +Przenoszenie... +Zmienianie nazwy... +Wybierz folder docelowy. +Operacja nie jest obsługiwana dla tego folderu. +Błąd podczas zmiany nazwy pliku lub folderu +Potwierdź kopiowanie plików +Czy na pewno chcesz skopiować pliki do archiwum +6100 +Potwierdź usunięcie pliku +Potwierdź usunięcie folderu +Potwierdź usunięcie wielu plików +Czy na pewno chcesz usunąć plik „{0}”? +Czy na pewno chcesz usunąć folder „{0}” i całą zawartość? +Elementów: {0} - czy na pewno chcesz je usunąć? +Usuwanie... +Błąd podczas usuwania pliku lub folderu +System nie może przenieść pliku o długiej ścieżce do Kosza +6300 +Utwórz folder +Utwórz plik +Nazwa folderu: +Nazwa pliku: +Nowy folder +Nowy plik +Błąd podczas tworzenia folderu +Błąd podczas tworzenia pliku +6400 +- komentarz +&Komentarz: +Zaznacz +Odznacz +Maska: +6600 +Właściwości +Historia folderów +Komunikaty diagnostyczne +Komunikat +7100 +Komputer +Sieć +Dokumenty +System +7200 +Dodaj +Wypakuj +Testuj +Kopiuj +Przenieś +Usuń +Informacje +7300 +Podziel plik +&Podziel do: +Rozmiar &woluminów (bajty): +Dzielenie... +Potwierdź podział +Czy na pewno chcesz podzielić plik na {0} woluminów? +Rozmiar woluminu musi być mniejszy od rozmiaru oryginalnego pliku +Nieprawidłowy rozmiar woluminu +Określony rozmiar woluminu: {0} bajtów.\nCzy na pewno chcesz podzielić archiwum na takie woluminy? +7400 +Złącz pliki +&Złącz do: +Łączenie... +Zaznacz tylko pierwszą część podzielonego pliku +To nie jest poprawna część podzielonego pliku +Nie można odnaleźć co najmniej jednej części podzielonego pliku +7500 +Obliczanie sumy kontrolnej... +Informacja o sumie kontrolnej +Suma kontrolna CRC dla danych: +Suma kontrolna CRC dla danych i nazw: +7600 +Test wydajności +Użycie pamięci: +Kompresja +Dekompresja +Ocena +Całkowita ocena +Aktualnie +Wynik +Użycie CPU +Ocena / Użycie +Przebiegi: +7700 +Dowiązanie +Dowiąż +Element źródłowy: +Element docelowy: +7710 +Rodzaj dowiązania +Dowiązanie twarde +Dowiązanie symboliczne pliku +Dowiązanie symboliczne katalogu +Połączenie katalogów diff --git a/Utils/7-Zip/Lang/ps.txt b/Utils/7-Zip/Lang/ps.txt new file mode 100644 index 000000000..baef904d0 --- /dev/null +++ b/Utils/7-Zip/Lang/ps.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.53 : 2007-12-26 : Pathanisation Project : pathanisation.pakhtosoft.com +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Pashto +پښتو +401 +هوکې +بندول + + + +هو& +نه& +بندول& +مرسته + +پرمختلل& +440 +ټولو ته هو& +ټ&ولو ته نه +تمول +بياپېلول +شاليد& +پاسليد& +ځنډول& +څنډېدلی +په ډاډمنه توګه غواړئ چې بند يې کړئ؟ +500 +دوتنه& +سمون& +ليد& +خ&واپوري +توکي& +مرسته& +540 +پرانيستل& +دننه& پرانيستل +بهر پ&رانيستل +ليد& +سمون& +بي&انومول +...ته لمېسل& +...ته خوځول& +ړنګول& +...دوتنه چول& +...دوتنې يوځ&ايول +ځانتياوې +څرګند&ون +چېکسم شمېرل + +پوښۍ جوړول +دوتنه جوړول +و&تون +600 +ټول ټاکل& +ټول ناټاکل +ټاکنه نسکورول& +...ټاکل +...ناټاکل +پر ډول ټاکل +پر ډول ناټاکل +700 +لو&ی انځورنونه +و&اړه انځورنونه +لړ& +خبرتياوې& +730 +ناڼلي +پوړ ليد +۲‏ چوکاټه& +توکپټې& +ولۍ پوښۍ پرانيستل +يو کچه برول +...پوښيو مخينه +تاندول& +750 +ارشيو توکپټه +کره توکپټه +لویې تڼۍ +د تڼيو ليکنې ښودل +800 +پوښۍ خواپورو ته زياتول لکه& +نښه +900 +...غوراوي& +بنچمارک& +960 +...منځپانګه& +...۷‏-زېپ په اړه& +1003 +يونلور +نوم +شاتاړی +پوښۍ +کچ +بنډل شوی کچ +څانتياوې +جوړشوی +رسی +بدلون +کلک +څرګندون +کوډييز +چول مخکښې +چول وروسته +ويېپانګه +CRC +ډول +مخالف +لېله +کوربه چغ +دوتنه غونډال +کارن +ډله +غونډ +څرګندون +ځای +يونلور مختاړی +پوښۍ +دوتنې +نسخه +ډکون +ګڼډکون +افسېټ +پېوندونه +غوڼدونه +ډکونونه + + + + + + + + + + + + + + + +تېروتنه +بشپړ کچ +پاتې تشه +ځومبک کچ +نښکه +ځایي نوم +برابروونى +2100 +غوراوي +ژبه +:ژبه +سمونګر +:سمونګر& + +2200 +غونډال +:له ۷‏-زېپ سره ملول +2301 +۷‏-زېپ سيپۍ تړاو غورنۍ کښې زياتول +ځړبهيزه تړاو غورنۍ +:تړاو غورنۍ توکي +2320 +<پوښۍ> +<ارشيو> +ارشيو پرانيستل +...دوتنې ويستل +...ارشيو ته زياتول +ارشيو ازمويل +دلته ويستل +ته ويستل {0}‏ +ته زياتول {0} +...زېرل او برېښل +ته زياتول او برېښل {0} +2400 +پوښۍ +&کارنه پوښۍ +&لنډمهاله غونډال پوښۍ +&اوسنۍ +&څانګړې +يوازې له لېرېدونکو چليځونو لپاره کارول +.د لنډمهاله ارشيو دوتنو لپاره ځای وټاکئ +2500 +امستنې +توکي ښودل ".." +د دوتنو ريښتيني انځورنونه ښودل +غونډال غورنۍ ښودل +ټول کيل ټاکل& +کرښې ښودل + +انډوليز ټاکنې اکر& +لوی ياد مخونه کارول& +2900 +۷‏-زېپ په اړه +.دا يو وړيا ساوتری دی. خو، په نومکښلو سره د ساوتري د پرمختګ ملاتړ کولی شئ +3000 + +هېڅ تېروتنه نشته +ټاکل شوي څيزونه {0} +پوښۍ جوړولی نه شي '{0}' +.اوسمهاله چلښتونه دې ارشيو لپاره منلي نه دي +'{0}' دوتنه لکه د ارشيو نه شي پرانيستلی +کوډييز ارشيو پرانيستلی نه شي '{0}'. ناسمه تېرنويې؟ + + +.'{0}' دوتنه کښې بدلون راغلی\nپه ارشيو کښې يې اوسمهالول غواړئ؟ +'{0}'\nدوتنه اوسمهالولی نه شي +سمونګر پېلولی نه شي + + + + +ډېر زيات توکي +3300 +وباسي +زېرل کيږي +ازموينه +...پرانيستل کيږي +...ځیريږي +3400 +ويستل +:ته و&يستل +.د ويستلو دوتنو لپاره يو ځای وټاکئ +3410 +يونلور اکر +بشپړ يونلورنومونه +هېڅ يونلورنومونه +3420 +سرليکلو اکر +سرليکلو نه مخکښې پوښتل +بې له پارليکې سرليکل +شته دوتنې پرېښودل +خپله بيانومول +شته دوتنې خپله بيانومول +3500 +دوتنه ځاېناستی باورييل +.موخه پوښۍ دمخه بهيرلې دوتنې لري +غواړئ چې شته دوتنه ځاېناستې کړئ +له دې سره؟ +باېټه {0} +خپله ب&يانومول +3700 +.لپاره نامنلې زېرنې لېله '{0}' +.کښې اومتوک ستونزه '{0}' دوتنه ماته ده +.کښې سرس پاتې راغی '{0}' دوتنه ماته ده +کوډييزې دوتنې '{0}' کښې اومتوک ستونزه. ناسمه تېرنويې؟ +په کوډييزې دوتنې '{0}' کښې سرس پاتې راغی. ناسمه تېرنويې؟ +3800 +تېرنويې وليکئ +:تېرنويې وليکئ +:تېرنويې بيا وليکئ +تېرنويې ښودل& +تېرنويې سمون نه خوري +تېرنويې لپاره يوازې انګريزي توري، شمېرې او ځانګړي لوښې (!, #, $, ...) وکاروئ +تېرنويې ډېره اوږده ده +تېرنويې +3900 +:تېر مهال +:پاتې مهال +:بشپړ کچ +:چټکتیا +:بهيرلی +:زېرلو نسبت +:تېروتنه +:ارشيونه +4000 +ارشيو ته زياتول +:ارشيو& +:اوسمهاليز اکر& +:ارشيو بڼه& +:زېرنې &کچه +:زېرنې &لېله +:ويېپانګې کچه& +:ويې کچ& +:کلک غونډ کچ +:د مبي مزيو شمېر +:ارزښتمني& +غوراوي +ارشيو جوړول SF&X +ونډولې دوتنې زېرل +کوډییزونه +:کوډییزونې لېله +دوتنه &نومونه کوډييزول +:زېرلو لپاره ياد کارونه +:نازېرلو لپاره ياد کارونه +4050 +زېرمل +ډېر چټک +چټک +ليوی +زيات +ډېر زيات چټک +4060 +دوتنې زياتول او ځاېناستول +دوتنې اوسمهالول او زياتول +شته دوتنې تاندول +دوتنې هممهالول +4070 +لټول +ټولې دوتنې +نا-کلک +کلک +6000 +لمېسل +خوځول +:ته لمېسل +:ته خوځول +...لميسل کيږي +...خوځيږي +بيانوميږي +.موخه پوښۍ وټاکئ +.چلښت منلی نه دی +دوتنې يا پوښۍ بيانومولو ستونزه +دوتنې لمېسل باورييل +په ډاډمنه توګه دوتنې ارشيو ته لمېسل غواړئ؟ +6100 +دوتنې ړنګونه باورييل +پوښۍ ړنګونه باورييل +ګڼو دوتنو ړنګونه باورييل +په ډاډمنه توګه '{0}' ړنګول غواړئ؟ +په ډاډمنه توګه '{0}' پوښۍ او د دې ټوله منځپانګه ړنګول غواړئ؟ +په ډاډمنه توګه دا {0} توکي ړنګول غواړئ؟ +...ړنګيږي +دوتنې يا پوښۍ ړنګولو ستونزه + +6300 +پوښۍ جوړول +دوتنه جوړول +:پوښۍ نوم +:دوتنه نوم +نوې پوښۍ +نوې دوتنه +پوښۍ جوړولو ستونزه +دوتنې جوړولو ستونزه +6400 +څرګندون +:څرګندون& +ټاکل +ناټاکل +:وربوزۍ +6600 +ځانتياوې +پوښيو مخينه +رنځ نومېرنې استوزه +استوزه +7100 +سولګر +جال + +غونډال +7200 +زياتول +ويستل +ازمويل +لمېسل +خوځول +ړنګول +خبرتياوې +7300 +دوتنه چول +:ته چول& +:ډکونونو، باېټونو ته چول& +...چول کيږي +چونه باورييل +په ډاډمنه توګه دوتنه په {0} ډکونونو وېشل غواړئ؟ +ډکون کچ بايد د دوتنې ار کچ نه وړوکی وي +ناسم ډکون کچ +.باېټه {0} :ټاکلی ډکون کچ\nپه ډاډمنه توګه غواړئ چې ارشيو په داسې ډکونونو وويشئ؟ +7400 +دوتنې يوځايول +:ته يوځايول& +...يوځايږي +يوازې لمړۍ دوتنه ټاکل + + +7500 +...چېکسم شمېريږي +چېکسم خبرتياوې +:چېکسم CRC اومتوک لپاره +:چېکسم CRC اومتوک او نومونو لپاره +7600 +بنچمارک +:ياد کارونه +زېريږي +نازېريږي +کچونه +بشپړه کچونه +اوسنی +پايليز +مبي کارونه +کچونه / کارونه +:تيريږي diff --git a/Utils/7-Zip/Lang/pt-br.txt b/Utils/7-Zip/Lang/pt-br.txt new file mode 100644 index 000000000..a44134242 --- /dev/null +++ b/Utils/7-Zip/Lang/pt-br.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Francisco Jr +; 4.37 : Fabricio Biazzotto +; 15.07 : Atualizado por Felipe +; +; +; +; +; +; +; +; +0 +7-Zip +Portuguese Brazilian +Português Brasileiro +401 +OK +Cancelar + + + +&Sim +&Não +&Fechar +Ajuda + +&Continuar +440 +Sim pra &Todos +Não pra T&odos +Parar +Reiniciar +&Em 2º plano +&Em 1º plano +&Pausar +Pausado +Você tem certeza que você quer cancelar? +500 +&Arquivo +&Editar +&Visualizar +F&avoritos +&Ferramentas +&Ajuda +540 +&Abrir +Abrir &por Dentro +Abrir p&or Fora +&Visualizar +&Editar +Re&nomear +&Copiar Para... +&Mover Para... +&Apagar +&Dividir arquivo... +Com&binar arquivos... +P&ropriedades +Comen&tário +Calcular checksum +Diff +Criar Pasta +Criar Arquivo +S&air +Link +&Correntes Alternantes +600 +Selecionar &Tudo +Desmarcar Tudo +&Inverter Seleção +Selecionar... +Desmarcar... +Selecionar por Tipo +Desfazer seleção por Tipo +700 +Íco&nes Grandes +Íc&ones Pequenos +&Lista +&Detalhes +730 +Desorganizado +Visualização Plana +&2 Painéis +&Barra de Ferramentas +Abrir a Pasta Raiz +Um Nível Acima +Histórico das Pastas... +&Atualizar +Auto-Atualizar +750 +Barra de Ferramentas do Arquivo Compactado +Barra de Ferramentas Padrão +Botões Grandes +Mostrar o Texto dos Botões +800 +&Adicionar a pasta aos Favoritos como +Favorito +900 +&Opções... +&Benchmark +960 +&Conteúdo... +&Sobre o 7-Zip... +1003 +Caminho +Nome +Extensão +Pasta +Tamanho +Tamanho Compactado +Atributos +Criado +Acessado +Modificado +Sólido +Comentado +Criptografado +Dividir Antes +Dividir Depois +Dicionário + +Tipo +Anti +Método +Sistema Operacional Hospedeiro +Sistema de Arquivos +Usuário +Grupo +Bloco +Comentário +Posição +Prefixo do Caminho +Pastas +Arquivos +Versão +Volume +Multivolume +Offset +Links +Blocos +Volumes + +64 bits +Big-endian +CPU +Tamanho Físico +Tamanho dos Cabeçalhos +Checksum +Características +Endereço Virtual +ID +Nome Curto +Aplicativo Criador +Tamanho do Setor +Modo +Link Simbólico +Erro +Tamanho Total +Espaço Livre +Tamanho do Cluster +Rótulo +Nome Local +Provedor +Segurança da NT +Corrente Alternante +Aux +Apagado +É Árvore + + +Tipo de Erro +Erros +Erros +Avisos +Aviso +Correntes +Correntes Alternantes +Tamanho das Correntes Alternantes +Tamanho Virtual +Tempo Descompactado +Total do Tamanho Físico +Índice do Volume +Sub-Tipo +Comentário Curto +Página do Código + + + +Tamanho da Cauda +Tamanho do Toco Embutido +Link +Link Rígido +iNode + +Somente-Leitura +2100 +Opções +Idioma +Idioma: +Editor +&Editor: +&Diff: +2200 +Sistema +Associar o 7-Zip com: +Todos os usuários +2301 +Integrar o 7-Zip ao menu de contexto do shell +Menu de contexto em cascata +Itens do menu de contexto: +Ícones no menu de contexto +2320 + + +Abrir arquivo compactado +Extrair arquivos... +Adicionar ao arquivo compactado... +Testar arquivo compactado +Extrair Aqui +Extrair para {0} +Adicionar para {0} +Comprimir e enviar por email... +Comprimir para {0} e enviar por email +2400 +Pastas +&Pasta de trabalho +&Pasta temporária do sistema +&Atual +&Especificada: +Usar só pra drives removíveis +Especifique um local pros arquivos compactados temporários. +2500 +Configurações +Mostrar o item ".." +Mostrar os ícones reais dos arquivos +Mostrar o menu do sistema +&Selecionar a linha inteira +Mostrar as &linhas de grade +Clique único pra abrir um item +&Modo de seleção alternativo +Usar &grandes páginas de memória +2900 +Sobre o 7-Zip +7-Zip é um software grátis +3000 +O sistema não pôde alocar a quantia requerida de memória +Não há erros +{0} objeto(s) selecionado(s) +Não pôde criar a pasta '{0}' +Operações de atualização não são suportadas por este arquivo compactado. +Não pôde abrir o arquivo '{0}' como arquivo compactado +Não pôde abrir o arquivo compactado encriptado '{0}'. Senha errada? +Tipo de arquivo compactado não suportado +O arquivo {0} já existe +O arquivo '{0}' foi modificado.\nVocê quer atualizá-lo no arquivo compactado? +Não pôde atualizar o arquivo\n'{0}' +Não pôde iniciar o editor. +O arquivo parece um vírus (o nome do arquivo contém espaços longos no nome). +A operação não pode ser chamada de uma pasta que tem um caminho longo. +Você deve selecionar um arquivo +Você deve selecionar um ou mais arquivos +Itens demais +Não pôde abrir o arquivo como {0} arquivo compactado +O arquivo está aberto como {0} arquivo compactado +O arquivo compactado está aberto com o offset +3300 +Extraindo +Comprimindo +Testando +Abrindo... +Escaneando... +Removendo +3320 +Adicionando +Atualizando +Analisando +Replicando +Re-compactando +Ignorando +Apagando +Criando cabeçalho +3400 +Extrair +E&xtrair para: +Especifique um local pros arquivos extraídos. +3410 +Modo do caminho: +Nomes dos caminhos completos +Sem nomes de caminhos +Nomes dos caminhos absolutos +Nomes dos caminhos relativos +3420 +Modo de sobrescrição: +Perguntar antes de sobrescrever +Sobrescrever sem alertar +Ignorar os arquivos existentes +Auto-renomear +Auto-renomear os arquivos existentes +3430 +Eliminar duplicação da pasta raiz +Restaurar a segurança do arquivo +3500 +Confirmar a Substituição dos Arquivos +A pasta destino já contém o arquivo processado. +Você gostaria de substituir o arquivo existente +por este? +{0} bytes +A&uto-Renomear +3700 +Método de compressão não suportado por '{0}'. +Erro nos dados de '{0}'. O arquivo está danificado. +O CRC falhou em '{0}'. O arquivo está danificado. +Erros nos dados do arquivo encriptado '{0}'. Senha errada? +O CRC falhou no arquivo encriptado '{0}'. Senha errada? +3710 +Senha errada? +3721 +Método de compressão não suportado +Erro dos dados +O CRC falhou +Dados indisponíveis +Fim inesperado dos dados +Há alguns dados após o fim da carga dos dados +Não é arquivo compactado +Erro dos Cabeçalhos +Senha errada +3763 +Início indisponível do arquivo compactado +Início não confirmado do arquivo compactado + + + +Função não suportada +3800 +Inserir senha +Inserir senha: +Re-inserir a senha: +&Mostrar senha +As senhas não combinam +Usar apenas letras em Inglês, números e caracteres especiais (!, #, $, ...) para a senha +A senha é muito longa +Senha +3900 +Tempo decorrido: +Tempo restante: +Tamanho total: +Velocidade: +Processados: +Taxa de compressão: +Erros: +Arquivos: +4000 +Adicionar ao arquivo compactado +&Arquivo compactado: +&Modo de atualização: +Formato do &arquivo compactado: +Nível da &compressão: +Método de &compressão: +&Tamanho do dicionário: +&Tamanho da palavra: +Tamanho do bloco sólido: +Número de threads da CPU: +&Parâmetros: +Opções +Criar ar&quivo compactado SFX +Comprimir arquivos compartilhados +Encriptação +Método de encriptação: +Criptografar os &nomes dos arquivos +Uso de memória pra Compressão: +Uso de memória para Descompressão: +Apagar arquivos após a compressão +4040 +Armazenar links simbólicos +Armazenar links rígidos +Armazenar correntes de dados alternantes +Armazenar segurança do arquivo +4050 +Armazenar +Mais rápida +Rápida +Normal +Máximo +Ultra +4060 +Adicionar e substituir arquivos +Atualizar e adicionar arquivos +Atualizar arquivos existentes +Sincronizar arquivos +4070 +Navegar +Todos os Arquivos +Não-sólido +Sólido +6000 +Copiar +Mover +Copiar para: +Mover para: +Copiando... +Movendo... +Renomeando... +Selecionar a pasta destino. +A operação não é suportada por esta pasta. +Erro ao Renomear o Arquivo ou Pasta +Confirmar a Cópia do Arquivo +Você tem certeza que você quer copiar os arquivos pra dentro do arquivo compactado? +6100 +Confirmar a Exclusão do Arquivo +Confirmar a Exclusão da Pasta +Confirmar a Exclusão de Múltiplos Arquivos +Você tem certeza que você quer apagar '{0}'? +Você tem certeza que você quer apagar a pasta '{0}' e todo o conteúdo dela? +Você tem certeza que você quer apagar estes {0} itens? +Apagando... +Erro ao Apagar o Arquivo ou Pasta +O sistema não pode mover um arquivo com caminho longo para o Recycle Bin +6300 +Criar Pasta +Criar Arquivo +Nome da pasta: +Nome do Arquivo: +Nova Pasta +Novo Arquivo +Erro ao Criar a Pasta +Erro ao Criar o Arquivo +6400 +Comentário +&Comentário: +Selecionar +Desmarcar +Máscara: +6600 +Propriedades +Histórico das Pastas +Mensagens de diagnóstico +Mensagem +7100 +Computador +Rede +Documentos +Sistema +7200 +Adicionar +Extrair +Testar +Copiar +Mover +Apagar +Info +7300 +Dividir Arquivo +&Dividir para: +Dividir em &volumes, bytes: +Dividindo... +Confirmar a Divisão +Você tem certeza que você quer dividir o arquivo em {0} volumes? +O tamanho do volume deve ser menor do que o tamanho do arquivo original +Tamanho do volume incorreto +Tamanho do volume especificado: {0} bytes.\nVocê tem certeza que você quer dividir o arquivo compactado em tais volumes? +7400 +Combinar Arquivos +&Combinar em: +Combinando... +Selecionar só a primeira parte do arquivo dividido +Não pôde detectar o arquivo como parte do arquivo dividido +Não pôde achar mais do que uma parte do arquivo dividido +7500 +Calculando checksum... +Informação do checksum +Checksum do CRC pros dados: +Checksum do CRC pros dados e nomes: +7600 +Benchmark +Uso da memória: +Comprimindo +Descomprimindo +Avaliação +Total da Avaliação +Atual +Resultando +Uso da CPU +Avaliação / Uso +Passos: +7700 +Link +Link +Link de: +Link para: +7710 +Tipo de Link +Link Rígido +Link Simbólico do Arquivo +Link Simbólico do Diretório +Junção do Diretório diff --git a/Utils/7-Zip/Lang/pt.txt b/Utils/7-Zip/Lang/pt.txt new file mode 100644 index 000000000..6a378478b --- /dev/null +++ b/Utils/7-Zip/Lang/pt.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Carlos Macao +; : João Alves +; : João Frade (100 NOME TR) +; 4.46 : Rui Costa +; 9.17 : Sérgio Marques +; 15.00 : Rui Aguiar +; +; +; +; +; +0 +7-Zip +Portuguese Portugal +Português +401 +OK +Cancelar + + + +&Sim +&Não +&Fechar +Ajuda + +&Continuar +440 +Sim p/ &Todos +Não p/ T&odos +Parar +Reiniciar +&Segundo plano +P&rimeiro plano +&Pausar +Em pausa +Quer mesmo cancelar? +500 +&Ficheiro +&Editar +&Ver +F&avoritos +Ferramen&tas +&Ajuda +540 +&Abrir +Abrir &dentro +Abrir &fora +&Ver +&Editar +Mudar& o nome +&Copiar para... +&Mover para... +&Eliminar +&Separar ficheiro... +Com&binar ficheiros... +P&ropriedades +Come&ntário +Calcular o checksum +Diff +Criar pasta +Criar ficheiro +&Sair +Link +&Alternar Fluxo +600 +Seleccionar &Tudo +Desmarcar tudo +&Inverter selecção +Seleccionar... +Desmarcar... +Seleccionar por tipo +Desmarcar por tipo +700 +Ícones &grandes +Ícones &pequenos +&Lista +&Detalhes +730 +Sem ordem +Vista plana +&2 painéis +&Barras de ferramentas +Abrir pasta root +Subir um nível +Histórico de pastas... +&Actualizar +Auto Actualizar +750 +Barra de ferramentas do arquivo +Barra de ferramentas pré-definida +Botões grandes +Mostrar a legenda dos botões +800 +&Adicionar a pasta aos favoritos como +Marcador +900 +&Opções... +&Desempenho +960 +&Conteúdo... +&Acerca do 7-Zip... +1003 +Caminho +Nome +Extensão +pasta +Tamanho +Tamanho comprimido +Atributos +Criado +Acedido +Modificado +sólido +Comentado +Encriptado +Separar antes +Separar depois +Dicionário + +Tipo +Anti +Método +SO anfitrião +Sistema de ficheiros +Utilizador +Grupo +Bloco +Comentário +Posição +Prefixo do destino +pastas +ficheiros +Versão +Volume +Multivolume +Não definido +Ligações +Blocos +Volumes + +64-bit +Big-endian +CPU +Tamanho físico +Tamanho dos cabeçalhos +Soma de verificação +Características +Endereço virtual +ID +Abreviatura +Criador da aplicação +Tamanho do sector +Modo +Ligação +Erro +Tamanho total +Espaço livre +Tamanho do sector +Etiqueta +Nome local +Fornecedor +Segurança NT +Alternar Fluxo +Aux +Excluído +É Árvore + + +Tipo de Erro +Erros +Erros +Avisos +Aviso +Fluxo +Alternar Fluxo +Alternate Tamanho de Fluxos +Tamanho Virtual +Tamanho Descompactado +Tamanho Físico Total +Índice de Volume +SubTipo +Breve Comentário +Página de Código + + + +Tamanho Tail +Tamanho Stub Incorporado +Link +Link do Disco Rígido +iNode + +Só de leitura +2100 +Opções +Idioma +Idioma: +Editor +&Editor: +&Diff: +2200 +Sistema +Associar o 7-Zip com: +Todos os utilizadores +2301 +Integrar o 7-Zip no menu de contexto +Menu de contexto em cascata +Itens do menu de contexto: +Icons no menu de contexto +2320 + + +Abrir arquivo +Extrair ficheiros... +Adicionar ao arquivo... +Testar arquivo +Extrair para aqui +Extrair para {0} +Adicionar a {0} +Comprimir e enviar por e-mail... +Comprimir para {0} e enviar por e-mail +2400 +pastas +&Pasta de trabalho +Pasta &temporária +&Actual +&Especificada: +Utilizar só para discos amovíveis +Especifique a pasta para os ficheiros temporários. +2500 +Definições +Mostrar item ".." +Mostrar os ícones reais dos ficheiros +Mostrar o menu do sistema +Selecção de linha &completa +Mostrar as linhas da &grelha +Clique uma vez para abrir um item +Modo de seleçção &alternativo +Utilizar páginas de &memória grandes +2900 +Acerca do 7-Zip +O 7-Zip é um programa gratuito.\n\nO 7-Zip foi traduzido por: Rui Aguiar\n\trui_a_aguiar@hotmail.com +3000 +O sistema não consegue alocar a memória necessária +Não existem erros +{0} objecto(s) seleccionado(s) +Não é possível criar a pasta '{0}' +Este tipo de arquivo não permite actualizações. +Não é possível abrir o ficheiro '{0}' como arquivo +Não é possível abrir o arquivo encriptado '{0}'. Palavra-passe errada? +O arquivo não é suportado +Já existe o ficheiro {0} +O ficheiro '{0}' foi modificado.\nQuer actualizá-lo no arquivo? +Não foi possível actualizar o ficheiro\n'{0}' +Não foi possível iniciar o editor. +O ficheiro parece ser um vírus (o nome do ficheiro contém muitos espaços em branco). +A operação não pode ser invocada a partir de uma pasta com uma longa localização. +Tem que seleccionar um ficheiro +Tem que seleccionar um ou mais ficheiros +Demasiados itens +Não é possível abrir o ficheiro como arquivo {0} +Ficheiro aberto como arquivo {0} +Arquivo aberto com offset +3300 +A extrair... +A comprimir +A testar... +A abrir... +A pesquisar... +Removendo +3320 +A adicionar... +A actualizar... +A analisar... +Replicando +A recomprimir... +A ignorar... +A eliminar +Criando cabeçalho +3400 +Extrair +E&xtrair para: +Especifique o destino para os ficheiros extraídos. +3410 +Modo de nome de pasta +Nome de pastas completo +Sem nome de pastas +Caminhos absolutos +Caminhos relativos +3420 +Modo de sobrescrever +Perguntar antes de substituir +Sem confirmação +Ignorar ficheiros existentes +Mudar o nome automaticamente. +Mudar o nome automomaticamente os ficheiros existentes +3430 +Eliminar a duplicação da pasta de raiz +Restaurar segurança de ficheiros +3500 +Confirmar substituição de ficheiro +A pasta já possui um ficheiro com o mesmo nome. +Deseja substituir o ficheiro existente +por este? +{0} bytes +Mudar o nome a&utomaticamente +3700 +O método de compressão é inválido para '{0}'. +Erro de dados em '{0}'. O arquivo está danificado. +CRC falhou em '{0}'. O arquivo está danificado. +Erro de dados no ficheiro encriptado '{0}'. Palavra-passe errada? +CRC falhou no ficheiro encriptado '{0}'. Palavra-passe errada? +3710 +Palavra-passe errada? +3721 +Método de compressão não suportado +Erro nos dados +O CRC falhou +Dados indisponíveis +Fim inesperado nos dados +Existem alguns dados após o final dos dados de carga útil +Não é um arquivo +Erro nos Cabeçalhos +Palavra-passe errada +3763 +Início de arquivo indisponível +Início de arquivo não confirmado + + + +Funcionalidade não suportada +3800 +Insira a palavra-passe +Introduza a palavra-passe: +Reintroduza a palavra-passe: +&Mostrar palavra-passe +As palavras-passe não coincidem +Para a palavra-passe, utilize apenas letras inglesas, números e os caracteres especiais (!, #, $, ...) +A palavra-passe é muito comprida +Palavra-passe +3900 +Tempo decorrido: +Tempo restante: +Tamanho: +Velocidade: +Processado: +Rácio de compressão: +Erros: +Arquivos: +4000 +Adicionar ao arquivo +&Arquivo: +&Modo de actualização: +&Formato do arquivo: +Níve&l de compressão: +Método de &compressão: +Tamanho do &dicionário: +&Tamanho da &palavra: +Tamanho dos blocos sólidos: +Nº de processos do CPU: +&Parâmetros: +Opções +Criar arquivo SF&X +Comprimir ficheiros partilhados +Encriptação +Método de encriptação: +Encriptar &nomes de ficheiros +Utilização de memória para compressão: +Utilização de memória para descompressão: +Excluir ficheiros após compressão +4040 +Armazenar links simbólicos +Armazenar links do disco rígido +Armazenar fluxo de dados alternados +Armazenar segurança de ficheiros +4050 +Guardar +Muito rápido +Rápido +Normal +Máxima +Ultra +4060 +Adicionar e substituir ficheiros +Actualizar e adicionar ficheiros +Actualizar ficheiros +Sincronizar ficheiros +4070 +Procurar +Todos os ficheiros +Não sólido +sólido +6000 +Copiar +Mover +Copiar para: +Mover para: +A copiar... +A mover... +A mudar o nome... +Seleccione a pasta de destino. +Operação não suportada. +Erro ao mudar o nome do ficheiro ou pasta +Confirmar a cópia dos ficheiros +Quer mesmo copiar os ficheiros para o arquivo? +6100 +Confirmar a eliminação do ficheiro +Confirmar a eliminação da pasta +Confirmar a eliminação de múltiplos ficheiros +Quer mesmo eliminar o '{0}'? +Quer mesmo eliminar a pasta '{0}' e todo o seu conteúdo? +Quer mesmo eliminar os itens {0}? +A eliminar... +Erro ao eliminar o ficheiro ou pasta +O sistema não consegue mover para a reciclagem um ficheiro com uma localização longa +6300 +Criar pasta +Criar ficheiro +Nome da pasta: +Nome do ficheiro: +Nova Pasta +Novo ficheiro +Erro ao criar a pasta +Erro ao criar ficheiro +6400 +Comentário +&Comentário: +Seleccionar +Desseleccionar +Máscara: +6600 +Propriedades +Histórico de pastas +Mensagens de diagnóstico +Mensagem +7100 +Computador +Rede +Documentos +Sistema +7200 +Adicionar +Extrair +Testar +Copiar +Mover +Eliminar +Info +7300 +Separar ficheiro +&Separar para: +Separar por &volumes, bytes: +A separar... +Confirmar separação +Quer mesmo separar o ficheiro em {0} volumes? +O tamanho do volume tem de ser inferior ao tamanho do ficheiro original +Tamanho do volume incorrecto +Tamanho do volume especificado: {0} bytes.\nQuer mesmo separar o arquivo nestes volumes? +7400 +Combinar ficheiros +&Combinar para: +A combinar... +Seleccione apenas o primeiro ficheiro +Não foi possivel apagar o ficheiro como parte do ficheiro dividido +Não foi possível encontrar mais do que uma parte do ficheiro dividido +7500 +A calcular o checksum... +Informações do checksum +CRC checksum para dados: +CRC checksum para dados e nome: +7600 +Desempenho +Utilização de Memória: +A comprimir +A descomprimir +Desempenho +Desempenho Total +Actual +Resultante +Utilização CPU +Desemp. / Utiliza. +Passagens: +7700 +Link +Link +Link de: +Link para: +7710 +Link Tipo +Link do Disco Rígido +Link do Ficheiro Simbólico +Link do Directório Simbólico +Directório de Junção \ No newline at end of file diff --git a/Utils/7-Zip/Lang/ro.txt b/Utils/7-Zip/Lang/ro.txt new file mode 100644 index 000000000..0498a8e95 --- /dev/null +++ b/Utils/7-Zip/Lang/ro.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.59 : Lucian Nan : http://www.prizeeinternational.com +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Romanian +Română +401 +Bine +Anulare + + + +&Da +&Nu +&Închide +Ajutor + +&Continuă +440 +Da, pe &toate +N&ici unul +Opreşte +Restartează +În &fundal +La &suprafaţă +&Pauză +În pauză +Eşti sigur că vrei să anulezi? +500 +&Fişier +&Editează +&Vizualizează +F&avorite +&Unelte +&Ajutor +540 +&Deschide +Deschide î&n +Deschide în &afară +&Vizualizeză +&Editează +&Redenumeşte +&Copiază la... +&Mută la... +Şter&ge +Împarte &fişierul... +&Uneşte fişierele... +&Proprietăţi +Comen&tariu +Calculează suma de verificare + +Crează director +Crează fişier +&Ieşire +600 +&Selectează tot +&Deselectează tot +&Inversează selecţia +Selectează... +Deselectează... +Selectează după tip +Deselectează după tip +700 +Iconiţe m&ari +Iconiţe m&ici +&Listă +&Detalii +730 +Nesortat +Vedere plană +&2 panouri +Bare de &unelte +Deschide directorul rădăcină +Un nivel mai sus +Istoria directoarelor... +&Împrospătează +750 +Bara de arhivare +Bara de unelte standard +Butoane mari +Arată textul butoanelor +800 +&Adaugă directorul în Favorite ca +Semn de carte +900 +&Opţiuni... +&Banc de încercare +960 +&Conţinut... +&Despre 7-Zip... +1003 +Calea +Nume +Extensie +Director +Mărime +Mărimea pachetului +Atribute +Creată +Accesată +Modificată +Solidă +Comentat +Criptat +Împarte înainte +Împarte după +Dicţionar +CRC +Tip +Anti +Metoda +SO gazdă +Fişier de sistem +Utilizator +Grup +Blochează +Comentariu +Poziţia +Prefixul destinaţiei +Directoare +Fişiere +Versiunea +Volum +Multivolume +Ofset +Legături +Blocuri +Volume + +64-bit +Big-endian +CPU +Mărime fizică +Mărimea antetelor +Checksum +Caracteristici +Adresa virtuală + + + + + + +Eroare +Mărimea totală +Spaţiu liber +Mărimea grupului +Etichetă +Nume local +Distribuitor +2100 +Opţiuni +Limba +Limba: +Editor +&Editor: + +2200 +Sistem +Asociază 7-Zip cu: +2301 +Integrează 7-Zip în contextul meniului shell +Contextul meniului în cascadă +Obiectele meniului: +2320 + + +Deschide arhiva +Dezarhivează fişierele... +Adaugă într-o arhivă... +Testează arhiva +Dezarhivează aici +Dezarhivează în {0} +Adaugă în {0} +Arhivează şi trimite email... +Arhivează în {0} şi trimite email +2400 +Directoare +&Directorul de lucru +Directorul &tempotar al sistemului +&Actual +&Specificat: +Utilizează numai pentru discurile detaşabile +Specifică o destinaţie pentru arhivele temporare. +2500 +Setări +Arată ".." obiect +Arată iconiţele reale ale fişierului +Arată meniul sistemului +Selectează &tot rândul +Arată liniile de ghidare + +Mod de selectare &alternativă +Utilizează pagini &mari de memorie +2900 +Despre 7-Zip +7-Zip este un program gratuit. Oricum, poţi contribui la dezvoltarea 7-Zip înregistrându-te. +3000 +Sistemul nu poate aloca memoria necesară +Nu sunt erori +{0} obiect(e) selectat(e) +Nu pot crea directorul '{0}' +Operaţiile de actualizare nu sunt suportate pentru această arhivă. +Nu pot deschide fişierul '{0}' ca arhivă +Nu pot deschide arhiva criptată '{0}'. Parola greşită? +Tip de arhivă nesuportat +Fișierul {0} există deja +Fişierul '{0}' a fost modificat.\nDoreşti să îl actualizez în arhivă? +Nu pot actualiza fişierul\n'{0}' +Nu pot porni editorul. +The file looks like a virus (the file name contains long spaces in name). +Operația nu poate fi apelată dintr-un director cu cale lungă. +Trebuie să alegi un fișier +Trebuie să alegi unul sau mai multe fișiere +Prea multe obiecte +3300 +Dezarhivez +Arhivare +Testez +Deschid... +Citesc... +3400 +Dezarhivează +Dezarhivează în: +Specifică o destinaţie pentru fişierele dezarhivate. +3410 +Modul destinaţie +Numele întreg al destinaţiei +Fără locaţie +3420 +Modul de înlocuire +Întreabă înainte de a înlocui +Înlocuieşte fară a întreba +Sări peste fişierele existente +Auto redenumire +Auto redenumeşte fişierele existente +3500 +Aprobă înlocuirea fişierului +Fişierul există deja în directorul destinaţie. +Doriţi să înlocuiţi fişierul existent +cu acesta? +{0} octeţi +A&uto redenumire +3700 +Metodă de arhivare nesuportată pentru '{0}'. +Eroare de date la '{0}'. Fişierul este corupt. +Verificarea CRC a eşuat pentru '{0}'. Fişierul este corupt. +Erori de date la fişierul criptat '{0}'. Parolă greşită? +Verificarea CRC a eşuat pentru fişierul criptat '{0}'. Parolă greşită? +3800 +Introdu parola +Introdu parola: +Reintrodu parola: +&Arată parola +Parolele nu sunt identice +Utilizaţi numai litere, cifre şi caracterele speciale (!, #, $, ...) pentru parolă +Parola este prea lungă +Parola +3900 +Timp trecut: +Timp rămas: +Mărimea: +Viteza: +Procesat: +Rata de comprimare: +Erori: +Arhive: +4000 +Adaugă într-o arhivă +&Arhivează: +Modul de a&ctualizare: +&Formatul arhivei: +&Nivel de arhivare: +&Metoda de arhivare: +Mărimea &dicţionarului: +Mărimea &cuvântului: +Mărimea blocului solid: +Numărul de procesoare utilizate: +&Parametri: +Opţiuni +Crează arhivă SF&X +Arhivează fişierele partajate +Criptare +Metoda de criptare: +Criptează &numele fişierului +Memorie utilizată pentru arhivare: +Memorie utilizată pentru dezarhivare: +4050 +Stochează +Imediată +Rapidă +Normală +Maximă +Ultra +4060 +Adaugă şi înlocuieşte fişierele +Actualizează şi adaugă fişierele +Actualizează fişierele existente +Sincronizează fişierele +4070 +Caută +Toate fişierele +NEsolid +Solid +6000 +Copiază +Mută +Copiază la: +Mută la: +Copiez... +Mut... +Redenumesc... +Alege directorul destinaţie. +Operaţia nu este suportată. +Eroare la redenumirea fişierului sau directorului +Aprobă copierea fişierului +Eşti sigur că vrei să copiezi fişierele în arhivă +6100 +Aprobă ştergerea fişierului +Aprobă ştergerea directorului +Aprobă ştergerea mai multor fişiere +Eşti sigur că vrei să ştergi '{0}'? +Eşti sigur că vrei să ştergi directorul '{0}' şi tot conţinutul lui? +Eşti sigur că vrei să ştergi aceste {0} obiecte? +Şterg... +Eroare la ştergerea fişierului sau directorului +Sistemul nu poate muta un fişier cu cale lungă la Coşul de gunoi +6300 +Crează director +Crează fişier +Numele directorului: +Numele fişierului: +Director nou +Fişier nou +Eroare la crearea directorului +Eroare la crearea fişierului +6400 +Comentariu +&Comentariu: +Selectează +Deselectează +Masca: +6600 +Proprietăţi +Istoria directoarelor +Mesaje de diagnosticare +Mesaj +7100 +Computer +Reţea +Documente +Sistem +7200 +Arhivează +Dezarhivează +Testează +Copiază +Mută +Şterge +Info +7300 +Împarte fişierul +Î&mparte în: +Împarte în &volume, octeţi: +Împart... +Confirmă împărţirea +Eşti sigur că vrei să imparţi arhiva în {0} volume (părţi)? +Dimensiunea volumului trebuie să fie mai mică decât dimensiunea fişierului original +Dimensiunea volumului este incorectă +Dimensiunea volumului specificat: {0} octeţi.\nEşti sigur că vrei să împarţi arhiva în mai multe volume (părţi)? +7400 +Uneşte fişierele +&Uneşte în: +Unesc... +Alege doar prima parte din fişierul împărțit +Nu pot detecta fișierul ca parte a fișierului împărțit +Nu găsesc mai mult de o parte din fișierul împărțit +7500 +Calculez suma de control... +Informaţii despre suma de control +Suma de control CRC pentru conţinut: +Suma de control CRC pentru conţinut şi nume: +7600 +Banc de încercare +Memorie utilizată: +Arhivez +Dezarhivez +Rata +Rata totală +Actual +Rezultate +Utilizarea procesorului +Rata / Utilizare +Trecute: diff --git a/Utils/7-Zip/Lang/ru.txt b/Utils/7-Zip/Lang/ru.txt new file mode 100644 index 000000000..7e5cf4960 --- /dev/null +++ b/Utils/7-Zip/Lang/ru.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.10 : 2015-10-31 : Igor Pavlov +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Russian +Русский +401 +OK +Отмена + + + +&Да +&Нет +&Закрыть +Помощь + +&Продолжить +440 +Да для &всех +Нет для в&сех +Стоп +Перезапуск +&Фоном +&На передний план +&Пауза +На паузе +Вы действительно хотите прервать операцию? +500 +&Файл +&Правка +&Вид +&Избранное +С&ервис +&Справка +540 +&Открыть +Открыть &внутри +Открыть снару&жи +Просмотр +&Редактировать +Переи&меновать +&Копировать в... +&Переместить в... +&Удалить +Ра&збить файл... +О&бъединить файлы... +Сво&йства +Комме&нтарий... +Контрольная сумма +Сравнить +&Создать Папку +Созд&ать Файл +В&ыход +Ссылка +&Альтернативные Потоки +600 +Выделить в&се +Убрать выделение +&Обратить в&ыделение +Выделить... +Убрать выделение... +Выделить по типу +Убрать выделение по типу +700 +&Крупные значки +&Мелкие значки +Спис&ок +&Таблица +730 +Без сортировки +Плоский режим +&2 Панели +&Панели инструментов +Открыть корневую папку +Переход на один уровень вверх +История папок... +О&бновить +Автообновление +750 +Панель кнопок архиватора +Стандартная панель кнопок +Большие кнопки +Надписи на кнопках +800 +Добавить папку в &избранное как +Закладка +900 +Настройки... +Тестирование производительности +960 +&Оглавление... +О &программе... +1003 +Путь +Имя +Расширение +Папка +Размер +Сжатый +Атрибуты +Создан +Открыт +Изменен +Непрерывный +Комментарий +Зашифрован +Разбит До +Разбит После +Словарь + +Тип +Анти +Метод +Система +Файловая Система +Пользователь +Группа +Блок +Комментарий +Позиция +Путь +Папок +Файлов +Версия +Том +Многотомный +Смещение +Ссылок +Блоков +Томов + + + +Процессор +Физический Размер +Размер Заголовков +Контрольная Сумма +Характеристики +Виртуальный Адрес + +Короткое Имя +Создатель +Размер Сектора +Режим +Символьная Ссылка +Ошибка +Емкость +Свободно +Размер кластера +Метка +Локальное имя +Провайдер +NT Безопасность +Альтернативный Поток + +Удаленный +Дерево + + +Тип Ошибки +Ошибки +Ошибки +Предупреждения +Предупреждение +Потоки +Альтернативные Потоки +Размер Альтернативных потоков +Виртуальный Размер +Распакованный Размер +Общий Физический Размер +Номер Тома +Подтип +Короткий Комментарий +Кодовая Страница + + + +Размер Остатка +Размер Встроенного Блока +Ссылка +Жесткая Ссылка +iNode + +Только для чтения +2100 +Настройки +Язык +Язык: +Редактор +&Редактор: +&Программа сравнения: +2200 +Система +Ассоциировать 7-Zip с файлами: +Все пользователи +2301 +Встроить 7-Zip в контекстное меню оболочки +Каскадное контекстное меню +Элементы контекстного меню: +Иконки в контекстном меню +2320 +<Папка> +<Архив> +Открыть архив +Распаковать +Добавить к архиву... +Тестировать +Распаковать здесь +Распаковать в {0} +Добавить к {0} +Сжать и отправить по email... +Сжать в {0} и отправить по email +2400 +Папки +&Рабочая папка +&Системная временная папка +&Текущая +&Задать: +Использовать только для сменных носителей +Укажите положение для временных архивов. +2500 +Настройки +Показывать элемент ".." +Показывать реальные иконки файлов +Показывать системное меню +Курсор на всю строку +Показывать разделители +Открывать одним щелчком +Альтернативный режим пометки +Использовать большие страницы памяти +2900 +О программе 7-Zip +7-Zip является свободно распространяемой программой. +3000 +Недостаточно свободной памяти +Ошибок не найдено +Выделено объектов: {0} +Не удалось создать папку '{0}' +Операции изменения не поддерживаются для этого архива. +Не удалось открыть файл '{0}' как архив +Не удалось открыть зашифрованный архив '{0}'. Неверный пароль? +Неподдерживаемый тип архива +Файл {0} уже существует +Файл '{0}' был изменен.\nВы хотите обновить его в архиве? +Не удалось обновить файл\n'{0}' +Не удалось запустить редактор +Файл похож на вирус (имя файла содержит длинную последовательность пробелов). +Операция не может быть исполнена из папки, которая имеет длинный путь. +Вы должны выделить один файл +Вы должны выделить один или несколько файлов +Слишком много элементов +Не удалось открыть файл как {0} архив +Файл открыт как {0} архив +Архив открыт со смещением +3300 +Распаковка +Упаковка +Тестирование +Открытие... +Сканирование... +Удаление +3320 +Добавление +Обновление +Анализ +Копирование +Перепаковка +Пропуск +Удаление +Создание заголовков +3400 +Извлечь +&Распаковать в: +Укажите положение для извлекаемых файлов. +3410 +Пути к файлам: +Полные пути +Без путей +Абсолютные пути +Относительные пути +3420 +Перезапись: +С подтверждением +Без подтверждения +Пропускать +Переименовать автоматически +Переименовать существующие +3430 +Устранить дублирование корневой папки +Устанавливать права доступа +3500 +Подтверждение замены файла +Папка уже содержит обрабатываемый файл. +Заменить существующий файл +следующим файлом? +{0} байтов +Переименовать автом. +3700 +Неподдерживаемый метод сжатия для файла '{0}'. +Ошибка в данных в '{0}'. Файл испорчен. +Ошибка CRC в '{0}'. Файл испорчен. +Ошибка в данных зашифрованного файла '{0}'. Неверный пароль? +Ошибка CRC для зашифрованного файла '{0}'. Неверный пароль? +3710 +Неверный пароль? +3721 +Неподдерживаемый метод сжатия +Ошибка в данных +Ошибка CRC +Недоступные данные +Неожиданный конец данных +Есть данные после конца блока полезных данных +Не является архивом +Ошибка в заголовках +Неверный пароль +3763 +Недоступно начало архива +Неподтвержденное начало архива + + + +Неподдерживаемая функциональность +3800 +Ввод пароля +&Введите пароль: +Повторите пароль: +&Показать пароль +Пароли не совпадают +Для пароля используйте только символы латинского алфавита, цифры и специальные символы (!, #, $, ...) +Пароль слишком длинный +&Пароль +3900 +Прошло: +Осталось: +Всего: +Скорость: +Размер: +Степень сжатия: +Ошибок: +Архивов: +4000 +Добавить к архиву +&Архив: +&Режим изменения: +&Формат архива: +&Уровень сжатия: +&Метод сжатия: +Размер &словаря: +Размер с&лова: +Размер блока: +Число потоков: +&Параметры: +&Опции +Создать SF&X-архив +Сжимать открытые для записи файлы +Шифрование +Метод шифрования: +&Шифровать имена файлов +Объем памяти для упаковки: +Объем памяти для распаковки: +Удалять файлы после сжатия +4040 +Сохранять символьные ссылки +Сохранять жесткие ссылки +Сохранять альтернативные потоки +Сохранять права доступа +4050 +Без сжатия +Скоростной +Быстрый +Нормальный +Максимальный +Ультра +4060 +Добавить и заменить +Обновить и добавить +Обновить +Синхронизировать +4070 +Пролистать +Все файлы +По размеру файла +Непрерывный +6000 +Копировать +Переместить +Копировать в: +Переместить в: +Копирование... +Перемещение... +Переименование... +Укажите папку. +Операция не поддерживается для этой папки. +Ошибка при переименовании файла или папки +Подтверждение копирования файлов +Вы действительно хотите скопировать эти файлы в архив +6100 +Подтверждение удаления файла +Подтверждение удаления папки +Подтверждение удаления группы файлов +Вы действительно хотите удалить "{0}"? +Вы действительно хотите удалить папку "{0}" и все ее содержимое? +Вы действительно хотите удалить эти объекты ({0} шт.)? +Удаление... +Ошибка при удалении файла или папки +Система не поддерживает операцию удаления файлов с длинными путями в корзину +6300 +Создать папку +Создать файл +Имя папки: +Имя файла: +Новая папка +Новый файл +Ошибка при создании папки +Ошибка при создании файла +6400 +Комментарий +&Комментарий: +Выделить +Убрать выделение +Маска: +6600 +Свойства +История папок +Сообщения +Сообщение +7100 +Компьютер +Сеть +Документы +Система +7200 +Добавить +Извлечь +Тестировать +Копировать +Переместить +Удалить +Информация +7300 +Разбить файл +&Разбить в: +Разбить на &тома размером (в байтах): +Разбиение... +Подтверждение разбиения +Вы действительно хотите разбить файл на {0} частей? +Размер тома должен быть меньше размера исходного файла +Ошибка в поле для задания размера томов +Установленный размер тома: {0} байтов.\nВы действительно хотите разбить архив на такие тома? +7400 +Объединить файлы +&Объединить в: +Объединение... +Необходимо выделить только первую часть разбитого файла +Не удалось распознать разбитый файл +Не удалось найти более одной части разбитого файла +7500 +Вычисление контрольной суммы... +Контрольная сумма +Контрольная сумма CRC для данных: +Контрольная сумма CRC для данных и имен: +7600 +Тестирование производительности +Объем памяти: +Упаковка +Распаковка +Рейтинг +Общий рейтинг +Текущий +Итоговый +Нагрузка +Рейтинг / Нагр. +Проходов: +7700 +Ссылка +Связать +Источник: +Цель: +7710 +Тип ссылки +Жесткая ссылка +Символьная ссылка (Файл) +Символьная ссылка (Папка) +Точка соединения (Junction) diff --git a/Utils/7-Zip/Lang/sa.txt b/Utils/7-Zip/Lang/sa.txt new file mode 100644 index 000000000..c919de2e0 --- /dev/null +++ b/Utils/7-Zip/Lang/sa.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Vinayy Sharrma, अनुवादं विनय शर्मा संस्कृतम् गर्व कुरु, जय हिन्दं ! जय संस्कृतम्! एतत् साधारण अनुवादं अस्ति +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Sanskrit, Indian, हिन्दुस्तानं +संस्कृत +401 +ठीक अस्ति +रद्द + + + +&हाँ +&ना +&बंद कुरु +मददं + +&जारी रखे +440 +&सर्वस्य हाँ +&सर्वस्य ना +रूको +पुनः शुरु कुरु +&पॄष्ठ्भूमि +&अग्रभूमि(डेस्क्टोप) +&विश्राम +विश्रामितं +त्वम रद्द करना चाहते हो. तुम्हें यकीन अस्ति क्या? +500 +&फ़ाइलम् +&संपादनम् +&दर्शनम् +&मनपसंदम् +&औजारम् +&मददम् +540 +&अनावृतं +&अंदर अनावृतं +&बहिः अनावृतं +&दृश्यम् +&संपादनम् +&पुन: नामकरणम् +&में नकल बनाये... +&में ले जायें... +&मिटायें +&फ़ाइलस्य विभाजनं कुरु... +&फ़ाइलस्य संयोजनं कुरु... +&संपत्तियाँ वा गुणं +&टिप्पणी +&जाँच योगस्य गणनां कुरु +&अन्तर +&फोल्डरं निर्माणम् कुरु +&फ़ाइलं निर्माणम् कुरु +&निर्गमन +600 +&सर्व चयनं कुरु +&सर्व अचयनितं कुरु +&चयन उलटा कुरु +चयनं कुरु... +अचयनं कुरु... +प्रकार द्वारा चयनम् +प्रकार द्वारा अचयनम् +700 +विशाल प्रतीकं +लघु प्रतीकं +&सूची +&वर्णनं +730 +अवितरितम् +चौड़ा दृश्य +&२ फ़लक +&औजार पट्टीयाँ +मूल फोल्डरं अनावृतं +एक स्तर उर्ध्व चढ़े +फ़ोल्डरो का इतिहास... +&ताजा कुरु +750 +संग्रहम् उपकरणपट्टी +मानक औजार पट्टी +विशाल खटके(बटन) +खटके(बटन) के शब्द दिखायें +800 +&फोल्डरं मनपसंद में ऎसे जोड़े... +पुस्तचिन्हम् +900 +&विकल्पम्... +&बेञ्चमार्कम्(प्रामाणिक तुलना) +960 +&सामग्री... +7-जिप विषय... +1003 +मार्ग +नाम +विस्तारं +फोल्डरं +आकारं +कुल आकारं +विशेषता वा गुणधर्म +सर्जितं +चालितम् +परिवर्धितं +ठोस +टिप्पणी +गुप्तिकृतम् +के पूर्व विभाजनं(टुकडे) कुरु +के पश्चात विभाजनं(टुकडे) कुरु +शब्दकोशं +सीआरसी +प्रकारं +विरोधी +पद्धति +ओपरेटिंग सिस्टम +फ़ाइलं प्रणाली +प्रयोगकर्ता +समूहम् +रोक वा टुकड़े +प्रतिक्रिया +स्थानं +मार्ग प्रत्ययं +फोल्डर्स +फाइल्स +संस्करणम् +जत्था +अनेक जत्थे +ओफसेट +कडियाँ +टुकड़े +जत्थे + +64-बिट +विशाल-एन्डियन +सीपीयू +भौतिक आकारं +शीर्षकाः आकारं +जाँचयोग +चरित्रताऎं +आभासी पता +आईडी +संक्षिप्तः नामं +सर्जक अनुप्रयोगं +सेक्टरस्य आकारं +स्थिति +कड़ी +त्रुटि +कुल आकारं +स्वतन्त्र रिक्तस्थानं(खाली जगह) +क्लस्टर(समूह) आकारं +ध्यानाकर्षकं(लेबलम्) +स्थानिय नामम् +प्रदायकम् +2100 +विकल्पम् +भाषा +भाषा: +संपादकम् +&संपादक: +&अन्तर: +2200 +प्रणाली वा तंत्रम् +संबधित कुरु 7-जिप के साथ: +2301 +7-जिपस्य शेल(कवच) प्रसंग मेनु में जोडें +सोपानीकृत(केस्केडेड) प्रसंग मेनु +प्रसंग(कोन्टेक्स्ट) मेनु वस्तुएँ: +2320 +<फोल्डरं> +<संग्रहम्(आर्चिव)> +संग्रहम् अनावृतं +फ़ाइल्स बहिः निकाले... +संग्रहम् में जोड़े... +संग्रहमस्य जाँच कुरु +यहीं बहिः निकाले +{0} में बहिः निकाले +{0} में जोड़े +संकुचनं एवम् ईमेलम् कुरु... +{0} में दबायें एवम् ईमेलं कुरु +2400 +फ़ोल्डर्स +&कार्यरत फोल्डरं +&प्रणालयास्य अस्थायी(टेम्पररी) फोल्डरं +&चालू +&निर्दिष्ट: +मात्र हटाने योग्य(रिमूवेबल) ड्राईवाय ही प्रयोगं कुरु +अस्थायी संग्रहम् फाइलाय स्थानं निर्दिष्टं कुरु(बतायें). +2500 +व्यवस्थाएँ +दिखाओ ".."वस्तु +वास्तविक फ़ाइल प्रतिमायें दिखाओ +तंत्रस्य मेनु दिखाओ +&पूर्ण पन्क्तिस्य चयनं +&ग्रिड(जाल) रेखा दिखाओ +वस्तु अनावृताय एकं ही(सिंगल)-क्लिकम् +&वैकल्पिक चयनं स्थिति +&विशाल् स्मृति पृष्ठस्य प्रयोगं कुरु +2900 +7-जिप विषय +7-जिपं एतत निःशुल्क सॉफ़्टवेयर अस्ति. तथापि, भवान् पंजीकृतं(रजिस्टर्ड) होकर७-ज़िपस्य विकास में सहयोग कर सकते अस्ति. +3000 +तंत्रम् आवश्यक मात्रा में मेमोरी(स्मृति) वितरितं ना कर सकता अस्ति +इनमे कोई भी त्रुटि ना अस्ति +{0} चयनित वस्तु(एँ) +'{0}' फोल्डरं सर्जित ना कर सकता +एतत् संग्रहमस्य अद्यतनीकृत संचालन समर्थित ना अस्ति. +'{0}' फाइल को संग्रहम् के रूप में ना खोल सकता +'{0}' गुप्तिकृतम् संग्रहम् को ना खोल सकता. मिथ्या कूटशब्दम्? +असमर्थित संग्रहम् प्रकारं +फाइलं {0} पहले से मौजूद अस्ति +'{0}' फ़ाइल परिवर्धितं हुई अस्ति.\nक्या तुम संग्रहम् में इसे अद्यतनीकृतं करना चाहते हो? +फ़ाइल को अद्यतनीकृतं ना कर सकता\n'{0}' +संपादक को शुरू ना कर सकता. +यह फाइलं एक विषाणु(वायरस) जैसी लगती अस्ति(फाइलं नाम लंबी खाली जगह नाम में रखता अस्ति). +जिस फोल्डरं का लंबा मार्ग अस्ति उससे सञ्चालनं क्रिया ना बुलाई जा सकती. +तुम्हे एक फाइलं का चयन तो करना ही होगा +तुम्हे एक वा अधिक फाइलों को चुनना ही होगा +अत्यधिक वस्तुएँ +3300 +बहिः निकाल रहा अस्ति +संकुचनं कर रहा अस्ति +परीक्षणम् +अनावृतं कर रहा अस्ति... +तलाशी(स्कैनिंग) कर रहा अस्ति... +3400 +बहिः निकाले +&बहिः निकाले: +बहिः निकाली हुई फ़ाइलों के लिये स्थानं निर्दिष्टं कुरु. +3410 +मार्ग स्थिति +पूर्ण मार्गनामं +कोई मार्ग नामं ना अस्ति +3420 +अधिलेखन रीत +अधिलेखन करने से पहले पृच्छाः +बिना पृच्छाः अधिलेखनं(पुराने को मिटाना) कुरु +पहले से मौजूद फ़ाइलस को छोड़े +स्वचालित पुन: नामकरणं +पहले से मौजूद फ़ाइलस का स्वचालितं(ओटोमेटिक) पुन: नामकरणं कुरु +3500 +फ़ाइलं प्रतिस्थापनं को पक्का कुरु +गन्तव्य फोल्डरं में पहले से ही प्रक्रिया हुई फ़ाइलं अस्ति. +क्या भवान् पहले से मौजूद फ़ाइल को बदलना पसंद करेंगे? +इसके साथ? +{0} बाइट्स +स्वचालित पुन: नामकरणम् +3700 +'{0}' के लिए असहायक दबाने की पद्धति. +डेटा त्रुटि'{0}' में. फ़ाइलं टूटी हुई अस्ति. +'{0}' में सीआरसी असफल. फ़ाइलं टूटी हुई अस्ति. +'{0}' गुप्तिकृतम्(एनक्रिप्टेड) फाइलं में डेटा त्रुटि. मिथ्या कूटशब्दम्? +'{0}'गुप्तिकृतम्(एनक्रिप्टेड) फाइलं में सीआरसी असफल. मिथ्या कूटशब्दम्? +3800 +कूटशब्दम्(पासवर्ड) डाले +कूटशब्दम्(पासवर्ड) डाले: +कूटशब्दम् पुनः डाले: +&कूटशब्दम्(पासवर्ड) दिखाओ +कूटशब्दम् सहेजे हुए से अलग अस्ति +कूटशब्दम् के लिये मात्र इंग्लिश वर्णमाला, अंकाः और विशेष अक्षरों (!, #, $, ...) का ही उपयोग कुरु +कूटशब्दम् अत्यधिक विशाल अस्ति +कूटशब्दम्(पासवर्ड) +3900 +व्यतीत समय: +शेष बचा समय: +कुल आकारं: +गति: +प्रक्रिया किया हुआ: +दबाने(आकारं छोटा करने) का अनुपातं: +त्रुटियाँ: +संग्रहम्: +4000 +संग्रहम् में जोड़े +&संग्रहम्: +&अद्यतनीकरणं स्थिति(मोड): +संग्रहम् &ढाँचा: +&संकुचनम् स्तर: +&संकुचनम् विधि: +&शब्दकोशम् आकारं: +&शब्द आकारं: +ठोस टुकडे का आकारं: +सीपीयू सूत्र संख्या: +&परिमाप: +विकल्प +&एसएफ़एक्स(SFX) संग्रहम् निर्माणम् कुरु +साझी फाइलें संकुचितं कुरु +गुप्तिकरणम् +गुप्तिकरणम् पद्धति: +फ़ाइल &नाम गुप्तिकरणम् कुरु +संकुचनस्य स्मृति प्रयोग: +प्रसारणस्य स्मृति प्रयोग: +4050 +भण्डारणम् +सर्वाधिक तेज +तेज +साधारणम् +अधिकतम +अत्यन्त +4060 +फ़ाइलें जोड़े एवम् प्रतिस्थापित कुरु +फ़ाइले अद्यतनीकृतं कुरु एवम् जोड़े +अवस्थितं फ़ाइलें ताजा कुरु +फाइलें समक्रमण(सिंक्रोनाईज़) कुरु +4070 +ब्राउजम् वा घूमे +सर्वाः फ़ाइलें +अ-ठोसं +ठोसं +6000 +नकल +ले जायें +में नकल: +में ले जायें: +नकल... +ले जा रहा अस्ति... +पुन: नामकरणं... +गन्तव्य फोल्डरं चयनित कुरु. +एतत् फोल्डरं के लिये यह सञ्चालनं क्रिया समर्थितं ना अस्ति. +फ़ाइल वा फोल्डरं के पुन: नामकरणं में त्रुटि +फ़ाइल की नकल करना पक्का कुरु +तुम संग्रहम् में फाइलं की प्रतिलिपि करना चाहते हो क्या तुम्हे यकीन अस्ति +6100 +फ़ाइल मिटाये यह पक्का कुरु +फोल्डरं मिटायें पक्का कुरु +अनेक फ़ाइल मिटायें पक्का कुरु +क्या तुम्हे यकीन अस्ति कि तुम मिटाना चाहते हो '{0}'? +क्या तुम्हे यकीन अस्ति कि तुम फोल्डरं मिटाना चाहते हो '{0}' और इसकी सर्वाः सामग्री भी? +क्या तुम्हे यकीन अस्ति कि तुम मिटाना चाहते हो इन {0} वस्तुओं को? +मिटा रहा अस्ति... +फ़ाइलं किंवा फोल्डरं मिटाने में त्रुटि +तंत्र लंबे मार्ग वाली फाइलं को पुनःचक्रण पेटी(रिसाईकल बिन) में ना ले जा सकता अस्ति. +6300 +फ़ॊल्डर निर्माणम् कुरु +फ़ाइल निर्माणम् कुरु +फोल्डरं नाम: +फ़ाइल नाम: +नवीन फ़ॊल्डर +नवीन फ़ाइलं +फोल्डरं निर्माणम् करने में त्रुटि +फ़ाइल निर्माणम् करने में त्रुटि +6400 +टिप्पणी +&टिप्पणी: +चयनम् +चयन रद्द +मुखौटा: +6600 +गुणम् वा संपत्तियाँ +फ़ोल्डरों का इतिहास +निदानात्मकं संदेश +संदेशं +7100 +संगणकम् +सञ्जालम् +दस्तावेजम् +प्रणाली +7200 +जोड़े +बहिः निकाले +परीक्षणम् +नकल +ले जायें +मिटायें +सूचना +7300 +फ़ाइलस्य विभाजनं कुरु +&में विभाजनं: +जत्थों में विभाजनं, बाइट्स: +विभाजनं कर रहा अस्ति... +विभाजनं करना पक्का कुरु +क्या तुम्हे यकीन अस्ति कि तुम फाइलं को {0} जत्थों में विभाजित करना चाहते हो? +मूल फाइलं के आकारं की तुलना में जत्थे का आकारं छोटा ही होना चाहिए +जत्थे का आकारं मिथ्या अस्ति +निर्देशित जत्था आकारं: {0} बाइटस.\n भवान् संग्रहम् को ऎसे जत्थों में विभाजितं करना चाहते अस्ति, क्या आपको यकीन अस्ति? +7400 +फ़ाइले संयोजितं कुरु +&में संयोजनं कुरु: +संयोजनं हो रहा अस्ति... +विभाजितं फाइल का मात्र प्रथम भागं ही चयनितं कुरु +फाइलं को विभाजित फाइलं के भाग के रूप में पहचान ना सकता +विभाजित फाइलं का एक से ज्यादा भाग ना ढूँढ सकता +7500 +जाँचयोगस्य(चेकसम) गणनां कर रहा अस्ति... +जाँचयोग(चेकसम) माहिती +सीआरसी जाँचयोग(चेकसम) आँकड़ों के लिये : +सीआरसी जाँचयोग(चेकसम) आँकड़ों और नामों के लिये : +7600 +(कसौटी चिन्हं)बेञ्चमार्कम् +स्मृति उपयोग: +संकुचनं कर रहा अस्ति +प्रसारणं हो रहा अस्ति +क्रमांकन +कुल क्रमांकन +वर्तमानम् +परिणामम् +सीपीयू उपयोग +क्रमांकन / उपयोग +पास: diff --git a/Utils/7-Zip/Lang/si.txt b/Utils/7-Zip/Lang/si.txt new file mode 100644 index 000000000..5a4900181 --- /dev/null +++ b/Utils/7-Zip/Lang/si.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.59 : සුපුන් බුධාජීව (Supun Budhajeewa) +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Sinhala +සිංහල +401 +හරි +එපා + + + +ඔවු (&Y) +නැහැ (&N) +වසන්න (&C) +උදව් + +නැවත අරඹන්න (&C) +440 +සියල්ලටම ඔවු (&A) +සියල්ලටම නැහැ(&L) +නවතන්න +ප්‍රත්‍යාරම්භ කරන්න +පසුබිමින් (&B) +පෙරබිමින් (&F) +මදකට නවතන්න (&P) +මදකට නවතා ඇත +ඉවත්වීමට අවශ්‍ය බව විශ්වාස ද ? +500 +ගොනුව (&F) +සැකසුම් (&E) +දසුන (&V) +කැමතිම (&A) +මෙවලම් (&T) +උදව් (&H) +540 +විවෘත කරන්න (&O) +මෙහිම විවෘත කරන්න (&I) +පිටතින් විවෘත කරන්න (&U) +දසුන (&V) +සංස්කරණය කරන්න (&E) +නැවත නම් කරන්න (&M) +වෙනත් තැනකට පිටපත් කරන්න (&C)... +වෙනත් තැනකට ගෙනය‍න්න (&M)... +මකන්න (&D) +ගොනුව බෙදන්න (&S)... +ගොනු එකතු කරන්න (&B)... +වත්කම් (&R) +ටීකා (&N) +checksum ගණනය කරන්න + +බහාලුමක් තනන්න +ගොනුවක් තනන්න +ඉවත් වන්න (&X) +600 +සියල්ල තෝරන්න (&A) +තෝරන ලද සියල්ල ඉන් ඉවත් කරන්න +අනෙක් පැත්තට තෝරන්න (&I) +තෝරන්න... +තේරීම ඉවත් කරන්න... +වර්ගයෙන් තෝරන්න +වර්ගයෙන් තේරීම ඉවත් කරන්න +700 +විශාල මූර්ති (&G) +කුඩා මූර්ති (&M) +ලයිස්තුව (&L) +සවිස්තර (&D) +730 +අසුරන නොලද +පැතලි දසුන +පැනල &2 +මෙවලම් තීරු (&T) +ප්‍රධාන බහාලුම විවෘත කරන්න +ඉහළට එක් ස්ථරයක් +බහාලුම් අතීතය... +ප්‍රතිපූරණය කරන්න(&R) +750 +හැකිළුම් මෙවලම් තීරුව +සම්මත මෙවලම් තීරුව +විශාල බොත්තම් +බොත්තම් පෙළ දක්වන්න +800 +බහාලුම කැමතිම අංග වලට එකතු කරන අයුර (&A) +පොත් සලකුණ - අංක +900 +විකල්ප (&O)... +&Benchmark +960 +අන්තර්ගතය (&C)... +7-Zip පිළිබඳව (&A)... +1003 +මංපෙත +නම +දිගුව +බහාලුම +විශාලත්වය +හැකිළුමෙන් පසු විශාලත්වය +ලක්ෂණ +නිර්මාණය කළ දිනය +ප්‍රවේශ වූ දිනය +අළුත් කළ දිනය +සවි +ටීකා කොට ඇත +සුරක්ෂිතය +Split Before +Split After +Dictionary +CRC +වර්ගය +Anti +ක්‍රමය +ධාරක මෙහෙයුම් පද්ධතිය +ගොනු පද්ධතිය +පරිශිලක +සමූහය +Block +ටීකාව +පිහිටීම +Path Prefix +බහාලුම් +ගොනු +සංස්කරණය +Volume +Multivolume +Offset +සබැඳීන් +Blocks +Volumes + +බිට්-64 +Big-endian +මධ්‍යම සැකසුම් පද්ධතිය (CPU) +භෞතික විශාලත්වය +ශීර්ෂ විශාලත්වය +Checksum +මුහුණුවර +Virtual Address + + + + + + +දෝෂයක් +සම්පූර්ණ විශාලත්වය +නිදහස් ඉඩ +Cluster විශාලත්වය +නම් පත +Local Name +සපයන්නා +2100 +විකල්ප +භාෂාව +භාෂාව: +සංස්කාරකය +සංස්කාරකය (&E): + +2200 +පද්ධතිය +7-Zip සමග හවුල් කරන්න: +2301 +Shell context මෙනුව වෙත 7-Zip අන්තර්ගත කරන්න +Context menu අංග එක් අංගයක් යටතේ සඳහන් කරන්න‍‍‍ +Context මෙනු අංග: +2320 +<බහාලුම> +<හැකිළුම> +හැකිළුම විවෘත කරන්න +ගොනු ලිහන්න... +හැකිළුමකට ඇතුල් කරන්න... +හැකිළුම පරීක්ෂා කරන්න +මෙතැනට ලිහන්න +{0} වෙත ලිහන්න +{0} වෙත එක් කරන්න +හකුළා විදුලි තැපැල් කරන්න... +{0} වෙත හකුළා විදුලි තැපැල් කරන්න +2400 +බහාලුම් +සක්‍රීය බහාලුම් (&W) +පද්ධති තාවකාලික දෑ (Temp) බහාලුම (&S) +වත්මන් (&C) +තෝරන්න (&S): +ඉවත් කළ හැකි ධාවක සඳහා පමණක් භාවිතා කරන්න +තාවකාලික හැකිළුම් ගොනු සඳහා ස්ථානයක් දෙන්න. +2500 +සෙටිංග්ස් +".." අංගය පෙන්වන්න +ගොනු වල සත්‍ය මූර්තිය පෙන්වන්න +පද්ධති මෙනුව පෙන්වන්න +සම්පූර්ණ තීරු තේරීම (&F) +වගු රේභා පෙන්වන්න (&G) + +වෛකල්පිත තේරීම් ස්වභාවය (&A) +විශාල මතක පිටු භාවිතා කරන්න (&L) +2900 +7-Zip පිළිබඳව +7-Zip නිදහස් මෘදුකාංගයක් වුවත්, ලියාපදිංචි වීම මගින් 7-Zip හි වැඩි දියුණුව සඳහා ඔබට දායක විය හැකිය.\n\nමෙම සිංහල භාෂා පරිවර්තනය G.S.N. සුපුන් බුධාජීව (budhajeewa@gmail.com) විසින් සිදු කරන ලදී. +3000 +අවශ්‍ය මතක ප්‍රමාණය පද්ධතියට වෙන් කර ගත නොහැක +දෝෂ නොමැත +වස්තු {0}ක් තෝරා ඇත +'{0}' බහාලුම තැනිය නොහැක +මෙම හැකිළුම සඳහා යාවත්කාල කිරීම් සහයෝගය නොදක්වයි. +'{0}' ගොනුව හැකිළුමක් ලෙස විවෘත කළ නොහැක +සුරක්ෂිත '{0}' හැකිළුම විවෘත කළ නොහැක. මුරපදය වැරදි ද ? +සහයෝගී නොවන හැකිළුම් ක්‍රමයක් +{0} ගොනුව දැනටමත් ඇත +'{0}' ගොනුව නව්‍ය කෙරිනි.\nහැකිළුමෙහි එය යාවත්කාල කිරීමට ඔබට අවශ්‍ය ද ? +ගොනුව යාවත්කාල කල නොහැක\n'{0}' +සංස්කාරකය විවෘත කළ නොහැක. +ගොනුව වෛරසයක් වැනිය (ගොනු නාමයේ දිගු හිස් තැන් ඇත). +දිගු මංපෙතක් ඇති බහාලුමකින් ක්‍රියාකාරීත්වය කැඳවිය නොහැක. +එක් ගොනුවක් පමණක් තේරිය යුතුය. +ගොනු එකක් හෝ වැඩි ගණනක් තේරිය යුතුය. +අංග ඉතා අධිකය +3300 +ලිහමින් පවතී‍ +හකුළමින් පවතී +පරීක්ෂා කිරීම +විවෘත කරමින් පවතී... +සුපිරික්සමින් පවතී... +3400 +ලිහන්න +ලිහීමට තැනක් (&X) : +ලිහන ලද ගොනු සඳහා ස්ථානයක් තෝරන්න. +3410 +මංපෙත් ස්වභාවය +සම්පූර්ණ මංපෙත් නම් +මංපෙත් නම් අවශ්‍ය නැත +3420 +උඩින් ලිවීමේ ස්වභාවය +උඩින් ලියන්නට පෙර විමසන්න +විමසීමෙන් තොරව උඩින් ලියන්න +දැනටමත් ඇති ගොනු මගහරින්න +ගොනු ස්වයංක්‍රියව ප්‍රතිනම් කරන්න +දැනටමත් ඇති ගොනු‍ ප්‍රතිනම් කරන්න +3500 +ගොනු ප්‍රතිස්ථාපනය තහවුරු කර ගැනීම +ගමනාන්ත බහාලුමේ දැනටමත් නිර්මිත ගොනුවක් ඇත. +දැනටම පවතින පහත ගොනුව, +මෙය සමග ප්‍රතිස්ථාපනය කරන්න ද ? +{0} බයිට (Bytes) +ස්වයංක්‍රියව ප්‍රතිනම් කරන්න (&U) +3700 +'{0}' සඳහා සහයෝගය නොදක්වන හැකිළුම් ක්‍රමයක්. +'{0}' හි දත්ත දෝෂයකි. ගොනුව බිඳී ඇත. +'{0}' හි CRC අසමත් විනි. ගොනුව බිඳී ඇත. +සුරක්ෂිත '{0}' ගොනුවේ දත්ත දෝෂයකි. වැරදි මුරපදයක් ද ? +සුරක්ෂිත '{0}' ගොනුවේ CRC අසමත් විනි. වැරදි මුරපදයක් ද ? +3800 +මුරපදය ඇතුල් කරන්න +මුරපදය ඇතුල් කරන්න: +මුරපදය නැවත ඇතුල් කරන්න: +මුරපදය පෙන්වන්න (&S) +මුරපද නොගැලපේ +මුරපද සඳහා ඉංග්‍රිසි අකුරු, ඉලක්කම් සහ විශේෂිත සංකේත පමණක් භාවිතා කරන්න (!, #, $, ...) +මුරපදය දිග වැඩිය +මුරපදය +3900 +ගතවූ කාලය: +ඉතිරි කාලය: +සම්පූර්ණ විශාලත්වය: +වේගය: +ක්‍රියාවලියට භාජනය වූ ප්‍රමාණය: +හැකිළුම් අනුපාතය: +දෝෂ: +හැකිළුම්: +4000 +හැකිළුමකට එක් කරන්න +හැකිළුම (&A): +යාවත්කාල කිරීමේ ස්වභාවය (&U): +හැකිළුම් රටාව (&F): +හැකිළුම් මට්ටම (&L): +හැකිළුම් ක්‍රමය (&M): +&Dictionary size: +&Word size: +Solid block size: +Number of CPU threads: +පරාමිති (&P): +විකල්ප +SF&X හැකිළුමක් තනන්න +හවුල්කාර ගොනු ද හකුළන්න +සුරැකුම් +සුරැකුම් ක්‍රමය: +ගොනු නාම සුරකින්න (&S) +හැකිලීම සඳහා මතක භාවිතය: +ලිහීම ක්‍රියාව සඳහා මතක භාවිතය: +4050 +තැන්පත් කරන්න +ඉතා වේගවත් +වේගවත් +සාමාන්‍ය +උපරිම +අධි හැකිළුම්‍ +4060 +ගොනු එක් කර ප්‍රතිස්ථාපනය කරන්න +ගොනු යාවත්කාල කර එක් කරන්න +දැනටමත් ඇති ගොනු නැවුම් කරන්න +ගොනු සමකාලී කරන්න +4070 +සොයන්න +සියළු ගොනු +සවි-නොමැති +සවි +6000 +පිටපත් කරන්න +ගෙනයන්න +වෙනත් තැනකට පිටපත් කරන්න: +වෙනත් තැනකට ගෙනයන්න: +පිටපත් කරමින් පවතී... +ගෙනයමින් පවතී... +ප්‍රතිනම් කරමින් පවතී... +ගමනාන්ත බහාලුම තෝරන්න. +ක්‍රියාව කල නොහැක. +ගොනුව හෝ බහාලුම මැකීමේදී දෝෂයක් මතු විය +ගොනු පිටපත් කිරීම තහවුරු කිරීම +ගො‍නුව හැකිළුම වෙත පිටපත් කළ යුතු බව ඔබට විශ්වාස ද +6100 +ගොනු මැකීම තහවුරු කිරීම +බහාලුම් මැකීම තහවුරු කිරීම +බහු ගොනු මැකීම තහවුරු කිරීම +ඔබට '{0}' මැකීමට අවශ්‍ය බව විශ්වාස ද ? +ඔබට '{0}' බහාලුම හා එහි අන්තර්ගතය මැකීමට අවශ්‍ය බව විශ්වාස ද ? +ඔබට {0} යන වස්තු මැකීමට අවශ්‍ය බව විශ්වාස ද ? +මකමින් පවතී... +ගොනුව හෝ බහාලුම මැකීමේ දී දෝෂයක් මතු විය +දිගු මංපෙතක් ඇති ගොනුවක් කුණු බඳුනට යැවීම පද්ධතියට කල නොහැක. +6300 +බහාලුමක් තනන්න +ගොනුවක් තනන්න +බහාලුම් නාමය: +ගොනු නාමය: +නව බහාලුමක් +නව ගොනුවක් +බහාලුම තැනීමේදී දෝෂයක් මතුවිය +ගොනුව තැනීමේදී දෝෂයක් මතුවිය +6400 +ටීකාව +ටීකාව (&C): +තෝරන්න +තේරීම ඉවත් කරන්න +ගොනුවේ හෝ බහාලුමේ නම හෝ කොටසක්: +6600 +වත්කම් +බහාලුම් අතීතය +විනිශ්චීය පණිවුඩ +පණිවිඩය +7100 +පරිගණකය +ජාලය +ලියකියවිලි +පද්ධතිය +7200 +හකුළන්න +ලිහන්න +පරීක්ෂා කරන්න +පිටපත් කරන්න +ගෙන යන්න +මකන්න +තොරතුරු +7300 +ගොනුව බෙදන්න +ගොනුව බෙදා කොටස් මෙහි තැන්පත් කරන්න (&S): +කොටස් වලට බෙදන්න, බයිට (bytes): +ගොනුව බෙදමින් පවතී... +ගොනුව බෙදීම තහවුරු කරන්න +ගොනුව කොටස් {0} කට බෙදීමට අවශ්‍ය බව ඔබට විශ්වාස ද ? +බෙදූ කොටසක විශාලත්වය, මුල් ගොනුවේ විශාලත්වයට වඩා අඩු විය යුතුය +වැරදි කොටස් විශාලත්වයකි +සඳහන් කරන ලද කොටස් විශාලත්වය බයිට {0} කි.\nහැකිළුම මෙවන් කොටස් වලට බෙදියයුතු බව විශ්වාස ද ? +7400 +බෙදූ ගොනු එක් කරන්න +බෙදූ ගොනු එක් කර මෙහි තැනපත් කරන්න (&C): +බෙදූ ගොන එක් කරමින් පවතී... +පළමු ගොනුව පමණක් තෝරන්න +ගොනුව, බෙදන ලද ගොනුවක කොටසක් ලෙස හඳුනාගත නොහැක. +බෙදන ලද ගොනුවේ කොටස් වලින් එකකට වඩා සොයාගත නොහැක. +7500 +Checksum calculating... +Checksum information +CRC checksum for data: +CRC checksum for data and names: +7600 +Benchmark +මතක භාවිතය: +හැකිළුම් +ලිහුම් +ඇගයුම +සම්පූර්ණ ඇගයුම +වත්මන් +ප්‍රතිඵලිත +CPU භාවිතාව +ඇගයුම / භාවිතාව‍ +Passes: diff --git a/Utils/7-Zip/Lang/sk.txt b/Utils/7-Zip/Lang/sk.txt new file mode 100644 index 000000000..9715a09c8 --- /dev/null +++ b/Utils/7-Zip/Lang/sk.txt @@ -0,0 +1,477 @@ +;!@Lang2@!UTF-8! +; : Tomas Tomasek +; 9.07 : Pavel Devečka +; 9.38 beta : 2015-01-11 : Roman Horváth +; +; +; +; +; +; +; +; +0 +7-Zip +Slovak +Slovenčina +401 +OK +Zrušiť + + + +&Áno +&Nie +&Zavrieť +Pomocník + +Po&kračovať +440 +Áno na &všetko +Nie na vš&etko +Zastaviť +Reštartovať +&Pozadie +P&opredie +Po&zastaviť +Pozastavené +Ste si istý, že chcete akciu zrušiť? +500 +&Súbor +&Upraviť +&Zobraziť +&Obľúbené +&Nástroje +&Pomocník +540 +&Otvoriť +O&tvoriť vnútri +Ot&voriť externe +&Zobraziť +&Upraviť +&Premenovať +&Kopírovať do... +P&resunúť do... +O&dstrániť +Ro&zdeliť súbor... +Zlúč&iť súbory... +V&lastnosti +Ko&mentár +Vypočítať kontrolný súčet +Rozdiel (Diff) +Vytvoriť priečinok +Vytvoriť súbor +Uko&nčiť +Odkaz... +600 +Označiť všetko +Odznačiť všetko +Invertovať označenie +Označiť... +Odznačiť... +Označiť podľa typu +Odznačiť podľa typu +700 +&Veľké ikony +&Malé ikony +&Zoznam +&Podrobnosti +730 +Netriediť +Plochý vzhľad +&2 Panely +P&anely nástrojov +Otvoriť koreňový priečinok +O úroveň vyššie +História priečinkov... +&Obnoviť +Automatické obnovenie +750 +Archív +Štandard +Veľké ikony +Textový popis pod ikonami +800 +Pridať priečinok medzi obľúbené ako +Záložka +900 +N&astavenia... +&Skúšobný test +960 +&Obsah pomocníka... +O p&rograme 7-Zip +1003 +Cesta +Meno +Prípona +Priečinok +Veľkosť +Veľkosť po kompresii +Atribúty +Vytvorený +Sprístupnený +Zmenený +Jednoliaty +Komentovaný +Zašifrovaný +Rozdelený predtým +Rozdelený potom +Slovník +CRC +Typ +Anti +Metóda +Hostiteľský OS +Súborový systém +Používateľ +Skupina +Blok +Komentár +Pozícia +Predpona cesty +Priečinky +Súbory +Verzia +Zväzok +Multizväzok +Ofset +Odkazy +Bloky +Zväzky + +64-bitov +Big-endian +CPU +Fyzická veľkosť +Veľkosť hlavičiek +Kontrolný súčet +Charakteristiky +Virtuálna adresa +ID +Skrátený názov +Aplikácia +Veľkosť sektora +Režim +Symbolický odkaz +Chyba +Celková veľkosť +Voľné miesto +Veľkosť klastra +Menovka +Lokálny názov +Prevádzkovateľ +Bezpečnosť NT +Alternatívny prúd +Aux +Vymazané +Je strom + + +Typ chyby +Chyby +Chyby +Varovania +Varovanie +Prúdy +Alternatívne prúdy +Veľkosť alternatívneho prúdu +Virtuálna veľkosť +Veľkosť po rozbalení +Celková fyzická veľkosť +Index zväzku +Podtyp +Krátky komentár +Kódová stránka + + + +Veľkosť zakončenia +Veľkosť vloženého ústrižku +Odkaz +Pevný odkaz +iNode +2100 +Nastavenia +Jazyk +Jazyk: +Editor +Editor: +Vyhľadávač rozdielov (Diff): +2200 +Systém +Asociovať 7-Zip s vybranými typmi súborov: +2301 +Integrovať 7-Zip do kontextovej ponuky +Kaskádová kontextová ponuka +Položky kontextovej ponuky: +Ikony v kontextovej ponuke +2320 + + +Otvoriť archív +Rozbaliť súbory... +Pridať do archívu... +Otestovať archív +Rozbaliť tu +Rozbaliť do {0} +Pridať do {0} +Skomprimovať a poslať emailom... +Skomprimovať do {0} a poslať emailom +2400 +Priečinky +&Pracovný priečinok +&Systémový priečinok pre dočasné súbory +&Aktuálny priečinok +&Manuálne vybraný priečinok: +Po&užiť len pre vymeniteľné jednotky +Vyberte priečinok pre dočasné súbory. +2500 +Nastavenia +Ukázať položku ".." +Ukázať skutočné ikony súborov +Ukázať systémovú ponuku +Označiť celý riadok +Zobraziť čiary mriežky +Otvoriť položku jednoduchým kliknutím +Alternatívny režim výberu +Použitie veľkých stránok pamäti +2900 +O programe 7-Zip +7-Zip je voľne šíriteľný softvér +3000 +Systém nemôže alokovať požadované množstvo pamäte +V archíve sa nenašli žiadne chyby +{0} vybraných objektov +Nie je možné vytvoriť priečinok '{0}'. +Operácie aktualizácie nie sú pre tento archív podporované. +Súbor '{0}' nie je možné otvoriť ako archív +Nie je možné otvoriť šifrovaný archív '{0}'. Nesprávne heslo? +Nepodporovaný typ archívu +Súbor {0} už existuje. +Súbor '{0}' bol zmenený.\nChcete ho aktualizovať v archíve? +Nie je možné aktualizovať súbor\n'{0}' +Nie je možné spustiť editor. +Súbor vyzerá ako vírus. (Meno súboru obsahuje veľa medzier.) +Operácia nemôže byť vykonaná v priečinku, ktorý má dlhú cestu. +Musíte vybrať jeden súbor +Musíte vybrať jeden alebo viac súborov +Priveľa položiek +3300 +Rozbaľovanie +Komprimovanie +Výsledok testovania +Otváranie... +Prehľadávanie... +3400 +Rozbaliť +Rozbaliť do: +Špecifikujte priečinok pre rozbalené súbory. +3410 +Nastavenie názvov ciest: +Plné názvy ciest +Žiadne názvy ciest +Absolútne názvy ciest +Relatívne názvy ciest +3420 +Nastavenie prepísania: +Spýtať sa pred prepísaním +Prepísať bez výzvy +Preskočiť existujúce súbory +Automaticky premenovať +Automaticky premenovať existujúce súbory +3430 +Eliminovať duplikáty koreňového priečinka +Obnoviť práva súboru +3500 +Potvrdenie nahradenia súboru +Cieľový priečinok už obsahuje rozbaľovaný súbor. +Chcete nahradiť existujúci súbor +týmto súborom? +{0} bajtov +&Automaticky premenovať +3700 +Nepodporovaná kompresná metóda pre '{0}'. +Chybné údaje v '{0}'. Súbor je poškodený. +CRC zlyhalo v '{0}'. Súbor je poškodený. +Chybné údaje v šifrovanom súbore '{0}'. Nesprávne heslo? +CRC zlyhalo v šifrovanom súbore '{0}'. Nesprávne heslo? +3710 +Nesprávne heslo? +3721 +Nepodporovaná kompresná metóda +Chybné údaje +CRC zlyhalo +Údaje sú nedostupné +Neočakávaný koniec údajov +Za zužitkovateľnými údajmi sa nachádzajú ďalšie údaje +Nie je to archív +Chybné hlavičky +3763 +Začiatok archívu je nedostupný +Začiatok archívu nie je potvrdený + + + +Nepodporovaná funkcia +3800 +Zadajte heslo +Zadajte heslo: +Zopakujte heslo: +Ukázať heslo +Heslá nie sú zhodné +Používajte len písmená bez diakritiky, čísla a špeciálne znaky (!, #, $, ...) +Heslo je príliš dlhé +Heslo +3900 +Uplynutý čas: +Zostávajúci čas: +Veľkosť: +Rýchlosť: +Spracované: +Úroveň kompresie: +Chyby: +Archívy: +4000 +Pridať do archívu +&Archív: +&Nastavenie aktualizácie súborov v existujúcich archívoch: +&Formát archívu: +Ú&roveň kompresie: +&Kompresná metóda: +&Veľkosť slovníka: +V&eľkosť slova: +Veľk&osť jednoliateho bloku: +Poče&t CPU vlákien: +&Parametre: +Možnosti +Vytvoriť samorozbaľovací archív +Komprimovať zdieľané súbory +Šifrovanie +Metóda šifrovania: +Zašifrovať mená súborov +Pamäť potrebná na kompresiu: +Pamäť potrebná na dekompresiu: +Vymazať súbory po kompresii +4040 +Uložiť symbolické odkazy +Uložiť pevné odkazy +Uložiť alternatívne údajové prúdy +Uložiť práva súborov +4050 +Bez kompresie +Najrýchlejšia +Rýchla +Normálna +Maximálna +Ultra +4060 +Pridať a nahradiť súbory +Aktualizovať a pridať súbory +Aktualizovať existujúce súbory +Synchronizovať súbory +4070 +Prehľadávať +Všetky súbory +Nejednoliaty +Jednoliaty +6000 +Kopírovať +Presunúť +Kopírovať do: +Presunúť do: +Kopírovanie... +Presúvanie... +Premenovanie... +Vyberte cieľový priečinok. +Operácia nie je podporovaná pre tento priečinok. +Chyba pri premenovaní súboru alebo priečinka +Potvrdiť kopírovanie súboru/súborov +Ste si istý, že chcete kopírovať súbor/súbory do archívu +6100 +Potvrdenie odstránenia súboru +Potvrdenie odstránenia priečinka +Potvrdenie odstránenia viacerých položiek +Ste si istý, že chcete odstrániť súbor '{0}'? +Ste si istý, že chcete odstrániť priečinok '{0}' a celý jeho obsah? +Ste si istý, že chcete odstrániť týchto {0} položiek? +Odstraňovanie... +Chyba pri odstraňovaní súboru alebo priečinka +Systém nemôže presunúť do koša súbor s dlhou cestou +6300 +Vytvoriť priečinok +Vytvoriť súbor +Meno priečinka: +Meno súboru: +Nový priečinok +Nový súbor +Chyba pri vytváraní priečinka +Chyba pri vytváraní súboru +6400 +Komentár +&Komentár: +Označiť +Odznačiť +Maska: +6600 +Vlastnosti +História priečinkov +Diagnostické správy +Správa +7100 +Počítač +Sieť +Dokumenty +Systém +7200 +Pridať +Rozbaliť +Otestovať +Kopírovať +Presunúť +Odstrániť +Informácie +7300 +Rozdeliť súbor +&Rozdeliť na: +Roz&deliť na zväzky bajtov: +Rozdeľovanie... +Potvrdiť rozdeľovanie. +Ste si istý, že chcete rozdeliť súbor na {0} zväzkov? +Veľkosť zväzku musí byť menšia než veľkosť pôvodného súboru. +Nesprávna veľkosť zväzku +Určená veľkosť zväzku: {0} bajtov.\nSte si istý, že chcete rozdeliť archív na také zväzky? +7400 +Zlúčiť súbory +&Zlúčiť do: +Zlučovanie... +Vyberte len prvý súbor. +Nie je možné rozlíšiť súbor ako súčasť rozdeleného súboru +Nie je možné nájsť viac než jednu časť rozdeleného súboru +7500 +Výpočet kontrolného súčtu... +Informácie o kontrolnom súčte +CRC súčet pre údaje: +CRC súčet pre údaje a názvy: +7600 +Skúšobný test +Použitá pamäť: +Komprimovanie +Rozbaľovanie +Hodnotenie +Celkové hodnotenie +Aktuálne +Výsledné +Využitie CPU +Hodn. / Využitie +Testov bez chýb: +7700 +Odkaz +Odkaz +Odkaz z: +Odkaz do: +7710 +Typ odkazu +Pevný odkaz +Súbor symbolického odkazu +Priečinok symbolického odkazu +Prekríženie priečinkov diff --git a/Utils/7-Zip/Lang/sl.txt b/Utils/7-Zip/Lang/sl.txt new file mode 100644 index 000000000..2c3214a86 --- /dev/null +++ b/Utils/7-Zip/Lang/sl.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : tomazek +; 4.55 : miles +; +; +; +; +; +; +; +; +; +0 +7-Zip +Slovenian +Slovenski +401 +V redu +Prekliči + + + +&Da +&Ne +&Zapri +Pomoč + +&Nadaljuj +440 +Da za &vse +Ne za v&se +Zaustavi +Ponovno zaženi +&Ozadje +O&spredje +&Začasno zaustavi +Zaustavljen +Ste prepričani, da želite preklicati? +500 +&Datoteka +&Urejanje +&Pogled +Pr&iljubljene +O&rodja +Po&moč +540 +&Odpri +Odpri &znotraj +Odpri zu&naj +P&rikaz +&Urejanje +Prei&menuj +&Kopiraj ... +&Premakni ... +Iz&briši +&Razdeli datoteko ... +&Združi datoteke ... +L&astnosti +Opomb&e +Izračunaj preskusno vsoto + +Ustvari mapo +Ustvari datoteko +&Izhod +600 +Izberi &vse +Razveljavi izbiro vseh +&Preobrni izbor +Izberi ... +Razveljavi izbiro ... +Izberi glede na vrsto +Razveljavi izbiro glede na vrsto +700 +&Velike ikone +&Majhne ikone +&Seznam +&Podrobnosti +730 +Nerazvrščeno +Splošen pogled +&Dve podokni +&Orodne vrstice +Odpri korensko mapo +Nadrejena raven +Zgodovina mape ... +&Osveži +750 +Orodna vrstica arhiva +Navadna orodna vrstica +Veliki gumbi +Pokaži besedilo gumbov +800 +&Dodaj mapo med Priljubljene kot +Zaznamek +900 +&Možnosti ... +Me&ritev +960 +&Vsebina pomoči ... +&O programu 7-Zip ... +1003 +Pot +Ime +Pripona +Mapa +Velikost +Stisnjena velikost +Atributi +Izdelano +Uporabljeno +Spremenjeno +Trdno +Komentirano +Šifrirano +Razdeli pred +Razdeli po +Slovar +CRC +Vrsta +Anti +Metoda +Gostiteljski OS +Datotečni sistem +Uporabnik +Skupina +Blok +Opomba +Položaj +Predpona poti +Mape +Datoteke +Različica +Nosilec +Več nosilcev +Zamik +Povezave +Bloki +Nosilcev + + + + + + + + + + + + + + + +Napaka +Skupna velikost +Prostega prostora +Velikost gruče +Oznaka +Krajevno ime +Ponudnik +2100 +Možnosti +Jezik +Jezik: +Urejevalnik +&Urejevalnik: + +2200 +Sistem +Poveži 7-Zip z: +2301 +Integracija 7-Zip v kontekstni meni lupine +Kaskadni kontekstni meni +Izbire kontekstnega menija: +2320 + + +Odpri arhiv +Razširi datoteke ... +Stisni v arhiv ... +Preizkusi arhiv +Razširi semkaj +Razširi v {0} +Dodaj v {0} +Stisni in pošlji ... +Stisni v {0} in pošlji po e-pošti +2400 +Mape +&Delovna mapa +&Sistemska začasna mapa +&Trenutna mapa +&Navedeno: +Uporabi le za izmenljive pogone +Navedite mesto za začasne arhivske datoteke. +2500 +Nastavitve +Pokaži postavko ".." +Pokaži prave ikone datotek +Pokaži sistemski meni +&Izbor celotne vrstice +Pokaži &mrežne črte + +&Alternativni način izbiranja +Uporabi &velike spominske strani +2900 +O programu 7-Zip +7-Zip je brezplačen. Njegov razvoj podprete s tem, da se registrirate. +3000 + +Brez napak +Izbran(ih) {0} objekt(ov) +Mape '{0}' ni mogoče ustvariti +Za ta arhiv operacije osveževanja niso podprte. +Datoteke '{0}' ni mogoče odpreti kot arhiv +Šifriranega arhiva '{0}' ni mogoče odpreti. Je morda geslo napačno? + + +Datoteka '{0}' je bila spremenjena.\nJo želite osvežiti v arhivu? +Datoteke ni mogoče osvežiti\n'{0}' +Urejevalnika ni mogoče pognati. + + + + +Preveč izbir +3300 +Razširjanje +Stiskanje +Preizkušanje +Odpiranje ... +Pregledovanje ... +3400 +Razširi +R&azširi v: +Določite mesto razširjanja datotek. +3410 +Poti +Polne poti +Brez poti +3420 +Prepisovalni način +Zahtevaj potrditev +Prepiši brez potrditve +Preskoči obstoječe datoteke +Samodejno preimenuj +Samodejno preimenuj obstoječe datoteke +3500 +Potrditev zamenjave datoteke +Ciljna mapa že vsebuje obdelovano datoteko. +Želite zamenjati obstoječo datoteko +s to datoteko? +{0} bajtov +Samodejno &preimenuj +3700 +Nepodprta metoda stiskanja za '{0}'. +Podatkovna napaka v '{0}'. Datoteka je poškodovana. +Napaka CRC v '{0}'. Datoteka je poškodovana. +Podatkovna napaka v šifrirani datoteki '{0}'. Je geslo pravilno? +Napaka CRC v šifrirani datoteki '{0}'. Je geslo pravilno? +3800 +Vnos gesla +Vnesite geslo: +Ponovno vnesite geslo: +&Pokaži geslo +Gesli se ne ujemata +Za geslo uporabite le črke, številke in posebne znake angleške abecede (!, #, $, ...) +Geslo je predolgo +Geslo +3900 +Pretečeni čas: +Preostali čas: +Velikost: +Hitrost: +Obdelano: +Razmerje stiskanja: +Napake: +Arhivi: +4000 +Dodaj v arhiv +&Arhiv: +&Način osveževanja: +&Vrsta arhiva: +Raven &stiskanja: +&Metoda stiskanja: +&Velikost slovarja: +Velikost &besede: +Velikost trdnega bloka: +Število niti CPE: +&Parametri: +Možnosti +Izdelaj arhiv SF&X +Stisni skupne datoteke +Šifriranje +Metoda šifriranja: +Šifriraj &imena datotek +Poraba pomnilnika za stiskanje: +Poraba pomnilnika za razširjanje: +4050 +Brez stiskanja +Najhitrejše +Hitro +Običajno +Največje stiskanje +Ultra +4060 +Dodaj in zamenjaj datoteke +Osveži in dodaj datoteke +Osveži obstoječe datoteke +Sinhroniziraj datoteke +4070 +Prebrskaj +Vse datoteke +Ne-trdno +Trdno +6000 +Kopiraj +Premakni +Kopiraj v: +Premakni v: +Kopiranje ... +Premikanje ... +Preimenovanje ... +Izberite ciljno mapo. +Operacija ni podprta. +Napaka pri preimenovanju datoteke ali mape +Potrditev kopiranja datoteke +Ste prepričani, da želite kopirati datoteke v arhiv? +6100 +Potrditev brisanja datoteke +Potrditev brisanja mape +Potrditev brisanja več datotek +Ste prepričani, da želite zbrisati '{0}'? +Ste prepričani, da želite zbrisati mapo '{0}' in celotno njeno vsebino? +Ste prepričani, da želite zbrisati teh {0} postavk? +Brisanje ... +Napaka pri brisanju datoteke ali mape + +6300 +Izdelava mape +Ustvarjanje datoteke +Ime mape: +Ime datoteke: +Nova mapa +Nova datoteka +Napaka pri ustvarjanju mape +Napaka pri ustvarjanju datoteke +6400 +Opomba +&Opomba: +Izberi +Razveljavi izbiro +Maska: +6600 +Properties +Zgodovina map +Diagnostična sporočila +Sporočilo +7100 +Računalnik +Omrežje + +Sistem +7200 +Dodaj +Razširi +Preizkusi +Kopiraj +Premakni +Izbriši +Informacije +7300 +Razdeli datoteko +&Razdeli na: +Razdeli na &nosilce velikosti (v bajtih): +Razdeljevanje ... +Potrditev razdelitve +Ste prepričani, da želite razdeliti datoteko na {0} nosilcev? +Velikost nosilca mora biti manjša kot velikost izvorne datoteke +Neveljavna velikost nosilca +Navedena velikost nosilca: {0} bajtov.\nSte prepričani, da želite razdeliti arhiv na takšne nosilce? +7400 +Združi datoteke +&Združi v: +Združevanje ... +Izberite samo prvo datoteko + + +7500 +Izračun preskusne vsote ... +Podatki o preskusni vsoti +Preskusna vsota za podatke: +Preskusna vsota za podatke in imena: +7600 +Meritev +Poraba pomnilnika: +Stiskanje +Razširjanje +Ocena +Skupna ocena +Trenutno +Končno +Uporaba CPE +Ocena / uporaba +Prehodi: diff --git a/Utils/7-Zip/Lang/sq.txt b/Utils/7-Zip/Lang/sq.txt new file mode 100644 index 000000000..024a2b8f5 --- /dev/null +++ b/Utils/7-Zip/Lang/sq.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.37 : Mikel Hasko +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Albanian +Shqip +401 +Në rregull +Anulim + + + +&Po +&Jo +&Mbyll +Ndihmë + +&Vazhdim +440 +Po për të gjith&a +Jo për të gjit&ha +Ndalo +Rinis +Në &sfond +Në pla&n të parë +&Pushim +Në pushim +Jeni të sigurt se dëshironi ta anuloni? +500 +&Skedari +&Redaktimi +&Pamja +&Të parapëlqyerit +&Veglat +&Ndihma +540 +&Hap +Hap përbre&nda +Hap përjas&hta +&Pamja +&Redakto +Ri&emërto +&Kopjo tek... +&Zhvendos tek... +&Fshi +N&daj skedarin... +Kom&bino skedarët... +&Vetitë +Ko&menti +Llogarit shumën e verifikimit + +Krijo një dosje +Krijo një skedar +&Dil +600 +S&elekto të gjithë +Çse&lekto të gjithë +Anasill selekti&min +Selekto... +Çselekto... +Selekto sipas tipit +Çselekto sipas tipit +700 +Ikona të &mëdha +Ikona të &vogla +&Listë +&Detaje +730 +&Të parenditur +Pamje e rrafshtë +&2 panele +&Shiritat e veglave +Hap dosjen rrënjë +Një nivel më lartë +Historiku i dosjes... +&Rifresko +750 +Shiriti i veglave i arkivit +Shiriti standard i veglave +Butona të mëdhenj +Shfaq tekstin e butonave +800 +&Shto dosjen tek të parapëlqyerit si +Shënuesi +900 +&Opsionet... +&Etapa +960 +&Përmbajtjet... +&Për 7-Zip... +1003 +Shtegu +Emri +Prapashtesa +Dosja +Madhësia +Madhësia e mbërthimit +Atributet +Krijuar më +Hyrë së fundi më +Modifikuar më +I qëndrueshëm +I komentuar +I shifruar +Ndaj para +Ndaj pas +Fjalori +CRC +Tipi +Anti +Metoda +Pronari i sistemit +Sistemi i skedarit +Përdoruesi +Grupi +Blloku +Komenti +Pozicioni +Prefiksi i shtegut + + + + + + + + + + + + + + + + + + + + + + + + +Gabim +Madhësia totale +Hapësira e lirë +Madhësia e cluster-it +Etiketa +Emri lokal +Kujdestari +2100 +Opsionet +Gjuha +Gjuha: +Redaktuesi +&Redaktuesi: + +2200 +Sistemi +Lidh 7-Zip me: +2301 +Integro 7-Zip në kontekst meny +Kaskado kontekst menynë +Elementë të kontekst menysë: +2320 + + +Hap arkivin +Zbërthe skedarët... +Shto në arkiv... +Testo arkivin +Zbërthe këtu +Zbërthe në {0} +Shto tek {0} +Kompreso dhe dërgo me e-mail... +Kompreso në {0} dhe dërgo me e-mail +2400 +Dosje +&Dosja e punës +Dosja e përkohshme e &sistemit +Dosja &aktuale +I sp&ecifikuar: +Përdor vetëm për njësi të largueshme +Specifikoni një vendndodhje për skedarët e përkohshëm të arkivit. +2500 +Rregullimet +Shfaq &artikullin ".." +Shfaq &ikonat e vërteta të skedarëve +Shfaq &menynë e sistemit +Selekto të tërë &rreshtin +Shfaq &vijat e rrjetit + +Mënyrë alternative &selektimi +Përdor &faqe të mëdha të memories +2900 +Për 7-Zip +7-Zip është softuer falas. Megjithatë, ju mund të përkrahni në zhvillimin e 7-Zip duke e regjistruar atë. +3000 + +S'ka gabime +Selektuar {0} objekt(e) +S'mund të krijojë dosjen '{0}' +Operacionet e azhurnimit për këtë arkiv s'përkrahen. + + + + +Skedari '{0}' u modifikua.\nDoni ta azhurnoni atë edhe në arkiv? +S'mund të azhurnojë skedarin\n'{0}' +S'mund të hap redaktuesin. + + + + +Tepër shumë artikuj +3300 +Duke zbërthyer +Duke kompresuar +Duke testuar +Duke hapur... +Duke skanuar... +3400 +Zbërthe +Z&bërthe në: +Specifikoni një vendndodhje për skedarët e zbërthyer. +3410 +Mënyra e Shtegut +Emra të plotë Shtigjesh +Pa emra shtigjesh +3420 +Mënyra e mbishkrimit +Pyet para se të mbishkruaj +Mbishkruaj pa nxitje +Mbikalo skedarët ekzistues +Riemërto automatikisht +Riemërto auto. skedarët ekzistues +3500 +Konfirmo zëvendësimin e skedarëve +Dosja e destinacionit e përmban një herë skedarin e përpunuar. +Dëshironi ta zëvendësoni skedarin ekzistues +me këtë? +{0} bajt +R&iemërtim automatik +3700 +Metodë e papërkrahshme kompresimi për '{0}'. +Gabim të dhënash në '{0}'. Skedari është i prishur. +CRC dështoi '{0}'. Skedari është i prishur. + + +3800 +Fusni fjalëkalimin +Fusni fjalëkalimin: + +&Trego fjalëkalimin + + + +Fjalëkalimi +3900 +Koha e kaluar: +Koha e mbetur: +Madhësia: +Shpejtësia: + + +Gabime: + +4000 +Shto në arkiv +&Arkivi: +&Mënyra e azhurnimit: +&Formati i arkivit: +&Niveli i kompresimit: +Metoda e kompr&esimit: +Ma&dhësia e fjalorit: +Mad&hësia e fjalës: + + +&Parametrat: +Opsionet +Krijo një arkiv SF&X + + + +Shifro em&rat e skedarëve +Shfrytëzimi i memo. për kompresimin: +Shfrytëzimi i memo. për dekompresimin: +4050 +Ruaj +Më i shpejtë +I shpejtë +Normal +Maksimal +Ultra +4060 +Shto dhe zëvendëso skedarët +Azhurno dhe shto skedarët +Azhurno skedarët ekzistues +Sinkronizo skedarët +4070 +Shfleto +Të gjithë skedarët + + +6000 +Kopjo +Zhvendos +Kopjo tek: +Zhvendos tek: +Duke kopjuar... +Duke zhvendosur... +Duke riemërtuar... + +Operacioni s'përkrahet. +Gabim gjatë riemërtimit të skedarit apo dosjes +Konfirmim për kopjimin e skedarëve +Jeni të sigurt që doni të kopjoni skedarë në arkiv +6100 +Konfirmo fshirjen e skedarit +Konfirmo fshirjen e dosjes +Konfirmo fshirjen e shumëfishtë të skedarëve +Jeni të sigurt që doni të fshini '{0}'? +Jeni të sigurt që doni të fshini dosjen '{0}' dhe tërë përmbajtjen e saj? +Jeni të sigurt që doni t'i fshini këto {0} artikuj? +Duke fshirë... +Gabim gjatë fshirjes së skedarit apo dosjes + +6300 +Krijo një dosje +Krijo një skedar +Emri i dosjes: +Emri i skedarit: +Dosje e re +Skedar i ri +Gabim gjatë krijimit të dosjes +Gabim gjatë krijimit të skedarit +6400 +Komenti +&Komenti: +Selekto +Çselekto +Maska: +6600 + +Historiku i dosjes +Mesazhe diagnostikues +Mesazhi +7100 +Kompjuteri +Rrejti + +Sistemi +7200 +Shto +Zbërthe +Testo +Kopjo +Zhvendos +Fshi +Info +7300 +Ndaj skedarin +&Ndaj në: +Ndaj në &volume (madhësia jepet në bajt): +Duke ndarë... + + + + + +7400 +Kombino skedarët +&Kombino në: +Duke kombinuar... + + + +7500 +Duke llogaritur shumën e verifikimit... +Informacionet e shumës së verifikimit +Shuma e verifikimit CRC për të dhënat: +Shuma e verifikimit CRC për të dhënat dhe emrat: +7600 +Etapa +Shfrytëzimi i memories: +Kompresimi +Dekompresimi +Vlerësimi +Vlerësimi total +Aktualisht +Rezultati + + +Kalime: diff --git a/Utils/7-Zip/Lang/sr-spc.txt b/Utils/7-Zip/Lang/sr-spc.txt new file mode 100644 index 000000000..098317335 --- /dev/null +++ b/Utils/7-Zip/Lang/sr-spc.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Lazar +; 9.07 : Ozzii +; +; +; +; +; +; +; +; +; +0 +7-Zip +Serbian - Cyrillic +Српски - ћирилица +401 +У реду +Откажи + + + +Да +Не +Затвори +Помоћ + +Настави +440 +Да за све +Не за све +Стани +Поново +Позадина +На врху +Пауза +Пауза +Да ли сте сигурни да желите да прекинете? +500 +Датотека +Уређивање +Преглед +Омиљено +Алати +Помоћ +540 +Погледај +Отвори са 7-Zip-ом +Отвори са придруженом програмом +Прегледај +Промени +Преименуј +Копирај у... +Премести у... +Обриши +Подели фајл... +Спој делове... +Својства +Коментар +Израчунајте проверну величину +разлика +Нова фасцикла +Нова датотека +Излаз +600 +Изабери све +Поништи избор свега +Обрнути избор +Изабери... +Поништи избор... +Изабери по типу +Поништи избор по типу +700 +Иконе +Напоредно слагање +Списак +Детаљи +730 +Без сортирања +Раван преглед +2 Прозора +Траке са алаткама +Отвори почетну фасциклу +Горе за један ниво +Хронологија... +Освежавање +750 +Рад са архивама +Рад са датотекама +Велика дугмад +Прикажи текст испод дугмади +800 +Додај +Изабери +900 +Опције... +Benchmark +960 +Помоћ... +О програму... +1003 +Путања +Назив +Тип +Фасцикла +Величина +Величина у запакованом стању +Атрибути +Креирана +Приступано +Промењено +Солидно +Коментар +Шифровано +Подели пре +Подели после +Речник +ЦРЦ +Тип +Анти +Метод +Оперативни систем +Систем датотека +Корисник +Група +Блок +Коментар +Положај +Префикс путање +Фасцикле +Датотеке +Верзија +Волумен +ВишеВолумена +Офсет +Линкови +Блокови +Волумени + +64-бит +Big-endian +Процесор +Физичка величина +Величина заглавља +Провера резултата +Карактеристике +Виртуелна адреса +ИД +Кратко име +Креатор апликације +Величина сектора +Начин +Линк +Грешка +Укупни капацитет +Слободни простор +Величинa cluster-а +Назив +Локално име +Провајдер +2100 +Опције +Језик +Језик: +Промене у датотекама +Програм: +Разлика: +2200 +Систем +7-Zip отвара следеће типове датотека: +2301 +Убаци 7-Zip у системски мени +Каскадни системски мени +Ставке системског менија: +2320 + + +Отвори архиву +Издвој датотеке... +Додај у архиву... +Тестирај архиву +Издвој овде +Издвој у {0} +Додај у {0} +Додај и направи e-mail... +Додај у {0} и направи e-mail +2400 +Фасцикле +Радна фасцикла +Користи Windows-ову привремену фасциклу +Тренутна +Наведена: +Користи само за измењиве медије +Наведите локацију за смештање привремених датотека. +2500 +Подешавања +Прикажи ".." +Прикажи праве сличице датотека +Прикажи системски мени +Обележи цео ред +Прикажи линије мреже +Један клик за отварање ставке +Алтернативни начин за бирање +Користи велике меморијске блокове +2900 +О програму +7-Zip је бесплатан програм. +3000 +Систем не може да издвоји потребну количину меморије +Није било никаквих грешака +{0} објекат(а) изабрано +Не могу да креирам Фасциклу '{0}' +Операција освежавања није дозвољена за ову архиву. +Не могу да отворим датотеку '(0)' као архива +Не могу да отворим шифровану архиву '(0)'. Погрешна лозинка? +Неподржан тип архиве +Датотека {0} већ постоји +Датотека '{0}' је измјењена.\nДа ли желите ажурирати архиву? +Није могуће ажурирати датотеку\n'{0}' +Није могуће започети уређивање. +Датотека изгледа као вирус (име датотеке садржи пуно размака у имену). +Операција не може бити позвана из фасцикле која има дугу путању. +Морате да изаберете неку датотеку +Морате да изаберете једну или више датотека +Исувише ставки +3300 +Издвајање +Додајем +Тестирање +Отварање у току... +Скенирање... +3400 +Издвој +Издвој у: +Наведи локацију где ће се издвајати датотеке из архива. +3410 +Путање +Пуна путања +Без путање +3420 +Замена +Питај пре него што замениш +Замени без запиткивања +Прескочи постојеће датотеке +Аутоматска промена назива +Аутоматска промена назива постојећих датотека +3500 +Потврди замену датотеке +Циљна фасцикла већ садржи датотеку која се тренутно обрађује. +Да ли желите да замените постојећу датотеку +са овом? +{0} бајтова +Аутоматска промена назива +3700 +Неподржани метод компресије за '{0}'. +Грешка у '{0}'. Датотека је неисправана. +CRC грешка у '{0}'. Датотека је неисправана. +Грешке у кодирану датотеку '(0)' Погрешна лозинка. +ЦРЦ грешка у шифроване датотеке '(0)' Погрешна лозинка. +3800 +Унесите лозинку +Унесите лозинку: +Поново унесите лозинку: +Прикажи лозинку +Лозинке се не поклапају +Користи само енглеска слова, бројева и специјалних знакова (!, #, $, ...) За лозинке +Лозинка је предугачка +Шифра +3900 +Протекло време: +Преостало време: +Величина: +Брзина: +Обрађено: +Компресиони однос: +Грешке: +Архиве: +4000 +Додај у архиву +Архива: +Надоградња архива: +Формат архиве: +Ниво компресије: +Тип компресије: +Dictionary size: +Word size: +Величина чврстог блока: +Број низа процесора: +Параметри: +Опције +Креирај SFX архиву +Компресија дељене датотека +Шифровање +Метода шифровања: +Шифруј називе датотека +Потребна меморија - компресија: +Потребна меморија - декомпресија: +4050 +Без компресије +Брже +Брзо +Нормално +Максимално +Најбрже +4060 +Додај и замени датотеке +Освежи и додај датотеке +Озвежи постојеће датотеке +Синхронизуј датотеке +4070 +Прегледај +Све датотеке +Не-чврсте +Чврсто +6000 +Копирај +Исеци +Копирај у: +Премести у: +Копирање у току... +Премештање у току... +Преименовање у току... +Изаберите одредишну фасциклу. +Операција није подржана. +Грешка при преименовању датотеке или фасцикле +Потврди копирање датотеке +Да ли сте сигурни да желите да копирате датотеке у архиву +6100 +Потврдите брисање датотеке +Потврдите брисање фасцикле +Потврдите вишеструко брисање датотека +Јесте ли сигурни да желите да обришете '{0}'? +Јесте ли сигурни да желите да обришете фасциклу '{0}' и сав њен садржај? +Јесте ли сигурни да желите да обришете ове {0} податке? +Брисање у току... +Грешка при брисању датотеке или фасцикле +Систем не може да премести датотеку са дугом путу у корпу за отпатке +6300 +Креирај фасциклу +Креирај датотеку +Име фасцикле: +Име датотеке: +Нова фасцикла +Нова датотека +Грешка при креирању фасцикли +Грешка при креирању датотека +6400 +Коментар +Коментар: +Одабери +Поништи избор +Маска: +6600 +Особине +Хронологија +Дијагностичке поруке +Поруке +7100 +Рачунар +Мрежа +Документи +Систем +7200 +Додај +Издвој +Тестирај +Копирај +Премести +Избриши +Својства +7300 +Подели датотеку +Подели на: +Подели на делове, бајти: +Подела... +Потврда поделе +Да ли сте сигурни да желите да поделите датотеку на (0) дела? +Величине дела мора бити мањи од величине оригиналне датотеке +Неисправна величина волумена +Одређена величина волумена: {0} бајтова.\nДа ли сте сигурни да желите да поделите архиву у тих волумена? +7400 +Састави датотеке +Састави у: +Спајање... +Изаберите само први део поделе датотеке +Не могу да откријем датотеку као део поделе +Не може се наћи више од једног дела поделе +7500 +Израчунавање проверне величине... +Информација о проверне величине +ЦРЦ порвера за податак: +ЦРЦ провера за податак и имена: +7600 +Benchmark +Коришћење меморије: +Компресија +Декомпресија +Оцена +Потпуна оцена +Тренутно +Резултат +Употреба процесора +Рејтинг/Употреба +Пролази: diff --git a/Utils/7-Zip/Lang/sr-spl.txt b/Utils/7-Zip/Lang/sr-spl.txt new file mode 100644 index 000000000..cf66e8dd8 --- /dev/null +++ b/Utils/7-Zip/Lang/sr-spl.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Lazar +; 9.07 : Ozzii +; +; +; +; +; +; +; +; +; +0 +7-Zip +Serbian - Latin +Srpski - latinica +401 +U redu +Otkaži + + + +Da +Ne +Zatvori +Pomoć + +Nastavi +440 +Da za sve +Ne za sve +Stani +Ponovo +Pozadina +Na vrhu +Pauza +Pauza +Da li ste sigurni da želite da prekinete? +500 +Datoteka +Uređivanje +Pregled +Omiljeno +Alati +Pomoć +540 +Pogledaj +Otvori sa 7-Zip-om +Otvori sa pridruženom programom +Pregledaj +Promeni +Preimenuj +Kopiraj u... +Premesti u... +Obriši +Podeli fajl... +Spoj delove... +Svojstva +Komentar +Izračunajte provernu veličinu +razlika +Nova fascikla +Nova datoteka +Izlaz +600 +Izaberi sve +Poništi izbor svega +Obrnuti izbor +Izaberi... +Poništi izbor... +Izaberi po tipu +Poništi izbor po tipu +700 +Ikone +Naporedno slaganje +Spisak +Detalji +730 +Bez sortiranja +Ravan pregled +2 Prozora +Trake sa alatkama +Otvori početnu fasciklu +Gore za jedan nivo +Hronologija... +Osvežavanje +750 +Rad sa arhivama +Rad sa datotekama +Velika dugmad +Prikaži tekst ispod dugmadi +800 +Dodaj +Izaberi +900 +Opcije... +Benchmark +960 +Pomoć... +O programu... +1003 +Putanja +Naziv +Tip +Fascikla +Veličina +Veličina u zapakovanom stanju +Atributi +Kreirana +Pristupano +Promenjeno +Solidno +Komentar +Šifrovano +Podeli pre +Podeli posle +Rečnik +CRC +Tip +Anti +Metod +Operativni sistem +Sistem datoteka +Korisnik +Grupa +Blok +Komentar +Položaj +Prefiks putanje +Fascikle +Datoteke +Verzija +Volumen +VišeVolumena +Ofset +Linkovi +Blokovi +Volumeni + +64-bit +Big-endian +Procesor +Fizička veličina +Veličina zaglavlja +Provera rezultata +Karakteristike +Virtuelna adresa +ID +Kratko ime +Kreator aplikacije +Veličina sektora +Način +Link +Greška +Ukupni kapacitet +Slobodni prostor +Veličina cluster-a +Naziv +Lokalno ime +Provajder +2100 +Opcije +Jezik +Jezik: +Promene u datotekama +Program: +Razlika: +2200 +Sistem +7-Zip otvara sledeće tipove datoteka: +2301 +Ubaci 7-Zip u sistemski meni +Kaskadni sistemski meni +Stavke sistemskog menija: +2320 + + +Otvori arhivu +Izdvoj datoteke... +Dodaj u arhivu... +Testiraj arhivu +Izdvoj ovde +Izdvoj u {0} +Dodaj u {0} +Dodaj i napravi e-mail... +Dodaj u {0} i napravi e-mail +2400 +Fascikle +Radna fascikla +Koristi Windows-ovu privremenu fasciklu +Trenutna +Navedena: +Koristi samo za izmenjive medije +Navedite lokaciju za smeštanje privremenih datoteka. +2500 +Podešavanja +Prikaži ".." +Prikaži prave sličice datoteka +Prikaži sistemski meni +Obeleži ceo red +Prikaži linije mreže +Jedan klik za otvaranje stavke +Alternativni način za biranje +Koristi velike memorijske blokove +2900 +O programu +7-Zip je besplatan program. +3000 +Sistem ne može da izdvoji potrebnu količinu memorije +Nije bilo nikakvih grešaka +{0} objekat(a) izabrano +Ne mogu da kreiram Fasciklu '{0}' +Operacija osvežavanja nije dozvoljena za ovu arhivu. +Ne mogu da otvorim datoteku '(0)' kao arhiva +Ne mogu da otvorim šifrovanu arhivu '(0)'. Pogrešna lozinka? +Nepodržan tip arhive +Datoteka {0} već postoji +Datoteka '{0}' je izmjenjena.\nDa li želite ažurirati arhivu? +Nije moguće ažurirati datoteku\n'{0}' +Nije moguće započeti uređivanje. +Datoteka izgleda kao virus (ime datoteke sadrži puno razmaka u imenu). +Operacija ne može biti pozvana iz fascikle koja ima dugu putanju. +Morate da izaberete neku datoteku +Morate da izaberete jednu ili više datoteka +Isuviše stavki +3300 +Izdvajanje +Dodajem +Testiranje +Otvaranje u toku... +Skeniranje... +3400 +Izdvoj +Izdvoj u: +Navedi lokaciju gde će se izdvajati datoteke iz arhiva. +3410 +Putanje +Puna putanja +Bez putanje +3420 +Zamena +Pitaj pre nego što zameniš +Zameni bez zapitkivanja +Preskoči postojeće datoteke +Automatska promena naziva +Automatska promena naziva postojećih datoteka +3500 +Potvrdi zamenu datoteke +Ciljna fascikla već sadrži datoteku koja se trenutno obrađuje. +Da li želite da zamenite postojeću datoteku +sa ovom? +{0} bajtova +Automatska promena naziva +3700 +Nepodržani metod kompresije za '{0}'. +Greška u '{0}'. Datoteka je neispravana. +CRC greška u '{0}'. Datoteka je neispravana. +Greške u kodiranu datoteku '(0)' Pogrešna lozinka. +CRC greška u šifrovane datoteke '(0)' Pogrešna lozinka. +3800 +Unesite lozinku +Unesite lozinku: +Ponovo unesite lozinku: +Prikaži lozinku +Lozinke se ne poklapaju +Koristi samo engleska slova, brojeva i specijalnih znakova (!, #, $, ...) Za lozinke +Lozinka je predugačka +Šifra +3900 +Proteklo vreme: +Preostalo vreme: +Veličina: +Brzina: +Obrađeno: +Kompresioni odnos: +Greške: +Arhive: +4000 +Dodaj u arhivu +Arhiva: +Nadogradnja arhiva: +Format arhive: +Nivo kompresije: +Tip kompresije: +Dictionary size: +Word size: +Veličina čvrstog bloka: +Broj niza procesora: +Parametri: +Opcije +Kreiraj SFX arhivu +Kompresija deljene datoteka +Šifrovanje +Metoda šifrovanja: +Šifruj nazive datoteka +Potrebna memorija - kompresija: +Potrebna memorija - dekompresija: +4050 +Bez kompresije +Brže +Brzo +Normalno +Maksimalno +Najbrže +4060 +Dodaj i zameni datoteke +Osveži i dodaj datoteke +Ozveži postojeće datoteke +Sinhronizuj datoteke +4070 +Pregledaj +Sve datoteke +Ne-čvrste +Čvrsto +6000 +Kopiraj +Iseci +Kopiraj u: +Premesti u: +Kopiranje u toku... +Premeštanje u toku... +Preimenovanje u toku... +Izaberite odredišnu fasciklu. +Operacija nije podržana. +Greška pri preimenovanju datoteke ili fascikle +Potvrdi kopiranje datoteke +Da li ste sigurni da želite da kopirate datoteke u arhivu +6100 +Potvrdite brisanje datoteke +Potvrdite brisanje fascikle +Potvrdite višestruko brisanje datoteka +Jeste li sigurni da želite da obrišete '{0}'? +Jeste li sigurni da želite da obrišete fasciklu '{0}' i sav njen sadržaj? +Jeste li sigurni da želite da obrišete ove {0} podatke? +Brisanje u toku... +Greška pri brisanju datoteke ili fascikle +Sistem ne može da premesti datoteku sa dugom putu u korpu za otpatke +6300 +Kreiraj fasciklu +Kreiraj datoteku +Ime fascikle: +Ime datoteke: +Nova fascikla +Nova datoteka +Greška pri kreiranju fascikli +Greška pri kreiranju datoteka +6400 +Komentar +Komentar: +Odaberi +Poništi izbor +Maska: +6600 +Osobine +Hronologija +Dijagnostičke poruke +Poruke +7100 +Računar +Mreža +Dokumenti +Sistem +7200 +Dodaj +Izdvoj +Testiraj +Kopiraj +Premesti +Izbriši +Svojstva +7300 +Podeli datoteku +Podeli na: +Podeli na delove, bajti: +Podela... +Potvrda podele +Da li ste sigurni da želite da podelite datoteku na (0) dela? +Veličine dela mora biti manji od veličine originalne datoteke +Neispravna veličina volumena +Određena veličina volumena: {0} bajtova.\nDa li ste sigurni da želite da podelite arhivu u tih volumena? +7400 +Sastavi datoteke +Sastavi u: +Spajanje... +Izaberite samo prvi deo podele datoteke +Ne mogu da otkrijem datoteku kao deo podele +Ne može se naći više od jednog dela podele +7500 +Izračunavanje proverne veličine... +Informacija o proverne veličine +CRC porvera za podatak: +CRC provera za podatak i imena: +7600 +Benchmark +Korišćenje memorije: +Kompresija +Dekompresija +Ocena +Potpuna ocena +Trenutno +Rezultat +Upotreba procesora +Rejting/Upotreba +Prolazi: diff --git a/Utils/7-Zip/Lang/sv.txt b/Utils/7-Zip/Lang/sv.txt new file mode 100644 index 000000000..adaeeb966 --- /dev/null +++ b/Utils/7-Zip/Lang/sv.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; : Andreas M Nilsson, Christoffer Enqvist +; 4.59 : Bernhard Eriksson +; +; +; +; +; +; +; +; +; +0 +7-Zip +Swedish +Svenska +401 +OK +Avbryt + + + +&Ja +&Nej +&Stäng +Hjälp + +F&ortsätt +440 +Ja till &Alla +Nej till A&lla +Stopp +Starta om +&Bakgrunden +&Förgrunden +&Pausa +Pausad +Är du säker på att du vill avbryta? +500 +&Arkiv +&Redigera +&Visa +&Favoriter +Verkt&yg +&Hjälp +540 +&Öppna +Öppna &internt +Öppna &externt +&Visa +&Redigera +&Byt namn +&Kopiera till... +&Flytta till... +&Ta bort +&Dela upp fil... +&Sätt ihop filer... +E&genskaper +Komme&ntera +Beräkna checksumma + +Skapa mapp +Skapa fil +&Avsluta +600 +Markera &alla +Avmarkera alla +&Invertera markering +Markera... +Avmarkera... +Markera efter typ +Avmarkera efter typ +700 +St&ora ikoner +Sm&å ikoner +&Lista +&Detaljerad lista +730 +Osorterade +Platt vy +&2 Paneler +&Verktygsfält +Öppna rotmappen +Upp en nivå +Mapphistorik... +&Uppdatera +750 +Verktygsfältet Arkiv +Verktygsfältet Standard +Stora Knappar +Visa Knapptext +800 +&Lägg mappen till Favoriter som +Bokmärke +900 +&Alternativ... +&Benchmark +960 +&Innehåll... +&Om 7-Zip... +1003 +Sökväg +Namn +Filändelse +Mapp +Storlek +Storlek komprimerad +Attribut +Skapad +Använd +Ändrad +Sammanhängande (Solid) +Kommenterad +Krypterad +Delad före +Delad efter +Ordlista +CRC +Typ +Anti +Metod +Värd OS +Filsystem +Användare +Grupp +Block +Kommentar +Position +Sökvägs prefix +Kataloger +Filer +Version +Volym +Multivolym +Offset +Länkar +Block +Volymer + +64-bitars +Big-endian +CPU +Fysisk storlek +Storlek på header +Checksumma +Karakteristisk +Virtuell adress + + + + + + +Fel +Total Storlek +Ledigt utrymme +Kluster storlek +Etikett +Datornamn +Nätverkstyp +2100 +Alternativ +Språk +Språk: +Redigerare +&Redigerare: + +2200 +System +Associera med 7-Zip: +2301 +Lägg till 7-Zip som alternativ i Utforskarens högerklicksmenyn +Placera 7-Zip som en undermeny +Objekt i högerklicksmenyn: +2320 + + +Öppna +Packa upp filer... +Lägg till arkiv... +Kontrollera arkivet +Packa upp här +Packa upp till {0} +Lägg till {0} +Komprimera och skicka som e-post... +Komprimera till {0} och skicka som e-post +2400 +Mappar +&Arbetsmapp +&Systemets temp-mapp +A&ktuell +Spe&cificerad: +Använd enbart för &flyttbara enheter +Ange plats där temporära arkivfiler ska sparas. +2500 +Inställningar +Visa ".." objektet +Visa riktiga ikoner, för filer innehållande ikoner (el. länkade) +Visa system-menyn +Markera &hel rad +Visa &rutnät + +&Alternativt markeringsläge +Använd &stora minnessidor +2900 +Om 7-Zip +7-Zip är fri programvara. Du kan emellertid stödja den fortsatta utvecklingen av 7-Zip genom att donera. Den aktuella översättningen på svenska är gjord av Wermlandsdata, baserad på arbete utfört av Andreas M Nilsson och Christoffer Enqvist. +3000 +Systemet kan inte allokera den begärda minnesmängden +Inga fel påträffades +{0} objekt markerade +Kan inte skapa mapp '{0}' +Uppdatering stöds inte för det här arkivet. +Kan inte öppna filen '{0}' som ett arkiv +Kan inte öppna det krypterade arkivet '{0}'. Fel lösenord? +Arkiv typen stöds ej +Filen {0} existerar redan +Filen '{0}' har blivit ändrad.\nVill du uppdatera den i arkivet? +Kan inte uppdatera filen\n'{0}' +Kan inte starta redigeraren. +Filen verkar vara ett virus (filnamnet innehåller 'långa' mellanslag). +Operation kan inte utföras från en katalog med en så lång sökväg. +Du måste välja en fil +Du måste välja en eller flera filer +För många objekt +3300 +Packar upp +Komprimerar +Kontrollerar +Öppnar... +Skannar... +3400 +Packa upp +&Packa upp till: +Ange sökväg för uppackade filer. +3410 +&Sökvägstyp +Kompletta sökvägar +Inga sökvägar +3420 +&Överskrivning +Fråga före överskrivning +Skriv över befintliga filer +Hoppa över befintliga filer +Automatisk omdöpning +Automatisk omdöpning av befintliga filer +3500 +Bekräfta överskrivning av fil +Målmappen innehåller redan den behandlade filen. +Vill du skriva över den befintliga filen +med den här? +{0} bytes +A&utomatisk omdöpning +3700 +Komprimeringsmetoden stöds inte för '{0}'. +Datafel i '{0}'. Filen är korrupt. +CRC-fel i '{0}'. Filen är korrupt. +Datafel i den krypterade filen '{0}'. Fel lösenord? +CRC-fel i den krypterade filen '{0}'. Fel lösenord? +3800 +Ange lösenord +Ange lösenord: +Upprepa lösenord: +&Visa lösenord +Lösenorden stämmer inte överens. +Använd endast engelska tecken, siffror och special tecken (!, #, $, ...) till lösenord +Lösenordet är för långt. +&Lösenord +3900 +Förfluten tid: +Återstående tid: +Storlek: +Hastighet: +Bearbetat: +Komprimeringsgrad: +Fel: +Arkiv: +4000 +Lägg till arkiv +&Arkiv: +&Uppdateringsmetod: +Arkiv&format: +Komprimeringsniv&å: +&Komprimeringsmetod: +Storlek på &ordlista: +Storlek på o&rd: +Solit block storlek: +Antal trådar: +&Parametrar: +Alternativ +Skapa sj&älvuppackande arkiv +Komprimera delade filer +Kryptering +Krypteringsmetod: +Kryptera fil&namn +Minne behövt vid komprimering: +Minne behövt vid dekomprimering: +4050 +Okomprimerat +Snabbaste +Snabb +Normal +Maximal +Ultra +4060 +Lägg till och ersätt filer +Lägg till och uppdatera befintliga filer +Uppdatera enbart befintliga filer +Synkronisera filer +4070 +Bläddra +Alla filer +Icke-solit +Solit +6000 +Kopiera +Flytta +Kopiera till: +Flytta till: +Kopierar... +Flyttar... +Döper om... +Välj målmapp. +Funktionen stöds inte. +Ett fel uppstod under omdöpning av fil eller mapp +Bekräfta kopiering av fil +Är du säker på att du vill kopiera filerna till arkivet +6100 +Bekräfta borttagning av fil +Bekräfta borttagning av mapp +Bekräfta borttagning av flera filer +Är du säker på att du vill ta bort '{0}'? +Är du säker på att du vill ta bort mappen '{0}' och allt dess innehåll? +Är du säker på att du vill ta bort de här {0} objekten? +Tar bort... +Ett fel uppstod under borttagning av fil eller mapp +Systemet kan inte flytta en fil med s lng skvg till papperskorgen +6300 +Skapa mapp +Skapa fil +Mappnamn: +Filnamn: +Ny mapp +Ny fil +Fel vid skapande av mapp +Fel vid skapande av fil +6400 +Kommentar +&Kommentar: +Markera +Avmarkera +Filter: +6600 +Egenskaper +Mapphistorik +Diagnostiska meddelanden +Meddelande +7100 +Dator +Nätverk +Dokument +System +7200 +Lägg till +Packa upp +Testa +Kopiera +Flytta +Radera +Info +7300 +Dela Upp Fil +&Dela upp till: +Dela upp i &delar (volymer), bytes: +Delar upp... +Bekräfta uppdelning +Är det säkert du vill dela upp filen i {0} volymer? +Volymstorleken måste vara mindre än storleken på originalfilen. +Felaktig volymstorlek. +Specificerad volymstorlek: {0} byte.\nÄr du säker du vill dela arkivet i sådana delar? +7400 +Sätt Ihop Filer +&Sätt ihop till: +Sätter ihop... +Markera bara första filen +Kan inte upptäcka att filen är en del av en uppdelad fil +Kan inte hitta mer än en del av en uppdelad fil +7500 +Beräknar checksumma... +Checksumma information +CRC checksumma för data: +CRC checksumma för data och namn: +7600 +Benchmark +Minnesanvändning: +Komprimering +Dekomprimering +Prestanda +Total prestanda +Aktuellt +Resultat +CPU Användning +Rate / Användning +Omgångar: diff --git a/Utils/7-Zip/Lang/ta.txt b/Utils/7-Zip/Lang/ta.txt new file mode 100644 index 000000000..a65c116df --- /dev/null +++ b/Utils/7-Zip/Lang/ta.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 3.13 : Ve Elanjelian : ThamiZha! team : www.thamizha.com +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Tamil +தமிழ் +401 +சரி +இரத்து + + + +ஆம் +வேண்டாம் +மூடு +உதவி + +தொடரவும் +440 +அனைத்திற்கும் ஆம் +அனைத்திற்கும் இல்லை +நிறுத்து +மீள்துவங்கு +பின்புலம் +முன்புலம் +தற்காலிகமாக நிறுத்து +தற்காலிக நிறுத்தல் +உறுதியாகவே இரத்து செய்ய விரும்புகிறீர்களா? +500 +கோப்பு +பதிப்பு +பார்வை +விருப்பங்கள் +கருவிகள் +உதவி +540 +திற +உள்ளே திற +வெளியே திற +பார்வை +பதிப்பு +மாற்றுப்பெயரிடு +இங்கு நகலெடு... +இங்கு நகர்த்து... +அழி + + +தன்மைகள் +கருத்துரை + + +கோப்பை உருவாக்கு +கோப்பு உருவாக்கு +வெளியேறு +600 +அனைத்தும் தேர்ந்தெடு +அனைத்தும் நீக்கு +தெரிவை புரட்டு +தேர்ந்தெடு... +நீக்கு... +வகைப்படி தெரிவுசெய் +வகைப்படி நீக்கு +700 +பெரிய உருபிகள் +சிறிய உருபிகள் +பட்டியல் +தகவல்கள் +730 +வரிசைப்படுத்தப்படாதது + +2 பலகங்கள் +கருவிப்பட்டைகள் +வேர் அடைவைத் திற +ஒரு படி மேல் +அடைவுகளின் வரலாறு... +புதுக்கல் +750 +காப்பக கருவிப்பட்டை +பொதுவான கருவிப்பட்டை +பெரிய பொத்தான்கள் +பொத்தான்களின் உரையைக் காட்டு +800 +அடைவை விரும்பியவற்றுள் இப்படி இணை +புத்தகக்குறி +900 +விருப்பத்தேர்வு... +மதிப்பீட்டு அளவை +960 +பொருளடக்கம்... +7-ஜிப்பைப் பற்றி... +1003 +பாதை +பெயர் +நீட்டிப்பு +அடைவு +அளவு +கட்டப்பட்ட அளவு +பண்புக்கூறு +உருவாக்கப்பட்டது +அனுகப்பட்டது +மாற்றப்பட்டது +திண்மம் +கருத்துரைக்கப்பட்ட +மறைக்குறியீட்டப்பட்டது +முன் பிரி +பின் பிரி +அகராதி +CRC +வகை +தடுப்பு +வழி +புரவலரின் OS +கோப்பு மண்டலம் +பயனர் +குழு +கட்டம் +குறிப்பு + + + + + + + + + + + + + + + + + + + + + + + + + + +தவறு +மொத்த அளவு +காளி இடம் +கொத்தணியின் அளவு +வில்லை +இடத்துரி பெயர் +வழங்குபவர் +2100 +தேர்வுகள் +மொழி +மொழி: +பதிப்பாளன் +பதிப்பாளன்: + +2200 +மண்டலம் +7-ஜிப்பை இதனுடன் தொடர்புப்படுத்து: +2301 +7-ஜிப்பை வெற்று சூழல்பட்டியலுடன் ஒருங்கிணை +விழுதொடரும் சூழல் பட்டியல் +சூழல் பட்டியல் உருப்படிகள்: +2320 +<அடைவு> +<காப்பகம்> +காப்பகத்தைத் திற +கோப்புகளை வெளிக்கொணர்... +காப்பகத்தில் இணை... +காப்பகத்தைச் சோதனைசெய் +இங்கு வெளிக்கொணர் +{0}-ல் வெளிக்கொணர் +{0}-ல் இணை +இறுக்கி மின்னஞ்சலனுப்பு... +{0}-க்கு இறுக்கி அஞ்சலனுப்பு +2400 +அடைவுகள் +பணியிலுள்ள அடைவு +மண்டல தற்காலிக அடைவு +நடப்பு +குறிப்பிட்ட: +கழற்று இயக்கிகளை மட்டும் பயன்படுத்து +கோப்புகளைத் தற்காலிக காப்பகப்படுத்தும் இடத்தைக் குறிப்பிடுக. +2500 +அமைவுகள் +".." உருப்படியைக் காட்டு +கோப்பு உருபிகளைக் காட்டு +மண்டல பட்டியலைக் காட்டு + + + + + +2900 +7-ஜிப்பைப் பற்றி +தமிழாக்கம் (c) 2004 தமிழா! குழு - www.thamizha.com/\n\n7-ஜிப் ஒரு பரிநிரல் ஆகும். ஆனால், நீங்கள் 7-ஜிப்பின் மேம்பாட்டை ஆதரிக்க விரும்பினால், பதிவுபெற்றுங்கள். பதிவுபெற்ற பயனராக, நீங்கள் தொழில்நுட்ப உதவியும் பெறலாம். +3000 + +தவறுகளேதுமில்லை +{0} பொருள் தெரிவானது +'{0}' அடைவை உருவாக்க இயலவில்லை +இக்காப்பகத்தில் புதுப்பிக்கும் செயல்களுக்கு ஆதரவில்லை. + + + + +'{0}' கோப்பு மாற்றப்பட்டது.\nஇதனை காப்பகத்தில் புதுப்பிக்க வேண்டுமா? +பின்வரும் கோப்பை புதுப்பிக்க இயலவில்லை\n'{0}' +பதிப்பாளனைத் துவக்க இயலவில்லை. + + + + +மிகவும் அதிகமான உருப்படிகள் +3300 +வெளிக்கொணரப்படுகின்றது +இறுக்கப்படுகின்றது +சோதனை... +திறக்கப்படுகின்றது... + +3400 +வெளிக்கொணர் +இங்கு வெளிக்கொணர்: +வெளிக்கொணர்ந்த கோப்புகளுக்கான இடத்தைக் குறிப்பிடு. +3410 +பாதை முறைமை +முழு பாதைப்பெயர்கள் +பாதைப்பெயர்களில்லை +3420 +மேலெழுதல் முறைமை +மேலெழுதுவதற்கு முன் கேள் +கேட்காமல் மேலெழுது +தற்பொழுதுள்ள கோப்புகளைத் தவிர் +தானாக மாற்றுப்பெயரிடு + +3500 +கோப்பு மாற்றத்தை உறுதிசெய் +சேரிட அடைவு ஏற்கனவே செயல்படுத்தப்பட்ட கோப்பைக் கொண்டுள்ளது. +தற்பொழுதுள்ள கோப்பை +இதக்கொண்டு மாற்ற விரும்புகிறீர்களா? +{0} பைட்கள் +தானாக மாற்றுப்பெயரிடு +3700 +'{0}'-ல் ஆதரவில்லாத இறுக்கல் முறை. +'{0}'-ல் தரவுத் தவறு. கோப்பு முறிந்துள்ளது. +'{0}'-ல் CRC தோல்வியுற்றது. கோப்பு முறிந்துள்ளது. + + +3800 +கடவுச்சொல்லை உள்ளிடுக +கடவுச்சொல்லை உள்ளிடுக: + +கடவுச்சொல்லை காட்டு + + + +கடவுச்சொல் +3900 +மீதமுள்ள நேரம்: +மீதமுள்ள நேரம்: +அளவு: +வேகம்: + + +தவறுகள்: + +4000 +காப்பகத்திலிணை +காப்பகம்: +புதுபிக்கும் முறைமை: +காப்பக வடிவம்: +இறுக்க வகை: +இறுக்கும் வழி: +அகராதி அளவு: +வார்த்தை அளவு: + + +அளபுருகள்: +விருப்பத்தேர்வுகள் +SFX காப்பகம் உறுவாக்கு + + + +பெயரை மறைக்குறியீடாக்கு +இறுக்க நினைவக பயன்பாடு: +பெருக்க நினைவக பயன்பாடு: +4050 +தேக்கு +அதிவிரைவான +விரைவான +சாதாரண +அதிகமான +சிறப்பான +4060 +சேர்த்து கோப்புகளை மாற்று +புதிப்பித்து கோப்புகளை சேர் +உள்ள கோப்புகளைப் புதுப்பி +கோப்புகளை ஒத்தியக்கு +4070 +உலாவு +அனைத்து கோப்புகளும் + + +6000 +நகல் +நகர்த்து +இங்கு நகலெடு: +இங்கு நகர்த்து: +நகலெடுக்கப்படுகிறது... +நகர்த்தப்படுகிறது... +பெயர்மாற்றப்படுகிறது... + +அத்தகைய செயலுக்கு ஆதரவில்லை. +கோப்பையோ அடைவையோ பெயர்மாற்றும்போது தவறு + + +6100 +கோப்பு அழிப்பை உறுதிசெய் +அடைவு அழிப்பை உறுதிசெய் +பல கோப்பு அழிப்பை உறுதிசெய் +'{0}'-ஐ உறுதியாக அழிக்க விரும்புகிறீர்களா? +'{0}' அடைவையும் அதிலுள்ளவற்றயும் உறுதியாகவே அழிக்க விரும்புகிறீர்களா? +இந்த {0} உருப்படிகளை உறுதியாக அழிக்க விரும்புகிறீர்களா? +அழிக்கப்படுகிறது... +கோப்பையோ அடைவையோ அழிக்கும்போது தவறு + +6300 +அடைவு உருவாக்கு +கோப்பு உருவாக்கு +அடைவின் பெயர்: +கோப்பின் பெயர்: +புதிய அடைவு +புதிய கோப்பு +அடைவு உருவாக்கும்போது தவறு +கோப்பு உருவாக்கையில் தவறேற்பட்டது +6400 +கருத்துரை +கருத்துரை: +தெரிவுசெய் +நீக்கு +முகமுடி: +6600 + +அடைவுகளின் வரலாறு +அறிவழிச் செய்திகள் +செய்தி +7100 +கணினி +பிணையம் + +மண்டலம் +7200 +இணை +வெளிக்கொணர் +பரிசோதி +நகல் +நகர்த்து +அழி +தகவல் +7300 + + +கனவளவுகளுக்கு, பைட்களுக்குப் பிரி: + + + + + + +7400 + + + + + + +7500 + + + + +7600 +மதிப்பீட்டு அளவை +நினைவக பயன்: +இறுக்கப்படுகையில் +பெருக்கப்படுகையில் +புள்ளிகள் +மொத்த புள்ளிகள் +நடப்பு +முடிவில் + + +சரியானவை: diff --git a/Utils/7-Zip/Lang/th.txt b/Utils/7-Zip/Lang/th.txt new file mode 100644 index 000000000..96e06cc03 --- /dev/null +++ b/Utils/7-Zip/Lang/th.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.09 : Chayanon Ruamcharoen +; 4.10 : Zafire06 +; 9.13 : Kom10 +; +; +; +; +; +; +; +; +0 +7-Zip +Thai +ไทย +401 +ตกลง +ยกเลิก + + + +&ใช่ +&ไม่ +&ออก +ช่วยเหลือ + +&ดำเนินการต่อ +440 +ใช่ทั้งหมด +ไม่ทั้งหมด +หยุด +ฟื้นฟู +&ทำงานเป็นพื้นหลัง +&ทำงานเป็นพื้นหน้า +&หยุดชั่วคราว +หยุดชั่วคราว +คุณแน่ใจหรือว่าจะยกเลิก +500 +&แฟ้ม +&แก้ไข +&มุมมอง +&รายการโปรด +&เครื่องมือ +&ช่วยเหลือ +540 +&เปิด +เปิดในหน้าต่างเดิม +เปิดในหน้าต่างใหม่ +&มุมมอง +&แก้ไข +&เปลี่ยนชื่อ +&คัดลอกไปที่... +&วางที่... +&ลบ +&แยกไฟล์... +รวมไฟล์... +&คุณสมบัติ +&หมายเหตุ +คำนวณ checksum +Diff +สร้างโฟลเดอร์ +สร้างไฟล์ +ออก +600 +เลือกทั้งหมด +ยกเลิกการเลือกทั้งหมด +&สลับการเลือกให้เป็นตรงกันข้าม +เลือก... +ยกเลิกการเลือก... +เลือกด้วยแบบชนิด +ยกเลิกการเลือกด้วยแบบชนิด +700 +&ไอคอนขนาดใหญ่ +&ไอคอนขนาดเล็ก +&แสดงเป็นรายการ +&แสดงแบบละเอียด +730 +ไม่เลือก +แสดงไฟล์และโฟลด์เดอร์ทั้งหมด +&แสดง 2 แผง +&แถบเครื่องมือ +เปิดรากโฟลเดอร์ +เลื่อนขึ้นหนึ่งระดับ +ประวัติโฟลเดอร์... +&ฟื้นฟู +750 +แถบเครื่องมือเอกสาร +แถบเครื่องมือธรรมดา +ปุ่มขนาดใหญ่ +แสดงข้อความบนปุ่ม +800 +&เพิ่มโฟลเดอร์เข้ารายการโปรด +คั่นหน้าที่ +900 +&ตัวเลือก... +&เกณฑ์เปรียบเทียบสมรรถนะ +960 +&เนื้อหาและดัชนี... +&เกี่ยวกับ 7-Zip... +1003 +ที่ตั้ง +ชื่อ +ชนิด +โฟลเดอร์ +ขนาด +ขนาดเมื่อถูกจัดเก็บ +ลักษณะประจำ +สร้างเมื่อ +เข้าถึงเมื่อ +ดัดแปรเมื่อ +ต่อเนื่อง +หมายเหตุ +การเข้ารหัสลับ +ก่อนแบ่ง +หลังแบ่ง +ดิคชันนารี +ซีอาร์ซี +แบบชนิด +ต่อต้าน +วิธีการ +OS ที่ใช้ +ไฟล์ระบบ +ผู้ใช้ +กลุ่ม +บล็อก +หมายเหตุ +ตำแหน่ง +คำนำหน้าที่ตั้ง +โฟลเดอร์ +ไฟล์ +เวอร์ชั่น +วอลลุ่ม +มัลติวอลลุ่ม +ออฟเซ็ท +ลิ้งค์ +บล็อค +Volumes + +64-บิท +Big-endian +CPU +ขนาดทางกายภาพ +ขนาดเฮดเดอร์ +Checksum +คุณลักษณะ +Virtual Address +ID +ชื่อย่อ +ผู้สร้างโปรแกรม +ขนาด Sector +โหมด +ลิงค์ +เกิดข้อผิดพลาด +ขนาดทั้งหมด +ช่องว่างที่เหลืออยู่ +ขนาดกลุ่ม +ป้าย +ชื่อเฉพาะ +ผู้ให้บริการ +2100 +ตัวเลือก +ภาษา +ภาษา: +บรรณาธิกรณ์ +&บรรณาธิกรณ์: +&Diff: +2200 +ระบบ +ทำให้ 7-Zip ทำงานร่วมกับ: +2301 +รวบรวมคำสั่ง 7-Zip ไปที่แถบเมนูลัด +แยกเป็นแถบคำสั่ง 7-Zip +วัตถุที่ปรากฏบนเมนูลัด: +2320 +<โฟลเดอร์> +<เอกสาร> +เปิดเอกสาร +แยกไฟล์... +เพิ่มเข้าเอกสาร... +ทดสอบเอกสาร +แยกไฟล์ที่นี่ +แยกไฟล์ไปที่ {0} +เพิ่มเข้า {0} +บีบอัดแล้วส่งอีเมลล์... +บีบอัดเป็น {0} แล้วส่งอีเมลล์ +2400 +โฟลเดอร์ +&โฟลเดอร์ที่ทำงานอยู่ +&โฟลเดอร์ต่างๆของระบบ +&โฟลเดอร์ปัจจุบัน +&ระบุ: +ใช้สำหรับไดรฟ์แบบถอดได้เท่านั้น +ระบุที่ตั้งสำหรับไฟล์เอกสารชั่วคราว +2500 +กำหนด +แสดงวัตถุ ".." +แสดงไอคอนไฟล์ที่แท้จริง +แสดงเมนูระบบ +&เลือกเต็มแถว +แสดง &เส้นกริด +คลิกครั้งเดียวเพื่อเปิดไฟล์ +&โหมดการเลือกอื่น +ใช้ &เพจความจำขนาดใหญ่ +2900 +เกี่ยวกับ 7-Zip +7-Zip เป็นฟรีแวร์ อย่างไรก็ตาม คุณสามารถสนับสนุนการพัฒนาของ 7-Zip ได้โดยการลงทะเบียน เมื่อคุณเป็นผู้ใช้ที่ลงทะเบียนแล้ว คุณจะได้รับการสนับสนุนทางเทคนิคจากเรา +3000 +ระบบไม่สามารถใช้หน่วยความจำตามที่ระบุได้ +ไม่มีข้อผิดพลาด +{0} วัตถุที่เลือกไว้ +ไม่สามารถสร้างโฟลเดอร์ '{0}' +ปรับปรุงการทำงานไม่สนับสนุนสำหรับเอกสาร +ไม่สามารถเปิดไฟล์ '{0}' เป็นเอกสารได้ +ไม่สามารถเปิดไฟล์ที่เข้ารหัสได้ '{0}' พาสเวิร์ดผิดหรือไม่? +ชนิดของไฟล์บีบอัดไม่รองรับ +ไฟล์ {0} มีอยู่แล้ว +ไฟล์ '{0}' ได้ถูกดัดแปรแล้ว\nคุณต้องการจะปรับปรุงเอกสารหรือไม่ +ไม่สามารถปรับปรุงไฟล์\n'{0}' +ไม่สามารถเปิดตัวแก้ไขได้ +ไฟล์อาจเป็นไวรัส (ชื่อไฟล์มีช่องว่างยาว) +ไม่สามารถดำเเนินการได้จากโฟลเดอร์ที่มีที่ตั้งยาว +ท่านต้องเลือกไฟล์ +ท่านต้องเลือกไฟล์หนึ่งไฟล์หรือมากว่า +มีวัตถุมากเกินไป +3300 +กำลังแยกไฟล์ +กำลังบีบอัด +กำลังทดสอบ +กำลังเปิด... +กำลังสแกน... +3400 +แยกไฟล์ +แยกไฟล์ไปที่: +ระบุที่ตั้งสำหรับไฟล์ที่แยกออกมา +3410 +ที่ตั้ง +ชื่อที่ตั้งแบบเต็ม +ไม่มีชื่อที่ตั้ง +3420 +การบันทึกทับ +ถามก่อนมีการบันทึกทับ +บันทึกทับโดยไม่มีข้อความพร้อมรับ +ข้ามไฟล์ที่มีอยู่ +เปลี่ยนชื่ออัตโนมัติ +เปลี่ยนชื่อไฟล์ที่มีอยู่อัตโนมัติ +3500 +ยืนยันการแทนที่ไฟล์ +โฟลเดอร์ปลายทางมีไฟล์ที่ได้ประมวลผลแล้ว +คุณต้องการแทนที่ไฟล์ที่มีอยู่หรือไม่ +ด้วย +{0} ไบต์ +เปลี่ยนชื่ออัตโนมัติ +3700 +ไม่รองรับวิธีการบีบอัดนี้สำหรับ '{0}' +ข้อมูลใน '{0}' ผิดพลาด ไฟล์ชำรุด +ซีอาร์ซีใน '{0}' ไม่สามารถใช้การได้ ไฟล์ชำรุด +ข้อมูลในไฟล์บีบอัด '{0}' ผิดพลาด รหัสผ่านไม่ถูกต้อง? + +3800 +ใส่รหัสผ่าน +ใส่รหัสผ่าน: +ใส่รหัสผ่านอีกครั้ง: +&แสดงรหัสผ่าน +รหัสผผ่านไม่ตรง +ตั้งรหัสผ่านด้วยอักษรภาษาอังกฤษ หรืออักขระ (!, #, $, ...) +รห้สผ่านยาวเกินไป +รหัสผ่าน +3900 +ใช้เวลาไปแล้ว: +ต้องใช้เวลาอีก: +ขนาด: +ความเร็ว: +ดำเนินการแล้ว: +อัตราส่วนการบีบอัด: +ความผิดพลาด: +เอกสาร: +4000 +เพิ่มเข้าเอกสาร +&เอกสาร: +&การปรับปรุง: +รูปแบบการบีบอัดที่ต้องการใช้: +อัตราการบีบอัด: +&วิธีการบีบอัด: +&ขนาดดิคชันนารี: +&ขนาดอักษร: +ขนาด Solid block: +จำนวน CPU threads: +&พารามิเตอร์: +ตัวเลือก +สร้างเอกสาร SFX +บีบอัดแชร์ไฟล์ +การเข้ารหัส +วิธีการเข้ารหัส: +สร้างรหัสผ่าน +หน่วยความจำที่ใช้ในการบีบอัด: +หน่วยความจำที่ใช้ในการแตกออก: +4050 +เก็บเฉยๆ +เร็วที่สุด +เร็ว +ปกติ +ดี +ดีที่สุด +4060 +เพิ่มและแทนที่ไฟล์ +ปรับปรุงและเพิ่ม +ทำให้ไฟล์ที่มีอยู่ใช้การได้ดีขึ้น +ทำให้ไฟล์ประสานกัน +4070 +ค้นดู +ไฟล์ทั้งหมด +Non-solid +Solid +6000 +คัดลอก +ย้าย +คัดลอกไปที่: +ย้ายที่: +กำลังคัดลอก... +กำลังวาง... +กำลังเปลี่ยนชื่อ... +เลือกโฟลเดอร์ที่ตั้ง +การปฏิบัติการไม่สนับสนุน +เกิดข้อผิดพลาดในการเปลี่ยนชื่อไฟล์หรือโฟลเดอร์ +ยืนยันการคัดลอกไฟล์ +ท่านมั่นใจที่จะคัดลอกไฟล์ไปยังเอกสารหรือไม่ +6100 +ยืนยันการลบไฟล์ +ยืนยันการลบโฟลเดอร์ +ยืนยันการลบไฟล์แบบควบซ้อน +คุณแน่ใจหรือว่าคุณต้องการจะลบไฟล์ '{0}'? +คุณแน่ใจหรือว่าคุณต้องการจะลบโฟลเดอร์ '{0}' และข้อมูลของมันทั้งหมด +คุณแน่ใจหรือว่าจะลบวัตถุ {0} เหล่านี้ +กำลังลบ... +เกิดข้อผิดพลาดในการลบไฟล์หรือโฟลเดอร์ +ระบบไม่สามารถย้ายไฟล์ที่ชื่อที่ตั้งยาวไปยังถังขยะได้ +6300 +สร้างโฟลเดอร์ +สร้างไฟล์ +ชื่อโฟลเดอร์: +ชื่อไฟล์: +โฟลเดอร์ใหม่ +ไฟล์ใหม่ +เกิดข้อผิดพลาดในการสร้างโฟลเดอร์ +เหิดข้อผิดพลาดในการสร้างไฟล์ +6400 +หมายเหตุ +&หมายเหตุ: +เลือก +ยกเลิกการเลือก +ตัวพราง: +6600 +คุณสมบัติ +ประวัติโฟลเดอร์ +ข้อความวินิจฉัย +ข้อความ +7100 +คอมพิวเตอร์ +เครือข่าย +เอกสาร +ระบบ +7200 +เพิ่มเข้า +แยกไฟล์ +ทดสอบ +คัดลอก +ย้าย +ลบ +เกี่ยวกับ +7300 +แยกไฟล์ +&แยกไปยัง: +ขนาดไฟล์ที่ต้องการแบ่ง, ไบต์: +กำลังแยก... +ยืนยันการแยก +ท่านมั่นใจว่าต้องการแยกไฟล์เป็น {0} volumes? +ขนาด Volume ต้องเล็กกว่าขนาดไฟล์ต้นฉบับ +ขนาด volume ไม่ถูกต้อง +ระบุขนาด volume: {0} ไบท์.\nท่านมั่นใจว่าต้องการแบ่งไฟล์เป็น volumes ดังกล่าว? +7400 +รวมไฟล์ +&รวมไปยัง: +กำลังรวม... +เลือกเฉพาะส่วนแรกของไฟล์แยก +ไม่สามารถตรวจพบไฟล์ว่าเป็นส่วนหนึ่งของไฟล์แยก +ไม่สามารถหาไฟล์แยกได้มากหนึ่ง +7500 +กำลังคำนวณ Checksum... +ข้อมูล Checksum +CRC checksum ของข้อมูล: +CRC checksum ของข้อมูลและชื่อ: +7600 +เกณฑ์เปรียบเทียบสมรรถนะ +หน่วยความจำที่ใช้: +การบีบอัด +การยกเลิกบีบอัด +เกณฑ์ความสามารถ +เกณฑ์ความสามารถทั้งหมด +ปัจจุบัน +ผลการประเมิน +การใช้งาน CPU +ประสิทธิภาพ /การใช้งาน +ข้อความ: diff --git a/Utils/7-Zip/Lang/tr.txt b/Utils/7-Zip/Lang/tr.txt new file mode 100644 index 000000000..c0f3ae379 --- /dev/null +++ b/Utils/7-Zip/Lang/tr.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : 2009-09-22 : X-FoRcE +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Turkish +Türkçe +401 +Tamam +İptal + + + +&Evet +&Hayır +&Kapat +Yardım + +De&vam et +440 +Tümüne E&vet +Tümüne Ha&yır +Dur +Tekrar başlat +&Arka planda +Ö&nde +&Duraklat +Duraklatıldı - +İptal edilsin mi? +500 +&Dosya +Dü&zenle +Gö&rüntüle +Sı&k Kullanılanlar +&Araçlar +&Yardım +540 +&Aç +Pa&nelde Aç +Pence&rede Aç +&Görüntüle +Dü&zenle +Yeni a&d ver +K&opyala +&Taşı +&Sil +&Parçala... +&Birleştir... +Öz&ellikler +Açıkla&ma +Toplam checksum hesapla +Fark +Yeni k&lasör +Yeni dos&ya +Çı&k +600 +&Tümünü seç +Tüm seçimi ka&ldır +&Aksini seç +Seç... +Seçimi kaldır... +Bu uzantıyı seç +Uzantılı seçimi kaldır +700 +&Büyük Simgeler +&Küçük Simgeler +&Liste +&Detaylar +730 +Sırasız +Düz Görünüm +&2 Panel aç +&Araç çubukları +Kök Klasörü Aç +Bir Seviye Yukarı +Klasör Geçmişi... +&Yenile +750 +Arşiv çubuğu +Standart çubuk +Büyük düğmeler +Düğme metinleri görünsün +800 +Geçerli &klasörü ekle +Yer +900 +&Seçenekler... +&Performans ölçümü +960 +İç&indekiler... +7-Zip &Hakkında... +1003 +Yol +Ad +Uzantı +Klasör +Boyut +Arşivde boyutu +Öznitelikler +Oluşturma +Erişim +Değiştirme +Katı +Açıklanmış +Şifrelenmiş +Önceki parça +Sonraki parça +Sözlük +CRC +Tür +Anti +Sıkıştırma şekli +İşletim sistemi +Dosya Sistemi +Kullanıcı +Grup +Blok +Açıklama +Konum +Yol Öneki +Klasörler +Dosyalar +Sürüm +Cilt +Çoklu Cilt +Konum +Bağlantılar +Bloklar +Ciltler + +64-bit +Big-endian +İşlemci +Fiziksel Boyut +Başlık Boyutu +Checksum +Karakteristik +Sanal Adres +ID +Kısa İsim +Oluşturan Yazılım +Kesim Boyutu +Biçim +Bağlantı +Hata +Toplam Boyut +Boş Alan +Küme Boyutu +Etiket +Yerel Ad +Sağlayıcı +2100 +Seçenekler +Dil +Dil: +Düzenleyici +Metin &düzenleyici: +&Fark: +2200 +Sistem +7-Zip ile ilişkilendir: +2301 +İçerik menülerinde 7-Zip görünsün +Kademeli içerik menüsü +İçerik menü öğeleri: +2320 + + +Arşivi aç +Dosyaları çıkart... +Arşivle... +Arşivi sına +Burada çıkart +{0} klasörüne çıkart +{0} olarak arşivle +Sıkıştırıp postala... +{0} olarak sıkıştır ve postala +2400 +Klasörler +Ça&lışma klasörü +&Sistem TEMP klasörü +&Geçerli klasör +&Belirtilen klasör: +Sadece çıkarılabilen sürücüler için kullan +Geçici arşiv dosyaları için bir yer belirleyin. +2500 +Ayarlar +".." öğesi görünsün +Gerçek dosya simgeleri görünsün +Sistem menüsü görünsün +&Tüm satır seçilsin +Tabl&o çizgileri görünsün +Öğeyi açmak için tek tıkla +&Alternatif seçim kipi +Geniş &bellek sayfaları kullan +2900 +7-Zip hakkında +7-Zip özgür bir yazılımdır. Ancak, kayıt olarak 7-zip geliştirme faaliyetine destek olabilirsiniz. +3000 +Sistem gerekli belleği ayarlayamadı +Hata yok. +{0} adet öğe seçili +'{0}' klasörü oluşturulamıyor +Bu arşiv üzerinde güncelleme yapamazsınız. +'{0}' arşiv dosyası olarak açılamıyor. +'{0}' dosyası açılamıyor. Şifreniz yanlış olabilir mi? +Desteklenmeyen arşiv tipi +Dosya {0} zaten mevcut +'{0}' dosyası değişmiş.\nArşivde güncellensin mi? +'{0}' dosyası güncellenemedi +Metin düzenleyici başlatılamadı. +Bu dosya virüs gibi görünüyor.(Dosya ismi uzun boşluk içeriyor). +The operation cannot be called from a folder that has a long path. +Bir dosya seçmelisiniz +Bir veya daha fazla dosya seçmelisiniz +Çok fazla öğe +3300 +çıkartılıyor +sıkıştırılıyor +Sınanıyor +açılıyor... +Taranıyor... +3400 +Çıkart +&Çıkartılacak yer: +Çıkartılacak dosyalar için bir yer belirleyin. +3410 +Yol adları +Tam yol adları +Yol adları olmasın +3420 +Olan dosyalar +Üzerine yazmak için sor +Sormadan üzerine yaz +Çıkartma +Arşivdekilere yeni ad ver +Olanlara yeni ad ver +3500 +Üzerine Yazma Durumu +Hedef klasörde bu adla bir dosya var. Üzerine yazılsın mı? +Mevcut dosya: +Çıkartılan dosya: +{0} bayt +&Yeni ad ver +3700 +'{0}' için sıkıştırma şekli tanınamadı. +'{0}' bozuk. (Veri hatası) +'{0}' bozuk. (CRC hatası) +Şifrelenmiş '{0}' dosyası hatalı. Şifreniz yanlış olabilir mi? +'{0}' dosyasında CRC hatası. Şifreniz yanlış olabilir mi? +3800 +Parola Girişi +Parolayı girin: +Şifre tekrarı: +Par&ola görünsün +Şifreler birbiriyle uyuşmuyor. +Şifre için İngilizce harfler, sayılar ve özel karekterden (!, #, $, ...) kullanabilirsiniz. +Şifre çok uzun +Parola +3900 +Geçen süre: +Kalan süre: +Boyut: +Hız: +İşlenen: +Sıkıştırma oranı: +Hatalı: +Arşivler: +4000 +Arşivle +&Arşiv: +&Güncelleme şekli: +Arşiv &biçimi: +Sıkıştırma dü&zeyi: +Sı&kıştırma şekli: +&Sözlük boyutu: +Ke&lime boyutu: +Aralıksız blok boyutu: +İşlemci iş parçası sayısı: +&Parametreler: +Seçenekler +Ke&ndi çıkartsın (SFX) +Paylaşılan dosyaları sıkıştır +Şifreleme +Şifreleme metodu: +Dosya adlarını şi&frele +Bellek kullanımı (Sıkıştırma): +Bellek kullanımı (Çözme): +4050 +Sıkıştırmasız +En hızlı +Hızlı +Normal +Maksimum +Ultra +4060 +Dosyaları ekle, olanları çıkart +Dosyaları ekle, eskileri güncelle +Sadece eskileri güncelle +Dosyaları eşitle +4070 +Gözat +Tüm dosyalar +Aralıklı +Aralıksız +6000 +Kopyala +Taşı +Kopyalanacak yer: +Taşınacak yer: +Kopyalanıyor... +Taşınıyor... +Dosya Adı Değiştiriliyor... +Hedef klasörü seçiniz. +Bu klasör için istenen işlem desteklenmiyor. +Dosya veya Klasör Adlandırma Hatası +Kopyalama Onayı +Dosyalar arşive kopyalansın mı +6100 +Dosya Silme Onayı +Klasör Silme Onayı +Birden Fazla Dosya Silme Onayı +'{0}' silinsin mi? +'{0}' klasörü ve içindekiler silinsin mi? +{0} silinsin mi? +Siliniyor... +Dosya veya Klasör Silme Hatası +Dosya yolu uzun olduğundan Geri Dönüşüm Kutusuna taşınamıyor +6300 +Yeni klasör +Yeni dosya +Klasör adı: +Dosya Adı: +Yeni Klasör +Yeni Dosya +Klasör Oluşturma Hatası +Dosya Oluşturma Hatası +6400 +Açıklama +&Açıklama: +Seç +Seçimi kaldır +Seçim ifadesi: +6600 +Özellikler +Klasör Geçmişi +Tanılayıcı iletiler +İleti +7100 +Bilgisayar +Ağ +Belgeler +Sistem +7200 +Arşivle +Çıkart +Sına +Kopyala +Taşı +Sil +Bilgi +7300 +Parçala +Şu &klasörde parçala: +Bayt/&cilt olarak parçala: +Parçalanıyor... +Silmeyi onaylayın +Dosyayı {0} parçaya ayırmak istediğinizden emin misiniz? +Parça büyüklüğü, orjinal dosya boyutundan küçük olmalıdır +Yanlış cilt boyutu +Belirtilen cilt boyutu: {0} bayt.\nBu boyutta ciltlere ayırmak istediğinize emin misiniz? +7400 +Birleştir +Şu &klasörde birleştir: +Birleştiriliyor... +Sadece ilk parçayı seçiniz +Parçalanan dosya tespit edilemedi +Parçalanmış dosyanın bir parçadan fazlası bulunamadı +7500 +Checksum değeri hesaplanıyor... +Checksum bilgisi +Verinin CRC değeri: +Verinin CRC değeri ve isimler: +7600 +Bilgisayar performansı +Bellek kullanımı: +Sıkıştırılıyor +Çözülüyor +Puan +Toplam Puan +Mevcut +Sonuç +İşlemci kullanımı +Puan / Kullanım +Başarılı: diff --git a/Utils/7-Zip/Lang/tt.txt b/Utils/7-Zip/Lang/tt.txt new file mode 100644 index 000000000..878f6cec0 --- /dev/null +++ b/Utils/7-Zip/Lang/tt.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.16 : Amychok : (Ne laŭdiĝu ke vi scias multajn lingvojn hontu ke vi ne scias patran lingvon) +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Tatar +Татарча +401 +Ярый +Юкка чыгару + + + +&Әйе +Юк& +&Ябырга +Ярдәм + +&Бару +440 +&Барысынга әйе +Барысынга юк +Стоп +Яңадан +&Җирлектә +&Алга +&Тыныш +Тынышта +Сезгә чынлап киләме операцияне өзәргә? +500 +&Файл +&Төзәтү +&Кыяфәт +&Сайланма +&Кораллар +&Белешмә +540 +&Ачырга +&Ачырга эчендә +&Ачырга тышында +&Карау +&Редакцияләү +Исе&м үзгәрү +&Кабатларга монда... +&Күчәрергә монда... +&Бетерергә +&Ватырга файлны... +Берләштерергә &файлларны... +&Үзлекләр +&Аңлатма +Тикшерү җыелма +Diff +&Ясарга папканы... +&Ясарга файлны... +&Чыгу +600 +&Сайларга бөтенесене +Сайлануны алырга +&Сайлануны әйләндерергә +Сайларга +Сайлануны алырга +Сайларга төр буенча +Алырга сайлануны төр буенча +700 +&Зур галәмәтләр +&Вак галәмәтләр +&Исемлек +&Җәдвәл +730 +Сортлаусыз +Яссы тарыз +&2 тәрәзә +&Кораллар тактасы +Ачырга тамыр папканы +Бер дәрәҗәгә өскәрәк +Элеккеге папкалар... +&Яңартырга +750 +Архивчының кнопкалар тактасы +Кнопкаларның стандарт тактасы +Зур кнопкалар +Язмалар кнопкаларда +800 +&Өстәрге папканы сайланмага, көбәк: +Китап битбилге +900 +&Көйләр... +&Җитештерүчәнлекне cыналу +960 +&Эчтәлек... +7-Zip &турында... +1003 +Юл +Исем +Киңәеш +Папка +Зурлык +Кысык +Үзенчәлекләр +Ясалган +Ачылган +Үзгәртелгән +Бөтен +Аңлатма +Шифрланган +Ватылган моңа кадәр +Аннан соң ватылган +Сүзлек +CRC +Төр +Каршы +Ысул +Система +Файл система +Кулланучы +төркем +Блок +Тәфсир +Торыш +Юл +Папка +Файл +Сүрүм +Том +Күп томлы +Күченү +Сылтамалар +Блок +Том + +64-бит +Big-endian +Барыштыручы +Физик Зурлыгы +Сәрләүхәрнең зурлыгы +тикшерү җыелма +Сыйфатламалар +Санал Адресы +ID +Кыска Исеме +Ясаучы +Бүлемтекнең Зурлыгы +Тарыз +Сылтама +Ялгыш +Сыемлык +Буш +Күмәк зурлыгы +Тамга +Урындагы исеме +Җибәрүче +2100 +Көйләр +Тел +Тел: +Мөхәрир +&Мөхәрир: +&Diff: +2200 +Система +7-Zip бәйләргә: +2301 +Тыгарга 7-Zip'ны ярының контекст менюга +Каскадлы контекст меню +Баглам меню гонсырлар: +2320 +<Папка> +<Архив> +Архив ачу +Чишү +Архивка өстәрге +Сынарга +Чишенергә монда +Чишенергә: {0}' папкага +Өстәрге: {0}ка +Кысып җибәрергә e-mail аша... +Кысып {0}ка, җибәрергә e-mail аша +2400 +Папкалар +&Эш папка +&Системаның вакытлы папкасы +&Агымдагы +&Күрсәтергә: +Файдаланырга алмаш таратучылар өчен генә +Сайлагыз урыны вакытлы архивларга +2500 +Көйләр +Күрсәтергә гонсырны".." +Күрсәтергә чынбарлык файлларның сынчыкларны +Күрсәтергә систем меню +Күрсәткечне бөтен юлга +Күрсәтергә бүлгечләрне +Ачырга чиртү белән +Альтернатив билге тарызы +Файдаланырга иснең зур битләр белән +2900 +7-Zip программа турында +Программа 7-Zip тараттылыра бушлай +3000 +Буш исе җитми +Ялгышлар юк +{0} объект сайлаган +Архив ясап булмады: {0} +Бу архив өчен үзгәртү операцияләр эшләмилер. +Файл ачып булмады '{0}' архив кебек +Шифрлы архив ацып булмады '{0}'. Пароль туры килмәде? +Программа бу архив төрә белән эшләми +Файл {0} бар инде +Файл '{0}' үзгәргән иде.\nСезгә килә яңартырга аны архивта? +Файл яңартып булмады\n'{0}' +Мөхәрирне җибәреп булмады. +Файл вируска охшаган (файл исемендә озын аралар эзлеклелеге бар). +Операция башкарылганга булдыралмы папкадан озын юл бөлән. +Сез бер файл сайларга тиеш +Сез бер я берничә файл сайларга тиеш +Гонсырлар артык күп +3300 +Чишү +Кысу бара +Сынау +Ачу... +Тарау... +3400 +Чыгарырга +Чишенергә монда: +Күрсәтегәз чыгара торган файлларга урынны. +3410 +Юллар +&Тулы юллар +Юлларсыз +3420 +Алмаш +Раслау белән +Раслаусыз +Үткәрергә +Исем үзгәрү автом. +Исем. үзгәр. автом. +3500 +Файл алмаштыруга раслау +Эшкертү торган файл папкада бар инде. +Алмаштырырга бар файлны +бу файл белән? +{0} байт +Исем үзгәрү автом. +3700 +Бу кысу ысулы файл өчен кулланылмы '{0}'. +Ялгыш мәгълүмәтләрдә '{0}'. Файл бозылган. +Ялгыш CRC'да '{0}'. Файл бозылган. +Ялгыш шифрлы файл мәгълүмәтләрдә '{0}'. Пароль дөресме? +Ялгыш шифрлы файл CRC'да '{0}'. Пароль дөресме? +3800 +Пароль язу +&Языгыз пароль: +&Кабатлагыз парольны: +&Күрсәтергә пароль +Парольлар тиңсез +Парольга языгыз латин әлифбасын галәмәтләрне гына, саннар һәм махсус галәмәтләрне (!, #, $, ...) +Пароль бик озын +Пароль +3900 +Узган: +Калган: +Барлыгы: +Тизлек: +Зурлыгы: +Кысу катылыгы: +Ялгыш: +Архив: +4000 +Архивка өстәрге +&Архив: +&Үзгәртү тарызы: +Архив форматы: +&Кысу дәрәҗәсе: +&Кысу ысулы: +&Лөгать зурлыгы: +&Cүз зурлыгы: +Блок зурлыгы: +Агымнарның исәбе: +&Параметрлар: +Опцияләр +Ясарга SF&X-архив +Кысарга яздыруга ачкан файлларны +Шифрлау +Шифрлау ысулы: +&Шифрларга файллар исемнәрне +Иснең күләме урау өчен: +Иснең күләме Чишү өчен: +4050 +Кысмаска +Бик тиз +Тиз +Гадәти +Иң зур +Ультра +4060 +Өстәрге һәм алмаштырырга +Яңартырга һәм өстәрге +Яңартырга +Синхронлаштыру +4070 +Актарырга +Бөтен файллар +Файл зурлыгына сайларга +Өзлексез +6000 +Кабатларга +Күчәрергә +Кабатларга монда: +Күчәрергә монда: +Кабатлану... +Күчү... +Исем үзгәрү... +Күрсәтегәз папканы. +Бу папка өчен операция кулланылмы. +Ялгыш файлның\папканың исем үзгәрү чакта +Файлларны кабатларга раслау +Сезгә чын киләме кабатларга бу файлларны архивка +6100 +Файл бетерүгә раслау +Папка бетерүгә раслау +Файллар төркемне бетерүгә раслау +Сезгә чын киләме бетерергә "{0}"? +Сезгә чын киләме бетерергә папканы "{0}" һәм өчендәге файлларны? +Сезгә чын киләме бетерергә бу объектларны ({0} данә)? +Бетерү... +Ялгыш файлны/папканы бетерүдә +Файллар бетерүне озын юллар белән кәрзингә система кулланылмы +6300 +Ясарга папканы +Ясарга файл +Папка исеме: +Файл исеме: +Яңа папка +Яңа файл +Ялгыш папка ясаганда +Ялгыш файл ясаганда +6400 +Аңлатма +&Аңлатма: +Сайларга +Алырга сайлануны +Үрнәк: +6600 +Үзлекләр +Элеккеге папкалар +Игъланнар +Игълан +7100 +Санак +Челтәр +Кәгазләр +Система +7200 +Өстәрге +Чыгарырга +Сынарга +Кабатларга +Күчәрергә +Бетерергә +Хәбәр +7300 +Өзергә файлны +&Өзергә монда: +&Ватырга томларга, шундый зурлыгы бөлән, байт: +Өзелү... +Өзелүгә раслау +Сезгә чын киләме өзергә файл {0} бүләккә? +Том зурлыгы чыгыш файлдан азрак булырга тиеш +Ялгыш томлар зурлыкны күрсәтү кырда +Тәгаенле том зурлыгы: {0} байт.\nСезгә чын киләме архив өзергә шундый томларга? +7400 +Берләштерергә файлларны +&Берләштерергә монда: +Берләштерү... +Кирәк сайларга өзелгән файлның беренче бүләкне гына +Өзелгән файлны белеп булмады +Өзелгән файлның табылган бер бүләк гәне +7500 +Хисаплау тикшерү җыелманы... +Тикшерү җыелма +CRC'ның тикшерү җыелмасы мәгълүматлар өчән: +CRC'ның тикшерү җыелмасы мәгълүматлар һәм исемнәр өчән: +7600 +Җитештерүчәнлекне cыналу +Иснең күләме: +Урау +Чишү +Шөһрәтлелек +Гомуми шөһрәтлелек +Агымдагы +Нәтиҗәле +Куллану +Шөһрәтлелек / Куллану. +Узу: diff --git a/Utils/7-Zip/Lang/ug.txt b/Utils/7-Zip/Lang/ug.txt new file mode 100644 index 000000000..6257c0708 --- /dev/null +++ b/Utils/7-Zip/Lang/ug.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4.59 : Sahran +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Uyghur +ئۇيغۇرچە +401 +جەزملە +ۋاز كەچ + + + +(&Y)ھەئە +ياق(&N) +ياپ(&C) +ياردەم + +داۋاملاشتۇر(&C) +440 +ھەممىسى ھەئە(&A) +ھەممىسى ياق(&L) +توختا +قايتا باشلا +ئارقا سۇپا(&B) +ئالدى سۇپا(&F) +ۋاقىتلىق توختا(&P) +ۋاقىتلىق توختىتىلدى +راستىنلا ۋاز كېچەمسىز؟ +500 +ھۆججەت(&F) +تەھرىر(&E) +كۆرۈنۈش(&V) +يىغقۇچ(&A) +قورال(&T) +ياردەم(&H) +540 +ئاچ(&O) +نۆۋەتتىكى كۆزنەكتە ئاچ(&I) +يېڭى كۆزنەكتە ئاچ(&U) +كۆرۈنۈش(&V) +تەھرىر(&E) +ئات ئۆزگەرت(&M) +كۆچۈرۈش ئورنى(&C)… +يۆتكەش ئورنى(&M)… +ئۆچۈر(&D) +ھۆججەت پارچىلا(&S)… +ھۆججەت بىرلەشتۈر(&B)… +خاسلىق(&R) +ئىزاھات(&N) +ھۆججەت دەلىللە + +يېڭى قىسقۇچ +يېڭى ھۆججەت +چېكىن(&X) +600 +ھەممىنى تاللا(&A) +ھەممىنى تاللىما +ئەكسىچە تاللا(&I) +تاللا… +ئەكسىچە تاللا… +ئوخشاش تۈردىكى ھۆججەتنى تاللا +ئوخشاش تۈردىكى ھۆججەتنى ئەكسىچە تاللا +700 +چوڭ سىنبەلگە(&G) +كىچىك سىنبەلگە(&M) +تىزىملىك(&L) +تەپسىلىي(&D) +730 +تەرتىپلەنمىگەن +تەكشىلىك كۆرۈنۈش +&2 يۈز +قورال ستونى(&T) +غول قىسقۇچنى ئاچ +يۇقىرىغا +قىسقۇچ تارىخى… +يېڭىلا(&R) +750 +پرىس قورال ستونى +ئۆلچەملىك قورال ستونى +چوڭ كۇنۇپكا +كۇنۇپكا خېتىنى كۆرسەت +800 +يىغقۇچقا قوش(&A) +خەتكۈچ +900 +تاللانما(&O)… +ئۆلچەملىك سىناش(&B) +960 +مۇندەرىجە(&C)… +7-Zip (&A)ھەققىدە +1003 +يول +ئاتى +كېڭەيتىلگەن ئاتى +قىسقۇچ +چوڭلۇقى +بوغچا چوڭلۇقى +خاسلىق +قۇرغان ۋاقىت +زىيارەت ۋاقتى +ئۆزگەرتكەن ۋاقىت +پۇختا +ئىزاھات +شىفىرلانغان +ئاۋال پارچىلا +كېيىن پارچىلا +لۇغەت +CRC +تىپى +قارشى +ئۇسۇل +ئاساسىي مەشغۇلات سىستېمىسى +ھۆججەت سىستېمىسى +ئىشلەتكۈچى +گۇرۇپپا +بۆلەك +ئىزاھات +ئورۇن +يول ئالدى قوشۇلغۇچى +قىسقۇچ +ھۆججەت +نەشرى +ئەن +كۆپ ئەن +ئورۇن ھالقىش +ئۇلانما +بۆلەك +ئەنلەش + +64-bit +Big-endian +CPU +فىزىكىلىق چوڭلۇقى +ھۆججەت باشى چوڭلۇقى +يىغىندا تەكشۈر +ئالاھىدىلىك +مەۋھۇم ئادرېس + + + + + + +خاتالىق +ئومۇمى سىغىمى +ئىشلىتىلىشچان بوشلۇق +توپلاشتۇرغۇچ چوڭلۇقى +ئەن +يەرلىك ئاتى +تەمىنلىگۈچى +2100 +تاللانما +تىل +تىل: +تەھرىرلىگۈچ +تەھرىرلىگۈچ(&E): + +2200 +سىستېما +7-Zip بىلەن باغلانغان ھۆججەت تىپى: +2301 +7-Zip نى ئوڭ كۇنۇپكا تىزىملىكىگە قوش +ئوڭ تىزىملىكنى دەستىلە +ئوڭ تىزىملىكتە كۆرۈنىدىغان تۈرنى تاللاش +2320 +<قىسقۇچ> +<پرىس> +پرىس ئاچ +ھۆججەت يەش… +پرىسقا قوش +پرىس سىنا +مۇشۇ يەرگە يەش +{0} غا يەش‪‬ +{0}‬ غا قوش ‪ +پرىس ۋە ئېلخەت… +‬ غا پرىسلاپ ئېلخەتتە يوللا +2400 +قىسقۇچ +خىزمەت مۇندەرىجىسى(&W) +(&S)سىستېما ۋاقىتلىق قىسقۇچ +(&C)نۆۋەتتىكى +(&S)بەلگىلەنگەن قىسقۇچ: +يان دىسكىغىلا ئىشلىتىلىدۇ +پرىس ھۆججىتىنى يېشىدىغان ۋاقىتلىق ئورۇندىن بىرنى بەلگىلەڭ. +2500 +تەڭشەك +كۆرسەت“..”تۈر +ھەقىقىي ھۆججەت سىنبەلگىسى كۆرسەت +سىستېما تىزىملىكىنى كۆرسەت +پۈتۈن قۇر تاللا(&F) +سېتكا كۆرسەت(&G) + +شەيئى تاللاش مودىلى(&A) +چوڭ ئەسلەك بېتى ئىشلەت(&L) +2900 +‎7-Zip‏ ھەققىدە +‏7-Zip ‏ھەقسىز دېتال. ئەمما تىزىملىتىش ئارقىلىق ئۇنى ئېچىشنى قوللىسىڭىز بولىدۇ. +3000 +سىستېما لازىملىق ئەسلەكنى تەقسىملىيەلمەيدۇ +خاتالىق يوق +{0} تۈر تاللاندى +“{0}” قىسقۇچ قۇرالمايدۇ +بۇ پرىس يېڭىلاش مەشغۇلاتىنى قوللىمايدۇ +'{0}' ھۆججەتنى پرىس سۈپىتىدە ئاچالمايدۇ +'{0}' شىفىرلانغان پرىسنى ئاچالمايدۇ. ئىم خاتا +قوللىمايدىغان پرىس تېپى +{0} ھۆججەت مەۋجۇد +“{0}”ئۆزگەرتىلدى\nپرىس ھۆججىتىدە يېڭىلامسىز؟ +“{0}”ھۆججەتنى يېڭىلىيالمىدى\n +تەھرىرلىگۈچنى قوزغىتالمىدى +بۇ ھۆججەت ۋىرۇستەك تۇرىدۇ (ھۆججەت ئاتىدا كۆپ بوشلۇق بار) +يولى ئۇزۇن قىسقۇچقا بۇ مەشغۇلاتنى ئېلىپ بارالمايدۇ. +چوقۇم ھۆججەتتىن بىرنى تاللاڭ +چوقۇم بىر ياكى بىر قانچە ھۆججەت تاللاڭ +تۈر بەك كۆپ +3300 +يېشىۋاتىدۇ +پرىسلاۋاتىدۇ +سىناۋاتىدۇ +ئېچىۋاتىدۇ… +ئىزدەۋاتىدۇ… +3400 +يەش +يېشىش ئورنى(&X): +ھۆججەت يېشىدىغان جايدىن بىرنى كۆرسىتىڭ +3410 +يول مودېلى +تولۇق يول ئاتى +يول ئاتى يوق +3420 +قاپلاش مودېلى +قاپلاشتىن بۇرۇن سورا +ئەسكەرتمەي قاپلا +مەۋجۇد ھۆججەتتىن ئاتلا +ئۆزلۈكىدىن ئاتىنى ئۆزگەرت +مەۋجۇد ھۆججەت ئاتىنى ئۆزگەرت +3500 +ھۆججەت ئالماشتۇرۇشنى جەزملە +بۇ قىسقۇچ ئوخشاش ئاتلىق ھۆججەتتىن بىرنى ئۆز ئىچىگە ئالغان +بۇنىڭغا مەۋجۇد ھۆججەتنى +ئالماشتۇرامسىز؟ +{0} بايت +ئۆزلۈكىدىن ئات ئۆزگەرت(&U) +3700 +{0} قوللىمايدىغان پرىسلاش مودېلى +“{0}” سانلىق مەلۇمات خاتا. ھۆججەت بۇزۇلغان +“{0}” ئورۇندىكى CRC تەكشۈرۈش مەغلۇپ بولدى، ھۆججەت بۇزۇلغان +»{0}« شىفىرلانغان ھۆججەت سانلىق مەلۇماتىدا خاتالىق بار، ئىم خاتا. +“{0}” شىفىرلانغان ھۆججەت CRC سانلىق مەلۇمات دەلىللەشتە خاتالىق بار، ئىم خاتا. +3800 +ئىم كىرگۈزۈڭ +ئىم كىرگۈزۈڭ: +ئىمنى قايتا كىرگۈزۈڭ +ئىم كۆرسەت(&S) +ئىم ماس كەلمىدى +(!、#、$...)ئىمغا ئىنگلىزچە ھەرپ، سان ۋە ئالاھىدە ھەرپ-بەلگىلەرلا ئىشلىتىلىدۇ +ئىم بەك ئۇزۇن +ئىم +3900 +كەتكەن ۋاقىت: +قالغان ۋاقىت: +ئومۇمىي چوڭلۇقى: +سۈرئىتى: +بىر تەرەپ قىلىندى: +پرىس نىسبىتى: +خاتالىق: +پرىس: +4000 +پرىسقا قوش +پرىس(&A): +يېڭىلاش مودېلى(&U): +پرىسلاش شەكلى(&F): +پرىسلاش دەرىجىسى(&L): +پرىسلاش مودېلى(&M): +لۇغەت چوڭلۇقى(&D): +سۆز چوڭلۇقى(&W): +مۇقىم سانلىق مەلۇمات چوڭلۇقى: +CPU ئېقىم سانى : +پارامېتىر(&P): +تاللانما +ئۆزى يېشىلىدىغان پرىس ياسا(&X) +ھەمبەھىر ھۆججەت پرىسلا +شىفىرلاش +شىفىرلاش ئۇسۇلى: +شىفىرلىق ھۆججەت ئاتى(&N) +پرىسلاشقا كېرەكلىك ئەسلەك: +يېشىشكە كېرەكلىك ئەسلەك: +4050 +ساقلا +ئەڭ تېز +تېز +نورمال +ئەڭ چوڭ +ئەڭ زور چەكتە +4060 +ھۆججەت قوش ۋە ئالماشتۇر +ھۆججەت يېڭىلا ۋە قوش +مەۋجۇد ھۆججەتنى يېڭىلا +ھۆججەت قەدەمداشلا +4070 +كۆز يۈگۈرت +ھەممە ھۆججەت +مۇقىمسىز +مۇقىم +6000 +كۆچۈر +يۆتكە +كۆچۈرۈش ئورنى: +يۆتكەش ئورنى: +كۆچۈرۈۋاتىدۇ… +يۆتكەۋاتىدۇ… +ئاتىنى ئۆزگەرتىۋاتىدۇ… +نىشان قىسقۇچ تاللاڭ +نۆۋەتتىكى مەشغۇلاتنى قوللىمايدۇ +ھۆججەت ياكى قىسقۇچ ئاتىنى ئۆزگەرتىش خاتالىقى +ھۆججەت كۆچۈرۈشنى جەزملە +ھۆججەتنى پرىسقا راستىنلا كۆچۈرەمسىز؟ +6100 +ھۆججەت ئۆچۈرۈشنى جەزملە +قىسقۇچ ئۆچۈرۈشنى جەزملە +كۆپ ھۆججەت ئۆچۈرۈشنى جەزملە +“{0}” راستىنلا ئۆچۈرەمسىز؟ +“{0}” قىسقۇچ ۋە مەزمۇننى راستىنلا ئۆچۈرەمسىز؟ +{0} تۈرنى راستىنلا ئۆچۈرەمسىز؟ +ئۆچۈرۈۋاتىدۇ… +قىسقۇچ ياكى ھۆججەت ئۆچۈرۈش خاتالىقى +سىستېما يولى ئۇزۇن بولغان ھۆججەتنى ئەخلەتخاناغا يۆتكىيەلمەيدۇ +6300 +قىسقۇچ قۇر +ھۆججەت قۇر +قىسقۇچ ئاتى +ھۆججەت ئاتى +يېڭى قىسقۇچ +يېڭى ھۆججەت +قىسقۇچ قۇرۇش خاتالىقى +ھۆججەت قۇرۇش خاتالىقى +6400 +ئىزاھات +ئىزاھات(&C) +تاللاش +ئەكسىچە تاللا +ماسكا: +6600 +خاسلىق +قىسقۇچ تارىخى +دىئاگنوز ئۇچۇرى +ئۇچۇر +7100 +كومپيۇتېر +تور قوشنا +پۈتۈكلەر +سىستېما +7200 +قوش +يەش +سىنا +كۆچۈر +يۆتكە +ئۆچۈر +ئۇچۇر +7300 +ھۆججەت پارچىلا +پارچىلاش سانى(&S): +پارچە چوڭلۇقى، بايت(&V): +پارچىلاۋاتىدۇ… +پارچىلاشنى جەزملە +ھۆججەتنى {0} پارچىغا بۆلەمسىز؟ +پارچە چوڭلۇقى چوقۇم ئەسلى ھۆججەتتىن كىچىك بولۇشى لازىم +پارچە چوڭلۇقى خاتا +بايت{0} بەلگىلەنگەن پارچە چوڭلۇقى\nنۆۋەتتىكى ھۆججەتنى پارچىلامسىز؟ +7400 +ھۆججەت بىرلەشتۈر +بىرلەشتۈرۈش(&C): +بىرلەشتۈرۈۋاتىدۇ… +بىرىنچى ھۆججەتنىلا تاللا +بۆلەكلەنگەن ھۆججەت پارچىسى ئىكەنلىكىنى بايقىيالمىدى +باشقا ھۆججەت پارچىسىنى بايقىيالمىدى +7500 +تەكشۈرۈۋاتىدۇ… +تەكشۈرۈش ئۇچۇرى +CRC سانلىق مەلۇمات تەكشۈرۈش: +CRC سانلىق مەلۇمات ۋە ھۆججەت ئاتى تەكشۈرۈش: +7600 +ئاساسىي تەكشۈرۈش +ئىشلىتىلگەن ئەسلەك: +پرىسلاۋاتىدۇ +يېشىۋاتىدۇ +سۈرئىتى +ئوتتۇرىچە سۈرئىتى +نۆۋەتتە +نەتىجە +CPU ئىشلىتىلىشى +ئىشلىتىش سۈرئىتى +يوللاش: diff --git a/Utils/7-Zip/Lang/uk.txt b/Utils/7-Zip/Lang/uk.txt new file mode 100644 index 000000000..885f30389 --- /dev/null +++ b/Utils/7-Zip/Lang/uk.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; : Andrij Ilechko +; : Mokiy Mazaylo +; : Sergiy Gontaruk +; : Misha Padalka +; 15.02 : 2015-05-19 : Yurii Petrashko +; +; +; +; +; +; +0 +7-Zip +Ukrainian +Українська +401 +OK +Скасувати + + + +&Так +&Ні +&Закрити +Довідка + +&Продовжити +440 +Так для &всіх +Ні для вс&іх +Зупинити +Перезапустити +&На задньому плані +&На передньому плані +&Пауза +Призупинено +Ви впевнені, що бажаєте скасувати операцію? +500 +&Файл +&Редагування +&Вигляд +&Уподобання +&Інструменти +&Допомога +540 +&Відкрити +Відкрити в&середині +Відкрити &зовні +&Переглянути +&Редагувати +Пере&йменувати +&Копіювати до... +Пере&містити до... +Ви&далити +Роз&бити файл... +Об'&єднати файли... +В&ластивості +Комент&ар +Обчислити контрольну суму +Порівнювач +Створити папку +Створити файл +Ви&хід +Посилання +Ал&ьтернативні потоки +600 +Ви&брати все +Зняти вибір +&Інвертувати вибір +Вибрати... +Зняти вибір... +Вибрати за типом +Зняти вибір за типом +700 +Вели&кі піктограми +&Дрібні піктограми +&Список +&Таблиця +730 +Без сортування +Плоский вигляд +&2 панелі +&Панелі інструментів +Відкрити кореневу папку +Вище на один рівень +Історія папок... +&Оновити +Автооновлення +750 +Панель архіву +Стандартна панель +Великі кнопки +Текст на кнопках +800 +&Додати папку до вподобань як +Закладка +900 +&Налаштування... +&Тестування продуктивності +960 +&Зміст... +&Про 7-Zip... +1003 +Шлях +Ім'я +Розширення +Папка +Розмір +Розмір в архіві +Атрибути +Створено +Відкрито +Змінено +Неперервний +З коментарем +Зашифровано +Розбито до +Розбито після +Словник + +Тип +Анти +Метод +Походження +Файлова система +Користувач +Група +Блок +Коментар +Позиція +Префікс шляху +Папок +Файлів +Версія +Том +Багатотомний +Зсув +Посилань +Блоків +Частин + + + +Процесор +Фізичний розмір +Розмір заголовків +Контрольна сума +Властивості +Віртуальна адреса + +Коротке ім'я +Створено програмою +Розмір сектора +Режим +Посилання +Помилка +Загальний обсяг +Вільний простір +Розмір кластеру +Мітка +Локальне ім'я +Провайдер +Безбека NT +Альтернативний потік + +Видалено +Дерево + + +Тип помилки +Помилки +Помилки +Попередження +Попередження +Потоки +Альтернативні потоки +Розмір альтернативних потоків +Віртуальний розмір +Розпакований розмір +Загальний фізичний розмір +Індекс тому +Підтип +Короткий коментар +Кодова сторінка + + + +Розмір залишку +Розмір вбудованої заглушки +Посилання +Жорстке посилання +iNode + +Лише для читання +2100 +Опції +Мова +Мова: +Редагування +&Редактор: +&Порівнювач: +2200 +Система +Асоціювати 7-Zip з: +Усі користувачі +2301 +Інтегрувати 7-Zip до контекстного меню оболонки +Каскадне контекстне меню +Пункти контекстного меню: +Піктограми в контекстному меню +2320 +<Папка> +<Архів> +Відкрити архів +Видобути файли... +Додати до архіву... +Тестувати архів +Видобути до поточної папки +Видобути до {0} +Додати до {0} +Стиснути та надіслати... +Стиснути до {0} та надіслати +2400 +Папки +&Робоча папка +&Системна тимчасова папка +&Поточна +&Задати: +Використовувати тільки для змінних носіїв +Вкажіть розташування тимчасових архівних файлів. +2500 +Налаштування +Відображати елемент ".." +Відображати справжні піктограми файлів +Відображати системне меню +Вибір &цілого рядка +Відображати лінії &сітки +Відкривати об'єкти одним кліком +&Альтернативний режим виділення +Використовувати &великі сторінки пам'яті +2900 +Про 7-Zip +7-Zip є вільним програмним забезпеченням +3000 +Система не може виділити необхідний обсяг пам'яті +Без помилок +Обрано об'єктів: {0} +Не вдається створити папку '{0}' +Операція оновлення не підтримується для даного архіву. +Не вдається відкрити файл '{0}' як архів +Не вдається відкрити зашифрований архів '{0}'. Хибний пароль? +Непідтримуватий тип архіву +Файл {0} вже існує +Файл '{0}' було змінено.\nБажаєте оновити його в архіві? +Неможливо оновити файл\n'{0}' +Не вдається запустити редактор. +Файл виглядає як вірус (ім'я файлу містить довгу послідовність пробілів). +Операцію не можна викликати з папки, яка має довгий шлях. +Ви повинні вибрати один файл +Ви повинні вибрати один або декілька файлів +Забагато елементів +Не вдалося відкрити файл як {0} архів +Файл відкрито як {0} архів +Архів відкрито зі зсувом +3300 +Видобування +Стиснення +Тестування +Відкриття... +Сканування... +Видалення +3320 +Додавання +Оновлення +Аналіз +Реплікація +Перепакування +Пропуск +Видалення +Створення заголовків +3400 +Видобути +В&идобути до: +Вкажіть розташування для видобутих файлів. +3410 +Обробка шляхів +Повні шляхи +Без шляхів +Абсолютні шляхи +Відносні шляхи +3420 +Режим перезапису +Запитувати перед перезаписом +Перезаписувати без запиту +Пропускати існуючі файли +Автоматично перейменовувати +Автоматично перейменовувати існуючі файли +3430 +Усувати дублювання кореневої папки +Відновляти дані безпеки файлу +3500 +Підтвердіть заміну файлу +Папка призначення вже містить оброблюваний файл. +Бажаєте замінити існуючий файл +на такий? +{0} байт +&Автоматично перейменовувати +3700 +Непідтривуваний метод стиснення для '{0}'. +Помилка даних у '{0}'. Файл пошкоджено. +Помилка CRC у '{0}'. Файл пошкоджено. +Помилка даних у зашифрованому файлі '{0}'. Хибний пароль? +Помилка CRC у зашифрованому файлі '{0}'. Хибний пароль? +3710 +Хибний пароль? +3721 +Непідтримуваний метод стиснення +Помилка даних +Помилка CRC +Недоступні дані +Неочікуваний кінець даних +Існують деякі дані після закінчення корисних даних +Не є архівом +Помилка заголовків +Неправильний пароль +3763 +Недоступний початок архіву +Непідтверджений початок архіву + + + +Непідтримувана функція +3800 +Уведіть пароль +Уведіть пароль: +Повторіть пароль: +&Відображати пароль +Паролі не співпадають +Для паролю використовуйте лише англійські літери, цифри та спеціальні символи (!, #, $, ...) +Пароль занадто довгий +Пароль +3900 +Минуло часу: +Залишилося: +Загалом: +Швидкість: +Оброблено: +Ступінь стиснення: +Помилок: +Архівів: +4000 +Додати до архіву +&Архів: +&Режим оновлення: +&Формат архіву: +С&тупінь стиснення: +&Метод стискання: +&Розмір словника: +Р&озмір слова: +Розмір блоку: +Кількість потоків: +&Параметри: +Налаштування +&Створити SFX архів +Стискати спільні файли +Шифрування +Метод шифрування: +Шифрувати &імена файлів +Необхідно пам'яті для стискання: +Необхідно пам'яті для видобування: +Видалити файли після стиснення +4040 +Зберігати символічні посилання +Зберігати жорсткі посилання +Зберігати альтернативні потоки даних +Зберігати дані безпеки файлу +4050 +Без стиснення +Найшвидше +Швидке +Нормальне +Максимальне +Ультра +4060 +Додати та замінити файли +Оновити та замінити файли +Оновити існуючі файли +Синхронізувати файли +4070 +Переглянути +Усі файли +За розміром файлу +Неперервний +6000 +Копіювати +Перемістити +Копіювати до: +Перемістити до: +Копіювання... +Переміщення... +Перейменування... +Виберіть папку призначення. +Операція не підтримується для цієї папки. +Помилка перейменування файлу або папки +Підтвердіть копіювання файлу +Ви впевнені, що хочете скопіювати файли до архіву +6100 +Підтвердіть видалення файлу +Підтвердіть видалення папки +Підтвердіть видалення декількох файлів +Ви впевнені, що хочете видалити '{0}'? +Ви впевнені, що хочете видалити папку '{0}' і весь її вміст? +Ви впевнені, що хочете видалити ці елементи ({0} шт.)? +Видалення... +Помилка при видаленні файлу або папки +Системі не вдалося перемістити файл із довгим шляхом до Кошика +6300 +Створити папку +Створити файл +Ім'я папки: +Ім'я файлу: +Нова папка +Новий файл +Помилка при створенні папки +Помилка при створенні файлу +6400 +Коментар +&Коментар: +Вибрати +Зняти вибір +Маска: +6600 +Властивості +Історія папок +Діагностичні повідомлення +Повідомлення +7100 +Комп'ютер +Мережа +Документи +Система +7200 +Додати +Видобути +Тестувати +Копіювати +Перемістити +Видалити +Інформація +7300 +Розбити файл +&Розбити до: +Розбити на &томи розміром, байт: +Розбиття... +Підтвердіть розбиття +Ви впевнені, що бажаєте розбити архів на {0} томів? +Розмір тому має бути меншим за розмір вихідного файлу +Неправильний розмір тому +Задано розмір тому: {0} байт.\nВи впевнені, що бажаєте розбити архів на такі томи? +7400 +Об'єднати файли +&Об'єднати до: +Об'єднання... +Виберіть тільки першу частину розбитого файлу +Не вдалося визначити файл, як частину розбитого файлу +Не вдалося знайти більше однієї частини розбитого файлу +7500 +Обчислення контрольної суми... +Інформація про контрольну суму +Контрольна сума CRC для даних: +Контрольна сума CRC для даних та імен: +7600 +Тестування продуктивності +Використано пам'яті: +Стискання +Видобування +Рейтинг +Загальний рейтинг +Поточні значення +Підсумкові значення +Завант. ЦП +Рейтинг/Завант. +Проходів: +7700 +Посилання +Пов'язати +Джерело: +Мета: +7710 +Тип посилання +Жорстке посилання +Символічне посилання (файл) +Символічне посилання (каталог) +Точка з'єднання (каталог) diff --git a/Utils/7-Zip/Lang/uz.txt b/Utils/7-Zip/Lang/uz.txt new file mode 100644 index 000000000..71762c0ad --- /dev/null +++ b/Utils/7-Zip/Lang/uz.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 9.07 : Sherzod Mamatkulov +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Uzbek +O'zbek +401 +OK +Bekor + + + +&Ha +&Yo'q +&Yopish +Yordam + +&Davom et +440 +H&ammasiga ha +Hammasiga y&o'q +To'xta +Qayta boshla +&Orqa fon +Ol&di fon +&Pauza +Pauza qilingan +Haqiqatdan ham bekor qilishni istaysizmi? +500 +&Fayl +&Tahrir +&Ko'rinish +&Xatcho'plar +&Asboblar +&Yordam +540 +&Ochish +&Ichkarida ochish +&Tashqarida ochish +&Ko'rish +Ta&hrirlash +&Qayta nomlash +&Nusxalash... +Ko'chi&rish... +O'chirish +&Faylni bo'laklash... +Fayllarni &birlashtirish... +&Xossalari +&Sharh... +Nazorat summasini hisoblash +Farq +Papka yaratish +Fayl yaratish +&Chiqish +600 +H&ammasini tanla +Hammasini tashla +&Tanlanishni teskarila +Tanlash... +Tashlash... +Turi bo'yicha tanla +Turi bo'yicha tashla +700 +&Yirik ikonlar +&Mitti ikonlar +&Ro'yxat +&Tafsilotlar +730 +Saralanmagan +Tekis ko'rinish +&2 ta panel +&Uskunalar majmuasi +Ildiz papkasini och +Bir bosqich yuqoriga +Papkalar tarixi... +&Qayta och +750 +Arxiv toolbari +Standart toolbar +Yirik tugmalar +Tugmalar matnini ko'rsat +800 +&Papkani ushbu xatcho'pga qo'sh +Xatcho'p +900 +Tanl&ovlar... +&Baholash +960 +Yordam &tarkibi... +&7-Zip haqida... +1003 +Yo'lak +Nomi +Kengaytma +Papka +Hajmi +Siqilgan hajmi +Atributlari +Yaratilgan +Ochilgan +O'zgartirilgan +Yaxlit +Sharhlangan +Tilsimlangan +Bundan oldin bo'laklangan +Bundan keyin bo'laklangan +Lug'at +CRC +Turi +Anti +Uslub +Mezbon OS +Fayl tizimi +Foydalanuvchi +Guruh +Block +Sharh +Joylashuv +Yo'lak prefiksi +Papkalar soni +Fayllar soni +Versiya +Tom +Ko'p-tomli +Offset +Ulanmalar +Bloklar soni +Tomlar soni + +64-bit +Big-endian +Protsessor +Fizik hajmi +Header hajmi +Nazorat summasi +Tavsifi +Virtual adresi +ID +Qisqa nomi +Yaratgan dastur +Sektor hajmi +Uslubi +Ulanma +Xato +Umumiy hajmi +Bo'sh joy +Klaster hajmi +Yorliq +Lokal nomi +Provayder +2100 +Tanlovlar +Til +Til: +Muharrir +&Muharrir: +&Farq: +2200 +Tizim +Ushbu arxivlarni 7-Zip bilan biriktir: +2301 +7-Zipni qobiq kontekst menyusiga qo'sh +Kontekst menyusi pog'onali bo'lsin +Kontekst menyu bandlari: +2320 + + +Arxivni och +Fayllarni ajrat... +Arxivga qo'sh... +Arxivni sina +Shu joyga ajrat +{0}ga ajrat +{0}ga qo'sh +Siq va emailda jo'nat... +{0}ga siq va emailda jo'nat +2400 +Papkalar +&Ish papkasi +Tizim &vaqtinchalik (temp) papkasi +&Joriy papka +&Tayinlangan: +Faqat olinadigan drayvlar uchun ishlat +Vaqtinchalik arxiv fayllari uchun manzilni tayinlang. +2500 +Sharoit +".." qismini ko'rsat +Fayllarning haqiqiy ikonlarini ko'rsat +Tizim menyusini ko'rsat +&To'liq yo'lakni tanlash +&Panjara chiziqlarini ko'rsat +&Faylni ochish uchun bitta klik yetarli +&Muqobil tanlash uslubini qo'lla +&Yirik xotira pageini ishlat +2900 +7-Zip haqida +7-Zip - bepul dasturiy ta'minot. +3000 +Tizim kerakli miqdordagi xotirani band qila olmadi +Hechqanday xatolik aniqlanmadi +{0} ta qism tanlangan +'{0}' papkasini yarata olmadim +Bu arxivga nisbatan yangilash amallari bajarilmaydi. +'{0}' faylini arxiv sifatida ocha olmadim +Tilsimlangan '{0}' arxivni ocha olmadim. Noto'g'ri parol kiritildimi? +Noma'lum arxiv turi +{0} fayli oldindan mavjud +'{0}' fayli o'zgartirildi.\nUni arxiv ichida yangilashni xohlaysizmi? +Ushbu faylni yangilay olmadim\n'{0}' +Muharrirni ocha olmadim. +Bu fayl virusga o'xshaydi (fayl nomida uzun bo'shliq bor). +Bu amalni uzun yo'lakli papkada chaqirib bo'lmaydi. +Bitta faylni tanlashingiz lozim +Bitta yoki undan ortiq faylni tanlashingiz lozim +Qismlar o'ta ko'p +3300 +Ajratilmoqda +Siquv ketmoqda +sinaldi +Ochilmoqda... +Tekshirilmoqda... +3400 +Ajratish +&Buyerga ajrat: +Ajratilgan fayllar uchun manzil tayinlang. +3410 +Yo'lak uslubi +To'liq yo'lak nomlari +Yo'lak nomi yo'q +3420 +Ustidan yozish uslubi +Yozib yuborishdan oldin so'ra +So'ramasdan yozib yubor +Oldindan mavjud fayllarni tashlab ket +Avtomatik tarzda qayta nomla +Mavjud fayllarni avto qayta nomla +3500 +Fayl ustidan yozishni tasdiqlash +Manziliy papkada ishlangan fayl oldindan mavjud. +Mavjud faylni +bunisi bilan almashtirasizmi? +{0} bayt +A&vtomatik tarzda qayta nomla +3700 +'{0}'dagi siquv metodi notanish. +'{0}'da data xatosi yuz berdi. Fayl zararlangan. +'{0}'da CRC amalga oshmadi. Fayl zararlangan. +Tilsimlangan '{0}' faylida data xatosi yuz berdi. Parol noto'g'ri shekilli +Tilsimlangan '{0}' faylida CRC amalga oshmadi. Parol noto'g'ri shekilli +3800 +Parolni kiritish +Parolni kiriting: +Parolni qayta kiriting: +&Parolni ko'rsat +Parollar bir xil emas +Parol uchun faqat lotincha harflar, raqam va maxsus belgilar (!, #, $, ...) ishlating +Parol haddan tashqari uzun +Parol +3900 +O'tgan vaqt: +Qolgan vaqt: +Jami hajmi: +Tezlik: +Ishlandi: +Siquv nisbati: +Xatolar: +Arxivlar: +4000 +Arxivga qo'shish +&Arxiv: +&Yangilash uslubi: +Arxiv &formati: +Siq&uv bosqichi: +&Siquv metodi: +&Lug'at hajmi: +So'z haj&mi: +Yaxlit blok hajmi: +CPU oqimlari soni: +&Parametrlar: +Tanlovlar +SF&X arxiv yarat +Baham ko'rilgan fayllarni ham siq +Tilsimlash +Tilsimlash metodi: +Fayl &nomlarini tilsimla +Siquvda ishlatiladigan xotira: +Ajratuvda ishlatiladigan xotira: +4050 +Saqlash +Eng tez +Tez +O'rtacha +Eng zo'r +Ultra +4060 +Fayllarni qo'sh va almashtir +Fayllarni yangila va qo'sh +Mavjud fayllarni yangila +Fayllarni sinxronla +4070 +Belgila +Barcha fayllar +No-yaxlit +Yaxlit +6000 +Nusxalash +Ko'chirish +Ushbu katalogga nusxala: +Ushbu katalogga ko'chir: +Nusxalanmoqda... +Ko'chirilmoqda... +Qayta nomlanmoqda... +Manziliy papkani tanlang. +Ushbu papkaga nisbatan bu amalni qo'llab bo'lmaydi +Fayl yoki papkani qayta nomlashda xato yuz berdi +Faylni nusxalashni tasdiqlang +Haqiqatdan ham fayllarni arxivga nusxalashni xohlaysizmi +6100 +Faylni o'chirishni tasdiqlang +Papkani o'chirishni tasdiqlang +Ko'plab fayllarni o'chirishni tasdiqlang +Haqiqatdan ham '{0}'ni o'chirib tashlamoqchimisiz? +Haqiqatdan ham '{0}' papkasini butun tarkibi bilan o'chirib tashlamoqchimisiz? +Haqiqatdan ham ushbu {0} ta qismni o'chirib tashlamoqchimisiz? +O'chirilmoqda... +Fayl yoki papkani o'chirishda xato yuz berdi +Tizim uzun yo'lakli faylni Recycle Bin (Korzina)ga ko'chira olmaydi +6300 +Papka yaratish +Fayl yaratish +Papka nomi: +Fayl nomi: +Yangi papka +Yangi fayl +Papka yaratishda xato yuz berdi +Fayl yaratishda xatolik yuz berdi +6400 +sharhi +&Sharh: +Tanlash +Tashlash +Maska: +6600 +Xossalari +Papkalar tarixi +Diagnostik xabarlar +Xabar +7100 +Kompyuter +Tarmoq +Hujjatlar +Tizim +7200 +Qo'sh +Ajrat +Sina +Nusxala +Ko'chir +O'chir +Ma'lumot +7300 +Faylni bo'laklash +&Ushbu katalogga bo'lakla: +&Tomlarga bo'lakla, bayt: +Bo'laklanmoqda... +Bo'laklash tasdig'i +Haqiqatdan ham faylni {0} ta tomga bo'lmoqchimisiz? +Tom hajmi original fayl hajmidan kichikroq bo'lishi lozim +Tom hajmi noto'g'ri +Berilgan tom hajmi: {0} bayt.\nHaqiqatdan ham arxivni shunaqa bo'laklarga bo'lmoqchimisiz? +7400 +Fayllarni birlashtirish +&Ushbu katalogga birlashtir: +Birlashtirilmoqda... +Bo'lak faylning faqat birinchi qismini tanla +Bu fayl bo'lak faylning qismi emas +Bo'lak faylning bittadan ortiq qismi topilmadi +7500 +Nazorat summasi hisoblanmoqda... +Nazorat summasi ma'lumoti +Data uchun CRC checksum: +Data va nomlar uchun CRC checksum: +7600 +Baholash +Xotira ishlatilishi: +Siqish +Ajratish +Reyting +Umumiy reyting +Joriy +Natijaviy +CPU bandligi +Reyting / Ishlatish +O'tganlar: diff --git a/Utils/7-Zip/Lang/va.txt b/Utils/7-Zip/Lang/va.txt new file mode 100644 index 000000000..b7ecf4bd0 --- /dev/null +++ b/Utils/7-Zip/Lang/va.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 4:26 : Tomas Miralles +; 4.44 : Fernando Verdú +; +; +; +; +; +; +; +; +; +0 +7-Zip +Valencian +Valencià +401 +Acceptar +Cancel·lar + + + +&Si +&No +Tan&car +Ajuda + +&Continuar +440 +Si a &tot +No a t&ot +Parar +Reiniciar +Segon pla +Primer pla +&Pausa +Parat +Està segur que vol cancel·lar? +500 +&Arxiu +&Editar +&Visualitzar +Favorits +Ferramentes +Ajuda +540 +&Obrir +Obrir d&ins +Obrir fora +&Visualitzar +&Editar +Renom&enar +&Copiar a... +&Moure a... +&Suprimir +&Separar fitxer... +Com&binar fitxers... +P&ropietats +Come&ntari +Calcular checksum + +Crear directori +Crear fitxer +Eixir +600 +Seleccion&ar-ho tot +Deseleccionar-ho tot +&Invertir selecció +Seleccionar... +No seleccionar... +Seleccionar per tipus +No seleccionar per tipus +700 +Icones g&rans +Icones menudes +&Llista +&Detalls +730 +No ordenat +Vista plana +&2 Taules +&Barres de ferramentes +Obrir directori arrel +Directori pare +Historial de carpetes... +Actualitza&r +750 +Arxiu +Estàndard +Botons grans +Mostrar text dels botons +800 +&Afegir el directori als Favorits com a +Personal +900 +&Opcions... +&Banc de proves +960 +&Contingut... +Sobre 7-Zip... +1003 +Adreça +Nom +Tipus d'arxiu +Directori +Tamany +Tamany comprimit +Atributs +Creat +ültim accés +Última modificació +Compacte +Comentari +Xifrat +Expandit abans +Expandit després +Diccionari +CRC +Tipus +Anti +Mètode +SO d'origen +Sistema de fitxers +Usuari +Grup +Bloc +Comentari +Posició +Prefix de ruta + + + + + + + + + + + + + + + + + + + + + + + + +Error +Tamany total +Espai lliure +Tamany sector +Etiqueta +Nom local +Proveïdor +2100 +Opcions +Idioma +Idioma: +Editor +&Editor: + +2200 +Sistema +Associar 7-Zip amb: +2301 +Integrar 7-Zip dins el menu contextual de Windows +Menu contextual en cascada +Objectes del menu contextual: +2320 + + +Obrir arxiu +Extraure fitxers... +Afegir a l'arxiu... +Comprovar arxiu +Extraure ací +Extraure a {0} +Afegir a {0} +Comprimir i enviar per correu electrònic... +Comprimir a {0} i enviar per correu electrònic +2400 +Directoris +Directori de &treball +Directori temporal del &sistema +Directori a&ctual +E&specificar directori: +Utilitzar només per a discs extraibles +Especificar un directori per als arxius temporals. +2500 +Ajusts +Mostrar l'objecte ".." +Mostrar icones reals dels fitxers +Mostrar el menú del sistema +Seleccionar &tota la la fila +Mostrar &línies de la taula + +Mode de selecció &alternatiu +Utilitzar pàgines de memòria &grans +2900 +Sobre 7-Zip +7-Zip és un programa lliure (GNU LGPL). Pot col·laborar en el desenvolupament del 7-zip registrant-lo, com a usuari registrat podrà rebre suport tècnic. +3000 + +No hi ha errors +{0} objecte(s) seleccionat(s) +No es pot crear el directori '{0}' +Les operacions d'actualització d'este arxiu no estan suportades. +No es pot obrir el fitxer '{0}' com arxiu +No es pot obrir l'arxiu xifrat '{0}'. contrasenya incorrecta? + + +El fitxer '{0}' ha sigut modificat.\nVol actualitzar-lo a l'arxiu? +No es pot actualitzar el fitxer\n'{0}' +No es pot executar l'editor. + + + + +Massa objectes +3300 +Extraent +Comprimint +Provant +Obrint... +Escanejant... +3400 +Extraure +E&xtraure a: +Seleccione destinació per als fitxers extrets. +3410 +Mode d'adreça +Adreça sencera +Sense adreça +3420 +Sobreescriu +Pregunta abans de sobreescriure +Sobreescriu sense confirmació +Conserva arxius ja existents +Reanomena automàticament +Reanomena automàticament arxius ja existents +3500 +Confirmar substitució de fitxers +El directori de destinació conté un fitxer amb el mateix nom. +Vol substituir el fitxer existent +per este altre? +{0} bytes +Renomenar a&utomàticament +3700 +Mètode de compressió no vàlid per a '{0}'. +Error de dades en '{0}'. L'arxiu està corrupte. +CRC ha fallat en '{0}'. L'arxiu està corrupte. +Errors de dades en l'arxiu xifrat '{0}'. Contrasenya incorrecta? +CRC incorrecte en l'arxiu xifrat '{0}'. Contrasenya incorrecta? +3800 +Introduir contrasenya +Introduir contrasenya: +Reintroduir contrasenya: +Mo&strar contrasenya +Les contrasenyes no coincideixen +Useu només lletres de l'alfabet anglès, números i caràcters especials (!, #, $, ...) per a la contrasenya +Contrasenya massa llarga +Contrasenya +3900 +Temps transcorregut: +Temps restant: +Mida: +Velocitat: + + +Errors: + +4000 +Afegir a l'arxiu +&Arxiu: +Mode d'act&ualització: +&Format de l'arxiu: +&Nivell de compressió: +Tipus de co&mpressió: +Tamany &diccionari: +Tamany ¶ula: + + +&Paràmetres: +Opcions +Crear arxiu SF&X + +Xifrat +Métode de xifrat: +Encriptar el nom dels fitxers +Us de memòria Comprimint: +Us de memòria Descomprimint: +4050 +Sense compressió +La més ràpida +Ràpida +Normal +Màxima +Ultra +4060 +Afegir i substituir fitxers +Actualitzar i afegir fitxers +Actualitzar fitxers existents +Sincronitzar fitxers +4070 +Visualitzar +Tots els fitxers + + +6000 +Copiar +Moure +Copiar a: +Moure a: +Copiant... +Movent... +Renomenant... +Seleccioneu carpeta de destinació. +Operació no permesa. +Error renomenant fitxer o carpeta +Confirmar copia de fitxer +Està segur que vol copiar els fitxers a l'arxiu +6100 +Confirmar supressió del fitxer +Confirmar supressió del directori +Confirmar supressió m�ltiple de fitxers +Està segur de voler suprimir '{0}'? +Està segur de voler suprimir la carpeta '{0}' i tot el seu contingut? +Està segur de voler esborrar estos {0} elements? +Suprimint... +Error esborrant fitxer o carpeta + +6300 +Crear carpeta +Crear fitxer +Nom de carpeta: +Nom de fitxer: +Carpeta nova +Fitxer nou +Error creant carpeta +Error creant el fitxer +6400 +Comentari +&Comentari: +Seleccionar +No seleccionar +Màscara: +6600 + +Historial de directoris +Missatges de diagnosi +Missatge +7100 +El meu ordinador +Entorn de xarxa + +Sistema +7200 +Afegir +Extraure +Provar +Copiar +Moure +Esborrar +Info +7300 +Separar fitxer +&Separar a: +Separar en &volums, bytes: +Separant... +Confirma divissió +Esteu segurs que voleu dividir el fitxer en {0} volums? +La mida del volum ha de ser menor que la mida original del fitxer +Mida incorrecta de volum +Mida del volum especificada: {0} bytes.\nEsteu segurs que voleu dividir l'arxiu en volums? +7400 +Combinar fitxers +&Combinar a: +Combinant... +Seleccioneu només el primer fitxer + + +7500 +Calculant checksum... +Informació checksum +CRC checksum per a les dades: +CRC checksum per a dades i noms: +7600 +Banc de proves +Us de memoria: +Comprimint +Descomprimint +Taxa +Taxa total +Actual +Resultant + + +Passades: diff --git a/Utils/7-Zip/Lang/vi.txt b/Utils/7-Zip/Lang/vi.txt new file mode 100644 index 000000000..05def96a0 --- /dev/null +++ b/Utils/7-Zip/Lang/vi.txt @@ -0,0 +1,404 @@ +;!@Lang2@!UTF-8! +; 2.30 : : Tran Hong Ha +; 4.42 : : Le Vu Hoang +; 4.48 : : Nguyen Hong Quan +; 9.07 : 2011-04-12 : Vietnamize Team +; +; +; +; +; +; +; +0 +7-Zip +Vietnamese +Tiếng Việt +401 +Đồng ý +Hủy bỏ + + + +Có +Không +Đóng +Giúp đỡ + +Tiếp tục +440 +Có tất cả +Không tất cả +Dừng +Làm lại +Chạy nền +Chế độ ưu tiên +Dừng +Đã dừng +Bạn chắc chắn muốn hủy bỏ? +500 +Tập tin +Biên tập +Xem +Ưa thích +Công cụ +Giúp đỡ +540 +Mở +Mở tại đây +Mở trong cửa sổ khác +Xem +Biên tập +Đổi tên +Sao chép đến... +Di chuyển đến... +Xoá +Chia cắt tệp nén... +Nối tệp nén... +Thuộc tính +Chú thích +Tính checksum (md5) +So sánh +Tạo thư mục +Tạo tệp nén +Thoát +600 +Chọn tất cả +Bỏ chọn tất cả +Đảo lựa chọn +Chọn... +Bỏ chọn... +Chọn theo loại +Bỏ chọn theo loại +700 +Biểu tượng lớn +Biểu tượng nhỏ +Danh sách +Chi tiết +730 +Không sắp xếp +Mọi tập tin và thư mục con +2 bảng +Thanh công cụ +Mở thư mục gốc +Lên một cấp +Lịch sử thư mục... +Nạp lại +750 +Thanh công cụ nén +Thanh công cụ chuẩn +Sử dụng nút lớn +Hiển thị chữ trên nút +800 +Thêm thư mục vào 'Ưa thích' như là +Đánh dấu +900 +Tùy chọn... +Đo tốc độ +960 +Nội dung... +Về 7-Zip... +1003 +Đường dẫn +Tên +Phần mở rộng +Thư mục +Kích cỡ thực +Kích cỡ nén +Thuộc tính +Thời điểm tạo +Thời điểm truy xuất +Thời điểm sửa đổi +Kiểu nén Solid +Ghi chú +Được mã hoá +Chia nhỏ trước +Chia nhỏ sau +Từ điển +CRC +Loại +Anti +Phương thức nén +Hệ điều hành +Tệp hệ thống +Người dùng +Tập đoàn +Số thứ tự +Chú thích +Vị trí +Đường dẫn đầu +Thư mục +Tập tin +Phiên bản +Kích cỡ +Đa kích cỡ +Offset +Liên kết +Tập tin +Kích cỡ + +64-bit +Big-endian +CPU +Kích cỡ lý thuyết +Kích cỡ hiện tại +Checksum +Đặc điểm +Địa chỉ ảo +ID +Tên ngắn +Trình tạo ứng dụng +Kích cỡ vùng +Chế độ +Liên kết +Lỗi +Tổng dung lượng +Dung lượng trống +Dung lượng cluster +Nhãn +Tên mạng cục bộ +Nhà cung cấp +2100 +Các tùy chọn +Ngôn ngữ hiển thị +Ngôn ngữ: +Biên tập +Trình biên tập: +Trình so sánh: +2200 +Hệ thống +Kết hợp 7-Zip với: +2301 +Tích hợp 7-Zip vào menu ngữ cảnh +Xếp tầng menu ngữ cảnh +Menu ngữ cảnh: +2320 + + +Mở tệp nén +Giải nén tệp... +Thêm vào tệp nén... +Kiểm tra tệp nén +Giải nén tại đây +Giải nén vào {0} +Thêm vào {0} +Nén và gởi qua email... +Nén thành {0} và gởi qua email +2400 +Thư mục +Thư mục hiện hành +Hệ thống thư mục tạm +Hiện tại +Đặc biệt: +Chỉ sử dụng cho ổ đĩa di động +Xác định vị trí cho các tệp lưu trữ tạm thời. +2500 +Thiết lập +Hiển thị mục ".." +Hiển thị biểu tượng thực của tệp +Hiển thị menu hệ thống +Chọn cả dòng +Hiển thị lưới +Nhắp chuột để mở +Chế độ chọn luân phiên +Sử dụng bộ nhớ lớn +2900 +Về 7-Zip +7-Zip là một phần mềm miễn phí. +3000 +Không thể cấp thêm dung lượng RAM yêu cầu +Không xuất hiện lỗi +{0} đối tượng đã chọn +Không thể tạo thư mục '{0}' +Tệp nén này không được hỗ trợ cập nhật. +Không thể mở '{0}' như là tệp nén +Không thể mở tập tin nén '{0}' bị mã hóa . Mật khẩu sai? +Không hỗ trợ tệp nén này +Tệp {0} đang tồn tại +Tệp '{0}' đã bị thay đổi.\nBạn có muốn cập nhật nó vào tập tin nén? +Không thể cập nhật tệp\n'{0}' +Không thể khởi động trình biên tập. +Tập tin này có thể là virus (tên tập tin có chứa khoảng cách dài). +Không thể thực hiện với một thư mục có đường dẫn quá dài. +Bạn phải chọn một tập tin +Bạn phải chọn một hoặc 2 tập tin +Quá nhiều tập tin +3300 +Đang giải nén... +Đang nén... +Đang kiểm tra... +Đang mở... +Đang quét... +3400 +Giải nén +Giải nén vào: +Chọn nơi để giải nén tệp. +3410 +Chọn đường dẫn +Đường dẫn đầy đủ +Không có đường dẫn +3420 +Chế độ ghi đè +Hỏi trước khi ghi đè +Ghi đè không cần hỏi +Bỏ qua tệp đã có +Tự động đổi tên +Tự động đổi tên tệp đã có +3500 +Xác nhận thay thế +Thư mục đích đã có tập tin đó. +Bạn có muốn thay thế tập tin đã có +bằng tập tin mới? +{0} bytes +Tự động đổi tên +3700 +Phương thức nén không hỗ trợ cho '{0}'. +Lỗi dữ liệu trong '{0}'. Tệp đã bị hỏng. +Lỗi chẵn/lẻ (CRC) trong '{0}'. Tệp đã bị hỏng. +Lỗi dữ liệu trong tệp nén bị mã hóa '{0}'. Mật khẩu sai? +Kiểm tra CRC thất bại trong tệp nén bị mã hóa '{0}'. Mật khẩu sai? +3800 +Vui lòng nhập mật khẩu +Nhập mật khẩu: +Nhập lại mật khẩu: +Xem mật khẩu +Mật khẩu không khớp nhau +Chỉ đặt mật khẩu bằng tiếng Anh, số và những kí tự đặc biệt (!, #, $, ...) cho mật khẩu +Mật khẩu quá dài +Mật khẩu +3900 +Thời gian đã qua: +Thời gian còn lại: +Tổng kích cỡ: +Tốc độ: +Đã nén: +Tỷ lệ nén: +Lỗi: +Tệp nén: +4000 +Thêm vào tệp nén +Tệp nén: +Chế độ cập nhật: +Dạng tệp nén: +Mức độ nén: +Phương thức nén: +Kích cỡ thư mục: +Kích cỡ văn bản: +Kích cỡ nén Solid: +Số luồng xử lý CPU: +Tham số: +Tùy chọn +Tạo trình tự giải nén tệp +Nén tập tin chia sẻ +Mã hóa +Phương thức mã hóa: +Mã hoá tên tệp +Bộ nhớ dùng cho việc nén: +Bộ nhớ dùng cho việc giải nén: +4050 +Lưu trữ +Nhanh nhất +Nhanh +Bình thường +Tối đa +Siêu nhanh +4060 +Thêm và thay thế +Thêm và cập nhật +Cập nhật tập tin đã có +Đồng bộ +4070 +Duyệt +Mọi tập tin +Không nén dạng Solid +Solid +6000 +Sao chép +Di chuyển +Sao chép đến: +Di chuyển đến: +Đang thêm... +Đang di chuyển... +Đang đổi tên... +Chọn thư mục đến. +Thao tác không được hỗ trợ cho tập tin này. +Lỗi khi đổi tên tệp hoặc thư mục +Xác nhận thêm +Bạn muốn thêm vào tệp nén? +6100 +Xác nhận xoá +Xác nhận xoá thư mục +Xác nhận xoá nhiều tệp +Bạn có chắc chắn muốn xoá '{0}'? +Bạn có chắc chắn muốn xoá thư mục '{0}' và mọi tập tin bên trong? +Bạn có chắc chắn muốn xoá {0} ? +Đang xóa... +Lỗi khi đang xóa tệp hoặc thư mục +Hệ thống không thể xóa tệp với đường dẫn dài vào Thùng rác +6300 +Tạo thư mục +Tạo tệp nén +Tên thư mục: +Tên tệp mới: +Thư mục mới +Tệp mới +Lỗi khi tạo thư mục +Lỗi khi tạo tệp +6400 +Chú thích +Chú thích: +Chọn +Bỏ chọn +Ẩn danh: +6600 +Thuộc tính +Lịch sử thư mục +Thông tin chẩn đoán +Thông tin +7100 +Máy tính +Mạng +Tài liệu +Hệ thống +7200 +Thêm +Giải nén +Kiểm tra +Sao chép +Di chuyển +Xoá +Thông tin +7300 +Chia nhỏ tệp +Chia nhỏ và lưu tại: +Chia thành nhiều phần, bytes: +Đang chia nhỏ... +Xác nhận việc chia nhỏ +Bạn có chắc muốn chia nhỏ tệp nén thành {0} phần? +Kích cỡ mỗi phần phải nhỏ hơn tệp gốc +Kích cỡ phần chia chưa đúng +Kích cỡ phần chia đã đặt: {0} bytes.\nBạn chắc chắn muốn chia tệp nén theo kích cỡ chia đã đặt? +7400 +Nối tệp +Nối thành: +Đang nối... +Chỉ chọn phần đầu của tệp bị chia nhỏ +Không thể xem tập tin như phần nối của tệp bị chia cắt +Không tìm thấy thêm phần nối nào của tệp chia cắt +7500 +Đang tính checksum... +Thông tin checksum +CRC checksum cho dữ liệu: +CRC checksum cho dữ liệu và tên: +7600 +Đo tốc độ +Bộ nhớ sử dụng: +Đang nén +Đang giải nén +Đánh giá +Tổng đánh giá +Hiện thời +Kết quả +Mức dùng CPU +Tốc độ / Mức dùng +Đã qua: diff --git a/Utils/7-Zip/Lang/yo.txt b/Utils/7-Zip/Lang/yo.txt new file mode 100644 index 000000000..3fa9560a5 --- /dev/null +++ b/Utils/7-Zip/Lang/yo.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 15.00 : 2015-03-29 : Ibrahim Oyekan +; +; +; +; +; +; +; +; +; +; +0 +7-Zip +Yoruba +Yoruba +401 +O DAA +Pa re + + + +&Bẹẹni +&Bẹẹkọ +&Pádé +Ìrànlọwọ + +&Tẹ́-síwájú +440 +Bẹẹni fun &gbogbo ẹ +Bẹẹkọ fun &gbogbo ẹ +Dúró +Ṣàtúnbẹ̀rẹ̀ +&Ẹ̣̀hìn-ìgbéhìn +&Ojú-ìgbéhìn +&Dádúró +Ìdúró +Ṣe ẹ dájú pe ẹnyin fẹ́ paarẹ +500 +&Faíli +&Tunkọ +&Ìwò +&Aàyò +&Irinṣẹ́ +&Ìrànlọwọ +540 +&Ṣi +Ṣi &si ínú +Ṣi &si íta +&Ìwò +&Tunkọ +&Tun orukọ kọ +&Ṣẹ̀dà si... +&Gbé si... +&Paarẹ +&Pín faíli... +Ṣà àwọn faíli kópọ̀... +&Àbùdá +&Ọrọ ìwòye... +Ṣe iṣiro checksum +íyàtọ̀ +Dá àpò faíli silẹ́ +Dá faíli silẹ́ +&Pádé +Ìtọ́kasí +&Yiyan agbara détà +600 +Àṣàyàn &gbogbo faíli +Paa Àṣàyàn gbogbo faíli +&Yi Àṣàyàn Padà +Àṣàyàn... +Paa Àṣàyàn... +Àṣàyàn bi irú faíli +Paa Àṣàyàn bi irú faíli +700 +&Àmi ńlá +&Àmi Kékeré +&Akọjọ́ +&Awọn alaye +730 +Lai tọ lẹsẹsẹ +Iwò Ṣepẹtẹ +&Irinṣẹ́ méjì +&Pẹpẹ irinṣẹ́ +Ṣi pìlẹ̀ +Lọ sókè lẹẹkan +Ìtàn àpò faíli... +&Sọdọ̀tun +Isọdọ̀tun aládàáṣẹ́ +750 +Kó pẹpẹ irinṣẹ́ jọ́pọ +Ojúlówó pẹpẹ irinṣẹ́ +Onini ńlá +Fihàn Ìpilẹ̀sọ́ ọ̀rọ̀ Onini +800 +Fi àpò faíli si àpò faíli ayanfẹ +Àmì ìwé +900 +&Ìyàn... +&Ala +960na +&Àkóónú... +&Nípa 7-Zip... +1003 +Ọnà +Orukọ +Ìkọpọmó +Àpò faíli +Ìwọn +Ìwọn àkójọpọ̀ +Àwòmọ́ +Idásílẹ́ +Ìráyè sí +Atúnṣe +Alagbara +Ọrọ ìwòye +Ìwépọ̀ +Kọkọ pín +Pín lẹ́hìn +Ìwe itúmọ̀-èdè + +Irú +Egboogi +Ito lẹsẹsẹ +OS agbalejo +Ìlànà ètò fáìlì +Onilò +Ìwọ́pọ̀ +Dínà +Ọrọ ìwòye +Ipò +Ìpele ọ̀nà +Àpò faíli +Faíli +Ẹya +Ọ̀pọ̀ òǹlò +Ọ̀pọ̀ òǹlò ọpọlọpọ +Aiṣedeede +Awọn Ìtọ́kasí +Àkọsílẹ +Awọn ọ̀pọ̀ òǹlò + +Bíìtì-8 +Endian itóbi +CPU +Ìwọn gangan +Ìwọn àkọsórí +Checksum +Ti ìwà +Àdírẹ́ẹ̀sì àfojúunúṣe +ID +Orúkọ kuru +Ohun èlò eleda +Ìwọn apákàan +Móòdù +Ìtọ́kasí to ni aami +Ìṣiṣe +Ìwọn lapapọ +Aaye to ṣẹku +Ìwọn ìṣùpọ̀ +Aṣàmì +Agbègbè orúkọ +Olùpèsè +Ààbò NT +Yiyan agbara détà +Olurànlọwọ +Ààtàn +O jẹ igi + + +Irú +Awọn ìṣiṣe +Awọn ìṣiṣe +Awọn ìkìlọ̀ +Ìkìlọ̀ +Agbara détà +Yiyan agbara détà +Ìwọn Yiyan Agbara +Ìwọn àfojúunúṣe +Ìwọn ìtú erú +Ìwọn gangan lapapọ +Atọ́kà ọ̀pọ̀ òǹlò +ẹ̀ka-ìwọn +ọrọ ìwòye kuru +Ojú-ìwé kóòdù + + + +Ìwọn ìrú +Ìwọn àfibọ̀ ìyọkúrò +Ìtọ́kasí +Ìtọ́kasí lile +iNode + +Kàn kàá +2100 +Ìyàn +Èdè +Èdè: +Aṣàtúnṣe +&Aṣàtúnṣe: +&íyàtọ̀: +2200 +Ìlànà ètò +Da fáìlì pọ-mọ 7-Zip: +Gbogbo onilò +2301 +Sọ 7-Zip pọ̀ mọ mẹ́nù ọ̀gàngán ipò ṣẹ́ẹ̀lì +Mẹ́nù ọ̀gàngán ipò pérété +Ijẹri ninu mẹ́nù ọ̀gàngán ipò: +Àmì ninu mẹ́nù ọ̀gàngán ipò +2320 +<Àpò faíli> +<Àpò faíli àkójọ́pọ> +Ṣi àpò faíli àkójọ́pọ +Tú faíli silẹ... +Fi si àpò faíli àkójọ́pọ... +Dán àpò faíli àkójọ́pọ wò +Tú faíli si inú ibí +Tú faíli si inú {0} +Fi si {0} +Kó faíli jọ́pọ, ko rán í-meèlì... +Kó faíli jọ́pọ si {0} ko rán í-meèlì +2400 +Àpò faíli +&Àpò faíli iṣiṣẹ́ +&Ìlànà ètò àpò faíli ibùgbé +&Lọ́wọ́lọ́wọ́ +&Pàtó kan: +Lò fun àwo àká-ọ̀rọ̀ yiyọ nìkan +Yan ilé fun àpò faíli àkójọ́pọ ibùgbé +2500 +Ìtò +Fihàn ".." ijẹri +Fihàn àmì faíli gidi +Fihàn mẹ́nù ìlànà ètò +&Àṣàyàn gbogbo ìlà ìbú +Fihàn &àwọn ìlà gírìdì +Ìṣíra tẹ̀ lẹ́ẹ̀kan láti ṣí ijẹri +&Yiyan móòdù àṣàyàn +Lò &ojú-ìwé ti o nlò ibi ìpamọ́ ńlá +2900 +Nípa 7-Zip +Ẹ̀yà àìrídìmú ṣ'ofo ni 7-Zip +3000 +Ìlànà ètò ò le pín ibi ìpamọ́ ti o tó +Kò si iṣiṣe kankan +Iye àṣàyàn: {0} +Kò lé dá àpò faíli '{0}' +Kò lé ṣàfikùn àpò faíli àkójọ́pọ yí. +Kò lé ṣí àpò faíli '{0}' sí àpò faíli àkójọ́pọ +Kò lé ṣí àpò faíli àkójọ́pọ (ìpàrokò). ọrọ̀ aṣínà láìpé +Faíli yí o baamu +Faíli {0} ti wà níbẹ +Faíli '{0}' títúnṣe.\n ṣe ẹ fẹ̀ túnṣe si inú àpò faíli àkójọ́pọ? +Kò le ṣàfikún fun faíli yí \n'{0}' +Kò le ṣí Olótùú. +Faíli yí jọ àkóràn(Ààyè to wa ni àárín orukọ faíli ti poju). +Kò le pè ìmú iṣiṣẹ́ yí láti àpò faíli to ni ọ̀nà gígùn. +Ẹ gbọdọ ṣàyàn faíli kan. +Ẹ gbọdọ ṣàyàn faíli kan tàbí faíli pupọ +Ijẹri ti ẹ ṣà ti pọju +Kò le ṣí faíli yí bí {0} àpò faíli àkójọ́pọ +Faíli yí ti ṣí bí {0} àpò faíli àkójọ́pọ +Àpò faíli àkójọ́pọ yí ti ṣí pẹlu aiṣedeede +3300 +Ìtúsilẹ +Ìkójọ́pọ +Ìdánwò +Ìṣíṣí... +Ìṣẹ̀dà àwòrán ... +Ìyọkúrò +3320 +Ìfi-sí +Ìṣàfikùn +Ìtúpalẹ̀ +Ìfijọ +Ìṣatopọ +Mbẹ́ +Ìpaarẹ +Ìdá àkọsórí +3400 +Túsilẹ +&Tú faíli si inú: +Yan ibi ti awọn faíli ma tú si. +3410 +Móòdù ọ̀nà: +Gbogbo orukọ ọ̀nà +Kò si orukọ ọ̀nà +Orukọ ọ̀nà ọlọ́gangan +Orukọ ọ̀nà ìbátan +3420 +Móòdù ìkọsórí: +Béèrè kí ó tó kọ sórí faíli +Kọ sórí faíli lai béèrè +Mà wo faíli tó ti wà níbẹ +Tun orukọ kọ laládàáṣiṣẹ́ +Tun kọ orukọ faíli tó ti wà níbẹ laládàáṣiṣẹ́ +3430 +Mú ìfijọ àpò faíli ìpìlẹ̀ kúrò +Da ààbò faíli padà +3500 +Tẹnumọ́ àfirọ́pò faíli +Àpò fáìlì èbúté ti ní fáìlì ìgbésẹ́. +Ṣe ẹ fẹ̀ ṣàfirọ́pò fun fáìlì tó ti wà níbẹ +pẹlu fáìlì yí? +Báìtì {0} +&Tun orukọ kọ laládàáṣiṣẹ́ +3700 +Kọ si àtìlẹ́yìn fun ètò àkójọ́pọ yí '{0}'. +Ìṣiṣe détà ṣẹlẹ ní inú '{0}'. Fáìlì ti bajẹ. +Ìkùnà CRC ṣẹlẹ ní inú '{0}'. Fáìlì ti bajẹ. +Ìṣiṣe détà ṣẹlẹ ní inú fáìlì pàroko '{0}'. Tun wo ọ̀rọ̀ aṣínà +Ìkùnà CRC ṣẹlẹ ní inú fáìlì pàroko '{0}'. Tun wo ọ̀rọ̀ aṣínà +3710 +Tun wo ọ̀rọ̀ aṣínà +3721 +Ko si àtìlẹ́yìn fun ètò àkójọ́pọ yí +Ìṣiṣe détà ṣẹlẹ +Détà ò ṣeélò +Ìkùnà CRC +Détà ti parí lójijì +Détà ṣi wa lẹ̀hìn détà ọ̀gangan +Kò ṣe faíli akójọ́pọ +Ìṣiṣe àkọlé +Tun wo ọ̀rọ̀ aṣínà +3763 +Ìbẹ̀rẹ̀ faíli akójọ́pọ ò ṣeélò +Ìbẹ̀rẹ̀ faíli akójọ́pọ ò ṣe tẹnumọ́ + + + +Ko si àtìlẹ́yìn fun àfidámọ̀ yí +3800 +Tẹ̀ ọ̀rọ̀ aṣínà +Tẹ̀ ọ̀rọ̀ aṣínà: +ṣítẹ̀ ọ̀rọ̀ aṣínà: +&Fihàn ọ̀rọ̀ aṣínà +Awọn ọ̀rọ̀ aṣínà ò dọgba +Lò ábídí, iye tàbí aami Gẹ̀ẹ́sì nìkan (!, #, $, ...) fun ọ̀rọ̀ aṣínà +Ọ̀rọ̀ aṣínà ti gùn ju +Ọ̀rọ̀ aṣínà +3900 +Àsìkò ti okan: +Àsìkò ti o ku: +Ìwọn lapapọ: +Ìyára: +Ìṣètò: +Ìpín Ìkójọ́pọ: +Awọn ìṣiṣe: +Awọn faíli àkójọ́pọ: +4000 +Fi si àpò faíli àkójọ́pọ +&Faíli àkójọ́pọ: +&Móòdù ìṣàfikún: +&Ìgúnrégé faíli àkójọ́pọ: +&Ìpele àkójọ́pọ: +&Ọ̀nà àkójọ́pọ: +&Ìwọn àtúmọ̀-èdè: +&Ìwọn ó̩ró̩gbólóhùn: +Ìwọn sèdíwọ: +Iye èròjà atẹ̀lélànà CPU: +&Awọn afòdiwọ̀n: +Ìyàn +Dá àpò faíli àkójọ́pọ fun SF&X +Ko faíli alájọpín jọ́pọ +Ìpàrokò +Móòdù ìpàrokò: +&Ṣe ìpàrokò fun orúkọ faíli +ìlò ibi ìpamọ́ fun àkójọ́pọ: +ìlò ibi ìpamọ́ fun ìtúsilẹ: +Paarẹ faíli lẹ̀hìn àkójọ́pọ +4040 +Fi ìtọ́kasí to ni aami pamọ́ +Fi ìtọ́kasí lile pamọ́ +Fi agbara détà pamọ́ +Fi àfirọ́pò faíli pamọ́ +4050 +Ṣàfipamọ́ +Kíá ju +Kíákíá +Déédéé +Ki o pọju +Ki o púpọ̀ +4060 +Fi faíli si ki o tun fi rọ́pò +Ṣàfikùn faili ki o tun fi si +Sọ awọn faili lọ́wọ́ di ọ̀tun +Mú awọn faíli dọ́gba +4070 +Wáròyìn +Gbogbo faíli +Lai le +Lile +6000 +Ṣẹ̀dà +Gbé +Ṣẹ̀dà si: +Gbé si: +Ìṣẹ̀dà +Ìgbé... +Ìtunkọ... +Ṣàyàn èbúté àpò faíli. +Ìmú ṣiṣẹ́ o ni àtìlẹ́yìn fun àpò faíli. +Ìṣiṣe ṣẹlẹ ní ìtunkọ àpò faíli +Tẹnumọ́ ìṣẹ̀dà faíli +Ṣe ẹ́ dájú pe ẹ fẹ́ ṣẹ̀dà awọn faíli yí si àpò faíli àkójọ́pọ? +6100 +Tẹnumọ́ ìpaarẹ faíli +Tẹnumọ́ ìpaarẹ àpò faíli +Tẹnumọ́ ìpaarẹ àpò faíli ọ̀pọ̀ +Ṣe ẹ́ dájú pe ẹ fẹ́ paarẹ '{0}'? +Ṣe ẹ́ dájú pe ẹ fẹ́ paarẹ '{0}' a àti gbogbo àkóónú ẹ? +Ṣe ẹ́ dájú pe ẹ fẹ́ paarẹ iye ijẹri yí {0} ? +Ìpaarẹ... +Ìṣiṣe ṣẹlẹ ni ìpaarẹ faíli tàbí àpò faíli +Ìlànà ètò o le gbé faíli to ni orúkọ gígùn si inú Ààtàn +6300 +Dá àpò faíli +Dá faíli +Orúkọ àpò faíli: +Orúkọ faíli: +Àpò faíli +Faíli tuntun +Ìṣiṣe ṣẹlẹ ni ìdá àpò faíli +Ìṣiṣe ṣẹlẹ ni ìdá faíli +6400 +Ọrọ ìwòye +&Ọrọ ìwòye: +Ṣàyàn +Paa Àṣàyàn +Asẹ́ iye: +6600 +Àbùdá +Akọọ́lẹ̀ àpò faíli +Atọpinpin-Àìṣedédé iṣé +Iṣé +7100 +Kọ̀mpútà +Alásopọ̀ +Àkọsílẹ̀ +Ìlànà ètò +7200 +Fi-sí +Túsilẹ +Dán-wò +Ṣẹ̀dà +Gbé +Paarẹ +Ìròyìn +7300 +Pín faíli +&Pín si: +Pín si &ọ̀pọ̀ òǹlò, báìtì: +Ìpín... +Tẹnumọ́ Ìpín +Ṣe ẹ́ dájú pe ẹ fẹ́ pín faíli si ọ̀pọ̀ òǹlò {0}? +Ọ̀̀pọ̀ òǹlò láti kéré ju ìwọn faíli ojulowo lọ +ìwọn ọ̀pọ̀ òǹlò láìpé +Yan ìwọn ọ̀pọ̀ òǹlò: {0} báìtì.\nṢe ẹ́ dájú pe ẹ fẹ́ pín àpò faíli àkójọ́pọ si ọ̀pọ̀ òǹlò awọn yí? +7400 +Kó faíli pọ̀ +&Kó faíli pọ̀ si: +Ìkópọ̀... +Ṣàyàn akọkọ faíli ìpín nìkan +Ko lè rí faíli ni inu faíli ìpín +Ko lè rí ju apá faíli kan lọ +7500 +Ìkà checksum... +Ìròyìn Checksum +CRC checksum fun détà: +CRC checksum fun détà àti orúkọ: +7600 +Ala +Ìlò ibi ìpamọ́: +Akójọ́pọ +Ìtúsilẹ +Ìgbéléwọ̀n +Awọn ìgbéléwọ̀n lapapọ +Lọ́wọ́lọ́wọ́ +èsì +Ìlò CPU +Ìgbéléwọ̀n / Ìlò +Ìwé ìjáde: +7700 +Ìtọ́kasí +Ìtọ́kasí +Ìtọ́kasí láti: +Ìtọ́kasí: +7710 +Irú Ìtọ́kasí +Ìtọ́kasí lile +Faíli Ìtọ́kasí to ni aami +Iwé ilana Ìtọ́kasí to ni aami +Idapọ iwé ilana diff --git a/Utils/7-Zip/Lang/zh-cn.txt b/Utils/7-Zip/Lang/zh-cn.txt new file mode 100644 index 000000000..994abc726 --- /dev/null +++ b/Utils/7-Zip/Lang/zh-cn.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 2.30 : 2002-09-07 : Modern Tiger, kaZek, Hutu Li +; 3.08 : 2003-08-29 : Tunghsiao Liu (aka. Sparanoid) +; 16.00 : 2016-05-16 : Tunghsiao Liu (aka. Sparanoid) +; +; +; +; +; +; +; +; +0 +7-Zip +Chinese Simplified +简体中文 +401 +确定 +取消 + + + +是(&Y) +否(&N) +关闭(&C) +帮助 + +继续(&C) +440 +全是(&A) +全否(&L) +停止 +重新开始 +后台(&B) +前台(&F) +暂停(&P) +已暂停 +您真的要取消吗? +500 +文件(&F) +编辑(&E) +查看(&V) +书签(&A) +工具(&T) +帮助(&H) +540 +打开(&O) +当前窗口打开(&I) +新建窗口打开(&U) +查看(&V) +编辑(&E) +重命名(&M) +复制到(&C)... +移动到(&M)... +删除(&D) +分割文件(&S)... +合并文件(&B)... +属性(&R) +注释(&N) +文件校验 +文件比较 +新建文件夹 +新建文件 +退出(&X) +链接 +交替数据流(&A) +600 +全选(&A) +全部取消 +反选(&I) +选择... +取消选择... +选择相同类型的文件 +取消选择相同类型的文件 +700 +大图标(&G) +小图标(&M) +列表(&L) +详细信息(&D) +730 +不排序 +平铺模式 +双版面(&2) +工具栏(&T) +打开根文件夹 +向上 +文件夹历史... +刷新(&R) +自动刷新 +750 +档案工具栏 +标准工具栏 +大按钮 +显示按钮文字 +800 +添加到书签(&A) +书签 +900 +选项(&O) +基准测试(&B) +960 +查看帮助(&C) +关于 7-Zip (&A) +1003 +路径 +名称 +扩展名 +文件夹 +大小 +压缩后大小 +属性 +创建时间 +访问时间 +修改时间 +固实 +注释 +加密 +之前分割 +之后分割 +字典大小 + +类型 +剔除项 +算法 +主操作系统 +文件系统 +用户 +组 +字块 +注释 +定位 +路径前缀 +文件夹 +文件 +版本 +卷 +多卷压缩 +偏移 +链接 +字块 +分卷 + +64 位 +大端序 +CPU +物理大小 +文件头大小 +校验和 +特征 +虚拟地址 +ID +短文件名 +创建程序 +扇区大小 +模式 +链接 +错误 +总大小 +可用空间 +簇大小 +卷标 +本地名称 +供应者 +NT 安全 +交替数据流 +Aux +已删除 +树状结构 + + +错误类型 +错误 +错误 +警告 +警告 +数据流 +交替数据流 +交替数据流大小 +虚拟大小 +释放大小 +完整物理大小 +卷索引 +SubType +短评论 +代码页 + + + +尾部大小 +嵌入尾部大小 +链接类型 +硬链接 +iNode + +只读 +2100 +选项 +语言 +选择语言: +编辑器 +指定编辑器(&E): +指定文件比较程序(&D): +2200 +系统 +使用 7-Zip 关联的文件类型: +所有用户 +2301 +添加 7-Zip 到右键菜单 +层叠右键菜单 +选择在右键菜单中显示的项目: +右键菜单显示图标 +2320 +<文件夹> +<档案> +打开压缩包 +提取文件... +添加到压缩包... +测试压缩包 +提取到当前位置 +提取到 {0} +添加到 {0} +压缩并邮寄... +压缩 {0} 并邮寄 +2400 +文件夹 +工作文件夹(&W) +系统临时文件夹(&S) +当前文件夹(&C) +指定位置(&S) +仅用于可移动设备 +指定一个存放临时压缩包的位置。 +2500 +显示 +显示「..」项 (双击向上) +显示真实图标 +显示系统菜单 +整行选择(&F) +显示网格线(&G) +单击打开项目 +7-Zip 传统选择模式(&A) +使用大内存页(&L) +2900 +关于 7-Zip +7-Zip 是一款自由软件。您可以通过捐赠的方式来支持 7-Zip 的开发。 +3000 +系统无法分配所需内存 +未发现错误 +选定 {0} 个项目 +无法创建文件夹「{0}」 +不支持此压缩包的更新操作。 +无法作为压缩包打开文件「{0}」 +无法打开加密压缩包「{0}」。密码错误? +不支持的压缩包格式 +文件 {0} 已存在 +文件「{0}」已修改。\n你想在压缩文件中更新它? +无法更新文件\n「{0}」。 +无法运行外部编辑。 +此文件似乎是病毒文件(文件名中包含多个空格)。 +无法为过长的路径完成该操作。 +您必须选择一个文件 +您至少要选择一个文件 +项目太多 +无法作为 {0} 压缩包打开该文件 +文件以 {0} 格式打开 +压缩包包含偏移 +3300 +正在提取 +正在压缩 +正在测试 +正在打开... +正在搜索... +正在移除 +3320 +正在添加 +正在更新 +正在分析 +正在复制 +正在打包 +正在跳过 +正在删除 +正在创建文件头 +3400 +提取 +提取到(&X): +指定一个提取文件的位置。 +3410 +路径模式 +完整路径 +无路径 +绝对路径 +相对路径 +3420 +覆盖模式 +在覆盖前询问 +不提示自动覆盖 +跳过已经存在的文件 +自动重命名 +重命名现有文件 +3430 +排除重复的根文件夹 +恢复文件安全设置 +3500 +确认文件替换 +此文件夹已包含一个相同名称的文件。 +是否将现有文件 +替换为 +{0} 字节 +自动重新命名(&U) +3700 +不支持的压缩算法「{0}」。 +数据「{0}」发生错误,文件已损坏。 +CRC 校验「{0}」失败,文件已损坏。 +加密文件「{0}」数据有误,密码错误? +加密文件「{0}」CRC 数据校验有误,密码错误? +3710 +密码错误? +3721 +不支持的压缩算法 +数据错误 +CRC 校验失败 +数据不可用 +文件末端错误 +有效数据外包含额外数据 +非压缩包 +头部错误 +密码错误 +3763 +档案起始位置不可用 +无法确认档案起始位置 + + + +不支持此功能 +3800 +输入密码 +输入密码: +重新输入: +显示密码(&S) +密码不匹配 +密码只允许英文字符,数字,以及特殊字符 (!、#、$...) +密码过长 +密码 +3900 +已用时间: +剩余时间: +总大小: +速度: +已处理: +压缩率: +发生错误: +压缩包: +4000 +添加到压缩包 +压缩包(&A): +更新方式(&U): +压缩格式(&F): +压缩等级(&L): +压缩方法(&M): +字典大小(&D): +单词大小(&W): +固实数据大小: +CPU 线程数: +参数(&P): +选项 +创建自释放程序(&X) +压缩共享文件 +加密 +加密算法: +加密文件名(&N) +压缩所需内存: +解压缩所需内存: +操作完成后删除源文件 +4040 +保存符号链接 +保存硬链接 +保存交替数据流 +保存文件安全设置 +4050 +仅存储 +极速压缩 +快速压缩 +标准压缩 +最大压缩 +极限压缩 +4060 +添加并替换文件 +更新并添加文件 +只刷新已存在的文件 +同步压缩包内容 +4070 +浏览 +所有文件 +非固实 +固实 +6000 +复制 +移动 +复制到: +移动到: +正在复制... +正在移动... +正在重新命名... +选择目标文件夹。 +不支持当前操作 +无法重命名文件或文件夹。 +确认文件复制 +您确定复制文件到压缩包 +6100 +确认文件删除 +确认文件夹删除 +确认删除多个文件 +确实要删除 「{0}」吗? +确实要删除文件夹「{0}」以及全部内容吗? +确实要删除这 {0} 项? +正在删除... +无法删除文件或文件夹. +系统无法将过长路径的文件移动到回收站 +6300 +新建文件夹 +新建文件 +文件夹名称: +文件名: +新建文件夹 +新建文件.txt +无法创建文件夹 +无法新建文件 +6400 +注释 +注释(&C): +选择 +取消选定 +掩码: +6600 +属性 +文件夹历史 +诊断信息 +信息 +7100 +我的电脑 +网络 +我的文档 +系统 +7200 +添加 +提取 +测试 +复制 +移动 +删除 +信息 +7300 +分割文件 +分割文件到(&S): +分卷大小,字节(&V): +正在分割... +确认分割 +您确认要将文件分割为 {0} 个分卷? +分卷大小必须小于原文件大小 +分卷大小错误 +指定分卷大小:{0} 字节。\n您确定要分割当前文件吗? +7400 +合并文件 +合并文件到(&S): +正在合并... +请选择分卷的首个文件 +无法识别文件为压缩分卷 +无法找到其他压缩分卷 +7500 +正在校验... +校验信息 +CRC 数据校验: +CRC 数据及文件名校验: +7600 +基准测试 +内存使用: +压缩 +解压缩 +评分 +总体评分 +当前 +结果 +CPU 使用率 +使用率评分 +已通过: +7700 +链接 +链接 +链接自: +链接到: +7710 +链接类型 +硬链接 +文件符号链接(Symbolic Link) +目录符号链接(Symbolic Link) +目录接合点(Directory Junction) diff --git a/Utils/7-Zip/Lang/zh-tw.txt b/Utils/7-Zip/Lang/zh-tw.txt new file mode 100644 index 000000000..8b89469d7 --- /dev/null +++ b/Utils/7-Zip/Lang/zh-tw.txt @@ -0,0 +1,495 @@ +;!@Lang2@!UTF-8! +; 4.59 : Leon Tseng, sec2, 琥珀 +; 9.07 - 15.00 : Jack Pang : http://www.developershome.com/7-zip/ +; +; +; +; +; +; +; +; +; +0 +7-Zip +Chinese Traditional +繁體中文 +401 +確定 +取消 + + + +是(&Y) +否(&N) +關閉(&C) +說明 + +繼續(&C) +440 +全部皆是(&A) +全部皆否(&L) +停止 +重新開始 +背景作業(&B) +前景作業(&F) +暫停(&P) +暫停 +您確定要取消嗎? +500 +檔案(&F) +編輯(&E) +檢視(&V) +我的最愛(&A) +工具(&T) +說明(&H) +540 +開啟(&O) +在內部開啟(&I) +在外部開啟(&U) +檢視(&V) +編輯(&E) +重新命名(&M) +複製到(&C)... +移動到(&M)... +刪除(&D) +分割檔案(&S)... +合併檔案(&B)... +內容(&R) +註解(&N) +計算驗證值 +比較檔案 +建立資料夾 +建立檔案 +結束(&X) +連結 +附加資料流(&A) +600 +全選(&A) +全不選 +反向選擇(&I) +選取... +取消選取... +依類型選取 +依類型不選取 +700 +大圖示(&G) +小圖示(&M) +清單(&L) +詳細資料(&D) +730 +不排序 +攤開檢視 +雙窗格(&2) +工具列(&T) +開啟根目錄 +上移一層 +資料夾歷程記錄... +重新整理(&R) +自動重新整理 +750 +壓縮檔工具列 +標準工具列 +大型按鈕 +顯示按鈕文字 +800 +將資料夾加入我的最愛為(&A) +書籤 +900 +選項(&O)... +效能測試(&B) +960 +內容(&C)... +關於 7-Zip(&A)... +1003 +路徑 +名稱 +副檔名 +資料夾 +大小 +封裝後大小 +屬性 +建立日期 +存取日期 +修改日期 +緊密 +註解 +加密 +分割前 +分割後 +字典大小 + +類型 +防護 +方式 +主機作業系統 +檔案系統 +使用者 +群組 +區塊 +註解 +位置 +路徑前綴 +資料夾 +檔案 +版本 +卷 +多卷 +偏移 +連結 +區塊 +分卷 + +64 位 +大端序 +CPU +物理大小 +標頭大小 +驗證值 +特徵 +虛擬地址 +ID +簡稱 +創建程式 +扇區大小 +模式 +符號連結 +錯誤 +全部大小 +可用空間 +叢集大小 +標籤 +本機名稱 +提供者 +NT 安全性 +附加資料流 +Aux +刪除日期 +是否樹狀結構 + + +錯誤類型 +錯誤 +錯誤 +警告 +警告 +資料流 +附加資料流 +附加資料流大小 +虛擬大小 +解封後大小 +總物理大小 +卷索引 +子類型 +簡短註解 +代碼頁 + + + +文件尾大小 +嵌入式殘端大小 +連結 +硬連結 +iNode + +唯讀 +2100 +選項 +語言 +介面語言: +編輯器 +編輯器(&E): +檔案比較程式(&D): +2200 +系統 +使 7-Zip 與之產生關聯: +所有使用者 +2301 +將 7-Zip 整合到快顯功能表中 +串聯式快顯功能表 +快顯功能表項目: +快顯功能表顯示圖示 +2320 +<資料夾> +<壓縮檔> +開啟壓縮檔 +解壓縮檔案... +加入壓縮檔... +測試壓縮檔 +解壓縮至此 +解壓縮至 {0} +加入 {0} +壓縮並郵寄... +壓縮成 {0} 並郵寄 +2400 +資料夾 +工作資料夾(&W) +系統暫存資料夾(&S) +目前的資料夾(&C) +指定的資料夾(&S): +僅用於卸除式磁碟機 +請指定存放暫存壓縮檔的位置。 +2500 +設定 +顯示 ".." 項目 +顯示實際檔案圖示 +顯示系統選單 +整列選取(&F) +顯示格線(&G) +單擊開啟項目 +使用替代選擇模式(&A) +使用大記憶體分頁(&L) +2900 +關於 7-Zip +7-Zip 為自由軟體 +3000 +系統未能提供所需記憶體空間 +沒有任何錯誤 +已選取 {0} 個物件 +無法建立資料夾 '{0}' +此壓縮檔未支援更新操作。 +無法開啟壓縮檔 '{0}' +無法開啟加密的壓縮檔 '{0}'。錯誤的密碼? +不支援的壓縮檔類型 +檔案 {0} 已存在 +檔案 '{0}' 已被修改過。\n您是否要在此壓縮檔內更新檔案? +無法更新檔案\n'{0}' +無法啟動編輯器。 +檔案似是病毒(檔案名稱含有很多空格)。 +不能完成操作,因資料夾路徑過長。 +您必須選擇一個檔案 +您必須選擇最少一個檔案 +項目過多 +無法開啟為 {0} 壓縮檔 +開啟為 {0} 壓縮檔 +壓縮檔以偏移值開啟 +3300 +正在解壓縮 +正在壓縮 +測試 +正在開啟... +正在掃瞄... +正在移除 +3320 +正在加入 +正在更新 +正在分析 +正在複製 +正在重新封裝 +正在略過 +正在刪除 +正在建立標頭 +3400 +解壓縮 +解壓縮至(&X): +請指定存放暫存壓縮檔的位置。 +3410 +路徑模式: +完整的路徑名稱 +不要路徑名稱 +絕對路徑 +相對路徑 +3420 +覆寫模式 +覆寫前先詢問我 +覆寫時不詢問 +略過現有的檔案 +自動重新命名 +自動重新命名現有的檔案 +3430 +刪除重複的根目錄 +恢復檔案安全設定 +3500 +確認取代檔案 +目的資料夾已包含要處理的檔案。 +您要取代現有的檔案 +而改用這個檔案嗎? +{0} 位元組 +自動重新命名(&U) +3700 +'{0}' 未支援此壓縮方式。 +'{0}' 中的資料含有錯誤。檔案已損壞。 +'{0}' 的 CRC 驗證失敗。檔案已損壞。 +加密檔 '{0}' 中的資料含有錯誤。錯誤的密碼? +加密檔 '{0}' 的 CRC 驗證失敗。錯誤的密碼? +3710 +錯誤的密碼? +3721 +不支援此壓縮方式 +資料含有錯誤 +CRC 驗證失敗 +資料不能使用 +資料異常終結 +有效負載盡頭外還有其他資料 +不是壓縮檔 +標頭錯誤 +密碼錯誤 +3763 +壓縮檔的開端不能使用 +未能確認壓縮檔的開端 + + + +不支援的功能 +3800 +輸入密碼 +輸入密碼: +重新輸入密碼: +顯示密碼(&S) +密碼不一致 +僅能使用英文字母、數字和特殊字元 (!, #, $, ...) 當作密碼 +密碼太長 +密碼 +3900 +經過時間: +剩餘時間: +大小: +速度: +已處理: +壓縮率: +錯誤數: +壓縮檔: +4000 +加入壓縮檔 +壓縮檔(&A): +更新模式(&U): +壓縮檔格式(&F): +壓縮層級(&L): +壓縮方式(&M): +字典大小(&D): +字組大小(&W): +結實區塊大小: +CPU 線程數: +參數(&P): +選項 +建立自解壓縮檔(&X) +壓縮共用檔案 +加密 +加密方法: +加密檔名(&N) +壓縮時記憶體使用: +解壓縮時記憶體使用: +壓縮後刪除檔案 +4040 +儲存符號連結 +儲存硬連結 +儲存附加資料流 +儲存檔案安全設定 +4050 +封存 +最快速壓縮 +快速壓縮 +一般壓縮 +最大壓縮 +極致壓縮 +4060 +加入並取代檔案 +更新並加入檔案 +更新現有的檔案 +同步處理檔案 +4070 +瀏覽 +所有檔案 +非結實 +結實 +6000 +複製 +移動 +複製到: +移動到: +正在複製... +正在移動... +正在重新命名... +選擇目標資料夾。 +未支援的操作。 +重新命名檔案或資料夾時發生錯誤 +確認複製檔案 +您確定要複製檔案至壓縮檔? +6100 +確認刪除檔案 +確認刪除資料夾 +確認刪除多個檔案 +您確定要刪除 '{0}' 嗎? +您確定要刪除資料夾 '{0}' 以及它所有的內容嗎? +您確定要刪除這 {0} 個項目嗎? +正在刪除... +刪除檔案或資料夾時發生錯誤 +系統不能移動路徑過長的檔案到資源回收筒 +6300 +建立資料夾 +建立檔案 +資料夾名稱: +檔案名稱: +新增資料夾 +新增檔案 +建立資料夾時發生錯誤 +建立檔案時發生錯誤 +6400 +註解 +註解(&C): +選取 +取消選取 +遮罩: +6600 +內容 +資料夾歷程記錄 +診斷訊息 +訊息 +7100 +電腦 +網路 +文件 +系統 +7200 +加入 +解壓縮 +測試 +複製 +移動 +刪除 +資訊 +7300 +分割檔案 +分割到(&S): +分割壓縮檔,位元組(&V): +正在分割... +確認分割 +您確定要分割檔案為 {0} 個? +分割大小必須小於原始檔案大小 +不正確的分割大小 +指定的分割大小: {0} 位元組。\n您確定要分割為這些壓縮檔嗎? +7400 +合併檔案 +合併到(&C): +正在合併... +僅選取第一個檔案 +未能確認此檔案為完整檔案分割出來的一部分 +找不到完整檔案的其他部分 +7500 +正在計算驗證值... +驗證值資訊 +資料的 CRC 驗證值: +資料及名稱的 CRC 驗證值: +7600 +效能測試 +記憶體使用: +壓縮 +解壓縮 +評等 +整體評等 +目前 +結果 +CPU 使用 +評等 / 使用 +通過數: +7700 +連結 +連結 +連結自: +連結到: +7710 +連結類型 +硬連結 +檔案符號連結 +目錄符號連結 +目錄連接點 diff --git a/Moose Mission Setup/Moose Mission Update/License.txt b/Utils/7-Zip/License.txt similarity index 100% rename from Moose Mission Setup/Moose Mission Update/License.txt rename to Utils/7-Zip/License.txt diff --git a/Moose Mission Setup/Moose Mission Update/Uninstall.exe b/Utils/7-Zip/Uninstall.exe similarity index 97% rename from Moose Mission Setup/Moose Mission Update/Uninstall.exe rename to Utils/7-Zip/Uninstall.exe index e214183c8..dab4e4e8a 100644 Binary files a/Moose Mission Setup/Moose Mission Update/Uninstall.exe and b/Utils/7-Zip/Uninstall.exe differ diff --git a/Moose Mission Setup/Moose Mission Update/descript.ion b/Utils/7-Zip/descript.ion similarity index 100% rename from Moose Mission Setup/Moose Mission Update/descript.ion rename to Utils/7-Zip/descript.ion diff --git a/Moose Mission Setup/Moose Mission Update/readme.txt b/Utils/7-Zip/readme.txt similarity index 99% rename from Moose Mission Setup/Moose Mission Update/readme.txt rename to Utils/7-Zip/readme.txt index c6a5e53c1..228e9a0ce 100644 --- a/Moose Mission Setup/Moose Mission Update/readme.txt +++ b/Utils/7-Zip/readme.txt @@ -1,4 +1,4 @@ -7-Zip 16.02 +7-Zip 16.04 ----------- 7-Zip is a file archiver for Windows NT / 2000 / 2003 / 2008 / 2012 / XP / Vista / 7 / 8 / 10. diff --git a/Utils/lua/5.1/bin/lua.exe b/Utils/lua/5.1/bin/lua.exe new file mode 100644 index 000000000..d8566c515 Binary files /dev/null and b/Utils/lua/5.1/bin/lua.exe differ diff --git a/Utils/lua/5.1/bin/lua51.dll b/Utils/lua/5.1/bin/lua51.dll new file mode 100644 index 000000000..36418f3f3 Binary files /dev/null and b/Utils/lua/5.1/bin/lua51.dll differ diff --git a/Utils/lua/5.1/bin/luac.exe b/Utils/lua/5.1/bin/luac.exe new file mode 100644 index 000000000..9c64f9926 Binary files /dev/null and b/Utils/lua/5.1/bin/luac.exe differ diff --git a/Utils/lua/5.1/bin/luadocumentor.bat b/Utils/lua/5.1/bin/luadocumentor.bat new file mode 100644 index 000000000..3d449219a --- /dev/null +++ b/Utils/lua/5.1/bin/luadocumentor.bat @@ -0,0 +1,3 @@ +@echo off +"C:\Program Files\lua\5.1\bin\lua.exe" -e "package.path=\"C:\\Users\\svenv\\AppData\\Roaming/luarocks/share/lua/5.1/?.lua;C:\\Users\\svenv\\AppData\\Roaming/luarocks/share/lua/5.1/?/init.lua;c:\\program files\\lua\\5.1\\/share/lua/5.1/?.lua;c:\\program files\\lua\\5.1\\/share/lua/5.1/?/init.lua;C:\\Program Files (x86)\\LuaRocks\\lua\\?.lua;\"..package.path; package.cpath=\"C:\\Users\\svenv\\AppData\\Roaming/luarocks/lib/lua/5.1/?.dll;c:\\program files\\lua\\5.1\\/lib/lua/5.1/?.dll;\"..package.cpath" -e "local k,l,_=pcall(require,\"luarocks.loader\") _=k and l.add_context(\"luadocumentor\",\"0.1.5-1\")" "c:\program files\lua\5.1\\lib\luarocks\rocks\luadocumentor\0.1.5-1\bin\luadocumentor" %* +exit /b %ERRORLEVEL% diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lauxlib.h b/Utils/lua/5.1/include/lauxlib.h similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lauxlib.h rename to Utils/lua/5.1/include/lauxlib.h diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lua.h b/Utils/lua/5.1/include/lua.h similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lua.h rename to Utils/lua/5.1/include/lua.h diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lua.hpp b/Utils/lua/5.1/include/lua.hpp similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lua.hpp rename to Utils/lua/5.1/include/lua.hpp diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/include/luaconf.h b/Utils/lua/5.1/include/luaconf.h similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/include/luaconf.h rename to Utils/lua/5.1/include/luaconf.h diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lualib.h b/Utils/lua/5.1/include/lualib.h similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/include/lualib.h rename to Utils/lua/5.1/include/lualib.h diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/liblua.a b/Utils/lua/5.1/lib/liblua.a similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/liblua.a rename to Utils/lua/5.1/lib/liblua.a diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/lua/5.1/checks.dll b/Utils/lua/5.1/lib/lua/5.1/checks.dll similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/lua/5.1/checks.dll rename to Utils/lua/5.1/lib/lua/5.1/checks.dll diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/lua/5.1/lfs.dll b/Utils/lua/5.1/lib/lua/5.1/lfs.dll similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/lua/5.1/lfs.dll rename to Utils/lua/5.1/lib/lua/5.1/lfs.dll diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE b/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE rename to Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md b/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md rename to Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua b/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua rename to Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/manifest b/Utils/lua/5.1/lib/luarocks/rocks/manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/manifest rename to Utils/lua/5.1/lib/luarocks/rocks/manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md b/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec b/Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec rename to Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest b/Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest rename to Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/man/man1/lua.1 b/Utils/lua/5.1/man/man1/lua.1 similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/man/man1/lua.1 rename to Utils/lua/5.1/man/man1/lua.1 diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/man/man1/luac.1 b/Utils/lua/5.1/man/man1/luac.1 similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/man/man1/luac.1 rename to Utils/lua/5.1/man/man1/luac.1 diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/defaultcss.lua b/Utils/lua/5.1/share/lua/5.1/defaultcss.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/defaultcss.lua rename to Utils/lua/5.1/share/lua/5.1/defaultcss.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/docgenerator.lua b/Utils/lua/5.1/share/lua/5.1/docgenerator.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/docgenerator.lua rename to Utils/lua/5.1/share/lua/5.1/docgenerator.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/extractors.lua b/Utils/lua/5.1/share/lua/5.1/extractors.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/extractors.lua rename to Utils/lua/5.1/share/lua/5.1/extractors.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/fs/lfs.lua b/Utils/lua/5.1/share/lua/5.1/fs/lfs.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/fs/lfs.lua rename to Utils/lua/5.1/share/lua/5.1/fs/lfs.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/lddextractor.lua b/Utils/lua/5.1/share/lua/5.1/lddextractor.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/lddextractor.lua rename to Utils/lua/5.1/share/lua/5.1/lddextractor.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/markdown.lua b/Utils/lua/5.1/share/lua/5.1/markdown.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/markdown.lua rename to Utils/lua/5.1/share/lua/5.1/markdown.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua b/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/extension/match.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/extension/match.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/extension/match.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/extension/match.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua b/Utils/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua b/Utils/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/loader.lua b/Utils/lua/5.1/share/lua/5.1/metalua/loader.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/loader.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/loader.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/pprint.lua b/Utils/lua/5.1/share/lua/5.1/metalua/pprint.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/pprint.lua rename to Utils/lua/5.1/share/lua/5.1/metalua/pprint.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/repl.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/repl.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/repl.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/repl.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/treequery.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/treequery.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/treequery.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/treequery.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua b/Utils/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua rename to Utils/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/apimodel.lua b/Utils/lua/5.1/share/lua/5.1/models/apimodel.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/apimodel.lua rename to Utils/lua/5.1/share/lua/5.1/models/apimodel.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua b/Utils/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua rename to Utils/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/internalmodel.lua b/Utils/lua/5.1/share/lua/5.1/models/internalmodel.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/internalmodel.lua rename to Utils/lua/5.1/share/lua/5.1/models/internalmodel.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua b/Utils/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua rename to Utils/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/ldparser.lua b/Utils/lua/5.1/share/lua/5.1/models/ldparser.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/models/ldparser.lua rename to Utils/lua/5.1/share/lua/5.1/models/ldparser.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Date.lua b/Utils/lua/5.1/share/lua/5.1/pl/Date.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Date.lua rename to Utils/lua/5.1/share/lua/5.1/pl/Date.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/List.lua b/Utils/lua/5.1/share/lua/5.1/pl/List.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/List.lua rename to Utils/lua/5.1/share/lua/5.1/pl/List.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Map.lua b/Utils/lua/5.1/share/lua/5.1/pl/Map.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Map.lua rename to Utils/lua/5.1/share/lua/5.1/pl/Map.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/MultiMap.lua b/Utils/lua/5.1/share/lua/5.1/pl/MultiMap.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/MultiMap.lua rename to Utils/lua/5.1/share/lua/5.1/pl/MultiMap.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/OrderedMap.lua b/Utils/lua/5.1/share/lua/5.1/pl/OrderedMap.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/OrderedMap.lua rename to Utils/lua/5.1/share/lua/5.1/pl/OrderedMap.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Set.lua b/Utils/lua/5.1/share/lua/5.1/pl/Set.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/Set.lua rename to Utils/lua/5.1/share/lua/5.1/pl/Set.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/app.lua b/Utils/lua/5.1/share/lua/5.1/pl/app.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/app.lua rename to Utils/lua/5.1/share/lua/5.1/pl/app.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/array2d.lua b/Utils/lua/5.1/share/lua/5.1/pl/array2d.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/array2d.lua rename to Utils/lua/5.1/share/lua/5.1/pl/array2d.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/class.lua b/Utils/lua/5.1/share/lua/5.1/pl/class.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/class.lua rename to Utils/lua/5.1/share/lua/5.1/pl/class.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/comprehension.lua b/Utils/lua/5.1/share/lua/5.1/pl/comprehension.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/comprehension.lua rename to Utils/lua/5.1/share/lua/5.1/pl/comprehension.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/config.lua b/Utils/lua/5.1/share/lua/5.1/pl/config.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/config.lua rename to Utils/lua/5.1/share/lua/5.1/pl/config.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/data.lua b/Utils/lua/5.1/share/lua/5.1/pl/data.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/data.lua rename to Utils/lua/5.1/share/lua/5.1/pl/data.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/dir.lua b/Utils/lua/5.1/share/lua/5.1/pl/dir.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/dir.lua rename to Utils/lua/5.1/share/lua/5.1/pl/dir.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/file.lua b/Utils/lua/5.1/share/lua/5.1/pl/file.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/file.lua rename to Utils/lua/5.1/share/lua/5.1/pl/file.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/func.lua b/Utils/lua/5.1/share/lua/5.1/pl/func.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/func.lua rename to Utils/lua/5.1/share/lua/5.1/pl/func.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/init.lua b/Utils/lua/5.1/share/lua/5.1/pl/init.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/init.lua rename to Utils/lua/5.1/share/lua/5.1/pl/init.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/input.lua b/Utils/lua/5.1/share/lua/5.1/pl/input.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/input.lua rename to Utils/lua/5.1/share/lua/5.1/pl/input.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/lapp.lua b/Utils/lua/5.1/share/lua/5.1/pl/lapp.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/lapp.lua rename to Utils/lua/5.1/share/lua/5.1/pl/lapp.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/lexer.lua b/Utils/lua/5.1/share/lua/5.1/pl/lexer.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/lexer.lua rename to Utils/lua/5.1/share/lua/5.1/pl/lexer.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/luabalanced.lua b/Utils/lua/5.1/share/lua/5.1/pl/luabalanced.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/luabalanced.lua rename to Utils/lua/5.1/share/lua/5.1/pl/luabalanced.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/operator.lua b/Utils/lua/5.1/share/lua/5.1/pl/operator.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/operator.lua rename to Utils/lua/5.1/share/lua/5.1/pl/operator.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/path.lua b/Utils/lua/5.1/share/lua/5.1/pl/path.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/path.lua rename to Utils/lua/5.1/share/lua/5.1/pl/path.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/permute.lua b/Utils/lua/5.1/share/lua/5.1/pl/permute.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/permute.lua rename to Utils/lua/5.1/share/lua/5.1/pl/permute.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/platf/luajava.lua b/Utils/lua/5.1/share/lua/5.1/pl/platf/luajava.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/platf/luajava.lua rename to Utils/lua/5.1/share/lua/5.1/pl/platf/luajava.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/pretty.lua b/Utils/lua/5.1/share/lua/5.1/pl/pretty.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/pretty.lua rename to Utils/lua/5.1/share/lua/5.1/pl/pretty.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/seq.lua b/Utils/lua/5.1/share/lua/5.1/pl/seq.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/seq.lua rename to Utils/lua/5.1/share/lua/5.1/pl/seq.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/sip.lua b/Utils/lua/5.1/share/lua/5.1/pl/sip.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/sip.lua rename to Utils/lua/5.1/share/lua/5.1/pl/sip.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/strict.lua b/Utils/lua/5.1/share/lua/5.1/pl/strict.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/strict.lua rename to Utils/lua/5.1/share/lua/5.1/pl/strict.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/stringio.lua b/Utils/lua/5.1/share/lua/5.1/pl/stringio.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/stringio.lua rename to Utils/lua/5.1/share/lua/5.1/pl/stringio.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/stringx.lua b/Utils/lua/5.1/share/lua/5.1/pl/stringx.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/stringx.lua rename to Utils/lua/5.1/share/lua/5.1/pl/stringx.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/tablex.lua b/Utils/lua/5.1/share/lua/5.1/pl/tablex.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/tablex.lua rename to Utils/lua/5.1/share/lua/5.1/pl/tablex.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/template.lua b/Utils/lua/5.1/share/lua/5.1/pl/template.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/template.lua rename to Utils/lua/5.1/share/lua/5.1/pl/template.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/test.lua b/Utils/lua/5.1/share/lua/5.1/pl/test.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/test.lua rename to Utils/lua/5.1/share/lua/5.1/pl/test.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/text.lua b/Utils/lua/5.1/share/lua/5.1/pl/text.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/text.lua rename to Utils/lua/5.1/share/lua/5.1/pl/text.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/utils.lua b/Utils/lua/5.1/share/lua/5.1/pl/utils.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/utils.lua rename to Utils/lua/5.1/share/lua/5.1/pl/utils.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/xml.lua b/Utils/lua/5.1/share/lua/5.1/pl/xml.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/pl/xml.lua rename to Utils/lua/5.1/share/lua/5.1/pl/xml.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/file.lua b/Utils/lua/5.1/share/lua/5.1/template/file.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/file.lua rename to Utils/lua/5.1/share/lua/5.1/template/file.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/index.lua b/Utils/lua/5.1/share/lua/5.1/template/index.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/index.lua rename to Utils/lua/5.1/share/lua/5.1/template/index.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua b/Utils/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua rename to Utils/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/item.lua b/Utils/lua/5.1/share/lua/5.1/template/item.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/item.lua rename to Utils/lua/5.1/share/lua/5.1/template/item.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/page.lua b/Utils/lua/5.1/share/lua/5.1/template/page.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/page.lua rename to Utils/lua/5.1/share/lua/5.1/template/page.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/recordtypedef.lua b/Utils/lua/5.1/share/lua/5.1/template/recordtypedef.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/recordtypedef.lua rename to Utils/lua/5.1/share/lua/5.1/template/recordtypedef.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/usage.lua b/Utils/lua/5.1/share/lua/5.1/template/usage.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/usage.lua rename to Utils/lua/5.1/share/lua/5.1/template/usage.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/utils.lua b/Utils/lua/5.1/share/lua/5.1/template/utils.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/template/utils.lua rename to Utils/lua/5.1/share/lua/5.1/template/utils.lua diff --git a/Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/templateengine.lua b/Utils/lua/5.1/share/lua/5.1/templateengine.lua similarity index 100% rename from Moose Development Evironment Setup/LuaFiles/lua/5.1/share/lua/5.1/templateengine.lua rename to Utils/lua/5.1/share/lua/5.1/templateengine.lua