From d77279328ef2a518ba7f3a7705a07ded785e3ae6 Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Fri, 6 Mar 2026 19:07:54 +0100 Subject: [PATCH] Work in progress refactor for toolkit --- .DS_Store | Bin 8196 -> 8196 bytes .gitignore | 4 +- .vscode/settings.json | 5 +- DcsTypes.lua | 1349 ---------- classes/fleetClasses/GlobalFleetManager.lua | 22 - main.lua | 82 - .../classes}/_baseClasses/Queue.lua | 5 +- {classes => src/classes}/api/SpearheadApi.lua | 9 +- .../classes}/api/SpearheadApiDoc.lua | 0 .../classes}/capClasses/CapAirbase.lua | 34 +- .../classes}/capClasses/GlobalCapManager.lua | 31 +- .../capClasses/airGroups/AirGroup.lua | 27 +- .../capClasses/airGroups/CapGroup.lua | 42 +- .../capClasses/airGroups/InterceptGroup.lua | 50 +- .../capClasses/airGroups/SweepGroup.lua | 39 +- .../capClasses/detection/DetectionManager.lua | 6 +- .../runwayBombing/RunwayBombingTracker.lua | 15 +- .../classes}/capClasses/taskings/CAP.lua | 33 +- .../capClasses/taskings/INTERCEPT.lua | 31 +- .../classes}/capClasses/taskings/RTB.lua | 21 +- .../classes}/capClasses/taskings/SWEEP.lua | 27 +- .../classes}/configuration/CapConfig.lua | 4 +- .../classes}/configuration/GlobalConfig.lua | 3 +- .../classes}/configuration/StageConfig.lua | 6 +- .../classes}/definitions/aliases.lua | 0 .../classes}/fleetClasses/FleetGroup.lua | 56 +- .../fleetClasses/GlobalFleetManager.lua | 26 + .../classes}/helpers/MizGroupsManager.lua | 13 +- .../classes}/helpers/SpawnManager.lua | 32 +- .../classes}/persistence/Persistence.lua | 21 +- {classes => src/classes}/spearhead_db.lua | 3 +- {classes => src/classes}/spearhead_events.lua | 5 +- .../classes}/spearhead_routeutil.lua | 4 +- .../stageClasses/GlobalStageManager.lua | 6 +- .../stageClasses/Groups/SpearheadGroup.lua | 9 +- .../Groups/SpearheadSceneryObject.lua | 11 +- .../stageClasses/SpecialZones/BlueSam.lua | 8 +- .../stageClasses/SpecialZones/FarpZone.lua | 6 +- .../stageClasses/SpecialZones/StageBase.lua | 8 +- .../stageClasses/SpecialZones/SupplyHub.lua | 7 +- .../SpecialZones/abstract/BuildableZone.lua | 7 +- .../stageClasses/Stages/BaseStage/Stage.lua | 6 +- .../stageClasses/Stages/ExtraStage.lua | 5 +- .../stageClasses/Stages/PrimaryStage.lua | 5 +- .../stageClasses/Stages/WaitingStage.lua | 5 +- .../stageClasses/drawings/CustomDrawing.lua | 18 +- .../drawings/helper/DrawingHelper.lua | 7 +- .../stageClasses/helpers/BattleManager.lua | 28 +- .../stageClasses/helpers/MaxLoadConfig.lua | 20 + .../helpers/MissionCommandsHelper.lua | 47 +- .../helpers/SupplyConfigHelper.lua | 31 +- .../helpers/SupplyUnitsTracker.lua | 45 +- .../missions/BuildableMission.lua | 48 +- .../missions/RunwayStrikeMission.lua | 7 +- .../stageClasses/missions/ZoneMission.lua | 5 +- .../missions/baseMissions/Mission.lua | 29 +- .../classes/util/DcsUtil.lua | 2289 ++++++----------- src/classes/util/Logger.lua | 75 + src/classes/util/MissionEditorWarnings.lua | 26 + src/classes/util/Util.lua | 503 ++++ src/main.lua | 96 + 61 files changed, 1987 insertions(+), 3375 deletions(-) delete mode 100644 DcsTypes.lua delete mode 100644 classes/fleetClasses/GlobalFleetManager.lua delete mode 100644 main.lua rename {classes => src/classes}/_baseClasses/Queue.lua (84%) rename {classes => src/classes}/api/SpearheadApi.lua (83%) rename {classes => src/classes}/api/SpearheadApiDoc.lua (100%) rename {classes => src/classes}/capClasses/CapAirbase.lua (92%) rename {classes => src/classes}/capClasses/GlobalCapManager.lua (62%) rename {classes => src/classes}/capClasses/airGroups/AirGroup.lua (92%) rename {classes => src/classes}/capClasses/airGroups/CapGroup.lua (66%) rename {classes => src/classes}/capClasses/airGroups/InterceptGroup.lua (83%) rename {classes => src/classes}/capClasses/airGroups/SweepGroup.lua (67%) rename {classes => src/classes}/capClasses/detection/DetectionManager.lua (93%) rename {classes => src/classes}/capClasses/runwayBombing/RunwayBombingTracker.lua (85%) rename {classes => src/classes}/capClasses/taskings/CAP.lua (88%) rename {classes => src/classes}/capClasses/taskings/INTERCEPT.lua (89%) rename {classes => src/classes}/capClasses/taskings/RTB.lua (82%) rename {classes => src/classes}/capClasses/taskings/SWEEP.lua (87%) rename {classes => src/classes}/configuration/CapConfig.lua (92%) rename {classes => src/classes}/configuration/GlobalConfig.lua (86%) rename {classes => src/classes}/configuration/StageConfig.lua (84%) rename {classes => src/classes}/definitions/aliases.lua (100%) rename {classes => src/classes}/fleetClasses/FleetGroup.lua (63%) create mode 100644 src/classes/fleetClasses/GlobalFleetManager.lua rename {classes => src/classes}/helpers/MizGroupsManager.lua (84%) rename {classes => src/classes}/helpers/SpawnManager.lua (90%) rename {classes => src/classes}/persistence/Persistence.lua (92%) rename {classes => src/classes}/spearhead_db.lua (99%) rename {classes => src/classes}/spearhead_events.lua (99%) rename {classes => src/classes}/spearhead_routeutil.lua (99%) rename {classes => src/classes}/stageClasses/GlobalStageManager.lua (98%) rename {classes => src/classes}/stageClasses/Groups/SpearheadGroup.lua (92%) rename {classes => src/classes}/stageClasses/Groups/SpearheadSceneryObject.lua (73%) rename {classes => src/classes}/stageClasses/SpecialZones/BlueSam.lua (92%) rename {classes => src/classes}/stageClasses/SpecialZones/FarpZone.lua (90%) rename {classes => src/classes}/stageClasses/SpecialZones/StageBase.lua (94%) rename {classes => src/classes}/stageClasses/SpecialZones/SupplyHub.lua (86%) rename {classes => src/classes}/stageClasses/SpecialZones/abstract/BuildableZone.lua (93%) rename {classes => src/classes}/stageClasses/Stages/BaseStage/Stage.lua (97%) rename {classes => src/classes}/stageClasses/Stages/ExtraStage.lua (84%) rename {classes => src/classes}/stageClasses/Stages/PrimaryStage.lua (68%) rename {classes => src/classes}/stageClasses/Stages/WaitingStage.lua (87%) rename {classes => src/classes}/stageClasses/drawings/CustomDrawing.lua (58%) rename {classes => src/classes}/stageClasses/drawings/helper/DrawingHelper.lua (93%) rename {classes => src/classes}/stageClasses/helpers/BattleManager.lua (86%) create mode 100644 src/classes/stageClasses/helpers/MaxLoadConfig.lua rename {classes => src/classes}/stageClasses/helpers/MissionCommandsHelper.lua (88%) rename classes/stageClasses/helpers/SupplyConfig.lua => src/classes/stageClasses/helpers/SupplyConfigHelper.lua (67%) rename {classes => src/classes}/stageClasses/helpers/SupplyUnitsTracker.lua (87%) rename {classes => src/classes}/stageClasses/missions/BuildableMission.lua (78%) rename {classes => src/classes}/stageClasses/missions/RunwayStrikeMission.lua (97%) rename {classes => src/classes}/stageClasses/missions/ZoneMission.lua (98%) rename {classes => src/classes}/stageClasses/missions/baseMissions/Mission.lua (78%) rename classes/spearhead_base.lua => src/classes/util/DcsUtil.lua (57%) create mode 100644 src/classes/util/Logger.lua create mode 100644 src/classes/util/MissionEditorWarnings.lua create mode 100644 src/classes/util/Util.lua create mode 100644 src/main.lua diff --git a/.DS_Store b/.DS_Store index 4b3a3c0283ea79121b114dc723b8e5e496a85858..dd3bcfbdc5a6f9b2baad3dc6000d463bdf36ffa8 100644 GIT binary patch delta 682 zcmZp1XmOa}&uF$WU^hRb*<>C8sn{h9K)}MF$B@pD$xxD;@8Xh_lb-|><4D@@um0N7 zDV7Q?Rst|*jRRk zWQH7uM22D@Ol2s}%|{pxQ8igYM2T_2W@`~H#`;X4qLQ3+g!v4t&DX(hO98qZD2MEJ zyKmKDw_$FF%Oi}(CXeiP2G$86FR(DAFysRrS?rm!*+: { [number]: T } - ----@class MGRS ----@field UTMZone string ----@field MGRSDigraph string ----@field Easting number ----@field Northing number - - -do -- env - ---@class env - ---@field mission table TODO: Mission - ---@field warehouses table - ---@field info fun(log:string, showMessageBox:boolean?) Prints passed log line with prefix 'info' - ---@field warning fun(log:string, showMessageBox:boolean?) Prints passed log line with prefix 'warning' - ---@field error fun(log:string, showMessageBox:boolean?) Prints passed log line with prefix 'error' - ---@field setErrorMessageBoxEnabled fun(toggle:boolean?) Enables or disables the lua error box to show up on a lua error - ---@field getValueDictByKey fun(value:string) : string Returns a string associated with the passed dictionary key value. - env = env -end - -do -- Mission table - - ---@class Mission - ---@field drawings Array - - ---@alias PrimitiveType - ---| "Polygon" - ---| "Line" - ---| "TextBox" - - ---@alias PolygonMode - ---| "circle" - ---| "free" - ---| "oval" - ---| "rect" - ---| "arrow" - - ---@alias LineMode - ---| "segment" - ---| "segments" - ---| "free" - - ---@class DrawingObject - ---@field primitiveType PrimitiveType - ---@field name string - ---@field visible boolean - ---@field layerName string? - ---@field mapX number - ---@field mapY number - ---@field colorString string Hex ARGB color - ---@field style string - ---@field thickness number - - ---@class Polygon : DrawingObject - ---@field polygonMode PolygonMode - ---@field fillColorString string? - - ---@class Circle : Polygon - ---@field radius number - - ---@class Free : Polygon - ---@field points Array - - ---@class Oval : Polygon - ---@field r1 number - ---@field r2 number - ---@field angle number? - - ---@class Rect : Polygon - ---@field width number - ---@field height number - ---@field angle number? - - ---@class Arrow : Polygon - ---@field length number - ---@field angle number? - - ---@class Line : DrawingObject - ---@field primitiveType PrimitiveType # PrimitiveType.Line - ---@field lineMode LineMode - ---@field closed boolean - ---@field points Array - - ---@class Segment : Line - - ---@class Segments : Line - - ---@class FreeLine : Line - - ---@class TextBox : DrawingObject - ---@field fontSize number - ---@field text string - ---@field fillColorString string - ---@field borderThickness number - -end - -do -- timer - ---@class timer - ---@field getTime fun() : number returns the time in the mission (in seconds. 3 decimals) - ---@field getAbsTime fun() : number returns the real time in seconds. 0 for midnight, 43200 for noon - ---@field getTime0 fun() : number returns the mission start time in seconds - ---@field scheduleFunction fun(functionToCall: function, arguments: any|nil, modelTime: number) : number schedule the function to be run at 'modelTime' and returns the functionID - ---@field removeFunction fun(functionID:number) removes a scheduled function from the scheduler - ---@field setFunctionTime fun(functionID:number, modelTime:number) reschedules an scheduled function - timer = timer -end - - -do -- land - ---@class land - ---@field getHeight fun(position:Vec2) : number returns the distance from the sea-level to the ground alt at point - ---@field getSurfaceHeightWithSeabed fun(position:Vec2) : sufaceHeight: number, depth: number returns the surface height and the depth of the seabed respectively. - ---@field getSurfaceType fun(position: Vec2) : SurfaceType returns the surface type at a certain position - ---@field isVisible fun(origin: Vec3, target: Vec3) returns whether or not there's line between the two points that's not interrupted by terrain. - ---@field getIP fun(origin:Vec3, direction:number, distance:number) TODO: Describe - ---@field profile fun(start:Vec3, end:Vec3) : Array Returns a list of terrain points between two points. Amount is not directly known. - ---@field getClosestPointOnRoads fun(roadType: RoadType, x : number, y : number) : x: number, y: number return x and y coordinate of the closest point on a road type. - ---@field findPathOnRoads fun(roadType: RoadType, startX: number, startY: number, endX: number, endY: number) : Array Returns a list of Vec2 points of a road. Can be quite long! - land = land - - ---@enum SurfaceType - land.SurfaceType = { - LAND = 1, - SHALLOW_WATER = 2, - WATER = 3, - ROAD = 4, - RUNWAY = 5 - } - - ---@alias RoadType - ---| "roads" - ---| "railroads" -end - -do -- atmosphere - ---@class atmosphere - ---@field getWind fun(point:Vec3): Vec3 returns a velocity vector for the wind at a point - ---@field getWindWithTurbulence fun(point:Vec3): Vec3 return a velocity vector for the wind including turbulent air - ---@field getTemperatureAndPressure fun(point:Vec3) : temp: number, pressure: number returns temperature and pressure. Kelvins and Pascals. - atmosphere = atmosphere -end - -do -- world - ---@class Event - ---@field id world.event - ---@field time number - - ---@class EventHandler - ---@field onEvent fun(event: Event) - - ---@class world - ---@field addEventHandler fun(handler: EventHandler) Adds an event handler that will be called on DCS events. - ---@field removeEventHandler fun(handler: EventHandler) Removes an event handler from the "to call table" - ---@field getPlayer fun() : Unit returns the unit object that is specified as "Player" in the mission editor - ---@field getAirbases fun(side: CoalitionSide?) : Array returns airbases (ships, bases, farps) of a side, or all if side is not passed - ---@field searchObjects fun(category: ObjectCategory, searchVolume: Volume, handler: fun(item:Object, value : any?), value: any?) : table searches a volume or space for objects of a specific type and can call the handler function on each found object - ---@field getMarkPanels fun() : table TODO: describe - ---@field removeJunk fun(searchVolume: Volume) : number searches a volume for any wrecks, craters or debris and removes it - ---@field getFogThickness fun() : number returns the global fog thickness. 0 if no fog is present - ---@field setFogThickness fun(thickness: number) sets the fog thickness. 100 to 5000. 0 to remove fog - ---@field getFogVisibilityDistance fun() : number returns the visibility distance in mist - ---@field setFogVisibilityDistance fun(visibility:number) sets the visibility distance. 100 to 100000. If 0 the fog will be removed. - ---@field setFogAnimation fun(dataTable: Array>) {relative time (seconds), visibility (meters), thickness (meters)} eg. {5, 1000, 500}, - ---@field weather table TODO: describe weather - world = world - - - do -- Event Types - ---@enum world.event - world.event = { - S_EVENT_INVALID = 0, - S_EVENT_SHOT = 1, - S_EVENT_HIT = 2, - S_EVENT_TAKEOFF = 3, - S_EVENT_LAND = 4, - S_EVENT_CRASH = 5, - S_EVENT_EJECTION = 6, - S_EVENT_REFUELING = 7, - S_EVENT_DEAD = 8, - S_EVENT_PILOT_DEAD = 9, - S_EVENT_BASE_CAPTURED = 10, - S_EVENT_MISSION_START = 11, - S_EVENT_MISSION_END = 12, - S_EVENT_TOOK_CONTROL = 13, - S_EVENT_REFUELING_STOP = 14, - S_EVENT_BIRTH = 15, - S_EVENT_HUMAN_FAILURE = 16, - S_EVENT_DETAILED_FAILURE = 17, - S_EVENT_ENGINE_STARTUP = 18, - S_EVENT_ENGINE_SHUTDOWN = 19, - S_EVENT_PLAYER_ENTER_UNIT = 20, - S_EVENT_PLAYER_LEAVE_UNIT = 21, - S_EVENT_PLAYER_COMMENT = 22, - S_EVENT_SHOOTING_START = 23, - S_EVENT_SHOOTING_END = 24, - S_EVENT_MARK_ADDED = 25, - S_EVENT_MARK_CHANGE = 26, - S_EVENT_MARK_REMOVED = 27, - S_EVENT_KILL = 28, - S_EVENT_SCORE = 29, - S_EVENT_UNIT_LOST = 30, - S_EVENT_LANDING_AFTER_EJECTION = 31, - S_EVENT_PARATROOPER_LENDING = 32, - S_EVENT_DISCARD_CHAIR_AFTER_EJECTION = 33, - S_EVENT_WEAPON_ADD = 34, - S_EVENT_TRIGGER_ZONE = 35, - S_EVENT_LANDING_QUALITY_MARK = 36, - S_EVENT_BDA = 37, - S_EVENT_AI_ABORT_MISSION = 38, - S_EVENT_DAYNIGHT = 39, - S_EVENT_FLIGHT_TIME = 40, - S_EVENT_PLAYER_SELF_KILL_PILOT = 41, - S_EVENT_PLAYER_CAPTURE_AIRFIELD = 42, - S_EVENT_EMERGENCY_LANDING = 43, - S_EVENT_UNIT_CREATE_TASK = 44, - S_EVENT_UNIT_DELETE_TASK = 45, - S_EVENT_SIMULATION_START = 46, - S_EVENT_WEAPON_REARM = 47, - S_EVENT_WEAPON_DROP = 48, - S_EVENT_UNIT_TASK_COMPLETE = 49, - S_EVENT_UNIT_TASK_STAGE = 50, - S_EVENT_MAC_EXTRA_SCORE = 51, - S_EVENT_MISSION_RESTART = 52, - S_EVENT_MISSION_WINNER = 53, - S_EVENT_RUNWAY_TAKEOFF = 54, - S_EVENT_RUNWAY_TOUCH = 55, - S_EVENT_MAC_LMS_RESTART = 56, - S_EVENT_SIMULATION_FREEZE = 57, - S_EVENT_SIMULATION_UNFREEZE = 58, - S_EVENT_HUMAN_AIRCRAFT_REPAIR_START = 59, - S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH = 60, - S_EVENT_MAX = 61, - } - end - - ---@enum BirthPlace - world.BirthPlace = { - wsBirthPlace_Air = 1, - wsBirthPlace_RunWay = 2, - wsBirthPlace_Park = 3, - wsBirthPlace_Heliport_Hot = 4, - wsBirthPlace_Heliport_Cold = 5, - } - - do --Volumes - ---@class Volume - ---@field id VolumeType - - ---@class Segment - ---@field params SegmentParams - - ---@class SegmentParams - ---@field from Vec3 - ---@field to Vec3 - - ---@class Box : Volume - ---@field params BoxParams - - ---@class BoxParams - ---@field min Vec3 - ---@field max Vec3 - - ---@class Sphere : Volume - ---@field params SphereParams - - ---@class SphereParams - ---@field point Vec3 - ---@field radius number - - ---@class VolumePyramid : Volume - ---@field params VolumePyramidParams - - ---@class VolumePyramidParams - ---@field pos Vec3 - ---@field length number - ---@field halfAngleHor number - ---@field halfAngleVer number - end - - ---@enum VolumeType - world.VolumeType = { - SEGMENT = 1, - BOX = 2, - SPHERE = 3, - PYRAMID = 4 - } -end - -do -- coalition - ---@class coalition - ---@field addGroup fun(countryID: CountryID, groupCategory: GroupCategory, groupData: MissionGroupTable) : Group Spawn a group. If the name of the group or unit is already present the unit will be replaced. - ---@field addStaticObject fun(countryID: CountryID, data: MissionStaticObjectTable) : StaticObject Dynamically adds a static object to the mission. Name needs to be unique. UnitID and groupID can be ommitted and will be created automatically - ---@field getGroups fun(coalitionID : CoalitionSide, category: GroupCategory?) : Array returns group objects of a specific category (or all if no category is specified) - ---@field getStaticObjects fun(coalitionID: CoalitionSide) : Array returns static objects in a coalition - ---@field getAirbases fun(coalitionID: CoalitionSide) : Array returns airbases belonging to a coalition - ---@field getPlayers fun(coalitionID: CoalitionSide) : Array returns units currently occupied by players - ---@field getServiceProviders fun(coalitionID: CoalitionSide, serviceType: CoalitionService) : Array Returns all units that provide a specific service. (AWACS, Tankers etc.) - ---@field addRefPoint fun(coalitionID: CoalitionSide, refPoint: RefPoint) adds a new reference point to the coalition - ---@field getRefPoints fun(coalitionID: CoalitionSide) : table TODO: Ref point return table - ---@field getMainRefPoint fun(coalitionID: CoalitionSide) : Vec3 returns bullseye location for coalition - ---@field getCountryCoalition fun(countryID: CountryID) : CoalitionSide returns coalitionID for a specific countryID - coalition = coalition - - ---@class RefPoint - ---@field callsign number - ---@field type number - ---@field point Vec3 - - - do -- group tables - ---@class MissionGroupTable - end - - do -- static object tables - ---@class MissionStaticObjectTable - ---@field heading number - ---@field groupId number - ---@field shape_name string - ---@field type string - ---@field unitId number - ---@field rate number - ---@field name string - ---@field category string - ---@field x number - ---@field y number - ---@field dead boolean - end - - ---@enum CoalitionSide - coalition.side = { - NEUTRAL = 0, - RED = 1, - BLUE = 2, - } - - ---@enum CoalitionService - coalition.service = { - ATC = 0, - AWACS = 1, - TANKER = 2, - FAC = 3 - } -end - -do -- trigger - ---@class Trigger - ---@field action TriggerActions - ---@field misc TriggerMisc - trigger = trigger - - ---@class TriggerMisc - ---@field getUserFlag fun(flagName: string) : number returns the value of a user flag. - ---@field getZone fun(zoneName: string) : Array returns triggerzones. Only works for cilinders really. For more detailed zone data see: env.mission.triggers.zones - trigger.misc = trigger.misc - - ---@class TriggerActions : OutText, OutSound, OtherCommands, MarkCommands, AITriggerCommands - ---@field ctfColorTag fun(unitName: string, smokeColor: SmokePlumeColor, minAlt: number?) Created a smoke plume behind a specified aircraft - ---@field setUserFlag fun(flagName: string, userFlagValue: boolean|number) Sets a user flag to a specified value - ---@field explosion fun(point: Vec3, power: number) Creates an explosion at a given point at the specified power. - ---@field smoke fun(point: Vec3, color: SmokeColor) Creates colored smoke marker at a given point - ---@field effectSmokeBig fun(point: Vec3, effect: SmokeEffect, density: number, name: string?) Creates a large smoke effect on a vec3 point of a specified type and density. - ---@field effectSmokeStop fun(name: string) Stop a smoke effect effect of the passsed name - ---@field illuminationBomb fun(point: Vec3, power: number) Creates an ilumination bomb that will burn for 300 seconds - ---@field signalFlare fun(point: Vec3, flareColor: FlareColor, azimuth: number) Creates a signal flare at the given point in the specified color. The flare will be launched in the direction of the azimuth variable. - ---@field radioTransmission fun(fileName: string, point:Vec3, modulation: Modulation, loop: boolean, frequency: number, power: number, name: string?) Transmits an audio file to be broadcast over a specific frequency eneminating from the specified point. - ---@field stopRadioTransmission fun(name: string) Stops a radio transmission of the passed name - ---@field setUnitInternalCargo fun(unitName: string, mass: number) Sets the internal cargo for the specified unit at the specified mass - trigger.action = trigger.action - - ---@class OutSound - ---@field outSound fun(fileName: string) Plays a sound file to all players. - ---@field outSoundForCoalition fun(coalitionSide: CoalitionSide, soundFile: string) Plays a sound file to all players on the specified coalition. - ---@field outSoundForCountry fun(country: CountryID, soundfile: string) Plays a sound file to all players on the specified country. - ---@field outSoundForGroup fun(groupId: number, soundFile: string) Plays a sound file to all players in the specified group. - ---@field outSoundForUnit fun(unitId: number, soundFile: string) Plays a sound file to all players in the specified unit. - - ---@class OutText - ---@field outText fun(text: string, displayTime: number, clearview: boolean?) Displays the passed string of text for the specified time to all players. - ---@field outTextForCoalition fun(coalitionId: CoalitionSide, text: string, displayTime: number, clearview: boolean?) Displays the passed string of text for the specified time to all players belonging to the specified coalition. - ---@field outTextForCountry fun(country: CountryID, text: string, displayTime: number, clearview: boolean?) Displays the passed string of text for the specified time to all players belonging to the specified country. - ---@field outTextForGroup fun(groupId: number, text: string, displayTime: number, clearView: boolean?) Displays the passed string of text for the specified time to all players in the specified group. - ---@field outTextForUnit fun(unitId: number, text: string, displayTime: number, clearView: boolean?) Displays the passed string of text for the specified time to all players in the specified unit. - - ---@class OtherCommands - ---@field addOtherCommand fun(name: string, userFlagName: string, userFlagValue: string) Adds a command to the "F10 Other" radio menu allowing players to call commands and set flags within the mission. - ---@field removeOtherCommand fun(name: string) Removes the command that matches the specified name input variable from the "F10 Other" radio menu. - ---@field addOtherCommandForCoalition fun(coalitionId: CoalitionSide, name: string, userFlagName: string, userFlagValue: number) Adds a command to the "F10 Other" radio menu allowing players to call commands and set flags within the mission. - ---@field removeOtherCommandForCoalition fun(coalitionId: CoalitionSide, name: string) Removes the command that matches the specified name input variable from the "F10 Other" radio menu if the command was added for coalition. - ---@field addOtherCommandForGroup fun(groupId: number, name: string, userFlagName: string, userFlagValue: number) Adds a command to the "F10 Other" radio menu allowing players to call commands and set flags within the mission. - ---@field removeOtherCommandForGroup fun(groupId: number, name: string) Removes the command that matches the specified name input variable from the "F10 Other" radio menu if the command exists for the specified group. - - ---@class MarkCommands - ---@field markToAll fun(id: number, text:string, point:Vec3, readOnly: boolean?, message: string?) Adds a mark point to all on the F10 map with attached text. - ---@field markToCoalition fun(id: number, text: string, point: Vec3, coalitionID: CoalitionSide, readOnly: boolean?, message: string) Adds a mark point to a coalition on the F10 map with attached text. - ---@field markToGroup fun(id: number, text: string, point: Vec3, groupID: number, readOnly: boolean?, message: string?) Adds a mark point to a group on the F10 map with attached text. - ---@field removeMark fun(id: number) Removes a mark panel from the f10 map - ---@field markupToAll fun(shapeID: ShapeId, coalition: DrawCoalition, id: number, ... : any) Complex parameters.
See: https://wiki.hoggitworld.com/view/DCS_func_markupToAll - ---@field lineToAll fun(coalition: DrawCoalition, id: number, startPoint:Vec3, endPoint: Vec3, color:table, lineType: LineType, readonly: boolean?, message: string?) Creates a line on the F10 map from one point to another. - ---@field circleToAll fun(coalition: DrawCoalition, id: number, center: Vec3 , radius: number, color: table , fillColor: table , lineType: LineType , readOnly: boolean?, message: string?) Creates a circle on the map with a given radius, color, fill color, and outline. - ---@field rectToAll fun(coalition:DrawCoalition, id:number, startPoint: Vec3, endPoint:Vec3, color: table, fillColor: table, lineType: LineType , readOnly: boolean?, message: string?) Creates a rectangle on the map from the startpoint in one corner to the endPoint in the opposite corner. - ---@field quadToAll fun(coalition:DrawCoalition, id:number, point1: Vec3, point2:Vec3, point3:Vec3, point4:Vec3,color: table, fillColor: table, lineType: LineType , readOnly: boolean?, message: string?) Creates a shape defined by the 4 points on the F10 map. - ---@field textToAll fun(coalition:DrawCoalition, id: number, point:Vec3, color: table, fillColor: table, fontSize:number, readOnly:boolean, text:string) Creates a text imposed on the map at a given point. Text scales with the map. - ---@field arrowToAll fun(coalition:DrawCoalition, id: number, startPoint:Vec3, endPoint:Vec3, color:table, fillColor:table, lineType:LineType, readonly:boolean?, message: string?) Creates an arrow from the startPoint to the endPoint on the F10 map. The arrow will be "pointing at" the startPoint - ---@field setMarkupRadius fun(id:number, radius:number) Updates the radius of the specified mark to be the new value. - ---@field setMarkupText fun(id:number, text: string) Updates the text value of the passed mark to the passed text value. - ---@field setMarkupFontSize fun(id:number, fontSize:number) Updates the font size of the specified mark to be the new value. - ---@field setMarkupColor fun(id:number, color:table) Updates the color of the specified mark to be the new value. - ---@field setMarkupColorFill fun(id: number, color: table) Updates the fill color of the specified mark to be the new value. - ---@field setMarkupTypeLine fun(id:number, lineType: LineType) Updates the type line of the specified mark to be the new value. - ---@field setMarkupPositionEnd fun(id: number, end:Vec3) Updates the position of a mark that was defined at the last point given to create it. - ---@field setMarkupPositionStart fun(id: number, end:Vec3) Updates the position of a mark that was defined at the last point given to create it. - - ---@class AITriggerCommands - ---@field setAITask fun(group:Group, taskIndex:number) Sets the task of the specified index to be the one and only active task. - ---@field pushAITask fun(group:Group, taskIndex:number) Pushes the task of the specified index to the front of the tasking queue. - ---@field activateGroup fun(group:Group) Activates the specified group if it is setup for "late activation." Calls the Group.activate function. - ---@field deactivateGroup fun(group:Group) Deactivates the specified group. Calls the Group.destroy function. - ---@field setGroupAIOn fun(group:Group) Turns the specified groups AI on. Calls the Group.getController(setOnOff(true)) function. - ---@field setGroupAIOff fun(group:Group) Turns the specified groups AI off. Calls the Group.getController(setOnOff(false)) function. - ---@field groupStopMoving fun(group:Group) Orders the specified group to stop moving. Calls Group.getController(setCommand()) function and sets the stopRoute command to true. - ---@field groupContinueMoving fun(group:Group) Orders the specified group to resume moving. Calls Group.getController(setCommand()) function and sets the stopRoute command to false. - - ---@enum SmokeColor - trigger.smokeColor = { - Green = 0, - Red = 1, - White = 2, - Orange = 3, - Blue = 4 - } - - ---@enum FlareColor - trigger.flareColor = { - Green = 0, - Red = 1, - White = 2, - Yellow = 3 - } - - ---@alias SmokePlumeColor - ---| 0 Disabled - ---| 1 Green - ---| 2 Red - ---| 3 White - ---| 4 Orange - ---| 5 Blue - - ---@alias SmokeEffect - ---| 1 small smoke and fire - ---| 2 medium smoke and fire - ---| 3 large smoke and fire - ---| 4 huge smoke and fire - ---| 5 small smoke - ---| 6 medium smoke - ---| 7 large smoke - ---| 8 huge smoke - - ---@alias Modulation - ---| 0 AM - ---| 1 FM - - ---@alias ShapeId - ---| 1 Line - ---| 2 Circle - ---| 3 Rect - ---| 4 Arrow - ---| 5 Text - ---| 6 Quad - ---| 7 Freeform - - ---@alias LineType - ---| 0 No Line - ---| 1 Solid - ---| 2 Dashed - ---| 3 Dotted - ---| 4 Dot Dash - ---| 5 Long Dash - ---| 6 Two Dash - - ---@alias DrawCoalition - ---| -1 All - ---| 0 Neutral - ---| 1 Red - ---| 2 Blue - - ---@class TriggerZone - ---@field point Vec3 - ---@field radius number -end - -do --coord - ---@class Coord - ---@field LLtoLO fun(lattitude: number, longitude:number, altitude: number?):Vec3 Returns a point from latitude and longitude in the vec3 format. - ---@field LOtoLL fun(point:Vec3): lattitude:number, longitude:number, altitude:number Returns multiple values of a given vec3 point in latitude, longitude, and altitude - ---@field LLtoMGRS fun(lattitude: number, longitude:number):MGRS Returns an MGRS table from the latitude and longitude coordinates provided - ---@field MGRStoLL fun(mgrs:MGRS): lattitude:number, longitude:number, altitude:number Returns multiple values of a given in MGRS coordinates and converts it to latitude, longitude, and altitude - coord = coord -end - -do -- missioncommands - ---@class MissionCommands - ---@field addCommand fun(name:string, path: table?, functionToRun: function, argument: any?):table Adds a command to the "F10 Other" radio menu allowing players to run specified scripting functions. - ---@field addSubMenu fun(name: string, path: table?): table Creates a submenu of a specified name for all players. - ---@field removeItem fun(path:table?) Removes the item of the specified path from the F10 radio menu for all. - ---@field addCommandForCoalition fun(coalition: CoalitionSide, name: string, path: table?, functionToRun:function, argument:any?):table Adds a command to the "F10 Other" radio menu allowing players to run specified scripting functions. - ---@field addSubMenuForCoalition fun(coalition:CoalitionSide, name: string, path:table?):table Creates a submenu of a specified name for the specified coalition. Can be used to create nested sub menues. If the path is not specified, submenu is added to the root menu. - ---@field removeItemForCoalition fun(coalition:CoalitionSide, path:table?) Removes the item of the specified path from the F10 radio menu for the specified coalition. - ---@field addCommandForGroup fun(groupId: number, name: string, path: table?, functionToRun:function, argument:any?):table Adds a command to the "F10 Other" radio menu allowing players to run specified scripting functions. - ---@field addSubMenuForGroup fun(groupId: number, name:string, path:table?): table Creates a submenu of a specified name for the specified group. - ---@field removeItemForGroup fun(groupId: number, path:table?) Removes the item of the specified path from the F10 radio menu for the specified group. - missionCommands = missionCommands -end - -do -- net - ---@class Net - ---@field send_chat fun(message:string, all:boolean?) Sends a chat message. - ---@field send_chat_to fun(message: string, playerID: number, fromID: number?) Sends a chat message to the player with the passed id. - ---@field load_mission fun(name:string):boolean Loads the specified mission. - ---@field load_next_mission fun():boolean Load the next mission from the server mission list. - ---@field get_player_list fun():table? Returns players currently connected TODO: Document table - ---@field get_my_player_id fun():number returns playerID - ---@field get_server_id fun():number returns the playerID for the server (currently always 1) - ---@field get_player_info fun(playerID: number, attribute? : string) : PlayerInfo Returns a table of attributes for a given playerId. If optional attribute present only that value is returned - ---@field kick fun(playerID:number, message:string?):boolean Kicks a player from the server. Can display a message to the user. - ---@field get_stat fun(playeID:number, statID:number?):number - ---@field get_name fun(playerID:number):string get players name - ---@field get_slot fun(playerID:number):coalitionID:CoalitionSide,slotID:number gets coalitionID and slotID of a player - ---@field force_player_slot fun(playerID: number, sideID: CoalitionSide, slotID:number) forces a - ---@field lua2json fun(luaObject:any):string converts a lua object to a json string - ---@field json2lua fun(json: string):table converts a json string to a lua object - ---@field dostring_in fun(state:string, dostring:string):string Executes a lua string in a given lua environment in the game. - ---@field log fun(text:string) writes INFO log to, recommend using "env" singleton to log as it supports all levels. - net = net - - ---@class PlayerInfo - ---@field id number - ---@field name string - ---@field side CoalitionSide - ---@field slotID number - ---@field ping number - ---@field ipaddr string - ---@field ucid string - - -- undocumented - --@field set_slot - --@field recv_chat -end - -do -- Country - ---@class CountrySingleton - ---@field name table - country = country - - - ---@enum CountryID - country.id = { - RUSSIA = 1, - UKRAINE = 2, - USA = 3, - TURKEY = 4, - UK = 5, - FRANCE = 6, - GERMANY = 7, - CANADA = 8, - SPAIN = 9, - THE_NETHERLANDS = 10, - BELGIUM = 11, - NORWAY = 12, - DENMARK = 13, - ISRAEL = 14, - GEORGIA = 15, - INSURGENTS = 16, - ABKHAZIA = 17, - SOUTH_OSETIA = 18, - ITALY = 19 - } -end - ---======================== --- Classes ---======================== - - -do -- Controller - ---@class Controller - ---@field setTask fun(self:Controller, task: Task) Sets the task of the controller to the passed task - ---@field setCommand function - ---@field getDetectedTargets fun(self:Controller, type1: DetectionType?, type2: DetectionType?, type3: DetectionType?) : Array Returns a list of units that are detected by the controller.
Only works for unit controllers, not group controllers. - Controller = Controller - - ---@enum DetectionType - Controller.Detection = { - VISUAL = 1, - OPTIC = 2, - RADAR = 4, - IRST = 8, - RWR = 16, - DLINK = 32 - } - - ---@class DetectedObject - ---@field object Object - ---@field visible boolean - ---@field type boolean - ---@field distance boolean - - ---@alias TaskType - ---| "NoTask" - ---| "AttackGroup" attack group - ---| - - ---@class Task - ---@field id TaskType - - do -- Task Aliases - AI = AI - - ---@enum WeaponExpend - AI.Task.WeaponExpend = { - - } - end - - do --TaskWrapper - - ---@class WrapperTask : Task - - end - - do -- Main Tasks - ---@class MainTask : Task - - ---@class AttackGroup : MainTask - ---@field params AttackGroupParams - - ---@class AttackGroupParams - ---@field groupId number - ---@field weaponType WeaponFlag? - ---@field expend AI.Task.WeaponExpend? - ---@field directionEnabled boolean? - ---@field altitude number? - ---@field attackQtyLimit boolean? - ---@field attackQty number? - - ---@class AttackUnit : Task - ---@field params AttackUnitParams - - ---@class AttackUnitParams - ---@field unitId number - ---@field weaponType WeaponFlag? - ---@field expend AI.Task.WeaponExpend? - ---@field direction number? - ---@field attackQtyLimit boolean? - ---@field attackQty number? - ---@field groupAttack number? - - ---@class Bombing : Task - ---@field params BombingTaskParams - - ---@class BombingTaskParams - ---@field point Vec2 - ---@field attackQty number - ---@field weaponType WeaponFlag? - ---@field expend AI.Task.WeaponExpend? - ---@field attackQtyLimit boolean? - ---@field direction number? - ---@field groupAttack boolean? - ---@field altitude number? - ---@field altitudeEnabled boolean? - ---@field attackType string "DIVE" - - ---@class Strafing : Task - --[[ - TODO - ]] - - ---@class CarpetBombing : Task - --[[ - TODO - ]] - - ---@class AttackMapObject : Task - --[[ - TODO - ]] - - ---@class BombingRunway : Task - --[[ - TODO - ]] - - ---@class orbit : Task - --[[ - TODO - ]] - - ---@class refueling : Task - --[[ - TODO - ]] - - ---@class land : Task - --[[ - TODO - ]] - - ---@class follow : Task - --[[ - TODO - ]] - - ---@class followBigFormation : Task - --[[ - TODO - ]] - - ---@class escort : Task - --[[ - TODO - ]] - - ---@class Embarking : Task - --[[ - TODO - ]] - - ---@class fireAtPoint : Task - --[[ - TODO - ]] - - ---@class hold : Task - --[[ - TODO - ]] - - ---@class FAC_AttackGroup : Task - --[[ - TODO - ]] - - ---@class EmbarkToTransport : Task - --[[ - TODO - ]] - - ---@class DisembarkFromTransport : Task - --[[ - TODO - ]] - - ---@class CargoTransportation : Task - --[[ - TODO - ]] - - ---@class goToWaypoint : Task - --[[ - TODO - ]] - - ---@class groundEscort : Task - --[[ - TODO - ]] - - ---@class RecoveryTanker : Task - --[[ - TODO - ]] - - - end - - ---@class EnrouteTask : Task - - do -- AI - ---@class AI - AI = AI - AI = { - -- AI.Option - Option = { - -- AI.Option.Air - Air = { - - ---@enum AI.Option.Air.id - id = { - JETT_TANKS_IF_EMPTY = "25", - SILENCE = "7", - ROE = "0", - RADAR_USING = "3", - OPTION_RADIO_USAGE_ENGAGE = "22", - PROHIBIT_AG = "17", - ECM_USING = "13", - PROHIBIT_WP_PASS_REPORT = "19", - PROHIBIT_AA = "14", - REACTION_ON_THREAT = "1", - PREFER_VERTICAL = "32", - FORCED_ATTACK = "26", - PROHIBIT_AB = "16", - RTB_ON_OUT_OF_AMMO = "10", - MISSILE_ATTACK = "18", - PROHIBIT_JETT = "15", - OPTION_RADIO_USAGE_CONTACT = "21", - FLARE_USING = "4", - OPTION_RADIO_USAGE_KILL = "23", - FORMATION = "5", - RTB_ON_BINGO = "6", - NO_OPTION = "-1", - }, - - val = { - ---@enum AI.Option.Air.val.FLARE_USING - FLARE_USING = { - WHEN_FLYING_NEAR_ENEMIES = "3", - WHEN_FLYING_IN_SAM_WEZ = "2", - AGAINST_FIRED_MISSILE = "1", - NEVER = "0", - }, - - ---@enum AI.Option.Air.val.RADAR_USING - RADAR_USING = { - FOR_ATTACK_ONLY = "1", - FOR_SEARCH_IF_REQUIRED = "2", - NEVER = "0", - FOR_CONTINUOUS_SEARCH = "3", - }, - - ---@enum AI.Option.Air.val.REACTION_ON_THREAT - REACTION_ON_THREAT = { - BYPASS_AND_ESCAPE = "3", - EVADE_FIRE = "2", - NO_REACTION = "0", - PASSIVE_DEFENCE = "1", - ALLOW_ABORT_MISSION = "4", - }, - - ---@enum AI.Option.Air.val.MISSILE_ATTACK - MISSILE_ATTACK = { - HALF_WAY_RMAX_NEZ = "2", - MAX_RANGE = "0", - TARGET_THREAT_EST = "3", - RANDOM_RANGE = "4", - NEZ_RANGE = "1", - }, - - ---@enum AI.Option.Air.val.ECM_USING - ECM_USING = { - ALWAYS_USE = "3", - NEVER_USE = "0", - USE_IF_DETECTED_LOCK_BY_RADAR = "2", - USE_IF_ONLY_LOCK_BY_RADAR = "1", - }, - - ---@enum AI.Option.Air.val.ROE - ROE = { - WEAPON_FREE = "0", - RETURN_FIRE = "3", - OPEN_FIRE = "2", - WEAPON_HOLD = "4", - OPEN_FIRE_WEAPON_FREE = "1", - }, - } - }, - Ground = { - ---@enum AI.Option.Ground.id - id = { - EVASION_OF_ARM = "31", - ALARM_STATE = "9", - DISPERSE_ON_ATTACK = "8", - ENGAGE_AIR_WEAPONS = "20", - AC_ENGAGEMENT_RANGE_RESTRICTION = "24", - FORMATION = "5", - ROE = "0", - NO_OPTION = "-1", - }, - - val = { - ---@enum AI.Option.Ground.val.ALARM_STATE - ALARM_STATE = { - AUTO = "0", - GREEN = "1", - RED = "2", - }, - ---@enum AI.Option.Ground.val.ROE - ROE = { - OPEN_FIRE = "2", - WEAPON_HOLD = "4", - RETURN_FIRE = "3" - } - } - }, - Naval = { - ---@enum AI.Option.Naval.id - id = { - ROE = "0", - NO_OPTION = "-1", - }, - val = { - - ---@enum AI.Option.Naval.val.ROE - ROE = { - OPEN_FIRE = "2", - WEAPON_HOLD = "4", - RETURN_FIRE = "3", - }, - } - } - }, - Task = { - ---@enum AI.Task.OrbitPattern - OrbitPattern = { - RACE_TRACK = "Race-Track", - CIRCLE = "Circle", - }, - - ---@enum AI.Task.Designation - Designation = { - WP = "WP", - NO = "No", - LASER = "Laser", - IR_POINTER = "IR-Pointer", - AUTO = "Auto", - }, - - ---@enum AI.Task.TurnMethod - TurnMethod = { - FLY_OVER_POINT = "Fly Over Point", - FIN_POINT = "Fin Point", - }, - - ---@enum AI.Task.VehicleFormation - VehicleFormation = { - VEE = "Vee", - ECHELON_RIGHT = "EchelonR", - OFF_ROAD = "Off Road", - RANK = "Rank", - ECHELON_LEFT = "EchelonL", - ON_ROAD = "On Road", - CONE = "Cone", - DIAMOND = "Diamond", - }, - - ---@enum AI.Task.AltitudeType - AltitudeType = { - RADIO = "RADIO", - BARO = "BARO", - }, - - ---@enum AI.Task.WaypointType - WaypointType = { - TAKEOFF = "TakeOff", - TAKEOFF_PARKING = "TakeOffParking", - TURNING_POINT = "Turning Point", - TAKEOFF_PARKING_HOT = "TakeOffParkingHot", - LAND = "Land", - }, - - ---@enum AI.Task.WeaponExpend - WeaponExpend = { - QUARTER = "Quarter", - TWO = "Two", - ONE = "One", - FOUR = "Four", - HALF = "Half", - ALL = "All", - }, - }, - ---@enum AI.Skill - Skill = { - PLAYER = "Player", - AVERAGE = "Average", - HIGH = "High", - EXCELLENT = "Excellent", - GOOD = "Good", - CLIENT = "Client" - } - } - end -end - -do -- Object - ---@class Object - ---@field getName fun(self:Object): string returns the name of the object in the mission environment - ---@field isExist fun(self:Object): boolean Return a boolean value based on whether the object currently exists in the mission. - ---@field destroy fun(self:Object) Destroys the object, physically removing it from the game world without creating an event. - ---@field getCategory fun(self:Object): category: ObjectCategory, subCategory:number Returns an enumerator of the category for the specific object.
!!Dependent on how called. Check docs - ---@field getTypeName fun(self:Object): string returns the typename of the object - ---@field getDesc fun(self:Object):table returns description table, which is different for each type and subtype and even object - ---@field hasAttribute fun(self:Object, attribute:string):boolean Returns a boolean value if the object in question has the passed attribute. - ---@field getPoint fun(self:Object):Vec3 Returns a vec3 table of the x, y, and z coordinates for the position of the given object in 3D space. - ---@field getPosition fun(self:Object):Position Returns a Position3 table of the objects current position and orientation in 3D space. - ---@field getVelocity fun(self:Object):Vec3 Returns a vec3 table of the objects velocity vectors. - ---@field inAir fun(self:Object):boolean Returns a boolean value if the object in question is in the air. - Object = Object - - ---@enum ObjectCategory - Object.Category = { - UNIT = 1, - WEAPON = 2, - STATIC = 3, - BASE = 4, - SCENERY = 5, - Cargo = 6 - } -end - -do --SceneryObject - ---@class SceneryObject : Object - ---@field getLife fun(self:SceneryObject):number gets the life of a sceneryObject - ---@field getDescByName fun(typeName:string):table gets the description based on the typename - SceneryObject = SceneryObject -end - -do --CoalitionObject - ---@class CoalitionObject : Object - ---@field getCoalition fun(self:CoalitionObject):CoalitionSide Returns an enumerator that defines the coalition that an object currently belongs to. - ---@field getCountry fun(self:CoalitionObject):CountryID Returns an enumerator that defines the country that an object currently belongs to. - CoalitionObject = CoalitionObject -end - -do --Unit - ---@class Unit : CoalitionObject - ---@field Category UnitCategory - ---@field getByName fun(name: string): Unit? - ---@field getDescByName fun(typeName: string): table? - ---@field isActive fun(self:Unit): boolean Returns a boolean value if the unit is activated - ---@field getPlayerName fun(self:Unit): string? Returns a string value of the name of the player if the unit is currently controlled by a player - ---@field getID fun(self:Unit): number Returns a number which defines the unique mission id of a given object. - ---@field getNumber fun(self:Unit):number Returns a numerical value of the default index of the specified unit within the group as defined within the mission editor or addGroup scripting function. - ---@field getCategoryEx fun(self:Unit):number Returns an enumerator of the category for the specific object. - ---@field getObjectID fun(self:Unit):number Returns the runtime object Id associated with the unit. - ---@field getController fun(self:Unit):Controller Returns the controller of the specified object. - ---@field getGroup fun(self:Unit):Group Gets the group of the unit - ---@field getCallsign fun(self:Unit): string Returns a localized string of the units callsign - ---@field getLife fun(self:Unit): number Returns the current "life" of a unit. - ---@field getLife0 fun(self:Unit):number Returns the initial life value of a unit. - ---@field getFuel fun(self:Unit):number Returns a percentage of the current fuel remaining in an aircraft's inventory based on the maximum possible fuel load. - ---@field getAmmo fun(self:Unit):table returns ammo table TODO: specify table - ---@field getSensors fun(self:Unit):table returns sensors table TODO: Specify table - ---@field hasSensors fun(self:Unit, sensorType: SensorType?, subType:OpticType|RadarType|nil) : boolean Returns true if the unit has the specified sensors. - ---@field getRadar fun(self:Unit) : isOperational:boolean, mostInteresting: Object Returns two values. The first value is a boolean indicating if any radar on the Unit is operational. - ---@field getDrawArgumentValue fun(self:Unit, arg:number): number Returns the current value for an animation argument on the external model of the given object - ---@field getNearestCargos fun(self:Unit): table Returns a table of friendly cargo objects indexed numerically and sorted by distance from the helicopter. - ---@field enableEmission fun(self:Unit, setting:boolean) Sets the passed group or unit objects radar emitters on or off. - ---@field getDescentCapacity fun(self:Unit):number Returns the number of infantry that can be embark onto the aircraft. - Unit = Unit - - ---@enum UnitCategory - Unit.Category = { - AIRPLANE = 0, - HELICOPTER = 1, - GROUND_UNIT = 2, - SHIP = 3, - STRUCTURE = 4 - } - - ---@enum SensorType - Unit.SensorType = { - OPTIC = 0, - RADAR = 1, - IRST = 2, - RWR = 3 - } - - ---@enum OpticType - Unit.OpticType = { - TV = 0, --TV-sensor - LLTV = 1, --Low-level TV-sensor - IR = 2 --Infra-Red optic sensor - } - - ---@enum RadarType - Unit.RadarType = { - AS = 0, --air search radar - SS = 1 --surface/land search radar - } -end - -do --StaticObject - ---@class StaticObject : CoalitionObject - ---@field getByName fun(name:string): StaticObject? Returns a static object by name - ---@field getDescByName fun(typeName: string): table? returns the description of this static object type - ---@field getID fun(self:StaticObject):number Returns a number which defines the unique mission id of a given object. - ---@field getLife fun(self:StaticObject) number Returns the current "life" of a static object. - ---@field getCargoDisplayName fun(self:StaticObject): string Returns a string of a cargo objects mass in the format ' mass kg' - ---@field getCargoWeight fun(self:StaticObject): number Returns the mass of a cargo object measured in kg. - ---@field getDrawArgumentValue fun(self:Unit, arg:number): number Returns the current value for an animation argument on the external model of the given object - StaticObject = StaticObject -end - -do -- Airbase - ---@class Airbase: CoalitionObject - ---@field getByName fun(name:string): Airbase? Gets an Airfield by name - ---@field getDescByName fun(typeName: string): table? Gets airfield description - ---@field getCallsign fun(self:Airbase): string - ---@field getUnit fun(self:Airbase): Unit gets the unit associated with the airbase. (eg. Aircraft Carrier) - ---@field getID fun(self:Airbase): number Returns a number which defines the unique mission id of a given object. - ---@field getCategoryEx fun(self:Airbase):number Get category type - ---@field getParking fun(self:Airbase, available:boolean?): Array Returns a table of parking data for a given airbase. - ---@field getRunways fun(self:Airbase): Array Returns a table with runway information like length, width, course, and Name. - ---@field getTechObjectPos fun(self:Airbase, objectType:number|string): Vec3 Returns a table of vec3 objects corresponding to the passed value. - ---@field getDispatcherTowerPos fun(self:Airbase): Vec3 Returns the tower position - ---@field getRadioSilentMode fun(self:Airbase): boolean Returns a boolean value for whether or not the ATC for the passed airbase object has been silenced. - ---@field setRadioSilentMode fun(self:Airbase, silent:boolean) Sets the ATC belonging to an airbase object to be silent and unresponsive. - ---@field autoCapture fun(self:Airbase, setting:boolean) Enables or disables the airbase and FARP auto capture game mechanic where ownership of a base can change based on the presence of ground forces or the default setting assigned in the editor. - ---@field autoCaptureIsOn fun(self:Airbase): boolean Returns the current autoCapture setting for the passed base. - ---@field setCoalition fun(self:Airbase, side:CoalitionSide) Changes airbase's coalition to the set value. - ---@field getWarehouse fun(self:Airbase): Warehouse Returns the warehouse object associated with the airbase object. - Airbase = Airbase - - ---@class ParkingSpot - ---@field Term_Index number index - ---@field vTerminalPos Vec3 Position - ---@field TO_AC boolean - ---@field Term_Index_0 number - ---@field Term_Type TerminalType terminal type, see TerminalType - ---@field fDistToRW number distance to runway - - ---@class Runway - ---@field course number - ---@field Name string - ---@field position Vec3 - ---@field length number - ---@field width number - - ---@enum AirbaseCategory - Airbase.Category = { - AIRDROME = 0, - HELIPAD = 1, - SHIP = 2, - } - - ---@alias TerminalType - ---| 16 Valid spawn points on runway - ---| 40 Helicopter only spawn - ---| 68 Hardened Air Shelter - ---| 72 Open/Shelter air airplane only - ---| 100 Small shelter - ---| 104 Open air spawn -end - -do --Warehouse - ---@class Warehouse - ---@field getByName fun(name:string):Warehouse Returns an instance of the calling class for the object of a specified name. - ---@field getCargoAsWarehouse fun(object:StaticObject):Warehouse Returns a warehouse object that exists within the passed Static Object cargo crate. - ---@field addItem fun(self:Warehouse, itemType:string|table, count:number) Adds the passed amount of a given item to the warehouse. - ---@field getItemCount fun(self:Warehouse, itemType:string|table): number Returns the number of the passed type of item currently in a warehouse object. - ---@field setItem fun(self:Warehouse, itemType: string|table, count:number) Sets the passed amount of a given item to the warehouse. - ---@field removeItem fun(self:Warehouse, itemType:string|table, count:number) Removes the amount of the passed item from the warehouse. - ---@field addLiquid fun(self:Warehouse, liquidType:LiquidType, count:number) Adds the passed amount of a liquid fuel into the warehouse inventory - ---@field getLiquidAmount fun(self:Warehouse, liquidType:LiquidType): number Returns the amount of the passed liquid type within a given warehouse. - ---@field setLiquidAmount fun(self:Warehouse, liquidType:LiquidType, count:number) Sets the passed amount of a liquid fuel into the warehouse inventory - ---@field removeLiquid fun(self:Warehouse, liquidType:LiquidType, count:number) Removes the set amount of liquid from the inventory in a warehouse. - ---@field getOwner fun(self:Warehouse): Airbase Returns the airbase object associated with the warehouse object - ---@field getInventory fun(self:Warehouse, itemType: string|table): table Returns a full itemized list of everything currently in a warehouse. - Warehouse = Warehouse - - ---@alias LiquidType - ---|0 jetfuel - ---|1 Aviation gasoline - ---|2 MW50 - ---|3 Diesel -end - -do -- Weapon - ---@class Weapon : CoalitionObject - ---@field getLauncher fun(self:Weapon): Unit Returns the Unit object that had launched the weapon. - ---@field getTarget fun(self:Weapon): Object? Returns the target object that the weapon is guiding to. - ---@field getCategoryEx fun(self:Weapon): ObjectCategory Returns an enumerator of the category for the specific object. - Weapon = Weapon - - ---@enum WeaponCategory - Weapon.Category = { - SHELL = 0, - MISSILE = 1, - ROCKET = 2, - BOMB = 3 - } - - do -- WeaponFlag - ---@alias WeaponFlag - ---| 0 No Weapon - ---| 2 LGB - ---| 4 TvGB - ---| 8 SNSGB - ---| 16 HEBomb - ---| 32 Penetrator - ---| 64 NapalmBomb - ---| 128 FAEBomb - ---| 256 ClusterBomb - ---| 512 Dispencer - ---| 1024 CandleBomb - ---| 2147483648 ParachuteBomb - ---| 14 GuidedBomb (LGB + TvGB + SNSGB) - ---| 2147485680 AnyUnguidedBomb (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb) - ---| 2147485694 AnyBomb (GuidedBomb + AnyUnguidedBomb) - ---| 2048 LightRocket - ---| 4096 MarkerRocket - ---| 8192 CandleRocket - ---| 16384 HeavyRocket - ---| 30720 AnyRocket (LightRocket + MarkerRocket + CandleRocket + HeavyRocket) - ---| 32768 AntiRadarMissile - ---| 65536 AntiShipMissile - ---| 131072 AntiTankMissile - ---| 262144 FireAndForgetASM - ---| 524288 LaserASM - ---| 1048576 TeleASM - ---| 2097152 CruiseMissile - ---| 1073741824 AntiRadarMissile2 - ---| 8589934592 Decoys - ---| 1572864 GuidedASM (LaserASM + TeleASM) - ---| 1835008 TacticalASM (GuidedASM + FireAndForgetASM) - ---| 4161536 AnyASM (AntiRadarMissile + AntiShipMissile + AntiTankMissile + FireAndForgetASM + GuidedASM + CruiseMissile) - ---| 4194304 SRAAM - ---| 8388608 MRAAM - ---| 16777216 LRAAM - ---| 33554432 IR_AAM - ---| 67108864 SAR_AAM - ---| 134217728 AR_AAM - ---| 264241152 AnyAMM(IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM) - ---| 268402688 AnyMissile (ASM + AnyAAM) - ---| 36012032 AnyAutonomousMissile (IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile) - ---| 268435456 GUN_POD - ---| 536870912 BuiltInCannon - ---| 805306368 Cannons (GUN_POD + BuiltInCannon) - ---| 17179869184 SmokeShell - ---| 34359738368 Illumination Shell - ---| 51539607552 MarkerShell - ---| 68719476736 SubmunitionDispenserShell - ---| 137438953472 GuidedShell - ---| 206963736576 ConventionalShell - ---| 258503344128 AnyShell - ---| 4294967296 Torpedo - ---| 2956984318 AnyAGWeapon (BuiltInCannon + GUN_POD + AnyBomb + AnyRocket + AnyASM) - ---| 264241152 AnyAAWeapon (BuiltInCannon + GUN_POD + AnyAAM) - ---| 2952822768 UnguidedWeapon (Cannons + BuiltInCannon + GUN_POD + AnyUnguidedBomb + AnyRocket) - ---| 268402702 GuidedWeapon (GuidedBomb + AnyASM + AnyAAM) - ---| 3221225470 AnyWeapon (AnyBomb + AnyRocket + AnyMissile + Cannons) - ---| 13312 MarkerWeapon (MarkerRocket + CandleRocket + CandleBomb) - ---| 209379642366 ArmWeapon (AnyWeapon - MarkerWeapon) - end - - ---@enum GuidanceType - Weapon.GuidanceType = { - INS = 1, - IR = 2, - RADAR_ACTIVE = 3, - RADAR_SEMI_ACTIVE = 4, - RADAR_PASSIVE = 5, - TV = 6, - LASER = 7, - TELE = 8 - } - - ---@enum MissileCategory - Weapon.MissileCategory = { - AAM = 1, - SAM = 2, - BM = 3, - ANTI_SHIP = 4, - CRUISE = 5, - OTHER = 6 - } - - ---@enum WarheadType - Weapon.WarheadType = { - AP = 0, - HE = 1, - SHAPED_EXPLOSIVE = 2 - } -end - -do --Group - ---@class Group - ---@field getByName fun(name:string): Group? gets group by name - ---@field isExist fun(self:Group) : boolean checks if the Group currently exists - ---@field activate fun(self:Group) activates the group - ---@field destroy fun(self:Group) destroys a group - ---@field getCategory fun(self:Group): objectCategory: ObjectCategory, subCategory:number - ---@field getCoalition fun(self:Group): CoalitionSide - ---@field getName fun(self:Group):string - ---@field getID fun(self:Group):number - ---@field getUnit fun(self:Group, index:number): Unit? - ---@field getUnits fun(self:Group): Array - ---@field getSize fun(self:Group): number - ---@field getInitialSize fun(self:Group): number - ---@field getController fun(self:Group):Controller - ---@field enableEmission fun(self:Group, enabled:boolean) - Group = Group - - ---@enum GroupCategory - Group.Category = { - AIRPLANE = 0, - HELICOPTER = 1, - GROUND = 2, - SHIP = 3, - TRAIN = 4, - } -end - -do --Spot - ---@class Spot - ---@field createInfraRed fun(source:Object, localPoint: Vec3?, targetPoint:Vec3, lasercode:number?):Spot Creates an infrared ray emanating from the given object to a point in 3d space. Can be seen with night vision goggles. - ---@field createLaser fun(source:Object, localRef: Vec3, targetPoint:Vec3, lasercode:number?):Spot Creates a laser ray emanating from the given object to a point in 3d space. - ---@field destroy fun(self:Spot) destroys the laser/ir beam - ---@field getCategory fun(self:Spot) : ObjectCategory - ---@field getPoint fun(self:Spot): Vec3 - ---@field setPoint fun(self:Spot, point:Vec3) sets the target spot - ---@field getCode fun(self:Spot): number Returns the number that is used to define the laser code for which laser designation can track. - ---@field setCode fun(self:Spot, code:number) sets the laster code. - Spot = Spot -end diff --git a/classes/fleetClasses/GlobalFleetManager.lua b/classes/fleetClasses/GlobalFleetManager.lua deleted file mode 100644 index 51f5e7d..0000000 --- a/classes/fleetClasses/GlobalFleetManager.lua +++ /dev/null @@ -1,22 +0,0 @@ - - -local GlobalFleetManager = {} - -local fleetGroups = {} - -GlobalFleetManager.start = function(database) - - local logger = Spearhead.LoggerTemplate.new("CARRIERFLEET", "INFO") - - local all_groups = Spearhead.classes.helpers.MizGroupsManager.getAllGroupNames() - for _, groupName in pairs(all_groups) do - if Spearhead.Util.startswith(string.lower(groupName), "carriergroup" ) == true then - logger:info("Registering " .. groupName .. " as a managed fleet") - local carrierGroup = Spearhead.internal.FleetGroup:new(groupName, database, logger) - table.insert(fleetGroups, carrierGroup) - end - end -end - -if not Spearhead.internal then Spearhead.internal = {} end -Spearhead.internal.GlobalFleetManager = GlobalFleetManager \ No newline at end of file diff --git a/main.lua b/main.lua deleted file mode 100644 index 3f851b5..0000000 --- a/main.lua +++ /dev/null @@ -1,82 +0,0 @@ ---Single player purpose - -local defaultLogLevel = "INFO" - -if SpearheadConfig and SpearheadConfig.debugEnabled == true then - defaultLogLevel = "DEBUG" -end - -local startTime = timer.getTime() * 1000 - -Spearhead.Events.Init(defaultLogLevel) - -local dbLogger = Spearhead.LoggerTemplate.new("database", defaultLogLevel) -local standardLogger = Spearhead.LoggerTemplate.new("", defaultLogLevel) -local databaseManager = Spearhead.DB.New(dbLogger) -Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(defaultLogLevel) -- initiate - -local capConfig = Spearhead.internal.configuration.CapConfig:new(); -local stageConfig = Spearhead.internal.configuration.StageConfig:new(); - -local startingStage = stageConfig.startingStage or 1 -if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then - standardLogger:info("Persistence enabled") - local persistenceLogger = Spearhead.LoggerTemplate.new("Persistence", defaultLogLevel) - Spearhead.classes.persistence.Persistence.Init(persistenceLogger) - - local persistanceStage = Spearhead.classes.persistence.Persistence.GetActiveStage() - if persistanceStage then - standardLogger:info("Persistance activated and using persistant active stage: " .. persistanceStage) - startingStage = persistanceStage - end -else - standardLogger:info("Persistence disabled") -end - -local spawnLogger = Spearhead.LoggerTemplate.new("SpawnManager", defaultLogLevel) -local spawnManager = Spearhead.classes.helpers.SpawnManager.new(spawnLogger) -local detectionLogger = Spearhead.LoggerTemplate.new("DetectionManager", defaultLogLevel) -local detectionManager = Spearhead.classes.capClasses.detection.DetectionManager.New(detectionLogger) - -Spearhead.classes.capClasses.GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager) -Spearhead.internal.GlobalStageManager.NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager) - -Spearhead.internal.GlobalFleetManager.start(databaseManager) - -local SetStageDelayed = function(number, time) - Spearhead.Events.PublishStageNumberChanged(number) - return nil -end - -timer.scheduleFunction(SetStageDelayed, startingStage, timer.getTime() + 3) - -env.info(startTime .. "ms / " .. timer.getTime() * 1000 .. "ms") -local duration = (timer.getTime() * 1000) - startTime -standardLogger:info("Spearhead Initialisation duration: " .. tostring(duration) .. "ms") - -Spearhead.LoadingDone() - -Spearhead.internal.GlobalStageManager:printFullOverview() - ---Check lines of code in directory per file: --- Get-ChildItem . -Include *.lua -Recurse | foreach {""+(Get-Content $_).Count + " => " + $_.name }; GCI . -Include *.lua* -Recurse | foreach{(GC $_).Count} | measure-object -sum | % Sum --- find . -name '*.lua' | xargs wc -l - ---- ==================== DEBUG ORDER OR ZONE VEC =========================== --- local zone = Spearhead.DcsUtil.getZoneByName("MISSIONSTAGE_99") - --- local count = Spearhead.Util.tableLength(zone.verts) - --- for i = 1, count - 1 do - --- local a = zone.verts[i] --- local b = zone.verts[i+1] - --- local color = {0,0,0,1} - --- color[i] = 1 - --- trigger.action.textToAll(-1, 46+i , { x= a.x, y = 0, z = a.z } , color, {0,0,0}, 24 , true , "" .. i ) --- trigger.action.lineToAll(-1 , 56+i , { x= a.x, y = 0, z = a.z } , { x = b.x, y = 0, z = b.z } , color , 1, true) - --- end diff --git a/classes/_baseClasses/Queue.lua b/src/classes/_baseClasses/Queue.lua similarity index 84% rename from classes/_baseClasses/Queue.lua rename to src/classes/_baseClasses/Queue.lua index 5d50c5c..44b0a92 100644 --- a/classes/_baseClasses/Queue.lua +++ b/src/classes/_baseClasses/Queue.lua @@ -44,7 +44,4 @@ function Queue:toList() return items end - -if Spearhead == nil then Spearhead = {} end -if Spearhead._baseClasses == nil then Spearhead._baseClasses = {} end -Spearhead._baseClasses.Queue = Queue \ No newline at end of file +return Queue \ No newline at end of file diff --git a/classes/api/SpearheadApi.lua b/src/classes/api/SpearheadApi.lua similarity index 83% rename from classes/api/SpearheadApi.lua rename to src/classes/api/SpearheadApi.lua index 5fba5e4..4cbc90b 100644 --- a/classes/api/SpearheadApi.lua +++ b/src/classes/api/SpearheadApi.lua @@ -1,3 +1,6 @@ +local SpearheadEvents = require("classes.spearhead_events") +local GlobalStageManager = require("classes.stageClasses.GlobalStageManager") + ---@type Array local MissionCompleteListeners = {} @@ -16,18 +19,18 @@ SpearheadAPI = { return false, "stageNumber " .. stageNumber .. " is not a valid number" end - Spearhead.Events.PublishStageNumberChanged(stageNumber) + SpearheadEvents.PublishStageNumberChanged(stageNumber) return true, "" end, getCurrentStage = function() - return Spearhead.StageNumber or nil + return GlobalStageManager.getCurrentStage() or nil end, isStageComplete = function(stageNumber) if type(stageNumber) ~= "number" then return false, "stageNumber " .. stageNumber .. " is not a valid number" end - local isComplete = Spearhead.internal.GlobalStageManager.isStageComplete(stageNumber) + local isComplete = GlobalStageManager.isStageComplete(stageNumber) if isComplete == nil then return nil, "no stage found with number " .. stageNumber end diff --git a/classes/api/SpearheadApiDoc.lua b/src/classes/api/SpearheadApiDoc.lua similarity index 100% rename from classes/api/SpearheadApiDoc.lua rename to src/classes/api/SpearheadApiDoc.lua diff --git a/classes/capClasses/CapAirbase.lua b/src/classes/capClasses/CapAirbase.lua similarity index 92% rename from classes/capClasses/CapAirbase.lua rename to src/classes/capClasses/CapAirbase.lua index 345429f..db14a11 100644 --- a/classes/capClasses/CapAirbase.lua +++ b/src/classes/capClasses/CapAirbase.lua @@ -1,3 +1,11 @@ +local Util = require("classes.util.Util") +local CapGroup = require("classes.capClasses.airGroups.CapGroup") +local SweepGroup = require("classes.capClasses.airGroups.SweepGroup") +local InterceptGroup = require("classes.capClasses.airGroups.InterceptGroup") +local RunwayBombingTracker = require("classes.capClasses.runwayBombing.RunwayBombingTracker") +local SpearheadEvents = require("classes.util.SpearheadEvents") +local RunwayStrikeMission = require("classes.stageClasses.missions.RunwayStrikeMission") + ---@class CapBase : OnStageChangedListener ---@field private airbaseName string ---@field private logger table @@ -54,7 +62,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw local baseData = database:getAirbaseDataForZone(airbaseName) if baseData and baseData.CapGroups then for key, name in pairs(baseData.CapGroups) do - local capGroup = Spearhead.classes.capClasses.airGroups.CapGroup.New(name, capConfig, logger, spawnManager) + local capGroup = CapGroup.New(name, capConfig, logger, spawnManager) if capGroup then self.capGroupsByName[name] = capGroup end @@ -63,7 +71,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw if baseData and baseData.SweepGroups then for key, name in pairs(baseData.SweepGroups) do - local sweepGroup = Spearhead.classes.capClasses.airGroups.SweepGroup.New(name, capConfig, logger, spawnManager) + local sweepGroup = SweepGroup.New(name, capConfig, logger, spawnManager) if sweepGroup then self.sweepGroupsByName[name] = sweepGroup end @@ -72,22 +80,21 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw if baseData and baseData.InterceptGroups then for key, name in pairs(baseData.InterceptGroups) do - local interceptGroup = Spearhead.classes.capClasses.airGroups.InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager) + local interceptGroup = InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager) if interceptGroup then self.interceptGroupsByName[name] = interceptGroup end end end - local capFlights = Spearhead.Util.tableLength(self.capGroupsByName) - local sweepFlights = Spearhead.Util.tableLength(self.sweepGroupsByName) - local interceptFlights = Spearhead.Util.tableLength(self.interceptGroupsByName) + local capFlights = Util.tableLength(self.capGroupsByName) + local sweepFlights = Util.tableLength(self.sweepGroupsByName) + local interceptFlights = Util.tableLength(self.interceptGroupsByName) logger:info(airbaseName .. " : " .. capFlights .." CAP | " .. sweepFlights .. " SWEEP | " .. interceptFlights .. " INTERCEPT") self:CreateRunwayStrikeMission(database) - - Spearhead.Events.AddStageNumberChangedListener(self) + SpearheadEvents.AddStageNumberChangedListener(self) timer.scheduleFunction(CheckStateContinuous, self, timer.getTime() + 15) @@ -111,7 +118,7 @@ function CapBase:CreateRunwayStrikeMission(database) " at airbase " .. self.airbaseName .. " with heading " .. runway.course .. " and length " .. runway.length .. " and width " .. runway.width) - local mission = Spearhead.classes.stageClasses.missions.RunwayStrikeMission.new(runway, self.airbaseName, + local mission = RunwayStrikeMission.new(runway, self.airbaseName, database, self.logger, self.runwayBombingTracker) self.runwayStrikeMissions[runway.Name] = mission end @@ -338,7 +345,7 @@ function CapBase:CheckAndScheduleIntercept() local unit = Unit.getByName(unitName) if unit and unit:isExist() then local unitPos = unit:getPoint() - if Spearhead.Util.is3dPointInZone(unitPos, zone) == true then + if Util.is3dPointInZone(unitPos, zone) == true then if not unitsToInterceptPerZone[zone.name] then unitsToInterceptPerZone[zone.name] = {} end @@ -356,7 +363,7 @@ function CapBase:CheckAndScheduleIntercept() for name, targets in pairs(unitsToInterceptPerZone) do local required = 0 - local nrTargets = Spearhead.Util.tableLength(targets) + local nrTargets = Util.tableLength(targets) if targets and nrTargets > 0 then required = math.ceil(nrTargets / ratio) end @@ -424,7 +431,4 @@ function CapBase:IsBaseActiveWhenStageIsActive(stageNumber) return false end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -Spearhead.classes.capClasses.CapAirbase = CapBase +return CapBase diff --git a/classes/capClasses/GlobalCapManager.lua b/src/classes/capClasses/GlobalCapManager.lua similarity index 62% rename from classes/capClasses/GlobalCapManager.lua rename to src/classes/capClasses/GlobalCapManager.lua index 8b25ca1..88f3edc 100644 --- a/classes/capClasses/GlobalCapManager.lua +++ b/src/classes/capClasses/GlobalCapManager.lua @@ -1,3 +1,9 @@ +local Logger = require("classes.util.Logger") +local Util = require("classes.util.Util") +local RunwayBombingTracker = require("classes.capClasses.runwayBombing.RunwayBombingTracker") +local CapAirbase = require("classes.capClasses.CapAirbase") + +---@class GlobalCapManager local GlobalCapManager = {} do local airbasesPerStage = {} @@ -17,9 +23,9 @@ do function GlobalCapManager.start(database, capConfig, detectionManager, stageConfig, logLevel, spawnManager) if initiated == true then return end - local logger = Spearhead.LoggerTemplate.new("AirbaseManager", logLevel) - local bombTrackLogger = Spearhead.LoggerTemplate.new("RunwayBombingTracker", logLevel) - local runwayBombingTracker = Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker.new(bombTrackLogger) + local logger = Logger.new("AirbaseManager", logLevel) + local bombTrackLogger = Logger.new("RunwayBombingTracker", logLevel) + local runwayBombingTracker = RunwayBombingTracker.new(bombTrackLogger) local zones = database:getStagezoneNames() if zones then @@ -32,9 +38,9 @@ do if airbaseNames then for _, airbaseName in pairs(airbaseNames) do if airbaseName then - local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, logLevel) + local airbaseSpecificLogger = Logger.new("CAP_" .. airbaseName, logLevel) - local airbase = Spearhead.classes.capClasses.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager) + local airbase = CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager) if airbase then table.insert(airbasesPerStage[stageName], airbase) @@ -46,16 +52,14 @@ do end end - logger:info("Initiated " .. Spearhead.Util.tableLength(allAirbasesByName) .. " airbases for cap") + logger:info("Initiated " .. Util.tableLength(allAirbasesByName) .. " airbases for cap") initiated = true - local InfoFunctions = {} - ---returns if there is CAP active ---@param zoneName any ---@param activeZoneNumber number ---@return boolean - InfoFunctions.IsCapActiveWhenZoneIsActive = function(zoneName, activeZoneNumber) + GlobalCapManager.IsCapActiveWhenZoneIsActive = function(zoneName, activeZoneNumber) for _, airbase in pairs(airbasesPerStage[zoneName]) do if airbase:IsBaseActiveWhenStageIsActive(activeZoneNumber) == true then return true @@ -63,14 +67,7 @@ do end return false end - - Spearhead.capInfo = InfoFunctions end end - - -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -Spearhead.classes.capClasses.GlobalCapManager = GlobalCapManager +return GlobalCapManager diff --git a/classes/capClasses/airGroups/AirGroup.lua b/src/classes/capClasses/airGroups/AirGroup.lua similarity index 92% rename from classes/capClasses/airGroups/AirGroup.lua rename to src/classes/capClasses/airGroups/AirGroup.lua index a70db61..ea5a5ce 100644 --- a/classes/capClasses/airGroups/AirGroup.lua +++ b/src/classes/capClasses/airGroups/AirGroup.lua @@ -1,3 +1,8 @@ +local SpearheadEvents = require("classes.spearhead_events") +local RTBMission = require("classes.capClasses.taskings.RTB") +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") + ---@class AirGroup : OnUnitLostListener ---@field protected _logger Logger ---@field protected _groupName string @@ -26,13 +31,13 @@ function AirGroup:New(groupName, groupType, config, logger, spawnManager) local group = Group.getByName(self._groupName) if group then - Spearhead.Events.addOnGroupRTBListener(self._groupName, self) - Spearhead.Events.addOnGroupRTBInTenListener(self._groupName, self) - Spearhead.Events.addOnGroupOnStationListener(self._groupName, self) + SpearheadEvents.addOnGroupRTBListener(self._groupName, self) + SpearheadEvents.addOnGroupRTBInTenListener(self._groupName, self) + SpearheadEvents.addOnGroupOnStationListener(self._groupName, self) for _, unit in pairs(group:getUnits()) do - Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self) - Spearhead.Events.addOnUnitLandEventListener(unit:getName(), self) + SpearheadEvents.addOnUnitLostEventListener(unit:getName(), self) + SpearheadEvents.addOnUnitLandEventListener(unit:getName(), self) end spawnManager:DestroyGroup(groupName) @@ -105,7 +110,7 @@ function AirGroup:SendRTB(airbase) end end if location then - local mission = Spearhead.classes.capClasses.taskings.RTB.getAsMission(airbase, { x= location.x, y= location.z }, self._config) + local mission = RTBMission.getAsMission(airbase, { x= location.x, y= location.z }, self._config) group:getController():setTask(mission) self._logger:debug("AirGroup:SendRTB - Task set for group: " .. self._groupName) end @@ -248,7 +253,7 @@ function AirGroup:OnLastUnitLanded() return time + 5 end - if pos and Spearhead.Util.VectorDistance3d(pos, data.lastLocations[unit:getName()]) > 10 then + if pos and Util.VectorDistance3d(pos, data.lastLocations[unit:getName()]) > 10 then data.lastChangeTime = time end data.lastLocations[unit:getName()] = pos @@ -426,14 +431,10 @@ do --EVENT LISTENERS end function AirGroup:Destroy() - Spearhead.DcsUtil.DestroyGroup(self._groupName) + self._spawnManager:DestroyGroup(self._groupName) end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end -Spearhead.classes.capClasses.airGroups.AirGroup = AirGroup +return AirGroup ---@alias AirGroupState ---| "UnSpawned" diff --git a/classes/capClasses/airGroups/CapGroup.lua b/src/classes/capClasses/airGroups/CapGroup.lua similarity index 66% rename from classes/capClasses/airGroups/CapGroup.lua rename to src/classes/capClasses/airGroups/CapGroup.lua index 65a2e88..40319bb 100644 --- a/classes/capClasses/airGroups/CapGroup.lua +++ b/src/classes/capClasses/airGroups/CapGroup.lua @@ -1,3 +1,7 @@ +local AirGroup = require("classes.capClasses.airGroups.AirGroup") +local CAP = require("classes.capClasses.taskings.CAP") +local Util = require("classes.util.Util") +local MissionEditorWarner = require("classes.util.MissionEditorWarnings") ---@class CapGroup : AirGroup ---@field private _targetZoneIdPerStage table @@ -14,9 +18,9 @@ CapGroup.__index = CapGroup ---@return CapGroup function CapGroup.New(groupName, config, logger, spawnManager) - setmetatable(CapGroup, Spearhead.classes.capClasses.airGroups.AirGroup) + setmetatable(CapGroup, AirGroup) local self = setmetatable({}, CapGroup) --[[@as CapGroup]] - Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "CAP", config, logger, spawnManager) + AirGroup.New(self, groupName, "CAP", config, logger, spawnManager) self._targetZoneIdPerStage = {} @@ -65,10 +69,10 @@ function CapGroup:SendToZone(zone, targetZoneID, airbase) end if isInAir == true then - local mission = Spearhead.classes.capClasses.taskings.CAP.getAsMission(self._groupName, airbase, zone, self._config) + local mission = CAP.getAsMission(self._groupName, airbase, zone, self._config) self:SetMission(mission) else - local mission = Spearhead.classes.capClasses.taskings.CAP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config) + local mission = CAP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config) if mission then self:SetMission(mission) else @@ -80,8 +84,8 @@ end ---@private function CapGroup:InitWithName(groupName) - local split_string = Spearhead.Util.split_string(groupName, "_") - local partCount = Spearhead.Util.tableLength(split_string) + local split_string = Util.split_string(groupName, "_") + local partCount = Util.tableLength(split_string) if partCount >= 3 then local configPart = split_string[2] @@ -95,34 +99,34 @@ function CapGroup:InitWithName(groupName) elseif first == "[" then self._isBackup = false else - Spearhead.AddMissionEditorWarning("Could not parse the CAP config for group: " .. groupName) + MissionEditorWarner.Add("Could not parse the CAP config for group: " .. groupName) return end - local subsplit = Spearhead.Util.split_string(configPart, "|") + local subsplit = Util.split_string(configPart, "|") if subsplit then for key, value in pairs(subsplit) do - local keySplit = Spearhead.Util.split_string(value, "]") + local keySplit = Util.split_string(value, "]") local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) - local commaSeperated = Spearhead.Util.split_string(allActives, ",") + local commaSeperated = Util.split_string(allActives, ",") for _, value in pairs(commaSeperated) do - local dashSeperated = Spearhead.Util.split_string(value, "-") - if Spearhead.Util.tableLength(dashSeperated) > 1 then + local dashSeperated = Util.split_string(value, "-") + if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) for i = from, till do - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i)) else self._targetZoneIdPerStage[tostring(i)] = targetZone end end else - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A", tostring(dashSeperated[1])) else self._targetZoneIdPerStage[tostring(dashSeperated[1])] = targetZone @@ -132,15 +136,11 @@ function CapGroup:InitWithName(groupName) end end - env.info("Capgroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage)) + env.info("Capgroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage)) else - Spearhead.AddMissionEditorWarning("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount) + MissionEditorWarner.Add("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount) end end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end -Spearhead.classes.capClasses.airGroups.CapGroup = CapGroup \ No newline at end of file +return CapGroup \ No newline at end of file diff --git a/classes/capClasses/airGroups/InterceptGroup.lua b/src/classes/capClasses/airGroups/InterceptGroup.lua similarity index 83% rename from classes/capClasses/airGroups/InterceptGroup.lua rename to src/classes/capClasses/airGroups/InterceptGroup.lua index 5c99313..bfe98fa 100644 --- a/classes/capClasses/airGroups/InterceptGroup.lua +++ b/src/classes/capClasses/airGroups/InterceptGroup.lua @@ -1,3 +1,9 @@ +local AirGroup = require("classes.capClasses.airGroups.AirGroup") +local INTERCEPT = require("classes.capClasses.taskings.INTERCEPT") +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") +local MissionEditorWarner = require("classes.util.MissionEditorWarnings") + ---@class InterceptGroup : AirGroup ---@field private _targetNames Array ---@field private _targetZoneName string @@ -22,9 +28,9 @@ InterceptGroup.__index = InterceptGroup ---@return InterceptGroup? function InterceptGroup.New(groupName, config, logger, detectionManager, spawnManager) - setmetatable(InterceptGroup, Spearhead.classes.capClasses.airGroups.AirGroup) + setmetatable(InterceptGroup, AirGroup) local self = setmetatable({}, InterceptGroup) - Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "INTERCEPT", config, logger, spawnManager) + AirGroup.New(self, groupName, "INTERCEPT", config, logger, spawnManager) local group = Group.getByName(groupName) if not group then @@ -135,7 +141,7 @@ function InterceptGroup:GetClosestTarget() local targetUnit = Unit.getByName(targetName) if targetUnit and targetUnit:isExist() then local pos = targetUnit:getPoint() - local distance = Spearhead.Util.VectorDistance3d(groupPoint, pos) + local distance = Util.VectorDistance3d(groupPoint, pos) if distance < closestDistance then closestDistance = distance closestUnit = targetUnit @@ -179,7 +185,7 @@ function InterceptGroup:UpdateTask() end end - if Spearhead.DcsUtil.IsBingoFuel(self._groupName) then + if DcsUtil.IsBingoFuel(self._groupName) then self._logger:debug("InterceptGroup: " .. self._groupName .. " is at bingo fuel, returning to base") self:SendRTB(self._airbase) return nil -- Return to base if bingo fuel @@ -187,7 +193,7 @@ function InterceptGroup:UpdateTask() if selfDetected and self:IsInAir() == true then if self._currentTargetName and self._currentTargetName == closestUnit:getName() then - local distance = Spearhead.Util.VectorDistance3d(closestUnit:getPoint(), groupPoint) + local distance = Util.VectorDistance3d(closestUnit:getPoint(), groupPoint) if distance < 30 * 1852 then -- If the target is within 10 nautical miles, continue attacking self._logger:debug("InterceptGroup: " .. self._groupName .. " continues attacking target " .. closestUnit:getName()) @@ -199,7 +205,7 @@ function InterceptGroup:UpdateTask() local vec3 = closestUnit:getPoint() local vec2 = { x = vec3.x, y = vec3.z } local groupPointVec2 = { x = groupPoint.x, y = groupPoint.z } - local mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getUnitInterceptMissionFromAir(self._groupName, groupPointVec2, vec2, closestUnit, self._airbase, self._config, self._maxSpeed, alt) + local mission = INTERCEPT.getUnitInterceptMissionFromAir(self._groupName, groupPointVec2, vec2, closestUnit, self._airbase, self._config, self._maxSpeed, alt) self:SetMission(mission) self._currentTargetName = closestUnit:getName() return 15 -- Just continue attacking the detected target @@ -219,7 +225,7 @@ function InterceptGroup:UpdateTask() local mission = nil if self:IsInAir() == true then -- If the group is in the air, create an intercept mission - mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getMissionFromInAir( + mission = INTERCEPT.getMissionFromInAir( self._groupName, { x = groupPoint.x, y = groupPoint.z }, interceptPoint, @@ -229,7 +235,7 @@ function InterceptGroup:UpdateTask() alt ) else - mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getMissionFromAirbase( + mission = INTERCEPT.getMissionFromAirbase( self._groupName, interceptPoint, self._airbase, @@ -310,33 +316,33 @@ end ---@private function InterceptGroup:InitWithName(groupName) - local split_string = Spearhead.Util.split_string(groupName, "_") - local partCount = Spearhead.Util.tableLength(split_string) + local split_string = Util.split_string(groupName, "_") + local partCount = Util.tableLength(split_string) if partCount >= 3 then local configPart = split_string[2] configPart = string.sub(configPart, 2, #configPart) - local subsplit = Spearhead.Util.split_string(configPart, "|") + local subsplit = Util.split_string(configPart, "|") if subsplit then for key, value in pairs(subsplit) do - local keySplit = Spearhead.Util.split_string(value, "]") + local keySplit = Util.split_string(value, "]") local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) - local commaSeperated = Spearhead.Util.split_string(allActives, ",") + local commaSeperated = Util.split_string(allActives, ",") for _, value in pairs(commaSeperated) do - local dashSeperated = Spearhead.Util.split_string(value, "-") - if Spearhead.Util.tableLength(dashSeperated) > 1 then + local dashSeperated = Util.split_string(value, "-") + if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) for i = from, till do - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i)) else self._targetZoneIdPerStage[tostring(i)] = targetZone end end else - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A", tostring(dashSeperated[1])) else self._targetZoneIdPerStage[tostring(dashSeperated[1])] = targetZone @@ -346,16 +352,12 @@ function InterceptGroup:InitWithName(groupName) end end - env.info("interceptGroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage)) + env.info("interceptGroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage)) else - Spearhead.AddMissionEditorWarning("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount) + MissionEditorWarner.Add("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount) end end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end -Spearhead.classes.capClasses.airGroups.InterceptGroup = InterceptGroup \ No newline at end of file +return InterceptGroup \ No newline at end of file diff --git a/classes/capClasses/airGroups/SweepGroup.lua b/src/classes/capClasses/airGroups/SweepGroup.lua similarity index 67% rename from classes/capClasses/airGroups/SweepGroup.lua rename to src/classes/capClasses/airGroups/SweepGroup.lua index af77f6f..4ad1812 100644 --- a/classes/capClasses/airGroups/SweepGroup.lua +++ b/src/classes/capClasses/airGroups/SweepGroup.lua @@ -1,3 +1,8 @@ +local AirGroup = require("classes.capClasses.airGroups.AirGroup") +local SWEEP = require("classes.capClasses.taskings.SWEEP") +local Util = require("classes.util.Util") +local MissionEditorWarner = require("classes.util.MissionEditorWarnings") + ---@class SweepGroup : AirGroup ---@field _targetZoneIdPerStage table ---@field _currentTargetZoneID string? @@ -11,9 +16,9 @@ SweepGroup.__index = SweepGroup ---@param spawnManager SpawnManager ---@return SweepGroup function SweepGroup.New(groupName, config, logger, spawnManager) - setmetatable(SweepGroup, Spearhead.classes.capClasses.airGroups.AirGroup) + setmetatable(SweepGroup, AirGroup) local self = setmetatable({}, SweepGroup) --[[@as SweepGroup]] - Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "SWEEP", config, logger, spawnManager) + AirGroup.New(self, groupName, "SWEEP", config, logger, spawnManager) self._targetZoneIdPerStage = {} self:InitWithName(groupName) @@ -47,7 +52,7 @@ function SweepGroup:SendToZone(zone, targetZoneID, airbase) local group = Group.getByName(self._groupName) - local mission = Spearhead.classes.capClasses.taskings.SWEEP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config) + local mission = SWEEP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config) if mission then ---@type SetTaskParams local params = { @@ -68,35 +73,35 @@ end ---@private function SweepGroup:InitWithName(groupName) - local split_string = Spearhead.Util.split_string(groupName, "_") - local partCount = Spearhead.Util.tableLength(split_string) + local split_string = Util.split_string(groupName, "_") + local partCount = Util.tableLength(split_string) if partCount >= 3 then local configPart = split_string[2] configPart = string.sub(configPart, 2, #configPart) - local subsplit = Spearhead.Util.split_string(configPart, "|") + local subsplit = Util.split_string(configPart, "|") if subsplit then for key, value in pairs(subsplit) do - local keySplit = Spearhead.Util.split_string(value, "]") + local keySplit = Util.split_string(value, "]") local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) - local commaSeperated = Spearhead.Util.split_string(allActives, ",") + local commaSeperated = Util.split_string(allActives, ",") for _, value in pairs(commaSeperated) do - local dashSeperated = Spearhead.Util.split_string(value, "-") - if Spearhead.Util.tableLength(dashSeperated) > 1 then + local dashSeperated = Util.split_string(value, "-") + if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) for i = from, till do - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i)) else self._targetZoneIdPerStage[tostring(i)] = targetZone end end else - if Spearhead.Util.strContains(targetZone, "A") == true then + if Util.strContains(targetZone, "A") == true then self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A", tostring(dashSeperated[1])) else @@ -107,15 +112,11 @@ function SweepGroup:InitWithName(groupName) end end - env.info("SweepGroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage)) + env.info("SweepGroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage)) else - Spearhead.AddMissionEditorWarning("SWEEP Group with name: " .. + MissionEditorWarner.Add("SWEEP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount) end end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end -Spearhead.classes.capClasses.airGroups.SweepGroup = SweepGroup \ No newline at end of file +return SweepGroup \ No newline at end of file diff --git a/classes/capClasses/detection/DetectionManager.lua b/src/classes/capClasses/detection/DetectionManager.lua similarity index 93% rename from classes/capClasses/detection/DetectionManager.lua rename to src/classes/capClasses/detection/DetectionManager.lua index e0025cb..50b16b4 100644 --- a/classes/capClasses/detection/DetectionManager.lua +++ b/src/classes/capClasses/detection/DetectionManager.lua @@ -161,8 +161,4 @@ function DetectionManager:UpdateDetectedUnitsByCoalition(coalitionSide) end end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.detection then Spearhead.classes.capClasses.detection = {} end -Spearhead.classes.capClasses.detection.DetectionManager = DetectionManager +return DetectionManager diff --git a/classes/capClasses/runwayBombing/RunwayBombingTracker.lua b/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua similarity index 85% rename from classes/capClasses/runwayBombing/RunwayBombingTracker.lua rename to src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua index b6a945c..a8366ae 100644 --- a/classes/capClasses/runwayBombing/RunwayBombingTracker.lua +++ b/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua @@ -1,3 +1,6 @@ +local SpearheadEvents = require("classes.spearhead_events") +local Util = require("classes.util.Util") + ---@class RunwayBombingTracker : OnWeaponFiredListener ---@field trackedRunways table ---@field private _logger Logger @@ -11,8 +14,7 @@ function RunwayBombingTracker.new(logger) local self = setmetatable({}, RunwayBombingTracker) self._logger = logger - - Spearhead.Events.AddWeaponFiredListener(self) + SpearheadEvents.AddWeaponFiredListener(self) return self end @@ -111,15 +113,10 @@ function RunwayBombingTracker:OnWeaponImpact(weaponDesc, impactPoint) local zone= strikeMission:GetRunwayZone() - if Spearhead.Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then + if Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then strikeMission:RunwayHit(impactPoint, explosiveMass) end end end - -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.runwayBombing then Spearhead.classes.capClasses.runwayBombing = {} end -Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker = RunwayBombingTracker \ No newline at end of file +return RunwayBombingTracker \ No newline at end of file diff --git a/classes/capClasses/taskings/CAP.lua b/src/classes/capClasses/taskings/CAP.lua similarity index 88% rename from classes/capClasses/taskings/CAP.lua rename to src/classes/capClasses/taskings/CAP.lua index d198e39..ecc8f2b 100644 --- a/classes/capClasses/taskings/CAP.lua +++ b/src/classes/capClasses/taskings/CAP.lua @@ -1,3 +1,6 @@ +local Util = require("classes.util.Util") +local RTB = require("classes.capClasses.taskings.RTB") + ---@class CAPTasking local CAP = {} @@ -38,7 +41,7 @@ local function GetCAPPointFromTriggerZone(airBase, capZone) for indexA, pointA in ipairs(capZone.verts) do for indexB, pointB in ipairs(capZone.verts) do if pointA ~= pointB then - local distance = Spearhead.Util.VectorDistance2d(pointA, pointB) + local distance = Util.VectorDistance2d(pointA, pointB) if distance > furthestDistance then furthestDistance = distance furthestA = indexA @@ -58,12 +61,12 @@ local function GetCAPPointFromTriggerZone(airBase, capZone) local furthest = pointA local closest = pointB - local heading = Spearhead.Util.vectorHeadingFromTo(pointA, pointB) + local heading = Util.vectorHeadingFromTo(pointA, pointB) - if Spearhead.Util.VectorDistance2d(baseVec2, pointB) > Spearhead.Util.VectorDistance2d(baseVec2, pointA) then + if Util.VectorDistance2d(baseVec2, pointB) > Util.VectorDistance2d(baseVec2, pointA) then furthest = pointB closest = pointA - heading = Spearhead.Util.vectorHeadingFromTo(pointB, pointA) + heading = Util.vectorHeadingFromTo(pointB, pointA) end local distance = furthestDistance @@ -87,8 +90,8 @@ end local GetOutboundTask = function(airbase, capZone, capConfig) local airbaseVec3 = airbase:getPoint() local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z } - local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, capZone.location) - local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 18520) + local heading = Util.vectorHeadingFromTo(airbaseVec2, capZone.location) + local point = Util.vectorMove(airbaseVec2, heading, 18520) return { alt = 2000, @@ -130,9 +133,9 @@ function CAP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig) [1] = GetOutboundTask(airbase, capZone, capConfig), [2] = GetOutboundTask(airbase, capZone, capConfig), [3] = CAP.getAsTasking(groupName, airbase, capZone, capConfig), - [4] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig), - [5] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [6] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [4] = RTB.getApproachPoint(airbase, capZone.location, capConfig), + [5] = RTB.getInitialPoint(airbase), + [6] = RTB.getLandingPoint(airbase) } local mission = { @@ -155,9 +158,9 @@ end function CAP.getAsMission(groupName, airbase, capZone, capConfig) local points = { [1] = CAP.getAsTasking(groupName, airbase, capZone, capConfig), - [2] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig), - [3] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [4] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [2] = RTB.getApproachPoint(airbase, capZone.location, capConfig), + [3] = RTB.getInitialPoint(airbase), + [4] = RTB.getLandingPoint(airbase) } local mission = { @@ -320,8 +323,4 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig) } end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end -Spearhead.classes.capClasses.taskings.CAP = CAP +return CAP diff --git a/classes/capClasses/taskings/INTERCEPT.lua b/src/classes/capClasses/taskings/INTERCEPT.lua similarity index 89% rename from classes/capClasses/taskings/INTERCEPT.lua rename to src/classes/capClasses/taskings/INTERCEPT.lua index a649be2..8ed2600 100644 --- a/classes/capClasses/taskings/INTERCEPT.lua +++ b/src/classes/capClasses/taskings/INTERCEPT.lua @@ -1,4 +1,5 @@ - +local Util = require("classes.util.Util") +local RTB = require("classes.capClasses.taskings.RTB") ---@class InterceptTasking local INTERCEPT = {} @@ -14,11 +15,11 @@ function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, con local airbaseVec3 = airbase:getPoint() local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z } - local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, interceptPoint) + local heading = Util.vectorHeadingFromTo(airbaseVec2, interceptPoint) env.info("BLAAT: heading from runway to first point: " .. heading) - local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 3*1852) + local point = Util.vectorMove(airbaseVec2, heading, 3*1852) local pointA, pointB, pointC, pointD = INTERCEPT.getInterceptTaskPoint(groupName, point, interceptPoint, airbaseVec2, config, speed, alt) @@ -28,9 +29,9 @@ function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, con [3] = pointB, [4] = pointC, [5] = pointD, - [6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, interceptPoint, config), - [7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [6] = RTB.getApproachPoint(airbase, interceptPoint, config), + [7] = RTB.getInitialPoint(airbase), + [8] = RTB.getLandingPoint(airbase) } local mission = { @@ -67,9 +68,9 @@ function INTERCEPT.getMissionFromInAir(groupName, currentPosition, interceptPoin [3] = pointB, [4] = pointC, [5] = pointD, - [6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, interceptPoint, config), - [7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [6] = RTB.getApproachPoint(airbase, interceptPoint, config), + [7] = RTB.getInitialPoint(airbase), + [8] = RTB.getLandingPoint(airbase) } local mission = { @@ -109,9 +110,9 @@ function INTERCEPT.getUnitInterceptMissionFromAir(groupName, currentPoint, targe [3] = pointB, [4] = pointC, [5] = pointD, - [6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, currentPoint, config), - [7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [6] = RTB.getApproachPoint(airbase, currentPoint, config), + [7] = RTB.getInitialPoint(airbase), + [8] = RTB.getLandingPoint(airbase) } local mission = { @@ -392,8 +393,4 @@ function INTERCEPT.getUnitInterceptTaskPoint(groupName, currentPoint, targetPosi end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end -Spearhead.classes.capClasses.taskings.INTERCEPT = INTERCEPT \ No newline at end of file +return INTERCEPT \ No newline at end of file diff --git a/classes/capClasses/taskings/RTB.lua b/src/classes/capClasses/taskings/RTB.lua similarity index 82% rename from classes/capClasses/taskings/RTB.lua rename to src/classes/capClasses/taskings/RTB.lua index c00108c..7ebfa5a 100644 --- a/classes/capClasses/taskings/RTB.lua +++ b/src/classes/capClasses/taskings/RTB.lua @@ -1,3 +1,4 @@ +local Util = require("classes.util.Util") ---@class RTBTasking local RTB = {} @@ -33,7 +34,7 @@ local getRunwayIntoWindCourseRad = function(airbase) local runways = airbase:getRunways() local windVec = atmosphere.getWind(airbase:getPoint()) - local mPerS = Spearhead.Util.vectorMagnitude(windVec) + local mPerS = Util.vectorMagnitude(windVec) if mPerS > 0 then for i = 1, #runways do @@ -48,7 +49,7 @@ local getRunwayIntoWindCourseRad = function(airbase) end local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0} - local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec) + local alignment = Util.vectorAlignment(windVec, runwayVec) if minAlignment == nil or alignment < minAlignment then activeCourse = i @@ -68,7 +69,7 @@ local getRunwayIntoWindCourseRad = function(airbase) end local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0} - local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec) + local alignment = Util.vectorAlignment(windVec, runwayVec) if minAlignment == nil or alignment < minAlignment then activeCourse = i @@ -102,7 +103,7 @@ local function calcInitialPoint(airbase) local flipped = (heading + 180) % 360 local basePoint = airbase:getPoint() local basePointVec2 = {x = basePoint.x, y = basePoint.z} - local point = Spearhead.Util.vectorMove(basePointVec2, flipped, 22000) + local point = Util.vectorMove(basePointVec2, flipped, 22000) return point, flipped @@ -116,10 +117,10 @@ end function RTB.getApproachPoint(airbase, missionPoint, capConfig) local initialPoint, headingFromRunway = calcInitialPoint(airbase) - local pointA = Spearhead.Util.vectorMove(initialPoint, headingFromRunway - 45, 9000) - local pointB = Spearhead.Util.vectorMove(initialPoint, headingFromRunway + 45, 9000) + local pointA = Util.vectorMove(initialPoint, headingFromRunway - 45, 9000) + local pointB = Util.vectorMove(initialPoint, headingFromRunway + 45, 9000) - if Spearhead.Util.VectorDistance2d(missionPoint, pointA) > Spearhead.Util.VectorDistance2d(missionPoint, pointB) then + if Util.VectorDistance2d(missionPoint, pointA) > Util.VectorDistance2d(missionPoint, pointB) then pointA = pointB end @@ -194,8 +195,4 @@ function RTB.getLandingPoint(airbase) end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end -Spearhead.classes.capClasses.taskings.RTB = RTB \ No newline at end of file +return RTB \ No newline at end of file diff --git a/classes/capClasses/taskings/SWEEP.lua b/src/classes/capClasses/taskings/SWEEP.lua similarity index 87% rename from classes/capClasses/taskings/SWEEP.lua rename to src/classes/capClasses/taskings/SWEEP.lua index 63bb99f..ed2ee40 100644 --- a/classes/capClasses/taskings/SWEEP.lua +++ b/src/classes/capClasses/taskings/SWEEP.lua @@ -1,3 +1,6 @@ +local Util = require("classes.util.Util") +local RTB = require("classes.capClasses.taskings.RTB") + ---@class SWEEPTasking local SWEEP = {} @@ -31,7 +34,7 @@ local function GetCAPPointFromTriggerZone(airBase, capZone) for indexA, pointA in ipairs(capZone.verts) do for indexB, pointB in ipairs(capZone.verts) do if pointA ~= pointB then - local distance = Spearhead.Util.VectorDistance2d(pointA, pointB) + local distance = Util.VectorDistance2d(pointA, pointB) if distance > furthestDistance then furthestDistance = distance furthestA = indexA @@ -51,12 +54,12 @@ local function GetCAPPointFromTriggerZone(airBase, capZone) local furthest = pointA local closest = pointB - local heading = Spearhead.Util.vectorHeadingFromTo(pointA, pointB) + local heading = Util.vectorHeadingFromTo(pointA, pointB) - if Spearhead.Util.VectorDistance2d(baseVec2, pointB) > Spearhead.Util.VectorDistance2d(baseVec2, pointA) then + if Util.VectorDistance2d(baseVec2, pointB) > Util.VectorDistance2d(baseVec2, pointA) then furthest = pointB closest = pointA - heading = Spearhead.Util.vectorHeadingFromTo(pointB, pointA) + heading = Util.vectorHeadingFromTo(pointB, pointA) end local distance = furthestDistance @@ -80,8 +83,8 @@ end local GetOutboundTask = function(airbase, capZone, capConfig) local airbaseVec3 = airbase:getPoint() local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z } - local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, capZone.location) - local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 18520) + local heading = Util.vectorHeadingFromTo(airbaseVec2, capZone.location) + local point = Util.vectorMove(airbaseVec2, heading, 18520) return { alt = 2000, @@ -128,9 +131,9 @@ function SWEEP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig) [3] = pointA, [4] = pointB, [5] = pointC, - [6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig), - [7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase), - [8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase) + [6] = RTB.getApproachPoint(airbase, capZone.location, capConfig), + [7] = RTB.getInitialPoint(airbase), + [8] = RTB.getLandingPoint(airbase) } local mission = { @@ -280,8 +283,4 @@ function SWEEP.getAsTasking(groupName, airbase, capZone, capConfig) return pointA, pointB, pointC end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end -if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end -Spearhead.classes.capClasses.taskings.SWEEP = SWEEP +return SWEEP diff --git a/classes/configuration/CapConfig.lua b/src/classes/configuration/CapConfig.lua similarity index 92% rename from classes/configuration/CapConfig.lua rename to src/classes/configuration/CapConfig.lua index bac55f3..076cbe9 100644 --- a/classes/configuration/CapConfig.lua +++ b/src/classes/configuration/CapConfig.lua @@ -95,6 +95,4 @@ function CapConfig:getDeathDelay() return self._deathDelay end -if not Spearhead.internal then Spearhead.internal = {} end -if not Spearhead.internal.configuration then Spearhead.internal.configuration = {} end -Spearhead.internal.configuration.CapConfig = CapConfig; \ No newline at end of file +return CapConfig \ No newline at end of file diff --git a/classes/configuration/GlobalConfig.lua b/src/classes/configuration/GlobalConfig.lua similarity index 86% rename from classes/configuration/GlobalConfig.lua rename to src/classes/configuration/GlobalConfig.lua index 011efe2..102703c 100644 --- a/classes/configuration/GlobalConfig.lua +++ b/src/classes/configuration/GlobalConfig.lua @@ -29,6 +29,5 @@ function GlobalConfig:getBriefingTime() end -if Spearhead == nil then Spearhead = {} end -Spearhead.GlobalConfig = GlobalConfig.New() +return GlobalConfig diff --git a/classes/configuration/StageConfig.lua b/src/classes/configuration/StageConfig.lua similarity index 84% rename from classes/configuration/StageConfig.lua rename to src/classes/configuration/StageConfig.lua index 956f21d..6b617f5 100644 --- a/classes/configuration/StageConfig.lua +++ b/src/classes/configuration/StageConfig.lua @@ -7,8 +7,6 @@ --- @field startingStage integer --- @field maxMissionsPerStage integer --- @field AmountPreactivateStage integer - - local StageConfig = {}; ---comment @@ -34,6 +32,4 @@ function StageConfig:new() return o; end -if not Spearhead.internal then Spearhead.internal = {} end -if not Spearhead.internal.configuration then Spearhead.internal.configuration = {} end -Spearhead.internal.configuration.StageConfig = StageConfig; \ No newline at end of file +return StageConfig \ No newline at end of file diff --git a/classes/definitions/aliases.lua b/src/classes/definitions/aliases.lua similarity index 100% rename from classes/definitions/aliases.lua rename to src/classes/definitions/aliases.lua diff --git a/classes/fleetClasses/FleetGroup.lua b/src/classes/fleetClasses/FleetGroup.lua similarity index 63% rename from classes/fleetClasses/FleetGroup.lua rename to src/classes/fleetClasses/FleetGroup.lua index e792f82..2e703dc 100644 --- a/classes/fleetClasses/FleetGroup.lua +++ b/src/classes/fleetClasses/FleetGroup.lua @@ -1,3 +1,10 @@ +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") +local MissionEditorWarning = require("classes.util.MissionEditorWarnings") +local RouteUtil = require("classes.spearhead_routeutil") +local SpearheadEvents = require("classes.spearhead_events") + +---@class FleetGroup local FleetGroup = {} ---comment @@ -13,9 +20,9 @@ function FleetGroup:new(fleetGroupName, database, logger) o.fleetGroupName = fleetGroupName o.logger = logger - local split_name = Spearhead.Util.split_string(fleetGroupName, "_") - if Spearhead.Util.tableLength(split_name) < 2 then - Spearhead.AddMissionEditorWarning("CARRIERGROUP should have at least 2 parts. CARRIERGROUP_") + local split_name = Util.split_string(fleetGroupName, "_") + if Util.tableLength(split_name) < 2 then + MissionEditorWarning.Add("CARRIERGROUP should have at least 2 parts. CARRIERGROUP_") return nil end o.fleetNameIdentifier = split_name[2] @@ -27,12 +34,12 @@ function FleetGroup:new(fleetGroupName, database, logger) do --INIT local carrierRouteZones = database:getCarrierRouteZones() for _, zoneName in pairs(carrierRouteZones) do - if Spearhead.Util.strContains(string.lower(zoneName), "_".. string.lower(o.fleetNameIdentifier) .. "_" ) == true then - local zone = Spearhead.DcsUtil.getZoneByName(zoneName) - if zone and zone.zone_type == Spearhead.DcsUtil.ZoneType.Polygon then - local split_string = Spearhead.Util.split_string(zoneName, "_") - if Spearhead.Util.tableLength(split_string) < 3 then - Spearhead.AddMissionEditorWarning( + if Util.strContains(string.lower(zoneName), "_".. string.lower(o.fleetNameIdentifier) .. "_" ) == true then + local zone = DcsUtil.getZoneByName(zoneName) + if zone and zone.zone_type == DcsUtil.ZoneType.Polygon then + local split_string = Util.split_string(zoneName, "_") + if Util.tableLength(split_string) < 3 then + MissionEditorWarning.Add( "CARRIERROUTE should at least have 3 parts. Check the documentation for: " .. zoneName) else @@ -48,7 +55,7 @@ function FleetGroup:new(fleetGroupName, database, logger) for ii = i + 1, 4 do local a = zone.verts[i] local b = zone.verts[ii] - local dist = Spearhead.Util.VectorDistance2d(a, b) + local dist = Util.VectorDistance2d(a, b) if biggest == nil or dist > biggest then biggestA = a @@ -65,17 +72,17 @@ function FleetGroup:new(fleetGroupName, database, logger) return nil, nil end - if Spearhead.Util.startswith(namePart, "%[") == true then - namePart = Spearhead.Util.split_string(namePart, "[")[1] + if Util.startswith(namePart, "%[") == true then + namePart = Util.split_string(namePart, "[")[1] end - if Spearhead.Util.strContains(namePart, "%]") == true then - namePart = Spearhead.Util.split_string(namePart, "]")[1] + if Util.strContains(namePart, "%]") == true then + namePart = Util.split_string(namePart, "]")[1] end - local split_numbers = Spearhead.Util.split_string(namePart, "-") - if Spearhead.Util.tableLength(split_numbers) < 2 then - Spearhead.AddMissionEditorWarning("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) + local split_numbers = Util.split_string(namePart, "-") + if Util.tableLength(split_numbers) < 2 then + MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) return nil, nil end @@ -83,7 +90,7 @@ function FleetGroup:new(fleetGroupName, database, logger) local second = tonumber(split_numbers[2]) if first == nil or second == nil then - Spearhead.AddMissionEditorWarning("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) + MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) return nil, nil end return first, second @@ -97,11 +104,11 @@ function FleetGroup:new(fleetGroupName, database, logger) end o.pointsPerZone[zoneName] = { pointA = { x = pointA.x, z = pointA.y, y = 0 }, pointB = { x = pointB.x, z = pointB.y, y = 0} } else - Spearhead.AddMissionEditorWarning("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) + MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) end end else - Spearhead.AddMissionEditorWarning("CARRIERROUTE cannot be a cilinder: " .. zoneName) + MissionEditorWarning.Add("CARRIERROUTE cannot be a cilinder: " .. zoneName) end end end @@ -115,7 +122,7 @@ function FleetGroup:new(fleetGroupName, database, logger) local group = Group.getByName(groupName) if group then - logger:info("Sending " .. fleetGroupName .. " to " .. targetZone) + logger:info("Sending " .. groupName .. " to " .. targetZone) group:getController():setTask(task) end end @@ -124,14 +131,13 @@ function FleetGroup:new(fleetGroupName, database, logger) local targetZone = self.targetZonePerStage[tostring(number)] if targetZone and targetZone ~= self.currentTargetZone then local points = self.pointsPerZone[targetZone] - local task = Spearhead.RouteUtil.CreateCarrierRacetrack(points.pointA, points.pointB) + local task = RouteUtil.CreateCarrierRacetrack(points.pointA, points.pointB) timer.scheduleFunction(SetTaskAsync, { task = task, targetZone = targetZone, groupName = self.fleetGroupName, logger = self.logger }, timer.getTime() + 5) end end - Spearhead.Events.AddStageNumberChangedListener(o) + SpearheadEvents.AddStageNumberChangedListener(o) return o end -if not Spearhead.internal then Spearhead.internal = {} end -Spearhead.internal.FleetGroup = FleetGroup +return FleetGroup diff --git a/src/classes/fleetClasses/GlobalFleetManager.lua b/src/classes/fleetClasses/GlobalFleetManager.lua new file mode 100644 index 0000000..11aa78c --- /dev/null +++ b/src/classes/fleetClasses/GlobalFleetManager.lua @@ -0,0 +1,26 @@ +local Logger = require("classes.util.Logger") +local Util = require("classes.util.Util") +local FleetGroup = require("classes.fleetClasses.FleetGroup") +local MizGroupsManager = require("classes.helpers.MizGroupsManager") + + +---@class GlobalFleetManager +local GlobalFleetManager = {} + +local fleetGroups = {} + +GlobalFleetManager.start = function(database) + + local logger = Logger.new("CARRIERFLEET", "INFO") + + local all_groups = MizGroupsManager.getAllGroupNames() + for _, groupName in pairs(all_groups) do + if Util.startswith(string.lower(groupName), "carriergroup" ) == true then + logger:info("Registering " .. groupName .. " as a managed fleet") + local carrierGroup = FleetGroup:new(groupName, database, logger) + table.insert(fleetGroups, carrierGroup) + end + end +end + +return GlobalFleetManager \ No newline at end of file diff --git a/classes/helpers/MizGroupsManager.lua b/src/classes/helpers/MizGroupsManager.lua similarity index 84% rename from classes/helpers/MizGroupsManager.lua rename to src/classes/helpers/MizGroupsManager.lua index 68ad5f8..1e03b9a 100644 --- a/classes/helpers/MizGroupsManager.lua +++ b/src/classes/helpers/MizGroupsManager.lua @@ -1,3 +1,5 @@ +local DcsUtil = require("classes.util.DcsUtil") + ---@class SpawnData ---@field groupTemplate table ---@field isStatic boolean @@ -14,17 +16,17 @@ MizGroupsManager._spawnTemplateData = {} do --init for coalition_name, coalition_data in pairs(env.mission.coalition) do - local coalition_nr = Spearhead.DcsUtil.stringToCoalition(coalition_name) + local coalition_nr = DcsUtil.stringToCoalition(coalition_name) if coalition_data.country then for country_index, country_data in pairs(coalition_data.country) do for category_name, categorydata in pairs(country_data) do - local category_id = Spearhead.DcsUtil.stringToGroupCategory(category_name) + local category_id = DcsUtil.stringToGroupCategory(category_name) if category_id ~= nil and type(categorydata) == "table" and categorydata.group ~= nil and type(categorydata.group) == "table" then for group_index, group in pairs(categorydata.group) do local name = group.name local skippable = false local isStatic = false - if category_id == Spearhead.DcsUtil.GroupCategory.STATIC then + if category_id == DcsUtil.GroupCategory.STATIC then isStatic = true local unit = group.units[1] if unit and unit.category == "Heliports" then @@ -75,7 +77,4 @@ function MizGroupsManager.getSpawnTemplateData(groupName) return MizGroupsManager._spawnTemplateData[groupName] end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end -Spearhead.classes.helpers.MizGroupsManager = MizGroupsManager +return MizGroupsManager diff --git a/classes/helpers/SpawnManager.lua b/src/classes/helpers/SpawnManager.lua similarity index 90% rename from classes/helpers/SpawnManager.lua rename to src/classes/helpers/SpawnManager.lua index 15bdf08..14f4686 100644 --- a/classes/helpers/SpawnManager.lua +++ b/src/classes/helpers/SpawnManager.lua @@ -1,3 +1,8 @@ +local MizGroupsManager = require("classes.helpers.MizGroupsManager") +local Persistence = require("classes.persistence.Persistence") +local SpearheadEvents = require("classes.spearhead_events") +local Util = require("classes.util.Util") + ---@class SpawnManager : OnUnitLostListener ---@field private _persistedUnits table ---@field private _logger Logger @@ -29,7 +34,7 @@ end ---@return boolean isStatic function SpawnManager:SpawnGroup(groupName, overrides, isGroupPersistant) - local spawnData = Spearhead.classes.helpers.MizGroupsManager.getSpawnTemplateData(groupName) + local spawnData = MizGroupsManager.getSpawnTemplateData(groupName) if spawnData == nil then env.error("SpawnManager:SpawnGroup - No spawn template found for group: " .. groupName) @@ -67,7 +72,7 @@ end ---@param groupName string ---@return boolean function SpawnManager:IsGroupStatic(groupName) - local isStatic = Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName) + local isStatic = MizGroupsManager.IsGroupStatic(groupName) if isStatic ~= nil then return isStatic end return StaticObject.getByName(groupName) ~= nil @@ -89,7 +94,7 @@ function SpawnManager:OnUnitLost(object) heading = heading end - Spearhead.classes.persistence.Persistence.UnitKilled( + Persistence.UnitKilled( name, object:getPoint(), heading, @@ -119,7 +124,7 @@ do --- privates country = override.countryID or spawnData.country end - local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate) + local spawnTemplate = Util.deepCopyTable(spawnData.groupTemplate) ---@type Array local removeableUnitNames = {} --[[ @@ -131,8 +136,8 @@ do --- privates for _, unit in pairs(spawnTemplate["units"]) do local name = unit["name"] - Spearhead.Events.addOnUnitLostEventListener(name, self) - local state = Spearhead.classes.persistence.Persistence.UnitState(name) + SpearheadEvents.addOnUnitLostEventListener(name, self) + local state = Persistence.UnitState(name) if state then if state.isDead == true then removeableUnitNames[#removeableUnitNames+1] = name @@ -170,7 +175,7 @@ do --- privates if isPersistent == true then self._persistedUnits[unit:getName()] = true end - Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self) + SpearheadEvents.addOnUnitLostEventListener(unit:getName(), self) end return group @@ -195,10 +200,10 @@ do --- privates country = overrides.countryID or spawnData.country end - local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate) + local spawnTemplate = Util.deepCopyTable(spawnData.groupTemplate) --for static Objecst groupNames and unit names are the same and is always 1:1 - local persistentState = Spearhead.classes.persistence.Persistence.UnitState(groupName) + local persistentState = Persistence.UnitState(groupName) if persistentState then if persistentState.isDead == true then spawnTemplate["dead"] = true @@ -226,7 +231,7 @@ do --- privates if isPersistent == true then self._persistedUnits[groupName] = true - Spearhead.Events.addOnUnitLostEventListener(groupName, self) + SpearheadEvents.addOnUnitLostEventListener(groupName, self) end return object @@ -238,7 +243,7 @@ do --- privates if not unit then return end - local deadState = Spearhead.classes.persistence.Persistence.UnitState(unit:getName()) + local deadState = Persistence.UnitState(unit:getName()) if deadState and deadState.isDead == true then unit:destroy() -- Destroy the unit if it is dead local staticObject = { @@ -255,10 +260,7 @@ do --- privates end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end -Spearhead.classes.helpers.SpawnManager = SpawnManager +return SpawnManager --Old Spawn Method diff --git a/classes/persistence/Persistence.lua b/src/classes/persistence/Persistence.lua similarity index 92% rename from classes/persistence/Persistence.lua rename to src/classes/persistence/Persistence.lua index 2c267a7..02e179e 100644 --- a/classes/persistence/Persistence.lua +++ b/src/classes/persistence/Persistence.lua @@ -1,4 +1,6 @@ +local Util = require("classes.util.Util") + ---@class Perstistence ---@field private _path string ---@field private _updateRequired boolean @@ -81,7 +83,7 @@ do if lua then tables = lua - logger:debug("Loaded persistence data: " .. Spearhead.Util.toString(lua)) + logger:debug("Loaded persistence data: " .. Util.toString(lua)) else logger:error("Could not load persistence file, using default tables") end @@ -143,8 +145,8 @@ do local latestFile, lastNumber = default, 0 for file in lfs.dir(dir) do - local split = Spearhead.Util.split_string(file, ".") - local doesStartWith = Spearhead.Util.startswith(file, startsWith, true) + local split = Util.split_string(file, ".") + local doesStartWith = Util.startswith(file, startsWith, true) if split and #split > 0 and split[#split] == EXTENSION and doesStartWith == true then local numberString = split[#split-1] local number = tonumber(numberString) @@ -179,7 +181,7 @@ do if SpearheadConfig.Persistence.fileName then local userFileName = SpearheadConfig.Persistence.fileName - local split = Spearhead.Util.split_string(userFileName, ".") + local split = Util.split_string(userFileName, ".") if not split and #split < 3 then split[#split+1] = "0" @@ -199,12 +201,12 @@ do end end - local split = Spearhead.Util.split_string(fileName, ".") - local matchingPart = table.concat(Spearhead.Util.sublist(split, 1, #split-2), ".") + local split = Util.split_string(fileName, ".") + local matchingPart = table.concat(Util.sublist(split, 1, #split-2), ".") local lastFile = getLastFileOrDefault(dir--[[@as string]], matchingPart, fileName) - local fileSplit = Spearhead.Util.split_string(lastFile, ".") + local fileSplit = Util.split_string(lastFile, ".") fileSplit[#fileSplit-1] = tostring(tonumber(fileSplit[#fileSplit-1]) + 1) fileName = table.concat(fileSplit, ".") @@ -329,7 +331,4 @@ do end end -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.persistence == nil then Spearhead.classes.persistence = {} end -Spearhead.classes.persistence.Persistence = Persistence \ No newline at end of file +return Persistence \ No newline at end of file diff --git a/classes/spearhead_db.lua b/src/classes/spearhead_db.lua similarity index 99% rename from classes/spearhead_db.lua rename to src/classes/spearhead_db.lua index d29b4a6..8e3e8df 100644 --- a/classes/spearhead_db.lua +++ b/src/classes/spearhead_db.lua @@ -1009,5 +1009,4 @@ function Database:GetNewMissionCode() ]] end -if not Spearhead then Spearhead = {} end -Spearhead.DB = Database +return Database diff --git a/classes/spearhead_events.lua b/src/classes/spearhead_events.lua similarity index 99% rename from classes/spearhead_events.lua rename to src/classes/spearhead_events.lua index 3efa807..2b2a09d 100644 --- a/classes/spearhead_events.lua +++ b/src/classes/spearhead_events.lua @@ -1,4 +1,4 @@ - +---@class SpearheadEvents local SpearheadEvents = {} do @@ -398,5 +398,4 @@ do world.addEventHandler(e) end -if Spearhead == nil then Spearhead = {} end -Spearhead.Events = SpearheadEvents \ No newline at end of file +return SpearheadEvents \ No newline at end of file diff --git a/classes/spearhead_routeutil.lua b/src/classes/spearhead_routeutil.lua similarity index 99% rename from classes/spearhead_routeutil.lua rename to src/classes/spearhead_routeutil.lua index 4d27da9..74cc5f5 100644 --- a/classes/spearhead_routeutil.lua +++ b/src/classes/spearhead_routeutil.lua @@ -1,3 +1,4 @@ +---@class SpearheadRouteUtil local ROUTE_UTIL = {} do --setup route util ---comment @@ -461,5 +462,4 @@ do --setup route util end end -if Spearhead == nil then Spearhead = {} end -Spearhead.RouteUtil = ROUTE_UTIL \ No newline at end of file +return ROUTE_UTIL \ No newline at end of file diff --git a/classes/stageClasses/GlobalStageManager.lua b/src/classes/stageClasses/GlobalStageManager.lua similarity index 98% rename from classes/stageClasses/GlobalStageManager.lua rename to src/classes/stageClasses/GlobalStageManager.lua index 54f9c80..d1f43f7 100644 --- a/classes/stageClasses/GlobalStageManager.lua +++ b/src/classes/stageClasses/GlobalStageManager.lua @@ -20,6 +20,8 @@ local currentStage = -99 local GlobalStageManager = {} GlobalStageManager.__index = GlobalStageManager +GlobalStageManager.getCurrentStage = function() return currentStage end + ---comment ---@param database Database ---@param stageConfig StageConfig @@ -45,6 +47,7 @@ function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnMa end } + Spearhead.Events.AddStageNumberChangedListener(OnStageNumberChangedListener) for _, stageName in pairs(database:getStagezoneNames()) do @@ -282,5 +285,4 @@ GlobalStageManager.isStageComplete = function (stageNumber) return true end -if not Spearhead.internal then Spearhead.internal = {} end -Spearhead.internal.GlobalStageManager = GlobalStageManager +return GlobalStageManager diff --git a/classes/stageClasses/Groups/SpearheadGroup.lua b/src/classes/stageClasses/Groups/SpearheadGroup.lua similarity index 92% rename from classes/stageClasses/Groups/SpearheadGroup.lua rename to src/classes/stageClasses/Groups/SpearheadGroup.lua index 52ba6fb..efccb30 100644 --- a/classes/stageClasses/Groups/SpearheadGroup.lua +++ b/src/classes/stageClasses/Groups/SpearheadGroup.lua @@ -1,5 +1,5 @@ - +local DcsUtil = require("classes.util.DcsUtil") ---@class SpearheadGroup : OnUnitLostListener ---@field private _groupName string @@ -149,7 +149,7 @@ end function SpearheadGroup:SetInvisible() if self._isStatic == true then - local country = Spearhead.DcsUtil.GetNeutralCountry() + local country = DcsUtil.GetNeutralCountry() ---@type SpawnOverrides local overrides = { @@ -187,7 +187,4 @@ function SpearheadGroup:SetVisible() end end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end -Spearhead.classes.stageClasses.Groups.SpearheadGroup = SpearheadGroup +return SpearheadGroup diff --git a/classes/stageClasses/Groups/SpearheadSceneryObject.lua b/src/classes/stageClasses/Groups/SpearheadSceneryObject.lua similarity index 73% rename from classes/stageClasses/Groups/SpearheadSceneryObject.lua rename to src/classes/stageClasses/Groups/SpearheadSceneryObject.lua index 6d26f56..873d674 100644 --- a/classes/stageClasses/Groups/SpearheadSceneryObject.lua +++ b/src/classes/stageClasses/Groups/SpearheadSceneryObject.lua @@ -1,3 +1,5 @@ +local Persistence = require("classes.persistence.Persistence") + ---@class SpearheadSceneryObject ---@field private persistentName string The persistent name of the scenery object ---@field private objectID number The ID of the scenery object @@ -47,7 +49,7 @@ end function SpearheadSceneryObject:MarkDead() if self.isDead == true then return end self.isDead = true - Spearhead.classes.persistence.Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery") + Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery") end function SpearheadSceneryObject:UpdateStatePersistently() @@ -55,7 +57,7 @@ function SpearheadSceneryObject:UpdateStatePersistently() return end - local state = Spearhead.classes.persistence.Persistence.UnitState(self.persistentName) + local state = Persistence.UnitState(self.persistentName) if state and state.isDead == true then trigger.action.explosion(self:GetPoint(), 1000) self.isDead = true @@ -71,7 +73,4 @@ function SpearheadSceneryObject:GetPoint() return Object.getPoint(self.internalObj) end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end -Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject = SpearheadSceneryObject +return SpearheadSceneryObject diff --git a/classes/stageClasses/SpecialZones/BlueSam.lua b/src/classes/stageClasses/SpecialZones/BlueSam.lua similarity index 92% rename from classes/stageClasses/SpecialZones/BlueSam.lua rename to src/classes/stageClasses/SpecialZones/BlueSam.lua index 970a5d1..61243d4 100644 --- a/classes/stageClasses/SpecialZones/BlueSam.lua +++ b/src/classes/stageClasses/SpecialZones/BlueSam.lua @@ -148,10 +148,4 @@ function BlueSam:OnBuildingComplete() self:SpawnGroups() end - - -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end -Spearhead.classes.stageClasses.SpecialZones.BlueSam = BlueSam +return BlueSam diff --git a/classes/stageClasses/SpecialZones/FarpZone.lua b/src/classes/stageClasses/SpecialZones/FarpZone.lua similarity index 90% rename from classes/stageClasses/SpecialZones/FarpZone.lua rename to src/classes/stageClasses/SpecialZones/FarpZone.lua index 5faf715..a871cbd 100644 --- a/classes/stageClasses/SpecialZones/FarpZone.lua +++ b/src/classes/stageClasses/SpecialZones/FarpZone.lua @@ -132,8 +132,4 @@ function FarpZone:SetPadsBlue() end end -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end -Spearhead.classes.stageClasses.SpecialZones.FarpZone = FarpZone +return FarpZone diff --git a/classes/stageClasses/SpecialZones/StageBase.lua b/src/classes/stageClasses/SpecialZones/StageBase.lua similarity index 94% rename from classes/stageClasses/SpecialZones/StageBase.lua rename to src/classes/stageClasses/SpecialZones/StageBase.lua index 476194f..c808d2d 100644 --- a/classes/stageClasses/SpecialZones/StageBase.lua +++ b/src/classes/stageClasses/SpecialZones/StageBase.lua @@ -187,10 +187,4 @@ function StageBase:OnBuildingComplete() self:FinaliseBlueStage() end - - -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end -Spearhead.classes.stageClasses.SpecialZones.StageBase = StageBase +return StageBase diff --git a/classes/stageClasses/SpecialZones/SupplyHub.lua b/src/classes/stageClasses/SpecialZones/SupplyHub.lua similarity index 86% rename from classes/stageClasses/SpecialZones/SupplyHub.lua rename to src/classes/stageClasses/SpecialZones/SupplyHub.lua index 8d578b7..3c5fb11 100644 --- a/classes/stageClasses/SpecialZones/SupplyHub.lua +++ b/src/classes/stageClasses/SpecialZones/SupplyHub.lua @@ -80,9 +80,4 @@ function SupplyHub:Activate() end - -if not Spearhead then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end -Spearhead.classes.stageClasses.SpecialZones.SupplyHub = SupplyHub \ No newline at end of file +return SupplyHub \ No newline at end of file diff --git a/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua similarity index 93% rename from classes/stageClasses/SpecialZones/abstract/BuildableZone.lua rename to src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua index 42e3749..9294973 100644 --- a/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua +++ b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua @@ -197,9 +197,4 @@ function BuildableZone:SpawnAmount(amount) return true end -if not Spearhead then Spearhead = {} end -Spearhead.classes = Spearhead.classes or {} -Spearhead.classes.stageClasses = Spearhead.classes.stageClasses or {} -Spearhead.classes.stageClasses.SpecialZones = Spearhead.classes.stageClasses.SpecialZones or {} -Spearhead.classes.stageClasses.SpecialZones.abstract = Spearhead.classes.stageClasses.SpecialZones.abstract or {} -Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone = BuildableZone \ No newline at end of file +return BuildableZone \ No newline at end of file diff --git a/classes/stageClasses/Stages/BaseStage/Stage.lua b/src/classes/stageClasses/Stages/BaseStage/Stage.lua similarity index 97% rename from classes/stageClasses/Stages/BaseStage/Stage.lua rename to src/classes/stageClasses/Stages/BaseStage/Stage.lua index fc63302..912727c 100644 --- a/classes/stageClasses/Stages/BaseStage/Stage.lua +++ b/src/classes/stageClasses/Stages/BaseStage/Stage.lua @@ -575,11 +575,7 @@ function Stage:ActivateBlueStage() timer.scheduleFunction(ActivateBlueAsync, self, timer.getTime() + 3) end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end -if not Spearhead.classes.stageClasses.Stages.BaseStage then Spearhead.classes.stageClasses.Stages.BaseStage = {} end -Spearhead.classes.stageClasses.Stages.BaseStage.Stage = Stage +return Stage diff --git a/classes/stageClasses/Stages/ExtraStage.lua b/src/classes/stageClasses/Stages/ExtraStage.lua similarity index 84% rename from classes/stageClasses/Stages/ExtraStage.lua rename to src/classes/stageClasses/Stages/ExtraStage.lua index 2d10263..240be3d 100644 --- a/classes/stageClasses/Stages/ExtraStage.lua +++ b/src/classes/stageClasses/Stages/ExtraStage.lua @@ -61,9 +61,6 @@ function ExtraStage:OnStageNumberChanged(number) end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end -Spearhead.classes.stageClasses.Stages.ExtraStage = ExtraStage +return ExtraStage diff --git a/classes/stageClasses/Stages/PrimaryStage.lua b/src/classes/stageClasses/Stages/PrimaryStage.lua similarity index 68% rename from classes/stageClasses/Stages/PrimaryStage.lua rename to src/classes/stageClasses/Stages/PrimaryStage.lua index a7560d7..d305377 100644 --- a/classes/stageClasses/Stages/PrimaryStage.lua +++ b/src/classes/stageClasses/Stages/PrimaryStage.lua @@ -22,9 +22,6 @@ function PrimaryStage.New(database, stageConfig, logger, initData, spawnManager) end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end -Spearhead.classes.stageClasses.Stages.PrimaryStage = PrimaryStage +return PrimaryStage diff --git a/classes/stageClasses/Stages/WaitingStage.lua b/src/classes/stageClasses/Stages/WaitingStage.lua similarity index 87% rename from classes/stageClasses/Stages/WaitingStage.lua rename to src/classes/stageClasses/Stages/WaitingStage.lua index adfa12c..8c3e073 100644 --- a/classes/stageClasses/Stages/WaitingStage.lua +++ b/src/classes/stageClasses/Stages/WaitingStage.lua @@ -69,9 +69,6 @@ function WaitingStage:GetExpectedTime() return self._startTime + self._waitTimeSeconds end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end -Spearhead.classes.stageClasses.Stages.WaitingStage = WaitingStage +return WaitingStage diff --git a/classes/stageClasses/drawings/CustomDrawing.lua b/src/classes/stageClasses/drawings/CustomDrawing.lua similarity index 58% rename from classes/stageClasses/drawings/CustomDrawing.lua rename to src/classes/stageClasses/drawings/CustomDrawing.lua index 4b97dda..fa97160 100644 --- a/classes/stageClasses/drawings/CustomDrawing.lua +++ b/src/classes/stageClasses/drawings/CustomDrawing.lua @@ -1,9 +1,10 @@ +local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper") +local Util = require("classes.util.Util") ---@class CustomDrawing ---@field private _id integer? ---@field private _drawingObject DrawingObject ----@field private _helper DrawingHelper ---@field private _startingStage number ---@field private _removeAtStage number local CustomDrawing = {} @@ -17,12 +18,11 @@ function CustomDrawing.New(drawingObject, id) local self = setmetatable({}, CustomDrawing) self._drawingObject = drawingObject self._id = id - self._helper = Spearhead.classes.stageClasses.drawings.helper.DrawingHelper local name = drawingObject.name - local split = Spearhead.Util.split_string(name or "", "_") + local split = Util.split_string(name or "", "_") local secondPart = split[2] or "1" - local splitPart = Spearhead.Util.split_string(secondPart, ":") + local splitPart = Util.split_string(secondPart, ":") self._startingStage = tonumber(splitPart[1]) or 1 self._removeAtStage = tonumber(splitPart[2]) or math.huge return self @@ -35,18 +35,14 @@ function CustomDrawing:GetStartAndStop() end function CustomDrawing:Draw() - self._id = self._helper.Draw(self._drawingObject) + self._id = DrawingHelper.Draw(self._drawingObject) end function CustomDrawing:Remove() if self._id ~= nil then - self._helper.Remove(self._id) + DrawingHelper.Remove(self._id) self._id = nil end end -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end -Spearhead.classes.stageClasses.drawings.CustomDrawing = CustomDrawing \ No newline at end of file +return CustomDrawing \ No newline at end of file diff --git a/classes/stageClasses/drawings/helper/DrawingHelper.lua b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua similarity index 93% rename from classes/stageClasses/drawings/helper/DrawingHelper.lua rename to src/classes/stageClasses/drawings/helper/DrawingHelper.lua index c05262d..99d6c93 100644 --- a/classes/stageClasses/drawings/helper/DrawingHelper.lua +++ b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua @@ -220,9 +220,4 @@ end ---@field public b number -if not Spearhead then Spearhead = {} end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end -if not Spearhead.classes.stageClasses.drawings.helper then Spearhead.classes.stageClasses.drawings.helper = {} end -Spearhead.classes.stageClasses.drawings.helper.DrawingHelper = DrawingHelper \ No newline at end of file +return DrawingHelper \ No newline at end of file diff --git a/classes/stageClasses/helpers/BattleManager.lua b/src/classes/stageClasses/helpers/BattleManager.lua similarity index 86% rename from classes/stageClasses/helpers/BattleManager.lua rename to src/classes/stageClasses/helpers/BattleManager.lua index 707c5ee..3dec4f3 100644 --- a/classes/stageClasses/helpers/BattleManager.lua +++ b/src/classes/stageClasses/helpers/BattleManager.lua @@ -1,3 +1,7 @@ +local Logger = require("classes.util.Logger") +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") + ---@class BattleManager ---@field private _name string ---@field private _logger Logger @@ -21,7 +25,7 @@ function BattleManager.New(redGroups, blueGroups, name, logLevel) self._isActive = false self._name = name - self._logger = Spearhead.LoggerTemplate.new("BattleManager_" .. name, logLevel) + self._logger = Logger.new("BattleManager_" .. name, logLevel) self._redGroups = redGroups self._blueGroups = blueGroups @@ -167,7 +171,7 @@ function BattleManager:getBestAmmo(unit) end end - local entry = Spearhead.Util.randomFromList(shells) + local entry = Util.randomFromList(shells) if entry and entry.desc and entry.desc.warhead then local caliber = entry.desc.warhead.caliber if caliber > 50 then @@ -213,10 +217,10 @@ function BattleManager:ToShootingHulls(groups) end end - local hulls = Spearhead.Util.getSeparatedConvexHulls(points, 50) + local hulls = Util.getSeparatedConvexHulls(points, 50) local enlargedHulls = {} for _, hull in pairs(hulls) do - local enlarged = Spearhead.Util.enlargeConvexHull(hull, 25) + local enlarged = Util.enlargeConvexHull(hull, 25) if enlarged then table.insert(enlargedHulls, enlarged) end @@ -237,15 +241,15 @@ end ---@return Vec2? function BattleManager:GetRandomPoint(origin, groupHulls) - local hull = Spearhead.Util.randomFromList(groupHulls) --[[@as Array]] + local hull = Util.randomFromList(groupHulls) --[[@as Array]] if not hull then return nil end - local shootPoints = Spearhead.Util.GetTangentHullPointsFromOrigin(hull, origin) + local shootPoints = Util.GetTangentHullPointsFromOrigin(hull, origin) if debugDrawing == true then self:DrawDebugZone({ hull }) end - return Spearhead.Util.randomFromList(shootPoints) --[[@as Vec2]] + return Util.randomFromList(shootPoints) --[[@as Vec2]] end do --DEBUG @@ -258,7 +262,7 @@ do --DEBUG color = {r = 0, g = 0, b = 1, a = 1} end - Spearhead.DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1) + DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1) end ---@param hulls Array> @@ -274,13 +278,9 @@ do --DEBUG location = { x=drawHull[1].x, y=drawHull[1].y }, } - Spearhead.DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1) + DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1) end end end --DEBUG -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end -Spearhead.classes.stageClasses.helpers.BattleManager = BattleManager +return BattleManager diff --git a/src/classes/stageClasses/helpers/MaxLoadConfig.lua b/src/classes/stageClasses/helpers/MaxLoadConfig.lua new file mode 100644 index 0000000..0d7f407 --- /dev/null +++ b/src/classes/stageClasses/helpers/MaxLoadConfig.lua @@ -0,0 +1,20 @@ +---@class MaxLoadConfig +---@field maxInternalLoad number + +---@type table +local MaxLoadConfig = { + ["Mi-8MT"] = { + maxInternalLoad = 4000, + }, + ["CH-47Fbl1"] = { + maxInternalLoad = 10000 + }, + ["Mi-24P"] = { + maxInternalLoad = 2000 + }, + ["UH-1H"] = { + maxInternalLoad = 2000 + } +} + +return MaxLoadConfig \ No newline at end of file diff --git a/classes/stageClasses/helpers/MissionCommandsHelper.lua b/src/classes/stageClasses/helpers/MissionCommandsHelper.lua similarity index 88% rename from classes/stageClasses/helpers/MissionCommandsHelper.lua rename to src/classes/stageClasses/helpers/MissionCommandsHelper.lua index 5c78a58..0b19dd3 100644 --- a/classes/stageClasses/helpers/MissionCommandsHelper.lua +++ b/src/classes/stageClasses/helpers/MissionCommandsHelper.lua @@ -1,3 +1,10 @@ +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") +local Logger = require("classes.util.Logger") +local SpearheadEvents = require("classes.spearhead_events") +local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker") +local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper") + ---@class MissionCommandsHelper ---@field missionsByCode table @table of missions by their code @@ -17,8 +24,8 @@ MissionCommandsHelper.__index = MissionCommandsHelper ---@param groupPos Vec2 local function sortMissions(list, groupPos) table.sort(list, function(a, b) - local distA = Spearhead.Util.VectorDistance2d(groupPos, a.location or {x=0, y=0}) - local distB = Spearhead.Util.VectorDistance2d(groupPos, b.location or {x=0, y=0}) + local distA = Util.VectorDistance2d(groupPos, a.location or {x=0, y=0}) + local distB = Util.VectorDistance2d(groupPos, b.location or {x=0, y=0}) return distA < distB; end) end @@ -33,7 +40,7 @@ function MissionCommandsHelper.getOrCreate(logLevel) if instance == nil then instance = setmetatable({}, MissionCommandsHelper) - instance._logger = Spearhead.LoggerTemplate.new("MissionCommandsHelper", logLevel) + instance._logger = Logger.new("MissionCommandsHelper", logLevel) instance._logger:info("Creating MissionCommandsHelper instance") @@ -45,7 +52,7 @@ function MissionCommandsHelper.getOrCreate(logLevel) instance._supplyHubGroups = {} instance._stageBriefings = {} - instance._supplyUnitsTracker = Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker.getOrCreate(logLevel) + instance._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logLevel) ---comment ---@param selfA MissionCommandsHelper @@ -56,7 +63,7 @@ function MissionCommandsHelper.getOrCreate(logLevel) return time + 10 end - for _, unit in pairs(Spearhead.DcsUtil.getAllPlayerUnits()) do + for _, unit in pairs(DcsUtil.getAllPlayerUnits()) do if unit and unit:isExist() then local group = unit:getGroup() if group then @@ -71,7 +78,7 @@ function MissionCommandsHelper.getOrCreate(logLevel) end timer.scheduleFunction(instance.updateContinuous, instance, timer.getTime() + 5) - Spearhead.Events.AddOnPlayerEnterUnitListener(instance) + SpearheadEvents.AddOnPlayerEnterUnitListener(instance) end @@ -174,7 +181,7 @@ function MissionCommandsHelper:AddOverviewCommand(groupID) local text = "Missions Overview\n\n" - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(id) + local group = DcsUtil.GetPlayerGroupByGroupID(id) ---@type Vec2 local groupPos = { x=0, y=0 } if group then @@ -193,7 +200,7 @@ function MissionCommandsHelper:AddOverviewCommand(groupID) if lead and lead:isExist() == true then local pos = lead:getPoint() local Vec2Pos = { x= pos.x, y=pos.z } - local distance = Spearhead.Util.VectorDistance2d(Vec2Pos, mission.location) / 1852 + local distance = Util.VectorDistance2d(Vec2Pos, mission.location) / 1852 distanceText = string.format("~%d", math.floor(distance)) end end @@ -323,7 +330,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID) local perFolder = 9 - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) ---@type Vec2 local groupPos = { x=0, y=0 } if group then @@ -351,7 +358,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID) for _, mission in pairs(primaryMissions) do count = count + 1 if count <= perFolder then - local copied = Spearhead.Util.deepCopyTable(path) + local copied = Util.deepCopyTable(path) self:addMissionCommands(groupID, copied, mission) else local name = "Next Menu ..." @@ -380,7 +387,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID) for _, mission in pairs(secondaryMissions) do count = count + 1 if count <= perFolder then - local copied = Spearhead.Util.deepCopyTable(path) + local copied = Util.deepCopyTable(path) self:addMissionCommands(groupID, copied, mission) else local name = "Next Menu ..." @@ -401,14 +408,14 @@ function MissionCommandsHelper:addMissionCommands(groupId, path, mission) if path then - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId) + local group = DcsUtil.GetPlayerGroupByGroupID(groupId) local distance = "[?]" if group then local lead = group:getUnit(1) if lead and lead:isExist() == true then local pos = lead:getPoint() local Vec2Pos = { x= pos.x, y=pos.z } - local dist = Spearhead.Util.VectorDistance2d(Vec2Pos, mission.location) / 1852 + local dist = Util.VectorDistance2d(Vec2Pos, mission.location) / 1852 distance = "[" .. string.format("~%dnM", math.floor(dist)) .. "]" end end @@ -435,7 +442,7 @@ function MissionCommandsHelper:AddSupplyHubCommandsIfApplicable(groupID) self._logger:debug("Adding supply hub commands for group: " .. tostring(groupID)) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) if group == nil then return end local unit = group:getUnit(1) @@ -482,7 +489,7 @@ end function MissionCommandsHelper:AddCargoCommands(groupID) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) if group == nil then return end local unit = group:getUnit(1) @@ -504,7 +511,7 @@ function MissionCommandsHelper:AddCargoCommands(groupID) local cargo = self._supplyUnitsTracker:GetCargoInUnit(unit:getID()) if cargo then for cargoType, amount in pairs(cargo) do - local cargoConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(cargoType) + local cargoConfig = SupplyConfigHelper.getSupplyConfig(cargoType) if cargoConfig then for i = 1, amount do local path = { [1] = folderNames.cargo } @@ -531,7 +538,7 @@ function MissionCommandsHelper:addMissionFolders(groupId) missionCommands.addSubMenuForGroup(groupId, folderNames.supplyHub) end - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId) + local group = DcsUtil.GetPlayerGroupByGroupID(groupId) if group == nil then return end local unit = group:getUnit(1) @@ -561,8 +568,4 @@ function MissionCommandsHelper:ResetFolders(groupID) self:addMissionFolders(groupID) end -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end -Spearhead.classes.stageClasses.helpers.MissionCommandsHelper = MissionCommandsHelper +return MissionCommandsHelper diff --git a/classes/stageClasses/helpers/SupplyConfig.lua b/src/classes/stageClasses/helpers/SupplyConfigHelper.lua similarity index 67% rename from classes/stageClasses/helpers/SupplyConfig.lua rename to src/classes/stageClasses/helpers/SupplyConfigHelper.lua index baccfac..885bd87 100644 --- a/classes/stageClasses/helpers/SupplyConfig.lua +++ b/src/classes/stageClasses/helpers/SupplyConfigHelper.lua @@ -1,4 +1,6 @@ +local Util = require("classes.util.Util") + ---@alias SupplyType ---| "FARP_CRATE" ---| "SAM_CRATE" @@ -65,24 +67,6 @@ local SupplyConfig = { }, } ----@class MaxLoadConfig ----@field maxInternalLoad number - ----@type table -MaxLoadConfig = { - ["Mi-8MT"] = { - maxInternalLoad = 4000, - }, - ["CH-47Fbl1"] = { - maxInternalLoad = 10000 - }, - ["Mi-24P"] = { - maxInternalLoad = 2000 - }, - ["UH-1H"] = { - maxInternalLoad = 2000 - } -} ---@class SupplyConfigHelper local SupplyConfigHelper = {} @@ -92,7 +76,7 @@ local SupplyConfigHelper = {} ---@return SupplyConfig? function SupplyConfigHelper.fromObjectName(name) for configName, config in pairs(SupplyConfig) do - if Spearhead.Util.startswith(name, configName, true) == true then + if Util.startswith(name, configName, true) == true then return config end end @@ -104,11 +88,6 @@ function SupplyConfigHelper.getSupplyConfig(type) return SupplyConfig[type] end -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end -if Spearhead.classes.stageClasses.helpers.supplies == nil then Spearhead.classes.stageClasses.helpers.supplies = {} end -Spearhead.classes.stageClasses.helpers.supplies.MaxLoadConfig = MaxLoadConfig -Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper = SupplyConfigHelper + +return SupplyConfigHelper diff --git a/classes/stageClasses/helpers/SupplyUnitsTracker.lua b/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua similarity index 87% rename from classes/stageClasses/helpers/SupplyUnitsTracker.lua rename to src/classes/stageClasses/helpers/SupplyUnitsTracker.lua index 72c7797..cc033bb 100644 --- a/classes/stageClasses/helpers/SupplyUnitsTracker.lua +++ b/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua @@ -1,4 +1,12 @@ +local Logger = require("classes.util.Logger") +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") +local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper") +local SpearheadEvents = require("classes.spearhead_events") +local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper") +local MaxLoadConfig = require("classes.stageClasses.helpers.MaxLoadConfig") + env.info("Spearhead SupplyUnitsTracker loaded") ---@class SupplyUnitsTracker @@ -23,7 +31,7 @@ function SupplyUnitsTracker.getOrCreate(logLevel) if singleton == nil then singleton = setmetatable({}, SupplyUnitsTracker) - singleton._logger = Spearhead.LoggerTemplate.new("SupplyUnitsTracker", logLevel) + singleton._logger = Logger.new("SupplyUnitsTracker", logLevel) singleton._unitPositions = {} singleton._cargoInUnits = {} singleton._supplyUnitsByName = {} @@ -31,9 +39,9 @@ function SupplyUnitsTracker.getOrCreate(logLevel) singleton._registeredHubs = {} singleton._supplyUnitSpawnedListener = {} - singleton._commandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(singleton._logger.LogLevel) + singleton._commandsHelper = MissionCommandsHelper.getOrCreate(singleton._logger.LogLevel) - Spearhead.Events.AddOnPlayerEnterUnitListener(singleton) + SpearheadEvents.AddOnPlayerEnterUnitListener(singleton) ---@param selfA SupplyUnitsTracker local function updateTask(selfA, time) @@ -96,7 +104,7 @@ function SupplyUnitsTracker:AddOnSupplyUnitSpawnedListener(listener) end function SupplyUnitsTracker:Update() - local players = Spearhead.DcsUtil.getAllPlayerUnits() + local players = DcsUtil.getAllPlayerUnits() for _, player in pairs(players) do if player ~= nil and player:isExist() and self:IsSupplyUnit(player) == true then self._supplyUnitsByName[player:getName()] = player @@ -127,7 +135,7 @@ function SupplyUnitsTracker:AddCargoToUnit(unitID, crateType) if unitID == nil or crateType == nil then return end - local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID) + local unit = DcsUtil.GetPlayerUnitByID(unitID) if unit == nil then return end if self._cargoInUnits[unitID] == nil then @@ -174,7 +182,7 @@ function SupplyUnitsTracker:UpdateWeightForUnit(unit) local weight = 0 if self._cargoInUnits[tostring(unit:getID())] then for crateType, count in pairs(self._cargoInUnits[tostring(unit:getID())]) do - local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType) + local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType) if crateConfig and count then weight = weight + (crateConfig.weight * count) end @@ -197,7 +205,7 @@ function SupplyUnitsTracker:CheckUnitsInZones() if enabled == true then local zone = hub:GetZone() if zone ~= nil then - if Spearhead.Util.is3dPointInZone(pos, zone) then + if Util.is3dPointInZone(pos, zone) then self._commandsHelper:MarkUnitInSupplyHub(group:getID()) else self._commandsHelper:MarkUnitOutsideSupplyHub(group:getID()) @@ -241,7 +249,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType) self._logger:debug("Unload requested for unit: " .. unitID .. " crateType: " .. crateType) - local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID) + local unit = DcsUtil.GetPlayerUnitByID(unitID) if unit == nil or unit:isExist() == false then return end local group = unit:getGroup() if group == nil then @@ -251,7 +259,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType) self:RemoveCargoFromUnit(unitID, crateType) self:UpdateWeightForUnit(unit) - local cargoConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType) + local cargoConfig = SupplyConfigHelper.getSupplyConfig(crateType) if cargoConfig == nil then self._logger:error("Invalid crate type: " .. crateType) @@ -285,10 +293,10 @@ function SupplyUnitsTracker:UnitRequestCrateLoading(groupID, crateType) self._logger:debug("UnitRequestCrateLoading called with groupID: " .. groupID .. " and crateType: " .. crateType) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) if group ~= nil then - local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType) + local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType) if crateConfig == nil then self._logger:error("Invalid crate type: " .. crateType) return @@ -341,7 +349,7 @@ end ---@return boolean function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType) - local crateConfigA = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType) + local crateConfigA = SupplyConfigHelper.getSupplyConfig(crateType) if crateConfigA == nil then trigger.action.outTextForUnit(unit:getID(), "Invalid crate type: " .. crateType, 5) return false @@ -354,7 +362,7 @@ function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType) end end - local unitConfig = Spearhead.classes.stageClasses.helpers.supplies.MaxLoadConfig[unit:getTypeName()] + local unitConfig = MaxLoadConfig[unit:getTypeName()] if unitConfig == nil then trigger.action.outTextForUnit(unit:getID(), "Your unit type is not configured for logistics: " .. crateType, 5) self._logger:error("Invalid unit type: " .. unit:getTypeName()) @@ -383,10 +391,10 @@ end ---@param crateType CrateType function SupplyUnitsTracker:UnitRequestCrateSpawn(groupID, crateType) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) if group == nil then - local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType) + local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType) if crateConfig == nil then self._logger:error("Invalid crate type: " .. crateType) return @@ -446,9 +454,4 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit) end - -if Spearhead == nil then Spearhead = {} end -if Spearhead.classes == nil then Spearhead.classes = {} end -if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end -if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end -Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker = SupplyUnitsTracker \ No newline at end of file +return SupplyUnitsTracker \ No newline at end of file diff --git a/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua similarity index 78% rename from classes/stageClasses/missions/BuildableMission.lua rename to src/classes/stageClasses/missions/BuildableMission.lua index 745d855..cf42f58 100644 --- a/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -1,4 +1,10 @@ - +local Mission = require("classes.stageClasses.missions.baseMissions.Mission") +local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") +local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker") +local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper") +local GlobalConfig = require("classes.configuration.GlobalConfig") +local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper") ---@class BuildableMission : Mission, SupplyUnitSpawnedListener ---@field private _requiredKilos number @@ -27,7 +33,6 @@ BuildableMission.__index = BuildableMission ---@param logger Logger function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType) - local Mission = Spearhead.classes.stageClasses.missions.baseMissions.Mission setmetatable(BuildableMission, Mission) local self = setmetatable({}, { __index = BuildableMission }) @@ -42,7 +47,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi if noLandingZone then local verts = noLandingZone.verts - local enlarged = Spearhead.Util.enlargeConvexHull(verts, 300) + local enlarged = Util.enlargeConvexHull(verts, 300) ---@type SpearheadTriggerZone local dropOfZone = { @@ -71,7 +76,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self._onCrateDroppedOfListeners = {} self._completeListeners = {} self._markIDsPerGroup = {} - self._supplyUnitsTracker = Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker.getOrCreate(logger.LogLevel) + self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logger.LogLevel) self._state = "NEW" @@ -82,7 +87,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self.priority = "secondary" - self._missionCommandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(self._logger.LogLevel) + self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(self._logger.LogLevel) self._crateType = requiredCrateType @@ -96,11 +101,11 @@ end function BuildableMission:ShowBriefing(groupID) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID) + local group = DcsUtil.GetPlayerGroupByGroupID(groupID) if group == nil then return end - local unitType = Spearhead.DcsUtil.getUnitTypeFromGroup(group) - local coords = Spearhead.DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) + local unitType = DcsUtil.getUnitTypeFromGroup(group) + local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) local siteType = "FARP" if self._crateType == "SAM_CRATE" then @@ -119,18 +124,18 @@ function BuildableMission:ShowBriefing(groupID) "\n\n" .. "NOTE: Do not land in the orange construction zone!" - trigger.action.outTextForGroup(groupID, briefing, Spearhead.GlobalConfig:getBriefingTime()) + trigger.action.outTextForGroup(groupID, briefing, GlobalConfig:getBriefingTime()) end function BuildableMission:MarkMissionAreaToGroup(groupID) if self._markIDsPerGroup[groupID] then - Spearhead.DcsUtil.RemoveMark(self._markIDsPerGroup[groupID]) + DcsUtil.RemoveMark(self._markIDsPerGroup[groupID]) end local text = "[" .. self.code .. "] " .. self.name .. " | " .. self._crateType local location = { x= self.location.x, y=land.getHeight(self.location), z=self.location.y } - local markID = Spearhead.DcsUtil.AddMarkToGroup(groupID, text, location) + local markID = DcsUtil.AddMarkToGroup(groupID, text, location) self._markIDsPerGroup[groupID] = markID end @@ -163,7 +168,7 @@ function BuildableMission:SpawnActive() local lineColor = { r=230/255, g=93/255, b=49/255, a=1} ---@type DrawColor local fillColor = { r=230/255, g=93/255, b=49/255, a=0.2} - self._noLandingZoneId = Spearhead.DcsUtil.DrawZone(self._noLandingZone, lineColor, fillColor, 6) + self._noLandingZoneId = DcsUtil.DrawZone(self._noLandingZone, lineColor, fillColor, 6) if self._dropOffZone == nil then self._logger:error("No drop off zone found for mission: " .. self.code) @@ -172,7 +177,7 @@ function BuildableMission:SpawnActive() local lineColor2 = { r=0, g=0, b=1, a=1} local fillColor2 = { r=0, g=0, b=1, a=0} - self._dropOffZoneId = Spearhead.DcsUtil.DrawZone(self._dropOffZone, lineColor2, fillColor2, 6) + self._dropOffZoneId = DcsUtil.DrawZone(self._dropOffZone, lineColor2, fillColor2, 6) ---@param selfA BuildableMission ---@param time number @@ -230,17 +235,17 @@ function BuildableMission:CheckCratesInZone() local crates = self._supplyUnitsTracker:GetCargoCratesDropped() for _, staticObject in pairs(crates) do - if staticObject and staticObject:isExist() and Spearhead.Util.startswith(staticObject:getName(), self._crateType, true) then + if staticObject and staticObject:isExist() and Util.startswith(staticObject:getName(), self._crateType, true) then local pos = staticObject:getPoint() - if Spearhead.Util.is3dPointInZone(pos, self._dropOffZone) then + if Util.is3dPointInZone(pos, self._dropOffZone) then table.insert(foundCrates, staticObject) end end end for _, foundCrate in pairs(foundCrates) do - local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.fromObjectName(foundCrate:getName()) + local crateConfig = SupplyConfigHelper.fromObjectName(foundCrate:getName()) if crateConfig then self._droppedKilos = self._droppedKilos + crateConfig.weight foundCrate:destroy() @@ -249,8 +254,8 @@ function BuildableMission:CheckCratesInZone() end if self._droppedKilos >= self._requiredKilos then - Spearhead.DcsUtil.RemoveMark(self._noLandingZoneId) - Spearhead.DcsUtil.RemoveMark(self._dropOffZoneId) + DcsUtil.RemoveMark(self._noLandingZoneId) + DcsUtil.RemoveMark(self._dropOffZoneId) self:NotifyMissionComplete() self._state = "COMPLETED" end @@ -258,7 +263,7 @@ function BuildableMission:CheckCratesInZone() if self._state == "COMPLETED" then for groupID, markID in pairs(self._markIDsPerGroup) do if markID then - Spearhead.DcsUtil.RemoveMark(markID) + DcsUtil.RemoveMark(markID) self._markIDsPerGroup[groupID] = nil end end @@ -267,7 +272,4 @@ function BuildableMission:CheckCratesInZone() end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end -Spearhead.classes.stageClasses.missions.BuildableMission = BuildableMission \ No newline at end of file +return BuildableMission \ No newline at end of file diff --git a/classes/stageClasses/missions/RunwayStrikeMission.lua b/src/classes/stageClasses/missions/RunwayStrikeMission.lua similarity index 97% rename from classes/stageClasses/missions/RunwayStrikeMission.lua rename to src/classes/stageClasses/missions/RunwayStrikeMission.lua index a07155e..a130e33 100644 --- a/classes/stageClasses/missions/RunwayStrikeMission.lua +++ b/src/classes/stageClasses/missions/RunwayStrikeMission.lua @@ -537,9 +537,4 @@ function RunwayStrikeMission:RunwayToSpearheadZone(runway) } end - - -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end -Spearhead.classes.stageClasses.missions.RunwayStrikeMission = RunwayStrikeMission \ No newline at end of file +return RunwayStrikeMission \ No newline at end of file diff --git a/classes/stageClasses/missions/ZoneMission.lua b/src/classes/stageClasses/missions/ZoneMission.lua similarity index 98% rename from classes/stageClasses/missions/ZoneMission.lua rename to src/classes/stageClasses/missions/ZoneMission.lua index 1f20207..49609f7 100644 --- a/classes/stageClasses/missions/ZoneMission.lua +++ b/src/classes/stageClasses/missions/ZoneMission.lua @@ -517,7 +517,4 @@ function ZoneMission:MarkLastContact(unit) self._lastContactMarkerID = Spearhead.DcsUtil.AddMarkToAll("Last Contact: " .. self.name .. " [" .. self.code .. "]", point) end -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end -Spearhead.classes.stageClasses.missions.ZoneMission = ZoneMission +return ZoneMission diff --git a/classes/stageClasses/missions/baseMissions/Mission.lua b/src/classes/stageClasses/missions/baseMissions/Mission.lua similarity index 78% rename from classes/stageClasses/missions/baseMissions/Mission.lua rename to src/classes/stageClasses/missions/baseMissions/Mission.lua index 0acaac9..22e183c 100644 --- a/classes/stageClasses/missions/baseMissions/Mission.lua +++ b/src/classes/stageClasses/missions/baseMissions/Mission.lua @@ -1,5 +1,8 @@ - +local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper") +local DcsUtil = require("classes.util.DcsUtil") +local Util = require("classes.util.Util") +local GlobalConfig = require("classes.configuration.GlobalConfig") ---@class Mission ---@field name string @@ -49,7 +52,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief self.location = database:GetLocationForMissionZone(zoneName) self.missionTypeDisplay = self.missionType - self._missionCommandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(logger.LogLevel) + self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(logger.LogLevel) return true, "success" end @@ -77,11 +80,11 @@ end ---@param groupId number function Mission:ShowBriefing(groupId) - local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId) + local group = DcsUtil.GetPlayerGroupByGroupID(groupId) if group == nil then return end - local unitType = Spearhead.DcsUtil.getUnitTypeFromGroup(group) - local coords = Spearhead.DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) + local unitType = DcsUtil.getUnitTypeFromGroup(group) + local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) self._logger:debug("Coords converted: " .. coords) local stateString = self:ToStateString() @@ -89,12 +92,12 @@ function Mission:ShowBriefing(groupId) local briefing = self._missionBriefing - briefing = Spearhead.Util.replaceString(briefing, "{{coords}}", coords) - briefing = Spearhead.Util.replaceString(briefing, "{{ coords }}", coords) + briefing = Util.replaceString(briefing, "{{coords}}", coords) + briefing = Util.replaceString(briefing, "{{ coords }}", coords) local text = "Mission [" .. self.code .. "] " .. self.name .. "\n \n" .. briefing .. " \n \n" .. stateString - trigger.action.outTextForGroup(groupId, text, Spearhead.GlobalConfig:getBriefingTime()); + trigger.action.outTextForGroup(groupId, text, GlobalConfig:getBriefingTime()); end @@ -135,14 +138,6 @@ function Mission:ToStateString() return "status: in progress" end --endregion - - -if not Spearhead.classes then Spearhead.classes = {} end -if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end -if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end -if not Spearhead.classes.stageClasses.missions.baseMissions then Spearhead.classes.stageClasses.missions.baseMissions = {} end -Spearhead.classes.stageClasses.missions.baseMissions.Mission = Mission - do --aliases --- @alias MissionPriority @@ -168,4 +163,4 @@ do --aliases end - +return Mission \ No newline at end of file diff --git a/classes/spearhead_base.lua b/src/classes/util/DcsUtil.lua similarity index 57% rename from classes/spearhead_base.lua rename to src/classes/util/DcsUtil.lua index 311b0b0..0366be0 100644 --- a/classes/spearhead_base.lua +++ b/src/classes/util/DcsUtil.lua @@ -1,1443 +1,846 @@ ---- DEFAULT Values -if Spearhead == nil then Spearhead = {} end - -local UTIL = {} -do -- INIT UTIL - ---splits a string in sub parts by seperator - ---@param input string - ---@param seperator string - ---@return table result list of strings - function UTIL.split_string(input, seperator) - if seperator == nil then - seperator = " " - end - - local result = {} - if input == nil then - return result - end - - for str in string.gmatch(input, "[^" .. seperator .. "]+") do - table.insert(result, str) - end - return result - end - - ---comment - ---@param table any - ---@return number - function UTIL.tableLength(table) - if table == nil then return 0 end - - local count = 0 - for _ in pairs(table) do count = count + 1 end - return count - end - - ---@param orig table - ---@return table copy - function UTIL.deepCopyTable(orig) - local orig_type = type(orig) - local copy - if orig_type == 'table' then - copy = {} - for orig_key, orig_value in next, orig, nil do - copy[UTIL.deepCopyTable(orig_key)] = UTIL.deepCopyTable(orig_value) - end - setmetatable(copy, UTIL.deepCopyTable(getmetatable(orig))) - else -- number, string, boolean, etc - copy = orig - end - return copy - end - - ---Gets a random from the list - ---@param list Array - ---@return any @random element from the list - function UTIL.randomFromList(list) - local max = #list - - if max == 0 or max == nil then - return nil - end - - local random = math.random(0, max) - if random == 0 then random = 1 end - - return list[random] - end - - ---@param list Array - ---@param start number start - ---@param n number length - ---@return Array - function UTIL.sublist(list, start, n) - local result = {} - for i = start, n do - result[#result + 1] = list[i] - end - return result - end - - ---@param str string - ---@param find string - ---@param replace string - ---@return string - function UTIL.replaceString(str, find, replace) - if str == nil then return "" end - if find == nil or replace == nil then return str end - - local result = str:gsub(find, replace) - return result - end - - local function table_print(tt, indent, done) - done = done or {} - indent = indent or 0 - if type(tt) == "table" then - local sb = {} - for key, value in pairs(tt) do - table.insert(sb, string.rep(" ", indent)) -- indent it - if type(value) == "table" and not done[value] then - done[value] = true - table.insert(sb, "[\"" ..key .. "\"]" .. " = {\n"); - table.insert(sb, table_print(value, indent + 2, done)) - table.insert(sb, string.rep(" ", indent)) -- indent it - table.insert(sb, "},\n"); - elseif "number" == type(key) then - table.insert(sb, string.format("\"%s\",\n", tostring(value))) - else - table.insert(sb, string.format( - "[\"%s\"] = \"%s\",\n", tostring(key), tostring(value))) - end - end - return table.concat(sb) - else - return tt .. "\n" - end - end - - ---comment - ---@param str string - ---@param findable string - ---@param ignoreCase boolean? - ---@return boolean - UTIL.startswith = function(str, findable, ignoreCase) - if ignoreCase == true then - return string.lower(str):find('^' .. string.lower(findable)) ~= nil - end - - return str:find('^' .. findable) ~= nil - end - - ---comment - ---@param str string - ---@param findable string - ---@return boolean - UTIL.strContains = function(str, findable) - return str:find(findable) ~= nil - end - - ---comment - ---@param str string - ---@param findableTable table - ---@return boolean - UTIL.startswithAny = function(str, findableTable) - for key, value in pairs(findableTable) do - if type(value) == "string" and UTIL.startswith(str, value) then return true end - end - return false - end - - function UTIL.toString(something) - if something == nil then - return "nil" - elseif "table" == type(something) then - return table_print(something) - elseif "string" == type(something) then - return something - else - return tostring(something) - end - end - - ---comment - ---@param a Vec2 - ---@param b Vec2 - ---@return number - function UTIL.VectorDistance2d(a, b) - return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2) - end - - ---comment - ---@param a Vec3 - ---@param b Vec3 - ---@return number - function UTIL.VectorDistance3d(a, b) - return UTIL.vectorMagnitude({ x = a.x - b.x, y = a.y - b.y, z = a.z - b.z }) - end - - ---comment - ---@param vec Vec3 - ---@return number - function UTIL.vectorMagnitude(vec) - return (vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2) ^ 0.5 - end - - ---@param vec Vec3 - ---@return Vec3 - function UTIL.vectorNormalize(vec) - local magnitude = UTIL.vectorMagnitude(vec) - if magnitude == 0 then - return { x = 0, y = 0, z = 0 } - end - return { x = vec.x / magnitude, y = vec.y / magnitude, z = vec.z / magnitude } - end - - ---@param vec Vec2 - ---@param direction number @in degrees - ---@param distance number - ---@return Vec2 - function UTIL.vectorMove(vec, direction, distance) - local rad = math.rad(direction) - local x = vec.x + (math.cos(rad) * distance) - local y = vec.y + (math.sin(rad) * distance) - - return { x = x, y = y} - end - - ---comment - ---@param vec1 Vec2 - ---@param vec2 Vec2 - ---@return number in degrees - function UTIL.vectorHeadingFromTo(vec1, vec2) - local dx = vec2.x - vec1.x - local dy = vec2.y - vec1.y - local heading = math.deg(math.atan2(dy, dx)) - if heading < 0 then - heading = heading + 360 - end - return heading - end - - - - ---@param vec1 Vec3 - ---@param vec2 Vec3 - ---@return number alignment a number in range [-1,1]. > 0 same direction. < 0 opposite direction - function UTIL.vectorAlignment(vec1, vec2) - local vec1Norm = UTIL.vectorNormalize(vec1) - local vec2Norm = UTIL.vectorNormalize(vec2) - - return ((vec1Norm.x * vec2Norm.x) + (vec1Norm.y * vec2Norm.y) + (vec1Norm.z * vec2Norm.z)) - end - - local function isInComplexPolygon(polygon, x, y) - local function getEdges(poly) - local result = {} - for i = 1, #poly do - local point1 = poly[i] - local point2Index = i + 1 - if point2Index > #poly then point2Index = 1 end - local point2 = poly[point2Index] - local edge = { x1 = point1.x, z1 = point1.y, x2 = point2.x, z2 = point2.y } - table.insert(result, edge) - end - return result - end - - local edges = getEdges(polygon) - local count = 0; - for _, edge in pairs(edges) do - if (x < edge.x1) ~= (x < edge.x2) and y < edge.z1 + ((x - edge.x1) / (edge.x2 - edge.x1)) * (edge.z2 - edge.z1) then - count = count + 1 - -- if (yp < y1) != (yp < y2) and xp < x1 + ((yp-y1)/(y2-y1))*(x2-x1) then - -- count = count + 1 - end - end - return count % 2 == 1 - end - - ---comment - ---@param polygon Array of pairs { x, y } - ---@param x number X location - ---@param y number Y location - ---@return boolean - function UTIL.IsPointInPolygon(polygon, x, y) - return isInComplexPolygon(polygon, x, y) - end - - ---@param point Vec3 - ---@param zone SpearheadTriggerZone - function UTIL.is3dPointInZone(point, zone) - if zone.zone_type == "Polygon" and zone.verts then - if UTIL.IsPointInPolygon(zone.verts, point.x, point.z) == true then - return true - end - else - if (((point.x - zone.location.x) ^ 2 + (point.z - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then - return true - end - end - - return false - end - - ---@param point Vec2 - ---@param zone SpearheadTriggerZone - function UTIL.is2dPointInZone(point, zone) - if zone.zone_type == "Polygon" and zone.verts then - if UTIL.IsPointInPolygon(zone.verts, point.x, point.y) == true then - return true - end - else - if (((point.x - zone.location.x) ^ 2 + (point.y - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then - return true - end - end - - return false - end - - ---comment - ---@param points Array points - ---@return Array hullPoints - function UTIL.getConvexHull(points) - if #points == 0 then - return {} - end - - ---comment - ---@param a Vec2 - ---@param b Vec2 - ---@param c Vec2 - ---@return boolean - local function ccw(a, b, c) - return (b.y - a.y) * (c.x - a.x) > (b.x - a.x) * (c.y - a.y) - end - - table.sort(points, function(left, right) - return left.y < right.y - end) - - local hull = {} - -- lower hull - for _, point in pairs(points) do - while #hull >= 2 and not ccw(hull[#hull - 1], hull[#hull], point) do - table.remove(hull, #hull) - end - table.insert(hull, point) - end - - -- upper hull - local t = #hull + 1 - for i = #points, 1, -1 do - local point = points[i] - while #hull >= t and not ccw(hull[#hull - 1], hull[#hull], point) do - table.remove(hull, #hull) - end - table.insert(hull, point) - end - table.remove(hull, #hull) - return hull - end - - ---Splits points into clusters with at least minSeparation between clusters, returns convex hull for each cluster - ---@param points Array - ---@param minSeparation number - ---@return Array> hulls - function UTIL.getSeparatedConvexHulls(points, minSeparation) - if #points == 0 then return {} end - - -- Simple clustering: group points that are within minSeparation of each other - local clusters = {} - local assigned = {} - - for i, p in ipairs(points) do - if not assigned[i] then - local cluster = { p } - assigned[i] = true - -- Find all points close to p (BFS) - local queue = { i } - while #queue > 0 do - local idx = table.remove(queue) - local base = points[idx] - for j, q in ipairs(points) do - if not assigned[j] then - local dx = base.x - q.x - local dy = base.y - q.y - if (dx * dx + dy * dy) <= (minSeparation * minSeparation) then - table.insert(cluster, q) - assigned[j] = true - table.insert(queue, j) - end - end - end - end - table.insert(clusters, cluster) - end - end - - -- Compute convex hull for each cluster - local hulls = {} - for _, cluster in ipairs(clusters) do - local hull = UTIL.getConvexHull(cluster) - if #hull > 0 then - table.insert(hulls, hull) - end - end - - return hulls - end - - ---@param points Array - function UTIL.enlargeConvexHull(points, meters) - if points == nil or #points == 0 then - return {} - end - - ---@type Array - local allpoints = {} - - for _, point in pairs(points) do - table.insert(allpoints, point) - - allpoints[#allpoints + 1] = point - allpoints[#allpoints+1] = { x = point.x + meters, y = point.y, } - allpoints[#allpoints+1] = { x = point.x - meters, y = point.y, } - allpoints[#allpoints+1] = { x = point.x, y = point.y + meters, } - allpoints[#allpoints+1] = { x = point.x, y = point.y - meters, } - - allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, } - allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, } - allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, } - allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, } - end - - return UTIL.getConvexHull(allpoints) - end - - ---Returns hull points visible from origin (not blocked by hull edges) ----@param hull Array ----@param origin Vec2 ----@return Array -function UTIL.GetVisibleHullPointsFromOrigin(hull, origin) - local function segmentsIntersect(a, b, c, d) - -- Helper: returns true if segment ab intersects cd (excluding endpoints) - local function ccw(p1, p2, p3) - return (p3.y - p1.y) * (p2.x - p1.x) > (p2.y - p1.y) * (p3.x - p1.x) - end - return (ccw(a, c, d) ~= ccw(b, c, d)) and (ccw(a, b, c) ~= ccw(a, b, d)) - end - - local n = #hull - local visible = {} - - for i = 1, n do - local p = hull[i] - local isVisible = true - - -- Check against all hull edges except those incident to p - for j = 1, n do - local a = hull[j] - local b = hull[(j % n) + 1] - -- skip edges incident to p - if (a ~= p and b ~= p) then - if segmentsIntersect(origin, p, a, b) then - isVisible = false - break - end - end - end - - if isVisible then - table.insert(visible, p) - end - end - - return visible -end - ----Returns the two tangent points ("scratch points") from origin to the convex hull ----@param hull Array ----@param origin Vec2 ----@return Array -function UTIL.GetTangentHullPointsFromOrigin(hull, origin) - - if hull == nil or #hull <= 0 then - return {} - end - - local function orientation(a, b, c) - -- Returns >0 if c is to the left of ab, <0 if to the right, 0 if colinear - return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) - end - - local n = #hull - if n == 0 then return {} end - if n == 1 then return { hull[1] } end - - -- Find left tangent: the hull point where all other points are to the right of the line from origin to that point - local function findTangent(isLeft) - local best = 1 - for i = 2, n do - local o = orientation(origin, hull[best], hull[i]) - if (isLeft and o < 0) or (not isLeft and o > 0) then - best = i - end - end - return hull[best] - end - - local leftTangent = findTangent(true) - local rightTangent = findTangent(false) - - -- If tangents are the same (can happen if origin is colinear), only return one - if leftTangent.x == rightTangent.x and leftTangent.y == rightTangent.y then - return { leftTangent } - else - return { leftTangent, rightTangent } - end -end - -end -Spearhead.Util = UTIL - ----DCS UTIL Takes inspiration from MIST but only takes the things it needs, changes for DCS updates and different vision for advanced mission scripting stuff. ----It also adds functions that make the other TDCS scripts easier without taking too much "control" away like MOOSE can sometimes. -local DCS_UTIL = {} -do -- INIT DCS_UTIL - do -- local databases - --[[ - groupdata = { - category, - country_id, - group_template - } - ]] -- - - --[[ - zone = { - name, - - zone_type, - x, - y, - radius - verts, - - } - ]] -- - - ---@alias SpearheadTriggerZoneType - ---| "Cilinder" - ---| "Polygon" - - ---@class SpearheadTriggerZone - ---@field name string - ---@field location Vec2 - ---@field radius number - ---@field verts Array - ---@field zone_type SpearheadTriggerZoneType - ---@field properties Array? - - ---@type Array - DCS_UTIL.__trigger_zones = {} - end - - DCS_UTIL.Coalition = - { - NEUTRAL = 0, - RED = 1, - BLUE = 2 - } - - DCS_UTIL.ZoneType = { - Cilinder = 0, - Polygon = 2 - } - - ---@enum SpearheadGroupCategory - DCS_UTIL.GroupCategory = { - AIRPLANE = 0, - HELICOPTER = 1, - GROUND = 2, - SHIP = 3, - TRAIN = 4, - STATIC = 5 --CUSTOM CATEGORY - } - - DCS_UTIL.__airbaseNamesById = {} - - ---@type table - DCS_UTIL.__airbaseZonesByName = {} - - DCS_UTIL.__airportsStartingCoalition = {} - DCS_UTIL.__warehouseStartingCoalition = {} - function DCS_UTIL.__INIT() - do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment - - do --init trigger zones - for i, trigger_zone in pairs(env.mission.triggers.zones) do - -- reorder verts as they are not ordered correctly in the ME - local verts = {} - if Spearhead.Util.tableLength(trigger_zone.verticies) >= 4 then - table.insert(verts, { x = trigger_zone.verticies[4].x, y = trigger_zone.verticies[4].y }) - table.insert(verts, { x = trigger_zone.verticies[3].x, y = trigger_zone.verticies[3].y }) - table.insert(verts, { x = trigger_zone.verticies[2].x, y = trigger_zone.verticies[2].y }) - table.insert(verts, { x = trigger_zone.verticies[1].x, y = trigger_zone.verticies[1].y }) - end - - local zoneType = "Cilinder" - if trigger_zone.type == DCS_UTIL.ZoneType.Polygon then - zoneType = "Polygon" - end - - ---@type SpearheadTriggerZone - local zone = { - name = trigger_zone.name, - zone_type = zoneType, - location = { x = trigger_zone.x, y = trigger_zone.y }, - radius = trigger_zone.radius, - verts = verts, - properties = {} - } - - if trigger_zone.properties then - for _, kvPair in pairs(trigger_zone.properties) do - local key = kvPair["key"] - local value = kvPair["value"] - zone.properties[#zone.properties + 1] = { key = key, value = value } - end - end - - DCS_UTIL.__trigger_zones[zone.name] = zone - end - end - - do -- init airports and warehouses - if env.warehouses.airports then - for warehouse_id, value in pairs(env.warehouses.airports) do - if warehouse_id ~= nil then - warehouse_id = tostring(warehouse_id) or "nil" - local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition) - DCS_UTIL.__airportsStartingCoalition[warehouse_id] = coalitionNumber - end - end - end - - if env.warehouses.warehouses then - DCS_UTIL.__warehouseStartingCoalition[-1] = "placeholder" - for warehouse_id, value in pairs(env.warehouses.warehouses) do - if warehouse_id ~= nil then - warehouse_id = tostring(warehouse_id) or "nil" - local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition) - DCS_UTIL.__warehouseStartingCoalition[warehouse_id] = coalitionNumber - end - end - end - end - - do -- fill airbaseNames and zones - local airbases = world.getAirbases() - if airbases then - for _, airbase in pairs(airbases) do - local name = airbase:getName() - - airbase:autoCapture(false) - - DCS_UTIL.__airbaseNamesById[tostring(airbase:getID())] = name - - if name then - ---@type Array - local relevantPoints = {} - for _, x in pairs(airbase:getRunways()) do - if x.position and x.position.x and x.position.z then - table.insert(relevantPoints, { x = x.position.x, y = x.position.z }) - end - end - - for _, x in pairs(airbase:getParking()) do - if x.vTerminalPos and x.vTerminalPos.x and x.vTerminalPos.z then - table.insert(relevantPoints, { x = x.vTerminalPos.x, y = x.vTerminalPos.z }) - end - end - - local points = UTIL.getConvexHull(relevantPoints) - local enlargedPoints = UTIL.enlargeConvexHull(points, 750) - - local triggerZone = { - name = name, - location = { x = airbase:getPoint().x, y = airbase:getPoint().z }, - zone_type = "Polygon", - radius = 0, - verts = enlargedPoints - } - - if SpearheadConfig and SpearheadConfig.debugEnabled == true then - DCS_UTIL.DrawZone(triggerZone, { r = 0, g = 1, b = 0, a = 1 }, { a = 0, r = 0, g = 1, b = 0 }, 1) - end - - DCS_UTIL.__airbaseZonesByName[name] = triggerZone - end - end - end - end - end - end - - ---maps the coalition name to the DCS coalition integer - ---@param input string the name - ---@return integer - function DCS_UTIL.stringToCoalition(input) - --[[ - coalition.side = { - NEUTRAL = 0 - RED = 1 - BLUE = 2 - } - ]] -- - local input = string.lower(input) - if input == 'neutrals' or input == "neutral" or input == "0" then - return DCS_UTIL.Coalition.NEUTRAL - end - - if input == 'red' or input == "1" then - return DCS_UTIL.Coalition.RED - end - - if input == 'blue' or input == "2" then - return DCS_UTIL.Coalition.BLUE - end - - return -1 - end - - - ---destroy the given unit - ---@param unitName string - function DCS_UTIL.DestroyUnit(unitName) - local unit = Unit.getByName(unitName) - if unit and unit:isExist() then - unit:destroy() - end - end - - --- takes a list of units and returns all the units that are in any of the zones - ---@param unit_names table unit names - ---@param zone_names table zone names - ---@return table unit list of objects { unit = UNIT, zone_name = zoneName} - function DCS_UTIL.getUnitsInZones(unit_names, zone_names) - local units = {} - - ---@type Array - local zones = {} - - for k = 1, #unit_names do - local unit = Unit.getByName(unit_names[k]) or StaticObject.getByName(unit_names[k]) - if unit and unit:isExist() == true then - units[#units + 1] = unit - end - end - - for index, zone_name in pairs(zone_names) do - local zone = DCS_UTIL.__trigger_zones[zone_name] - if zone then - zones[#zones + 1] = zone - end - end - - local in_zone_units = {} - for units_ind = 1, #units do - local lUnit = units[units_ind] - local unit_pos = lUnit:getPosition().p - local lCat = Object.getCategory(lUnit) - for zone_name, zone in pairs(zones) do - if unit_pos and ((lCat == 1 and lUnit:isActive() == true) or lCat ~= 1) then -- it is a unit and is active or it is not a unit - local isInZone = UTIL.is3dPointInZone(unit_pos, zone) - if isInZone == true then - in_zone_units[#in_zone_units + 1] = { unit = lUnit, zone_name = zone.name } - end - end - end - end - return in_zone_units - end - - --- takes a list of groups and returns all the group leaders that are in any of the zones - ---@param group_names table unit names - ---@param zone_name string zone names - ---@return table groupnames list of group names - function DCS_UTIL.getGroupsInZone(group_names, zone_name) - local zone = DCS_UTIL.__trigger_zones[zone_name] - if zone == nil then - return {} - end - - return DCS_UTIL.areGroupsInCustomZone(group_names, zone) - end - - --- takes a x, y poistion and checks if it is inside any of the zones - ---@param group_names Array North South position - ---@param zone SpearheadTriggerZone - ---@return Array groupnames list of groups that are in the zone - function DCS_UTIL.areGroupsInCustomZone(group_names, zone) - local units = {} - if Spearhead.Util.tableLength(group_names) < 1 then return {} end - - for k = 1, #group_names do - local entry = nil - local group = Group.getByName(group_names[k]) - if group ~= nil then - entry = { unit = group:getUnit(1), groupname = group_names[k] } - else - entry = { unit = StaticObject.getByName(group_names[k]), groupname = group_names[k] } - end - - if entry and entry.unit and entry.unit:isExist() == true then - units[#units + 1] = entry - end - end - - local result_groups = {} - for _, entry in pairs(units) do - local pos = entry.unit:getPoint() - local isInZone = UTIL.is3dPointInZone(pos, zone) - if isInZone == true then - table.insert(result_groups, entry.groupname) - end - end - return result_groups - end - - --- takes a x, y poistion and checks if it is inside any of the zones - ---@param x number North South position - ---@param z number West East position - ---@param zone_names table zone names - ---@return table zones list of objects { zone_name = zoneName} - function DCS_UTIL.isPositionInZones(x, z, zone_names) - ---@type Array - local zones = {} - for index, zone_name in pairs(zone_names) do - local zone = DCS_UTIL.__trigger_zones[zone_name] - if zone then - zones[#zones + 1] = zone - end - end - - local result_zones = {} - for zone_name, zone in pairs(zones) do - if UTIL.is3dPointInZone({ x = x, z = z, y = 0 }, zone) == true then - result_zones[#result_zones + 1] = zone.name - end - end - return result_zones - end - - --- takes a x, y poistion and checks if it is inside any of the zones - ---@param x number North South position - ---@param z number West East position - ---@param zone_name string zone name - ---@return boolean result - function DCS_UTIL.isPositionInZone(x, z, zone_name) - local zone = DCS_UTIL.__trigger_zones[zone_name] - if UTIL.is3dPointInZone({ x = x, y = 0, z = z }, zone) then - return true - end - return false - end - - --- takes a x, y poistion and checks if it is inside any of the zones - ---@param zone_name string - ---@param parent_zone_name string - ---@return boolean result - function DCS_UTIL.isZoneInZone(zone_name, parent_zone_name) - local zoneA = DCS_UTIL.__trigger_zones[zone_name] --[[@as SpearheadTriggerZone]] - if zoneA == nil then return false end - local zoneB = DCS_UTIL.__trigger_zones[parent_zone_name] --[[@as SpearheadTriggerZone]] - if zoneB == nil then return false end - return UTIL.is3dPointInZone({ x = zoneA.location.x, y = 0, z = zoneA.location.y }, zoneB) - end - - ---comment - ---@param zone_name any - ---@return SpearheadTriggerZone? zone { name,b zone_type, x, z, radius, verts } - function DCS_UTIL.getZoneByName(zone_name) - if zone_name == nil then return nil end - return DCS_UTIL.__trigger_zones[zone_name] - end - - ---comment - ---@param airbaseName string - ---@return SpearheadTriggerZone? zone - function DCS_UTIL.getAirbaseZoneByName(airbaseName) - if airbaseName == nil then return nil end - return DCS_UTIL.__airbaseZonesByName[airbaseName] - end - - ---maps the category name to the DCS group category - ---@param input string the name - ---@return integer? - function DCS_UTIL.stringToGroupCategory(input) - input = string.lower(input) - if input == 'airplane' or input == 'plane' then - return DCS_UTIL.GroupCategory.AIRPLANE - end - if input == 'helicopter' then - return DCS_UTIL.GroupCategory.HELICOPTER - end - if input == 'ground' or input == 'vehicle' then - return DCS_UTIL.GroupCategory.GROUND - end - if input == 'ship' then - return DCS_UTIL.GroupCategory.SHIP - end - if input == 'train' then - return DCS_UTIL.GroupCategory.TRAIN - end - if input == "static" then - return DCS_UTIL.GroupCategory.STATIC - end - return nil; - end - - ---@type table - local config = - { - ["ah-64d_blk_ii"] = "MGRS", - ["fa-18c_hornet"] = "DMS", - ["av8bna"] = "DMS", - ["f-14b"] = "DMS", - ["f-14a-135-gr"] = "DMS" - } - - - ---@param location Vec2 - ---@param unitType string - function DCS_UTIL.convertVec2ToUnitUsableType(location, unitType) - - local height = land.getHeight(location) - local vec3 = { x = location.x, y = height, z = location.y } - - local unitType = string.lower(unitType or "") - local conversionType = config[unitType] - - if not conversionType then conversionType = "DDM" end - return DCS_UTIL.convertToDisplayCoord(vec3, conversionType) - end - - ---@alias CoordType - ---| "MGRS" MGRS - ---| "DMS" DECIMAL SECONDS - ---| "DDM" DECIMAL MINUTES - - ---@private - ---@param location Vec3 - ---@param coordType CoordType - function DCS_UTIL.convertToDisplayCoord(location, coordType) - local lattitude, longitude, altitude = coord.LOtoLL(location) - - if coordType == "MGRS" then - local mgrs = coord.LLtoMGRS(lattitude, longitude) - return string.format("%s %s %s %s", mgrs.UTMZone, mgrs.MGRSDigraph, mgrs.Easting, mgrs.Northing) - end - - -- Convert DD to DDM (Degrees Decimal Minutes) - local function dd_to_ddm(dd) - local degrees = math.floor(math.abs(dd)) - local minutes = (math.abs(dd) - degrees) * 60 - local sign = dd >= 0 and 1 or -1 - return degrees * sign, minutes - end - - local lat_deg, lat_min = dd_to_ddm(lattitude) - local lon_deg, lon_min = dd_to_ddm(longitude) - - local lat_hemisphere = lattitude >= 0 and "N" or "S" - local lon_hemisphere = longitude >= 0 and "E" or "W" - - if coordType == "DDM" then - return string.format("%s%02d°%06.3f' %s%03d°%06.3f' %dft", - lat_hemisphere, math.abs(lat_deg), lat_min, - lon_hemisphere, math.abs(lon_deg), lon_min, - altitude * 3,28084) - end - - if coordType == "DMS" then - - local lat_min_display = math.floor(lat_min) - local lon_min_display = math.floor(lon_min) - - local lat_sec_display = math.floor((lat_min - lat_min_display) * 60) - local lon_sec_display = math.floor((lon_min - lon_min_display) * 60) - - return string.format("%s%02d°%02d'%02d %s%03d°%02d'%02d %dft", - lat_hemisphere, math.abs(lat_deg), lat_min_display, lat_sec_display, - lon_hemisphere, math.abs(lon_deg), lon_min_display, lon_sec_display, - altitude * 3,28084) - end - - end - - ---@param zone SpearheadTriggerZone - ---@return Array sceneryObjects - function DCS_UTIL.getSceneryObjectsInZone(zone) - ---@type Volume - local volume - - if(zone.zone_type == "Cilinder") then - local y = land.getHeight({ x = zone.location.x, y = zone.location.y }) - ---@type Sphere - local sphere = { - id = world.VolumeType.SPHERE, - params = { - point = { x = zone.location.x, y = y, z = zone.location.y }, - radius = zone.radius - } - } - volume = sphere - else - local minX = nil - local maxX = nil - local minZ = nil - local maxZ = nil - - for _, point in pairs(zone.verts) do - if minX == nil or point.x < minX then - minX = point.x - end - if maxX == nil or point.x > maxX then - maxX = point.x - end - if minZ == nil or point.y < minZ then - minZ = point.y - end - if maxZ == nil or point.y > maxZ then - maxZ = point.y - end - end - - if(minX == nil or maxX == nil or minZ == nil or maxZ == nil) then - return {} - end - - ---@type Vec3 - local min = { - x = minX, - y = land.getHeight({ x = minX, y = minZ }) - 100, - z = minZ - } - - ---@type Vec3 - local max = { - x = maxX, - y = land.getHeight({ x = maxX, y = maxZ }) + 500, - z = maxZ - } - - ---@type Box - local box = { - id = world.VolumeType.BOX, - params = { - min = min, - max = max - } - } - volume = box - end - - ---@type Array - local sceneryObjects = {} - - ---@param object SceneryObject - local onFound = function(object) - if object and object:isExist() and - object:hasAttribute("Buildings") - then - local obj = Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject.New(object["id_"]) - table.insert(sceneryObjects, obj) - end - end - - world.searchObjects(Object.Category.SCENERY, volume, onFound) - return sceneryObjects - end - - ---@param group Group - function DCS_UTIL.getUnitTypeFromGroup(group) - for _, unit in pairs(group:getUnits()) do - if unit and unit:isExist() then - return unit:getTypeName() - end - end - end - - - ---comment Get all units that are players - ---@return Array units - function DCS_UTIL.getAllPlayerUnits() - local units = {} - for i = 0, 2 do - local players = coalition.getPlayers(i) - for key, unit in pairs(players) do - units[#units + 1] = unit - end - end - return units - end - - ---get base name from ID - ---@param baseId number - ---@return string? name - function DCS_UTIL.getAirbaseName(baseId) - local stringified = tostring(baseId) - return DCS_UTIL.__airbaseNamesById[stringified] - end - - ---get base from id - ---@param baseId number - ---@return Airbase? table - function DCS_UTIL.getAirbaseById(baseId) - local name = DCS_UTIL.getAirbaseName(baseId) - if name == nil then return nil end - return Airbase.getByName(name) - end - - ---Get the starting coalition of a farp or airbase - ---@param airbase Airbase - ---@return number? coalition - function DCS_UTIL.getStartingCoalition(airbase) - if airbase == nil then - return nil - end - - --STRING based dictionary otherwise it'll be a string/collapsed array - local baseId = tostring(airbase:getID()) - - local result = DCS_UTIL.__airportsStartingCoalition[baseId] - if result == nil then - result = DCS_UTIL.__warehouseStartingCoalition[baseId] - end - return result - end - - function DCS_UTIL.CleanCorpse(unitName) - local unitName = "dead_" .. unitName - - local object = StaticObject.getByName(unitName) - - if object then - object:destroy() - end - end - - ---@class DrawColor - ---@field r number - ---@field g number - ---@field b number - ---@field a number - - local drawID = 400 - ---@param zone SpearheadTriggerZone - ---@param lineColor DrawColor - ---@param fillColor DrawColor - ---@param lineStyle LineType - ---@return number drawID - function DCS_UTIL.DrawZone(zone, lineColor, fillColor, lineStyle) - if lineStyle == nil then lineStyle = 4 end - drawID = drawID + 1 - if zone.zone_type == "Cilinder" then - trigger.action.circleToAll(-1, drawID, { x = zone.location.x, y = 0, z = zone.location.y }, zone.radius, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, lineStyle, true) - else - local functionString = "trigger.action.markupToAll(7, -1, " .. drawID .. "," - for _, vecpoint in pairs(zone.verts) do - functionString = functionString .. " { x=" .. vecpoint.x .. ", y=0,z=" .. vecpoint.y .. "}," - end - functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")" - - ---@diagnostic disable-next-line: deprecated - local f, err = loadstring(functionString) - if f then - f() - else - env.error("Something failed when drawing complex drawing" .. err) - end - end - local fillColorMapped = { - fillColor.r or 0, - fillColor.g or 0, - fillColor.b or 0, - fillColor.a or 0.5 - } - - local lineColorMapped = { - lineColor.r or 0, - lineColor.g or 0, - lineColor.b or 0, - lineColor.a or 1 - } - - trigger.action.setMarkupColorFill(drawID, fillColorMapped) - trigger.action.setMarkupColor(drawID, lineColorMapped) - - return drawID - end - - ---@param start Vec3 - ---@param finish Vec3 - ---@param lineColor DrawColor - ---@param lineStyle LineType - function DCS_UTIL.DrawLine(start, finish, lineColor, lineStyle) - if lineStyle == nil then lineStyle = 4 end - drawID = drawID + 1 - - local lineColorMapped = { - lineColor.r or 0, - lineColor.g or 0, - lineColor.b or 0, - lineColor.a or 1 - } - - trigger.action.lineToAll(-1, drawID, start, finish, lineColorMapped, lineStyle) - return drawID - end - - ---@param groupID number - ---@param text string - ---@param location Vec3 - ---@return number markID - function DCS_UTIL.AddMarkToGroup(groupID, text, location) - drawID = drawID + 1 - trigger.action.markToGroup(drawID, text, location, groupID, true, nil) - return drawID - end - - ---comment - ---@param text any - ---@param location Vec3 - ---@return integer - function DCS_UTIL.AddMarkToAll(text, location) - drawID = drawID + 1 - trigger.action.markToAll(drawID, text, location, true, nil) - return drawID - end - - ---@param markId number - function DCS_UTIL.RemoveMark(markId) - if markId ~= nil then - trigger.action.removeMark(markId) - end - end - - ---comment - ---@param drawID number - ---@param lineColor DrawColor - function DCS_UTIL.SetLineColor(drawID, lineColor) - local lineColorMapped = { - lineColor.r or 0, - lineColor.g or 0, - lineColor.b or 0, - lineColor.a or 1 - } - trigger.action.setMarkupColor(drawID, lineColorMapped) - end - - ---comment - ---@param drawID number - ---@param fillColor DrawColor - function DCS_UTIL.SetFillColor(drawID, fillColor) - local lineColorMapped = { - fillColor.r or 0, - fillColor.g or 0, - fillColor.b or 0, - fillColor.a or 1 - } - trigger.action.setMarkupColorFill(drawID, lineColorMapped) - end - - function DCS_UTIL.RemoveZoneDraw(drawID) - if drawID ~= nil then - trigger.action.removeMark(drawID) - end - end - - - ---@return number? id - function DCS_UTIL.GetNeutralCountry() - for name, id in pairs(country.id) do - if coalition.getCountryCoalition(id) == DCS_UTIL.Coalition.NEUTRAL then - return id - end - end - end - - - function DCS_UTIL.NeedsRTBInTen(groupName, fuelOffset) - - local isBingo = DCS_UTIL.IsBingoFuel(groupName, fuelOffset) - if isBingo then return true end - - local aliveUnits = 0 - local group = Group.getByName(groupName) - if group then - for _ , unit in pairs(group:getUnits()) do - if unit and unit:isExist() == true and unit:inAir() == true then - aliveUnits = aliveUnits + 1 - end - end - - if aliveUnits / group:getInitialSize() <= 0.5 then - return true - end - end - - return false - end - - ---@return boolean - function DCS_UTIL.IsBingoFuel(groupName, offset) - if offset == nil then offset = 0 end - local bingoSetting = 0.20 - bingoSetting = bingoSetting + offset - - local group = Group.getByName(groupName) - if group then - for _, unit in pairs(group:getUnits()) do - if unit and unit:isExist() == true and unit:inAir() == true and unit:getFuel() < bingoSetting then - return true - end - end - end - - return false - end - - ---comment - ---@param groupId number - ---@return Group? - function DCS_UTIL.GetPlayerGroupByGroupID(groupId) - for i = 0, 2 do - local players = coalition.getPlayers(i) - for key, unit in pairs(players) do - if unit and unit:isExist() == true then - local group = unit:getGroup() - if group and group:getID() == groupId then - return group - end - end - end - end - end - - ---@param unitID number - ---@return Unit? - function DCS_UTIL.GetPLayerUnitByID(unitID) - for i = 0, 2 do - local players = coalition.getPlayers(i) - for key, unit in pairs(players) do - if unit and unit:getID() == unitID then - return unit - end - end - end - end - - DCS_UTIL.__INIT(); -end -Spearhead.DcsUtil = DCS_UTIL - ---- @class Logger ---- @field LoggerName string the name of the logger ---- @field LogLevel string the log level of the logger -local LOGGER = {} -do - local PreFix = "Spearhead" - - ---comment - ---@param logger_name any - ---@param logLevel LogLevel - ---@return Logger - function LOGGER.new(logger_name, logLevel) - LOGGER.__index = LOGGER - local self = setmetatable({}, LOGGER) - self.LoggerName = logger_name or "(loggername not set)" - self.LogLevel = logLevel or "INFO" - - return self - end - - ---@param message any the message - function LOGGER:info(message) - if message == nil then - return - end - message = UTIL.toString(message) - - if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" then - env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) - end - end - - ---comment - ---@param message string - function LOGGER:warn(message) - if message == nil then - return - end - message = UTIL.toString(message) - - if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" then - env.warning("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) - end - end - - ---@param message any -- the message - function LOGGER:error(message) - if message == nil then - return - end - - message = UTIL.toString(message) - - if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" or self.LogLevel == "ERROR" then - env.error("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) - end - end - - ---@param message any the message - function LOGGER:debug(message) - if message == nil then - return - end - - message = UTIL.toString(message) - if self.LogLevel == "DEBUG" then - env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "][DEBUG] " .. message) - end - end -end -Spearhead.LoggerTemplate = LOGGER - -Spearhead.MissionEditingWarnings = {} -function Spearhead.AddMissionEditorWarning(warningMessage) - table.insert(Spearhead.MissionEditingWarnings, warningMessage or "skip") -end - -local loadDone = false -Spearhead.LoadingDone = function() - if loadDone == true then - return - end - - local warningLogger = Spearhead.LoggerTemplate.new("MISSIONPARSER", "INFO") - if Spearhead.Util.tableLength(Spearhead.MissionEditingWarnings) > 0 then - for key, message in pairs(Spearhead.MissionEditingWarnings) do - warningLogger:warn(message) - end - else - warningLogger:info("No issues detected") - end - - loadDone = true -end +local Util = require("classes.util.Util") + +---DCS UTIL Takes inspiration from MIST but only takes the things it needs, changes for DCS updates and different vision for advanced mission scripting stuff. +---It also adds functions that make the other TDCS scripts easier without taking too much "control" away like MOOSE can sometimes. +---@class DcsUtil +local DCS_UTIL = {} +do -- INIT DCS_UTIL + do -- local databases + --[=[ + groupdata = { + category, + country_id, + group_template + } + --]=] + + --[[ + zone = { + name, + + zone_type, + x, + y, + radius + verts, + + } + something ]] + + ---@alias SpearheadTriggerZoneType + ---| "Cilinder" + ---| "Polygon" + + ---@class SpearheadTriggerZone + ---@field name string + ---@field location Vec2 + ---@field radius number + ---@field verts Array + ---@field zone_type SpearheadTriggerZoneType + ---@field properties Array? + + ---@type Array + DCS_UTIL.__trigger_zones = {} + end + + DCS_UTIL.Coalition = + { + NEUTRAL = 0, + RED = 1, + BLUE = 2 + } + + DCS_UTIL.ZoneType = { + Cilinder = 0, + Polygon = 2 + } + + ---@enum SpearheadGroupCategory + DCS_UTIL.GroupCategory = { + AIRPLANE = 0, + HELICOPTER = 1, + GROUND = 2, + SHIP = 3, + TRAIN = 4, + STATIC = 5 --CUSTOM CATEGORY + } + + DCS_UTIL.__airbaseNamesById = {} + + ---@type table + DCS_UTIL.__airbaseZonesByName = {} + + DCS_UTIL.__airportsStartingCoalition = {} + DCS_UTIL.__warehouseStartingCoalition = {} + function DCS_UTIL.__INIT() + do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment + + do --init trigger zones + for i, trigger_zone in pairs(env.mission.triggers.zones) do + -- reorder verts as they are not ordered correctly in the ME + local verts = {} + if Util.tableLength(trigger_zone.verticies) >= 4 then + table.insert(verts, { x = trigger_zone.verticies[4].x, y = trigger_zone.verticies[4].y }) + table.insert(verts, { x = trigger_zone.verticies[3].x, y = trigger_zone.verticies[3].y }) + table.insert(verts, { x = trigger_zone.verticies[2].x, y = trigger_zone.verticies[2].y }) + table.insert(verts, { x = trigger_zone.verticies[1].x, y = trigger_zone.verticies[1].y }) + end + + local zoneType = "Cilinder" + if trigger_zone.type == DCS_UTIL.ZoneType.Polygon then + zoneType = "Polygon" + end + + ---@type SpearheadTriggerZone + local zone = { + name = trigger_zone.name, + zone_type = zoneType, + location = { x = trigger_zone.x, y = trigger_zone.y }, + radius = trigger_zone.radius, + verts = verts, + properties = {} + } + + if trigger_zone.properties then + for _, kvPair in pairs(trigger_zone.properties) do + local key = kvPair["key"] + local value = kvPair["value"] + zone.properties[#zone.properties + 1] = { key = key, value = value } + end + end + + DCS_UTIL.__trigger_zones[zone.name] = zone + end + end + + do -- init airports and warehouses + if env.warehouses.airports then + for warehouse_id, value in pairs(env.warehouses.airports) do + if warehouse_id ~= nil then + warehouse_id = tostring(warehouse_id) or "nil" + local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition) + DCS_UTIL.__airportsStartingCoalition[warehouse_id] = coalitionNumber + end + end + end + + if env.warehouses.warehouses then + DCS_UTIL.__warehouseStartingCoalition[-1] = "placeholder" + for warehouse_id, value in pairs(env.warehouses.warehouses) do + if warehouse_id ~= nil then + warehouse_id = tostring(warehouse_id) or "nil" + local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition) + DCS_UTIL.__warehouseStartingCoalition[warehouse_id] = coalitionNumber + end + end + end + end + + do -- fill airbaseNames and zones + local airbases = world.getAirbases() + if airbases then + for _, airbase in pairs(airbases) do + local name = airbase:getName() + + airbase:autoCapture(false) + + DCS_UTIL.__airbaseNamesById[tostring(airbase:getID())] = name + + if name then + ---@type Array + local relevantPoints = {} + for _, x in pairs(airbase:getRunways()) do + if x.position and x.position.x and x.position.z then + table.insert(relevantPoints, { x = x.position.x, y = x.position.z }) + end + end + + for _, x in pairs(airbase:getParking()) do + if x.vTerminalPos and x.vTerminalPos.x and x.vTerminalPos.z then + table.insert(relevantPoints, { x = x.vTerminalPos.x, y = x.vTerminalPos.z }) + end + end + + local points = Util.getConvexHull(relevantPoints) + local enlargedPoints = Util.enlargeConvexHull(points, 750) + + local triggerZone = { + name = name, + location = { x = airbase:getPoint().x, y = airbase:getPoint().z }, + zone_type = "Polygon", + radius = 0, + verts = enlargedPoints + } + + if SpearheadConfig and SpearheadConfig.debugEnabled == true then + DCS_UTIL.DrawZone(triggerZone, { r = 0, g = 1, b = 0, a = 1 }, { a = 0, r = 0, g = 1, b = 0 }, 1) + end + + DCS_UTIL.__airbaseZonesByName[name] = triggerZone + end + end + end + end + end + end + + ---maps the coalition name to the DCS coalition integer + ---@param input string the name + ---@return integer + function DCS_UTIL.stringToCoalition(input) + --[[ + coalition.side = { + NEUTRAL = 0 + RED = 1 + BLUE = 2 + } + ]] -- + local input = string.lower(input) + if input == 'neutrals' or input == "neutral" or input == "0" then + return DCS_UTIL.Coalition.NEUTRAL + end + + if input == 'red' or input == "1" then + return DCS_UTIL.Coalition.RED + end + + if input == 'blue' or input == "2" then + return DCS_UTIL.Coalition.BLUE + end + + return -1 + end + + + ---destroy the given unit + ---@param unitName string + function DCS_UTIL.DestroyUnit(unitName) + local unit = Unit.getByName(unitName) + if unit and unit:isExist() then + unit:destroy() + end + end + + --- takes a list of units and returns all the units that are in any of the zones + ---@param unit_names table unit names + ---@param zone_names table zone names + ---@return table unit list of objects { unit = UNIT, zone_name = zoneName} + function DCS_UTIL.getUnitsInZones(unit_names, zone_names) + local units = {} + + ---@type Array + local zones = {} + + for k = 1, #unit_names do + local unit = Unit.getByName(unit_names[k]) or StaticObject.getByName(unit_names[k]) + if unit and unit:isExist() == true then + units[#units + 1] = unit + end + end + + for index, zone_name in pairs(zone_names) do + local zone = DCS_UTIL.__trigger_zones[zone_name] + if zone then + zones[#zones + 1] = zone + end + end + + local in_zone_units = {} + for units_ind = 1, #units do + local lUnit = units[units_ind] + local unit_pos = lUnit:getPosition().p + local lCat = Object.getCategory(lUnit) + for zone_name, zone in pairs(zones) do + if unit_pos and ((lCat == 1 and lUnit:isActive() == true) or lCat ~= 1) then -- it is a unit and is active or it is not a unit + local isInZone = Util.is3dPointInZone(unit_pos, zone) + if isInZone == true then + in_zone_units[#in_zone_units + 1] = { unit = lUnit, zone_name = zone.name } + end + end + end + end + return in_zone_units + end + + --- takes a list of groups and returns all the group leaders that are in any of the zones + ---@param group_names table unit names + ---@param zone_name string zone names + ---@return table groupnames list of group names + function DCS_UTIL.getGroupsInZone(group_names, zone_name) + local zone = DCS_UTIL.__trigger_zones[zone_name] + if zone == nil then + return {} + end + + return DCS_UTIL.areGroupsInCustomZone(group_names, zone) + end + + --- takes a x, y poistion and checks if it is inside any of the zones + ---@param group_names Array North South position + ---@param zone SpearheadTriggerZone + ---@return Array groupnames list of groups that are in the zone + function DCS_UTIL.areGroupsInCustomZone(group_names, zone) + local units = {} + if Util.tableLength(group_names) < 1 then return {} end + + for k = 1, #group_names do + local entry = nil + local group = Group.getByName(group_names[k]) + if group ~= nil then + entry = { unit = group:getUnit(1), groupname = group_names[k] } + else + entry = { unit = StaticObject.getByName(group_names[k]), groupname = group_names[k] } + end + + if entry and entry.unit and entry.unit:isExist() == true then + units[#units + 1] = entry + end + end + + local result_groups = {} + for _, entry in pairs(units) do + local pos = entry.unit:getPoint() + local isInZone = Util.is3dPointInZone(pos, zone) + if isInZone == true then + table.insert(result_groups, entry.groupname) + end + end + return result_groups + end + + --- takes a x, y poistion and checks if it is inside any of the zones + ---@param x number North South position + ---@param z number West East position + ---@param zone_names table zone names + ---@return table zones list of objects { zone_name = zoneName} + function DCS_UTIL.isPositionInZones(x, z, zone_names) + ---@type Array + local zones = {} + for index, zone_name in pairs(zone_names) do + local zone = DCS_UTIL.__trigger_zones[zone_name] + if zone then + zones[#zones + 1] = zone + end + end + + local result_zones = {} + for zone_name, zone in pairs(zones) do + if Util.is3dPointInZone({ x = x, z = z, y = 0 }, zone) == true then + result_zones[#result_zones + 1] = zone.name + end + end + return result_zones + end + + --- takes a x, y poistion and checks if it is inside any of the zones + ---@param x number North South position + ---@param z number West East position + ---@param zone_name string zone name + ---@return boolean result + function DCS_UTIL.isPositionInZone(x, z, zone_name) + local zone = DCS_UTIL.__trigger_zones[zone_name] + if Util.is3dPointInZone({ x = x, y = 0, z = z }, zone) then + return true + end + return false + end + + --- takes a x, y poistion and checks if it is inside any of the zones + ---@param zone_name string + ---@param parent_zone_name string + ---@return boolean result + function DCS_UTIL.isZoneInZone(zone_name, parent_zone_name) + local zoneA = DCS_UTIL.__trigger_zones[zone_name] --[[@as SpearheadTriggerZone]] + if zoneA == nil then return false end + local zoneB = DCS_UTIL.__trigger_zones[parent_zone_name] --[[@as SpearheadTriggerZone]] + if zoneB == nil then return false end + return Util.is3dPointInZone({ x = zoneA.location.x, y = 0, z = zoneA.location.y }, zoneB) + end + + ---comment + ---@param zone_name any + ---@return SpearheadTriggerZone? zone { name,b zone_type, x, z, radius, verts } + function DCS_UTIL.getZoneByName(zone_name) + if zone_name == nil then return nil end + return DCS_UTIL.__trigger_zones[zone_name] + end + + ---comment + ---@param airbaseName string + ---@return SpearheadTriggerZone? zone + function DCS_UTIL.getAirbaseZoneByName(airbaseName) + if airbaseName == nil then return nil end + return DCS_UTIL.__airbaseZonesByName[airbaseName] + end + + ---maps the category name to the DCS group category + ---@param input string the name + ---@return integer? + function DCS_UTIL.stringToGroupCategory(input) + input = string.lower(input) + if input == 'airplane' or input == 'plane' then + return DCS_UTIL.GroupCategory.AIRPLANE + end + if input == 'helicopter' then + return DCS_UTIL.GroupCategory.HELICOPTER + end + if input == 'ground' or input == 'vehicle' then + return DCS_UTIL.GroupCategory.GROUND + end + if input == 'ship' then + return DCS_UTIL.GroupCategory.SHIP + end + if input == 'train' then + return DCS_UTIL.GroupCategory.TRAIN + end + if input == "static" then + return DCS_UTIL.GroupCategory.STATIC + end + return nil; + end + + ---@type table + local config = + { + ["ah-64d_blk_ii"] = "MGRS", + ["fa-18c_hornet"] = "DMS", + ["av8bna"] = "DMS", + ["f-14b"] = "DMS", + ["f-14a-135-gr"] = "DMS" + } + + + ---@param location Vec2 + ---@param unitType string + function DCS_UTIL.convertVec2ToUnitUsableType(location, unitType) + + local height = land.getHeight(location) + local vec3 = { x = location.x, y = height, z = location.y } + + local unitType = string.lower(unitType or "") + local conversionType = config[unitType] + + if not conversionType then conversionType = "DDM" end + return DCS_UTIL.convertToDisplayCoord(vec3, conversionType) + end + + ---@alias CoordType + ---| "MGRS" MGRS + ---| "DMS" DECIMAL SECONDS + ---| "DDM" DECIMAL MINUTES + + ---@private + ---@param location Vec3 + ---@param coordType CoordType + function DCS_UTIL.convertToDisplayCoord(location, coordType) + local lattitude, longitude, altitude = coord.LOtoLL(location) + + if coordType == "MGRS" then + local mgrs = coord.LLtoMGRS(lattitude, longitude) + return string.format("%s %s %s %s", mgrs.UTMZone, mgrs.MGRSDigraph, mgrs.Easting, mgrs.Northing) + end + + -- Convert DD to DDM (Degrees Decimal Minutes) + local function dd_to_ddm(dd) + local degrees = math.floor(math.abs(dd)) + local minutes = (math.abs(dd) - degrees) * 60 + local sign = dd >= 0 and 1 or -1 + return degrees * sign, minutes + end + + local lat_deg, lat_min = dd_to_ddm(lattitude) + local lon_deg, lon_min = dd_to_ddm(longitude) + + local lat_hemisphere = lattitude >= 0 and "N" or "S" + local lon_hemisphere = longitude >= 0 and "E" or "W" + + if coordType == "DDM" then + return string.format("%s%02d°%06.3f' %s%03d°%06.3f' %dft", + lat_hemisphere, math.abs(lat_deg), lat_min, + lon_hemisphere, math.abs(lon_deg), lon_min, + altitude * 3,28084) + end + + if coordType == "DMS" then + + local lat_min_display = math.floor(lat_min) + local lon_min_display = math.floor(lon_min) + + local lat_sec_display = math.floor((lat_min - lat_min_display) * 60) + local lon_sec_display = math.floor((lon_min - lon_min_display) * 60) + + return string.format("%s%02d°%02d'%02d %s%03d°%02d'%02d %dft", + lat_hemisphere, math.abs(lat_deg), lat_min_display, lat_sec_display, + lon_hemisphere, math.abs(lon_deg), lon_min_display, lon_sec_display, + altitude * 3,28084) + end + + end + + ---@param zone SpearheadTriggerZone + ---@return Array sceneryObjects + function DCS_UTIL.getSceneryObjectsInZone(zone) + ---@type Volume + local volume + + if(zone.zone_type == "Cilinder") then + local y = land.getHeight({ x = zone.location.x, y = zone.location.y }) + ---@type Sphere + local sphere = { + id = world.VolumeType.SPHERE, + params = { + point = { x = zone.location.x, y = y, z = zone.location.y }, + radius = zone.radius + } + } + volume = sphere + else + local minX = nil + local maxX = nil + local minZ = nil + local maxZ = nil + + for _, point in pairs(zone.verts) do + if minX == nil or point.x < minX then + minX = point.x + end + if maxX == nil or point.x > maxX then + maxX = point.x + end + if minZ == nil or point.y < minZ then + minZ = point.y + end + if maxZ == nil or point.y > maxZ then + maxZ = point.y + end + end + + if(minX == nil or maxX == nil or minZ == nil or maxZ == nil) then + return {} + end + + ---@type Vec3 + local min = { + x = minX, + y = land.getHeight({ x = minX, y = minZ }) - 100, + z = minZ + } + + ---@type Vec3 + local max = { + x = maxX, + y = land.getHeight({ x = maxX, y = maxZ }) + 500, + z = maxZ + } + + ---@type Box + local box = { + id = world.VolumeType.BOX, + params = { + min = min, + max = max + } + } + volume = box + end + + ---@type Array + local sceneryObjects = {} + + ---@param object SceneryObject + local onFound = function(object) + if object and object:isExist() and + object:hasAttribute("Buildings") + then + local obj = Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject.New(object["id_"]) + table.insert(sceneryObjects, obj) + end + end + + world.searchObjects(Object.Category.SCENERY, volume, onFound) + return sceneryObjects + end + + ---@param group Group + function DCS_UTIL.getUnitTypeFromGroup(group) + for _, unit in pairs(group:getUnits()) do + if unit and unit:isExist() then + return unit:getTypeName() + end + end + end + + + ---comment Get all units that are players + ---@return Array units + function DCS_UTIL.getAllPlayerUnits() + local units = {} + for i = 0, 2 do + local players = coalition.getPlayers(i) + for key, unit in pairs(players) do + units[#units + 1] = unit + end + end + return units + end + + ---get base name from ID + ---@param baseId number + ---@return string? name + function DCS_UTIL.getAirbaseName(baseId) + local stringified = tostring(baseId) + return DCS_UTIL.__airbaseNamesById[stringified] + end + + ---get base from id + ---@param baseId number + ---@return Airbase? table + function DCS_UTIL.getAirbaseById(baseId) + local name = DCS_UTIL.getAirbaseName(baseId) + if name == nil then return nil end + return Airbase.getByName(name) + end + + ---Get the starting coalition of a farp or airbase + ---@param airbase Airbase + ---@return number? coalition + function DCS_UTIL.getStartingCoalition(airbase) + if airbase == nil then + return nil + end + + --STRING based dictionary otherwise it'll be a string/collapsed array + local baseId = tostring(airbase:getID()) + + local result = DCS_UTIL.__airportsStartingCoalition[baseId] + if result == nil then + result = DCS_UTIL.__warehouseStartingCoalition[baseId] + end + return result + end + + function DCS_UTIL.CleanCorpse(unitName) + local unitName = "dead_" .. unitName + + local object = StaticObject.getByName(unitName) + + if object then + object:destroy() + end + end + + ---@class DrawColor + ---@field r number + ---@field g number + ---@field b number + ---@field a number + + local drawID = 400 + ---@param zone SpearheadTriggerZone + ---@param lineColor DrawColor + ---@param fillColor DrawColor + ---@param lineStyle LineType + ---@return number drawID + function DCS_UTIL.DrawZone(zone, lineColor, fillColor, lineStyle) + if lineStyle == nil then lineStyle = 4 end + drawID = drawID + 1 + if zone.zone_type == "Cilinder" then + trigger.action.circleToAll(-1, drawID, { x = zone.location.x, y = 0, z = zone.location.y }, zone.radius, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, lineStyle, true) + else + local functionString = "trigger.action.markupToAll(7, -1, " .. drawID .. "," + for _, vecpoint in pairs(zone.verts) do + functionString = functionString .. " { x=" .. vecpoint.x .. ", y=0,z=" .. vecpoint.y .. "}," + end + functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")" + + ---@diagnostic disable-next-line: deprecated + local f, err = loadstring(functionString) + if f then + f() + else + env.error("Something failed when drawing complex drawing" .. err) + end + end + local fillColorMapped = { + fillColor.r or 0, + fillColor.g or 0, + fillColor.b or 0, + fillColor.a or 0.5 + } + + local lineColorMapped = { + lineColor.r or 0, + lineColor.g or 0, + lineColor.b or 0, + lineColor.a or 1 + } + + trigger.action.setMarkupColorFill(drawID, fillColorMapped) + trigger.action.setMarkupColor(drawID, lineColorMapped) + + return drawID + end + + ---@param start Vec3 + ---@param finish Vec3 + ---@param lineColor DrawColor + ---@param lineStyle LineType + function DCS_UTIL.DrawLine(start, finish, lineColor, lineStyle) + if lineStyle == nil then lineStyle = 4 end + drawID = drawID + 1 + + local lineColorMapped = { + lineColor.r or 0, + lineColor.g or 0, + lineColor.b or 0, + lineColor.a or 1 + } + + trigger.action.lineToAll(-1, drawID, start, finish, lineColorMapped, lineStyle) + return drawID + end + + ---@param groupID number + ---@param text string + ---@param location Vec3 + ---@return number markID + function DCS_UTIL.AddMarkToGroup(groupID, text, location) + drawID = drawID + 1 + trigger.action.markToGroup(drawID, text, location, groupID, true, nil) + return drawID + end + + ---comment + ---@param text any + ---@param location Vec3 + ---@return integer + function DCS_UTIL.AddMarkToAll(text, location) + drawID = drawID + 1 + trigger.action.markToAll(drawID, text, location, true, nil) + return drawID + end + + ---@param markId number + function DCS_UTIL.RemoveMark(markId) + if markId ~= nil then + trigger.action.removeMark(markId) + end + end + + ---comment + ---@param drawID number + ---@param lineColor DrawColor + function DCS_UTIL.SetLineColor(drawID, lineColor) + local lineColorMapped = { + lineColor.r or 0, + lineColor.g or 0, + lineColor.b or 0, + lineColor.a or 1 + } + trigger.action.setMarkupColor(drawID, lineColorMapped) + end + + ---comment + ---@param drawID number + ---@param fillColor DrawColor + function DCS_UTIL.SetFillColor(drawID, fillColor) + local lineColorMapped = { + fillColor.r or 0, + fillColor.g or 0, + fillColor.b or 0, + fillColor.a or 1 + } + trigger.action.setMarkupColorFill(drawID, lineColorMapped) + end + + function DCS_UTIL.RemoveZoneDraw(drawID) + if drawID ~= nil then + trigger.action.removeMark(drawID) + end + end + + + ---@return number? id + function DCS_UTIL.GetNeutralCountry() + for name, id in pairs(country.id) do + if coalition.getCountryCoalition(id) == DCS_UTIL.Coalition.NEUTRAL then + return id + end + end + end + + + function DCS_UTIL.NeedsRTBInTen(groupName, fuelOffset) + + local isBingo = DCS_UTIL.IsBingoFuel(groupName, fuelOffset) + if isBingo then return true end + + local aliveUnits = 0 + local group = Group.getByName(groupName) + if group then + for _ , unit in pairs(group:getUnits()) do + if unit and unit:isExist() == true and unit:inAir() == true then + aliveUnits = aliveUnits + 1 + end + end + + if aliveUnits / group:getInitialSize() <= 0.5 then + return true + end + end + + return false + end + + ---@return boolean + function DCS_UTIL.IsBingoFuel(groupName, offset) + if offset == nil then offset = 0 end + local bingoSetting = 0.20 + bingoSetting = bingoSetting + offset + + local group = Group.getByName(groupName) + if group then + for _, unit in pairs(group:getUnits()) do + if unit and unit:isExist() == true and unit:inAir() == true and unit:getFuel() < bingoSetting then + return true + end + end + end + + return false + end + + ---comment + ---@param groupId number + ---@return Group? + function DCS_UTIL.GetPlayerGroupByGroupID(groupId) + for i = 0, 2 do + local players = coalition.getPlayers(i) + for key, unit in pairs(players) do + if unit and unit:isExist() == true then + local group = unit:getGroup() + if group and group:getID() == groupId then + return group + end + end + end + end + end + + ---@param unitID number + ---@return Unit? + function DCS_UTIL.GetPlayerUnitByID(unitID) + for i = 0, 2 do + local players = coalition.getPlayers(i) + for key, unit in pairs(players) do + if unit and unit:getID() == unitID then + return unit + end + end + end + end + + DCS_UTIL.__INIT(); +end +return DCS_UTIL diff --git a/src/classes/util/Logger.lua b/src/classes/util/Logger.lua new file mode 100644 index 0000000..29fa232 --- /dev/null +++ b/src/classes/util/Logger.lua @@ -0,0 +1,75 @@ + +local Util = require("classes.util.Util") + +--- @class Logger +--- @field LoggerName string the name of the logger +--- @field LogLevel string the log level of the logger +local LOGGER = {} +do + local PreFix = "Spearhead" + + ---comment + ---@param logger_name any + ---@param logLevel LogLevel + ---@return Logger + function LOGGER.new(logger_name, logLevel) + LOGGER.__index = LOGGER + local self = setmetatable({}, LOGGER) + self.LoggerName = logger_name or "(loggername not set)" + self.LogLevel = logLevel or "INFO" + + return self + end + + ---@param message any the message + function LOGGER:info(message) + if message == nil then + return + end + message = Util.toString(message) + + if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" then + env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) + end + end + + ---comment + ---@param message string + function LOGGER:warn(message) + if message == nil then + return + end + message = Util.toString(message) + + if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" then + env.warning("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) + end + end + + ---@param message any -- the message + function LOGGER:error(message) + if message == nil then + return + end + + message = Util.toString(message) + + if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" or self.LogLevel == "ERROR" then + env.error("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message) + end + end + + ---@param message any the message + function LOGGER:debug(message) + if message == nil then + return + end + + message = Util.toString(message) + if self.LogLevel == "DEBUG" then + env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "][DEBUG] " .. message) + end + end +end + +return LOGGER \ No newline at end of file diff --git a/src/classes/util/MissionEditorWarnings.lua b/src/classes/util/MissionEditorWarnings.lua new file mode 100644 index 0000000..a5ff7ea --- /dev/null +++ b/src/classes/util/MissionEditorWarnings.lua @@ -0,0 +1,26 @@ + +---@class MissionEditingWarnings +local MissionEditingWarnings = {} +function MissionEditingWarnings.Add(warningMessage) + table.insert(MissionEditingWarnings, warningMessage or "skip") +end + +---@param logger Logger +function MissionEditingWarnings.WriteAll(logger) + + if not logger then + return + end + + if not MissionEditingWarnings or #MissionEditingWarnings == 0 then + return + end + + logger:warn("Mission Editor Warnings:") + for _, warning in ipairs(MissionEditingWarnings) do + logger:warn("- " .. warning) + end + +end + +return MissionEditingWarnings \ No newline at end of file diff --git a/src/classes/util/Util.lua b/src/classes/util/Util.lua new file mode 100644 index 0000000..41dc0ff --- /dev/null +++ b/src/classes/util/Util.lua @@ -0,0 +1,503 @@ +---@class Util +local UTIL = {} +do -- INIT UTIL + ---splits a string in sub parts by seperator + ---@param input string + ---@param seperator string + ---@return table result list of strings + function UTIL.split_string(input, seperator) + if seperator == nil then + seperator = " " + end + + local result = {} + if input == nil then + return result + end + + for str in string.gmatch(input, "[^" .. seperator .. "]+") do + table.insert(result, str) + end + return result + end + + ---comment + ---@param table any + ---@return number + function UTIL.tableLength(table) + if table == nil then return 0 end + + local count = 0 + for _ in pairs(table) do count = count + 1 end + return count + end + + ---@param orig table + ---@return table copy + function UTIL.deepCopyTable(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[UTIL.deepCopyTable(orig_key)] = UTIL.deepCopyTable(orig_value) + end + setmetatable(copy, UTIL.deepCopyTable(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy + end + + ---Gets a random from the list + ---@param list Array + ---@return any @random element from the list + function UTIL.randomFromList(list) + local max = #list + + if max == 0 or max == nil then + return nil + end + + local random = math.random(0, max) + if random == 0 then random = 1 end + + return list[random] + end + + ---@param list Array + ---@param start number start + ---@param n number length + ---@return Array + function UTIL.sublist(list, start, n) + local result = {} + for i = start, n do + result[#result + 1] = list[i] + end + return result + end + + ---@param str string + ---@param find string + ---@param replace string + ---@return string + function UTIL.replaceString(str, find, replace) + if str == nil then return "" end + if find == nil or replace == nil then return str end + + local result = str:gsub(find, replace) + return result + end + + local function table_print(tt, indent, done) + done = done or {} + indent = indent or 0 + if type(tt) == "table" then + local sb = {} + for key, value in pairs(tt) do + table.insert(sb, string.rep(" ", indent)) -- indent it + if type(value) == "table" and not done[value] then + done[value] = true + table.insert(sb, "[\"" ..key .. "\"]" .. " = {\n"); + table.insert(sb, table_print(value, indent + 2, done)) + table.insert(sb, string.rep(" ", indent)) -- indent it + table.insert(sb, "},\n"); + elseif "number" == type(key) then + table.insert(sb, string.format("\"%s\",\n", tostring(value))) + else + table.insert(sb, string.format( + "[\"%s\"] = \"%s\",\n", tostring(key), tostring(value))) + end + end + return table.concat(sb) + else + return tt .. "\n" + end + end + + ---comment + ---@param str string + ---@param findable string + ---@param ignoreCase boolean? + ---@return boolean + UTIL.startswith = function(str, findable, ignoreCase) + if ignoreCase == true then + return string.lower(str):find('^' .. string.lower(findable)) ~= nil + end + + return str:find('^' .. findable) ~= nil + end + + ---comment + ---@param str string + ---@param findable string + ---@return boolean + UTIL.strContains = function(str, findable) + return str:find(findable) ~= nil + end + + ---comment + ---@param str string + ---@param findableTable table + ---@return boolean + UTIL.startswithAny = function(str, findableTable) + for key, value in pairs(findableTable) do + if type(value) == "string" and UTIL.startswith(str, value) then return true end + end + return false + end + + function UTIL.toString(something) + if something == nil then + return "nil" + elseif "table" == type(something) then + return table_print(something) + elseif "string" == type(something) then + return something + else + return tostring(something) + end + end + + ---comment + ---@param a Vec2 + ---@param b Vec2 + ---@return number + function UTIL.VectorDistance2d(a, b) + return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2) + end + + ---comment + ---@param a Vec3 + ---@param b Vec3 + ---@return number + function UTIL.VectorDistance3d(a, b) + return UTIL.vectorMagnitude({ x = a.x - b.x, y = a.y - b.y, z = a.z - b.z }) + end + + ---comment + ---@param vec Vec3 + ---@return number + function UTIL.vectorMagnitude(vec) + return (vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2) ^ 0.5 + end + + ---@param vec Vec3 + ---@return Vec3 + function UTIL.vectorNormalize(vec) + local magnitude = UTIL.vectorMagnitude(vec) + if magnitude == 0 then + return { x = 0, y = 0, z = 0 } + end + return { x = vec.x / magnitude, y = vec.y / magnitude, z = vec.z / magnitude } + end + + ---@param vec Vec2 + ---@param direction number @in degrees + ---@param distance number + ---@return Vec2 + function UTIL.vectorMove(vec, direction, distance) + local rad = math.rad(direction) + local x = vec.x + (math.cos(rad) * distance) + local y = vec.y + (math.sin(rad) * distance) + + return { x = x, y = y} + end + + ---comment + ---@param vec1 Vec2 + ---@param vec2 Vec2 + ---@return number in degrees + function UTIL.vectorHeadingFromTo(vec1, vec2) + local dx = vec2.x - vec1.x + local dy = vec2.y - vec1.y + local heading = math.deg(math.atan2(dy, dx)) + if heading < 0 then + heading = heading + 360 + end + return heading + end + + + + ---@param vec1 Vec3 + ---@param vec2 Vec3 + ---@return number alignment a number in range [-1,1]. > 0 same direction. < 0 opposite direction + function UTIL.vectorAlignment(vec1, vec2) + local vec1Norm = UTIL.vectorNormalize(vec1) + local vec2Norm = UTIL.vectorNormalize(vec2) + + return ((vec1Norm.x * vec2Norm.x) + (vec1Norm.y * vec2Norm.y) + (vec1Norm.z * vec2Norm.z)) + end + + local function isInComplexPolygon(polygon, x, y) + local function getEdges(poly) + local result = {} + for i = 1, #poly do + local point1 = poly[i] + local point2Index = i + 1 + if point2Index > #poly then point2Index = 1 end + local point2 = poly[point2Index] + local edge = { x1 = point1.x, z1 = point1.y, x2 = point2.x, z2 = point2.y } + table.insert(result, edge) + end + return result + end + + local edges = getEdges(polygon) + local count = 0; + for _, edge in pairs(edges) do + if (x < edge.x1) ~= (x < edge.x2) and y < edge.z1 + ((x - edge.x1) / (edge.x2 - edge.x1)) * (edge.z2 - edge.z1) then + count = count + 1 + -- if (yp < y1) != (yp < y2) and xp < x1 + ((yp-y1)/(y2-y1))*(x2-x1) then + -- count = count + 1 + end + end + return count % 2 == 1 + end + + ---comment + ---@param polygon Array of pairs { x, y } + ---@param x number X location + ---@param y number Y location + ---@return boolean + function UTIL.IsPointInPolygon(polygon, x, y) + return isInComplexPolygon(polygon, x, y) + end + + ---@param point Vec3 + ---@param zone SpearheadTriggerZone + function UTIL.is3dPointInZone(point, zone) + if zone.zone_type == "Polygon" and zone.verts then + if UTIL.IsPointInPolygon(zone.verts, point.x, point.z) == true then + return true + end + else + if (((point.x - zone.location.x) ^ 2 + (point.z - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then + return true + end + end + + return false + end + + ---@param point Vec2 + ---@param zone SpearheadTriggerZone + function UTIL.is2dPointInZone(point, zone) + if zone.zone_type == "Polygon" and zone.verts then + if UTIL.IsPointInPolygon(zone.verts, point.x, point.y) == true then + return true + end + else + if (((point.x - zone.location.x) ^ 2 + (point.y - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then + return true + end + end + + return false + end + + ---comment + ---@param points Array points + ---@return Array hullPoints + function UTIL.getConvexHull(points) + if #points == 0 then + return {} + end + + ---comment + ---@param a Vec2 + ---@param b Vec2 + ---@param c Vec2 + ---@return boolean + local function ccw(a, b, c) + return (b.y - a.y) * (c.x - a.x) > (b.x - a.x) * (c.y - a.y) + end + + table.sort(points, function(left, right) + return left.y < right.y + end) + + local hull = {} + -- lower hull + for _, point in pairs(points) do + while #hull >= 2 and not ccw(hull[#hull - 1], hull[#hull], point) do + table.remove(hull, #hull) + end + table.insert(hull, point) + end + + -- upper hull + local t = #hull + 1 + for i = #points, 1, -1 do + local point = points[i] + while #hull >= t and not ccw(hull[#hull - 1], hull[#hull], point) do + table.remove(hull, #hull) + end + table.insert(hull, point) + end + table.remove(hull, #hull) + return hull + end + + ---Splits points into clusters with at least minSeparation between clusters, returns convex hull for each cluster + ---@param points Array + ---@param minSeparation number + ---@return Array> hulls + function UTIL.getSeparatedConvexHulls(points, minSeparation) + if #points == 0 then return {} end + + -- Simple clustering: group points that are within minSeparation of each other + local clusters = {} + local assigned = {} + + for i, p in ipairs(points) do + if not assigned[i] then + local cluster = { p } + assigned[i] = true + -- Find all points close to p (BFS) + local queue = { i } + while #queue > 0 do + local idx = table.remove(queue) + local base = points[idx] + for j, q in ipairs(points) do + if not assigned[j] then + local dx = base.x - q.x + local dy = base.y - q.y + if (dx * dx + dy * dy) <= (minSeparation * minSeparation) then + table.insert(cluster, q) + assigned[j] = true + table.insert(queue, j) + end + end + end + end + table.insert(clusters, cluster) + end + end + + -- Compute convex hull for each cluster + local hulls = {} + for _, cluster in ipairs(clusters) do + local hull = UTIL.getConvexHull(cluster) + if #hull > 0 then + table.insert(hulls, hull) + end + end + + return hulls + end + + ---@param points Array + function UTIL.enlargeConvexHull(points, meters) + if points == nil or #points == 0 then + return {} + end + + ---@type Array + local allpoints = {} + + for _, point in pairs(points) do + table.insert(allpoints, point) + + allpoints[#allpoints + 1] = point + allpoints[#allpoints+1] = { x = point.x + meters, y = point.y, } + allpoints[#allpoints+1] = { x = point.x - meters, y = point.y, } + allpoints[#allpoints+1] = { x = point.x, y = point.y + meters, } + allpoints[#allpoints+1] = { x = point.x, y = point.y - meters, } + + allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, } + allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, } + allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, } + allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, } + end + + return UTIL.getConvexHull(allpoints) + end + + ---Returns hull points visible from origin (not blocked by hull edges) +---@param hull Array +---@param origin Vec2 +---@return Array +function UTIL.GetVisibleHullPointsFromOrigin(hull, origin) + local function segmentsIntersect(a, b, c, d) + -- Helper: returns true if segment ab intersects cd (excluding endpoints) + local function ccw(p1, p2, p3) + return (p3.y - p1.y) * (p2.x - p1.x) > (p2.y - p1.y) * (p3.x - p1.x) + end + return (ccw(a, c, d) ~= ccw(b, c, d)) and (ccw(a, b, c) ~= ccw(a, b, d)) + end + + local n = #hull + local visible = {} + + for i = 1, n do + local p = hull[i] + local isVisible = true + + -- Check against all hull edges except those incident to p + for j = 1, n do + local a = hull[j] + local b = hull[(j % n) + 1] + -- skip edges incident to p + if (a ~= p and b ~= p) then + if segmentsIntersect(origin, p, a, b) then + isVisible = false + break + end + end + end + + if isVisible then + table.insert(visible, p) + end + end + + return visible +end + +---Returns the two tangent points ("scratch points") from origin to the convex hull +---@param hull Array +---@param origin Vec2 +---@return Array +function UTIL.GetTangentHullPointsFromOrigin(hull, origin) + + if hull == nil or #hull <= 0 then + return {} + end + + local function orientation(a, b, c) + -- Returns >0 if c is to the left of ab, <0 if to the right, 0 if colinear + return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) + end + + local n = #hull + if n == 0 then return {} end + if n == 1 then return { hull[1] } end + + -- Find left tangent: the hull point where all other points are to the right of the line from origin to that point + local function findTangent(isLeft) + local best = 1 + for i = 2, n do + local o = orientation(origin, hull[best], hull[i]) + if (isLeft and o < 0) or (not isLeft and o > 0) then + best = i + end + end + return hull[best] + end + + local leftTangent = findTangent(true) + local rightTangent = findTangent(false) + + -- If tangents are the same (can happen if origin is colinear), only return one + if leftTangent.x == rightTangent.x and leftTangent.y == rightTangent.y then + return { leftTangent } + else + return { leftTangent, rightTangent } + end +end + +end + +return UTIL \ No newline at end of file diff --git a/src/main.lua b/src/main.lua new file mode 100644 index 0000000..763ac58 --- /dev/null +++ b/src/main.lua @@ -0,0 +1,96 @@ +--Single player purpose + +local Logger = require("classes.util.Logger") +local DcsUtil = require("classes.util.DcsUtil") +local Database = require("classes.spearhead_db") +local SpearheadEvents = require("classes.spearhead_events") +local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper") +local CapConfig = require("classes.configuration.CapConfig") +local StageConfig = require("classes.configuration.StageConfig") +local Persistence = require("classes.persistence.Persistence") +local SpawnManager = require("classes.helpers.SpawnManager") +local DetectionManager = require("classes.capClasses.detection.DetectionManager") +local GlobalCapManager = require("classes.capClasses.GlobalCapManager") +local GlobalStageManager = require("classes.stageClasses.GlobalStageManager") +local GlobalFleetManager = require("classes.fleetClasses.GlobalFleetManager") +local MissionEditorWarnings = require("classes.util.MissionEditorWarnings") + +local defaultLogLevel = "INFO" + +if SpearheadConfig and SpearheadConfig.debugEnabled == true then + defaultLogLevel = "DEBUG" +end + +local startTime = timer.getTime() * 1000 + +SpearheadEvents.Init(defaultLogLevel) + +local dbLogger = Logger.new("database", defaultLogLevel) +local standardLogger = Logger.new("", defaultLogLevel) +local databaseManager = Database.New(dbLogger) +MissionCommandsHelper.getOrCreate(defaultLogLevel) -- initiate + +local capConfig = CapConfig:new(); +local stageConfig = StageConfig:new(); + +local startingStage = stageConfig.startingStage or 1 +if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then + standardLogger:info("Persistence enabled") + local persistenceLogger = Logger.new("Persistence", defaultLogLevel) + Persistence.Init(persistenceLogger) + + local persistanceStage = Persistence.GetActiveStage() + if persistanceStage then + standardLogger:info("Persistance activated and using persistant active stage: " .. persistanceStage) + startingStage = persistanceStage + end +else + standardLogger:info("Persistence disabled") +end + +local spawnLogger = Logger.new("SpawnManager", defaultLogLevel) +local spawnManager = SpawnManager.new(spawnLogger) +local detectionLogger = Logger.new("DetectionManager", defaultLogLevel) +local detectionManager = DetectionManager.New(detectionLogger) + +GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager) +GlobalStageManager.NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager) +GlobalFleetManager.start(databaseManager) + +local SetStageDelayed = function(number, time) + SpearheadEvents.PublishStageNumberChanged(number) + return nil +end + +timer.scheduleFunction(SetStageDelayed, startingStage, timer.getTime() + 3) + +env.info(startTime .. "ms / " .. timer.getTime() * 1000 .. "ms") +local duration = (timer.getTime() * 1000) - startTime +standardLogger:info("Spearhead Initialisation duration: " .. tostring(duration) .. "ms") + +local missionEditorWarningsLogger = Logger.new("MissionEditorWarnings", defaultLogLevel) +MissionEditorWarnings.WriteAll(missionEditorWarningsLogger) +GlobalStageManager:printFullOverview() + +--Check lines of code in directory per file: +-- Get-ChildItem . -Include *.lua -Recurse | foreach {""+(Get-Content $_).Count + " => " + $_.name }; GCI . -Include *.lua* -Recurse | foreach{(GC $_).Count} | measure-object -sum | % Sum +-- find . -name '*.lua' | xargs wc -l + +--- ==================== DEBUG ORDER OR ZONE VEC =========================== +-- local zone = Spearhead.DcsUtil.getZoneByName("MISSIONSTAGE_99") + +-- local count = Spearhead.Util.tableLength(zone.verts) + +-- for i = 1, count - 1 do + +-- local a = zone.verts[i] +-- local b = zone.verts[i+1] + +-- local color = {0,0,0,1} + +-- color[i] = 1 + +-- trigger.action.textToAll(-1, 46+i , { x= a.x, y = 0, z = a.z } , color, {0,0,0}, 24 , true , "" .. i ) +-- trigger.action.lineToAll(-1 , 56+i , { x= a.x, y = 0, z = a.z } , { x = b.x, y = 0, z = b.z } , color , 1, true) + +-- end