Compare commits

...

135 Commits

Author SHA1 Message Date
Thomas b33890ff03 Merge pull request #2613 from FlightControl-Master/master-ng
Merge
2026-07-17 07:20:29 +02:00
Thomas 1be2c92a5c Merge pull request #2612 from shaji-Dev/master-ng
CTLD + ENUMS
2026-07-17 07:19:31 +02:00
shafik 4c8a17fe57 Merge remote-tracking branch 'origin/master-ng' into master-ng 2026-07-16 19:58:51 +02:00
shafik 64dea17982 [FIXED] Hardcoded "blue" coalition in SET filters (Doesn't work for redfor in PvP).
[FIXED] Unnecessary new COORDINATE objects that don't hold reference (used only for distance calc).
2026-07-16 19:58:36 +02:00
shafik b1f86c702d [ADDED] F-100 weapons enums 2026-07-16 19:48:35 +02:00
Thomas 1a9540d0d4 Merge pull request #2611 from FlightControl-Master/develop
Develop
2026-07-16 06:45:05 +02:00
Thomas cdfaac527c Merge pull request #2606 from shaji-Dev/master-ng
[FIX] "Parameter #1 (group id) missed" refreshing menus for dead groups
2026-07-15 19:53:58 +02:00
Thomas 4e3bf9969b Merge pull request #2610 from FlightControl-Master/master-ng
Merge from master
2026-07-15 19:52:43 +02:00
Thomas 74c16bd4f0 Merge pull request #2609 from leka1986/agent/group-change-option-event
Add group option change event support
2026-07-15 19:51:38 +02:00
leka1986 55e048b322 Add group option change event support 2026-07-15 18:39:46 +02:00
Thomas b31fb7ece3 Merge pull request #2608 from FlightControl-Master/master-ng
Merge from master
2026-07-15 18:35:50 +02:00
Thomas 149e3421d9 Merge pull request #2607 from patpatpowercat/develop
Update Mantis.lua
2026-07-15 18:34:53 +02:00
patpatpowercat 338ec34604 Update Mantis.lua
Added ships to MANTIS.

NAVYGROUPs may be integrated. Need to be aware MANTIS doesn't change ROE.

SEAD does not (by default) effect ships.

Ships are individually identified, not as group. Group will react to jamming as a whole, will go live/sleep based upon longest range/best radar.

No longer need prefixes for either ground or naval units.
2026-07-14 21:47:47 -07:00
Shafik 3d79a16d3a [FIX] "Parameter #1 (group id) missed" refreshing menus for dead groups 2026-07-13 11:02:42 +03:00
Thomas efa08c1280 Merge pull request #2605 from FlightControl-Master/master-ng
Merge from master
2026-07-12 17:58:28 +02:00
Thomas 589e65963f Merge pull request #2604 from FlightControl-Master/leka1986-patch-2
Fix aircraft model names for Lancer and Kiowa
2026-07-12 17:57:29 +02:00
leka1986 af4f20af67 Fix aircraft model names for Lancer and Kiowa 2026-07-12 13:30:33 +02:00
Applevangelist b1b8630d21 Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-28 09:31:16 +02:00
Applevangelist 98ed7d50c1 #EASYGCICAP
* Added `SetDefaultINTERCEPTAlt()`
2026-06-28 09:30:45 +02:00
Applevangelist 4ba81cb8bc Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-27 10:57:53 +02:00
Applevangelist 626b12f486 #MSRS #HOUND corrected frequency formatting to allow 1000ths of a frequency 2026-06-27 10:57:27 +02:00
Thomas 36c0297344 Merge pull request #2603 from FlightControl-Master/master-ng
Update ScheduleDispatcher.lua
2026-06-26 12:35:03 +02:00
Thomas 8c60a8c678 Update ScheduleDispatcher.lua
Undoing previous change as some delayed event calls stopped working, probably FSM. Need to find the reason for that.
2026-06-26 12:31:54 +02:00
Thomas 6829d75464 Merge pull request #2602 from FlightControl-Master/master-ng
Merge
2026-06-24 06:30:19 +02:00
Thomas 867f919d5f Merge pull request #2601 from FlightControl-Master/leka1986-patch-2
Update Utils.lua
2026-06-24 06:29:28 +02:00
leka1986 f769a0deb5 Update Utils.lua
Added KA-50_3 door check.
2026-06-24 01:56:31 +02:00
Applevangelist 4efd71e36a Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-23 12:30:14 +02:00
Applevangelist 7e9dd9deff #EASYGCICAP - fall back to GCI behaviour if no CAP Points have been defined. 2026-06-23 12:29:45 +02:00
Applevangelist fed9174bcb Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-21 12:53:35 +02:00
Applevangelist b6ea6606fc #SCHEDULEDISPATCHER - Fixing a memory leak. Thanks to @Shazzer1951 2026-06-21 12:51:50 +02:00
Thomas 9963c737a3 Merge pull request #2599 from FlightControl-Master/master-ng
Merge from master
2026-06-14 17:53:05 +02:00
Thomas 5005203206 Merge pull request #2598 from patpatpowercat/develop
Update Airboss.lua
2026-06-14 17:52:13 +02:00
patpatpowercat a3455855b8 Update Airboss.lua
Remove max speed check that limits WOD in high winds.

This restriction seems redundant with GetHeadingIntoWind_new should return 30 with 0 wind (max carrier speed) regardless of requested WOD speed.
2026-06-14 08:36:38 -07:00
Applevangelist 73d3ed119c Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-14 16:11:05 +02:00
Applevangelist d1e4dd3fe9 #EVENT - small fix 2026-06-14 16:10:34 +02:00
Applevangelist 23112c9954 Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-14 13:45:08 +02:00
Applevangelist 9326cfad1c #AIRBASE - Add Syria Airbases 2026-06-14 13:44:44 +02:00
Applevangelist 23c59d906f Merge remote-tracking branch 'origin/develop' into develop 2026-06-14 12:07:31 +02:00
Applevangelist cc62655ffe Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-14 12:07:25 +02:00
Applevangelist b8e114101b #EVENT - Event Shoot fix for ZELL Boosters 2026-06-14 12:06:54 +02:00
Thomas 401e9d9e8e Merge pull request #2597 from FlightControl-Master/master-ng
Merge from master
2026-06-14 09:57:46 +02:00
Thomas f083b77390 Merge pull request #2596 from patpatpowercat/develop
Update Airboss.lua
2026-06-14 09:56:13 +02:00
patpatpowercat db3bc3742e Update Airboss.lua
Fix: manually stopped recovery windows immediately re-open. _CheckRecoveryTimes re-opened any window in its active time range without checking recovery.OVER, while DeleteRecoveryWindow failed to remove still-open windows. Added the OVER guard on the open path and made window deletion reliable and iteration-safe.
2026-06-13 09:36:27 -07:00
Applevangelist 9b1a3e4894 Merge remote-tracking branch 'origin/master-ng' into develop
# Conflicts:
#	Moose Development/Moose/Core/Spawn.lua
2026-06-11 17:34:53 +02:00
Applevangelist bf10196662 xx 2026-06-11 17:34:19 +02:00
Thomas 6c32aa6044 Merge pull request #2595 from geofffranks/fix/spawn-air-takeoff-event-args
fix(Spawn): air-spawn takeoff event never fired (wrong arg packing)
2026-06-11 07:59:43 +02:00
Geoff Franks edf70e971c fix(Spawn): air-spawn takeoff event never fired (wrong arg packing)
SPAWN:SpawnAtAirbase scheduled the synthetic takeoff event for air-spawned
groups with:

    self:ScheduleOnce(5, BASE.CreateEventTakeoff,
                      {GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject()})

BASE:ScheduleOnce(Start, SchedulerFunction, ...) forwards its trailing
arguments to the scheduled function as varargs (it wraps `...` in a table
internally). Wrapping the arguments in a table here made that table argument
number one, so CreateEventTakeoff ran with the {group, time, dcs} table as
`self`. A plain table has no :F(), the very first line errored, and the
S_EVENT_TAKEOFF event was never raised. Air-spawned AI_A2A_DISPATCHER GCI
defenders therefore never activated (observed: zero QRA scrambled with
takeoff = Air).

The sibling call site in SpawnAtParkingSpot is correct because it uses
SCHEDULER:New(nil, fn, {args}, 5), which DOES take a single argument table.
Drop the braces so the args pass as varargs, matching CreateEventTakeoff's
(self=group, EventTime, Initiator) signature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 21:02:40 -04:00
Thomas 7c5af54473 Merge pull request #2594 from FlightControl-Master/master-ng
Merge from master
2026-06-07 20:04:55 +02:00
Thomas a0420e1cb6 Merge pull request #2593 from patpatpowercat/develop
Update Mantis.lua
2026-06-07 20:04:10 +02:00
Applevangelist 2aa9b91ce5 Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-05 14:25:35 +02:00
Applevangelist 27bd27a2e5 #EASYGCICAP - create correct number of Alert5 missions instead of relying on the number of required assets 2026-06-05 14:25:02 +02:00
patpatpowercat 8e219c5877 Update Mantis.lua
Widened (long-range systems): Nike, Hawk, SA-5, SA-12, SA-20A/B, SA-21/S-400, SA-22, SA-23/B, Patriot PAC-2/3, NASAMS, HQ-22, THAAD, IRIS-T, SON-9 → matches actual radar coverage rather than missile kinematic range
Tightened (short-range systems): SA-15, SA-19, HQ-7, HQ-17, Rapier → SHORAD shouldn't be jammable from absurd standoff
2026-06-01 11:20:24 -07:00
Applevangelist fdc19a6898 Merge remote-tracking branch 'origin/develop' into develop 2026-05-24 13:01:26 +02:00
Applevangelist d3ebf023fb Merge remote-tracking branch 'origin/master-ng' into develop 2026-05-24 13:01:22 +02:00
Applevangelist 3d1dcd78a3 #SPAWN - fix SpawnOnRunway if definitely requested (SP only!) 2026-05-24 13:00:57 +02:00
Thomas d40c559d2d Merge pull request #2592 from FlightControl-Master/master-ng
Merge
2026-05-21 20:04:54 +02:00
Thomas 9cda1b88ea Merge pull request #2591 from patpatpowercat/develop
Add jammer ability to MANTIS
2026-05-21 20:03:54 +02:00
patpatpowercat 09f99b9a74 Merge branch 'develop' of https://github.com/FlightControl-Master/MOOSE into develop 2026-05-19 09:41:34 -07:00
Thomas ff5205e686 Merge pull request #2590 from FlightControl-Master/master-ng
Merge from master
2026-05-18 06:24:53 +02:00
Thomas ebd105f80d Merge pull request #2589 from FlightControl-Master/leka1986-patch-1
Update Shorad.lua
2026-05-18 06:23:59 +02:00
leka1986 cc8a4e0bad Update CTLD_Localization.lua
Added Italian localization.
2026-05-16 19:29:50 +02:00
leka1986 5f70e2d6b1 Add Italian locale support to CTLD
Added Italian Localization
2026-05-16 19:29:07 +02:00
leka1986 95f38fbf55 Update Shorad.lua
Fix tgtgrp2 is nil.
2026-05-16 19:27:06 +02:00
Applevangelist aec3466f13 Merge remote-tracking branch 'origin/master-ng' into develop 2026-05-14 10:47:23 +02:00
Applevangelist 696630fe4d #SUPPRESSION - fix typo 2026-05-14 10:46:22 +02:00
Applevangelist 47aa524677 Merge remote-tracking branch 'origin/master-ng' into develop 2026-05-10 13:04:56 +02:00
Applevangelist 79f03c164c xx 2026-05-10 13:04:29 +02:00
patpatpowercat ca7d3a48a7 Update Mantis.lua
The following code is modified MANTIS code that adds jamming capability. It has new custom code for all SAMs, fixes a couple SAM issues (S-300V/V4, adds SON-9). Clients/players can select their loadout, and then utilize the F10 menu to turn the jammer on/off. For AI aircraft, they can be setup with whatever loadout, and then scripted to turn their jammer on/off.
2026-05-08 14:02:06 -07:00
Thomas 2556dbe145 Merge pull request #2588 from FlightControl-Master/master-ng
Update Auftrag.lua
2026-05-05 11:47:29 +02:00
Thomas af1e9546e5 Update Auftrag.lua
line 6613 - Fix for HasSEAD should it find statics unexpectedly
2026-05-05 11:46:16 +02:00
Thomas 3203a22668 Merge pull request #2587 from FlightControl-Master/master-ng
Merge
2026-05-05 10:34:35 +02:00
Thomas b69ac2f86f Merge pull request #2586 from FlightControl-Master/leka1986-patch-1
Update CTLD.lua
2026-05-05 10:33:36 +02:00
leka1986 0d410f3e55 Update CTLD.lua
remove whitespace
2026-05-03 19:51:24 +02:00
leka1986 cbe6756330 Update CTLD.lua 2026-05-03 19:27:46 +02:00
leka1986 07045be32b Update CTLD_Localization.lua
Added traditional Chinese and Taiwan Chinese
2026-05-03 19:27:16 +02:00
leka1986 52a2132463 Update CTLD_Localization.lua
Added CH,  PT-BR, TR.
2026-05-03 16:21:14 +02:00
leka1986 9272b1f18c Update CTLD.lua
### Summary
- Added an optional CTLD group locale resolver for group-targeted menus and messages.
- Routed CTLD group menu/message localization through group-aware lookup while preserving `self.locale` as the default fallback.
- Added an optional cargo display formatter with group context for missions that need custom cargo labels.
- Added `MENU_CRATE_SINGLE` localization so single-crate menu labels use the localization table, matching multi-crate labels.

### Compatibility
Default behavior is unchanged unless a mission calls `SetGroupLocaleResolver` or `SetCargoDisplayFormatter`.

### Motivation
This allows missions with per-player or per-group language settings to localize CTLD menus and group messages without changing the global CTLD locale, This can be used to persist localization choice using the player name.
2026-05-03 16:19:44 +02:00
Applevangelist b84880c0dd Merge remote-tracking branch 'origin/develop' into develop 2026-05-01 12:46:49 +02:00
Applevangelist a9be18b284 Merge remote-tracking branch 'origin/master-ng' into develop 2026-05-01 12:46:45 +02:00
Thomas 93178df67f Merge pull request #2585 from FlightControl-Master/master-ng
Merge from master
2026-04-30 17:38:17 +02:00
Thomas f34bf1e052 Merge pull request #2584 from HoodiNahi/fix/spawn-init-randomize-zones-nil-gaurd
Fix(Spawn):add nil gaurd to InitRandomizeZones
2026-04-30 17:37:30 +02:00
HoodiNahi e159eb83b7 fix syntax 2026-04-30 20:07:36 +05:30
HoodiNahi 2581836058 Fix(Spawn):add nil gaurd to InitRandomizeZones 2026-04-30 20:03:52 +05:30
Thomas d9651e1dea Merge pull request #2583 from FlightControl-Master/master-ng
Pr
2026-04-27 17:34:03 +02:00
Thomas 0347f185a5 Merge pull request #2582 from FlightControl-Master/leka1986-patch-1
Leka1986 patch 1
2026-04-27 17:33:27 +02:00
leka1986 5e2218de38 Expand locale options in CTLD.lua
Updated language locale options to include Spanish and Russian.
2026-04-26 19:26:23 +02:00
leka1986 6db5441bb1 Modify parking spot handling in Spawn.lua
Refactor parking spot usage logic to use explicit spots when available.
2026-04-26 19:13:09 +02:00
leka1986 13b7e43729 Update CTLD_Localization.lua
Russian localization.
2026-04-26 19:11:26 +02:00
leka1986 a72f7298d0 Update CTLD.lua
Added Russian locale, 

- my_ctld.locale = "ru"
2026-04-26 19:10:03 +02:00
Applevangelist 801cc105da Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-25 16:49:58 +02:00
Applevangelist f186b4bd58 xx 2026-04-25 16:49:10 +02:00
Frank 79f13fa6ae Update Warehouse.lua
- fixes bug that descriptors are not obtained
2026-04-25 16:45:26 +02:00
Applevangelist d38fc4ec8f Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-23 12:41:40 +02:00
Applevangelist ba1575d674 #MSRS - Added Hound Jammer option functionality 2026-04-23 12:41:01 +02:00
Applevangelist 391182e23f Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-21 18:30:01 +02:00
Applevangelist 6d5fb64fde #TARS - Docu additions 2026-04-21 18:29:25 +02:00
Frank 5df1fb88f1 Merge branch 'master-ng' of https://github.com/FlightControl-Master/MOOSE into master-ng 2026-04-20 21:47:38 +02:00
Frank 2e4d4f056a Update SRS.lua
- fixed bug if no frequencies and/or modulations are specified (UTILS.EnsureTable returned an empty table not nil. therefore, self.frequencies and self.modulations was not used)
2026-04-20 21:47:36 +02:00
Thomas a9ceda4edd Merge pull request #2580 from FlightControl-Master/master-ng
Merge from master
2026-04-20 06:36:40 +02:00
Thomas e76fd23396 Merge pull request #2579 from FlightControl-Master/leka1986-patch-1
Update Spawn.lua
2026-04-20 06:35:31 +02:00
leka1986 7df1eb963f Update CSAR.lua
CSAR now treats aircraft with AircraftType[type] <= 0 as not CSAR-capable when building the active SAR unit list, while still allowing those type keys to exist for other systems such as FARP storage setup.

Added those to the type,

CSAR.AircraftType["Ka-50_3"] = 0
CSAR.AircraftType["Ka-50"] = 0
CSAR.AircraftType["AV8BNA"] = 0
2026-04-19 20:36:44 +02:00
leka1986 aff1d3c7db Update Spawn.lua
SPAWN:SpawnAtAirbase() and SPAWN:ParkAircraft() now handle HELIPAD/FARP parking the same way as airbases: explicit parking is honored first, helicopter spawns try the smarter parking search before falling back to the simpler free-spot table.
2026-04-19 20:35:20 +02:00
Applevangelist d15f6cdb44 Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-19 15:31:01 +02:00
Applevangelist c59b668eec #TARS
- Correct optical view projection implemented (ellipse bc of the angle of view)
- Duration now describes the number of expositions your camera has
- Interval of shots is dependent on the speed of the TARS unit
- Added platform parameters overlap (of shots, usually 25% for faster movers, 50% for slower ones), overlap is clamped by minimum interval — at high speeds the interval floor is reached and overlap effectively increases (and you go through shots really fast)
- Fixed zone draw for debug
2026-04-19 15:29:40 +02:00
Applevangelist 4620a83317 Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-16 12:38:47 +02:00
Applevangelist 87d0c4e9d4 #TARS - Added TARS_SESSION.debugunitsearch = false and F10 search zone draw for debugging 2026-04-16 12:38:15 +02:00
Thomas 74361f6a3a Merge pull request #2578 from FlightControl-Master/master-ng
Merge
2026-04-16 07:00:29 +02:00
Thomas b82b882e02 Merge pull request #2577 from FlightControl-Master/leka1986-patch-1
Update CTLD.lua
2026-04-16 06:59:46 +02:00
leka1986 347783d4b7 Update CTLD_Localization.lua
---
-- @field Messages
CTLD.Messages = {
    EN = {
        -- ============================================================
        -- Crate / Cargo Loading
        -- ============================================================
        CRATE_LOADED_GROUNDCREW         = "Crate %s loaded by ground crew!",
        CRATE_UNLOADED_GROUNDCREW       = "Crate %s unloaded by ground crew!",
        CRATE_LOADED_ID                 = "Crate ID %d for %s loaded!",
        LOADED_FULL                     = "Loaded %d %s.",
        LOADED_SETS_LEFTOVER            = "Loaded %d %s(s), with %d leftover crate(s).",
        LOADED_SETS                     = "Loaded %d %s(s).",
        LOADED_PARTIAL                  = "Loaded only %d/%d crate(s) of %s.",
        LOADED_PARTIAL_LIMIT            = "Loaded only %d/%d crate(s) of %s. Cargo limit is now reached!",
        LOADED_BATCH                    = "Loaded %d %s.",
        LOADED_BATCH_PARTIAL            = "Some sets could not be fully loaded.",
        -- ============================================================
        -- Dropping / Unloading
        -- ============================================================
        DROPPED_FULL                    = "Dropped %d %s.",
        DROPPED_SETS_LEFTOVER           = "Dropped %d %s(s), with %d leftover crate(s).",
        DROPPED_SETS                    = "Dropped %d %s(s).",
        DROPPED_PARTIAL                 = "Dropped %d/%d crate(s) of %s.",
        DROPPED_INTO_ACTION             = "Dropped %s into action!",
        DROPPED_BEACON                  = "Dropped %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        CRATES_POSITIONED               = "%d crates for %s have been positioned near you!",
        CRATES_DROPPED                  = "%d crates for %s have been dropped!",
        -- ============================================================
        -- Troops
        -- ============================================================
        BOARDED                         = "%s boarded!",
        BOARDING                        = "%s boarding!",
        TROOPS_RETURNED                 = "Troops have returned to base!",
        -- ============================================================
        -- Deployment
        -- ============================================================
        DEPLOYED_NEAR_YOU               = "%s have been deployed near you!",
        UNITS_REMOVED                   = "%s have been removed",
        -- ============================================================
        -- Build / Repair
        -- ============================================================
        BUILD_STARTED                   = "Build started, ready in %d seconds!",
        REPAIR_STARTED                  = "Repair started using %s taking %d secs",
        NO_UNIT_TO_REPAIR               = "No unit close enough to repair!",
        CANT_REPAIR_WITH                = "Can't repair this unit with %s",
        CRATES_MOVE_BEFORE_BUILD        = "*** Crates need to be moved before building!",
        -- ============================================================
        -- Errors - Chopper / Weight / Capacity
        -- ============================================================
        CHOPPER_CANNOT_CARRY            = "Sorry this chopper cannot carry crates!",
        TOO_HEAVY                       = "Sorry, that's too heavy to load!",
        FULLY_LOADED                    = "Sorry, we are fully loaded!",
        CRAMMED                         = "Sorry, we're crammed already!",
        NO_CAPACITY_NOW                 = "No capacity to load more now!",
        NO_MORE_CAPACITY                = "No more capacity to load crates!",
        CANNOT_LOAD_NONE_OR_FULL        = "Cannot load crates: either none found or no capacity left.",
        -- ============================================================
        -- Errors - Position
        -- ============================================================
        NEED_TO_LAND_OR_HOVER_LOAD      = "You need to land or hover in position to load!",
        HOVER_OVER_CRATES               = "Hover over the crates to pick them up!",
        LAND_OR_HOVER_OVER_CRATES       = "Land or hover over the crates to pick them up!",
        MUST_LAND_OR_HOVER_CRATES       = "You must land or hover to load crates!",
        NEED_TO_LAND_BUILD              = "You need to land / stop to build something, Pilot!",
        NOT_CLOSE_ENOUGH_LOGISTICS      = "You are not close enough to a logistics zone!",
        NOT_CLOSE_ENOUGH_DROP           = "You are not close enough to a drop zone!",
        NOT_CLOSE_ENOUGH_ZONE_NM        = "Negative, need to be closer than %dnm to a zone!",
        CANNOT_BUILD_LOADING_AREA       = "You cannot build in a loading area, Pilot!",
        -- ============================================================
        -- Errors - Doors
        -- ============================================================
        OPEN_DOORS_LOAD_CARGO           = "You need to open the door(s) to load cargo!",
        OPEN_DOORS_LOAD_TROOPS          = "You need to open the door(s) to load troops!",
        OPEN_DOORS_EXTRACT_TROOPS       = "You need to open the door(s) to extract troops!",
        OPEN_DOORS_UNLOAD_TROOPS        = "You need to open the door(s) to unload troops!",
        OPEN_DOORS_DROP_CARGO           = "You need to open the door(s) to drop cargo!",
        -- ============================================================
        -- Errors - Stock / Availability
        -- ============================================================
        ALL_GONE                        = "Sorry, all %s are gone!",
        RAN_OUT_OF                      = "Sorry, we ran out of %s",
        CARGO_NOT_AVAILABLE_ZONE        = "The requested cargo is not available in this zone!",
        ENOUGH_CRATES_NEARBY            = "There are enough crates nearby already! Take care of those first!",
        NO_CRATES_WITHIN                = "No (loadable) crates within %d meters!",
        NO_CRATES_WITHIN_PLAIN          = "No crates within %d meters!",
        NO_CRATES_IN_RANGE              = "No crates found in range!",
        NO_NAMED_CRATES_IN_RANGE        = "No \"%s\" crates found in range!",
        NO_LOADABLE_CRATES              = "Sorry, no loadable crates nearby or max cargo weight reached!",
        NO_UNITS_TO_EXTRACT             = "No units close enough to extract!",
        NO_UNIT_CONFIG                  = "No unit configuration found for %s",
        CANT_ONBOARD                    = "Can't onboard %s",
        TOO_MANY_UNITS_NEARBY           = "You already have %d units nearby!",
        NO_CRATE_GROUPS                 = "No crate groups found for this unit!",
        NO_CRATE_SET                    = "No crate set found or index invalid!",
        NO_CRATE_IN_SET                 = "No crate found in that set!",
        NO_TROOP_CHUNK                  = "No troop cargo chunk found for ID %d!",
        TROOP_CHUNK_EMPTY               = "Troop chunk is empty for ID %d!",
        -- ============================================================
        -- Nothing loaded / in stock
        -- ============================================================
        NOTHING_LOADED                  = "Nothing loaded!\nTroop limit: %d | Crate limit %d | Weight limit %d kgs",
        NOTHING_LOADED_AIRDROP          = "Nothing loaded or not within airdrop parameters!",
        NOTHING_LOADED_HOVER            = "Nothing loaded or not hovering within parameters!",
        NOTHING_IN_STOCK                = "Nothing in stock!",
        NOTHING_TO_PACK                 = "Nothing to pack at this distance pilot!",
        NOTHING_TO_REMOVE               = "Nothing to remove at this distance pilot!",
        -- ============================================================
        -- Zone / Info
        -- ============================================================
        ROGER_ZONE                      = "Roger, %s zone %s!",
        -- ============================================================
        -- Report: Hover / Flight Parameters
        -- ============================================================
        HOVER_PARAMS_METRIC             = "Hover parameters (autoload/drop):\n - Min height %dm \n - Max height %dm \n - Max speed 2mps \n - In parameter: %s",
        HOVER_PARAMS_IMPERIAL           = "Hover parameters (autoload/drop):\n - Min height %dft \n - Max height %dft \n - Max speed 6ftps \n - In parameter: %s",
        FLIGHT_PARAMS_IMPERIAL          = "Flight parameters (airdrop):\n - Min height %dft \n - Max height %dft \n - In parameter: %s",
        FLIGHT_PARAMS_METRIC            = "Flight parameters (airdrop):\n - Min height %dm \n - Max height %dm \n - In parameter: %s",
        -- ============================================================
        -- Report Titles  (REPORT:New())
        -- ============================================================
        REPORT_CRATES_FOUND             = "Crates Found Nearby:",
        REPORT_REMOVING_CRATES          = "Removing Crates Found Nearby:",
        REPORT_TRANSPORT_CHECKOUT       = "Transport Checkout Sheet",
        REPORT_INVENTORY                = "Inventory Sheet",
        REPORT_BUILD_CHECKLIST          = "Checklist Buildable Crates",
        REPORT_REPAIR_CHECKLIST         = "Checklist Repairs",
        REPORT_BEACONS                  = "Active Zone Beacons",
        -- ============================================================
        -- Report Section Headers  (report:Add())
        -- ============================================================
        REPORT_SECTION_TROOPS           = "        -- TROOPS --",
        REPORT_SECTION_CRATES           = "       -- CRATES --",
        REPORT_SECTION_CRATES_GC        = "       -- CRATES loaded via Ground Crew --",
        REPORT_SECTION_NONE             = "        N O N E",
        REPORT_SECTION_NONE_ALT         = "     --- None found! ---",
        REPORT_SECTION_NONE_REPAIR      = "     --- None Found ---",
        REPORT_GC_LOADABLE_HINT         = "Probably ground crew loadable (F8)",
        REPORT_TOTAL_MASS               = "Total Mass: %s kg. Loadable: %s kg.",
        REPORT_TROOPS_CRATES_COUNT      = "Troops: %d(%d), Crates: %d(%d)",
        REPORT_TROOPS_CRATETYPES_COUNT  = "Troops: %d, Cratetypes: %d",
        -- ============================================================
        -- Report Row Templates  (per-item lines in reports)
        -- ============================================================
        REPORT_ROW_TROOP                = "Troop: %s size %d",
        REPORT_ROW_CRATE                = "Crate: %s %d/%d",
        REPORT_ROW_CRATE_SIZE1          = "Crate: %s size 1",
        REPORT_ROW_GC_CRATE             = "GC loaded Crate: %s size 1",
        REPORT_ROW_DROPPED_CRATE        = "Dropped crate for %s, %dkg",
        REPORT_ROW_CRATE_KG             = "Crate for %s, %dkg",
        REPORT_ROW_CRATE_REMOVED        = "Crate for %s, %dkg removed",
        REPORT_ROW_UNIT_STOCK           = "Unit: %s | Soldiers: %d | Stock: %s",
        REPORT_ROW_TYPE_CRATE_STOCK     = "Type: %s | Crates per Set: %d | Stock: %s",
        REPORT_ROW_TYPE_STOCK           = "Type: %s | Stock: %s",
        REPORT_ROW_BUILD_CHECK          = "Type: %s | Required %d | Found %d | Can Build %s",
        REPORT_ROW_REPAIR_CHECK         = "Type: %s | Required %d | Found %d | Can Repair %s",
        REPORT_ROW_BEACON               = " %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        -- ============================================================
        -- Weight / Crate limit tokens
        -- ============================================================
        WEIGHT_LIMIT                    = "Weight limit reached",
        CRATE_LIMIT                     = "Crate limit reached",
        -- ============================================================
        -- Menu labels - Top level
        -- ============================================================
        MENU_CTLD                       = "CTLD",
        MENU_MANAGE_TROOPS              = "Manage Troops",
        MENU_MANAGE_CRATES              = "Manage Crates",
        MENU_MANAGE_UNITS               = "Manage Units",
        -- ============================================================
        -- Menu labels - Troops
        -- ============================================================
        MENU_LOAD_TROOPS                = "Load troops",
        MENU_DROP_TROOPS                = "Drop Troops",
        MENU_DROP_ALL_TROOPS            = "Drop ALL troops",
        MENU_EXTRACT_TROOPS             = "Extract troops",
        MENU_DROP_N_TROOPS              = "Drop (%d) %s",
        -- ============================================================
        -- Menu labels - Crates: Get
        -- ============================================================
        MENU_GET_CRATES                 = "Get Crates",
        MENU_GET                        = "Get",
        MENU_GET_AND_LOAD               = "Get and Load",
        MENU_GET_ANYWAY                 = "Get anyway",
        MENU_PARTIALLY_LOAD             = "Partially load",
        MENU_OUT_OF_STOCK               = "Out of stock",
        MENU_TROOP_LIMIT                = "Troop limit reached",
        -- ============================================================
        -- Menu labels - Crates: Load
        -- ============================================================
        MENU_LOAD_CRATES                = "Load Crates",
        MENU_LOAD_ALL                   = "Load ALL",
        MENU_SHOW_LOADABLE_CRATES       = "Show loadable crates",
        MENU_NO_CRATES_FOUND_RESCAN     = "No crates found! Rescan?",
        MENU_USE_C130_LOAD              = "Use C-130 Load system",
        MENU_LOAD_SINGLE                = "Load",
        -- ============================================================
        -- Menu labels - Crates: Drop
        -- ============================================================
        MENU_DROP_CRATES                = "Drop Crates",
        MENU_DROP_ALL_CRATES            = "Drop ALL crates",
        MENU_DROP                       = "Drop",
        MENU_DROP_AND_BUILD             = "Drop and build",
        MENU_DROP_N_SETS                = "Drop %d Set%s",
        MENU_NO_CRATES_TO_DROP          = "No crates to drop!",
        -- ============================================================
        -- Menu labels - Crates: Build / Repair / Pack / Remove
        -- ============================================================
        MENU_BUILD_CRATES               = "Build crates",
        MENU_REPAIR                     = "Repair",
        MENU_PACK_CRATES                = "Pack crates",
        MENU_PACK                       = "Pack",
        MENU_SCAN_PACKABLE_UNITS        = "Scan packable units nearby",
        MENU_NO_PACKABLE_UNITS_FOUND_RESCAN = "No packable units found! Rescan?",
        MENU_PACK_ALL                   = "Pack nearby",
        MENU_PACK_AND_LOAD              = "Pack and Load",
        MENU_PACK_AND_LOAD_ALL          = "Pack and Load nearby",
        MENU_PACK_AND_REMOVE            = "Pack and Remove",
        MENU_PACK_AND_REMOVE_ALL        = "Pack and Remove nearby",
        MENU_REMOVE_CRATES              = "Remove crates",
        MENU_REMOVE_CRATES_NEARBY       = "Remove crates nearby",
        MENU_LIST_CRATES_NEARBY         = "List crates nearby",
        MENU_CRATES_NEEDED              = "%d crate%s %s (%dkg)",
        -- ============================================================
        -- Menu labels - Units (C-130)
        -- ============================================================
        MENU_GET_UNITS                  = "Get Units",
        MENU_REMOVE_UNITS_NEARBY        = "Remove units nearby",
        -- ============================================================
        -- Menu labels - Info / Cargo
        -- ============================================================
        MENU_LIST_BOARDED_CARGO         = "List boarded cargo",
        MENU_INVENTORY                  = "Inventory",
        MENU_LIST_ZONE_BEACONS          = "List active zone beacons",
        -- ============================================================
        -- Menu labels - Smokes / Flares / Beacons
        -- ============================================================
        MENU_SMOKES_FLARES_BEACONS      = "Smokes, Flares, Beacons",
        MENU_SMOKE_ZONES_NEARBY         = "Smoke zones nearby",
        MENU_DROP_SMOKE_NOW             = "Drop smoke now",
        MENU_RED_SMOKE                  = "Red smoke",
        MENU_BLUE_SMOKE                 = "Blue smoke",
        MENU_GREEN_SMOKE                = "Green smoke",
        MENU_ORANGE_SMOKE               = "Orange smoke",
        MENU_WHITE_SMOKE                = "White smoke",
        MENU_FLARE_ZONES_NEARBY         = "Flare zones nearby",
        MENU_FIRE_FLARE_NOW             = "Fire flare now",
        MENU_DROP_BEACON_NOW            = "Drop beacon now",
        -- ============================================================
        -- Menu labels - Parameters
        -- ============================================================
        MENU_SHOW_FLIGHT_PARAMS         = "Show flight parameters",
        MENU_SHOW_HOVER_PARAMS          = "Show hover parameters",
        STOCK_NONE                      = "none",
        STOCK_UNLIMITED                 = "unlimited",
        BUILD_YES                       = "YES",
        BUILD_NO                        = "NO",
    },
  DE = {
        -- ============================================================
        -- Kiste / Fracht laden
        -- ============================================================
        CRATE_LOADED_GROUNDCREW         = "Kiste %s vom Bodenpersonal geladen!",
        CRATE_UNLOADED_GROUNDCREW       = "Kiste %s vom Bodenpersonal entladen!",
        CRATE_LOADED_ID                 = "Kiste ID %d für %s geladen!",
        LOADED_FULL                     = "%d %s geladen.",
        LOADED_SETS_LEFTOVER            = "%d %s geladen, %d Kiste(n) übrig.",
        LOADED_SETS                     = "%d %s geladen.",
        LOADED_PARTIAL                  = "Nur %d/%d Kiste(n) von %s geladen.",
        LOADED_PARTIAL_LIMIT            = "Nur %d/%d Kiste(n) von %s geladen. Frachtlimit erreicht!",
        LOADED_BATCH                    = "%d %s geladen.",
        LOADED_BATCH_PARTIAL            = "Einige Sets konnten nicht vollständig geladen werden.",
        -- ============================================================
        -- Abwerfen / Entladen
        -- ============================================================
        DROPPED_FULL                    = "%d %s abgeworfen.",
        DROPPED_SETS_LEFTOVER           = "%d %s abgeworfen, %d Kiste(n) übrig.",
        DROPPED_SETS                    = "%d %s abgeworfen.",
        DROPPED_PARTIAL                 = "%d/%d Kiste(n) von %s abgeworfen.",
        DROPPED_INTO_ACTION             = "%s im Einsatz abgesetzt!",
        DROPPED_BEACON                  = "%s abgesetzt | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        CRATES_POSITIONED               = "%d Kisten für %s in Ihrer Nähe positioniert!",
        CRATES_DROPPED                  = "%d Kisten für %s abgeworfen!",
        -- ============================================================
        -- Truppen
        -- ============================================================
        BOARDED                         = "%s eingestiegen!",
        BOARDING                        = "%s steigt ein!",
        TROOPS_RETURNED                 = "Truppen zur Basis zurückgekehrt!",
        -- ============================================================
        -- Einsatz
        -- ============================================================
        DEPLOYED_NEAR_YOU               = "%s in Ihrer Nähe eingesetzt!",
        UNITS_REMOVED                   = "%s entfernt",
        -- ============================================================
        -- Bauen / Reparieren
        -- ============================================================
        BUILD_STARTED                   = "Bau gestartet, fertig in %d Sekunden!",
        REPAIR_STARTED                  = "Reparatur mit %s gestartet, dauert %d Sek.",
        NO_UNIT_TO_REPAIR               = "Keine Einheit in Reichweite zum Reparieren!",
        CANT_REPAIR_WITH                = "Diese Einheit kann nicht mit %s repariert werden",
        CRATES_MOVE_BEFORE_BUILD        = "*** Kisten müssen vor dem Bau verschoben werden!",
        -- ============================================================
        -- Fehler - Hubschrauber / Gewicht / Kapazität
        -- ============================================================
        CHOPPER_CANNOT_CARRY            = "Dieser Hubschrauber kann keine Kisten transportieren!",
        TOO_HEAVY                       = "Entschuldigung, das ist zu schwer zum Laden!",
        FULLY_LOADED                    = "Entschuldigung, wir sind voll beladen!",
        CRAMMED                         = "Entschuldigung, wir sind bereits voll besetzt!",
        NO_CAPACITY_NOW                 = "Aktuell keine Ladekapazität mehr vorhanden!",
        NO_MORE_CAPACITY                = "Keine Kapazität mehr für weitere Kisten!",
        CANNOT_LOAD_NONE_OR_FULL        = "Laden nicht möglich: keine Kisten gefunden oder Kapazität erschöpft.",
        -- ============================================================
        -- Fehler - Position
        -- ============================================================
        NEED_TO_LAND_OR_HOVER_LOAD      = "Bitte landen oder schweben Sie zum Laden!",
        HOVER_OVER_CRATES               = "Schweben Sie über die Kisten, um sie aufzunehmen!",
        LAND_OR_HOVER_OVER_CRATES       = "Landen oder schweben Sie über die Kisten, um sie aufzunehmen!",
        MUST_LAND_OR_HOVER_CRATES       = "Sie müssen landen oder schweben, um Kisten zu laden!",
        NEED_TO_LAND_BUILD              = "Sie müssen landen / anhalten, um etwas zu bauen, Pilot!",
        NOT_CLOSE_ENOUGH_LOGISTICS      = "Sie sind nicht nah genug an einer Logistikzone!",
        NOT_CLOSE_ENOUGH_DROP           = "Sie sind nicht nah genug an einer Abwurfzone!",
        NOT_CLOSE_ENOUGH_ZONE_NM        = "Negativ, Sie müssen näher als %d Seemeilen an einer Zone sein!",
        CANNOT_BUILD_LOADING_AREA       = "In einem Ladebereich kann nicht gebaut werden, Pilot!",
        -- ============================================================
        -- Fehler - Türen
        -- ============================================================
        OPEN_DOORS_LOAD_CARGO           = "Bitte öffnen Sie die Tür(en) zum Laden von Fracht!",
        OPEN_DOORS_LOAD_TROOPS          = "Bitte öffnen Sie die Tür(en) zum Einladen von Truppen!",
        OPEN_DOORS_EXTRACT_TROOPS       = "Bitte öffnen Sie die Tür(en) zum Aussteigen der Truppen!",
        OPEN_DOORS_UNLOAD_TROOPS        = "Bitte öffnen Sie die Tür(en) zum Entladen der Truppen!",
        OPEN_DOORS_DROP_CARGO           = "Bitte öffnen Sie die Tür(en) zum Abwerfen der Fracht!",
        -- ============================================================
        -- Fehler - Bestand / Verfügbarkeit
        -- ============================================================
        ALL_GONE                        = "Entschuldigung, alle %s sind vergriffen!",
        RAN_OUT_OF                      = "Entschuldigung, %s ist nicht mehr vorrätig",
        CARGO_NOT_AVAILABLE_ZONE        = "Die angeforderte Fracht ist in dieser Zone nicht verfügbar!",
        ENOUGH_CRATES_NEARBY            = "Es sind bereits genügend Kisten in der Nähe! Bitte zuerst um diese kümmern!",
        NO_CRATES_WITHIN                = "Keine (ladbaren) Kisten in %d Metern Umkreis!",
        NO_CRATES_WITHIN_PLAIN          = "Keine Kisten in %d Metern Umkreis!",
        NO_CRATES_IN_RANGE              = "Keine Kisten in Reichweite gefunden!",
        NO_NAMED_CRATES_IN_RANGE        = "Keine \"%s\"-Kisten in Reichweite gefunden!",
        NO_LOADABLE_CRATES              = "Entschuldigung, keine ladbaren Kisten in der Nähe oder maximales Frachtgewicht erreicht!",
        NO_UNITS_TO_EXTRACT             = "Keine Einheiten nah genug zum Aussteigen!",
        NO_UNIT_CONFIG                  = "Keine Einheitenkonfiguration für %s gefunden",
        CANT_ONBOARD                    = "%s kann nicht eingeladen werden",
        TOO_MANY_UNITS_NEARBY           = "Sie haben bereits %d Einheiten in der Nähe!",
        NO_CRATE_GROUPS                 = "Keine Kistengruppen für diese Einheit gefunden!",
        NO_CRATE_SET                    = "Kein Kistenset gefunden oder Index ungültig!",
        NO_CRATE_IN_SET                 = "Keine Kiste in diesem Set gefunden!",
        NO_TROOP_CHUNK                  = "Kein Truppenfracht-Block für ID %d gefunden!",
        TROOP_CHUNK_EMPTY               = "Truppenfracht-Block für ID %d ist leer!",
        -- ============================================================
        -- Nichts geladen / kein Bestand
        -- ============================================================
        NOTHING_LOADED                  = "Nichts geladen!\nTruppenlimit: %d | Kistenlimit: %d | Gewichtslimit: %d kg",
        NOTHING_LOADED_AIRDROP          = "Nichts geladen oder nicht innerhalb der Abwurfparameter!",
        NOTHING_LOADED_HOVER            = "Nichts geladen oder Schwebeparameter nicht erfüllt!",
        NOTHING_IN_STOCK                = "Nichts vorrätig!",
        NOTHING_TO_PACK                 = "Nichts in dieser Entfernung zum Verpacken, Pilot!",
        NOTHING_TO_REMOVE               = "Nichts in dieser Entfernung zum Entfernen, Pilot!",
        -- ============================================================
        -- Zone / Info
        -- ============================================================
        ROGER_ZONE                      = "Verstanden, %s Zone %s!",
        -- ============================================================
        -- Report: Schwebe- / Flugparameter
        -- ============================================================
        HOVER_PARAMS_METRIC             = "Schwebeparameter (Autoladen/Abwurf):\n - Min. Höhe %dm \n - Max. Höhe %dm \n - Max. Geschwindigkeit 2m/s \n - Im Parameter: %s",
        HOVER_PARAMS_IMPERIAL           = "Schwebeparameter (Autoladen/Abwurf):\n - Min. Höhe %dft \n - Max. Höhe %dft \n - Max. Geschwindigkeit 6ft/s \n - Im Parameter: %s",
        FLIGHT_PARAMS_IMPERIAL          = "Flugparameter (Luftabwurf):\n - Min. Höhe %dft \n - Max. Höhe %dft \n - Im Parameter: %s",
        FLIGHT_PARAMS_METRIC            = "Flugparameter (Luftabwurf):\n - Min. Höhe %dm \n - Max. Höhe %dm \n - Im Parameter: %s",
        -- ============================================================
        -- Report-Titel
        -- ============================================================
        REPORT_CRATES_FOUND             = "Kisten in der Nähe:",
        REPORT_REMOVING_CRATES          = "Entferne Kisten in der Nähe:",
        REPORT_TRANSPORT_CHECKOUT       = "Transport-Checkliste",
        REPORT_INVENTORY                = "Inventarliste",
        REPORT_BUILD_CHECKLIST          = "Checkliste baubare Kisten",
        REPORT_REPAIR_CHECKLIST         = "Checkliste Reparaturen",
        REPORT_BEACONS                  = "Aktive Zonenfeuer",
        -- ============================================================
        -- Report-Sektionskopfzeilen
        -- ============================================================
        REPORT_SECTION_TROOPS           = "        -- TRUPPEN --",
        REPORT_SECTION_CRATES           = "       -- KISTEN --",
        REPORT_SECTION_CRATES_GC        = "       -- KISTEN via Bodenpersonal geladen --",
        REPORT_SECTION_NONE             = "        K E I N E",
        REPORT_SECTION_NONE_ALT         = "     --- Keine gefunden! ---",
        REPORT_SECTION_NONE_REPAIR      = "     --- Keine gefunden ---",
        REPORT_GC_LOADABLE_HINT         = "Wahrscheinlich durch Bodenpersonal ladbar (F8)",
        REPORT_TOTAL_MASS               = "Gesamtgewicht: %s kg. Ladbar: %s kg.",
        REPORT_TROOPS_CRATES_COUNT      = "Truppen: %d(%d), Kisten: %d(%d)",
        REPORT_TROOPS_CRATETYPES_COUNT  = "Truppen: %d, Kistentypen: %d",
        -- ============================================================
        -- Report-Zeilenvorlagen
        -- ============================================================
        REPORT_ROW_TROOP                = "Truppe: %s Größe %d",
        REPORT_ROW_CRATE                = "Kiste: %s %d/%d",
        REPORT_ROW_CRATE_SIZE1          = "Kiste: %s Größe 1",
        REPORT_ROW_GC_CRATE             = "Bodenpersonal-Kiste: %s Größe 1",
        REPORT_ROW_DROPPED_CRATE        = "Abgeworfene Kiste für %s, %dkg",
        REPORT_ROW_CRATE_KG             = "Kiste für %s, %dkg",
        REPORT_ROW_CRATE_REMOVED        = "Kiste für %s, %dkg entfernt",
        REPORT_ROW_UNIT_STOCK           = "Einheit: %s | Soldaten: %d | Bestand: %s",
        REPORT_ROW_TYPE_CRATE_STOCK     = "Typ: %s | Kisten pro Set: %d | Bestand: %s",
        REPORT_ROW_TYPE_STOCK           = "Typ: %s | Bestand: %s",
        REPORT_ROW_BUILD_CHECK          = "Typ: %s | Benötigt: %d | Gefunden: %d | Baubar: %s",
        REPORT_ROW_REPAIR_CHECK         = "Typ: %s | Benötigt: %d | Gefunden: %d | Reparierbar: %s",
        REPORT_ROW_BEACON               = " %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        -- ============================================================
        -- Gewichts- / Kistenlimit-Token
        -- ============================================================
        WEIGHT_LIMIT                    = "Gewichtslimit erreicht",
        CRATE_LIMIT                     = "Kistenlimit erreicht",
        -- ============================================================
        -- Menübezeichnungen - Obere Ebene
        -- ============================================================
        MENU_CTLD                       = "CTLD",
        MENU_MANAGE_TROOPS              = "Truppen verwalten",
        MENU_MANAGE_CRATES              = "Kisten verwalten",
        MENU_MANAGE_UNITS               = "Einheiten verwalten",
        -- ============================================================
        -- Menübezeichnungen - Truppen
        -- ============================================================
        MENU_LOAD_TROOPS                = "Truppen einladen",
        MENU_DROP_TROOPS                = "Truppen absetzen",
        MENU_DROP_ALL_TROOPS            = "ALLE Truppen absetzen",
        MENU_EXTRACT_TROOPS             = "Truppen aufnehmen",
        MENU_DROP_N_TROOPS              = "(%d) %s absetzen",
        -- ============================================================
        -- Menübezeichnungen - Kisten: Holen
        -- ============================================================
        MENU_GET_CRATES                 = "Kisten holen",
        MENU_GET                        = "Holen",
        MENU_GET_AND_LOAD               = "Holen und laden",
        MENU_GET_ANYWAY                 = "Trotzdem holen",
        MENU_PARTIALLY_LOAD             = "Teilweise laden",
        MENU_OUT_OF_STOCK               = "Nicht vorrätig",
        MENU_TROOP_LIMIT                = "Truppenlimit erreicht",
        -- ============================================================
        -- Menübezeichnungen - Kisten: Laden
        -- ============================================================
        MENU_LOAD_CRATES                = "Kisten laden",
        MENU_LOAD_ALL                   = "ALLE laden",
        MENU_SHOW_LOADABLE_CRATES       = "Ladbare Kisten anzeigen",
        MENU_NO_CRATES_FOUND_RESCAN     = "Keine Kisten gefunden! Neu scannen?",
        MENU_USE_C130_LOAD              = "C-130-Ladesystem verwenden",
        MENU_LOAD_SINGLE                = "Lade",
        -- ============================================================
        -- Menübezeichnungen - Kisten: Abwerfen
        -- ============================================================
        MENU_DROP_CRATES                = "Kisten abwerfen",
        MENU_DROP_ALL_CRATES            = "ALLE Kisten abwerfen",
        MENU_DROP                       = "Abwerfen",
        MENU_DROP_AND_BUILD             = "Abwerfen und bauen",
        MENU_DROP_N_SETS                = "%d Set%s abwerfen",
        MENU_NO_CRATES_TO_DROP          = "Keine Kisten zum Abwerfen!",
        -- ============================================================
        -- Menübezeichnungen - Kisten: Bauen / Reparieren / Packen / Entfernen
        -- ============================================================
        MENU_BUILD_CRATES               = "Kisten bauen",
        MENU_REPAIR                     = "Reparieren",
        MENU_PACK_CRATES                = "Kisten packen",
        MENU_PACK                       = "Packen",
        MENU_SCAN_PACKABLE_UNITS        = "Packbare Einheiten in der Nähe scannen",
        MENU_NO_PACKABLE_UNITS_FOUND_RESCAN = "Keine packbaren Einheiten gefunden! Neu scannen?",
        MENU_PACK_ALL                   = "In der Nähe packen",
        MENU_PACK_AND_LOAD              = "Packen und laden",
        MENU_PACK_AND_LOAD_ALL          = "In der Nähe packen und laden",
        MENU_PACK_AND_REMOVE            = "Packen und entfernen",
        MENU_PACK_AND_REMOVE_ALL        = "In der Nähe packen und entfernen",
        MENU_REMOVE_CRATES              = "Kisten entfernen",
        MENU_REMOVE_CRATES_NEARBY       = "Nahe Kisten entfernen",
        MENU_LIST_CRATES_NEARBY         = "Nahe Kisten auflisten",
        MENU_CRATES_NEEDED              = "%d Kiste%s %s (%dkg)",
        -- ============================================================
        -- Menübezeichnungen - Einheiten (C-130)
        -- ============================================================
        MENU_GET_UNITS                  = "Einheiten holen",
        MENU_REMOVE_UNITS_NEARBY        = "Nahe Einheiten entfernen",
        -- ============================================================
        -- Menübezeichnungen - Info / Fracht
        -- ============================================================
        MENU_LIST_BOARDED_CARGO         = "Geladene Fracht anzeigen",
        MENU_INVENTORY                  = "Inventar",
        MENU_LIST_ZONE_BEACONS          = "Aktive Zonenfeuer anzeigen",
        -- ============================================================
        -- Menübezeichnungen - Rauch / Leuchtfeuer / Baken
        -- ============================================================
        MENU_SMOKES_FLARES_BEACONS      = "Rauch, Leuchtfeuer, Baken",
        MENU_SMOKE_ZONES_NEARBY         = "Nahe Zonen einrauchen",
        MENU_DROP_SMOKE_NOW             = "Rauch jetzt setzen",
        MENU_RED_SMOKE                  = "Roter Rauch",
        MENU_BLUE_SMOKE                 = "Blauer Rauch",
        MENU_GREEN_SMOKE                = "Grüner Rauch",
        MENU_ORANGE_SMOKE               = "Oranger Rauch",
        MENU_WHITE_SMOKE                = "Weißer Rauch",
        MENU_FLARE_ZONES_NEARBY         = "Nahe Zonen befeuern",
        MENU_FIRE_FLARE_NOW             = "Leuchtfeuer jetzt abfeuern",
        MENU_DROP_BEACON_NOW            = "Bake jetzt setzen",
        -- ============================================================
        -- Menübezeichnungen - Parameter
        -- ============================================================
        MENU_SHOW_FLIGHT_PARAMS         = "Flugparameter anzeigen",
        MENU_SHOW_HOVER_PARAMS          = "Schwebeparameter anzeigen",
        STOCK_NONE                      = "keiner",
        STOCK_UNLIMITED                 = "unbegrenzt",
        BUILD_YES                       = "JA",
        BUILD_NO                        = "NEIN",
},
FR = {
        --- ============================================================
        -- Chargement caisse / fret
        -- ============================================================
        CRATE_LOADED_GROUNDCREW         = "Caisse(s) %s chargée(s) par l'équipe au sol !",
        CRATE_UNLOADED_GROUNDCREW       = "Caisse(s) %s déchargée(s) par l'équipe au sol !",
        CRATE_LOADED_ID                 = "Caisse(s) ID %d pour %s chargée(s) !",
        LOADED_FULL                     = "%d %s chargé(s).",
        LOADED_SETS_LEFTOVER            = "%d %s chargé(s), %d caisse(s) restante(s).",
        LOADED_SETS                     = "%d %s chargé(s).",
        LOADED_PARTIAL                  = "Seulement %d/%d caisse(s) de %s chargée(s).",
        LOADED_PARTIAL_LIMIT            = "Seulement %d/%d caisse(s) de %s chargée(s). Limite de fret atteinte !",
        LOADED_BATCH                    = "%d %s chargé(s).",
        LOADED_BATCH_PARTIAL            = "Certains ensembles n'ont pas pu être complètement chargés.",
        -- ============================================================
        -- Largage / Déchargement
        -- ============================================================
        DROPPED_FULL                    = "%d %s largué(s).",
        DROPPED_SETS_LEFTOVER           = "%d %s largué(s), %d caisse(s) restante(s).",
        DROPPED_SETS                    = "%d %s largué(s).",
        DROPPED_PARTIAL                 = "%d/%d caisse(s) de %s larguée(s).",
        DROPPED_INTO_ACTION             = "%s engagé(s) en action !",
        DROPPED_BEACON                  = "%s largué | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        CRATES_POSITIONED               = "%d caisses pour %s positionnées près de vous !",
        CRATES_DROPPED                  = "%d caisses pour %s larguées !",
        -- ============================================================
        -- Troupes
        -- ============================================================
        BOARDED                         = "%s embarqué(s) !",
        BOARDING                        = "%s en cours d'embarquement !",
        TROOPS_RETURNED                 = "Les troupes sont retournées à la base !",
        -- ============================================================
        -- Déploiement
        -- ============================================================
        DEPLOYED_NEAR_YOU               = "%s déployé(s) près de vous !",
        UNITS_REMOVED                   = "%s supprimé(s)",
        -- ============================================================
        -- Construction / Réparation
        -- ============================================================
        BUILD_STARTED                   = "Construction démarrée, prête dans %d secondes !",
        REPAIR_STARTED                  = "Réparation démarrée avec %s, durée %d sec.",
        NO_UNIT_TO_REPAIR               = "Aucune unité(s) assez proche pour être réparée(s) !",
        CANT_REPAIR_WITH                = "Impossible de réparer cette unité avec %s",
        CRATES_MOVE_BEFORE_BUILD        = "*** Les caisses doivent être déplacées avant la construction !",
        -- ============================================================
        -- Erreurs - Hélicoptère / Poids / Capacité
        -- ============================================================
        CHOPPER_CANNOT_CARRY            = "Cet hélicoptère ne peut pas transporter de caisses !",
        TOO_HEAVY                       = "Désolé, c'est trop lourd à charger !",
        FULLY_LOADED                    = "Désolé, capacité maximale atteinte !",
        CRAMMED                         = "Désolé, nous sommes déjà au complet !",
        NO_CAPACITY_NOW                 = "Aucune capacité de chargement disponible pour le moment !",
        NO_MORE_CAPACITY                = "Plus de capacité pour charger des caisses !",
        CANNOT_LOAD_NONE_OR_FULL        = "Chargement impossible : aucune caisse trouvée ou capacité épuisée.",
        -- ============================================================
        -- Erreurs - Position
        -- ============================================================
        NEED_TO_LAND_OR_HOVER_LOAD      = "Vous devez atterrir ou rester en vol stationnaire pour charger !",
        HOVER_OVER_CRATES               = "Survolez les caisses en stationnaire pour les récupérer !",
        LAND_OR_HOVER_OVER_CRATES       = "Atterrissez ou survolez les caisses en stationnaire pour les récupérer !",
        MUST_LAND_OR_HOVER_CRATES       = "Vous devez atterrir ou rester en stationnaire pour charger les caisses !",
        NEED_TO_LAND_BUILD              = "Vous devez atterrir / vous arrêter pour construire quelque chose, Pilote !",
        NOT_CLOSE_ENOUGH_LOGISTICS      = "Vous n'êtes pas assez proche d'une zone logistique !",
        NOT_CLOSE_ENOUGH_DROP           = "Vous n'êtes pas assez proche d'une zone de largage !",
        NOT_CLOSE_ENOUGH_ZONE_NM        = "Négatif, vous devez être à moins de %d nm d'une zone !",
        CANNOT_BUILD_LOADING_AREA       = "Vous ne pouvez pas construire dans une zone de chargement, Pilote !",
        -- ============================================================
        -- Erreurs - Portes
        -- ============================================================
        OPEN_DOORS_LOAD_CARGO           = "Vous devez ouvrir la/les porte(s) pour charger du fret !",
        OPEN_DOORS_LOAD_TROOPS          = "Vous devez ouvrir la/les porte(s) pour embarquer des troupes !",
        OPEN_DOORS_EXTRACT_TROOPS       = "Vous devez ouvrir la/les porte(s) pour extraire des troupes !",
        OPEN_DOORS_UNLOAD_TROOPS        = "Vous devez ouvrir la/les porte(s) pour débarquer des troupes !",
        OPEN_DOORS_DROP_CARGO           = "Vous devez ouvrir la/les porte(s) pour larguer du fret !",
        -- ============================================================
        -- Erreurs - Stock / Disponibilité
        -- ============================================================
        ALL_GONE                        = "Désolé, tous les %s sont épuisés !",
        RAN_OUT_OF                      = "Désolé, nous n'avons plus de %s !",
        CARGO_NOT_AVAILABLE_ZONE        = "Le fret demandé n'est pas disponible dans cette zone !",
        ENOUGH_CRATES_NEARBY            = "Il y a déjà suffisamment de caisses à proximité ! Occupez-vous d'abord de celles-ci !",
        NO_CRATES_WITHIN                = "Aucune caisse (chargeable) dans un rayon de %d mètres !",
        NO_CRATES_WITHIN_PLAIN          = "Aucune caisse dans un rayon de %d mètres !",
        NO_CRATES_IN_RANGE              = "Aucune caisse trouvée à portée !",
        NO_NAMED_CRATES_IN_RANGE        = "Aucune caisse \"%s\" trouvée à portée !",
        NO_LOADABLE_CRATES              = "Désolé, aucune caisse chargeable à proximité ou poids maximum atteint !",
        NO_UNITS_TO_EXTRACT             = "Aucune unité assez proche pour être extraite !",
        NO_UNIT_CONFIG                  = "Aucune configuration d'unité trouvée pour %s",
        CANT_ONBOARD                    = "Impossible d'embarquer %s",
        TOO_MANY_UNITS_NEARBY           = "Vous avez déjà %d unités à proximité !",
        NO_CRATE_GROUPS                 = "Aucun groupe de caisses trouvé pour cette unité !",
        NO_CRATE_SET                    = "Aucun ensemble de caisses trouvé ou index invalide !",
        NO_CRATE_IN_SET                 = "Aucune caisse trouvée dans cet ensemble !",
        NO_TROOP_CHUNK                  = "Aucun bloc de fret de troupes trouvé pour l'ID %d !",
        TROOP_CHUNK_EMPTY               = "Le bloc de fret de troupes pour l'ID %d est vide !",
        -- ============================================================
        -- Rien de chargé / en stock
        -- ============================================================
        NOTHING_LOADED                  = "Rien de chargé !\nLimite de troupes : %d | Limite de caisses : %d | Limite en poids : %d kg",
        NOTHING_LOADED_AIRDROP          = "Rien de chargé ou paramètres de largage non respectés !",
        NOTHING_LOADED_HOVER            = "Rien de chargé ou paramètres de vol stationnaire non respectés !",
        NOTHING_IN_STOCK                = "Rien en stock !",
        NOTHING_TO_PACK                 = "Rien à charger à cette distance, Pilote !",
        NOTHING_TO_REMOVE               = "Rien à retirer à cette distance, Pilote !",
        -- ============================================================
        -- Zone / Info
        -- ============================================================
        ROGER_ZONE                      = "Compris, zone %s %s !",
        -- ============================================================
        -- Rapport : Paramètres stationnaire / vol
        -- ============================================================
        HOVER_PARAMS_METRIC             = "Paramètres stationnaires (autochargement/largage) :\n - Hauteur min. %dm \n - Hauteur max. %dm \n - Vitesse max. 2m/s \n - Dans les paramètres : %s",
        HOVER_PARAMS_IMPERIAL           = "Paramètres stationnaires (autochargement/largage) :\n - Hauteur min. %dft \n - Hauteur max. %dft \n - Vitesse max. 6ft/s \n - Dans les paramètres : %s",
        FLIGHT_PARAMS_IMPERIAL          = "Paramètres de vol (largage aérien) :\n - Hauteur min. %dft \n - Hauteur max. %dft \n - Dans les paramètres : %s",
        FLIGHT_PARAMS_METRIC            = "Paramètres de vol (largage aérien) :\n - Hauteur min. %dm \n - Hauteur max. %dm \n - Dans les paramètres : %s",
        -- ============================================================
        -- Titres de rapport
        -- ============================================================
        REPORT_CRATES_FOUND             = "Caisses trouvées à proximité :",
        REPORT_REMOVING_CRATES          = "Suppression des caisses à proximité :",
        REPORT_TRANSPORT_CHECKOUT       = "Fiche de contrôle transport",
        REPORT_INVENTORY                = "Fiche d'inventaire",
        REPORT_BUILD_CHECKLIST          = "Checklist caisses constructibles",
        REPORT_REPAIR_CHECKLIST         = "Checklist réparations",
        REPORT_BEACONS                  = "Balises de zone actives",
        -- ============================================================
        -- En-têtes de sections de rapport
        -- ============================================================
        REPORT_SECTION_TROOPS           = "        -- TROUPES --",
        REPORT_SECTION_CRATES           = "       -- CAISSES --",
        REPORT_SECTION_CRATES_GC        = "       -- CAISSES chargées via équipe au sol --",
        REPORT_SECTION_NONE             = "        A U C U N",
        REPORT_SECTION_NONE_ALT         = "     --- Aucun trouvé ! ---",
        REPORT_SECTION_NONE_REPAIR      = "     --- Aucun trouvé ---",
        REPORT_GC_LOADABLE_HINT         = "Probablement chargeable via l’équipe au sol (F8)",
        REPORT_TOTAL_MASS               = "Masse totale : %s kg. Chargeable : %s kg.",
        REPORT_TROOPS_CRATES_COUNT      = "Troupes : %d(%d), Caisses : %d(%d)",
        REPORT_TROOPS_CRATETYPES_COUNT  = "Troupes : %d, Types de caisses : %d",
        -- ============================================================
        -- Modèles de lignes de rapport
        -- ============================================================
        REPORT_ROW_TROOP                = "Troupe : %s taille %d",
        REPORT_ROW_CRATE                = "Caisse : %s %d/%d",
        REPORT_ROW_CRATE_SIZE1          = "Caisse : %s taille 1",
        REPORT_ROW_GC_CRATE             = "Caisses chargées par l'équipe au sol : %s taille 1",
        REPORT_ROW_DROPPED_CRATE        = "Caisses larguées pour %s, %dkg",
        REPORT_ROW_CRATE_KG             = "Caisses pour %s, %dkg",
        REPORT_ROW_CRATE_REMOVED        = "Caisses pour %s, %dkg retirées",
        REPORT_ROW_UNIT_STOCK           = "Unités : %s | Soldats : %d | Stock : %s",
        REPORT_ROW_TYPE_CRATE_STOCK     = "Type : %s | Caisses par ensemble : %d | Stock : %s",
        REPORT_ROW_TYPE_STOCK           = "Type : %s | Stock : %s",
        REPORT_ROW_BUILD_CHECK          = "Type : %s | Requis : %d | Trouvé : %d | Constructible : %s",
        REPORT_ROW_REPAIR_CHECK         = "Type : %s | Requis : %d | Trouvé : %d | Réparable : %s",
        REPORT_ROW_BEACON               = " %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
        -- ============================================================
        -- Tokens limite poids / caisses
        -- ============================================================
        WEIGHT_LIMIT                    = "Limite de poids atteinte",
        CRATE_LIMIT                     = "Limite de caisses atteinte",
        -- ============================================================
        -- Libellés de menu - Niveau supérieur
        -- ============================================================
        MENU_CTLD                       = "CTLD",
        MENU_MANAGE_TROOPS              = "Gérer les troupes",
        MENU_MANAGE_CRATES              = "Gérer les caisses",
        MENU_MANAGE_UNITS               = "Gérer les unités",
        -- ============================================================
        -- Libellés de menu - Troupes
        -- ============================================================
        MENU_LOAD_TROOPS                = "Embarquer troupes",
        MENU_DROP_TROOPS                = "Déposer troupes",
        MENU_DROP_ALL_TROOPS            = "Déposer TOUTES les troupes",
        MENU_EXTRACT_TROOPS             = "Extraire troupes",
        MENU_DROP_N_TROOPS              = "Déposer (%d) %s",
        -- ============================================================
        -- Libellés de menu - Caisses : Récupérer
        -- ============================================================
        MENU_GET_CRATES                 = "Récupérer caisses",
        MENU_GET                        = "Récupérer",
        MENU_GET_AND_LOAD               = "Récupérer et charger",
        MENU_GET_ANYWAY                 = "Récupérer quand même",
        MENU_PARTIALLY_LOAD             = "Chargement partiel",
        MENU_OUT_OF_STOCK               = "Rupture de stock",
        MENU_TROOP_LIMIT                = "Limite de troupes atteinte",
        -- ============================================================
        -- Libellés de menu - Caisses : Charger
        -- ============================================================
        MENU_LOAD_CRATES                = "Charger caisses",
        MENU_LOAD_ALL                   = "Tout charger",
        MENU_SHOW_LOADABLE_CRATES       = "Afficher caisses chargeables",
        MENU_NO_CRATES_FOUND_RESCAN     = "Aucune caisse trouvée ! Rescanner ?",
        MENU_USE_C130_LOAD              = "Utiliser le système de chargement C-130",
        MENU_LOAD_SINGLE                = "Charger",
        -- ============================================================
        -- Libellés de menu - Caisses : Larguer
        -- ============================================================
        MENU_DROP_CRATES                = "Larguer caisses",
        MENU_DROP_ALL_CRATES            = "Larguer TOUTES les caisses",
        MENU_DROP                       = "Larguer",
        MENU_DROP_AND_BUILD             = "Larguer et construire",
        MENU_DROP_N_SETS                = "Larguer %d ensemble%s",
        MENU_NO_CRATES_TO_DROP          = "Aucune caisse à larguer !",
        -- ============================================================
        -- Libellés de menu - Caisses : Construire / Réparer / Emballer / Retirer
        -- ============================================================
        MENU_BUILD_CRATES               = "Construire caisses",
        MENU_REPAIR                     = "Réparer",
        MENU_PACK_CRATES                = "Emballer caisses",
        MENU_PACK                       = "Emballer",
        MENU_SCAN_PACKABLE_UNITS        = "Scanner unités emballables à proximité",
        MENU_NO_PACKABLE_UNITS_FOUND_RESCAN = "Aucune unité emballable trouvée ! Rescanner ?",
        MENU_PACK_ALL                   = "Emballer à proximité",
        MENU_PACK_AND_LOAD              = "Emballer et charger",
        MENU_PACK_AND_LOAD_ALL          = "Emballer et charger à proximité",
        MENU_PACK_AND_REMOVE            = "Emballer et retirer",
        MENU_PACK_AND_REMOVE_ALL        = "Emballer et retirer à proximité",
        MENU_REMOVE_CRATES              = "Retirer caisses",
        MENU_REMOVE_CRATES_NEARBY       = "Retirer caisses proches",
        MENU_LIST_CRATES_NEARBY         = "Lister caisses proches",
        MENU_CRATES_NEEDED              = "%d caisse%s %s (%dkg)",
        -- ============================================================
        -- Libellés de menu - Unités (C-130)
        -- ============================================================
        MENU_GET_UNITS                  = "Récupérer unités",
        MENU_REMOVE_UNITS_NEARBY        = "Retirer les unités proches",
        -- ============================================================
        -- Libellés de menu - Info / Fret
        -- ============================================================
        MENU_LIST_BOARDED_CARGO         = "Lister le fret embarqué",
        MENU_INVENTORY                  = "Inventaire",
        MENU_LIST_ZONE_BEACONS          = "Lister les balises de zones actives",
        -- ============================================================
        -- Libellés de menu - Fumigènes / Fusées / Balises
        -- ============================================================
        MENU_SMOKES_FLARES_BEACONS      = "Fumigènes, Fusées, Balises",
        MENU_SMOKE_ZONES_NEARBY         = "Fumigène sur les zones proches",
        MENU_DROP_SMOKE_NOW             = "Poser fumigène maintenant",
        MENU_RED_SMOKE                  = "Fumigène rouge",
        MENU_BLUE_SMOKE                 = "Fumigène bleu",
        MENU_GREEN_SMOKE                = "Fumigène vert",
        MENU_ORANGE_SMOKE               = "Fumigène orange",
        MENU_WHITE_SMOKE                = "Fumigène blanc",
        MENU_FLARE_ZONES_NEARBY         = "Baliser zones proches",
        MENU_FIRE_FLARE_NOW             = "Tirer une fusée maintenant",
        MENU_DROP_BEACON_NOW            = "Poser une balise maintenant",
        -- ============================================================
        -- Libellés de menu - Paramètres
        -- ============================================================
        MENU_SHOW_FLIGHT_PARAMS         = "Afficher paramètres de vol",
        MENU_SHOW_HOVER_PARAMS          = "Afficher les paramètres stationnaire",
        STOCK_NONE                      = "aucun",
        STOCK_UNLIMITED                 = "illimité",
        BUILD_YES                       = "OUI",
        BUILD_NO                        = "NON",
    },
    ES={
      CRATE_LOADED_GROUNDCREW="Contenedor %s cargado por el quipo de tierra.",
      CRATE_UNLOADED_GROUNDCREW="Contenedor %s descargado por el quipo de tierra.",
      CRATE_LOADED_ID="Contenedor ID %d para %s cargado.",
      LOADED_FULL="Cargado %d %s.",
      LOADED_SETS_LEFTOVER="Cargado %d %s(s), de %d contenedor(es) restante(s).",
      LOADED_SETS="Cargado %d %s(s).",
      LOADED_PARTIAL="Cargado sólo %d/%d contenedor(es) de %s.",
      LOADED_PARTIAL_LIMIT="Cargado sólo %d/%d contenedor(es) de %s. Límite de carga alcanzado.",
      LOADED_BATCH="Cargado %d %s.",
      LOADED_BATCH_PARTIAL="Some sets could not be fully loaded.",
      DROPPED_FULL="Entregado %d %s.",
      DROPPED_SETS_LEFTOVER="Entregado %d %s(s), de %d conenedor(es) restante(s).",
      DROPPED_SETS="Entregado %d %s(s).",
      DROPPED_PARTIAL="Entregado %d/%d contenedor(es) de %s.",
      DROPPED_INTO_ACTION="¡Soltados %s en acción!",
      DROPPED_BEACON="Entregado %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
      CRATES_POSITIONED="%d contenedores para %s servidos cerca de ti.",
      CRATES_DROPPED="%d contenedores para %s han sido entregados.",
      BOARDED="¡%s a bordo!",
      BOARDING="¡%s entrando!",
      TROOPS_RETURNED="¡Las tropas han vuelto a la base!",
      DEPLOYED_NEAR_YOU="%s han sido servidas cerca de tí.",
      UNITS_REMOVED="%s ha sido eliminado",
      BUILD_STARTED="Construcción comenzada, listo en %d segundos.",
      REPAIR_STARTED="Reparación comenzaza usando %s, tardará %d segundos.",
      NO_UNIT_TO_REPAIR="No hay unidades cercanas que necesiten reparación.",
      CANT_REPAIR_WITH="No se puede reparar esta unidad con %s",
      CRATES_MOVE_BEFORE_BUILD="*** Los contenedores deben ser movidos antes de construirse.",
      CHOPPER_CANNOT_CARRY="Lo siento, este helicóptero no puede transportar contenedores.",
      TOO_HEAVY="Lo siento, esta carga es muy pesada.",
      FULLY_LOADED="Lo siento, vamos hasta arriba.",
      CRAMMED="Lo siento, vamos a tope.",
      NO_CAPACITY_NOW="No queda capacidad para cargar más.",
      NO_MORE_CAPACITY="No queda capacidad para cargar más contenedores.",
      CANNOT_LOAD_NONE_OR_FULL="No se pueden cargar contenedores: n hay o no queda capacidad.",
      NEED_TO_LAND_OR_HOVER_LOAD="Necesitas aterrizar o mantenerte en estacionario para cargar.",
      HOVER_OVER_CRATES="Mantente en estacionario sobre el contenedor para recogerlo.",
      LAND_OR_HOVER_OVER_CRATES="Aterriza o mantente en estacionario para recoger el contenedor.",
      MUST_LAND_OR_HOVER_CRATES="Necesitas aterrizar o mantenerte en eestacionario para cargar contenedores.",
      NEED_TO_LAND_BUILD="Necesitas aterrizar/parar para construir algo.",
      NOT_CLOSE_ENOUGH_LOGISTICS="No estás cerca de una zona de logística.",
      NOT_CLOSE_ENOUGH_DROP="No estás en una zona de entrega.",
      NOT_CLOSE_ENOUGH_ZONE_NM="Negativo, tienes que estar a menos de %dnm de la zona.",
      CANNOT_BUILD_LOADING_AREA="No puedes construir en la zona de carga.",
      OPEN_DOORS_LOAD_CARGO="Necesitas abrir las puertas para cargar.",
      OPEN_DOORS_LOAD_TROOPS="Necesitas abrir las puertas para que embarquen las tropas.",
      OPEN_DOORS_EXTRACT_TROOPS="Necesitas abrir las puertas para poder sacar a las tropas de aquí.",
      OPEN_DOORS_UNLOAD_TROOPS="Necesitas abrir las puertas para que desembarquen las tropas.",
      OPEN_DOORS_DROP_CARGO="Necesitas abrir las puertas para descargar la carga.",
      ALL_GONE="Lo siento, todos %s se han servido.",
      RAN_OUT_OF="Lo siento, nos hemos quedad sin %s",
      CARGO_NOT_AVAILABLE_ZONE="La carga solicitada no está disponible en esta zona.",
      ENOUGH_CRATES_NEARBY="Hay contenedores cerca de ti listas. Encárgate primero de ellos.",
      NO_CRATES_WITHIN="No ha contenedores (cargables) en %d metros.",
      NO_CRATES_WITHIN_PLAIN="No hay contenedores en %d metros.",
      NO_CRATES_IN_RANGE="No se han encontrado contenedores en rango.",
      NO_NAMED_CRATES_IN_RANGE="No se han encontrado \"%s\" conenedores en rango.",
      NO_LOADABLE_CRATES="Lo siento, no hay contenedores cercanos o se ha alcanzado el peso máximo.",
      NO_UNITS_TO_EXTRACT="No hay unidades cercanas para extracción.",
      NO_UNIT_CONFIG="No se ha encontrado configuración de unidad para %s",
      CANT_ONBOARD="No puede subir %s",
      TOO_MANY_UNITS_NEARBY="Ya tienes %d unidades próximas.",
      NO_CRATE_GROUPS="No se han encontrado grupos de contendeores para esta unidad.",
      NO_CRATE_SET="No se ha encontrado contenedor o su index es inválido.",
      NO_CRATE_IN_SET="No se ha encontrado contenedor para este set.",
      NO_TROOP_CHUNK="No se han encontrado tropas para el id %d!",
      TROOP_CHUNK_EMPTY="Troop chunk is empty for ID %d!",
      NOTHING_LOADED="Nada cargado.\nLímite tropas: %d | Límite contenedores: %d | Peso límite: %d kg.",
      NOTHING_LOADED_AIRDROP="Nada cargado o no estás en parámetros de lanzamiento aéreo.",
      NOTHING_LOADED_HOVER="Nada cargado o no estás en parámetros de estacionario.",
      NOTHING_IN_STOCK="¡Nada en stock!",
      NOTHING_TO_PACK="Nada para empaquetar a esta distancia.",
      NOTHING_TO_REMOVE="Nada para eliminar a esta distancia.",
      ROGER_ZONE="Recibido, %s cona %s!",
      HOVER_PARAMS_METRIC="Parámetros en estacionario (autocarga/suelta):\n - Altura mínima %dm \n - Altura máxima %dm \n - Velocidad máxima 2mps \n - En parámetros: %s",
      HOVER_PARAMS_IMPERIAL="Parámetros en estacionario (autocarga/suelta):\n - Altura mínima  %dft \n - Altura máxima %dft \n - Velocidad máxima 6ftps \n - En parámetros: %s",
      FLIGHT_PARAMS_IMPERIAL="Parámetros vuelo (lanzamiento aéreo):\n - Altura mínima  %dft \n - Altura máxima %dft \n - En parámetros: %s",
      FLIGHT_PARAMS_METRIC="Parámetros vuelo (lanzamiento aéreo):\n - Altura mínima  %dm \n - Altura máxima %dm \n - En parámetros: %s",
      REPORT_CRATES_FOUND="Contenedores encontrados cerca:",
      REPORT_REMOVING_CRATES="Contenedores eliminados cerca:",
      REPORT_TRANSPORT_CHECKOUT="Informe de transporte",
      REPORT_INVENTORY="Inventario",
      REPORT_BUILD_CHECKLIST="Contenedores construibles",
      REPORT_REPAIR_CHECKLIST="Reparaciones",
      REPORT_BEACONS="Active Zone Beacons",
      REPORT_SECTION_TROOPS="        -- TROPAS --",
      REPORT_SECTION_CRATES="    -- CONTENEDORES --",
      REPORT_SECTION_CRATES_GC="       -- Contenedores cargados por equipo de tierra --",
      REPORT_SECTION_NONE="        N A D A",
      REPORT_SECTION_NONE_ALT="     --- Nada encontrado ---",
      REPORT_SECTION_NONE_REPAIR="     --- Nada encontrado ---",
      REPORT_GC_LOADABLE_HINT="Probablemente cargable por el equipo de tierra (F8)",
      REPORT_TOTAL_MASS="Peso total: %s kg. Cargable: %s kg.",
      REPORT_TROOPS_CRATES_COUNT="Tropas: %d(%d), Contenedores: %d(%d)",
      REPORT_TROOPS_CRATETYPES_COUNT="Tropas: %d, Tipos contenedores: %d",
      REPORT_ROW_TROOP="Tropas: %s tamaño %d",
      REPORT_ROW_CRATE="Contenedores: %s %d/%d",
      REPORT_ROW_CRATE_SIZE1="Contenedores: %s tamaño 1",
      REPORT_ROW_GC_CRATE="Contenedores cargados: %s tamaño 1",
      REPORT_ROW_DROPPED_CRATE="Entregado contenedor para %s, %dkg",
      REPORT_ROW_CRATE_KG="Contenedor para %s, %dkg",
      REPORT_ROW_CRATE_REMOVED="Contenedor para %s, %dkg eliminado",
      REPORT_ROW_UNIT_STOCK="Unidad: %s | Soldados: %d | Stock: %s",
      REPORT_ROW_TYPE_CRATE_STOCK="Tipo: %s | Contenedores por set: %d | Stock: %s",
      REPORT_ROW_TYPE_STOCK="Tipo: %s | Stock: %s",
      REPORT_ROW_BUILD_CHECK="Tipo: %s | Rquiere %d | Encontrados %d | Construible %s",
      REPORT_ROW_REPAIR_CHECK="Tipo: %s | Requiere %d | Encontrados %d | Reparable %s",
      REPORT_ROW_BEACON=" %s | FM %s Mhz | VHF %s KHz | UHF %s Mhz ",
      WEIGHT_LIMIT="Alcanzado límite de pesoWeight limit reached",
      CRATE_LIMIT="Alcanzado límite contenedores",
      MENU_CTLD="CTLD",
      MENU_MANAGE_TROOPS="Gestionar tropas",
      MENU_MANAGE_CRATES="Gestionar contenedores",
      MENU_MANAGE_UNITS="Gestionar unidades",
      MENU_LOAD_TROOPS="Cargar tropas",
      MENU_DROP_TROOPS="Entregar tropas",
      MENU_DROP_ALL_TROOPS="Entregar TODAS tropas",
      MENU_EXTRACT_TROOPS="Extraer tropas",
      MENU_DROP_N_TROOPS="Soltar (%d) %s",
      MENU_GET_CRATES="Solicitar contenedores",
      MENU_GET="Solicitar",
      MENU_GET_AND_LOAD="Solicitar y cargar",
      MENU_GET_ANYWAY="Solicitar de todas formas",
      MENU_PARTIALLY_LOAD="Carga parcial",
      MENU_OUT_OF_STOCK="Sin stock",
      MENU_TROOP_LIMIT="Limite de tropas alcanzado",
      MENU_LOAD_CRATES="Cargar contenedores",
      MENU_LOAD_ALL="Cargar TODO",
      MENU_SHOW_LOADABLE_CRATES="Mostrar contenedores carbables",
      MENU_NO_CRATES_FOUND_RESCAN="Contenedores no encontrados, ¿buscar?",
      MENU_USE_C130_LOAD="Usar sistmea de carga del C-130",
      MENU_LOAD_SINGLE="Cargar",
      MENU_DROP_CRATES="Soltar cargas",
      MENU_DROP_ALL_CRATES="Soltar TODAS cargas",
      MENU_DROP="Soltar",
      MENU_DROP_AND_BUILD="Soltar y constuir",
      MENU_DROP_N_SETS="Soltar %d Set %s",
      MENU_NO_CRATES_TO_DROP="No hay cargas para soltar",
      MENU_BUILD_CRATES="Construir contenedores",
      MENU_REPAIR="Reparar",
      MENU_PACK_CRATES="Empaquetar cargas",
      MENU_PACK="Empaquetar",
      MENU_SCAN_PACKABLE_UNITS="Buscar unidades empaquetables cercanas",
      MENU_NO_PACKABLE_UNITS_FOUND_RESCAN="No se encontraron unidades empaquetables. ¿Buscar de nuevo?",
      MENU_PACK_ALL="Empaquetar cercanas",
      MENU_PACK_AND_LOAD="Empaquetar y cargar",
      MENU_PACK_AND_LOAD_ALL="Empaquetar y cargar cercanas",
      MENU_PACK_AND_REMOVE="Empaquetar y eliminar",
      MENU_PACK_AND_REMOVE_ALL="Empaquetar y eliminar cercanas",
      MENU_REMOVE_CRATES="Eliminar cargas",
      MENU_REMOVE_CRATES_NEARBY="Eliminar cargas cercanas",
      MENU_LIST_CRATES_NEARBY="Listar cargas cercanas",
      MENU_CRATES_NEEDED="%d contenedor%s %s (%dkg)",
      MENU_GET_UNITS="Obtener unidades",
      MENU_REMOVE_UNITS_NEARBY="Eliminar unidades cercanas",
      MENU_LIST_BOARDED_CARGO="Lista de cargas a bordo",
      MENU_INVENTORY="Inventario",
      MENU_LIST_ZONE_BEACONS="Lista de balizas activas",
      MENU_SMOKES_FLARES_BEACONS="Humos, Bengalas, Balizas",
      MENU_SMOKE_ZONES_NEARBY="Humo en zonas cercanas",
      MENU_DROP_SMOKE_NOW="Lanzar humo ahora",
      MENU_RED_SMOKE="Humo rojo",
      MENU_BLUE_SMOKE="Humo azul",
      MENU_GREEN_SMOKE="Humo verde",
      MENU_ORANGE_SMOKE="Humo naranja",
      MENU_WHITE_SMOKE="Humo blanco",
      MENU_FLARE_ZONES_NEARBY="Bengalas en zonas cercanas",
      MENU_FIRE_FLARE_NOW="Disparar bengala ahora",
      MENU_DROP_BEACON_NOW="Soltar baliza ahora",
      MENU_SHOW_FLIGHT_PARAMS="Mostrar parámetros de vuelo",
      MENU_SHOW_HOVER_PARAMS="Mostrar parámetros estacionario",
      STOCK_NONE="Nada",
      STOCK_UNLIMITED="ilimitado",
      BUILD_YES="SI",
      BUILD_NO="NO",
      },
  }
2026-04-15 20:08:45 +02:00
leka1986 0b2f07ca6c Update CTLD.lua
- **Changed** the pack menu layout so pack actions now open into dedicated `Pack`, `Pack and Load`, and `Pack and Remove` submenus.
- **Added** scanning for nearby packable units within each pack submenu.
- **Added** direct selection of individual nearby packable units from the pack menus.
- **Changed** the pack menu order so detected nearby units appear first, followed by the nearby bulk action and the scan action.
- **Added** nearby bulk actions in each pack submenu (`Pack nearby`, `Pack and Load nearby`, `Pack and Remove nearby`).
- **Changed** pack menu refresh behavior so nearby packable units are rebuilt after major logistics actions and after build completion.
- **Fixed** selected `Pack and Load` so it only loads the crates created by the chosen packed unit.
- **Fixed** selected `Pack and Remove` so it only removes the crates created by the chosen packed unit.
- **Changed** pre-pack event handling so before-pack callbacks receive the specific group being packed.
- **Added** localization for the new pack menu wording in English, German, French, and Spanish.
2026-04-15 20:06:57 +02:00
Thomas 7c5d5543e0 Merge pull request #2576 from FlightControl-Master/master-ng
Update TARS.lua
2026-04-15 10:29:15 +02:00
Thomas 3d10716b1f Update TARS.lua
#TARS Documentation addition
2026-04-15 10:28:39 +02:00
Thomas c48a7d4400 Merge pull request #2575 from FlightControl-Master/master-ng
Merge
2026-04-14 06:29:09 +02:00
Thomas 79130d4fe2 Merge pull request #2574 from Rolln-dev/Rolln/AIRBOSS
[BUGFIX] AIRBOSS:_LSOGrades
2026-04-14 06:28:13 +02:00
Rolln-dev aebb6ac0db [BUGFIX] AIRBOSS:_LSOGrades When points are deducted for a 1-wire pass, we also need to change the grade according to the new points. 2026-04-13 19:20:20 -06:00
Applevangelist 3eb910b47e Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-12 13:13:21 +02:00
Applevangelist 6223b8e1a7 #TARS - docu fixes 2026-04-12 13:12:58 +02:00
Applevangelist 533a4dfa6c Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-12 12:58:33 +02:00
Applevangelist dbc752253b #TARS Initial Release 2026-04-12 12:56:15 +02:00
Applevangelist 7f074781f4 xx 2026-04-12 12:51:13 +02:00
Applevangelist ab77fcbc1f Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-08 15:18:20 +02:00
Applevangelist 56520092c3 #EASYGCICAP - Fix restart function to restart, not start, the Airwings, and call Status itself afterwards 2026-04-08 15:17:54 +02:00
Applevangelist 252a1b0761 Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-08 14:44:20 +02:00
Applevangelist 51e5f53965 #LEGION Fix for MinDistance when nil and spawning on a ship 2026-04-08 14:43:53 +02:00
Applevangelist b0976d1613 Merge remote-tracking branch 'origin/develop' into develop 2026-04-07 12:22:27 +02:00
Applevangelist a737ca71e6 Merge remote-tracking branch 'origin/master-ng' into develop 2026-04-07 12:22:24 +02:00
Applevangelist 1071300a7f #MSRS - Added HOUND/OpenA combo 2026-04-07 12:19:37 +02:00
Thomas 2490958090 Merge pull request #2573 from FlightControl-Master/master-ng
#INTEL add rcs info to contact data
2026-04-06 19:07:23 +02:00
Applevangelist b78b76e579 #INTEL add rcs info to contact data 2026-04-06 18:49:53 +02:00
Thomas efff22fc18 Merge pull request #2571 from FlightControl-Master/master-ng
Merge
2026-03-31 19:35:34 +02:00
Thomas 4b27e92210 Merge pull request #2569 from FlightControl-Master/master-ng
Merge
2026-03-30 08:38:19 +02:00
Applevangelist f2063f41f6 Merge remote-tracking branch 'origin/master-ng' into develop 2026-03-27 17:42:30 +01:00
Thomas 12241e931a Merge pull request #2567 from FlightControl-Master/master-ng
merge
2026-03-27 15:18:15 +01:00
Thomas 4cb6debef8 Merge pull request #2565 from FlightControl-Master/master-ng
Merge from master
2026-03-26 06:45:10 +01:00
Thomas efe4bf3912 Merge pull request #2563 from FlightControl-Master/master-ng
Merge pull request #2562 from FlightControl-Master/develop
2026-03-24 13:32:26 +01:00
28 changed files with 7195 additions and 583 deletions
+23 -1
View File
@@ -735,6 +735,12 @@ do -- Event Handling
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when an option is changed for an AI group.
-- The event identifies the initiating group, but does not provide the option ID or value.
-- @function [parent=#BASE] OnEventGroupChangeOption
-- @param #BASE self
-- @param Core.Event#EVENTDATA EventData The EventData structure.
--- Occurs when a player creates a dynamic cargo object from the F8 ground crew menu.
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
@@ -855,7 +861,7 @@ end
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Object Initiator The initiating object of the event.
function BASE:CreateEventTakeoff( EventTime, Initiator )
self:F( { EventTime, Initiator } )
--self:F( { EventTime, Initiator } )
local Event = {
id = world.event.S_EVENT_TAKEOFF,
@@ -880,6 +886,22 @@ end
world.onEvent(Event)
end
--- Creation of a `S_EVENT_GROUP_CHANGE_OPTION` event.
-- @param #BASE self
-- @param DCS#Time EventTime The time stamp of the event.
-- @param DCS#Group Initiator The initiating group of the event.
function BASE:CreateEventGroupChangeOption( EventTime, Initiator )
self:F( { EventTime, Initiator } )
local Event = {
id = EVENTS.GroupChangeOption,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
-- @param #BASE self
+8 -7
View File
@@ -1380,12 +1380,12 @@ function DATABASE:_RegisterDynamicGroup(Groupname)
local DCSUnitName = DCSUnit:getName()
-- Add unit.
self:I(string.format("Register Unit: %s", tostring(DCSUnitName)))
self:T(string.format("Register Unit: %s", tostring(DCSUnitName)))
self:AddUnit( tostring(DCSUnitName), true )
end
else
self:E({"Group does not exist: ", DCSGroup})
self:T({"Group does not exist: ", DCSGroup})
end
return self
end
@@ -1488,27 +1488,28 @@ end
-- @return #DATABASE self
function DATABASE:_RegisterAirbase(airbase)
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
local countHSyria = 0
--local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
--local countHSyria = 0
if airbase then
-- Get the airbase name.
local DCSAirbaseName = airbase:getName()
-- DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
--[[ DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
if IsSyria and DCSAirbaseName == "H" and countHSyria > 0 then
--[[
--
local p = airbase:getPosition().p
local mgrs = COORDINATE:New(p.x,p.z,p.y):ToStringMGRS()
self:I("Airbase on Syria map named H @ "..mgrs)
countHSyria = countHSyria + 1
if countHSyria > 1 then return self end
--]]
--
return self
elseif IsSyria and DCSAirbaseName == "H" and countHSyria == 0 then
countHSyria = countHSyria + 1
end
--]]
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=airbase:getID()
+31 -8
View File
@@ -278,6 +278,7 @@ EVENTS = {
SimulationUnfreeze = world.event.S_EVENT_SIMULATION_UNFREEZE or -1,
HumanAircraftRepairStart = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_START or -1,
HumanAircraftRepairFinish = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH or -1,
GroupChangeOption = world.event.S_EVENT_GROUP_CHANGE_OPTION or -1,
-- dynamic cargo
NewDynamicCargo = world.event.S_EVENT_NEW_DYNAMIC_CARGO or -1,
DynamicCargoLoaded = world.event.S_EVENT_DYNAMIC_CARGO_LOADED or -1,
@@ -291,23 +292,25 @@ EVENTS = {
--
-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.
-- * A GROUP : A DCS Group object is involved in the Event.
--
-- @type EVENTDATA
-- @field #number id The identifier of the event.
--
-- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
-- @field DCS#Unit initiator (UNIT/STATIC/SCENERY/GROUP) The initiating @{DCS#Unit} or @{DCS#StaticObject}. For `S_EVENT_GROUP_CHANGE_OPTION`, this is a DCS Group.
-- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).
-- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name.
-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object.
-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
-- @field DCS#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}.
-- @field #string IniDCSGroupName (UNIT) The initiating Group name.
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object.
-- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName).
-- @field DCS#Group IniDCSGroup (UNIT/GROUP) The initiating @{DCS#Group}.
-- @field #string IniDCSGroupName (UNIT/GROUP) The initiating Group name.
-- @field Wrapper.Group#GROUP IniGroup (UNIT/GROUP) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object.
-- @field #string IniGroupName (UNIT/GROUP) The initiating GROUP name (same as IniDCSGroupName).
-- @field DCS#Group.Category IniGroupCategory (GROUP) The category of the initiating group.
-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot.
-- @field #string IniPlayerUCID (UNIT) The UCID of the initiating player in case the Unit is a client or player slot and on a multi-player server.
-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator.
-- @field DCS#coalition.side IniCoalition (UNIT/GROUP) The coalition of the initiator.
-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator.
-- @field #string IniTypeName (UNIT) The type name of the initiator.
--
@@ -734,6 +737,12 @@ local _EVENTMETA = {
Side = "I",
Event = "OnEventHumanAircraftRepairFinish",
Text = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH"
},
[EVENTS.GroupChangeOption] = {
Order = 1,
Side = "I",
Event = "OnEventGroupChangeOption",
Text = "S_EVENT_GROUP_CHANGE_OPTION"
},
-- dynamic cargo
[EVENTS.NewDynamicCargo] = {
@@ -1234,7 +1243,16 @@ function EVENT:onEvent( Event )
if Event.initiator then
Event.IniObjectCategory = Object.getCategory(Event.initiator)
if Event.id == EVENTS.GroupChangeOption then
Event.IniDCSGroup = Event.initiator
Event.IniDCSGroupName = Group.getName(Event.initiator)
Event.IniGroupName = Event.IniDCSGroupName
Event.IniGroup = GROUP:FindByName(Event.IniDCSGroupName)
Event.IniCoalition = Group.getCoalition(Event.initiator)
Event.IniGroupCategory = Group.getCategory(Event.initiator)
else
Event.IniObjectCategory = Object.getCategory(Event.initiator)
end
if Event.IniObjectCategory == Object.Category.STATIC then
---
@@ -1453,7 +1471,12 @@ function EVENT:onEvent( Event )
-- Weapon.
if Event.weapon and type(Event.weapon) == "table" and Event.weapon.isExist and Event.weapon:isExist() then
Event.Weapon = Event.weapon
Event.WeaponName = Event.weapon:isExist() and Event.weapon:getTypeName() or "Unknown Weapon"
if Event.weapon_name == "ZELL Booster" then
Event.WeaponName = "ZELL Booster"
else
Event.WeaponName = Event.weapon:isExist() and Event.weapon.getTypeName and Event.weapon:getTypeName() or "Unknown Weapon"
end
if Event.weapon_name == "ZELL Booster" then Event.WeaponName = "ZELL Booster" end
Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit!
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon.getPlayerName and Event.Weapon:getPlayerName()
--Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName()
+14 -3
View File
@@ -869,10 +869,21 @@ do
local MenuTable = {}
for MenuText, Menu in pairs( self.Menus or {} ) do
local tag = Menu.MenuTag or math.random(1,10000)
MenuTable[#MenuTable+1] = {Tag=tag, Enty=Menu}
MenuTable[#MenuTable+1] = {Tag=tag, Entry=Menu}
end
table.sort(MenuTable, function (k1, k2) return k1.tag < k2.tag end )
for _, Menu in pairs( MenuTable ) do
local function SortTable(k1,k2)
if not k1 then
if not k2 then return true else return false end
elseif not k2 then
if not k1 then return true else return false end
else
return (k1.Tag or 15) <= (k2.Tag or 15)
end
return false
end
table.sort(MenuTable, SortTable)
--table.sort(MenuTable, function (k1, k2) return (k1.tag or 15) <= (k2.tag or 15) end )
for _, Menu in ipairs( MenuTable ) do
Menu.Entry:Refresh()
end
end
@@ -375,3 +375,13 @@ function SCHEDULEDISPATCHER:NoTrace( Scheduler )
Scheduler.ShowTrace = false
end
--- Helper for memory cleanup for self stopping schedulers
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
-- @param #string CallID (Optional) Scheduler Call ID.
function SCHEDULEDISPATCHER:_Reclaim( Scheduler, CallID )
self:Stop( Scheduler, CallID ) -- remove DCS timer, nil ScheduleID
if self.Schedule[Scheduler] then self.Schedule[Scheduler][CallID] = nil end
self.ObjectSchedulers[CallID] = nil
self.PersistentSchedulers[CallID] = nil
end
+145 -22
View File
@@ -62,7 +62,8 @@ do -- SET_BASE
-- @field #table List Unused table.
-- @field Core.Scheduler#SCHEDULER CallScheduler
-- @field #SET_BASE.Filters Filter Filters
-- @field #booleaen filterNoRegex If true, FilterPrefix ignores special characters and evaluates plain string.
-- @field #boolean filterNoRegex If true, FilterPrefix ignores special characters and evaluates plain string. Defaults to false.
-- @field #boolean filterReplaceDash If true then if filterNoRegex is false, replace dashes with regex pattern friendly pattern. Defaults to true
-- @extends Core.Base#BASE
--- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects.
@@ -102,6 +103,7 @@ do -- SET_BASE
},
},
filterNoRegex=false,
filterReplaceDash=true,
}
--- Filters
@@ -256,7 +258,8 @@ do -- SET_BASE
-- @return #boolean Returns `true`, if the pattern is contained in the name and false otherwise.
function SET_BASE:_SearchPattern(Name, Pattern, NoRegex, ReplaceDash)
NoRegex=NoRegex or self.filterNoRegex
if ReplaceDash==true then
ReplaceDash=ReplaceDash or self.filterReplaceDash
if ReplaceDash==true and NoRegex ~= true then
-- Not sure why "-" is replaced by "%-" ?! - So we can still match group names with a dash in them
-- reason is that the string is interpreted as a pattern and "-" is a special character then. For interpreting it as a string, fourth parameter needs to be set to true.
Pattern=Pattern:gsub("-", "%%-")
@@ -265,6 +268,16 @@ do -- SET_BASE
return contain
end
---Set Regex Options for FilterPrefix function.
-- @param #SET_BASE self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_BASE self
function SET_BASE:FilterSetRegex(NoRegex,ReplaceDash)
if NoRegex ~= nil then self.filterNoRegex = NoRegex end
self.filterReplaceDash = ReplaceDash or true
return self
end
--- Gets the Set.
-- @param #SET_BASE self
@@ -1198,7 +1211,21 @@ do
-- @param #SET_GROUP self
-- @return #SET_GROUP self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_GROUP] FilterSetRegex
-- @param #SET_GROUP self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_GROUP self
--- Builds a set of objects of same coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @function [parent=#SET_GROUP] FilterCoalitions
-- @param #SET_GROUP self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" and coalition.side.RED, coalition.side.BLUE,coalition.side.NEUTRAL
-- @param #boolean Clear If `true`, clear any previously defined filters.
-- @return #SET_GROUP self
end
--- Get a *new* set table that only contains alive groups.
@@ -2116,7 +2143,7 @@ do
if self.Filter.GroupPrefixes and MGroupInclude then
local MGroupPrefix = false
for GroupPrefixId, GroupPrefix in pairs(self.Filter.GroupPrefixes) do
if self:_SearchPattern(MGroup:GetName(), GroupPrefix, false, true) then
if self:_SearchPattern(MGroup:GetName(), GroupPrefix, self.filterNoRegex, self.filterReplaceDash) then
MGroupPrefix = true
end
end
@@ -2337,6 +2364,26 @@ do -- SET_UNIT
-- @param #SET_UNIT self
-- @return #SET_UNIT self
--- Filter the set once
-- @function [parent=#SET_UNIT] FilterOnce
-- @param #SET_UNIT self
-- @return #SET_UNIT self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_UNIT] FilterSetRegex
-- @param #SET_UNIT self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_UNIT self
--- Builds a set of objects of same coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @function [parent=#SET_UNIT] FilterCoalitions
-- @param #SET_UNIT self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" and coalition.side.RED, coalition.side.BLUE,coalition.side.NEUTRAL
-- @param #boolean Clear If `true`, clear any previously defined filters.
-- @return #SET_UNIT self
return self
end
@@ -3348,7 +3395,7 @@ do -- SET_UNIT
if self.Filter.UnitPrefixes and MUnitInclude then
local MUnitPrefix = false
for UnitPrefixId, UnitPrefix in pairs(self.Filter.UnitPrefixes) do
if self:_SearchPattern(MUnit:GetName(), UnitPrefix, false, true) then
if self:_SearchPattern(MUnit:GetName(), UnitPrefix, self.filterNoRegex, self.filterReplaceDash) then
MUnitPrefix = true
end
end
@@ -3544,7 +3591,27 @@ do -- SET_STATIC
-- Inherits from BASE
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.STATICS)) -- Core.Set#SET_STATIC
--- Filter the set once
-- @function [parent=#SET_STATIC] FilterOnce
-- @param #SET_STATIC self
-- @return #SET_STATIC self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_STATIC] FilterSetRegex
-- @param #SET_STATIC self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_STATIC self
--- Builds a set of objects of same coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @function [parent=#SET_STATIC] FilterCoalitions
-- @param #SET_STATIC self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" and coalition.side.RED, coalition.side.BLUE,coalition.side.NEUTRAL
-- @param #boolean Clear If `true`, clear any previously defined filters.
-- @return #SET_STATIC self
return self
end
@@ -4119,7 +4186,7 @@ do -- SET_STATIC
if self.Filter.StaticPrefixes then
local MStaticPrefix = false
for StaticPrefixId, StaticPrefix in pairs(self.Filter.StaticPrefixes) do
if self:_SearchPattern(MStatic:GetName(), StaticPrefix, false, true) then
if self:_SearchPattern(MStatic:GetName(), StaticPrefix, self.filterNoRegex, self.filterReplaceDash) then
MStaticPrefix = true
end
end
@@ -4303,7 +4370,27 @@ do -- SET_CLIENT
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.CLIENTS)) -- #SET_CLIENT
self:FilterActive(false)
--- Filter the set once
-- @function [parent=#SET_CLIENT] FilterOnce
-- @param #SET_CLIENT self
-- @return #SET_CLIENT self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_CLIENT] FilterSetRegex
-- @param #SET_CLIENT self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_CLIENT self
--- Builds a set of objects of same coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @function [parent=#SET_CLIENT] FilterCoalitions
-- @param #SET_CLIENT self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" and coalition.side.RED, coalition.side.BLUE,coalition.side.NEUTRAL
-- @param #boolean Clear If `true`, clear any previously defined filters.
-- @return #SET_CLIENT self
return self
end
@@ -4902,7 +4989,7 @@ do -- SET_CLIENT
if self.Filter.ClientPrefixes and MClientInclude then
local MClientPrefix = false
for ClientPrefixId, ClientPrefix in pairs(self.Filter.ClientPrefixes) do
if self:_SearchPattern(MClient.UnitName, ClientPrefix) then
if self:_SearchPattern(MClient.UnitName, ClientPrefix, self.filterNoRegex, self.filterReplaceDash) then
MClientPrefix = true
end
end
@@ -4926,7 +5013,7 @@ do -- SET_CLIENT
local playername = MClient:GetPlayerName() or "Unknown"
--self:T(playername)
for _,_Playername in pairs(self.Filter.Playernames) do
if playername and self:_SearchPattern(playername,_Playername) then
if playername and self:_SearchPattern(playername,_Playername,self.filterNoRegex, self.filterReplaceDash) then
MClientPlayername = true
end
end
@@ -4939,7 +5026,7 @@ do -- SET_CLIENT
local callsign = MClient:GetCallsign()
--self:I(callsign)
for _,_Callsign in pairs(self.Filter.Callsigns) do
if callsign and self:_SearchPattern(callsign,_Callsign, true) then
if callsign and self:_SearchPattern(callsign,_Callsign, self.filterNoRegex, self.filterReplaceDash) then
MClientCallsigns = true
end
end
@@ -5360,7 +5447,7 @@ do -- SET_PLAYER
if self.Filter.ClientPrefixes then
local MClientPrefix = false
for ClientPrefixId, ClientPrefix in pairs(self.Filter.ClientPrefixes) do
if self:_SearchPattern(MClient.UnitName,ClientPrefix) then
if self:_SearchPattern(MClient.UnitName,ClientPrefix,self.filterNoRegex, self.filterReplaceDash) then
MClientPrefix = true
end
end
@@ -5830,7 +5917,19 @@ do -- SET_ZONE
function SET_ZONE:New()
-- Inherits from BASE
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.ZONES))
--- Filter the set once
-- @function [parent=#SET_ZONE] FilterOnce
-- @param #SET_ZONE self
-- @return #SET_ZONE self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_ZONE] FilterSetRegex
-- @param #SET_ZONE self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_ZONE self
return self
end
@@ -6068,7 +6167,7 @@ do -- SET_ZONE
if self.Filter.Prefixes then
local MZonePrefix = false
for ZonePrefixId, ZonePrefix in pairs(self.Filter.Prefixes) do
if self:_SearchPattern(MZoneName, ZonePrefix, false, true) then
if self:_SearchPattern(MZoneName, ZonePrefix, self.filterNoRegex, self.filterReplaceDash) then
MZonePrefix = true
end
end
@@ -6577,7 +6676,7 @@ do -- SET_ZONE_GOAL
if self.Filter.Prefixes then
local MZonePrefix = false
for ZonePrefixId, ZonePrefix in pairs(self.Filter.Prefixes) do
if self:_SearchPattern(MZoneName, ZonePrefix, false, true) then
if self:_SearchPattern(MZoneName, ZonePrefix, self.filterNoRegex, self.filterReplaceDash) then
MZonePrefix = true
end
end
@@ -6713,7 +6812,19 @@ do -- SET_OPSZONE
-- Inherits from BASE
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.OPSZONES))
--- Filter the set once
-- @function [parent=#SET_OPSZONE] FilterOnce
-- @param #SET_OPSZONE self
-- @return #SET_OPSZONE self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_OPSZONE] FilterSetRegex
-- @param #SET_OPSZONE self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_OPSZONE self
return self
end
@@ -6938,7 +7049,7 @@ do -- SET_OPSZONE
for ZonePrefixId, ZonePrefix in pairs(self.Filter.Prefixes) do
-- Prefix
if self:_SearchPattern(MZoneName, ZonePrefix, false, true) then
if self:_SearchPattern(MZoneName, ZonePrefix, self.filterNoRegex, self.filterReplaceDash) then
MZonePrefix = true
break --Break the loop as we found the prefix.
end
@@ -7732,7 +7843,7 @@ function SET_OPSGROUP:_EventOnBirth(Event)
local MGroupPrefix = false
for GroupPrefixId, GroupPrefix in pairs(self.Filter.GroupPrefixes) do
if self:_SearchPattern(MGroup:GetName(), GroupPrefix, false, true) then
if self:_SearchPattern(MGroup:GetName(), GroupPrefix, self.filterNoRegex, self.filterReplaceDash) then
MGroupPrefix = true
end
end
@@ -8066,7 +8177,7 @@ do -- SET_SCENERY
if self.Filter.Prefixes then
local MSceneryPrefix = false
for ZonePrefixId, ZonePrefix in pairs(self.Filter.Prefixes) do
if self:_SearchPattern(MSceneryName, ZonePrefix, false, true) then
if self:_SearchPattern(MSceneryName, ZonePrefix, self.filterNoRegex, self.filterReplaceDash) then
MSceneryPrefix = true
end
end
@@ -8289,7 +8400,19 @@ do -- SET_DYNAMICCARGO
--- Inherits from BASE
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.DYNAMICCARGO)) -- Core.Set#SET_DYNAMICCARGO
--- Filter the set once
-- @function [parent=#SET_DYNAMICCARGO] FilterOnce
-- @param #SET_DYNAMICCARGO self
-- @return #SET_DYNAMICCARGO self
---Set Regex Options for FilterPrefix function.
-- @function [parent=#SET_DYNAMICCARGO] FilterSetRegex
-- @param #SET_DYNAMICCARGO self
-- @param #boolean NoRegex If true, switch off Regex pattern matching for FilterPrefixes.
-- @param #boolean ReplaceDash If false, switch off dash "-" replacement in strings for FilterPrefixes.
-- @return #SET_DYNAMICCARGO self
return self
end
@@ -8337,7 +8460,7 @@ do -- SET_DYNAMICCARGO
if self.Filter.StaticPrefixes then
local DCargoPrefix = false
for StaticPrefixId, StaticPrefix in pairs(self.Filter.StaticPrefixes) do
if self:_SearchPattern(DCargo:GetName(), StaticPrefix, false, true) then
if self:_SearchPattern(DCargo:GetName(), StaticPrefix, self.filterNoRegex, self.filterReplaceDash) then
DCargoPrefix = true
end
end
@@ -8505,7 +8628,7 @@ do -- SET_DYNAMICCARGO
function SET_DYNAMICCARGO:FilterCurrentOwner(PlayerName)
self:FilterFunction(
function(cargo)
if cargo and cargo.Owner and self:_SearchPattern(cargo.Owner, PlayerName, true) then
if cargo and cargo.Owner and self:_SearchPattern(cargo.Owner, PlayerName, self.filterNoRegex, self.filterReplaceDash) then
return true
else
return false
+96 -25
View File
@@ -1184,6 +1184,7 @@ end
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
-- @param #SPAWN self
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If nil or empty, the method returns self without effect.
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
-- @param #boolean RandomizePositionInZone If nil or true, also the position inside the selected random zone will be randomized. Set to false to use the center of the zone.
-- @return #SPAWN self
@@ -1201,6 +1202,9 @@ end
function SPAWN:InitRandomizeZones( SpawnZoneTable, RandomizePositionInZone )
--self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } )
if not SpawnZoneTable then
return self
end
local temptable = {}
for _,_temp in pairs(SpawnZoneTable) do
temptable[#temptable+1] = _temp
@@ -2149,6 +2153,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
local parkingspots = {}
local parkingindex = {}
local spots
local useexplicitspots = false
-- Spawn happens on ground, i.e. at an airbase, a FARP or a ship.
if spawnonground and not SpawnTemplate.parked then
@@ -2178,15 +2183,41 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
local scanscenery = false
local verysafe = false
-- Use exact parking data when provided, otherwise let helicopters on ships/FARPs
-- use the smarter parking search before falling back to the procedural queue path.
-- Number of free parking spots at the airbase.
if autoparking then
if Parkingdata~=nil then
-- Parking data explicitly set by user as input parameter.
nfree = #Parkingdata
spots = Parkingdata
useexplicitspots = true
elseif autoparking and AirbaseCategory == Airbase.Category.HELIPAD and ishelo then
if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first.
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types.
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
end
else
-- Terminal type explicitly given.
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
end
if nfree >= nunits then
useexplicitspots = true
else
-- These places work procedural and have some kind of build in queue ==> Less effort.
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
end
elseif autoparking then
-- These places work procedural and have some kind of build in queue ==> Less effort.
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
elseif Parkingdata~=nil then
-- Parking data explicitly set by user as input parameter. (This was commented out for some unknown reason. But I need it this way.)
nfree=#Parkingdata
spots=Parkingdata
else
if ishelo then
if termtype == nil then
@@ -2238,7 +2269,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
local _notenough = false
-- Need to differentiate some cases again.
if autoparking then
if autoparking and not useexplicitspots then
-- On free spot required in these cases.
if nfree >= 1 then
@@ -2271,6 +2302,10 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
end
end
if useexplicitspots and parkingspots[1] then
PointVec3 = parkingspots[1]
end
-- Not enough spots ==> Prepare airstart.
if _notenough then
@@ -2296,9 +2331,15 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
Takeoff = GROUP.Takeoff.Air
spawnonground = false
else
else
if not Takeoff == GROUP.Takeoff.Runway then
self:E( string.format( "WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
return nil
else
Takeoff = GROUP.Takeoff.Runway
spawnonground = false
self:E( string.format( "WARNING: Group %s set to runway spawning at %s, this only works in Single Player!", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
end
end
end
@@ -2339,7 +2380,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if spawnonground then
-- Ships and FARPS seem to have a build in queue.
if autoparking then
if autoparking and not useexplicitspots then
-- Spawn on ship. We take only the position of the ship.
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
@@ -2357,7 +2398,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
else
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
-- Spawn in air as requested initially. Original template orientation is preserved, altitude is already correctly set.
SpawnTemplate.units[UnitID].x = TX
SpawnTemplate.units[UnitID].y = TY
SpawnTemplate.units[UnitID].alt = PointVec3.y
@@ -2390,7 +2431,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if Takeoff == GROUP.Takeoff.Air then
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
--SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() }, 5 ) --No need to create a new SCHEDULER instance every time!
self:ScheduleOnce(5, BASE.CreateEventTakeoff, {GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject()})
self:ScheduleOnce(5, BASE.CreateEventTakeoff, GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject())
end
end
@@ -2582,21 +2623,51 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
local scanscenery = false
local verysafe = false
-- Number of free parking spots at the airbase.
if spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort.
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
--[[
elseif Parkingdata~=nil then
-- Parking data explicitly set by user as input parameter.
nfree=#Parkingdata
spots=Parkingdata
]]
else
if ishelo then
-- Use exact parking data when provided, otherwise let helicopters on FARPs
-- use the smarter parking search before falling back to the procedural queue path.
local useexplicitspots = false
-- Number of free parking spots at the airbase.
if Parkingdata~=nil then
-- Parking data explicitly set by user as input parameter.
nfree = #Parkingdata
spots = Parkingdata
useexplicitspots = true
elseif spawnonfarp and ishelo then
if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first.
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types.
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
end
else
-- Terminal type explicitly given.
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, nil )
nfree = #spots
end
if nfree >= nunits then
useexplicitspots = true
else
-- These places work procedural and have some kind of build in queue ==> Less effort.
--self:T2( string.format( "Group %s is spawned on farp %s using procedural spots.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
end
elseif spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort.
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
else
if ishelo then
if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first.
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
@@ -2659,7 +2730,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
local _notenough = false
-- Need to differentiate some cases again.
if spawnonship or spawnonfarp or spawnonrunway then
if (spawnonship or spawnonfarp or spawnonrunway) and not useexplicitspots then
-- On free spot required in these cases.
if nfree >= 1 then
+2 -1
View File
@@ -87,7 +87,8 @@ do -- world
-- @field S_EVENT_SIMULATION_UNFREEZE = 58
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_START = 59
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH = 60
-- @field S_EVENT_MAX = 61
-- @field S_EVENT_GROUP_CHANGE_OPTION = 61
-- @field S_EVENT_MAX = 62
--- The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
-- @type world.BirthPlace
@@ -1848,7 +1848,7 @@ do -- DETECTION_BASE
return self
end
--- Validate if the detected item is locked.
--- Validate if the detected item is locked (not in the radar sense, though!).
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #boolean
@@ -1858,7 +1858,7 @@ do -- DETECTION_BASE
end
--- Lock a detected item.
--- Lock a detected item (not in the radar sense, though!).
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #DETECTION_BASE
@@ -1869,7 +1869,7 @@ do -- DETECTION_BASE
return self
end
--- Unlock a detected item.
--- Unlock a detected item (not in the radar sense, though!).
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #DETECTION_BASE
File diff suppressed because it is too large Load Diff
+13 -8
View File
@@ -795,15 +795,20 @@ do
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
local tgtcoord1 = tgtgrp1:GetCoordinate()
local tgtgrp2 = self.Groupset:FindNearestGroupFromPointVec2(tgtcoord)
local tgtcoord2 = tgtgrp2:GetCoordinate()
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
if dist1 < dist2 then
targetunit = tgtgrp1
targetcat = Object.Category.UNIT
if tgtgrp2 then
local tgtcoord2 = tgtgrp2:GetCoordinate()
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
if dist1 < dist2 then
targetunit = tgtgrp1
targetcat = Object.Category.UNIT
else
targetunit = tgtgrp2
targetcat = Object.Category.UNIT
end
else
targetunit = tgtgrp2
targetunit = tgtgrp1
targetcat = Object.Category.UNIT
end
end
@@ -1485,7 +1485,7 @@ function SUPPRESSION:onafterStop(Controllable, From, Event, To)
local text=string.format("Stopping SUPPRESSION for group %s", self.Controllable:GetName())
MESSAGE:New(text, 10):ToAllIf(self.Debug)
sefl:T(self.lid..text)
self:T(self.lid..text)
-- Clear all pending schedules
self.CallScheduler:Clear()
@@ -4097,7 +4097,7 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay,
-- Get name of template group.
local templategroupname=group:GetName()
local unit = group:GetUnit(1)
local Descriptors= (unit and unit:IsAlive()) and unit:GetDesc() or {}
local Descriptors= (unit and unit:IsAlive()~=nil) and unit:GetDesc() or {}
local Category=group:GetCategory()
local TypeName=group:GetTypeName() or "none"
local SpeedMax=group:GetSpeedMax()
@@ -4115,7 +4115,7 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay,
for _i,_unit in pairs(group:GetUnits()) do
local unit=_unit --Wrapper.Unit#UNIT
local Desc=unit:GetDesc()
-- Weight. We sum up all units in the group.
local unitweight=forceweight or Desc.massEmpty
if unitweight then
+1
View File
@@ -115,6 +115,7 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Squadron.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Target.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/EasyGCICAP.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/EasyA2G.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/TARS.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/ShapeBase.lua' )
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Circle.lua' )
+60 -22
View File
@@ -2717,17 +2717,27 @@ function AIRBOSS:DeleteRecoveryWindow( Window, Delay )
self:ScheduleOnce( Delay, self.DeleteRecoveryWindow, self, Window )
else
for i, _recovery in pairs( self.recoverytimes ) do
local recovery = _recovery -- #AIRBOSS.Recovery
if not Window then
return
end
if Window and Window.ID == recovery.ID then
if Window.OPEN then
-- Window is currently open.
self:RecoveryStop()
else
table.remove( self.recoverytimes, i )
end
-- If this window is currently open, stop recovery first. Mark it OVER so the
-- recovery time check cannot re-open it before/while we remove it.
if Window.OPEN then
Window.OPEN = false
Window.OVER = true
if self:IsRecovering() then
self:RecoveryStop()
end
end
-- Remove the window from the queue by its unique ID. Iterate over a numerically
-- indexed copy of the keys and remove via ipairs-safe reverse loop so that the
-- removal does not corrupt traversal (the window may appear once).
for i = #self.recoverytimes, 1, -1 do
local recovery = self.recoverytimes[i] -- #AIRBOSS.Recovery
if recovery and recovery.ID == Window.ID then
table.remove( self.recoverytimes, i )
end
end
end
@@ -4078,15 +4088,23 @@ function AIRBOSS:_CheckRecoveryTimes()
if self:IsRecovering() then
-- Carrier is already recovering.
state = "in progress"
else
-- Start recovery.
elseif not recovery.OVER then
-- Start recovery. Only if the window has not already been closed/cancelled.
-- The OVER guard prevents a window that was stopped manually (e.g. via the
-- Skipper "Stop Recovery" menu) from being immediately re-opened on the next
-- status tick while its [START,STOP) range is still active.
self:RecoveryStart( recovery.CASE, recovery.OFFSET )
state = "starting now"
recovery.OPEN = true
else
-- Window was already closed/cancelled within its active time range.
state = "cancelled"
end
-- Set current recovery window.
currwindow = recovery
-- Set current recovery window (unless this window has been cancelled).
if not recovery.OVER then
currwindow = recovery
end
else -- Stop time HAS passed.
@@ -4183,13 +4201,16 @@ function AIRBOSS:_CheckRecoveryTimes()
-- Time into the wind 1 day or if longer recovery time + the 5 min early.
local t = math.max( nextwindow.STOP - nextwindow.START + self.dTturn, 60 * 60 * 24 )
-- Recovery wind on deck in knots.
-- Recovery wind on deck in knots.
-- NOTE: Do NOT clamp the desired wind-over-deck (WOD) to the carrier's max hull
-- speed here. WOD = carrier speed + headwind, so a WOD target above the hull's
-- top speed is achievable whenever there is wind. CarrierTurnIntoWind ->
-- GetHeadingIntoWind already converts the WOD target into the required hull
-- speed and caps THAT at the carrier's max speed (Vmax) internally. Clamping the
-- WOD target itself capped achievable WOD at ~30 kts (the supercarrier's max
-- hull speed) even in strong wind, which made high-WOD recovery windows fall
-- short of their requested value.
local v = UTILS.KnotsToMps( nextwindow.SPEED )
-- Check that we do not go above max possible speed.
local vmax = self.carrier:GetSpeedMax() / 3.6 -- convert to m/s
v = math.min( v, vmax )
-- Route carrier into the wind. Sets self.turnintowind=true
self:CarrierTurnIntoWind( t, v, uturn )
@@ -4361,11 +4382,20 @@ function AIRBOSS:onafterRecoveryStop( From, Event, To )
self:CarrierResumeRoute( coord )
end
-- Delete current recovery window if open.
if self.recoverywindow and self.recoverywindow.OPEN == true then
-- Mark the current recovery window closed and cancelled, then remove it from the
-- queue. We do NOT gate this on Window.OPEN: that flag is only set by
-- _CheckRecoveryTimes (not by RecoveryStart), and the recovery time check nils and
-- rebuilds self.recoverywindow every status tick, so OPEN is not a reliable signal
-- here. Setting OVER=true is what actually prevents the window from being re-opened
-- on the next tick while its [START,STOP) range is still active.
--
-- The removal is deferred by one tick (Delay>0) so it does not mutate the
-- recoverytimes table while _CheckRecoveryTimes may be iterating over it (the natural
-- close path calls RecoveryStop() from inside that loop).
if self.recoverywindow then
self.recoverywindow.OPEN = false
self.recoverywindow.OVER = true
self:DeleteRecoveryWindow( self.recoverywindow )
self:DeleteRecoveryWindow( self.recoverywindow, 1 )
end
-- Check recovery windows. This sets self.recoverywindow to the next window.
@@ -12903,6 +12933,14 @@ function AIRBOSS:_LSOgrade( playerData )
-- Circuit edit only take points awary from a 1 wire if there are more than 4 other deviations
if playerData.wire == 1 and points >= 3 and N > 4 then
points = points -1
-- We also need to change the grade based on the new points.
if points == 4 then
grade = "OK"
elseif points == 3 then
grade = "(OK)"
elseif points == 2 then
grade = "--"
end
end
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
+1 -1
View File
@@ -6610,7 +6610,7 @@ function AUFTRAG:GetDCSMissionTask(MissionGroup)
local SeadUnitSet = SET_UNIT:New()
for _,_unit in pairs (ScanUnitSet.Set) do
local unit = _unit -- Wrapper.Unit#UNTI
if unit and unit:IsAlive() and unit:HasSEAD() then
if unit and unit:IsAlive() and unit.HasSEAD and unit:HasSEAD() then
self:T("Adding UNIT for SEAD: "..unit:GetName())
local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,2956984318)
table.insert(DCStasks, task)
+8 -2
View File
@@ -504,6 +504,9 @@ CSAR.AircraftType["OH58D"] = 2
CSAR.AircraftType["CH-47Fbl1"] = 31
CSAR.AircraftType["AH-6J"] = 2
CSAR.AircraftType["MH-6J"] = 2
CSAR.AircraftType["Ka-50_3"] = 0
CSAR.AircraftType["Ka-50"] = 0
CSAR.AircraftType["AV8BNA"] = 0
--- CSAR class version.
-- @field #string version
@@ -2538,8 +2541,11 @@ function CSAR:_AddMedevacMenuItem()
if _unit then
--self:T("Unitname ".._unit:GetName().." IsAlive "..tostring(_unit:IsAlive()).." IsPlayer "..tostring(_unit:IsPlayer()))
if _unit:IsAlive() and _unit:IsPlayer() then
local unitName = _unit:GetName()
_UnitList[unitName] = unitName
local _maxUnits = self.AircraftType[_unit:GetTypeName()]
if _maxUnits == nil or _maxUnits > 0 then
local unitName = _unit:GetName()
_UnitList[unitName] = unitName
end
end -- end isAlive
end -- end if _unit
end -- end for
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+46 -15
View File
@@ -21,7 +21,7 @@
--
-------------------------------------------------------------------------
-- Date: September 2023
-- Last Update: Mar 2026
-- Last Update: June 2026
-------------------------------------------------------------------------
--
--- **Ops** - Easy GCI & CAP Manager
@@ -135,6 +135,7 @@
-- local mywing = EASYGCICAP:New("Blue CAP Operations",AIRBASE.Caucasus.Kutaisi,"blue","Blue EWR")
--
-- -- Add a CAP patrol point belonging to our airbase, we'll be at 30k ft doing 400 kn, initial direction 90 degrees (East), leg 20NM
-- -- NOTE - Skip this function and do not create CAP Points if you want GCI behaviour only.
-- mywing:AddPatrolPointCAP(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone 1"):GetCoordinate(),30000,400,90,20)
--
-- -- Add a Squadron with template "Blue Sq1 M2000c", 20 airframes, skill good, Modex starting with 102 and skin "Vendee Jeanne"
@@ -190,9 +191,10 @@
-- * @{#EASYGCICAP.SetDefaultResurrection}: Set how many seconds the AirWing stays inoperable after the AirWing STATIC HQ ist destroyed, default 900 secs.
-- * @{#EASYGCICAP.SetDefaultCAPSpeed}: Set how many knots the CAP flights should do (will be altitude corrected), default 300 kn.
-- * @{#EASYGCICAP.SetDefaultCAPAlt}: Set at which altitude (ASL) the CAP planes will fly, default 25,000 ft.
-- * @{#EASYGCICAP.SetDefaultINTERCEPTAlt}: Set at which altitude (ASL) the Intercept planes will fly, default 25,000 ft.
-- * @{#EASYGCICAP.SetDefaultCAPDirection}: Set the initial direction from the CAP point the planes will fly in degrees, default is 90°.
-- * @{#EASYGCICAP.SetDefaultCAPLeg}: Set the length of the CAP leg, default is 15 NM.
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CVAP/GCI), defaults to 2.
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CAP/GCI), defaults to 2.
-- * @{#EASYGCICAP.SetDefaultMissionRange}: Set how many NM the planes can go from the home base, defaults to 100.
-- * @{#EASYGCICAP.SetDefaultNumberAlert5Standby}: Set how many planes will be spawned on cold standby (Alert5), default 2.
-- * @{#EASYGCICAP.SetDefaultEngageRange}: Set max engage range for CAP flights if they detect intruders, defaults to 50.
@@ -286,7 +288,7 @@ EASYGCICAP = {
--- EASYGCICAP class version.
-- @field #string version
EASYGCICAP.version="0.1.35"
EASYGCICAP.version="0.1.38"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--
@@ -587,6 +589,17 @@ function EASYGCICAP:SetDefaultCAPAlt(Altitude)
return self
end
--- Set default INTERCEPT Altitude in feet
-- @param #EASYGCICAP self
-- @param #number Altitude (Optional) Altitude defaults to 25000
-- @return #EASYGCICAP self
function EASYGCICAP:SetDefaultINTERCEPTAlt(Altitude)
self:T(self.lid.."SetDefaultINTERCEPTAlt")
self.interceptalt = Altitude or 25000
return self
end
--
--- Set default CAP lieg initial direction in degrees
-- @param #EASYGCICAP self
-- @param #number Direction (Optional) Direction defaults to 90 (East)
@@ -754,6 +767,15 @@ end
function EASYGCICAP:_AddAirwing(Airbasename, Alias)
self:T(self.lid.."_AddAirwing "..Airbasename)
-- Gather Some Stats
local function counttable(tbl)
local count = 0
for _,_data in pairs(tbl) do
count = count + 1
end
return count
end
local CapFormation = self.CapFormation
local DespawnAfterLanding = self.DespawnAfterLanding
local DespawnAfterHolding = self.DespawnAfterHolding
@@ -772,7 +794,11 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
CAP_Wing:SetMarker(false)
CAP_Wing:SetAirbase(AIRBASE:FindByName(Airbasename))
CAP_Wing:SetRespawnAfterDestroyed()
CAP_Wing:SetNumberCAP(self.capgrouping)
--- #DONE avoid wings with no CAP points starting CAP anyhow; AirWing uses this to start CAP and creates points when there are none.
if counttable(self.ManagedCP) >0 then
CAP_Wing:SetNumberCAP(self.capgrouping)
end
CAP_Wing:SetCapCloseRaceTrack(true)
if self.showpatrolpointmarks then
@@ -854,16 +880,18 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
end
if self.noalert5 > 0 then
local alert
if self.ClassName == "EASYGCICAP" then
alert = AUFTRAG:NewALERT5(AUFTRAG.Type.INTERCEPT)
elseif self.ClassName == "EASYA2G" then
alert = AUFTRAG:NewALERT5(AUFTRAG.Type.BAI)
for i=1,self.noalert5 do
local alert
if self.ClassName == "EASYGCICAP" then
alert = AUFTRAG:NewALERT5(AUFTRAG.Type.INTERCEPT)
elseif self.ClassName == "EASYA2G" then
alert = AUFTRAG:NewALERT5(AUFTRAG.Type.BAI)
end
alert:SetRequiredAssets(self.capgrouping)
alert:SetRepeat(99)
CAP_Wing:AddMission(alert)
table.insert(self.ListOfAuftrag,alert)
end
alert:SetRequiredAssets(self.noalert5)
alert:SetRepeat(99)
CAP_Wing:AddMission(alert)
table.insert(self.ListOfAuftrag,alert)
end
self.wings[Airbasename] = { CAP_Wing, AIRBASE:FindByName(Airbasename):GetZone(), Airbasename }
@@ -1037,7 +1065,7 @@ function EASYGCICAP:_SetCAPPatrolPoints()
MESSAGE:New(self.lid.."You are trying to create a CAP point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
return
end
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
local Coordinate = data.Coordinate
local Altitude = data.Altitude
local Speed = data.Speed
@@ -1503,6 +1531,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
local overhead = self.overhead
local capspeed = self.capspeed + 100
local capalt = self.capalt
local interalt = self.interceptalt or self.capalt
local maxsize = self.maxinterceptsize
local repeatsonfailure = self.repeatsonfailure
@@ -1590,6 +1619,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
:SetRepeatOnFailure(repeats)
:SetMissionSpeed(UTILS.KnotsToAltKIAS(capspeed,capalt))
:SetMissionAltitude(capalt)
:SetEngageAltitude(interalt)
if nogozoneset:Count() > 0 then
InterceptAuftrag:AddConditionSuccess(
@@ -1835,9 +1865,10 @@ function EASYGCICAP:onafterRestart(From,Event,To)
-- self.wings[Airbasename] = { CAP_Wing, AIRBASE:FindByName(Airbasename):GetZone(), Airbasename }
for _,_wing in pairs(self.wings or {}) do
for _,_aw in pairs(_wing) do
_wing[1]:Start()
_wing[1]:Restart()
end
end
end
self:__Status(5)
return self
end
@@ -1270,6 +1270,15 @@ function INTEL:_UpdateContact(Contact)
else
Contact.maneuvering = false
end
local typename = Contact.group:GetTypeName()
local base_rcs = INTEL.RCS_Table[typename]
if not base_rcs then
-- Fallback: category default
local cat = Contact.group:GetCategory()
base_rcs = (cat and INTEL.RCS_CategoryDefault[cat]) or INTEL.RCS_Reference
end
Contact.rcs = base_rcs
end
end
+1 -1
View File
@@ -2581,7 +2581,7 @@ end
-- @return #boolean Returns `true` if given cohort can meet all requirements.
function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight, RangeMin)
RangeMin = RangeMin or 0
RangeMin = RangeMin or -1
--- Function to check category.
local function CheckCategory(_cohort)
File diff suppressed because it is too large Load Diff
+109 -32
View File
@@ -61,24 +61,21 @@
--
-- # The MSRS Concept
--
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
-- This class allows to broadcast sound files or text to speech via Simple Radio Standalone (SRS).
--
-- ## Prerequisites
--
-- * This script needs SRS version >= 1.9.6
-- * You need to de-sanitize os, io and lfs in the missionscripting.lua
-- * Optional: DCS-gRPC as backend to communicate with SRS (via infra)
-- * Optional: HOUNDTTS as backend to communicate with SRS (via infra)
-- * Optional but recommended: HOUND TTS as backend to communicate with SRS (via plugin)
-- * Optional: DCS-gRPC as backend to communicate with SRS (via plugin)
--
-- ## Known Issues
--
-- ## Knwon Issues
--
-- ### Pop-up Window
-- ### Pop-up Window (with backend windows)
--
-- The text-to-speech conversion of SRS is done via an external exe file. When this file is called, a windows `cmd` window is briefly opended. That puts DCS out of focus, which is annoying,
-- expecially in VR but unavoidable (if you have a solution, please feel free to share!).
-- expecially in VR, but unavoidable unless you use HOUD or gRPC as backends.
--
-- NOTE that this is not an issue if the mission is running on a server.
-- Also NOTE that using DCS-gRPC and Hound-TTS as backend create no pop-up window.
--
-- # Play Sound Files
--
@@ -137,16 +134,17 @@
--
-- See @{#MSRS.LoadConfigFile} for details on how to set this up.
--
-- ## TTS Providers
--
-- The default provider for generating speech from text is the native Windows TTS service. Note that you need to install the voices you want to use.
-- ## TTS (text-to-speech) Providers
--
-- The **currently recommended** backend is HOUND TTS (no pop-ups), which has a wide variety of TTS providers.
-- The *default* provider for generating speech from text is the native Windows TTS service. Note that you need to install the voices you want to use.
--
-- **Pro-Tip** - use the command line with power shell to call `DCS-SR-ExternalAudio.exe` - it will tell you what is missing
-- and also the Google Console error, in case you have missed a step in setting up your Google TTS.
-- For example, `.\DCS-SR-ExternalAudio.exe -t "Text Message" -f 255 -m AM -c 2 -s 2 -z -G "Path_To_You_Google.Json"`
-- plays a message on 255 MHz AM for the blue coalition in-game.
--
-- ### Google
-- ### Google (best speech synthesis)
--
-- In order to use Google Cloud for TTS you need to use @{#MSRS.SetProvider} and @{#MSRS.SetProviderOptionsGoogle} functions:
--
@@ -162,7 +160,7 @@
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
--
-- ### Amazon Web Service [Only DCS-gRPC backend]
-- ### Amazon Web Service [Only HOUDN and DCS-gRPC backend]
--
-- In order to use Amazon Web Service (AWS) for TTS you need to use @{#MSRS.SetProvider} and @{#MSRS.SetProviderOptionsAmazon} functions:
--
@@ -173,7 +171,7 @@
--
-- You can set the voice to use with AWS via @{#MSRS.SetVoiceAmazon}.
--
-- ### Microsoft Azure [Only DCS-gRPC backend]
-- ### Microsoft Azure [Only HOUND and DCS-gRPC backend]
--
-- In order to use Microsoft Azure for TTS you need to use @{#MSRS.SetProvider} and @{#MSRS.SetProviderOptionsAzure} functions:
--
@@ -184,6 +182,12 @@
--
-- You can set the voice to use with Azure via @{#MSRS.SetVoiceAzure}.
--
-- ### Piper, OpenAI and further provider options [Only HOUND backend]
--
-- You can use further providers with HOUND TTS as a backend, see [Hound-TTS](https://github.com/uriba107/HoundTTS/releases) for setup.
--
-- msrs:SetProvider(MSRS.Provider.PIPER) -- e.g. for piper
--
-- ## Backend
--
-- The default interface to SRS is via calling the 'DCS-SR-ExternalAudio.exe'. As noted above, this has the unavoidable drawback that a pop-up briefly appears
@@ -191,13 +195,13 @@
--
-- ## Hound TTS as an alternative to 'DCS-SR-ExternalAudio.exe' for TTS
--
-- An alternative interface to SRS is [Hound-TTS](https://github.com/uriba107/HoundTTS/releases). This does not call an exe file and therefore avoids the annoying pop-up window.
-- the recommended alternative interface to SRS is [Hound-TTS](https://github.com/uriba107/HoundTTS/releases). This does not call an exe file and therefore avoids the annoying pop-up window.
-- In addition to Windows and Google cloud, it also offers Piper local voice creation and others as providers for TTS.
--
-- Use @{#MSRS.SetDefaultBackendHound} to enable [Hound-TTS](https://github.com/uriba107/HoundTTS/releases) as an alternate backend.
-- This can be useful if the popup should be avoided or to use Piper or others for TTS. Please note, only text-to-speech is supported and it it cannot be used to transmit audio files.
--
-- Hound TTS must be installed and configured per the [Hound TTS](https://github.com/uriba107/HoundTTS#installation) prior to use.
-- Hound TTS must be installed and configured per the [Hound TTS](https://github.com/uriba107/HoundTTS#installation) GitHub prior to use.
-- If a cloud TTS provider is being used, the API key(s) must be set as per the documentation.
-- Hound TTS can be used both with DCS dedicated server and regular DCS installations.
--
@@ -280,7 +284,7 @@ MSRS = {
--- MSRS class version.
-- @field #string version
MSRS.version="0.3.5"
MSRS.version="0.3.7"
--- Voices
-- @type MSRS.Voices
@@ -731,14 +735,16 @@ MSRS.Backend = {
-- @field #string AZURE Microsoft Azure (`azure`). Only possible with DCS-gRPC backend.
-- @field #string AMAZON Amazon Web Service (`aws`). Only possible with DCS-gRPC backend.
-- @field #string PIPER Piper local voice service. Only possible with Hound-TTS backend.
-- @field #string KITTEN Kitten voice server. Only possible with Hound-TTS backend.
-- @field #string KITTEN Kitten voice server. Only possible with Hound-TTS backend. Superseded by OpenAI
-- @field #string OPENAI OpenAI voice server. Only possible with Hound-TTS backend.
MSRS.Provider = {
WINDOWS = "win",
GOOGLE = "gcloud",
AZURE = "azure",
AMAZON = "aws",
PIPER = "piper",
KITTEN = "kitten",
KITTEN = "openai",
OPENAI = "openai",
}
--- Function for UUID.
@@ -1471,6 +1477,15 @@ function MSRS:SetTTSProviderKitten()
return self
end
--- Use OpenAI to provide text-to-speech. Only supported if used in combination with Hound-TTS as backend.
-- @param #MSRS self
-- @return #MSRS self
function MSRS:SetTTSProviderOpenAI()
self:F()
self:SetProvider(MSRS.Provider.OPENAI)
return self
end
--- Print SRS help to DCS log file.
-- @param #MSRS self
-- @return #MSRS self
@@ -1605,7 +1620,7 @@ function MSRS:PlayText(Text, Delay, Coordinate, Speed, Speaker)
else
local speaker = Speaker or self.Speaker
if self.backend==MSRS.Backend.GRPC then
self:T(self.lid.."Transmitting")
self:_DCSgRPCtts(Text, nil, nil , nil, nil, nil, nil, Coordinate)
@@ -2088,19 +2103,16 @@ function MSRS:_HoundTextToSpeech(Message,Frequencies,Modulations,Volume,Label,Co
return
end
Frequencies = UTILS.EnsureTable(Frequencies)
Modulations = UTILS.EnsureTable(Modulations)
Frequencies = UTILS.EnsureTable(Frequencies or self.frequencies)
Modulations = UTILS.EnsureTable(Modulations or self.modulations)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.1f",_f))
for _,_f in pairs(Frequencies) do
table.insert(ffs,string.format("%.3f",_f))
end
local freqs = table.concat(ffs, ",")
local modus = table.concat(Modulations or self.modulations, ",")
local modus = table.concat(Modulations, ",")
local coal=Coalition or self.coalition
local gender=Gender or self.gender
@@ -2144,7 +2156,7 @@ function MSRS:_HoundTextToSpeech(Message,Frequencies,Modulations,Volume,Label,Co
gender = gender,
speaker = Speaker or self.Speaker,
}
local speechtime = HoundTTS.Transmit(Message, TransmissionP, ProviderP)
return speechtime
@@ -2202,7 +2214,7 @@ function MSRS:_HoundTestTone(Frequencies, Modulations, Coalition)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.1f",_f))
table.insert(ffs,string.format("%.3f",_f))
end
local freqs = table.concat(ffs, ",")
@@ -2258,6 +2270,71 @@ function MSRS._HoundTranslate(Message,Parameters,CallbackFunction)
return
end
--- Create and run a radio jammer for a number of seconds on given frequencies. Requires HOUND backend v0.2.0-beta5 or better.
-- @param #MSRS self
-- @param #table Frequencies The table of frequencies to use.
-- @param #table Modulations The table of modulations to use.
-- @param #number Coalition (Optional) The coalition to use. Defaults to previously set coalition on this instance.
-- @param #string Noisetype (Optional) One of "white" (default) | "chirp" | "harsh" | "jam".
-- @param #number Volume (Optional) Volume 0.01.0 (default 1.0).
-- @param #number Seconds (Optional) How long in seconds this jammer runs. Defaults to 30 seconds.
-- @param #string Label (Optional) The label to use, defaults to "MSRS".
-- @param DCS#Vec3 Vec3 (Optional) Vec3 of the sender's position.
-- @param #boolean Encrypt (Optional) If true, use the SRS encrypt option.
-- @param #number EncKey (Optional) If encrypt is true, use this encrypt key.
-- @return #number ID The Jammer ID to switch the jamming off again with `MSRS.RadioJammerOff()`
function MSRS:RadioJammerOn(Frequencies, Modulations, Coalition, Noisetype, Volume, Seconds, Label, Vec3, Encrypt, EncKey)
self:T(self.lid.."RadioJammerOn")
Frequencies = UTILS.EnsureTable(Frequencies)
Modulations = UTILS.EnsureTable(Modulations)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.3f",_f))
end
local freqs = table.concat(ffs, ",")
local modus = table.concat(Modulations or self.modulations, ",")
-- Replace modulation
modus=modus:gsub("0", "AM")
modus=modus:gsub("1", "FM")
local coal=Coalition or self.coalition or coalition.side.RED
local secs = Seconds or 30
local TransmissionP = {}
local ProviderP = {}
TransmissionP.transmitter = "srs"
TransmissionP.freqs = freqs
TransmissionP.modulations = modus
TransmissionP.coalition = coal or self.coalition -- number 0=spectator, 1=red, 2=blue
TransmissionP.name = Label or self.Label -- string client name shown in SRS
TransmissionP.point = Vec3 -- DCS Vec3 (optional) — initial transmitter position
TransmissionP.encrypt = Encrypt -- bool
TransmissionP.encKey = EncKey -- number 0255
ProviderP.noiseType = Noisetype or "white"
ProviderP.volume = Volume or 1
local ID = HoundTTS.TransmitNoise(TransmissionP, ProviderP)
self.NoiseID = ID
self:ScheduleOnce(secs,MSRS.RadioJammerOff,self,ID)
return ID
end
--- Switch off a running Jammer using its ID.
-- @param #MSRS self
-- @param #number ID
function MSRS:RadioJammerOff(ID)
return HoundTTS.KillSession(ID or self.NoiseID)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Config File
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+43 -2
View File
@@ -523,7 +523,7 @@ ENUMS.ReportingName =
Tornado = "Tornado",
-- Transport / Bomber / Others
Atlas = "A400",
Lancer = "B1-B",
Lancer = "B-1B",
Stratofortress = "B-52H",
Herc = "C-130",
Hercules = "C-130J-30",
@@ -568,7 +568,7 @@ ENUMS.ReportingName =
Apache = "AH-64",
Chinook = "CH-47",
Sea_Stallion = "CH-53",
Kiowa = "OH-58",
Kiowa = "OH58D",
Seahawk = "SH-60",
Blackhawk = "UH-60",
Sea_King = "S-61",
@@ -2126,6 +2126,47 @@ ENUMS.Storage.weapons.containers.UH60_GAU19_RIGHT = 'weapons.containers.{UH60_GA
ENUMS.Storage.weapons.containers.UH60_M230_RIGHT = 'weapons.containers.{UH60_M230_RIGHT}'
ENUMS.Storage.weapons.containers.UH60L_M2_GUNNER = 'weapons.containers.{UH60L_M2_GUNNER}'
ENUMS.Storage.weapons.adapters.GD_F100_SUU_13 = 'weapons.adapters.GD_F100_SUU-13'
ENUMS.Storage.weapons.containers.GPU_5_POD = 'weapons.containers.{GPU_5_POD}'
ENUMS.Storage.weapons.bombs.BOLT_117 = 'weapons.bombs.BOLT-117'
ENUMS.Storage.weapons.shells.F100_M39_20_TP_T = 'weapons.shells.F100_M39_20_TP_T'
ENUMS.Storage.weapons.gunmounts.M_39_F_100 = 'weapons.gunmounts.M-39 F-100'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_275_L = 'weapons.droptanks.GD_F100_TANK_275_L'
ENUMS.Storage.weapons.bombs.BLU_4B_R_GROUP_R = 'weapons.bombs.BLU-4B_R_GROUP_R'
ENUMS.Storage.weapons.containers.F100_CAMERA_P2 = 'weapons.containers.F100_CAMERA_P2'
ENUMS.Storage.weapons.containers.HB_ORD_SUU_7 = 'weapons.containers.HB_ORD_SUU_7'
ENUMS.Storage.weapons.adapters.SidewinderPylon = 'weapons.adapters.SidewinderPylon'
ENUMS.Storage.weapons.adapters.apu_470 = 'weapons.adapters.apu_470'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_335_R = 'weapons.droptanks.GD_F100_TANK_335_R'
ENUMS.Storage.weapons.bombs.BLU_3B_R_GROUP_R = 'weapons.bombs.BLU-3B_R_GROUP_R'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_335_L = 'weapons.droptanks.GD_F100_TANK_335_L'
ENUMS.Storage.weapons.adapters.mbdz_u2t = 'weapons.adapters.mbdz_u2t'
ENUMS.Storage.weapons.containers.ZellRocket = 'weapons.containers.ZellRocket'
ENUMS.Storage.weapons.containers.apu_73 = 'weapons.containers.apu-73'
ENUMS.Storage.weapons.gunmounts.GAU_13 = 'weapons.gunmounts.GAU-13'
ENUMS.Storage.weapons.shells.F100_M39_20_TP = 'weapons.shells.F100_M39_20_TP'
ENUMS.Storage.weapons.shells.F100_M39_20_API = 'weapons.shells.F100_M39_20_API'
ENUMS.Storage.weapons.adapters.bdz_umk2b = 'weapons.adapters.bdz_umk2b'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_450 = 'weapons.droptanks.GD_F100_TANK_450'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_275_R = 'weapons.droptanks.GD_F100_TANK_275_R'
ENUMS.Storage.weapons.bombs.BLU_18_B_GROUP = 'weapons.bombs.BLU-18/B_GROUP'
ENUMS.Storage.weapons.containers.ZELL_Booster = 'weapons.containers.ZELL Booster'
ENUMS.Storage.weapons.adapters.apu_60 = 'weapons.adapters.apu_60'
ENUMS.Storage.weapons.gunmounts.GPU_5_POD = 'weapons.gunmounts.{GPU_5_POD}'
ENUMS.Storage.weapons.containers.F100_CAMERA_KA71A = 'weapons.containers.F100_CAMERA_KA71A'
ENUMS.Storage.weapons.bombs.BLU_3_R_GROUP_R = 'weapons.bombs.BLU-3_R_GROUP_R'
ENUMS.Storage.weapons.shells.F100_M39_20_HEI = 'weapons.shells.F100_M39_20_HEI'
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_200 = 'weapons.droptanks.GD_F100_TANK_200'
ENUMS.Storage.weapons.adapters.apu_73 = 'weapons.adapters.apu-73'
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.AKAN_NO_TRC'
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.AKAN'
ENUMS.Storage.weapons.shells.F100_M39_20_HEI_T = 'weapons.shells.F100_M39_20_HEI_T'
ENUMS.Storage.weapons.shells.F100_M39_20_API_T = 'weapons.shells.F100_M39_20_API_T'
ENUMS.Storage.weapons.containers.GD_F100_STRIKE_CAMERA = 'weapons.containers.GD_F100_STRIKE_CAMERA'
ENUMS.Storage.weapons.bombs.BLU_49_B = 'weapons.bombs.BLU-49/B'
ENUMS.Storage.weapons.containers.GD_F100_SUU_13 = 'weapons.containers.GD_F100_SUU-13'
---
-- @type ENUMS.FARPType
-- @field #string FARP
@@ -2378,6 +2378,11 @@ function UTILS.IsLoadingDoorOpen( unit_name )
BASE:T(unit_name .. " front door(s) are open or doors removed")
return true
end
if type_name == "Ka-50_3" and unit:getDrawArgumentValue(38) == 1 then
BASE:T(unit_name .. " cockpit door is open")
return true
end
if type_name=="C-130J-30" and (unit:getDrawArgumentValue(86)==1)then
BASE:T(unit_name.." rear doors are open")
+392 -72
View File
@@ -23,6 +23,7 @@
-- @field #boolean isAirdrome Airbase is an airdrome.
-- @field #boolean isHelipad Airbase is a helipad.
-- @field #boolean isShip Airbase is a ship.
-- @field #boolean isZell Airbase is a ZELL Booster.
-- @field #table parking Parking spot data.
-- @field #table parkingByID Parking spot data table with ID as key.
-- @field #table parkingWhitelist List of parking spot terminal IDs considered for spawning.
@@ -458,115 +459,420 @@ AIRBASE.TheChannel = {
--- Airbases of the Syria map
--
-- * `AIRBASE.Syria.Abu_al_Duhur` Abu al-Duhur
-- * `AIRBASE.Syria.Adana_Sakirpasa` Adana Sakirpasa
-- * `AIRBASE.Syria.Akrotiri` Akrotiri
-- * `AIRBASE.Syria.Al_Qusayr` Al Qusayr
-- * `AIRBASE.Syria.Al_Dumayr` Al-Dumayr
-- * `AIRBASE.Syria.Aleppo` Aleppo
-- * `AIRBASE.Syria.An_Nasiriyah` An Nasiriyah
-- * `AIRBASE.Syria.At_Tanf` At Tanf
-- * `AIRBASE.Syria.Bassel_Al_Assad` Bassel Al-Assad
-- * `AIRBASE.Syria.Beirut_Rafic_Hariri` Beirut-Rafic Hariri
-- * `AIRBASE.Syria.Ben_Gurion` Ben Gurion
-- * `AIRBASE.Syria.Damascus` Damascus
-- * `AIRBASE.Syria.Deir_ez_Zor` Deir ez-Zor
-- * `AIRBASE.Syria.Ercan` Ercan
-- * `AIRBASE.Syria.Eyn_Shemer` Eyn Shemer
-- * `AIRBASE.Syria.Gaziantep` Gaziantep
-- * `AIRBASE.Syria.Gazipasa` Gazipasa
-- * `AIRBASE.Syria.Gecitkale` Gecitkale
-- * `AIRBASE.Syria.H` H
-- * `AIRBASE.Syria.H3` H3
-- * `AIRBASE.Syria.H3_Northwest` H3 Northwest
-- * `AIRBASE.Syria.H3_Southwest` H3 Southwest
-- * `AIRBASE.Syria.H4` H4
-- * `AIRBASE.Syria.Haifa` Haifa
-- * `AIRBASE.Syria.Hama` Hama
-- * `AIRBASE.Syria.Hatay` Hatay
-- * `AIRBASE.Syria.Hatzor` Hatzor
-- * `AIRBASE.Syria.Herzliya` Herzliya
-- * `AIRBASE.Syria.Incirlik` Incirlik
-- * `AIRBASE.Syria.Jirah` Jirah
-- * `AIRBASE.Syria.Khalkhalah` Khalkhalah
-- * `AIRBASE.Syria.Kharab_Ishk` Kharab Ishk
-- * `AIRBASE.Syria.King_Abdullah_II` King Abdullah II
-- * `AIRBASE.Syria.King_Hussein_Air_College` King Hussein Air College
-- * `AIRBASE.Syria.Kingsfield` Kingsfield
-- * `AIRBASE.Syria.Kiryat_Shmona` Kiryat Shmona
-- * `AIRBASE.Syria.Kuweires` Kuweires
-- * `AIRBASE.Syria.Lakatamia` Lakatamia
-- * `AIRBASE.Syria.Larnaca` Larnaca
-- * `AIRBASE.Syria.Marj_Ruhayyil` Marj Ruhayyil
-- * `AIRBASE.Syria.Marj_as_Sultan_North` Marj as Sultan North
-- * `AIRBASE.Syria.Marj_as_Sultan_South` Marj as Sultan South
-- * `AIRBASE.Syria.Marka` Marka
-- * `AIRBASE.Syria.Megiddo` Megiddo
-- * `AIRBASE.Syria.Mezzeh` Mezzeh
-- * `AIRBASE.Syria.Minakh` Minakh
-- * `AIRBASE.Syria.Muwaffaq_Salti` Muwaffaq Salti
-- * `AIRBASE.Syria.Naqoura` Naqoura
-- * `AIRBASE.Syria.Nicosia` Nicosia
-- * `AIRBASE.Syria.Palmachim` Palmachim
-- * `AIRBASE.Syria.Palmyra` Palmyra
-- * `AIRBASE.Syria.Paphos` Paphos
-- * `AIRBASE.Syria.Pinarbashi` Pinarbashi
-- * `AIRBASE.Syria.Prince_Hassan` Prince Hassan
-- * `AIRBASE.Syria.Qabr_as_Sitt` Qabr as Sitt
-- * `AIRBASE.Syria.Ramat_David` Ramat David
-- * `AIRBASE.Syria.Rayak` Rayak
-- * `AIRBASE.Syria.Rene_Mouawad` Rene Mouawad
-- * `AIRBASE.Syria.Rosh_Pina` Rosh Pina
-- * `AIRBASE.Syria.Ruwayshid` Ruwayshid
-- * `AIRBASE.Syria.Sanliurfa` Sanliurfa
-- * `AIRBASE.Syria.Sayqal` Sayqal
-- * `AIRBASE.Syria.Shayrat` Shayrat
-- * `AIRBASE.Syria.Tabqa` Tabqa
-- * `AIRBASE.Syria.Taftanaz` Taftanaz
-- * `AIRBASE.Syria.Tal_Siman` Tal Siman
-- * `AIRBASE.Syria.Tel_Nof` Tel Nof
-- * `AIRBASE.Syria.Tha_lah` Tha'lah
-- * `AIRBASE.Syria.Tiyas` Tiyas
-- * `AIRBASE.Syria.Wujah_Al_Hajar` Wujah Al Hajar
-- * AIRBASE.Syria.Abu_al_Duhur
-- * AIRBASE.Syria.Adana_Sakirpasa
-- * AIRBASE.Syria.Adiyaman
-- * AIRBASE.Syria.Akrotiri
-- * AIRBASE.Syria.Al_Dumayr
-- * AIRBASE.Syria.Al_Qusayr
-- * AIRBASE.Syria.Aleppo
-- * AIRBASE.Syria.An_Nasiriyah
-- * AIRBASE.Syria.At_Tanf
-- * AIRBASE.Syria.Bassel_Al_Assad
-- * AIRBASE.Syria.Beirut_Rafic_Hariri
-- * AIRBASE.Syria.Ben_Gurion
-- * AIRBASE.Syria.Chukurova
-- * AIRBASE.Syria.Damascus
-- * AIRBASE.Syria.Deir_ez_Zor
-- * AIRBASE.Syria.Diyarbakir
-- * AIRBASE.Syria.Ercan
-- * AIRBASE.Syria.Eyn_Shemer
-- * AIRBASE.Syria.Gaziantep
-- * AIRBASE.Syria.Gazipasa
-- * AIRBASE.Syria.Gecitkale
-- * AIRBASE.Syria.Gulechoba
-- * AIRBASE.Syria.H3
-- * AIRBASE.Syria.H3_Northwest
-- * AIRBASE.Syria.H3_Southwest
-- * AIRBASE.Syria.H4
-- * AIRBASE.Syria.H4_Emergency
-- * AIRBASE.Syria.HC01
-- * AIRBASE.Syria.HC02
-- * AIRBASE.Syria.HC03
-- * AIRBASE.Syria.HC04
-- * AIRBASE.Syria.HC05
-- * AIRBASE.Syria.HC06
-- * AIRBASE.Syria.HI01
-- * AIRBASE.Syria.HI02
-- * AIRBASE.Syria.HI03
-- * AIRBASE.Syria.HI05
-- * AIRBASE.Syria.HI06
-- * AIRBASE.Syria.HI07
-- * AIRBASE.Syria.HI08
-- * AIRBASE.Syria.HI09
-- * AIRBASE.Syria.HI11
-- * AIRBASE.Syria.HI12
-- * AIRBASE.Syria.HI13
-- * AIRBASE.Syria.HI14
-- * AIRBASE.Syria.HI15
-- * AIRBASE.Syria.HI16
-- * AIRBASE.Syria.HI17
-- * AIRBASE.Syria.HI18
-- * AIRBASE.Syria.HI20
-- * AIRBASE.Syria.HI21
-- * AIRBASE.Syria.HI22
-- * AIRBASE.Syria.HI23
-- * AIRBASE.Syria.HI24
-- * AIRBASE.Syria.HI25
-- * AIRBASE.Syria.HI26
-- * AIRBASE.Syria.HJ01
-- * AIRBASE.Syria.HJ02
-- * AIRBASE.Syria.HJ03
-- * AIRBASE.Syria.HJ04
-- * AIRBASE.Syria.HL01
-- * AIRBASE.Syria.HL02
-- * AIRBASE.Syria.HL03
-- * AIRBASE.Syria.HL04
-- * AIRBASE.Syria.HL05
-- * AIRBASE.Syria.HL06
-- * AIRBASE.Syria.HL07
-- * AIRBASE.Syria.HL08
-- * AIRBASE.Syria.HL09
-- * AIRBASE.Syria.HL10
-- * AIRBASE.Syria.HL11
-- * AIRBASE.Syria.HL12
-- * AIRBASE.Syria.HL13
-- * AIRBASE.Syria.HMed00
-- * AIRBASE.Syria.HMed01
-- * AIRBASE.Syria.HMed02
-- * AIRBASE.Syria.HMed03
-- * AIRBASE.Syria.HMed04
-- * AIRBASE.Syria.HMed05
-- * AIRBASE.Syria.HMed06
-- * AIRBASE.Syria.HMed07
-- * AIRBASE.Syria.HMed08
-- * AIRBASE.Syria.HMed09
-- * AIRBASE.Syria.HMed10
-- * AIRBASE.Syria.HMed11
-- * AIRBASE.Syria.HMed12
-- * AIRBASE.Syria.HMed13
-- * AIRBASE.Syria.HMed14
-- * AIRBASE.Syria.HMed15
-- * AIRBASE.Syria.HMed16
-- * AIRBASE.Syria.HMed17
-- * AIRBASE.Syria.HMed18
-- * AIRBASE.Syria.HMed19
-- * AIRBASE.Syria.HMed20
-- * AIRBASE.Syria.HMed21
-- * AIRBASE.Syria.HMed22
-- * AIRBASE.Syria.HMed23
-- * AIRBASE.Syria.HMed24
-- * AIRBASE.Syria.HMed25
-- * AIRBASE.Syria.HMed26
-- * AIRBASE.Syria.HMed27
-- * AIRBASE.Syria.HMed28
-- * AIRBASE.Syria.HMed29
-- * AIRBASE.Syria.HMed30
-- * AIRBASE.Syria.HOil01
-- * AIRBASE.Syria.HOil02
-- * AIRBASE.Syria.HOil03
-- * AIRBASE.Syria.HOil04
-- * AIRBASE.Syria.HOil05
-- * AIRBASE.Syria.HOil06
-- * AIRBASE.Syria.HS02
-- * AIRBASE.Syria.HS03
-- * AIRBASE.Syria.HS04
-- * AIRBASE.Syria.HS05
-- * AIRBASE.Syria.HS06
-- * AIRBASE.Syria.HS07
-- * AIRBASE.Syria.HS08
-- * AIRBASE.Syria.HS09
-- * AIRBASE.Syria.HS10
-- * AIRBASE.Syria.HS11
-- * AIRBASE.Syria.HS12
-- * AIRBASE.Syria.HS13
-- * AIRBASE.Syria.HS14
-- * AIRBASE.Syria.HS15
-- * AIRBASE.Syria.HS16
-- * AIRBASE.Syria.HS17
-- * AIRBASE.Syria.HS18
-- * AIRBASE.Syria.HS19
-- * AIRBASE.Syria.HS20
-- * AIRBASE.Syria.HS21
-- * AIRBASE.Syria.HS22
-- * AIRBASE.Syria.HS23
-- * AIRBASE.Syria.HS24
-- * AIRBASE.Syria.HS25
-- * AIRBASE.Syria.HS26
-- * AIRBASE.Syria.HS27
-- * AIRBASE.Syria.HS28
-- * AIRBASE.Syria.HS29
-- * AIRBASE.Syria.HS30
-- * AIRBASE.Syria.HS31
-- * AIRBASE.Syria.HS32
-- * AIRBASE.Syria.HS33
-- * AIRBASE.Syria.HS34
-- * AIRBASE.Syria.HS35
-- * AIRBASE.Syria.HS36
-- * AIRBASE.Syria.HS37
-- * AIRBASE.Syria.HS38
-- * AIRBASE.Syria.HS39
-- * AIRBASE.Syria.HS40
-- * AIRBASE.Syria.HS41
-- * AIRBASE.Syria.HS42
-- * AIRBASE.Syria.HStad01
-- * AIRBASE.Syria.HStad02
-- * AIRBASE.Syria.HStad03
-- * AIRBASE.Syria.HStad04
-- * AIRBASE.Syria.HStad05
-- * AIRBASE.Syria.HStad06
-- * AIRBASE.Syria.HT01
-- * AIRBASE.Syria.HT02
-- * AIRBASE.Syria.H_med_orig_01
-- * AIRBASE.Syria.H_med_orig_02
-- * AIRBASE.Syria.H_med_orig_03
-- * AIRBASE.Syria.H_med_orig_04
-- * AIRBASE.Syria.H_med_orig_05
-- * AIRBASE.Syria.H_med_orig_06
-- * AIRBASE.Syria.H_med_orig_07
-- * AIRBASE.Syria.H_med_orig_08
-- * AIRBASE.Syria.H_med_orig_09
-- * AIRBASE.Syria.Haifa
-- * AIRBASE.Syria.Hama
-- * AIRBASE.Syria.Hatay
-- * AIRBASE.Syria.Hatzerim
-- * AIRBASE.Syria.Hatzor
-- * AIRBASE.Syria.Herzliya
-- * AIRBASE.Syria.Incirlik
-- * AIRBASE.Syria.Jirah
-- * AIRBASE.Syria.Kahramanmaras
-- * AIRBASE.Syria.Kedem
-- * AIRBASE.Syria.Khalkhalah
-- * AIRBASE.Syria.Kharab_Ishk
-- * AIRBASE.Syria.King_Abdullah_II
-- * AIRBASE.Syria.King_Hussein_Air_College
-- * AIRBASE.Syria.Kingsfield
-- * AIRBASE.Syria.Kiryat_Shmona
-- * AIRBASE.Syria.Konya
-- * AIRBASE.Syria.Kuweires
-- * AIRBASE.Syria.Lakatamia
-- * AIRBASE.Syria.Larnaca
-- * AIRBASE.Syria.Marj_Ruhayyil
-- * AIRBASE.Syria.Marj_as_Sultan_North
-- * AIRBASE.Syria.Marj_as_Sultan_South
-- * AIRBASE.Syria.Marka
-- * AIRBASE.Syria.Megiddo
-- * AIRBASE.Syria.Mezzeh
-- * AIRBASE.Syria.Minakh
-- * AIRBASE.Syria.Muwaffaq_Salti
-- * AIRBASE.Syria.Naqoura
-- * AIRBASE.Syria.Nevatim
-- * AIRBASE.Syria.Nicosia
-- * AIRBASE.Syria.Palmachim
-- * AIRBASE.Syria.Palmyra
-- * AIRBASE.Syria.Paphos
-- * AIRBASE.Syria.Pinarbashi
-- * AIRBASE.Syria.Prince_Hassan
-- * AIRBASE.Syria.Qabr_as_Sitt
-- * AIRBASE.Syria.Ramat_David
-- * AIRBASE.Syria.Rayak
-- * AIRBASE.Syria.Rene_Mouawad
-- * AIRBASE.Syria.Rosh_Pina
-- * AIRBASE.Syria.Ruwayshid
-- * AIRBASE.Syria.Sanliurfa
-- * AIRBASE.Syria.Sanliurfa_Heliport
-- * AIRBASE.Syria.Sayqal
-- * AIRBASE.Syria.Shayrat
-- * AIRBASE.Syria.T2
-- * AIRBASE.Syria.T3
-- * AIRBASE.Syria.Tabqa
-- * AIRBASE.Syria.Taftanaz
-- * AIRBASE.Syria.Tal_Siman
-- * AIRBASE.Syria.Tel_Nof
-- * AIRBASE.Syria.Teyman
-- * AIRBASE.Syria.Tha_lah
-- * AIRBASE.Syria.Tiyas
-- * AIRBASE.Syria.Wujah_Al_Hajar
-- * AIRBASE.Syria.Zarqa
--
-- @field Syria
AIRBASE.Syria = {
["Abu_al_Duhur"] = "Abu al-Duhur",
["Adana_Sakirpasa"] = "Adana Sakirpasa",
["Adiyaman"] = "Adiyaman",
["Akrotiri"] = "Akrotiri",
["Al_Qusayr"] = "Al Qusayr",
["Al_Dumayr"] = "Al-Dumayr",
["Al_Qusayr"] = "Al Qusayr",
["Aleppo"] = "Aleppo",
["An_Nasiriyah"] = "An Nasiriyah",
["At_Tanf"] = "At Tanf",
["Bassel_Al_Assad"] = "Bassel Al-Assad",
["Beirut_Rafic_Hariri"] = "Beirut-Rafic Hariri",
["Ben_Gurion"] = "Ben Gurion",
["Chukurova"] = "Chukurova",
["Damascus"] = "Damascus",
["Deir_ez_Zor"] = "Deir ez-Zor",
["Diyarbakir"] = "Diyarbakir",
["Ercan"] = "Ercan",
["Eyn_Shemer"] = "Eyn Shemer",
["Gaziantep"] = "Gaziantep",
["Gazipasa"] = "Gazipasa",
["Gecitkale"] = "Gecitkale",
["H"] = "H",
["Gulechoba"] = "Gulechoba",
["H3"] = "H3",
["H3_Northwest"] = "H3 Northwest",
["H3_Southwest"] = "H3 Southwest",
["H4"] = "H4",
["H4_Emergency"] = "H4 Emergency",
["HC01"] = "HC01",
["HC02"] = "HC02",
["HC03"] = "HC03",
["HC04"] = "HC04",
["HC05"] = "HC05",
["HC06"] = "HC06",
["HI01"] = "HI01",
["HI02"] = "HI02",
["HI03"] = "HI03",
["HI05"] = "HI05",
["HI06"] = "HI06",
["HI07"] = "HI07",
["HI08"] = "HI08",
["HI09"] = "HI09",
["HI11"] = "HI11",
["HI12"] = "HI12",
["HI13"] = "HI13",
["HI14"] = "HI14",
["HI15"] = "HI15",
["HI16"] = "HI16",
["HI17"] = "HI17",
["HI18"] = "HI18",
["HI20"] = "HI20",
["HI21"] = "HI21",
["HI22"] = "HI22",
["HI23"] = "HI23",
["HI24"] = "HI24",
["HI25"] = "HI25",
["HI26"] = "HI26",
["HJ01"] = "HJ01",
["HJ02"] = "HJ02",
["HJ03"] = "HJ03",
["HJ04"] = "HJ04",
["HL01"] = "HL01",
["HL02"] = "HL02",
["HL03"] = "HL03",
["HL04"] = "HL04",
["HL05"] = "HL05",
["HL06"] = "HL06",
["HL07"] = "HL07",
["HL08"] = "HL08",
["HL09"] = "HL09",
["HL10"] = "HL10",
["HL11"] = "HL11",
["HL12"] = "HL12",
["HL13"] = "HL13",
["HMed00"] = "HMed00",
["HMed01"] = "HMed01",
["HMed02"] = "HMed02",
["HMed03"] = "HMed03",
["HMed04"] = "HMed04",
["HMed05"] = "HMed05",
["HMed06"] = "HMed06",
["HMed07"] = "HMed07",
["HMed08"] = "HMed08",
["HMed09"] = "HMed09",
["HMed10"] = "HMed10",
["HMed11"] = "HMed11",
["HMed12"] = "HMed12",
["HMed13"] = "HMed13",
["HMed14"] = "HMed14",
["HMed15"] = "HMed15",
["HMed16"] = "HMed16",
["HMed17"] = "HMed17",
["HMed18"] = "HMed18",
["HMed19"] = "HMed19",
["HMed20"] = "HMed20",
["HMed21"] = "HMed21",
["HMed22"] = "HMed22",
["HMed23"] = "HMed23",
["HMed24"] = "HMed24",
["HMed25"] = "HMed25",
["HMed26"] = "HMed26",
["HMed27"] = "HMed27",
["HMed28"] = "HMed28",
["HMed29"] = "HMed29",
["HMed30"] = "HMed30",
["HOil01"] = "HOil01",
["HOil02"] = "HOil02",
["HOil03"] = "HOil03",
["HOil04"] = "HOil04",
["HOil05"] = "HOil05",
["HOil06"] = "HOil06",
["HS02"] = "HS02",
["HS03"] = "HS03",
["HS04"] = "HS04",
["HS05"] = "HS05",
["HS06"] = "HS06",
["HS07"] = "HS07",
["HS08"] = "HS08",
["HS09"] = "HS09",
["HS10"] = "HS10",
["HS11"] = "HS11",
["HS12"] = "HS12",
["HS13"] = "HS13",
["HS14"] = "HS14",
["HS15"] = "HS15",
["HS16"] = "HS16",
["HS17"] = "HS17",
["HS18"] = "HS18",
["HS19"] = "HS19",
["HS20"] = "HS20",
["HS21"] = "HS21",
["HS22"] = "HS22",
["HS23"] = "HS23",
["HS24"] = "HS24",
["HS25"] = "HS25",
["HS26"] = "HS26",
["HS27"] = "HS27",
["HS28"] = "HS28",
["HS29"] = "HS29",
["HS30"] = "HS30",
["HS31"] = "HS31",
["HS32"] = "HS32",
["HS33"] = "HS33",
["HS34"] = "HS34",
["HS35"] = "HS35",
["HS36"] = "HS36",
["HS37"] = "HS37",
["HS38"] = "HS38",
["HS39"] = "HS39",
["HS40"] = "HS40",
["HS41"] = "HS41",
["HS42"] = "HS42",
["HStad01"] = "HStad01",
["HStad02"] = "HStad02",
["HStad03"] = "HStad03",
["HStad04"] = "HStad04",
["HStad05"] = "HStad05",
["HStad06"] = "HStad06",
["HT01"] = "HT01",
["HT02"] = "HT02",
["H_med_orig_01"] = "H_med_orig_01",
["H_med_orig_02"] = "H_med_orig_02",
["H_med_orig_03"] = "H_med_orig_03",
["H_med_orig_04"] = "H_med_orig_04",
["H_med_orig_05"] = "H_med_orig_05",
["H_med_orig_06"] = "H_med_orig_06",
["H_med_orig_07"] = "H_med_orig_07",
["H_med_orig_08"] = "H_med_orig_08",
["H_med_orig_09"] = "H_med_orig_09",
["Haifa"] = "Haifa",
["Hama"] = "Hama",
["Hatay"] = "Hatay",
["Hatzerim"] = "Hatzerim",
["Hatzor"] = "Hatzor",
["Herzliya"] = "Herzliya",
["Incirlik"] = "Incirlik",
["Jirah"] = "Jirah",
["Kahramanmaras"] = "Kahramanmaras",
["Kedem"] = "Kedem",
["Khalkhalah"] = "Khalkhalah",
["Kharab_Ishk"] = "Kharab Ishk",
["King_Abdullah_II"] = "King Abdullah II",
["King_Hussein_Air_College"] = "King Hussein Air College",
["Kingsfield"] = "Kingsfield",
["Kiryat_Shmona"] = "Kiryat Shmona",
["Konya"] = "Konya",
["Kuweires"] = "Kuweires",
["Lakatamia"] = "Lakatamia",
["Larnaca"] = "Larnaca",
@@ -579,6 +885,7 @@ AIRBASE.Syria = {
["Minakh"] = "Minakh",
["Muwaffaq_Salti"] = "Muwaffaq Salti",
["Naqoura"] = "Naqoura",
["Nevatim"] = "Nevatim",
["Nicosia"] = "Nicosia",
["Palmachim"] = "Palmachim",
["Palmyra"] = "Palmyra",
@@ -592,15 +899,20 @@ AIRBASE.Syria = {
["Rosh_Pina"] = "Rosh Pina",
["Ruwayshid"] = "Ruwayshid",
["Sanliurfa"] = "Sanliurfa",
["Sanliurfa_Heliport"] = "Sanliurfa Heliport",
["Sayqal"] = "Sayqal",
["Shayrat"] = "Shayrat",
["T2"] = "T2",
["T3"] = "T3",
["Tabqa"] = "Tabqa",
["Taftanaz"] = "Taftanaz",
["Tal_Siman"] = "Tal Siman",
["Tel_Nof"] = "Tel Nof",
["Teyman"] = "Teyman",
["Tha_lah"] = "Tha'lah",
["Tiyas"] = "Tiyas",
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
["Zarqa"] = "Zarqa",
}
--- Airbases of the Mariana Islands map
@@ -1673,6 +1985,7 @@ elseif self.category==Airbase.Category.SHIP then
self.category=Airbase.Category.HELIPAD
_DATABASE:AddStatic(AirbaseName)
end
if self:GetTypeName() == "Zell" then self.isZell = true end
else
self:E("ERROR: Unknown airbase category!")
end
@@ -2122,6 +2435,13 @@ function AIRBASE:IsShip()
return self.isShip
end
--- Check if airbase is a ZELL booster.
-- @param #AIRBASE self
-- @return #boolean If true, airbase is a ZELL booster.
function AIRBASE:IsZell()
return self.isZell
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Parking
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+1
View File
@@ -112,6 +112,7 @@ Ops/OpsZone.lua
Ops/ArmyGroup.lua
Ops/OpsTransport.lua
Ops/Target.lua
Ops/TARS.lua
Sound/UserSound.lua
Sound/SoundOutput.lua