Moving repositories around.

This commit is contained in:
iTracerFacer 2025-11-17 07:25:47 -06:00
parent f76d741588
commit e3d6e41b95
1807 changed files with 0 additions and 63448 deletions

View File

@ -1,752 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MOOSE CTLD: MEDEVAC & Salvage System Guide</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #e0e0e0;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
margin: 0;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: rgba(26, 26, 46, 0.95);
padding: 30px;
border-radius: 10px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.5);
}
h1 {
color: #ff6b6b;
text-align: center;
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
border-bottom: 3px solid #ff6b6b;
padding-bottom: 15px;
}
h2 {
color: #4ecdc4;
font-size: 1.8em;
margin-top: 40px;
margin-bottom: 20px;
border-left: 5px solid #4ecdc4;
padding-left: 15px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
}
h3 {
color: #ffe66d;
font-size: 1.3em;
margin-top: 25px;
margin-bottom: 15px;
text-transform: uppercase;
letter-spacing: 1px;
}
.subtitle {
text-align: center;
color: #a8dadc;
font-size: 1.2em;
margin-bottom: 30px;
font-style: italic;
}
.overview-box {
background: rgba(78, 205, 196, 0.1);
border-left: 4px solid #4ecdc4;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.menu-tree {
background: #0f0f1e;
padding: 20px;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
line-height: 1.8;
overflow-x: auto;
border: 2px solid #4ecdc4;
margin: 20px 0;
}
.menu-tree .highlight {
color: #ff6b6b;
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
background: rgba(15, 15, 30, 0.8);
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
th {
background: linear-gradient(135deg, #4ecdc4 0%, #3ab4aa 100%);
color: #0f0f1e;
padding: 15px;
text-align: left;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.5px;
}
td {
padding: 12px 15px;
border-bottom: 1px solid rgba(78, 205, 196, 0.2);
}
tr:hover {
background: rgba(78, 205, 196, 0.1);
}
.step-list {
background: rgba(255, 107, 107, 0.1);
border-left: 4px solid #ff6b6b;
padding: 15px 15px 15px 40px;
margin: 15px 0;
border-radius: 5px;
}
.step-list li {
margin: 10px 0;
padding-left: 10px;
}
.pro-tip {
background: rgba(255, 230, 109, 0.15);
border: 2px solid #ffe66d;
padding: 15px;
margin: 20px 0;
border-radius: 8px;
position: relative;
}
.pro-tip::before {
content: "💡 PRO TIP";
color: #ffe66d;
font-weight: bold;
display: block;
margin-bottom: 10px;
font-size: 1.1em;
}
.warning-box {
background: rgba(255, 107, 107, 0.15);
border: 2px solid #ff6b6b;
padding: 15px;
margin: 20px 0;
border-radius: 8px;
}
.warning-box::before {
content: "⚠️ IMPORTANT";
color: #ff6b6b;
font-weight: bold;
display: block;
margin-bottom: 10px;
font-size: 1.1em;
}
.badge {
display: inline-block;
padding: 5px 12px;
background: #4ecdc4;
color: #0f0f1e;
border-radius: 20px;
font-size: 0.85em;
font-weight: bold;
margin-left: 10px;
}
.badge-salvage1 {
background: #ff6b6b;
}
.badge-salvage2 {
background: #ffe66d;
color: #0f0f1e;
}
code {
background: rgba(78, 205, 196, 0.2);
padding: 2px 8px;
border-radius: 4px;
font-family: 'Courier New', monospace;
color: #4ecdc4;
}
.scenario-box {
background: rgba(15, 15, 30, 0.8);
padding: 15px;
margin: 15px 0;
border-radius: 8px;
border-left: 4px solid #ffe66d;
}
.scenario-box h4 {
color: #ffe66d;
margin-top: 0;
font-size: 1.1em;
}
.quick-ref {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.quick-ref-card {
background: rgba(15, 15, 30, 0.8);
padding: 20px;
border-radius: 8px;
border-top: 4px solid #4ecdc4;
}
.quick-ref-card h4 {
color: #4ecdc4;
margin-top: 0;
font-size: 1.2em;
}
.comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin: 20px 0;
}
.comparison > div {
background: rgba(15, 15, 30, 0.8);
padding: 20px;
border-radius: 8px;
}
.comparison .medevac {
border-top: 4px solid #ff6b6b;
}
.comparison .slingload {
border-top: 4px solid #ffe66d;
}
ul, ol {
margin: 10px 0;
}
li {
margin: 8px 0;
}
.footer {
text-align: center;
margin-top: 50px;
padding-top: 20px;
border-top: 2px solid rgba(78, 205, 196, 0.3);
color: #a8dadc;
font-style: italic;
}
@media print {
body {
background: white;
color: black;
}
.container {
background: white;
box-shadow: none;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🚁 MOOSE CTLD: COMPLETE MEDEVAC & SALVAGE SYSTEM GUIDE 📦</h1>
<p class="subtitle">Dynamic Battlefield Economy & Rescue Operations</p>
<div class="overview-box">
<h3>OVERVIEW</h3>
<p>The CTLD system features a comprehensive salvage economy with <strong>TWO distinct methods</strong> for earning salvage points: <strong>MEDEVAC crew rescue missions</strong> and <strong>Sling-Load salvage crate recovery</strong>. Both systems feed into a shared coalition salvage pool that can be used to build out-of-stock equipment.</p>
</div>
<h2>📋 Complete Menu Structure</h2>
<div class="menu-tree">
F10 > CTLD
├─── Operations
│ ├─── Troop Transport
│ │ ├─── Load Troops
│ │ ├─── Load Troops (Type)
│ │ │ ├─── [Assault Squad]
│ │ │ ├─── [MANPADS Team]
│ │ │ ├─── [AT Team]
│ │ │ └─── [Mortar Team]
│ │ ├─── Unload Troops
│ │ └─── Unload Troops (Attack Mode)
│ │
│ ├─── Build
│ │ ├─── Build Here
│ │ ├─── Build (Advanced)
│ │ │ ├─── [Category] > [Item]
│ │ │ └─── Build Here (Attack Mode)
│ │ └─── Build (Attack Mode)
│ │
│ └─── <span class="highlight">MEDEVAC ⭐</span>
│ ├─── List Active Missions
│ ├─── Vectors to Nearest Crew
│ ├─── Coalition Salvage Points
│ └─── Admin/Settings
│ └─── Clear All MEDEVAC Missions
├─── Logistics
│ ├─── Request Crate
│ │ └─── [Category] > [Item]
│ │
│ ├─── Recipe Info
│ │ └─── [Category] > [Item Details]
│ │
│ ├─── Crate Management
│ │ ├─── List Nearby Crates
│ │ ├─── Drop All Loaded Crates
│ │ ├─── Drop Single Crate
│ │ └─── Re-mark Crate (Smoke)
│ │
│ └─── Show Inventory at Nearest Zone
├─── Field Tools
│ ├─── Create Drop Zone (AO)
│ │
│ ├─── <span class="highlight">Salvage Collection Zones ⭐</span>
│ │ ├─── Create Salvage Zone Here
│ │ └─── Show Active Salvage Zones
│ │
│ └─── Smoke My Location
│ ├─── Green / Red / White / Orange / Blue
├─── Navigation
│ ├─── Request Vectors to Nearest Crate
│ ├─── <span class="highlight">Vectors to Nearest Salvage Crate ⭐</span>
│ ├─── Vectors to Nearest Pickup Zone
│ └─── Hover Coach (Enable/Disable)
└─── Admin/Help
├─── Player Guides
│ ├─── Quick Start Guide
│ ├─── Hover Pickup Tutorial
│ ├─── Build System Guide
│ └─── JTAC Operations
└─── Show CTLD Status
</div>
<h2>🚑 SALVAGE METHOD #1: MEDEVAC RESCUE <span class="badge badge-salvage1">CREW RECOVERY</span></h2>
<p><strong>CONCEPT:</strong> Rescue stranded vehicle crews and deliver them to MASH zones</p>
<h3>How It Works</h3>
<ol class="step-list">
<li>When friendly vehicles are destroyed, there's a <strong>% chance the crew survives</strong><br>
<em>(Default: 50% survival chance, configurable per coalition)</em></li>
<li>After a <strong>5-minute delay</strong> (battle clearance), surviving crew spawns near the wreck with a MEDEVAC mission announcement</li>
<li>Crew will:
<ul>
<li>Pop smoke when rescue helicopter approaches (8km detection)</li>
<li>Send colorful radio messages ("Follow the smoke!")</li>
<li>Wait up to <strong>1 hour</strong> before being declared KIA</li>
<li>May include MANPADS soldier for self-defense (10% chance)</li>
</ul>
</li>
<li>Load crew via normal troop pickup (land near crew, auto-loads)</li>
<li>Fly to any MASH (Mobile Army Surgical Hospital) zone</li>
<li>Land in MASH zone and wait <strong>15 seconds</strong> for automatic crew offload</li>
<li>Salvage points awarded based on vehicle value!</li>
</ol>
<h3>Salvage Value Scale</h3>
<p>Value is determined by the destroyed vehicle type (from catalog):</p>
<table>
<tr>
<th>Vehicle Type</th>
<th>Salvage Points</th>
<th>Examples</th>
</tr>
<tr>
<td>Light Vehicles</td>
<td>1-5 points</td>
<td>Humvees, trucks, light armor</td>
</tr>
<tr>
<td>Medium Vehicles</td>
<td>5-15 points</td>
<td>APCs, IFVs, light tanks</td>
</tr>
<tr>
<td>Heavy Vehicles</td>
<td>15-30 points</td>
<td>MBTs, heavy armor</td>
</tr>
<tr>
<td>Special Assets</td>
<td>30-50 points</td>
<td>SAMs, artillery, C2 vehicles</td>
</tr>
</table>
<div class="pro-tip">
<strong>Example:</strong> Rescue a T-90 crew = ~25 salvage points
</div>
<h3>MEDEVAC F10 Menu Commands</h3>
<ul>
<li><code>F10 > Operations > MEDEVAC > List Active Missions</code> - Shows all pending rescues with locations</li>
<li><code>F10 > Operations > MEDEVAC > Vectors to Nearest Crew</code> - Bearing/distance to closest MEDEVAC</li>
<li><code>F10 > Operations > MEDEVAC > Coalition Salvage Points</code> - Check your coalition's total salvage balance</li>
</ul>
<h2>📦 SALVAGE METHOD #2: SLING-LOAD RECOVERY <span class="badge badge-salvage2">EQUIPMENT SALVAGE</span></h2>
<p><strong>CONCEPT:</strong> Recover enemy equipment wreckage via DCS sling-load mechanics</p>
<h3>How It Works</h3>
<ol class="step-list">
<li>When <strong>ENEMY</strong> ground units die, there's a <strong>15% chance</strong> (configurable) to spawn a physical cargo crate near the wreck for <strong>YOUR coalition</strong> to collect</li>
<li>Crate naming:
<ul>
<li><code>SALVAGE-B-XXXXXX</code> (Blue coalition can collect, spawns from RED deaths)</li>
<li><code>SALVAGE-R-XXXXXX</code> (Red coalition can collect, spawns from BLUE deaths)</li>
</ul>
</li>
<li>Orange smoke marks crate location for 2 minutes after spawn</li>
<li>Crate has a random weight class (determines helicopter requirement & reward)</li>
<li>Use standard <strong>DCS F6 RADIO MENU</strong> sling-load to hook the crate</li>
<li>Fly to a Salvage Collection Zone (create via F10 > Field Tools menu)</li>
<li>Land/drop crate inside the zone boundary</li>
<li>Automatic detection awards salvage points based on weight + condition!</li>
<li>Crate expires after <strong>3 HOURS</strong> if not collected (warnings at 30min & 5min)</li>
</ol>
<div class="warning-box">
<strong>NOT hover-pickup!</strong> This is pure DCS sling-load mechanics using F6 RADIO MENU!
</div>
<h3>Weight Classes & Reward Matrix</h3>
<p>Crate weight determines both helicopter requirements and base reward value:</p>
<table>
<tr>
<th>Weight Class</th>
<th>Weight Range</th>
<th>Helicopter</th>
<th>Base Reward</th>
<th>Spawn Chance</th>
</tr>
<tr>
<td><strong>Light</strong></td>
<td>1500-2500 kg</td>
<td>UH-1H Huey, UH-60</td>
<td>2 pts/500kg</td>
<td>50%</td>
</tr>
<tr>
<td><strong>Medium</strong></td>
<td>2501-5000 kg</td>
<td>Mi-8 Hip, Ka-50</td>
<td>3 pts/500kg</td>
<td>30%</td>
</tr>
<tr>
<td><strong>Heavy</strong></td>
<td>5001-8000 kg</td>
<td>Large Helos</td>
<td>5 pts/500kg</td>
<td>15%</td>
</tr>
<tr>
<td><strong>Super Heavy</strong></td>
<td>8001-12000 kg</td>
<td>CH-47 Chinook ONLY</td>
<td>8 pts/500kg</td>
<td>5%</td>
</tr>
</table>
<h3>Reward Calculation Formula</h3>
<div class="pro-tip">
<strong>Final Reward = (Weight ÷ 500) × Base Multiplier × Condition Bonus</strong>
<br><br>
<strong>Example Light Crate (2000kg):</strong>
<ul style="margin-top: 10px;">
<li>Base: (2000 ÷ 500) × 2 = <strong>8 points</strong></li>
<li>If Undamaged: 8 × 1.5 = <strong>12 points</strong></li>
<li>If Damaged: 8 × 1.0 = <strong>8 points</strong></li>
<li>If Heavy Damage: 8 × 0.5 = <strong>4 points</strong></li>
</ul>
</div>
<h3>⚠️ Condition-Based Multipliers - FLY CAREFULLY!</h3>
<p>Crate health affects your reward! Damage reduces salvage value:</p>
<table>
<tr>
<th>Condition</th>
<th>Health Range</th>
<th>Multiplier</th>
<th>Example (8pt base)</th>
</tr>
<tr style="background: rgba(78, 205, 196, 0.15);">
<td><strong>UNDAMAGED ✓</strong></td>
<td>≥ 90% health</td>
<td><strong>1.5x</strong></td>
<td><strong>12 points (+50% BONUS!)</strong></td>
</tr>
<tr>
<td>Damaged</td>
<td>50-89% health</td>
<td>1.0x</td>
<td>8 points (normal)</td>
</tr>
<tr style="background: rgba(255, 107, 107, 0.1);">
<td><strong>Heavy Damage ⚠</strong></td>
<td>&lt; 50% health</td>
<td><strong>0.5x</strong></td>
<td><strong>4 points (-50% penalty)</strong></td>
</tr>
<tr style="background: rgba(255, 107, 107, 0.2);">
<td><strong>DESTROYED ✗</strong></td>
<td>0% health</td>
<td><strong>0x</strong></td>
<td><strong>0 points (crate lost)</strong></td>
</tr>
</table>
<div class="pro-tip">
Smooth flying = 50% bonus! Crash landing = 50% penalty!
</div>
<h3>Example Salvage Scenarios</h3>
<div class="scenario-box">
<h4>Scenario A: Light Crate, Perfect Delivery</h4>
<ul>
<li>Crate: 2000kg Light class</li>
<li>Flown carefully, no damage</li>
<li><strong>Reward: (2000÷500) × 2 × 1.5 = 12 salvage points</strong></li>
</ul>
</div>
<div class="scenario-box">
<h4>Scenario B: Medium Crate, Rough Landing</h4>
<ul>
<li>Crate: 4000kg Medium class</li>
<li>Damaged during transport (60% health)</li>
<li><strong>Reward: (4000÷500) × 3 × 1.0 = 24 salvage points</strong></li>
</ul>
</div>
<div class="scenario-box">
<h4>Scenario C: Super Heavy Crate, Crashed</h4>
<ul>
<li>Crate: 10,000kg Super Heavy (Chinook required!)</li>
<li>Heavy damage (40% health remaining)</li>
<li><strong>Reward: (10000÷500) × 8 × 0.5 = 80 salvage points</strong></li>
<li><em>(Would be 160 if undamaged!)</em></li>
</ul>
</div>
<div class="scenario-box">
<h4>Scenario D: Heavy Crate, Destroyed</h4>
<ul>
<li>Crate: 7000kg Heavy class</li>
<li>Crate destroyed in crash</li>
<li><strong>Reward: 0 points (crate removed from mission)</strong></li>
</ul>
</div>
<h3>Sling-Load Salvage F10 Menu Commands</h3>
<ul>
<li><code>F10 > Field Tools > Salvage Collection Zones > Create Salvage Zone Here</code> - Spawns a 300m collection zone at your position</li>
<li><code>F10 > Field Tools > Salvage Collection Zones > Show Active Salvage Zones</code> - Lists all active salvage drop-off points</li>
<li><code>F10 > Navigation > Vectors to Nearest Salvage Crate</code> - Bearing/distance/weight/value info</li>
</ul>
<h3>Spawn Restrictions</h3>
<p>Salvage crates will <strong>NOT</strong> spawn:</p>
<ul>
<li>Within 1000m of active pickup zones (prevents clutter)</li>
<li>Within 1km of airbases (avoids spawn on runways)</li>
<li>10-25 meters from wreck location (random placement)</li>
</ul>
<h3>Lifecycle & Warnings</h3>
<ul>
<li><strong>Spawn:</strong> Orange smoke + coalition announcement (grid, weight, estimated value)</li>
<li><strong>30 Minutes Remaining:</strong> First warning message</li>
<li><strong>5 Minutes Remaining:</strong> Urgent warning message</li>
<li><strong>Expiration:</strong> Crate removed + expiration message</li>
<li><strong>Total Lifetime:</strong> 3 HOURS (10,800 seconds, configurable)</li>
</ul>
<h2>💰 Using Salvage Points</h2>
<h3>What Are Salvage Points?</h3>
<p>Salvage points are a <strong>coalition-wide resource pool</strong> that allows you to build equipment that is normally out-of-stock at your current location.</p>
<h3>When Salvage Is Used</h3>
<p>Salvage auto-applies when:</p>
<ol>
<li>You request a crate that is <strong>OUT OF STOCK</strong> at nearest supply zone</li>
<li>Coalition has enough salvage points to cover the cost</li>
<li>Cost = item's required crate count (e.g., M1 Abrams = 3 crates = 3 salvage)</li>
</ol>
<h3>Salvage Balance</h3>
<p>Check your coalition's salvage point balance:</p>
<p><code>F10 > Operations > MEDEVAC > Coalition Salvage Points</code></p>
<p><em>Or build/request menu will show salvage balance when out-of-stock</em></p>
<h2>🎯 Strategic Considerations</h2>
<div class="comparison">
<div class="medevac">
<h4 style="color: #ff6b6b;">MEDEVAC Advantages</h4>
<ul>
<li>✓ More consistent rewards (vehicle value-based)</li>
<li>✓ Easier execution (normal troop pickup + land at MASH)</li>
<li>✓ Lower skill requirement</li>
<li>✓ Supports role-play/immersion</li>
<li>✓ No condition penalties</li>
</ul>
</div>
<div class="slingload">
<h4 style="color: #ffe66d;">Sling-Load Salvage Advantages</h4>
<ul>
<li>✓ Higher potential rewards (up to 160pts for perfect Chinook delivery!)</li>
<li>✓ More frequent opportunities (every enemy kill = 15% chance)</li>
<li>✓ Skill-based system (rewards good flying)</li>
<li>✓ Can be done solo or coordinated</li>
<li>✓ Creates dynamic battlefield scavenging gameplay</li>
</ul>
</div>
</div>
<h3>Combined Strategy</h3>
<p>Smart coalitions will:</p>
<ul>
<li>Assign dedicated MEDEVAC pilots for steady income</li>
<li>Have salvage scavengers follow the front line for crate collection</li>
<li>Prioritize high-value targets for maximum salvage spawns</li>
<li>Practice smooth sling-load flying for condition bonuses</li>
<li>Coordinate Chinook pilots for Super Heavy crate recovery</li>
</ul>
<h2>🚀 Quick Reference</h2>
<div class="quick-ref">
<div class="quick-ref-card">
<h4>MEDEVAC Quick Steps</h4>
<ol>
<li>Listen for MEDEVAC announcement (friendly vehicle crew spawned)</li>
<li><code>F10 > Ops > MEDEVAC > Vectors to Nearest Crew</code></li>
<li>Fly to location, follow smoke</li>
<li>Land near crew (auto-loads like troops)</li>
<li>Fly to MASH zone</li>
<li>Land and wait 15 seconds</li>
<li>Salvage awarded! Vehicle respawns shortly after.</li>
</ol>
</div>
<div class="quick-ref-card">
<h4>Sling-Load Salvage Quick Steps</h4>
<ol>
<li>Listen for salvage spawn announcement (enemy died → crate spawned)</li>
<li><code>F10 > Navigation > Vectors to Nearest Salvage Crate</code></li>
<li>Fly to location (orange smoke = crate)</li>
<li>Use <strong>DCS F6 RADIO MENU > Sling Load > Hook Cargo</strong></li>
<li>Fly carefully to Salvage Collection Zone</li>
<li>Land or drop crate inside zone</li>
<li>Salvage awarded based on weight + condition!</li>
</ol>
</div>
</div>
<h3>Key Differences</h3>
<table>
<tr>
<th>Feature</th>
<th>MEDEVAC</th>
<th>Sling-Load Salvage</th>
</tr>
<tr>
<td>Pickup Method</td>
<td>Hover pickup OR land → auto-loads troops</td>
<td>DCS F6 menu sling-load ONLY (not CTLD hover pickup!)</td>
</tr>
<tr>
<td>Reward Type</td>
<td>Fixed value per vehicle type</td>
<td>Variable value based on weight + flying skill</td>
</tr>
<tr>
<td>Time Window</td>
<td>1-hour window before crew KIA</td>
<td>3-hour window before crate expires</td>
</tr>
<tr>
<td>Skill Level</td>
<td>Easy to Medium</td>
<td>Medium to Hard (condition bonuses)</td>
</tr>
</table>
<h2>🔧 Troubleshooting</h2>
<h3>"I can't sling-load the salvage crate!"</h3>
<ul>
<li>Use DCS F6 RADIO MENU, not F10 CTLD hover pickup</li>
<li>Make sure helicopter supports sling-load (Huey, Hip, Chinook, etc.)</li>
<li>Check crate weight vs. helicopter capacity</li>
</ul>
<h3>"Crate disappeared before I got there!"</h3>
<ul>
<li>Crates expire after 3 hours</li>
<li>Check <code>F10 > Navigation > Vectors</code> for time remaining</li>
<li>Warnings sent at 30min and 5min</li>
</ul>
<h3>"I didn't get full reward for my delivery!"</h3>
<ul>
<li>Check crate health - damage reduces reward by up to 50%</li>
<li>Fly smoothly, avoid crashes, gentle landings</li>
<li>Undamaged crates give 50% BONUS!</li>
</ul>
<h3>"No MEDEVAC missions spawning!"</h3>
<ul>
<li>Check crew survival chance settings (default 50%)</li>
<li>Only friendly vehicle deaths spawn MEDEVAC</li>
<li>5-minute delay after death before crew spawns</li>
</ul>
<h3>"Where do I create Salvage Collection Zones?"</h3>
<ul>
<li><code>F10 > Field Tools > Salvage Collection Zones > Create Salvage Zone Here</code></li>
<li>Zone spawns at your current position with 300m radius</li>
</ul>
<h2>⚙️ Configuration Notes</h2>
<p>Mission makers can adjust:</p>
<ul>
<li>MEDEVAC crew survival chance (default 50% per coalition)</li>
<li>Sling-load salvage spawn chance (default 15% per coalition)</li>
<li>Crate lifetime (default 3 hours)</li>
<li>Weight class probabilities and reward rates</li>
<li>Condition multipliers</li>
<li>MANPADS spawn chance with crews (default 10%)</li>
<li>Spawn restrictions and distances</li>
</ul>
<p>All settings are per-coalition and fully configurable via the CTLD config table.</p>
<div class="footer">
<p><strong>System Design:</strong> F99th Squadron + AI Collaboration</p>
<p><strong>Implementation:</strong> MOOSE Framework + CTLD Module</p>
<p><strong>Concept Inspiration:</strong> Real-world combat salvage & rescue operations</p>
<p><strong>Gameplay Balance:</strong> Community tested & refined</p>
<br>
<p style="font-size: 1.2em; color: #4ecdc4;">Fly safe. Rescue smart. Salvage everything. 🚁📦</p>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,118 +0,0 @@
-- init_mission_dual_coalition.lua
-- Use in Mission Editor with DO SCRIPT FILE load order:
-- 1) Moose.lua
-- 2) Moose_CTLD_Pure/Moose_CTLD.lua
-- 3) Moose_CTLD_Pure/catalogs/CrateCatalog_CTLD_Extract.lua -- optional but recommended catalog with BLUE+RED items (_CTLD_EXTRACTED_CATALOG)
-- 4) Moose_CTLD_Pure/Moose_CTLD_FAC.lua -- optional FAC/RECCE support
-- 5) DO SCRIPT: dofile on this file OR paste the block below directly
--
-- IMPORTANT: F10 menu ordering depends on script execution order!
-- Load this initialization script BEFORE other mission scripts (TADC, CVN, Intel, etc.)
-- to ensure CTLD and FAC appear earlier in the F10 menu.
--
-- Zones you should create in the Mission Editor (as trigger zones):
-- BLUE: PICKUP_BLUE_MAIN, DROP_BLUE_1, FOB_BLUE_A
-- RED : PICKUP_RED_MAIN, DROP_RED_1, FOB_RED_A
-- Adjust names below if you use different zone names.
-- Create CTLD instances only if Moose and CTLD are available
if _MOOSE_CTLD and _G.BASE then
local blueCfg = {
CoalitionSide = coalition.side.BLUE,
PickupZoneSmokeColor = trigger.smokeColor.Green,
AllowedAircraft = { -- transport-capable unit type names (case-sensitive as in DCS DB)
'UH-1H','Mi-8MTV2','Mi-24P','SA342M','SA342L','SA342Minigun','UH-60L','CH-47Fbl1','CH-47F','Mi-17','GazelleAI'
},
-- Optional: drive zone activation from mission flags (preferred: set per-zone below via flag/activeWhen)
MapDraw = {
Enabled = true,
DrawMASHZones = true, -- Enable MASH zone drawing
},
Zones = {
PickupZones = { { name = 'ALPHA', flag = 9001, activeWhen = 0 } },
DropZones = { { name = 'BRAVO', flag = 9002, activeWhen = 0 } },
FOBZones = { { name = 'CHARLIE', flag = 9003, activeWhen = 0 } },
MASHZones = { { name = 'MASH Alpha', freq = '251.0 AM', radius = 500, flag = 9010, activeWhen = 0 } },
SalvageDropZones = { { name = 'S1', flag = 9020, radius = 500, activeWhen = 0 } },
},
BuildRequiresGroundCrates = true,
}
env.info('[DEBUG] blueCfg.Zones.MASHZones count: ' .. tostring(blueCfg.Zones and blueCfg.Zones.MASHZones and #blueCfg.Zones.MASHZones or 'NIL'))
if blueCfg.Zones and blueCfg.Zones.MASHZones and blueCfg.Zones.MASHZones[1] then
env.info('[DEBUG] blueCfg.Zones.MASHZones[1].name: ' .. tostring(blueCfg.Zones.MASHZones[1].name))
end
ctldBlue = _MOOSE_CTLD:New(blueCfg)
local redCfg = {
CoalitionSide = coalition.side.RED,
PickupZoneSmokeColor = trigger.smokeColor.Green,
AllowedAircraft = { -- transport-capable unit type names (case-sensitive as in DCS DB)
'UH-1H','Mi-8MTV2','Mi-24P','SA342M','SA342L','SA342Minigun','UH-60L','CH-47Fbl1','CH-47F','Mi-17','GazelleAI'
},
-- Optional: drive zone activation for RED via per-zone flag/activeWhen
MapDraw = {
Enabled = true,
DrawMASHZones = true, -- Enable MASH zone drawing
},
Zones = {
PickupZones = { { name = 'DELTA', flag = 9101, activeWhen = 0 } },
DropZones = { { name = 'ECHO', flag = 9102, activeWhen = 0 } },
FOBZones = { { name = 'FOXTROT', flag = 9103, activeWhen = 0 } },
MASHZones = { { name = 'MASH Bravo', freq = '252.0 AM', radius = 500, flag = 9111, activeWhen = 0 } },
SalvageDropZones = { { name = 'S2', flag = 9020, radius = 500, activeWhen = 0 } },
},
BuildRequiresGroundCrates = true,
}
env.info('[DEBUG] redCfg.Zones.MASHZones count: ' .. tostring(redCfg.Zones and redCfg.Zones.MASHZones and #redCfg.Zones.MASHZones or 'NIL'))
if redCfg.Zones and redCfg.Zones.MASHZones and redCfg.Zones.MASHZones[1] then
env.info('[DEBUG] redCfg.Zones.MASHZones[1].name: ' .. tostring(redCfg.Zones.MASHZones[1].name))
end
ctldRed = _MOOSE_CTLD:New(redCfg)
-- Merge catalog into both CTLD instances if catalog was loaded
env.info('[init_mission_dual_coalition] Checking for catalog: '..((_CTLD_EXTRACTED_CATALOG and 'FOUND') or 'NOT FOUND'))
if _CTLD_EXTRACTED_CATALOG then
local count = 0
for k,v in pairs(_CTLD_EXTRACTED_CATALOG) do count = count + 1 end
env.info('[init_mission_dual_coalition] Catalog has '..tostring(count)..' entries')
env.info('[init_mission_dual_coalition] Merging catalog into CTLD instances')
ctldBlue:MergeCatalog(_CTLD_EXTRACTED_CATALOG)
ctldRed:MergeCatalog(_CTLD_EXTRACTED_CATALOG)
env.info('[init_mission_dual_coalition] Catalog merged successfully')
-- Verify merge
local blueCount = 0
for k,v in pairs(ctldBlue.Config.CrateCatalog) do blueCount = blueCount + 1 end
env.info('[init_mission_dual_coalition] BLUE catalog now has '..tostring(blueCount)..' entries')
else
env.info('[init_mission_dual_coalition] WARNING: _CTLD_EXTRACTED_CATALOG not found - catalog not loaded!')
env.info('[init_mission_dual_coalition] Available globals: '..((_G._CTLD_EXTRACTED_CATALOG and 'in _G') or 'not in _G'))
end
else
env.info('[init_mission_dual_coalition] Moose or CTLD missing; skipping CTLD init')
end
-- Optional: FAC/RECCE for both sides (requires Moose_CTLD_FAC.lua)
if _MOOSE_CTLD_FAC and _G.BASE and ctldBlue and ctldRed then
facBlue = _MOOSE_CTLD_FAC:New(ctldBlue, {
CoalitionSide = coalition.side.BLUE,
Arty = { Enabled = false },
})
-- facBlue:AddRecceZone({ name = 'RECCE_BLUE_1' })
facBlue:Run()
facRed = _MOOSE_CTLD_FAC:New(ctldRed, {
CoalitionSide = coalition.side.RED,
Arty = { Enabled = false },
})
-- facRed:AddRecceZone({ name = 'RECCE_RED_1' })
facRed:Run()
else
env.info('[init_mission_dual_coalition] FAC not initialized (missing Moose/CTLD/FAC or CTLD not created)')
end

Binary file not shown.

View File

@ -1,301 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Complete MOOSE CTLD System — Player & Mission Setup Guide</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; line-height: 1.5; color: #1b1f23; padding: 2rem; max-width: 960px; margin: auto; }
h1, h2, h3 { line-height: 1.25; }
code, pre { background: #f6f8fa; border-radius: 4px; padding: 0.2em 0.4em; }
.note { background: #fff8c5; border: 1px solid #e3d888; padding: 0.75rem; border-radius: 6px; }
.screenshot { border: 1px dashed #c9d1d9; padding: 0.75rem; border-radius: 8px; color: #57606a; background: #f6f8fa; margin: 1rem 0; }
.screenshot strong { color: #24292f; }
hr { border: 0; border-top: 1px solid #d0d7de; margin: 2rem 0; }
ul { margin: 0.25rem 0 1rem 1.25rem; }
</style>
</head>
<body>
<h1>Complete MOOSE CTLD System — Player &amp; Mission Setup Guide</h1>
<p>Welcome! This guide explains what logistics means in DCS, how the CTLD system lets players change the battlefield, and exactly how to use the in-game menus. It also includes a concise mission-maker setup section.</p>
<hr />
<h2>What is CTLD and why it matters</h2>
<ul>
<li>CTLD (logistics &amp; troop transport) turns helicopters and transports into force multipliers.</li>
<li>You request “crates” at Supply (Pickup) Zones, deliver them, and build combat units, SAM sites, radars, FOBs, and support vehicles.</li>
<li>You can also transport troops and deploy them to hold ground or attack.</li>
<li>Every delivered asset can change the front line: new air defenses, JTACs, EWR coverage, armor pushes, or an FOB that shortens logistics legs.</li>
</ul>
<div class="screenshot"><strong>Screenshot placeholder:</strong> F10 -&gt; CTLD root menu</div>
<p><em>Tip:</em> The loop youll repeat is <strong>Request → Deliver → Build → Fight</strong>.</p>
<hr />
<h2>Getting started (players)</h2>
<ol>
<li>Spawn in a supported helicopter or transport.</li>
<li>Fly to a friendly Supply (Pickup) Zone.</li>
<li>Open F10 Other -&gt; CTLD.</li>
<li>Use <em>Logistics -&gt; Request Crate</em> to spawn crates; use <em>Operations -&gt; Build</em> to assemble units/sites.</li>
<li>Use <em>Navigation</em> to get vectors and Hover Coach, and <em>Field Tools</em> to mark or create a quick Drop Zone.</li>
<li>Deliver, build, and watch the mission evolve.</li>
</ol>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Example Pickup Zone with smoke</div>
<hr />
<h2>Menu overview (matches in-game structure)</h2>
<p>Below are the menu groups and the common actions youll see under each. Some options appear only when relevant (e.g., inventory enabled, crates nearby, zones configured).</p>
<h3>Operations</h3>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Operations menu open</div>
<ul>
<li><strong>Troop Transport</strong>
<ul>
<li><strong>Load Troops</strong>: Load infantry while inside an ACTIVE Supply (Pickup) Zone if the mission enforces this rule.</li>
<li><strong>Deploy Troops (Defend)</strong>: Unload troops to hold the current area and defend nearby.</li>
<li><strong>Deploy Troops (Attack)</strong>: Unload troops and order them to seek and engage enemies or move toward enemy-held bases (mission-configured behavior and speed). Static/unsuitable units will hold position.</li>
<li><em>Notes:</em>
<ul>
<li>Troop loading may be restricted to Pickup Zones. The nearest zone will be shown in messages if youre outside.</li>
<li>Deployment is blocked inside Pickup Zones when restrictions are enabled.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Build</strong>
<ul>
<li><strong>Build Here</strong>: Consumes nearby crates (within the Build Radius) and spawns the unit/site at your position. Includes a “confirm within X seconds” safety and a cooldown between builds.</li>
<li><strong>Build (Advanced) → Buildable Near You</strong>
<ul>
<li>Lists everything that can be built with crates youve dropped nearby (and optionally what youre carrying, depending on mission settings).</li>
<li>Per item youll see:
<ul>
<li><strong>Build [Hold Position]</strong>: Spawns and orders the unit/site to hold.</li>
<li><strong>Build [Attack (N m)]</strong>: Spawns and orders mobile units to seek/attack within the configured radius. Static/unsuitable units will still hold.</li>
</ul>
</li>
<li><strong>Refresh Buildable List</strong>: Re-scan nearby crates and update the list.</li>
</ul>
</li>
<li>FOB-only recipes can require building inside an FOB Zone when enabled (mission-specific rule).</li>
</ul>
</li>
</ul>
<h3>Logistics</h3>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Logistics -&gt; Request Crate</div>
<ul>
<li><strong>Request Crate</strong>
<ul>
<li>Menu is organized by categories (e.g., Combat Vehicles, AAA, SAM short range, Support, Artillery, etc.).</li>
<li>Each entry shows how many crates are required (e.g., “M1097 Avenger (2 crates)”).</li>
<li>Requests generally require being within the maximum distance to an ACTIVE Pickup Zone.</li>
<li>When inventory is enabled, stock is tracked per zone; out-of-stock types cannot be requested at that location until resupplied.</li>
</ul>
</li>
<li><strong>Recipe Info</strong>
<ul>
<li>Browse categories and see each items description; use this to plan which crates you need to build a unit or a multi-crate site.</li>
</ul>
</li>
<li><strong>Request Crate (In Stock Here)</strong>
<ul>
<li>Appears when inventory menus are enabled and the mission-maker has exposed this view.</li>
<li>Shows only items in stock at your nearest active Supply Zone and lets you spawn them directly.</li>
<li>Includes a “Refresh” option to update the list after requests.</li>
</ul>
</li>
<li><strong>Crate handling tips</strong>
<ul>
<li>Crates are marked with smoke at spawn.</li>
<li>Use <em>Navigation → Request Vectors to Nearest Crate</em> if you lose sight of it.</li>
<li>Hover pickup: hold roughly 520 m AGL, very low ground speed, steady for a few seconds to auto-load.</li>
<li>Crates have a mission-configured lifetime and will self-cleanup if not used.</li>
</ul>
</li>
</ul>
<h3>Field Tools</h3>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Field Tools menu open</div>
<ul>
<li><strong>Create Drop Zone (AO)</strong>: Quickly creates a temporary Drop Zone around your current position for coordination or scripted objectives.</li>
<li><strong>Smoke My Location</strong>: Green / Red / White / Orange / Blue — mark your current spot with smoke to help other players find you or the build point.</li>
</ul>
<h3>Navigation</h3>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Navigation menu open</div>
<ul>
<li><strong>Hover Coach: Enable / Disable</strong>: In-game guidance messages to help you nail the hover pickup window (AGL, drift, speed, “hold steady” cues).</li>
<li><strong>Request Vectors to Nearest Crate</strong>: Prints bearing and range to the closest friendly crate.</li>
<li><strong>Vectors to Nearest Pickup Zone</strong>: Bearing and range to the nearest active Supply (Pickup) Zone; if none are active, youll get helpful direction to the nearest configured one.</li>
</ul>
<h3>Admin/Help</h3>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Admin/Help menu open</div>
<ul>
<li><strong>Show CTLD Status</strong>: Quick summary of active crates, how many zones exist, and whether Build Confirm/Cooldown are ON.</li>
<li><strong>Draw CTLD Zones on Map / Clear CTLD Map Drawings</strong>: Draws labeled circles for Pickup/Drop/FOB zones on the F10 map for your coalition; clear them when youre done.</li>
<li><strong>Debug → Enable/Disable logging</strong>: Toggle detailed logging (mission maker troubleshooting).</li>
<li><strong>Player Guides</strong>: Zones Guide; Inventory How It Works; CTLD Basics; Troop Transport &amp; JTAC Use; Hover Pickup &amp; Slingloading; Build System; SAM Sites.</li>
<li><strong>Coalition Summary</strong> (if exposed by mission maker): A roll-up of coalition CTLD activity.</li>
</ul>
<hr />
<h2>How players influence the mission</h2>
<ul>
<li>Build air defenses (SAM/AAA) to protect friendly FARPs/FOBs and deny enemy air.</li>
<li>Deploy armor and ATGM teams to push objectives, ambush enemy convoys, or hold key terrain.</li>
<li>Build EWR/JTAC for better situational awareness and targeting support.</li>
<li>Establish FOBs to create forward supply hubs and shorten flight times.</li>
</ul>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Example built SAM site</div>
<hr />
<h2>Mission setup (for mission makers)</h2>
<p>Keep this section short and focused. You can find the defaults and toggles inside:</p>
<ul>
<li><code>Moose_CTLD_Pure/Moose_CTLD.lua</code> (main CTLD implementation; see the <code>CTLD.Config</code> table)</li>
<li><code>Moose_CTLD_Pure/Moose_CTLD_FAC.lua</code> (optional FAC/RECCE support)</li>
<li><code>Moose_CTLD_Pure/catalogs/</code> (example catalogs with ready-to-use recipes)</li>
<li><code>Moose_CTLD_Pure/init_mission_dual_coalition.lua</code> (ready-to-use minimal init for BLUE+RED)</li>
</ul>
<h3>Load order (Do Script File in Mission Editor)</h3>
<ol>
<li><code>Moose.lua</code></li>
<li><code>Moose_CTLD_Pure/Moose_CTLD.lua</code></li>
<li>A catalog file from <code>Moose_CTLD_Pure/catalogs/</code> (optional but recommended)</li>
<li><code>Moose_CTLD_Pure/Moose_CTLD_FAC.lua</code> (optional FAC/RECCE)</li>
<li>Your mission init block (you can use <code>Moose_CTLD_Pure/init_mission_dual_coalition.lua</code> as-is or adapt it)</li>
</ol>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Mission Editor Do Script File list</div>
<p><strong>Minimal snippet (example)</strong> — keep it to the point:</p>
<ul>
<li>Create a CTLD instance per coalition with: CoalitionSide, AllowedAircraft, Zones (Pickup/Drop/FOB definitions), and key toggles.</li>
<li>Optionally create a FAC module instance and run it.</li>
<li>Optionally merge a crate catalog.</li>
</ul>
<p><em>Hint:</em> See the shipped <code>init_mission_dual_coalition.lua</code> for a clean example of both BLUE and RED.</p>
<h3>Zones you must create in the Mission Editor</h3>
<ul>
<li>Pickup (Supply): e.g., <code>ALPHA</code> (BLUE), <code>DELTA</code> (RED)</li>
<li>Drop: e.g., <code>BRAVO</code> (BLUE), <code>ECHO</code> (RED)</li>
<li>FOB: e.g., <code>CHARLIE</code> (BLUE), <code>FOXTROT</code> (RED)</li>
</ul>
<p>Use the names referenced by your init script. The example init uses flags to control active/inactive state.</p>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Trigger zones for Pickup/Drop/FOB</div>
<h3>Frequently configured options (where to change)</h3>
<p>All of the following live under <code>CTLD.Config</code> in <code>Moose_CTLD.lua</code> or can be provided in the table passed to <code>_MOOSE_CTLD:New({...})</code> in your init script.</p>
<ul>
<li><strong>Logistics rules</strong>
<ul>
<li><code>RequirePickupZoneForCrateRequest</code></li>
<li><code>RequirePickupZoneForTroopLoad</code></li>
<li><code>PickupZoneMaxDistance</code></li>
<li><code>ForbidDropsInsidePickupZones</code></li>
<li><code>ForbidTroopDeployInsidePickupZones</code></li>
<li><code>ForbidChecksActivePickupOnly</code></li>
</ul>
</li>
<li><strong>Building behavior</strong>
<ul>
<li><code>BuildRadius</code></li>
<li><code>BuildSpawnOffset</code></li>
<li><code>BuildConfirmEnabled</code> + <code>BuildConfirmWindowSeconds</code></li>
<li><code>BuildCooldownEnabled</code> + <code>BuildCooldownSeconds</code></li>
<li><code>RestrictFOBToZones</code></li>
<li><code>AutoBuildFOBInZones</code></li>
</ul>
</li>
<li><strong>Inventory system (per-zone stock)</strong>
<ul>
<li><code>Inventory.Enabled</code></li>
<li><code>Inventory.ShowStockInMenu</code></li>
<li><code>Inventory.HideZeroStockMenu</code></li>
<li><code>Inventory.FOBStockFactor</code></li>
</ul>
</li>
<li><strong>Hover &amp; pickup quality-of-life</strong>
<ul>
<li><code>HoverCoachConfig</code> (messages/timing/thresholds)</li>
<li><code>TroopSpawnOffset</code></li>
</ul>
</li>
<li><strong>AI behavior for Attack builds</strong>
<ul>
<li><code>AttackAI.VehicleSearchRadius</code></li>
<li><code>AttackAI.MoveSpeedKmh</code></li>
</ul>
</li>
<li><strong>Menus</strong>
<ul>
<li><code>UseGroupMenus</code></li>
<li><code>UseCategorySubmenus</code></li>
<li><code>PickupZoneSmokeColor</code></li>
</ul>
</li>
</ul>
<h3>Crate catalog (recipes)</h3>
<ul>
<li>Use one of the provided catalogs under <code>Moose_CTLD_Pure/catalogs/</code> or your own.</li>
<li>Each entry defines a display label, side, category, stock, and a build function.</li>
<li>Multi-crate “SITE” entries build multi-unit groups (SAM sites or composite systems).</li>
<li><strong>Typical workflow</strong>
<ul>
<li>Load your chosen catalog after <code>Moose_CTLD.lua</code>.</li>
<li>Merge it into each CTLD instance you created.</li>
</ul>
</li>
</ul>
<div class="screenshot"><strong>Screenshot placeholder:</strong> Request Crate categories</div>
<h3>Dual-coalition setup</h3>
<ul>
<li>Instantiate two CTLD instances (one per side), each with its own zone names and smoke colors.</li>
<li>Instantiate two FAC modules if you want auto-lase/RECCE for both sides.</li>
<li>The included <code>init_mission_dual_coalition.lua</code> shows a minimal working setup.</li>
</ul>
<h3>FAC/RECCE (optional, from <code>Moose_CTLD_FAC.lua</code>)</h3>
<ul>
<li><strong>What it adds</strong>: Auto-lase with configurable laser codes, IR markers, map marks; manual target lists; multi-strike helper; artillery/naval/air tasking; RECCE sweeps with DMS/MGRS.</li>
<li><strong>Player usage</strong>: Look for an F10 FAC/RECCE menu in qualifying aircraft or groups.</li>
<li><strong>Mission knobs</strong>: CoalitionSide, auto-lase behavior, code reservations, marker type/color, on-station logic—see <code>Moose_CTLD_FAC.lua</code> or pass overrides to <code>:New()</code>.</li>
</ul>
<h3>Sanity checks and troubleshooting</h3>
<ul>
<li>Use <em>Admin/Help -&gt; Show CTLD Status</em> to verify counts and toggles quickly.</li>
<li>Draw zones to confirm names/positions match your intent.</li>
<li>If crates dont spawn: check zone active state, distance to zone, and inventory stock.</li>
<li>If builds dont trigger: check Build Radius, confirm window, cooldown, and that the crates match the recipe.</li>
</ul>
<hr />
<h2>Screenshot ideas (drop your captures in the placeholders above)</h2>
<ul>
<li>CTLD root menu with the five groups (Operations, Logistics, Field Tools, Navigation, Admin/Help)</li>
<li>Request Crate with category submenus visible</li>
<li>Build (Advanced) -&gt; Buildable Near You list</li>
<li>Hover Coach prompt during a near-perfect hover</li>
<li>Vectors message to a crate / pickup zone</li>
<li>Zone drawings on the F10 map (Pickup/Drop/FOB labeled)</li>
<li>In Stock Here list (if enabled)</li>
<li>Example SAM site placed after a build</li>
</ul>
<hr />
<h2>Appendix: File locations and names</h2>
<ul>
<li>Main CTLD: <code>Moose_CTLD_Pure/Moose_CTLD.lua</code></li>
<li>FAC/RECCE: <code>Moose_CTLD_Pure/Moose_CTLD_FAC.lua</code></li>
<li>Example dual-coalition init: <code>Moose_CTLD_Pure/init_mission_dual_coalition.lua</code></li>
<li>Catalogs: <code>Moose_CTLD_Pure/catalogs/</code></li>
</ul>
<p>No large code is required; most options are cleanly exposed in the config tables. Keep snippets tiny when needed.</p>
</body>
</html>

View File

@ -1,438 +0,0 @@
# Complete MOOSE CTLD System — Player & Mission Setup Guide
Welcome! This guide explains what logistics means in DCS, how the CTLD system lets players change the battlefield, and exactly how to use the in-game menus. It also includes a concise mission-maker setup section.
---
## What is CTLD and why it matters
- CTLD (logistics & troop transport) turns helicopters and transports into force multipliers.
- You request “crates” at Supply (Pickup) Zones, deliver them, and build combat units, SAM sites, radars, FOBs, and support vehicles.
- You can also transport troops and deploy them to hold ground or attack.
- Every delivered asset can change the front line: new air defenses, JTACs, EWR coverage, armor pushes, or an FOB that shortens logistics legs.
[screenshot: F10 -> CTLD root menu]
Tip: The loop youll repeat is Request → Pickup → Transport → Deliver → Build → Fight.
---
## Getting started (players)
1) Spawn in a supported helicopter or transport.
2) Fly to a friendly Supply (Pickup) Zone.
3) Open F10 Other -> CTLD.
4) Use Logistics -> Request Crate to spawn crates; use Operations -> Build to assemble units/sites.
5) Use Navigation to get vectors and Hover Coach, and Field Tools to mark or create a quick Drop Zone.
6) Deliver, build, and watch the mission evolve.
[screenshot: Example Pickup Zone with smoke]
---
## Menu overview (matches in-game structure)
Below are the menu groups and the common actions youll see under each. Some options appear only when relevant (e.g., inventory enabled, crates nearby, zones configured).
### Operations
[screenshot: Operations menu open]
- Troop Transport
- Load Troops: Load infantry while inside an ACTIVE Supply (Pickup) Zone if the mission enforces this rule.
- Deploy Troops (Defend): Unload troops to hold the current area and defend nearby.
- Deploy Troops (Attack): Unload troops and order them to seek and engage enemies or move toward enemy-held bases (mission-configured behavior and speed). Static/unsuitable units will hold position.
- Notes
- Troop loading may be restricted to Pickup Zones. The nearest zone will be shown in messages if youre outside.
- Deployment is blocked inside Pickup Zones when restrictions are enabled.
- Build
- Build Here: Consumes nearby crates (within the Build Radius) and spawns the unit/site at your position. Includes a "confirm within X seconds" safety and a cooldown between builds.
- Build (Advanced) → Buildable Near You
- Lists everything that can be built with crates you've dropped nearby (and optionally what you're carrying, depending on mission settings).
- Per item you'll see:
- Build [Hold Position]: Spawns and orders the unit/site to hold.
- Build [Attack (N m)]: Spawns and orders mobile units to seek/attack within the configured radius. Static/unsuitable units will still hold.
- Refresh Buildable List: Re-scan nearby crates and update the list.
- FOB-only recipes can require building inside an FOB Zone when enabled (mission-specific rule).
- MEDEVAC (if enabled in mission)
- List Active MEDEVAC Requests: Shows all pending rescue missions with grid coordinates and time remaining
- Nearest MEDEVAC Location: Bearing and range to the closest MEDEVAC crew needing rescue
- Coalition Salvage Points: Display current salvage point balance for your coalition
- Vectors to Nearest MEDEVAC: Full details (bearing, range, time remaining) to nearest crew
- MASH Locations: Shows all active MASH (Mobile Army Surgical Hospital) zones where you can deliver crews
- Pop Smoke at Crew Locations: Marks all active crew locations with smoke for easier visual identification
- Pop Smoke at MASH Zones: Marks all MASH zones with smoke
- MASH & Salvage System - Guide: In-game quick reference for the MEDEVAC system (same as in Admin/Help -> Player Guides)
- Admin/Settings → Clear All MEDEVAC Missions: Debug/admin tool to reset all active MEDEVAC missions
### Logistics
[screenshot: Logistics -> Request Crate]
- Request Crate
- Menu is organized by categories (e.g., Combat Vehicles, AAA, SAM short range, Support, Artillery, etc.).
- Each entry shows how many crates are required (e.g., “M1097 Avenger (2 crates)”).
- Requests generally require being within the maximum distance to an ACTIVE Pickup Zone.
- When inventory is enabled, stock is tracked per zone; out-of-stock types cannot be requested at that location until resupplied.
- Recipe Info
- Browse categories and see each items description; use this to plan which crates you need to build a unit or a multi-crate site.
- Request Crate (In Stock Here)
- Appears when inventory menus are enabled and the mission-maker has exposed this view.
- Shows only items in stock at your nearest active Supply Zone and lets you spawn them directly.
- Includes a “Refresh” option to update the list after requests.
- Crate handling tips
- Crates are marked with smoke at spawn.
- Use Navigation -> Request Vectors to Nearest Crate if you lose sight of it.
- Hover pickup: hold roughly 520 m AGL, very low ground speed, steady for a few seconds to auto-load.
- Crates have a mission-configured lifetime and will self-cleanup if not used.
### Field Tools
[screenshot: Field Tools menu open]
- Create Drop Zone (AO)
- Quickly creates a temporary Drop Zone around your current position for coordination or scripted objectives.
- Smoke My Location
- Green / Red / White / Orange / Blue: Mark your current spot with smoke to help other players find you or the build point.
### Navigation
[screenshot: Navigation menu open]
- Hover Coach: Enable / Disable
- In-game guidance messages to help you nail the hover pickup window (AGL, drift, speed, “hold steady” cues).
- Request Vectors to Nearest Crate
- Prints bearing and range to the closest friendly crate.
- Vectors to Nearest Pickup Zone
- Bearing and range to the nearest active Supply (Pickup) Zone; if none are active, youll get helpful direction to the nearest configured one.
### Admin/Help
[screenshot: Admin/Help menu open]
- Show CTLD Status
- Quick summary of active crates, how many zones exist, and whether Build Confirm/Cooldown are ON.
- Draw CTLD Zones on Map / Clear CTLD Map Drawings
- Draws labeled circles for Pickup/Drop/FOB zones on the F10 map for your coalition; clear them when youre done.
- Debug → Enable logging / Disable logging
- Toggles detailed logging (mission maker troubleshooting).
- Player Guides (in-game quick reference)
- Zones Guide
- Inventory How It Works
- CTLD Basics (2-minute tour)
- Troop Transport & JTAC Use
- Hover Pickup & Slingloading
- Build System: Build Here and Advanced
- SAM Sites: Building, Repairing, and Augmenting
- Coalition Summary (if exposed by mission maker)
- A roll-up of coalition CTLD activity (counts, highlights). Exact placement depends on mission configuration.
---
## How players influence the mission
- Build air defenses (SAM/AAA): Protect friendly FARPs/FOBs and deny enemy air.
- Deploy armor and ATGM teams: Push objectives, ambush enemy convoys, or hold key terrain.
- Build EWR/JTAC: Improve situational awareness and targeting support.
- Establish FOBs: Create forward supply hubs to shorten flight times and increase the tempo of logistics.
- Rescue MEDEVAC crews: Save downed vehicle crews, earn salvage points, and keep friendly vehicles in the fight.
[screenshot: Example built SAM site]
Practical tip: Coordinate. One player can shuttle crates while others escort or build. FOBs multiply everyone's effectiveness.
---
## MEDEVAC & Salvage System (Player Operations Guide)
The MEDEVAC (Medical Evacuation) and Salvage system adds a high-stakes rescue mission layer to logistics. When friendly ground vehicles are destroyed, their crews may survive and call for rescue. Successfully rescuing and delivering these crews to MASH zones earns your coalition Salvage Points—a critical resource that keeps logistics flowing even when supply zones run dry.
### What is MEDEVAC?
- **Vehicle destruction triggers rescue missions**: When a friendly ground vehicle (tank, APC, AA vehicle, etc.) is destroyed, the crew has a chance to survive and spawn near the wreck.
- **Time-limited rescue window**: Crews have a limited time (typically 60 minutes) to be rescued. If no one comes, they're KIA and the vehicle is permanently lost.
- **Coalition-wide benefit**: Any helicopter pilot can attempt the rescue. Successful delivery to MASH earns salvage points for the entire coalition.
### How the rescue workflow works
1. **Vehicle destroyed → Crew spawns** (after a delay, typically 5 minutes to let the battle clear)
- Crew spawns near the wreck with a small offset toward the nearest enemy
- Invulnerability period during announcement (crews can't be killed immediately)
- MEDEVAC request broadcast to coalition with grid coordinates and salvage value
- Map marker created (if enabled) showing location and time remaining
2. **Navigate to crew location**
- Use Operations → MEDEVAC → Vectors to Nearest MEDEVAC for bearing and range
- Or check Navigation → Vectors to Nearest MEDEVAC Crew
- Crews pop smoke when they detect approaching helicopters (typically within 8 km)
- Watch for humorous greeting messages when you get close!
3. **Load the crew**
- Hover nearby and load troops normally (Operations → Troop Transport → Load Troops)
- System automatically detects MEDEVAC crew and marks them as rescued
- **Original vehicle respawns at its death location** (if enabled), fully repaired and ready to fight
- You'll see a confirmation message with crew size and salvage value
4. **Deliver to MASH zone**
- Fly to any friendly MASH (Mobile Army Surgical Hospital) zone
- Use Operations → MEDEVAC → MASH Locations or Navigation → Vectors to Nearest MASH
- Deploy troops inside the MASH zone (Operations → Troop Transport → Deploy)
- **Salvage points automatically awarded** to your coalition
- Coalition-wide message announces the delivery, points earned, and new total
### Warning system
The mission keeps you informed of time-critical rescues:
- **15-minute warning**: "WARNING: [vehicle] crew at [grid] - rescue window expires in 15 minutes!"
- **5-minute warning**: "URGENT: [vehicle] crew at [grid] - rescue window expires in 5 minutes!"
- **Timeout**: If rescue window expires, crew is KIA and vehicle is permanently lost
### MASH Zones (Mobile Army Surgical Hospital)
**Fixed MASH zones** are pre-configured by the mission maker at friendly bases or FARPs. These are always active and visible on the map (use Admin/Help → Draw CTLD Zones to see them).
**Mobile MASH** can be built by players using MASH crates from the logistics catalog:
- Request and build Mobile MASH crates like any other unit
- Creates a new delivery zone with radio beacon
- Perfect for forward operations near active combat zones
- Multiple mobile MASHs can be deployed to reduce delivery times
- If destroyed, that MASH zone stops accepting deliveries
### Salvage Points: The economic engine
**Earning salvage**:
- Each vehicle type has a salvage value (typically 1 point per crew member)
- Deliver crews to MASH to earn points for your coalition
- Coalition-wide pool: everyone benefits from everyone's rescues
**Using salvage**:
- When you request crates and the supply zone is OUT OF STOCK, salvage automatically applies (if enabled)
- System consumes salvage points equal to the item's cost
- Lets you build critical items even when supply lines are exhausted
- Check current balance: Operations → MEDEVAC → Coalition Salvage Points
**Strategic value**:
- High-value vehicles (tanks, AA systems) typically award more salvage
- Prioritize rescues based on salvage value and proximity
- Mobile MASH deployment near combat zones multiplies salvage income
- Salvage can unlock mission-critical capabilities when inventory runs low
### Crew survival mechanics (mission-configurable)
- **Survival chance**: Configurable per coalition (default ~50%). Not every destroyed vehicle spawns a crew.
- **MANPADS chance**: Some crew members may spawn with anti-air weapons (default ~10%), providing limited self-defense
- **Crew size**: Varies by vehicle type (catalog-defined). Tanks typically have 3-4 crew, APCs 2-3.
- **Crew defense**: Crews will return fire if engaged during rescue (can be disabled)
- **Invulnerability**: Crews are typically immortal during the announcement delay and often remain protected until rescue to prevent instant death
### Best practices for MEDEVAC operations
1. **Monitor requests actively**: Use Operations → MEDEVAC → List Active MEDEVAC Requests to see all pending missions
2. **Prioritize by value and time**: High salvage + low time remaining = top priority
3. **Deploy Mobile MASH forward**: Reduce delivery time by placing MASH near active combat zones
4. **Coordinate with team**: Share MEDEVAC locations. One player can rescue while another delivers to MASH.
5. **Use smoke marking**: Operations → MEDEVAC → Pop Smoke at Crew Locations marks all crews with smoke
6. **Check salvage before major operations**: Know your coalition's salvage balance before pushing objectives
7. **Risk assessment**: Don't sacrifice your aircraft for low-value rescues in hot zones. Dead rescuer = no rescue.
### MEDEVAC menu quick reference (Operations → MEDEVAC)
- **List Active MEDEVAC Requests**: Overview of all pending rescues (grid, vehicle type, time left)
- **Nearest MEDEVAC Location**: Quick bearing/range to closest crew
- **Vectors to Nearest MEDEVAC**: Detailed navigation info with time remaining
- **Coalition Salvage Points**: Check current balance
- **MASH Locations**: Shows all active MASH zones (fixed and mobile)
- **Pop Smoke at Crew Locations**: Visual marking for all active crews
- **Pop Smoke at MASH Zones**: Visual marking for all delivery zones
- **MASH & Salvage System - Guide**: In-game reference (same content available in Admin/Help → Player Guides)
### MEDEVAC statistics (if enabled)
Some missions track detailed statistics available via Admin/Help → Show MEDEVAC Statistics:
- Crews spawned, rescued, delivered to MASH
- Timed out and killed in action
- Vehicles respawned
- Salvage earned, used, and current balance
[screenshot: MEDEVAC request message with grid coordinates]
[screenshot: Operations → MEDEVAC menu]
[screenshot: Mobile MASH deployed with beacon]
---
## How players influence the mission
- Build air defenses (SAM/AAA): Protect friendly FARPs/FOBs and deny enemy air.
- Deploy armor and ATGM teams: Push objectives, ambush enemy convoys, or hold key terrain.
- Build EWR/JTAC: Improve situational awareness and targeting support.
- Establish FOBs: Create forward supply hubs to shorten flight times and increase the tempo of logistics.
- Rescue MEDEVAC crews: Save downed vehicle crews, earn salvage points, and keep friendly vehicles in the fight.
[screenshot: Example built SAM site]
Practical tip: Coordinate. One player can shuttle crates while others escort or build. FOBs multiply everyone's effectiveness.
---
## Mission setup (for mission makers)
Keep this section short and focused. You can find the defaults and toggles inside:
- `Moose_CTLD_Pure/Moose_CTLD.lua` (main CTLD implementation; see the `CTLD.Config` table)
- `Moose_CTLD_Pure/Moose_CTLD_FAC.lua` (optional FAC/RECCE support)
- `Moose_CTLD_Pure/catalogs/` (example catalogs with ready-to-use recipes)
- `Moose_CTLD_Pure/init_mission_dual_coalition.lua` (ready-to-use minimal init for BLUE+RED)
### Load order (Do Script File in Mission Editor)
1) `Moose.lua`
2) `Moose_CTLD.lua`
3) A catalog file from `/catalogs/`
4) `Moose_CTLD_FAC.lua` (optional FAC/RECCE)
5) Your mission init block (you can use `Moose_CTLD_Pure/init_mission_dual_coalition.lua` as-is or adapt it)
<img width="390" height="170" alt="image" src="https://github.com/user-attachments/assets/fd468f5c-5240-47f0-8603-a7996e20ba7e" />
Minimal snippet (example) — keep it to the point:
- Create a CTLD instance per coalition with: CoalitionSide, AllowedAircraft, Zones (Pickup/Drop/FOB definitions), and key toggles.
- Optionally create a FAC module instance and run it.
- Optionally merge a crate catalog.
Hint: See the shipped `init_mission_dual_coalition.lua` for a clean example of both BLUE and RED.
### Zones you must create in the Mission Editor
- Pickup (Supply): e.g., `ALPHA` (BLUE), `DELTA` (RED)
- Drop: e.g., `BRAVO` (BLUE), `ECHO` (RED)
- FOB: e.g., `CHARLIE` (BLUE), `FOXTROT` (RED)
- MASH (optional, for MEDEVAC): e.g., `MASH_BLUE_1`, `MASH_RED_1` (accepts crew deliveries for salvage points)
Use the names referenced by your init script. The example init uses flags to control active/inactive state.
[screenshot: Trigger zones for Pickup/Drop/FOB/MASH]
### Frequently configured options (where to change)
All of the following live under `CTLD.Config` in `Moose_CTLD.lua` or can be provided in the table passed to `_MOOSE_CTLD:New({...})` in your init script.
- Logistics rules
- `RequirePickupZoneForCrateRequest`: Enforce being near an ACTIVE Supply Zone to request crates
- `RequirePickupZoneForTroopLoad`: Enforce being inside a Supply Zone to load troops
- `PickupZoneMaxDistance`: Max distance to the nearest ACTIVE zone for crate requests
- `ForbidDropsInsidePickupZones`: Block dropping crates inside Supply Zones
- `ForbidTroopDeployInsidePickupZones`: Block troop deployment inside Supply Zones
- `ForbidChecksActivePickupOnly`: If true, restrictions apply only to ACTIVE zones
- Building behavior
- `BuildRadius`: How far to search for crates around the player when building
- `BuildSpawnOffset`: Push spawn a few meters ahead of the aircraft to avoid collisions
- `BuildConfirmEnabled` + `BuildConfirmWindowSeconds`: Double-press safety to prevent accidental builds
- `BuildCooldownEnabled` + `BuildCooldownSeconds`: Per-group cooldown after a successful build
- `RestrictFOBToZones`: When true, FOB-only builds must occur inside an FOB Zone
- `AutoBuildFOBInZones`: When true, crates for FOBs inside an FOB Zone can auto-build
- Inventory system (per-zone stock)
- `Inventory.Enabled`: Track stock per Supply Zone and FOB
- `Inventory.ShowStockInMenu`: Show counts in menu labels
- `Inventory.HideZeroStockMenu`: Enable the special “In Stock Here” menu at nearest zone
- `Inventory.FOBStockFactor`: % of initial stock seeded when a new FOB is built
- Hover & pickup quality-of-life
- `HoverCoachConfig`: Message timing and thresholds for the in-game hover guidance
- `TroopSpawnOffset`: Spawn troops slightly forward to avoid overlaps
- AI behavior for Attack builds
- `AttackAI.VehicleSearchRadius`: How far spawned vehicles look for enemies when ordered to Attack
- `AttackAI.MoveSpeedKmh`: Movement speed for Attack orders
- MEDEVAC & Salvage system (optional feature)
- `MEDEVAC.Enabled`: Master switch for the rescue/salvage system
- `MEDEVAC.CrewSurvivalChance`: Per-coalition probability that destroyed vehicle crews survive (0.0-1.0)
- `MEDEVAC.ManPadSpawnChance`: Probability crews spawn with MANPADS for self-defense
- `MEDEVAC.CrewSpawnDelay`: Seconds after death before crew spawns (allows battle to clear)
- `MEDEVAC.CrewTimeout`: Max time for rescue before crew is KIA (default 3600 = 1 hour)
- `MEDEVAC.CrewImmortalDuringDelay`: Invulnerability during announcement delay
- `MEDEVAC.PopSmokeOnApproach`: Auto-smoke when helos get close (default true)
- `MEDEVAC.RespawnOnPickup`: Original vehicle respawns when crew is rescued (default true)
- `MEDEVAC.Salvage.Enabled`: Enable salvage points economy
- `MEDEVAC.Salvage.AutoApply`: Auto-use salvage for out-of-stock items (default true)
- `MEDEVAC.MapMarkers.Enabled`: Create F10 map markers for active MEDEVAC requests
- `Zones.MASHZones`: Configure fixed MASH delivery zones (Mobile MASH can be built by players)
- Menus
- `UseGroupMenus`: Per-group F10 menus (recommended)
- `UseCategorySubmenus`: Organize Request Crate/Recipe Info by category
- `PickupZoneSmokeColor`: Color for crate spawn smoke marks
### Crate catalog (recipes)
- Use one of the provided catalogs under `Moose_CTLD_Pure/catalogs/` or your own.
- Each entry defines a display label, side, category, stock, and a build function.
- Multi-crate “SITE” entries build multi-unit groups (SAM sites or composite systems).
- Typical workflow
- Load your chosen catalog after `Moose_CTLD.lua`.
- Merge it into each CTLD instance you created.
[screenshot: Request Crate categories]
### Dual-coalition setup
- Instantiate two CTLD instances (one per side), each with its own zone names and smoke colors.
- Instantiate two FAC modules if you want auto-lase/RECCE for both sides.
- The included `init_mission_dual_coalition.lua` shows a minimal working setup.
### FAC/RECCE (optional, from `Moose_CTLD_FAC.lua`)
- What it adds
- Auto-lase with configurable laser codes, IR markers, map marks
- Manual target lists, quick multi-strike helper
- Artillery/Naval/Air tasking (HE/illum/mortar, carpet/TALD prompts)
- RECCE sweeps: detects and marks units with DMS/MGRS
- Player usage
- Look for an F10 FAC/RECCE menu in qualifying aircraft or groups
- Mission knobs
- CoalitionSide, auto-lase behavior, code reservations, marker type/color, and on-station logic are configurable in `Moose_CTLD_FAC.lua` or via `:New()` overrides
### Sanity checks and troubleshooting
- Use Admin/Help -> Show CTLD Status to verify counts and toggles quickly.
- Draw zones to confirm names/positions match your intent.
- If crates dont spawn: check zone active state, distance to zone, and inventory stock.
- If builds dont trigger: check Build Radius, confirm window, cooldown, and that the crates match the recipe.
---
## Screenshot ideas (drop your captures in the placeholders above)
- CTLD root menu with the five groups (Operations, Logistics, Field Tools, Navigation, Admin/Help)
- Request Crate with category submenus visible
- Build (Advanced) -> Buildable Near You list
- Hover Coach prompt during a near-perfect hover
- Vectors message to a crate / pickup zone
- Zone drawings on the F10 map (Pickup/Drop/FOB labeled)
- In Stock Here list (if enabled)
- Example SAM site placed after a build
---
## Appendix: File locations and names
- Main CTLD: `Moose_CTLD_Pure/Moose_CTLD.lua`
- FAC/RECCE: `Moose_CTLD_Pure/Moose_CTLD_FAC.lua`
- Example dual-coalition init: `Moose_CTLD_Pure/init_mission_dual_coalition.lua`
- Catalogs: `Moose_CTLD_Pure/catalogs/`
No large code is required; most options are cleanly exposed in the config tables. Keep snippets tiny when needed.

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-16"?>
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>DCS CTLD Menu Navigation</Name>
<Id>a8f7c9d2-4e6b-4c1a-9f3e-2a8d7c6b5e4f</Id>
<Commands>
<Command>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c0d</Id>
<CommandString>load troops</CommandString>
<ActionSequence>
<PressKey>
<KeyCodes>{RALT}\{F2}{F1}{F1}</KeyCodes>
</PressKey>
</ActionSequence>
</Command>
<Command>
<Id>4b8c9d0e-1f2a-3b4c-5d6e-7f8a9b0c1d2e</Id>
<CommandString>show status;ctld status;check status</CommandString>
<ActionSequence>
<PressKey>
<KeyCodes>{RALT}\{F5}{F2}</KeyCodes>
</PressKey>
</ActionSequence>
</Command>
</Commands>
</Profile>

View File

@ -1,266 +0,0 @@
# DCS CTLD Voice Attack Profile Guide
## Overview
This Voice Attack profile provides voice command navigation for the Moose CTLD (Combat Troop and Logistics Deployment) menu system in DCS World. All commands use direct navigation - saying the command automatically navigates through the entire F10 menu path.
## Installation
### 1. Import the Profile
1. Open Voice Attack
2. Click the wrench icon (Edit Profile)
3. Click "Import Profile"
4. Navigate to `CTLD_VoiceAttack_Profile.xml`
5. Select the profile and click OK
### 2. DCS Key Binding (No Configuration Needed!)
The profile uses **Right Alt + Backslash** (`RAlt + \`) which works in all situations:
- **On the ground:** Backslash `\` alone opens F10, but `RAlt + \` also works
- **In the air:** Only `RAlt + \` works (backslash alone is disabled)
The profile uses `RAlt + \` for all commands, ensuring compatibility both on ground and in air.
**No DCS configuration changes needed** - this is the default binding!
## F10 Key Binding
### How DCS F10 Menu Works
- **On ground:** Backslash `\` key opens F10 menu
- **In the air:** `\` is disabled, must use `Right Alt + \`
### Voice Attack Profile
All commands use **`RAlt + \`** which works in both situations:
```
"load troops" → RAlt + \ + F2 + F1 + F1
"build here" → RAlt + \ + F2 + F2 + F1
"vectors to pickup" → RAlt + \ + F4 + F2
```
This ensures voice commands work whether you're on the ground or flying!
## Command Reference
### OPERATIONS: Troop Transport
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "load troops" | Load troops at supply zone | Operations → Troop Transport → Load Troops |
| "deploy troops"<br>"deploy hold"<br>"deploy defend" | Deploy troops in defensive posture | Operations → Troop Transport → Deploy [Hold Position] |
| "deploy attack"<br>"troops attack" | Deploy troops with attack orders | Operations → Troop Transport → Deploy [Attack] |
### OPERATIONS: Build
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "build here"<br>"build at position" | Build collected crates at location | Operations → Build → Build Here |
| "refresh buildable list"<br>"refresh build list" | Update list of buildable items | Operations → Build → Refresh Buildable List |
### OPERATIONS: MEDEVAC (if enabled)
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "list medevac"<br>"active medevac requests" | Show all active MEDEVAC missions | Operations → MEDEVAC → List Active MEDEVAC Requests |
| "nearest medevac location"<br>"medevac location" | Show nearest MEDEVAC crew location | Operations → MEDEVAC → Nearest MEDEVAC Location |
| "salvage points"<br>"check salvage" | Display coalition salvage points | Operations → MEDEVAC → Coalition Salvage Points |
| "vectors to medevac"<br>"medevac vectors" | Get bearing/range to nearest crew | Operations → MEDEVAC → Vectors to Nearest MEDEVAC |
| "mash locations"<br>"show mash" | List all MASH zones | Operations → MEDEVAC → MASH Locations |
| "smoke crew locations"<br>"mark crews" | Pop smoke at MEDEVAC crew positions | Operations → MEDEVAC → Pop Smoke at Crew Locations |
| "smoke mash zones"<br>"mark mash" | Pop smoke at MASH delivery zones | Operations → MEDEVAC → Pop Smoke at MASH Zones |
### LOGISTICS: Crate Management
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "drop one crate"<br>"drop crate" | Drop single loaded crate | Logistics → Crate Management → Drop One Loaded Crate |
| "drop all crates"<br>"drop cargo" | Drop all loaded crates | Logistics → Crate Management → Drop All Loaded Crates |
| "mark nearest crate"<br>"smoke crate"<br>"remark crate" | Re-mark closest crate with smoke | Logistics → Crate Management → Re-mark Nearest Crate |
| "show inventory"<br>"check inventory"<br>"zone inventory" | Display zone inventory | Logistics → Show Inventory at Nearest Zone |
### FIELD TOOLS
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "create drop zone"<br>"mark drop zone" | Create new drop zone at position | Field Tools → Create Drop Zone (AO) |
| "smoke green"<br>"green smoke" | Pop green smoke at location | Field Tools → Smoke My Location → Green |
| "smoke red"<br>"red smoke" | Pop red smoke at location | Field Tools → Smoke My Location → Red |
| "smoke white"<br>"white smoke" | Pop white smoke at location | Field Tools → Smoke My Location → White |
| "smoke orange"<br>"orange smoke" | Pop orange smoke at location | Field Tools → Smoke My Location → Orange |
| "smoke blue"<br>"blue smoke" | Pop blue smoke at location | Field Tools → Smoke My Location → Blue |
### NAVIGATION
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "vectors to crate"<br>"find crate"<br>"nearest crate" | Get bearing/range to nearest crate | Navigation → Request Vectors to Nearest Crate |
| "vectors to pickup"<br>"find pickup zone"<br>"nearest pickup" | Get bearing/range to pickup zone | Navigation → Vectors to Nearest Pickup Zone |
| "smoke nearest zone"<br>"mark nearest zone" | Smoke closest zone (any type) | Navigation → Smoke Nearest Zone |
| "smoke all zones"<br>"mark all zones"<br>"smoke nearby zones" | Smoke all zones within 5km | Navigation → Smoke All Nearby Zones (5km) |
| "vectors to mash"<br>"find mash"<br>"nearest mash" | Get bearing/range to MASH | Navigation → Vectors to Nearest MASH |
| "enable hover coach"<br>"hover coach on" | Enable hover pickup guidance | Navigation → Hover Coach: Enable |
| "disable hover coach"<br>"hover coach off" | Disable hover pickup guidance | Navigation → Hover Coach: Disable |
### STATUS & ADMIN
| Voice Command | Action | Menu Path |
|--------------|--------|-----------|
| "show status"<br>"ctld status"<br>"check status" | Display CTLD system status | Admin/Help → Show CTLD Status |
| "draw zones on map"<br>"show zones"<br>"mark zones on map" | Draw all zones on F10 map | Admin/Help → Draw CTLD Zones on Map |
| "clear map drawings"<br>"clear map marks"<br>"remove zone marks" | Remove zone drawings from map | Admin/Help → Clear CTLD Map Drawings |
| "medevac statistics"<br>"medevac stats"<br>"show medevac stats" | Display MEDEVAC statistics | Admin/Help → Show MEDEVAC Statistics |
### QUICK ACCESS COMMANDS
These are alternate phrases for commonly used functions:
| Voice Command | Equivalent To |
|--------------|---------------|
| "quick pickup"<br>"pickup mode" | "load troops" |
| "quick deploy"<br>"fast deploy" | "deploy troops" |
| "quick build"<br>"fast build" | "build here" |
## Usage Tips
### 1. Voice Recognition Accuracy
- Speak clearly and at normal volume
- Pause briefly between words for best recognition
- If a command doesn't work, try an alternate phrase
- Train Voice Attack with your voice for better accuracy
### 2. Menu Navigation Timing
- Commands execute instantly with no delays
- DCS menu system is fast - no need to wait between commands
- If you're in a different menu, the command will navigate from wherever you are
### 3. Common Workflows
**Troop Transport Mission:**
1. "vectors to pickup" (find supply zone)
2. "load troops" (board passengers)
3. Fly to destination
4. "deploy hold" or "deploy attack" (unload with orders)
**Crate Logistics Mission:**
1. "vectors to pickup" (find supply zone)
2. Use manual F10 menu to request specific crates
3. "vectors to crate" (find spawned crate)
4. Pick up crate
5. "build here" (deploy at destination)
**MEDEVAC Mission:**
1. "list medevac" (check active requests)
2. "vectors to medevac" (find nearest crew)
3. Pick up crew (auto-load when landed nearby)
4. "vectors to mash" (find hospital)
5. Deploy at MASH (auto-unload)
6. "salvage points" (check rewards)
**Reconnaissance:**
1. "smoke all zones" (mark nearby objectives)
2. "draw zones on map" (see all zones on F10)
3. "vectors to pickup" (return to base)
4. "clear map drawings" (clean up map)
### 4. Combat Situations
Voice commands work best when:
- ✓ Flying stable (not in combat maneuvers)
- ✓ Hands free for flight controls
- ✓ Clear of radio chatter/background noise
- ✗ Not recommended during combat or emergency procedures
### 5. Request Crate Limitation
**Note:** The profile does NOT include voice commands for requesting specific crate types because:
- There are dozens of crate types (vehicles, SAMs, FOBs, etc.)
- Categories vary by mission configuration
- Manual F10 navigation (F2 → Logistics → Request Crate) is more practical
Use voice commands for navigation/status, manual F10 for crate requests.
## Troubleshooting
### Command Not Recognized
1. Check Voice Attack is running and profile is active
2. Train Voice Attack with your voice (Tools → Train Profile)
3. Try alternate phrases for the command
4. Verify microphone input levels
### Wrong Menu Opens
1. Verify DCS is using default key bindings (RAlt + \ for F10)
2. Check that backslash key isn't rebound in DCS controls
3. Try manual RAlt + \ to verify F10 menu opens
### Command Works But Menu Doesn't Navigate
1. Verify DCS is the active window
2. Check F10 menu is not already open
3. Ensure no other key bindings conflict with F-keys
4. Try manual navigation to verify menu structure matches profile
### MEDEVAC Commands Not Available
- These commands only work if MEDEVAC system is enabled in the mission
- Check mission briefing or use "show status" to verify MEDEVAC is active
## Profile Customization
### Adding New Commands
1. Open Voice Attack profile editor
2. Click "New Command"
3. Set "When I say" to your phrase
4. Add Action: "Send keys to active window"
5. Enter key sequence (e.g., `{RALT}{F2}{F1}{F1}`)
6. Save command
### Modifying Existing Commands
1. Find command in list
2. Click "Edit"
3. Modify "When I say" phrases
4. Update key sequence if menu structure changed
5. Save changes
### Key Sequence Format
- `{RALT}` = Right Alt key
- `\\` = Backslash key (escaped in XML)
- `{F1}` through `{F9}` = Function keys
- Example: `{RALT}\\{F2}{F3}{F1}` = RAlt, \, F2, F3, F1 in sequence
## Menu Structure Reference
```
CTLD (Root - F2)
├── F1: Operations
│ ├── F1: Troop Transport
│ ├── F2: Build
│ └── F3: MEDEVAC
├── F2: Logistics
│ ├── F1: Request Crate
│ ├── F2: Recipe Info
│ ├── F3: Crate Management
│ └── F4: Show Inventory
├── F3: Field Tools
├── F4: Navigation
└── F5: Admin/Help
```
See full menu tree diagram in main documentation.
## Version Information
- **Profile Version:** 1.0
- **CTLD Version:** 0.1.0-alpha (Moose_CTLD_Pure)
- **Voice Attack Version:** 1.8+ (tested on 1.10)
- **DCS Version:** Compatible with current stable/open beta
## Support & Updates
If the menu structure changes in future CTLD updates:
1. Check `Moose_CTLD.lua` function `BuildGroupMenus()` (around line 2616)
2. Update key sequences in Voice Attack profile
3. Test each command to verify navigation
## Credits
- **CTLD System:** Moose_CTLD_Pure custom implementation
- **Voice Attack:** VoiceAttack by VoiceAttack.com
- **DCS World:** Eagle Dynamics
---
**Happy Flying! 🚁**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,587 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>CTLD VoiceAttack Profile &mdash; Command Reference</title>
<style>
:root {
color-scheme: light dark;
--bg: #0f141a;
--bg-alt: #162029;
--fg: #f0f3f6;
--fg-muted: #c8d2dd;
--accent: #2f8dda;
--accent-soft: rgba(47, 141, 218, 0.14);
--border: rgba(240, 243, 246, 0.14);
--border-strong: rgba(240, 243, 246, 0.28);
}
body {
margin: 0;
font-family: "Segoe UI", "Roboto", sans-serif;
font-size: 15px;
line-height: 1.6;
background: var(--bg);
color: var(--fg);
}
main {
margin: 0 auto;
padding: 48px 32px 64px;
max-width: 1180px;
}
header {
position: sticky;
top: 0;
margin: -48px -32px 36px;
padding: 36px 32px 24px;
background: linear-gradient(160deg, rgba(47, 141, 218, 0.35), rgba(15, 20, 26, 0.0));
border-bottom: 1px solid var(--border);
backdrop-filter: blur(10px);
}
h1 {
margin: 0 0 4px;
font-size: 30px;
letter-spacing: 0.02em;
}
h2 {
margin-top: 44px;
margin-bottom: 12px;
font-size: 22px;
color: var(--accent);
}
p.lead {
margin: 8px 0 16px;
color: var(--fg-muted);
max-width: 880px;
}
.callout {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 12px;
padding: 18px 22px;
margin-bottom: 28px;
box-shadow: 0 16px 32px rgba(0, 0, 0, 0.22);
}
.callout strong {
color: var(--accent);
}
table {
width: 100%;
border-collapse: collapse;
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.18);
}
thead {
background: rgba(47, 141, 218, 0.18);
color: var(--fg);
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 12px;
}
th, td {
padding: 14px 18px;
vertical-align: top;
border-bottom: 1px solid var(--border);
}
tbody tr:last-child td {
border-bottom: none;
}
tbody tr:nth-child(odd) {
background: rgba(255, 255, 255, 0.02);
}
code {
font-family: "Cascadia Code", "Fira Code", monospace;
font-size: 13px;
background: rgba(255, 255, 255, 0.04);
padding: 2px 6px;
border-radius: 6px;
border: 1px solid var(--border);
}
ul {
padding-left: 22px;
margin: 0;
}
.phrases span {
display: inline-block;
background: var(--accent-soft);
color: var(--accent);
border: 1px solid rgba(47, 141, 218, 0.35);
border-radius: 999px;
padding: 4px 12px;
margin: 2px 6px 2px 0;
font-size: 13px;
}
footer {
margin-top: 64px;
font-size: 13px;
color: var(--fg-muted);
border-top: 1px solid var(--border);
padding-top: 18px;
}
@media (max-width: 900px) {
main {
padding: 36px 18px 48px;
}
header {
margin: -36px -18px 24px;
padding: 28px 18px 18px;
}
table, thead, tbody, th, td, tr {
display: block;
}
thead {
display: none;
}
tbody tr {
margin-bottom: 18px;
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
}
td {
border: none;
border-bottom: 1px solid var(--border);
}
td::before {
content: attr(data-label);
display: block;
font-weight: 600;
margin-bottom: 6px;
color: var(--accent);
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 11px;
}
tbody tr:last-child td {
border-bottom: none;
}
}
</style>
</head>
<body>
<main>
<header>
<h1>CTLD VoiceAttack Command Reference</h1>
<p class="lead">All phrases below assume the VoiceAttack profile sends <code>Right&nbsp;Alt&nbsp;+&nbsp;Backslash</code> to open the radio menu, then <code>F10 &gt; F2</code> to enter the CTLD root. Speak any phrase shown to run the navigation sequence automatically.</p>
</header>
<section class="callout">
<strong>Pro Tip:</strong> Fine-tune the pause durations inside VoiceAttack if your DCS instance needs more/less time for menus to populate. You can also add your own synonyms by editing the command string list for any entry.
</section>
<h2>Operations &mdash; Troop Transport</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>load troops</span>
<span>load infantry</span>
</td>
<td data-label="Action">Load default troop package.</td>
<td data-label="Menu Path">Operations → Troop Transport → Load Troops</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>load assault squad</span>
<span>load assault team</span>
</td>
<td data-label="Action">Load Assault Squad preset (AS).</td>
<td data-label="Menu Path">Operations → Troop Transport → Load Troops (Type) → Assault Squad</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>load manpads team</span>
<span>load aa squad</span>
</td>
<td data-label="Action">Load MANPADS Team preset (AA).</td>
<td data-label="Menu Path">Operations → Troop Transport → Load Troops (Type) → MANPADS Team</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>load anti tank team</span>
<span>load at squad</span>
</td>
<td data-label="Action">Load Anti-Tank Team preset (AT).</td>
<td data-label="Menu Path">Operations → Troop Transport → Load Troops (Type) → AT Team</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>load mortar team</span>
<span>load mortar squad</span>
</td>
<td data-label="Action">Load Mortar Team preset (AR).</td>
<td data-label="Menu Path">Operations → Troop Transport → Load Troops (Type) → Mortar Team</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>deploy troops hold</span>
<span>deploy hold</span>
</td>
<td data-label="Action">Unload troops with Hold/Defend behavior.</td>
<td data-label="Menu Path">Operations → Troop Transport → Deploy [Hold Position]</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>deploy troops attack</span>
<span>deploy attack</span>
</td>
<td data-label="Action">Unload troops with Attack/Advance behavior.</td>
<td data-label="Menu Path">Operations → Troop Transport → Deploy [Attack]</td>
</tr>
</tbody>
</table>
<h2>Operations &mdash; Build</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>build here</span>
<span>build at position</span>
</td>
<td data-label="Action">Build using nearby crates (with confirm/cooldown rules).</td>
<td data-label="Menu Path">Operations → Build → Build Here</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>open build advanced</span>
<span>build advanced menu</span>
</td>
<td data-label="Action">Open the dynamic build menu.</td>
<td data-label="Menu Path">Operations → Build → Build (Advanced)</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>open buildable near you</span>
<span>show buildable list</span>
</td>
<td data-label="Action">Focus the “Buildable Near You” submenu.</td>
<td data-label="Menu Path">Operations → Build → Build (Advanced) → Buildable Near You</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>refresh build list</span>
<span>refresh buildable list</span>
</td>
<td data-label="Action">Rescan crate availability for builds.</td>
<td data-label="Menu Path">Operations → Build → Refresh Buildable List</td>
</tr>
</tbody>
</table>
<h2>Operations &mdash; MEDEVAC</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>list medevac requests</span>
<span>active medevac</span>
</td>
<td data-label="Action">Show all active MEDEVAC crews.</td>
<td data-label="Menu Path">Operations → MEDEVAC → List Active MEDEVAC Requests</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>nearest medevac location</span>
<span>medevac location</span>
</td>
<td data-label="Action">Display nearest crew position.</td>
<td data-label="Menu Path">Operations → MEDEVAC → Nearest MEDEVAC Location</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>check salvage points</span>
<span>show salvage</span>
</td>
<td data-label="Action">Report coalition salvage totals.</td>
<td data-label="Menu Path">Operations → MEDEVAC → Coalition Salvage Points</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>vectors to medevac</span>
<span>medevac vectors</span>
</td>
<td data-label="Action">Provide bearing/range to nearest crew.</td>
<td data-label="Menu Path">Operations → MEDEVAC → Vectors to Nearest MEDEVAC</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>show mash locations</span>
<span>list mash</span>
</td>
<td data-label="Action">List all MASH delivery zones.</td>
<td data-label="Menu Path">Operations → MEDEVAC → MASH Locations</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke crew locations</span>
<span>mark crews</span>
</td>
<td data-label="Action">Drop smoke on every active crew.</td>
<td data-label="Menu Path">Operations → MEDEVAC → Pop Smoke at Crew Locations</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke mash zones</span>
<span>mark mash</span>
</td>
<td data-label="Action">Drop smoke on all MASH zones.</td>
<td data-label="Menu Path">Operations → MEDEVAC → Pop Smoke at MASH Zones</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>medevac guide</span>
<span>salvage guide</span>
</td>
<td data-label="Action">Show in-game MEDEVAC/salvage quick reference.</td>
<td data-label="Menu Path">Operations → MEDEVAC → MASH &amp; Salvage System Guide</td>
</tr>
</tbody>
</table>
<h2>Logistics</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>open request crate</span>
<span>request crate menu</span>
</td>
<td data-label="Action">Open the crate request submenu (choose item manually).</td>
<td data-label="Menu Path">Logistics → Request Crate</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>open recipe info</span>
<span>recipe info menu</span>
</td>
<td data-label="Action">Open recipe info submenu.</td>
<td data-label="Menu Path">Logistics → Recipe Info</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>drop one crate</span>
<span>drop crate</span>
</td>
<td data-label="Action">Drop a single loaded crate.</td>
<td data-label="Menu Path">Logistics → Crate Management → Drop One Loaded Crate</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>drop all crates</span>
<span>drop cargo</span>
</td>
<td data-label="Action">Drop every loaded crate.</td>
<td data-label="Menu Path">Logistics → Crate Management → Drop All Loaded Crates</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>remark nearest crate</span>
<span>smoke crate</span>
</td>
<td data-label="Action">Smoke the nearest friendly crate.</td>
<td data-label="Menu Path">Logistics → Crate Management → Re-mark Nearest Crate (Smoke)</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>show zone inventory</span>
<span>check inventory</span>
</td>
<td data-label="Action">Show stock at nearest supply/FOB zone.</td>
<td data-label="Menu Path">Logistics → Show Inventory at Nearest Zone</td>
</tr>
</tbody>
</table>
<h2>Field Tools</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>create drop zone</span>
<span>mark drop zone</span>
</td>
<td data-label="Action">Create a player drop zone (AO).</td>
<td data-label="Menu Path">Field Tools → Create Drop Zone (AO)</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke green</span>
<span>green smoke</span>
</td>
<td data-label="Action">Drop green smoke at your position.</td>
<td data-label="Menu Path">Field Tools → Smoke My Location → Green</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke red</span>
<span>red smoke</span>
</td>
<td data-label="Action">Drop red smoke at your position.</td>
<td data-label="Menu Path">Field Tools → Smoke My Location → Red</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke white</span>
<span>white smoke</span>
</td>
<td data-label="Action">Drop white smoke at your position.</td>
<td data-label="Menu Path">Field Tools → Smoke My Location → White</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke orange</span>
<span>orange smoke</span>
</td>
<td data-label="Action">Drop orange smoke at your position.</td>
<td data-label="Menu Path">Field Tools → Smoke My Location → Orange</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke blue</span>
<span>blue smoke</span>
</td>
<td data-label="Action">Drop blue smoke at your position.</td>
<td data-label="Menu Path">Field Tools → Smoke My Location → Blue</td>
</tr>
</tbody>
</table>
<h2>Navigation &amp; Hover Coach</h2>
<table>
<thead>
<tr>
<th scope="col">Phrases</th>
<th scope="col">Action</th>
<th scope="col">Menu Path</th>
</tr>
</thead>
<tbody>
<tr>
<td class="phrases" data-label="Phrases">
<span>vectors to crate</span>
<span>find crate</span>
</td>
<td data-label="Action">Show bearing/range to nearest friendly crate.</td>
<td data-label="Menu Path">Navigation → Request Vectors to Nearest Crate</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>vectors to pickup zone</span>
<span>find pickup zone</span>
</td>
<td data-label="Action">Show bearing/range to nearest supply zone.</td>
<td data-label="Menu Path">Navigation → Vectors to Nearest Pickup Zone</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke nearest zone</span>
<span>mark nearest zone</span>
</td>
<td data-label="Action">Smoke the closest zone (pickup/drop/FOB/MASH).</td>
<td data-label="Menu Path">Navigation → Smoke Nearest Zone (Pickup/Drop/FOB/MASH)</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>smoke all zones</span>
<span>mark all zones</span>
</td>
<td data-label="Action">Smoke every zone within 5&nbsp;km.</td>
<td data-label="Menu Path">Navigation → Smoke All Nearby Zones (5km)</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>vectors to medevac crew</span>
<span>find medevac crew</span>
</td>
<td data-label="Action">Show bearing/range to the nearest crew (shortcut).</td>
<td data-label="Menu Path">Navigation → Vectors to Nearest MEDEVAC Crew</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>vectors to mash</span>
<span>find mash</span>
</td>
<td data-label="Action">Show bearing/range to nearest MASH.</td>
<td data-label="Menu Path">Navigation → Vectors to Nearest MASH</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>enable hover coach</span>
<span>hover coach on</span>
</td>
<td data-label="Action">Enable hover coach prompts for this group.</td>
<td data-label="Menu Path">Navigation → Hover Coach: Enable</td>
</tr>
<tr>
<td class="phrases" data-label="Phrases">
<span>disable hover coach</span>
<span>hover coach off</span>
</td>
<td data-label="Action">Disable hover coach prompts for this group.</td>
<td data-label="Menu Path">Navigation → Hover Coach: Disable</td>
</tr>
</tbody>
</table>
<footer>
Generated for <code>CTLD_VoiceAttack_Profile_F10.vap</code> (Right Alt + Backslash → F10 → F2). Tweak phrases or delays directly inside VoiceAttack to match your mission&apos;s pace.
</footer>
</main>
</body>
</html>

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-16"?>
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>DCS CTLD Menu Navigation</Name>
<Id>a8f7c9d2-4e6b-4c1a-9f3e-2a8d7c6b5e4f</Id>
<Commands>
<!-- OPERATIONS: TROOP TRANSPORT -->
<Command>
<CommandString>load troops</CommandString>
<ActionSequence>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c0d</Id>
<ActionType>PressKey</ActionType>
<Delay>0</Delay>
<KeyCodes>
<unsignedShort>165</unsignedShort>
</KeyCodes>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c0e</Id>
<ActionType>Pause</ActionType>
<Delay>200</Delay>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c0f</Id>
<ActionType>PressKey</ActionType>
<Delay>0</Delay>
<KeyCodes>
<unsignedShort>220</unsignedShort>
</KeyCodes>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c10</Id>
<ActionType>Pause</ActionType>
<Delay>300</Delay>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c11</Id>
<ActionType>PressKey</ActionType>
<Delay>0</Delay>
<KeyCodes>
<unsignedShort>113</unsignedShort>
</KeyCodes>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c12</Id>
<ActionType>Pause</ActionType>
<Delay>300</Delay>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c13</Id>
<ActionType>PressKey</ActionType>
<Delay>0</Delay>
<KeyCodes>
<unsignedShort>112</unsignedShort>
</KeyCodes>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c14</Id>
<ActionType>Pause</ActionType>
<Delay>300</Delay>
</CommandAction>
<CommandAction>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c15</Id>
<ActionType>PressKey</ActionType>
<Delay>0</Delay>
<KeyCodes>
<unsignedShort>112</unsignedShort>
</KeyCodes>
</CommandAction>
</ActionSequence>
<Id>3a7f2b1e-8c4d-4f9a-b2e1-5d6c7a8b9c0d</Id>
</Command>
</Commands>
</Profile>

View File

@ -1,174 +0,0 @@
# CTLD Voice Attack - Quick Reference Card
## Essential Commands (Most Used)
### Troop Operations
```
"load troops" → Load troops at supply zone
"deploy hold" → Deploy troops (defensive)
"deploy attack" → Deploy troops (offensive)
```
### Logistics
```
"build here" → Build crates at position
"drop all crates" → Drop all loaded cargo
"show inventory" → Check zone stock
```
### Navigation
```
"vectors to pickup" → Find supply zone
"vectors to crate" → Find dropped crate
"smoke nearest zone" → Mark closest zone
```
### MEDEVAC (if enabled)
```
"list medevac" → Show active requests
"vectors to medevac" → Find crew
"vectors to mash" → Find hospital
"salvage points" → Check rewards
```
### Status
```
"show status" → CTLD system status
"hover coach on/off" → Toggle pickup guidance
```
---
## Full Command List
### OPERATIONS
| Command | Action |
|---------|--------|
| load troops | Board passengers |
| deploy hold / deploy defend | Unload defensive |
| deploy attack / troops attack | Unload offensive |
| build here / build at position | Build collected crates |
| refresh buildable list | Update build options |
### MEDEVAC (if enabled)
| Command | Action |
|---------|--------|
| list medevac / active medevac requests | List all missions |
| nearest medevac location | Find closest crew |
| salvage points / check salvage | Show points |
| vectors to medevac / medevac vectors | Bearing to crew |
| mash locations / show mash | List hospitals |
| smoke crew locations / mark crews | Mark crews |
| smoke mash zones / mark mash | Mark hospitals |
### LOGISTICS
| Command | Action |
|---------|--------|
| drop one crate / drop crate | Drop single crate |
| drop all crates / drop cargo | Drop all crates |
| mark nearest crate / smoke crate | Re-mark crate |
| show inventory / check inventory | Zone stock |
### FIELD TOOLS
| Command | Action |
|---------|--------|
| create drop zone / mark drop zone | New drop zone |
| smoke green / green smoke | Green smoke |
| smoke red / red smoke | Red smoke |
| smoke white / white smoke | White smoke |
| smoke orange / orange smoke | Orange smoke |
| smoke blue / blue smoke | Blue smoke |
### NAVIGATION
| Command | Action |
|---------|--------|
| vectors to crate / find crate | Find crate |
| vectors to pickup / find pickup zone | Find supply |
| smoke nearest zone / mark nearest zone | Mark nearest |
| smoke all zones / smoke nearby zones | Mark all <5km |
| vectors to mash / find mash | Find MASH |
| enable hover coach / hover coach on | Coach ON |
| disable hover coach / hover coach off | Coach OFF |
### STATUS & ADMIN
| Command | Action |
|---------|--------|
| show status / ctld status | System status |
| draw zones on map / show zones | Draw zones |
| clear map drawings | Clear drawings |
| medevac statistics / medevac stats | MEDEVAC stats |
### QUICK ACCESS
| Command | Same As |
|---------|---------|
| quick pickup / pickup mode | load troops |
| quick deploy / fast deploy | deploy hold |
| quick build / fast build | build here |
---
## F10 Key Binding
**DCS Default (No config needed):**
- On ground: `\` key opens F10
- In air: `RAlt + \` required (backslash alone disabled)
**Voice Attack Profile:**
- All commands use `RAlt + \` (works everywhere)
- Example: "load troops" → **RAlt \ F2 F1 F1**
---
## Common Workflows
### Troop Transport
1. "vectors to pickup"
2. "load troops"
3. Fly to LZ
4. "deploy hold" or "deploy attack"
### Crate Delivery
1. "vectors to pickup"
2. Request crates (manual F10)
3. "vectors to crate"
4. Pick up & deliver
5. "build here"
### MEDEVAC
1. "list medevac"
2. "vectors to medevac"
3. Land near crew (auto-load)
4. "vectors to mash"
5. Land at MASH (auto-unload)
6. "salvage points"
### Zone Recon
1. "smoke all zones" (mark <5km)
2. "draw zones on map" (F10 view)
3. "vectors to pickup" (navigate)
4. "clear map drawings" (cleanup)
---
## Tips
✓ Speak clearly at normal volume
✓ Use alternate phrases if not recognized
✓ Train Voice Attack with your voice
✓ Best when flying stable, not in combat
✗ Don't use for crate requests (too many types)
---
## Troubleshooting
- **Not recognized:** Train profile, try alternate phrase
- **Wrong menu:** Check F10 key (RAlt vs slash)
- **Doesn't navigate:** DCS must be active window
- **MEDEVAC missing:** System not enabled in mission
---
**Print this card for cockpit reference!**
Profile: CTLD_VoiceAttack_Profile.xml
Guide: CTLD_VoiceAttack_Guide.md
CTLD Version: 0.1.0-alpha

View File

@ -1,283 +0,0 @@
# CTLD Voice Attack Integration
This directory contains a complete Voice Attack profile for hands-free navigation of the Moose CTLD (Combat Troop and Logistics Deployment) menu system in DCS World.
## Files in This Package
| File | Purpose |
|------|---------|
| **CTLD_VoiceAttack_Profile.xml** | Voice Attack profile (import this) |
| **CTLD_VoiceAttack_Guide.md** | Complete user guide with all commands |
| **CTLD_VoiceAttack_QuickRef.md** | Quick reference card (print for cockpit) |
| **CTLD_Menu_Structure.md** | Full F10 menu tree diagram |
| **Moose_CTLD.lua** | Source CTLD system (menu structure defined here) |
## Quick Start
### 1. Install
1. Open Voice Attack
2. Import `CTLD_VoiceAttack_Profile.xml`
3. Activate the profile
### 2. F10 Key Binding (Already Configured!)
**DCS Default Behavior:**
- On ground: `\` (backslash) opens F10 menu
- In air: `RAlt + \` required (backslash alone disabled)
**Voice Attack Profile:**
- Uses `RAlt + \` for all commands
- Works both on ground and in air
- **No DCS configuration needed!**
### 3. Test
In DCS, say: **"show status"**
- Should open: F10 → CTLD → Admin/Help → Show CTLD Status
## Most Useful Commands
```
"load troops" → Load passengers
"deploy hold" → Unload defensive
"build here" → Build crates
"drop all crates" → Drop cargo
"vectors to pickup" → Find supply zone
"vectors to crate" → Find crate
"smoke nearest zone" → Mark zone
"show status" → System info
```
## Command Categories
- **Troop Operations:** Load, deploy (defensive/offensive)
- **Build Operations:** Build here, refresh list
- **MEDEVAC:** List requests, vectors, MASH locations, salvage points
- **Logistics:** Drop crates, re-mark crate, check inventory
- **Navigation:** Vectors to zones/crates/MASH, smoke zones
- **Field Tools:** Create drop zone, smoke colors
- **Status:** Show status, draw zones, statistics
See `CTLD_VoiceAttack_Guide.md` for complete command list.
## Documentation
### For New Users
Start here: **CTLD_VoiceAttack_Guide.md**
- Installation instructions
- All commands with examples
- Common workflows
- Troubleshooting
### For Flying
Print this: **CTLD_VoiceAttack_QuickRef.md**
- One-page command list
- Essential workflows
- Tips for in-flight use
### For Developers
Reference: **CTLD_Menu_Structure.md**
- Complete F10 menu tree
- Key path tables
- Menu behavior notes
- Source code references
## How It Works
### Direct Navigation
All commands use **direct navigation** - one voice command executes the entire menu path:
```
Say: "load troops"
Sends: RAlt + \ + F2 + F1 + F1
Result: Operations → Troop Transport → Load Troops
```
No step-by-step navigation, no waiting between keys.
### No TTS Feedback
Commands execute silently - DCS provides on-screen feedback.
### All Non-Admin Functions Included
Profile includes:
- ✓ All operational commands
- ✓ All status/info commands
- ✓ Navigation and smoke
- ✓ MEDEVAC operations
- ✗ Specific crate requests (too many types - use manual F10)
- ✗ Debug/admin functions (intentionally excluded)
## Voice Attack Tips
### Improve Recognition
1. Train profile with your voice (Tools → Train Profile)
2. Speak clearly at normal volume
3. Use alternate phrases if not recognized
4. Reduce background noise
### Best Practices
- ✓ Use during stable flight
- ✓ Keep hands free for controls
- ✓ Combine with manual F10 for crate requests
- ✗ Don't use during combat maneuvers
- ✗ Don't use during emergency procedures
## Menu Structure Overview
```
CTLD (F2)
├── Operations (F1)
│ ├── Troop Transport
│ ├── Build
│ └── MEDEVAC
├── Logistics (F2)
│ ├── Request Crate
│ ├── Recipe Info
│ ├── Crate Management
│ └── Show Inventory
├── Field Tools (F3)
├── Navigation (F4)
└── Admin/Help (F5)
```
Full structure: `CTLD_Menu_Structure.md`
## Limitations
### Not Included
1. **Crate Requests:** Too many types (dozens of vehicles, SAMs, etc.)
- Use manual F10: CTLD → Logistics → Request Crate
2. **Typed Troop Loading:** Submenu with 4+ troop types
- Use manual F10: CTLD → Operations → Troop Transport → Load Troops (Type)
3. **Advanced Build Menu:** Dynamic list of buildable items
- Use manual F10: CTLD → Operations → Build → Build (Advanced)
4. **Debug Commands:** Admin logging controls
- Not needed for normal operations
### Why These Are Excluded
- **Crate requests:** Mission-specific, too many variations
- **Typed troops:** Rare use case, 4+ submenu items
- **Advanced build:** Dynamic content, better with manual selection
- **Debug:** Admin-only, not for regular flight ops
Use voice commands for quick actions, manual F10 for detailed selections.
## Compatibility
- **CTLD Version:** 0.1.0-alpha (Moose_CTLD_Pure)
- **Voice Attack:** 1.8+ (tested on 1.10)
- **DCS World:** Current stable/open beta
- **Menu Type:** Per-player (MENU_GROUP)
## Customization
### Add New Commands
1. Open profile in Voice Attack
2. Study menu structure: `CTLD_Menu_Structure.md`
3. Create command with key sequence
4. Test in DCS
### Update for Menu Changes
1. Check `Moose_CTLD.lua` function `BuildGroupMenus()` (~line 2616)
2. Update key sequences in Voice Attack
3. Update documentation files
4. Test all modified commands
## Troubleshooting
| Problem | Solution |
|---------|----------|
| Command not recognized | Train profile, try alternate phrase |
| Wrong menu opens | Verify DCS default binding (RAlt + \), check Controls settings |
| Menu doesn't navigate | DCS must be active window, F10 not already open |
| MEDEVAC missing | System not enabled in mission |
| Works on ground but not in air | Expected! Profile uses RAlt + \ (works in air) |
Full troubleshooting: `CTLD_VoiceAttack_Guide.md`
## Examples
### Troop Transport Mission
```
1. Say: "vectors to pickup" → Find supply zone
2. Fly to zone
3. Say: "load troops" → Board passengers
4. Fly to LZ
5. Say: "deploy hold" → Unload defensive
```
### Crate Logistics Mission
```
1. Say: "vectors to pickup" → Find supply zone
2. Manual F10 to request crates → (Too many types for voice)
3. Say: "vectors to crate" → Find spawned crate
4. Pick up and fly to target
5. Say: "build here" → Deploy at destination
```
### MEDEVAC Mission
```
1. Say: "list medevac" → Check active requests
2. Say: "vectors to medevac" → Find nearest crew
3. Land nearby (auto-load)
4. Say: "vectors to mash" → Find hospital
5. Land at MASH (auto-unload)
6. Say: "salvage points" → Check rewards
```
### Reconnaissance
```
1. Say: "smoke all zones" → Mark nearby zones
2. Say: "draw zones on map" → See all zones on F10
3. Manual F10 map navigation
4. Say: "clear map drawings" → Clean up
```
More workflows: `CTLD_VoiceAttack_Guide.md`
## Support
### If Menu Structure Changes
Menu structure is defined in `Moose_CTLD.lua`:
- Function: `CTLD:BuildGroupMenus(group)`
- Line: ~2616
Compare with `CTLD_Menu_Structure.md` to identify changes.
### Profile Updates
1. Check code for menu changes
2. Update Voice Attack key sequences
3. Update documentation
4. Test all commands
### Help Resources
- CTLD source code: `Moose_CTLD.lua`
- Menu diagram: `CTLD_Menu_Structure.md`
- Full guide: `CTLD_VoiceAttack_Guide.md`
- Quick ref: `CTLD_VoiceAttack_QuickRef.md`
## Version History
### Version 1.0 (Current)
- Initial release
- 40+ voice commands
- Direct navigation (no step-by-step)
- No TTS feedback
- Supports RAlt or slash key for F10
- All non-admin functions included
- Comprehensive documentation
## Credits
- **CTLD System:** Moose_CTLD_Pure custom implementation
- **Voice Attack:** VoiceAttack by VoiceAttack.com
- **DCS World:** Eagle Dynamics
- **MOOSE Framework:** FlightControl-Master
---
**Ready to fly hands-free? Import the profile and start with "show status"!**
Questions? See `CTLD_VoiceAttack_Guide.md` for detailed help.

View File

@ -1,334 +0,0 @@
-- CrateCatalog_CTLD_Extract.lua
-- Auto-generated from CTLD.lua (Operation_Polar_Shield) spawnableCrates config
-- Returns a table of crate definitions suitable for CTLD:MergeCatalog()
-- Notes:
-- - Each entry has keys: description/menu, dcsCargoType, required or requires (composite), side, category, build(point, headingDeg)
-- - Single-unit entries spawn one unit by DCS type. Composite "SITE" entries spawn a multi-unit group approximating system components.
local function singleUnit(unitType)
return function(point, headingDeg)
local name = string.format('%s-%d', unitType, math.random(100000,999999))
local hdg = math.rad(headingDeg or 0)
return {
visible=false, lateActivation=false, tasks={}, task='Ground Nothing', route={},
units={ { type=unitType, name=name, x=point.x, y=point.z, heading=hdg } },
name = 'CTLD_'..name
}
end
end
-- Build a single AIR unit that spawns in the air at a configured altitude/speed.
-- Falls back gracefully to singleUnit behavior if config is unavailable/disabled.
local function singleAirUnit(unitType)
return function(point, headingDeg)
local cfg = (rawget(_G, 'CTLD') and CTLD.Config and CTLD.Config.DroneAirSpawn) or nil
if not cfg or cfg.Enabled == false then
return singleUnit(unitType)(point, headingDeg)
end
local name = string.format('%s-%d', unitType, math.random(100000,999999))
local hdgDeg = headingDeg or 0
local hdg = math.rad(hdgDeg)
local alt = tonumber(cfg.AltitudeMeters) or 1200
local spd = tonumber(cfg.SpeedMps) or 120
-- Create a tiny 2-point route to ensure forward flight at the chosen altitude.
local function fwdOffset(px, pz, meters, headingRadians)
return px + math.sin(headingRadians) * meters, pz + math.cos(headingRadians) * meters
end
local p1x, p1z = point.x, point.z
local p2x, p2z = fwdOffset(point.x, point.z, 1000, hdg) -- 1 km ahead
local group = {
visible=false,
lateActivation=false,
tasks={},
task='CAS',
route={
points={
{
alt = alt, alt_type = 'BARO',
type = 'Turning Point', action = 'Turning Point',
x = p1x, y = p1z,
speed = spd, ETA = 0, ETA_locked = false,
task = {}
},
{
alt = alt, alt_type = 'BARO',
type = 'Turning Point', action = 'Turning Point',
x = p2x, y = p2z,
speed = spd, ETA = 0, ETA_locked = false,
task = {}
}
}
},
units={
{
type=unitType, name=name,
x=p1x, y=p1z,
heading=hdg,
speed = spd,
alt = alt, alt_type = 'BARO'
}
},
name = 'CTLD_'..name
}
return group
end
end
local function multiUnits(units)
-- units: array of { type, dx, dz }
return function(point, headingDeg)
local hdg = math.rad(headingDeg or 0)
local function off(dx, dz) return { x = point.x + dx, z = point.z + dz } end
local list = {}
for i,u in ipairs(units) do
local p = off(u.dx or 0, u.dz or 3*i)
table.insert(list, {
type = u.type, name = string.format('CTLD-%s-%d', u.type, math.random(100000,999999)),
x = p.x, y = p.z, heading = hdg
})
end
return { visible=false, lateActivation=false, tasks={}, task='Ground Nothing', route={}, units=list, name=string.format('CTLD_SITE_%d', math.random(100000,999999)) }
end
end
local BLUE = coalition.side.BLUE
local RED = coalition.side.RED
local cat = {}
cat['BLUE_M1128_STRYKER_MGS_CRATE'] = { hidden=true, description='M1128 Stryker MGS crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1128_STRYKER_MGS'] = { menuCategory='Combat Vehicles', menu='M1128 Stryker MGS', description='M1128 Stryker MGS', dcsCargoType='container_cargo', requires={ BLUE_M1128_STRYKER_MGS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1128 Stryker MGS'), unitType='M1128 Stryker MGS', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M60A3_PATTON_CRATE'] = { hidden=true, description='M-60A3 Patton crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M60A3_PATTON'] = { menuCategory='Combat Vehicles', menu='M-60A3 Patton', description='M-60A3 Patton', dcsCargoType='container_cargo', requires={ BLUE_M60A3_PATTON_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-60'), unitType='M-60', MEDEVAC=true, salvageValue=3, crewSize=4 }
cat['BLUE_HMMWV_TOW_CRATE'] = { hidden=true, description='Humvee - TOW crate', dcsCargoType='container_cargo', required=1, initialStock=36, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_HMMWV_TOW'] = { menuCategory='Combat Vehicles', menu='Humvee - TOW', description='Humvee - TOW', dcsCargoType='container_cargo', requires={ BLUE_HMMWV_TOW_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1045 HMMWV TOW'), unitType='M1045 HMMWV TOW', MEDEVAC=true, salvageValue=3, crewSize=2 }
cat['BLUE_M1134_STRYKER_ATGM_CRATE']= { hidden=true, description='M1134 Stryker ATGM crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1134_STRYKER_ATGM'] = { menuCategory='Combat Vehicles', menu='M1134 Stryker ATGM', description='M1134 Stryker ATGM', dcsCargoType='container_cargo', requires={ BLUE_M1134_STRYKER_ATGM_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1134 Stryker ATGM'), unitType='M1134 Stryker ATGM', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_LAV25_CRATE'] = { hidden=true, description='LAV-25 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_LAV25'] = { menuCategory='Combat Vehicles', menu='LAV-25', description='LAV-25', dcsCargoType='container_cargo', requires={ BLUE_LAV25_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('LAV-25'), unitType='LAV-25', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M2A2_BRADLEY_CRATE'] = { hidden=true, description='M2A2 Bradley crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M2A2_BRADLEY'] = { menuCategory='Combat Vehicles', menu='M2A2 Bradley', description='M2A2 Bradley', dcsCargoType='container_cargo', requires={ BLUE_M2A2_BRADLEY_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-2 Bradley'), unitType='M-2 Bradley', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_VAB_MEPHISTO_CRATE'] = { hidden=true, description='ATGM VAB Mephisto crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_VAB_MEPHISTO'] = { menuCategory='Combat Vehicles', menu='ATGM VAB Mephisto', description='ATGM VAB Mephisto', dcsCargoType='container_cargo', requires={ BLUE_VAB_MEPHISTO_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('VAB_Mephisto'), unitType='VAB_Mephisto', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M1A2C_ABRAMS_CRATE'] = { hidden=true, description='M1A2C Abrams crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1A2C_ABRAMS'] = { menuCategory='Combat Vehicles', menu='M1A2C Abrams', description='M1A2C Abrams', dcsCargoType='container_cargo', requires={ BLUE_M1A2C_ABRAMS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1A2C_SEP_V3'), unitType='M1A2C_SEP_V3', MEDEVAC=true, salvageValue=3, crewSize=4 }
-- Combat Vehicles (RED)
cat['RED_BTR82A_CRATE'] = { hidden=true, description='BTR-82A crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BTR82A'] = { menuCategory='Combat Vehicles', menu='BTR-82A', description='BTR-82A', dcsCargoType='container_cargo', requires={ RED_BTR82A_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-82A'), unitType='BTR-82A', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BRDM2_CRATE'] = { hidden=true, description='BRDM-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BRDM2'] = { menuCategory='Combat Vehicles', menu='BRDM-2', description='BRDM-2', dcsCargoType='container_cargo', requires={ RED_BRDM2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BRDM-2'), unitType='BRDM-2', MEDEVAC=true, salvageValue=2, crewSize=2 }
cat['RED_BMP3_CRATE'] = { hidden=true, description='BMP-3 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BMP3'] = { menuCategory='Combat Vehicles', menu='BMP-3', description='BMP-3', dcsCargoType='container_cargo', requires={ RED_BMP3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-3'), unitType='BMP-3', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BMP2_CRATE'] = { hidden=true, description='BMP-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BMP2'] = { menuCategory='Combat Vehicles', menu='BMP-2', description='BMP-2', dcsCargoType='container_cargo', requires={ RED_BMP2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-2'), unitType='BMP-2', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BTR80_CRATE'] = { hidden=true, description='BTR-80 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BTR80'] = { menuCategory='Combat Vehicles', menu='BTR-80', description='BTR-80', dcsCargoType='container_cargo', requires={ RED_BTR80_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-80'), unitType='BTR-80', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_T72B3_CRATE'] = { hidden=true, description='T-72B3 crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
cat['RED_T72B3'] = { menuCategory='Combat Vehicles', menu='T-72B3', description='T-72B3', dcsCargoType='container_cargo', requires={ RED_T72B3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('T-72B3'), unitType='T-72B3', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['RED_T90M_CRATE'] = { hidden=true, description='T-90M crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
cat['RED_T90M'] = { menuCategory='Combat Vehicles', menu='T-90M', description='T-90M', dcsCargoType='container_cargo', requires={ RED_T90M_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('CHAP_T90M'), unitType='CHAP_T90M', MEDEVAC=true, salvageValue=3, crewSize=3 }
-- Support (BLUE)
cat['BLUE_MRAP_JTAC'] = { menuCategory='Support', menu='MRAP - JTAC', description='JTAC MRAP', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MaxxPro_MRAP'), MEDEVAC=true, salvageValue=1, crewSize=4, roles={'JTAC'}, jtac={ platform='ground' } }
cat['BLUE_M818_AMMO'] = { menuCategory='Support', menu='M-818 Ammo Truck', description='M-818 Ammo Truck', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M 818'), salvageValue=1, crewSize=2 }
cat['BLUE_M978_TANKER'] = { menuCategory='Support', menu='M-978 Tanker', description='M-978 Tanker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M978 HEMTT Tanker'), salvageValue=1, crewSize=2 }
cat['BLUE_EWR_FPS117'] = { menuCategory='Support', menu='EWR Radar FPS-117', description='EWR Radar FPS-117', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('FPS-117'), salvageValue=1, crewSize=3 }
-- Support (RED)
cat['RED_TIGR_JTAC'] = { menuCategory='Support', menu='Tigr - JTAC', description='JTAC Tigr', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Tigr_233036'), MEDEVAC=true, salvageValue=1, crewSize=4, roles={'JTAC'}, jtac={ platform='ground' } }
cat['RED_URAL4320_AMMO'] = { menuCategory='Support', menu='Ural-4320-31 Ammo Truck', description='Ural-4320-31 Ammo Truck', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Ural-4320-31'), salvageValue=1, crewSize=2 }
cat['RED_ATZ10_TANKER'] = { menuCategory='Support', menu='ATZ-10 Refueler', description='ATZ-10 Refueler', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ATZ-10'), salvageValue=1, crewSize=2 }
cat['RED_EWR_1L13'] = { menuCategory='Support', menu='EWR Radar 1L13', description='EWR Radar 1L13', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('1L13 EWR'), salvageValue=1, crewSize=3 }
-- Artillery (BLUE)
cat['BLUE_MLRS_CRATE'] = { hidden=true, description='MLRS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_MLRS'] = { menuCategory='Artillery', menu='MLRS', description='MLRS', dcsCargoType='container_cargo', requires={ BLUE_MLRS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MLRS'), salvageValue=2, crewSize=3 }
cat['BLUE_SMERCH_CM_CRATE'] = { hidden=true, description='Smerch (CM) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_SMERCH_CM'] = { menuCategory='Artillery', menu='Smerch_CM', description='Smerch (CM)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_CM_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch'), salvageValue=2, crewSize=3 }
cat['BLUE_L118_105MM'] = { menuCategory='Artillery', menu='L118 Light Artillery 105mm', description='L118 105mm', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('L118_Unit'), salvageValue=1, crewSize=5 }
cat['BLUE_SMERCH_HE_CRATE'] = { hidden=true, description='Smerch (HE) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_SMERCH_HE'] = { menuCategory='Artillery', menu='Smerch_HE', description='Smerch (HE)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_HE_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch_HE'), salvageValue=2, crewSize=3 }
cat['BLUE_M109_CRATE'] = { hidden=true, description='M-109 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M109'] = { menuCategory='Artillery', menu='M-109', description='M-109', dcsCargoType='container_cargo', requires={ BLUE_M109_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-109'), salvageValue=2, crewSize=4 }
-- Artillery (RED)
cat['RED_GVOZDIKA_CRATE'] = { hidden=true, description='SAU Gvozdika crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_GVOZDika'] = { menuCategory='Artillery', menu='SAU Gvozdika', description='SAU Gvozdika', dcsCargoType='container_cargo', requires={ RED_GVOZDIKA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Gvozdika'), salvageValue=2, crewSize=3 }
cat['RED_2S19_MSTA_CRATE'] = { hidden=true, description='SPH 2S19 Msta crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_2S19_MSTA'] = { menuCategory='Artillery', menu='SPH 2S19 Msta', description='SPH 2S19 Msta', dcsCargoType='container_cargo', requires={ RED_2S19_MSTA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Msta'), salvageValue=2, crewSize=4 }
cat['RED_URAGAN_BM27_CRATE'] = { hidden=true, description='Uragan BM-27 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
cat['RED_URAGAN_BM27'] = { menuCategory='Artillery', menu='Uragan_BM-27', description='Uragan BM-27', dcsCargoType='container_cargo', requires={ RED_URAGAN_BM27_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Uragan_BM-27'), salvageValue=2, crewSize=3 }
cat['RED_BM21_GRAD_CRATE'] = { hidden=true, description='BM-21 Grad crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_BM21_GRAD'] = { menuCategory='Artillery', menu='BM-21 Grad Ural', description='BM-21 Grad Ural', dcsCargoType='container_cargo', requires={ RED_BM21_GRAD_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Grad-URAL'), salvageValue=2, crewSize=3 }
cat['RED_PLZ05_CRATE'] = { hidden=true, description='PLZ-05 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
cat['RED_PLZ05'] = { menuCategory='Artillery', menu='PLZ-05 Mobile Artillery', description='PLZ-05', dcsCargoType='container_cargo', requires={ RED_PLZ05_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('PLZ05'), salvageValue=2, crewSize=4 }
-- AAA (BLUE)
cat['BLUE_GEPARD'] = { menuCategory='AAA', menu='Gepard AAA', description='Gepard AAA', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Gepard'), salvageValue=1, crewSize=3 }
cat['BLUE_CRAM'] = { menuCategory='AAA', menu='LPWS C-RAM', description='LPWS C-RAM', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('HEMTT_C-RAM_Phalanx'), salvageValue=1, crewSize=2 }
cat['BLUE_VULCAN_M163'] = { menuCategory='AAA', menu='SPAAA Vulcan M163', description='Vulcan M163', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Vulcan'), salvageValue=1, crewSize=2 }
cat['BLUE_BOFORS40'] = { menuCategory='AAA', menu='Bofors 40mm', description='Bofors 40mm', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('bofors40'), salvageValue=1, crewSize=4 }
-- AAA (RED)
cat['RED_URAL_ZU23'] = { menuCategory='AAA', menu='Ural-375 ZU-23', description='Ural-375 ZU-23', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Ural-375 ZU-23'), salvageValue=1, crewSize=3 }
cat['RED_SHILKA'] = { menuCategory='AAA', menu='ZSU-23-4 Shilka', description='ZSU-23-4 Shilka', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU-23-4 Shilka'), salvageValue=1, crewSize=3 }
cat['RED_ZSU57_2'] = { menuCategory='AAA', menu='ZSU_57_2', description='ZSU_57_2', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU_57_2'), salvageValue=1, crewSize=3 }
cat['BLUE_M1097_AVENGER_CRATE'] = { hidden=true, description='M1097 Avenger crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1097_AVENGER'] = { menuCategory='SAM short range', menu='M1097 Avenger', description='M1097 Avenger', dcsCargoType='container_cargo', requires={ BLUE_M1097_AVENGER_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1097 Avenger') }
cat['BLUE_M48_CHAPARRAL_CRATE'] = { hidden=true, description='M48 Chaparral crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M48_CHAPARRAL'] = { menuCategory='SAM short range', menu='M48 Chaparral', description='M48 Chaparral', dcsCargoType='container_cargo', requires={ BLUE_M48_CHAPARRAL_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M48 Chaparral') }
cat['BLUE_ROLAND_ADS_CRATE'] = { hidden=true, description='Roland ADS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_ROLAND_ADS'] = { menuCategory='SAM short range', menu='Roland ADS', description='Roland ADS', dcsCargoType='container_cargo', requires={ BLUE_ROLAND_ADS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Roland ADS') }
cat['BLUE_M6_LINEBACKER'] = { menuCategory='SAM short range', menu='M6 Linebacker', description='M6 Linebacker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M6 Linebacker') }
cat['BLUE_RAPIER_LN'] = { menuCategory='SAM short range', menu='Rapier Launcher', description='Rapier Launcher', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_launcher') }
cat['BLUE_RAPIER_SR'] = { menuCategory='SAM short range', menu='Rapier SR', description='Rapier SR', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_blindfire_radar') }
cat['BLUE_RAPIER_TR'] = { menuCategory='SAM short range', menu='Rapier Tracker', description='Rapier Tracker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_optical_tracker_unit') }
cat['BLUE_RAPIER_SITE'] = { menuCategory='SAM short range', menu='Rapier - All crates', description='Rapier Site', dcsCargoType='container_cargo', requires={ BLUE_RAPIER_LN=1, BLUE_RAPIER_SR=1, BLUE_RAPIER_TR=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='rapier_fsa_launcher'}, {type='rapier_fsa_blindfire_radar', dx=12, dz=6}, {type='rapier_fsa_optical_tracker_unit', dx=-12, dz=6} }) }
-- SAM short range (RED)
cat['RED_OSA_9K33_CRATE'] = { hidden=true, description='9K33 Osa crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_OSA_9K33'] = { menuCategory='SAM short range', menu='9K33 Osa', description='9K33 Osa', dcsCargoType='container_cargo', requires={ RED_OSA_9K33_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Osa 9A33 ln') }
cat['RED_STRELA1_9P31_CRATE'] = { hidden=true, description='9P31 Strela-1 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_STRELA1_9P31'] = { menuCategory='SAM short range', menu='9P31 Strela-1', description='9P31 Strela-1', dcsCargoType='container_cargo', requires={ RED_STRELA1_9P31_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-1 9P31') }
cat['RED_TUNGUSKA_2S6_CRATE'] = { hidden=true, description='2K22 Tunguska crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_TUNGUSKA_2S6'] = { menuCategory='SAM short range', menu='2K22 Tunguska', description='2K22 Tunguska', dcsCargoType='container_cargo', requires={ RED_TUNGUSKA_2S6_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('2S6 Tunguska') }
cat['RED_STRELA10M3_CRATE'] = { hidden=true, description='SA-13 Strela-10M3 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_STRELA10M3'] = { menuCategory='SAM short range', menu='SA-13 Strela-10M3', description='SA-13 Strela-10M3', dcsCargoType='container_cargo', requires={ RED_STRELA10M3_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-10M3') }
-- HQ-7 components and site
cat['RED_HQ7_LN_CRATE'] = { hidden=true, description='HQ-7 Launcher crate', dcsCargoType='container_cargo', required=1, initialStock=20, side=RED, category=Group.Category.GROUND }
cat['RED_HQ7_LN'] = { menuCategory='SAM short range', menu='HQ-7_Launcher', description='HQ-7 Launcher', dcsCargoType='container_cargo', requires={ RED_HQ7_LN_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_LN_SP') }
cat['RED_HQ7_STR'] = { menuCategory='SAM short range', menu='HQ-7_STR_SP', description='HQ-7 STR', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_STR_SP') }
cat['RED_HQ7_SITE'] = { menuCategory='SAM short range', menu='HQ-7 - All crates', description='HQ-7 Site', dcsCargoType='container_cargo', requires={ RED_HQ7_LN=1, RED_HQ7_STR=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='HQ-7_LN_SP'}, {type='HQ-7_STR_SP', dx=10, dz=8} }) }
-- SAM mid range (BLUE) HAWK + NASAMS
cat['BLUE_HAWK_LN'] = { menuCategory='SAM mid range', menu='HAWK Launcher', description='HAWK Launcher', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk ln') }
cat['BLUE_HAWK_SR'] = { menuCategory='SAM mid range', menu='HAWK Search Radar', description='HAWK SR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk sr') }
cat['BLUE_HAWK_TR'] = { menuCategory='SAM mid range', menu='HAWK Track Radar', description='HAWK TR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk tr') }
cat['BLUE_HAWK_PCP'] = { menuCategory='SAM mid range', menu='HAWK PCP', description='HAWK PCP', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk pcp') }
cat['BLUE_HAWK_CWAR'] = { menuCategory='SAM mid range', menu='HAWK CWAR', description='HAWK CWAR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk cwar') }
cat['BLUE_HAWK_SITE'] = { menuCategory='SAM mid range', menu='HAWK - All crates', description='HAWK Site', dcsCargoType='container_cargo', requires={ BLUE_HAWK_LN=1, BLUE_HAWK_SR=1, BLUE_HAWK_TR=1, BLUE_HAWK_PCP=1, BLUE_HAWK_CWAR=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='Hawk ln'}, {type='Hawk sr', dx=12, dz=8}, {type='Hawk tr', dx=-12, dz=8}, {type='Hawk pcp', dx=18, dz=12}, {type='Hawk cwar', dx=-18, dz=12} }) }
-- HAWK site repair/augment (adds +1 launcher, repairs site by respawn)
cat['BLUE_HAWK_REPAIR'] = { menuCategory='SAM mid range', menu='HAWK Repair/Launcher +1', description='HAWK Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
-- Build is handled specially in CTLD:BuildSpecificAtGroup for isRepair entries
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['BLUE_NASAMS_LN'] = { menuCategory='SAM mid range', menu='NASAMS Launcher 120C', description='NASAMS LN 120C', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_LN_C') }
cat['BLUE_NASAMS_RADAR'] = { menuCategory='SAM mid range', menu='NASAMS Search/Track Radar', description='NASAMS Radar', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_Radar_MPQ64F1') }
cat['BLUE_NASAMS_CP'] = { menuCategory='SAM mid range', menu='NASAMS Command Post', description='NASAMS CP', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_Command_Post') }
cat['BLUE_NASAMS_SITE'] = { menuCategory='SAM mid range', menu='NASAMS - All crates', description='NASAMS Site', dcsCargoType='container_cargo', requires={ BLUE_NASAMS_LN=1, BLUE_NASAMS_RADAR=1, BLUE_NASAMS_CP=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='NASAMS_LN_C'}, {type='NASAMS_Radar_MPQ64F1', dx=12, dz=8}, {type='NASAMS_Command_Post', dx=-12, dz=8} }) }
-- SAM mid range (RED) KUB
cat['RED_KUB_LN'] = { menuCategory='SAM mid range', menu='KUB Launcher', description='KUB Launcher', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Kub 2P25 ln') }
cat['RED_KUB_RADAR'] = { menuCategory='SAM mid range', menu='KUB Radar', description='KUB Radar', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Kub 1S91 str') }
cat['RED_KUB_SITE'] = { menuCategory='SAM mid range', menu='KUB - All crates', description='KUB Site', dcsCargoType='container_cargo', requires={ RED_KUB_LN=1, RED_KUB_RADAR=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='Kub 2P25 ln'}, {type='Kub 1S91 str', dx=12, dz=8} }) }
-- KUB site repair/augment (adds +1 launcher, repairs site by respawn)
cat['RED_KUB_REPAIR'] = { menuCategory='SAM mid range', menu='KUB Repair/Launcher +1', description='KUB Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- SAM long range (BLUE) Patriot
cat['BLUE_PATRIOT_LN'] = { menuCategory='SAM long range', menu='Patriot Launcher', description='Patriot Launcher', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot ln') }
cat['BLUE_PATRIOT_RADAR'] = { menuCategory='SAM long range', menu='Patriot Radar', description='Patriot Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot str') }
cat['BLUE_PATRIOT_ECS'] = { menuCategory='SAM long range', menu='Patriot ECS', description='Patriot ECS', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot ECS') }
cat['BLUE_PATRIOT_SITE'] = { menuCategory='SAM long range', menu='Patriot - All crates', description='Patriot Site', dcsCargoType='container_cargo', requires={ BLUE_PATRIOT_LN=1, BLUE_PATRIOT_RADAR=1, BLUE_PATRIOT_ECS=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='Patriot ln'}, {type='Patriot str', dx=14, dz=10}, {type='Patriot ECS', dx=-14, dz=10} }) }
-- Patriot site repair/augment (adds +1 launcher, repairs site by respawn)
cat['BLUE_PATRIOT_REPAIR'] = { menuCategory='SAM long range', menu='Patriot Repair/Launcher +1', description='Patriot Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- SAM long range (RED) BUK
cat['RED_BUK_LN'] = { menuCategory='SAM long range', menu='BUK Launcher', description='BUK Launcher', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk LN 9A310M1') }
cat['RED_BUK_SR'] = { menuCategory='SAM long range', menu='BUK Search Radar', description='BUK Search Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk SR 9S18M1') }
cat['RED_BUK_CC'] = { menuCategory='SAM long range', menu='BUK CC Radar', description='BUK CC Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk CC 9S470M1') }
cat['RED_BUK_SITE'] = { menuCategory='SAM long range', menu='BUK - All crates', description='BUK Site', dcsCargoType='container_cargo', requires={ RED_BUK_LN=1, RED_BUK_SR=1, RED_BUK_CC=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='SA-11 Buk LN 9A310M1'}, {type='SA-11 Buk SR 9S18M1', dx=12, dz=8}, {type='SA-11 Buk CC 9S470M1', dx=-12, dz=8} }) }
-- BUK site repair/augment (adds +1 launcher, repairs site by respawn)
cat['RED_BUK_REPAIR'] = { menuCategory='SAM long range', menu='BUK Repair/Launcher +1', description='BUK Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- Drones (JTAC)
cat['BLUE_MQ9'] = { menuCategory='Drones', menu='MQ-9 Reaper - JTAC', description='MQ-9 JTAC', dcsCargoType='container_cargo', required=1, initialStock=3, side=BLUE, category=Group.Category.AIRPLANE, build=singleAirUnit('MQ-9 Reaper'), roles={'JTAC'}, jtac={ platform='air' } }
cat['RED_WINGLOONG'] = { menuCategory='Drones', menu='WingLoong-I - JTAC', description='WingLoong-I JTAC', dcsCargoType='container_cargo', required=1, initialStock=3, side=RED, category=Group.Category.AIRPLANE, build=singleAirUnit('WingLoong-I'), roles={'JTAC'}, jtac={ platform='air' } }
-- FOB crates (Support) — three small crates build a FOB site
cat['FOB_SMALL'] = { hidden=true, description='FOB small crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
-- spawns a harmless placeholder truck for visibility; consumed by FOB_SITE build
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['FOB_SITE'] = { menuCategory='Support', menu='FOB Crates - All', description='FOB Site', isFOB=true, dcsCargoType='container_cargo', requires={ FOB_SMALL=3 }, initialStock=0, side=nil, category=Group.Category.GROUND,
build=multiUnits({ {type='HEMTT TFFT'}, {type='Ural-375 PBU', dx=10, dz=8}, {type='Ural-375', dx=-10, dz=8} }) }
-- Mobile MASH (Support) — three crates build a Mobile MASH unit
cat['MOBILE_MASH_SMALL'] = { hidden=true, description='Mobile MASH crate', dcsCargoType='container_cargo', required=1, initialStock=6, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
-- spawns placeholder truck for visibility; consumed by MOBILE_MASH build
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['BLUE_MOBILE_MASH'] = { menuCategory='Support', menu='Mobile MASH - All', description='Blue Mobile MASH Unit', isMobileMASH=true, dcsCargoType='container_cargo', requires={ MOBILE_MASH_SMALL=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-113') }
cat['RED_MOBILE_MASH'] = { menuCategory='Support', menu='Mobile MASH - All', description='Red Mobile MASH Unit', isMobileMASH=true, dcsCargoType='container_cargo', requires={ MOBILE_MASH_SMALL=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR_D') }
-- =========================
-- Troop Type Definitions
-- =========================
-- These define the composition of troop squads for Load/Unload Troops (NOT crates)
-- Structure: { label, size, unitsBlue, unitsRed, units (fallback) }
local troops = {}
-- Assault Squad: general-purpose rifles/MG
troops['AS'] = {
label = 'Assault Squad',
size = 8,
unitsBlue = { 'Soldier M4', 'Soldier M249' },
unitsRed = { 'Infantry AK', 'Infantry AK ver3' },
units = { 'Infantry AK' },
}
-- MANPADS Team: Anti-air element
troops['AA'] = {
label = 'MANPADS Team',
size = 4,
unitsBlue = { 'Soldier stinger', 'Stinger comm' },
unitsRed = { 'SA-18 Igla-S manpad', 'SA-18 Igla comm' },
units = { 'Infantry AK' },
}
-- AT Team: Anti-tank element
troops['AT'] = {
label = 'AT Team',
size = 4,
unitsBlue = { 'Soldier RPG', 'Soldier RPG' },
unitsRed = { 'Soldier RPG', 'Soldier RPG' },
units = { 'Infantry AK' },
}
-- Mortar Team: Indirect fire element
troops['AR'] = {
label = 'Mortar Team',
size = 4,
unitsBlue = { '2B11 mortar' },
unitsRed = { '2B11 mortar' },
units = { '2B11 mortar' },
}
-- Export troop types
_CTLD_TROOP_TYPES = troops
-- Also export as a global for mission setups that load via DO SCRIPT FILE (no return capture)
_CTLD_EXTRACTED_CATALOG = cat
return cat

View File

@ -1,334 +0,0 @@
-- CrateCatalog_CTLD_Extract.lua
-- Auto-generated from CTLD.lua (Operation_Polar_Shield) spawnableCrates config
-- Returns a table of crate definitions suitable for CTLD:MergeCatalog()
-- Notes:
-- - Each entry has keys: description/menu, dcsCargoType, required or requires (composite), side, category, build(point, headingDeg)
-- - Single-unit entries spawn one unit by DCS type. Composite "SITE" entries spawn a multi-unit group approximating system components.
local function singleUnit(unitType)
return function(point, headingDeg)
local name = string.format('%s-%d', unitType, math.random(100000,999999))
local hdg = math.rad(headingDeg or 0)
return {
visible=false, lateActivation=false, tasks={}, task='Ground Nothing', route={},
units={ { type=unitType, name=name, x=point.x, y=point.z, heading=hdg } },
name = 'CTLD_'..name
}
end
end
-- Build a single AIR unit that spawns in the air at a configured altitude/speed.
-- Falls back gracefully to singleUnit behavior if config is unavailable/disabled.
local function singleAirUnit(unitType)
return function(point, headingDeg)
local cfg = (rawget(_G, 'CTLD') and CTLD.Config and CTLD.Config.DroneAirSpawn) or nil
if not cfg or cfg.Enabled == false then
return singleUnit(unitType)(point, headingDeg)
end
local name = string.format('%s-%d', unitType, math.random(100000,999999))
local hdgDeg = headingDeg or 0
local hdg = math.rad(hdgDeg)
local alt = tonumber(cfg.AltitudeMeters) or 1200
local spd = tonumber(cfg.SpeedMps) or 120
-- Create a tiny 2-point route to ensure forward flight at the chosen altitude.
local function fwdOffset(px, pz, meters, headingRadians)
return px + math.sin(headingRadians) * meters, pz + math.cos(headingRadians) * meters
end
local p1x, p1z = point.x, point.z
local p2x, p2z = fwdOffset(point.x, point.z, 1000, hdg) -- 1 km ahead
local group = {
visible=false,
lateActivation=false,
tasks={},
task='CAS',
route={
points={
{
alt = alt, alt_type = 'BARO',
type = 'Turning Point', action = 'Turning Point',
x = p1x, y = p1z,
speed = spd, ETA = 0, ETA_locked = false,
task = {}
},
{
alt = alt, alt_type = 'BARO',
type = 'Turning Point', action = 'Turning Point',
x = p2x, y = p2z,
speed = spd, ETA = 0, ETA_locked = false,
task = {}
}
}
},
units={
{
type=unitType, name=name,
x=p1x, y=p1z,
heading=hdg,
speed = spd,
alt = alt, alt_type = 'BARO'
}
},
name = 'CTLD_'..name
}
return group
end
end
local function multiUnits(units)
-- units: array of { type, dx, dz }
return function(point, headingDeg)
local hdg = math.rad(headingDeg or 0)
local function off(dx, dz) return { x = point.x + dx, z = point.z + dz } end
local list = {}
for i,u in ipairs(units) do
local p = off(u.dx or 0, u.dz or 3*i)
table.insert(list, {
type = u.type, name = string.format('CTLD-%s-%d', u.type, math.random(100000,999999)),
x = p.x, y = p.z, heading = hdg
})
end
return { visible=false, lateActivation=false, tasks={}, task='Ground Nothing', route={}, units=list, name=string.format('CTLD_SITE_%d', math.random(100000,999999)) }
end
end
local BLUE = coalition.side.BLUE
local RED = coalition.side.RED
local cat = {}
cat['BLUE_M1128_STRYKER_MGS_CRATE'] = { hidden=true, description='M1128 Stryker MGS crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1128_STRYKER_MGS'] = { menuCategory='Combat Vehicles', menu='M1128 Stryker MGS', description='M1128 Stryker MGS', dcsCargoType='container_cargo', requires={ BLUE_M1128_STRYKER_MGS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1128 Stryker MGS'), unitType='M1128 Stryker MGS', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M60A3_PATTON_CRATE'] = { hidden=true, description='M-60A3 Patton crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M60A3_PATTON'] = { menuCategory='Combat Vehicles', menu='M-60A3 Patton', description='M-60A3 Patton', dcsCargoType='container_cargo', requires={ BLUE_M60A3_PATTON_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-60'), unitType='M-60', MEDEVAC=true, salvageValue=3, crewSize=4 }
cat['BLUE_HMMWV_TOW_CRATE'] = { hidden=true, description='Humvee - TOW crate', dcsCargoType='container_cargo', required=1, initialStock=36, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_HMMWV_TOW'] = { menuCategory='Combat Vehicles', menu='Humvee - TOW', description='Humvee - TOW', dcsCargoType='container_cargo', requires={ BLUE_HMMWV_TOW_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1045 HMMWV TOW'), unitType='M1045 HMMWV TOW', MEDEVAC=true, salvageValue=3, crewSize=2 }
cat['BLUE_M1134_STRYKER_ATGM_CRATE']= { hidden=true, description='M1134 Stryker ATGM crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1134_STRYKER_ATGM'] = { menuCategory='Combat Vehicles', menu='M1134 Stryker ATGM', description='M1134 Stryker ATGM', dcsCargoType='container_cargo', requires={ BLUE_M1134_STRYKER_ATGM_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1134 Stryker ATGM'), unitType='M1134 Stryker ATGM', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_LAV25_CRATE'] = { hidden=true, description='LAV-25 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_LAV25'] = { menuCategory='Combat Vehicles', menu='LAV-25', description='LAV-25', dcsCargoType='container_cargo', requires={ BLUE_LAV25_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('LAV-25'), unitType='LAV-25', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M2A2_BRADLEY_CRATE'] = { hidden=true, description='M2A2 Bradley crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M2A2_BRADLEY'] = { menuCategory='Combat Vehicles', menu='M2A2 Bradley', description='M2A2 Bradley', dcsCargoType='container_cargo', requires={ BLUE_M2A2_BRADLEY_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-2 Bradley'), unitType='M-2 Bradley', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_VAB_MEPHISTO_CRATE'] = { hidden=true, description='ATGM VAB Mephisto crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_VAB_MEPHISTO'] = { menuCategory='Combat Vehicles', menu='ATGM VAB Mephisto', description='ATGM VAB Mephisto', dcsCargoType='container_cargo', requires={ BLUE_VAB_MEPHISTO_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('VAB_Mephisto'), unitType='VAB_Mephisto', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['BLUE_M1A2C_ABRAMS_CRATE'] = { hidden=true, description='M1A2C Abrams crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1A2C_ABRAMS'] = { menuCategory='Combat Vehicles', menu='M1A2C Abrams', description='M1A2C Abrams', dcsCargoType='container_cargo', requires={ BLUE_M1A2C_ABRAMS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1A2C_SEP_V3'), unitType='M1A2C_SEP_V3', MEDEVAC=true, salvageValue=3, crewSize=4 }
-- Combat Vehicles (RED)
cat['RED_BTR82A_CRATE'] = { hidden=true, description='BTR-82A crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BTR82A'] = { menuCategory='Combat Vehicles', menu='BTR-82A', description='BTR-82A', dcsCargoType='container_cargo', requires={ RED_BTR82A_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-82A'), unitType='BTR-82A', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BRDM2_CRATE'] = { hidden=true, description='BRDM-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BRDM2'] = { menuCategory='Combat Vehicles', menu='BRDM-2', description='BRDM-2', dcsCargoType='container_cargo', requires={ RED_BRDM2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BRDM-2'), unitType='BRDM-2', MEDEVAC=true, salvageValue=2, crewSize=2 }
cat['RED_BMP3_CRATE'] = { hidden=true, description='BMP-3 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BMP3'] = { menuCategory='Combat Vehicles', menu='BMP-3', description='BMP-3', dcsCargoType='container_cargo', requires={ RED_BMP3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-3'), unitType='BMP-3', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BMP2_CRATE'] = { hidden=true, description='BMP-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BMP2'] = { menuCategory='Combat Vehicles', menu='BMP-2', description='BMP-2', dcsCargoType='container_cargo', requires={ RED_BMP2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-2'), unitType='BMP-2', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_BTR80_CRATE'] = { hidden=true, description='BTR-80 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
cat['RED_BTR80'] = { menuCategory='Combat Vehicles', menu='BTR-80', description='BTR-80', dcsCargoType='container_cargo', requires={ RED_BTR80_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-80'), unitType='BTR-80', MEDEVAC=true, salvageValue=2, crewSize=3 }
cat['RED_T72B3_CRATE'] = { hidden=true, description='T-72B3 crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
cat['RED_T72B3'] = { menuCategory='Combat Vehicles', menu='T-72B3', description='T-72B3', dcsCargoType='container_cargo', requires={ RED_T72B3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('T-72B3'), unitType='T-72B3', MEDEVAC=true, salvageValue=3, crewSize=3 }
cat['RED_T90M_CRATE'] = { hidden=true, description='T-90M crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
cat['RED_T90M'] = { menuCategory='Combat Vehicles', menu='T-90M', description='T-90M', dcsCargoType='container_cargo', requires={ RED_T90M_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('CHAP_T90M'), unitType='CHAP_T90M', MEDEVAC=true, salvageValue=3, crewSize=3 }
-- Support (BLUE)
cat['BLUE_MRAP_JTAC'] = { menuCategory='Support', menu='MRAP - JTAC', description='JTAC MRAP', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MaxxPro_MRAP'), MEDEVAC=true, salvageValue=1, crewSize=4, roles={'JTAC'}, jtac={ platform='ground' } }
cat['BLUE_M818_AMMO'] = { menuCategory='Support', menu='M-818 Ammo Truck', description='M-818 Ammo Truck', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M 818'), salvageValue=1, crewSize=2 }
cat['BLUE_M978_TANKER'] = { menuCategory='Support', menu='M-978 Tanker', description='M-978 Tanker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M978 HEMTT Tanker'), salvageValue=1, crewSize=2 }
cat['BLUE_EWR_FPS117'] = { menuCategory='Support', menu='EWR Radar FPS-117', description='EWR Radar FPS-117', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('FPS-117'), salvageValue=1, crewSize=3 }
-- Support (RED)
cat['RED_TIGR_JTAC'] = { menuCategory='Support', menu='Tigr - JTAC', description='JTAC Tigr', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Tigr_233036'), MEDEVAC=true, salvageValue=1, crewSize=4, roles={'JTAC'}, jtac={ platform='ground' } }
cat['RED_URAL4320_AMMO'] = { menuCategory='Support', menu='Ural-4320-31 Ammo Truck', description='Ural-4320-31 Ammo Truck', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Ural-4320-31'), salvageValue=1, crewSize=2 }
cat['RED_ATZ10_TANKER'] = { menuCategory='Support', menu='ATZ-10 Refueler', description='ATZ-10 Refueler', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ATZ-10'), salvageValue=1, crewSize=2 }
cat['RED_EWR_1L13'] = { menuCategory='Support', menu='EWR Radar 1L13', description='EWR Radar 1L13', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('1L13 EWR'), salvageValue=1, crewSize=3 }
-- Artillery (BLUE)
cat['BLUE_MLRS_CRATE'] = { hidden=true, description='MLRS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_MLRS'] = { menuCategory='Artillery', menu='MLRS', description='MLRS', dcsCargoType='container_cargo', requires={ BLUE_MLRS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MLRS'), salvageValue=2, crewSize=3 }
cat['BLUE_SMERCH_CM_CRATE'] = { hidden=true, description='Smerch (CM) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_SMERCH_CM'] = { menuCategory='Artillery', menu='Smerch_CM', description='Smerch (CM)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_CM_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch'), salvageValue=2, crewSize=3 }
cat['BLUE_L118_105MM'] = { menuCategory='Artillery', menu='L118 Light Artillery 105mm', description='L118 105mm', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('L118_Unit'), salvageValue=1, crewSize=5 }
cat['BLUE_SMERCH_HE_CRATE'] = { hidden=true, description='Smerch (HE) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_SMERCH_HE'] = { menuCategory='Artillery', menu='Smerch_HE', description='Smerch (HE)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_HE_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch_HE'), salvageValue=2, crewSize=3 }
cat['BLUE_M109_CRATE'] = { hidden=true, description='M-109 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M109'] = { menuCategory='Artillery', menu='M-109', description='M-109', dcsCargoType='container_cargo', requires={ BLUE_M109_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-109'), salvageValue=2, crewSize=4 }
-- Artillery (RED)
cat['RED_GVOZDIKA_CRATE'] = { hidden=true, description='SAU Gvozdika crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_GVOZDika'] = { menuCategory='Artillery', menu='SAU Gvozdika', description='SAU Gvozdika', dcsCargoType='container_cargo', requires={ RED_GVOZDIKA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Gvozdika'), salvageValue=2, crewSize=3 }
cat['RED_2S19_MSTA_CRATE'] = { hidden=true, description='SPH 2S19 Msta crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_2S19_MSTA'] = { menuCategory='Artillery', menu='SPH 2S19 Msta', description='SPH 2S19 Msta', dcsCargoType='container_cargo', requires={ RED_2S19_MSTA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Msta'), salvageValue=2, crewSize=4 }
cat['RED_URAGAN_BM27_CRATE'] = { hidden=true, description='Uragan BM-27 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
cat['RED_URAGAN_BM27'] = { menuCategory='Artillery', menu='Uragan_BM-27', description='Uragan BM-27', dcsCargoType='container_cargo', requires={ RED_URAGAN_BM27_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Uragan_BM-27'), salvageValue=2, crewSize=3 }
cat['RED_BM21_GRAD_CRATE'] = { hidden=true, description='BM-21 Grad crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_BM21_GRAD'] = { menuCategory='Artillery', menu='BM-21 Grad Ural', description='BM-21 Grad Ural', dcsCargoType='container_cargo', requires={ RED_BM21_GRAD_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Grad-URAL'), salvageValue=2, crewSize=3 }
cat['RED_PLZ05_CRATE'] = { hidden=true, description='PLZ-05 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
cat['RED_PLZ05'] = { menuCategory='Artillery', menu='PLZ-05 Mobile Artillery', description='PLZ-05', dcsCargoType='container_cargo', requires={ RED_PLZ05_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('PLZ05'), salvageValue=2, crewSize=4 }
-- AAA (BLUE)
cat['BLUE_GEPARD'] = { menuCategory='AAA', menu='Gepard AAA', description='Gepard AAA', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Gepard'), salvageValue=1, crewSize=3 }
cat['BLUE_CRAM'] = { menuCategory='AAA', menu='LPWS C-RAM', description='LPWS C-RAM', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('HEMTT_C-RAM_Phalanx'), salvageValue=1, crewSize=2 }
cat['BLUE_VULCAN_M163'] = { menuCategory='AAA', menu='SPAAA Vulcan M163', description='Vulcan M163', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Vulcan'), salvageValue=1, crewSize=2 }
cat['BLUE_BOFORS40'] = { menuCategory='AAA', menu='Bofors 40mm', description='Bofors 40mm', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('bofors40'), salvageValue=1, crewSize=4 }
-- AAA (RED)
cat['RED_URAL_ZU23'] = { menuCategory='AAA', menu='Ural-375 ZU-23', description='Ural-375 ZU-23', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND, build=singleUnit('Ural-375 ZU-23'), salvageValue=1, crewSize=3 }
cat['RED_SHILKA'] = { menuCategory='AAA', menu='ZSU-23-4 Shilka', description='ZSU-23-4 Shilka', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU-23-4 Shilka'), salvageValue=1, crewSize=3 }
cat['RED_ZSU57_2'] = { menuCategory='AAA', menu='ZSU_57_2', description='ZSU_57_2', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU_57_2'), salvageValue=1, crewSize=3 }
cat['BLUE_M1097_AVENGER_CRATE'] = { hidden=true, description='M1097 Avenger crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M1097_AVENGER'] = { menuCategory='SAM short range', menu='M1097 Avenger', description='M1097 Avenger', dcsCargoType='container_cargo', requires={ BLUE_M1097_AVENGER_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1097 Avenger') }
cat['BLUE_M48_CHAPARRAL_CRATE'] = { hidden=true, description='M48 Chaparral crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_M48_CHAPARRAL'] = { menuCategory='SAM short range', menu='M48 Chaparral', description='M48 Chaparral', dcsCargoType='container_cargo', requires={ BLUE_M48_CHAPARRAL_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M48 Chaparral') }
cat['BLUE_ROLAND_ADS_CRATE'] = { hidden=true, description='Roland ADS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
cat['BLUE_ROLAND_ADS'] = { menuCategory='SAM short range', menu='Roland ADS', description='Roland ADS', dcsCargoType='container_cargo', requires={ BLUE_ROLAND_ADS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Roland ADS') }
cat['BLUE_M6_LINEBACKER'] = { menuCategory='SAM short range', menu='M6 Linebacker', description='M6 Linebacker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M6 Linebacker') }
cat['BLUE_RAPIER_LN'] = { menuCategory='SAM short range', menu='Rapier Launcher', description='Rapier Launcher', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_launcher') }
cat['BLUE_RAPIER_SR'] = { menuCategory='SAM short range', menu='Rapier SR', description='Rapier SR', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_blindfire_radar') }
cat['BLUE_RAPIER_TR'] = { menuCategory='SAM short range', menu='Rapier Tracker', description='Rapier Tracker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_optical_tracker_unit') }
cat['BLUE_RAPIER_SITE'] = { menuCategory='SAM short range', menu='Rapier - All crates', description='Rapier Site', dcsCargoType='container_cargo', requires={ BLUE_RAPIER_LN=1, BLUE_RAPIER_SR=1, BLUE_RAPIER_TR=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='rapier_fsa_launcher'}, {type='rapier_fsa_blindfire_radar', dx=12, dz=6}, {type='rapier_fsa_optical_tracker_unit', dx=-12, dz=6} }) }
-- SAM short range (RED)
cat['RED_OSA_9K33_CRATE'] = { hidden=true, description='9K33 Osa crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_OSA_9K33'] = { menuCategory='SAM short range', menu='9K33 Osa', description='9K33 Osa', dcsCargoType='container_cargo', requires={ RED_OSA_9K33_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Osa 9A33 ln') }
cat['RED_STRELA1_9P31_CRATE'] = { hidden=true, description='9P31 Strela-1 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_STRELA1_9P31'] = { menuCategory='SAM short range', menu='9P31 Strela-1', description='9P31 Strela-1', dcsCargoType='container_cargo', requires={ RED_STRELA1_9P31_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-1 9P31') }
cat['RED_TUNGUSKA_2S6_CRATE'] = { hidden=true, description='2K22 Tunguska crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_TUNGUSKA_2S6'] = { menuCategory='SAM short range', menu='2K22 Tunguska', description='2K22 Tunguska', dcsCargoType='container_cargo', requires={ RED_TUNGUSKA_2S6_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('2S6 Tunguska') }
cat['RED_STRELA10M3_CRATE'] = { hidden=true, description='SA-13 Strela-10M3 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
cat['RED_STRELA10M3'] = { menuCategory='SAM short range', menu='SA-13 Strela-10M3', description='SA-13 Strela-10M3', dcsCargoType='container_cargo', requires={ RED_STRELA10M3_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-10M3') }
-- HQ-7 components and site
cat['RED_HQ7_LN_CRATE'] = { hidden=true, description='HQ-7 Launcher crate', dcsCargoType='container_cargo', required=1, initialStock=20, side=RED, category=Group.Category.GROUND }
cat['RED_HQ7_LN'] = { menuCategory='SAM short range', menu='HQ-7_Launcher', description='HQ-7 Launcher', dcsCargoType='container_cargo', requires={ RED_HQ7_LN_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_LN_SP') }
cat['RED_HQ7_STR'] = { menuCategory='SAM short range', menu='HQ-7_STR_SP', description='HQ-7 STR', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_STR_SP') }
cat['RED_HQ7_SITE'] = { menuCategory='SAM short range', menu='HQ-7 - All crates', description='HQ-7 Site', dcsCargoType='container_cargo', requires={ RED_HQ7_LN=1, RED_HQ7_STR=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='HQ-7_LN_SP'}, {type='HQ-7_STR_SP', dx=10, dz=8} }) }
-- SAM mid range (BLUE) HAWK + NASAMS
cat['BLUE_HAWK_LN'] = { menuCategory='SAM mid range', menu='HAWK Launcher', description='HAWK Launcher', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk ln') }
cat['BLUE_HAWK_SR'] = { menuCategory='SAM mid range', menu='HAWK Search Radar', description='HAWK SR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk sr') }
cat['BLUE_HAWK_TR'] = { menuCategory='SAM mid range', menu='HAWK Track Radar', description='HAWK TR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk tr') }
cat['BLUE_HAWK_PCP'] = { menuCategory='SAM mid range', menu='HAWK PCP', description='HAWK PCP', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk pcp') }
cat['BLUE_HAWK_CWAR'] = { menuCategory='SAM mid range', menu='HAWK CWAR', description='HAWK CWAR', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Hawk cwar') }
cat['BLUE_HAWK_SITE'] = { menuCategory='SAM mid range', menu='HAWK - All crates', description='HAWK Site', dcsCargoType='container_cargo', requires={ BLUE_HAWK_LN=1, BLUE_HAWK_SR=1, BLUE_HAWK_TR=1, BLUE_HAWK_PCP=1, BLUE_HAWK_CWAR=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='Hawk ln'}, {type='Hawk sr', dx=12, dz=8}, {type='Hawk tr', dx=-12, dz=8}, {type='Hawk pcp', dx=18, dz=12}, {type='Hawk cwar', dx=-18, dz=12} }) }
-- HAWK site repair/augment (adds +1 launcher, repairs site by respawn)
cat['BLUE_HAWK_REPAIR'] = { menuCategory='SAM mid range', menu='HAWK Repair/Launcher +1', description='HAWK Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
-- Build is handled specially in CTLD:BuildSpecificAtGroup for isRepair entries
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['BLUE_NASAMS_LN'] = { menuCategory='SAM mid range', menu='NASAMS Launcher 120C', description='NASAMS LN 120C', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_LN_C') }
cat['BLUE_NASAMS_RADAR'] = { menuCategory='SAM mid range', menu='NASAMS Search/Track Radar', description='NASAMS Radar', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_Radar_MPQ64F1') }
cat['BLUE_NASAMS_CP'] = { menuCategory='SAM mid range', menu='NASAMS Command Post', description='NASAMS CP', dcsCargoType='container_cargo', required=1, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('NASAMS_Command_Post') }
cat['BLUE_NASAMS_SITE'] = { menuCategory='SAM mid range', menu='NASAMS - All crates', description='NASAMS Site', dcsCargoType='container_cargo', requires={ BLUE_NASAMS_LN=1, BLUE_NASAMS_RADAR=1, BLUE_NASAMS_CP=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='NASAMS_LN_C'}, {type='NASAMS_Radar_MPQ64F1', dx=12, dz=8}, {type='NASAMS_Command_Post', dx=-12, dz=8} }) }
-- SAM mid range (RED) KUB
cat['RED_KUB_LN'] = { menuCategory='SAM mid range', menu='KUB Launcher', description='KUB Launcher', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Kub 2P25 ln') }
cat['RED_KUB_RADAR'] = { menuCategory='SAM mid range', menu='KUB Radar', description='KUB Radar', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Kub 1S91 str') }
cat['RED_KUB_SITE'] = { menuCategory='SAM mid range', menu='KUB - All crates', description='KUB Site', dcsCargoType='container_cargo', requires={ RED_KUB_LN=1, RED_KUB_RADAR=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='Kub 2P25 ln'}, {type='Kub 1S91 str', dx=12, dz=8} }) }
-- KUB site repair/augment (adds +1 launcher, repairs site by respawn)
cat['RED_KUB_REPAIR'] = { menuCategory='SAM mid range', menu='KUB Repair/Launcher +1', description='KUB Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=8, side=RED, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- SAM long range (BLUE) Patriot
cat['BLUE_PATRIOT_LN'] = { menuCategory='SAM long range', menu='Patriot Launcher', description='Patriot Launcher', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot ln') }
cat['BLUE_PATRIOT_RADAR'] = { menuCategory='SAM long range', menu='Patriot Radar', description='Patriot Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot str') }
cat['BLUE_PATRIOT_ECS'] = { menuCategory='SAM long range', menu='Patriot ECS', description='Patriot ECS', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Patriot ECS') }
cat['BLUE_PATRIOT_SITE'] = { menuCategory='SAM long range', menu='Patriot - All crates', description='Patriot Site', dcsCargoType='container_cargo', requires={ BLUE_PATRIOT_LN=1, BLUE_PATRIOT_RADAR=1, BLUE_PATRIOT_ECS=1 }, initialStock=0, side=BLUE, category=Group.Category.GROUND,
build=multiUnits({ {type='Patriot ln'}, {type='Patriot str', dx=14, dz=10}, {type='Patriot ECS', dx=-14, dz=10} }) }
-- Patriot site repair/augment (adds +1 launcher, repairs site by respawn)
cat['BLUE_PATRIOT_REPAIR'] = { menuCategory='SAM long range', menu='Patriot Repair/Launcher +1', description='Patriot Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=6, side=BLUE, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- SAM long range (RED) BUK
cat['RED_BUK_LN'] = { menuCategory='SAM long range', menu='BUK Launcher', description='BUK Launcher', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk LN 9A310M1') }
cat['RED_BUK_SR'] = { menuCategory='SAM long range', menu='BUK Search Radar', description='BUK Search Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk SR 9S18M1') }
cat['RED_BUK_CC'] = { menuCategory='SAM long range', menu='BUK CC Radar', description='BUK CC Radar', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('SA-11 Buk CC 9S470M1') }
cat['RED_BUK_SITE'] = { menuCategory='SAM long range', menu='BUK - All crates', description='BUK Site', dcsCargoType='container_cargo', requires={ RED_BUK_LN=1, RED_BUK_SR=1, RED_BUK_CC=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
build=multiUnits({ {type='SA-11 Buk LN 9A310M1'}, {type='SA-11 Buk SR 9S18M1', dx=12, dz=8}, {type='SA-11 Buk CC 9S470M1', dx=-12, dz=8} }) }
-- BUK site repair/augment (adds +1 launcher, repairs site by respawn)
cat['RED_BUK_REPAIR'] = { menuCategory='SAM long range', menu='BUK Repair/Launcher +1', description='BUK Repair (adds launcher)', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, isRepair=true, build=function(point, headingDeg)
return singleUnit('Ural-375')(point, headingDeg)
end }
-- Drones (JTAC)
cat['BLUE_MQ9'] = { menuCategory='Drones', menu='MQ-9 Reaper - JTAC', description='MQ-9 JTAC', dcsCargoType='container_cargo', required=1, initialStock=3, side=BLUE, category=Group.Category.AIRPLANE, build=singleAirUnit('MQ-9 Reaper'), roles={'JTAC'}, jtac={ platform='air' } }
cat['RED_WINGLOONG'] = { menuCategory='Drones', menu='WingLoong-I - JTAC', description='WingLoong-I JTAC', dcsCargoType='container_cargo', required=1, initialStock=3, side=RED, category=Group.Category.AIRPLANE, build=singleAirUnit('WingLoong-I'), roles={'JTAC'}, jtac={ platform='air' } }
-- FOB crates (Support) — three small crates build a FOB site
cat['FOB_SMALL'] = { hidden=true, description='FOB small crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
-- spawns a harmless placeholder truck for visibility; consumed by FOB_SITE build
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['FOB_SITE'] = { menuCategory='Support', menu='FOB Crates - All', description='FOB Site', isFOB=true, dcsCargoType='container_cargo', requires={ FOB_SMALL=3 }, initialStock=0, side=nil, category=Group.Category.GROUND,
build=multiUnits({ {type='HEMTT TFFT'}, {type='Ural-375 PBU', dx=10, dz=8}, {type='Ural-375', dx=-10, dz=8} }) }
-- Mobile MASH (Support) — three crates build a Mobile MASH unit
cat['MOBILE_MASH_SMALL'] = { hidden=true, description='Mobile MASH crate', dcsCargoType='container_cargo', required=1, initialStock=6, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
-- spawns placeholder truck for visibility; consumed by MOBILE_MASH build
return singleUnit('Ural-375')(point, headingDeg)
end }
cat['BLUE_MOBILE_MASH'] = { menuCategory='Support', menu='Mobile MASH - All', description='Blue Mobile MASH Unit', isMobileMASH=true, dcsCargoType='container_cargo', requires={ MOBILE_MASH_SMALL=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-113') }
cat['RED_MOBILE_MASH'] = { menuCategory='Support', menu='Mobile MASH - All', description='Red Mobile MASH Unit', isMobileMASH=true, dcsCargoType='container_cargo', requires={ MOBILE_MASH_SMALL=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR_D') }
-- =========================
-- Troop Type Definitions
-- =========================
-- These define the composition of troop squads for Load/Unload Troops (NOT crates)
-- Structure: { label, size, unitsBlue, unitsRed, units (fallback) }
local troops = {}
-- Assault Squad: general-purpose rifles/MG
troops['AS'] = {
label = 'Assault Squad',
size = 8,
unitsBlue = { 'Soldier M4', 'Soldier M249' },
unitsRed = { 'Infantry AK', 'Infantry AK ver3' },
units = { 'Infantry AK' },
}
-- MANPADS Team: Anti-air element
troops['AA'] = {
label = 'MANPADS Team',
size = 4,
unitsBlue = { 'Soldier stinger', 'Stinger comm' },
unitsRed = { 'SA-18 Igla-S manpad', 'SA-18 Igla comm' },
units = { 'Infantry AK' },
}
-- AT Team: Anti-tank element
troops['AT'] = {
label = 'AT Team',
size = 4,
unitsBlue = { 'Soldier RPG', 'Soldier RPG' },
unitsRed = { 'Soldier RPG', 'Soldier RPG' },
units = { 'Infantry AK' },
}
-- Mortar Team: Indirect fire element
troops['AR'] = {
label = 'Mortar Team',
size = 4,
unitsBlue = { '2B11 mortar' },
unitsRed = { '2B11 mortar' },
units = { '2B11 mortar' },
}
-- Export troop types
_CTLD_TROOP_TYPES = troops
-- Also export as a global for mission setups that load via DO SCRIPT FILE (no return capture)
_CTLD_EXTRACTED_CATALOG = cat
return cat

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

View File

@ -1,48 +0,0 @@
MOOSE Dual Coalition Zone Capture - Example Mission
===================================================
MISSION OVERVIEW:
This is a demonstration mission showcasing the MOOSE Dual Coalition Zone Capture system's
dynamic behavior and visual feedback mechanisms.
SCENARIO:
Four strategic zones have been marked across the battlefield:
• Zone 1: Initially controlled by RED forces
• Zone 2: Initially controlled by BLUE forces
• Zone 3 & 4: Neutral territory, awaiting capture
DEMONSTRATION FEATURES:
Ground units from both coalitions patrol the battlefield in a continuous cycle, moving between
zones to demonstrate the system's real-time response to territorial changes. Units are configured
in a non-combat mode to clearly showcase zone state transitions without interference from combat.
WHAT YOU'LL SEE:
✓ Color-coded zone boundaries changing as units enter/exit (Red/Blue/Green/Orange)
✓ Tactical information markers updating with force compositions
✓ Smoke signals marking zone status changes
✓ Automatic messaging system announcing captures and attacks
✓ F10 radio menu commands for zone status queries
✓ Victory condition tracking as zones are captured
OBSERVING THE DEMONSTRATION:
• Use F10 Map to view zone boundaries and tactical markers
• Monitor chat messages for zone status updates
• Access F10 → Zone Control → "Get Zone Status Report" for detailed information
• Watch as zones transition between Empty → Captured → Attacked → Guarded states
• Victory condition triggers when one coalition controls all four zones
PURPOSE:
This mission serves as both a tutorial and testing environment for mission makers looking to
implement the zone capture system in their own scenarios. It demonstrates proper configuration,
visual feedback, and system behavior without the chaos of active combat.
MISSION MAKER NOTES:
Examine the mission file to see:
- Proper trigger zone naming conventions
- BLUEHQ and REDHQ group placement
- Script loading order in triggers
- Zone configuration in the Lua file
- Unit waypoint setup for continuous patrol demonstration
This is a reference implementation - feel free to modify, expand, or use as a template for your
own mission designs!

View File

@ -1,845 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MOOSE Dual Coalition Zone Capture - Mission Maker Guide</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
overflow: hidden;
}
header {
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
color: white;
padding: 40px;
text-align: center;
}
header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
header .subtitle {
font-size: 1.2em;
opacity: 0.9;
font-weight: 300;
}
.content {
padding: 40px;
}
h2 {
color: #2c3e50;
margin-top: 30px;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 3px solid #667eea;
font-size: 1.8em;
}
h3 {
color: #34495e;
margin-top: 25px;
margin-bottom: 12px;
font-size: 1.4em;
}
h4 {
color: #555;
margin-top: 20px;
margin-bottom: 10px;
font-size: 1.2em;
}
p {
margin-bottom: 15px;
text-align: justify;
}
ul, ol {
margin-left: 30px;
margin-bottom: 20px;
}
li {
margin-bottom: 8px;
}
.feature-box {
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.warning-box {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.success-box {
background: #d4edda;
border-left: 4px solid #28a745;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.error-box {
background: #f8d7da;
border-left: 4px solid #dc3545;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
code {
background: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
color: #e83e8c;
}
pre {
background: #2c3e50;
color: #ecf0f1;
padding: 20px;
border-radius: 5px;
overflow-x: auto;
margin: 20px 0;
font-family: 'Courier New', monospace;
line-height: 1.4;
}
pre code {
background: none;
color: inherit;
padding: 0;
}
.step-number {
display: inline-block;
background: #667eea;
color: white;
width: 30px;
height: 30px;
border-radius: 50%;
text-align: center;
line-height: 30px;
font-weight: bold;
margin-right: 10px;
}
.quick-ref {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 5px;
margin: 20px 0;
}
.quick-ref h3 {
color: white;
margin-top: 0;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background: #667eea;
color: white;
font-weight: bold;
}
tr:hover {
background: #f5f5f5;
}
.color-indicator {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 3px;
vertical-align: middle;
margin-right: 8px;
border: 1px solid #333;
}
.red { background: #ff0000; }
.blue { background: #0000ff; }
.green { background: #00ff00; }
.orange { background: #ff8800; }
footer {
background: #2c3e50;
color: white;
text-align: center;
padding: 20px;
font-size: 0.9em;
}
.toc {
background: #f8f9fa;
padding: 20px;
border-radius: 5px;
margin: 20px 0;
}
.toc ul {
list-style: none;
margin-left: 0;
}
.toc li {
padding: 5px 0;
}
.toc a {
color: #667eea;
text-decoration: none;
font-weight: 500;
}
.toc a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🎯 MOOSE Dual Coalition Zone Capture</h1>
<div class="subtitle">Complete Mission Maker Implementation Guide</div>
</header>
<div class="content">
<!-- Introduction -->
<section id="introduction">
<h2>📖 Introduction</h2>
<p>
The <strong>MOOSE Dual Coalition Zone Capture</strong> system is a fully-featured, balanced territorial control framework for DCS World missions.
This script creates dynamic capture zones that both RED and BLUE coalitions can fight over, with automatic victory detection,
tactical information displays, and comprehensive player feedback systems.
</p>
<div class="feature-box">
<h3>✨ Key Features</h3>
<ul>
<li><strong>Easy Configuration:</strong> Define zones with simple Lua tables - no complex coding required</li>
<li><strong>Dual Coalition Support:</strong> Both RED and BLUE can capture zones and win</li>
<li><strong>Dynamic Visual Feedback:</strong> Color-coded zone boundaries, smoke markers, and flares</li>
<li><strong>Tactical Information:</strong> Real-time unit counts and MGRS coordinates for small enemy forces</li>
<li><strong>F10 Radio Menu:</strong> Players can check status, progress, and refresh visuals</li>
<li><strong>Automatic Victory Detection:</strong> First coalition to capture all zones wins</li>
<li><strong>Flexible Initial Ownership:</strong> Set zones to start under RED, BLUE, or NEUTRAL control</li>
<li><strong>Comprehensive Logging:</strong> Detailed debug output for troubleshooting</li>
</ul>
</div>
</section>
<!-- Table of Contents -->
<div class="toc">
<h3>📑 Table of Contents</h3>
<ul>
<li><a href="#requirements">1. Requirements</a></li>
<li><a href="#quick-start">2. Quick Start Guide</a></li>
<li><a href="#detailed-setup">3. Detailed Setup Instructions</a></li>
<li><a href="#configuration">4. Configuration Options</a></li>
<li><a href="#zone-states">5. Understanding Zone States</a></li>
<li><a href="#player-features">6. Player Features</a></li>
<li><a href="#troubleshooting">7. Troubleshooting</a></li>
<li><a href="#advanced">8. Advanced Customization</a></li>
</ul>
</div>
<!-- Requirements -->
<section id="requirements">
<h2>📋 Requirements</h2>
<h3>Essential Components</h3>
<ol>
<li><strong>DCS World</strong> - Any recent version</li>
<li><strong>MOOSE Framework</strong> - Latest version recommended
<ul>
<li>Download from: <a href="https://github.com/FlightControl-Master/MOOSE" target="_blank">https://github.com/FlightControl-Master/MOOSE</a></li>
<li>You need the <code>Moose_.lua</code> file</li>
</ul>
</li>
<li><strong>This Script</strong> - <code>Moose_DualCoalitionZoneCapture.lua</code></li>
</ol>
<h3>Mission Prerequisites</h3>
<div class="warning-box">
<h4>⚠️ Required Mission Elements</h4>
<p>Your mission MUST contain the following groups (case-sensitive):</p>
<ul>
<li><code>BLUEHQ</code> - A BLUE coalition ground unit group (can be a single unit)</li>
<li><code>REDHQ</code> - A RED coalition ground unit group (can be a single unit)</li>
</ul>
<p><strong>Why?</strong> These groups serve as command centers for the messaging system. They can be placed anywhere,
even hidden or spawned late. Without them, the script will fail to initialize.</p>
</div>
</section>
<!-- Quick Start -->
<section id="quick-start">
<h2>🚀 Quick Start Guide</h2>
<p>Get up and running in 5 minutes:</p>
<h3><span class="step-number">1</span>Mission Editor Setup</h3>
<ol>
<li>Create trigger zones at locations you want to be capturable (e.g., airbases, towns)</li>
<li>Name each zone starting with <code>Capture</code> - for example:
<ul>
<li><code>Capture Severomorsk</code></li>
<li><code>Capture Murmansk</code></li>
<li><code>Capture Zone-1</code></li>
</ul>
</li>
<li>Create two ground unit groups named <code>BLUEHQ</code> and <code>REDHQ</code></li>
</ol>
<h3><span class="step-number">2</span>Load MOOSE Framework</h3>
<ol>
<li>In Mission Editor → Triggers → New Trigger</li>
<li>Type: <strong>MISSION START</strong></li>
<li>Actions → DO SCRIPT FILE → Select <code>Moose_.lua</code></li>
</ol>
<h3><span class="step-number">3</span>Configure Zone Ownership</h3>
<p>Open <code>Moose_DualCoalitionZoneCapture.lua</code> in a text editor and edit the <code>ZONE_CONFIG</code> section:</p>
<pre><code>local ZONE_CONFIG = {
RED = {
"Capture Severomorsk",
"Capture Murmansk"
},
BLUE = {
"Capture Banak"
},
NEUTRAL = {
"Capture Contested Valley"
}
}</code></pre>
<h3><span class="step-number">4</span>Load the Script</h3>
<ol>
<li>In the same trigger, add another action</li>
<li>Actions → DO SCRIPT FILE → Select <code>Moose_DualCoalitionZoneCapture.lua</code></li>
</ol>
<div class="success-box">
<h4>✅ Done!</h4>
<p>Save your mission, start it, and the zone capture system will automatically initialize.
Check the DCS.log file to verify successful zone creation.</p>
</div>
</section>
<!-- Detailed Setup -->
<section id="detailed-setup">
<h2>📐 Detailed Setup Instructions</h2>
<h3>Step 1: Creating Trigger Zones</h3>
<h4>In DCS Mission Editor:</h4>
<ol>
<li>Click the <strong>Trigger Zones</strong> button (or press F5)</li>
<li>Click <strong>New</strong> to create a zone</li>
<li>Set the zone type to <strong>Circular</strong> or <strong>Polygon</strong></li>
<li>Position the zone over the area you want to be capturable</li>
<li><strong>CRITICAL:</strong> Name the zone with any name you choose (e.g., "Capture Severomorsk")</li>
<li>Adjust the size to encompass the tactical area</li>
<li>Repeat for all capture locations</li>
</ol>
<div class="warning-box">
<h4>⚠️ Zone Naming Rules</h4>
<ul>
<li>Zone names in the mission editor MUST EXACTLY match the names in your Lua config</li>
<li>Names are case-sensitive: <code>Capture Zone-1</code><code>capture zone-1</code></li>
<li>Spaces matter: <code>Capture Zone-1</code><code>CaptureZone-1</code></li>
<li>Best practice: Use the "Capture [Location]" format for clarity</li>
</ul>
</div>
<h3>Step 2: Creating Command Centers</h3>
<p>The script requires two "command center" groups to function:</p>
<h4>BLUEHQ Setup:</h4>
<ol>
<li>Place any BLUE ground unit (e.g., M-1 Abrams, Infantry, HMMWV)</li>
<li>Name the GROUP (not the unit): <code>BLUEHQ</code></li>
<li>You can make it immortal via triggers if desired</li>
<li>Location doesn't matter - can even be in an unreachable area</li>
</ol>
<h4>REDHQ Setup:</h4>
<ol>
<li>Place any RED ground unit (e.g., T-90, BTR-80, Infantry)</li>
<li>Name the GROUP: <code>REDHQ</code></li>
<li>Same rules as BLUEHQ</li>
</ol>
<div class="feature-box">
<h4>💡 Pro Tip: Hidden Command Centers</h4>
<p>You can hide these units by:</p>
<ul>
<li>Placing them far off-map</li>
<li>Setting them to "UNCONTROLLED" start state</li>
<li>Using the "Late Activation" option</li>
<li>Adding a trigger to activate them after mission start</li>
</ul>
<p>They only need to exist in the mission file - they don't need to be active or visible.</p>
</div>
<h3>Step 3: Script Loading Order</h3>
<p>Create a MISSION START trigger with these actions <strong>IN ORDER</strong>:</p>
<ol>
<li><strong>DO SCRIPT FILE:</strong> <code>Moose_.lua</code> (MUST be first)</li>
<li><strong>DO SCRIPT FILE:</strong> <code>Moose_DualCoalitionZoneCapture.lua</code> (MUST be after MOOSE)</li>
<li>(Optional) Any other scripts that depend on this system</li>
</ol>
<div class="error-box">
<h4>❌ Common Loading Errors</h4>
<ul>
<li><strong>Script loaded before MOOSE:</strong> Will crash with "attempt to index a nil value"</li>
<li><strong>Wrong trigger type:</strong> Must be MISSION START, not TIME MORE or ONCE</li>
<li><strong>DO SCRIPT instead of DO SCRIPT FILE:</strong> Use FILE to load external Lua files</li>
</ul>
</div>
</section>
<!-- Configuration -->
<section id="configuration">
<h2>⚙️ Configuration Options</h2>
<h3>Zone Ownership Configuration</h3>
<p>Edit the <code>ZONE_CONFIG</code> table at the top of the script:</p>
<pre><code>local ZONE_CONFIG = {
-- Zones that start under RED coalition control
RED = {
"Capture Severomorsk-1",
"Capture Severomorsk-3",
"Capture Murmansk International"
},
-- Zones that start under BLUE coalition control
BLUE = {
"Capture Banak",
"Capture Kirkenes"
},
-- Zones that start neutral (empty/uncontrolled)
NEUTRAL = {
"Capture Contested Valley",
"Capture No Man's Land"
}
}</code></pre>
<div class="warning-box">
<h4>⚠️ Important: Initial Ownership vs. Unit Presence</h4>
<p>The ownership you set here is the <strong>starting state</strong> of the zone. However:</p>
<ul>
<li>If you place RED units in a zone configured as BLUE, the zone will immediately flip to RED when the mission starts</li>
<li>Empty zones (no units) will respect your configured ownership</li>
<li>The script scans for units every 30 seconds (configurable)</li>
</ul>
<p><strong>Best Practice:</strong> Either start zones empty/neutral, or ensure ground units match the configured ownership.</p>
</div>
<h3>Advanced Settings</h3>
<pre><code>local ZONE_SETTINGS = {
guardDelay = 1, -- Seconds before entering Guard state after capture
scanInterval = 30, -- How often to scan for units in zones (seconds)
captureScore = 200 -- Points awarded for capturing a zone
}</code></pre>
<table>
<tr>
<th>Setting</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td><code>guardDelay</code></td>
<td>1</td>
<td>Delay (in seconds) before a captured zone enters the "Guarded" state. Shorter = faster transitions.</td>
</tr>
<tr>
<td><code>scanInterval</code></td>
<td>30</td>
<td>How frequently the script checks for units in zones. Lower = more responsive but more CPU usage.</td>
</tr>
<tr>
<td><code>captureScore</code></td>
<td>200</td>
<td>Points awarded when a zone is captured (requires MOOSE scoring system to be active).</td>
</tr>
</table>
</section>
<!-- Zone States -->
<section id="zone-states">
<h2>🎨 Understanding Zone States</h2>
<p>Zones can be in one of four states, each with distinct visual indicators:</p>
<table>
<tr>
<th>State</th>
<th>Color</th>
<th>Smoke</th>
<th>Description</th>
</tr>
<tr>
<td><strong>RED Controlled</strong></td>
<td><span class="color-indicator red"></span>Red Border</td>
<td>Red Smoke</td>
<td>Zone is secured by RED coalition forces</td>
</tr>
<tr>
<td><strong>BLUE Controlled</strong></td>
<td><span class="color-indicator blue"></span>Blue Border</td>
<td>Blue Smoke</td>
<td>Zone is secured by BLUE coalition forces</td>
</tr>
<tr>
<td><strong>Neutral/Empty</strong></td>
<td><span class="color-indicator green"></span>Green Border</td>
<td>Green Smoke</td>
<td>Zone is uncontrolled and can be captured by either side</td>
</tr>
<tr>
<td><strong>Contested/Attacked</strong></td>
<td><span class="color-indicator orange"></span>Orange Border</td>
<td>White Smoke</td>
<td>Zone is under attack - both coalitions have units present</td>
</tr>
</table>
<h3>State Transitions</h3>
<div class="feature-box">
<h4>How Zones Change Ownership:</h4>
<ol>
<li><strong>Empty → Captured:</strong> Move ground units into an empty zone</li>
<li><strong>Captured → Attacked:</strong> Enemy forces enter a controlled zone</li>
<li><strong>Attacked → Captured:</strong> One side eliminates all enemy forces</li>
<li><strong>Captured → Empty:</strong> All units leave the zone</li>
<li><strong>Captured → Guard:</strong> Zone remains secured after a brief delay</li>
</ol>
</div>
<h3>Tactical Information Markers</h3>
<p>Each zone displays a tactical marker with real-time information:</p>
<ul>
<li><strong>Force Counts:</strong> Shows R: (RED units), B: (BLUE units)</li>
<li><strong>MGRS Coordinates:</strong> When ≤10 enemy units, shows their exact positions</li>
<li><strong>Coalition-Specific:</strong> Each side sees their enemies marked</li>
<li><strong>Auto-Refresh:</strong> Updates every 60 seconds</li>
</ul>
<p><strong>Example tactical marker:</strong></p>
<pre><code>TACTICAL: Capture Severomorsk-1
Forces: R:5 B:12
TGTS: T-90@38U LV 12345 67890, BTR-80@38U LV 12346 67891</code></pre>
</section>
<!-- Player Features -->
<section id="player-features">
<h2>👥 Player Features</h2>
<h3>F10 Radio Menu Commands</h3>
<p>Players from both coalitions have access to F10 radio menu commands under <strong>"Zone Control"</strong>:</p>
<table>
<tr>
<th>Command</th>
<th>Description</th>
</tr>
<tr>
<td><strong>Get Zone Status Report</strong></td>
<td>Displays current ownership of all zones with detailed breakdown</td>
</tr>
<tr>
<td><strong>Check Victory Progress</strong></td>
<td>Shows percentage toward victory and zones remaining</td>
</tr>
<tr>
<td><strong>Refresh Zone Colors</strong></td>
<td>Manually redraws all zone boundaries (troubleshooting tool)</td>
</tr>
</table>
<h3>Automatic Status Updates</h3>
<p>The script provides automatic notifications:</p>
<ul>
<li><strong>Every 5 minutes:</strong> Zone control report broadcast to both coalitions</li>
<li><strong>On zone capture:</strong> Both sides notified when a zone changes hands</li>
<li><strong>On zone attack:</strong> Alerts when a zone comes under attack</li>
<li><strong>At 80% victory:</strong> Warning that one side is close to winning</li>
<li><strong>On victory:</strong> Dramatic announcement with 60-second countdown</li>
</ul>
<h3>Victory Conditions</h3>
<div class="quick-ref">
<h3>🏆 How to Win</h3>
<p>The first coalition to <strong>capture ALL zones</strong> wins the mission.</p>
<ul>
<li>Total zones must be controlled by one coalition</li>
<li>Victory triggers a 60-second countdown</li>
<li>Celebratory effects: smoke, flares, messages</li>
<li>Mission ends automatically with appropriate user flag set</li>
</ul>
</div>
</section>
<!-- Troubleshooting -->
<section id="troubleshooting">
<h2>🔧 Troubleshooting</h2>
<h3>Script Won't Load</h3>
<div class="error-box">
<h4>❌ Problem: "attempt to index a nil value"</h4>
<p><strong>Cause:</strong> MOOSE framework not loaded before this script</p>
<p><strong>Solution:</strong> Ensure MOOSE is loaded FIRST in your MISSION START trigger</p>
</div>
<div class="error-box">
<h4>❌ Problem: "GROUP:FindByName() returned nil"</h4>
<p><strong>Cause:</strong> BLUEHQ or REDHQ groups don't exist or are misnamed</p>
<p><strong>Solution:</strong> Verify you have groups (not units) named exactly <code>BLUEHQ</code> and <code>REDHQ</code></p>
</div>
<h3>Zones Not Working</h3>
<div class="error-box">
<h4>❌ Problem: "Zone 'X' not found in mission editor!"</h4>
<p><strong>Cause:</strong> Zone name mismatch between Lua config and mission editor</p>
<p><strong>Solution:</strong>
<ol>
<li>Check DCS.log for the exact error message</li>
<li>Open mission editor and verify trigger zone names</li>
<li>Ensure names match EXACTLY (case-sensitive, spaces matter)</li>
<li>Update either the mission or Lua config to match</li>
</ol>
</p>
</div>
<h3>Zones Not Capturing</h3>
<div class="warning-box">
<h4>⚠️ Problem: Units in zone but ownership not changing</h4>
<p><strong>Possible Causes:</strong></p>
<ul>
<li><strong>Wrong unit types:</strong> Only ground units, planes, and helicopters are scanned</li>
<li><strong>Dead units:</strong> Script only counts alive units</li>
<li><strong>Scan timing:</strong> Wait 30 seconds for the next scan cycle</li>
<li><strong>Both coalitions present:</strong> Zone enters "Attacked" state, doesn't flip ownership</li>
</ul>
<p><strong>Solution:</strong> Eliminate all enemy forces to capture the zone</p>
</div>
<h3>Visual Issues</h3>
<div class="feature-box">
<h4>💡 Problem: Zone colors wrong or not showing</h4>
<p><strong>Solutions:</strong></p>
<ul>
<li>Use F10 → Zone Control → "Refresh Zone Colors"</li>
<li>Zone colors auto-refresh every 2 minutes</li>
<li>Check DCS graphics settings (markers must be enabled)</li>
<li>Restart mission if issue persists</li>
</ul>
</div>
<h3>Checking Logs</h3>
<p>The script provides extensive logging. To view:</p>
<ol>
<li>Open <code>DCS.log</code> file in your Saved Games\DCS folder</li>
<li>Search for <code>[CAPTURE Module]</code> or <code>[INIT]</code></li>
<li>Look for initialization messages and error reports</li>
</ol>
<p><strong>Successful initialization looks like:</strong></p>
<pre><code>[CAPTURE Module] [INIT] Starting zone initialization...
[CAPTURE Module] [INIT] Creating zone: Capture Severomorsk-1 (Coalition: RED)
[CAPTURE Module] [INIT] ✓ Zone 'Capture Severomorsk-1' initialized successfully
[CAPTURE Module] [INIT] Zone initialization complete. Total zones created: 11</code></pre>
</section>
<!-- Advanced -->
<section id="advanced">
<h2>🔬 Advanced Customization</h2>
<h3>Adjusting Scan Performance</h3>
<p>If you experience performance issues with many units:</p>
<pre><code>local ZONE_SETTINGS = {
scanInterval = 60, -- Scan less frequently (every 60 seconds)
}</code></pre>
<p>For fast-paced action:</p>
<pre><code>local ZONE_SETTINGS = {
scanInterval = 15, -- Scan more frequently (every 15 seconds)
}</code></pre>
<h3>Disabling Logging</h3>
<p>To reduce log spam, add this BEFORE loading the script:</p>
<pre><code>CAPTURE_ZONE_LOGGING = { enabled = false }</code></pre>
<h3>Mission Integration</h3>
<p>The script sets user flags on victory:</p>
<ul>
<li><code>BLUE_VICTORY</code> = 1 when BLUE wins</li>
<li><code>RED_VICTORY</code> = 1 when RED wins</li>
</ul>
<p>You can use these flags in mission triggers to:</p>
<ul>
<li>End the mission</li>
<li>Trigger victory cutscenes</li>
<li>Award points or bonuses</li>
<li>Transition to next phase</li>
</ul>
<h3>Modifying Messages</h3>
<p>All player messages are in the event handler functions. Search for:</p>
<ul>
<li><code>OnEnterGuarded</code> - Zone secured messages</li>
<li><code>OnEnterCaptured</code> - Zone captured messages</li>
<li><code>OnEnterAttacked</code> - Zone under attack messages</li>
<li><code>CheckVictoryCondition</code> - Victory messages</li>
</ul>
<h3>Zone-Specific Behavior</h3>
<p>To create different behaviors for specific zones, modify the event handlers to check zone names:</p>
<pre><code>local function OnEnterCaptured(ZoneCapture)
local zoneName = ZoneCapture:GetZoneName()
if zoneName == "Capture MainBase" then
-- Special behavior for main base capture
US_CC:MessageTypeToCoalition("CRITICAL: Main base captured!", MESSAGE.Type.Information)
else
-- Standard behavior for other zones
end
end</code></pre>
<h3>Integration with Other Scripts</h3>
<p>Access zone data from other scripts:</p>
<pre><code>-- Get current ownership status
local status = GetZoneOwnershipStatus()
-- Returns: { blue = X, red = Y, neutral = Z, total = N, zones = {...} }
-- Broadcast status manually
BroadcastZoneStatus()
-- Refresh visuals manually
RefreshAllZoneColors()</code></pre>
</section>
<!-- Final Tips -->
<section id="tips">
<h2>💡 Best Practices & Tips</h2>
<div class="success-box">
<h4>✅ Mission Design Tips</h4>
<ul>
<li><strong>Zone Size:</strong> Make zones large enough to encompass tactical areas but not so large they overlap</li>
<li><strong>Zone Placement:</strong> Position over airbases, FOBs, or strategic terrain features</li>
<li><strong>Starting Balance:</strong> Consider giving RED more zones for defensive scenarios, or split evenly for balanced play</li>
<li><strong>Ground Units:</strong> Populate zones with defending forces appropriate to difficulty level</li>
<li><strong>Respawning:</strong> Consider using MOOSE's spawn system to continuously reinforce zones</li>
<li><strong>AI Behavior:</strong> Set AI ground units to "Ground Hold" or "Ground On Road" for best results</li>
</ul>
</div>
<div class="feature-box">
<h4>🎮 Player Experience</h4>
<ul>
<li>Brief players on F10 radio menu commands before mission start</li>
<li>Place zones at recognizable landmarks for easy navigation</li>
<li>Consider adding custom mission briefing with zone locations</li>
<li>Test zone sizes with different unit counts to ensure good balance</li>
<li>Use neutral zones as "no man's land" for dynamic front lines</li>
</ul>
</div>
<div class="quick-ref">
<h3>🚀 Quick Reference Card</h3>
<p><strong>Required Groups:</strong> BLUEHQ, REDHQ</p>
<p><strong>Zone Naming:</strong> Must match exactly between mission and Lua</p>
<p><strong>Load Order:</strong> MOOSE → This Script</p>
<p><strong>Victory Condition:</strong> Capture all zones</p>
<p><strong>F10 Menu:</strong> Zone Control → Status/Progress/Refresh</p>
<p><strong>Log Location:</strong> Saved Games\DCS\Logs\DCS.log</p>
</div>
</section>
<!-- Support -->
<section id="support">
<h2>📞 Support & Resources</h2>
<h3>Script Author</h3>
<div class="feature-box">
<p><strong>Author:</strong> F99th-TracerFacer</p>
<p><strong>Discord Community:</strong> <a href="https://discord.gg/7wBVWKK3" target="_blank">https://discord.gg/7wBVWKK3</a></p>
<p>Join the Discord for support, updates, and discussion about this script and other DCS mission development topics.</p>
</div>
<h3>Additional Resources</h3>
<ul>
<li><strong>MOOSE Documentation:</strong> <a href="https://flightcontrol-master.github.io/MOOSE_DOCS/" target="_blank">https://flightcontrol-master.github.io/MOOSE_DOCS/</a></li>
<li><strong>MOOSE Discord:</strong> <a href="https://discord.gg/gj68fm969S" target="_blank">https://discord.gg/gj68fm969S</a></li>
<li><strong>DCS Forums:</strong> <a href="https://forum.dcs.world" target="_blank">https://forum.dcs.world</a></li>
</ul>
<div class="success-box">
<h4>✨ Version Information</h4>
<p><strong>Script Version:</strong> 2.0 (Dual Coalition)</p>
<p><strong>Author:</strong> F99th-TracerFacer</p>
<p><strong>Last Updated:</strong> October 2025</p>
<p><strong>Compatibility:</strong> DCS World 2.9+, MOOSE Latest</p>
</div>
</section>
</div>
<footer>
<p><strong>MOOSE Dual Coalition Zone Capture System</strong></p>
<p>Created by F99th-TracerFacer for the DCS World Community | Powered by MOOSE Framework</p>
<p>Discord: <a href="https://discord.gg/7wBVWKK3" style="color: #fff; text-decoration: underline;">https://discord.gg/7wBVWKK3</a></p>
<p>© 2025 | This guide is provided as-is for educational purposes</p>
</footer>
</div>
</body>
</html>

View File

@ -1,288 +0,0 @@
# MOOSE Dual Coalition Zone Capture System
A dynamic zone capture and control system for DCS World missions using the MOOSE framework. This script enables territory-based gameplay where RED and BLUE coalitions compete to capture and hold strategic zones across the battlefield.
![Version](https://img.shields.io/badge/version-2.0-blue)
![DCS](https://img.shields.io/badge/DCS-2.9%2B-green)
![MOOSE](https://img.shields.io/badge/MOOSE-Latest-orange)
![License](https://img.shields.io/badge/license-MIT-lightgrey)
## 🎯 Features
- **🎨 Visual Feedback**: Color-coded zone boundaries (Red/Blue/Green/Orange) that change dynamically
- **💨 Smoke Signals**: Automatic smoke markers indicating zone status
- **📍 Tactical Information**: Real-time force composition and MGRS coordinates for enemies
- **🏆 Victory Conditions**: Automatic win detection when one coalition captures all zones
- **📻 F10 Radio Menu**: Player-accessible status reports and progress tracking
- **⚙️ Highly Configurable**: Simple zone ownership configuration via Lua tables
- **🔄 Dual Coalition**: Full support for both RED and BLUE coalitions
- **📊 Auto-Reporting**: Periodic status updates every 5 minutes
- **🎮 Player-Friendly**: Clear messaging and intuitive state transitions
## 🚀 Quick Start
### Prerequisites
1. **DCS World** (version 2.9 or higher)
2. **MOOSE Framework** ([Download here](https://github.com/FlightControl-Master/MOOSE))
3. Basic knowledge of DCS Mission Editor
### Installation
1. **Download the files:**
- `Moose_DualCoalitionZoneCapture.lua` - Main script
- `Moose_DualCoalitionZoneCapture.miz` - Example mission
- `Moose_.lua` - MOOSE framework (get latest version)
2. **In DCS Mission Editor:**
- Create trigger zones for each capture point (e.g., "Capture Zone-1", "Capture Severomorsk")
- Create two groups: `BLUEHQ` (any BLUE ground unit) and `REDHQ` (any RED ground unit)
3. **Configure zones** in `Moose_DualCoalitionZoneCapture.lua`:
```lua
local ZONE_CONFIG = {
RED = {
"Capture Zone-1",
"Capture Zone-2"
},
BLUE = {
"Capture Zone-3",
"Capture Zone-4"
},
NEUTRAL = {
-- Empty zones at mission start
}
}
```
4. **Load scripts** via Mission Start trigger:
- Action 1: DO SCRIPT FILE → `Moose_.lua`
- Action 2: DO SCRIPT FILE → `Moose_DualCoalitionZoneCapture.lua`
5. **Save and test** your mission!
## 📖 How It Works
### Zone States
Zones transition between four distinct states:
| State | Color | Smoke | Description |
|-------|-------|-------|-------------|
| **RED Controlled** | 🔴 Red Border | Red | Zone secured by RED coalition |
| **BLUE Controlled** | 🔵 Blue Border | Blue | Zone secured by BLUE coalition |
| **Neutral/Empty** | 🟢 Green Border | Green | Uncontrolled, ready for capture |
| **Contested** | 🟠 Orange Border | White | Multiple coalitions present - fighting for control |
### Capture Mechanics
- **To Capture**: Move ground units into a zone
- **To Hold**: Eliminate all enemy forces in the zone
- **To Win**: Capture ALL zones on the map
The script automatically scans zones every 30 seconds (configurable) and updates ownership based on unit presence.
### Tactical Information Markers
Each zone displays real-time tactical data:
```
TACTICAL: Capture Severomorsk-1
Forces: R:5 B:12
TGTS: T-90@38U LV 12345 67890, BTR-80@38U LV 12346 67891
```
- **Force Counts**: Number of units per coalition
- **MGRS Coordinates**: Precise enemy locations (when ≤10 units)
- **Coalition-Specific**: Each side sees their enemies marked
## ⚙️ Configuration Options
### Zone Settings
```lua
local ZONE_SETTINGS = {
guardDelay = 1, -- Seconds before entering Guard state after capture
scanInterval = 30, -- How often to scan for units (seconds)
captureScore = 200 -- Points awarded for zone capture
}
```
### Performance Tuning
For missions with many units:
```lua
scanInterval = 60 -- Scan less frequently
```
For fast-paced action:
```lua
scanInterval = 15 -- More responsive zone changes
```
### Logging Control
Disable detailed logging:
```lua
CAPTURE_ZONE_LOGGING = { enabled = false }
```
## 👥 Player Features
### F10 Radio Menu Commands
Players access zone information via **F10 → Zone Control**:
- **Get Zone Status Report**: Current ownership of all zones
- **Check Victory Progress**: Percentage toward victory
- **Refresh Zone Colors**: Manually redraw zone boundaries
### Automatic Notifications
- ✅ Zone capture/loss announcements
- ⚠️ Attack warnings when zones are contested
- 📊 Status reports every 5 minutes
- 🏆 Victory alerts at 80% and 100% completion
- 🎉 Victory countdown with celebratory effects
## 🎮 Example Mission
The included `Moose_DualCoalitionZoneCapture.miz` demonstrates:
- Proper zone configuration
- HQ group placement
- Script loading order
- AI patrol patterns for testing
- All visual and messaging features
**Use this mission as a template for your own scenarios!**
## 🔧 Troubleshooting
### Common Issues
#### ❌ Script Won't Load
**Error**: "attempt to index a nil value"
- **Cause**: MOOSE not loaded first
- **Fix**: Ensure load order is MOOSE → Capture Script
#### ❌ Zone Not Found
**Error**: "Zone 'X' not found in mission editor!"
- **Cause**: Zone name mismatch
- **Fix**: Verify zone names match EXACTLY (case-sensitive!)
#### ⚠️ Zones Not Capturing
- Only ground units, planes, and helicopters are scanned
- Wait 30 seconds for scan cycle
- Eliminate ALL enemy forces to capture
- Check DCS.log for detailed information
### Checking Logs
Open `Saved Games\DCS\Logs\DCS.log` and search for:
- `[CAPTURE Module]` - General logging
- `[INIT]` - Initialization messages
- `[TACTICAL]` - Tactical marker updates
- `[VICTORY]` - Victory condition checks
## 🏗️ Mission Design Tips
### Best Practices
- **Zone Size**: Large enough for tactical areas, avoid overlaps
- **Zone Placement**: Position over airbases, FOBs, strategic terrain
- **Starting Balance**: Consider defensive vs. offensive scenarios
- **AI Behavior**: Use "Ground Hold" or "Ground On Road" waypoints
- **Player Briefing**: Document F10 menu commands in mission brief
### Integration with Other Scripts
Access zone data from other scripts:
```lua
-- Get current ownership status
local status = GetZoneOwnershipStatus()
-- Returns: { blue = X, red = Y, neutral = Z, total = N, zones = {...} }
-- Manual status broadcast
BroadcastZoneStatus()
-- Refresh zone visuals
RefreshAllZoneColors()
```
### Victory Flags
The script sets user flags on victory:
- `BLUE_VICTORY = 1` when BLUE wins
- `RED_VICTORY = 1` when RED wins
Use these in triggers to end missions or transition to next phase.
## 📋 Requirements
### Essential Components
- ✅ DCS World 2.9 or higher
- ✅ MOOSE Framework (latest version)
- ✅ Trigger zones in mission editor
- ✅ BLUEHQ and REDHQ groups
### Mission Prerequisites
- At least one trigger zone per capture point
- Exact zone name matching between editor and Lua config
- Both HQ groups must exist (can be hidden/inactive)
## 📞 Support & Resources
### Get Help
- **Discord Community**: [https://discord.gg/7wBVWKK3](https://discord.gg/7wBVWKK3)
- **Author**: F99th-TracerFacer
- **GitHub Issues**: Report bugs or request features
### Additional Resources
- [MOOSE Documentation](https://flightcontrol-master.github.io/MOOSE_DOCS/)
- [MOOSE Discord](https://discord.gg/gj68fm969S)
- [DCS Forums](https://forum.dcs.world)
## 📄 License
This script is provided free for use in DCS World missions. Feel free to modify and distribute.
## 🙏 Credits
- **Author**: F99th-TracerFacer
- **Framework**: MOOSE by FlightControl
- **Community**: DCS World Mission Makers
## 🎯 Version History
### Version 2.0 (Current)
- ✨ Full dual coalition support (RED & BLUE)
- ✨ Tactical information markers with MGRS coordinates
- ✨ Auto-victory detection and countdown
- ✨ F10 radio menu commands
- ✨ Periodic status reports
- ✨ Enhanced visual feedback system
- ✨ Configurable zone ownership via Lua tables
### Version 1.0
- Initial release
- Basic zone capture mechanics
- Single coalition focus
---
<div align="center">
**🎮 Happy Mission Making! 🚁**
*Created with ❤️ for the DCS World Community*
[Discord](https://discord.gg/7wBVWKK3) • [Documentation](Mission_Maker_Guide.html) • [Report Issue](#)
</div>

View File

@ -1,940 +0,0 @@
--[[
Script: Moose_DynamicGroundBattle.lua
Written by: [F99th-TracerFacer]
Version: 1.0.3
Date: 11 November 2024
Updated: 12 November 2024
Description: This script creates a dynamic ground battle between Red and Blue coalitions
along a series of zones which can be arranged in a line or any other configuration creating a dynamic ground battle.
Capture Zone Behavior
- Zone Capture states: Captured, Guarded, Empty, Attacked, Neutral
- Zone Colors: Red, Blue, Green, Orange
Red: Captured by Red
Blue: Captured by Blue
Orange: Contested
Green: Empty
Spawning And Patrol Behavior:
- Infantry and armor groups for both sides spawn at random locations in their own zones.
- Each group then calculates the shortest distance to the nearest enemy zone and moves to that zone to patrol.
- Every ASSIGN_TASKS_SCHED seconds, the script will check the ZONE_CAPTURE states of all zones and assign tasks to groups accordingly.
- Any group NOT moving, will recieve orders to patrol the nearest enemy zone. Any unit already moving will be left alone.
- Any troops dropped off through CTLD in these zones will begin to obey these orders as well.
- Spawn frequency calculated based on the number of alive warehouses.
- Infantry can be disabled from moving patrols if desired.
- In the event of DCS assigning a ridiculous path to an object, simply stop the object and it will be reassigned a new patrol path next round.
Warehouse System & Spawn Frequencey Behavior:
1. Warehouses:
- Each side (Red and Blue) has a set of warehouses defined in the `redWarehouses` and `blueWarehouses` tables.
- The number of warehouses can be adjusted by adding or removing entries from these tables and ensuring there is a matching object in the mission editor.
2. Spawn Frequency Calculation:
- The function `CalculateSpawnFrequency` calculates the spawn frequency based on the number of alive warehouses.
- The spawn frequency is a ratio of alive warehouses to total warehouses.
- If all warehouses are alive, the spawn frequency is (100%) of the base setting.
- If half of the warehouses are alive, the spawn frequency is (50%).
- If no warehouses are alive, the spawn frequency is (0%) (no more spawns).
- So for example, if you set your spawn frequency to 300 seconds, and only 50% of your warehouses are alive, the actual spawn frequency will be 600 seconds.
- This dynamic adjustment ensures that the reinforcement rate is directly impacted by the number of operational warehouses.
3. Mark points are automatically added to the map for each warehouse.
- Include the warehouse name and a list of nearby ground units within a specified radius.
- Uppdated every `UPDATE_MARK_POINTS_SCHED` seconds.
- The maximum distance to search for units near a warehouse is defined by the `MAX_WAREHOUSE_UNIT_LIST_DISTANCE` variable.
- The mark points are displayed to all players on the map as a form of "intel" on the battlefield.
- Can be disabled by setting `ENABLE_WAREHOUSE_MARKERS` to false.
General Setup Requirements:
- The script relies on the MOOSE framework for DCS World. Ensure that the MOOSE framework is installed and running on the mission.
- Ensure that all groups and zones mentioned below are created in the mission editor. You can adjust the names of the groups and zones as needed or
add more groups and zones to the script. Ensure that the names in this script match the names in the mission editor.
Groups and Zones to be created in the editor (all LATE ACTIVATE):
- Red Infantry Groups: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
- Red Armor Groups: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6
- Blue Infantry Groups: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
- Blue Armor Groups: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5
- Red Zones: FrontLine1, FrontLine2, FrontLine3, FrontLine4, FrontLine5, FrontLine6
- Blue Zones: FrontLine7, FrontLine8, FrontLine9, FrontLine10, FrontLine11, FrontLine12
- Red Warehouses: RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1, RedWarehouse4-1, RedWarehouse5-1, RedWarehouse6-1
- Blue Warehouses: BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1, BlueWarehouse4-1, BlueWarehouse5-1, BlueWarehouse6-1
- ** Note Warehouse names are based on the static "unit name" in the mission editor. **
--]]
--[[
--If you don't have command centers setup in another file, uncommnent this section below:
-- Create Command Centers and Missions for each side
-- Must have a blue unit named "BLUEHQ" and a red unit named "REDHQ" in the mission editor.
--Build Command Center and Mission for Blue
US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
US_Mission = MISSION:New( US_CC, "Insurgent Sandstorm", "Primary", "Clear the front lines of enemy activity.", coalition.side.BLUE)
US_Score = SCORING:New( "Insurgent Sandstorm - Blue" )
US_Mission:AddScoring( US_Score )
US_Mission:Start()
US_Score:SetMessagesHit(false)
US_Score:SetMessagesDestroy(false)
US_Score:SetMessagesScore(false)
--Build Command Center and Mission Red
RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
RU_Mission = MISSION:New (RU_CC, "Insurgent Sandstorm", "Primary", "Destroy U.S. and NATO forces.", coalition.side.RED)
RU_Score = SCORING:New("Insurgent Sandstorm - Red")
RU_Mission:AddScoring( RU_Score)
RU_Mission:Start()
RU_Score:SetMessagesHit(false)
RU_Score:SetMessagesDestroy(false)
RU_Score:SetMessagesScore(false)
]]
-- Infantry Patrol Settings
-- Due to some maps or locations where infantry moving is either not desired or has problems with the terrain you can disable infantry moving patrols.
-- Set to false, infantry units will spawn, and never move from their spawn location. This could be considered a defensive position and probably a good idea.
local MOVING_INFANTRY_PATROLS = false
local ENABLE_WAREHOUSE_MARKERS = true -- Enable or disable the warehouse markers on the map.
local UPDATE_MARK_POINTS_SCHED = 60 -- Update the map markers for warehouses every 300 seconds. ENABLE_WAREHOUSE_MARKERS must be set to true for this to work.
local MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Maximum distance to search for units near a warehouse to display on map markers.
-- Control Spawn frequency and limits of ground units.
local INIT_RED_INFANTRY = 5 -- Initial number of Red Infantry groups
local MAX_RED_INFANTRY = 100 -- Maximum number of Red Infantry groups
local SPAWN_SCHED_RED_INFANTRY = 1800 -- Spawn Red Infantry groups every 1800 seconds
local INIT_RED_ARMOR = 25 -- Initial number of Red Armor groups
local MAX_RED_ARMOR = 200 -- Maximum number of Red Armor groups
local SPAWN_SCHED_RED_ARMOR = 300 -- Spawn Red Armor groups every 300 seconds
local INIT_BLUE_INFANTRY = 5 -- Initial number of Blue Infantry groups
local MAX_BLUE_INFANTRY = 100 -- Maximum number of Blue Infantry groups
local SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Spawn Blue Infantry groups every 1800 seconds
local INIT_BLUE_ARMOR = 25 -- Initial number of Blue Armor groups0
local MAX_BLUE_ARMOR = 200 -- Maximum number of Blue Armor groups
local SPAWN_SCHED_BLUE_ARMOR = 300 -- Spawn Blue Armor groups every 300 seconds
local ASSIGN_TASKS_SCHED = 600 -- Assign tasks to groups every 600 seconds. New groups added will wait this long before moving.
-- Define capture zones for each side with a visible radius.
-- These zones will be used to create capture zones for each side. The capture zones will be used to determine the state of each zone (captured, guarded, empty, attacked, neutral).
-- The zones will also be used to spawn ground units for each side.
-- The zones should be created in the mission editor and named accordingly.
-- You can add more zones as needed. The script will create capture zones for each zone and assign tasks to groups based on the zone states.
-- Maybe the zones are along a front line, or they follow a road, or they are scattered around the map. You can arrange the zones in any configuration you like.
local redZones = {
ZONE:New("FrontLine1"),
ZONE:New("FrontLine2"),
ZONE:New("FrontLine3"),
ZONE:New("FrontLine4"),
ZONE:New("FrontLine5"),
ZONE:New("FrontLine6")
}
local blueZones = {
ZONE:New("FrontLine7"),
ZONE:New("FrontLine8"),
ZONE:New("FrontLine9"),
ZONE:New("FrontLine10"),
ZONE:New("FrontLine11"),
ZONE:New("FrontLine12")
}
-- Define warehouses for each side. These warehouses will be used to calculate the spawn frequency of ground units.
-- The warehouses should be created in the mission editor and named accordingly.
local redWarehouses = {
STATIC:FindByName("RedWarehouse1-1"), -- Static units key of off unit name in mission editor rather than just the name field. weird. =\ (hours wasted! ha!)
STATIC:FindByName("RedWarehouse2-1"),
STATIC:FindByName("RedWarehouse3-1"),
STATIC:FindByName("RedWarehouse4-1"),
STATIC:FindByName("RedWarehouse5-1"),
STATIC:FindByName("RedWarehouse6-1")
}
local blueWarehouses = {
STATIC:FindByName("BlueWarehouse1-1"),
STATIC:FindByName("BlueWarehouse2-1"),
STATIC:FindByName("BlueWarehouse3-1"),
STATIC:FindByName("BlueWarehouse4-1"),
STATIC:FindByName("BlueWarehouse5-1"),
STATIC:FindByName("BlueWarehouse6-1")
}
-- Define templates for infantry and armor groups. These templates will be used to randomize the groups spawned in the zones.
-- The templates should be created in the mission editor and named accordingly.
-- You can add more templates as needed. The script will randomly select a template for each group spawned.
-- The more templates you make, the more variety you can add to the groups that are spawned.
local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
"RedInfantry3",
"RedInfantry4",
"RedInfantry5",
"RedInfantry6"
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
"RedArmor3",
"RedArmor4",
"RedArmor5",
"RedArmor6",
"RedArmor7",
"RedArmor8",
"RedArmor9",
"RedArmor10"
}
local blueInfantryTemplates = {
"BlueInfantry1",
"BlueInfantry2",
"BlueInfantry3",
"BlueInfantry4",
"BlueInfantry5",
"BlueInfantry6"
}
local blueArmorTemplates = {
"BlueArmor1",
"BlueArmor2",
"BlueArmor3",
"BlueArmor4",
"BlueArmor5"
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- DO NOT EDIT BELOW THIS LINE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Track active markers to prevent memory leaks
local activeMarkers = {}
-- Function to add mark points on the map for each warehouse in the provided list
local function addMarkPoints(warehouses, coalition)
for _, warehouse in ipairs(warehouses) do
if warehouse then
local warehousePos = warehouse:GetVec3()
local details
if coalition == 2 then
if warehouse:GetCoalition() == 2 then
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\n"
else
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
end
elseif coalition == 1 then
if warehouse:GetCoalition() == 1 then
details = "Warehouse: " .. warehouse:GetName() .. "\nThis warehouse needs to be protected.\nNearby Units:\n"
else
details = "Warehouse: " .. warehouse:GetName() .. "\nThis is a primary target as it is directly supplying enemy units.\n"
end
end
local coordinate = COORDINATE:NewFromVec3(warehousePos)
local marker = MARKER:New(coordinate, details):ToCoalition(coalition):ReadOnly()
table.insert(activeMarkers, marker)
else
env.info("addMarkPoints: Warehouse not found or is nil")
end
end
end
local function updateMarkPoints()
-- Clean up old markers first
for _, marker in ipairs(activeMarkers) do
if marker then
marker:Remove()
end
end
activeMarkers = {}
addMarkPoints(redWarehouses, 2) -- Blue coalition sees red warehouses as targets
addMarkPoints(blueWarehouses, 2) -- Blue coalition sees blue warehouses as needing protection
addMarkPoints(redWarehouses, 1) -- Red coalition sees red warehouses as needing protection
addMarkPoints(blueWarehouses, 1) -- Red coalition sees blue warehouses as targets
end
-- If enabled, update the mark points for the warehouses every UPDATE_MARK_POINTS_SCHED seconds.
if ENABLE_WAREHOUSE_MARKERS then
SCHEDULER:New(nil, updateMarkPoints, {}, 10, UPDATE_MARK_POINTS_SCHED)
end
-- Table to keep track of zones and their statuses
local zoneStatuses = {}
-- Reusable SET_GROUP to prevent memory leaks from repeated creation
local cachedAllGroups = nil
local function getAllGroups()
if not cachedAllGroups then
cachedAllGroups = SET_GROUP:New():FilterActive():FilterStart()
end
return cachedAllGroups
end
-- Function to create a capture zone
local function CreateCaptureZone(zone, coalition)
local captureZone = ZONE_CAPTURE_COALITION:New(zone, coalition)
if captureZone then
local coordinate = captureZone:GetCoordinate()
if coordinate then
env.info("Created capture zone at coordinates: " .. coordinate:ToStringLLDMS())
captureZone:Start(5, 30) -- Check every 5 seconds, capture after 30 seconds
else
env.error("Failed to get coordinates for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
else
env.error("Failed to create capture zone for zone: " .. zone:GetName() .. " Did you add the group to the editor?")
end
return captureZone
end
-- Custom OnEnterCaptured method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterCaptured(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
self:UndrawZone()
self:DrawZone(-1, {0, 0, 1}, 2) -- Draw the zone on the map for 30 seconds, blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s has been captured by Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterGuarded method
--- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterGuarded(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw zone DARK BLUE for guarded
self:UndrawZone()
self:DrawZone(-1, {0, 0, 0.5}, 2) -- Draw the zone on the map for 30 seconds, dark blue color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
-- Draw zone DARK RED for guarded
self:UndrawZone()
self:DrawZone(-1, {0.5, 0, 0}, 2) -- Draw the zone on the map for 30 seconds, dark red color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is under protection of Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterEmpty method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterEmpty(From, Event, To)
if From ~= To then
self:E({ Coalition = "None" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "None" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now empty", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Custom OnEnterAttacked method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterAttacked(From, Event, To)
if From ~= To then
local Coalition = self:GetCoalition()
self:E({ Coalition = Coalition })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = Coalition }
if Coalition == coalition.side.BLUE then
self:Smoke(SMOKECOLOR.Blue)
-- Draw the zone orange for contested
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is under attack by Russia", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is attacking the USA", self:GetZoneName()), MESSAGE.Type.Information)
else
self:Smoke(SMOKECOLOR.Red)
self:UndrawZone()
self:DrawZone(-1, {1, 0.5, 0}, 2) -- Draw the zone on the map for 30 seconds, orange color, and thickness 2
RU_CC:MessageTypeToCoalition(string.format("%s is under attack by the USA", self:GetZoneName()), MESSAGE.Type.Information)
US_CC:MessageTypeToCoalition(string.format("%s is attacking Russia", self:GetZoneName()), MESSAGE.Type.Information)
end
end
end
-- Custom OnEnterNeutral method
--- @param Functional.Protect#ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:OnEnterNeutral(From, Event, To)
if From ~= To then
self:E({ Coalition = "Neutral" })
local zoneName = self:GetZoneName()
zoneStatuses[zoneName] = { zone = self, coalition = "Neutral" }
self:Smoke(SMOKECOLOR.Green)
self:UndrawZone()
self:DrawZone(-1, {0, 1, 0}, 2) -- Draw the zone on the map for 30 seconds, green color, and thickness 2
US_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
RU_CC:MessageTypeToCoalition(string.format("%s is now neutral", self:GetZoneName()), MESSAGE.Type.Information)
end
end
-- Create capture zones for Red and Blue
local redCaptureZones = {}
local blueCaptureZones = {}
-- Iterate over all red zones to create capture zones
for _, zone in ipairs(redZones) do
-- Attempt to create a capture zone for the current red zone
local captureZone = CreateCaptureZone(zone, coalition.side.RED)
if captureZone then
-- If successful, add the capture zone to the redCaptureZones table
table.insert(redCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Red capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, red color, and thickness 2
zone:DrawZone(30, {1, 0, 0}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.RED }
else
-- If creation fails, log an error message
env.error("Failed to create Red capture zone: " .. zone:GetName())
end
end
-- Iterate over all blue zones to create capture zones
for _, zone in ipairs(blueZones) do
-- Attempt to create a capture zone for the current blue zone
local captureZone = CreateCaptureZone(zone, coalition.side.BLUE)
if captureZone then
-- If successful, add the capture zone to the blueCaptureZones table
table.insert(blueCaptureZones, captureZone)
-- Log the creation of the capture zone
env.info("Created Blue capture zone: " .. zone:GetName())
-- Draw the zone on the map with infinite duration, blue color, and thickness 2
zone:DrawZone(30, {0, 0, 1}, 2)
-- Initialize the zone status
zoneStatuses[zone:GetName()] = { zone = captureZone, coalition = coalition.side.BLUE }
else
-- If creation fails, log an error message
env.error("Failed to create Blue capture zone: " .. zone:GetName())
end
end
-- Function to handle zone capture
local function OnZoneCaptured(event)
local zone = event.zone
local coalition = event.coalition
if zone and coalition then
env.info("OnZoneCaptured: Zone " .. zone:GetName() .. " captured by coalition " .. coalition)
-- Update the zone state
if coalition == coalition.side.RED then
zoneStates[zone:GetName()] = "RED"
zone:SetCoalition(coalition.side.RED)
elseif coalition == coalition.side.BLUE then
zoneStates[zone:GetName()] = "BLUE"
zone:SetCoalition(coalition.side.BLUE)
else
zoneStates[zone:GetName()] = "NEUTRAL"
zone:SetCoalition(coalition.side.NEUTRAL)
end
else
env.error("OnZoneCaptured: Invalid zone or coalition")
end
end
-- Function to handle zone guarded events
local function OnZoneGuarded(event)
local zone = event.Zone
local coalition = event.Coalition
if coalition == coalition.side.RED then
env.info("Red is guarding zone: " .. zone:GetName())
elseif coalition == coalition.side.BLUE then
env.info("Blue is guarding zone: " .. zone:GetName())
end
end
-- Function to handle zone empty events
local function OnZoneEmpty(event)
local zone = event.Zone
env.info("Zone is empty: " .. zone:GetName())
end
-- Function to handle zone attacked events
local function OnZoneAttacked(event)
local zone = event.Zone
local attackingGroups = zone:GetGroups()
local makeup = {}
for _, group in ipairs(attackingGroups) do
local groupName = group:GetName()
local unitTypes = {}
for _, unit in ipairs(group:GetUnits()) do
local unitType = unit:GetTypeName()
unitTypes[unitType] = (unitTypes[unitType] or 0) + 1
end
table.insert(makeup, {groupName = groupName, unitTypes = unitTypes})
end
local makeupMessage = ""
for _, groupInfo in ipairs(makeup) do
makeupMessage = makeupMessage .. "Group: " .. groupInfo.groupName .. "\n"
for unitType, count in pairs(groupInfo.unitTypes) do
makeupMessage = makeupMessage .. " " .. unitType .. ": " .. count .. "\n"
end
end
local messageText = "Zone is being attacked: " .. zone:GetName() .. "\n" .. makeupMessage
env.info(messageText)
-- Announce to the player
MESSAGE:New(messageText, 15):ToAll()
end
-- Function to handle zone neutral events
local function OnZoneNeutral(event)
local zone = event.Zone
env.info("Zone is neutral: " .. zone:GetName())
end
-- Function to check the ZONE_CAPTURE states of all zones
local function CheckZoneStates()
env.info("Checking zone states...")
local zoneStates = {}
local function processZones(zones, zoneType)
env.info("Processing " .. zoneType)
env.info("Number of zones: " .. #zones)
local allGroups = getAllGroups()
for _, zone in ipairs(zones) do
if zone then
env.info("processZones: Zone object is valid")
-- Check if the zone is of the correct type
if zone.ClassName == "ZONE_CAPTURE_COALITION" then
env.info("processZones: Zone is of type ZONE_CAPTURE_COALITION")
local coalition = zone:GetCoalition()
env.info("processZones: Zone coalition: " .. tostring(coalition))
if coalition == 1 then
zoneStates[zone:GetZoneName()] = "RED"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: RED")
elseif coalition == 2 then
zoneStates[zone:GetZoneName()] = "BLUE"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: BLUE")
else
zoneStates[zone:GetZoneName()] = "NEUTRAL"
env.info("processZones: Zone: " .. (zone:GetZoneName() or "nil") .. " State: NEUTRAL")
end
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
env.info("processZones: Checking group: " .. group:GetName())
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("processZones: IsCompletelyInZone method not found in group: " .. group:GetName())
-- Log available methods on the group object
for k, v in pairs(group) do
env.info("processZones: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("processZones: Invalid group")
end
end)
env.info("processZones: Number of groups in zone: " .. #groupsInZone)
else
env.error("processZones: Zone is not of type ZONE_CAPTURE_COALITION")
-- Log available methods on the zone object
for k, v in pairs(zone) do
env.info("processZones: Zone method: " .. tostring(k) .. " = " .. tostring(v))
end
end
if not zone.GetZoneName then
env.error("processZones: Missing GetZoneName method in " .. zoneType)
end
else
env.error("processZones: Invalid zone in " .. zoneType)
end
end
end
processZones(redCaptureZones, "redZones")
processZones(blueCaptureZones, "blueZones")
-- Log the zoneStates table
for zoneName, state in pairs(zoneStates) do
env.info("CheckZoneStates: Zone: " .. zoneName .. " State: " .. state)
end
return zoneStates
end
-- Function to assign tasks to groups
local function AssignTasks(group, zoneStates)
if not group or not group.GetCoalition or not group.GetCoordinate or not group.GetVelocity then
env.info("AssignTasks: Invalid group or missing methods")
return
end
local velocity = group:GetVelocityVec3()
local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2)
if speed > 0 then
env.info("AssignTasks: Group " .. group:GetName() .. " is already moving. No new orders sent.")
return
end
env.info("Assigning tasks to group: " .. group:GetName())
local groupCoalition = group:GetCoalition()
local groupCoordinate = group:GetCoordinate()
local closestZone = nil
local closestDistance = math.huge
env.info("Group Coalition: " .. tostring(groupCoalition))
env.info("Group Coordinate: " .. groupCoordinate:ToStringLLDMS())
for zoneName, state in pairs(zoneStates) do
env.info("Checking Zone: " .. zoneName .. " with state: " .. tostring(state))
-- Convert state to a number for comparison
local stateCoalition = (state == "RED" and 1) or (state == "BLUE" and 2) or nil
if stateCoalition and stateCoalition ~= groupCoalition then
local zone = ZONE:FindByName(zoneName)
if zone then
local zoneCoordinate = zone:GetCoordinate()
local distance = groupCoordinate:Get2DDistance(zoneCoordinate)
--env.info("Zone Coordinate: " .. zoneCoordinate:ToStringLLDMS())
--env.info("Distance to zone " .. zoneName .. ": " .. distance)
if distance < closestDistance then
closestDistance = distance
closestZone = zone
env.info("New closest zone: " .. zoneName .. " with distance: " .. distance)
end
else
env.info("AssignTasks: Zone not found - " .. zoneName)
end
else
env.info("Zone " .. zoneName .. " is already controlled by coalition: " .. tostring(state))
end
end
if closestZone then
env.info(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName())
--MESSAGE:New(group:GetName() .. " is moving to and patrolling zone " .. closestZone:GetName(), 10):ToAll()
-- Create a patrol task using the GROUP:PatrolZones method
local patrolZones = {closestZone}
local speed = 20 -- Example speed, adjust as needed
local formation = "Cone" -- Example formation, adjust as needed
local delayMin = 30 -- Example minimum delay, adjust as needed
local delayMax = 60 -- Example maximum delay, adjust as needed
group:PatrolZones(patrolZones, speed, formation, delayMin, delayMax)
else
env.info("AssignTasks: No suitable zone found for group " .. group:GetName())
end
end
-- Function to check if a group contains infantry units
local function IsInfantryGroup(group)
env.info("IsInfantryGroup: Checking group: " .. group:GetName())
for _, unit in ipairs(group:GetUnits()) do
local unitTypeName = unit:GetTypeName()
env.info("IsInfantryGroup: Checking unit: " .. unit:GetName() .. " with type: " .. unitTypeName)
if unitTypeName:find("Infantry") or unitTypeName:find("Soldier") or unitTypeName:find("Paratrooper") then
env.info("IsInfantryGroup: Found infantry unit in group: " .. group:GetName())
return true
end
end
return false
end
-- Function to assign tasks to groups
local function AssignTasksToGroups()
env.info("AssignTasksToGroups: Starting task assignments")
local zoneStates = CheckZoneStates()
local allGroups = getAllGroups()
local function processZone(zone, zoneColor)
if zone then
env.info("AssignTasksToGroups: Processing " .. zoneColor .. " zone: " .. zone:GetName())
local groupsInZone = {}
allGroups:ForEachGroup(function(group)
if group then
if group.IsCompletelyInZone then
if group:IsCompletelyInZone(zone) then
table.insert(groupsInZone, group)
end
else
env.error("AssignTasksToGroups: IsCompletelyInZone method not found in group: " .. group:GetName())
for k, v in pairs(group) do
env.info("AssignTasksToGroups: Group method: " .. tostring(k) .. " = " .. tostring(v))
end
end
else
env.error("AssignTasksToGroups: Invalid group")
end
end)
env.info("AssignTasksToGroups: Found " .. #groupsInZone .. " groups in " .. zoneColor .. " zone: " .. zone:GetName())
for _, group in ipairs(groupsInZone) do
if IsInfantryGroup(group) == true then
if MOVING_INFANTRY_PATROLS == true then
env.info("AssignTasksToGroups: Assigning tasks to infantry group: " .. group:GetName())
AssignTasks(group, zoneStates)
else
env.info("AssignTasksToGroups: Skipping infantry group: " .. group:GetName())
end
else
env.info("AssignTasksToGroups: Assigning tasks to group: " .. group:GetName())
AssignTasks(group, zoneStates)
end
end
else
env.info("AssignTasksToGroups: Invalid " .. zoneColor .. " zone")
end
end
for _, zone in ipairs(redZones) do
processZone(zone, "red")
end
for _, zone in ipairs(blueZones) do
processZone(zone, "blue")
end
env.info("AssignTasksToGroups: Task assignments completed. Running again in " .. ASSIGN_TASKS_SCHED .. " seconds.")
end
-- Function to calculate spawn frequency in seconds
local function CalculateSpawnFrequency(warehouses, baseFrequency)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 or aliveWarehouses == 0 then
return math.huge -- Stop spawning if there are no warehouses or no alive warehouses
end
local frequency = baseFrequency * (totalWarehouses / aliveWarehouses)
return frequency
end
local function CalculateSpawnFrequencyPercentage(warehouses)
local totalWarehouses = #warehouses
local aliveWarehouses = 0
for _, warehouse in ipairs(warehouses) do
local life = warehouse:GetLife()
if life and life > 0 then
aliveWarehouses = aliveWarehouses + 1
end
end
if totalWarehouses == 0 then
return 0 -- Avoid division by zero
end
local percentage = (aliveWarehouses / totalWarehouses) * 100
return math.floor(percentage)
end
-- Add event handlers for zone capture
for _, captureZone in ipairs(redCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
for _, captureZone in ipairs(blueCaptureZones) do
captureZone:OnEnterCaptured(OnZoneCaptured)
captureZone:OnEnterGuarded(captureZone.OnEnterGuarded)
captureZone:OnEnterEmpty(OnZoneEmpty)
captureZone:OnEnterAttacked(OnZoneAttacked)
captureZone:OnEnterNeutral(OnZoneNeutral)
end
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses, coalition.side.RED)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses, coalition.side.BLUE)
-- Display spawn frequency percentages to the user
MESSAGE:New("Red side spawn frequency: " .. redSpawnFrequencyPercentage .. "%", 30):ToRed()
MESSAGE:New("Blue side spawn frequency: " .. blueSpawnFrequencyPercentage .. "%", 30):ToBlue()
-- Schedule ground spawns using the calculated frequencies
redInfantrySpawn = SPAWN:New("RedInfantryGroup")
:InitRandomizeTemplate(redInfantryTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_INFANTRY, MAX_RED_INFANTRY)
:SpawnScheduled(redInfantrySpawnFrequency, 0.5)
redArmorSpawn = SPAWN:New("RedArmorGroup")
:InitRandomizeTemplate(redArmorTemplates)
:InitRandomizeZones(redZones)
:InitLimit(INIT_RED_ARMOR, MAX_RED_ARMOR)
:SpawnScheduled(redArmorSpawnFrequency, 0.5)
blueInfantrySpawn = SPAWN:New("BlueInfantryGroup")
:InitRandomizeTemplate(blueInfantryTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_INFANTRY, MAX_BLUE_INFANTRY)
:SpawnScheduled(blueInfantrySpawnFrequency, 0.5)
blueArmorSpawn = SPAWN:New("BlueArmorGroup")
:InitRandomizeTemplate(blueArmorTemplates)
:InitRandomizeZones(blueZones)
:InitLimit(INIT_BLUE_ARMOR, MAX_BLUE_ARMOR)
:SpawnScheduled(blueArmorSpawnFrequency, 0.5)
env.info("Dynamic Ground Battle & Zone capture initialized.")
-- Function to monitor and announce warehouse status
local function MonitorWarehouses()
local blueWarehousesAlive = 0
local redWarehousesAlive = 0
for _, warehouse in ipairs(blueWarehouses) do
if warehouse:IsAlive() then
blueWarehousesAlive = blueWarehousesAlive + 1
end
end
for _, warehouse in ipairs(redWarehouses) do
if warehouse:IsAlive() then
redWarehousesAlive = redWarehousesAlive + 1
end
end
-- Debug messages to check values
env.info("MonitorWarehouses: blueWarehousesAlive = " .. blueWarehousesAlive)
env.info("MonitorWarehouses: redWarehousesAlive = " .. redWarehousesAlive)
-- Calculate spawn frequencies
local redInfantrySpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_INFANTRY)
local redArmorSpawnFrequency = CalculateSpawnFrequency(redWarehouses, SPAWN_SCHED_RED_ARMOR)
local blueInfantrySpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_INFANTRY)
local blueArmorSpawnFrequency = CalculateSpawnFrequency(blueWarehouses, SPAWN_SCHED_BLUE_ARMOR)
-- Calculate spawn frequency percentages
local redSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(redWarehouses)
local blueSpawnFrequencyPercentage = CalculateSpawnFrequencyPercentage(blueWarehouses)
-- Log the values
env.info("MonitorWarehouses: redInfantrySpawnFrequency = " .. redInfantrySpawnFrequency)
env.info("MonitorWarehouses: redArmorSpawnFrequency = " .. redArmorSpawnFrequency)
env.info("MonitorWarehouses: blueInfantrySpawnFrequency = " .. blueInfantrySpawnFrequency)
env.info("MonitorWarehouses: blueArmorSpawnFrequency = " .. blueArmorSpawnFrequency)
env.info("MonitorWarehouses: redSpawnFrequencyPercentage = " .. redSpawnFrequencyPercentage)
env.info("MonitorWarehouses: blueSpawnFrequencyPercentage = " .. blueSpawnFrequencyPercentage)
local msg = "[Warehouse status:]\n"
msg = msg .. "Red warehouses alive: " .. redWarehousesAlive .. " Reinforcements Capacity: " .. redSpawnFrequencyPercentage .. "%" .. "\n"
msg = msg .. "Blue warehouses alive: " .. blueWarehousesAlive .. " Reinforcements Capacity: " .. blueSpawnFrequencyPercentage .. "%" .. "\n"
MESSAGE:New(msg, 30):ToAll()
end
-- Function to check the wincondition. If either side owns all zones, mission ends.
local winConditionScheduler = nil
local function checkWinCondition()
local blueOwned = true
local redOwned = true
for zoneName, owner in pairs(zoneStatuses) do
if owner ~= 1 then
redOwned = false
end
if owner ~= 2 then
blueOwned = false
end
end
if blueOwned then
MESSAGE:New("Blue side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("UsaTheme.ogg"):ToAll()
if winConditionScheduler then
winConditionScheduler:Stop()
end
return true
elseif redOwned then
MESSAGE:New("Red side wins! They own all the capture zones.", 60):ToAll()
SOUND:New("MotherRussia.ogg"):ToAll()
if winConditionScheduler then
winConditionScheduler:Stop()
end
return true
end
return false
end
-- Start monitoring the win condition with SCHEDULER instead of recursive TIMER
winConditionScheduler = SCHEDULER:New(nil, checkWinCondition, {}, 60, 60)
-- Scheduler to monitor warehouses every 120 seconds
SCHEDULER:New(nil, MonitorWarehouses, {}, 0, 120)
-- Scheduler to assign tasks to groups periodically
SCHEDULER:New(nil, AssignTasksToGroups, {}, 0, ASSIGN_TASKS_SCHED) -- Check every 600 seconds (10 minutes) - Adjust as needed
-- Create a mission menu
local missionMenu = MENU_MISSION:New("Warehouse Monitoring")
-- Add a menu item to run the MonitorWarehouses function
MENU_MISSION_COMMAND:New("Check Warehouse Status", missionMenu, MonitorWarehouses)

File diff suppressed because it is too large Load Diff

View File

@ -1,224 +0,0 @@
# Dynamic Ground Battle Plugin
## Overview
This is a **plugin version** of the Dynamic Ground Battle system designed to work alongside `Moose_DualCoalitionZoneCapture.lua`.
**Key difference from the standalone version:**
- ✅ Uses zones from `Moose_DualCoalitionZoneCapture.lua` (no duplicate zone management)
- ✅ Handles ONLY warehouse system + AI spawning + task assignment
- ✅ Zone capture, colors, messaging, win conditions = handled by DualCoalitionZoneCapture
- ✅ Cleaner separation of concerns
## Load Order (Critical!)
In your Mission Editor → Triggers → Mission Start:
```
1. DO SCRIPT FILE Moose_.lua
2. DO SCRIPT FILE Moose_DualCoalitionZoneCapture.lua ← Must load FIRST
3. DO SCRIPT FILE Moose_DynamicGroundBattle_Plugin.lua ← This file
4. DO SCRIPT FILE CTLD.lua (optional)
5. DO SCRIPT FILE CSAR.lua (optional)
```
## What This Plugin Does
### ✅ Warehouse System
- Red/Blue warehouses affect reinforcement spawn rates
- 100% alive = 100% spawn rate
- 50% alive = 50% spawn rate (2x delay)
- 0% alive = no more spawns
- Map markers show warehouse locations and intel
### ✅ Dynamic AI Spawning
- Spawns infantry and armor groups in **friendly zones only**
- Zones come from `DualCoalitionZoneCapture`'s `ZONE_CONFIG`
- As zones are captured/lost, spawn locations automatically update
- Configurable limits and spawn frequencies
### ✅ AI Task Assignment
- Groups patrol toward nearest enemy zone
- Reassignment every 600s (configurable)
- Only idle units get new orders (moving units ignored)
- Infantry movement can be disabled
### ✅ CTLD Integration
- Dropped troops automatically get AI tasking
- Works seamlessly with logistics operations
## What This Plugin Does NOT Do
- ❌ Zone capture logic (handled by DualCoalitionZoneCapture)
- ❌ Zone coloring/messaging (handled by DualCoalitionZoneCapture)
- ❌ Win conditions (handled by DualCoalitionZoneCapture)
- ❌ Scoring (handled by DualCoalitionZoneCapture)
## Configuration
Edit the top section of `Moose_DynamicGroundBattle_Plugin.lua`:
### Infantry Movement
```lua
local MOVING_INFANTRY_PATROLS = false -- Set true to enable infantry patrols
```
### Warehouse Markers
```lua
local ENABLE_WAREHOUSE_MARKERS = true
local UPDATE_MARK_POINTS_SCHED = 300 -- Update every 5 minutes
```
### Spawn Settings
```lua
-- Red Side
local INIT_RED_INFANTRY = 5
local MAX_RED_INFANTRY = 100
local SPAWN_SCHED_RED_INFANTRY = 1800 -- Every 30 minutes
local INIT_RED_ARMOR = 25
local MAX_RED_ARMOR = 200
local SPAWN_SCHED_RED_ARMOR = 300 -- Every 5 minutes
-- Blue Side
local INIT_BLUE_INFANTRY = 5
local MAX_BLUE_INFANTRY = 100
local SPAWN_SCHED_BLUE_INFANTRY = 1800
local INIT_BLUE_ARMOR = 25
local MAX_BLUE_ARMOR = 200
local SPAWN_SCHED_BLUE_ARMOR = 300
-- Task Assignment
local ASSIGN_TASKS_SCHED = 600 -- Reassign idle units every 10 minutes
```
### Warehouses
```lua
local redWarehouses = {
STATIC:FindByName("RedWarehouse1-1"),
STATIC:FindByName("RedWarehouse2-1"),
-- Add more as needed
}
local blueWarehouses = {
STATIC:FindByName("BlueWarehouse1-1"),
STATIC:FindByName("BlueWarehouse2-1"),
-- Add more as needed
}
```
### Unit Templates
```lua
local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
-- Add more for variety
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
-- Add more for variety
}
-- Same for blue side...
```
## Mission Editor Setup
### Required Groups (All LATE ACTIVATE)
**Red Side:**
- Infantry: `RedInfantry1`, `RedInfantry2`, `RedInfantry3`, `RedInfantry4`, `RedInfantry5`, `RedInfantry6`
- Armor: `RedArmor1`, `RedArmor2`, `RedArmor3`, `RedArmor4`, `RedArmor5`, `RedArmor6`
**Blue Side:**
- Infantry: `BlueInfantry1`, `BlueInfantry2`, `BlueInfantry3`, `BlueInfantry4`, `BlueInfantry5`, `BlueInfantry6`
- Armor: `BlueArmor1`, `BlueArmor2`, `BlueArmor3`, `BlueArmor4`, `BlueArmor5`
### Required Static Objects (Warehouses)
**Red Side:**
- Static objects with **Unit Name** (not Name field!): `RedWarehouse1-1`, `RedWarehouse2-1`, `RedWarehouse3-1`, etc.
**Blue Side:**
- Static objects with **Unit Name**: `BlueWarehouse1-1`, `BlueWarehouse2-1`, `BlueWarehouse3-1`, etc.
⚠️ **Important:** Warehouses use the "Unit Name" field in the static object properties, not the "Name" field!
### Zone Configuration
Zones come from `Moose_DualCoalitionZoneCapture.lua`. Edit that file's `ZONE_CONFIG`:
```lua
local ZONE_CONFIG = {
RED = {
"Capture Zone-1",
"Capture Zone-2",
"Capture Zone-3",
},
BLUE = {
"Capture Zone-4",
"Capture Zone-5",
"Capture Zone-6",
},
NEUTRAL = {}
}
```
## F10 Menu
- **Ground Battle → Check Warehouse Status** - Shows current warehouse count and reinforcement capacity
## Integration Points
### With DualCoalitionZoneCapture
- Reads `zoneCaptureObjects` and `zoneNames` arrays
- Dynamically spawns in zones controlled by the appropriate coalition
- AI routes to enemy zones based on current ownership
### With CTLD
- Any troops dropped via CTLD in friendly zones will automatically receive AI tasking
- They'll patrol toward nearest enemy zone like spawned units
## Performance & Memory Safety
This plugin version includes all the memory leak fixes from the standalone version:
✅ Marker cleanup prevents orphaning
✅ Reuses SET_GROUP instead of recreating
✅ Uses SCHEDULER instead of recursive TIMERs
✅ Efficient zone polling
## Troubleshooting
### "ERROR: Moose_DualCoalitionZoneCapture.lua must be loaded BEFORE this plugin!"
- Check your trigger load order
- DualCoalitionZoneCapture must be loaded in an earlier trigger
### Units not spawning
- Check `dcs.log` for errors
- Verify warehouse static objects exist with correct **Unit Names**
- Verify template groups exist and are set to LATE ACTIVATE
- Check that friendly zones exist (units only spawn in controlled zones)
### Units not moving
- If infantry: check `MOVING_INFANTRY_PATROLS` setting
- Verify enemy zones exist for AI to target
- Check `dcs.log` for task assignment messages (`[DGB PLUGIN]`)
### Warehouse markers not showing
- Set `ENABLE_WAREHOUSE_MARKERS = true`
- Check warehouse static objects are alive
- Markers update every `UPDATE_MARK_POINTS_SCHED` seconds
## Version History
- **1.0.0** (2024-11-15) - Initial plugin version
- Extracted from standalone Dynamic Ground Battle
- Integrated with DualCoalitionZoneCapture
- Added memory leak fixes
- Dynamic zone-based spawning

View File

@ -1,656 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moose Dynamic Ground Battle - Documentation</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 40px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
border-radius: 8px;
}
header {
border-bottom: 3px solid #2c5282;
padding-bottom: 20px;
margin-bottom: 30px;
}
h1 {
color: #2c5282;
font-size: 2.5em;
margin-bottom: 10px;
}
.version-info {
color: #666;
font-size: 0.9em;
margin-top: 10px;
}
h2 {
color: #2c5282;
font-size: 1.8em;
margin-top: 40px;
margin-bottom: 15px;
padding-bottom: 8px;
border-bottom: 2px solid #e2e8f0;
}
h3 {
color: #3182ce;
font-size: 1.3em;
margin-top: 25px;
margin-bottom: 12px;
}
h4 {
color: #4299e1;
font-size: 1.1em;
margin-top: 15px;
margin-bottom: 10px;
}
p {
margin-bottom: 15px;
text-align: justify;
}
ul, ol {
margin-left: 30px;
margin-bottom: 15px;
}
li {
margin-bottom: 8px;
}
code {
background-color: #f7fafc;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
color: #d73a49;
}
pre {
background-color: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 5px;
overflow-x: auto;
margin-bottom: 20px;
border-left: 4px solid #2c5282;
}
pre code {
background-color: transparent;
color: #d4d4d4;
padding: 0;
}
.feature-box {
background-color: #edf2f7;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #3182ce;
}
.warning {
background-color: #fff5f5;
border-left: 4px solid #fc8181;
padding: 15px;
margin-bottom: 20px;
border-radius: 4px;
}
.warning::before {
content: "⚠️ ";
font-weight: bold;
}
.info {
background-color: #ebf8ff;
border-left: 4px solid #4299e1;
padding: 15px;
margin-bottom: 20px;
border-radius: 4px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
th {
background-color: #2c5282;
color: white;
font-weight: 600;
}
tr:hover {
background-color: #f7fafc;
}
.toc {
background-color: #f7fafc;
padding: 20px;
border-radius: 5px;
margin-bottom: 30px;
}
.toc h3 {
margin-top: 0;
color: #2c5282;
}
.toc ul {
list-style-type: none;
margin-left: 0;
}
.toc li {
margin-bottom: 5px;
}
.toc a {
color: #3182ce;
text-decoration: none;
}
.toc a:hover {
text-decoration: underline;
}
.badge {
display: inline-block;
padding: 4px 10px;
border-radius: 12px;
font-size: 0.85em;
font-weight: 600;
margin-right: 8px;
}
.badge-red {
background-color: #feb2b2;
color: #742a2a;
}
.badge-blue {
background-color: #bee3f8;
color: #2c5282;
}
.badge-orange {
background-color: #fbd38d;
color: #7c2d12;
}
.badge-green {
background-color: #c6f6d5;
color: #22543d;
}
footer {
margin-top: 50px;
padding-top: 20px;
border-top: 2px solid #e2e8f0;
text-align: center;
color: #666;
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
pre {
padding: 15px;
font-size: 0.85em;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🎮 Moose Dynamic Ground Battle</h1>
<div class="version-info">
<strong>Version:</strong> 1.0.3 |
<strong>Author:</strong> F99th-TracerFacer |
<strong>Date:</strong> November 12, 2024
</div>
</header>
<div class="toc">
<h3>📋 Table of Contents</h3>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#installation">Installation Requirements</a></li>
<li><a href="#configuration">Configuration</a></li>
<li><a href="#gameplay">Gameplay Mechanics</a></li>
<li><a href="#menu">In-Game Menu</a></li>
<li><a href="#customization">Customization Tips</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ul>
</div>
<section id="overview">
<h2>Overview</h2>
<p>
Moose Dynamic Ground Battle is a sophisticated DCS World mission script that creates an engaging,
dynamic ground warfare system between Red and Blue coalitions. The script uses the MOOSE framework
to simulate realistic battlefield conditions with zone capture mechanics, intelligent AI movement,
and warehouse-based reinforcement systems.
</p>
</section>
<section id="features">
<h2>Features</h2>
<div class="feature-box">
<h3>🎯 Zone Capture System</h3>
<ul>
<li><strong>Multiple Zone States:</strong> Captured, Guarded, Empty, Attacked, and Neutral</li>
<li><strong>Visual Indicators:</strong>
<ul>
<li><span class="badge badge-red">Red</span> Captured by Red forces</li>
<li><span class="badge badge-blue">Blue</span> Captured by Blue forces</li>
<li><span class="badge badge-orange">Orange</span> Contested zone</li>
<li><span class="badge badge-green">Green</span> Empty/Neutral zone</li>
</ul>
</li>
<li><strong>Real-time Updates:</strong> Zone status changes trigger messages and visual updates</li>
</ul>
</div>
<div class="feature-box">
<h3>🚁 Intelligent AI Behavior</h3>
<ul>
<li><strong>Automated Spawning:</strong> Infantry and armor groups spawn at random locations within friendly zones</li>
<li><strong>Smart Pathfinding:</strong> Units automatically calculate and move to the nearest enemy zone</li>
<li><strong>Periodic Task Assignment:</strong> Every configurable interval, units receive new orders based on zone states</li>
<li><strong>CTLD Integration:</strong> Troops dropped via CTLD will automatically join the battle</li>
<li><strong>Stuck Unit Recovery:</strong> Units that become stuck can be reset to receive new patrol orders</li>
</ul>
</div>
<div class="feature-box">
<h3>🏭 Warehouse System</h3>
<ul>
<li><strong>Dynamic Reinforcement Rate:</strong> Spawn frequency adjusts based on warehouse survival</li>
<li><strong>Proportional Impact:</strong> 100% warehouses = 100% reinforcement rate, 50% warehouses = 50% rate</li>
<li><strong>Intelligence Markers:</strong> Automatic map markers showing warehouse locations and nearby units</li>
<li><strong>Strategic Importance:</strong> Warehouses become critical targets affecting enemy reinforcement capability</li>
</ul>
</div>
<div class="feature-box">
<h3>📊 Spawn Management</h3>
<ul>
<li><strong>Configurable Limits:</strong> Set initial spawn counts and maximum unit limits</li>
<li><strong>Template Randomization:</strong> Multiple unit templates for variety</li>
<li><strong>Frequency Control:</strong> Adjustable spawn intervals for infantry and armor</li>
<li><strong>Coalition Balance:</strong> Independent settings for Red and Blue forces</li>
</ul>
</div>
</section>
<section id="installation">
<h2>Installation Requirements</h2>
<h3>Prerequisites</h3>
<ol>
<li><strong>MOOSE Framework:</strong> This script requires the MOOSE framework for DCS World
<ul>
<li>Download from <a href="https://github.com/FlightControl-Master/MOOSE" target="_blank">MOOSE GitHub</a></li>
<li>Load MOOSE in your mission before this script</li>
</ul>
</li>
<li><strong>DCS World:</strong> Compatible with current DCS World versions</li>
<li><strong>Mission Editor:</strong> All groups, zones, and warehouses must be pre-configured</li>
</ol>
<h3>Mission Editor Setup</h3>
<h4>Required Groups (All LATE ACTIVATE)</h4>
<p><strong>Red Forces:</strong></p>
<pre><code>Infantry: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
Armor: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6</code></pre>
<p><strong>Blue Forces:</strong></p>
<pre><code>Infantry: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
Armor: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5</code></pre>
<h4>Required Zones</h4>
<p><strong>Red Zones:</strong></p>
<pre><code>FrontLine1, FrontLine2, FrontLine3, FrontLine4, FrontLine5, FrontLine6</code></pre>
<p><strong>Blue Zones:</strong></p>
<pre><code>FrontLine7, FrontLine8, FrontLine9, FrontLine10, FrontLine11, FrontLine12</code></pre>
<h4>Required Warehouses (Static Objects)</h4>
<div class="warning">
<strong>Important:</strong> Warehouse names are based on the static <strong>unit name</strong> in the mission editor, not the display name.
</div>
<p><strong>Red Warehouses:</strong></p>
<pre><code>RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1,
RedWarehouse4-1, RedWarehouse5-1, RedWarehouse6-1</code></pre>
<p><strong>Blue Warehouses:</strong></p>
<pre><code>BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1,
BlueWarehouse4-1, BlueWarehouse5-1, BlueWarehouse6-1</code></pre>
<h4>Optional: Command Centers</h4>
<p>If not using another script for command centers, create these units:</p>
<ul>
<li><code>BLUEHQ</code> - Blue coalition HQ unit</li>
<li><code>REDHQ</code> - Red coalition HQ unit</li>
</ul>
</section>
<section id="configuration">
<h2>Configuration</h2>
<h3>Basic Settings</h3>
<pre><code>-- Infantry Movement
MOVING_INFANTRY_PATROLS = false -- Set true to enable infantry movement
-- Warehouse Markers
ENABLE_WAREHOUSE_MARKERS = true
UPDATE_MARK_POINTS_SCHED = 60 -- Update interval in seconds
MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Search radius in meters
-- Task Assignment
ASSIGN_TASKS_SCHED = 600 -- Reassign tasks every 600 seconds</code></pre>
<h3>Spawn Configuration</h3>
<p><strong>Red Forces:</strong></p>
<pre><code>INIT_RED_INFANTRY = 5 -- Initial infantry groups
MAX_RED_INFANTRY = 100 -- Maximum infantry groups
SPAWN_SCHED_RED_INFANTRY = 1800 -- Spawn interval (seconds)
INIT_RED_ARMOR = 25 -- Initial armor groups
MAX_RED_ARMOR = 200 -- Maximum armor groups
SPAWN_SCHED_RED_ARMOR = 300 -- Spawn interval (seconds)</code></pre>
<p><strong>Blue Forces:</strong></p>
<pre><code>INIT_BLUE_INFANTRY = 5 -- Initial infantry groups
MAX_BLUE_INFANTRY = 100 -- Maximum infantry groups
SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Spawn interval (seconds)
INIT_BLUE_ARMOR = 25 -- Initial armor groups
MAX_BLUE_ARMOR = 200 -- Maximum armor groups
SPAWN_SCHED_BLUE_ARMOR = 300 -- Spawn interval (seconds)</code></pre>
<h3>Zone Configuration</h3>
<p>Zones can be arranged in any configuration - along a front line, following roads, or scattered across the map:</p>
<pre><code>local redZones = {
ZONE:New("FrontLine1"),
ZONE:New("FrontLine2"),
-- Add more zones as needed
}
local blueZones = {
ZONE:New("FrontLine7"),
ZONE:New("FrontLine8"),
-- Add more zones as needed
}</code></pre>
<h3>Template Customization</h3>
<p>Add variety by creating multiple unit templates:</p>
<pre><code>local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
-- Add more templates for variety
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
-- Add more templates for variety
}</code></pre>
</section>
<section id="gameplay">
<h2>Gameplay Mechanics</h2>
<h3>Zone Capture</h3>
<ul>
<li>Zones change ownership based on unit presence</li>
<li>Zones transition through states: Empty → Attacked → Captured → Guarded</li>
<li>Players receive notifications when zones change status</li>
<li>Visual indicators (smoke and map colors) show current ownership</li>
</ul>
<h3>Unit Behavior</h3>
<ol>
<li><strong>Spawn:</strong> Units spawn at random locations in friendly zones</li>
<li><strong>Task Assignment:</strong> Units calculate the nearest enemy zone</li>
<li><strong>Movement:</strong> Units patrol to and around enemy zones</li>
<li><strong>Reassignment:</strong> Stationary units receive new orders periodically</li>
<li><strong>Combat:</strong> Units engage enemies encountered during patrols</li>
</ol>
<h3>Warehouse Impact</h3>
<table>
<thead>
<tr>
<th>Warehouse Status</th>
<th>Spawn Rate Impact</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>100% Alive</td>
<td>Normal spawn rate</td>
<td>300 seconds</td>
</tr>
<tr>
<td>50% Alive</td>
<td>2x spawn delay</td>
<td>600 seconds</td>
</tr>
<tr>
<td>0% Alive</td>
<td>No more spawns</td>
<td>∞ (infinite)</td>
</tr>
</tbody>
</table>
<h3>Win Conditions</h3>
<ul>
<li>Mission ends when one coalition captures all zones</li>
<li>Periodic checks every 60 seconds</li>
<li>Victory message and sound plays for winning side</li>
</ul>
</section>
<section id="menu">
<h2>In-Game Menu</h2>
<p>Access warehouse status via the F10 menu:</p>
<pre><code>F10 → Warehouse Monitoring → Check Warehouse Status</code></pre>
<p>This displays:</p>
<ul>
<li>Number of warehouses alive per side</li>
<li>Current reinforcement capacity percentage</li>
<li>Real-time battlefield intelligence</li>
</ul>
</section>
<section id="customization">
<h2>Customization Tips</h2>
<h3>Adjusting Difficulty</h3>
<ul>
<li><strong>Increase Challenge:</strong> Reduce friendly spawn rates, increase enemy spawn rates</li>
<li><strong>Balance Forces:</strong> Adjust MAX values to limit unit counts</li>
<li><strong>Strategic Depth:</strong> Add more zones and warehouses</li>
<li><strong>Terrain Adaptation:</strong> Disable infantry movement for mountainous terrain</li>
</ul>
<h3>Adding More Units</h3>
<ol>
<li>Create new templates in mission editor</li>
<li>Add template names to the appropriate arrays</li>
<li>Ensure templates are set to LATE ACTIVATE</li>
<li>Test spawn behavior and patrol patterns</li>
</ol>
<h3>Zone Layouts</h3>
<ul>
<li><strong>Linear Front:</strong> Place zones in a line for traditional front-line combat</li>
<li><strong>Scattered:</strong> Distribute zones for multi-front warfare</li>
<li><strong>Road Network:</strong> Follow roads for realistic vehicle movement</li>
<li><strong>Strategic Points:</strong> Place zones at key terrain features</li>
</ul>
</section>
<section id="troubleshooting">
<h2>Troubleshooting</h2>
<h3>Common Issues</h3>
<div class="info">
<h4>Units Not Spawning:</h4>
<ul>
<li>Verify all template groups exist in mission editor</li>
<li>Check that groups are set to LATE ACTIVATE</li>
<li>Review DCS.log for error messages</li>
</ul>
</div>
<div class="info">
<h4>Units Not Moving:</h4>
<ul>
<li>Check <code>MOVING_INFANTRY_PATROLS</code> setting for infantry</li>
<li>Verify zones are properly named and created</li>
<li>Check that units aren't already moving when tasks are assigned</li>
</ul>
</div>
<div class="info">
<h4>Warehouse Markers Not Showing:</h4>
<ul>
<li>Ensure <code>ENABLE_WAREHOUSE_MARKERS = true</code></li>
<li>Verify warehouse static objects exist</li>
<li>Check that warehouse names match unit names (not display names)</li>
</ul>
</div>
<div class="info">
<h4>Zones Not Capturing:</h4>
<ul>
<li>Verify MOOSE framework is loaded</li>
<li>Check zone names match exactly</li>
<li>Ensure units are fully inside zones</li>
</ul>
</div>
</section>
<section id="structure">
<h2>Script Structure</h2>
<pre><code>├── Configuration Section (User Editable)
│ ├── Spawn Settings
│ ├── Zone Definitions
│ ├── Warehouse Definitions
│ └── Template Definitions
├── Core Functions (Do Not Edit)
│ ├── Zone Capture System
│ ├── Task Assignment Logic
│ ├── Warehouse Monitoring
│ ├── Spawn Frequency Calculator
│ └── Win Condition Checker
└── Initialization
├── Spawn Schedulers
├── Event Handlers
└── Menu Creation</code></pre>
</section>
<section id="performance">
<h2>Performance Considerations</h2>
<ul>
<li><strong>Unit Limits:</strong> Higher MAX values increase computational load</li>
<li><strong>Update Frequency:</strong> Longer intervals reduce CPU usage but decrease responsiveness</li>
<li><strong>Zone Count:</strong> More zones = more calculations per update</li>
<li><strong>Template Variety:</strong> More templates add minimal overhead</li>
</ul>
</section>
<section id="credits">
<h2>Credits</h2>
<ul>
<li><strong>Script Author:</strong> F99th-TracerFacer</li>
<li><strong>Framework:</strong> MOOSE Framework by FlightControl</li>
<li><strong>Community:</strong> DCS World Mission Editing Community</li>
</ul>
</section>
<section id="version-history">
<h2>Version History</h2>
<ul>
<li><strong>1.0.3</strong> (November 12, 2024) - Current release</li>
<li><strong>1.0.0</strong> (November 11, 2024) - Initial release</li>
</ul>
</section>
<section id="license">
<h2>License</h2>
<p>
This script is provided as-is for the DCS World community. Feel free to modify and
distribute with credit to the original author.
</p>
</section>
<footer>
<p><strong>Happy Mission Building! 🚁</strong></p>
<p>For issues, suggestions, or improvements, please contact the author or submit issues through your community channels.</p>
</footer>
</div>
</body>
</html>

View File

@ -1,308 +0,0 @@
# Moose Dynamic Ground Battle
**Version:** 1.0.3
**Author:** F99th-TracerFacer
**Date:** November 12, 2024
## Overview
Moose Dynamic Ground Battle is a sophisticated DCS World mission script that creates an engaging, dynamic ground warfare system between Red and Blue coalitions. The script uses the MOOSE framework to simulate realistic battlefield conditions with zone capture mechanics, intelligent AI movement, and warehouse-based reinforcement systems.
## Features
### 🎯 Zone Capture System
- **Multiple Zone States:** Captured, Guarded, Empty, Attacked, and Neutral
- **Visual Indicators:**
- 🔴 Red: Captured by Red forces
- 🔵 Blue: Captured by Blue forces
- 🟠 Orange: Contested zone
- 🟢 Green: Empty/Neutral zone
- **Real-time Updates:** Zone status changes trigger messages and visual updates
### 🚁 Intelligent AI Behavior
- **Automated Spawning:** Infantry and armor groups spawn at random locations within friendly zones
- **Smart Pathfinding:** Units automatically calculate and move to the nearest enemy zone
- **Periodic Task Assignment:** Every configurable interval, units receive new orders based on zone states
- **CTLD Integration:** Troops dropped via CTLD will automatically join the battle
- **Stuck Unit Recovery:** Units that become stuck can be reset to receive new patrol orders
### 🏭 Warehouse System
- **Dynamic Reinforcement Rate:** Spawn frequency adjusts based on warehouse survival
- **Proportional Impact:** 100% warehouses = 100% reinforcement rate, 50% warehouses = 50% rate
- **Intelligence Markers:** Automatic map markers showing warehouse locations and nearby units
- **Strategic Importance:** Warehouses become critical targets affecting enemy reinforcement capability
### 📊 Spawn Management
- **Configurable Limits:** Set initial spawn counts and maximum unit limits
- **Template Randomization:** Multiple unit templates for variety
- **Frequency Control:** Adjustable spawn intervals for infantry and armor
- **Coalition Balance:** Independent settings for Red and Blue forces
## Installation Requirements
### Prerequisites
1. **MOOSE Framework:** This script requires the MOOSE framework for DCS World
- Download from [MOOSE GitHub](https://github.com/FlightControl-Master/MOOSE)
- Load MOOSE in your mission before this script
2. **DCS World:** Compatible with current DCS World versions
3. **Mission Editor:** All groups, zones, and warehouses must be pre-configured
### Mission Editor Setup
#### Required Groups (All LATE ACTIVATE)
**Red Forces:**
```
Infantry: RedInfantry1, RedInfantry2, RedInfantry3, RedInfantry4, RedInfantry5, RedInfantry6
Armor: RedArmor1, RedArmor2, RedArmor3, RedArmor4, RedArmor5, RedArmor6
```
**Blue Forces:**
```
Infantry: BlueInfantry1, BlueInfantry2, BlueInfantry3, BlueInfantry4, BlueInfantry5, BlueInfantry6
Armor: BlueArmor1, BlueArmor2, BlueArmor3, BlueArmor4, BlueArmor5
```
#### Required Zones
**Red Zones:**
```
FrontLine1, FrontLine2, FrontLine3, FrontLine4, FrontLine5, FrontLine6
```
**Blue Zones:**
```
FrontLine7, FrontLine8, FrontLine9, FrontLine10, FrontLine11, FrontLine12
```
#### Required Warehouses (Static Objects)
**Red Warehouses:**
```
RedWarehouse1-1, RedWarehouse2-1, RedWarehouse3-1,
RedWarehouse4-1, RedWarehouse5-1, RedWarehouse6-1
```
**Blue Warehouses:**
```
BlueWarehouse1-1, BlueWarehouse2-1, BlueWarehouse3-1,
BlueWarehouse4-1, BlueWarehouse5-1, BlueWarehouse6-1
```
⚠️ **Important:** Warehouse names are based on the static **unit name** in the mission editor, not the display name.
#### Optional: Command Centers
If not using another script for command centers, create these units:
- `BLUEHQ` - Blue coalition HQ unit
- `REDHQ` - Red coalition HQ unit
## Configuration
### Basic Settings
```lua
-- Infantry Movement
MOVING_INFANTRY_PATROLS = false -- Set true to enable infantry movement
-- Warehouse Markers
ENABLE_WAREHOUSE_MARKERS = true
UPDATE_MARK_POINTS_SCHED = 60 -- Update interval in seconds
MAX_WAREHOUSE_UNIT_LIST_DISTANCE = 5000 -- Search radius in meters
-- Task Assignment
ASSIGN_TASKS_SCHED = 600 -- Reassign tasks every 600 seconds
```
### Spawn Configuration
**Red Forces:**
```lua
INIT_RED_INFANTRY = 5 -- Initial infantry groups
MAX_RED_INFANTRY = 100 -- Maximum infantry groups
SPAWN_SCHED_RED_INFANTRY = 1800 -- Spawn interval (seconds)
INIT_RED_ARMOR = 25 -- Initial armor groups
MAX_RED_ARMOR = 200 -- Maximum armor groups
SPAWN_SCHED_RED_ARMOR = 300 -- Spawn interval (seconds)
```
**Blue Forces:**
```lua
INIT_BLUE_INFANTRY = 5 -- Initial infantry groups
MAX_BLUE_INFANTRY = 100 -- Maximum infantry groups
SPAWN_SCHED_BLUE_INFANTRY = 1800 -- Spawn interval (seconds)
INIT_BLUE_ARMOR = 25 -- Initial armor groups
MAX_BLUE_ARMOR = 200 -- Maximum armor groups
SPAWN_SCHED_BLUE_ARMOR = 300 -- Spawn interval (seconds)
```
### Zone Configuration
Zones can be arranged in any configuration - along a front line, following roads, or scattered across the map:
```lua
local redZones = {
ZONE:New("FrontLine1"),
ZONE:New("FrontLine2"),
-- Add more zones as needed
}
local blueZones = {
ZONE:New("FrontLine7"),
ZONE:New("FrontLine8"),
-- Add more zones as needed
}
```
### Template Customization
Add variety by creating multiple unit templates:
```lua
local redInfantryTemplates = {
"RedInfantry1",
"RedInfantry2",
-- Add more templates for variety
}
local redArmorTemplates = {
"RedArmor1",
"RedArmor2",
-- Add more templates for variety
}
```
## Gameplay Mechanics
### Zone Capture
- Zones change ownership based on unit presence
- Zones transition through states: Empty → Attacked → Captured → Guarded
- Players receive notifications when zones change status
- Visual indicators (smoke and map colors) show current ownership
### Unit Behavior
1. **Spawn:** Units spawn at random locations in friendly zones
2. **Task Assignment:** Units calculate the nearest enemy zone
3. **Movement:** Units patrol to and around enemy zones
4. **Reassignment:** Stationary units receive new orders periodically
5. **Combat:** Units engage enemies encountered during patrols
### Warehouse Impact
- **Full Capacity:** All warehouses alive = normal spawn rate
- **Reduced Capacity:** 50% warehouses alive = 2x spawn delay
- **No Capacity:** 0% warehouses alive = no more spawns
- **Strategic Target:** Destroying enemy warehouses significantly impacts their reinforcement rate
### Win Conditions
- Mission ends when one coalition captures all zones
- Periodic checks every 60 seconds
- Victory message and sound plays for winning side
## In-Game Menu
Access warehouse status via the F10 menu:
```
F10 → Warehouse Monitoring → Check Warehouse Status
```
This displays:
- Number of warehouses alive per side
- Current reinforcement capacity percentage
- Real-time battlefield intelligence
## Customization Tips
### Adjusting Difficulty
- **Increase Challenge:** Reduce friendly spawn rates, increase enemy spawn rates
- **Balance Forces:** Adjust MAX values to limit unit counts
- **Strategic Depth:** Add more zones and warehouses
- **Terrain Adaptation:** Disable infantry movement for mountainous terrain
### Adding More Units
1. Create new templates in mission editor
2. Add template names to the appropriate arrays
3. Ensure templates are set to LATE ACTIVATE
4. Test spawn behavior and patrol patterns
### Zone Layouts
- **Linear Front:** Place zones in a line for traditional front-line combat
- **Scattered:** Distribute zones for multi-front warfare
- **Road Network:** Follow roads for realistic vehicle movement
- **Strategic Points:** Place zones at key terrain features
## Troubleshooting
### Common Issues
**Units Not Spawning:**
- Verify all template groups exist in mission editor
- Check that groups are set to LATE ACTIVATE
- Review DCS.log for error messages
**Units Not Moving:**
- Check `MOVING_INFANTRY_PATROLS` setting for infantry
- Verify zones are properly named and created
- Check that units aren't already moving when tasks are assigned
**Warehouse Markers Not Showing:**
- Ensure `ENABLE_WAREHOUSE_MARKERS = true`
- Verify warehouse static objects exist
- Check that warehouse names match unit names (not display names)
**Zones Not Capturing:**
- Verify MOOSE framework is loaded
- Check zone names match exactly
- Ensure units are fully inside zones
## Script Structure
```
├── Configuration Section (User Editable)
│ ├── Spawn Settings
│ ├── Zone Definitions
│ ├── Warehouse Definitions
│ └── Template Definitions
├── Core Functions (Do Not Edit)
│ ├── Zone Capture System
│ ├── Task Assignment Logic
│ ├── Warehouse Monitoring
│ ├── Spawn Frequency Calculator
│ └── Win Condition Checker
└── Initialization
├── Spawn Schedulers
├── Event Handlers
└── Menu Creation
```
## Performance Considerations
- **Unit Limits:** Higher MAX values increase computational load
- **Update Frequency:** Longer intervals reduce CPU usage but decrease responsiveness
- **Zone Count:** More zones = more calculations per update
- **Template Variety:** More templates add minimal overhead
## Credits
- **Script Author:** F99th-TracerFacer
- **Framework:** MOOSE Framework by FlightControl
- **Community:** DCS World Mission Editing Community
## Version History
- **1.0.3** (November 12, 2024) - Current release
- **1.0.0** (November 11, 2024) - Initial release
## License
This script is provided as-is for the DCS World community. Feel free to modify and distribute with credit to the original author.
## Support
For issues, suggestions, or improvements, please contact the author or submit issues through your community channels.
---
**Happy Mission Building! 🚁**

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry kind="con" path="org.eclipse.ldt.ExecutionEnvironmentContainer/lua/5.1"/>
<buildpathentry kind="src" path="src"/>
</buildpath>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Moose_Framework</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -1,2 +0,0 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

View File

@ -1,4 +0,0 @@
local function main()
end
main()

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry combineaccessrules="false" kind="prj" path="/Moose_Framework"/>
</buildpath>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Moose_Missions</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -1,2 +0,0 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

View File

@ -1,3 +0,0 @@
local PlanesClientSet = SET_CLIENT:New():FilterCategories( "plane" ):FilterStart()
local AirbasePolice = AIRBASEPOLICE_CAUCASUS:New( PlanesClientSet )

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,3 +0,0 @@
local PlanesClientSet = SET_CLIENT:New():FilterCategories( "plane" ):FilterStart()
local AirbasePolice = AIRBASEPOLICE_NEVADA:New( PlanesClientSet )

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,28 +0,0 @@
---
-- Name: AIB-001 - Spawned AI
-- Author: FlightControl
-- Date Created: 07 Dec 2016
--
-- # Situation:
--
-- For the red coalition, 2 client slots are foreseen.
-- We test the AI spawning frequency, validating the number of spawned AI,
-- matching the amount of players that not have joined the mission.
-- When players join, AI should fly to the nearest home base.
--
-- # Test cases:
--
-- 1. If no player is logging into the red slots, 2 red AI planes should be alive.
-- 2. If a player joins one red slot, one red AI plane should return to the nearest home base.
-- 3. If two players join the red slots, no AI plane should be spawned, and all airborne AI planes should return to the nearest home base.
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,43 +0,0 @@
-- Name: AIB-002 - Patrol AI.lua
-- Author: FlightControl
-- Date Created: 7 December 2016
--
-- # Situation:
--
-- For the red coalition, 2 client slots are foreseen.
-- For those players that have not joined the mission, red AI is spawned.
-- The red AI should start patrolling an area until fuel is empty and return to the home base.
--
-- # Test cases:
--
-- 1. If no player is logging into the red slots, 2 red AI planes should be alive.
-- 2. If a player joins one red slot, one red AI plane should return to the nearest home base.
-- 3. If two players join the red slots, no AI plane should be spawned, and all airborne AI planes should return to the nearest home base.
-- 4. Spawned AI should take-off from the airbase, and start patrolling the area around Anapa.
-- 5. When the AI is out-of-fuel, it should report it is returning to the home base, and land at Anapa.
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
local PatrolZones = {}
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local PatrolZoneGroup = GROUP:FindByName( "PatrolZone" )
local PatrolZone = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup )
PatrolZones[AIGroup] = AI_PATROL_ZONE:New( PatrolZone, 3000, 6000, 400, 600 )
PatrolZones[AIGroup]:ManageFuel( 0.2, 60 )
PatrolZones[AIGroup]:SetControllable( AIGroup )
PatrolZones[AIGroup]:__Start( 5 )
end

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,24 +0,0 @@
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
RU_AirbasesSet = SET_AIRBASE:New():FilterCoalitions("red"):FilterStart()
RU_AirbasesSet:Flush()
RU_AI_Balancer:ReturnToNearestAirbases( 10000, RU_AirbasesSet )
US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" )
US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 )
US_AI_Balancer = AI_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn )
--RU_AI_Balancer:ReturnToHomeAirbase( 10000 )
--local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Blue" )
--local PatrolZoneBlue = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup )
--local PatrolZoneB = AI_PATROL_ZONE:New( PatrolZoneBlue, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 )
--US_AI_Balancer:SetPatrolZone( PatrolZoneB )
--
--local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Red" )
--local PatrolZoneRed = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup )
--local PatrolZoneR = AI_PATROL_ZONE:New( PatrolZoneRed, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 )
--RU_AI_Balancer:SetPatrolZone( PatrolZoneR )

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,47 +0,0 @@
-- Name: AIB-004 - Respawn Test when Destroyed.lua
-- Author: FlightControl
-- Date Created: 7 January 2017
--
-- # Situation:
--
-- For the red coalition, 2 client slots are foreseen.
-- For those players that have not joined the mission, red AI is spawned.
-- The red AI should start patrolling an area.
--
-- The blue side has SAMs nearby.
-- Once the red AI takes off, the red AI is attacked by the blue SAMs.
-- Red AI should be killed and once that happens, a Respawn of the group should happen!
-- The Respawn happens through the InitCleanUp() API of SPAWN.
--
-- # Test cases:
--
-- 1. If no player is logging into the red slots, 2 red AI planes should be alive.
-- 2. If a player joins one red slot, one red AI plane should return to the nearest home base.
-- 3. If two players join the red slots, no AI plane should be spawned, and all airborne AI planes should return to the nearest home base.
-- 4. Monitor that once a red AI is destroyed, that it ReSpawns...
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local PatrolZoneGroup = GROUP:FindByName( "PatrolZone" )
local PatrolZone = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup )
local Patrol = AI_PATROL_ZONE:New( PatrolZone, 3000, 6000, 400, 600 )
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetControllable( AIGroup )
Patrol:__Start( 5 )
end

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,51 +0,0 @@
-- Name: AIB-005 - Patrol AI and Randomize Zones
-- Author: FlightControl
-- Date Created: 10 Jan 2016
--
-- # Situation:
--
-- For the red coalition, 2 client slots are foreseen.
-- For those players that have not joined the mission, red AI is spawned.
-- The red AI should start patrolling an area until fuel is empty and return to the home base.
-- For each AI being spawned, ensure that they fly to a random zone defined within the mission editor.
-- Right now there are two patrol zones defined, so the AI should start patrolliing in one of these zones.
--
-- # Test cases:
--
-- 1. If no player is logging into the red slots, 2 red AI planes should be alive.
-- 2. If a player joins one red slot, one red AI plane should return to the nearest home base.
-- 3. If two players join the red slots, no AI plane should be spawned, and all airborne AI planes should return to the nearest home base.
-- 4. Spawned AI should take-off from the airbase, and start patrolling the area around Anapa.
-- 5. When the AI is out-of-fuel, it should report it is returning to the home base, and land at Anapa.
-- 6. Ensure that you see the AI patrol in one of the two zones ...
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
-- Create the first polygon zone ...
PatrolZoneGroup1 = GROUP:FindByName( "PatrolZone1" )
PatrolZone1 = ZONE_POLYGON:New( "PatrolZone1", PatrolZoneGroup1 )
-- Create the second polygon zone ...
PatrolZoneGroup2 = GROUP:FindByName( "PatrolZone2" )
PatrolZone2 = ZONE_POLYGON:New( "PatrolZone2", PatrolZoneGroup2 )
-- Now, create an array of these zones ...
PatrolZoneArray = { PatrolZone1, PatrolZone2 }
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local Patrol = AI_PATROL_ZONE:New( PatrolZoneArray[math.random( 1, 2 )], 3000, 6000, 400, 600 )
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetControllable( AIGroup )
Patrol:Start()
end

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,43 +0,0 @@
-- Name: AIB-005 - Patrol AI and Randomize Zones
-- Author: FlightControl
-- Date Created: 10 Jan 2016
--
-- # Situation:
--
-- For the red coalition, 2 client slots are foreseen.
-- For those players that have not joined the mission, red AI is spawned.
-- You'll notice a lot of AI is being spawned, as there are a lot of slots...
-- If the SPAWN API :InitCleanUp( secs ) is NOT used, you'll notice that the planes block each other on the runway.
-- After a short period of time, nothing will move anymore...
-- The :InitCleanUp( seconds ) API of the SPAWN class ensure that any AI that is parked longer than the
-- specified amount of seconds, is respawned back at the parking position.
-- This frees up the other planes departing, and the airbase is in this way decluttered...
--
-- # Test cases:
--
-- 1. Observe the de-cluttering of planes at Krymsk.
-- 2. Play with the InitCleanUp API of the SPAWN class, extende the amount of seconds to find the optimal setting.
-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup.
RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" )
-- Define the SPAWN object for the red AI plane template.
-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off.
-- If a blocked plane exists, this red plane will be ReSpawned.
RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 )
-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter.
RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn )
-- Create the first polygon zone ...
PatrolZoneGroup1 = GROUP:FindByName( "PatrolZone1" )
PatrolZone1 = ZONE_POLYGON:New( "PatrolZone1", PatrolZoneGroup1 )
function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local Patrol = AI_PATROL_ZONE:New( PatrolZone1, 3000, 6000, 400, 600 )
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetControllable( AIGroup )
Patrol:__Start( 5 )
end

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,163 +0,0 @@
-- Name: AIB-007 - AI Balancers For all airports and both coalitions
-- Author: Delta99
-- Date Created: 11 Feb 2017
--
-- Originally created to solve issues jg7xman (from Moose Slack group) was having in creating
-- AI_BALANCER across multiple airbases.
-- # Situation:
--
-- AI_BALANCERS created per airbase for both coalitions. Mutiple patrol zones are created
-- for each side. Each flight that is created by AI_BALANCER will pick a random patrol zone
-- to patrol.
-- # Test Cases
--
-- 1. Observe at least 1 flight spawning and taking off from each airbase.
-- 2. Each flight patrols randomly in one of its sides zones.
-- 3. AI will respawn after killed.
-- 4. Additional client slots are available at Sochi. If players don't take a slot there
-- will be more than one AI taking off from Sochi.
-- 5. Batumi contains a flight of 3 units rather than just 1 like most of the rest of the airbases.
-- 6. Watch the coalition AI clash and kill each other.
-- Create the Red Patrol Zone Array
-- This zone array will be used in the AI_BALANCER to randomize the patrol
-- zone that each spawned group will patrol
RedPatrolZone = {}
RedPatrolZone[1] = ZONE:New( "RedPatrolZone1" )
RedPatrolZone[2] = ZONE:New( "RedPatrolZone2" )
RedPatrolZone[3] = ZONE:New( "RedPatrolZone3" )
RedPatrolZone[4] = ZONE:New( "RedPatrolZone4" )
RedPatrolZone[5] = ZONE:New( "RedPatrolZone5" )
RedPatrolZone[6] = ZONE:New( "RedPatrolZone6" )
-- Russian CAP Aircraft
-- These are the aircraft created in the mission editor that the AI will spawn
-- with replacing any CLIENT created aircraft in the mission that a human
-- player does not take.
RU_PlanesSpawn = {}
RU_PlanesSpawn[1] = SPAWN:New( "RU CAP Anapa AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Anapa_Vityazevo)
RU_PlanesSpawn[2] = SPAWN:New( "RU CAP Beslan AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Beslan)
RU_PlanesSpawn[3] = SPAWN:New( "RU CAP Gelendzhik AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Gelendzhik)
RU_PlanesSpawn[4] = SPAWN:New( "RU CAP Krasnodar Center AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Krasnodar_Center)
RU_PlanesSpawn[5] = SPAWN:New( "RU CAP Krasnodar Pashkovsky AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Krasnodar_Pashkovsky)
RU_PlanesSpawn[6] = SPAWN:New( "RU CAP Krymsk AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Krymsk)
RU_PlanesSpawn[7] = SPAWN:New( "RU CAP Maykop AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Maykop_Khanskaya)
RU_PlanesSpawn[8] = SPAWN:New( "RU CAP Mineralnye Vody AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Mineralnye_Vody)
RU_PlanesSpawn[9] = SPAWN:New( "RU CAP Mozdok AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Mozdok)
RU_PlanesSpawn[10] = SPAWN:New( "RU CAP Nalchik AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Nalchik)
RU_PlanesSpawn[11] = SPAWN:New( "RU CAP Novorossiysk AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Novorossiysk)
-- Russian Client Aircraft (via AI_BALANCER, AI will replace these if no human players are in the slot)
-- If you want more client slots per airbase that you want AI to be able to take control of then
-- name them with the prefixes below and they will be picked up automatically by FilterPrevixes.
--
-- For example, if you want another Client slot available at Anapa name it "RU CLIENT Anapa AB 2".
-- The code here does not need to be changed. Only an addition in the mission editor. An example
-- of this can be found on the USA side at Sochi AB.
RU_PlanesClientSet = {}
RU_PlanesClientSet[1] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Anapa AB")
RU_PlanesClientSet[2] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Beslan AB")
RU_PlanesClientSet[3] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Gelendzhik AB")
RU_PlanesClientSet[4] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Krasnodar Center AB")
RU_PlanesClientSet[5] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Krasnodar Pashkovsky AB")
RU_PlanesClientSet[6] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Krymsk AB")
RU_PlanesClientSet[7] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Maykop AB")
RU_PlanesClientSet[8] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Mineralnye Vody AB")
RU_PlanesClientSet[9] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Mozdok AB")
RU_PlanesClientSet[10] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Nalchik AB")
RU_PlanesClientSet[11] = SET_CLIENT:New():FilterPrefixes("RU CLIENT Novorossiysk AB")
-- We setup an array to store all the AI_BALANCERS that are going to be created. Basically one
-- per airbase. We loop through and create an AI_BALANCER as well as a separate OnAfterSpawned
-- function for each. The Patrol Zone is randomized in the first parameter to AI_PATROL_ZONE:New()
-- call. This is done for each of the AI_BALANCERS. To add more patrol zones, just define them in
-- the mission editor and add into the array above. Code here does not need to be changed. The
-- table.getn(RedPatrolZone) gets the number of elements in the RedPatrolZone array so that all
-- of them are included to pick randomly.
RU_AI_Balancer = {}
for i=1, 11 do
RU_AI_Balancer[i] = AI_BALANCER:New(RU_PlanesClientSet[i], RU_PlanesSpawn[i])
-- We set a local variable within the for loop to the AI_BALANCER that was just created.
-- I couldn't get RU_AI_BALANCER[i]:OnAfterSpawn to be recognized so this is just pointing
-- curAIBalancer to the relevant RU_AI_BALANCER array item for each loop.
-- So in this case there are essentially 11 OnAfterSpawned functions defined and handled.
local curAIBalancer = RU_AI_Balancer[i]
function curAIBalancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local Patrol = AI_PATROL_ZONE:New( RedPatrolZone[math.random( 1, table.getn(RedPatrolZone))], 1500, 5500, 700, 1400 )
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
end
-- US / Blue side is setup pretty much identically to the RU side above. Same detailed comments
-- above apply here. The main difference here is 10 airbases instead of 11.
-- Another difference is additional client slots at Sochi and a group defined at Batumi with
-- more than 1 unit per group (flight of 3 units). This is just to show that you can have more
-- client slots per airbase and more units in a single group that the AI will control. I think
-- this will also allow you to fly lead with AI on your wing or you can fly wing with an AI
-- leader.
-- Create the Blue Patrol Zone Array
BluePatrolZone = {}
BluePatrolZone[1] = ZONE:New( "BluePatrolZone1")
BluePatrolZone[2] = ZONE:New( "BluePatrolZone2")
BluePatrolZone[3] = ZONE:New( "BluePatrolZone3")
BluePatrolZone[4] = ZONE:New( "BluePatrolZone4")
BluePatrolZone[5] = ZONE:New( "BluePatrolZone5")
BluePatrolZone[6] = ZONE:New( "BluePatrolZone6")
--United States CAP Aircraft (these are used as templates for AI)
US_PlanesSpawn = {}
US_PlanesSpawn[1] = SPAWN:New( "US CAP Batumi AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Batumi)
US_PlanesSpawn[2] = SPAWN:New( "US CAP Gudauta AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Gudauta)
US_PlanesSpawn[3] = SPAWN:New( "US CAP Kobuleti AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Kobuleti)
US_PlanesSpawn[4] = SPAWN:New( "US CAP Kutaisi AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Kutaisi)
US_PlanesSpawn[5] = SPAWN:New( "US CAP Senaki AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Senaki_Kolkhi)
US_PlanesSpawn[6] = SPAWN:New( "US CAP Sochi AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Sochi_Adler)
US_PlanesSpawn[7] = SPAWN:New( "US CAP Soganlug AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Soganlug)
US_PlanesSpawn[8] = SPAWN:New( "US CAP Sukhumi AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Sukhumi_Babushara)
US_PlanesSpawn[9] = SPAWN:New( "US CAP Vaziani AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Vaziani)
US_PlanesSpawn[10] = SPAWN:New( "US CAP Tbilisi AB" ):InitCleanUp( 45 ):InitAirbase(AIRBASE.Caucasus.Tbilisi_Lochini)
--United States Client Aircraft (via AI_BALANCER, AI will replace these if no human players are in the slot)
US_PlanesClientSet = {}
US_PlanesClientSet[1] = SET_CLIENT:New():FilterPrefixes("US CLIENT Batumi AB")
US_PlanesClientSet[2] = SET_CLIENT:New():FilterPrefixes("US CLIENT Gudauta AB")
US_PlanesClientSet[3] = SET_CLIENT:New():FilterPrefixes("US CLIENT Kobuleti AB")
US_PlanesClientSet[4] = SET_CLIENT:New():FilterPrefixes("US CLIENT Kutaisi AB")
US_PlanesClientSet[5] = SET_CLIENT:New():FilterPrefixes("US CLIENT Senaki AB")
US_PlanesClientSet[6] = SET_CLIENT:New():FilterPrefixes("US CLIENT Sochi AB")
US_PlanesClientSet[7] = SET_CLIENT:New():FilterPrefixes("US CLIENT Soganlug AB")
US_PlanesClientSet[8] = SET_CLIENT:New():FilterPrefixes("US CLIENT Sukhumi AB")
US_PlanesClientSet[9] = SET_CLIENT:New():FilterPrefixes("US CLIENT Vaziani AB")
US_PlanesClientSet[10] = SET_CLIENT:New():FilterPrefixes("US CLIENT Tbilisi AB")
US_AI_Balancer = {}
for i=1, 10 do
US_AI_Balancer[i] = AI_BALANCER:New( US_PlanesClientSet[i], US_PlanesSpawn[i] )
local curAIBalancer = US_AI_Balancer[i]
function curAIBalancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup )
local Patrol = AI_PATROL_ZONE:New( BluePatrolZone[math.random( 1, table.getn(BluePatrolZone))], 1500, 5500, 700, 1400 )
Patrol:ManageFuel( 0.2, 60 )
Patrol:SetControllable( AIGroup )
Patrol:Start()
end
end

View File

@ -1,10 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
$dir
$file
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,20 +0,0 @@
---
-- Name: AIC-APC-000 - APC
-- Author: FlightControl
-- Date Created: 26 Mar 2018
-- Date Checked: 01 Jan 2021
-- Working example
--
-- A demonstration of the AI_CARGO_APC class.
-- This simple example transports Infantry.
-- The CARGO_GROUP objects are declared within the mission script.
local Infantry1 = CARGO_GROUP:New( GROUP:FindByName( "Infantry1" ), "Infantry", "Infantry1", 500, 25 )
local Infantry2 = CARGO_GROUP:New( GROUP:FindByName( "Infantry2" ), "Infantry", "Infantry2", 500, 25 )
local Infantry3 = CARGO_GROUP:New( GROUP:FindByName( "Infantry3" ), "Infantry", "Infantry3", 500, 25 )
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local APC = GROUP:FindByName( "APC" )
AICargoAPC = AI_CARGO_APC:New( APC, InfantryCargoSet, 500 )
AICargoAPC:__Pickup( 5 )

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,18 +0,0 @@
---
-- Name: AIC-APC-001 - APC with Cargo declared in ME
-- Author: FlightControl
-- Date Created: 26 Mar 2018
-- Date Checked: 01 Dec 2021
-- Changed Cargo auto tag from ~ to #, working example
--
-- A demonstration of the AI_CARGO_APC class.
-- This simple example transports Infantry.
-- The cargo is declared with the #CARGO tag in the mission editor.
-- So, within the mission, the infantry groups have the name:
-- e.g. Infantry1#CARGO(T=Infantry,RR=2000,NR=25)
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local APC = GROUP:FindByName( "APC" )
AICargoAPC = AI_CARGO_APC:New( APC, InfantryCargoSet, 500 )
AICargoAPC:__Pickup( 5 )

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,12 +0,0 @@
---
-- Name: AIC-APC-002 - APC Move by Game Master
-- Author: FlightControl
-- Date Created: 26 Mar 2018
-- Date Checked: 01 Jan 2021. Changed ~ to # in ME Group Names. Not sure how this is supposed to work for the Game Master
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local CargoCarrier = GROUP:FindByName( "Carrier" )
CargoTroops = AI_CARGO_APC:New( CargoCarrier, InfantryCargoSet, 500 )

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,15 +0,0 @@
---
-- Name: AIC-APC-003 - APC Troops and Equipment
-- Author: FlightControl
-- Date Created: 07 Apr 2018
-- Date Checked: 01 Jan 2021
-- Not sure what the test case is
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local CargoCarrier = GROUP:FindByName( "Carrier" )
CargoTroops = AI_CARGO_APC:New( CargoCarrier, InfantryCargoSet, 350 )

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,29 +0,0 @@
---
-- Name: AIC-APC-004 - APC Pickup
-- Author: FlightControl
-- Date Created: 23 Apr 2018
-- Date Checked: 01 Jan 2021, working example, changed Deploy to async call
BASE:TraceClass("AI_CARGO_APC")
BASE:TraceOn()
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local APC = GROUP:FindByName( "APC" )
Cargo_APC = AI_CARGO_APC:New( APC, InfantryCargoSet, 350 )
Cargo_APC:__Pickup( 1, ZONE:New( "Pickup" ):GetCoordinate() )
--- Loaded Handler OnAfter for Cargo_APC
-- @function [parent=#Cargo_APC] OnAfterLoaded
-- @param #Cargo_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From
-- @param #string Event
-- @param #string To
function Cargo_APC:OnAfterLoaded( APC, From, Event, To )
Cargo_APC:__Deploy( 1, ZONE:New( "Deploy" ):GetCoordinate() )
end

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

View File

@ -1,7 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
Remove-Item .\_unpacked -Force -Recurse
md "_unpacked"
cd "_unpacked"
. 7z x -r -y "..\$file.miz" *

View File

@ -1,29 +0,0 @@
---
-- Name: AIC-APC-001 - Troops Relocate APC
-- Author: FlightControl
-- Date Created: 07 Apr 2018
-- Date Checked: 01 Jan 2021, working
--
-- Demonstration of troops relocation when carrier is destroyed...
-- Carrier will relocate to the rescue carrier.
--
BASE:TraceClass("AI_CARGO_APC")
local InfantryCargoSet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
local CargoCarrier = GROUP:FindByName( "Carrier" )
CargoTroops = AI_CARGO_APC:New( CargoCarrier, InfantryCargoSet, 500 )
function CargoTroops:OnAfterDestroyed( CargoCarrier )
CargoTroops:F( { Destroyed = CargoCarrier } )
-- The coordinate is passed where the carrier is destroyed.
local NewCarrierGroup = self:FindCarrier( CargoCarrier:GetCoordinate(), 1000 ) -- which returns one Carrier GROUP object or nil.
if NewCarrierGroup then
self:SetCarrier( NewCarrierGroup )
self:__Pickup(1,ZONE:New("Pickup Zone"):GetCoordinate(),30)
end
end

View File

@ -1,6 +0,0 @@
$dir = split-path -parent $MyInvocation.MyCommand.Definition
cd $dir
$file = Split-Path $dir -leaf
cd "_unpacked"
. 7z a -r -y -tzip "..\$file.miz" *
cd ..

Some files were not shown because too many files have changed in this diff Show More