mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
Working Salvage (ME) zones, and working probability of both medevac and sling load spawn. Need to test dropping off salvage sling loads.
This commit is contained in:
parent
4a351a73dd
commit
bb59b12601
@ -1,220 +0,0 @@
|
||||
--[[
|
||||
EXAMPLE: How to Add MenuManager to Your Mission
|
||||
|
||||
This file shows the proper load order and trigger setup
|
||||
for using the Unified F10 Menu System in your DCS mission.
|
||||
]]--
|
||||
|
||||
--[[
|
||||
===============================================================================
|
||||
STEP 1: MISSION EDITOR - TRIGGERS TAB
|
||||
===============================================================================
|
||||
|
||||
Create a new trigger:
|
||||
|
||||
Trigger Name: "Load Mission Scripts"
|
||||
Type: ONCE
|
||||
Event: MISSION START
|
||||
|
||||
CONDITIONS:
|
||||
- TIME MORE (1) [This ensures mission is fully initialized]
|
||||
|
||||
ACTIONS (in this exact order):
|
||||
1. DO SCRIPT FILE: Moose.lua
|
||||
2. DO SCRIPT FILE: Moose_MenuManager.lua
|
||||
3. DO SCRIPT FILE: CTLD.lua
|
||||
4. DO SCRIPT FILE: Moose_FAC2MarkRecceZone.lua
|
||||
5. DO SCRIPT FILE: Moose_Intel.lua
|
||||
6. DO SCRIPT FILE: Moose_CaptureZones.lua
|
||||
7. DO SCRIPT FILE: Moose_NavalGroup.lua
|
||||
8. DO SCRIPT FILE: Moose_TADC_Load2nd.lua
|
||||
9. DO SCRIPT FILE: Moose_TADC_SquadronConfigs_Load1st.lua
|
||||
10. DO SCRIPT FILE: OnBirthMessage.lua
|
||||
11. ... (any other scripts)
|
||||
|
||||
===============================================================================
|
||||
STEP 2: FILE PLACEMENT
|
||||
===============================================================================
|
||||
|
||||
Place all .lua files in your mission folder:
|
||||
C:\Users\[YourName]\Saved Games\DCS\Missions\[MissionName].miz\
|
||||
|
||||
Or use the mission editor:
|
||||
1. Right-click mission in editor
|
||||
2. "Edit Mission"
|
||||
3. Click "Load/Unload lua scripts"
|
||||
4. Add files in order shown above
|
||||
|
||||
===============================================================================
|
||||
STEP 3: VERIFY LOAD ORDER
|
||||
===============================================================================
|
||||
|
||||
After mission loads, press F10 and verify:
|
||||
- F1: Mission Options (with submenus)
|
||||
- F2: CTLD
|
||||
- F3: AFAC Control
|
||||
|
||||
If order is wrong, check your trigger actions order.
|
||||
|
||||
===============================================================================
|
||||
STEP 4: CONFIGURATION (OPTIONAL)
|
||||
===============================================================================
|
||||
|
||||
Edit Moose_MenuManager.lua to customize:
|
||||
]]--
|
||||
|
||||
MenuManager.Config = {
|
||||
EnableMissionOptionsMenu = true, -- Set to false to disable parent menu
|
||||
MissionOptionsMenuName = "Mission Options", -- Change to "Utilities" or whatever
|
||||
Debug = false -- Set to true for debug logging
|
||||
}
|
||||
|
||||
--[[
|
||||
===============================================================================
|
||||
STEP 5: TESTING
|
||||
===============================================================================
|
||||
|
||||
1. Save mission
|
||||
2. Load mission in DCS
|
||||
3. Spawn as pilot
|
||||
4. Press F10
|
||||
5. Check menu structure matches expected layout
|
||||
|
||||
Expected result:
|
||||
F10 → Other Radio Items
|
||||
├─ F1: Mission Options
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ ├─ CVN Command
|
||||
│ └─ TADC Utilities
|
||||
├─ F2: CTLD
|
||||
└─ F3: AFAC Control
|
||||
|
||||
===============================================================================
|
||||
TROUBLESHOOTING
|
||||
===============================================================================
|
||||
|
||||
Problem: Menus in wrong order
|
||||
Solution: Check trigger actions are in correct order
|
||||
|
||||
Problem: "Mission Options" missing
|
||||
Solution: Verify Moose_MenuManager.lua loaded before other scripts
|
||||
|
||||
Problem: CTLD not at F2
|
||||
Solution: Ensure CTLD.lua loads right after Moose_MenuManager.lua
|
||||
|
||||
Problem: Script errors
|
||||
Solution: Check dcs.log file at:
|
||||
C:\Users\[YourName]\Saved Games\DCS\Logs\dcs.log
|
||||
|
||||
Enable debug mode in MenuManager for detailed logging:
|
||||
MenuManager.Config.Debug = true
|
||||
|
||||
===============================================================================
|
||||
ADVANCED: MULTIPLE COALITION MENUS
|
||||
===============================================================================
|
||||
|
||||
If your mission has both RED and BLUE players:
|
||||
|
||||
The MenuManager automatically creates "Mission Options" for both:
|
||||
- BLUE players see: F10 → F1: Mission Options (BLUE)
|
||||
- RED players see: F10 → F1: Mission Options (RED)
|
||||
|
||||
Each coalition's scripts only appear in their respective menu.
|
||||
|
||||
===============================================================================
|
||||
ADVANCED: DISABLING INDIVIDUAL MENUS
|
||||
===============================================================================
|
||||
|
||||
To hide a specific script's F10 menu without removing the script:
|
||||
|
||||
In Moose_Intel.lua:
|
||||
local EnableF10Menu = false -- Disables Intel menu
|
||||
|
||||
In Moose_CaptureZones.lua:
|
||||
-- Comment out the SetupZoneStatusCommands() call
|
||||
|
||||
This is useful for:
|
||||
- Training missions (hide complexity)
|
||||
- Specific mission types (no CVN = no CVN menu)
|
||||
- Server performance (reduce menu overhead)
|
||||
|
||||
===============================================================================
|
||||
EXAMPLE: ADDING YOUR OWN SCRIPT
|
||||
===============================================================================
|
||||
|
||||
If you create a new script "MyCustomScript.lua":
|
||||
|
||||
1. Add to trigger after Moose_MenuManager.lua
|
||||
2. In your script, use this pattern:
|
||||
]]--
|
||||
|
||||
-- MyCustomScript.lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
-- Will be under "Mission Options"
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Custom Feature")
|
||||
else
|
||||
-- Fallback if MenuManager not loaded
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Custom Feature")
|
||||
end
|
||||
|
||||
-- Add your commands
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something Cool", MyMenu, function()
|
||||
MESSAGE:New("Cool thing happened!", 10):ToBlue()
|
||||
end)
|
||||
|
||||
--[[
|
||||
===============================================================================
|
||||
EXAMPLE: MISSION-WIDE MENU (Both Coalitions)
|
||||
===============================================================================
|
||||
|
||||
For features available to all players:
|
||||
]]--
|
||||
|
||||
local UtilityMenu
|
||||
if MenuManager then
|
||||
UtilityMenu = MenuManager.CreateMissionMenu("Server Utilities")
|
||||
else
|
||||
UtilityMenu = MENU_MISSION:New("Server Utilities")
|
||||
end
|
||||
|
||||
MENU_MISSION_COMMAND:New("Show Server Time", UtilityMenu, function()
|
||||
local time = timer.getAbsTime()
|
||||
local hours = math.floor(time / 3600)
|
||||
local minutes = math.floor((time % 3600) / 60)
|
||||
MESSAGE:New(string.format("Server Time: %02d:%02d", hours, minutes), 5):ToAll()
|
||||
end)
|
||||
|
||||
--[[
|
||||
===============================================================================
|
||||
COMPLETE TRIGGER EXAMPLE (COPY/PASTE)
|
||||
===============================================================================
|
||||
|
||||
Trigger Name: Load Mission Scripts
|
||||
Type: ONCE
|
||||
Event: MISSION START
|
||||
Condition: TIME MORE (1)
|
||||
|
||||
Actions:
|
||||
DO SCRIPT FILE: Moose.lua
|
||||
DO SCRIPT FILE: Moose_MenuManager.lua
|
||||
DO SCRIPT FILE: CTLD.lua
|
||||
DO SCRIPT FILE: Moose_FAC2MarkRecceZone.lua
|
||||
DO SCRIPT FILE: Moose_Intel.lua
|
||||
DO SCRIPT FILE: Moose_CaptureZones.lua
|
||||
DO SCRIPT FILE: Moose_NavalGroup.lua
|
||||
DO SCRIPT FILE: Moose_TADC_Load2nd.lua
|
||||
|
||||
===============================================================================
|
||||
NOTES
|
||||
===============================================================================
|
||||
|
||||
- MenuManager is backward compatible: scripts work with or without it
|
||||
- CTLD and FAC use group menus (not coalition), so they stay at root level
|
||||
- Load order determines F-key positions
|
||||
- Mission Options will be F1 because it loads after CTLD (F2) and FAC (F3)
|
||||
- All other scripts nest under Mission Options automatically
|
||||
|
||||
===============================================================================
|
||||
]]--
|
||||
@ -1,91 +0,0 @@
|
||||
# F10 Menu System - Quick Reference
|
||||
|
||||
## Menu Structure
|
||||
```
|
||||
F10 → Mission Options (Blue players)
|
||||
├─ INTEL HQ
|
||||
├─ Zone Control
|
||||
└─ CVN Command
|
||||
|
||||
F10 → Mission Options (Red players)
|
||||
├─ INTEL HQ
|
||||
└─ (Red items)
|
||||
|
||||
F10 → TADC Utilities (all players)
|
||||
|
||||
F10 → CTLD (per-player, like CTLD always was)
|
||||
|
||||
F10 → AFAC Control (per-player, like FAC always was)
|
||||
|
||||
F10 → Welcome Messages (per-player)
|
||||
```
|
||||
|
||||
**Note**: Group menus (CTLD, FAC, Welcome) cannot be nested under coalition menus due to DCS limitations.
|
||||
|
||||
## Load Order (CRITICAL!)
|
||||
```
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← Must be FIRST
|
||||
3. CTLD.lua ← Group menu (any order)
|
||||
4. Moose_FAC2MarkRecceZone.lua ← Group menu (any order)
|
||||
5. OnBirthMessage.lua ← Group menu (any order)
|
||||
6. Moose_Intel.lua ← Under Mission Options
|
||||
7. Moose_CaptureZones.lua ← Under Mission Options
|
||||
8. Moose_NavalGroup.lua ← Under Mission Options
|
||||
9. Moose_TADC_Load2nd.lua ← Mission menu (root level)
|
||||
```
|
||||
|
||||
## Script Integration Pattern
|
||||
|
||||
### For Coalition Menus:
|
||||
```lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Menu")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Menu")
|
||||
end
|
||||
```
|
||||
|
||||
### For Mission Menus:
|
||||
```lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateMissionMenu("My Menu")
|
||||
else
|
||||
MyMenu = MENU_MISSION:New("My Menu")
|
||||
end
|
||||
```
|
||||
|
||||
## Configuration (in Moose_MenuManager.lua)
|
||||
```lua
|
||||
EnableMissionOptionsMenu = true -- false to disable
|
||||
MissionOptionsMenuName = "Mission Options" -- change name
|
||||
Debug = false -- true for logging
|
||||
```
|
||||
|
||||
## Disable Individual Script Menus
|
||||
```lua
|
||||
-- In each script (e.g., Moose_Intel.lua)
|
||||
local EnableF10Menu = false
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| Duplicate "Mission Options" | Fixed in v1.1 - only coalition menus now |
|
||||
| Empty menu | Check that scripts are loaded |
|
||||
| Group menus not under Mission Options | That's correct - DCS limitation |
|
||||
| TADC at root level | Correct - it's a mission menu (all players) |
|
||||
|
||||
## Files Modified
|
||||
- ✅ Moose_Intel.lua
|
||||
- ✅ Moose_CaptureZones.lua
|
||||
- ✅ Moose_NavalGroup.lua
|
||||
- ✅ Moose_TADC_Load2nd.lua
|
||||
- ✅ OnBirthMessage.lua (v1.1)
|
||||
|
||||
## New Files
|
||||
- ✅ Moose_MenuManager.lua (Core system v1.1)
|
||||
- ✅ F10_MENU_SYSTEM_GUIDE.md (Full documentation)
|
||||
- ✅ MENUMANAGER_UPDATE_NOTES.md (v1.1 changes)
|
||||
@ -1,262 +0,0 @@
|
||||
# Unified F10 Menu System Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The Unified F10 Menu Manager provides a consistent and organized F10 radio menu structure across all mission scripts. It ensures that the most frequently used menus (CTLD and FAC) maintain consistent positions while organizing all other mission options under a single parent menu.
|
||||
|
||||
## Menu Structure
|
||||
|
||||
```
|
||||
F10 - Other Radio Items
|
||||
├─ F1 - Mission Options <-- All other scripts go here
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ ├─ CVN Command
|
||||
│ ├─ TADC Utilities
|
||||
│ └─ (any other scripts)
|
||||
│
|
||||
├─ F2 - CTLD <-- Reserved, always in position 2
|
||||
│ ├─ Check Cargo
|
||||
│ ├─ Troop Transport
|
||||
│ ├─ Vehicle / FOB Transport
|
||||
│ └─ ...
|
||||
│
|
||||
└─ F3 - AFAC Control <-- Reserved, always in position 3
|
||||
├─ Targeting Mode
|
||||
├─ Laser Codes
|
||||
├─ Marker Settings
|
||||
└─ ...
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Consistent Positioning**: CTLD and FAC are always F10-F2 and F10-F3
|
||||
2. **Reduced Clutter**: All other menus are grouped under "Mission Options"
|
||||
3. **Easy Navigation**: Players know where to find commonly used functions
|
||||
4. **Scalable**: Easy to add new scripts without menu reorganization
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Load Order in Mission Editor
|
||||
|
||||
The scripts must be loaded in this specific order in your DCS mission:
|
||||
|
||||
```
|
||||
1. Moose.lua (MOOSE Framework)
|
||||
2. Moose_MenuManager.lua (Menu Manager - LOAD FIRST!)
|
||||
3. CTLD.lua (Will be F10-F2)
|
||||
4. Moose_FAC2MarkRecceZone.lua (Will be F10-F3)
|
||||
5. Moose_Intel.lua (Will be under Mission Options)
|
||||
6. Moose_CaptureZones.lua (Will be under Mission Options)
|
||||
7. Moose_NavalGroup.lua (Will be under Mission Options)
|
||||
8. Moose_TADC_Load2nd.lua (Will be under Mission Options)
|
||||
9. ... any other scripts ...
|
||||
```
|
||||
|
||||
**CRITICAL**: `Moose_MenuManager.lua` must be loaded BEFORE any script that creates F10 menus (except CTLD and FAC which use their own system).
|
||||
|
||||
### 2. Script Triggers in DCS
|
||||
|
||||
In the DCS Mission Editor, create triggers for "MISSION START":
|
||||
|
||||
```
|
||||
MISSION START
|
||||
└─ DO SCRIPT FILE: Moose.lua
|
||||
└─ DO SCRIPT FILE: Moose_MenuManager.lua
|
||||
└─ DO SCRIPT FILE: CTLD.lua
|
||||
└─ DO SCRIPT FILE: Moose_FAC2MarkRecceZone.lua
|
||||
└─ DO SCRIPT FILE: Moose_Intel.lua
|
||||
└─ DO SCRIPT FILE: Moose_CaptureZones.lua
|
||||
└─ DO SCRIPT FILE: Moose_NavalGroup.lua
|
||||
└─ DO SCRIPT FILE: Moose_TADC_Load2nd.lua
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### MenuManager Configuration
|
||||
|
||||
Edit `Moose_MenuManager.lua` to customize behavior:
|
||||
|
||||
```lua
|
||||
MenuManager.Config = {
|
||||
EnableMissionOptionsMenu = true, -- Set to false to disable parent menu
|
||||
MissionOptionsMenuName = "Mission Options", -- Change parent menu name
|
||||
Debug = false -- Enable debug logging
|
||||
}
|
||||
```
|
||||
|
||||
### Individual Script Configuration
|
||||
|
||||
Each script has been updated to support the MenuManager. If you want to disable a specific script's F10 menu, edit that script:
|
||||
|
||||
**Example - Disable Intel Menu:**
|
||||
```lua
|
||||
-- In Moose_Intel.lua, line 10
|
||||
local EnableF10Menu = false -- Changed from true to false
|
||||
```
|
||||
|
||||
## For Script Developers
|
||||
|
||||
### Adding New Scripts to the System
|
||||
|
||||
If you're creating a new script that needs an F10 menu, use the MenuManager:
|
||||
|
||||
#### Coalition Menu Example
|
||||
```lua
|
||||
-- Old way (creates root menu)
|
||||
local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
|
||||
-- New way (creates under Mission Options)
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
-- Fallback if MenuManager not loaded
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
|
||||
-- Add commands to your menu
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something", MyMenu, MyFunction)
|
||||
```
|
||||
|
||||
#### Mission Menu Example
|
||||
```lua
|
||||
-- Old way
|
||||
local MyMenu = MENU_MISSION:New("My Script")
|
||||
|
||||
-- New way
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateMissionMenu("My Script")
|
||||
else
|
||||
MyMenu = MENU_MISSION:New("My Script")
|
||||
end
|
||||
```
|
||||
|
||||
#### Creating Submenus
|
||||
```lua
|
||||
-- Create a parent menu under Mission Options
|
||||
local ParentMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Parent")
|
||||
|
||||
-- Create a submenu under your parent
|
||||
local SubMenu = MENU_COALITION:New(coalition.side.BLUE, "Submenu", ParentMenu)
|
||||
```
|
||||
|
||||
## CTLD and FAC Positioning
|
||||
|
||||
### Why CTLD and FAC Don't Use MenuManager
|
||||
|
||||
CTLD and FAC create **per-group menus** using `missionCommands.addSubMenuForGroup()`, which means each player/group gets their own instance. These are fundamentally different from coalition/mission menus.
|
||||
|
||||
The key is **load order**:
|
||||
- By loading CTLD first (after MenuManager), it becomes F10-F2
|
||||
- By loading FAC second, it becomes F10-F3
|
||||
- Mission Options loads third, becoming F10-F1
|
||||
|
||||
This ensures consistent positioning without code modifications to CTLD/FAC.
|
||||
|
||||
### If You Need to Modify CTLD or FAC
|
||||
|
||||
If you control the CTLD or FAC script source and want to move them under Mission Options, you would need to:
|
||||
|
||||
1. Keep them as group menus (they need to be)
|
||||
2. Accept that group menus can't be nested under coalition menus in DCS
|
||||
3. Load them in the desired order for consistent F-key positioning
|
||||
|
||||
**Recommendation**: Keep CTLD and FAC as-is (F2 and F3) since they're used most frequently.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Menus Appear in Wrong Order
|
||||
- **Cause**: Scripts loaded in wrong order
|
||||
- **Fix**: Check your mission triggers and ensure MenuManager loads first
|
||||
|
||||
### "Mission Options" Not Appearing
|
||||
- **Cause**: `EnableMissionOptionsMenu = false` in config
|
||||
- **Fix**: Edit `Moose_MenuManager.lua` and set to `true`
|
||||
|
||||
### Script Menu Appears at Root Instead of Under Mission Options
|
||||
- **Cause**: Script doesn't use MenuManager, or MenuManager not loaded
|
||||
- **Fix**: Update the script to use MenuManager API
|
||||
|
||||
### CTLD or FAC Position Changes
|
||||
- **Cause**: Another script is loading before them
|
||||
- **Fix**: Adjust load order so CTLD and FAC load immediately after MenuManager
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging to troubleshoot menu creation:
|
||||
|
||||
```lua
|
||||
-- In Moose_MenuManager.lua
|
||||
MenuManager.Config = {
|
||||
Debug = true -- Changed from false
|
||||
}
|
||||
```
|
||||
|
||||
Check `dcs.log` for messages like:
|
||||
```
|
||||
MenuManager: Initialized parent menus
|
||||
MenuManager: Created coalition menu 'INTEL HQ' for BLUE
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Disabling the System at Runtime
|
||||
|
||||
You can disable/enable the parent menu system during mission execution:
|
||||
|
||||
```lua
|
||||
-- Disable (all new menus will be created at root)
|
||||
MenuManager.DisableParentMenus()
|
||||
|
||||
-- Re-enable
|
||||
MenuManager.EnableParentMenus()
|
||||
```
|
||||
|
||||
### Creating Direct Root Menus
|
||||
|
||||
If you want a specific menu at the root level instead of under Mission Options:
|
||||
|
||||
```lua
|
||||
-- Pass 'nil' as parent to force root creation
|
||||
local RootMenu = MENU_COALITION:New(coalition.side.BLUE, "Special Root Menu", nil)
|
||||
```
|
||||
|
||||
### Custom Parent Menus
|
||||
|
||||
Create your own parent menu and pass it to MenuManager:
|
||||
|
||||
```lua
|
||||
local MyParent = MENU_COALITION:New(coalition.side.BLUE, "Advanced Options")
|
||||
local SubMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Sub Option", MyParent)
|
||||
```
|
||||
|
||||
## Updates and Maintenance
|
||||
|
||||
### Version History
|
||||
- **v1.0** - Initial release with support for Intel, Zones, CVN, and TADC scripts
|
||||
|
||||
### Modified Scripts
|
||||
The following scripts have been updated to use MenuManager:
|
||||
- `Moose_Intel.lua` - INTEL HQ menu
|
||||
- `Moose_CaptureZones.lua` - Zone Control menu
|
||||
- `Moose_NavalGroup.lua` - CVN Command menu
|
||||
- `Moose_TADC_Load2nd.lua` - TADC Utilities menu
|
||||
|
||||
### Backward Compatibility
|
||||
All scripts retain backward compatibility. If `MenuManager` is not loaded, they will create root-level menus as before.
|
||||
|
||||
## Questions and Support
|
||||
|
||||
For issues or questions about the Unified F10 Menu System, check:
|
||||
1. Load order in mission editor
|
||||
2. Debug logs in `dcs.log`
|
||||
3. Configuration settings in each script
|
||||
4. This guide's troubleshooting section
|
||||
|
||||
---
|
||||
|
||||
**Author**: Created for Operation Polar Shield mission series
|
||||
**Last Updated**: November 9, 2025
|
||||
**Version**: 1.0
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,194 +0,0 @@
|
||||
# FIXES APPLIED - November 9, 2025
|
||||
|
||||
## Issues Fixed
|
||||
|
||||
### 1. ✅ Duplicate "Mission Options" Menu (One Empty)
|
||||
**Root Cause**: MenuManager was creating both MENU_COALITION and MENU_MISSION parent menus with the same name.
|
||||
|
||||
**Fix**: Removed MENU_MISSION parent menu creation. Only coalition-specific parent menus are created now.
|
||||
|
||||
**Files Changed**: `Moose_MenuManager.lua`
|
||||
|
||||
---
|
||||
|
||||
### 2. ✅ OnBirthMessage Menu Not Integrated
|
||||
**Root Cause**: OnBirthMessage uses group menus (like CTLD/FAC) which cannot be nested under coalition menus due to DCS API limitations.
|
||||
|
||||
**Fix**:
|
||||
- Added configuration option to enable/disable menu
|
||||
- Added documentation explaining group menu behavior
|
||||
- Updated load order guidance
|
||||
|
||||
**Files Changed**: `OnBirthMessage.lua`
|
||||
|
||||
---
|
||||
|
||||
## What You'll See Now
|
||||
|
||||
### Before Fix
|
||||
```
|
||||
F10
|
||||
├─ Mission Options (Blue) ← Has content
|
||||
├─ Mission Options (???) ← EMPTY - The bug!
|
||||
├─ INTEL HQ (separate)
|
||||
├─ Zone Control (separate)
|
||||
├─ TADC Utilities
|
||||
├─ CTLD
|
||||
├─ AFAC Control
|
||||
└─ Welcome Messages (not integrated)
|
||||
```
|
||||
|
||||
### After Fix
|
||||
```
|
||||
F10
|
||||
├─ Mission Options (Blue) ← Clean, organized
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ └─ CVN Command
|
||||
├─ TADC Utilities ← Mission menu (all players see it)
|
||||
├─ CTLD ← Group menu (can't nest)
|
||||
├─ AFAC Control ← Group menu (can't nest)
|
||||
└─ Welcome Messages ← Group menu (can't nest)
|
||||
```
|
||||
|
||||
**Key**: Only ONE "Mission Options" per coalition, and it has content!
|
||||
|
||||
---
|
||||
|
||||
## Understanding DCS Menu Types
|
||||
|
||||
### Why Some Menus Can't Be Nested
|
||||
|
||||
DCS has three different menu systems:
|
||||
|
||||
1. **MENU_COALITION** - Team menus (Blue or Red)
|
||||
- Can be nested under other coalition menus ✅
|
||||
- Example: Intel, Zone Control, CVN
|
||||
|
||||
2. **MENU_MISSION** - Global menus (everyone sees same)
|
||||
- Cannot be nested under coalition menus ❌
|
||||
- Example: TADC Utilities
|
||||
|
||||
3. **Group Menus** - Per-player menus (each player has own)
|
||||
- Cannot be nested under ANY parent menu ❌
|
||||
- Example: CTLD, FAC, Welcome Messages
|
||||
|
||||
**Why?** These are different DCS API systems that don't interoperate. It's a DCS limitation, not a bug in our code.
|
||||
|
||||
---
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Disable OnBirthMessage F10 Menu
|
||||
In `OnBirthMessage.lua` (line 5):
|
||||
```lua
|
||||
local EnableF10Menu = false -- Set to false to hide menu
|
||||
```
|
||||
|
||||
### Disable Entire MenuManager System
|
||||
In `Moose_MenuManager.lua`:
|
||||
```lua
|
||||
MenuManager.Config.EnableMissionOptionsMenu = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [x] Only ONE "Mission Options" appears (per coalition)
|
||||
- [x] "Mission Options" contains items (not empty)
|
||||
- [x] TADC at root level (correct - mission menu)
|
||||
- [x] CTLD at root level (correct - group menu)
|
||||
- [x] FAC at root level (correct - group menu)
|
||||
- [x] Welcome Messages at root level (correct - group menu)
|
||||
- [x] OnBirthMessage has config option
|
||||
- [x] Documentation updated
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Core System
|
||||
- `Moose_MenuManager.lua` - v1.1
|
||||
- Removed duplicate menu creation
|
||||
- Updated CreateMissionMenu function
|
||||
- Added better documentation
|
||||
|
||||
### Scripts
|
||||
- `OnBirthMessage.lua`
|
||||
- Added EnableF10Menu config
|
||||
- Added documentation about group menus
|
||||
- Improved error handling
|
||||
|
||||
### Documentation
|
||||
- `F10_MENU_QUICK_REF.md` - Updated menu structure
|
||||
- `MENUMANAGER_UPDATE_NOTES.md` - NEW - Detailed explanation
|
||||
- `FIXES_APPLIED.md` - NEW - This file
|
||||
|
||||
---
|
||||
|
||||
## Load Order (Updated)
|
||||
|
||||
```
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← Creates coalition parent menus
|
||||
3. CTLD.lua ← Group menu
|
||||
4. Moose_FAC2MarkRecceZone.lua ← Group menu
|
||||
5. OnBirthMessage.lua ← Group menu
|
||||
6. Moose_Intel.lua ← Under Mission Options
|
||||
7. Moose_CaptureZones.lua ← Under Mission Options
|
||||
8. Moose_NavalGroup.lua ← Under Mission Options
|
||||
9. Moose_TADC_Load2nd.lua ← Mission menu (root)
|
||||
```
|
||||
|
||||
**Note**: Order of group menus (3-5) doesn't matter. They'll all appear at root regardless.
|
||||
|
||||
---
|
||||
|
||||
## What Changed vs v1.0
|
||||
|
||||
### v1.1 Changes
|
||||
1. Removed MENU_MISSION parent menu (was creating duplicate)
|
||||
2. Updated CreateMissionMenu to create root-level menus
|
||||
3. Added OnBirthMessage integration
|
||||
4. Clarified documentation about menu types
|
||||
5. Updated all guides with correct information
|
||||
|
||||
### Backward Compatibility
|
||||
✅ All v1.0 scripts still work
|
||||
✅ No breaking changes
|
||||
✅ Optional configurations added
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**Problem**: Two "Mission Options" menus (one empty) + OnBirthMessage not integrated
|
||||
|
||||
**Solution**:
|
||||
1. Fixed MenuManager to only create coalition parent menus
|
||||
2. Updated OnBirthMessage with config option
|
||||
3. Clarified documentation about DCS menu type limitations
|
||||
|
||||
**Result**: Clean, organized F10 menu structure with proper understanding of what can and cannot be nested.
|
||||
|
||||
---
|
||||
|
||||
## Questions?
|
||||
|
||||
**Q: Why can't CTLD be under Mission Options?**
|
||||
A: CTLD uses group menus (per-player). DCS doesn't allow nesting group menus under coalition menus.
|
||||
|
||||
**Q: Why is TADC at root level?**
|
||||
A: TADC is a mission menu (visible to all players). Can't nest mission menus under coalition menus.
|
||||
|
||||
**Q: Can I hide the Welcome Messages menu?**
|
||||
A: Yes! Set `EnableF10Menu = false` in OnBirthMessage.lua
|
||||
|
||||
**Q: Will this break my existing missions?**
|
||||
A: No! All changes are backward compatible.
|
||||
|
||||
---
|
||||
|
||||
*Applied: November 9, 2025*
|
||||
*Version: MenuManager v1.1*
|
||||
@ -1,398 +0,0 @@
|
||||
# Unified F10 Menu System
|
||||
|
||||
**Version 1.0** | **Created**: November 9, 2025 | **For**: DCS Mission Development
|
||||
|
||||
---
|
||||
|
||||
## 🎯 What This Does
|
||||
|
||||
Creates a unified F10 menu system that ensures **CTLD** and **FAC** are always in the same position (F2 and F3), while organizing all other mission scripts under a clean "Mission Options" parent menu.
|
||||
|
||||
**Result**: F10 → F2 for CTLD, F10 → F3 for FAC. Every mission. Every time.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Quick Start
|
||||
|
||||
### 1. Copy Files to Mission
|
||||
Copy these files to your mission folder:
|
||||
- `Moose_MenuManager.lua` (required)
|
||||
- `Moose_Intel.lua` (updated)
|
||||
- `Moose_CaptureZones.lua` (updated)
|
||||
- `Moose_NavalGroup.lua` (updated)
|
||||
- `Moose_TADC_Load2nd.lua` (updated)
|
||||
|
||||
### 2. Set Load Order in Mission Editor
|
||||
In DCS Mission Editor, Triggers tab, create "MISSION START" trigger:
|
||||
|
||||
```
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← MUST BE FIRST!
|
||||
3. CTLD.lua ← Will be F2
|
||||
4. Moose_FAC2MarkRecceZone.lua ← Will be F3
|
||||
5. Moose_Intel.lua ← Under Mission Options
|
||||
6. Moose_CaptureZones.lua ← Under Mission Options
|
||||
7. Moose_NavalGroup.lua ← Under Mission Options
|
||||
8. Moose_TADC_Load2nd.lua ← Under Mission Options
|
||||
```
|
||||
|
||||
### 3. Test
|
||||
- Start mission
|
||||
- Spawn as pilot
|
||||
- Press F10
|
||||
- Verify: F1 = Mission Options, F2 = CTLD, F3 = FAC
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation Files
|
||||
|
||||
| File | Purpose | When to Use |
|
||||
|------|---------|-------------|
|
||||
| **F10_MENU_SYSTEM_GUIDE.md** | Complete documentation | Full understanding |
|
||||
| **F10_MENU_QUICK_REF.md** | Quick reference card | Fast lookup |
|
||||
| **MENUMANAGER_SUMMARY.md** | System overview | Understanding concept |
|
||||
| **MENUMANAGER_VISUAL_GUIDE.md** | Visual diagrams | Visual learners |
|
||||
| **MENUMANAGER_TEMPLATE.lua** | Code templates | Integrating scripts |
|
||||
| **EXAMPLE_MISSION_SETUP.lua** | Mission setup example | Setting up missions |
|
||||
| **README.md** | This file | Getting started |
|
||||
|
||||
### Reading Order
|
||||
1. Start here (README.md) ← You are here
|
||||
2. Read **MENUMANAGER_SUMMARY.md** (understand the concept)
|
||||
3. Read **MENUMANAGER_VISUAL_GUIDE.md** (see diagrams)
|
||||
4. Read **F10_MENU_SYSTEM_GUIDE.md** (complete details)
|
||||
5. Use **F10_MENU_QUICK_REF.md** (ongoing reference)
|
||||
|
||||
---
|
||||
|
||||
## 🎮 What Players See
|
||||
|
||||
### Before
|
||||
```
|
||||
F10 → F1: Zone Control
|
||||
→ F2: TADC Utilities
|
||||
→ F3: INTEL HQ
|
||||
→ F4: CVN Command
|
||||
→ F5: CTLD ← Where is it this time?
|
||||
→ F6: AFAC Control ← Always different
|
||||
```
|
||||
|
||||
### After
|
||||
```
|
||||
F10 → F1: Mission Options ← Clean organization
|
||||
├─ INTEL HQ
|
||||
├─ Zone Control
|
||||
├─ CVN Command
|
||||
└─ TADC Utilities
|
||||
→ F2: CTLD ← ALWAYS HERE!
|
||||
→ F3: AFAC Control ← ALWAYS HERE!
|
||||
```
|
||||
|
||||
**Player Experience**: Press F10 → F2 for CTLD. Every time. Muscle memory works!
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Disable Entire System
|
||||
In `Moose_MenuManager.lua`:
|
||||
```lua
|
||||
MenuManager.Config.EnableMissionOptionsMenu = false
|
||||
```
|
||||
|
||||
### Disable Individual Script Menu
|
||||
In any script (e.g., `Moose_Intel.lua`):
|
||||
```lua
|
||||
local EnableF10Menu = false
|
||||
```
|
||||
|
||||
### Change Parent Menu Name
|
||||
In `Moose_MenuManager.lua`:
|
||||
```lua
|
||||
MenuManager.Config.MissionOptionsMenuName = "Utilities"
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
In `Moose_MenuManager.lua`:
|
||||
```lua
|
||||
MenuManager.Config.Debug = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ For Script Developers
|
||||
|
||||
### Integrating New Scripts
|
||||
|
||||
**Old way** (creates root menu):
|
||||
```lua
|
||||
local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
```
|
||||
|
||||
**New way** (uses MenuManager):
|
||||
```lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
```
|
||||
|
||||
**That's it!** Your menu now appears under "Mission Options" and falls back gracefully if MenuManager isn't loaded.
|
||||
|
||||
See **MENUMANAGER_TEMPLATE.lua** for more examples.
|
||||
|
||||
---
|
||||
|
||||
## ✅ What's Included
|
||||
|
||||
### Core Files
|
||||
- [x] `Moose_MenuManager.lua` - Menu management system
|
||||
|
||||
### Updated Scripts
|
||||
- [x] `Moose_Intel.lua` - INTEL HQ menu
|
||||
- [x] `Moose_CaptureZones.lua` - Zone Control menu
|
||||
- [x] `Moose_NavalGroup.lua` - CVN Command menu
|
||||
- [x] `Moose_TADC_Load2nd.lua` - TADC Utilities menu
|
||||
|
||||
### Documentation
|
||||
- [x] Complete user guide
|
||||
- [x] Quick reference card
|
||||
- [x] System summary
|
||||
- [x] Visual diagrams
|
||||
- [x] Code templates
|
||||
- [x] Setup examples
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Concepts
|
||||
|
||||
### Why Load Order Matters
|
||||
DCS creates F10 menus in the order scripts are loaded:
|
||||
- Script loaded 1st → F10-F1
|
||||
- Script loaded 2nd → F10-F2
|
||||
- Script loaded 3rd → F10-F3
|
||||
|
||||
By loading CTLD and FAC in specific positions, we ensure they're always F2 and F3.
|
||||
|
||||
### Why CTLD/FAC Don't Use MenuManager
|
||||
CTLD and FAC create **per-group menus** (each player/group gets their own). These can't be nested under coalition menus. Solution: Use load order to position them at F2 and F3.
|
||||
|
||||
### Backward Compatibility
|
||||
All scripts work with or without MenuManager:
|
||||
- **With MenuManager**: Organized under "Mission Options"
|
||||
- **Without MenuManager**: Creates root menu (old behavior)
|
||||
|
||||
No errors, no breaking changes.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| Menus in wrong order | Check script load order in mission triggers |
|
||||
| No "Mission Options" | Ensure `Moose_MenuManager.lua` loads first |
|
||||
| CTLD not at F2 | Load CTLD right after MenuManager |
|
||||
| FAC not at F3 | Load FAC right after CTLD |
|
||||
| Script errors | Enable debug mode, check dcs.log |
|
||||
|
||||
**Debug logs location**: `C:\Users\[You]\Saved Games\DCS\Logs\dcs.log`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Benefits
|
||||
|
||||
### For Players
|
||||
- ✅ CTLD always F2 (muscle memory)
|
||||
- ✅ FAC always F3 (consistent)
|
||||
- ✅ Clean, organized menus
|
||||
- ✅ Faster navigation (1 second vs 15 seconds)
|
||||
|
||||
### For Mission Makers
|
||||
- ✅ Professional appearance
|
||||
- ✅ Easy to add/remove scripts
|
||||
- ✅ Configurable per mission
|
||||
- ✅ Better player feedback
|
||||
|
||||
### For Developers
|
||||
- ✅ 3-line integration
|
||||
- ✅ Backward compatible
|
||||
- ✅ Well documented
|
||||
- ✅ Flexible configuration
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- **Consistent Positioning**: CTLD and FAC always in same position
|
||||
- **Clean Organization**: One parent menu instead of many root menus
|
||||
- **Easy Integration**: Minimal code changes to existing scripts
|
||||
- **Backward Compatible**: Works with or without MenuManager
|
||||
- **Configurable**: Enable/disable globally or per-script
|
||||
- **Scalable**: Add unlimited scripts without reorganization
|
||||
- **Well Documented**: Complete guides and examples
|
||||
|
||||
---
|
||||
|
||||
## 📖 Examples
|
||||
|
||||
### Example 1: Training Mission (Hide Everything Except CTLD)
|
||||
```lua
|
||||
// In Moose_MenuManager.lua
|
||||
MenuManager.Config.EnableMissionOptionsMenu = false
|
||||
|
||||
// In each other script
|
||||
local EnableF10Menu = false
|
||||
|
||||
Result: Only CTLD appears (F10 → F2)
|
||||
```
|
||||
|
||||
### Example 2: Custom Parent Menu Name
|
||||
```lua
|
||||
// In Moose_MenuManager.lua
|
||||
MenuManager.Config.MissionOptionsMenuName = "Squadron Utilities"
|
||||
|
||||
Result: F10 → F1 → Squadron Utilities
|
||||
```
|
||||
|
||||
### Example 3: Add Your Own Script
|
||||
```lua
|
||||
// In MyScript.lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Feature")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Feature")
|
||||
end
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Thing", MyMenu, DoThing)
|
||||
|
||||
Result: F10 → F1 → Mission Options → My Feature
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Technical Details
|
||||
|
||||
### Menu Types
|
||||
- **MENU_COALITION**: Visible to one coalition (Blue or Red)
|
||||
- **MENU_MISSION**: Visible to all players
|
||||
- **missionCommands (Group)**: Per-group menus (CTLD/FAC use this)
|
||||
|
||||
MenuManager handles the first two. Group menus remain at root level.
|
||||
|
||||
### Architecture
|
||||
```
|
||||
MenuManager (loads first)
|
||||
↓
|
||||
Creates "Mission Options" parent menu
|
||||
↓
|
||||
Other scripts register under it
|
||||
↓
|
||||
Result: F1 = Mission Options, F2 = CTLD, F3 = FAC
|
||||
```
|
||||
|
||||
### Files Modified
|
||||
Only menu creation code changed. All other functionality unchanged.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Success Criteria
|
||||
|
||||
- [x] CTLD always at F2
|
||||
- [x] FAC always at F3
|
||||
- [x] Other menus under F1
|
||||
- [x] Backward compatible
|
||||
- [x] Easy to integrate
|
||||
- [x] Well documented
|
||||
- [x] Tested and working
|
||||
|
||||
**Status**: All criteria met! ✅
|
||||
|
||||
---
|
||||
|
||||
## 📝 Version History
|
||||
|
||||
**v1.0** (November 9, 2025)
|
||||
- Initial release
|
||||
- Support for coalition and mission menus
|
||||
- Integration with Intel, Zones, CVN, TADC scripts
|
||||
- Complete documentation suite
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
1. **Always load MenuManager first** (after Moose.lua)
|
||||
2. **Load CTLD second** to ensure F2 position
|
||||
3. **Load FAC third** to ensure F3 position
|
||||
4. **Test load order** before deploying mission
|
||||
5. **Use debug mode** when troubleshooting
|
||||
6. **Check dcs.log** for error messages
|
||||
|
||||
---
|
||||
|
||||
## 🙋 Support
|
||||
|
||||
**Need Help?**
|
||||
1. Read **F10_MENU_SYSTEM_GUIDE.md** (comprehensive guide)
|
||||
2. Check **F10_MENU_QUICK_REF.md** (quick answers)
|
||||
3. Review **MENUMANAGER_VISUAL_GUIDE.md** (visual explanations)
|
||||
4. Use **MENUMANAGER_TEMPLATE.lua** (code examples)
|
||||
5. Enable debug mode and check logs
|
||||
|
||||
**Common Issues?**
|
||||
- See Troubleshooting section above
|
||||
- Check load order in mission editor
|
||||
- Verify all files are in mission folder
|
||||
- Enable debug logging for details
|
||||
|
||||
---
|
||||
|
||||
## 🎖️ Credits
|
||||
|
||||
**Created for**: F-99th Fighter Squadron
|
||||
**Mission**: Operation Polar Shield
|
||||
**Date**: November 9, 2025
|
||||
|
||||
**Design Philosophy**:
|
||||
- Keep it simple
|
||||
- Make it consistent
|
||||
- Document everything
|
||||
- Maintain compatibility
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
Free to use, modify, and distribute for DCS missions.
|
||||
Credit appreciated but not required.
|
||||
|
||||
---
|
||||
|
||||
## 🚦 Getting Started Checklist
|
||||
|
||||
- [ ] Read this README
|
||||
- [ ] Review MENUMANAGER_SUMMARY.md
|
||||
- [ ] Copy Moose_MenuManager.lua to mission
|
||||
- [ ] Set up load order in mission editor
|
||||
- [ ] Test in DCS
|
||||
- [ ] Configure as needed
|
||||
- [ ] Deploy to server
|
||||
|
||||
**Estimated setup time**: 10-15 minutes
|
||||
**Result**: Professional, organized F10 menus!
|
||||
|
||||
---
|
||||
|
||||
**Questions?** Start with the documentation files listed above.
|
||||
**Want to integrate a new script?** See MENUMANAGER_TEMPLATE.lua.
|
||||
**Need visual examples?** Check MENUMANAGER_VISUAL_GUIDE.md.
|
||||
|
||||
**Ready to get started?** Follow the Quick Start section at the top!
|
||||
|
||||
---
|
||||
|
||||
*Making DCS missions more organized, one F10 menu at a time.* 🎯✈️
|
||||
@ -1,270 +0,0 @@
|
||||
# Unified F10 Menu System - Summary
|
||||
|
||||
## What Was Created
|
||||
|
||||
A complete F10 menu organization system that ensures CTLD and FAC remain in consistent positions (F2 and F3) while grouping all other mission scripts under a "Mission Options" parent menu at F1.
|
||||
|
||||
## Files Created
|
||||
|
||||
1. **Moose_MenuManager.lua** - Core menu management system
|
||||
2. **F10_MENU_SYSTEM_GUIDE.md** - Complete documentation
|
||||
3. **F10_MENU_QUICK_REF.md** - Quick reference card
|
||||
4. **EXAMPLE_MISSION_SETUP.lua** - Mission integration example
|
||||
5. **MENUMANAGER_TEMPLATE.lua** - Script integration templates
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **Moose_Intel.lua** - Updated to use MenuManager
|
||||
2. **Moose_CaptureZones.lua** - Updated to use MenuManager
|
||||
3. **Moose_NavalGroup.lua** - Updated to use MenuManager
|
||||
4. **Moose_TADC_Load2nd.lua** - Updated to use MenuManager
|
||||
|
||||
## How It Works
|
||||
|
||||
### The Problem
|
||||
- F10 menu items appear in load order
|
||||
- CTLD and FAC could be at any position
|
||||
- Menu becomes cluttered with many scripts
|
||||
- Players waste time navigating to frequently-used items
|
||||
|
||||
### The Solution
|
||||
1. Load MenuManager first to create "Mission Options" parent menu
|
||||
2. Load CTLD second → becomes F10-F2 (consistent)
|
||||
3. Load FAC third → becomes F10-F3 (consistent)
|
||||
4. All other scripts register under "Mission Options" → F10-F1
|
||||
|
||||
### Result
|
||||
```
|
||||
F10 - Other Radio Items
|
||||
├─ F1 - Mission Options ← All other menus here
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ ├─ CVN Command
|
||||
│ └─ TADC Utilities
|
||||
│
|
||||
├─ F2 - CTLD ← Always here (muscle memory!)
|
||||
│
|
||||
└─ F3 - AFAC Control ← Always here
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
✅ **Consistent Positioning**: CTLD and FAC always F2 and F3
|
||||
✅ **Reduced Clutter**: One parent menu instead of many root menus
|
||||
✅ **Backward Compatible**: Scripts work with or without MenuManager
|
||||
✅ **Easy Integration**: 3-line change to existing scripts
|
||||
✅ **Configurable**: Can disable entire system or individual menus
|
||||
✅ **Scalable**: Add unlimited scripts without reorganization
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Mission Editor Setup
|
||||
|
||||
Load scripts in this order:
|
||||
```
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← NEW - Must be first!
|
||||
3. CTLD.lua
|
||||
4. Moose_FAC2MarkRecceZone.lua
|
||||
5. Moose_Intel.lua
|
||||
6. Moose_CaptureZones.lua
|
||||
7. Moose_NavalGroup.lua
|
||||
8. Moose_TADC_Load2nd.lua
|
||||
9. ... other scripts ...
|
||||
```
|
||||
|
||||
### 2. Test in Mission
|
||||
|
||||
1. Start mission
|
||||
2. Spawn as pilot
|
||||
3. Press F10
|
||||
4. Verify menu structure
|
||||
|
||||
### 3. Configuration (Optional)
|
||||
|
||||
Edit `Moose_MenuManager.lua`:
|
||||
```lua
|
||||
MenuManager.Config = {
|
||||
EnableMissionOptionsMenu = true, -- false to disable
|
||||
MissionOptionsMenuName = "Mission Options",
|
||||
Debug = false -- true for logging
|
||||
}
|
||||
```
|
||||
|
||||
## Integration Pattern
|
||||
|
||||
To integrate any script with MenuManager:
|
||||
|
||||
**Before:**
|
||||
```lua
|
||||
local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
```
|
||||
|
||||
**After:**
|
||||
```lua
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
```
|
||||
|
||||
That's it! The script now works with MenuManager but falls back gracefully if it's not loaded.
|
||||
|
||||
## Why CTLD/FAC Don't Use MenuManager
|
||||
|
||||
CTLD and FAC create **per-group menus** using DCS's native `missionCommands.addSubMenuForGroup()`. These are fundamentally different from MOOSE's coalition/mission menus and can't be nested under a parent menu.
|
||||
|
||||
**Solution**: Load order ensures consistent positioning:
|
||||
- MenuManager loads first → creates "Mission Options"
|
||||
- CTLD loads second → creates group menus (become F2)
|
||||
- FAC loads third → creates group menus (become F3)
|
||||
- "Mission Options" appears at F1 because coalition menus load before group menus
|
||||
|
||||
This gives us the consistent F1/F2/F3 structure we want.
|
||||
|
||||
## Benefits for Mission Makers
|
||||
|
||||
1. **Less Menu Navigation**: Players go straight to F2 for CTLD, F3 for FAC
|
||||
2. **Cleaner Interface**: One parent menu instead of 5+ root menus
|
||||
3. **Easier Maintenance**: Add/remove scripts without menu reorganization
|
||||
4. **Professional Look**: Organized, predictable menu structure
|
||||
5. **Player Feedback**: "Finally, I can find CTLD quickly!"
|
||||
|
||||
## Benefits for Script Developers
|
||||
|
||||
1. **3-Line Integration**: Minimal code changes
|
||||
2. **Backward Compatible**: Works with or without MenuManager
|
||||
3. **No Breaking Changes**: Existing scripts continue to work
|
||||
4. **Flexible**: Can opt-in or opt-out per script
|
||||
5. **Well Documented**: Templates and examples provided
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Menu Types in MOOSE/DCS
|
||||
|
||||
1. **MENU_MISSION**: Visible to all players
|
||||
2. **MENU_COALITION**: Visible to one coalition
|
||||
3. **MENU_GROUP**: Visible to specific group (CTLD/FAC use this)
|
||||
|
||||
MenuManager handles MENU_MISSION and MENU_COALITION. Group menus remain independent.
|
||||
|
||||
### Load Order Matters
|
||||
|
||||
DCS creates menus in load order:
|
||||
1. First loaded script → F1
|
||||
2. Second loaded script → F2
|
||||
3. Third loaded script → F3
|
||||
etc.
|
||||
|
||||
By controlling load order, we control F-key positions.
|
||||
|
||||
### Fallback Behavior
|
||||
|
||||
If MenuManager is not loaded or disabled:
|
||||
- Scripts create root-level menus (old behavior)
|
||||
- Everything still works, just not organized
|
||||
- No errors or warnings
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Global Configuration (in Moose_MenuManager.lua)
|
||||
```lua
|
||||
EnableMissionOptionsMenu = true -- Disable entire system
|
||||
MissionOptionsMenuName = "..." -- Change parent menu name
|
||||
Debug = false -- Enable logging
|
||||
```
|
||||
|
||||
### Per-Script Configuration (in each script)
|
||||
```lua
|
||||
local EnableF10Menu = false -- Disable this script's menu
|
||||
```
|
||||
|
||||
### Runtime Configuration
|
||||
```lua
|
||||
MenuManager.DisableParentMenus() -- Turn off at runtime
|
||||
MenuManager.EnableParentMenus() -- Turn on at runtime
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Menus wrong order | Load order incorrect | Check mission triggers |
|
||||
| No "Mission Options" | MenuManager not loaded | Add to triggers first |
|
||||
| CTLD not F2 | CTLD loaded too late | Load right after MenuManager |
|
||||
| Script errors | MenuManager syntax | Check debug logs |
|
||||
|
||||
Enable debug mode to see what's happening:
|
||||
```lua
|
||||
MenuManager.Config.Debug = true
|
||||
```
|
||||
|
||||
Check logs at: `C:\Users\[You]\Saved Games\DCS\Logs\dcs.log`
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Possible additions for future versions:
|
||||
- Menu hiding/showing based on game state
|
||||
- Menu reorganization at runtime
|
||||
- Per-player menu customization
|
||||
- Menu usage analytics
|
||||
- Internationalization support
|
||||
|
||||
## Version History
|
||||
|
||||
**v1.0** (November 9, 2025)
|
||||
- Initial release
|
||||
- Support for MENU_COALITION and MENU_MISSION
|
||||
- Integration with Intel, Zones, CVN, TADC scripts
|
||||
- Complete documentation and templates
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues:
|
||||
1. Read **F10_MENU_SYSTEM_GUIDE.md** (comprehensive)
|
||||
2. Read **F10_MENU_QUICK_REF.md** (quick answers)
|
||||
3. Check **EXAMPLE_MISSION_SETUP.lua** (mission setup)
|
||||
4. Use **MENUMANAGER_TEMPLATE.lua** (script integration)
|
||||
5. Enable debug mode and check dcs.log
|
||||
|
||||
## Credits
|
||||
|
||||
Created for the F-99th Fighter Squadron's Operation Polar Shield mission series.
|
||||
|
||||
**Design Goals**:
|
||||
- Keep CTLD and FAC in consistent positions
|
||||
- Reduce menu clutter
|
||||
- Easy to integrate
|
||||
- Backward compatible
|
||||
- Well documented
|
||||
|
||||
**Result**: All goals achieved! 🎉
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Load Order
|
||||
1. Moose.lua
|
||||
2. **Moose_MenuManager.lua** ← First!
|
||||
3. CTLD.lua ← F2
|
||||
4. FAC.lua ← F3
|
||||
5. Other scripts ← Under F1
|
||||
|
||||
### Integration Pattern
|
||||
```lua
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Name")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "Name")
|
||||
end
|
||||
```
|
||||
|
||||
### Result
|
||||
- F1: Mission Options (all other scripts)
|
||||
- F2: CTLD (always)
|
||||
- F3: FAC (always)
|
||||
|
||||
Simple, effective, backward compatible! 👍
|
||||
@ -1,368 +0,0 @@
|
||||
--[[
|
||||
TEMPLATE: Integrating Scripts with MenuManager
|
||||
|
||||
Use this template when updating existing scripts or creating new ones
|
||||
to work with the Unified F10 Menu System.
|
||||
]]--
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 1: Coalition Menu (most common)
|
||||
--=============================================================================
|
||||
|
||||
-- Configuration (add at top of script)
|
||||
local EnableF10Menu = true -- Set to false to disable F10 menu
|
||||
|
||||
-- Your existing script code here...
|
||||
|
||||
-- At the point where you create your menu (usually near the end):
|
||||
if EnableF10Menu then
|
||||
local MyScriptMenu
|
||||
|
||||
-- Use MenuManager if available, otherwise fallback to standard
|
||||
if MenuManager then
|
||||
MyScriptMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script Name")
|
||||
else
|
||||
MyScriptMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script Name")
|
||||
end
|
||||
|
||||
-- Add your menu commands
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Command 1", MyScriptMenu, MyFunction1)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Command 2", MyScriptMenu, MyFunction2)
|
||||
|
||||
-- Add submenus if needed
|
||||
local SubMenu = MENU_COALITION:New(coalition.side.BLUE, "Advanced Options", MyScriptMenu)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Advanced Command", SubMenu, MyAdvancedFunction)
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 2: Mission Menu (available to all players)
|
||||
--=============================================================================
|
||||
|
||||
if EnableF10Menu then
|
||||
local MyScriptMenu
|
||||
|
||||
if MenuManager then
|
||||
MyScriptMenu = MenuManager.CreateMissionMenu("My Script Name")
|
||||
else
|
||||
MyScriptMenu = MENU_MISSION:New("My Script Name")
|
||||
end
|
||||
|
||||
MENU_MISSION_COMMAND:New("Command 1", MyScriptMenu, MyFunction1)
|
||||
MENU_MISSION_COMMAND:New("Command 2", MyScriptMenu, MyFunction2)
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 3: Dual Coalition Menu (separate for each side)
|
||||
--=============================================================================
|
||||
|
||||
if EnableF10Menu then
|
||||
-- Blue Coalition Menu
|
||||
local BlueMenu
|
||||
if MenuManager then
|
||||
BlueMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script Name")
|
||||
else
|
||||
BlueMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script Name")
|
||||
end
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Blue Command", BlueMenu, MyBlueFunction)
|
||||
|
||||
-- Red Coalition Menu
|
||||
local RedMenu
|
||||
if MenuManager then
|
||||
RedMenu = MenuManager.CreateCoalitionMenu(coalition.side.RED, "My Script Name")
|
||||
else
|
||||
RedMenu = MENU_COALITION:New(coalition.side.RED, "My Script Name")
|
||||
end
|
||||
MENU_COALITION_COMMAND:New(coalition.side.RED, "Red Command", RedMenu, MyRedFunction)
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 4: Complex Menu with Multiple Levels
|
||||
--=============================================================================
|
||||
|
||||
if EnableF10Menu then
|
||||
-- Create main menu
|
||||
local MainMenu
|
||||
if MenuManager then
|
||||
MainMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MainMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
|
||||
-- Create submenus (these don't use MenuManager, just standard MOOSE)
|
||||
local SettingsMenu = MENU_COALITION:New(coalition.side.BLUE, "Settings", MainMenu)
|
||||
local ActionsMenu = MENU_COALITION:New(coalition.side.BLUE, "Actions", MainMenu)
|
||||
|
||||
-- Add commands to submenus
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Enable Feature", SettingsMenu, EnableFeature)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Disable Feature", SettingsMenu, DisableFeature)
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Action 1", ActionsMenu, Action1)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Action 2", ActionsMenu, Action2)
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 5: Dynamic Menu (populated at runtime)
|
||||
--=============================================================================
|
||||
|
||||
local MainMenu = nil
|
||||
|
||||
function CreateDynamicMenu()
|
||||
if EnableF10Menu then
|
||||
-- Create main menu if it doesn't exist
|
||||
if not MainMenu then
|
||||
if MenuManager then
|
||||
MainMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Dynamic Menu")
|
||||
else
|
||||
MainMenu = MENU_COALITION:New(coalition.side.BLUE, "Dynamic Menu")
|
||||
end
|
||||
end
|
||||
|
||||
-- Clear and rebuild menu items
|
||||
-- Note: MOOSE doesn't have a built-in clear, so you may need to track menu items
|
||||
-- and remove them, or just add new items dynamically
|
||||
|
||||
-- Example: Add menu items based on game state
|
||||
for i = 1, #SomeGameStateArray do
|
||||
local item = SomeGameStateArray[i]
|
||||
MENU_COALITION_COMMAND:New(
|
||||
coalition.side.BLUE,
|
||||
"Option " .. i .. ": " .. item.name,
|
||||
MainMenu,
|
||||
function() HandleOption(i) end
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Call this whenever game state changes
|
||||
SCHEDULER:New(nil, CreateDynamicMenu, {}, 30, 30) -- Rebuild every 30 seconds
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 6: Conditional Menu Creation
|
||||
--=============================================================================
|
||||
|
||||
-- Only create menu if certain conditions are met
|
||||
if EnableF10Menu then
|
||||
-- Check if feature is enabled in mission
|
||||
if CVN_GROUP and CVN_GROUP:IsAlive() then
|
||||
local CVNMenu
|
||||
if MenuManager then
|
||||
CVNMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "CVN Command")
|
||||
else
|
||||
CVNMenu = MENU_COALITION:New(coalition.side.BLUE, "CVN Command")
|
||||
end
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Request CVN Status", CVNMenu, GetCVNStatus)
|
||||
end
|
||||
|
||||
-- Check if airbase is available
|
||||
if AIRBASE:FindByName("Kutaisi") then
|
||||
local AirbaseMenu
|
||||
if MenuManager then
|
||||
AirbaseMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Kutaisi ATC")
|
||||
else
|
||||
AirbaseMenu = MENU_COALITION:New(coalition.side.BLUE, "Kutaisi ATC")
|
||||
end
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Request Landing", AirbaseMenu, RequestLanding)
|
||||
end
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 7: Menu with Event Handlers
|
||||
--=============================================================================
|
||||
|
||||
if EnableF10Menu then
|
||||
local SettingsMenu
|
||||
if MenuManager then
|
||||
SettingsMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Settings")
|
||||
else
|
||||
SettingsMenu = MENU_COALITION:New(coalition.side.BLUE, "Settings")
|
||||
end
|
||||
|
||||
-- Toggle setting with feedback
|
||||
local FeatureEnabled = false
|
||||
|
||||
local function ToggleFeature()
|
||||
FeatureEnabled = not FeatureEnabled
|
||||
local status = FeatureEnabled and "ENABLED" or "DISABLED"
|
||||
MESSAGE:New("Feature is now " .. status, 5):ToBlue()
|
||||
|
||||
-- Update menu text (by recreating menu or showing status elsewhere)
|
||||
-- Note: MOOSE doesn't allow changing menu text dynamically
|
||||
end
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Toggle Feature", SettingsMenu, ToggleFeature)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Show Status", SettingsMenu, function()
|
||||
local status = FeatureEnabled and "ENABLED" or "DISABLED"
|
||||
MESSAGE:New("Feature Status: " .. status, 5):ToBlue()
|
||||
end)
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
-- PATTERN 8: Integrating Existing Script with Minimal Changes
|
||||
--=============================================================================
|
||||
|
||||
-- BEFORE (typical existing script):
|
||||
-- local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
-- MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Command", MyMenu, MyFunction)
|
||||
|
||||
-- AFTER (minimal change for MenuManager support):
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script") -- Keep original as fallback
|
||||
end
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Command", MyMenu, MyFunction)
|
||||
|
||||
-- That's it! Only 3 lines changed, and it's backward compatible.
|
||||
|
||||
--=============================================================================
|
||||
-- BEST PRACTICES
|
||||
--=============================================================================
|
||||
|
||||
--[[
|
||||
1. Always check if MenuManager exists before using it
|
||||
- Ensures backward compatibility
|
||||
- Script works even if MenuManager not loaded
|
||||
|
||||
2. Add EnableF10Menu config option
|
||||
- Allows mission makers to disable menus without editing code
|
||||
- Useful for training missions or specific scenarios
|
||||
|
||||
3. Use descriptive menu names
|
||||
- "INTEL HQ" is better than "Intel"
|
||||
- "CVN Command" is better than "CVN"
|
||||
|
||||
4. Group related functions in submenus
|
||||
- Keeps main menu clean
|
||||
- Easier to navigate for players
|
||||
|
||||
5. Provide feedback for actions
|
||||
- Use MESSAGE:New() to confirm actions
|
||||
- Let players know what happened
|
||||
|
||||
6. Consider coalition-specific menus
|
||||
- Some features should only be available to one side
|
||||
- Use MENU_COALITION instead of MENU_MISSION
|
||||
|
||||
7. Test without MenuManager
|
||||
- Ensure fallback works
|
||||
- Don't rely on MenuManager being present
|
||||
|
||||
8. Document your menu structure
|
||||
- Comment what each menu does
|
||||
- Makes maintenance easier
|
||||
|
||||
9. Clean up menus when no longer needed
|
||||
- Remove dynamic menus when feature is destroyed
|
||||
- Example: Remove CVN menu when CVN is sunk
|
||||
|
||||
10. Use consistent naming
|
||||
- All scripts should follow same naming convention
|
||||
- Makes F10 menu predictable for players
|
||||
]]--
|
||||
|
||||
--=============================================================================
|
||||
-- COMMON MISTAKES TO AVOID
|
||||
--=============================================================================
|
||||
|
||||
--[[
|
||||
MISTAKE 1: Not checking if MenuManager exists
|
||||
❌ local MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
✅ if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
|
||||
MISTAKE 2: Creating menu too early
|
||||
❌ Creating menu before MOOSE is fully initialized
|
||||
✅ Create menus after all required objects exist
|
||||
Use SCHEDULER:New() with delay if needed
|
||||
|
||||
MISTAKE 3: Wrong menu type
|
||||
❌ Using MENU_MISSION when coalition-specific menu needed
|
||||
✅ Use MENU_COALITION for per-coalition features
|
||||
|
||||
MISTAKE 4: Not wrapping in EnableF10Menu check
|
||||
❌ Always creating menu even when not wanted
|
||||
✅ if EnableF10Menu then ... end
|
||||
|
||||
MISTAKE 5: Creating too many root menus
|
||||
❌ Each script creates its own root menu
|
||||
✅ Use MenuManager to group under "Mission Options"
|
||||
]]--
|
||||
|
||||
--=============================================================================
|
||||
-- TESTING CHECKLIST
|
||||
--=============================================================================
|
||||
|
||||
--[[
|
||||
After integrating MenuManager:
|
||||
|
||||
□ Script loads without errors
|
||||
□ Menu appears in correct location (under Mission Options)
|
||||
□ All menu commands work
|
||||
□ Script works WITHOUT MenuManager (fallback)
|
||||
□ EnableF10Menu = false hides menu
|
||||
□ No duplicate menus created
|
||||
□ Menu names are clear and descriptive
|
||||
□ Coalition-specific menus only show to correct side
|
||||
□ dcs.log shows no errors
|
||||
□ Test in multiplayer (if applicable)
|
||||
]]--
|
||||
|
||||
--=============================================================================
|
||||
-- EXAMPLE: Complete Script Integration
|
||||
--=============================================================================
|
||||
|
||||
-- Here's a complete example showing how to integrate a typical script:
|
||||
|
||||
--[[
|
||||
-- Original Script: MyFeatureScript.lua
|
||||
|
||||
local function DoSomething()
|
||||
MESSAGE:New("Did something!", 5):ToBlue()
|
||||
end
|
||||
|
||||
local function DoSomethingElse()
|
||||
MESSAGE:New("Did something else!", 5):ToBlue()
|
||||
end
|
||||
|
||||
local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Feature")
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something", MyMenu, DoSomething)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something Else", MyMenu, DoSomethingElse)
|
||||
]]--
|
||||
|
||||
-- Updated Script: MyFeatureScript.lua (MenuManager Compatible)
|
||||
|
||||
-- Configuration
|
||||
local EnableF10Menu = true -- Set to false to disable F10 menu
|
||||
|
||||
-- Feature functions (unchanged)
|
||||
local function DoSomething()
|
||||
MESSAGE:New("Did something!", 5):ToBlue()
|
||||
end
|
||||
|
||||
local function DoSomethingElse()
|
||||
MESSAGE:New("Did something else!", 5):ToBlue()
|
||||
end
|
||||
|
||||
-- Menu creation (updated)
|
||||
if EnableF10Menu then
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Feature")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Feature")
|
||||
end
|
||||
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something", MyMenu, DoSomething)
|
||||
MENU_COALITION_COMMAND:New(coalition.side.BLUE, "Do Something Else", MyMenu, DoSomethingElse)
|
||||
end
|
||||
|
||||
-- That's it! Your script now works with MenuManager and remains backward compatible.
|
||||
|
||||
--=============================================================================
|
||||
@ -1,222 +0,0 @@
|
||||
# F10 Menu System - Update Notes
|
||||
|
||||
## Issues Fixed
|
||||
|
||||
### Issue 1: Duplicate "Mission Options" Menu
|
||||
**Problem**: Two "Mission Options" menus appeared, one was empty.
|
||||
|
||||
**Cause**: MenuManager was creating three parent menus:
|
||||
- MENU_COALITION for Blue (correct)
|
||||
- MENU_COALITION for Red (correct)
|
||||
- MENU_MISSION for all players (unnecessary - this created the empty duplicate)
|
||||
|
||||
**Fix**: Removed the MENU_MISSION parent menu creation. Scripts that need mission-wide menus (like TADC) now create them directly at root level, which is the correct behavior.
|
||||
|
||||
### Issue 2: OnBirthMessage Menu Not Integrated
|
||||
**Problem**: OnBirthMessage script created its own root-level menu without coordination with MenuManager.
|
||||
|
||||
**Cause**: OnBirthMessage uses `missionCommands.addSubMenuForGroup()` which creates per-group menus (like CTLD and FAC). These cannot be nested under coalition menus.
|
||||
|
||||
**Fix**:
|
||||
- Added configuration option to OnBirthMessage
|
||||
- Added documentation explaining why it must remain at root level
|
||||
- Updated load order guidance
|
||||
|
||||
---
|
||||
|
||||
## Understanding DCS Menu Types
|
||||
|
||||
### Three Types of F10 Menus
|
||||
|
||||
1. **MENU_COALITION** - Visible to one coalition only
|
||||
- Example: Blue Intel, Red Intel
|
||||
- Can be nested under other coalition menus
|
||||
- MenuManager creates "Mission Options" parent for these
|
||||
|
||||
2. **MENU_MISSION** - Visible to ALL players
|
||||
- Example: TADC Utilities
|
||||
- Cannot be nested under coalition-specific menus
|
||||
- Should be created at root level
|
||||
|
||||
3. **Group Menus** (missionCommands) - Visible per-group
|
||||
- Example: CTLD, FAC, Welcome Messages
|
||||
- Each player/group gets their own instance
|
||||
- **CANNOT be nested** under coalition or mission menus
|
||||
- Must remain at root level
|
||||
|
||||
---
|
||||
|
||||
## Corrected Menu Structure
|
||||
|
||||
```
|
||||
F10 - Other Radio Items
|
||||
├─ F1 - Mission Options (Blue) ← MENU_COALITION (Blue players only)
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ └─ CVN Command
|
||||
│
|
||||
├─ F1 - Mission Options (Red) ← MENU_COALITION (Red players only)
|
||||
│ ├─ INTEL HQ
|
||||
│ └─ (Red-specific items)
|
||||
│
|
||||
├─ F2 - TADC Utilities ← MENU_MISSION (all players)
|
||||
│
|
||||
├─ F3 - CTLD ← Group menu (per-player)
|
||||
│
|
||||
├─ F4 - AFAC Control ← Group menu (per-player)
|
||||
│
|
||||
└─ F5 - Welcome Messages ← Group menu (per-player)
|
||||
```
|
||||
|
||||
**Note**: The F-key numbers will vary based on load order. What matters is:
|
||||
- Coalition-specific menus go under "Mission Options"
|
||||
- Group menus (CTLD, FAC, Welcome) stay at root
|
||||
- Mission menus (visible to all) stay at root
|
||||
|
||||
---
|
||||
|
||||
## Updated Load Order
|
||||
|
||||
```
|
||||
Mission Editor Triggers:
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← Creates "Mission Options" for Blue/Red
|
||||
3. CTLD.lua ← Group menu (any position)
|
||||
4. Moose_FAC2MarkRecceZone.lua ← Group menu (any position)
|
||||
5. OnBirthMessage.lua ← Group menu (any position)
|
||||
6. Moose_Intel.lua ← Under Mission Options
|
||||
7. Moose_CaptureZones.lua ← Under Mission Options
|
||||
8. Moose_NavalGroup.lua ← Under Mission Options
|
||||
9. Moose_TADC_Load2nd.lua ← MENU_MISSION (root level)
|
||||
```
|
||||
|
||||
**Key Points**:
|
||||
- Load MenuManager first (always)
|
||||
- Group menu scripts (CTLD, FAC, Welcome) can be in any order
|
||||
- Coalition-specific scripts register under "Mission Options"
|
||||
- Mission-wide scripts create root-level menus
|
||||
|
||||
---
|
||||
|
||||
## Scripts by Menu Type
|
||||
|
||||
### Coalition Menus (Under "Mission Options")
|
||||
- ✅ Moose_Intel.lua
|
||||
- ✅ Moose_CaptureZones.lua
|
||||
- ✅ Moose_NavalGroup.lua
|
||||
|
||||
### Mission Menus (Root Level)
|
||||
- ✅ Moose_TADC_Load2nd.lua
|
||||
|
||||
### Group Menus (Root Level - Cannot Be Nested)
|
||||
- ⚠️ CTLD.lua
|
||||
- ⚠️ Moose_FAC2MarkRecceZone.lua
|
||||
- ⚠️ OnBirthMessage.lua
|
||||
|
||||
---
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
### OnBirthMessage.lua
|
||||
Added configuration option:
|
||||
```lua
|
||||
-- At top of file (line 5)
|
||||
local EnableF10Menu = true -- Set to false to disable F10 menu
|
||||
```
|
||||
|
||||
Set to `false` to hide the Welcome Messages F10 menu entirely while keeping the welcome messages active.
|
||||
|
||||
---
|
||||
|
||||
## Why Group Menus Can't Be Nested
|
||||
|
||||
**Technical Limitation**: DCS's `missionCommands.addSubMenuForGroup()` creates menus that are specific to each player's group. These exist in a different namespace than MOOSE's coalition/mission menus and cannot be nested under them.
|
||||
|
||||
**Analogy**: Think of it like this:
|
||||
- Coalition menus are like "team channels" (Blue team sees Blue menus)
|
||||
- Mission menus are like "global broadcast" (everyone sees same menu)
|
||||
- Group menus are like "private DM" (each player has their own)
|
||||
|
||||
You can't put a private DM inside a team channel - they're different systems.
|
||||
|
||||
---
|
||||
|
||||
## What This Means for Users
|
||||
|
||||
### Blue Players See:
|
||||
```
|
||||
F10
|
||||
├─ Mission Options ← Their Blue-specific utilities
|
||||
├─ TADC Utilities ← Everyone sees this
|
||||
├─ CTLD ← Their own CTLD instance
|
||||
├─ AFAC Control ← Their own FAC instance
|
||||
└─ Welcome Messages ← Their own settings
|
||||
```
|
||||
|
||||
### Red Players See:
|
||||
```
|
||||
F10
|
||||
├─ Mission Options ← Their Red-specific utilities
|
||||
├─ TADC Utilities ← Everyone sees this
|
||||
├─ CTLD ← Their own CTLD instance
|
||||
├─ AFAC Control ← Their own FAC instance
|
||||
└─ Welcome Messages ← Their own settings
|
||||
```
|
||||
|
||||
**Key Benefit**: Each coalition's "Mission Options" is clean and organized, containing only their relevant utilities.
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After applying these fixes:
|
||||
- [ ] Only ONE "Mission Options" appears (per coalition)
|
||||
- [ ] "Mission Options" is NOT empty
|
||||
- [ ] TADC Utilities appears at root (visible to all)
|
||||
- [ ] CTLD appears at root (per-player)
|
||||
- [ ] FAC appears at root (per-player)
|
||||
- [ ] Welcome Messages appears at root (per-player)
|
||||
- [ ] Blue players see Blue-specific items under Mission Options
|
||||
- [ ] Red players see Red-specific items under Mission Options
|
||||
- [ ] No duplicate or empty menus
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
|
||||
### c:\DCS_MissionDev\DCS_Kola\Operation_Polar_Shield\Moose_MenuManager.lua
|
||||
- Removed MENU_MISSION parent menu creation
|
||||
- Updated CreateMissionMenu() to create root-level menus
|
||||
- Added documentation about menu types
|
||||
|
||||
### c:\DCS_MissionDev\DCS_Kola\Operation_Polar_Shield\OnBirthMessage.lua
|
||||
- Added EnableF10Menu configuration option
|
||||
- Added documentation about group menu limitations
|
||||
- Improved error handling
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**What Changed**:
|
||||
1. ✅ Removed duplicate "Mission Options" menu
|
||||
2. ✅ Added config option to OnBirthMessage
|
||||
3. ✅ Updated documentation about menu types
|
||||
4. ✅ Clarified load order requirements
|
||||
|
||||
**What Stayed The Same**:
|
||||
- All functionality preserved
|
||||
- Menu organization still clean
|
||||
- Coalition-specific items still grouped
|
||||
- Backward compatible
|
||||
|
||||
**Key Takeaway**:
|
||||
- Coalition menus → Can be organized under "Mission Options"
|
||||
- Mission menus → Must stay at root (everyone sees them)
|
||||
- Group menus → Must stay at root (can't be nested)
|
||||
|
||||
This is a DCS limitation, not a bug!
|
||||
|
||||
---
|
||||
|
||||
*Updated: November 9, 2025*
|
||||
@ -1,366 +0,0 @@
|
||||
# F10 Menu System - Visual Guide
|
||||
|
||||
## Before MenuManager (Typical Mission)
|
||||
|
||||
```
|
||||
F10 - Other Radio Items
|
||||
├─ F1 - Zone Control ← Changes based on load order
|
||||
├─ F2 - TADC Utilities ← Inconsistent position
|
||||
├─ F3 - INTEL HQ ← Player has to search
|
||||
├─ F4 - CVN Command ← Different every mission
|
||||
├─ F5 - CTLD ← Where is it this time?
|
||||
└─ F6 - AFAC Control ← Never the same
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- CTLD position changes between missions
|
||||
- Too many root-level menus (cluttered)
|
||||
- Players waste time searching for CTLD/FAC
|
||||
- No organization or grouping
|
||||
|
||||
---
|
||||
|
||||
## After MenuManager (Organized)
|
||||
|
||||
```
|
||||
F10 - Other Radio Items
|
||||
├─ F1 - Mission Options ← All utility scripts here
|
||||
│ ├─ INTEL HQ
|
||||
│ ├─ Zone Control
|
||||
│ ├─ CVN Command
|
||||
│ └─ TADC Utilities
|
||||
│
|
||||
├─ F2 - CTLD ← ALWAYS HERE! Muscle memory works!
|
||||
│ ├─ Check Cargo
|
||||
│ ├─ Troop Transport
|
||||
│ │ ├─ Unload / Extract Troops
|
||||
│ │ └─ Load From Zone
|
||||
│ ├─ Vehicle / FOB Transport
|
||||
│ │ ├─ Unload Vehicles
|
||||
│ │ └─ Load / Extract Vehicles
|
||||
│ ├─ Vehicle / FOB Crates / Drone
|
||||
│ └─ CTLD Commands
|
||||
│
|
||||
└─ F3 - AFAC Control ← ALWAYS HERE! Predictable!
|
||||
├─ Targeting Mode
|
||||
│ ├─ Auto Mode ON
|
||||
│ ├─ Auto Mode OFF
|
||||
│ └─ Manual Targeting
|
||||
├─ Laser Codes
|
||||
├─ Marker Settings
|
||||
│ ├─ Smoke Color
|
||||
│ └─ Flare Color
|
||||
└─ AFAC Status
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- CTLD always F2 (press F10 → F2 every time)
|
||||
- FAC always F3 (press F10 → F3 every time)
|
||||
- Other menus organized under F1
|
||||
- Clean, predictable interface
|
||||
|
||||
---
|
||||
|
||||
## Load Order Visualization
|
||||
|
||||
```
|
||||
Mission Editor Triggers - Script Load Order:
|
||||
┌────────────────────────────────────────┐
|
||||
│ 1. Moose.lua │ ← MOOSE Framework
|
||||
├────────────────────────────────────────┤
|
||||
│ 2. Moose_MenuManager.lua │ ← Creates "Mission Options" at F1
|
||||
├────────────────────────────────────────┤
|
||||
│ 3. CTLD.lua │ ← Creates CTLD menu → becomes F2
|
||||
├────────────────────────────────────────┤
|
||||
│ 4. Moose_FAC2MarkRecceZone.lua │ ← Creates FAC menu → becomes F3
|
||||
├────────────────────────────────────────┤
|
||||
│ 5. Moose_Intel.lua │ ← Registers under Mission Options
|
||||
│ 6. Moose_CaptureZones.lua │ ← Registers under Mission Options
|
||||
│ 7. Moose_NavalGroup.lua │ ← Registers under Mission Options
|
||||
│ 8. Moose_TADC_Load2nd.lua │ ← Registers under Mission Options
|
||||
│ 9. ... other scripts ... │ ← All register under Mission Options
|
||||
└────────────────────────────────────────┘
|
||||
|
||||
Result: F1 = Mission Options, F2 = CTLD, F3 = FAC
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Menu Type Comparison
|
||||
|
||||
### Coalition Menu (MENU_COALITION)
|
||||
```
|
||||
BLUE Players See: RED Players See:
|
||||
F10 F10
|
||||
├─ Mission Options ├─ Mission Options
|
||||
│ ├─ INTEL HQ (Blue) │ ├─ INTEL HQ (Red)
|
||||
│ └─ Zone Control (Blue) │ └─ (Red content)
|
||||
├─ CTLD ├─ CTLD
|
||||
└─ AFAC Control └─ AFAC Control
|
||||
```
|
||||
|
||||
### Mission Menu (MENU_MISSION)
|
||||
```
|
||||
ALL Players See Same:
|
||||
F10
|
||||
├─ Mission Options
|
||||
│ └─ TADC Utilities ← Everyone sees this
|
||||
├─ CTLD
|
||||
└─ AFAC Control
|
||||
```
|
||||
|
||||
### Group Menu (missionCommands - CTLD/FAC use this)
|
||||
```
|
||||
Each Group Sees Own:
|
||||
Group #1: Group #2:
|
||||
F10 F10
|
||||
├─ CTLD (Group #1) ├─ CTLD (Group #2)
|
||||
└─ AFAC (Group #1) └─ AFAC (Group #2)
|
||||
|
||||
Can't be nested under parent menus - that's why CTLD/FAC stay at root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Flowchart
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Your Script Wants to Create F10 Menu │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ MenuManager │
|
||||
│ Available? │
|
||||
└──┬───────┬───┘
|
||||
│ │
|
||||
Yes │ │ No
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────┐ ┌─────────────┐
|
||||
│ Register │ │ Create Root │
|
||||
│ Under │ │ Menu │
|
||||
│ Mission │ │ (Fallback) │
|
||||
│ Options │ │ │
|
||||
└──────────┘ └─────────────┘
|
||||
│ │
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ Menu Appears │
|
||||
│ in F10 │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Player Experience Comparison
|
||||
|
||||
### Without MenuManager
|
||||
```
|
||||
Player: "Where's CTLD?"
|
||||
→ Checks F1: Zone Control
|
||||
→ Checks F2: TADC
|
||||
→ Checks F3: Intel
|
||||
→ Checks F4: CVN
|
||||
→ Checks F5: CTLD ← FOUND IT!
|
||||
(Time wasted: 10-15 seconds)
|
||||
|
||||
Next Mission:
|
||||
Player: "Where's CTLD now?"
|
||||
→ Checks F1: Intel
|
||||
→ Checks F2: CVN
|
||||
→ Checks F3: Zone Control
|
||||
→ Checks F4: CTLD ← Position changed!
|
||||
(Frustration: High)
|
||||
```
|
||||
|
||||
### With MenuManager
|
||||
```
|
||||
Player: "Need CTLD"
|
||||
→ Press F10
|
||||
→ Press F2
|
||||
→ Found it!
|
||||
(Time: 1 second, every time)
|
||||
|
||||
Next Mission:
|
||||
Player: "Need CTLD"
|
||||
→ Press F10
|
||||
→ Press F2
|
||||
→ Found it! (same position)
|
||||
(Frustration: None, Efficiency: Max)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Example 1: Disable All Extra Menus (Training Mission)
|
||||
```lua
|
||||
-- In Moose_MenuManager.lua
|
||||
MenuManager.Config.EnableMissionOptionsMenu = false
|
||||
|
||||
-- Result: Only CTLD and FAC appear
|
||||
F10
|
||||
├─ CTLD
|
||||
└─ AFAC Control
|
||||
```
|
||||
|
||||
### Example 2: Disable Specific Script Menu
|
||||
```lua
|
||||
-- In Moose_Intel.lua
|
||||
local EnableF10Menu = false
|
||||
|
||||
-- Result: Intel menu hidden, others remain
|
||||
F10
|
||||
├─ Mission Options
|
||||
│ ├─ Zone Control
|
||||
│ ├─ CVN Command
|
||||
│ └─ TADC Utilities
|
||||
├─ CTLD
|
||||
└─ AFAC Control
|
||||
```
|
||||
|
||||
### Example 3: Custom Parent Menu Name
|
||||
```lua
|
||||
-- In Moose_MenuManager.lua
|
||||
MenuManager.Config.MissionOptionsMenuName = "Utilities"
|
||||
|
||||
-- Result: Different parent menu name
|
||||
F10
|
||||
├─ Utilities ← Changed from "Mission Options"
|
||||
│ ├─ INTEL HQ
|
||||
│ └─ ...
|
||||
├─ CTLD
|
||||
└─ AFAC Control
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ DCS Mission │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────────┐ │
|
||||
│ │ Moose.lua │ ← MOOSE Framework (loaded first) │
|
||||
│ └─────┬──────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼───────────────┐ │
|
||||
│ │ MenuManager │ ← Menu System (loaded 2nd) │
|
||||
│ │ - Creates F1 │ │
|
||||
│ │ - Provides API │ │
|
||||
│ └─────┬───────────────┘ │
|
||||
│ │ │
|
||||
│ ├─────────┬─────────┬─────────┬──────────┐ │
|
||||
│ │ │ │ │ │ │
|
||||
│ ┌─────▼───┐ ┌──▼────┐ ┌──▼────┐ ┌──▼────┐ ┌───▼──┐ │
|
||||
│ │ Intel │ │ Zones │ │ CVN │ │ TADC │ │ ... │ │
|
||||
│ │ Script │ │Script │ │Script │ │Script │ │ │ │
|
||||
│ └─────┬───┘ └──┬────┘ └──┬────┘ └──┬────┘ └───┬──┘ │
|
||||
│ │ │ │ │ │ │
|
||||
│ └────────┴─────────┴─────────┴──────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼──────┐ │
|
||||
│ │ Mission │ │
|
||||
│ │ Options │ ← F1 │
|
||||
│ │ (F10) │ │
|
||||
│ └────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────┐ │
|
||||
│ │ CTLD │ ← Loaded after MenuManager → F2 │
|
||||
│ └─────────┘ │
|
||||
│ │
|
||||
│ ┌─────────┐ │
|
||||
│ │ FAC │ ← Loaded after CTLD → F3 │
|
||||
│ └─────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
|
||||
Players press F10 and see:
|
||||
F1: Mission Options (all utility scripts)
|
||||
F2: CTLD (always here)
|
||||
F3: FAC (always here)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
Operation_Polar_Shield/
|
||||
├── Core System
|
||||
│ └── Moose_MenuManager.lua ← The menu manager
|
||||
│
|
||||
├── Scripts (Updated)
|
||||
│ ├── Moose_Intel.lua ← Uses MenuManager
|
||||
│ ├── Moose_CaptureZones.lua ← Uses MenuManager
|
||||
│ ├── Moose_NavalGroup.lua ← Uses MenuManager
|
||||
│ └── Moose_TADC_Load2nd.lua ← Uses MenuManager
|
||||
│
|
||||
├── Scripts (Unchanged)
|
||||
│ ├── CTLD.lua ← Creates own menu (F2)
|
||||
│ └── Moose_FAC2MarkRecceZone.lua ← Creates own menu (F3)
|
||||
│
|
||||
└── Documentation
|
||||
├── F10_MENU_SYSTEM_GUIDE.md ← Full guide
|
||||
├── F10_MENU_QUICK_REF.md ← Quick reference
|
||||
├── MENUMANAGER_SUMMARY.md ← Summary
|
||||
├── MENUMANAGER_TEMPLATE.lua ← Code templates
|
||||
├── EXAMPLE_MISSION_SETUP.lua ← Setup example
|
||||
└── MENUMANAGER_VISUAL_GUIDE.md ← This file!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Before
|
||||
- ❌ CTLD position: Variable (F4-F8)
|
||||
- ❌ FAC position: Variable (F5-F9)
|
||||
- ❌ Root menus: 6-8 items (cluttered)
|
||||
- ❌ Player navigation time: 10-15 seconds
|
||||
- ❌ Player satisfaction: Low (complaints)
|
||||
|
||||
### After
|
||||
- ✅ CTLD position: Always F2
|
||||
- ✅ FAC position: Always F3
|
||||
- ✅ Root menus: 3 items (clean)
|
||||
- ✅ Player navigation time: 1 second
|
||||
- ✅ Player satisfaction: High (positive feedback)
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ Press F10, then: │
|
||||
├──────────────────────────────────────┤
|
||||
│ F1 → Mission Options │
|
||||
│ All utility/support features │
|
||||
│ │
|
||||
│ F2 → CTLD │
|
||||
│ Cargo/troop transport │
|
||||
│ │
|
||||
│ F3 → AFAC Control │
|
||||
│ Forward air controller │
|
||||
└──────────────────────────────────────┘
|
||||
|
||||
Every mission. Every time. Consistent!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The key to this system working is **load order**!
|
||||
|
||||
1. Load MenuManager first
|
||||
2. Load CTLD second (→ F2)
|
||||
3. Load FAC third (→ F3)
|
||||
4. Load everything else (→ under F1)
|
||||
|
||||
Simple, effective, professional! 🎯
|
||||
@ -43,7 +43,8 @@ local blueCfg = {
|
||||
--DropZones = { { name = 'BRAVO', flag = 9002, activeWhen = 0 } },
|
||||
--FOBZones = { { name = 'CHARLIE', flag = 9003, activeWhen = 0 } },
|
||||
MASHZones = { { name = 'A1', freq = '256.0 AM', radius = 500, flag = 9010, activeWhen = 0 } },
|
||||
},
|
||||
SalvageDropZones= { { name = 'S1', radius = 500, flag = 9011, activeWhen = 0 } },
|
||||
}, -- closes Zones table
|
||||
BuildRequiresGroundCrates = true,
|
||||
}
|
||||
env.info('[DEBUG] blueCfg.Zones.MASHZones count: ' .. tostring(blueCfg.Zones and blueCfg.Zones.MASHZones and #blueCfg.Zones.MASHZones or 'NIL'))
|
||||
|
||||
@ -1,971 +0,0 @@
|
||||
.--[[
|
||||
Simple AFAC System v1.0
|
||||
========================
|
||||
|
||||
A lightweight, standalone Forward Air Controller system for DCS World.
|
||||
No external dependencies required.
|
||||
|
||||
Features:
|
||||
- Automatic AFAC aircraft detection
|
||||
- Target scanning with line-of-sight verification
|
||||
- Laser designation with customizable codes
|
||||
- Visual marking (smoke/flares)
|
||||
- F10 map markers with detailed target information
|
||||
- Auto and manual targeting modes
|
||||
- Clean F10 menu integration
|
||||
|
||||
Author: Based on original FAC script, streamlined for simplicity
|
||||
]]
|
||||
|
||||
-- =====================================================
|
||||
-- CONFIGURATION
|
||||
-- =====================================================
|
||||
|
||||
AFAC = {}
|
||||
|
||||
AFAC.Config = {
|
||||
-- Detection ranges
|
||||
maxRange = 18520, -- Maximum AFAC detection range in meters
|
||||
|
||||
-- Aircraft types that auto-qualify as AFAC (perfect for dynamic spawning)
|
||||
afacAircraft = {
|
||||
-- Helicopters
|
||||
"SA342L",
|
||||
"SA342Mistral",
|
||||
"SA342Minigun",
|
||||
"UH-60L",
|
||||
"UH-1H",
|
||||
"OH-58D",
|
||||
"AH-64D_BLK_II",
|
||||
"Mi-8MT",
|
||||
"Mi-24P",
|
||||
"Ka-50",
|
||||
"Ka-50_3",
|
||||
"AH-1W",
|
||||
|
||||
-- Light Aircraft
|
||||
"TF-51D",
|
||||
"P-51D-30-NA",
|
||||
"Bf-109K-4",
|
||||
"FW-190D9",
|
||||
"I-16",
|
||||
"C-101EB",
|
||||
"C-101CC",
|
||||
"L-39ZA",
|
||||
"L-39C",
|
||||
|
||||
-- Jets (for high-speed FAC)
|
||||
--"A-10C",
|
||||
--"A-10C_2",
|
||||
--"AV8BNA",
|
||||
--"F-16C_50",
|
||||
--"FA-18C_hornet",
|
||||
--"F-14",
|
||||
--"A-4E-C"
|
||||
},
|
||||
|
||||
-- Available laser codes
|
||||
laserCodes = {'1688', '1677', '1666', '1113', '1115', '1111'},
|
||||
|
||||
-- Smoke/flare colors
|
||||
smokeColors = {
|
||||
GREEN = 0,
|
||||
RED = 1,
|
||||
WHITE = 2,
|
||||
ORANGE = 3,
|
||||
BLUE = 4
|
||||
},
|
||||
|
||||
-- Default marker settings
|
||||
defaultSmokeColor = {
|
||||
[1] = 4, -- RED coalition uses BLUE smoke
|
||||
[2] = 3 -- BLUE coalition uses ORANGE smoke
|
||||
},
|
||||
|
||||
-- Marker duration (seconds)
|
||||
mapMarkerDuration = 120,
|
||||
smokeInterval = 300,
|
||||
|
||||
-- Target update intervals (throttled to reduce per-second scanning)
|
||||
autoUpdateInterval = 2.5,
|
||||
manualScanRange = 18520,
|
||||
|
||||
-- Debug mode
|
||||
debug = true
|
||||
}
|
||||
|
||||
-- =====================================================
|
||||
-- CORE DATA STRUCTURES
|
||||
-- =====================================================
|
||||
|
||||
AFAC.Data = {
|
||||
pilots = {}, -- Active AFAC pilots
|
||||
targets = {}, -- Current targets per pilot
|
||||
laserPoints = {}, -- Laser designations
|
||||
irPoints = {}, -- IR pointers
|
||||
smokeMarks = {}, -- Smoke marker tracking
|
||||
onStation = {}, -- On-station status
|
||||
laserCodes = {}, -- Assigned laser codes per pilot
|
||||
markerSettings = {}, -- Per-pilot marker preferences
|
||||
menuIds = {}, -- F10 menu tracking
|
||||
manualTargets = {}, -- Manual mode target lists
|
||||
nextMarkerId = 1000 -- Map marker ID counter
|
||||
}
|
||||
|
||||
-- =====================================================
|
||||
-- UTILITY FUNCTIONS
|
||||
-- =====================================================
|
||||
|
||||
-- Debug logging
|
||||
function AFAC.log(message)
|
||||
if AFAC.Config.debug then
|
||||
env.info("AFAC: " .. tostring(message))
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if table contains value
|
||||
function AFAC.contains(table, value)
|
||||
for i = 1, #table do
|
||||
if table[i] == value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Calculate distance between two points
|
||||
function AFAC.getDistance(point1, point2)
|
||||
local dx = point1.x - point2.x
|
||||
local dz = point1.z - point2.z
|
||||
return math.sqrt(dx * dx + dz * dz)
|
||||
end
|
||||
|
||||
-- Get unit heading in radians
|
||||
function AFAC.getHeading(unit)
|
||||
local unitPos = unit:getPosition()
|
||||
if unitPos then
|
||||
local heading = math.atan2(unitPos.x.z, unitPos.x.x)
|
||||
if heading < 0 then
|
||||
heading = heading + 2 * math.pi
|
||||
end
|
||||
return heading
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Convert coordinates to Lat/Long string
|
||||
function AFAC.coordToString(point)
|
||||
local lat, lon = coord.LOtoLL(point)
|
||||
local latDeg = math.floor(lat)
|
||||
local latMin = (lat - latDeg) * 60
|
||||
local lonDeg = math.floor(lon)
|
||||
local lonMin = (lon - lonDeg) * 60
|
||||
|
||||
local latDir = latDeg >= 0 and "N" or "S"
|
||||
local lonDir = lonDeg >= 0 and "E" or "W"
|
||||
|
||||
return string.format("%02d°%06.3f'%s %03d°%06.3f'%s",
|
||||
math.abs(latDeg), latMin, latDir,
|
||||
math.abs(lonDeg), lonMin, lonDir)
|
||||
end
|
||||
|
||||
-- Get MGRS coordinate string
|
||||
function AFAC.getMGRS(point)
|
||||
local lat, lon = coord.LOtoLL(point)
|
||||
-- Simplified MGRS - in real implementation you'd want full MGRS conversion
|
||||
return string.format("MGRS: %02d%s%05d%05d",
|
||||
math.floor(lat), "ABC"[math.random(1,3)],
|
||||
math.random(10000, 99999), math.random(10000, 99999))
|
||||
end
|
||||
|
||||
-- Get group ID from unit
|
||||
function AFAC.getGroupId(unit)
|
||||
local group = unit:getGroup()
|
||||
if group then
|
||||
return group:getID()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Notify coalition
|
||||
function AFAC.notifyCoalition(message, duration, coalition)
|
||||
trigger.action.outTextForCoalition(coalition, message, duration or 10)
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- AIRCRAFT DETECTION & MANAGEMENT
|
||||
-- =====================================================
|
||||
|
||||
-- Check if unit qualifies as AFAC (by aircraft type only)
|
||||
function AFAC.isAFAC(unit)
|
||||
if not unit then
|
||||
AFAC.log("isAFAC: unit is nil")
|
||||
return false
|
||||
end
|
||||
|
||||
local unitType = unit:getTypeName()
|
||||
AFAC.log("Checking unit type: " .. tostring(unitType))
|
||||
|
||||
-- Check aircraft type only - perfect for dynamic spawning
|
||||
local result = AFAC.contains(AFAC.Config.afacAircraft, unitType)
|
||||
AFAC.log("isAFAC result for " .. unitType .. ": " .. tostring(result))
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Add pilot to AFAC system
|
||||
function AFAC.addPilot(unit)
|
||||
local unitName = unit:getName()
|
||||
local groupId = AFAC.getGroupId(unit)
|
||||
|
||||
if not groupId then return end
|
||||
|
||||
-- Initialize pilot data
|
||||
AFAC.Data.pilots[unitName] = {
|
||||
name = unitName,
|
||||
unit = unit,
|
||||
coalition = unit:getCoalition(),
|
||||
groupId = groupId
|
||||
}
|
||||
|
||||
-- Set default laser code
|
||||
AFAC.Data.laserCodes[unitName] = AFAC.Config.laserCodes[1]
|
||||
|
||||
-- Set default marker settings
|
||||
AFAC.Data.markerSettings[unitName] = {
|
||||
type = "SMOKE",
|
||||
color = AFAC.Config.defaultSmokeColor[unit:getCoalition()]
|
||||
}
|
||||
|
||||
-- Set on station
|
||||
AFAC.Data.onStation[unitName] = true
|
||||
|
||||
-- Notify player
|
||||
local message = string.format("AFAC System Active\nAircraft: %s\nUse F10 menu to control targeting",
|
||||
unit:getTypeName())
|
||||
trigger.action.outTextForGroup(groupId, message, 15)
|
||||
|
||||
-- Start auto-lasing
|
||||
AFAC.startAutoLasing(unitName)
|
||||
|
||||
AFAC.log("Added AFAC pilot: " .. unitName)
|
||||
end
|
||||
|
||||
-- Remove pilot from system
|
||||
function AFAC.removePilot(unitName)
|
||||
if not AFAC.Data.pilots[unitName] then return end
|
||||
|
||||
-- Clean up laser points
|
||||
AFAC.cancelLasing(unitName)
|
||||
|
||||
-- Clean up data
|
||||
AFAC.Data.pilots[unitName] = nil
|
||||
AFAC.Data.targets[unitName] = nil
|
||||
AFAC.Data.laserPoints[unitName] = nil
|
||||
AFAC.Data.irPoints[unitName] = nil
|
||||
AFAC.Data.smokeMarks[unitName] = nil
|
||||
AFAC.Data.onStation[unitName] = nil
|
||||
AFAC.Data.laserCodes[unitName] = nil
|
||||
AFAC.Data.markerSettings[unitName] = nil
|
||||
AFAC.Data.manualTargets[unitName] = nil
|
||||
|
||||
AFAC.log("Removed AFAC pilot: " .. unitName)
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- TARGET DETECTION
|
||||
-- =====================================================
|
||||
|
||||
-- Find nearest visible enemy to AFAC unit
|
||||
function AFAC.findNearestTarget(afacUnit, maxRange)
|
||||
local afacPoint = afacUnit:getPoint()
|
||||
local afacCoalition = afacUnit:getCoalition()
|
||||
local enemyCoalition = afacCoalition == 1 and 2 or 1
|
||||
|
||||
local nearestTarget = nil
|
||||
local nearestDistance = maxRange or AFAC.Config.maxRange
|
||||
|
||||
-- Search for enemy units
|
||||
local searchVolume = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = afacPoint,
|
||||
radius = nearestDistance
|
||||
}
|
||||
}
|
||||
|
||||
local function checkUnit(foundUnit)
|
||||
if foundUnit:getCoalition() ~= enemyCoalition then return end
|
||||
if not foundUnit:isActive() then return end
|
||||
if foundUnit:inAir() then return end
|
||||
if foundUnit:getLife() <= 1 then return end
|
||||
|
||||
local unitPoint = foundUnit:getPoint()
|
||||
local distance = AFAC.getDistance(afacPoint, unitPoint)
|
||||
|
||||
if distance >= nearestDistance then return end
|
||||
|
||||
-- Check line of sight
|
||||
local offsetAfacPos = {x = afacPoint.x, y = afacPoint.y + 2, z = afacPoint.z}
|
||||
local offsetUnitPos = {x = unitPoint.x, y = unitPoint.y + 2, z = unitPoint.z}
|
||||
|
||||
if not land.isVisible(offsetAfacPos, offsetUnitPos) then return end
|
||||
|
||||
-- Priority system: SAMs first, then vehicles, then infantry
|
||||
local priority = 1
|
||||
if foundUnit:hasAttribute("SAM TR") or foundUnit:hasAttribute("IR Guided SAM") then
|
||||
priority = 0.1 -- Highest priority
|
||||
elseif foundUnit:hasAttribute("Vehicles") then
|
||||
priority = 0.5
|
||||
end
|
||||
|
||||
local adjustedDistance = distance * priority
|
||||
|
||||
if adjustedDistance < nearestDistance then
|
||||
nearestDistance = adjustedDistance
|
||||
nearestTarget = foundUnit
|
||||
end
|
||||
end
|
||||
|
||||
world.searchObjects(Object.Category.UNIT, searchVolume, checkUnit)
|
||||
|
||||
return nearestTarget
|
||||
end
|
||||
|
||||
-- Scan area for multiple targets (manual mode)
|
||||
function AFAC.scanForTargets(afacUnit, maxCount)
|
||||
local afacPoint = afacUnit:getPoint()
|
||||
local afacCoalition = afacUnit:getCoalition()
|
||||
local enemyCoalition = afacCoalition == 1 and 2 or 1
|
||||
|
||||
local targets = {}
|
||||
local samTargets = {}
|
||||
|
||||
local searchVolume = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = afacPoint,
|
||||
radius = AFAC.Config.manualScanRange
|
||||
}
|
||||
}
|
||||
|
||||
local function checkUnit(foundUnit)
|
||||
if foundUnit:getCoalition() ~= enemyCoalition then return end
|
||||
if not foundUnit:isActive() then return end
|
||||
if foundUnit:inAir() then return end
|
||||
if foundUnit:getLife() <= 1 then return end
|
||||
|
||||
local unitPoint = foundUnit:getPoint()
|
||||
|
||||
-- Check line of sight
|
||||
local offsetAfacPos = {x = afacPoint.x, y = afacPoint.y + 2, z = afacPoint.z}
|
||||
local offsetUnitPos = {x = unitPoint.x, y = unitPoint.y + 2, z = unitPoint.z}
|
||||
|
||||
if not land.isVisible(offsetAfacPos, offsetUnitPos) then return end
|
||||
|
||||
-- Separate SAMs from other targets
|
||||
if foundUnit:hasAttribute("SAM TR") or foundUnit:hasAttribute("IR Guided SAM") then
|
||||
table.insert(samTargets, foundUnit)
|
||||
else
|
||||
table.insert(targets, foundUnit)
|
||||
end
|
||||
end
|
||||
|
||||
world.searchObjects(Object.Category.UNIT, searchVolume, checkUnit)
|
||||
|
||||
-- Priority: SAMs first, then others
|
||||
local finalTargets = {}
|
||||
for i = 1, math.min(#samTargets, maxCount or 10) do
|
||||
table.insert(finalTargets, samTargets[i])
|
||||
end
|
||||
|
||||
local remainingSlots = (maxCount or 10) - #finalTargets
|
||||
for i = 1, math.min(#targets, remainingSlots) do
|
||||
table.insert(finalTargets, targets[i])
|
||||
end
|
||||
|
||||
return finalTargets
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- LASER DESIGNATION SYSTEM
|
||||
-- =====================================================
|
||||
|
||||
-- Start laser designation on target
|
||||
function AFAC.startLasing(afacUnit, target, laserCode)
|
||||
local unitName = afacUnit:getName()
|
||||
|
||||
-- Cancel existing lasing
|
||||
AFAC.cancelLasing(unitName)
|
||||
|
||||
local targetPoint = target:getPoint()
|
||||
local targetVector = {x = targetPoint.x, y = targetPoint.y + 2, z = targetPoint.z}
|
||||
|
||||
-- Create laser and IR points
|
||||
local success, result = pcall(function()
|
||||
local laserSpot = Spot.createLaser(afacUnit, {x = 0, y = 2, z = 0}, targetVector, laserCode)
|
||||
local irSpot = Spot.createInfraRed(afacUnit, {x = 0, y = 2, z = 0}, targetVector)
|
||||
return {laser = laserSpot, ir = irSpot}
|
||||
end)
|
||||
|
||||
if success and result then
|
||||
AFAC.Data.laserPoints[unitName] = result.laser
|
||||
AFAC.Data.irPoints[unitName] = result.ir
|
||||
AFAC.log("Started lasing target for " .. unitName)
|
||||
else
|
||||
AFAC.log("Failed to create laser designation for " .. unitName)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update laser position
|
||||
function AFAC.updateLasing(unitName, target)
|
||||
local laserSpot = AFAC.Data.laserPoints[unitName]
|
||||
local irSpot = AFAC.Data.irPoints[unitName]
|
||||
|
||||
if not laserSpot or not irSpot then return end
|
||||
|
||||
local targetPoint = target:getPoint()
|
||||
local targetVector = {x = targetPoint.x, y = targetPoint.y + 2, z = targetPoint.z}
|
||||
|
||||
laserSpot:setPoint(targetVector)
|
||||
irSpot:setPoint(targetVector)
|
||||
end
|
||||
|
||||
-- Cancel laser designation
|
||||
function AFAC.cancelLasing(unitName)
|
||||
local laserSpot = AFAC.Data.laserPoints[unitName]
|
||||
local irSpot = AFAC.Data.irPoints[unitName]
|
||||
|
||||
if laserSpot then
|
||||
Spot.destroy(laserSpot)
|
||||
AFAC.Data.laserPoints[unitName] = nil
|
||||
end
|
||||
|
||||
if irSpot then
|
||||
Spot.destroy(irSpot)
|
||||
AFAC.Data.irPoints[unitName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- VISUAL MARKING SYSTEM
|
||||
-- =====================================================
|
||||
|
||||
-- Create smoke or flare marker
|
||||
function AFAC.createVisualMarker(target, markerType, color)
|
||||
local targetPoint = target:getPoint()
|
||||
local markerPoint = {x = targetPoint.x, y = targetPoint.y + 2, z = targetPoint.z}
|
||||
|
||||
if markerType == "SMOKE" then
|
||||
trigger.action.smoke(markerPoint, color)
|
||||
else -- FLARE
|
||||
trigger.action.signalFlare(markerPoint, color, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create F10 map marker with target details
|
||||
function AFAC.createMapMarker(target, spotter)
|
||||
local targetPoint = target:getPoint()
|
||||
local coalition = AFAC.Data.pilots[spotter].coalition
|
||||
|
||||
-- Get target details
|
||||
local velocity = target:getVelocity()
|
||||
local speed = 0
|
||||
if velocity then
|
||||
speed = math.sqrt(velocity.x^2 + velocity.z^2) * 2.237 -- Convert to mph
|
||||
end
|
||||
|
||||
local heading = AFAC.getHeading(target) * 180 / math.pi
|
||||
local coords = AFAC.coordToString(targetPoint)
|
||||
local mgrs = AFAC.getMGRS(targetPoint)
|
||||
local altitude = math.floor(targetPoint.y)
|
||||
|
||||
local markerText = string.format("%s\n%s\n%s\nAlt: %dm/%dft\nHdg: %03d°\nSpd: %.0f mph\nSpotter: %s",
|
||||
target:getTypeName(),
|
||||
coords,
|
||||
mgrs,
|
||||
altitude,
|
||||
altitude * 3.28084,
|
||||
heading,
|
||||
speed,
|
||||
spotter
|
||||
)
|
||||
|
||||
local markerId = AFAC.Data.nextMarkerId
|
||||
AFAC.Data.nextMarkerId = AFAC.Data.nextMarkerId + 1
|
||||
|
||||
trigger.action.markToCoalition(markerId, markerText, targetPoint, coalition, false, "AFAC Target")
|
||||
|
||||
-- Schedule marker removal
|
||||
timer.scheduleFunction(
|
||||
function(args)
|
||||
trigger.action.removeMark(args[1])
|
||||
end,
|
||||
{markerId},
|
||||
timer.getTime() + AFAC.Config.mapMarkerDuration
|
||||
)
|
||||
|
||||
return markerId
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- AUTOMATIC LASING SYSTEM
|
||||
-- =====================================================
|
||||
|
||||
-- Start automatic target lasing
|
||||
function AFAC.startAutoLasing(unitName)
|
||||
timer.scheduleFunction(AFAC.autoLaseUpdate, {unitName}, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
-- Auto-lasing update function
|
||||
function AFAC.autoLaseUpdate(args)
|
||||
local unitName = args[1]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
-- Check if pilot still exists and is on station
|
||||
if not pilot or not AFAC.Data.onStation[unitName] then
|
||||
return -- Don't reschedule
|
||||
end
|
||||
|
||||
local afacUnit = pilot.unit
|
||||
if not afacUnit or not afacUnit:isActive() or afacUnit:getLife() <= 0 then
|
||||
AFAC.removePilot(unitName)
|
||||
return
|
||||
end
|
||||
|
||||
local currentTarget = AFAC.Data.targets[unitName]
|
||||
local laserCode = AFAC.Data.laserCodes[unitName]
|
||||
local markerSettings = AFAC.Data.markerSettings[unitName]
|
||||
|
||||
-- Check if current target is still valid
|
||||
if currentTarget and (not currentTarget:isActive() or currentTarget:getLife() <= 1) then
|
||||
-- Target destroyed
|
||||
local message = string.format("[%s] Target %s destroyed. Good job! Scanning for new targets.",
|
||||
unitName, currentTarget:getTypeName())
|
||||
AFAC.notifyCoalition(message, 10, pilot.coalition)
|
||||
|
||||
AFAC.Data.targets[unitName] = nil
|
||||
AFAC.cancelLasing(unitName)
|
||||
currentTarget = nil
|
||||
end
|
||||
|
||||
-- Find new target if needed
|
||||
if not currentTarget then
|
||||
local newTarget = AFAC.findNearestTarget(afacUnit)
|
||||
if newTarget then
|
||||
AFAC.Data.targets[unitName] = newTarget
|
||||
|
||||
-- Start lasing
|
||||
AFAC.startLasing(afacUnit, newTarget, laserCode)
|
||||
|
||||
-- Create visual markers
|
||||
AFAC.createVisualMarker(newTarget, markerSettings.type, markerSettings.color)
|
||||
AFAC.createMapMarker(newTarget, unitName)
|
||||
|
||||
-- Notify coalition
|
||||
local message = string.format("[%s] Lasing new target: %s, CODE: %s",
|
||||
unitName, newTarget:getTypeName(), laserCode)
|
||||
AFAC.notifyCoalition(message, 10, pilot.coalition)
|
||||
|
||||
currentTarget = newTarget
|
||||
end
|
||||
end
|
||||
|
||||
-- Update laser position if we have a target
|
||||
if currentTarget then
|
||||
AFAC.updateLasing(unitName, currentTarget)
|
||||
|
||||
-- Update smoke markers periodically
|
||||
local nextSmokeTime = AFAC.Data.smokeMarks[unitName]
|
||||
if not nextSmokeTime or nextSmokeTime < timer.getTime() then
|
||||
AFAC.createVisualMarker(currentTarget, markerSettings.type, markerSettings.color)
|
||||
AFAC.Data.smokeMarks[unitName] = timer.getTime() + AFAC.Config.smokeInterval
|
||||
end
|
||||
end
|
||||
|
||||
-- Schedule next update
|
||||
timer.scheduleFunction(AFAC.autoLaseUpdate, args, timer.getTime() + AFAC.Config.autoUpdateInterval)
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- F10 MENU SYSTEM
|
||||
-- =====================================================
|
||||
|
||||
-- Add F10 menus for AFAC pilot
|
||||
function AFAC.addMenus(unitName)
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
if not pilot then return end
|
||||
|
||||
local groupId = pilot.groupId
|
||||
|
||||
-- Main AFAC menu
|
||||
local mainMenu = missionCommands.addSubMenuForGroup(groupId, "AFAC Control")
|
||||
|
||||
-- Targeting mode menu
|
||||
local targetMenu = missionCommands.addSubMenuForGroup(groupId, "Targeting Mode", mainMenu)
|
||||
missionCommands.addCommandForGroup(groupId, "Auto Mode ON", targetMenu, AFAC.setAutoMode, {unitName, true})
|
||||
missionCommands.addCommandForGroup(groupId, "Auto Mode OFF", targetMenu, AFAC.setAutoMode, {unitName, false})
|
||||
|
||||
-- Manual targeting
|
||||
local manualMenu = missionCommands.addSubMenuForGroup(groupId, "Manual Targeting", targetMenu)
|
||||
missionCommands.addCommandForGroup(groupId, "Scan for Targets", manualMenu, AFAC.manualScan, {unitName})
|
||||
|
||||
-- Target selection (will be populated after scan)
|
||||
local selectMenu = missionCommands.addSubMenuForGroup(groupId, "Select Target", manualMenu)
|
||||
for i = 1, 10 do
|
||||
missionCommands.addCommandForGroup(groupId, "Target " .. i, selectMenu, AFAC.selectManualTarget, {unitName, i})
|
||||
end
|
||||
|
||||
-- Laser code menu
|
||||
local laserMenu = missionCommands.addSubMenuForGroup(groupId, "Laser Codes", mainMenu)
|
||||
for _, code in ipairs(AFAC.Config.laserCodes) do
|
||||
missionCommands.addCommandForGroup(groupId, "Code: " .. code, laserMenu, AFAC.setLaserCode, {unitName, code})
|
||||
end
|
||||
|
||||
-- Marker settings
|
||||
local markerMenu = missionCommands.addSubMenuForGroup(groupId, "Marker Settings", mainMenu)
|
||||
|
||||
-- Smoke colors
|
||||
local smokeMenu = missionCommands.addSubMenuForGroup(groupId, "Smoke Color", markerMenu)
|
||||
for colorName, colorValue in pairs(AFAC.Config.smokeColors) do
|
||||
missionCommands.addCommandForGroup(groupId, colorName, smokeMenu, AFAC.setMarkerColor, {unitName, "SMOKE", colorValue})
|
||||
end
|
||||
|
||||
-- Flare colors (limited selection)
|
||||
local flareMenu = missionCommands.addSubMenuForGroup(groupId, "Flare Color", markerMenu)
|
||||
missionCommands.addCommandForGroup(groupId, "GREEN", flareMenu, AFAC.setMarkerColor, {unitName, "FLARE", 0})
|
||||
missionCommands.addCommandForGroup(groupId, "WHITE", flareMenu, AFAC.setMarkerColor, {unitName, "FLARE", 2})
|
||||
missionCommands.addCommandForGroup(groupId, "ORANGE", flareMenu, AFAC.setMarkerColor, {unitName, "FLARE", 3})
|
||||
|
||||
-- Status
|
||||
missionCommands.addCommandForGroup(groupId, "AFAC Status", mainMenu, AFAC.showStatus, {unitName})
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- F10 MENU FUNCTIONS
|
||||
-- =====================================================
|
||||
|
||||
-- Set auto/manual mode
|
||||
function AFAC.setAutoMode(args)
|
||||
local unitName = args[1]
|
||||
local autoMode = args[2]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
AFAC.Data.onStation[unitName] = autoMode
|
||||
|
||||
if autoMode then
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Auto targeting mode enabled", 10)
|
||||
AFAC.startAutoLasing(unitName)
|
||||
else
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Auto targeting mode disabled", 10)
|
||||
AFAC.cancelLasing(unitName)
|
||||
AFAC.Data.targets[unitName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Manual target scan
|
||||
function AFAC.manualScan(args)
|
||||
local unitName = args[1]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
local targets = AFAC.scanForTargets(pilot.unit, 10)
|
||||
AFAC.Data.manualTargets[unitName] = targets
|
||||
|
||||
-- Report found targets
|
||||
if #targets > 0 then
|
||||
local afacPoint = pilot.unit:getPoint()
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Targets found:", 5)
|
||||
|
||||
for i, target in ipairs(targets) do
|
||||
local targetPoint = target:getPoint()
|
||||
local distance = AFAC.getDistance(afacPoint, targetPoint)
|
||||
local bearing = math.atan2(targetPoint.z - afacPoint.z, targetPoint.x - afacPoint.x) * 180 / math.pi
|
||||
if bearing < 0 then bearing = bearing + 360 end
|
||||
|
||||
local message = string.format("Target %d: %s, Bearing %03d°, Range %.1fkm",
|
||||
i, target:getTypeName(), bearing, distance / 1000)
|
||||
trigger.action.outTextForGroup(pilot.groupId, message, 15)
|
||||
|
||||
-- Create map marker
|
||||
AFAC.createMapMarker(target, unitName)
|
||||
end
|
||||
else
|
||||
trigger.action.outTextForGroup(pilot.groupId, "No targets found in range", 10)
|
||||
end
|
||||
end
|
||||
|
||||
-- Select manual target
|
||||
function AFAC.selectManualTarget(args)
|
||||
local unitName = args[1]
|
||||
local targetIndex = args[2]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
local targets = AFAC.Data.manualTargets[unitName]
|
||||
if not targets or not targets[targetIndex] then
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Invalid target selection", 10)
|
||||
return
|
||||
end
|
||||
|
||||
local target = targets[targetIndex]
|
||||
if not target:isActive() or target:getLife() <= 1 then
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Selected target is no longer active", 10)
|
||||
return
|
||||
end
|
||||
|
||||
-- Set as current target
|
||||
AFAC.Data.targets[unitName] = target
|
||||
|
||||
-- Start lasing
|
||||
local laserCode = AFAC.Data.laserCodes[unitName]
|
||||
AFAC.startLasing(pilot.unit, target, laserCode)
|
||||
|
||||
-- Create markers
|
||||
local markerSettings = AFAC.Data.markerSettings[unitName]
|
||||
AFAC.createVisualMarker(target, markerSettings.type, markerSettings.color)
|
||||
|
||||
-- Notify
|
||||
local message = string.format("Designating Target %d: %s, CODE: %s",
|
||||
targetIndex, target:getTypeName(), laserCode)
|
||||
trigger.action.outTextForGroup(pilot.groupId, message, 10)
|
||||
|
||||
AFAC.notifyCoalition("[" .. unitName .. "] " .. message, 10, pilot.coalition)
|
||||
end
|
||||
|
||||
-- Set laser code
|
||||
function AFAC.setLaserCode(args)
|
||||
local unitName = args[1]
|
||||
local laserCode = args[2]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
AFAC.Data.laserCodes[unitName] = laserCode
|
||||
trigger.action.outTextForGroup(pilot.groupId, "Laser code set to: " .. laserCode, 10)
|
||||
|
||||
-- Update current lasing if active
|
||||
local currentTarget = AFAC.Data.targets[unitName]
|
||||
if currentTarget then
|
||||
AFAC.startLasing(pilot.unit, currentTarget, laserCode)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set marker color/type
|
||||
function AFAC.setMarkerColor(args)
|
||||
local unitName = args[1]
|
||||
local markerType = args[2]
|
||||
local color = args[3]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
AFAC.Data.markerSettings[unitName] = {
|
||||
type = markerType,
|
||||
color = color
|
||||
}
|
||||
|
||||
local colorNames = {"GREEN", "RED", "WHITE", "ORANGE", "BLUE"}
|
||||
trigger.action.outTextForGroup(pilot.groupId,
|
||||
string.format("Marker set to %s %s", colorNames[color + 1] or "UNKNOWN", markerType), 10)
|
||||
end
|
||||
|
||||
-- Show AFAC status
|
||||
function AFAC.showStatus(args)
|
||||
local unitName = args[1]
|
||||
local pilot = AFAC.Data.pilots[unitName]
|
||||
|
||||
if not pilot then return end
|
||||
|
||||
local status = "AFAC STATUS:\n\n"
|
||||
|
||||
for pilotName, pilotData in pairs(AFAC.Data.pilots) do
|
||||
if pilotData.coalition == pilot.coalition thenn then
|
||||
local target = AFAC.Data.targets[pilotName]
|
||||
local laserCode = AFAC.Data.laserCodes[pilotName]
|
||||
local onStation = AFAC.Data.onStation[pilotName]
|
||||
|
||||
if target and target:isActive() then
|
||||
status = status .. string.format("%s: Targeting %s, CODE: %s\n",
|
||||
pilotName, target:getTypeName(), laserCode)
|
||||
elseif onStation then
|
||||
status = status .. string.format("%s: On station, searching for targets\n", pilotName)
|
||||
else
|
||||
status = status .. string.format("%s: Off station\n", pilotName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
trigger.action.outTextForGroup(pilot.groupId, status, 30)
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- EVENT HANDLERS
|
||||
-- =====================================================
|
||||
|
||||
-- Event handler for unit spawning and player connections
|
||||
AFAC.EventHandler = {}
|
||||
|
||||
function AFAC.EventHandler:onEvent(event)
|
||||
-- Handle new unit spawning
|
||||
if event.id == world.event.S_EVENT_BIRTH then
|
||||
AFAC.log("S_EVENT_BIRTH triggered")
|
||||
local unit = event.initiator
|
||||
|
||||
if unit and Object.getCategory(unit) == Object.Category.UNIT then
|
||||
local objDesc = unit:getDesc()
|
||||
AFAC.log("Birth event - Unit category: " .. tostring(objDesc.category))
|
||||
if objDesc.category == Unit.Category.AIRPLANE or objDesc.category == Unit.Category.HELICOPTER then
|
||||
AFAC.log("Birth event - Aircraft detected: " .. unit:getTypeName())
|
||||
if AFAC.isAFAC(unit) then
|
||||
AFAC.log("Birth event - AFAC aircraft confirmed, scheduling add")
|
||||
-- Delay slightly to ensure unit is fully initialized
|
||||
timer.scheduleFunction(
|
||||
function(args)
|
||||
local u = args[1]
|
||||
if u and u:isActive() then
|
||||
AFAC.log("Adding pilot from birth event: " .. u:getName())
|
||||
AFAC.addPilot(u)
|
||||
AFAC.addMenus(u:getName())
|
||||
end
|
||||
end,
|
||||
{unit},
|
||||
timer.getTime() + 2
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug: Log ALL player enter events to see what's happening
|
||||
if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT then
|
||||
AFAC.log("PLAYER ENTERED UNIT - Type: " .. (event.initiator and event.initiator:getTypeName() or "UNKNOWN"))
|
||||
end
|
||||
|
||||
-- Handle player entering existing unit (like joining a running UH-1H)
|
||||
if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT then
|
||||
AFAC.log("S_EVENT_PLAYER_ENTER_UNIT triggered")
|
||||
local unit = event.initiator
|
||||
|
||||
if unit and Object.getCategory(unit) == Object.Category.UNIT then
|
||||
local objDesc = unit:getDesc()
|
||||
AFAC.log("Player enter - Unit category: " .. tostring(objDesc.category))
|
||||
if objDesc.category == Unit.Category.AIRPLANE or objDesc.category == Unit.Category.HELICOPTER then
|
||||
AFAC.log("Player enter - Aircraft detected: " .. unit:getTypeName())
|
||||
if AFAC.isAFAC(unit) then
|
||||
local unitName = unit:getName()
|
||||
AFAC.log("Player enter - AFAC aircraft confirmed: " .. unitName)
|
||||
|
||||
-- Check if already registered
|
||||
if not AFAC.Data.pilots[unitName] then
|
||||
AFAC.log("Player enter - Not registered, adding pilot")
|
||||
-- Add pilot and menus for existing aircraft
|
||||
timer.scheduleFunction(
|
||||
function(args)
|
||||
local u = args[1]
|
||||
if u and u:isActive() then
|
||||
AFAC.log("Adding pilot from player enter event: " .. u:getName())
|
||||
AFAC.addPilot(u)
|
||||
AFAC.addMenus(u:getName())
|
||||
end
|
||||
end,
|
||||
{unit},
|
||||
timer.getTime() + 1
|
||||
)
|
||||
else
|
||||
AFAC.log("Player enter - Already registered")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- =====================================================
|
||||
-- INITIALIZATION
|
||||
-- =====================================================
|
||||
|
||||
-- Add event handler
|
||||
world.addEventHandler(AFAC.EventHandler)
|
||||
|
||||
-- Continuous check for new AFAC pilots (catches players joining existing aircraft)
|
||||
function AFAC.checkForNewPilots()
|
||||
for coalitionId = 1, 2 do
|
||||
local airGroups = coalition.getGroups(coalitionId, Group.Category.AIRPLANE)
|
||||
local heliGroups = coalition.getGroups(coalitionId, Group.Category.HELICOPTER)
|
||||
|
||||
local allGroups = {}
|
||||
for _, group in ipairs(airGroups) do table.insert(allGroups, group) end
|
||||
for _, group in ipairs(heliGroups) do table.insert(allGroups, group) end
|
||||
|
||||
for _, group in ipairs(allGroups) do
|
||||
local units = group:getUnits()
|
||||
if units then
|
||||
for _, unit in ipairs(units) do
|
||||
if unit and unit:isActive() and AFAC.isAFAC(unit) then
|
||||
local unitName = unit:getName()
|
||||
|
||||
-- Check if this is a player-controlled AFAC that we haven't registered yet
|
||||
if unit:getPlayerName() and not AFAC.Data.pilots[unitName] then
|
||||
AFAC.log("Found new player AFAC: " .. unitName .. " (Player: " .. unit:getPlayerName() .. ")")
|
||||
AFAC.addPilot(unit)
|
||||
AFAC.addMenus(unitName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Reschedule check every 10 seconds
|
||||
timer.scheduleFunction(AFAC.checkForNewPilots, nil, timer.getTime() + 10)
|
||||
end
|
||||
|
||||
-- Initialize existing units (for mission restart)
|
||||
timer.scheduleFunction(
|
||||
function()
|
||||
for coalitionId = 1, 2 do
|
||||
local airGroups = coalition.getGroups(coalitionId, Group.Category.AIRPLANE)
|
||||
local heliGroups = coalition.getGroups(coalitionId, Group.Category.HELICOPTER)
|
||||
|
||||
local allGroups = {}
|
||||
for _, group in ipairs(airGroups) do table.insert(allGroups, group) end
|
||||
for _, group in ipairs(heliGroups) do table.insert(allGroups, group) end
|
||||
|
||||
for _, group in ipairs(allGroups) do
|
||||
local units = group:getUnits()
|
||||
if units then
|
||||
for _, unit in ipairs(units) do
|
||||
if unit and unit:isActive() and AFAC.isAFAC(unit) then
|
||||
AFAC.addPilot(unit)
|
||||
AFAC.addMenus(unit:getName())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
AFAC.log("AFAC System initialized")
|
||||
|
||||
-- Start continuous pilot checking
|
||||
AFAC.checkForNewPilots()
|
||||
end,
|
||||
nil,
|
||||
timer.getTime() + 5
|
||||
)
|
||||
|
||||
-- Success message
|
||||
trigger.action.outText("Simple AFAC System v1.0 loaded successfully!", 10)
|
||||
AFAC.log("AFAC Script fully loaded and initialized")
|
||||
|
||||
-- Heartbeat disabled in production to avoid periodic UI/network churn
|
||||
-- To re-enable for debugging, uncomment lines below:
|
||||
-- function AFAC.heartbeat()
|
||||
-- AFAC.log("AFAC System heartbeat - script is running")
|
||||
-- timer.scheduleFunction(AFAC.heartbeat, nil, timer.getTime() + 30)
|
||||
-- end
|
||||
-- timer.scheduleFunction(AFAC.heartbeat, nil, timer.getTime() + 30)
|
||||
@ -1,349 +0,0 @@
|
||||
# Mission Setup Checklist - F10 Menu System
|
||||
|
||||
## Pre-Setup
|
||||
- [ ] Back up your current mission file (.miz)
|
||||
- [ ] Have all script files ready
|
||||
- [ ] Have DCS Mission Editor open
|
||||
|
||||
---
|
||||
|
||||
## Step 1: File Preparation (5 minutes)
|
||||
|
||||
### Required Files
|
||||
- [ ] `Moose.lua` (MOOSE Framework)
|
||||
- [ ] `Moose_MenuManager.lua` (NEW - Menu System)
|
||||
- [ ] `CTLD.lua`
|
||||
- [ ] `Moose_FAC2MarkRecceZone.lua`
|
||||
|
||||
### Optional Files (Your Scripts)
|
||||
- [ ] `Moose_Intel.lua`
|
||||
- [ ] `Moose_CaptureZones.lua`
|
||||
- [ ] `Moose_NavalGroup.lua`
|
||||
- [ ] `Moose_TADC_Load2nd.lua`
|
||||
- [ ] Other custom scripts...
|
||||
|
||||
### Copy Files
|
||||
- [ ] Extract mission .miz file to folder (or use editor)
|
||||
- [ ] Place all .lua files in mission folder
|
||||
- [ ] Note: Mission Editor can also load scripts directly
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Mission Editor Setup (5 minutes)
|
||||
|
||||
### Open Mission
|
||||
- [ ] Open mission in DCS Mission Editor
|
||||
- [ ] Go to Triggers tab
|
||||
|
||||
### Create Load Trigger
|
||||
- [ ] Create new trigger: "Load Mission Scripts"
|
||||
- [ ] Set Type: **ONCE**
|
||||
- [ ] Set Event: **MISSION START**
|
||||
|
||||
### Add Condition
|
||||
- [ ] Add condition: **TIME MORE**
|
||||
- [ ] Set time: **1 second**
|
||||
- [ ] (Ensures mission is initialized)
|
||||
|
||||
### Add Script Actions (IN THIS ORDER!)
|
||||
- [ ] Action 1: DO SCRIPT FILE → `Moose.lua`
|
||||
- [ ] Action 2: DO SCRIPT FILE → `Moose_MenuManager.lua` ⚠️ CRITICAL ORDER!
|
||||
- [ ] Action 3: DO SCRIPT FILE → `CTLD.lua`
|
||||
- [ ] Action 4: DO SCRIPT FILE → `Moose_FAC2MarkRecceZone.lua`
|
||||
- [ ] Action 5: DO SCRIPT FILE → `Moose_Intel.lua`
|
||||
- [ ] Action 6: DO SCRIPT FILE → `Moose_CaptureZones.lua`
|
||||
- [ ] Action 7: DO SCRIPT FILE → `Moose_NavalGroup.lua`
|
||||
- [ ] Action 8: DO SCRIPT FILE → `Moose_TADC_Load2nd.lua`
|
||||
- [ ] Action 9+: (Any other scripts...)
|
||||
|
||||
### Save Mission
|
||||
- [ ] Save mission
|
||||
- [ ] Note the file path for testing
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Testing (5 minutes)
|
||||
|
||||
### Basic Test
|
||||
- [ ] Start mission in DCS
|
||||
- [ ] Spawn as any pilot (Blue coalition recommended)
|
||||
- [ ] Press **F10**
|
||||
|
||||
### Verify Menu Structure
|
||||
- [ ] F1: "Mission Options" exists
|
||||
- [ ] F1 → Contains: INTEL HQ, Zone Control, CVN Command, TADC Utilities
|
||||
- [ ] F2: "CTLD" exists
|
||||
- [ ] F2 → Contains: Check Cargo, Troop Transport, etc.
|
||||
- [ ] F3: "AFAC Control" exists
|
||||
- [ ] F3 → Contains: Targeting Mode, Laser Codes, etc.
|
||||
|
||||
### If Wrong Order
|
||||
- [ ] Exit mission
|
||||
- [ ] Check trigger action order in editor
|
||||
- [ ] Verify MenuManager is action #2
|
||||
- [ ] Verify CTLD is action #3
|
||||
- [ ] Verify FAC is action #4
|
||||
- [ ] Save and retest
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Configuration (Optional)
|
||||
|
||||
### Global Settings
|
||||
Open `Moose_MenuManager.lua`:
|
||||
- [ ] Review `EnableMissionOptionsMenu` (true/false)
|
||||
- [ ] Review `MissionOptionsMenuName` (change if desired)
|
||||
- [ ] Review `Debug` (enable for troubleshooting)
|
||||
|
||||
### Individual Script Settings
|
||||
For each script (Intel, Zones, CVN, TADC):
|
||||
- [ ] Check `EnableF10Menu` variable (top of file)
|
||||
- [ ] Set to `false` to hide that script's menu
|
||||
- [ ] Useful for training missions or specific scenarios
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Advanced Testing (Optional)
|
||||
|
||||
### Test Both Coalitions
|
||||
- [ ] Spawn as Blue pilot → Verify Blue menus
|
||||
- [ ] Spawn as Red pilot → Verify Red menus
|
||||
- [ ] Each coalition should see their own "Mission Options"
|
||||
|
||||
### Test Multiple Players
|
||||
- [ ] Host multiplayer server (or local)
|
||||
- [ ] Have multiple clients join
|
||||
- [ ] Each client sees consistent menus
|
||||
- [ ] CTLD/FAC menus are per-group (expected)
|
||||
|
||||
### Test Debug Mode
|
||||
- [ ] Enable debug in `Moose_MenuManager.lua`
|
||||
- [ ] Start mission
|
||||
- [ ] Check `dcs.log` file
|
||||
- [ ] Location: `C:\Users\[You]\Saved Games\DCS\Logs\dcs.log`
|
||||
- [ ] Look for "MenuManager:" messages
|
||||
- [ ] Verify menus created successfully
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Troubleshooting
|
||||
|
||||
### Problem: No "Mission Options" Menu
|
||||
Cause: MenuManager not loaded or disabled
|
||||
- [ ] Verify `Moose_MenuManager.lua` is in mission folder
|
||||
- [ ] Verify it's action #2 in trigger (after Moose.lua)
|
||||
- [ ] Check `EnableMissionOptionsMenu = true` in config
|
||||
- [ ] Enable debug mode and check logs
|
||||
|
||||
### Problem: CTLD Not at F2
|
||||
Cause: Load order incorrect
|
||||
- [ ] Verify CTLD.lua is action #3 (after MenuManager)
|
||||
- [ ] Check no other script loads between MenuManager and CTLD
|
||||
- [ ] Reorder trigger actions
|
||||
- [ ] Save and retest
|
||||
|
||||
### Problem: FAC Not at F3
|
||||
Cause: Load order incorrect
|
||||
- [ ] Verify FAC.lua is action #4 (after CTLD)
|
||||
- [ ] Check no other script loads between CTLD and FAC
|
||||
- [ ] Reorder trigger actions
|
||||
- [ ] Save and retest
|
||||
|
||||
### Problem: Script Errors on Load
|
||||
Cause: Syntax error or missing dependency
|
||||
- [ ] Check `dcs.log` for error messages
|
||||
- [ ] Verify all files are present
|
||||
- [ ] Verify Moose.lua loads first
|
||||
- [ ] Enable debug mode for detailed logging
|
||||
- [ ] Check file paths in trigger actions
|
||||
|
||||
### Problem: Menus Appear at Root Level
|
||||
Cause: Script doesn't use MenuManager
|
||||
- [ ] Verify script has MenuManager integration code
|
||||
- [ ] Check pattern: `if MenuManager then ... else ... end`
|
||||
- [ ] Review MENUMANAGER_TEMPLATE.lua for correct pattern
|
||||
- [ ] Update script accordingly
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Documentation
|
||||
|
||||
### For Mission Makers
|
||||
- [ ] Read `F10_MENU_SYSTEM_GUIDE.md` (comprehensive)
|
||||
- [ ] Bookmark `F10_MENU_QUICK_REF.md` (quick reference)
|
||||
- [ ] Save `EXAMPLE_MISSION_SETUP.lua` for future missions
|
||||
|
||||
### For Players
|
||||
- [ ] Create mission briefing mentioning menu structure
|
||||
- [ ] Example: "CTLD is at F10→F2, FAC is at F10→F3"
|
||||
- [ ] Note any disabled menus (if applicable)
|
||||
|
||||
### For Server Admins
|
||||
- [ ] Document any configuration changes
|
||||
- [ ] Note which scripts/menus are active
|
||||
- [ ] Keep backup of working configuration
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Deployment
|
||||
|
||||
### Pre-Deployment
|
||||
- [ ] Final test of all menus
|
||||
- [ ] Verify no script errors
|
||||
- [ ] Test with multiple players (if multiplayer)
|
||||
- [ ] Backup final working version
|
||||
|
||||
### Deployment
|
||||
- [ ] Upload mission to server (if multiplayer)
|
||||
- [ ] Update mission briefing/description
|
||||
- [ ] Notify players of menu structure
|
||||
- [ ] Monitor first mission for issues
|
||||
|
||||
### Post-Deployment
|
||||
- [ ] Collect player feedback
|
||||
- [ ] Monitor for errors
|
||||
- [ ] Adjust configuration if needed
|
||||
- [ ] Document any issues for future missions
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card (Print This!)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ F10 MENU SYSTEM - LOAD ORDER │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 1. Moose.lua │
|
||||
│ 2. Moose_MenuManager.lua ← FIRST! │
|
||||
│ 3. CTLD.lua ← F2 │
|
||||
│ 4. Moose_FAC2MarkRecceZone.lua ← F3 │
|
||||
│ 5. Other scripts... ← Under F1 │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────┐
|
||||
│ RESULT IN GAME │
|
||||
├─────────────────────────────────────────┤
|
||||
│ F10 → F1: Mission Options │
|
||||
│ F2: CTLD │
|
||||
│ F3: AFAC Control │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### ❌ Mistake 1: Loading Scripts Before MenuManager
|
||||
```
|
||||
❌ Wrong:
|
||||
1. Moose.lua
|
||||
2. Moose_Intel.lua
|
||||
3. Moose_MenuManager.lua ← Too late!
|
||||
|
||||
✅ Correct:
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua ← First!
|
||||
3. Moose_Intel.lua
|
||||
```
|
||||
|
||||
### ❌ Mistake 2: Loading Other Scripts Between MenuManager and CTLD
|
||||
```
|
||||
❌ Wrong:
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua
|
||||
3. Moose_Intel.lua ← Pushes CTLD down!
|
||||
4. CTLD.lua ← Not F2 anymore!
|
||||
|
||||
✅ Correct:
|
||||
1. Moose.lua
|
||||
2. Moose_MenuManager.lua
|
||||
3. CTLD.lua ← F2!
|
||||
4. Moose_Intel.lua
|
||||
```
|
||||
|
||||
### ❌ Mistake 3: Not Using MenuManager in Script
|
||||
```lua
|
||||
❌ Wrong (creates root menu):
|
||||
local MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
|
||||
✅ Correct (uses MenuManager):
|
||||
local MyMenu
|
||||
if MenuManager then
|
||||
MyMenu = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "My Script")
|
||||
else
|
||||
MyMenu = MENU_COALITION:New(coalition.side.BLUE, "My Script")
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Success Checklist
|
||||
|
||||
After setup, you should have:
|
||||
- [ ] ✅ Mission loads without errors
|
||||
- [ ] ✅ F1 shows "Mission Options" with submenus
|
||||
- [ ] ✅ F2 shows "CTLD" (always)
|
||||
- [ ] ✅ F3 shows "AFAC Control" (always)
|
||||
- [ ] ✅ All menu commands work
|
||||
- [ ] ✅ Both coalitions see correct menus
|
||||
- [ ] ✅ Players can find CTLD/FAC quickly
|
||||
- [ ] ✅ No duplicate or orphaned menus
|
||||
- [ ] ✅ dcs.log shows no errors
|
||||
- [ ] ✅ Professional, organized appearance
|
||||
|
||||
**All checked?** You're ready to go! 🎉
|
||||
|
||||
---
|
||||
|
||||
## Time Estimates
|
||||
|
||||
| Task | Time | Difficulty |
|
||||
|------|------|-----------|
|
||||
| Copy files | 2 min | Easy |
|
||||
| Set up triggers | 5 min | Easy |
|
||||
| Basic testing | 5 min | Easy |
|
||||
| Configuration | 5 min | Medium |
|
||||
| Troubleshooting | 0-15 min | Varies |
|
||||
| **Total** | **15-30 min** | **Easy** |
|
||||
|
||||
---
|
||||
|
||||
## Help & Resources
|
||||
|
||||
**Getting Started:**
|
||||
- This checklist (you are here)
|
||||
- `MENUMANAGER_README.md`
|
||||
|
||||
**Understanding:**
|
||||
- `MENUMANAGER_SUMMARY.md`
|
||||
- `MENUMANAGER_VISUAL_GUIDE.md`
|
||||
|
||||
**Reference:**
|
||||
- `F10_MENU_QUICK_REF.md`
|
||||
- `F10_MENU_SYSTEM_GUIDE.md`
|
||||
|
||||
**Development:**
|
||||
- `MENUMANAGER_TEMPLATE.lua`
|
||||
- `EXAMPLE_MISSION_SETUP.lua`
|
||||
|
||||
---
|
||||
|
||||
## Final Notes
|
||||
|
||||
✅ **Backup** your mission before making changes
|
||||
✅ **Test** thoroughly before deploying
|
||||
✅ **Document** your configuration
|
||||
✅ **Monitor** first live mission
|
||||
✅ **Iterate** based on feedback
|
||||
|
||||
**Remember**: The key is load order!
|
||||
1. MenuManager first
|
||||
2. CTLD second (F2)
|
||||
3. FAC third (F3)
|
||||
4. Everything else
|
||||
|
||||
**Good luck and happy mission making!** 🚁✈️
|
||||
|
||||
---
|
||||
|
||||
*Last updated: November 9, 2025*
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,965 +0,0 @@
|
||||
# Universal TADC System - Mission Maker's Guide
|
||||
## Tactical Air Defense Controller with Automated Logistics
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
1. [What is TADC?](#what-is-tadc)
|
||||
2. [System Overview](#system-overview)
|
||||
3. [Quick Start Guide](#quick-start-guide)
|
||||
4. [Detailed Configuration](#detailed-configuration)
|
||||
5. [Zone-Based Defense Setup](#zone-based-defense-setup)
|
||||
6. [Cargo Replenishment System](#cargo-replenishment-system)
|
||||
7. [Testing & Troubleshooting](#testing--troubleshooting)
|
||||
8. [Advanced Features](#advanced-features)
|
||||
9. [Common Scenarios](#common-scenarios)
|
||||
|
||||
---
|
||||
|
||||
## What is TADC?
|
||||
|
||||
**TADC (Tactical Air Defense Controller)** is an automated air defense system for DCS missions that creates realistic, dynamic fighter aircraft responses to airborne threats. Think of it as an AI commander that:
|
||||
|
||||
- **Detects enemy aircraft** automatically
|
||||
- **Launches fighters** to intercept threats
|
||||
- **Manages squadron resources** (aircraft availability, cooldowns)
|
||||
- **Replenishes squadrons** through cargo aircraft deliveries
|
||||
- **Operates independently** for both RED and BLUE coalitions
|
||||
|
||||
### Why Use TADC?
|
||||
|
||||
✅ **Realistic Air Defense** - Squadrons respond intelligently to threats
|
||||
✅ **Dynamic Gameplay** - Air battles happen organically without manual triggers
|
||||
✅ **Balanced Competition** - Both sides operate with equal capabilities
|
||||
✅ **Sustainable Operations** - Cargo system allows long missions with resupply
|
||||
✅ **Easy Configuration** - Simple tables instead of complex scripting
|
||||
|
||||
---
|
||||
|
||||
## System Overview
|
||||
|
||||
The TADC system consists of **three main scripts** that work together:
|
||||
|
||||
### 1. Squadron Configuration (`Moose_TADC_SquadronConfigs_Load1st.lua`)
|
||||
**Purpose:** Define all fighter squadrons for RED and BLUE coalitions
|
||||
**Contains:** Aircraft templates, airbases, patrol parameters, zone assignments
|
||||
**Load Order:** **FIRST** (must load before main TADC script)
|
||||
|
||||
### 2. Main TADC System (`Moose_TADC_Load2nd.lua`)
|
||||
**Purpose:** Core threat detection and interceptor management
|
||||
**Contains:** Threat scanning, squadron selection, intercept logic, F10 menus
|
||||
**Load Order:** **SECOND** (after squadron config)
|
||||
|
||||
### 3. Cargo Dispatcher (`Moose_TADC_CargoDispatcher.lua`)
|
||||
**Purpose:** Automated squadron resupply through cargo aircraft
|
||||
**Contains:** Squadron monitoring, cargo spawning, delivery tracking
|
||||
**Load Order:** **THIRD** (optional, only if using resupply system)
|
||||
|
||||
---
|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before setting up TADC, you need:
|
||||
|
||||
- ✅ **MOOSE Framework** loaded in your mission (download from [MOOSE GitHub](https://github.com/FlightControl-Master/MOOSE))
|
||||
- ✅ **Fighter aircraft templates** created in DCS mission editor (as GROUPS, not units)
|
||||
- ✅ **Airbases** under correct coalition control
|
||||
- ✅ (Optional) **Cargo aircraft templates** for resupply missions
|
||||
|
||||
### 5-Minute Setup
|
||||
|
||||
#### Step 1: Create Fighter Templates
|
||||
|
||||
1. Open your mission in DCS Mission Editor
|
||||
2. Place fighter aircraft as **LATE ACTIVATION GROUPS** (not individual units)
|
||||
3. Name them clearly (example: `RED_CAP_Kilpyavr_MiG29`)
|
||||
4. Position them at or near the airbases they'll operate from
|
||||
5. Set them to the correct coalition (RED or BLUE)
|
||||
|
||||
**Important:** Use GROUP templates, not UNIT templates!
|
||||
|
||||
#### Step 2: Load MOOSE Framework
|
||||
|
||||
1. In mission editor, go to **Triggers**
|
||||
2. Create a new trigger: **MISSION START**
|
||||
3. Add action: **DO SCRIPT FILE**
|
||||
4. Select your MOOSE.lua file
|
||||
5. This must be the FIRST script loaded
|
||||
|
||||
#### Step 3: Load Squadron Configuration
|
||||
|
||||
1. Create another **DO SCRIPT FILE** action (after MOOSE)
|
||||
2. Select `Moose_TADC_SquadronConfigs_Load1st.lua`
|
||||
3. Edit the file to configure your squadrons (see below)
|
||||
|
||||
#### Step 4: Load Main TADC System
|
||||
|
||||
1. Create another **DO SCRIPT FILE** action
|
||||
2. Select `Moose_TADC_Load2nd.lua`
|
||||
3. (Optional) Adjust settings in the file if needed
|
||||
|
||||
#### Step 5: (Optional) Load Cargo Dispatcher
|
||||
|
||||
1. If using resupply system, create another **DO SCRIPT FILE** action
|
||||
2. Select `Moose_TADC_CargoDispatcher.lua`
|
||||
|
||||
**Load Order in Mission Editor:**
|
||||
```
|
||||
1. MOOSE.lua
|
||||
2. Moose_TADC_SquadronConfigs_Load1st.lua
|
||||
3. Moose_TADC_Load2nd.lua
|
||||
4. Moose_TADC_CargoDispatcher.lua (optional)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Detailed Configuration
|
||||
|
||||
### Squadron Configuration Explained
|
||||
|
||||
Open `Moose_TADC_SquadronConfigs_Load1st.lua` and find the squadron configuration sections.
|
||||
|
||||
#### Basic Squadron Example
|
||||
|
||||
```lua
|
||||
{
|
||||
templateName = "RED_CAP_Kilpyavr_MiG29", -- Must match mission editor template name
|
||||
displayName = "Kilpyavr CAP MiG-29A", -- Human-readable name for logs/messages
|
||||
airbaseName = "Kilpyavr", -- Exact airbase name from DCS
|
||||
aircraft = 12, -- Maximum aircraft in squadron
|
||||
skill = AI.Skill.EXCELLENT, -- AI pilot skill level
|
||||
altitude = 20000, -- Patrol altitude (feet)
|
||||
speed = 350, -- Patrol speed (knots)
|
||||
patrolTime = 30, -- Time on station (minutes)
|
||||
type = "FIGHTER" -- Aircraft role
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameter Guide
|
||||
|
||||
| Parameter | Description | Example Values |
|
||||
|-----------|-------------|----------------|
|
||||
| **templateName** | Group name from mission editor (EXACT match) | `"RED_CAP_Base_F15"` |
|
||||
| **displayName** | Friendly name shown in messages | `"Kilpyavr CAP Squadron"` |
|
||||
| **airbaseName** | DCS airbase name (case sensitive) | `"Kilpyavr"`, `"Nellis AFB"` |
|
||||
| **aircraft** | Max squadron size | `8`, `12`, `16` |
|
||||
| **skill** | AI difficulty | `AI.Skill.AVERAGE`, `GOOD`, `HIGH`, `EXCELLENT`, `ACE` |
|
||||
| **altitude** | CAP patrol altitude | `15000` (feet) |
|
||||
| **speed** | CAP patrol speed | `300` (knots) |
|
||||
| **patrolTime** | Minutes on station before RTB | `20`, `30`, `40` |
|
||||
| **type** | Aircraft role | `"FIGHTER"` |
|
||||
|
||||
### Finding Airbase Names
|
||||
|
||||
**Method 1: Mission Editor**
|
||||
1. Open mission editor
|
||||
2. Click on any airbase
|
||||
3. The exact name appears in the properties panel
|
||||
4. Copy this name EXACTLY (case sensitive!)
|
||||
|
||||
**Method 2: Common Airbases**
|
||||
|
||||
**Kola Peninsula (Example Map):**
|
||||
- RED: `"Kilpyavr"`, `"Severomorsk-1"`, `"Severomorsk-3"`, `"Murmansk International"`
|
||||
- BLUE: `"Luostari Pechenga"`, `"Ivalo"`, `"Alakurtti"`
|
||||
|
||||
**Nevada:**
|
||||
- `"Nellis AFB"`, `"McCarran International"`, `"Creech AFB"`, `"Tonopah Test Range"`
|
||||
|
||||
**Caucasus:**
|
||||
- `"Batumi"`, `"Gudauta"`, `"Senaki-Kolkhi"`, `"Kobuleti"`, `"Kutaisi"`
|
||||
|
||||
### Adding Multiple Squadrons
|
||||
|
||||
You can add as many squadrons as you want. Just copy the squadron block and modify the values:
|
||||
|
||||
```lua
|
||||
RED_SQUADRON_CONFIG = {
|
||||
-- First Squadron
|
||||
{
|
||||
templateName = "RED_CAP_Base1_MiG29",
|
||||
displayName = "Base 1 CAP",
|
||||
airbaseName = "Kilpyavr",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER"
|
||||
},
|
||||
|
||||
-- Second Squadron (different base)
|
||||
{
|
||||
templateName = "RED_CAP_Base2_SU27",
|
||||
displayName = "Base 2 CAP",
|
||||
airbaseName = "Severomorsk-1",
|
||||
aircraft = 16,
|
||||
skill = AI.Skill.ACE,
|
||||
altitude = 25000,
|
||||
speed = 380,
|
||||
patrolTime = 25,
|
||||
type = "FIGHTER"
|
||||
},
|
||||
|
||||
-- Add more squadrons here...
|
||||
}
|
||||
```
|
||||
|
||||
**Repeat the same process for BLUE squadrons** in the `BLUE_SQUADRON_CONFIG` section.
|
||||
|
||||
---
|
||||
|
||||
## Zone-Based Defense Setup
|
||||
|
||||
Zones allow squadrons to have specific areas of responsibility, creating realistic layered defense.
|
||||
|
||||
### Why Use Zones?
|
||||
|
||||
- **Border Defense:** Squadrons patrol specific sectors
|
||||
- **Layered Defense:** Multiple squadrons cover overlapping areas
|
||||
- **Priority Response:** Squadrons respond differently based on threat location
|
||||
- **Realistic Behavior:** Fighters don't fly across the entire map for minor threats
|
||||
|
||||
### Zone Types
|
||||
|
||||
Each squadron can have up to 3 zone types:
|
||||
|
||||
1. **Primary Zone** - Main area of responsibility (full response)
|
||||
2. **Secondary Zone** - Support area (reduced response, 60% by default)
|
||||
3. **Tertiary Zone** - Emergency fallback (enhanced response when squadron weakened)
|
||||
|
||||
### Creating Zones in Mission Editor
|
||||
|
||||
**Method: Helicopter Waypoint Method**
|
||||
|
||||
1. Place a **helicopter group** (late activation, any type)
|
||||
2. Name it clearly (example: `"RED BORDER"`)
|
||||
3. Add waypoints that outline your zone boundary
|
||||
4. The script will automatically create a polygon zone from these waypoints
|
||||
5. Repeat for each zone you want to create
|
||||
|
||||
**Example Zone Setup:**
|
||||
```
|
||||
Mission Editor:
|
||||
- Helicopter Group: "RED BORDER" with waypoints forming a polygon
|
||||
- Helicopter Group: "BLUE BORDER" with waypoints forming a polygon
|
||||
- Helicopter Group: "CONTESTED ZONE" with waypoints forming a polygon
|
||||
```
|
||||
|
||||
### Configuring Zone Response
|
||||
|
||||
Add zone configuration to your squadron:
|
||||
|
||||
```lua
|
||||
{
|
||||
templateName = "RED_CAP_Kilpyavr_MiG29",
|
||||
displayName = "Kilpyavr CAP",
|
||||
airbaseName = "Kilpyavr",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
|
||||
-- Zone Configuration
|
||||
primaryZone = "RED BORDER", -- Main responsibility area
|
||||
secondaryZone = "CONTESTED ZONE", -- Backup coverage
|
||||
tertiaryZone = nil, -- No tertiary zone
|
||||
|
||||
-- Optional: Customize zone behavior
|
||||
zoneConfig = {
|
||||
primaryResponse = 1.0, -- Full response in primary zone
|
||||
secondaryResponse = 0.6, -- 60% response in secondary
|
||||
tertiaryResponse = 1.4, -- 140% response in tertiary
|
||||
enableFallback = false, -- Don't auto-switch to tertiary
|
||||
fallbackThreshold = 0.3, -- Switch when <30% aircraft remain
|
||||
secondaryLowPriorityFilter = true, -- Ignore small threats in secondary
|
||||
secondaryLowPriorityThreshold = 2 -- "Small threat" = 2 or fewer aircraft
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Zone Behavior Examples
|
||||
|
||||
**Example 1: Border Defense Squadron**
|
||||
```lua
|
||||
primaryZone = "RED BORDER", -- Patrols the border
|
||||
secondaryZone = "INTERIOR", -- Helps with interior threats if needed
|
||||
tertiaryZone = nil -- No fallback
|
||||
```
|
||||
|
||||
**Example 2: Base Defense with Fallback**
|
||||
```lua
|
||||
primaryZone = "NORTHERN SECTOR", -- Main patrol area
|
||||
secondaryZone = nil, -- No secondary
|
||||
tertiaryZone = "BASE PERIMETER", -- Falls back to defend base when weakened
|
||||
enableFallback = true, -- Auto-switch to tertiary when low
|
||||
fallbackThreshold = 0.4 -- Switch at 40% strength
|
||||
```
|
||||
|
||||
**Example 3: Layered Defense**
|
||||
```lua
|
||||
-- Squadron A: Outer layer
|
||||
primaryZone = "OUTER PERIMETER"
|
||||
|
||||
-- Squadron B: Middle layer
|
||||
primaryZone = "MIDDLE PERIMETER"
|
||||
|
||||
-- Squadron C: Inner/base defense
|
||||
primaryZone = "BASE DEFENSE"
|
||||
```
|
||||
|
||||
### Global Response (No Zones)
|
||||
|
||||
If you **DON'T** want zone restrictions, simply leave all zones as `nil`:
|
||||
|
||||
```lua
|
||||
{
|
||||
templateName = "RED_CAP_Base_MiG29",
|
||||
displayName = "Global Response CAP",
|
||||
airbaseName = "Kilpyavr",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
|
||||
-- No zones = responds to threats anywhere on the map
|
||||
primaryZone = nil,
|
||||
secondaryZone = nil,
|
||||
tertiaryZone = nil
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cargo Replenishment System
|
||||
|
||||
The cargo system automatically replenishes squadrons by spawning transport aircraft that fly supplies to airbases.
|
||||
|
||||
### How Cargo Works
|
||||
|
||||
1. **Monitoring:** Script checks squadron aircraft counts every minute
|
||||
2. **Detection:** When squadron drops below threshold (90% by default), cargo is dispatched
|
||||
3. **Spawning:** Transport aircraft spawns at a supply airfield
|
||||
4. **Delivery:** Flies to destination airbase and lands
|
||||
5. **Replenishment:** Squadron aircraft count increases upon delivery
|
||||
6. **Cooldown:** 5-minute cooldown before next delivery to same base
|
||||
|
||||
### Cargo Aircraft Detection
|
||||
|
||||
The system detects cargo by aircraft name patterns:
|
||||
- `CARGO`
|
||||
- `TRANSPORT`
|
||||
- `C130` or `C-130`
|
||||
- `AN26` or `AN-26`
|
||||
|
||||
**Delivery Methods:**
|
||||
- **Landing:** Aircraft lands at destination airbase
|
||||
|
||||
### Configuring Cargo Templates
|
||||
|
||||
Edit `Moose_TADC_CargoDispatcher.lua` and find `CARGO_SUPPLY_CONFIG`:
|
||||
|
||||
```lua
|
||||
local CARGO_SUPPLY_CONFIG = {
|
||||
red = {
|
||||
cargoTemplate = "CARGO_RED_AN26_TEMPLATE", -- Template name from mission editor
|
||||
supplyAirfields = {"Airbase1", "Airbase2"}, -- List of supply bases
|
||||
replenishAmount = 4, -- Aircraft added per delivery
|
||||
threshold = 0.90 -- Trigger at 90% capacity
|
||||
},
|
||||
blue = {
|
||||
cargoTemplate = "CARGO_BLUE_C130_TEMPLATE",
|
||||
supplyAirfields = {"Airbase3", "Airbase4"},
|
||||
replenishAmount = 4,
|
||||
threshold = 0.90
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Creating Cargo Templates
|
||||
|
||||
1. **In Mission Editor:**
|
||||
- Place transport aircraft group (C-130, An-26, etc.)
|
||||
- Name it: `CARGO_RED_AN26_TEMPLATE` or `CARGO_BLUE_C130_TEMPLATE`
|
||||
- Set **LATE ACTIVATION**
|
||||
- Position at any friendly airbase (starting position doesn't matter)
|
||||
|
||||
2. **In Configuration:**
|
||||
- Use the EXACT template name in `cargoTemplate` field
|
||||
- List supply airbases in `supplyAirfields` array
|
||||
- Set how many aircraft each delivery adds (`replenishAmount`)
|
||||
|
||||
### Supply Airfield Strategy
|
||||
|
||||
**Choose rear/safe airbases for supplies:**
|
||||
|
||||
```lua
|
||||
red = {
|
||||
cargoTemplate = "CARGO_RED_AN26_TEMPLATE",
|
||||
supplyAirfields = {
|
||||
"Rear_Base_1", -- Far from frontline, safe
|
||||
"Rear_Base_2", -- Alternate supply source
|
||||
"Central_Logistics_Hub" -- Main supply depot
|
||||
},
|
||||
replenishAmount = 4,
|
||||
threshold = 0.90
|
||||
}
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use 3-5 supply airbases for redundancy
|
||||
- Choose bases far from combat zones
|
||||
- Ensure supply bases are well-defended
|
||||
- Balance geographic coverage
|
||||
|
||||
### Disabling Cargo System
|
||||
|
||||
If you don't want automated resupply:
|
||||
1. **Don't load** `Moose_TADC_CargoDispatcher.lua`
|
||||
2. Squadrons will operate with their initial aircraft count only
|
||||
3. System still works perfectly for shorter missions
|
||||
|
||||
---
|
||||
|
||||
## Testing & Troubleshooting
|
||||
|
||||
### Validation Tools
|
||||
|
||||
The system includes built-in validation. Check the DCS log file after mission start for:
|
||||
|
||||
```
|
||||
[Universal TADC] ═══════════════════════════════════════
|
||||
[Universal TADC] Configuration Validation Results:
|
||||
[Universal TADC] ✓ All templates exist
|
||||
[Universal TADC] ✓ All airbases valid
|
||||
[Universal TADC] ✓ All zones found
|
||||
[Universal TADC] Configuration is VALID
|
||||
[Universal TADC] ═══════════════════════════════════════
|
||||
```
|
||||
|
||||
### In-Game F10 Menu Commands
|
||||
|
||||
Press **F10** in-game to access TADC utilities:
|
||||
|
||||
**Available to Each Coalition:**
|
||||
- **Show Squadron Resource Summary** - Current aircraft counts
|
||||
- **Show Airbase Status Report** - Operational status of all bases
|
||||
- **Show Active Interceptors** - Currently airborne fighters
|
||||
- **Show Threat Summary** - Detected enemy aircraft
|
||||
- **Broadcast Squadron Summary Now** - Force immediate status update
|
||||
- **Show Cargo Delivery Log** - Recent supply missions
|
||||
- **Show Zone Coverage Map** - Squadron zone assignments
|
||||
|
||||
**Available to All (Mission Commands):**
|
||||
- **Emergency Cleanup Interceptors** - Remove stuck/dead groups
|
||||
- **Show TADC System Status** - Uptime and system health
|
||||
- **Check for Stuck Aircraft** - Manual stuck aircraft check
|
||||
- **Show Airbase Health Status** - Parking/spawn issues
|
||||
|
||||
### Common Issues & Solutions
|
||||
|
||||
#### Issue: "Template not found in mission"
|
||||
|
||||
**Cause:** Template name in config doesn't match mission editor
|
||||
**Solution:**
|
||||
1. Check exact spelling and case
|
||||
2. Ensure template is in mission editor
|
||||
3. Verify template is a GROUP (not a unit)
|
||||
4. Check template name in mission editor properties
|
||||
|
||||
#### Issue: "Airbase not found or wrong coalition"
|
||||
|
||||
**Cause:** Airbase name wrong or captured by enemy
|
||||
**Solution:**
|
||||
1. Check exact airbase spelling (case sensitive)
|
||||
2. Verify airbase is owned by correct coalition in mission editor
|
||||
3. Use `_G.TDAC_CheckAirbase("AirbaseName")` in DCS console
|
||||
|
||||
#### Issue: "No interceptors launching"
|
||||
|
||||
**Check:**
|
||||
1. Are enemy aircraft detected? (F10 → Show Threat Summary)
|
||||
2. Are squadrons operational? (F10 → Show Squadron Resource Summary)
|
||||
3. Is airbase captured/destroyed? (F10 → Show Airbase Status Report)
|
||||
4. Are squadrons on cooldown? (F10 → Show Squadron Resource Summary)
|
||||
5. Check intercept ratio settings (might be too low)
|
||||
|
||||
#### Issue: "Cargo not delivering"
|
||||
|
||||
**Check:**
|
||||
1. Is cargo template name correct?
|
||||
2. Are supply airbases valid and friendly?
|
||||
3. Is destination airbase captured/operational?
|
||||
4. Check parking availability (F10 → Show Airbase Health Status)
|
||||
5. Look for "Cargo delivery detected" messages in log
|
||||
|
||||
#### Issue: "Aircraft spawning stuck at parking"
|
||||
|
||||
**Cause:** Parking spots occupied or insufficient space
|
||||
**Solution:**
|
||||
1. Use F10 → Check for Stuck Aircraft
|
||||
2. Use F10 → Emergency Cleanup Interceptors
|
||||
3. Check airbase parking capacity (larger aircraft need more space)
|
||||
4. Reduce squadron sizes if parking is limited
|
||||
|
||||
### DCS Console Diagnostics
|
||||
|
||||
Open DCS Lua console (**F12** or scripting console) and run:
|
||||
|
||||
```lua
|
||||
-- Check all supply airbase ownership
|
||||
_G.TDAC_CheckAirbaseOwnership()
|
||||
|
||||
-- Check specific airbase
|
||||
_G.TDAC_CheckAirbase("Kilpyavr")
|
||||
|
||||
-- Validate dispatcher configuration
|
||||
_G.TDAC_RunConfigCheck()
|
||||
|
||||
-- Check airbase parking availability
|
||||
_G.TDAC_LogAirbaseParking("Kilpyavr")
|
||||
|
||||
-- Test cargo spawn (debugging)
|
||||
_G.TDAC_CargoDispatcher_TestSpawn("CARGO_RED_AN26_TEMPLATE", "SupplyBase", "DestinationBase")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Intercept Ratio System
|
||||
|
||||
The `interceptRatio` setting controls how many fighters launch per enemy aircraft.
|
||||
|
||||
**In `Moose_TADC_Load2nd.lua`:**
|
||||
|
||||
```lua
|
||||
local TADC_SETTINGS = {
|
||||
red = {
|
||||
interceptRatio = 0.8, -- RED launches 0.8 fighters per threat
|
||||
maxActiveCAP = 8, -- Max 8 groups in air simultaneously
|
||||
defaultCooldown = 300, -- 5-minute cooldown after engagement
|
||||
},
|
||||
blue = {
|
||||
interceptRatio = 1.2, -- BLUE launches 1.2 fighters per threat
|
||||
maxActiveCAP = 10, -- Max 10 groups in air simultaneously
|
||||
defaultCooldown = 300,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Intercept Ratio Chart:**
|
||||
|
||||
| Ratio | 1 Enemy | 4 Enemies | 8 Enemies | Effect |
|
||||
|-------|---------|-----------|-----------|--------|
|
||||
| 0.5 | 1 fighter | 2 fighters | 4 fighters | Conservative response |
|
||||
| 0.8 | 1 fighter | 4 fighters | 7 fighters | **Balanced (default)** |
|
||||
| 1.0 | 1 fighter | 4 fighters | 8 fighters | 1:1 parity |
|
||||
| 1.4 | 2 fighters | 6 fighters | 12 fighters | Strong response |
|
||||
| 2.0 | 2 fighters | 8 fighters | 16 fighters | Overwhelming force |
|
||||
|
||||
**Tactical Effects:**
|
||||
- **Low (0.5-0.8):** Sustainable defense, squadrons last longer
|
||||
- **Medium (0.8-1.2):** Balanced dogfights, realistic attrition
|
||||
- **High (1.4-2.0):** Strong defense, rapid squadron depletion
|
||||
|
||||
**Asymmetric Scenarios:**
|
||||
```lua
|
||||
-- RED advantage
|
||||
red = { interceptRatio = 1.4 },
|
||||
blue = { interceptRatio = 0.8 }
|
||||
|
||||
-- BLUE advantage
|
||||
red = { interceptRatio = 0.8 },
|
||||
blue = { interceptRatio = 1.4 }
|
||||
```
|
||||
|
||||
### Distance-Based Engagement
|
||||
|
||||
Control how far squadrons will chase threats:
|
||||
|
||||
```lua
|
||||
{
|
||||
templateName = "RED_CAP_Base_MiG29",
|
||||
displayName = "Base Defense",
|
||||
airbaseName = "Kilpyavr",
|
||||
aircraft = 12,
|
||||
-- ... other settings ...
|
||||
|
||||
zoneConfig = {
|
||||
maxEngagementRange = 50000, -- Won't engage threats >50km from base
|
||||
primaryResponse = 1.0,
|
||||
secondaryResponse = 0.6
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Cooldown System
|
||||
|
||||
After launching interceptors, squadrons go on cooldown to prevent spam:
|
||||
|
||||
```lua
|
||||
local TADC_SETTINGS = {
|
||||
red = {
|
||||
defaultCooldown = 300, -- 5 minutes between launches
|
||||
-- ... other settings ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Per-Squadron Cooldown (optional):**
|
||||
```lua
|
||||
{
|
||||
templateName = "RED_CAP_Base_MiG29",
|
||||
cooldownOverride = 600, -- This squadron: 10-minute cooldown
|
||||
-- ... other settings ...
|
||||
}
|
||||
```
|
||||
|
||||
### Aircraft Skill Levels
|
||||
|
||||
Adjust AI difficulty per squadron:
|
||||
|
||||
```lua
|
||||
skill = AI.Skill.AVERAGE -- Easiest, good for training
|
||||
skill = AI.Skill.GOOD -- Below average
|
||||
skill = AI.Skill.HIGH -- Average pilots
|
||||
skill = AI.Skill.EXCELLENT -- Above average (recommended)
|
||||
skill = AI.Skill.ACE -- Hardest, expert pilots
|
||||
```
|
||||
|
||||
**Mixed Difficulty Example:**
|
||||
```lua
|
||||
RED_SQUADRON_CONFIG = {
|
||||
{
|
||||
displayName = "Elite Squadron",
|
||||
skill = AI.Skill.ACE, -- Best pilots
|
||||
aircraft = 8,
|
||||
-- ...
|
||||
},
|
||||
{
|
||||
displayName = "Regular Squadron",
|
||||
skill = AI.Skill.GOOD, -- Average pilots
|
||||
aircraft = 12,
|
||||
-- ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: Simple Border Defense
|
||||
|
||||
**Goal:** RED defends northern border, BLUE defends southern border
|
||||
|
||||
```lua
|
||||
-- RED Configuration
|
||||
RED_SQUADRON_CONFIG = {
|
||||
{
|
||||
templateName = "RED_CAP_North_MiG29",
|
||||
displayName = "Northern Border CAP",
|
||||
airbaseName = "Northern_Base",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "RED BORDER"
|
||||
}
|
||||
}
|
||||
|
||||
-- BLUE Configuration
|
||||
BLUE_SQUADRON_CONFIG = {
|
||||
{
|
||||
templateName = "BLUE_CAP_South_F16",
|
||||
displayName = "Southern Border CAP",
|
||||
airbaseName = "Southern_Base",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "BLUE BORDER"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**In Mission Editor:**
|
||||
- Create zone "RED BORDER" (helicopter waypoints on northern border)
|
||||
- Create zone "BLUE BORDER" (helicopter waypoints on southern border)
|
||||
|
||||
---
|
||||
|
||||
### Scenario 2: Layered Defense Network
|
||||
|
||||
**Goal:** Multiple squadrons covering overlapping zones with different priorities
|
||||
|
||||
```lua
|
||||
RED_SQUADRON_CONFIG = {
|
||||
-- Outer Layer: Long-range interceptors
|
||||
{
|
||||
templateName = "RED_LONG_RANGE_MiG31",
|
||||
displayName = "Long Range Interceptors",
|
||||
airbaseName = "Forward_Base",
|
||||
aircraft = 8,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 35000,
|
||||
speed = 450,
|
||||
patrolTime = 20,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "OUTER PERIMETER"
|
||||
},
|
||||
|
||||
-- Middle Layer: General defense
|
||||
{
|
||||
templateName = "RED_CAP_MiG29",
|
||||
displayName = "Middle Defense CAP",
|
||||
airbaseName = "Central_Base",
|
||||
aircraft = 12,
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 25000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "MIDDLE PERIMETER",
|
||||
secondaryZone = "OUTER PERIMETER"
|
||||
},
|
||||
|
||||
-- Inner Layer: Point defense
|
||||
{
|
||||
templateName = "RED_BASE_DEFENSE_SU27",
|
||||
displayName = "Base Defense",
|
||||
airbaseName = "Main_Base",
|
||||
aircraft = 16,
|
||||
skill = AI.Skill.ACE,
|
||||
altitude = 20000,
|
||||
speed = 320,
|
||||
patrolTime = 40,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "BASE PERIMETER",
|
||||
tertiaryZone = "BASE PERIMETER",
|
||||
zoneConfig = {
|
||||
enableFallback = true,
|
||||
fallbackThreshold = 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Scenario 3: Sustained Operations with Resupply
|
||||
|
||||
**Goal:** Long mission with automated squadron replenishment
|
||||
|
||||
**Squadron Config:**
|
||||
```lua
|
||||
RED_SQUADRON_CONFIG = {
|
||||
{
|
||||
templateName = "RED_CAP_Frontline_MiG29",
|
||||
displayName = "Frontline CAP",
|
||||
airbaseName = "Frontline_Base",
|
||||
aircraft = 12, -- Will be resupplied
|
||||
skill = AI.Skill.EXCELLENT,
|
||||
altitude = 20000,
|
||||
speed = 350,
|
||||
patrolTime = 30,
|
||||
type = "FIGHTER",
|
||||
primaryZone = "COMBAT ZONE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Cargo Config** (in `Moose_TADC_CargoDispatcher.lua`):
|
||||
```lua
|
||||
local CARGO_SUPPLY_CONFIG = {
|
||||
red = {
|
||||
cargoTemplate = "CARGO_RED_AN26",
|
||||
supplyAirfields = {
|
||||
"Rear_Base_1", -- Safe logistics hub
|
||||
"Rear_Base_2", -- Backup supply source
|
||||
"Central_Depot" -- Main supply depot
|
||||
},
|
||||
replenishAmount = 4, -- +4 aircraft per delivery
|
||||
threshold = 0.75 -- Trigger at 75% (9/12 aircraft)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Mission Flow:**
|
||||
1. Frontline squadron intercepts threats
|
||||
2. Squadron drops to 9 aircraft (75%)
|
||||
3. Cargo automatically dispatched from rear base
|
||||
4. Transport flies to frontline base
|
||||
5. Cargo delivers, squadron back to 12 aircraft
|
||||
6. Cycle repeats throughout mission
|
||||
|
||||
---
|
||||
|
||||
### Scenario 4: Asymmetric Warfare
|
||||
|
||||
**Goal:** RED has numerical superiority, BLUE has quality advantage
|
||||
|
||||
```lua
|
||||
-- RED: More squadrons, lower skill
|
||||
local TADC_SETTINGS = {
|
||||
red = {
|
||||
interceptRatio = 0.8, -- Conservative response
|
||||
maxActiveCAP = 12, -- More groups allowed
|
||||
}
|
||||
}
|
||||
|
||||
RED_SQUADRON_CONFIG = {
|
||||
{
|
||||
templateName = "RED_CAP_1",
|
||||
airbaseName = "Base_1",
|
||||
aircraft = 16, -- Large squadron
|
||||
skill = AI.Skill.GOOD, -- Average skill
|
||||
-- ...
|
||||
},
|
||||
{
|
||||
templateName = "RED_CAP_2",
|
||||
airbaseName = "Base_2",
|
||||
aircraft = 16,
|
||||
skill = AI.Skill.GOOD,
|
||||
-- ...
|
||||
},
|
||||
{
|
||||
templateName = "RED_CAP_3",
|
||||
airbaseName = "Base_3",
|
||||
aircraft = 16,
|
||||
skill = AI.Skill.GOOD,
|
||||
-- ...
|
||||
}
|
||||
}
|
||||
|
||||
-- BLUE: Fewer squadrons, higher skill
|
||||
local TADC_SETTINGS = {
|
||||
blue = {
|
||||
interceptRatio = 1.2, -- Aggressive response
|
||||
maxActiveCAP = 8, -- Fewer groups
|
||||
}
|
||||
}
|
||||
|
||||
BLUE_SQUADRON_CONFIG = {
|
||||
{
|
||||
templateName = "BLUE_CAP_1",
|
||||
airbaseName = "Base_1",
|
||||
aircraft = 10, -- Smaller squadron
|
||||
skill = AI.Skill.ACE, -- Elite pilots
|
||||
-- ...
|
||||
},
|
||||
{
|
||||
templateName = "BLUE_CAP_2",
|
||||
airbaseName = "Base_2",
|
||||
aircraft = 10,
|
||||
skill = AI.Skill.ACE,
|
||||
-- ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tips for New Mission Makers
|
||||
|
||||
### Start Simple
|
||||
|
||||
1. **First Mission:** Use 1-2 squadrons per side with no zones
|
||||
2. **Second Mission:** Add zone-based defense
|
||||
3. **Third Mission:** Add cargo resupply system
|
||||
4. **Advanced:** Multi-squadron layered defense with fallback
|
||||
|
||||
### Realistic Aircraft Numbers
|
||||
|
||||
**Small Airbase:** 6-8 aircraft per squadron
|
||||
**Medium Airbase:** 10-12 aircraft per squadron
|
||||
**Large Airbase:** 14-18 aircraft per squadron
|
||||
|
||||
**Balance across map:** If RED has 40 total aircraft, BLUE should have similar unless asymmetric
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- **Limit active groups:** Use `maxActiveCAP` to prevent FPS drops
|
||||
- **Zone sizes matter:** Smaller zones = less scanning overhead
|
||||
- **Cargo cooldowns:** Prevent cargo spam with reasonable cooldowns
|
||||
- **Squadron counts:** 3-5 squadrons per side is a good starting point
|
||||
|
||||
### Testing Workflow
|
||||
|
||||
1. **Create minimal setup** (1 squadron each side)
|
||||
2. **Test in mission editor** using "Fly Now"
|
||||
3. **Check F10 menus** for squadron status
|
||||
4. **Spawn enemy aircraft** to test intercepts
|
||||
5. **Review DCS.log** for validation messages
|
||||
6. **Expand gradually** once basic system works
|
||||
|
||||
### Common Mistakes to Avoid
|
||||
|
||||
❌ **Using UNIT templates instead of GROUP templates**
|
||||
✅ Use GROUP templates (late activation groups)
|
||||
|
||||
❌ **Misspelling airbase names**
|
||||
✅ Copy exact names from mission editor
|
||||
|
||||
❌ **Loading scripts in wrong order**
|
||||
✅ Squadron Config → Main TADC → Cargo Dispatcher
|
||||
|
||||
❌ **Setting intercept ratio too high**
|
||||
✅ Start with 0.8-1.0, adjust after testing
|
||||
|
||||
❌ **Forgetting to load MOOSE first**
|
||||
✅ MOOSE must be first script loaded
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Universal TADC system provides mission makers with powerful, automated air defense capabilities that create dynamic, realistic air combat scenarios. By following this guide, even new mission makers can create sophisticated missions with minimal scripting knowledge.
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
✅ **Three scripts work together:** Squadron Config → Main TADC → Cargo Dispatcher
|
||||
✅ **Configuration is simple:** Edit tables, not complex code
|
||||
✅ **Both coalitions operate independently:** Balanced or asymmetric scenarios
|
||||
✅ **Zones enable tactical behavior:** Realistic area-of-responsibility system
|
||||
✅ **Cargo enables sustained operations:** Long missions with automatic resupply
|
||||
✅ **Built-in validation:** Checks configuration before mission starts
|
||||
✅ **F10 menus provide visibility:** Monitor system status in real-time
|
||||
|
||||
### Getting Help
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check DCS.log for validation errors
|
||||
2. Use F10 menu diagnostics
|
||||
3. Run console commands for detailed info
|
||||
4. Review this guide's troubleshooting section
|
||||
5. Start simple and expand gradually
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. Set up your first squadron (1 RED, 1 BLUE)
|
||||
2. Test basic intercept behavior
|
||||
3. Add zones for tactical depth
|
||||
4. Implement cargo resupply for long missions
|
||||
5. Experiment with advanced features
|
||||
|
||||
Happy mission making! 🚁✈️
|
||||
|
||||
---
|
||||
*Author: F99th-TracerFacer
|
||||
*Document Version: 1.0*
|
||||
*Last Updated: October 2025*
|
||||
*Compatible with: MOOSE Framework & DCS World*
|
||||
@ -124,13 +124,13 @@ CTLD.Messages = {
|
||||
medevac_vectors = "MEDEVAC: {vehicle} crew bearing {brg}°, range {rng} {rng_u}. Time remaining: {time_remain} mins.",
|
||||
medevac_salvage_status = "Coalition Salvage Points: {points}. Use salvage to build out-of-stock items.",
|
||||
medevac_salvage_used = "Built {item} using {salvage} salvage points. Remaining: {remaining}.",
|
||||
medevac_salvage_insufficient = "Out of stock and insufficient salvage. Need {need} salvage points (have {have}). Deliver MEDEVAC crews to MASH to earn more.",
|
||||
medevac_salvage_insufficient = "Out of stock. Requires {need} salvage points (need {deficit} more). Earn salvage by delivering MEDEVAC crews to MASH or sling-loading enemy wreckage.",
|
||||
medevac_crew_warn_15min = "WARNING: {vehicle} crew at {grid} - rescue window expires in 15 minutes!",
|
||||
medevac_crew_warn_5min = "URGENT: {vehicle} crew at {grid} - rescue window expires in 5 minutes!",
|
||||
medevac_unload_hold = "MEDEVAC: Stay grounded in the MASH zone for {seconds} seconds to offload casualties.",
|
||||
|
||||
-- Sling-Load Salvage messages
|
||||
slingload_salvage_spawned = "SALVAGE OPPORTUNITY: Enemy wreckage at {grid}. Weight: {weight}kg, Est. Value: {reward}pts. {time_remain} to collect.",
|
||||
slingload_salvage_spawned = "SALVAGE OPPORTUNITY: Enemy wreckage at {grid}. Weight: {weight}kg, Est. Value: {reward}pts. {time_remain} remaining to collect!",
|
||||
slingload_salvage_delivered = "{player} delivered {weight}kg salvage for {reward} points ({condition})! Coalition total: {total}",
|
||||
slingload_salvage_expired = "SALVAGE LOST: Crate {id} at {grid} deteriorated.",
|
||||
slingload_salvage_damaged = "CAUTION: Salvage crate damaged in transit. Value reduced to {reward}pts.",
|
||||
@ -236,7 +236,7 @@ CTLD.Config = {
|
||||
|
||||
-- Safety offsets to avoid spawning units too close to player aircraft
|
||||
BuildSpawnOffset = 40, -- meters: shift build point forward from the aircraft (0 = spawn centered on aircraft)
|
||||
TroopSpawnOffset = 40, -- meters: shift troop unload point forward from the aircraft
|
||||
TroopSpawnOffset = 25, -- meters: shift troop unload point forward from the aircraft
|
||||
DropCrateForwardOffset = 35, -- meters: drop loaded crates this far in front of the aircraft
|
||||
|
||||
-- === Build & Crate Handling ===
|
||||
@ -366,11 +366,11 @@ CTLD.Config = {
|
||||
LabelOffsetX = 200, -- meters: horizontal nudge; adjust if text appears left-anchored in your DCS build
|
||||
-- Per-kind label prefixes
|
||||
LabelPrefixes = {
|
||||
Pickup = 'Supply Zone',
|
||||
Drop = 'Drop Zone',
|
||||
FOB = 'FOB Zone',
|
||||
MASH = 'MASH Zone',
|
||||
SalvageDrop = 'Salvage Collection Zone',
|
||||
Pickup = 'Supply',
|
||||
Drop = 'Drop',
|
||||
FOB = 'FOB',
|
||||
MASH = 'MASH',
|
||||
SalvageDrop = 'Salvage',
|
||||
}
|
||||
},
|
||||
|
||||
@ -409,13 +409,13 @@ CTLD.Config = {
|
||||
|
||||
-- Spawn probability when enemy ground units die
|
||||
SpawnChance = {
|
||||
[coalition.side.BLUE] = 0.90, -- 90% chance when BLUE unit dies (RED can collect the salvage)
|
||||
[coalition.side.RED] = 0.90, -- 90% chance when RED unit dies (BLUE can collect the salvage)
|
||||
[coalition.side.BLUE] = 0.15, -- 15% chance when BLUE unit dies (RED can collect the salvage)
|
||||
[coalition.side.RED] = 0.15, -- 90% chance when RED unit dies (BLUE can collect the salvage)
|
||||
},
|
||||
|
||||
-- Weight classes with spawn probabilities and reward rates
|
||||
WeightClasses = {
|
||||
{ name = 'Light', min = 1500, max = 2500, probability = 0.50, rewardPer500kg = 2 }, -- Huey-capable
|
||||
{ name = 'Light', min = 500, max = 1000, probability = 0.50, rewardPer500kg = 2 }, -- Huey-capable
|
||||
{ name = 'Medium', min = 2501, max = 5000, probability = 0.30, rewardPer500kg = 3 }, -- Hip/Mi-8
|
||||
{ name = 'Heavy', min = 5001, max = 8000, probability = 0.15, rewardPer500kg = 5 }, -- Large helos
|
||||
{ name = 'SuperHeavy', min = 8001, max = 12000, probability = 0.05, rewardPer500kg = 8 }, -- Chinook only
|
||||
@ -505,8 +505,8 @@ CTLD.MEDEVAC = {
|
||||
-- Crew spawning
|
||||
-- Per-coalition spawn probabilities for asymmetric scenarios
|
||||
CrewSurvivalChance = {
|
||||
[coalition.side.BLUE] = .50, -- probability (0.0-1.0) that BLUE crew survives to spawn MEDEVAC request. 1.0 = 100% (testing), 0.02 = 2% (production)
|
||||
[coalition.side.RED] = .50, -- probability (0.0-1.0) that RED crew survives to spawn MEDEVAC request
|
||||
[coalition.side.BLUE] = .30, -- probability (0.0-1.0) that BLUE crew survives to spawn MEDEVAC request. 1.0 = 100% (testing), 0.02 = 2% (production)
|
||||
[coalition.side.RED] = .30, -- probability (0.0-1.0) that RED crew survives to spawn MEDEVAC request
|
||||
},
|
||||
ManPadSpawnChance = {
|
||||
[coalition.side.BLUE] = 0.1, -- probability (0.0-1.0) that BLUE crew spawns with a MANPADS soldier. 1.0 = 100% (testing), 0.1 = 10% (production)
|
||||
@ -9203,9 +9203,10 @@ function CTLD:_TryUseSalvageForCrate(group, crateKey, catalogEntry)
|
||||
local available = CTLD._salvagePoints[self.Side] or 0
|
||||
if available < salvageCost then
|
||||
-- Send insufficient salvage message
|
||||
local deficit = salvageCost - available
|
||||
_msgGroup(group, _fmtTemplate(CTLD.Messages.medevac_salvage_insufficient, {
|
||||
need = salvageCost,
|
||||
have = available
|
||||
deficit = deficit
|
||||
}))
|
||||
return false
|
||||
end
|
||||
@ -10593,6 +10594,13 @@ function CTLD:_SpawnSlingLoadSalvageCrate(unitPos, unitTypeName, enemySide, even
|
||||
-- Calculate expiration time
|
||||
local lifetime = cfg.CrateLifetime or 10800
|
||||
local timeRemainMin = math.floor(lifetime / 60)
|
||||
local timeRemainHrs = math.floor(timeRemainMin / 60)
|
||||
local timeRemainStr
|
||||
if timeRemainHrs >= 1 then
|
||||
timeRemainStr = string.format("%d hr%s", timeRemainHrs, timeRemainHrs > 1 and "s" or "")
|
||||
else
|
||||
timeRemainStr = string.format("%d min%s", timeRemainMin, timeRemainMin > 1 and "s" or "")
|
||||
end
|
||||
local grid = self:_GetMGRSString(spawnPos)
|
||||
|
||||
-- Announce to coalition
|
||||
@ -10600,7 +10608,7 @@ function CTLD:_SpawnSlingLoadSalvageCrate(unitPos, unitTypeName, enemySide, even
|
||||
grid = grid,
|
||||
weight = weight,
|
||||
reward = rewardValue,
|
||||
time_remain = timeRemainMin,
|
||||
time_remain = timeRemainStr,
|
||||
})
|
||||
_msgCoalition(enemySide, msg)
|
||||
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user