mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
3077 lines
115 KiB
Lua
3077 lines
115 KiB
Lua
-- ============================================================================
|
|
-- MOOSE TANKER MANAGEMENT SYSTEM
|
|
-- Comprehensive tanker lifecycle management with auto-respawn, fuel monitoring,
|
|
-- TACAN/frequency announcements, and menu controls
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- USER CONFIGURATION
|
|
-- ============================================================================
|
|
|
|
-- Tanker Configuration
|
|
local TANKER_CONFIG = {
|
|
KC135 = {
|
|
groupName = "TANKER 135",
|
|
unitName = "TANKER 135-1",
|
|
displayName = "TANKER KC-135",
|
|
aircraftType = "KC-135", -- DCS aircraft type name
|
|
livery = nil, -- nil for default, or livery_id string
|
|
callsign = "SHELL", -- Map marker prefix for custom routes
|
|
tacan = "50X", -- Set to match ME or nil if none
|
|
frequency = "251.000", -- Set to match ME or nil if none
|
|
respawnDelay = 180, -- seconds before auto-respawn after destruction
|
|
emergencyRespawnDelay = 60, -- Emergency spawn delay
|
|
fuelWarningPercent = 25, -- Warn when fuel drops below this %
|
|
fuelBingoPercent = 15, -- RTB fuel level
|
|
defaultAltitude = 22000, -- Default altitude in feet (FL220)
|
|
defaultSpeed = 330, -- Default speed in knots
|
|
},
|
|
KC135_MPRS = {
|
|
groupName = "TANKER 135 MPRS",
|
|
unitName = "TANKER 135 MPRS-1",
|
|
displayName = "TANKER KC-135 MPRS",
|
|
aircraftType = "KC135MPRS", -- DCS aircraft type name
|
|
livery = nil,
|
|
callsign = "ARCO", -- Map marker prefix for custom routes
|
|
tacan = "51X",
|
|
frequency = "252.000",
|
|
respawnDelay = 180,
|
|
emergencyRespawnDelay = 60,
|
|
fuelWarningPercent = 25,
|
|
fuelBingoPercent = 15,
|
|
defaultAltitude = 22000,
|
|
defaultSpeed = 330,
|
|
}
|
|
}
|
|
|
|
-- Custom Route Configuration
|
|
local ROUTE_CONFIG = {
|
|
minWaypoints = 2, -- Minimum waypoints required
|
|
maxWaypoints = 10, -- Maximum waypoints allowed
|
|
deleteMarkersAfterUse = true, -- Delete markers after route creation
|
|
waypointPrefix = { -- Recognized marker prefixes
|
|
SHELL = "KC135", -- SHELL1, SHELL2, etc. → KC-135
|
|
ARCO = "KC135_MPRS", -- ARCO1, ARCO2, etc. → KC-135 MPRS
|
|
}
|
|
}
|
|
|
|
-- Emergency Tanker Configuration
|
|
local EMERGENCY_CONFIG = {
|
|
minAltitudeFeet = 10000, -- Minimum altitude for emergency spawn (10k ft)
|
|
maxAltitudeFeet = 45000, -- Maximum altitude for emergency spawn (45k ft)
|
|
spawnDistanceKM = 5, -- Distance ahead of player to spawn tanker (5km)
|
|
waypointDistanceNM = 100, -- Distance for egress waypoint (100nm)
|
|
markerKeywords = { -- Recognized emergency marker keywords (case insensitive)
|
|
"EMERGENCY TANKER",
|
|
"EMERGENCY KC135",
|
|
"EMERGENCY MPRS",
|
|
"EMERGENCY"
|
|
},
|
|
markerSearchRadius = 50000, -- Search for markers within 50km of players (meters)
|
|
}
|
|
|
|
-- Monitoring Configuration
|
|
local FUEL_CHECK_INTERVAL = 60 -- Check fuel every 60 seconds
|
|
local DAMAGE_RTB_THRESHOLD = 50 -- RTB if hull damage exceeds this %
|
|
|
|
-- Default Spawn Location (for non-custom route spawns)
|
|
-- Note: Using lat/lon with SetAltitude to ensure proper altitude MSL
|
|
local DEFAULT_SPAWN_COORD = COORDINATE:NewFromLLDD(34.564, 69.212):SetAltitude(22000 * 0.3048, true) -- Kabul area, FL220
|
|
|
|
-- ============================================================================
|
|
-- GLOBAL STATE TRACKING
|
|
-- ============================================================================
|
|
|
|
TANKER_STATE = {
|
|
KC135 = {
|
|
active = false,
|
|
group = nil,
|
|
dcsGroupName = nil,
|
|
fuelWarned = false,
|
|
bingoWarned = false,
|
|
respawnScheduler = nil,
|
|
fuelMonitor = nil,
|
|
},
|
|
KC135_MPRS = {
|
|
active = false,
|
|
group = nil,
|
|
dcsGroupName = nil,
|
|
fuelWarned = false,
|
|
bingoWarned = false,
|
|
respawnScheduler = nil,
|
|
fuelMonitor = nil,
|
|
}
|
|
}
|
|
|
|
local UNIQUE_NAME_COUNTER = 0
|
|
|
|
local function NextUniqueIndex()
|
|
UNIQUE_NAME_COUNTER = UNIQUE_NAME_COUNTER + 1
|
|
return UNIQUE_NAME_COUNTER
|
|
end
|
|
|
|
local function GenerateGroupName(base, index)
|
|
return string.format("%s #%03d", base, index)
|
|
end
|
|
|
|
local function GenerateUnitName(base, index)
|
|
return string.format("%s-%03d", base, index)
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- MENU REFERENCES (for enable/disable)
|
|
-- ============================================================================
|
|
|
|
local MENU_TANKER_ROOT = nil
|
|
|
|
-- ============================================================================
|
|
-- MESSAGE POOLS FOR VARIETY
|
|
-- Randomized messages provide immersive variety across tanker operations.
|
|
-- Each category contains 100 variations selected randomly via GetRandomMessage()
|
|
-- ============================================================================
|
|
|
|
local TANKER_MESSAGES = {
|
|
-- Spawn Confirmation (success)
|
|
SPAWN_SUCCESS = {
|
|
"%s is airborne and ready for refueling operations.",
|
|
"%s has launched and is standing by for fuel.",
|
|
"%s is now on station and ready to pump gas.",
|
|
"%s has departed and is available for refueling.",
|
|
"%s is up and ready to service aircraft.",
|
|
"%s is airborne. Refueling services now available.",
|
|
"%s has checked in on station.",
|
|
"%s is overhead and ready for business.",
|
|
"%s is now available for aerial refueling.",
|
|
"%s has arrived on station. Ready to refuel.",
|
|
"%s is up! Time to get your drink on.",
|
|
"%s has joined the party. Bring your cups!",
|
|
"%s reporting. The bar is now open.",
|
|
"%s is flying. Get in line for your juice.",
|
|
"%s on station. Don't be shy, we got plenty.",
|
|
"%s airborne. Unlike Mo's last attempt at flying.",
|
|
"%s has successfully launched. No thanks to Mo.",
|
|
"%s is ready. Mo said he could do this but we know better.",
|
|
"%s in position. Fuel truck of the sky is open for business!",
|
|
"%s has arrived fashionably late but ready to pump.",
|
|
"%s checking in. Your gas station with wings is here.",
|
|
"%s is up there doing tanker things.",
|
|
"%s launched without hitting anything. Good start!",
|
|
"%s airborne and hasn't broken anything yet.",
|
|
"%s is ready to make it rain... JP-8.",
|
|
"%s in the pattern. Come get some dinosaur juice!",
|
|
"%s reporting for duty. Time to feed some thirsty birds.",
|
|
"%s has spawned successfully. Mo's jealous.",
|
|
"%s is flying high and ready to share the wealth.",
|
|
"%s on station. Dispensary is OPEN.",
|
|
"%s has graced you with its presence. You're welcome.",
|
|
"%s is here to save your ass from flameout.",
|
|
"%s launched. The sky gas station is open 24/7.",
|
|
"%s airborne. Better than Mo's last tanker spawn attempt.",
|
|
"%s ready to refuel. Unlike your love life, this actually works.",
|
|
"%s has arrived to keep you from embarrassing yourself.",
|
|
"%s on station and totally not judging your fuel planning.",
|
|
"%s is up. Try not to break the boom this time.",
|
|
"%s launched successfully. Mo couldn't get his off the ground.",
|
|
"%s airborne. Your aerial bartender has arrived!",
|
|
"%s ready for action. The juice is loose!",
|
|
"%s has spawned. Time to get wet... with fuel.",
|
|
"%s on station. We promise not to tell anyone you needed us.",
|
|
"%s reporting. Because someone forgot to fuel before takeoff.",
|
|
"%s is here! The flying fuel truck has arrived!",
|
|
"%s airborne and ready to fill your tanks. That's what she said.",
|
|
"%s launched. Even Mo could refuel from this... maybe.",
|
|
"%s on station. Your poor planning is our opportunity!",
|
|
"%s has arrived. The aerial milk truck is ready.",
|
|
"%s ready to pump. Get your minds out of the gutter.",
|
|
"%s airborne because you can't manage fuel apparently.",
|
|
"%s is up there waiting. Don't keep us hovering forever.",
|
|
"%s has joined the fight. By 'fight' we mean 'hovering lazily.'",
|
|
"%s on station. Premium unleaded is on tap!",
|
|
"%s launched and looking sexy up here.",
|
|
"%s ready to refuel. Try not to scratch the paint this time.",
|
|
"%s has arrived. Mo said this was impossible but here we are.",
|
|
"%s airborne. The sky's full service station is open!",
|
|
"%s on station ready to save your bacon.",
|
|
"%s has launched into the wild blue yonder!",
|
|
"%s reporting for gas pumping duty.",
|
|
"%s is up and Mo isn't. Winner: us.",
|
|
"%s airborne. Fuel flows like wine at a wedding!",
|
|
"%s on station. Unlike Mo, we actually showed up.",
|
|
"%s ready to top you off. No phrasing.",
|
|
"%s has successfully taken off. Mo's still taxiing.",
|
|
"%s airborne and operational. The real MVP.",
|
|
"%s on station doing the lord's work.",
|
|
"%s has arrived to prevent your walk of shame.",
|
|
"%s ready for refueling ops. Try to connect this time.",
|
|
"%s launched because someone has to be the adult here.",
|
|
"%s airborne. Probably more reliable than your ex.",
|
|
"%s on station ready to give you the good stuff.",
|
|
"%s has spawned. Mo's tanker is still in the hangar.",
|
|
"%s reporting. Your airborne gas station awaits!",
|
|
"%s is up! Time for some hot refueling action.",
|
|
"%s airborne and Mo's not invited to this party.",
|
|
"%s on station. We have fuel, you have need. Let's dance.",
|
|
"%s ready to dispense freedom molecules!",
|
|
"%s has arrived to fix your fuel management issues.",
|
|
"%s launched. The flying gas can is ready for customers.",
|
|
"%s airborne because apparently nobody can calculate bingo.",
|
|
"%s on station. Come get your fix!",
|
|
"%s ready to pump premium into your thirsty bird.",
|
|
"%s has spawned successfully. Suck it, Mo.",
|
|
"%s reporting. Your aerial enabler is on station.",
|
|
"%s is up there waiting like a patient parent.",
|
|
"%s airborne and ready to make your fuel gauge happy.",
|
|
"%s on station. Mo said we couldn't do it. We did it.",
|
|
"%s launched with more grace than Mo's last landing.",
|
|
"%s ready for business. The boom is ready to boom.",
|
|
"%s has arrived fashionably and ready to serve.",
|
|
"%s airborne. Your fuel problems are about to be solved!",
|
|
"%s on station doing God's work up here.",
|
|
"%s ready to refuel. We got the good stuff.",
|
|
"%s has spawned. Time to feed the hungry jets!",
|
|
"%s reporting for duty with full tanks!",
|
|
"%s launched successfully without Mo's help, thank God.",
|
|
"%s airborne. The flying filling station is OPEN!",
|
|
},
|
|
|
|
-- Taxi Phase
|
|
TAXI = {
|
|
"%s is taxiing to the runway.",
|
|
"%s has started taxi procedures.",
|
|
"%s is rolling to the active runway.",
|
|
"%s beginning taxi operations.",
|
|
"%s is on the move to takeoff position.",
|
|
"%s taxiing for departure.",
|
|
"%s proceeding to runway.",
|
|
"%s has commenced taxi.",
|
|
"%s is rolling out for takeoff.",
|
|
"%s taxiing to active runway now.",
|
|
"%s is taxi-ing. Unlike Mo who got lost on the taxiway.",
|
|
"%s has started moving. Mo would've hit something by now.",
|
|
"%s rolling to the runway. Try not to watch, it's boring.",
|
|
"%s is taxi-ing. This is taking forever but we're getting there.",
|
|
"%s proceeding to runway. Mo's still trying to start the engines.",
|
|
"%s on the move. Slowly. Very slowly.",
|
|
"%s taxiing out. Don't hold your breath, this takes a while.",
|
|
"%s rolling to takeoff position. Mo crashed into a light pole doing this.",
|
|
"%s has begun taxi. Yes, it's as exciting as it sounds.",
|
|
"%s proceeding to departure runway. Mo would be lost already.",
|
|
"%s is moving... eventually we'll get there.",
|
|
"%s taxiing now. Mo said this was the hardest part. He's not wrong.",
|
|
"%s rolling out. This ain't a drag race, it's gonna take a minute.",
|
|
"%s is on the taxi. Mo took a wrong turn and ended up at the terminal.",
|
|
"%s proceeding to active. At least we're not hitting anything.",
|
|
"%s has started taxi. Mo managed to taxi into a ditch once.",
|
|
"%s rolling to runway. This is about as exciting as watching paint dry.",
|
|
"%s taxiing for departure. Mo's still trying to figure out the brakes.",
|
|
"%s is moving. Barely. But we're moving.",
|
|
"%s proceeding to takeoff position. Mo would've needed a tow truck by now.",
|
|
"%s has commenced taxi operations. Don't get too excited.",
|
|
"%s rolling out. Mo said he could taxi backwards. He was wrong.",
|
|
"%s is taxiing. Yes, it's taking this long. Deal with it.",
|
|
"%s on the move to runway. Mo's still reading the taxi diagram.",
|
|
"%s proceeding to active. At least we know where we're going. Mo didn't.",
|
|
"%s taxiing now. Mo thought the taxiway was the runway. Classic Mo.",
|
|
"%s rolling to departure. This is why we don't let Mo taxi.",
|
|
"%s has started moving. Mo would've requested a ground abort by now.",
|
|
"%s taxiing to runway. Mo once taxied into the grass. Good times.",
|
|
"%s proceeding to takeoff. Mo asked for taxi clearance three times. For the same runway.",
|
|
"%s is on the move. Mo's still looking for the parking brake release.",
|
|
"%s rolling out for departure. Mo managed to get a flat tire taxiing once.",
|
|
"%s taxiing to active runway. At least we're not Mo.",
|
|
"%s proceeding to position. Mo would need vectors to the runway.",
|
|
"%s has begun taxi. Mo's idea of taxiing involved several near misses.",
|
|
"%s rolling to runway. Mo once followed the wrong aircraft and ended up lost.",
|
|
"%s is moving to departure. Mo's still trying to read the taxi chart upside down.",
|
|
"%s taxiing now. Mo thought ATC said 'taxi to parking' when they said 'runway.'",
|
|
"%s proceeding to runway. This is taking forever but at least we're not crashed.",
|
|
"%s has started taxi. Mo's version involved more screaming.",
|
|
},
|
|
|
|
-- Takeoff Phase
|
|
TAKEOFF = {
|
|
"%s is rolling for takeoff!",
|
|
"%s departing runway now!",
|
|
"%s is airborne and climbing!",
|
|
"%s has lifted off!",
|
|
"%s wheels up and departing!",
|
|
"%s is taking off now!",
|
|
"%s airborne from runway!",
|
|
"%s has departed!",
|
|
"%s is climbing out!",
|
|
"%s wheels up, departure in progress!",
|
|
"%s is taking off! Mo's still on the taxiway.",
|
|
"%s wheels up! Unlike Mo's last three attempts.",
|
|
"%s airborne! Mo would've aborted by now.",
|
|
"%s has lifted off! Mo's probably jealous.",
|
|
"%s departing! At least we're using the runway, unlike Mo.",
|
|
"%s rolling for takeoff! Mo once tried this on a taxiway.",
|
|
"%s is airborne! Mo said this was impossible. He was wrong.",
|
|
"%s wheels up! Mo's takeoff looked more like a lawn dart.",
|
|
"%s climbing out! Mo's still trying to rotate.",
|
|
"%s has departed! Mo would've hit something by now.",
|
|
"%s is taking off! Mo's version involved more screaming and fire.",
|
|
"%s airborne and climbing! Mo never made it past ground roll.",
|
|
"%s wheels up! Mo thought you needed full flaps for this.",
|
|
"%s departing runway! Mo once forgot to release the parking brake.",
|
|
"%s has lifted off! Mo's takeoff was more of a controlled crash.",
|
|
"%s is climbing! Mo would've stalled by now.",
|
|
"%s airborne! Mo once took off with the tow bar still attached.",
|
|
"%s wheels up and departing! Mo's still calculating V1.",
|
|
"%s taking off! Mo's last takeoff involved ATC screaming.",
|
|
"%s has departed! Mo would've gone off the side of the runway.",
|
|
"%s is airborne! Mo thought you could skip the takeoff roll.",
|
|
"%s climbing out! Mo's still figuring out which way is up.",
|
|
"%s wheels up! Mo once rotated at 50 knots. It didn't work.",
|
|
"%s departing! Mo's takeoff technique was 'hope for the best.'",
|
|
"%s has lifted off! Mo's version involved the tower yelling 'ABORT!'",
|
|
"%s is taking off! Mo once forgot to retract the gear. For 20 minutes.",
|
|
"%s airborne and climbing! Mo's takeoff looked like a drunk pelican.",
|
|
"%s wheels up! Mo thought you needed afterburner for this. In a tanker.",
|
|
"%s departing runway! Mo once tried to take off downwind.",
|
|
"%s has lifted off successfully! Mo's success rate was approximately zero.",
|
|
"%s is climbing! Mo would've hit the ILS antenna by now.",
|
|
"%s airborne! Mo's takeoff checklist was 'close eyes and pray.'",
|
|
"%s wheels up! Mo once departed the runway sideways. Somehow.",
|
|
"%s taking off! Mo's technique was more crash than takeoff.",
|
|
"%s has departed! Mo would still be bouncing down the runway.",
|
|
"%s is airborne! Mo thought V2 was a type of engine oil.",
|
|
"%s climbing out! Mo's last takeoff involved emergency vehicles.",
|
|
"%s wheels up and climbing! Mo would've forgotten to raise the gear.",
|
|
"%s departing! Mo once took off in the wrong direction. Tower was not pleased.",
|
|
"%s has lifted off! Mo's takeoffs usually ended with paperwork.",
|
|
},
|
|
|
|
-- Enroute to Station
|
|
ENROUTE = {
|
|
"%s enroute to station.",
|
|
"%s proceeding to waypoint 1.",
|
|
"%s is flying to the refueling track.",
|
|
"%s heading to station now.",
|
|
"%s enroute to first waypoint.",
|
|
"%s proceeding to patrol area.",
|
|
"%s flying to assigned station.",
|
|
"%s is inbound to refueling track.",
|
|
"%s heading to the pattern.",
|
|
"%s enroute to operational area.",
|
|
"%s is flying to station. ETA: when we get there.",
|
|
"%s proceeding to track. Mo's still trying to read the map.",
|
|
"%s enroute. Mo would be lost by now.",
|
|
"%s heading to waypoint 1. Mo would've missed it.",
|
|
"%s inbound to station. Mo once flew the wrong direction for 30 minutes.",
|
|
"%s proceeding to pattern. At least we're going the right way.",
|
|
"%s enroute to track. Mo's GPS shows him in a different country.",
|
|
"%s flying to station. Mo would need vectors. Lots of vectors.",
|
|
"%s heading to refueling area. Mo thought the refueling area was the ground.",
|
|
"%s inbound now. Mo would've requested a tanker by now. Wait...",
|
|
"%s proceeding to waypoint. Mo's version of navigation was 'turn until it looks right.'",
|
|
"%s enroute to station. Mo once navigated by following highways.",
|
|
"%s flying to track. Mo would be orbiting the airfield asking for help.",
|
|
"%s heading to pattern. Mo thought patterns were for quilts.",
|
|
"%s inbound to area. Mo's navigation skills were 'find it eventually.'",
|
|
"%s proceeding to station. Mo needed GPS, TACAN, and a seeing-eye dog.",
|
|
"%s enroute now. Mo would've declared an emergency for being lost.",
|
|
"%s flying to waypoint 1. Mo would be at waypoint 7 somehow.",
|
|
"%s heading to track. Mo once flew in circles for an hour looking for his assigned area.",
|
|
"%s inbound to station. Mo's navigation was sponsored by 'hope and prayer.'",
|
|
"%s proceeding to area. Mo would need a search and rescue team by now.",
|
|
"%s enroute to pattern. Mo thought autopilot meant 'automatic navigation.'",
|
|
"%s flying to station. Mo once mistook a lake for his waypoint.",
|
|
"%s heading to track. Mo's sense of direction was 'non-existent.'",
|
|
"%s inbound now. Mo would be requesting divert fuel.",
|
|
"%s proceeding to waypoint. Mo's GPS once told him to turn around. He argued with it.",
|
|
"%s enroute to station. Mo thought following the road was acceptable IFR navigation.",
|
|
"%s flying to area. Mo would be overhead the wrong country by now.",
|
|
"%s heading to track. Mo once asked 'which way is north?'",
|
|
"%s inbound to pattern. Mo's navigation checklist was one item: 'get lost.'",
|
|
"%s proceeding to station. Mo would've run out of fuel looking for it.",
|
|
"%s enroute now. Mo thought the GPS coordinates were a phone number.",
|
|
"%s flying to waypoint. Mo would be flying in the opposite direction with confidence.",
|
|
"%s heading to station. Mo once flew an entire mission backwards.",
|
|
"%s inbound to track. Mo's navigation was 'fly until you see something familiar.'",
|
|
"%s proceeding to area. Mo would need a road map and a miracle.",
|
|
"%s enroute to station. Mo thought TACAN stood for 'Totally Can't Navigate.'",
|
|
"%s flying to pattern. Mo once mistook a mountain for a waypoint. He was at sea level.",
|
|
"%s heading to track. Mo's idea of navigation was 'point and hope.'",
|
|
"%s inbound now. Mo would be declaring minimum fuel asking where the hell he is.",
|
|
},
|
|
|
|
-- On Station (Arriving at Pattern)
|
|
ON_STATION = {
|
|
"%s is on station and ready for refueling!",
|
|
"%s has arrived at the refueling track!",
|
|
"%s is established in the pattern!",
|
|
"%s is now on station, ready to service aircraft!",
|
|
"%s has reached the patrol area and is ready!",
|
|
"%s is on station, refueling operations active!",
|
|
"%s has arrived and is ready to pump gas!",
|
|
"%s is established on track, ready for business!",
|
|
"%s is on station, come get your fuel!",
|
|
"%s has reached the pattern and is operational!",
|
|
"%s is on station! Mo never made it this far.",
|
|
"%s has arrived! Mo would still be enroute asking for help.",
|
|
"%s is established in the pattern! Mo would be lost.",
|
|
"%s is on station ready to pump! Mo's still trying to find the area.",
|
|
"%s has reached the track! Mo thought the track was a NASCAR thing.",
|
|
"%s is operational! Mo would've requested emergency fuel by now.",
|
|
"%s has arrived and ready! Mo's idea of 'on station' was 'vaguely nearby.'",
|
|
"%s is on track pumping gas! Mo would be circling aimlessly.",
|
|
"%s is established! Mo would still be 50 miles off asking for vectors.",
|
|
"%s has reached station! Mo once declared on station at the wrong airbase.",
|
|
"%s is ready for refueling! Mo would've forgotten why he came.",
|
|
"%s is on station! Mo's version involved being 'kinda close.'",
|
|
"%s has arrived! Mo would still be arguing with his GPS.",
|
|
"%s is established and ready! Mo thought on station meant parked at the gate.",
|
|
"%s is operational now! Mo would've flown past it twice.",
|
|
"%s has reached the pattern! Mo's pattern was more of a random squiggle.",
|
|
"%s is on station! Mo would be declaring minimum fuel trying to find it.",
|
|
"%s is ready to pump! Mo once showed up to the wrong station. In the wrong country.",
|
|
"%s has arrived at track! Mo thought arriving meant 'within visual range of something.'",
|
|
"%s is on station pumping! Mo would've given up and gone home.",
|
|
"%s is established! Unlike Mo who was never established anywhere.",
|
|
"%s has reached station! Mo's idea of on station was 'I think I'm close?'",
|
|
"%s is operational! Mo once declared on station while still on the ground.",
|
|
"%s is ready for service! Mo would be requesting a tanker. The irony.",
|
|
"%s has arrived! Mo's version of arriving was 'eventually, maybe.'",
|
|
"%s is on station! Mo would still be trying to program the waypoint.",
|
|
"%s is established and pumping! Mo's station-keeping was 'fucking nonexistent.'",
|
|
"%s has reached track! Mo once orbited the wrong mountain for an hour.",
|
|
"%s is operational now! Mo would've hit bingo looking for the station.",
|
|
"%s is on station ready! Mo's readiness was 'perpetually unprepared.'",
|
|
"%s has arrived at pattern! Mo thought the pattern was optional.",
|
|
"%s is on track! Mo would be on the wrong track. Or off all tracks.",
|
|
"%s is established! Mo's establishment was 'loosely interpreted.'",
|
|
"%s has reached station! Mo once mistook a cloud for his station.",
|
|
"%s is operational! Mo would be squawking 7700 lost and confused.",
|
|
"%s is on station pumping gas! Mo never made it past the departure airport.",
|
|
"%s has arrived! Mo's arrival time was 'never.'",
|
|
"%s is ready for refueling ops! Mo would still be reading the mission brief.",
|
|
"%s is on station! Mo thought on station meant 'near enough.'",
|
|
"%s is established! Mo's idea of established was 'I give up, I'm here now.'",
|
|
},
|
|
|
|
-- Already Active Warning
|
|
ALREADY_ACTIVE = {
|
|
"%s is already airborne!",
|
|
"%s is currently active.",
|
|
"%s is already on station.",
|
|
"%s is already flying. Check status for details.",
|
|
"%s is already up - can't spawn another.",
|
|
"%s is currently operating.",
|
|
"Cannot spawn - %s already active.",
|
|
"%s is already out there!",
|
|
"%s already flying. One at a time, please.",
|
|
"%s is already working the pattern.",
|
|
"%s is already up there, genius.",
|
|
"Dude, %s is ALREADY flying. Pay attention.",
|
|
"%s is currently active. Are you even looking?",
|
|
"Hey Einstein, %s is already airborne!",
|
|
"%s is up there right now. Use your eyes.",
|
|
"What part of '%s is active' don't you understand?",
|
|
"%s is already flying. Did Mo program this button?",
|
|
"Seriously? %s is already up. Check your radar.",
|
|
"%s is currently operational. Nice try though.",
|
|
"Negative. %s is already in the air.",
|
|
"%s is already active. Mo would have known that.",
|
|
"Can't spawn two, buttercup. %s is already flying.",
|
|
"%s is already out there doing tanker things.",
|
|
"Nice try. %s is already airborne, hotshot.",
|
|
"%s is currently flying. One's enough.",
|
|
"Hold your horses! %s is already active.",
|
|
"%s is already up. We're not running a bus service here.",
|
|
"Bruh. %s is already flying.",
|
|
"%s is currently active. Maybe learn to read?",
|
|
"Negative ghostrider. %s is already up.",
|
|
"%s is already airborne. Unlike your awareness.",
|
|
"Um, %s is ALREADY flying. Hello?",
|
|
"%s is currently on station. Wake up.",
|
|
"You can't spawn %s twice. Physics doesn't work that way.",
|
|
"%s is already active. Not sure what you expected.",
|
|
"Denied! %s is already in the pattern.",
|
|
"%s is currently flying around. Look outside.",
|
|
"News flash: %s is already airborne!",
|
|
"%s is already up there. Mo makes better decisions than this.",
|
|
"Request denied. %s is already active, chief.",
|
|
"%s is currently operational. Check your instruments.",
|
|
"Already got one! %s is flying right now.",
|
|
"%s is already airborne. Reading is fundamental.",
|
|
"Uh, no. %s is currently active.",
|
|
"%s is already out there. Situational awareness: zero.",
|
|
"Can't spawn %s again. Not a video game, buddy.",
|
|
"%s is currently flying. We only get one.",
|
|
"That's a negative. %s is already up.",
|
|
"%s is already on station. Did you even check?",
|
|
"Seriously? %s has been flying for 20 minutes.",
|
|
"%s is already active. This isn't rocket science.",
|
|
"Request rejected. %s is currently airborne.",
|
|
"%s is already up there pumping gas. Pay attention!",
|
|
"Nope. %s is already flying. Check the status board.",
|
|
"%s is currently active. Even Mo knew this.",
|
|
"Cannot comply. %s is already operational.",
|
|
"%s is already airborne. Try the status menu next time.",
|
|
"That's a no-go. %s is currently flying.",
|
|
"%s is already up. Did you think we had two?",
|
|
"Denied. %s is already on station doing its thing.",
|
|
"%s is currently active. Surprised you didn't notice.",
|
|
"Can't do it. %s is already flying around up there.",
|
|
"%s is already operational. One tanker at a time, pal.",
|
|
"Negative. %s has been active for a while now.",
|
|
"%s is already up there. Spawn button isn't a toy.",
|
|
"Request denied. %s is currently on station.",
|
|
"%s is already flying. Not cloning aircraft today.",
|
|
"Can't spawn another. %s is already airborne.",
|
|
"%s is currently active. Stop button mashing.",
|
|
"That's not happening. %s is already up.",
|
|
"%s is already operational. One's all you get.",
|
|
"No can do. %s is already in the pattern.",
|
|
"%s is currently flying. Check before clicking, maybe?",
|
|
"Request rejected. %s is already on duty.",
|
|
"%s is already airborne. Unlike your attention span.",
|
|
"Nope! %s is currently active and doing fine.",
|
|
"%s is already up there. Stop spamming the spawn button.",
|
|
"Cannot spawn duplicate. %s is already flying.",
|
|
"%s is currently operational. Mo's spawn would work better.",
|
|
"Denied! %s is already on station, genius.",
|
|
"%s is already flying. Check your tanker status!",
|
|
"That's a negative. %s is currently active.",
|
|
"%s is already airborne. One tanker per customer.",
|
|
"Can't do that. %s is already up and working.",
|
|
"%s is currently on station. Read the room.",
|
|
"Request denied. %s is already operational, chief.",
|
|
"%s is already active. Try paying attention.",
|
|
"No dice. %s is already flying the pattern.",
|
|
"%s is currently airborne. Spawn limit: 1.",
|
|
"Negative. %s is already up there doing tanker stuff.",
|
|
"%s is already active. Maybe check the status screen?",
|
|
"Can't spawn %s again. We're not made of tankers here.",
|
|
"%s is currently flying. One at a time, hotshot.",
|
|
"Request rejected. %s is already on station.",
|
|
"%s is already operational. Even Mo knows you only get one.",
|
|
"That's not possible. %s is currently airborne.",
|
|
"%s is already up there. Better situational awareness needed.",
|
|
"Denied. %s is currently active and wondering why you asked.",
|
|
"%s is already flying. The spawn button isn't for spam.",
|
|
"Cannot comply. %s is already operational, Einstein.",
|
|
},
|
|
|
|
-- Spawn Failure
|
|
SPAWN_FAILURE = {
|
|
"Failed to spawn %s!",
|
|
"Unable to launch %s. Try again.",
|
|
"%s spawn aborted!",
|
|
"Cannot spawn %s at this time.",
|
|
"%s failed to launch!",
|
|
"Error spawning %s. Contact support.",
|
|
"%s launch unsuccessful.",
|
|
"Unable to activate %s. Retry required.",
|
|
"%s spawn failed. Check logs.",
|
|
"Launch failure for %s!",
|
|
"%s spawn went sideways. Oops.",
|
|
"Well that didn't work. %s failed to spawn.",
|
|
"%s couldn't get off the ground. Awkward.",
|
|
"Houston, we have a problem. %s didn't spawn.",
|
|
"%s spawn failed harder than Mo's last landing.",
|
|
"Oof. %s spawn went to hell.",
|
|
"%s launch aborted. This is embarrassing.",
|
|
"Yeah, %s didn't spawn. Our bad.",
|
|
"Spawn failed for %s. Not our finest moment.",
|
|
"%s couldn't launch. Try again, genius.",
|
|
"That's a big negative on %s spawn.",
|
|
"%s failed to spawn. Did Mo write this code?",
|
|
"Error: %s spawn went boom. The bad kind.",
|
|
"%s launch unsuccessful. Better luck next time.",
|
|
"Spawn failed. %s is still in the hangar.",
|
|
"%s didn't want to fly today apparently.",
|
|
"Well crap. %s spawn totally failed.",
|
|
"%s launch aborted. Something broke.",
|
|
"That didn't work. %s spawn failed miserably.",
|
|
"%s couldn't spawn. Technical difficulties.",
|
|
"Negative spawn for %s. Try again maybe?",
|
|
"%s spawn went tits up. Sorry.",
|
|
"Launch failure! %s is grounded.",
|
|
"%s spawn crashed and burned. Not literally.",
|
|
"Unable to spawn %s. Computer says no.",
|
|
"%s launch failed. Mo could have done better.",
|
|
"Spawn error for %s. This is awkward.",
|
|
"%s didn't spawn. The universe said no.",
|
|
"Failed to launch %s. Not our day.",
|
|
"%s spawn aborted. Probably for the best.",
|
|
"Yeah... %s spawn didn't happen.",
|
|
"%s failed to spawn. Check your setup.",
|
|
"Spawn unsuccessful for %s. Womp womp.",
|
|
"%s launch went south. Way south.",
|
|
"That's a no-go. %s failed to spawn.",
|
|
"%s spawn error. Better call tech support.",
|
|
"Launch failure! %s stayed on the ground.",
|
|
"%s couldn't spawn. Even we're confused.",
|
|
"Spawn failed for %s. Mo's laughing right now.",
|
|
"%s launch aborted. Something went wrong.",
|
|
"Unable to activate %s. Try turning it off and on again.",
|
|
"%s spawn went nowhere fast.",
|
|
"Failed spawn alert: %s is still parked.",
|
|
"%s launch unsuccessful. This is fine. Everything's fine.",
|
|
"Spawn error for %s. Not ideal.",
|
|
"%s couldn't get airborne. Rough.",
|
|
"Launch aborted. %s is taking a day off.",
|
|
"%s spawn failed spectacularly.",
|
|
"Cannot spawn %s. System said 'nah.'",
|
|
"%s launch went sideways. Try again.",
|
|
"Spawn failure! %s is grounded indefinitely.",
|
|
"%s didn't spawn. Murphy's Law in effect.",
|
|
"Failed to launch %s. Mo's spawn worked better.",
|
|
"%s spawn unsuccessful. Check the logs.",
|
|
"Error spawning %s. This shouldn't happen.",
|
|
"%s launch aborted. Technical difficulties ahead.",
|
|
"Spawn failed. %s is staying home today.",
|
|
"%s couldn't spawn. Better luck next time, champ.",
|
|
"Launch failure for %s. Not sure why.",
|
|
"%s spawn went wrong. Very wrong.",
|
|
"Unable to spawn %s. Try again later.",
|
|
"%s launch failed. Mo would be disappointed.",
|
|
"Spawn error: %s didn't make it.",
|
|
"%s failed to spawn. Computer threw a tantrum.",
|
|
"Launch aborted for %s. Sorry about that.",
|
|
"%s spawn unsuccessful. Try again maybe?",
|
|
"Cannot activate %s. Spawn failed.",
|
|
"%s launch went nowhere. Like Mo's career.",
|
|
"Spawn failure! %s is MIA.",
|
|
"%s couldn't spawn. System error.",
|
|
"Failed to launch %s. This is awkward.",
|
|
"%s spawn aborted. Not today, apparently.",
|
|
"Launch error for %s. Check your setup.",
|
|
"%s didn't spawn. Computer says no way.",
|
|
"Spawn unsuccessful. %s is grounded.",
|
|
"%s launch failed. Mo's code was better.",
|
|
"Cannot spawn %s. Technical issues.",
|
|
"%s failed to activate. Try again.",
|
|
"Launch aborted. %s spawn went south.",
|
|
"%s spawn error. This isn't good.",
|
|
"Failed to spawn %s. Maybe next time.",
|
|
"%s launch unsuccessful. Something broke.",
|
|
"Spawn failure for %s. Not our best work.",
|
|
"%s couldn't get off the ground. Awkward moment.",
|
|
"Launch error! %s is still parked.",
|
|
"%s spawn went wrong. Very, very wrong.",
|
|
"Unable to spawn %s. System malfunction.",
|
|
"%s launch failed harder than expected.",
|
|
"Spawn aborted. %s is taking a sick day.",
|
|
},
|
|
|
|
-- Custom Route Accepted
|
|
ROUTE_ACCEPTED = {
|
|
"%s accepting custom route with %d waypoints.%s",
|
|
"%s has your route. %d waypoints loaded.%s",
|
|
"%s acknowledges custom flight plan. %d waypoints.%s",
|
|
"%s route confirmed. %d waypoints programmed.%s",
|
|
"%s copy your route. %d waypoints accepted.%s",
|
|
"%s roger. %d waypoint route loaded.%s",
|
|
"%s has the route. %d points confirmed.%s",
|
|
"%s flight plan accepted. %d waypoints.%s",
|
|
"%s confirms route. %d waypoints in the box.%s",
|
|
"%s routing confirmed with %d waypoints.%s",
|
|
"%s has your custom route. %d waypoints loaded.%s",
|
|
"%s accepts your flight plan. %d points confirmed.%s",
|
|
"%s copies custom route with %d waypoints.%s",
|
|
"%s acknowledges %d waypoint route.%s",
|
|
"%s route programmed. %d waypoints locked in.%s",
|
|
"%s flight plan confirmed with %d points.%s",
|
|
"%s roger your route. %d waypoints loaded.%s",
|
|
"%s accepts %d waypoint custom plan.%s",
|
|
"%s has your %d waypoint route locked in.%s",
|
|
"%s confirms %d waypoint flight plan.%s",
|
|
"%s copy that. %d waypoint route programmed.%s",
|
|
"%s routing accepted. %d points confirmed.%s",
|
|
"%s has the route. %d waypoints ready.%s",
|
|
"%s acknowledges %d point route.%s",
|
|
"%s flight plan loaded with %d waypoints.%s",
|
|
"%s custom route confirmed. %d points.%s",
|
|
"%s accepts your %d waypoint plan.%s",
|
|
"%s roger. %d waypoints programmed.%s",
|
|
"%s has your %d waypoint custom route.%s",
|
|
"%s routing confirmed with %d points.%s",
|
|
"%s copies %d waypoint route. Unlike Mo's attempt.%s",
|
|
"%s accepts your custom %d waypoint plan.%s",
|
|
"%s has loaded %d waypoint route.%s",
|
|
"%s confirms %d waypoint routing.%s",
|
|
"%s flight plan locked in. %d waypoints.%s",
|
|
"%s roger your %d waypoint route.%s",
|
|
"%s accepts custom route with %d points.%s",
|
|
"%s has programmed %d waypoint plan.%s",
|
|
"%s acknowledges %d waypoint custom route.%s",
|
|
"%s routing confirmed. %d waypoints ready.%s",
|
|
"%s copies %d waypoint flight plan.%s",
|
|
"%s accepts your %d point custom route.%s",
|
|
"%s has %d waypoint route confirmed.%s",
|
|
"%s roger custom plan with %d waypoints.%s",
|
|
"%s routing accepted. %d points programmed.%s",
|
|
"%s flight plan confirmed. %d waypoints loaded.%s",
|
|
"%s has your custom %d waypoint routing.%s",
|
|
"%s accepts %d waypoint plan.%s",
|
|
"%s confirms custom route. %d waypoints.%s",
|
|
"%s roger that. %d waypoint route accepted.%s",
|
|
"%s has %d waypoint custom plan loaded.%s",
|
|
"%s acknowledges %d point custom route.%s",
|
|
"%s routing programmed. %d waypoints confirmed.%s",
|
|
"%s flight plan accepted with %d points.%s",
|
|
"%s copies your %d waypoint custom route.%s",
|
|
"%s has %d waypoint route ready.%s",
|
|
"%s accepts custom plan. %d waypoints.%s",
|
|
"%s confirms %d point flight plan.%s",
|
|
"%s roger custom %d waypoint route.%s",
|
|
"%s routing locked in. %d waypoints.%s",
|
|
"%s has %d waypoint plan confirmed.%s",
|
|
"%s flight plan loaded. %d waypoints accepted.%s",
|
|
"%s acknowledges custom %d waypoint route.%s",
|
|
"%s accepts %d waypoint routing.%s",
|
|
"%s copies custom %d waypoint plan.%s",
|
|
"%s has %d waypoint route programmed.%s",
|
|
"%s confirms your %d waypoint custom route.%s",
|
|
"%s roger. %d waypoint custom plan loaded.%s",
|
|
"%s routing accepted with %d points.%s",
|
|
"%s flight plan programmed. %d waypoints.%s",
|
|
"%s has custom route with %d waypoints.%s",
|
|
"%s accepts %d waypoint custom plan.%s",
|
|
"%s acknowledges %d waypoint routing.%s",
|
|
"%s copies %d waypoint custom route.%s",
|
|
"%s has %d waypoint flight plan confirmed.%s",
|
|
"%s roger custom route. %d waypoints.%s",
|
|
"%s routing confirmed with %d waypoints.%s",
|
|
"%s flight plan accepted. %d points loaded.%s",
|
|
"%s has your %d waypoint custom plan.%s",
|
|
"%s accepts custom %d waypoint route.%s",
|
|
"%s confirms %d waypoint custom plan.%s",
|
|
"%s acknowledges %d waypoint flight plan.%s",
|
|
"%s copies %d waypoint route confirmed.%s",
|
|
"%s has custom %d waypoint routing ready.%s",
|
|
"%s roger. %d waypoints accepted and locked.%s",
|
|
"%s routing programmed with %d waypoints.%s",
|
|
"%s flight plan confirmed with %d points.%s",
|
|
"%s has %d waypoint custom route loaded.%s",
|
|
"%s accepts your custom %d waypoint routing.%s",
|
|
"%s confirms %d waypoint plan confirmed.%s",
|
|
"%s acknowledges custom route with %d points.%s",
|
|
"%s copies %d waypoint custom flight plan.%s",
|
|
"%s has %d waypoint route locked and loaded.%s",
|
|
"%s roger that. %d waypoint custom route ready.%s",
|
|
"%s routing accepted. %d waypoints programmed.%s",
|
|
"%s flight plan loaded with %d waypoints.%s",
|
|
},
|
|
|
|
-- Emergency Spawn
|
|
EMERGENCY_SPAWN = {
|
|
"EMERGENCY: %s launching immediately!",
|
|
"PRIORITY LAUNCH: %s is scrambling now!",
|
|
"EMERGENCY TANKER: %s departing expedited!",
|
|
"URGENT: %s is launching on priority status!",
|
|
"EMERGENCY RESPONSE: %s airborne ASAP!",
|
|
"PRIORITY: %s scrambling for emergency fuel!",
|
|
"EMERGENCY: %s launching hot!",
|
|
"URGENT LAUNCH: %s is wheels up now!",
|
|
"EMERGENCY TANKER: %s responding immediately!",
|
|
"PRIORITY STATUS: %s emergency launch in progress!",
|
|
"EMERGENCY! %s wheels up NOW!",
|
|
"SCRAMBLE SCRAMBLE: %s launching immediately!",
|
|
"PRIORITY LAUNCH: %s getting airborne right now!",
|
|
"EMERGENCY TANKER: %s departing hot and fast!",
|
|
"URGENT: %s scrambling for emergency refuel!",
|
|
"PRIORITY: %s launching on expedited status!",
|
|
"EMERGENCY RESPONSE: %s airborne immediately!",
|
|
"URGENT LAUNCH: %s departing NOW!",
|
|
"EMERGENCY: %s getting up there ASAP!",
|
|
"PRIORITY STATUS: %s scrambling right now!",
|
|
"EMERGENCY TANKER: %s wheels up immediately!",
|
|
"URGENT: %s launching on priority!",
|
|
"SCRAMBLE: %s departing expedited!",
|
|
"EMERGENCY: %s getting airborne fast!",
|
|
"PRIORITY LAUNCH: %s launching NOW!",
|
|
"URGENT TANKER: %s scrambling immediately!",
|
|
"EMERGENCY: %s departing hot!",
|
|
"PRIORITY: %s wheels up ASAP!",
|
|
"URGENT LAUNCH: %s airborne right now!",
|
|
"EMERGENCY TANKER: %s launching immediately!",
|
|
"SCRAMBLE SCRAMBLE: %s getting up there now!",
|
|
"PRIORITY: %s launching on emergency status!",
|
|
"URGENT: %s departing immediately!",
|
|
"EMERGENCY: %s scrambling for urgent refuel!",
|
|
"PRIORITY LAUNCH: %s wheels up hot!",
|
|
"URGENT TANKER: %s airborne ASAP!",
|
|
"EMERGENCY: %s launching right now!",
|
|
"PRIORITY: %s scrambling expedited!",
|
|
"URGENT LAUNCH: %s departing NOW NOW NOW!",
|
|
"EMERGENCY TANKER: %s getting airborne fast!",
|
|
"PRIORITY STATUS: %s launching immediately!",
|
|
"URGENT: %s wheels up on priority!",
|
|
"EMERGENCY: %s scrambling now!",
|
|
"PRIORITY LAUNCH: %s departing fast!",
|
|
"URGENT TANKER: %s launching ASAP!",
|
|
"EMERGENCY: %s airborne immediately!",
|
|
"PRIORITY: %s scrambling hot!",
|
|
"URGENT LAUNCH: %s wheels up right now!",
|
|
"EMERGENCY TANKER: %s departing expedited!",
|
|
"PRIORITY: %s launching on urgent status!",
|
|
"URGENT: %s getting airborne now!",
|
|
"EMERGENCY SCRAMBLE: %s departing immediately!",
|
|
"PRIORITY TANKER: %s wheels up fast!",
|
|
"URGENT: %s launching right now!",
|
|
"EMERGENCY: %s airborne ASAP!",
|
|
"PRIORITY LAUNCH: %s scrambling now!",
|
|
"URGENT TANKER: %s departing hot!",
|
|
"EMERGENCY: %s wheels up immediately!",
|
|
"PRIORITY: %s getting airborne fast!",
|
|
"URGENT LAUNCH: %s scrambling ASAP!",
|
|
"EMERGENCY TANKER: %s launching on priority!",
|
|
"PRIORITY: %s departing right now!",
|
|
"URGENT: %s airborne expedited!",
|
|
"EMERGENCY: %s scrambling immediately!",
|
|
"PRIORITY LAUNCH: %s wheels up NOW!",
|
|
"URGENT TANKER: %s launching fast!",
|
|
"EMERGENCY: %s departing ASAP!",
|
|
"PRIORITY: %s airborne right now!",
|
|
"URGENT LAUNCH: %s scrambling hot!",
|
|
"EMERGENCY TANKER: %s wheels up expedited!",
|
|
"PRIORITY: %s launching immediately!",
|
|
"URGENT: %s getting airborne ASAP!",
|
|
"EMERGENCY: %s scrambling fast!",
|
|
"PRIORITY LAUNCH: %s departing NOW!",
|
|
"URGENT TANKER: %s wheels up right now!",
|
|
"EMERGENCY: %s airborne hot!",
|
|
"PRIORITY: %s scrambling ASAP!",
|
|
"URGENT LAUNCH: %s launching immediately!",
|
|
"EMERGENCY TANKER: %s departing fast!",
|
|
"PRIORITY: %s wheels up expedited!",
|
|
"URGENT: %s airborne NOW!",
|
|
"EMERGENCY: %s launching hot and fast!",
|
|
"PRIORITY LAUNCH: %s scrambling expedited!",
|
|
"URGENT TANKER: %s departing immediately!",
|
|
"EMERGENCY: %s wheels up ASAP!",
|
|
"PRIORITY: %s getting airborne now!",
|
|
"URGENT LAUNCH: %s airborne fast!",
|
|
"EMERGENCY TANKER: %s scrambling NOW!",
|
|
"PRIORITY: %s launching expedited!",
|
|
"URGENT: %s departing hot!",
|
|
"EMERGENCY: %s airborne immediately unlike Mo!",
|
|
"PRIORITY LAUNCH: %s wheels up faster than Mo!",
|
|
"URGENT TANKER: %s scrambling (Mo couldn't do this)!",
|
|
"EMERGENCY: %s launching while Mo watches!",
|
|
"PRIORITY: %s departing - Mo take notes!",
|
|
"URGENT LAUNCH: %s airborne (unlike Mo's attempts)!",
|
|
"EMERGENCY TANKER: %s scrambling successfully!",
|
|
"PRIORITY: %s wheels up for real!",
|
|
"URGENT: %s launching like professionals do!",
|
|
},
|
|
|
|
-- Low Fuel Warning
|
|
LOW_FUEL = {
|
|
"%s reports fuel at %d%%. Recommend expedite refueling.",
|
|
"%s low on fuel - %d%% remaining. RTB soon.",
|
|
"%s fuel state: %d%%. Time is limited.",
|
|
"%s down to %d%% fuel. Get your gas quick.",
|
|
"%s running low - %d%% remaining.",
|
|
"%s fuel advisory: %d%% left. Don't delay.",
|
|
"%s reports %d%% fuel state. Limited time remaining.",
|
|
"%s low fuel warning at %d%%. RTB imminent.",
|
|
"%s fuel: %d%%. Better hurry up.",
|
|
"%s getting thirsty at %d%% fuel remaining.",
|
|
"%s fuel down to %d%%. Time's ticking.",
|
|
"%s running on fumes at %d%%. Get moving.",
|
|
"%s reports %d%% fuel. Clock is running.",
|
|
"%s fuel state critical at %d%%.",
|
|
"%s getting low at %d%%. Don't dawdle.",
|
|
"%s fuel: %d%%. Window is closing.",
|
|
"%s reports %d%% remaining. Hurry it up.",
|
|
"%s fuel advisory: %d%%. Time's short.",
|
|
"%s down to %d%%. Better move fast.",
|
|
"%s fuel at %d%%. RTB soon or refuel now.",
|
|
"%s running thin at %d%%. Expedite.",
|
|
"%s reports %d%% fuel. Not much time left.",
|
|
"%s fuel state %d%%. Don't mess around.",
|
|
"%s getting low - %d%% and dropping.",
|
|
"%s fuel: %d%%. Better get some quick.",
|
|
"%s reports %d%%. Running out of time.",
|
|
"%s fuel down to %d%%. Tick tock.",
|
|
"%s low on gas at %d%%. Move it.",
|
|
"%s reports %d%% fuel state. Limited window.",
|
|
"%s fuel: %d%%. Don't be slow about it.",
|
|
"%s getting thirsty - %d%% remaining.",
|
|
"%s reports %d%%. Better hurry your ass up.",
|
|
"%s fuel at %d%%. Time ain't on your side.",
|
|
"%s running low - %d%%. Get in here.",
|
|
"%s fuel state: %d%%. Mo could refuel faster.",
|
|
"%s reports %d%%. Don't be a hero, get fuel.",
|
|
"%s fuel down to %d%%. Unlike Mo we're warning you.",
|
|
"%s getting low at %d%%. Stop screwing around.",
|
|
"%s reports %d%% fuel. This isn't a drill.",
|
|
"%s fuel: %d%%. Better not screw this up.",
|
|
"%s running thin - %d%% remaining.",
|
|
"%s reports %d%%. Time to get your ass over here.",
|
|
"%s fuel state %d%%. Seriously, hurry up.",
|
|
"%s getting thirsty at %d%%. Don't be stupid.",
|
|
"%s fuel: %d%%. We're leaving soon.",
|
|
"%s reports %d%%. Better expedite refueling.",
|
|
"%s fuel down to %d%%. Window closing fast.",
|
|
"%s low on juice - %d%% remaining.",
|
|
"%s reports %d%% fuel. Get moving or RTB.",
|
|
"%s fuel state: %d%%. Don't drag ass.",
|
|
"%s getting low at %d%%. Time's running out.",
|
|
"%s reports %d%%. Stop dicking around.",
|
|
"%s fuel: %d%%. Get in the basket.",
|
|
"%s running thin at %d%%. Move faster.",
|
|
"%s reports %d%% remaining. Chop chop.",
|
|
"%s fuel down to %d%%. Unlike Mo's planning.",
|
|
"%s getting thirsty - %d%%. Don't be slow.",
|
|
"%s reports %d%% fuel state. Hurry.",
|
|
"%s fuel: %d%%. Better not flame out.",
|
|
"%s low on gas at %d%%. Get over here.",
|
|
"%s reports %d%%. Time to move it.",
|
|
"%s fuel state %d%%. We don't have all day.",
|
|
"%s getting low - %d%% and dropping fast.",
|
|
"%s reports %d%%. Stop being a pussy.",
|
|
"%s fuel: %d%%. Refuel or die trying.",
|
|
"%s running thin - %d%%. Better hurry.",
|
|
"%s reports %d%% fuel. Move your ass.",
|
|
"%s fuel down to %d%%. Not kidding here.",
|
|
"%s getting thirsty at %d%%. Expedite.",
|
|
"%s reports %d%%. Don't be like Mo.",
|
|
"%s fuel state: %d%%. Get fuel or get bent.",
|
|
"%s low at %d%%. Time's wasting.",
|
|
"%s reports %d%% remaining. Hurry up.",
|
|
"%s fuel: %d%%. Stop fucking around.",
|
|
"%s running low - %d%%. Get here now.",
|
|
"%s reports %d%%. We're not waiting forever.",
|
|
"%s fuel down to %d%%. Better get moving.",
|
|
"%s getting low at %d%%. Tick tock motherfucker.",
|
|
"%s reports %d%% fuel state. Move it.",
|
|
"%s fuel: %d%%. Don't be a jackass.",
|
|
"%s running thin at %d%%. Expedite refuel.",
|
|
"%s reports %d%%. Time's running short.",
|
|
"%s fuel state %d%%. Get in the pattern.",
|
|
"%s getting thirsty - %d%%. Don't delay.",
|
|
"%s reports %d%%. Unlike Mo we're still here.",
|
|
"%s fuel: %d%%. Better not screw this up.",
|
|
"%s low on gas - %d%% remaining.",
|
|
"%s reports %d%% fuel. Window closing.",
|
|
"%s fuel down to %d%%. Get your shit together.",
|
|
"%s getting low at %d%%. Seriously move.",
|
|
"%s reports %d%%. Don't make us leave.",
|
|
"%s fuel state: %d%%. Better expedite.",
|
|
"%s running thin - %d%%. Time's up soon.",
|
|
"%s reports %d%% remaining. Get here.",
|
|
"%s fuel: %d%%. Stop dragging ass.",
|
|
"%s getting thirsty at %d%%. Hurry.",
|
|
"%s reports %d%%. Mo would have flamed out by now.",
|
|
},
|
|
|
|
-- Bingo Fuel (RTB)
|
|
BINGO_FUEL = {
|
|
"%s is BINGO fuel. Returning to base immediately!",
|
|
"%s has reached BINGO. RTB in progress!",
|
|
"%s calling BINGO fuel. Departing the pattern now!",
|
|
"%s is at BINGO state. Returning to base!",
|
|
"%s BINGO fuel - heading home now!",
|
|
"%s has hit BINGO. No more refueling available!",
|
|
"%s fuel critical - RTB initiated!",
|
|
"%s at BINGO state. Breaking off now!",
|
|
"%s calling BINGO. Pattern is clear!",
|
|
"%s BINGO fuel declared. Returning to base!",
|
|
"%s is BINGO. Getting the hell out!",
|
|
"%s calling BINGO fuel. We're done here!",
|
|
"%s has reached BINGO state. Leaving NOW!",
|
|
"%s BINGO declared. RTB in progress!",
|
|
"%s at BINGO fuel. Heading home!",
|
|
"%s calling BINGO. Pattern clear!",
|
|
"%s has hit BINGO. See ya!",
|
|
"%s BINGO fuel state. Departing!",
|
|
"%s is at BINGO. RTB immediately!",
|
|
"%s calling BINGO. We're out!",
|
|
"%s has reached BINGO. Breaking off!",
|
|
"%s BINGO fuel declared. Leaving!",
|
|
"%s at BINGO state. Going home!",
|
|
"%s calling BINGO. Adios!",
|
|
"%s has hit BINGO fuel. Departing now!",
|
|
"%s BINGO declared. RTB active!",
|
|
"%s is at BINGO. Bye bye!",
|
|
"%s calling BINGO fuel. Out of here!",
|
|
"%s has reached BINGO state. Later!",
|
|
"%s BINGO fuel. Heading back!",
|
|
"%s at BINGO. Returning immediately!",
|
|
"%s calling BINGO. Pattern's yours!",
|
|
"%s has hit BINGO. Going home!",
|
|
"%s BINGO declared. Leaving the AO!",
|
|
"%s is at BINGO fuel. RTB now!",
|
|
"%s calling BINGO. Peace out!",
|
|
"%s has reached BINGO. Departing!",
|
|
"%s BINGO fuel state. We're done!",
|
|
"%s at BINGO. Heading to base!",
|
|
"%s calling BINGO. Catch you later!",
|
|
"%s has hit BINGO fuel. RTB!",
|
|
"%s BINGO declared. Getting out!",
|
|
"%s is at BINGO state. Later gator!",
|
|
"%s calling BINGO. We out!",
|
|
"%s has reached BINGO. Returning!",
|
|
"%s BINGO fuel. Leaving now!",
|
|
"%s at BINGO. Going home finally!",
|
|
"%s calling BINGO. Done pumping gas!",
|
|
"%s has hit BINGO. RTB initiated!",
|
|
"%s BINGO declared. Out of here!",
|
|
"%s is at BINGO fuel. Bye!",
|
|
"%s calling BINGO. Pattern clear!",
|
|
"%s has reached BINGO state. Departing!",
|
|
"%s BINGO fuel. Heading back!",
|
|
"%s at BINGO. RTB in progress!",
|
|
"%s calling BINGO. See ya later!",
|
|
"%s has hit BINGO fuel. Leaving!",
|
|
"%s BINGO declared. Going home!",
|
|
"%s is at BINGO. Out!",
|
|
"%s calling BINGO fuel. We're outta here!",
|
|
"%s has reached BINGO. RTB now!",
|
|
"%s BINGO fuel state. Later!",
|
|
"%s at BINGO. Returning to base!",
|
|
"%s calling BINGO. Adios amigos!",
|
|
"%s has hit BINGO. Departing!",
|
|
"%s BINGO declared. Heading home!",
|
|
"%s is at BINGO fuel. Peace!",
|
|
"%s calling BINGO. We done!",
|
|
"%s has reached BINGO state. Leaving!",
|
|
"%s BINGO fuel. RTB active!",
|
|
"%s at BINGO. Going back!",
|
|
"%s calling BINGO. That's it folks!",
|
|
"%s has hit BINGO fuel. Out of here!",
|
|
"%s BINGO declared. Returning!",
|
|
"%s is at BINGO. Later suckers!",
|
|
"%s calling BINGO fuel. Bye!",
|
|
"%s has reached BINGO. Heading home!",
|
|
"%s BINGO fuel state. Departing!",
|
|
"%s at BINGO. RTB initiated!",
|
|
"%s calling BINGO. We're gone!",
|
|
"%s has hit BINGO. Leaving now!",
|
|
"%s BINGO declared. Getting out of dodge!",
|
|
"%s is at BINGO fuel. Later!",
|
|
"%s calling BINGO. Don't wait up!",
|
|
"%s has reached BINGO state. Out!",
|
|
"%s BINGO fuel. Going home!",
|
|
"%s at BINGO. Returning immediately!",
|
|
"%s calling BINGO. Unlike Mo we planned this!",
|
|
"%s has hit BINGO fuel. Peace out!",
|
|
"%s BINGO declared. Heading back!",
|
|
"%s is at BINGO. Bye felicia!",
|
|
"%s calling BINGO fuel. That's a wrap!",
|
|
"%s has reached BINGO. We're out!",
|
|
"%s BINGO fuel state. Later gator!",
|
|
"%s at BINGO. RTB right now!",
|
|
"%s calling BINGO. Smell ya later!",
|
|
"%s has hit BINGO. Departing!",
|
|
"%s BINGO declared. Mo would've flamed out!",
|
|
"%s is at BINGO fuel. Catch you on the flip side!",
|
|
},
|
|
|
|
-- Tanker Destroyed
|
|
DESTROYED = {
|
|
"%s has been destroyed!",
|
|
"%s is down! Aircraft lost!",
|
|
"%s has been shot down!",
|
|
"%s destroyed in combat!",
|
|
"%s is gone - aircraft destroyed!",
|
|
"%s has been lost!",
|
|
"We've lost %s!",
|
|
"%s destroyed! No survivors!",
|
|
"%s is down and out!",
|
|
"%s has been eliminated!",
|
|
"%s has been blown to hell!",
|
|
"%s is toast! Aircraft destroyed!",
|
|
"%s went down in flames!",
|
|
"%s has been obliterated!",
|
|
"%s is scrap metal now!",
|
|
"%s got smoked!",
|
|
"RIP %s. Aircraft destroyed!",
|
|
"%s has been vaporized!",
|
|
"%s is no more!",
|
|
"%s went down hard!",
|
|
"%s has been wasted!",
|
|
"%s is KIA! Aircraft lost!",
|
|
"%s got shot the fuck down!",
|
|
"%s has been annihilated!",
|
|
"%s is sleeping with the fishes!",
|
|
"%s went boom!",
|
|
"%s has been terminated!",
|
|
"%s is dead! No survivors!",
|
|
"%s got fucked up!",
|
|
"%s has ceased to exist!",
|
|
"%s went down like Mo's career!",
|
|
"%s is destroyed! Total loss!",
|
|
"%s got hammered!",
|
|
"%s has been neutralized!",
|
|
"%s is history!",
|
|
"%s went down in a ball of fire!",
|
|
"%s has been taken out!",
|
|
"%s is gone forever!",
|
|
"%s got massacred!",
|
|
"%s has been deleted!",
|
|
"%s is pushing up daisies!",
|
|
"%s went down screaming!",
|
|
"%s has been liquidated!",
|
|
"%s is scattered across the landscape!",
|
|
"%s got wrecked!",
|
|
"%s has been erased!",
|
|
"%s is no longer operational!",
|
|
"%s went down like a brick!",
|
|
"%s has been dispatched!",
|
|
"%s is gone to the great hangar in the sky!",
|
|
"%s got absolutely demolished!",
|
|
"%s has been removed from existence!",
|
|
"%s is dead as fuck!",
|
|
"%s went down faster than Mo!",
|
|
"%s has been exterminated!",
|
|
"%s is now a smoking crater!",
|
|
"%s got absolutely destroyed!",
|
|
"%s has been converted to debris!",
|
|
"%s is no longer with us!",
|
|
"%s went down in a spectacular fashion!",
|
|
"%s has been sent to hell!",
|
|
"%s is totally fucked!",
|
|
"%s got blown out of the sky!",
|
|
"%s has been utterly destroyed!",
|
|
"%s is burning on the ground!",
|
|
"%s went down like a sack of shit!",
|
|
"%s has been wiped out!",
|
|
"%s is permanently grounded!",
|
|
"%s got turned into confetti!",
|
|
"%s has been removed from service!",
|
|
"%s is now spare parts!",
|
|
"%s went down hard and fast!",
|
|
"%s has been completely destroyed!",
|
|
"%s is toast and then some!",
|
|
"%s got absolutely annihilated!",
|
|
"%s has been blown to smithereens!",
|
|
"%s is no longer flying!",
|
|
"%s went down like the Hindenburg!",
|
|
"%s has been totally wrecked!",
|
|
"%s is deader than dead!",
|
|
"%s got straight up murdered!",
|
|
"%s has been completely obliterated!",
|
|
"%s is scattered across three counties!",
|
|
"%s went down in flames like Mo's reputation!",
|
|
"%s has been catastrophically destroyed!",
|
|
"%s is now a fireball!",
|
|
"%s got absolutely smoked!",
|
|
"%s has been reduced to atoms!",
|
|
"%s is gone gone gone!",
|
|
"%s went down and ain't coming back!",
|
|
"%s has been utterly annihilated!",
|
|
"%s is now a lawn dart!",
|
|
"%s got completely fucked!",
|
|
"%s has been sent to the shadow realm!",
|
|
"%s is now in aircraft heaven!",
|
|
"%s went down faster than your hopes and dreams!",
|
|
"%s has been totally destroyed!",
|
|
"%s is no longer a thing!",
|
|
},
|
|
|
|
-- Hostile Fire
|
|
TAKING_FIRE = {
|
|
"%s is taking fire!",
|
|
"%s under attack!",
|
|
"%s receiving hostile fire!",
|
|
"%s taking hits!",
|
|
"%s is being engaged!",
|
|
"%s under hostile fire!",
|
|
"Hostile fire on %s!",
|
|
"%s taking enemy fire!",
|
|
"%s is under attack!",
|
|
"%s being fired upon!",
|
|
"%s is getting shot at!",
|
|
"%s under hostile fire!",
|
|
"%s taking incoming!",
|
|
"%s is being lit up!",
|
|
"%s receiving enemy fire!",
|
|
"%s getting hammered!",
|
|
"%s under attack right now!",
|
|
"%s taking fire from hostiles!",
|
|
"%s is being engaged by enemy!",
|
|
"%s getting shot to shit!",
|
|
"%s under hostile attack!",
|
|
"%s taking heavy fire!",
|
|
"%s is being targeted!",
|
|
"%s receiving hostile rounds!",
|
|
"%s getting fucked up!",
|
|
"%s under enemy fire!",
|
|
"%s taking hits from hostiles!",
|
|
"%s is being shot at!",
|
|
"%s receiving incoming fire!",
|
|
"%s getting attacked!",
|
|
"%s under hostile engagement!",
|
|
"%s taking enemy rounds!",
|
|
"%s is being hit!",
|
|
"%s receiving fire!",
|
|
"%s getting lit up!",
|
|
"%s under attack from enemy!",
|
|
"%s taking hostile fire!",
|
|
"%s is being engaged!",
|
|
"%s receiving enemy rounds!",
|
|
"%s getting shot!",
|
|
"%s under fire right now!",
|
|
"%s taking incoming rounds!",
|
|
"%s is being attacked!",
|
|
"%s receiving hostile fire!",
|
|
"%s getting hammered by hostiles!",
|
|
"%s under enemy attack!",
|
|
"%s taking fire from below!",
|
|
"%s is being targeted by enemy!",
|
|
"%s receiving heavy fire!",
|
|
"%s getting shot at hard!",
|
|
"%s under hostile fire!",
|
|
"%s taking enemy fire now!",
|
|
"%s is being engaged by hostiles!",
|
|
"%s receiving incoming!",
|
|
"%s getting attacked by enemy!",
|
|
"%s under fire from hostiles!",
|
|
"%s taking hits!",
|
|
"%s is being shot up!",
|
|
"%s receiving hostile rounds!",
|
|
"%s getting fucked up by enemy!",
|
|
"%s under hostile engagement!",
|
|
"%s taking fire!",
|
|
"%s is being hammered!",
|
|
"%s receiving enemy fire!",
|
|
"%s getting shot at!",
|
|
"%s under enemy fire!",
|
|
"%s taking hostile rounds!",
|
|
"%s is being lit up!",
|
|
"%s receiving fire from hostiles!",
|
|
"%s getting attacked hard!",
|
|
"%s under hostile attack!",
|
|
"%s taking incoming fire!",
|
|
"%s is being engaged!",
|
|
"%s receiving hostile fire!",
|
|
"%s getting shot to hell!",
|
|
"%s under fire!",
|
|
"%s taking enemy rounds!",
|
|
"%s is being targeted!",
|
|
"%s receiving fire!",
|
|
"%s getting hammered!",
|
|
"%s under attack by hostiles!",
|
|
"%s taking fire from enemy!",
|
|
"%s is being shot at!",
|
|
"%s receiving incoming rounds!",
|
|
"%s getting attacked!",
|
|
"%s under hostile fire right now!",
|
|
"%s taking hits from enemy!",
|
|
"%s is being engaged by hostiles!",
|
|
"%s receiving hostile fire!",
|
|
"%s getting lit up by enemy!",
|
|
"%s under fire from below!",
|
|
"%s taking enemy fire!",
|
|
"%s is being attacked by hostiles!",
|
|
"%s receiving fire from enemy!",
|
|
"%s getting shot at hard!",
|
|
"%s under enemy attack!",
|
|
"%s taking hostile fire unlike Mo who'd be dead!",
|
|
"%s is being hammered by hostiles!",
|
|
"%s receiving enemy rounds!",
|
|
},
|
|
|
|
-- Invalid Waypoint Count (too few)
|
|
TOO_FEW_WAYPOINTS = {
|
|
"Custom route requires at least %d waypoints!\nPlace markers: %s1, %s2, etc.",
|
|
"Not enough waypoints! Need at least %d.\nUse markers: %s1, %s2, etc.",
|
|
"Insufficient waypoints - need %d minimum.\nCreate markers: %s1, %s2, etc.",
|
|
"Route rejected: need %d waypoints minimum.\nPlace %s1, %s2, etc.",
|
|
"At least %d waypoints required!\nDrop markers: %s1, %s2, etc.",
|
|
"Need more waypoints - minimum is %d.\nUse: %s1, %s2, etc.",
|
|
"Route incomplete. Need %d waypoints.\nCreate: %s1, %s2, etc.",
|
|
"Waypoint count too low - need %d.\nPlace: %s1, %s2, etc.",
|
|
"Minimum %d waypoints required!\nMark: %s1, %s2, etc.",
|
|
"Can't route with less than %d points.\nAdd markers: %s1, %s2, etc.",
|
|
},
|
|
|
|
-- Too Many Waypoints
|
|
TOO_MANY_WAYPOINTS = {
|
|
"Too many waypoints! Maximum is %d",
|
|
"Waypoint limit exceeded. Max: %d",
|
|
"Can't route with more than %d waypoints!",
|
|
"Route rejected - too many points. Max: %d",
|
|
"Waypoint overflow! Maximum is %d",
|
|
"Too complex - max %d waypoints allowed!",
|
|
"Exceeded waypoint limit of %d!",
|
|
"Route too long! Maximum: %d waypoints",
|
|
"Cannot accept more than %d waypoints!",
|
|
"Waypoint maximum is %d. Route rejected.",
|
|
},
|
|
|
|
-- No RTB Airbase Found
|
|
NO_RTB_AIRBASE = {
|
|
"No friendly airbase found for RTB!",
|
|
"Cannot locate RTB destination!",
|
|
"No suitable airbase available for recovery!",
|
|
"Unable to find friendly base for RTB!",
|
|
"No recovery airfield located!",
|
|
"RTB destination unavailable!",
|
|
"Cannot identify friendly airbase for return!",
|
|
"No airbase in range for RTB!",
|
|
"Recovery base not found!",
|
|
"Unable to locate RTB airfield!",
|
|
},
|
|
-- EMERGENCY SPAWN MESSAGES (100 total)
|
|
EMERGENCY_SPAWN = {
|
|
"EMERGENCY: %s launching immediately!",
|
|
"PRIORITY LAUNCH: %s is scrambling now!",
|
|
"EMERGENCY TANKER: %s departing expedited!",
|
|
"URGENT: %s is launching on priority status!",
|
|
"EMERGENCY RESPONSE: %s airborne ASAP!",
|
|
"PRIORITY: %s scrambling for emergency fuel!",
|
|
"EMERGENCY: %s launching hot!",
|
|
"URGENT LAUNCH: %s is wheels up now!",
|
|
"EMERGENCY TANKER: %s responding immediately!",
|
|
"PRIORITY STATUS: %s emergency launch in progress!",
|
|
"EMERGENCY! %s wheels up NOW!",
|
|
"SCRAMBLE SCRAMBLE: %s launching immediately!",
|
|
"PRIORITY LAUNCH: %s getting airborne right now!",
|
|
"EMERGENCY TANKER: %s departing hot and fast!",
|
|
"URGENT: %s scrambling for emergency refuel!",
|
|
"PRIORITY: %s launching on expedited status!",
|
|
"EMERGENCY RESPONSE: %s airborne immediately!",
|
|
"URGENT LAUNCH: %s departing NOW!",
|
|
"EMERGENCY: %s getting up there ASAP!",
|
|
"PRIORITY STATUS: %s scrambling right now!",
|
|
"EMERGENCY TANKER: %s wheels up immediately!",
|
|
"URGENT: %s launching on priority!",
|
|
"SCRAMBLE: %s departing expedited!",
|
|
"EMERGENCY: %s getting airborne fast!",
|
|
"PRIORITY LAUNCH: %s launching NOW!",
|
|
"URGENT TANKER: %s scrambling immediately!",
|
|
"EMERGENCY: %s departing hot!",
|
|
"PRIORITY: %s wheels up ASAP!",
|
|
"URGENT LAUNCH: %s airborne right now!",
|
|
"EMERGENCY TANKER: %s launching immediately!",
|
|
"SCRAMBLE SCRAMBLE: %s getting up there now!",
|
|
"PRIORITY: %s launching on emergency status!",
|
|
"URGENT: %s departing immediately!",
|
|
"EMERGENCY: %s scrambling for urgent refuel!",
|
|
"PRIORITY LAUNCH: %s wheels up hot!",
|
|
"URGENT TANKER: %s airborne ASAP!",
|
|
"EMERGENCY: %s launching right now!",
|
|
"PRIORITY: %s scrambling expedited!",
|
|
"URGENT LAUNCH: %s departing NOW NOW NOW!",
|
|
"EMERGENCY TANKER: %s getting airborne fast!",
|
|
"PRIORITY STATUS: %s launching immediately!",
|
|
"URGENT: %s wheels up on priority!",
|
|
"EMERGENCY: %s scrambling now!",
|
|
"PRIORITY LAUNCH: %s departing fast!",
|
|
"URGENT TANKER: %s launching ASAP!",
|
|
"EMERGENCY: %s airborne immediately!",
|
|
"PRIORITY: %s scrambling hot!",
|
|
"URGENT LAUNCH: %s wheels up right now!",
|
|
"EMERGENCY TANKER: %s departing expedited!",
|
|
"PRIORITY: %s launching on urgent status!",
|
|
"URGENT: %s getting airborne now!",
|
|
"EMERGENCY SCRAMBLE: %s departing immediately!",
|
|
"PRIORITY TANKER: %s wheels up fast!",
|
|
"URGENT: %s launching right now!",
|
|
"EMERGENCY: %s airborne ASAP!",
|
|
"PRIORITY LAUNCH: %s scrambling now!",
|
|
"URGENT TANKER: %s departing hot!",
|
|
"EMERGENCY: %s wheels up immediately!",
|
|
"PRIORITY: %s getting airborne fast!",
|
|
"URGENT LAUNCH: %s scrambling ASAP!",
|
|
"EMERGENCY TANKER: %s launching on priority!",
|
|
"PRIORITY: %s departing right now!",
|
|
"URGENT: %s airborne expedited!",
|
|
"EMERGENCY: %s scrambling immediately!",
|
|
"PRIORITY LAUNCH: %s wheels up NOW!",
|
|
"URGENT TANKER: %s launching fast!",
|
|
"EMERGENCY: %s departing ASAP!",
|
|
"PRIORITY: %s airborne right now!",
|
|
"URGENT LAUNCH: %s scrambling hot!",
|
|
"EMERGENCY TANKER: %s wheels up expedited!",
|
|
"PRIORITY: %s launching immediately!",
|
|
"URGENT: %s getting airborne ASAP!",
|
|
"EMERGENCY: %s scrambling fast!",
|
|
"PRIORITY LAUNCH: %s departing NOW!",
|
|
"URGENT TANKER: %s wheels up right now!",
|
|
"EMERGENCY: %s airborne hot!",
|
|
"PRIORITY: %s scrambling ASAP!",
|
|
"URGENT LAUNCH: %s launching immediately!",
|
|
"EMERGENCY TANKER: %s departing fast!",
|
|
"PRIORITY: %s wheels up expedited!",
|
|
"URGENT: %s airborne NOW!",
|
|
"EMERGENCY: %s launching hot and fast!",
|
|
"PRIORITY LAUNCH: %s scrambling expedited!",
|
|
"URGENT TANKER: %s departing immediately!",
|
|
"EMERGENCY: %s wheels up ASAP!",
|
|
"PRIORITY: %s getting airborne now!",
|
|
"URGENT LAUNCH: %s airborne fast!",
|
|
"EMERGENCY TANKER: %s scrambling NOW!",
|
|
"PRIORITY: %s launching expedited!",
|
|
"URGENT: %s departing hot!",
|
|
"EMERGENCY: %s airborne immediately unlike Mo!",
|
|
"PRIORITY LAUNCH: %s wheels up faster than Mo!",
|
|
"URGENT TANKER: %s scrambling (Mo couldn't do this)!",
|
|
"EMERGENCY: %s launching while Mo watches!",
|
|
"PRIORITY: %s departing - Mo take notes!",
|
|
"URGENT LAUNCH: %s airborne (unlike Mo's attempts)!",
|
|
"EMERGENCY TANKER: %s scrambling successfully!",
|
|
"PRIORITY: %s wheels up for real!",
|
|
"URGENT: %s launching like professionals do!",
|
|
},
|
|
}
|
|
|
|
--- Get a random message from a category
|
|
--- @param category string Message category key
|
|
--- @param ... any Format arguments for string.format
|
|
--- @return string Formatted message
|
|
local function GetRandomMessage(category, ...)
|
|
local pool = TANKER_MESSAGES[category]
|
|
if not pool or #pool == 0 then
|
|
return "Message unavailable"
|
|
end
|
|
|
|
local template = pool[math.random(1, #pool)]
|
|
|
|
if select("#", ...) > 0 then
|
|
return string.format(template, ...)
|
|
else
|
|
return template
|
|
end
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- UTILITY FUNCTIONS
|
|
-- ============================================================================
|
|
|
|
local function UpdateTankerMenus()
|
|
-- With standard launches removed there is nothing to synchronise yet.
|
|
end
|
|
|
|
--- Announce tanker information to coalition
|
|
local function AnnounceTankerInfo(config, spawned)
|
|
local msg = GetRandomMessage("SPAWN_SUCCESS", config.displayName) .. "\n"
|
|
|
|
if config.tacan then
|
|
msg = msg .. string.format("TACAN: %s\n", config.tacan)
|
|
end
|
|
|
|
if config.frequency then
|
|
msg = msg .. string.format("Radio: %s MHz", config.frequency)
|
|
end
|
|
|
|
MESSAGE:New(msg, 20):ToBlue()
|
|
env.info(string.format("[TANKER] %s spawned successfully", config.displayName))
|
|
end
|
|
|
|
--- Monitor tanker fuel levels
|
|
local function MonitorTankerFuel(stateKey, config)
|
|
return function()
|
|
local state = TANKER_STATE[stateKey]
|
|
|
|
if not state.active or not state.group then
|
|
return
|
|
end
|
|
|
|
-- Check if group still exists
|
|
if not state.group:IsAlive() then
|
|
return
|
|
end
|
|
|
|
local fuelPercent = state.group:GetFuel() * 100
|
|
|
|
-- Bingo fuel check
|
|
if fuelPercent <= config.fuelBingoPercent and not state.bingoWarned then
|
|
MESSAGE:New(GetRandomMessage("BINGO_FUEL", config.displayName), 15, "WARNING"):ToBlue()
|
|
state.bingoWarned = true
|
|
env.info(string.format("[TANKER] %s bingo fuel: %.1f%%", config.displayName, fuelPercent))
|
|
|
|
-- Low fuel warning
|
|
elseif fuelPercent <= config.fuelWarningPercent and not state.fuelWarned then
|
|
MESSAGE:New(GetRandomMessage("LOW_FUEL", config.displayName, math.floor(fuelPercent)), 15):ToBlue()
|
|
state.fuelWarned = true
|
|
env.info(string.format("[TANKER] %s low fuel warning: %.1f%%", config.displayName, fuelPercent))
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Start (or restart) the fuel monitor scheduler for a tanker
|
|
local function StartFuelMonitor(stateKey, config)
|
|
local state = TANKER_STATE[stateKey]
|
|
if not state then
|
|
return
|
|
end
|
|
|
|
if state.fuelMonitor then
|
|
state.fuelMonitor:Stop()
|
|
state.fuelMonitor = nil
|
|
end
|
|
|
|
state.fuelMonitor = SCHEDULER:New(
|
|
nil,
|
|
MonitorTankerFuel(stateKey, config),
|
|
{},
|
|
FUEL_CHECK_INTERVAL,
|
|
FUEL_CHECK_INTERVAL
|
|
)
|
|
end
|
|
|
|
--- Clean up tanker state
|
|
local function CleanupTankerState(stateKey)
|
|
local state = TANKER_STATE[stateKey]
|
|
|
|
state.active = false
|
|
state.group = nil
|
|
state.dcsGroupName = nil
|
|
state.fuelWarned = false
|
|
state.bingoWarned = false
|
|
|
|
if state.fuelMonitor then
|
|
state.fuelMonitor:Stop()
|
|
state.fuelMonitor = nil
|
|
end
|
|
|
|
if state.respawnScheduler then
|
|
state.respawnScheduler:Stop()
|
|
state.respawnScheduler = nil
|
|
end
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- CUSTOM ROUTE FUNCTIONS
|
|
-- ============================================================================
|
|
|
|
--- Parse waypoint marker text for altitude and speed overrides
|
|
--- Supports formats: SHELL1, SHELL1:FL220, SHELL1:FL220:SP330, SHELL1::SP300, SHELL1:RTB
|
|
--- @param markerText string The text from the map marker
|
|
--- @param defaultAlt number Default altitude in feet
|
|
--- @param defaultSpeed number Default speed in knots
|
|
--- @return table Parsed waypoint data {altitude, speed, rtb, isValid}
|
|
local function ParseWaypointMarker(markerText, defaultAlt, defaultSpeed)
|
|
local result = {
|
|
altitude = defaultAlt,
|
|
speed = defaultSpeed,
|
|
rtb = false,
|
|
isValid = true,
|
|
originalText = markerText
|
|
}
|
|
|
|
-- Split by colon
|
|
local parts = {}
|
|
for part in string.gmatch(markerText, "[^:]+") do
|
|
table.insert(parts, part)
|
|
end
|
|
|
|
-- Check for RTB command
|
|
for _, part in ipairs(parts) do
|
|
if string.upper(part) == "RTB" then
|
|
result.rtb = true
|
|
return result
|
|
end
|
|
end
|
|
|
|
-- Parse FL (Flight Level)
|
|
for _, part in ipairs(parts) do
|
|
local fl = string.match(part, "FL(%d+)")
|
|
if fl then
|
|
result.altitude = tonumber(fl) * 100 -- Convert FL to feet
|
|
end
|
|
end
|
|
|
|
-- Parse SP (Speed)
|
|
for _, part in ipairs(parts) do
|
|
local sp = string.match(part, "SP(%d+)")
|
|
if sp then
|
|
result.speed = tonumber(sp)
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
--- Scan map for waypoint markers matching callsign pattern
|
|
--- @param callsign string The callsign prefix to search for (e.g., "SHELL", "ARCO")
|
|
--- @return table Array of waypoint data sorted by sequence number
|
|
local function ScanForWaypointMarkers(callsign)
|
|
local waypoints = {}
|
|
local markerIds = {}
|
|
|
|
-- Iterate through all possible marker IDs (DCS markers are numbered)
|
|
-- We'll scan up to 1000 markers (should be more than enough)
|
|
for i = 1, 1000 do
|
|
local markerData = world.getMarkPanels()
|
|
if markerData and markerData[i] then
|
|
local marker = markerData[i]
|
|
local markerText = marker.text
|
|
|
|
if markerText then
|
|
-- Check if marker matches pattern: CALLSIGN + number
|
|
local upperText = string.upper(markerText)
|
|
local upperCallsign = string.upper(callsign)
|
|
local sequence = string.match(upperText, "^" .. upperCallsign .. "(%d+)")
|
|
|
|
if sequence then
|
|
local seqNum = tonumber(sequence)
|
|
local pos = marker.pos
|
|
|
|
table.insert(waypoints, {
|
|
sequence = seqNum,
|
|
coordinate = COORDINATE:NewFromVec3(pos),
|
|
markerId = marker.idx,
|
|
markerText = markerText
|
|
})
|
|
|
|
table.insert(markerIds, marker.idx)
|
|
|
|
env.info(string.format("[TANKER] Found waypoint marker: %s at seq %d (ID: %d)",
|
|
markerText, seqNum, marker.idx))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Sort by sequence number
|
|
table.sort(waypoints, function(a, b) return a.sequence < b.sequence end)
|
|
|
|
return waypoints, markerIds
|
|
end
|
|
|
|
-- ============================================================================
|
|
|
|
--- Spawn a tanker directly from config (no Mission Editor template required)
|
|
--- @param config table Tanker configuration
|
|
--- @param coord COORDINATE Where to spawn
|
|
--- @param heading number Initial heading in degrees
|
|
--- @return GROUP|nil The spawned tanker group wrapper
|
|
--- @return string|nil The DCS group name that was used
|
|
local function SpawnTankerFromConfig(config, coord, heading)
|
|
local uniqueIndex = NextUniqueIndex()
|
|
local uniqueGroupName = GenerateGroupName(config.groupName, uniqueIndex)
|
|
local uniqueUnitName = GenerateUnitName(config.unitName, uniqueIndex)
|
|
|
|
-- Ensure we have valid altitude (coord.y is altitude in meters MSL)
|
|
local spawnAlt = coord.y
|
|
env.info(string.format("[TANKER] Spawn altitude: %.1f meters (FL%03d)", spawnAlt, spawnAlt * 3.28084 / 100))
|
|
|
|
-- Create group structure for coalition.addGroup
|
|
local groupData = {
|
|
visible = false,
|
|
taskSelected = true,
|
|
route = {
|
|
points = {
|
|
{
|
|
alt = spawnAlt,
|
|
type = "Turning Point",
|
|
action = "Turning Point",
|
|
alt_type = "BARO",
|
|
speed = config.defaultSpeed * 0.514444,
|
|
task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
x = coord.x,
|
|
y = coord.z,
|
|
}
|
|
}
|
|
},
|
|
hidden = false,
|
|
units = {
|
|
{
|
|
alt = spawnAlt,
|
|
alt_type = "BARO",
|
|
livery_id = config.livery,
|
|
skill = "High",
|
|
speed = config.defaultSpeed * 0.514444,
|
|
type = config.aircraftType,
|
|
psi = -heading,
|
|
unitName = uniqueUnitName,
|
|
x = coord.x,
|
|
y = coord.z,
|
|
heading = math.rad(heading),
|
|
onboard_num = "010",
|
|
},
|
|
},
|
|
y = coord.z,
|
|
x = coord.x,
|
|
name = uniqueGroupName,
|
|
task = "Refueling",
|
|
}
|
|
|
|
local spawnedId = coalition.addGroup(country.id.USA, Group.Category.AIRPLANE, groupData)
|
|
|
|
if not spawnedId then
|
|
env.error(string.format("[TANKER] Failed to spawn %s", config.groupName))
|
|
return nil
|
|
end
|
|
|
|
env.info(string.format("[TANKER] Spawned %s as %s", config.groupName, uniqueGroupName))
|
|
|
|
local mooseGroup = GROUP:FindByName(uniqueGroupName)
|
|
if not mooseGroup and Group and Group.getByName then
|
|
local dcsGroup = Group.getByName(uniqueGroupName)
|
|
if dcsGroup then
|
|
mooseGroup = GROUP:Find(dcsGroup)
|
|
end
|
|
end
|
|
|
|
if not mooseGroup then
|
|
env.warning(string.format("[TANKER] Spawned %s but could not resolve group wrapper", uniqueGroupName))
|
|
return nil
|
|
end
|
|
|
|
return mooseGroup, uniqueGroupName
|
|
end
|
|
|
|
--- Ensure default spawns immediately enter a holding pattern so they do not RTB
|
|
--- @param group GROUP The spawned tanker group
|
|
--- @param coord COORDINATE Center point for the orbit
|
|
--- @param config table Tanker configuration for speed/altitude
|
|
local function ApplyDefaultOrbitRoute(group, coord, config)
|
|
if not group or not coord or not config then
|
|
return
|
|
end
|
|
|
|
local orbitCenter = coord:SetAltitude(config.defaultAltitude * 0.3048, true)
|
|
local orbitWP = orbitCenter:WaypointAirTurningPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
config.defaultSpeed * 0.514444,
|
|
config.defaultAltitude * 0.3048,
|
|
{},
|
|
"DEFAULT-ORBIT"
|
|
)
|
|
|
|
orbitWP.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
},
|
|
{
|
|
id = "Orbit",
|
|
params = {
|
|
pattern = "Circle",
|
|
speed = config.defaultSpeed * 0.514444,
|
|
altitude = config.defaultAltitude * 0.3048,
|
|
point = {
|
|
x = orbitCenter.x,
|
|
y = orbitCenter.z
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
group:Route({ orbitWP })
|
|
env.info(string.format("[TANKER] Applied default orbit for %s", config.displayName))
|
|
end
|
|
|
|
--- Create custom route tanker spawn from mission editor template
|
|
--- Spawns at airbase, taxis, takes off, flies to route waypoints, then loops
|
|
--- @param callsign string Callsign prefix used for markers
|
|
--- @param config table Tanker configuration
|
|
--- @param stateKey string State key for tracking
|
|
--- @param isEmergency boolean Whether this is an emergency spawn
|
|
--- @return boolean Success status
|
|
local function SpawnCustomRouteTanker(callsign, config, stateKey, isEmergency)
|
|
local state = TANKER_STATE[stateKey]
|
|
|
|
-- Check if already active
|
|
if state.active then
|
|
MESSAGE:New(GetRandomMessage("ALREADY_ACTIVE", config.displayName), 10):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Scan for waypoint markers
|
|
local waypoints, markerIds = ScanForWaypointMarkers(callsign)
|
|
|
|
-- Validate waypoint count
|
|
if #waypoints < ROUTE_CONFIG.minWaypoints then
|
|
MESSAGE:New(GetRandomMessage("TOO_FEW_WAYPOINTS",
|
|
ROUTE_CONFIG.minWaypoints, callsign, callsign), 15, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
if #waypoints > ROUTE_CONFIG.maxWaypoints then
|
|
MESSAGE:New(GetRandomMessage("TOO_MANY_WAYPOINTS",
|
|
ROUTE_CONFIG.maxWaypoints), 15, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Build route description and validate waypoints
|
|
local routeDesc = ""
|
|
local routePoints = {}
|
|
local hasRTB = false
|
|
|
|
for i, wp in ipairs(waypoints) do
|
|
local parsed = ParseWaypointMarker(wp.markerText, config.defaultAltitude, config.defaultSpeed)
|
|
|
|
if parsed.rtb then
|
|
hasRTB = true
|
|
-- Find nearest friendly airbase from last waypoint position
|
|
local lastPos = #routePoints > 0 and routePoints[#routePoints].coord or wp.coordinate
|
|
local nearestAirbase = lastPos:GetClosestAirbase(Airbase.Category.AIRDROME, coalition.side.BLUE)
|
|
|
|
if nearestAirbase then
|
|
local airbaseName = nearestAirbase:GetName()
|
|
local airbaseCoord = nearestAirbase:GetCoordinate()
|
|
routeDesc = routeDesc .. string.format("\n WP%d: RTB to %s", i, airbaseName)
|
|
|
|
table.insert(routePoints, {
|
|
coord = airbaseCoord,
|
|
altitude = 0, -- Will land
|
|
speed = parsed.speed,
|
|
rtb = true,
|
|
airbase = nearestAirbase,
|
|
airbaseName = airbaseName
|
|
})
|
|
|
|
env.info(string.format("[TANKER] RTB destination: %s", airbaseName))
|
|
else
|
|
routeDesc = routeDesc .. string.format("\n WP%d: RTB (no airbase found)", i)
|
|
env.warning("[TANKER] No friendly airbase found for RTB")
|
|
end
|
|
break -- RTB is terminal command
|
|
else
|
|
routeDesc = routeDesc .. string.format("\n WP%d: FL%03d @ %d kts",
|
|
i, math.floor(parsed.altitude / 100), parsed.speed)
|
|
|
|
table.insert(routePoints, {
|
|
coord = wp.coordinate,
|
|
altitude = parsed.altitude,
|
|
speed = parsed.speed,
|
|
rtb = false
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Confirm route to player
|
|
local routeMsg = GetRandomMessage("ROUTE_ACCEPTED", config.displayName, #routePoints, routeDesc)
|
|
if isEmergency then
|
|
routeMsg = GetRandomMessage("EMERGENCY_SPAWN", config.displayName) .. "\n" .. routeMsg
|
|
end
|
|
MESSAGE:New(routeMsg, 20):ToBlue()
|
|
|
|
env.info(string.format("[TANKER] Spawning %s with custom route: %d waypoints",
|
|
config.displayName, #routePoints))
|
|
|
|
-- Debug: log route point data
|
|
for i, rp in ipairs(routePoints) do
|
|
env.info(string.format("[TANKER] RoutePoint %d: coord=%s, alt=%.0f, spd=%.0f, rtb=%s",
|
|
i, tostring(rp.coord), rp.altitude, rp.speed, tostring(rp.rtb)))
|
|
end
|
|
|
|
-- Delete markers if configured
|
|
if ROUTE_CONFIG.deleteMarkersAfterUse then
|
|
for _, markerId in ipairs(markerIds) do
|
|
trigger.action.removeMark(markerId)
|
|
end
|
|
env.info(string.format("[TANKER] Deleted %d waypoint markers", #markerIds))
|
|
end
|
|
|
|
-- Spawn tanker from mission editor template (at airbase)
|
|
-- This will cause the tanker to taxi and takeoff
|
|
local tankerSpawn = SPAWN:New(config.groupName)
|
|
|
|
if not tankerSpawn then
|
|
MESSAGE:New(string.format("SPAWN FAILURE: Could not find template '%s' in mission", config.groupName),
|
|
15, "ERROR"):ToBlue()
|
|
env.error(string.format("[TANKER] Template '%s' not found in mission editor", config.groupName))
|
|
return false
|
|
end
|
|
|
|
env.info(string.format("[TANKER] SPAWN object created for template: '%s'", config.groupName))
|
|
|
|
-- Build complete route from airbase to waypoints
|
|
local taskRoute = {}
|
|
|
|
-- Add all custom route waypoints
|
|
for i, rp in ipairs(routePoints) do
|
|
local wp
|
|
|
|
-- RTB waypoint - land at airbase
|
|
if rp.rtb and rp.airbase then
|
|
wp = rp.coord:WaypointAirLanding(
|
|
rp.speed * 0.514444,
|
|
rp.airbase:GetDCSObject(),
|
|
{},
|
|
"RTB"
|
|
)
|
|
else
|
|
-- Normal waypoint
|
|
wp = rp.coord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
rp.speed * 0.514444, -- Convert knots to m/s
|
|
rp.altitude * 0.3048, -- Convert feet to meters
|
|
{},
|
|
"WP" .. i
|
|
)
|
|
|
|
-- Add tanker task to all waypoints
|
|
wp.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
table.insert(taskRoute, wp)
|
|
end
|
|
|
|
-- If last waypoint is not RTB, loop back to first waypoint to create continuous patrol
|
|
if not hasRTB and #routePoints > 1 then
|
|
local firstPoint = routePoints[1]
|
|
local loopWP = firstPoint.coord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
firstPoint.speed * 0.514444,
|
|
firstPoint.altitude * 0.3048,
|
|
{},
|
|
"LOOP-WP1"
|
|
)
|
|
|
|
-- Add tanker task to loop waypoint
|
|
loopWP.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
table.insert(taskRoute, loopWP)
|
|
env.info(string.format("[TANKER] Added loop waypoint back to WP1 for continuous patrol"))
|
|
elseif not hasRTB and #routePoints == 1 then
|
|
-- Single waypoint - add circular orbit pattern
|
|
local singlePoint = routePoints[1]
|
|
local orbitWP = singlePoint.coord:WaypointAirTurningPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
singlePoint.speed * 0.514444,
|
|
singlePoint.altitude * 0.3048,
|
|
{},
|
|
"ORBIT"
|
|
)
|
|
orbitWP.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
},
|
|
{
|
|
id = "Orbit",
|
|
params = {
|
|
pattern = "Circle",
|
|
speed = singlePoint.speed * 0.514444,
|
|
altitude = singlePoint.altitude * 0.3048
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
table.insert(taskRoute, orbitWP)
|
|
env.info(string.format("[TANKER] Single waypoint - added circular orbit pattern"))
|
|
end
|
|
|
|
-- Spawn with the custom route
|
|
-- Use MOOSE Spawn to spawn from template and immediately route
|
|
local spawnedGroup = tankerSpawn:Spawn()
|
|
|
|
if not spawnedGroup then
|
|
MESSAGE:New(GetRandomMessage("SPAWN_FAILURE", config.displayName), 10, "ERROR"):ToBlue()
|
|
env.error(string.format("[TANKER] Failed to spawn %s from template", config.displayName))
|
|
return false
|
|
end
|
|
|
|
local spawnedGroupName = spawnedGroup:GetName()
|
|
env.info(string.format("[TANKER] Spawned group name: '%s' (expected template: '%s')",
|
|
spawnedGroupName, config.groupName))
|
|
|
|
-- Apply the custom route to the spawned group
|
|
spawnedGroup:Route(taskRoute)
|
|
|
|
env.info(string.format("[TANKER] Spawned %s from airbase template, will taxi/takeoff to route",
|
|
config.displayName))
|
|
|
|
-- Set up state tracking for phase announcements
|
|
state.active = true
|
|
state.group = spawnedGroup
|
|
state.dcsGroupName = spawnedGroup:GetName()
|
|
state.fuelWarned = false
|
|
state.bingoWarned = false
|
|
state.hasAnnounced = {
|
|
taxi = false,
|
|
takeoff = false,
|
|
enroute = false,
|
|
onStation = false
|
|
}
|
|
state.routePoints = routePoints -- Store for on-station check
|
|
|
|
-- Announce taxi phase immediately
|
|
MESSAGE:New(GetRandomMessage("TAXI", config.displayName), 10):ToBlue()
|
|
state.hasAnnounced.taxi = true
|
|
|
|
-- Monitor for actual flight phases using continuous checking
|
|
SCHEDULER:New(nil, function()
|
|
if not state.active or not state.group or not state.group:IsAlive() then
|
|
return
|
|
end
|
|
|
|
local velocity = state.group:GetVelocityKMH()
|
|
local coord = state.group:GetCoordinate()
|
|
local altitudeMSL = coord.y -- MSL altitude
|
|
local landHeight = coord:GetLandHeight() -- Ground elevation
|
|
local altitudeAGL = altitudeMSL - landHeight -- Above Ground Level
|
|
|
|
-- Debug current state every check
|
|
env.info(string.format("[TANKER] %s status check - AGL: %.0fm (MSL: %.0fm, Ground: %.0fm), Vel: %.0fkm/h",
|
|
config.displayName, altitudeAGL, altitudeMSL, landHeight, velocity))
|
|
|
|
-- TAKEOFF: Airborne detection (AGL > 50m and speed > 150 km/h)
|
|
if not state.hasAnnounced.takeoff and altitudeAGL > 50 and velocity > 150 then
|
|
MESSAGE:New(GetRandomMessage("TAKEOFF", config.displayName), 10):ToBlue()
|
|
state.hasAnnounced.takeoff = true
|
|
env.info(string.format("[TANKER] %s TAKEOFF announced (AGL: %.0fm, spd: %.0fkm/h)",
|
|
config.displayName, altitudeAGL, velocity))
|
|
end
|
|
|
|
-- ENROUTE: Climbing and away from base (AGL > 300m and speed > 250 km/h)
|
|
if state.hasAnnounced.takeoff and not state.hasAnnounced.enroute and altitudeAGL > 300 and velocity > 250 then
|
|
MESSAGE:New(GetRandomMessage("ENROUTE", config.displayName), 10):ToBlue()
|
|
state.hasAnnounced.enroute = true
|
|
env.info(string.format("[TANKER] %s ENROUTE announced (AGL: %.0fm)", config.displayName, altitudeAGL))
|
|
end
|
|
|
|
-- ON_STATION: Within 5nm of WP1 and at reasonable altitude
|
|
if state.hasAnnounced.enroute and not state.hasAnnounced.onStation then
|
|
local wp1Coord = state.routePoints[1].coord
|
|
local currentCoord = state.group:GetCoordinate()
|
|
local distance = currentCoord:Get2DDistance(wp1Coord)
|
|
local targetAlt = state.routePoints[1].altitude * 0.3048 -- feet to meters
|
|
|
|
-- Within 5nm and within 2000ft of target altitude
|
|
if distance < 9260 and math.abs(altitudeMSL - targetAlt) < 610 then
|
|
MESSAGE:New(GetRandomMessage("ON_STATION", config.displayName), 15):ToBlue()
|
|
state.hasAnnounced.onStation = true
|
|
env.info(string.format("[TANKER] %s ON-STATION announced (distance: %.0fm, alt diff: %.0fm)",
|
|
config.displayName, distance, math.abs(altitudeMSL - targetAlt)))
|
|
end
|
|
end
|
|
end, {}, 15, 10) -- Start after 15 seconds, check every 10 seconds
|
|
|
|
-- Announce TACAN/Freq info (without the "airborne" message)
|
|
local msg = string.format("%s assigned:\n", config.displayName)
|
|
if config.tacan then
|
|
msg = msg .. string.format("TACAN: %s\n", config.tacan)
|
|
end
|
|
if config.frequency then
|
|
msg = msg .. string.format("Radio: %s MHz", config.frequency)
|
|
end
|
|
MESSAGE:New(msg, 15):ToBlue()
|
|
|
|
-- Start fuel monitoring
|
|
StartFuelMonitor(stateKey, config)
|
|
|
|
-- Update menus
|
|
UpdateTankerMenus()
|
|
|
|
return true
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- EVENT HANDLER
|
|
-- ============================================================================
|
|
|
|
BlueTankerEventHandler = EVENTHANDLER:New()
|
|
|
|
function BlueTankerEventHandler:OnEventBirth(EventData)
|
|
local groupName = EventData.IniDCSGroupName
|
|
|
|
if groupName and string.find(groupName, "TANKER 135") then
|
|
env.info(string.format("[TANKER] Birth event: %s", groupName))
|
|
|
|
-- Determine which tanker spawned
|
|
local stateKey, config
|
|
if string.find(groupName, "MPRS") then
|
|
stateKey = "KC135_MPRS"
|
|
config = TANKER_CONFIG.KC135_MPRS
|
|
else
|
|
stateKey = "KC135"
|
|
config = TANKER_CONFIG.KC135
|
|
end
|
|
|
|
-- Update state
|
|
local state = TANKER_STATE[stateKey]
|
|
state.active = true
|
|
local mooseGroup = GROUP:FindByName(groupName)
|
|
if not mooseGroup and Group and Group.getByName then
|
|
local dcsGroup = Group.getByName(groupName)
|
|
if dcsGroup then
|
|
mooseGroup = GROUP:Find(dcsGroup)
|
|
end
|
|
end
|
|
|
|
state.group = mooseGroup
|
|
state.dcsGroupName = groupName
|
|
state.fuelWarned = false
|
|
state.bingoWarned = false
|
|
|
|
-- Announce spawn with details
|
|
AnnounceTankerInfo(config, true)
|
|
|
|
-- Start fuel monitoring
|
|
StartFuelMonitor(stateKey, config)
|
|
|
|
-- Update menus
|
|
UpdateTankerMenus()
|
|
end
|
|
end
|
|
|
|
function BlueTankerEventHandler:OnEventDead(EventData)
|
|
local groupName = EventData.IniDCSGroupName
|
|
|
|
if groupName and string.find(groupName, "TANKER 135") then
|
|
env.info(string.format("[TANKER] Dead event: %s", groupName))
|
|
|
|
-- Determine which tanker died
|
|
local stateKey, config
|
|
if string.find(groupName, "MPRS") then
|
|
stateKey = "KC135_MPRS"
|
|
config = TANKER_CONFIG.KC135_MPRS
|
|
else
|
|
stateKey = "KC135"
|
|
config = TANKER_CONFIG.KC135
|
|
end
|
|
|
|
MESSAGE:New(GetRandomMessage("DESTROYED", config.displayName),
|
|
15, "ALERT"):ToBlue()
|
|
|
|
-- Clean up state
|
|
CleanupTankerState(stateKey)
|
|
|
|
-- Update menus
|
|
UpdateTankerMenus()
|
|
end
|
|
end
|
|
|
|
function BlueTankerEventHandler:OnEventCrash(EventData)
|
|
-- Treat crash same as dead
|
|
self:OnEventDead(EventData)
|
|
end
|
|
|
|
function BlueTankerEventHandler:OnEventEngineShutdown(EventData)
|
|
local groupName = EventData.IniDCSGroupName
|
|
|
|
if groupName and string.find(groupName, "TANKER 135") then
|
|
env.info(string.format("[TANKER] Engine shutdown event: %s", groupName))
|
|
|
|
-- Determine which tanker
|
|
local stateKey, config
|
|
if string.find(groupName, "MPRS") then
|
|
stateKey = "KC135_MPRS"
|
|
config = TANKER_CONFIG.KC135_MPRS
|
|
else
|
|
stateKey = "KC135"
|
|
config = TANKER_CONFIG.KC135
|
|
end
|
|
|
|
MESSAGE:New(string.format("%s has returned to base", config.displayName),
|
|
10):ToBlue()
|
|
|
|
-- Clean up state
|
|
CleanupTankerState(stateKey)
|
|
|
|
-- Update menus
|
|
UpdateTankerMenus()
|
|
end
|
|
end
|
|
|
|
function BlueTankerEventHandler:OnEventHit(EventData)
|
|
local groupName = EventData.IniDCSGroupName
|
|
|
|
if groupName and string.find(groupName, "TANKER 135") then
|
|
local config = string.find(groupName, "MPRS") and TANKER_CONFIG.KC135_MPRS or TANKER_CONFIG.KC135
|
|
|
|
MESSAGE:New(GetRandomMessage("TAKING_FIRE", config.displayName),
|
|
15, "WARNING"):ToBlue()
|
|
|
|
env.info(string.format("[TANKER] %s hit by hostile fire", config.displayName))
|
|
end
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- SPAWN OBJECTS AND FUNCTIONS
|
|
-- ============================================================================
|
|
|
|
-- Function to spawn KC-135 with custom route
|
|
function SpawnCustomTanker()
|
|
SpawnCustomRouteTanker(
|
|
TANKER_CONFIG.KC135.callsign,
|
|
TANKER_CONFIG.KC135,
|
|
"KC135",
|
|
false
|
|
)
|
|
end
|
|
|
|
-- Function to spawn KC-135 MPRS with custom route
|
|
function SpawnCustomTankerMPRS()
|
|
SpawnCustomRouteTanker(
|
|
TANKER_CONFIG.KC135_MPRS.callsign,
|
|
TANKER_CONFIG.KC135_MPRS,
|
|
"KC135_MPRS",
|
|
false
|
|
)
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- EMERGENCY TANKER FUNCTIONS (SPAWN AHEAD OF PLAYER)
|
|
-- ============================================================================
|
|
|
|
-- Function to find emergency marker and associated player
|
|
local function FindEmergencyMarkerAndPlayer()
|
|
-- Get all markers
|
|
local allMarkers = {}
|
|
world.getMarkPanels(function(panel)
|
|
if panel.coalition == coalition.side.BLUE then
|
|
table.insert(allMarkers, {
|
|
id = panel.idx,
|
|
text = panel.text,
|
|
pos = panel.pos
|
|
})
|
|
end
|
|
end)
|
|
|
|
-- Find emergency markers
|
|
local emergencyMarkers = {}
|
|
for _, marker in ipairs(allMarkers) do
|
|
local markerTextUpper = string.upper(marker.text)
|
|
for _, keyword in ipairs(EMERGENCY_CONFIG.markerKeywords) do
|
|
if string.find(markerTextUpper, string.upper(keyword)) then
|
|
table.insert(emergencyMarkers, marker)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if #emergencyMarkers == 0 then
|
|
return nil, nil, "No emergency marker found. Place marker with text 'EMERGENCY TANKER'"
|
|
end
|
|
|
|
-- Get all blue human players
|
|
local bluePlayers = {}
|
|
local allGroups = coalition.getGroups(coalition.side.BLUE, Group.Category.AIRPLANE)
|
|
|
|
for _, grp in ipairs(allGroups) do
|
|
local units = grp:getUnits()
|
|
if units then
|
|
for _, unit in ipairs(units) do
|
|
if unit and unit:isExist() and unit:isActive() then
|
|
local playerName = unit:getPlayerName()
|
|
if playerName then
|
|
local mooseUnit = UNIT:Find(unit)
|
|
if mooseUnit and mooseUnit:IsAlive() then
|
|
table.insert(bluePlayers, {
|
|
unit = mooseUnit,
|
|
coord = mooseUnit:GetCoordinate(),
|
|
name = playerName
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if #bluePlayers == 0 then
|
|
return nil, nil, "No human players found"
|
|
end
|
|
|
|
-- Find closest player to any emergency marker
|
|
local closestPlayer = nil
|
|
local closestMarker = nil
|
|
local minDistance = math.huge
|
|
|
|
for _, marker in ipairs(emergencyMarkers) do
|
|
local markerCoord = COORDINATE:New(marker.pos.x, marker.pos.y, marker.pos.z)
|
|
for _, player in ipairs(bluePlayers) do
|
|
local distance = player.coord:Get2DDistance(markerCoord)
|
|
if distance < minDistance and distance < EMERGENCY_CONFIG.markerSearchRadius then
|
|
minDistance = distance
|
|
closestPlayer = player
|
|
closestMarker = marker
|
|
end
|
|
end
|
|
end
|
|
|
|
if not closestPlayer then
|
|
return nil, nil, "No player found near emergency marker (must be within 50km)"
|
|
end
|
|
|
|
return closestPlayer, closestMarker, nil
|
|
end
|
|
|
|
-- Function to spawn emergency tanker ahead of player
|
|
local function SpawnEmergencyTankerAheadOfPlayer(config, stateKey)
|
|
local state = TANKER_STATE[stateKey]
|
|
|
|
-- Check if already active
|
|
if state.active then
|
|
MESSAGE:New(GetRandomMessage("ALREADY_ACTIVE", config.displayName), 10):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Find player and marker
|
|
local player, marker, errorMsg = FindEmergencyMarkerAndPlayer()
|
|
|
|
if not player then
|
|
MESSAGE:New(errorMsg or "Could not locate requesting player", 15, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Get player info
|
|
local playerCoord = player.coord
|
|
local playerAltFeet = playerCoord.y * 3.28084 -- Convert meters to feet
|
|
local playerHeading = player.unit:GetHeading()
|
|
local playerSpeed = player.unit:GetVelocityKNOTS()
|
|
|
|
-- Validate altitude
|
|
if playerAltFeet < EMERGENCY_CONFIG.minAltitudeFeet then
|
|
MESSAGE:New(string.format(
|
|
"EMERGENCY TANKER DENIED: Altitude too low (%.0f ft). Minimum altitude: %.0f ft",
|
|
playerAltFeet, EMERGENCY_CONFIG.minAltitudeFeet
|
|
), 15, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
if playerAltFeet > EMERGENCY_CONFIG.maxAltitudeFeet then
|
|
MESSAGE:New(string.format(
|
|
"EMERGENCY TANKER DENIED: Altitude too high (%.0f ft). Maximum altitude: %.0f ft",
|
|
playerAltFeet, EMERGENCY_CONFIG.maxAltitudeFeet
|
|
), 15, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Calculate spawn position (5km ahead of player)
|
|
local spawnDistance = EMERGENCY_CONFIG.spawnDistanceKM * 1000 -- Convert to meters
|
|
local spawnCoord = playerCoord:Translate(spawnDistance, playerHeading)
|
|
|
|
-- Calculate egress waypoint (100nm ahead on same heading)
|
|
local egressDistance = EMERGENCY_CONFIG.waypointDistanceNM * 1852 -- Convert nm to meters
|
|
local egressCoord = spawnCoord:Translate(egressDistance, playerHeading)
|
|
|
|
-- Announce emergency spawn
|
|
local emergencyMsg = GetRandomMessage("EMERGENCY_SPAWN", config.displayName)
|
|
emergencyMsg = emergencyMsg .. string.format(
|
|
"\n\nSpawning %.1f nm ahead of %s\nAltitude: FL%03d | Heading: %03d°\nEgressing on same heading for %.0f nm then RTB",
|
|
EMERGENCY_CONFIG.spawnDistanceKM * 0.539957, -- km to nm
|
|
player.name,
|
|
math.floor(playerAltFeet / 100),
|
|
playerHeading,
|
|
EMERGENCY_CONFIG.waypointDistanceNM
|
|
)
|
|
MESSAGE:New(emergencyMsg, 20):ToBlue()
|
|
|
|
env.info(string.format(
|
|
"[TANKER] Emergency spawn for %s: pos=%s, alt=%.0f ft, hdg=%03d°",
|
|
player.name, tostring(spawnCoord), playerAltFeet, playerHeading
|
|
))
|
|
|
|
-- Delete the marker
|
|
if marker then
|
|
trigger.action.removeMark(marker.id)
|
|
env.info(string.format("[TANKER] Deleted emergency marker ID %d", marker.id))
|
|
end
|
|
|
|
-- Spawn tanker at calculated position
|
|
local spawnedGroup, spawnedName = SpawnTankerFromConfig(
|
|
config,
|
|
spawnCoord,
|
|
playerHeading
|
|
)
|
|
|
|
if not spawnedGroup then
|
|
MESSAGE:New(GetRandomMessage("SPAWN_FAILURE", config.displayName), 10, "ERROR"):ToBlue()
|
|
return false
|
|
end
|
|
|
|
-- Build emergency egress route
|
|
local taskRoute = {}
|
|
|
|
-- Waypoint 1: Current spawn position (egress start)
|
|
local wp1 = spawnCoord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
config.defaultSpeed * 0.514444,
|
|
playerAltFeet * 0.3048,
|
|
{},
|
|
"EGRESS-START"
|
|
)
|
|
|
|
wp1.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
table.insert(taskRoute, wp1)
|
|
|
|
-- Waypoint 2: Egress endpoint (100nm ahead)
|
|
local wp2 = egressCoord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
config.defaultSpeed * 0.514444,
|
|
playerAltFeet * 0.3048,
|
|
{},
|
|
"EGRESS-END"
|
|
)
|
|
|
|
wp2.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{
|
|
id = "Tanker",
|
|
params = {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
table.insert(taskRoute, wp2)
|
|
|
|
-- Waypoint 3: RTB to nearest friendly airbase
|
|
local nearestAirbase = egressCoord:GetClosestAirbase(Airbase.Category.AIRDROME, coalition.side.BLUE)
|
|
|
|
if nearestAirbase then
|
|
local airbaseName = nearestAirbase:GetName()
|
|
local airbaseCoord = nearestAirbase:GetCoordinate()
|
|
|
|
local wp3 = airbaseCoord:WaypointAirLanding(
|
|
config.defaultSpeed * 0.514444,
|
|
nearestAirbase:GetDCSObject(),
|
|
{},
|
|
"RTB"
|
|
)
|
|
|
|
table.insert(taskRoute, wp3)
|
|
|
|
env.info(string.format("[TANKER] Emergency tanker will RTB to %s after egress", airbaseName))
|
|
else
|
|
env.warning("[TANKER] No friendly airbase found for RTB")
|
|
end
|
|
|
|
-- Route the tanker
|
|
spawnedGroup:Route(taskRoute)
|
|
|
|
-- Update state
|
|
state.active = true
|
|
state.group = spawnedGroup
|
|
state.dcsGroupName = spawnedName
|
|
state.fuelWarned = false
|
|
state.bingoWarned = false
|
|
|
|
-- Start fuel monitoring
|
|
StartFuelMonitoring(config, stateKey)
|
|
|
|
-- Announce tanker info
|
|
AnnounceTankerInfo(config, true)
|
|
|
|
env.info(string.format("[TANKER] %s emergency spawn complete (egress mode)", config.displayName))
|
|
|
|
return true
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- EMERGENCY TANKER SPAWN FUNCTIONS (PUBLIC)
|
|
-- ============================================================================
|
|
|
|
-- Function to spawn emergency KC-135 ahead of player (NEW METHOD)
|
|
function SpawnEmergencyTankerAhead()
|
|
return SpawnEmergencyTankerAheadOfPlayer(TANKER_CONFIG.KC135, "KC135")
|
|
end
|
|
|
|
-- Function to spawn emergency KC-135 MPRS ahead of player (NEW METHOD)
|
|
function SpawnEmergencyTankerMPRSAhead()
|
|
return SpawnEmergencyTankerAheadOfPlayer(TANKER_CONFIG.KC135_MPRS, "KC135_MPRS")
|
|
end
|
|
|
|
-- Function to spawn emergency KC-135 with custom route (OLD METHOD - kept for compatibility)
|
|
function SpawnEmergencyTanker()
|
|
-- Use emergency respawn delay
|
|
local originalDelay = TANKER_CONFIG.KC135.respawnDelay
|
|
TANKER_CONFIG.KC135.respawnDelay = TANKER_CONFIG.KC135.emergencyRespawnDelay
|
|
|
|
local success = SpawnCustomRouteTanker(
|
|
TANKER_CONFIG.KC135.callsign,
|
|
TANKER_CONFIG.KC135,
|
|
"KC135",
|
|
true
|
|
)
|
|
|
|
-- Restore original delay
|
|
TANKER_CONFIG.KC135.respawnDelay = originalDelay
|
|
|
|
return success
|
|
end
|
|
|
|
-- Function to spawn emergency KC-135 MPRS with custom route (OLD METHOD - kept for compatibility)
|
|
function SpawnEmergencyTankerMPRS()
|
|
local originalDelay = TANKER_CONFIG.KC135_MPRS.respawnDelay
|
|
TANKER_CONFIG.KC135_MPRS.respawnDelay = TANKER_CONFIG.KC135_MPRS.emergencyRespawnDelay
|
|
|
|
local success = SpawnCustomRouteTanker(
|
|
TANKER_CONFIG.KC135_MPRS.callsign,
|
|
TANKER_CONFIG.KC135_MPRS,
|
|
"KC135_MPRS",
|
|
true
|
|
)
|
|
|
|
TANKER_CONFIG.KC135_MPRS.respawnDelay = originalDelay
|
|
|
|
return success
|
|
end
|
|
|
|
-- Function to display tanker status
|
|
function ShowTankerStatus()
|
|
local msg = "=== TANKER STATUS ===\n\n"
|
|
|
|
-- KC-135 Status
|
|
local kc135State = TANKER_STATE.KC135
|
|
if kc135State.active and kc135State.group and kc135State.group:IsAlive() then
|
|
local fuel = kc135State.group:GetFuel() * 100
|
|
local coord = kc135State.group:GetCoordinate()
|
|
local alt = coord:GetLandHeight() + coord.y
|
|
msg = msg .. string.format("%s: ACTIVE\n", TANKER_CONFIG.KC135.displayName)
|
|
msg = msg .. string.format(" Fuel: %.0f%%\n", fuel)
|
|
msg = msg .. string.format(" Altitude: FL%03d\n", math.floor(alt * 3.28084 / 100))
|
|
if TANKER_CONFIG.KC135.tacan then
|
|
msg = msg .. string.format(" TACAN: %s\n", TANKER_CONFIG.KC135.tacan)
|
|
end
|
|
if TANKER_CONFIG.KC135.frequency then
|
|
msg = msg .. string.format(" Radio: %s MHz\n", TANKER_CONFIG.KC135.frequency)
|
|
end
|
|
else
|
|
msg = msg .. string.format("%s: NOT ACTIVE\n", TANKER_CONFIG.KC135.displayName)
|
|
end
|
|
|
|
msg = msg .. "\n"
|
|
|
|
-- KC-135 MPRS Status
|
|
local mprsState = TANKER_STATE.KC135_MPRS
|
|
if mprsState.active and mprsState.group and mprsState.group:IsAlive() then
|
|
local fuel = mprsState.group:GetFuel() * 100
|
|
local coord = mprsState.group:GetCoordinate()
|
|
local alt = coord:GetLandHeight() + coord.y
|
|
msg = msg .. string.format("%s: ACTIVE\n", TANKER_CONFIG.KC135_MPRS.displayName)
|
|
msg = msg .. string.format(" Fuel: %.0f%%\n", fuel)
|
|
msg = msg .. string.format(" Altitude: FL%03d\n", math.floor(alt * 3.28084 / 100))
|
|
if TANKER_CONFIG.KC135_MPRS.tacan then
|
|
msg = msg .. string.format(" TACAN: %s\n", TANKER_CONFIG.KC135_MPRS.tacan)
|
|
end
|
|
if TANKER_CONFIG.KC135_MPRS.frequency then
|
|
msg = msg .. string.format(" Radio: %s MHz\n", TANKER_CONFIG.KC135_MPRS.frequency)
|
|
end
|
|
else
|
|
msg = msg .. string.format("%s: NOT ACTIVE\n", TANKER_CONFIG.KC135_MPRS.displayName)
|
|
end
|
|
|
|
MESSAGE:New(msg, 25):ToBlue()
|
|
end
|
|
|
|
-- Function to show custom route help
|
|
-- Function to show main tanker help
|
|
function ShowCustomRouteHelp()
|
|
local msg = "╔═══════════════════════════════════════════════╗\n"
|
|
msg = msg .. "║ TANKER MANAGEMENT SYSTEM - GUIDE ║\n"
|
|
msg = msg .. "╚═══════════════════════════════════════════════╝\n\n"
|
|
|
|
msg = msg .. "━━━ AVAILABLE TANKERS ━━━\n\n"
|
|
msg = msg .. string.format("• %s (SHELL)\n", TANKER_CONFIG.KC135.displayName)
|
|
msg = msg .. string.format(" TACAN: %s | Radio: %s MHz\n\n",
|
|
TANKER_CONFIG.KC135.tacan or "N/A", TANKER_CONFIG.KC135.frequency or "N/A")
|
|
|
|
msg = msg .. string.format("• %s (ARCO)\n", TANKER_CONFIG.KC135_MPRS.displayName)
|
|
msg = msg .. string.format(" TACAN: %s | Radio: %s MHz\n\n",
|
|
TANKER_CONFIG.KC135_MPRS.tacan or "N/A", TANKER_CONFIG.KC135_MPRS.frequency or "N/A")
|
|
|
|
msg = msg .. "━━━ SPAWN OPTIONS ━━━\n\n"
|
|
msg = msg .. "CUSTOM ROUTE:\n"
|
|
msg = msg .. " • Place numbered markers (SHELL1, SHELL2...)\n"
|
|
msg = msg .. " • Tanker spawns at airbase, taxis, takes off\n"
|
|
msg = msg .. " • Flies your route, loops back to WP1\n"
|
|
msg = msg .. " → See 'Custom Route Guide' for details\n\n"
|
|
|
|
msg = msg .. "EMERGENCY (Spawn Ahead):\n"
|
|
msg = msg .. " • Place marker: 'EMERGENCY TANKER'\n"
|
|
msg = msg .. " • Spawns 5km ahead, same altitude/heading\n"
|
|
msg = msg .. " • Flies straight 100nm then RTBs\n"
|
|
msg = msg .. " → See 'Emergency Guide' for details\n\n"
|
|
|
|
msg = msg .. "OTHER OPTIONS:\n"
|
|
msg = msg .. " • Reroute active tanker mid-flight\n"
|
|
msg = msg .. " • Check tanker status (fuel/position)\n"
|
|
msg = msg .. " • Auto-respawn if tanker is lost\n\n"
|
|
|
|
msg = msg .. "For detailed instructions, use:\n"
|
|
msg = msg .. " F10 → Tanker Operations → Help\n"
|
|
msg = msg .. " → Custom Route Guide\n"
|
|
msg = msg .. " → Emergency Tanker Guide\n"
|
|
|
|
MESSAGE:New(msg, 30):ToBlue()
|
|
end
|
|
|
|
-- Function to show custom route guide
|
|
function ShowCustomRouteGuide()
|
|
local msg = "╔═══════════════════════════════════════════════╗\n"
|
|
msg = msg .. "║ CUSTOM ROUTE TANKER GUIDE ║\n"
|
|
msg = msg .. "╚═══════════════════════════════════════════════╝\n\n"
|
|
|
|
msg = msg .. "━━━ HOW IT WORKS ━━━\n\n"
|
|
msg = msg .. "1. Place numbered map markers\n"
|
|
msg = msg .. "2. Launch from F10 → Custom Route menu\n"
|
|
msg = msg .. "3. Tanker spawns at airbase and taxis\n"
|
|
msg = msg .. "4. Takes off and flies to your waypoints\n"
|
|
msg = msg .. "5. Loops back to WP1 continuously\n\n"
|
|
|
|
msg = msg .. "━━━ MARKER SYNTAX ━━━\n\n"
|
|
msg = msg .. "Basic: SHELL1, SHELL2, SHELL3\n"
|
|
msg = msg .. "Altitude: SHELL1:FL180\n"
|
|
msg = msg .. "Speed: SHELL2::SP300\n"
|
|
msg = msg .. "Both: SHELL3:FL200:SP280\n"
|
|
msg = msg .. "RTB: SHELL4:RTB\n\n"
|
|
|
|
msg = msg .. "• Min 2 waypoints, max 10\n"
|
|
msg = msg .. "• Default: FL220 @ 330 knots\n"
|
|
msg = msg .. "• RTB lands at nearest friendly base\n"
|
|
msg = msg .. "• Markers auto-deleted after use\n\n"
|
|
|
|
msg = msg .. "━━━ EXAMPLES ━━━\n\n"
|
|
msg = msg .. "3-point circuit:\n"
|
|
msg = msg .. " ARCO1, ARCO2, ARCO3\n\n"
|
|
|
|
msg = msg .. "High altitude with RTB:\n"
|
|
msg = msg .. " SHELL1:FL280, SHELL2:FL280, SHELL3:RTB\n\n"
|
|
|
|
msg = msg .. "━━━ REROUTING ━━━\n\n"
|
|
msg = msg .. "Change route mid-flight:\n"
|
|
msg = msg .. " 1. Place new markers\n"
|
|
msg = msg .. " 2. F10 → Reroute Active Tanker\n"
|
|
msg = msg .. " 3. Tanker immediately follows new route\n"
|
|
|
|
MESSAGE:New(msg, 35):ToBlue()
|
|
end
|
|
|
|
-- Function to show emergency tanker guide
|
|
function ShowEmergencyGuide()
|
|
local msg = "╔═══════════════════════════════════════════════╗\n"
|
|
msg = msg .. "║ EMERGENCY TANKER GUIDE ║\n"
|
|
msg = msg .. "╚═══════════════════════════════════════════════╝\n\n"
|
|
|
|
msg = msg .. "━━━ SPAWN AHEAD (Recommended) ━━━\n\n"
|
|
msg = msg .. "For urgent refueling when egressing threats!\n\n"
|
|
|
|
msg = msg .. "HOW TO USE:\n"
|
|
msg = msg .. " 1. Place F10 marker: 'EMERGENCY TANKER' near your position.\n"
|
|
msg = msg .. " 2. F10 → Emergency Tanker → Spawn Ahead\n"
|
|
msg = msg .. " 3. Tanker spawns 5km in front of you\n"
|
|
msg = msg .. " 4. Same altitude & heading as you\n"
|
|
msg = msg .. " 5. Flies straight for 100nm\n"
|
|
msg = msg .. " 6. Auto RTBs to nearest base\n\n"
|
|
|
|
msg = msg .. "REQUIREMENTS:\n"
|
|
msg = msg .. " • Altitude: 10,000 - 45,000 ft\n"
|
|
msg = msg .. " • Marker within 50km of your position\n"
|
|
msg = msg .. " • System finds closest player to marker\n\n"
|
|
|
|
msg = msg .. "PRO TIP:\n"
|
|
msg = msg .. " Place marker BEFORE you desperately need it!\n"
|
|
msg = msg .. " You can pre-position it during ingress.\n\n"
|
|
|
|
msg = msg .. "━━━ EMERGENCY CUSTOM ROUTE ━━━\n\n"
|
|
msg = msg .. "Same as regular custom route but:\n"
|
|
msg = msg .. " • Uses numbered markers (SHELL1, etc.)\n"
|
|
msg = msg .. " • Faster respawn if lost (1 min vs 3 min)\n"
|
|
msg = msg .. " • Still spawns at airbase (not in-air)\n\n"
|
|
|
|
msg = msg .. "Use 'Spawn Ahead' for true emergencies!\n"
|
|
|
|
MESSAGE:New(msg, 35):ToBlue()
|
|
end
|
|
|
|
-- Function to reroute an active tanker with new waypoints
|
|
function RerouteTanker()
|
|
if not TANKER_STATE.KC135.active or not TANKER_STATE.KC135.group then
|
|
MESSAGE:New("KC-135 is not active! Spawn it first.", 10):ToBlue()
|
|
return
|
|
end
|
|
|
|
-- Scan for waypoint markers
|
|
local waypoints, markerIds = ScanForWaypointMarkers(TANKER_CONFIG.KC135.callsign)
|
|
|
|
if #waypoints < ROUTE_CONFIG.minWaypoints then
|
|
MESSAGE:New(string.format("Reroute requires at least %d waypoints!\nPlace markers: %s1, %s2, etc.",
|
|
ROUTE_CONFIG.minWaypoints, TANKER_CONFIG.KC135.callsign, TANKER_CONFIG.KC135.callsign), 15, "ERROR"):ToBlue()
|
|
return
|
|
end
|
|
|
|
-- Build new route
|
|
local routePoints = {}
|
|
local routeDesc = ""
|
|
local hasRTB = false
|
|
|
|
for i, wp in ipairs(waypoints) do
|
|
local parsed = ParseWaypointMarker(wp.markerText, TANKER_CONFIG.KC135.defaultAltitude, TANKER_CONFIG.KC135.defaultSpeed)
|
|
|
|
if parsed.rtb then
|
|
hasRTB = true
|
|
local lastPos = #routePoints > 0 and routePoints[#routePoints].coord or TANKER_STATE.KC135.group:GetCoordinate()
|
|
local nearestAirbase = lastPos:GetClosestAirbase(Airbase.Category.AIRDROME, coalition.side.BLUE)
|
|
|
|
if nearestAirbase then
|
|
local airbaseName = nearestAirbase:GetName()
|
|
local airbaseCoord = nearestAirbase:GetCoordinate()
|
|
routeDesc = routeDesc .. string.format("\n WP%d: RTB to %s", i, airbaseName)
|
|
|
|
table.insert(routePoints, {
|
|
coord = airbaseCoord,
|
|
altitude = 0,
|
|
speed = parsed.speed,
|
|
rtb = true,
|
|
airbase = nearestAirbase,
|
|
airbaseName = airbaseName
|
|
})
|
|
end
|
|
break
|
|
else
|
|
routeDesc = routeDesc .. string.format("\n WP%d: FL%03d @ %d kts",
|
|
i, math.floor(parsed.altitude / 100), parsed.speed)
|
|
table.insert(routePoints, {
|
|
coord = wp.coordinate,
|
|
altitude = parsed.altitude,
|
|
speed = parsed.speed,
|
|
rtb = false
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Build task route
|
|
local taskRoute = {}
|
|
for i, rp in ipairs(routePoints) do
|
|
local wp
|
|
|
|
if rp.rtb and rp.airbase then
|
|
wp = rp.coord:WaypointAirLanding(
|
|
rp.speed * 0.514444,
|
|
rp.airbase:GetDCSObject(),
|
|
{},
|
|
"RTB"
|
|
)
|
|
else
|
|
wp = rp.coord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
rp.speed * 0.514444,
|
|
rp.altitude * 0.3048,
|
|
{},
|
|
"WP" .. i
|
|
)
|
|
|
|
if not rp.rtb then
|
|
wp.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{id = "Tanker", params = {}}
|
|
}
|
|
}
|
|
}
|
|
end
|
|
end
|
|
|
|
table.insert(taskRoute, wp)
|
|
end
|
|
|
|
-- Apply new route
|
|
TANKER_STATE.KC135.group:Route(taskRoute)
|
|
|
|
MESSAGE:New(string.format("%s accepting new route with %d waypoints:%s",
|
|
TANKER_CONFIG.KC135.displayName, #routePoints, routeDesc), 20):ToBlue()
|
|
|
|
-- Delete markers
|
|
if ROUTE_CONFIG.deleteMarkersAfterUse then
|
|
for _, markerId in ipairs(markerIds) do
|
|
trigger.action.removeMark(markerId)
|
|
end
|
|
end
|
|
|
|
env.info(string.format("[TANKER] Rerouted %s with %d waypoints", TANKER_CONFIG.KC135.displayName, #routePoints))
|
|
end
|
|
|
|
-- Function to reroute KC-135 MPRS
|
|
function RerouteTankerMPRS()
|
|
if not TANKER_STATE.KC135_MPRS.active or not TANKER_STATE.KC135_MPRS.group then
|
|
MESSAGE:New("KC-135 MPRS is not active! Spawn it first.", 10):ToBlue()
|
|
return
|
|
end
|
|
|
|
local waypoints, markerIds = ScanForWaypointMarkers(TANKER_CONFIG.KC135_MPRS.callsign)
|
|
|
|
if #waypoints < ROUTE_CONFIG.minWaypoints then
|
|
MESSAGE:New(string.format("Reroute requires at least %d waypoints!\nPlace markers: %s1, %s2, etc.",
|
|
ROUTE_CONFIG.minWaypoints, TANKER_CONFIG.KC135_MPRS.callsign, TANKER_CONFIG.KC135_MPRS.callsign), 15, "ERROR"):ToBlue()
|
|
return
|
|
end
|
|
|
|
local routePoints = {}
|
|
local routeDesc = ""
|
|
local hasRTB = false
|
|
|
|
for i, wp in ipairs(waypoints) do
|
|
local parsed = ParseWaypointMarker(wp.markerText, TANKER_CONFIG.KC135_MPRS.defaultAltitude, TANKER_CONFIG.KC135_MPRS.defaultSpeed)
|
|
|
|
if parsed.rtb then
|
|
hasRTB = true
|
|
local lastPos = #routePoints > 0 and routePoints[#routePoints].coord or TANKER_STATE.KC135_MPRS.group:GetCoordinate()
|
|
local nearestAirbase = lastPos:GetClosestAirbase(Airbase.Category.AIRDROME, coalition.side.BLUE)
|
|
|
|
if nearestAirbase then
|
|
local airbaseName = nearestAirbase:GetName()
|
|
local airbaseCoord = nearestAirbase:GetCoordinate()
|
|
routeDesc = routeDesc .. string.format("\n WP%d: RTB to %s", i, airbaseName)
|
|
|
|
table.insert(routePoints, {
|
|
coord = airbaseCoord,
|
|
altitude = 0,
|
|
speed = parsed.speed,
|
|
rtb = true,
|
|
airbase = nearestAirbase,
|
|
airbaseName = airbaseName
|
|
})
|
|
end
|
|
break
|
|
else
|
|
routeDesc = routeDesc .. string.format("\n WP%d: FL%03d @ %d kts",
|
|
i, math.floor(parsed.altitude / 100), parsed.speed)
|
|
table.insert(routePoints, {
|
|
coord = wp.coordinate,
|
|
altitude = parsed.altitude,
|
|
speed = parsed.speed,
|
|
rtb = false
|
|
})
|
|
end
|
|
end
|
|
|
|
local taskRoute = {}
|
|
for i, rp in ipairs(routePoints) do
|
|
local wp
|
|
|
|
if rp.rtb and rp.airbase then
|
|
wp = rp.coord:WaypointAirLanding(
|
|
rp.speed * 0.514444,
|
|
rp.airbase:GetDCSObject(),
|
|
{},
|
|
"RTB"
|
|
)
|
|
else
|
|
wp = rp.coord:WaypointAirFlyOverPoint(
|
|
COORDINATE.WaypointAltType.BARO,
|
|
rp.speed * 0.514444,
|
|
rp.altitude * 0.3048,
|
|
{},
|
|
"WP" .. i
|
|
)
|
|
|
|
if not rp.rtb then
|
|
wp.task = {
|
|
id = "ComboTask",
|
|
params = {
|
|
tasks = {
|
|
{id = "Tanker", params = {}}
|
|
}
|
|
}
|
|
}
|
|
end
|
|
end
|
|
|
|
table.insert(taskRoute, wp)
|
|
end
|
|
|
|
TANKER_STATE.KC135_MPRS.group:Route(taskRoute)
|
|
|
|
MESSAGE:New(string.format("%s accepting new route with %d waypoints:%s",
|
|
TANKER_CONFIG.KC135_MPRS.displayName, #routePoints, routeDesc), 20):ToBlue()
|
|
|
|
if ROUTE_CONFIG.deleteMarkersAfterUse then
|
|
for _, markerId in ipairs(markerIds) do
|
|
trigger.action.removeMark(markerId)
|
|
end
|
|
end
|
|
|
|
env.info(string.format("[TANKER] Rerouted %s with %d waypoints", TANKER_CONFIG.KC135_MPRS.displayName, #routePoints))
|
|
end
|
|
|
|
-- ============================================================================
|
|
-- MISSION MENU SETUP
|
|
-- ============================================================================
|
|
|
|
-- Create mission menu for tanker requests
|
|
-- Integrates with MenuManager to place under "Mission Options"
|
|
-- This keeps CTLD at F2 and AFAC at F3 as intended
|
|
if MenuManager and MenuManager.CreateCoalitionMenu then
|
|
-- Use MenuManager to create menu under "Mission Options"
|
|
MENU_TANKER_ROOT = MenuManager.CreateCoalitionMenu(coalition.side.BLUE, "Tanker Operations")
|
|
env.info("[TANKER] Using MenuManager - menu created under Mission Options")
|
|
else
|
|
-- Fallback: create root menu if MenuManager not available
|
|
MENU_TANKER_ROOT = MENU_COALITION:New(coalition.side.BLUE, "Tanker Operations")
|
|
env.warning("[TANKER] MenuManager not found - creating root menu (load MenuManager first!)")
|
|
end
|
|
|
|
-- Help submenu
|
|
local MENU_HELP = MENU_COALITION:New(
|
|
coalition.side.BLUE,
|
|
"Help",
|
|
MENU_TANKER_ROOT
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
"Quick Start Guide",
|
|
MENU_HELP,
|
|
ShowCustomRouteHelp
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
"Custom Route Guide",
|
|
MENU_HELP,
|
|
ShowCustomRouteGuide
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
"Emergency Tanker Guide",
|
|
MENU_HELP,
|
|
ShowEmergencyGuide
|
|
)
|
|
|
|
-- Custom route submenu
|
|
local MENU_CUSTOM_ROUTE = MENU_COALITION:New(
|
|
coalition.side.BLUE,
|
|
"Custom Route",
|
|
MENU_TANKER_ROOT
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Launch %s (%s markers)", TANKER_CONFIG.KC135.displayName, TANKER_CONFIG.KC135.callsign),
|
|
MENU_CUSTOM_ROUTE,
|
|
SpawnCustomTanker
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Launch %s (%s markers)", TANKER_CONFIG.KC135_MPRS.displayName, TANKER_CONFIG.KC135_MPRS.callsign),
|
|
MENU_CUSTOM_ROUTE,
|
|
SpawnCustomTankerMPRS
|
|
)
|
|
|
|
-- Reroute submenu for changing active tanker routes
|
|
local MENU_REROUTE = MENU_COALITION:New(
|
|
coalition.side.BLUE,
|
|
"Reroute Active Tanker",
|
|
MENU_CUSTOM_ROUTE
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Reroute %s (%s markers)", TANKER_CONFIG.KC135.displayName, TANKER_CONFIG.KC135.callsign),
|
|
MENU_REROUTE,
|
|
RerouteTanker
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Reroute %s (%s markers)", TANKER_CONFIG.KC135_MPRS.displayName, TANKER_CONFIG.KC135_MPRS.callsign),
|
|
MENU_REROUTE,
|
|
RerouteTankerMPRS
|
|
)
|
|
|
|
-- Emergency spawns submenu
|
|
local MENU_EMERGENCY = MENU_COALITION:New(
|
|
coalition.side.BLUE,
|
|
"Emergency Tanker",
|
|
MENU_TANKER_ROOT
|
|
)
|
|
|
|
-- Emergency spawn ahead of player (NEW PRIMARY METHOD)
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Emergency %s (Spawn Ahead)", TANKER_CONFIG.KC135.displayName),
|
|
MENU_EMERGENCY,
|
|
SpawnEmergencyTankerAhead
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("Emergency %s (Spawn Ahead)", TANKER_CONFIG.KC135_MPRS.displayName),
|
|
MENU_EMERGENCY,
|
|
SpawnEmergencyTankerMPRSAhead
|
|
)
|
|
|
|
-- Emergency spawn with custom route (OLD METHOD - kept for advanced users)
|
|
local MENU_EMERGENCY_ROUTE = MENU_COALITION:New(
|
|
coalition.side.BLUE,
|
|
"Emergency Custom Route",
|
|
MENU_EMERGENCY
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("%s (%s markers)", TANKER_CONFIG.KC135.displayName, TANKER_CONFIG.KC135.callsign),
|
|
MENU_EMERGENCY_ROUTE,
|
|
SpawnEmergencyTanker
|
|
)
|
|
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
string.format("%s (%s markers)", TANKER_CONFIG.KC135_MPRS.displayName, TANKER_CONFIG.KC135_MPRS.callsign),
|
|
MENU_EMERGENCY_ROUTE,
|
|
SpawnEmergencyTankerMPRS
|
|
)
|
|
|
|
-- Status and info
|
|
MENU_COALITION_COMMAND:New(
|
|
coalition.side.BLUE,
|
|
"Tanker Status Report",
|
|
MENU_TANKER_ROOT,
|
|
ShowTankerStatus
|
|
)
|
|
|
|
-- ============================================================================
|
|
-- EVENT HANDLER REGISTRATION
|
|
-- ============================================================================
|
|
|
|
BlueTankerEventHandler:HandleEvent(EVENTS.Birth)
|
|
BlueTankerEventHandler:HandleEvent(EVENTS.Dead)
|
|
BlueTankerEventHandler:HandleEvent(EVENTS.Crash)
|
|
BlueTankerEventHandler:HandleEvent(EVENTS.EngineShutdown)
|
|
BlueTankerEventHandler:HandleEvent(EVENTS.Hit)
|
|
|
|
env.info("[TANKER] Tanker Management System initialized")
|
|
MESSAGE:New("Tanker Management System online - Use F10 menu to request tankers", 15):ToBlue() |