mirror of
https://github.com/akaAgar/the-universal-mission-for-dcs-world.git
synced 2026-09-03 18:30:38 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ec4598369 | |||
| e87222b715 | |||
| 8e7dc3ba7a | |||
| 548d81a5a6 | |||
| 0c20433ce4 | |||
| 051d548c8e | |||
| aab5ea1688 | |||
| a25e8e6bc1 | |||
| c16041f58b | |||
| e66fe93ea0 | |||
| ebffc5313a | |||
| 39039430c1 | |||
| 8d05b98a95 | |||
| 33f8986317 | |||
| a55012e383 | |||
| 6964bf2543 |
@@ -1,3 +1,4 @@
|
||||
_[Dd]ebug[Oo]utput/
|
||||
[Ii]nclude/[Ss]cript.lua
|
||||
*.miz
|
||||
*.pdf
|
||||
|
||||
Vendored
+5
-1
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"files.exclude": { "*.miz": true },
|
||||
"Lua.workspace.library": ["Libraries/dcs-world-api.lua"],
|
||||
"Lua.diagnostics.disable": ["deprecated"]
|
||||
"Lua.diagnostics.disable": ["deprecated"],
|
||||
"markdown-pdf.convertOnSave": true,
|
||||
"markdown-pdf.convertOnSaveExclude": ["README.md"],
|
||||
"markdown-pdf.headerTemplate": "<span class='title' style='display: none;'></span>",
|
||||
"markdown-pdf.styles": ["docs/style.css"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
@echo off
|
||||
cls
|
||||
|
||||
WHERE php >nul 2>nul
|
||||
IF %ERRORLEVEL% NEQ 0 goto ERROR-NO-PHP
|
||||
|
||||
@REM -------------------------------------------
|
||||
@REM CREATE SCENARIOS
|
||||
@REM -------------------------------------------
|
||||
@@ -9,18 +12,17 @@ echo THE ULTIMATE MISSION BUILDER SCRIPT:
|
||||
echo - Build [P]ersianGulf debug theater only (default)
|
||||
echo - Build all [D]ebug theaters
|
||||
echo - Build all [R]elease theaters
|
||||
echo - [C]ancel
|
||||
echo.
|
||||
set /p buildConfig=Your choice:
|
||||
echo.
|
||||
|
||||
IF "%buildConfig%" == "d" goto BUILD-DEBUG-ALL
|
||||
IF "%buildConfig%" == "D" goto BUILD-DEBUG-ALL
|
||||
IF "%buildConfig%" == "p" goto BUILD-DEBUG-PERSIAN
|
||||
IF "%buildConfig%" == "P" goto BUILD-DEBUG-PERSIAN
|
||||
IF "%buildConfig%" == "d" goto BUILD-DEBUG-ALL
|
||||
IF "%buildConfig%" == "D" goto BUILD-DEBUG-ALL
|
||||
IF "%buildConfig%" == "r" goto BUILD-RELEASE
|
||||
IF "%buildConfig%" == "R" goto BUILD-RELEASE
|
||||
IF "%buildConfig%" == "s" goto START-DEBUG
|
||||
IF "%buildConfig%" == "S" goto START-DEBUG
|
||||
goto CANCEL-END
|
||||
|
||||
:BUILD-DEBUG-ALL
|
||||
@@ -38,10 +40,16 @@ if exist *.miz del *.miz
|
||||
c:\php\php Make.php release
|
||||
goto COPY-TO-DCS
|
||||
|
||||
:COPY-TO-DCS
|
||||
:BUILD-MANUAL
|
||||
WHERE pandoc >nul 2>nul
|
||||
IF %ERRORLEVEL% NEQ 0 goto ERROR-NO-PANDOC
|
||||
pandoc README.md -o README.pdf
|
||||
goto END
|
||||
|
||||
@REM -------------------------------------------
|
||||
@REM COPY OUTPUT MIZ FILES TO DCS'S MISSIONS DIRECTORY
|
||||
@REM -------------------------------------------
|
||||
:COPY-TO-DCS
|
||||
if not exist "%userprofile%\Saved Games\DCS\Missions\" goto END
|
||||
if not exist *.miz goto END
|
||||
echo Copying output MIZ files to %userprofile%\Saved Games\DCS\Missions...
|
||||
@@ -54,5 +62,10 @@ echo.
|
||||
echo Build cancelled.
|
||||
goto END
|
||||
|
||||
:ERROR-NO-PHP
|
||||
echo.
|
||||
echo CRITICAL ERROR: PHP not found. Please install PHP and add it to the PATH.
|
||||
goto END
|
||||
|
||||
:END
|
||||
echo.
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
|
||||
**This is a BETA version, there may be bugs and there WILL be unbalanced stuff.**
|
||||
|
||||
The Universal Mission for DCS World is an attempt to create a fully dynamic single-player/PvE mission giving access to the whole content of DCS World in a structure similar to the one found in old "simulators", like the early Microprose games (think F-117 or the Strike Eagle serie).
|
||||
These game had both fun and clear objectives, endless replayability and a career system that made sure that something was at stake: crash and die, and you'll lose all these hard-earned medals.
|
||||
|
||||
As the original creator of [Briefing Room](https://github.com/DCS-BR-Tools/briefing-room-for-dcs) (now maintained by the talented John Harvey), I've always wanted to create an easy-to-use, enticing and fun mission generator for DCS, capable of creating CPU-light missions without requiring an external program.
|
||||
I think with The Universal Mission is, finally, the proper way to approach this problem. The current version is still an early beta but most core features are already working. I hope you'll like it.
|
||||
The Universal Mission for DCS World is a fully dynamic single-player/PvE mission giving access to the whole content of DCS World.
|
||||
|
||||
### Features
|
||||
|
||||
@@ -26,21 +22,23 @@ I think with The Universal Mission is, finally, the proper way to approach this
|
||||
[](./docs/target-zones.jpg)
|
||||
[](./docs/career-mode.jpg)
|
||||
|
||||
### Limitations of current beta version
|
||||
#### Limitations of current beta version
|
||||
|
||||
**Please read the "planned development" section below for more information.**
|
||||
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- Germany support will come soon, others will follow later
|
||||
- Not all mission types are supported yet
|
||||
- Career progress may be lost because of future updates, don't get too attached to it
|
||||
|
||||
### Known bugs
|
||||
<h4>Known bugs in latest release</h4>
|
||||
|
||||
- AWACS datalink info is now displayed on SA pages
|
||||
- Some player callsigns may cause an error on mission start, stick to the "basic" DCS callsigns (Enfield, Springfield, Uzi, Colt, Dodge, Ford, Chevy and Pontiac) to avoid this problem
|
||||
|
||||
## How to use/play The Universal Mission?
|
||||
|
||||
**Please refer to the [User's manual](https://github.com/akaAgar/the-universal-mission-for-dcs-world/blob/main/The%20Universal%20Mission%20-%20User's%20Manual.md) for additional information.**
|
||||
|
||||
### First setup
|
||||
|
||||
- Download the latest release from this GitHub page.
|
||||
@@ -67,102 +65,38 @@ Please refer to the "Advanced stuff you may want to try" section to learn all th
|
||||
- When you're ready, pick the "Begin mission" option, wait a few seconds (precaching all the game assets can take some time, especially if you have a slow CPU), you're ready to go!
|
||||
- Use the F10 mission and check the F10 map for additional information about the mission (see "Using the mission menu" below). Don't forget to come back to base alive, all awarded XP and completed objectives will only be saved to your pilot profile once you've landed
|
||||
|
||||
### Using the mission menu
|
||||
|
||||
Most features of The Universal Mission require the use of the "F10. Other" menu. To access it, press the "Communication menu" key (check the key bindings), navigate to the root menu by pressing F11 ("Previous menu") if need, then press "F10" to access the "Other" menu.
|
||||
The exact content of the menu will depend on the current phase of the mission.
|
||||
|
||||
#### On startup/when no mission is active
|
||||
|
||||
- **Display mission settings**: Displays the current mission settings, that will be applied if you choose to start the mission now.
|
||||
- **Change mission settings**: Allows you to change the mission settings to your taste.
|
||||
- **Blue coalition**: Who is the blue coalition? Determines the type of units that will be spawned. Available factions (e.g. NATO) depend on the missions's time period and theater.
|
||||
- **Red coalition**: Who is the red coalition? Determines the type of units that will be spawned. Available factions (e.g. USSR) depend on the missions's time period and theater.
|
||||
- **Mission type**: What will your mission be?
|
||||
- **Antiship strike**: Sink enemy warships and cargo ships.
|
||||
- **Ground attack**: Interdiction missions against armor, artillery and convoys.
|
||||
- **Interception**: Shoot down strategic airplanes (bombers, transports...) and enemy attack planes on interdiction missions.
|
||||
- **SEAD**: Destroy enemy SAM sites.
|
||||
- **Strike**: Destroy enemy structures and civilian buildings occupied by enemy forces.
|
||||
- **Target location**: Where on the map will the targets be spawned? Approximate distance to possible regions is displayed in the menu.
|
||||
- Missions taking place in enemy territory award 30% more XP to account for increased SAM threat and proximity of enemy airbases.
|
||||
- Make sure to pick a region not too far away from your starting location if you don't like long ingresses.
|
||||
- Picking a region very close to your starting location (for instance, the one where your airbase is located in) can also be a bad idea, as you might takeoff in range of an enemy SAM.
|
||||
- Be aware that targets of antiship strikes will always be spawned in open seas, which can be quite far if you picked a landlocked target zone.
|
||||
- **Target count**: How many objectives will be spawned. More objectives means potentially more xp in a single sortie, so better medals, but also more work and more risk. Be aware that you can RTB to rearm/refuel at any time between objectives, but you won't accumulate as many single-sortie XP as if you complete objectives without going back to base, because XP is awarded to your profile and reset each time you land.
|
||||
- **Enemy air defense**: Amount, quality and skill of enemy surface-to-air units (AAA, MANPADS and SAM). A higher setting awards more XP.
|
||||
- **Enemy air force**: Amount, quality and skill of enemy combat air patrols. A higher setting awards more XP.
|
||||
- **Wingmen count**: How many wingmen will fly by your side (from zero to three). A small XP penalty is added for each additional wingman. Wingman won't get replaced if they get shot during a mission, but they will (with full payload) each time you land and takeoff again. Only shown in single-player missions.
|
||||
- **Friendly AI CAP**: Should AI fighter aicraft be spawned regularly to patrol the AO and shoot down potential threats? Disabling this option will award you more XP (only if "Enemy air force" is not set to "None") but also means you and your wingmen will be alone against the whole enemy air force.
|
||||
- **View pilot career stats**: Displays a list of your achievements, as well as your medal case. Only available when playing single-player missions and if the Lua IO module has been unsanitized (see "First setup" above)
|
||||
- **Begin mission**: Starts a mission with the current settings.
|
||||
|
||||
#### During the mission
|
||||
|
||||
- **Mission status**: Displays a summary of the mission's status (list of objectives and progress on each objective).
|
||||
- **Objectives**: Displays a list of special commands related to each of the mission's objectives. Be aware that some objectives may have no special commands associated with them.
|
||||
- **Smoke marker on target**: Asks for a friendly JTAC to pop a smoke marker on the target. Makes finding the target easier, but will cost you a small XP penalty. Only available for missions where a JTAC is available (it's pretty hard to throw a smoke grenade at an airplane or a ship in the middle of the sea).
|
||||
- **Navigation**: Displays a list of commands related to navigational assistance.
|
||||
- **Navigation to objective [OBJECTIVE NAME]**: Displays the coordinates of the objective, its BRA ("fly X for Y") relative to the player's position and an estimated flight time and ETA. Some objectives types (e.g. strike missions) are provided with exact coordinates, but most will only have approximate coordiantes, so you'll have to search for targets yourself once in the objective area.
|
||||
- **Flight**: Displays a list of commands for your wingmen. Only shown in single-player missions and if wingmen are available for this mission.
|
||||
- **Cover me!**: Tasks your wingmen to immediately engage any nearby air threats.
|
||||
- **Engage**: Tasks your wingmen to engage a certain type of targets. Targets must be detected by your wingmen (see "Report contacts" below), or they won't be able to engage them.
|
||||
- **Report contacts**: Asks your wingmen for a list of all detected contacts. According to range and sensors capabilities, their reports can go from perfect ID (e.g. "Su-27") to very generic descriptions (e.g. "fighter" or even "aircraft")
|
||||
- **Hold position**: Tasks your wingmen to orbit at their current position. All other tasking will be aborted.
|
||||
- **Change altitude**: Asks your wingmen to change their altitude. This altitude will be employed when attacking on orbiting but not when rejoining/forming up with you (in that case, they'll match your altitude).
|
||||
- **Status report**: Asks your wingmen for a complete report (damage sustained, fuel status, available payload).
|
||||
- **Rejoin**: Asks your wingmen to rejoin and follow you. All other tasking will be aborted. This is the default tasking when wingmen take off and when they complete another task.
|
||||
- **AWACS**: Displays a list of commands for the AWACS. Only shown if an AWACS aircraft is available for this mission.
|
||||
- **Bogey dope**: Asks for the nearest enemy air threat
|
||||
- **Picture**: Asks for a summary of all detected enemy aircraft
|
||||
- **Display mission score**: Displays the number of XP gained and objectives completed since your last takeoff. They will be added to your flight log (and any promotions/medals be awarded) the next time you land. If you crash, eject or abort the mission, all currently "stowed" XP and objectives will be lost. Only available when playing single-player missions and if the Lua IO module has been unsanitized (see "First setup" above)
|
||||
- **Abort mission**: Aborts the current mission and forfeit all XP/objectives gained since last landing. The game will ask for confirmation so you don't select this option by mistake.
|
||||
|
||||
### Advanced stuff you may want to try
|
||||
|
||||
The Universal Mission is designed to be easily editable to suit your preferences. Here are a few things you could do after opening the .miz file in DCS World's mission editor.
|
||||
|
||||
#### Player aircraft
|
||||
|
||||
- Change the player aircraft starting condition (runway, parking or parking hot). Air starts are not recommended as all players must be on the ground to begin a new mission
|
||||
- Move it to another airbase, change its coalition (make sure blue players are spawned on an airbase located in a BLUFOR zone are red players are spawned on an airbase located in a REDFOR zone)
|
||||
- You may also add an aircraft carrier or a FARP for the player to take off from
|
||||
- Change its default loadout if you plan to play a specific kind of mission and don't want to lose time asking the ground crew to rearm your aircraft (e.g. if you know you want to play SEAD missions, you may as well stock up on AGM-88s)
|
||||
- Change the skill level from "Player" to "Client" and add other aircraft to create a multiplayer mission to play with your friends. Keep in mind that the persistent career/player stats system will be disabled in multiplayer missions and that all player aircraft must belong to the same coalition (TUM does not support PvP)
|
||||
|
||||
#### Zones
|
||||
|
||||
- All zones whose names starts with BLUFOR or REDFOR decide the territory (and airbases) controlled by the blue and red coalitions
|
||||
- Be aware that any change to the airbases coalitions will be superseded by the BLUFOR and REFOR zones
|
||||
- All zones whose names starts with WATER are seas, used to spawn ships
|
||||
- Zones with a name not starting with BLUFOR, REDFOR or WATER are target zones. These are zones where objectives can be spawned, who can be selected in the "objective location" setting of the intermission F10 menu
|
||||
- Change, add or remove zones to create new possible target areas. A maximum of 10 target areas can be created, so they fit the F10 menu
|
||||
|
||||
#### A few notes regarding multiplayer
|
||||
### A few notes regarding multiplayer
|
||||
|
||||
While The Universal Mission supports multiplayer and is perfectely suitable (and fun!) for playing with friends on a private server, it is **absolutely not suited for public servers** as missions settings can be edited by anyone at any time Using the mission menu.
|
||||
Please also note that PvP is not supported at the moment and that the mission will not launch if both coalitions have player slots.
|
||||
|
||||
#### Other parameters
|
||||
|
||||
- _(Not yet implemented in this version)_ By changing the year in mission time parameters, the time period will be changed accordingly and the proper factions and AI units will be spawned during the mission. Time periods are:
|
||||
- 1945 and before: World War 2
|
||||
- 1946-1959: Korea War
|
||||
- 1960-1974: Vietnam War
|
||||
- 1975-1989: Late Cold War
|
||||
- 1990-now: Modern
|
||||
- _(Not yet implemented in this version)_ Changing the weather to make it more cloudy or windy, or setting the mission to nighttime, will make the mission more difficult but also award more points.
|
||||
|
||||
## Planned development
|
||||
|
||||
### VERY high priority
|
||||
<h3>Planned for next version (could be subject to change)</h3>
|
||||
|
||||
- Additional "navigation" commands (vector to nearest airfield, complete weather report...)
|
||||
- Bugfix: AWACS datalink info not showing on SA pages
|
||||
- Improved score multiplier taking into account various aspects of mission difficulty (weather, nighttime ops...)
|
||||
- New objectives: helicopter (drop/pickup units...), CAP, CAS, OCA (airbase attack)
|
||||
- Support for the Germany and South America theaters
|
||||
- Support for more factions and five different time periods (World War 2, Korea war, Vietnam war, late Cold war, Modern)
|
||||
- Additional content
|
||||
- [ ] At least partial Germany map support
|
||||
- AI improvements
|
||||
- [ ] AI wingmen should engage tracking radars first when told to engage SAM sites, in order to disable the site ASAP
|
||||
- Balance improvements
|
||||
- [ ] Lowered enemy CAP respawn rate
|
||||
- [ ] Tweaked XP requirements for medals/promotions
|
||||
- Bug fixes
|
||||
- [ ] AWACS datalinked contacts not showing on SA pages
|
||||
- [x] Some player callsigns causing a script error at startup
|
||||
- Extras
|
||||
- [x] First draft of the PDF manual
|
||||
- New features
|
||||
- [ ] Additional commands in the "navigation" menu
|
||||
- [ ] Vector to nearest airfield
|
||||
- [ ] Weather report
|
||||
- [ ] Use of "Client" slot instead of "Player" slot even in single-player missions, allowing the player to respawn on death/ejection instead of having to start the whole mission again
|
||||
- [ ] Single-player mission autostart on player take off
|
||||
- Quality of life/minor tweaks
|
||||
- [ ] AI wingmen "Two was shot down!" call when witnessing another wingman killed
|
||||
- [ ] AI wingmen "Winchester!" call when out of ammo
|
||||
- [x] Increased AWACS aircraft spawn altitude
|
||||
- [ ] Target coordinates radio message displayed for a longer time so players have the time to write them down or enter them in their flight computer
|
||||
|
||||
### High priority
|
||||
|
||||
@@ -172,9 +106,12 @@ Please also note that PvP is not supported at the moment and that the mission wi
|
||||
- Better use of context for "ambient" radio messages (should only warn of a SAM launch if an AI pilot is there to witness it, etc)
|
||||
- Friendly air defenses
|
||||
- GitHub page
|
||||
- Improved score multiplier taking into account various aspects of mission difficulty (weather, nighttime ops...)
|
||||
- Laser designation of targets by JTAC
|
||||
- New objectives: helicopter (drop/pickup units...), CAP, CAS, OCA (airbase attack)
|
||||
- PDF manual
|
||||
- Support for all missing DCS World theaters
|
||||
- Support for more factions and five different time periods (World War 2, Korea war, Vietnam war, late Cold war, Modern)
|
||||
|
||||
### Medium priority
|
||||
|
||||
@@ -194,6 +131,7 @@ Please also note that PvP is not supported at the moment and that the mission wi
|
||||
## Misc
|
||||
|
||||
- **Released under the GNU GPL 3.0 licence**
|
||||
- Uses YoloWingPixie's [DCS World Schema API](https://github.com/YoloWingPixie/dcs-world-schema)
|
||||
- AI use/disclosure
|
||||
- [ChatGPT](https://chatgpt.com/): used to generate first draft of radio messages
|
||||
- [ElevenLabs](https://elevenlabs.io/fr): used to generate radio messages voiceover
|
||||
@@ -229,7 +167,7 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
|
||||
- **0.2.250729** (07/29/2025)
|
||||
- **MAJOR CHANGE:** Added all new wingman system
|
||||
- Far for perfect but a lot better than AI's default wingmen
|
||||
- Far for perfect but a lot better than DCS's default wingmen
|
||||
- Many more engage/orbit/go to commands (see "Using the mission menu" above)
|
||||
- All new contacts report system: more realistic (see "AI units reports" changes below in this changelog) and does not spam the player with "new contact" messages
|
||||
- AI wingmen added using mission editor are now despawned on mission start to avoid conflict with TUM's own wingman system
|
||||
@@ -257,7 +195,7 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
- Moved "Request objective coordinates" radio commands to new "Navigation" submenu, which will include additional navigational assist in future versions
|
||||
- Lowered MANPADS count and skill (MANPADS are overpowered in DCS, especially SA-18)
|
||||
- "New friendly/enemy aircraft taking off" radio messages now mention their BRAA relative to the player, number of bandits taking off now displayed as a word instead of digits
|
||||
- "Rifle!" and "Missile away!" radio calls now both used for any kind of A/G missiles
|
||||
- "Rifle!" and "Missile away!" radio calls now both used for any kind of A/G missiles (except antiship and antiradiation missiles, who
|
||||
- Tons of internal logic bugfixes and tweaks
|
||||
- Tweaked XP bonus/penalty for various mission settings
|
||||
- Vastly improved the way AI units reports on contact tracks. According to range and sensors capabilities, can go from perfect ID (e.g. "Su-27") to very generic descriptions (e.g. "fighter" or even "aircraft")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- ====================================================================================
|
||||
-- (DCS LUA ADD-ON) CONVERTER - UNITS CONVERSION FUNCTIONS
|
||||
--
|
||||
-- DCSEX.CONVERTER - UNITS CONVERSION FUNCTIONS
|
||||
-- ====================================================================================
|
||||
-- DCSEx.converter.celsiusToFahrenheit(t)
|
||||
-- DCSEx.converter.degreesToRadians(degrees)
|
||||
-- DCSEx.converter.fahrenheitToCelsius(fahrenheit)
|
||||
@@ -21,6 +21,7 @@ DCSEx.converter = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Converts Celsius degrees to Fahrenheit
|
||||
-------------------------------------
|
||||
-- @param t Temperature in Celsius degrees
|
||||
-- @return Temperature in Fahrenheit degrees
|
||||
-------------------------------------
|
||||
@@ -30,6 +31,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts angle in degrees to radians.
|
||||
-------------------------------------
|
||||
-- @param degrees Angle in degrees
|
||||
-- @return Angle in radians
|
||||
-------------------------------------
|
||||
@@ -39,6 +41,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts Fahrenheit degrees to Celsius
|
||||
-------------------------------------
|
||||
-- @param fahrenheit Temperature in Fahrenheit degrees
|
||||
-- @return Temperature in Celsius degrees
|
||||
-------------------------------------
|
||||
@@ -48,6 +51,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts feet to meters.
|
||||
-------------------------------------
|
||||
-- @param feet Distance in feet
|
||||
-- @return Distance in meters
|
||||
-------------------------------------
|
||||
@@ -57,6 +61,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts Kelvin degrees to Celsius
|
||||
-------------------------------------
|
||||
-- @param kelvin Temperature in Kelvin degrees
|
||||
-- @return Temperature in Celsius degrees
|
||||
-------------------------------------
|
||||
@@ -66,6 +71,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts Kelvin degrees to Fahrenheit
|
||||
-------------------------------------
|
||||
-- @param kelvin Temperature in Kelvin degrees
|
||||
-- @return Temperature in Fahrenheit degrees
|
||||
-------------------------------------
|
||||
@@ -75,6 +81,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts kilometers per hour to meters per second.
|
||||
-------------------------------------
|
||||
-- @param kmph speed in km/h
|
||||
-- @return speed in m/s
|
||||
-------------------------------------
|
||||
@@ -84,6 +91,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts knots to meters per second.
|
||||
-------------------------------------
|
||||
-- @param knots speed in knots
|
||||
-- @return speed in m/s
|
||||
-------------------------------------
|
||||
@@ -93,6 +101,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts meters to feet.
|
||||
-------------------------------------
|
||||
-- @param meters distance in meters
|
||||
-- @return distance in feet
|
||||
-------------------------------------
|
||||
@@ -102,6 +111,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts meters to nautical miles.
|
||||
-------------------------------------
|
||||
-- @param meters distance in meters
|
||||
-- @return distance in nautical miles
|
||||
-------------------------------------
|
||||
@@ -111,6 +121,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts meters per second to kilometers per hour.
|
||||
-------------------------------------
|
||||
-- @param mps speed in m/s
|
||||
-- @return speed in km/h
|
||||
-------------------------------------
|
||||
@@ -120,6 +131,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts meters per second to knots.
|
||||
-------------------------------------
|
||||
-- @param mps speed in m/s
|
||||
-- @return speed in knots
|
||||
-------------------------------------
|
||||
@@ -129,6 +141,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts nautical miles to meters.
|
||||
-------------------------------------
|
||||
-- @param nm distance in nautical miles
|
||||
-- @return distance in meters
|
||||
-------------------------------------
|
||||
@@ -138,6 +151,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts angle in radians to degrees.
|
||||
-------------------------------------
|
||||
-- @param degrees Angle in radians
|
||||
-- @return Angle in degrees
|
||||
-------------------------------------
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
-- ====================================================================================
|
||||
-- DCSTOOLS - FUNCTIONS LINKED TO DCS WORLD RULES AND TABLES
|
||||
-- DCSEX.DCS - FUNCTIONS HANDLING DCS WORLD'S GAME RULES AND TABLES
|
||||
-- ====================================================================================
|
||||
-- DCSEx.dcs.getBRAA(point, refPoint, showAltitude, metricSystem, casualFormat)
|
||||
-- DCSEx.dcs.getCJTFForCoalition(coalitionID)
|
||||
-- DCSEx.dcs.getCoalitionAsString(coalitionID)
|
||||
-- DCSEx.dcs.getCoalitionColor(coalitionID, alpha)
|
||||
-- DCSEx.dcs.getFirstUnitCallsign(group)
|
||||
-- DCSEx.dcs.getGroupCenterPoint(group)
|
||||
-- DCSEx.dcs.getGroupIDAsNumber(group)
|
||||
-- DCSEx.dcs.getNearestObject(refPoint, objectTable)
|
||||
-- DCSEx.dcs.getNearestObjects(refPoint, objectTable, maxCount)
|
||||
-- DCSEx.dcs.getNearestPoints(refPoint, pointsTable, maxCount)
|
||||
-- DCSEx.dcs.getObjectIDAsNumber(obj)
|
||||
-- DCSEx.dcs.getOppositeCoalition(coalitionID)
|
||||
-- DCSEx.dcs.getPlayerUnitsInGroup(group)
|
||||
-- DCSEx.dcs.getPlayerUnitsInGroupByID(groupID)
|
||||
-- DCSEx.dcs.getRadioModulationName(modulationID)
|
||||
-- DCSEx.dcs.getObjectIDAsNumber(obj)
|
||||
-- DCSEx.dcs.getUnitTypeFromFamily(unitFamily)
|
||||
-- DCSEx.dcs.getUnitFamilyForDecade(unitFamily, decade) -- TODO: remove?
|
||||
-- DCSEx.dcs.getUnitCategoryFromFamily(unitFamily)
|
||||
-- DCSEx.dcs.loadMission(fileName)
|
||||
-- DCSEx.dcs.outPicture(fileName, durationSeconds, clearView, startDelay, horizontalAlign, verticalAlign, size, sizeUnits)
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.dcs = { }
|
||||
|
||||
-- TODO: add description and update file header
|
||||
function DCSEx.dcs.doNothing()
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets a BRAA (bearing, range, altitude, aspect) string about a point
|
||||
-- Format is "[bearing to unit] for [distance] at [altitude]"
|
||||
-------------------------------------
|
||||
-- @param unit A unit
|
||||
-- @param refPoint Reference point for the bearing and distance
|
||||
-- @param showAltitude Should altitude be displayed?
|
||||
@@ -86,6 +85,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the CJTF country for a given coalition
|
||||
-------------------------------------
|
||||
-- @param A coalition ID
|
||||
-- @return A country ID (country.id.CJTF_BLUE or country.id.CJTF_RED)
|
||||
-------------------------------------
|
||||
@@ -97,6 +97,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the name of a coalition, as a string ("blue", "red" or "neutral")
|
||||
-------------------------------------
|
||||
-- @param A coalition ID
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
@@ -109,8 +110,9 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the RGBA color table for the given coalition, accoding to NATO symbology colors
|
||||
-------------------------------------
|
||||
-- @param coalitionID A coalition side
|
||||
-- @param alpha (optional) Alpha. Default is 1
|
||||
-- @param alpha (optional) Alpha. Default is 1.0
|
||||
-- @return A RGBA color table
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.getCoalitionColor(coalitionID, alpha)
|
||||
@@ -123,7 +125,12 @@ function DCSEx.dcs.getCoalitionColor(coalitionID, alpha)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: description
|
||||
-------------------------------------
|
||||
-- Returns the callsign table for the first unit of the group
|
||||
-------------------------------------
|
||||
-- @param group A group
|
||||
-- @return A callsign table, or nil if no units or no group
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.getFirstUnitCallsign(group)
|
||||
if not group then return nil end
|
||||
|
||||
@@ -137,6 +144,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a vec3 point at the center of all units of a group
|
||||
-------------------------------------
|
||||
-- @param group A group object
|
||||
-- @return A vec3
|
||||
-------------------------------------
|
||||
@@ -162,6 +170,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the ID of a group as a number (here to fix a bug where sometimes ID is returned as a string)
|
||||
-------------------------------------
|
||||
-- @param group A group table
|
||||
-- @return An ID (as an number) or nil if group is nil or has no ID
|
||||
-------------------------------------
|
||||
@@ -175,6 +184,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the object nearest (in a 2D plane) from a given point
|
||||
-------------------------------------
|
||||
-- @param refPoint A reference point, as a vec2 or vec3
|
||||
-- @param objectTable A table of DCS objects
|
||||
-- @return The object nearest from the point, or nil if no object was found
|
||||
@@ -187,6 +197,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the nearest objects (in a 2D plane) from a given point
|
||||
-------------------------------------
|
||||
-- @param refPoint A reference point, as a vec2 or vec3
|
||||
-- @param objectTable A table of DCS objects
|
||||
-- @param maxCount (optional) Maximum number of objects to return
|
||||
@@ -218,6 +229,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the nearest points (in a 2D plane) from a given point
|
||||
-------------------------------------
|
||||
-- @param refPoint A reference point, as a vec2 or vec3
|
||||
-- @param objectTable A table of points (vec2 or vec3)
|
||||
-- @param maxCount (optional) Maximum number of points to return
|
||||
@@ -249,6 +261,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the coalition opposed to the provided coalition (coalition.side.NEUTRAL still returns NEUTRAL)
|
||||
-------------------------------------
|
||||
-- @param group A coalition
|
||||
-- @return Another coalition
|
||||
-------------------------------------
|
||||
@@ -260,6 +273,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all player-controlled units in a group
|
||||
-------------------------------------
|
||||
-- @param group A group object
|
||||
-- @return A table of unit objects
|
||||
-------------------------------------
|
||||
@@ -280,6 +294,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all player-controlled units in the group with the given ID
|
||||
-------------------------------------
|
||||
-- @param groupID A group ID
|
||||
-- @return A table of unit objects
|
||||
-------------------------------------
|
||||
@@ -289,6 +304,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a radio modulation type as a string
|
||||
-------------------------------------
|
||||
-- @param modulationID A modulation ID (from radio.modulation enum)
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
@@ -297,66 +313,9 @@ function DCSEx.dcs.getRadioModulationName(modulationID)
|
||||
return "AM"
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a remplacement unit family for given family if it's not available in this decade (e.g. SAMs in the 1940s). Else returns the original family.
|
||||
-- @param unitFamily An unit family
|
||||
-- @param decade (optional) A decade, or the current decade from env.mission.date.Year
|
||||
-- @return An unit family
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.getUnitFamilyForDecade(unitFamily, decade)
|
||||
-- TODO
|
||||
-- decade = decade or envMission.getDecade()
|
||||
|
||||
-- if decade < 1990 then
|
||||
-- if unitFamily == DCSEx.enums.unitFamily.UAVs then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.AttackHelicopters
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- if decade < 1970 then
|
||||
-- if unitFamily == DCSEx.enums.unitFamily.AWACS then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Transports
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.SAMShort then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.MobileAAA
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.SAMShortIR then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.MobileAAA
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- if decade < 1960 then
|
||||
-- if unitFamily == DCSEx.enums.unitFamily.AttackHelicopters then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Fighters
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.MANPADS then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Infantry
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.SAMLong then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.StaticAAA
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.SAMMedium then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.StaticAAA
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.SSMissiles then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Artillery
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.TransportHelicopters then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Transports
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- if decade < 1950 then
|
||||
-- if unitFamily == DCSEx.enums.unitFamily.MobileAAA then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.APC
|
||||
-- elseif unitFamily == DCSEx.enums.unitFamily.Tankers then
|
||||
-- unitFamily = DCSEx.enums.unitFamily.Transports
|
||||
-- end
|
||||
-- end
|
||||
|
||||
return unitFamily
|
||||
end
|
||||
|
||||
-- TODO: description
|
||||
function DCSEx.dcs.getUnitTypeFromFamily(unitFamily)
|
||||
return math.floor(unitFamily / 100)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the ID of an object as a number (here to fix a bug where sometimes ID is returned as a string)
|
||||
-------------------------------------
|
||||
-- @param obj An object (unit, static object...)
|
||||
-- @return An ID (as an number) or nil if unit is nil or has no ID
|
||||
-------------------------------------
|
||||
@@ -365,21 +324,36 @@ function DCSEx.dcs.getObjectIDAsNumber(obj)
|
||||
return tonumber(obj:getID())
|
||||
end
|
||||
|
||||
-- TODO: description & file header
|
||||
-------------------------------------
|
||||
-- Returns a the unit category (Unit.Category enum) an unit family (DCSEx.enums.unitFamily) belongs to
|
||||
-------------------------------------
|
||||
-- @param unitFamily A value from the Unit.Category enum
|
||||
-- @return A value from the DCSEx.enums.unitFamily enum
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.getUnitCategoryFromFamily(unitFamily)
|
||||
return math.floor(unitFamily / 100)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Loads another DCS World mission
|
||||
-------------------------------------
|
||||
-- @param fileName Filename of the mission
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.loadMission(fileName)
|
||||
net.dostring_in("mission", string.format("a_load_mission(\"%s\")", fileName))
|
||||
end
|
||||
|
||||
-- TODO: description & file header
|
||||
-- function DCSEx.dcs.isMultiplayer()
|
||||
-- if #net.get_player_list() > 0 then return true end
|
||||
-- if dcs and dcs.isServer() == true then return true end
|
||||
-- return false
|
||||
-- end
|
||||
|
||||
-- TODO: a_end_mission
|
||||
|
||||
-- TODO: description & file header
|
||||
-------------------------------------
|
||||
-- Displays a picture on the screen of ALL players
|
||||
-------------------------------------
|
||||
-- @param fileName Filename/ResourceName of the image in the mission resources
|
||||
-- @param durationSeconds Duration (in seconds) during which the image should be displayed
|
||||
-- @param startDelay After how many seconds should the image be displayed? (default: 0)
|
||||
-- @param horizontalAlign Horizontal alignment of the image (0/1/2=left/center/right) (default: 1)
|
||||
-- @param verticalAlign Vertical alignment of the image (0/1/2=top/center/bottom) (default: 1)
|
||||
-- @param size Size of the image, in pixels or % of the screen (see sizeUnits) (default: 100)
|
||||
-- @param sizeUnits If 0, the size parameter is in pixels. If 1, it's in % of screen size (default: 0)
|
||||
-------------------------------------
|
||||
function DCSEx.dcs.outPicture(fileName, durationSeconds, clearView, startDelay, horizontalAlign, verticalAlign, size, sizeUnits)
|
||||
clearView = clearView or false
|
||||
startDelay = startDelay or 0
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
-- ====================================================================================
|
||||
-- DCSEX.ENUMS - VARIOUS ENUMS
|
||||
-- ====================================================================================
|
||||
-- DCSEx.enums.lineType
|
||||
-- DCSEx.enums.taskEvent
|
||||
-- DCSEx.enums.taskFamily
|
||||
-- DCSEx.enums.taskFlag
|
||||
-- DCSEx.enums.timePeriod
|
||||
-- DCSEx.enums.unitFamily
|
||||
-- DCSEx.enums.victoryCondition
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.enums = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Line types for map markers. The enum is missing from DCS
|
||||
-- Line types for map markers. This enum is missing from DCS
|
||||
-------------------------------------
|
||||
DCSEx.enums.lineType = {
|
||||
NO_LINE = 0,
|
||||
@@ -13,16 +25,6 @@ DCSEx.enums.lineType = {
|
||||
TWO_DASH = 6,
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
-- Event to check to see if a task/objective is complete
|
||||
-------------------------------------
|
||||
DCSEx.enums.spawnPointType = {
|
||||
LAND_LARGE = 1,
|
||||
LAND_MEDIUM = 2,
|
||||
LAND_SMALL = 3,
|
||||
SEA = 4,
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
-- Event to check to see if a task/objective is complete
|
||||
-------------------------------------
|
||||
@@ -67,7 +69,8 @@ DCSEx.enums.timePeriod = {
|
||||
KOREA_WAR = 2,
|
||||
VIETNAM_WAR = 3,
|
||||
COLD_WAR = 4,
|
||||
MODERN = 5
|
||||
GULF_WAR = 5,
|
||||
MODERN = 6
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
@@ -113,11 +116,13 @@ DCSEx.enums.unitFamily = {
|
||||
STATIC_STRUCTURE = 402
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
-- Victory conditions for tasks/objectives
|
||||
-------------------------------------
|
||||
DCSEx.enums.victoryCondition = {
|
||||
DESTROY = 1,
|
||||
DESTROY_NO_AIR_DEFENSE = 2,
|
||||
DESTROY_SCENERY = 3,
|
||||
DESTROY_TRACK_RADARS_ONLY = 4, -- for SEAD tasks
|
||||
|
||||
LAND_NEAR = 5,
|
||||
LAND_NEAR = 5
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
-- ====================================================================================
|
||||
-- (DCS LUA ADD-ON) ENVMISSION - FUNCTIONS RELATED TO THE ENV.MISSION TABLE
|
||||
--
|
||||
-- DCSEX.ENVMISSION - FUNCTIONS RELATED TO THE ENV.MISSION TABLE
|
||||
-- ====================================================================================
|
||||
-- DCSEx.envMission.getDecade(yearOffset)
|
||||
-- DCSEx.envMission.getDistanceToNearestPlayerSpawnPoint(point)
|
||||
-- DCSEx.envMission.getDistanceToNearestPlayerSpawnPoint(coalition, point)
|
||||
-- DCSEx.envMission.getGroup(groupID)
|
||||
-- DCSEx.envMission.getGroups(sideID)
|
||||
-- DCSEx.envMission.getPlayerGroups(coalitionId)
|
||||
-- DCSEx.envMission.getPlayerGroupsCenterPoint(coalitionId)
|
||||
-- DCSEx.envMission.setBriefing(side, text, picture)
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.envMission = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the decade during which the mission takes place (1940 to 2010)
|
||||
-------------------------------------
|
||||
-- @param yearOffset An offset to apply to the actual year
|
||||
-- @return The decade, as a number
|
||||
-------------------------------------
|
||||
@@ -22,6 +24,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the distance to the nearest player spawn point
|
||||
-------------------------------------
|
||||
-- @param coalition Coalition the players belong to
|
||||
-- @param point A vec3 or vec2
|
||||
-- @return The distance, in meters, to the nearest player spawn point, or nil if no player spawn points are present
|
||||
@@ -42,6 +45,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets information about a group
|
||||
-------------------------------------
|
||||
-- @param groupID Group ID
|
||||
-- @return Missiondata group table or nil if ID doesn't exist
|
||||
-------------------------------------
|
||||
@@ -59,6 +63,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets all unit groups
|
||||
-------------------------------------
|
||||
-- @param sideID Coalition ID (coalition.side.*), or nil to return unit groups from all coalitions
|
||||
-- @return Table of missiondata group tables
|
||||
-------------------------------------
|
||||
@@ -98,6 +103,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets all player groups
|
||||
-------------------------------------
|
||||
-- @param coalitionId Coalition ID (coalition.side.*), or nil to return unit groups from all coalitions
|
||||
-- @return Table of missiondata group tables
|
||||
-------------------------------------
|
||||
@@ -126,6 +132,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Return the center 2D point of all player groups
|
||||
-------------------------------------
|
||||
-- @param coalitionId Coalition ID (coalition.side.*), or nil to use unit groups from all coalitions
|
||||
-- @return A 2D point, or nil if no player groups
|
||||
-------------------------------------
|
||||
@@ -145,7 +152,13 @@ function DCSEx.envMission.getPlayerGroupsCenterPoint(coalitionId)
|
||||
return center
|
||||
end
|
||||
|
||||
-- TODO: description & file header
|
||||
-------------------------------------
|
||||
-- Sets the text for the briefing description in the briefing panel
|
||||
-------------------------------------
|
||||
-- @param side Coalition ID (coalition.side.*) of the coalition
|
||||
-- @param text Text of the briefing
|
||||
-- @param picture Resource name of the picture to use for the briefing
|
||||
-------------------------------------
|
||||
function DCSEx.envMission.setBriefing(side, text, picture)
|
||||
text = text or ""
|
||||
text = text:gsub("\n", "\\n")
|
||||
|
||||
@@ -1,106 +1,56 @@
|
||||
-- ====================================================================================
|
||||
-- DCSEx.IO - HANDLES READING/WRITING FILES
|
||||
-- DCSEX.IO - HANDLES READING/WRITING FILES
|
||||
-- ====================================================================================
|
||||
-- DCSEx.io.canReadAndWrite()
|
||||
-- DCSEx.io.load(fileName)
|
||||
-- DCSEx.io.save(fileName, values)
|
||||
-- DCSEx.io.save(fileName, str)
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.io = {}
|
||||
|
||||
do
|
||||
-------------------------------------
|
||||
-- Returns true if the IO table has been unsanitized (allowing IO operations)
|
||||
-- and false if it hasn't been
|
||||
--
|
||||
-- @return A boolean
|
||||
-------------------------------------
|
||||
function DCSEx.io.canReadAndWrite()
|
||||
return io ~= nil
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Loads a table from a text file
|
||||
--
|
||||
-- @param fileName Name of the file to read
|
||||
-- @param obfuscate Should the file contents be obfuscated?
|
||||
-- @return A table, or nil if something went wrong
|
||||
-------------------------------------
|
||||
-- function DCSEx.io.load(fileName, obfuscate)
|
||||
-- obfuscate = obfuscate or false -- TODO: obfuscation
|
||||
|
||||
-- -- IO table is sanitized, cannot read/write to disk
|
||||
-- if not DCSEx.io.canReadAndWrite() then return nil end
|
||||
|
||||
-- local saveFile = io.open(fileName, "r")
|
||||
-- if not saveFile then return nil end
|
||||
|
||||
-- local values = {}
|
||||
-- local rawText = saveFile:read("*all")
|
||||
-- for k, v in string.gmatch(rawText, "(%w+)=(%w+)") do
|
||||
-- local numval = tonumber(v)
|
||||
-- if numval then
|
||||
-- values[k] = tonumber(v)
|
||||
-- else
|
||||
-- values[k] = v
|
||||
-- -- trigger.action.outText("GET value \""..k.."\" AT \""..tostring(v).."\"", 1)
|
||||
-- end
|
||||
-- end
|
||||
-- saveFile:close()
|
||||
|
||||
-- return values
|
||||
-- end
|
||||
|
||||
function DCSEx.io.load(fileName)
|
||||
-- IO table is sanitized, cannot read/write to disk
|
||||
if not DCSEx.io.canReadAndWrite() then return nil end
|
||||
|
||||
local saveFile = io.open(fileName, "r")
|
||||
if not saveFile then return nil end
|
||||
local str = saveFile:read("*all")
|
||||
saveFile:close()
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Saves a table to a text file
|
||||
--
|
||||
-- @param fileName Name of the file to write to
|
||||
-- @param values Key/value table containing the values to save
|
||||
-- @param obfuscate Should the file contents be obfuscated?
|
||||
-- @return True if everything went right, false otherwise
|
||||
-------------------------------------
|
||||
-- function DCSEx.io.save(fileName, values, obfuscate)
|
||||
-- obfuscate = obfuscate or false -- TODO: obfuscation
|
||||
|
||||
-- -- IO table is sanitized, cannot read/write to disk
|
||||
-- if not DCSEx.io.canReadAndWrite() then return false end
|
||||
|
||||
-- -- No values or not a table
|
||||
-- if values == nil then return false end
|
||||
-- if type(values) ~= "table" then return false end
|
||||
|
||||
-- local saveFile = io.open(fileName, "w")
|
||||
-- if not saveFile then return false end
|
||||
|
||||
-- for k,v in pairs(values) do
|
||||
-- saveFile:write(k.."="..tostring(v).."\n")
|
||||
-- -- trigger.action.outText("SET value \""..k.."\" TO \""..tostring(v).."\"", 1)
|
||||
-- end
|
||||
-- saveFile:close()
|
||||
|
||||
-- return true
|
||||
-- end
|
||||
function DCSEx.io.save(fileName, str)
|
||||
-- IO table is sanitized, cannot read/write to disk
|
||||
if not DCSEx.io.canReadAndWrite() then return false end
|
||||
|
||||
local saveFile = io.open(fileName, "w")
|
||||
if not saveFile then return false end
|
||||
saveFile:write(str)
|
||||
saveFile:close()
|
||||
|
||||
return true
|
||||
end
|
||||
-------------------------------------
|
||||
-- Returns true if the IO table has been unsanitized (allowing IO operations) and false if it hasn't been
|
||||
-------------------------------------
|
||||
-- @return A boolean
|
||||
-------------------------------------
|
||||
function DCSEx.io.canReadAndWrite()
|
||||
return io ~= nil
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Loads a string from a text file
|
||||
-------------------------------------
|
||||
-- @param fileName Name of the file to read
|
||||
-- @return A string, or nil if something went wrong
|
||||
-------------------------------------
|
||||
function DCSEx.io.load(fileName)
|
||||
-- IO table is sanitized, cannot read/write to disk
|
||||
if not DCSEx.io.canReadAndWrite() then return nil end
|
||||
|
||||
local saveFile = io.open(fileName, "r")
|
||||
if not saveFile then return nil end
|
||||
local str = saveFile:read("*all")
|
||||
saveFile:close()
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Writes a string to a text file
|
||||
-------------------------------------
|
||||
-- @param fileName Name of the file to write to. It will be overwritten if it exists.
|
||||
-- @param values Key/value table containing the values to save
|
||||
-- @param str String to write
|
||||
-- @return True if everything went right, false otherwise
|
||||
-------------------------------------
|
||||
function DCSEx.io.save(fileName, str)
|
||||
-- IO table is sanitized, cannot read/write to disk
|
||||
if not DCSEx.io.canReadAndWrite() then return false end
|
||||
|
||||
local saveFile = io.open(fileName, "w")
|
||||
if not saveFile then return false end
|
||||
saveFile:write(str)
|
||||
saveFile:close()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
-- ====================================================================================
|
||||
-- (DCS LUA ADD-ON) MATH - EXTENSION TO THE "MATH" TABLE
|
||||
--
|
||||
-- DCSEX.MATH - MATH AND MATH-RELATED FUNCTIONS
|
||||
-- ====================================================================================
|
||||
-- (Constant) DCSEx.math.TWO_PI
|
||||
-- DCSEx.math.addVec(vecA, vecB)
|
||||
-- DCSEx.math.clamp(val, min, max)
|
||||
-- DCSEx.math.getBearing(point, refPoint, returnAsNESWstring)
|
||||
-- DCSEx.math.getDistance2D(vec2a, vec2b)
|
||||
-- DCSEx.math.getDistance3D(vec3a, vec3b)
|
||||
-- DCSEx.math.getRelativeHeading(point, refObject)
|
||||
-- DCSEx.math.getRelativeHeading(point, refObject, format)
|
||||
-- DCSEx.math.getVec2FromAngle(angle)
|
||||
-- DCSEx.math.isPointInsideCircle(center, radius, vec2)
|
||||
-- DCSEx.math.isPointInsidePolygon(polygon, vec2)
|
||||
@@ -28,12 +28,13 @@
|
||||
DCSEx.math = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Constants
|
||||
-- Two times Pi
|
||||
-------------------------------------
|
||||
DCSEx.math.TWO_PI = math.pi * 2
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the sum of two vec2 or vec3
|
||||
-------------------------------------
|
||||
-- @param vecA A vector
|
||||
-- @param vecB Another vector
|
||||
-- @return The sum of both vectors
|
||||
@@ -48,6 +49,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Clamp a number value between min and max
|
||||
-------------------------------------
|
||||
-- @param value The value to clamp
|
||||
-- @param min Minimum allowed value
|
||||
-- @param max Maximum allowed value
|
||||
@@ -59,6 +61,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets the bearing between two vectors, in degrees
|
||||
-------------------------------------
|
||||
-- @param point A vec2/vec3
|
||||
-- @param refPoint Vec2/vec3 to use as a reference point
|
||||
-- @param returnAsNESWstring Should the value be returned as a N/S/E/W string instead of a numeric value
|
||||
@@ -90,6 +93,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the pythagorean distance between two 2D points or the length of a single vector
|
||||
-------------------------------------
|
||||
-- @param vec2a A 2D point
|
||||
-- @param vec2b (optional) Another 2D point
|
||||
-- @return Distance between the points
|
||||
@@ -104,6 +108,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the pythagorean distance between two 3D points or the length of a single vector
|
||||
-------------------------------------
|
||||
-- @param vec3a A 3D point
|
||||
-- @param vec3b (optional) Another 3D point
|
||||
-- @return Distance between the points
|
||||
@@ -116,6 +121,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the relative heading difference between refObject and a given point
|
||||
-------------------------------------
|
||||
-- @param point The point for which to check the relative heading
|
||||
-- @param refObject The reference object against which relative heading should be measured
|
||||
-- @param format (optional) Return format. Possible formats are "clock" (1 o'clock...) or "cardinal" (NNW...)
|
||||
@@ -149,6 +155,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns an normalized vec2 from an angle/bearing in radians
|
||||
-------------------------------------
|
||||
-- @param unit Angle/bearing in radians
|
||||
-- @return A normalized vec2
|
||||
-------------------------------------
|
||||
@@ -158,6 +165,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Is a point inside a circle?
|
||||
-------------------------------------
|
||||
-- @param center The center of the circle, as a vec2
|
||||
-- @param radius The radius of the circle
|
||||
-- @param vec2 A vec2
|
||||
@@ -169,6 +177,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Is a point inside a polygon?
|
||||
-------------------------------------
|
||||
-- @param vec2[] A polygon, as a table of vec2
|
||||
-- @param vec2 A vec2
|
||||
-- @return True if vec2 is inside the polygon, false otherwise
|
||||
@@ -195,6 +204,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Compares two 2D or 3D points
|
||||
-------------------------------------
|
||||
-- @param pointA a Point2 or Point3
|
||||
-- @param pointB another Point2 or Point3
|
||||
-- @return True if points are the same, false otherwise
|
||||
@@ -210,7 +220,8 @@ function DCSEx.math.isSamePoint(pointA, pointB)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Linearly interpolates between two numbers
|
||||
-- Linearly interpolates two numbers
|
||||
-------------------------------------
|
||||
-- @param val0 Value vers l=0
|
||||
-- @param val1 Value vers l=1
|
||||
-- @param t Interpolation between 0 and 1
|
||||
@@ -222,6 +233,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Multiplies both the x and y components of a vec2 by a floating-point value
|
||||
-------------------------------------
|
||||
-- @param vec2 A vec2
|
||||
-- @param mult A floating-point value
|
||||
-- @return A vec2
|
||||
@@ -232,6 +244,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns an normalized vec2
|
||||
-------------------------------------
|
||||
-- @param unit A vec2
|
||||
-- @return A normalized vec2
|
||||
-------------------------------------
|
||||
@@ -242,6 +255,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random boolean
|
||||
-------------------------------------
|
||||
-- @return A boolean
|
||||
-------------------------------------
|
||||
function DCSEx.math.randomBoolean()
|
||||
@@ -250,20 +264,19 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random floating-point number between min and max
|
||||
-------------------------------------
|
||||
-- @param min Minimum floating-point value
|
||||
-- @param max Maximum floating-point value
|
||||
-- @return A number
|
||||
-------------------------------------
|
||||
function DCSEx.math.randomFloat(min, max)
|
||||
if min >= max then
|
||||
return min
|
||||
end
|
||||
|
||||
if min >= max then return min end
|
||||
return min + math.random() * (max - min)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random vec2 at a given distance of another vec2
|
||||
-------------------------------------
|
||||
-- @param point Reference point
|
||||
-- @param distance Distance from the reference point
|
||||
-- @return A vec2
|
||||
@@ -278,6 +291,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random vec2 in circle of a given center and radius
|
||||
-------------------------------------
|
||||
-- @param center Center of the circle as a vec2
|
||||
-- @param radius Radius of the circle
|
||||
-- @param minRadius (optional) Minimum inner radius circle in which points should not be spawned
|
||||
@@ -306,6 +320,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random sign as a number, -1 or 1
|
||||
-------------------------------------
|
||||
-- @return -1 50% of the time, 1 50% of the time
|
||||
-------------------------------------
|
||||
function DCSEx.math.randomSign()
|
||||
@@ -317,6 +332,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts a value to a boolean
|
||||
-------------------------------------
|
||||
-- @param val Value to convert
|
||||
-- @return A boolean, or nil if val was nil
|
||||
-------------------------------------
|
||||
@@ -331,6 +347,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts a vec2 to a vec3
|
||||
-------------------------------------
|
||||
-- @param vec2 A vec2
|
||||
-- @param y (Optional) A value for the vec3's y component or "land" to use land height
|
||||
-- @return A vec3 where v3.x=v2.x, v3.y=y and v3.z=v2.y
|
||||
@@ -349,6 +366,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Converts a vec3 to a vec2
|
||||
-------------------------------------
|
||||
-- @param vec3 A vec3
|
||||
-- @return A vec2 where v2.x=v3.x and v2.y=v3.z
|
||||
-------------------------------------
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
-- ====================================================================================
|
||||
-- (DCS LUA ADD-ON) STRING - EXTENSION TO THE "STRING" TABLE
|
||||
--
|
||||
-- DCSEX.STRING - FUNCTIONS RELATED TO STRING MANIPULATION
|
||||
-- ====================================================================================
|
||||
-- DCSEx.string.firstToUpper(str)
|
||||
-- DCSEx.string.getReadingTime(message)
|
||||
-- DCSEx.string.join(table, separator)
|
||||
-- DCSEx.string.getTimeString(timeInSeconds, separator)
|
||||
-- DCSEx.string.toStringNumber(number, firstToUpper)
|
||||
-- DCSEx.string.toStringThousandsSeparator(number)
|
||||
-- DCSEx.string.split(str, separator)
|
||||
-- DCSEx.string.startsWith(haystack, needle)
|
||||
-- DCSEx.string.trim(str)
|
||||
@@ -12,6 +16,7 @@ DCSEx.string = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Uppercases the fist letter of a string
|
||||
-------------------------------------
|
||||
-- @param str A string
|
||||
-- @return A string, with the first letter cast to upper case
|
||||
-------------------------------------
|
||||
@@ -21,6 +26,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Estimates the time (in seconds) required to read a string
|
||||
-------------------------------------
|
||||
-- @param message A text message
|
||||
-- @return A duration in seconds
|
||||
-------------------------------------
|
||||
@@ -31,7 +37,13 @@ function DCSEx.string.getReadingTime(message)
|
||||
return DCSEx.math.clamp(#message / 8.7, 3.0, 15.0) -- 10.7 letters per second, minimum length 3 seconds, max length 15 seconds
|
||||
end
|
||||
|
||||
-- TODO: description, update file header
|
||||
-------------------------------------
|
||||
-- Joins a table of string into a single string
|
||||
-------------------------------------
|
||||
-- @param table A table of strings
|
||||
-- @param separator Separator used to glue table entries (default: "")
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
function DCSEx.string.join(table, separator)
|
||||
local joinedString = ""
|
||||
|
||||
@@ -45,10 +57,16 @@ function DCSEx.string.join(table, separator)
|
||||
return joinedString
|
||||
end
|
||||
|
||||
-- TODO: description, file header
|
||||
function DCSEx.string.getTimeString(timeInSeconds, useColon)
|
||||
-------------------------------------
|
||||
-- Converts a time of day (in seconds since midnight) to a human-readable time string
|
||||
-------------------------------------
|
||||
-- @param timeInSeconds Number of seconds since midnight (default: current time)
|
||||
-- @param separator Separator between minutes and seconds (":", "h"...) (default: "")
|
||||
-- @return The time, as as string
|
||||
-------------------------------------
|
||||
function DCSEx.string.getTimeString(timeInSeconds, separator)
|
||||
timeInSeconds = timeInSeconds or timer.getAbsTime()
|
||||
useColon = useColon or false
|
||||
separator = separator or ""
|
||||
|
||||
timeInSeconds = math.max(0, timeInSeconds) % 86400
|
||||
|
||||
@@ -61,13 +79,15 @@ function DCSEx.string.getTimeString(timeInSeconds, useColon)
|
||||
local minutesStr = tostring(minutes)
|
||||
if #minutesStr == 1 then minutesStr = "0"..minutesStr end
|
||||
|
||||
local separator = ""
|
||||
if useColon then separator = ":" end
|
||||
|
||||
return hoursStr..separator..minutesStr
|
||||
end
|
||||
|
||||
-- TODO: description, file header
|
||||
-------------------------------------
|
||||
-- Converts a numeric value between 0 and 20 into its word/string representation
|
||||
-------------------------------------
|
||||
-- @param number A number (>=0, <=20)
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
function DCSEx.string.toStringNumber(number, firstToUpper)
|
||||
firstToUpper = firstToUpper or false
|
||||
local NUMBERS = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty" }
|
||||
@@ -81,8 +101,13 @@ function DCSEx.string.toStringNumber(number, firstToUpper)
|
||||
return DCSEx.string.toStringThousandsSeparator(number)
|
||||
end
|
||||
|
||||
-- TODO: description, file header
|
||||
-- Code from https://stackoverflow.com/questions/10989788/format-integer-in-lua
|
||||
-------------------------------------
|
||||
-- Converts a numeric value to a string, with proper thousands separators
|
||||
-- (Code taken from https://stackoverflow.com/questions/10989788/format-integer-in-lua)
|
||||
-------------------------------------
|
||||
-- @param number A number
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
function DCSEx.string.toStringThousandsSeparator(number)
|
||||
local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
|
||||
int = int:reverse():gsub("(%d%d%d)", "%1,")
|
||||
@@ -90,7 +115,8 @@ function DCSEx.string.toStringThousandsSeparator(number)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Splits a string
|
||||
-- Splits a string into a table
|
||||
-------------------------------------
|
||||
-- @param str The string to split
|
||||
-- @param separator The string to split
|
||||
-- @return A table of split strings
|
||||
@@ -105,6 +131,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Does a string starts with the given substring?
|
||||
-------------------------------------
|
||||
-- @param haystack The string
|
||||
-- @param needle The substring to look for
|
||||
-- @return True if it starts with the substring, false otherwise
|
||||
@@ -115,6 +142,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Trims a string
|
||||
-------------------------------------
|
||||
-- @param str A string
|
||||
-- @return A string
|
||||
-------------------------------------
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
-- ====================================================================================
|
||||
-- (DCS LUA ADD-ON) TABLE - EXTENSION TO THE "TABLE" TABLE
|
||||
--
|
||||
-- DCSEX.TABLE - FUNCTIONS RELATED TO TABLE MANIPULATION
|
||||
-- ====================================================================================
|
||||
-- DCSEx.table.contains(t, val)
|
||||
-- DCSEx.table.containsKey(t, k)
|
||||
-- DCSEx.table.containsAll(t, values)
|
||||
-- DCSEx.table.containsAny(t, values)
|
||||
-- DCSEx.table.containsAllKeys(t, keys)
|
||||
-- DCSEx.table.containsAnyKeys(t, keys)
|
||||
-- DCSEx.table.countNonNils(t)
|
||||
-- DCSEx.table.deepCopy(orig)
|
||||
-- DCSEx.table.dump(t)
|
||||
-- DCSEx.table.getKeys(t)
|
||||
-- DCSEx.table.getKeyFromValue(t, val)
|
||||
-- DCSEx.table.getKeys(t)
|
||||
-- DCSEx.table.getRandom(t)
|
||||
-- DCSEx.table.getRandomIndex(t)
|
||||
-- DCSEx.table.shuffle(t)
|
||||
@@ -19,6 +21,7 @@ DCSEx.table = {}
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains value val
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param val A value
|
||||
-- @return True if the table contains the value, false otherwise
|
||||
@@ -35,6 +38,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains key k
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param k A key
|
||||
-- @return True if the table contains the key, false otherwise
|
||||
@@ -47,10 +51,11 @@ function DCSEx.table.containsKey(t, k)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains all values in table values
|
||||
-- Returns true if table t contains ALL values from the "values" table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param values A table of values
|
||||
-- @return True if the table contains all values, false otherwise
|
||||
-- @return True if the table contains ALL values, false otherwise
|
||||
-------------------------------------
|
||||
function DCSEx.table.containsAll(t, values)
|
||||
if not t then return false end
|
||||
@@ -65,10 +70,11 @@ function DCSEx.table.containsAll(t, values)
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains at least one value in table values
|
||||
-- Returns true if table t contains AT LEAST ONE value from the "values" table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param values A table of values
|
||||
-- @return True if the table contains at least one value, false otherwise
|
||||
-- @return True if the table contains AT LEAST ONE value, false otherwise
|
||||
-------------------------------------
|
||||
function DCSEx.table.containsAny(t, values)
|
||||
if not t then return false end
|
||||
@@ -82,6 +88,13 @@ function DCSEx.table.containsAny(t, values)
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains ALL keys from the "keys" table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param keys A table of keys
|
||||
-- @return True if the table contains ALL keys, false otherwise
|
||||
-------------------------------------
|
||||
function DCSEx.table.containsAllKeys(t, keys)
|
||||
if not t then return false end
|
||||
|
||||
@@ -94,6 +107,13 @@ function DCSEx.table.containsAllKeys(t, keys)
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if table t contains AT LEAST ONE key from the "keys" table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param values A table of keys
|
||||
-- @return True if the table contains AT LEAST ONE key, false otherwise
|
||||
-------------------------------------
|
||||
function DCSEx.table.containsAnyKeys(t, keys)
|
||||
if not t then return false end
|
||||
|
||||
@@ -108,6 +128,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the number of non-nils elements in a table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @return A number
|
||||
-------------------------------------
|
||||
@@ -122,6 +143,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a deep copy of the table, doesn't work with recursive tables (code from http://lua-users.org/wiki/CopyTable)
|
||||
-------------------------------------
|
||||
-- @param orig A table
|
||||
-- @return A deep copied clone of the table
|
||||
-------------------------------------
|
||||
@@ -142,6 +164,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Dumps the content of a table as a string
|
||||
-------------------------------------
|
||||
-- @param orig A table
|
||||
-- @return A string representaton of the table
|
||||
-------------------------------------
|
||||
@@ -160,6 +183,7 @@ function DCSEx.table.dump(t)
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the key associated to a value in a table, or nil if not found
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @param val A value
|
||||
-- @return The key associated to this value in the table, or nil
|
||||
@@ -173,6 +197,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all the keys in an associative table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @return An array of keys
|
||||
-------------------------------------
|
||||
@@ -191,6 +216,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random value from a numerically-indexed table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @return A random element from the table
|
||||
-------------------------------------
|
||||
@@ -200,6 +226,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns a random index from a numerically-indexed table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @return A random index from the table
|
||||
-------------------------------------
|
||||
@@ -209,6 +236,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Randomly shuffles a numerically-indexed table
|
||||
-------------------------------------
|
||||
-- @param t A table
|
||||
-- @return A table with shuffled values
|
||||
-------------------------------------
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
-- ====================================================================================
|
||||
-- DCSEX.UNITCALLSIGNMAKER - GENERATES CALLSIGNS FOR NEW UNITS
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.unitCallsignMaker = {}
|
||||
|
||||
do
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
-- ====================================================================================
|
||||
-- DCSEX.UNITGROUMAKER - CREATES AND ADDS GROUPS TO THE GAME WORLD
|
||||
--
|
||||
-- DCSEX.UNITGROUPMAKER - CREATES AND ADDS GROUPS TO THE GAME WORLD
|
||||
-- ====================================================================================
|
||||
-- (local) createGroupTable(groupID, groupCategory, options)
|
||||
-- (local) getDefaultUnitSpread(groupCategory)
|
||||
-- (local) getNextGroupID()
|
||||
-- (local) getNextUnitID()
|
||||
-- (local) setAircraftTaskAwacs(groupTable)
|
||||
-- (local) setAircraftTaskCAP(groupTable)
|
||||
-- (local) setAircraftTaskFollow(groupTable, followedGroupID, xyDistance)
|
||||
-- (local) setAircraftTaskOrbit(groupTable, options)
|
||||
-- (local) setCommand(groupTable, actionID, actionValue)
|
||||
-- (local) setOption(groupTable, optionID, optionValue)
|
||||
-- DCSEx.unitGroupMaker.createStatic(side, point2, typeName, shapeName, heading, dead)
|
||||
-- DCSEx.unitGroupMaker.create(coalitionID, groupCategory, vec2, unitTypes, options)
|
||||
-- DCSEx.unitGroupMaker.initialize()
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.unitGroupMaker = {}
|
||||
@@ -18,6 +20,7 @@ DCSEx.unitGroupMaker = {}
|
||||
do
|
||||
local nextGroupID = 1 -- ID of the next generated group
|
||||
local nextUnitID = 1 -- ID of the next generated unit
|
||||
local dataLinkID = 201 -- Next datalink ID
|
||||
|
||||
local function createGroupTable(groupID, groupCategory, options)
|
||||
local groupTable = {
|
||||
@@ -442,9 +445,19 @@ do
|
||||
unitTable.name = unitTable.callsign.name
|
||||
|
||||
-- Special properties for unit
|
||||
unitTable.AddPropAircraft = {}
|
||||
if aircraftDB.properties then
|
||||
unitTable.AddPropAircraft = DCSEx.table.deepCopy(aircraftDB.properties)
|
||||
end
|
||||
-- Setup datalink
|
||||
local datalinkString = tostring(dataLinkID)
|
||||
if #datalinkString == 3 then
|
||||
datalinkString = "00"..datalinkString
|
||||
elseif #datalinkString == 4 then
|
||||
datalinkString = "0"..datalinkString
|
||||
end
|
||||
unitTable.AddPropAircraft["STN_L16"] = datalinkString
|
||||
dataLinkID = dataLinkID + 1
|
||||
|
||||
-- Common payload (fuel, gun ammo, etc)
|
||||
if aircraftDB.payload then
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
-- ====================================================================================
|
||||
-- DCSEX.UNITNAMESMAKER - GENERATE CREDIBLE AND UNIT NAMES FOR UNIT GROUPS
|
||||
-- ====================================================================================
|
||||
DCSEx.unitNamesMaker = {}
|
||||
|
||||
do
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-- ====================================================================================
|
||||
-- WORLDTOOLS - FUNCTIONS RELATED TO THE GAME WORLD
|
||||
-- DCSEX.WORLD - FUNCTIONS RELATED TO THE GAME WORLD
|
||||
-- ====================================================================================
|
||||
-- DCSEx.world.collidesWithScenery(vec2, radius)
|
||||
-- DCSEx.world.findSpawnPoint(vec2, minRadius, maxRadius, surfaceType, radiusWithoutScenery)
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
-- ====================================================================================
|
||||
-- ZONETOOLS - FUNCTIONS RELATED TO MAP TRIGGER ZONES
|
||||
-- DCSEX.ZONES - FUNCTIONS RELATED TO MAP TRIGGER ZONES
|
||||
-- ====================================================================================
|
||||
-- DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawName, readonly)
|
||||
-- DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawName, readOnly)
|
||||
-- DCSEx.zones.getAll()
|
||||
-- DCSEx.zones.getByName(name)
|
||||
-- DCSEx.zones.getCenter(zoneTable)
|
||||
-- DCSEx.zones.getProperty(zoneTable, propertyName)
|
||||
-- DCSEx.zones.getProperty(zoneTable, propertyName, defaultValue)
|
||||
-- DCSEx.zones.getPropertyBoolean(zoneTable, propertyName, defaultValue)
|
||||
-- DCSEx.zones.getPropertyFloat(zoneTable, propertyName, defaultValue, min, max)
|
||||
-- DCSEx.zones.getPropertyInt(zoneTable, propertyName, defaultValue, min, max)
|
||||
-- DCSEx.zones.getPropertyParse(zoneTable, propertyName, stringTable, valueTable, defaultValue)
|
||||
-- DCSEx.zones.getPropertyTable(zoneTable, propertyName)
|
||||
-- DCSEx.zones.getRadius(zoneTable, useMaxForQuads)
|
||||
-- DCSEx.zones.getRandomPointInside(zoneTable, surfaceType)
|
||||
-- DCSEx.zones.getSurfaceArea(zoneTable)
|
||||
-- DCSEx.zones.isPointInside(zoneTable, point)
|
||||
-- ====================================================================================
|
||||
|
||||
DCSEx.zones = { }
|
||||
|
||||
-- TODO: function description
|
||||
-------------------------------------
|
||||
-- Draws a zone on the F10, visible for all players
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone to draw
|
||||
-- @param lineColor Line color as a RGBA table
|
||||
-- @param fillColor Fill color as a RGBA table
|
||||
-- @param lineType Type of line from the DCSEx.enums.lineType enum
|
||||
-- @param drawName Should the name of the zone be drawn too (default: false)
|
||||
-- @param drawName Should the zone marker be read only? (default: true)
|
||||
-------------------------------------
|
||||
function DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawName, readOnly)
|
||||
drawName = drawName or false
|
||||
readOnly = readOnly or true
|
||||
@@ -64,6 +74,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all trigger zones
|
||||
-------------------------------------
|
||||
-- @return Table of zones
|
||||
-------------------------------------
|
||||
function DCSEx.zones.getAll()
|
||||
@@ -79,6 +90,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Finds and return a trigger zone by a certain name
|
||||
-------------------------------------
|
||||
-- @param name Case-insensitive name of the zone
|
||||
-- @return Zone table or nil if no zone with this name was found
|
||||
-------------------------------------
|
||||
@@ -100,6 +112,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the center of a zone
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by TMMissionData.getZones() or TMMissionData.getZoneByName(name)
|
||||
-- @return A vec2
|
||||
-------------------------------------
|
||||
@@ -119,6 +132,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the value of the property of a trigger zone, as a string
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @return The value of the property or nil if it doesn't exist
|
||||
@@ -141,6 +155,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the value of the property of a trigger zone, parsed against a case-insensitive table of strings
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @param defaultValue Default value to return if no match was found
|
||||
@@ -157,6 +172,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the value of the property of a trigger zone, as a float
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @param defaultValue Default value to return if no match was found
|
||||
@@ -174,6 +190,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the value of the property of a trigger zone, as an integer
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @param defaultValue Default value to return if no match was found
|
||||
@@ -189,6 +206,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Gets the value of a property of a trigger zone and parse it according to two correspondance tables
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @param stringTable A table of strings
|
||||
@@ -211,6 +229,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the value of the property of a trigger zone, as a table of comma-separated lowercase strings
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param propertyName Case-insensitive name of the property
|
||||
-- @return An table
|
||||
@@ -223,6 +242,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the radius of a zone, in meter
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by DCSEx.zones.getAll() or DCSEx.zones.getByName(name)
|
||||
-- @param useMaxForQuads If true, return largest distance between the center and a vertex. If false (default value), returns the mean distance. Only used if the zone is a quad.
|
||||
-- @return An table
|
||||
@@ -271,6 +291,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns the surface area of a zone
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by TMMissionData.getZones() or TMMissionData.getZoneByName(name)
|
||||
-- @return A number, in squared meters
|
||||
-------------------------------------
|
||||
@@ -289,6 +310,7 @@ end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns true if a point is inside a zone
|
||||
-------------------------------------
|
||||
-- @param zoneTable The zone table, returned by TMMissionData.getZones() or TMMissionData.getZoneByName(name)
|
||||
-- @param point A point, as a vec3 or vec2
|
||||
-- @return True if the point is inside the zone, false otherwise
|
||||
|
||||
@@ -561,7 +561,7 @@ Library.aircraft = {
|
||||
}
|
||||
},
|
||||
["A-50"] = {
|
||||
["altitude"] = 4898,
|
||||
["altitude"] = 11000,
|
||||
["speed"] = 220,
|
||||
["payload"] = {
|
||||
["chaff"] = 192,
|
||||
@@ -2460,7 +2460,7 @@ Library.aircraft = {
|
||||
["pylons"] = {}
|
||||
},
|
||||
["E-2C"] = {
|
||||
["altitude"] = 4510,
|
||||
["altitude"] = 9000,
|
||||
["speed"] = 133.3,
|
||||
["payload"] = {
|
||||
["chaff"] = 120,
|
||||
@@ -2479,7 +2479,7 @@ Library.aircraft = {
|
||||
["pylons"] = {}
|
||||
},
|
||||
["E-3A"] = {
|
||||
["altitude"] = 4800,
|
||||
["altitude"] = 11000,
|
||||
["speed"] = 220,
|
||||
["payload"] = {
|
||||
["chaff"] = 120,
|
||||
@@ -7567,7 +7567,7 @@ Library.aircraft = {
|
||||
}
|
||||
},
|
||||
["KJ-2000"] = {
|
||||
["altitude"] = 4898,
|
||||
["altitude"] = 11000,
|
||||
["speed"] = 220,
|
||||
["payload"] = {
|
||||
["fuel"] = 70000,
|
||||
|
||||
@@ -132,7 +132,7 @@ do
|
||||
groupInfo.unitsID = { DCSEx.unitGroupMaker.createStatic(TUM.settings.getEnemyCoalition(), objective.point2, units[1], "") }
|
||||
end
|
||||
else
|
||||
groupInfo = DCSEx.unitGroupMaker.create(TUM.settings.getEnemyCoalition(), DCSEx.dcs.getUnitTypeFromFamily(objectiveDB.targetFamilies[1]), objective.point2, units, groupOptions)
|
||||
groupInfo = DCSEx.unitGroupMaker.create(TUM.settings.getEnemyCoalition(), DCSEx.dcs.getUnitCategoryFromFamily(objectiveDB.targetFamilies[1]), objective.point2, units, groupOptions)
|
||||
end
|
||||
|
||||
if not groupInfo then
|
||||
|
||||
@@ -53,12 +53,10 @@ do
|
||||
[TUM.settings.id.TARGET_COUNT] = { "1", "2", "3", "4" },
|
||||
[TUM.settings.id.TARGET_LOCATION] = { },
|
||||
[TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Interception", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TIME_PERIOD] = { "World War 2", "Korea War", "Vietnam War", "Late Cold War", "Modern" }, -- Must match values in the DCSEx.enums.timePeriod enum
|
||||
[TUM.settings.id.TIME_PERIOD] = { "World War 2", "Korea War", "Vietnam War", "Late Cold War", "Gulf war", "Modern" }, -- Must match values in the DCSEx.enums.timePeriod enum
|
||||
[TUM.settings.id.WINGMEN] = { "None", "1", "2", "3" }
|
||||
}
|
||||
|
||||
local targetLocation
|
||||
|
||||
local function getFaction(side)
|
||||
if side == coalition.side.BLUE then
|
||||
return TUM.settings.getValue(TUM.settings.id.COALITION_BLUE, true)
|
||||
@@ -83,18 +81,20 @@ do
|
||||
[TUM.settings.id.WINGMEN] = 2
|
||||
}
|
||||
|
||||
-- TODO: set default time period according to mission year
|
||||
-- TODO: enable WW2
|
||||
-- if env.mission.date.Year <= 1945 then
|
||||
-- settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.WORLD_WAR_2
|
||||
-- elseif env.mission.date.Year < 1960 then
|
||||
-- settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.KOREA_WAR
|
||||
-- elseif env.mission.date.Year < 1975 then
|
||||
-- settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.VIETNAM_WAR
|
||||
-- elseif env.mission.date.Year < 1990 then
|
||||
-- settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.COLD_WAR
|
||||
-- else
|
||||
-- settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.MODERN
|
||||
-- end
|
||||
if env.mission.date.Year < 1960 then
|
||||
settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.KOREA_WAR
|
||||
elseif env.mission.date.Year < 1975 then
|
||||
settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.VIETNAM_WAR
|
||||
elseif env.mission.date.Year < 1990 then
|
||||
settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.COLD_WAR
|
||||
elseif env.mission.date.Year < 2000 then
|
||||
settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.GULF_WAR
|
||||
else
|
||||
settings[TUM.settings.id.TIME_PERIOD] = DCSEx.enums.timePeriod.MODERN
|
||||
end
|
||||
|
||||
for i,id in pairs(SETTING_VALUES[TUM.settings.id.COALITION_BLUE]) do
|
||||
if id == Library.factions.defaults[coalition.side.BLUE] then settings[TUM.settings.id.COALITION_BLUE] = i end
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
<div style="text-align:center">
|
||||
<img style="width:100%" src="docs/logo.png" alt="The Universal Mission for DCS World" />
|
||||
<p class="heavy" style="font-size:175%;">
|
||||
User's manual
|
||||
</p>
|
||||
<p class="heavy">
|
||||
The Universal Mission v0.2.250729<br />
|
||||
Created and maintained by Ambroise Garel (<a href='mailto:akaagarmail@gmail.com'>akaagarmail@gmail.com</a>)
|
||||
</p>
|
||||
<p class="heavy">
|
||||
<a href='https://github.com/akaAgar/the-universal-mission-for-dcs-world'>github.com/akaAgar/the-universal-mission-for-dcs-world</a><br />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<h2>Table of contents</h2>
|
||||
<ul>
|
||||
<li><a href="#page_welcome">Welcome to <em>The Universal Mission</em></a></li>
|
||||
<li><a href="#page_howtoplay">How to use/play The Universal Mission?</a></li>
|
||||
<li><a href="#page_menumission">Using the mission menu</a></li>
|
||||
<li><a href="#page_advancedstuff">Advanced stuff you may want to try</a></li>
|
||||
<li><a href="#page_multiplayer">A few notes regarding multiplayer</a></li>
|
||||
</ul>
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<div id="page_welcome"></div>
|
||||
<h2>Welcome to <em>The Universal Mission</em></h2>
|
||||
|
||||
_The Universal Mission for DCS World_ is an attempt to create a fully dynamic single-player/PvE mission giving access to the whole content of DCS World in a structure similar to the one found in old "simulators", like the early Microprose games (think F-117 or the Strike Eagle serie).
|
||||
|
||||
These game had both fun and clear objectives, endless replayability and a career system that made sure that something was at stake: crash and die, and you'll lose all these hard-earned medals.
|
||||
|
||||
As the original creator of [_Briefing Room for DCS World_](https://github.com/DCS-BR-Tools/briefing-room-for-dcs) (now maintained by the talented John Harvey), I've always wanted to create an easy-to-use, enticing and fun mission generator for DCS, capable of creating CPU-light missions without requiring an external program.
|
||||
|
||||
I think _The Universal Mission_ is, finally, the proper way to approach this problem. The current version is still an early beta but most core features are already working.
|
||||
|
||||
I hope you'll like it.
|
||||
|
||||
<h3>Features</h3>
|
||||
|
||||
- Can generate any kind of mission: ground attack, interception, strike, airbase attack, CAS, CAP, and more
|
||||
- Completely dynamic, no two missions are ever the same
|
||||
- Entirely self-contained inside a .miz file, no need for any external program
|
||||
- More than 300 voiced radio messages for immersive and realistic coms
|
||||
- Supports both single-player and small-scale PvE on closed servers
|
||||
- Persistent single player career mode, with awards and promotions. Dying won't reset your progress, but you have to come back to base alive for your kills and completed objectives to be saved to your profile, so watch out for SAMs on your way home
|
||||
- All new AI wingman system, smarter and more immersive than DCS's original wingmen
|
||||
- Uses advanced DCS World scripting functionalities (like the brand new Disposition singleton and net.dostring_in hacks) to achieve effects seldom seen in other scripts, such as graphic overlays and random but realistic placement of units in cities and forests without the use of handmade spawn points
|
||||
- Various little details to make the DCS World more alive, like crew running away from destroyed vehicles
|
||||
|
||||
<h3>Limitations of current beta version</h3>
|
||||
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- Germany support will come soon, others will follow later
|
||||
- Not all mission types are supported yet
|
||||
- Career progress may be lost because of future updates, don't get too attached to it
|
||||
|
||||
<h3>Known bugs</h3>
|
||||
- AWACS datalink info is now displayed on SA pages
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<div id="page_howtoplay"></div>
|
||||
<h2>How to use/play The Universal Mission?</h2>
|
||||
|
||||
<h3>First setup</h3>
|
||||
|
||||
- Download the latest release from this GitHub page.
|
||||
- Copy the provided autoexec.cfg file to your **[Saved Games]\DCS\Config directory**
|
||||
- Please note: as of DCS 2.9.18.12899, it seems the autoexec.cfg file [is no longer needed](https://www.digitalcombatsimulator.com/en/news/changelog/release/2.9.18.12899/) but I advise you to copy it anyway, ED might change its mind again.
|
||||
- Copy the .miz files for your theater(s) of choice to your **[Saved Games]\DCS\Missions directory**
|
||||
- _**(Optional but strongly recommended)**_ Unsanitize the Lua IO module. You don't have to do this, but the persistent career system won't work if you don't. To do it, open the file **[DCS World installation directory]\Scripts\MissionScripting.lua** with a text editor and comment or remove the line "sanitizeModule('io')". Make sure you restart DCS World once you've modified the file.
|
||||
- Please note: should you want to backup, delete or transfer it, career progress is saved in **[DCS World installation directory]\TheUniversalMission.sav**
|
||||
|
||||
<h3>Customizing the mission to your taste</h3>
|
||||
|
||||
- _**(Optional but you'll probably want to do it)**_ Open the .miz file in the DCS World mission editor and change the player unit to pick your desired aircraft. The default player unit is a Su-25T (as it is the only free DCS airplane equipped with weapons) and you probably won't want to stick with it.
|
||||
|
||||
Please refer to the "Advanced stuff you may want to try" section to learn all the ways you can customize The Universal Mission.
|
||||
|
||||
<h3>Starting the mission</h3>
|
||||
|
||||
- Launch the mission from the mission editor or the "Mission" selection in the main DCS World menu
|
||||
- You are now on the ramp or runway. Open the communication menu (see "Using the mission menu" below) and navigate to the F10/Other menu. From there, you can view and change mission settings. They include:
|
||||
- Who belong to the blue and red coalitions
|
||||
- The type of mission
|
||||
- The number and location of targets (you can use the F10 map to see where the available target zones are located).
|
||||
- The amount of enemy air force and air defense. The higher these settings, the more XP you'll recieve upon completion of a single-player mission
|
||||
- When you're ready, pick the "Begin mission" option, wait a few seconds (precaching all the game assets can take some time, especially if you have a slow CPU), you're ready to go!
|
||||
- Use the F10 mission and check the F10 map for additional information about the mission (see "Using the mission menu" below). Don't forget to come back to base alive, all awarded XP and completed objectives will only be saved to your pilot profile once you've landed
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<div id="page_menumission"></div>
|
||||
<h2>Using the mission menu</h2>
|
||||
|
||||
Most features of The Universal Mission require the use of the "F10. Other" menu. To access it, press the "Communication menu" key (check the key bindings), navigate to the root menu by pressing F11 ("Previous menu") if need, then press "F10" to access the "Other" menu.
|
||||
The exact content of the menu will depend on the current phase of the mission.
|
||||
|
||||
<h3>On startup/when no mission is active</h3>
|
||||
|
||||
- **Display mission settings**: Displays the current mission settings, that will be applied if you choose to start the mission now.
|
||||
- **Change mission settings**: Allows you to change the mission settings to your taste.
|
||||
- **Blue coalition**: Who is the blue coalition? Determines the type of units that will be spawned. Available factions (e.g. NATO) depend on the missions's time period and theater.
|
||||
- **Red coalition**: Who is the red coalition? Determines the type of units that will be spawned. Available factions (e.g. USSR) depend on the missions's time period and theater.
|
||||
- **Mission type**: What will your mission be?
|
||||
- **Antiship strike**: Sink enemy warships and cargo ships.
|
||||
- **Ground attack**: Interdiction missions against armor, artillery and convoys.
|
||||
- **Interception**: Shoot down strategic airplanes (bombers, transports...) and enemy attack planes on interdiction missions.
|
||||
- **SEAD**: Destroy enemy SAM sites.
|
||||
- **Strike**: Destroy enemy structures and civilian buildings occupied by enemy forces.
|
||||
- **Target location**: Where on the map will the targets be spawned? Approximate distance to possible regions is displayed in the menu.
|
||||
- Missions taking place in enemy territory award 30% more XP to account for increased SAM threat and proximity of enemy airbases.
|
||||
- Make sure to pick a region not too far away from your starting location if you don't like long ingresses.
|
||||
- Picking a region very close to your starting location (for instance, the one where your airbase is located in) can also be a bad idea, as you might takeoff in range of an enemy SAM.
|
||||
- Be aware that targets of antiship strikes will always be spawned in open seas, which can be quite far if you picked a landlocked target zone.
|
||||
- **Target count**: How many objectives will be spawned. More objectives means potentially more xp in a single sortie, so better medals, but also more work and more risk. Be aware that you can RTB to rearm/refuel at any time between objectives, but you won't accumulate as many single-sortie XP as if you complete objectives without going back to base, because XP is awarded to your profile and reset each time you land.
|
||||
- **Enemy air defense**: Amount, quality and skill of enemy surface-to-air units (AAA, MANPADS and SAM). A higher setting awards more XP.
|
||||
- **Enemy air force**: Amount, quality and skill of enemy combat air patrols. A higher setting awards more XP.
|
||||
- **Wingmen count**: How many wingmen will fly by your side (from zero to three). A small XP penalty is added for each additional wingman. Wingman won't get replaced if they get shot during a mission, but they will (with full payload) each time you land and takeoff again. Only shown in single-player missions.
|
||||
- **Friendly AI CAP**: Should AI fighter aicraft be spawned regularly to patrol the AO and shoot down potential threats? Disabling this option will award you more XP (only if "Enemy air force" is not set to "None") but also means you and your wingmen will be alone against the whole enemy air force.
|
||||
- **View pilot career stats**: Displays a list of your achievements, as well as your medal case. Only available when playing single-player missions and if the Lua IO module has been unsanitized (see "First setup" above)
|
||||
- **Begin mission**: Starts a mission with the current settings.
|
||||
|
||||
<h3>Other parameters</h3>
|
||||
|
||||
- _(Not yet implemented in this version)_ By changing the year in mission time parameters, the time period will be changed accordingly and the proper factions and AI units will be spawned during the mission. Time periods are:
|
||||
- 1945 and before: World War 2
|
||||
- 1946-1959: Korea War
|
||||
- 1960-1974: Vietnam War
|
||||
- 1975-1989: Late Cold War
|
||||
- 1990-now: Modern
|
||||
- _(Not yet implemented in this version)_ Changing the weather to make it more cloudy or windy, or setting the mission to nighttime, will make the mission more difficult but also award more points.
|
||||
|
||||
<h3>During the mission</h3>
|
||||
|
||||
- **Mission status**: Displays a summary of the mission's status (list of objectives and progress on each objective).
|
||||
- **Objectives**: Displays a list of special commands related to each of the mission's objectives. Be aware that some objectives may have no special commands associated with them.
|
||||
- **Smoke marker on target**: Asks for a friendly JTAC to pop a smoke marker on the target. Makes finding the target easier, but will cost you a small XP penalty. Only available for missions where a JTAC is available (it's pretty hard to throw a smoke grenade at an airplane or a ship in the middle of the sea).
|
||||
- **Navigation**: Displays a list of commands related to navigational assistance.
|
||||
- **Navigation to objective [OBJECTIVE NAME]**: Displays the coordinates of the objective, its BRA ("fly X for Y") relative to the player's position and an estimated flight time and ETA. Some objectives types (e.g. strike missions) are provided with exact coordinates, but most will only have approximate coordiantes, so you'll have to search for targets yourself once in the objective area.
|
||||
- **Flight**: Displays a list of commands for your wingmen. Only shown in single-player missions and if wingmen are available for this mission.
|
||||
- **Cover me!**: Tasks your wingmen to immediately engage any nearby air threats.
|
||||
- **Engage**: Tasks your wingmen to engage a certain type of targets. Targets must be detected by your wingmen (see "Report contacts" below), or they won't be able to engage them.
|
||||
- **Report contacts**: Asks your wingmen for a list of all detected contacts. According to range and sensors capabilities, their reports can go from perfect ID (e.g. "Su-27") to very generic descriptions (e.g. "fighter" or even "aircraft")
|
||||
- **Hold position**: Tasks your wingmen to orbit at their current position. All other tasking will be aborted.
|
||||
- **Change altitude**: Asks your wingmen to change their altitude. This altitude will be employed when attacking on orbiting but not when rejoining/forming up with you (in that case, they'll match your altitude).
|
||||
- **Status report**: Asks your wingmen for a complete report (damage sustained, fuel status, available payload).
|
||||
- **Rejoin**: Asks your wingmen to rejoin and follow you. All other tasking will be aborted. This is the default tasking when wingmen take off and when they complete another task.
|
||||
- **AWACS**: Displays a list of commands for the AWACS. Only shown if an AWACS aircraft is available for this mission.
|
||||
- **Bogey dope**: Asks for the nearest enemy air threat
|
||||
- **Picture**: Asks for a summary of all detected enemy aircraft
|
||||
- **Display mission score**: Displays the number of XP gained and objectives completed since your last takeoff. They will be added to your flight log (and any promotions/medals be awarded) the next time you land. If you crash, eject or abort the mission, all currently "stowed" XP and objectives will be lost. Only available when playing single-player missions and if the Lua IO module has been unsanitized (see "First setup" above)
|
||||
- **Abort mission**: Aborts the current mission and forfeit all XP/objectives gained since last landing. The game will ask for confirmation so you don't select this option by mistake.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<div id="page_advancedstuff"></div>
|
||||
<h2>Advanced stuff you may want to try</h2>
|
||||
|
||||
The Universal Mission is designed to be easily editable to suit your preferences. Here are a few things you could do after opening the .miz file in DCS World's mission editor.
|
||||
|
||||
<h3>Player aircraft</h3>
|
||||
|
||||
- Change the player aircraft starting condition (runway, parking or parking hot). Air starts are not recommended as all players must be on the ground to begin a new mission
|
||||
- Move it to another airbase, change its coalition (make sure blue players are spawned on an airbase located in a BLUFOR zone are red players are spawned on an airbase located in a REDFOR zone)
|
||||
- You may also add an aircraft carrier or a FARP for the player to take off from
|
||||
- Change its default loadout if you plan to play a specific kind of mission and don't want to lose time asking the ground crew to rearm your aircraft (e.g. if you know you want to play SEAD missions, you may as well stock up on AGM-88s)
|
||||
- Change the skill level from "Player" to "Client" and add other aircraft to create a multiplayer mission to play with your friends. Keep in mind that the persistent career/player stats system will be disabled in multiplayer missions and that all player aircraft must belong to the same coalition (TUM does not support PvP)
|
||||
|
||||
<h3>Zones</h3>
|
||||
|
||||
- All zones whose names starts with BLUFOR or REDFOR decide the territory (and airbases) controlled by the blue and red coalitions
|
||||
- Be aware that any change to the airbases coalitions will be superseded by the BLUFOR and REFOR zones
|
||||
- All zones whose names starts with WATER are seas, used to spawn ships
|
||||
- Zones with a name not starting with BLUFOR, REDFOR or WATER are target zones. These are zones where objectives can be spawned, who can be selected in the "objective location" setting of the intermission F10 menu
|
||||
- Change, add or remove zones to create new possible target areas. A maximum of 10 target areas can be created, so they fit the F10 menu
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
<!------------------------- NEW PAGE ------------------------->
|
||||
|
||||
<div id="page_multiplayer"></div>
|
||||
<h2>A few notes regarding multiplayer</h2>
|
||||
|
||||
While The Universal Mission supports multiplayer and is perfectely suitable (and fun!) for playing with friends on a private server, it is **absolutely not suited for public servers** as missions settings can be edited by anyone at any time Using the mission menu.
|
||||
Please also note that PvP is not supported at the moment and that the mission will not launch if both coalitions have player slots.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,35 @@
|
||||
html,
|
||||
body {
|
||||
background-color: white;
|
||||
color: black;
|
||||
font-family: Garamond, Georgia, "Times New Roman", Times, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-weight: bold;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
background-color: dimgray;
|
||||
color: white;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-weight: bold;
|
||||
padding: 0.2rem;
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
color: dimgray;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted dimgray;
|
||||
}
|
||||
|
||||
.heavy {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
Reference in New Issue
Block a user