Resolved conflicts

This commit is contained in:
PeekabooSteam 2023-04-09 09:54:21 +01:00
commit 7605dd26ff
44 changed files with 3106 additions and 478 deletions

View File

@ -2,6 +2,7 @@ var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var fs = require('fs');
var atcRouter = require('./routes/api/atc');
var indexRouter = require('./routes/index');
@ -23,12 +24,14 @@ app.use('/uikit', uikitRouter);
app.set('view engine', 'ejs');
let rawdata = fs.readFileSync('../olympus.json');
let config = JSON.parse(rawdata);
app.get('/config', (req, res) => res.send(config));
module.exports = app;
const DemoDataGenerator = require('./demo.js');
var demoDataGenerator = new DemoDataGenerator(10);
app.get('/demo/units', (req, res) => demoDataGenerator.units(req, res));
app.get('/demo/logs', (req, res) => demoDataGenerator.logs(req, res));
app.get('/demo/bullseyes', (req, res) => demoDataGenerator.bullseyes(req, res));

View File

@ -625,6 +625,7 @@ class DemoDataGenerator {
units(req, res){
var ret = this.demoUnits;
ret.time = Date.now();
res.send(JSON.stringify(ret));
};

View File

@ -1,12 +1,12 @@
{
"name": "DCSOlympus",
"version": "0.1.0-alpha",
"version": "0.1.1-alpha",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "DCSOlympus",
"version": "0.1.0-alpha",
"version": "0.1.1-alpha",
"dependencies": {
"@types/geojson": "^7946.0.10",
"@types/leaflet": "^1.9.0",

View File

@ -2,7 +2,7 @@
"name": "DCSOlympus",
"node-main": "./bin/www",
"main": "http://localhost:3000",
"version": "0.1.0-alpha",
"version": "0.1.1-alpha",
"private": true,
"scripts": {
"copy": "copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet.css",

View File

@ -5,7 +5,7 @@
position: absolute;
row-gap: 5px;
width: 230px;
z-index: 1000;
z-index: 9999;
}
#aircraft-spawn-menu {

View File

@ -77,6 +77,23 @@ form > div {
}
.ol-scrollable::-webkit-scrollbar {
width: 10px;
}
.ol-scrollable::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 100px;
}
.ol-scrollable::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
}
.ol-panel {
background-color: var(--background-steel);
border-radius: 15px;
@ -146,8 +163,9 @@ form > div {
}
.ol-select>.ol-select-options {
position: absolute;
border-radius: var( --border-radius-md );
overflow: hidden;
position: absolute;
max-height: 0;
translate: 0 -2px;
z-index: 1000;
@ -164,9 +182,15 @@ form > div {
overflow-y: auto;
padding: 8px 0;
min-width: 100%;
z-index:9999;
}
.ol-select.is-open[data-position="top"] > .ol-select-options {
top:0;
translate:0 -100%;
}
.ol-select>.ol-select-options > div {
@ -214,22 +238,6 @@ form > div {
text-decoration: underline;
}
.ol-select>.ol-select-options::-webkit-scrollbar {
width: 10px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 100px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
}
.ol-panel-list {
border-radius: var(--border-radius-sm);
@ -663,101 +671,93 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
}
#roe-buttons-container button::before, #reaction-to-threat-buttons-container button::before {
background-position:center;
background-repeat: no-repeat;
background-size:16px 16px;
content: "";
display:block;
height:16px;
width:16px;
height:24px;
width:24px;
}
#roe-buttons-container button[title="Free"]::before {
background-image: url( "/themes/olympus/images/icons_roe_free_light.svg");
}
#roe-buttons-container button[title="Designated free"]::before {
#roe-buttons-container button[title="Hold"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
}
#roe-buttons-container button[title="Designated"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
#roe-buttons-container button[title="Hold"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
}
/**/
#roe-buttons-container button[title="Return"]::before {
background-image: url( "/themes/olympus/images/icons_roe_defend_light.svg");
}
#roe-buttons-container button[title="Return"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_defend_dark.svg");
}
/**/
#roe-buttons-container button[title="Designated"]::before {
background-image: url( "/themes/olympus/images/icons_roe_target_light.svg");
}
#roe-buttons-container button[title="Hold"]::before {
background-image: url( "/themes/olympus/images/icons_actions_nothing_light.svg");
#roe-buttons-container button[title="Designated"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_target_dark.svg");
}
/**/
#roe-buttons-container button[title="Free"]::before {
background-image: url( "/themes/olympus/images/icons_roe_free_light.svg");
}
#roe-buttons-container button[title="Free"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_free_dark.svg");
}
#roe-buttons-container button[title="Designated free"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
}
#roe-buttons-container button[title="Designated"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
}
#roe-buttons-container button[title="Return"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_target_dark.svg");
}
#roe-buttons-container button[title="Hold"].selected::before {
background-image: url( "/themes/olympus/images/icons_actions_nothing_dark.svg");
}
/****************************************************************************************/
#reaction-to-threat-buttons-container button[title="None"]::before {
background-image: url( "/themes/olympus/images/icons_actions_nothing_light.svg");
background-image: url( "/themes/olympus/images/icons_threat_nothing_light.svg");
}
#reaction-to-threat-buttons-container button[title="Passive"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
}
#reaction-to-threat-buttons-container button[title="Evade"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
}
#reaction-to-threat-buttons-container button[title="Escape"]::before {
background-image: url( "/themes/olympus/images/icons_threat_retreat_light.svg");
}
#reaction-to-threat-buttons-container button[title="Abort"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
}
#reaction-to-threat-buttons-container button[title="None"]::before {
background-image: url( "/themes/olympus/images/icons_actions_nothing_light.svg");
}
#reaction-to-threat-buttons-container button[title="None"].selected::before {
background-image: url( "/themes/olympus/images/icons_actions_nothing_dark.svg");
background-image: url( "/themes/olympus/images/icons_threat_nothing_dark.svg");
}
/**/
#reaction-to-threat-buttons-container button[title="Passive"]::before {
background-image: url( "/themes/olympus/images/icons_threat_cms_light.svg");
}
#reaction-to-threat-buttons-container button[title="Passive"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
background-image: url( "/themes/olympus/images/icons_threat_cms_dark.svg");
}
/**/
#reaction-to-threat-buttons-container button[title="Evade"]::before {
background-image: url( "/themes/olympus/images/icons_threat_defend_light.svg");
}
#reaction-to-threat-buttons-container button[title="Evade"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
background-image: url( "/themes/olympus/images/icons_threat_defend_dark.svg");
}
#reaction-to-threat-buttons-container button[title="Escape"].selected::before {
background-image: url( "/themes/olympus/images/icons_threat_retreat_dark.svg");
}
#reaction-to-threat-buttons-container button[title="Abort"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
}
/****************************************************************************************/
#splash-screen {

View File

@ -12,11 +12,17 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
z-index: 1000;
}
#unit-control-panel h3 {
margin-bottom:8px;
}
#unit-control-panel #selected-units-container {
align-items: left;
border-radius: var( --border-radius-md );
display:flex;
flex-direction: column;
max-height: 136px;
overflow-y:auto;
row-gap: 4px;
}
@ -85,5 +91,10 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel h4 {
margin-bottom:8px;
margin-top:20px;
}
#unit-control-panel #threat,
#unit-control-panel #roe {
margin-top:12px;
}

View File

@ -58,7 +58,6 @@
display:flex;
flex-flow: column nowrap;
row-gap: 8px;
text-align: center;
width:45%;
}
@ -67,23 +66,23 @@
align-items: center;
column-gap: 8px;
display:flex;
justify-content: flex-end;
white-space: nowrap;
}
#loadout-items > *::before {
align-items: center;
background-color: var( --secondary-light-grey );
border-radius: 50%;
border-radius: var( --border-radius-sm );
content: attr( data-qty );
display:flex;
font-weight: var( --font-weight-bolder );
justify-content: center;
height:20px;
width:20px;
padding:1px 4px;
}
#loadout-items > *::after {
content: attr( data-item );
width:52px;
}

View File

@ -8,36 +8,61 @@ export class Dropdown {
constructor(ID: string, callback: CallableFunction, options: string[] | null = null)
{
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#defaultValue = this.#value.innerText;
this.#callback = callback;
this.#callback = callback;
if (options != null) {
this.setOptions(options);
}
}
// Do open/close toggle
this.#element.addEventListener("click", ev => {
if ( ev.target instanceof HTMLElement && ev.target.nodeName !== "A" ) {
ev.preventDefault();
}
this.#value.addEventListener( "click", ev => {
ev.stopPropagation();
this.#element.classList.toggle("is-open");
this.#element.classList.toggle( "is-open" );
this.#clip();
});
// Autoclose on mouseleave
this.#element.addEventListener("mouseleave", ev => {
this.#element.classList.remove("is-open");
this.#close();
});
}
#clip() {
const options = this.#options;
const bounds = options.getBoundingClientRect();
this.#element.dataset.position = ( bounds.bottom > window.innerHeight ) ? "top" : "";
}
#close() {
this.#element.classList.remove( "is-open" );
this.#element.dataset.position = "";
}
#open() {
this.#element.classList.add( "is-open" );
}
#toggle() {
if ( this.#element.classList.contains( "is-open" ) ) {
this.#close();
} else {
this.#open();
}
}
setOptions(optionsList: string[])
{
this.#optionsList = optionsList;
@ -47,7 +72,9 @@ export class Dropdown {
button.textContent = option;
div.appendChild(button);
button.addEventListener("click", (e: MouseEvent) => {
e.stopPropagation();
this.#value.innerText = option;
this.#close();
this.#callback( option, e );
});
return div;

View File

@ -168,7 +168,7 @@ export class MapContextMenu extends ContextMenu {
/********* Ground unit spawn menu *********/
#setGroundUnitRole(role: string) {
this.#spawnOptions.role = role;
this.#resetGroundUnitRole();
this.#resetGroundUnitType();
this.#groundUnitTypeDropdown.setOptions(groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label }));
this.#groundUnitTypeDropdown.selectValue(0);
this.clip();

View File

@ -75,7 +75,7 @@ export class Slider {
{
this.#value = newValue;
if (this.#slider != null)
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * 100);
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * parseFloat(this.#slider.max));
this.#onValue()
}
}
@ -120,7 +120,7 @@ export class Slider {
this.#dragged = false;
if (this.#slider != null)
{
this.#value = this.#minValue + parseFloat(this.#slider.value) / 100 * (this.#maxValue - this.#minValue);
this.#value = this.#minValue + parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue);
this.#callback(this.getValue());
}
}

View File

@ -9,8 +9,9 @@ import { AIC } from "./aic/aic";
import { ATC } from "./atc/atc";
import { FeatureSwitches } from "./featureswitches";
import { LogPanel } from "./panels/logpanel";
import { getAirbases, getBullseye as getBullseyes, getMission, getUnits, toggleDemoEnabled } from "./server/server";
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
import { UnitDataTable } from "./units/unitdatatable";
import { keyEventWasInInput } from "./other/utils";
var map: Map;
@ -69,16 +70,33 @@ function setup() {
/* Setup event handlers */
setupEvents();
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
/* Start periodically requesting updates */
startPeriodicUpdate();
getConfig(readConfig)
}
function readConfig(config: any)
{
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined)
{
const address = config["server"]["address"];
const port = config["server"]["port"];
if ((typeof address === 'string' || address instanceof String) && typeof port == 'number')
{
setAddress(window.location.hostname, <number>port);
}
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
/* Start periodically requesting updates */
startPeriodicUpdate();
}
else {
throw new Error('Could not read configuration file!');
}
}
function startPeriodicUpdate() {
requestUpdate();
@ -124,14 +142,16 @@ function checkSessionHash(newSessionHash: string) {
function setupEvents() {
/* Generic clicks */
document.addEventListener("click", (ev) => {
if (ev instanceof PointerEvent && ev.target instanceof HTMLElement) {
if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) {
const target = ev.target;
if (target.classList.contains("olympus-dialog-close")) {
target.closest("div.olympus-dialog")?.classList.add("hide");
}
const triggerElement = target.closest("[data-on-click]");
if (triggerElement instanceof HTMLElement) {
const eventName: string = triggerElement.dataset.onClick || "";
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
@ -148,23 +168,22 @@ function setupEvents() {
/* Keyup events */
document.addEventListener("keyup", ev => {
if ( keyEventWasInInput( ev ) ) {
return;
}
switch (ev.code) {
case "KeyL":
document.body.toggleAttribute("data-hide-labels");
break;
case "KeyD":
toggleDemoEnabled();
break;
case "Minus": // For Veltro's italian layout keyboard, which lacks a quote
case "Quote":
unitDataTable.toggle();
break
}
});
/*

View File

@ -26,6 +26,27 @@ export function ConvertDDToDMS(D: number, lng: boolean) {
}
export function dataPointMap( container:HTMLElement, data:any) {
Object.keys( data ).forEach( ( key ) => {
const val = "" + data[ key ]; // Ensure a string
container.querySelectorAll( `[data-point="${key}"]`).forEach( el => {
// We could probably have options here
if ( el instanceof HTMLInputElement ) {
el.value = val;
} else if ( el instanceof HTMLElement ) {
el.innerText = val;
}
});
});
}
export function deg2rad(deg: number) {
var pi = Math.PI;
return deg * (pi / 180);
@ -48,6 +69,15 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
}
export function keyEventWasInInput( event:KeyboardEvent ) {
const target = event.target;
return ( target instanceof HTMLElement && ( [ "INPUT", "TEXTAREA" ].includes( target.nodeName ) ) );
}
export function rad2deg(rad: number) {
var pi = Math.PI;
return rad / (pi / 180);

View File

@ -36,10 +36,17 @@ export class MouseInfoPanel extends Panel {
var el = <HTMLElement>this.getElement().querySelector(`#bullseye-${idx}`);
if ( el != null ) {
var dist = distance(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
var bear = bearing(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
el.dataset.bearing = zeroAppend(Math.floor(bear), 3);
let bng = zeroAppend(Math.floor(bear), 3);
if ( bng === "000" ) {
bng = "360";
}
el.dataset.bearing = bng;
el.dataset.distance = zeroAppend(Math.floor(dist*0.000539957), 3);
el.dataset.distanceUnits = "NM";
}

View File

@ -11,9 +11,13 @@ export class Panel {
this.#visible = true;
}
protected onHide() {}
hide() {
this.#element.classList.toggle("hide", true);
this.#visible = false;
this.onHide();
}
toggle() {

View File

@ -1,14 +1,18 @@
import { getUnitsManager } from "..";
import { Slider } from "../controls/slider";
import { dataPointMap } from "../other/utils";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { groundUnitsDatabase } from "../units/groundunitsdatabase";
import { Aircraft, GroundUnit, Unit } from "../units/unit";
import { UnitDatabase } from "../units/unitdatabase";
import { UnitsManager } from "../units/unitsmanager";
import { Panel } from "./panel";
const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"];
const reactionsToThreat: string[] = ["None", "Passive", "Evade", "Escape", "Abort"];
// const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"]; // Full list
// const reactionsToThreat: string[] = ["None", "Passive", "Evade", "Escape", "Abort"]; // Full list
const ROEs: string[] = [ "Hold", "Return", "Designated", "Free" ];
const reactionsToThreat: string[] = [ "None", "Passive", "Evade" ];
const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 };
const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 };
const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 };
@ -19,14 +23,23 @@ const altitudeIncrements: { [key: string]: number } = { Aircraft: 2500, Helicopt
export class UnitControlPanel extends Panel {
#altitudeSlider: Slider;
#airspeedSlider: Slider;
#expectedAltitude:number = -1;
#expectedSpeed: number = -1;
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
constructor(ID: string) {
super(ID);
/* Unit control sliders */
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048));
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => {
this.#expectedAltitude = value;
getUnitsManager().selectedUnitsSetAltitude(value * 0.3048)
});
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => {
this.#expectedSpeed = value;
getUnitsManager().selectedUnitsSetSpeed(value / 1.94384)
});
/* Option buttons */
this.#optionButtons["ROE"] = ROEs.map((option: string, index: number) => {
@ -55,6 +68,39 @@ export class UnitControlPanel extends Panel {
this.hide();
}
// Do this after panel is hidden (make sure there's a reset)
protected onHide() {
this.#expectedAltitude = -1;
this.#expectedSpeed = -1;
}
// Update function will only be allowed to update the sliders once it's matched the expected value for the first time (due to lag of Ajax request)
#updateCanSetAltitudeSlider( altitude:number ) {
if ( this.#expectedAltitude < 0 || altitude === this.#expectedAltitude ) {
this.#expectedAltitude = -1;
return true;
}
return false;
}
#updateCanSetSpeedSlider( altitude:number ) {
if ( this.#expectedSpeed < 0 || altitude === this.#expectedSpeed ) {
this.#expectedSpeed = -1;
return true;
}
return false;
}
update() {
var units = getUnitsManager().getSelectedUnits();
if (this.getElement() != null && units.length > 0) {
@ -69,23 +115,13 @@ export class UnitControlPanel extends Panel {
else
database = null; // TODO add databases for other unit types
if (index === 0) {
this.getElement().querySelectorAll(`[data-object|="unit"]`).forEach(marker => {
marker.setAttribute("data-coalition", unit.getMissionData().coalition);
const shortLabel = <HTMLElement>marker.querySelector(".unit-short-label");
if (shortLabel)
shortLabel.innerText = database?.getByName(unit.getBaseData().name)?.shortLabel || "";
});
}
console.log( unit.getBaseData() );
var button = document.createElement("button");
const unitName = <HTMLInputElement>this.getElement().querySelector("#unit-name");
var callsign = aircraftDatabase.getByName(unit.getBaseData().unitName)?.label || "";
var callsign = unit.getBaseData().unitName || "";
button.innerText = "";
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || "");
button.setAttribute("data-callsign", callsign);
unitName.value = callsign;
button.setAttribute("data-coalition", unit.getMissionData().coalition);
button.classList.add("pill", "highlight-coalition")
@ -104,6 +140,7 @@ export class UnitControlPanel extends Panel {
}
}
#showFlightControlSliders(units: Unit[])
{
if (getUnitsManager().getSelectedUnitsType() !== undefined)
@ -132,12 +169,24 @@ export class UnitControlPanel extends Panel {
this.#altitudeSlider.setIncrement(altitudeIncrements[unitsType]);
this.#airspeedSlider.setActive(targetSpeed != undefined);
if (targetSpeed != undefined)
this.#airspeedSlider.setValue(targetSpeed * 1.94384);
if (targetSpeed != undefined) {
targetSpeed *= 1.94384;
if ( this.#updateCanSetSpeedSlider( targetSpeed ) ) {
this.#airspeedSlider.setValue( targetSpeed );
}
}
this.#altitudeSlider.setActive(targetAltitude != undefined);
if (targetAltitude != undefined)
this.#altitudeSlider.setValue(targetAltitude / 0.3048);
if (targetAltitude != undefined) {
targetAltitude /= 0.3048;
if ( this.#updateCanSetAltitudeSlider( targetAltitude ) ) {
this.#altitudeSlider.setValue( targetAltitude );
}
}
}
else {
this.#airspeedSlider.setActive(false);

View File

@ -2,9 +2,8 @@ import * as L from 'leaflet'
import { setConnected } from '..';
import { SpawnOptions } from '../controls/mapcontextmenu';
/* Edit here to change server address */
const REST_ADDRESS = "http://localhost:30000/olympus";
const DEMO_ADDRESS = "http://localhost:3000/demo";
var REST_ADDRESS = "http://localhost:30000/olympus";
var DEMO_ADDRESS = window.location.href + "demo";
const UNITS_URI = "units";
const LOGS_URI = "logs";
const AIRBASES_URI = "airbases";
@ -24,9 +23,14 @@ export function GET(callback: CallableFunction, uri: string){
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}`, true);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
lastUpdateTime = parseInt(data.time);
setConnected(true);
if (parseInt(data.time) > lastUpdateTime)
{
callback(data);
lastUpdateTime = parseInt(data.time);
if (isNaN(lastUpdateTime))
lastUpdateTime = 0;
setConnected(true);
}
};
xmlHttp.onerror = function () {
console.error("An error occurred during the XMLHttpRequest");
@ -45,6 +49,24 @@ export function POST(request: object, callback: CallableFunction){
xhr.send(JSON.stringify(request));
}
export function getConfig(callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", window.location.href + "config", true);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
};
xmlHttp.onerror = function () {
console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file");
};
xmlHttp.send(null);
}
export function setAddress(address: string, port: number) {
REST_ADDRESS = `http://${address}:${port}/olympus`
console.log(`Setting REST address to ${REST_ADDRESS}`)
}
export function getAirbases(callback: CallableFunction) {
GET(callback, AIRBASES_URI);
}

View File

@ -573,6 +573,15 @@ export class GroundUnit extends Unit {
super(ID, data);
}
getMarkerHTML() {
var role = groundUnitsDatabase.getByName(this.getBaseData().name)?.loadouts[0].roles[0];
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
<div class="unit-selected-spotlight"></div>
<div class="unit-marker"></div>
<div class="unit-short-label">${role?.substring(0, 1)?.toUpperCase() || ""}</div>
</div>`
}
getMarkerCategory()
{
// TODO this is very messy

View File

@ -3,11 +3,13 @@ import { getMap, getUnitDataTable } from "..";
import { Unit } from "./unit";
import { cloneUnit } from "../server/server";
import { IDLE, MOVE_UNIT } from "../map/map";
import { keyEventWasInInput } from "../other/utils";
export class UnitsManager {
#units: { [ID: number]: Unit };
#copiedUnits: Unit[];
#selectionEventDisabled: boolean = false;
#pasteDisabled: boolean = false;
constructor() {
this.#units = {};
@ -330,16 +332,21 @@ export class UnitsManager {
pasteUnits()
{
for (let idx in this.#copiedUnits)
if (!this.#pasteDisabled)
{
var unit = this.#copiedUnits[idx];
cloneUnit(unit.ID, getMap().getMouseCoordinates());
for (let idx in this.#copiedUnits)
{
var unit = this.#copiedUnits[idx];
cloneUnit(unit.ID, getMap().getMouseCoordinates());
}
this.#pasteDisabled = true;
setTimeout(() => this.#pasteDisabled = false, 250);
}
}
#onKeyDown(event: KeyboardEvent)
{
if (event.key === "Delete")
if ( !keyEventWasInInput( event ) && event.key === "Delete")
{
this.selectedUnitsDelete();
}

View File

@ -10,13 +10,13 @@
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;600;700;800&display=swap" rel="stylesheet">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z4L2TC3YX0"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Z4L2TC3YX0');
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z4L2TC3YX0"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Z4L2TC3YX0');
</script>
</head>

View File

@ -7,7 +7,7 @@
<div class="ol-select-options">
<div id="olympus-toolbar-summary">
<h3>Olympus</h3>
<div class="accent-green app-version-number">v0.1.0</div>
<div class="accent-green app-version-number">v0.1.1</div>
</div>
<div>
<a href="https://www.discord.com" target="_blank">Discord</a>

View File

@ -982,6 +982,42 @@
</div>
</div>
<div class="example">
<div class="ol-select">
<div class="ol-select-value">
The selected value goes here
</div>
<div class="ol-select-options">
<div>
<button>Option 1</button>
</div>
<div>
<button>Option 2</button>
</div>
</div>
</div>
</div>
<div class="example">
<div class="ol-select" data-position="top">
<div class="ol-select-value">
Options go up
</div>
<div class="ol-select-options">
<div>
<button>Option 1</button>
</div>
<div>
<button>Option 2</button>
</div>
</div>
</div>
</div>
</div>
</div>
@ -991,7 +1027,7 @@
<div class="content-body">
<div class="example">
<div id="airbase-contextmenu" class="ol-panel">
<div id="airbase-contextmenu" class="ol-panel" style="position:relative;">
<h3 id="airbase-name">Al Alhambra</h3>
<dl id="airbase-properties" class="ol-data-grid">
<dt>Runway 1</dt>
@ -1048,6 +1084,46 @@
</div>
<div id="fuel-percentage" data-percentage="45"></div>
<div id="fuel-display">
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="example">
<div id="unit-info-panel" class="ol-panel" style="position:relative;">
<div class="ol-panel-board">
<div id="general" class="panel-section">
<h3 class="unit-name">Olympus 1-1</h3>
<div class="ol-group">
<div class="unit-label">Name</div>
<div class="unit-control">AI Controlled</div>
</div>
<div id="current-task" class="pill highlight-coalition" data-coalition="blue" data-current-task="Awaiting tasking"></div>
</div>
<div id="loadout-container" class="panel-section">
<div id="loadout">
<div id="loadout-silhouette" style="--loadout-background-image:url('/images/units/f-15.png');"></div>
<div id="loadout-items">
<div data-qty="1150" data-item="30mm AP"></div>
<div data-qty="2" data-item="AIM-9M"></div>
<div data-qty="6" data-item="Mk-82"></div>
</div>
</div>
<div id="fuel-percentage" data-percentage="45"></div>
<div id="fuel-display">
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>

View File

@ -1,23 +1,16 @@
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg">
<h3>Selected Units</h3>
<div id="unit-selection">
<div id="unit-identification">
<div data-object="unit-aircraft">
<div class="unit-marker"></div>
<div class="unit-short-label"></div>
</div>
<input id="unit-name" value="" readonly disabled />
<!-- <button id="edit-unit-name" data-on-click="editUnitName"></button> -->
</div>
<div id="selected-units-container" class="ol-scroll">
<div id="selected-units-container" class="ol-scrollable">
<!-- This is where all the unit selection buttons will be shown-->
<!-- <button class="pill highlight-coalition" data-coalition="blue" data-short-label="18">Olympus 1-1</button> -->
</div>
<hr />
<div id="flight-data">
<h4>Flight controls</h4>
<div class="slider-container flight-control-slider" id="airspeed-slider">
@ -52,9 +45,11 @@
</div>
</div>
<h4>Reaction to threat</h4>
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
<!-- This is where the reaction to threat buttons will be shown -->
<div id="threat">
<h4>Reaction to threat</h4>
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
<!-- This is where the reaction to threat buttons will be shown -->
</div>
</div>
<hr />

BIN
img/olympus.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,23 +1,25 @@
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
#define version "v0.1.1-alpha"
[Setup]
AppName=DCS Olympus
AppVerName=DCS Olympus Alpha v0.1.1
AppVerName={#version}
DefaultDirName={usersavedgames}\DCS.openbeta
DefaultGroupName=DCSOlympus
OutputBaseFilename=DCSOlympus
OutputBaseFilename=DCSOlympus_{#version}
UninstallFilesDir={app}\Mods\Services\Olympus
;SetupIconFile="..\img\olympus.ico"
[Tasks]
; NOTE: The following entry contains English phrases ("Create a desktop icon" and "Additional icons"). You are free to translate them into another language if required.
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
;Source: "..\scripts\OlympusExport.lua"; DestDir: "{app}\Scripts"; Flags: ignoreversion
;Source: "..\scripts\OlympusPatcher.exe"; DestDir: "{app}\Scripts"; Flags: ignoreversion
Source: "..\scripts\OlympusHook.lua"; DestDir: "{app}\Scripts\Hooks"; Flags: ignoreversion
Source: "..\olympus.json"; DestDir: "{app}\Mods\Services\Olympus"; Flags: onlyifdoesntexist
Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
Source: "..\scripts\unitPayloads.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
;Source: "..\scripts\OlympusMission.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
@ -30,6 +32,7 @@ Source: "..\client\public\*"; DestDir: "{app}\Mods\Services\Olympus\client\publi
Source: "..\client\routes\*"; DestDir: "{app}\Mods\Services\Olympus\client\routes"; Flags: ignoreversion recursesubdirs;
Source: "..\client\views\*"; DestDir: "{app}\Mods\Services\Olympus\client\views"; Flags: ignoreversion recursesubdirs;
Source: "..\client\*.*"; DestDir: "{app}\Mods\Services\Olympus\client"; Flags: ignoreversion;
Source: "..\img\olympus.ico"; DestDir: "{app}\Mods\Services\Olympus\img"; Flags: ignoreversion;
Source: "{#nwjsFolder}\*.*"; DestDir: "{app}\Mods\Services\Olympus\client"; Flags: ignoreversion recursesubdirs;
[Code]
@ -58,7 +61,7 @@ Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; Value
ChangesEnvironment=yes
[Icons]
Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon
Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus.ico"
;[Run]
;Filename: "{app}\Scripts\OlympusPatcher.exe"; Parameters: "-i"

View File

@ -15,7 +15,7 @@ declare_plugin(self_ID,
shortName = "Olympus",
fileMenuName = "Olympus",
version = "0.1.0-alpha",
version = "0.1.1-alpha",
state = "installed",
developerName= "DCS Refugees 767 squadron",
info = _("DCS Olympus is a mod for DCS World. It allows users to spawn, control, task, group, and remove units from a DCS World server using a real-time map interface, similarly to Real Time Strategy games. The user interface also provides useful informations units, like loadouts, fuel, tasking, and so on. In the future, more features for DCS World GCI and JTAC will be available."),

6
olympus.json Normal file
View File

@ -0,0 +1,6 @@
{
"server": {
"address": "localhost",
"port": 30000
}
}

View File

@ -341,8 +341,13 @@ function Olympus.delete(ID, lat, lng)
Olympus.debug("Olympus.delete " .. ID, 2)
local unit = Olympus.getUnitByID(ID)
if unit then
unit:destroy();
Olympus.debug("Olympus.delete completed successfully", 2)
if unit:getPlayerName() then
trigger.action.explosion(unit:getPoint() , 250 ) --consider replacing with forcibly deslotting the player, however this will work for now
Olympus.debug("Olympus.delete completed successfully", 2)
else
unit:destroy(); --works for AI units not players
Olympus.debug("Olympus.delete completed successfully", 2)
end
end
end
@ -436,40 +441,42 @@ function Olympus.setMissionData(arg, time)
local startIndex = Olympus.groupIndex
local endIndex = startIndex + Olympus.groupStep
local index = 0
for groupName, gp in pairs(mist.DBs.groupsByName) do
index = index + 1
if index > startIndex then
if groupName ~= nil then
local group = Group.getByName(groupName)
if group ~= nil then
local controller = group:getController()
for index, unit in pairs(group:getUnits()) do
local table = {}
table["targets"] = {}
table["targets"]["visual"] = controller:getDetectedTargets(1)
table["targets"]["radar"] = controller:getDetectedTargets(4)
table["targets"]["rwr"] = controller:getDetectedTargets(16)
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
if mist ~= nil and mist.DBs ~= nil and mist.DBs.groupsByName ~= nil then
for groupName, gp in pairs(mist.DBs.groupsByName) do
index = index + 1
if index > startIndex then
if groupName ~= nil then
local group = Group.getByName(groupName)
if group ~= nil then
local controller = group:getController()
for index, unit in pairs(group:getUnits()) do
local table = {}
table["targets"] = {}
table["targets"]["visual"] = controller:getDetectedTargets(1)
table["targets"]["radar"] = controller:getDetectedTargets(4)
table["targets"]["rwr"] = controller:getDetectedTargets(16)
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
table["hasTask"] = controller:hasTask()
table["ammo"] = unit:getAmmo()
table["fuel"] = unit:getFuel()
table["life"] = unit:getLife() / unit:getLife0()
unitsData[unit:getObjectID()] = table
table["hasTask"] = controller:hasTask()
table["ammo"] = unit:getAmmo()
table["fuel"] = unit:getFuel()
table["life"] = unit:getLife() / unit:getLife0()
unitsData[unit:getObjectID()] = table
end
end
end
end
if index >= endIndex then
break
end
end
if index >= endIndex then
break
if index ~= endIndex then
Olympus.groupIndex = 0
else
Olympus.groupIndex = endIndex
end
end
if index ~= endIndex then
Olympus.groupIndex = 0
else
Olympus.groupIndex = endIndex
end
-- Airbases data
local base = world.getAirbases()

View File

@ -1,40 +0,0 @@
local version = 'v0.1.0-alpha'
Olympus = {}
Olympus.OlympusDLL = nil
Olympus.cppRESTDLL = nil
Olympus.DLLsloaded = false
Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\'
log.write('Olympus.EXPORT.LUA', log.INFO, 'Executing OlympusExport.lua')
function Olympus.loadDLLs()
-- Add the .dll paths
package.cpath = package.cpath..';'..Olympus.OlympusModPath..'?.dll;'
local status
log.write('Olympus.HOOKS.LUA', log.INFO, 'Loading olympus.dll from ['..Olympus.OlympusModPath..']')
status, Olympus.OlympusDLL = pcall(require, 'olympus')
if status then
log.write('Olympus.HOOKS.LUA', log.INFO, 'olympus.dll loaded successfully')
return true
else
log.write('Olympus.HOOKS.LUA', log.ERROR, 'Error loading olympus.dll: '..Olympus.OlympusDLL)
return false
end
end
do
if isOlympusModuleInitialized~=true then
local OlympusName = 'Olympus ' .. version .. ' C++ module';
isOlympusModuleInitialized=true;
Olympus.DLLsloaded = Olympus.loadDLLs()
if Olympus.DLLsloaded then
log.write('Olympus.EXPORT.LUA', log.INFO, OlympusName..' successfully loaded.')
else
log.write('Olympus.EXPORT.LUA', log.ERROR, 'Failed to load '..OlympusName)
end
else
log.write('Olympus.EXPORT.LUA', log.INFO, 'olympus.dll already initialized')
end
end

View File

@ -1,4 +1,4 @@
local version = 'v0.1.0-alpha'
local version = 'v0.1.1-alpha'
Olympus = {}
Olympus.OlympusDLL = nil

View File

@ -1,135 +0,0 @@
local version = 'v0.1.0-alpha'
Olympus = {}
Olympus.groupIndex = 0
Olympus.groupStep = 40
function Olympus.notify(message, displayFor)
trigger.action.outText(message, displayFor)
end
function Olympus.setMissionData(arg, time)
local missionData = {}
-- Bullseye data
local bullseyes = {}
for i = 0, 2 do
local bullseyeVec3 = coalition.getMainRefPoint(i)
local bullseyeLatitude, bullseyeLongitude, bullseyeAltitude = coord.LOtoLL(bullseyeVec3)
bullseyes[i] = {}
bullseyes[i]["latitude"] = bullseyeLatitude
bullseyes[i]["longitude"] = bullseyeLongitude
end
-- Units tactical data
local unitsData = {}
local startIndex = Olympus.groupIndex
local endIndex = startIndex + Olympus.groupStep
local index = 0
for groupName, gp in pairs(mist.DBs.groupsByName) do
index = index + 1
if index > startIndex then
if groupName ~= nil then
local group = Group.getByName(groupName)
if group ~= nil then
local controller = group:getController()
for index, unit in pairs(group:getUnits()) do
local table = {}
table["targets"] = {}
table["targets"]["visual"] = controller:getDetectedTargets(1)
table["targets"]["radar"] = controller:getDetectedTargets(4)
table["targets"]["rwr"] = controller:getDetectedTargets(16)
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
table["hasTask"] = controller:hasTask()
table["ammo"] = unit:getAmmo()
table["fuel"] = unit:getFuel()
table["life"] = unit:getLife() / unit:getLife0()
unitsData[unit:getObjectID()] = table
end
end
end
end
if index >= endIndex then
break
end
end
if index ~= endIndex then
Olympus.groupIndex = 0
else
Olympus.groupIndex = endIndex
end
-- Airbases data
local base = world.getAirbases()
local airbases = {}
for i = 1, #base do
local info = {}
local latitude, longitude, altitude = coord.LOtoLL(Airbase.getPoint(base[i]))
info["callsign"] = Airbase.getCallsign(base[i])
local coalitionID = Airbase.getCoalition(base[i])
if coalitionID == 0 then
info["coalition"] = "neutral"
elseif coalitionID == 1 then
info["coalition"] = "red"
else
info["coalition"] = "blue"
end
info["latitude"] = latitude
info["longitude"] = longitude
if Airbase.getUnit(base[i]) then
info["unitId"] = Airbase.getUnit(base[i]):getID()
end
airbases[i] = info
end
local mission = {}
mission.theatre = env.mission.theatre
-- Assemble missionData table
missionData["bullseyes"] = bullseyes
missionData["unitsData"] = unitsData
missionData["airbases"] = airbases
missionData["mission"] = mission
local command = "Olympus.missionData = " .. Olympus.serializeTable(missionData) .. "\n" .. "Olympus.OlympusDLL.setMissionData()"
net.dostring_in("export", command)
return time + 1
end
function Olympus.serializeTable(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then
if type(name) == "number" then
tmp = tmp .. "[" .. name .. "]" .. " = "
else
tmp = tmp .. name .. " = "
end
end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
for k, v in pairs(val) do
tmp = tmp .. Olympus.serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "number" then
tmp = tmp .. tostring(val)
elseif type(val) == "string" then
tmp = tmp .. string.format("%q", val)
elseif type(val) == "boolean" then
tmp = tmp .. (val and "true" or "false")
else
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
end
return tmp
end
timer.scheduleFunction(Olympus.setMissionData, {}, timer.getTime() + 1)
Olympus.notify("OlympusMission " .. version .. " script loaded correctly", 10)

Binary file not shown.

View File

@ -1,42 +0,0 @@
import shutil
import sys
START_STRING = "-- Olympus START\n"
END_STRING = "-- Olympus END\n"
EXPORT_STRING = "local Olympuslfs=require('lfs');dofile(Olympuslfs.writedir()..'Scripts/OlympusExport.lua')\n"
def main(flag):
if flag == "-i":
try:
with open("Export.lua", "r") as f:
shutil.copyfile("Export.lua", "Export.lua.bak")
lines = f.readlines()
if START_STRING in lines:
return
except FileNotFoundError:
print('File does not exist')
with open("Export.lua", "a") as f:
f.writelines(["\n", START_STRING, EXPORT_STRING, END_STRING, "\n"])
elif flag == "-u":
try:
with open("Export.lua", "r") as f:
shutil.copyfile("Export.lua", "Export.lua.bak")
lines = f.readlines()
except FileNotFoundError:
print('File does not exist')
with open("Export.lua", "w") as f:
block = False
for line in lines:
if line == START_STRING:
block = True
if not block:
f.write(line)
if line == END_STRING:
block = False
if __name__ == "__main__":
main(sys.argv[1])

View File

@ -1,44 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['OlympusPatcher.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='OlympusPatcher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

305
scripts/coolEffects.lua Normal file
View File

@ -0,0 +1,305 @@
effects = {}
effects.shooterName = "TestInfantry"
effects.napalmCounter = 1
effects.fireCounter = 1
function effects.notify(message, displayFor)
trigger.action.outText(message, displayFor, false)
end
--------------------------------------------
--------------------------------------------
--------------------------------------------
----NAPALM
function effects.napalmSingle ()
unit = Unit.getByName(effects.shooterName)
local unitPos = unit:getPosition().p
vec3 = mist.utils.makeVec3GL(unitPos)
effects.spawnNapalm (vec3)
end
function effects.spawnNapalm (vec3)
napeName = "napalmStrike" .. effects.napalmCounter
effects.napalmCounter = effects.napalmCounter + 1
mist.dynAddStatic(
{
country = 20,
category = 'Fortifications',
hidden = true,
name = napeName,
type ="Fuel tank",
x = vec3.x,
y = vec3.z,
heading = 0,
} -- end of function
)
timer.scheduleFunction(effects.explode,vec3, timer.getTime() + 0.1)
timer.scheduleFunction(effects.napalam_death,napeName, timer.getTime() + 0.12)
end
function effects.explode(vec3)
trigger.action.explosion(vec3, 10)
end
function effects.napalam_death(staticName) --yes i know bad pun, removes the fuel tank after a set time
StaticObject.getByName(staticName):destroy()
end
--------------------------------------------
--------------------------------------------
--------------------------------------------
----Basic smoke or fire that despawns
function effects.smokeFire ()
unit = Unit.getByName(effects.shooterName)
local unitPos = unit:getPosition().p
vec3 = mist.utils.makeVec3GL(unitPos)
effects.createFire (vec3, 2)
-- 1 = small smoke and fire
-- 2 = medium smoke and fire
-- 3 = large smoke and fire
-- 4 = huge smoke and fire
-- 5 = small smoke
-- 6 = medium smoke
-- 7 = large smoke
-- 8 = huge smoke
end
function effects.createFire (vec3, size)
smokeName = "smokeName" .. effects.fireCounter
effects.fireCounter = effects.fireCounter + 1
trigger.action.effectSmokeBig(vec3 , size , 1, smokeName)
trigger.action.explosion(vec3, 1) -- looks wierd to spawn in on flat land without this
timer.scheduleFunction(effects.removeFire,smokeName, timer.getTime() + 20) --you could set a timer, or if selected give option to despawn later
end
function effects.removeFire (smokeName)
trigger.action.effectSmokeStop(smokeName)
end
--------------------------------------------
--------------------------------------------
--------------------------------------------
----White phosporus secondaries extra effect, like round cooking off
--if you up the number going pop to somewhere in the 200-400 region with a white phosporus impact it would look mental cool
function effects.secondaries ()
unit = Unit.getByName(effects.shooterName)
local unitPos = unit:getPosition().p
vec3 = mist.utils.makeVec3GL(unitPos)
--trigger.action.smoke(vec3 , 2 )
for i = 1,math.random(3,10) do
angle = mist.utils.toRadian((math.random(1,360)))
local randVec = mist.utils.makeVec3GL((mist.getRandPointInCircle(vec3 ,5 , 1 ,0 ,360)))
trigger.action.signalFlare(randVec , 2 , angle )
end
end
--------------------------------------------
--------------------------------------------
--------------------------------------------
----Depth Charges
-- these also make, on land, good dust clouds for a bomb hit in a sandy area?
-- local surface = land.getSurfaceType(mist.utils.makeVec2(unitPos)) -- optional check for water, value 3 or 2
function effects.depthCharge ()
local unit = Unit.getByName(effects.shooterName)
local unitPos = unit:getPosition().p
vec3 = mist.utils.makeVec3GL(unitPos)
vec3.y = vec3.y - 1000
bang = vec3
distance = 20
explosionSize = 2
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
trigger.action.explosion(vec3,explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
trigger.action.explosion(vec3,explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
bang = mist.getRandPointInCircle(vec3 , distance ,1,359,0)
trigger.action.explosion(mist.utils.makeVec3GL(bang),explosionSize)
timer.scheduleFunction(effects.depthChargeMain,vec3, timer.getTime() + 5)
end
function effects.depthChargeMain (vec3)
explosionSize = 250
trigger.action.explosion(vec3,explosionSize)
trigger.action.explosion(vec3,explosionSize)
vec3.x = vec3.x
trigger.action.explosion(vec3,explosionSize)
vec3.x = vec3.x - 10
trigger.action.explosion(vec3,explosionSize)
vec3.z = vec3.z
trigger.action.explosion(vec3,explosionSize)
vec3.z = vec3.z - 10
end
--------------------------------------------
--------------------------------------------
--------------------------------------------
----Normal small explosion
function effects.normalSmallExplosion (vec3)
unit = Unit.getByName(effects.shooterName)
local unitPos = unit:getPosition().p
vec3 = mist.utils.makeVec3GL(unitPos)
trigger.action.explosion(vec3,10)
end
do
longRangeShots = missionCommands.addSubMenu("Effects")
missionCommands.addCommand ("Napalm", longRangeShots, effects.napalmSingle)
missionCommands.addCommand ("Fire or smoke", longRangeShots, effects.smokeFire)
missionCommands.addCommand ("Secondary explosions", longRangeShots, effects.secondaries)
missionCommands.addCommand ("Depth Charge", longRangeShots, effects.depthCharge)
missionCommands.addCommand ("A regular explosion", longRangeShots, effects.normalSmallExplosion)
end
effects.notify("effects.lua ran", 2)

681
scripts/dynamicTanking.lua Normal file
View File

@ -0,0 +1,681 @@
tankers = {}
tankers.tankerName = "TankerClone"
function tankers.notify(message, displayFor)
trigger.action.outText(message, displayFor, false)
end
function tankers.setFrequency(freq)
unit = Unit.getByName(tankers.tankerName)
local controller = unit:getController()
freq = freq or 260 --in MHz, 260 channel 19 is our default tanker thing in refs
SetFrequency = {
id = 'SetFrequency',
params = {
frequency = freq*1000000 , --in Hz
modulation = 0, --AM 0 or FM 1
}
}
controller:setCommand(SetFrequency)
end
function tankers.changeCallsign()
---https://wiki.hoggitworld.com/view/DCS_command_setCallsign
unit = Unit.getByName(tankers.tankerName)
local controller = unit:getController()
SetCallsign = {
id = 'SetCallsign',
params = {
callname = 3, --1 texaco, --2 arco -- 3 shell
number = 1, --1 through 9 valid for tankers only ever 1?
}
}
controller:setCommand(SetCallsign)
end
--remember to only pick valid tacan channel ranges
-- https://wiki.radioreference.com/index.php/Instrument_Landing_System_(ILS)_Frequencies -- what freqs go with which tacans
-- you want the reply channels on the tankers so the fighter tunes the one you want
function tankers.setTacan(channel, xRay)
defaultTac = 40
defaultXray = true
channel = channel or defaultTac -- the channel you want to tell the fighters to enter in, if not provided defaults
xRay = xRay or defaultXray -- X or Y are only options so true or false
unit = Unit.getByName(tankers.tankerName)
local controller = unit:getController()
--tacan maths is easy
--for X ray reply it is, channel + 961, Yankee reply is channel + 1087
if xRay == true then
--to not break everyone elses datalink / tacan 37 and above (X)
if channel > 36 then
freq = channel + 961
ActivateBeacon = {
id = 'ActivateBeacon',
params = {
type = 4,
system = 3,
name = "TKR",
callsign = "ABC", --what shows as a listed word / plays as morese code, 3 max no spaces
frequency = freq*1000000,
}
}
controller:setCommand(ActivateBeacon)
end
elseif xRay == false then
--to not break everyone elses datalink / tacan 30 - 46 (Y) but I don't think the "above" is correct
if channel > 29 then
freq = channel + 1087
ActivateBeacon = {
id = 'ActivateBeacon',
params = {
type = 4,
system = 3,
name = "TKR",
callsign = "ABC", --what shows as a listed word / plays as morese code, 3 max no spaces
frequency = freq*1000000,
}
}
controller:setCommand(ActivateBeacon)
end
end
end
function tankers.dryPlugTanking () -- for whatever reason this ends up being no fuel transfer?
--tankers.setFrequency(260)
--tankers.setTacan(41, true)
--tankers.changeCallsign()
unit = Unit.getByName(tankers.tankerName)
cvn = Unit.getByName("CVN")
local cvnPos = cvn:getPosition().p
local tnkrPos = unit:getPosition().p
local speed = 250
local controller = unit:getController()
--if you want to try making a tanker do something else
--https://www.digitalcombatsimulator.com/en/support/faq/1267/#3307682 maybe? stop conditions etc
--personally i think delete the thing if it doesn't work
--there is a recovery tanker option, but for me it makes planes stall and hit the floor and we can fake it with this already
-- this might all seem very over the top compared to the docs, but if you don't do it the tanker instantly RTBs, though you can tank on final which is hillarious
task1 = {
["number"] = 1,
["auto"] = false,
["id"] = "ControlledTask",
["enabled"] = true,
["params"] =
{
["task"] =
{
["id"] = "Tanker",
["params"] =
{
}, -- end of ["params"]
}, -- end of ["task"]
["stopCondition"] =
{
["duration"] = 600,
["userFlag"] = "1",
}, -- end of ["stopCondition"]
}, -- end of ["params"]
}
task2 = {
["number"] = 2,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "ActivateBeacon",
["params"] =
{
["type"] = 4,
["AA"] = false,
["callsign"] = "TKR",
["modeChannel"] = "Y",
["channel"] = 71,
["system"] = 5,
["unitId"] = 188,
["bearing"] = true,
["frequency"] = 1032000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}
task3 =
{
["number"] = 3,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetFrequency",
["params"] =
{
["power"] = 10,
["modulation"] = 0,
["frequency"] = 305000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}
task4 =
{
["number"] = 4,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetInvisible",
["params"] =
{
["value"] = true,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}
point1 = {
['speed_locked'] = false,
['type'] = 'Turning Point',
['action'] = 'Turning Point',
['alt_type'] = 'BARO',
['y'] = cvnPos.z,
['x'] = cvnPos.x,
['speed'] = 128.611,
['task'] = {
['id'] = 'ComboTask',
['params'] = {
['tasks'] = {
[1] = task1, --tanker first
[2] = task2, --whatever second
[3] = task3,
[4] = task4,
}
}
},
['alt'] = tnkrPos.y
}
point2 = {
['speed_locked'] = true,
['type'] = 'Turning Point',
['action'] = 'Turning Point',
['alt_type'] = 'BARO',
['y'] = 30553,
['x'] = 35881,
['speed'] = 128.611,
['task'] = {
['id'] = 'ComboTask',
['params'] = {
['tasks'] = {
}
}
},
['alt'] = 2133.6
}
missionTask =
{
['id'] = 'Mission',
['params'] = {
['route'] = {
['points'] = {
[1] = point1,
--[2] = point2,
}
},
['airborne'] = true
}
}
controller:pushTask(missionTask)
end
function tankers.followInFront ()
unit = Unit.getByName(tankers.tankerName)
local controller = unit:getController()
FollowAheadOfGroup = {
["enabled"] = true,
["auto"] = false,
["id"] = "Follow",
["number"] = 1,
["params"] =
{
["lastWptIndexFlagChangedManually"] = false,
["groupId"] = 74,
["lastWptIndex"] = 2,
["lastWptIndexFlag"] = false,
["pos"] =
{
["y"] = 152.4, --mins for KC 135 to accidentally stern rejoin and overfly
["x"] = 1000.8,
["z"] = 39.9288,
}, -- end of ["pos"]
}, -- end of ["params"]
}
controller:pushTask(FollowAheadOfGroup)
end
function tankers.followInFrontClose ()
unit = Unit.getByName(tankers.tankerName)
local controller = unit:getController()
FollowAheadOfGroup = {
["enabled"] = true,
["auto"] = false,
["id"] = "Follow",
["number"] = 1,
["params"] =
{
["lastWptIndexFlagChangedManually"] = false,
["groupId"] = 74,
["lastWptIndex"] = 2,
["lastWptIndexFlag"] = false,
["pos"] =
{
["y"] = 25, --mins for KC 135 to accidentally stern rejoin and overfly
["x"] = 150,
["z"] = 41.45,
}, -- end of ["pos"]
}, -- end of ["params"]
}
controller:pushTask(FollowAheadOfGroup)
end
function tankers.cloneTanker()
local groupName = 'TankerClone' -- Name of the group in the ME
group = mist.getGroupData(groupName)
group.route = { points = mist.getGroupRoute(groupName, true) }
group.groupName = "Tanker1"
group.groupId = nil
group.units[1].unitId = nil
group.units[1].unitName = newName
group.country = country
group.category = 'AIRPLANE'
mist.dynAdd(group)
end
function tankers.newTanker()
local groupName = 'TankerClone' -- Name of the group in the ME
local cloneGroupPos = Unit.getByName(groupName):getPosition().p
cvn = Unit.getByName("CVN")
local cvnPos = cvn:getPosition().p
group = mist.getGroupData(groupName)
group.route = {
["points"] =
{
[1] =
{
["alt"] = 2133.6,
["action"] = "Turning Point",
["alt_type"] = "BARO",
["speed"] = 179.86111111111,
["task"] =
{
["id"] = "ComboTask",
["params"] =
{
["tasks"] =
{
[1] =
{
["number"] = 1,
["auto"] = false,
["id"] = "ControlledTask",
["enabled"] = true,
["params"] =
{
["task"] =
{
["id"] = "Tanker",
["params"] =
{
}, -- end of ["params"]
}, -- end of ["task"]
["stopCondition"] =
{
["duration"] = 900,
}, -- end of ["stopCondition"]
}, -- end of ["params"]
}, -- end of [1]
[2] =
{
["number"] = 2,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "ActivateBeacon",
["params"] =
{
["type"] = 4,
["AA"] = false,
["callsign"] = "TKR",
["modeChannel"] = "Y",
["channel"] = 71,
["system"] = 5,
["unitId"] = 188,
["bearing"] = true,
["frequency"] = 1032000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [2]
[3] =
{
["number"] = 3,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetFrequency",
["params"] =
{
["power"] = 10,
["modulation"] = 0,
["frequency"] = 260000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [3]
[4] =
{
["number"] = 4,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetInvisible",
["params"] =
{
["value"] = true,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [4]
}, -- end of ["tasks"]
}, -- end of ["params"]
}, -- end of ["task"]
["type"] = "Turning Point",
["ETA"] = 96.50677034026,
["ETA_locked"] = false,
["y"] = cvnPos.z,
["x"] = cvnPos.x,
["formation_template"] = "",
["speed_locked"] = true,
}, -- end of [1]
}, -- end of ["points"]
}
--group.units[1].type = "S-3B Tanker"
group.groupName = "Tanker1"
group.groupId = nil
group.units[1].unitId = nil
group.units[1].unitName = newName
group.country = country
group.category = 'AIRPLANE'
group.units[1].x = cloneGroupPos.x
group.units[1].y = cloneGroupPos.z
group.units[1].z = cloneGroupPos.y
group.units[1].speed = 999999
Group.destroy(Group.getByName(groupName))
mist.dynAdd(group)
--timer.scheduleFunction(mist.dynAdd,group, timer.getTime() + 0.00000000001)
end
function tankers.startEnrouteTankingTest (vec3) -- this is the one that works well, clone an existing tanker that is currently mission editor tanking
--tankers.setFrequency(260)
--tankers.setTacan(41, true)
--tankers.changeCallsign()
route = mist.getGroupRoute(tankers.tankerName, true)
unit = Unit.getByName(tankers.tankerName)
cvn = Unit.getByName("CVN")
local cvnPos = cvn:getPosition().p
local vec3 = vec3 or cvnPos
route[1].x = unit:getPosition().p.x
route[1].y = unit:getPosition().p.z
route[2].x = vec3.x
route[2].y = vec3.z
route[2].z = vec3.y + 100
mist.goRoute(tankers.tankerName , route )
end
function tankers.hyperSpace (vec3) -- this is the one that works well, clone an existing tanker that is currently mission editor tanking
local groupName = 'TankerClone' -- Name of the group in the ME
local cloneGroupPos = Unit.getByName(groupName):getPosition().p
cvn = Unit.getByName("CVN")
local cvnPos = cvn:getPosition().p
group = mist.getGroupData(groupName)
group.route = {
["points"] =
{
[1] =
{
["alt"] = 2133.6,
["action"] = "Turning Point",
["alt_type"] = "BARO",
["speed"] = 179.86111111111,
["task"] =
{
["id"] = "ComboTask",
["params"] =
{
["tasks"] =
{
[1] =
{
["number"] = 1,
["auto"] = false,
["id"] = "ControlledTask",
["enabled"] = true,
["params"] =
{
["task"] =
{
["id"] = "Tanker",
["params"] =
{
}, -- end of ["params"]
}, -- end of ["task"]
["stopCondition"] =
{
["duration"] = 900,
}, -- end of ["stopCondition"]
}, -- end of ["params"]
}, -- end of [1]
[2] =
{
["number"] = 2,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "ActivateBeacon",
["params"] =
{
["type"] = 4,
["AA"] = false,
["callsign"] = "TKR",
["modeChannel"] = "Y",
["channel"] = 71,
["system"] = 5,
["unitId"] = 188,
["bearing"] = true,
["frequency"] = 1032000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [2]
[3] =
{
["number"] = 3,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetFrequency",
["params"] =
{
["power"] = 10,
["modulation"] = 0,
["frequency"] = 260000000,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [3]
[4] =
{
["number"] = 4,
["auto"] = false,
["id"] = "WrappedAction",
["enabled"] = true,
["params"] =
{
["action"] =
{
["id"] = "SetInvisible",
["params"] =
{
["value"] = true,
}, -- end of ["params"]
}, -- end of ["action"]
}, -- end of ["params"]
}, -- end of [4]
}, -- end of ["tasks"]
}, -- end of ["params"]
}, -- end of ["task"]
["type"] = "Turning Point",
["ETA"] = 96.50677034026,
["ETA_locked"] = false,
["y"] = cvnPos.z,
["x"] = cvnPos.x,
["formation_template"] = "",
["speed_locked"] = true,
}, -- end of [1]
}, -- end of ["points"]
}
--group.units[1].type = "S-3B Tanker"
group.groupName = "Tanker1"
group.groupId = nil
group.units[1].unitId = nil
group.units[1].unitName = newName
group.country = country
group.category = 'AIRPLANE'
group.units[1].x = cvnPos.x-100
group.units[1].y = cvnPos.z
group.units[1].z = cloneGroupPos.y
group.units[1].heading = 0.000000000001
group.units[1].speed = 300
--Group.destroy(Group.getByName(groupName))
mist.dynAdd(group)
group.groupName = "Tanker2"
group.units[1].x = cvnPos.x+100
group.units[1].heading = 3.1415926537
group.units[1].y = cvnPos.z
mist.dynAdd(group)
end
handler = {}
local function protectedCall(...)
local status, retval = pcall(...)
if not status then
end
end
function tankers.eventHandler (event)
if (26 == event.id) then --this is when someone types into a mark
local vec3 = mist.utils.makeVec3GL(event.pos)
tankers.startEnrouteTankingTest (vec3)
end
end
function handler:onEvent(event)
protectedCall(tankers.eventHandler, event)
end
do
--world.addEventHandler(handler)
world.addEventHandler(handler)
end
do
longRangeShots = missionCommands.addSubMenu("Dynamic Tanking")
missionCommands.addCommand ("Hyperspace entry", longRangeShots, tankers.hyperSpace)
missionCommands.addCommand ("Start tanking", longRangeShots, tankers.startEnrouteTankingTest)
missionCommands.addCommand ("Frequency change approved", longRangeShots, tankers.setFrequency)
missionCommands.addCommand ("Callsign change approved", longRangeShots, tankers.changeCallsign)
missionCommands.addCommand ("Tacan change approved", longRangeShots, tankers.setTacan)
missionCommands.addCommand ("Start a new tanker", longRangeShots, tankers.newTanker)
missionCommands.addCommand ("Rejoin on a unit", longRangeShots, tankers.followInFront)
missionCommands.addCommand ("Rejoin close", longRangeShots, tankers.followInFrontClose)
end
tankers.notify("tankers.lua loaded",2)

112
scripts/forceBubble.lua Normal file
View File

@ -0,0 +1,112 @@
--Spawn a SAM integrated with IADS
--Spawn a normal SAM
--SAM bubble shields
forceBub = {}
forceBub.handler = {}
forceBub.missileList = {}
forceBub.missilesActive = 0
forceBub.shieldOn = false
function forceBub.notify(message, displayFor)
trigger.action.outText(message, displayFor, true)
end
function forceBub.setShield()
forceBub.notify("Shield on", 2)
end
function forceBub.stopShield()
forceBub.shieldOn = false
end
local function protectedCall(...)
local status, retval = pcall(...)
if not status then
--rf.notify("Caught error " .. retval,2)
end
end
function forceBub.handler:onEvent(event)
protectedCall(forceBub.eventHandler, event)
end
function forceBub.checkMissiles ()
local currentTime = timer.getTime()
if forceBub.missilesActive > 0 then
for index, data in pairs(forceBub.missileList) do
output = mist.utils.tableShow(forceBub.missileList[index])
if forceBub.missileList[index].exists == true then
if Object.isExist(forceBub.missileList[index].weapon) == true then
forceBub.missileList[index].pos = forceBub.missileList[index].weapon:getPosition()
local missilePosition = forceBub.missileList[index].pos.p
unit = Unit.getByName("Test")
local unitPosition = unit:getPosition().p
local distance = mist.utils.get3DDist(unitPosition , missilePosition )
forceBub.notify(distance,1)
if forceBub.shieldOn == true and distance < 100 then --this distance is the sweet spot any less and you probably take damage and die, less than 75 death
trigger.action.explosion(missilePosition , 1) --just blows up the missile
end
else
forceBub.missileList[index] = nil
forceBub.missilesActive = forceBub.missilesActive - 1
end
else
end
end
end
timer.scheduleFunction(forceBub.checkMisProtectCall,{},currentTime + 0.01)
end
function forceBub.eventHandler (event)
--forceBub.notify(mist.utils.tableShow(event),10)
if (event.id == 1) then
--check if weapon is a missile
--rf.notify("Missile fired id " .. event.weapon.id_ ,2)
forceBub.notify(mist.utils.tableShow(Weapon.getDesc(event.weapon)),10)
if Weapon.getDesc(event.weapon).missileCategory == 2 then
local newMis = {}
newMis.id = event.weapon.id_
newMis.pos = event.weapon:getPosition()
newMis.weapon = event.weapon
newMis.exists = Object.isExist(newMis.weapon)
forceBub.missileList[event.weapon.id_] = newMis
forceBub.missilesActive = forceBub.missilesActive + 1
end
end
end
function forceBub.checkMisProtectCall()
protectedCall(forceBub.checkMissiles,{})
end
function forceBub.setShield()
forceBub.shieldOn = true
end
do
forceField = missionCommands.addSubMenu("Force Field")
missionCommands.addCommand ("Forcefield on", forceField, forceBub.setShield)
missionCommands.addCommand ("Stop Field", forceField, forceBub.stopShield)
end
do
world.addEventHandler(forceBub.handler)
end
protectedCall(forceBub.checkMissiles,{})
forceBub.notify("forceBubble.lua loaded", 2)

628
scripts/poleGen.lua Normal file
View File

@ -0,0 +1,628 @@
--max range, altitude and it fails?
--shoot right up
--fix sa10 and sa 11
--different static layouts on a carrier depending on what is going on
--guns on a static ship at sea?
pg = {}
handler = {}
pg.name = "Sam"
pg.cloneName = "Clone"
pg.fakeTargetName = "Player"
pg.samCounter = 1
pg.droneAlt = 20000
pg.delay = 40
pg.missileSpeed = 565
pg.samLoc = {}
pg.samLoc.x = 1
pg.samLoc.y = 1
pg.samLoc.z = 1
pg.missilesActive = 0
pg.droneName = nil
pg.droneSpeed = 300
pg.hidden = false
pg.samDB = {[1] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[2] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[3] = {["missileDelay"] = 120, ["missileSpeed"] = 550},
[4] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[5] = {["missileDelay"] = 65, ["missileSpeed"] = 770},
[6] = {["missileDelay"] = 60, ["missileSpeed"] = 500},
[7] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[8] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[9] = {["missileDelay"] = 40, ["missileSpeed"] = 770},
[10] = {["missileDelay"] = 60, ["missileSpeed"] = 1400},
}
function pg.notify(message, displayFor)
trigger.action.outText(message, displayFor, false)
end
function pg.fakeSam(vec3)
playerTarget = Unit.getByName(pg.fakeTargetName)
pointFakeTarget = playerTarget:getPosition().p
vec3 = vec3 or pg.samLoc
vecSub = mist.vec.sub(pointFakeTarget , vec3)
planeHeading = mist.utils.getDir(vecSub)
missileType = 2
pg.spawnDrone (vec3,planeHeading,playerTarget,missileType)
--pg.notify("FakeSam Ran", 10)
targetID = Group.getByName("TargetDrone" .. pg.samCounter):getUnit(1):getID()
samGroup = Group.getByName("poleGenerator" .. pg.samCounter)
vars = {[1] = targetID, [2] = samGroup}
timer.scheduleFunction(pg.attack ,vars, timer.getTime() + 1)
pg.samCounter = pg.samCounter + 1
end
function pg.spawnSamSA2 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "S_75M_Volhov",
--["unitId"] = 35,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "SNR_75V",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnSamSA3 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "snr s-125 tr",
--["unitId"] = 35,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "5p73 s-125 ln",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnSamSA5 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "RPC_5N62V",
--["unitId"] = 35,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "RLS_19J6",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
[3] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "S-200_Launcher",
--["unitId"] = 34,
["y"] = vec3.z-80,
["x"] = vec3.x-80,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [3]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnSamSA6 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "Kub 1S91 str",
--["unitId"] = 35,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "Kub 2P25 ln",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnSamSA10 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "S-300PS 40B6M tr",
--["unitId"] = 35,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "S-300PS 64H6E sr",
--["unitId"] = 34,
["y"] = vec3.z-10,
["x"] = vec3.x-10,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
[3] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "S-300PS 54K6 cp",
--["unitId"] = 34,
["y"] = vec3.z-20,
["x"] = vec3.x-20,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [3]
[4] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "S-300PS 5P85C ln",
--["unitId"] = 34,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [4]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnSamSA11 (vec3,heading)
--where
--name
group = {}
group.groupName = "poleGenerator" .. pg.samCounter
group.units = {
[1] =
{
["skill"] = "High",
["coldAtStart"] = false,
["hidden"] = pg.hidden,
["type"] = "SA-11 Buk SR 9S18M1",
--["unitId"] = 35,
["y"] = vec3.z-40,
["x"] = vec3.x-40,
--["name"] = "Ground-1-2",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [1]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "SA-11 Buk CC 9S470M1",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
[2] =
{
["skill"] = "High",
["coldAtStart"] = false,
["type"] = "SA-11 Buk LN 9A310M1",
--["unitId"] = 34,
["y"] = vec3.z,
["x"] = vec3.x,
--["name"] = "Ground-1-1",
["heading"] = heading+math.pi,
["playerCanDrive"] = false,
}, -- end of [2]
}
group.hidden = pg.hidden
group.category = "VEHICLE"
group.country = 54
mist.dynAdd(group)
--heading
end
function pg.spawnDrone(vec3,planeHeading,playerTarget,missileType)
-- where is the plane going to be in x seconds
playerTargetPos = playerTarget:getPosition().p
futurePlayerTargetPos = playerTargetPos
playerMotionVec = Object.getVelocity(playerTarget)
--work out what type of SAM we are shooting to work out the delay, missile speed etc
if missileType == 2 then
pg.delay = pg.samDB[2].missileDelay
pg.missileSpeed = pg.samDB[2].missileSpeed
elseif missileType == 3 then
pg.delay = pg.samDB[3].missileDelay
pg.missileSpeed = pg.samDB[3].missileSpeed
elseif missileType == 5 then
pg.delay = pg.samDB[5].missileDelay
pg.missileSpeed = pg.samDB[5].missileSpeed
elseif missileType == 6 then
pg.delay = pg.samDB[6].missileDelay
pg.missileSpeed = pg.samDB[5].missileSpeed
elseif missileType == 10 then
pg.delay = pg.samDB[10].missileDelay
pg.missileSpeed = pg.samDB[10].missileSpeed
elseif missileType == 11 then
pg.delay = pg.samDB[11].missileDelay
pg.missileSpeed = pg.samDB[11].missileSpeed
else --assume SA2
pg.delay = pg.samDB[2].missileDelay
pg.missileSpeed = pg.samDB[2].missileSpeed
end
futurePlayerTargetPos.x = playerTargetPos.x + playerMotionVec.x*pg.delay
futurePlayerTargetPos.y = playerTargetPos.y + playerMotionVec.y*pg.delay
futurePlayerTargetPos.z = playerTargetPos.z + playerMotionVec.z*pg.delay
droneTurnPoint = mist.projectPoint(futurePlayerTargetPos, 10000 ,planeHeading+math.pi)
--this is where the plane will be when the missile is launched
--pythago to get hyp
--x^2 + y^x = hyp^2
x = mist.utils.get2DDist(futurePlayerTargetPos,vec3)
y = playerTargetPos.y
--pg.notify(y,5)
hyp = math.sqrt(x^2 + y^2)
roughFlightTime = hyp /pg.missileSpeed-- distance / speed
futurePlayerTargetPos.x = futurePlayerTargetPos.x + playerMotionVec.x*roughFlightTime
futurePlayerTargetPos.y = futurePlayerTargetPos.y + playerMotionVec.y*roughFlightTime
futurePlayerTargetPos.z = futurePlayerTargetPos.z + playerMotionVec.z*roughFlightTime
--this is where the plane will be when the missile arrives at its altitude
--now we need to work out where the drone is going to go
vecSub = mist.vec.sub(vec3,futurePlayerTargetPos)
heading = mist.utils.getDir(vecSub) --heading between picked location and future pos
extendDistance = x + 10000
alt = (((futurePlayerTargetPos.y) * extendDistance)/x)
droneAtTimePos = mist.projectPoint(vec3, extendDistance ,heading +math.pi)
extendDistance = extendDistance + pg.droneSpeed*roughFlightTime
droneAtStartPos = mist.projectPoint(vec3, extendDistance ,heading +math.pi)
--we want to curve the missile in the players direction
--planeHeading
pg.makeDrone(droneAtStartPos,heading, droneAtTimePos, futurePlayerTargetPos,alt,droneTurnPoint)
if missileType == 2 then
pg.spawnSamSA2 (vec3,heading)
elseif missileType == 3 then
pg.spawnSamSA3 (vec3,heading)
elseif missileType == 5 then
pg.spawnSamSA5 (vec3,heading)
elseif missileType == 6 then
pg.spawnSamSA6 (vec3,heading)
elseif missileType == 10 then
pg.spawnSamSA10 (vec3,heading)
else --assume SA2
pg.spawnSamSA2 (vec3,heading)
end
end
function pg.makeDrone(spawnVec,heading, routeVec, nextRouteVec,alt,droneTurnPoint)
--this spawns in the drone
group = DroneClone
group.groupName = "TargetDrone" .. pg.samCounter
group.groupId = nil
group.units[1].unitId = nil
group.units[1].unitName = nil
group.units[1].y = spawnVec.z
group.units[1].x = spawnVec.x
group.units[1].heading = heading
group.units[1].alt = alt
group.route["points"][2] = group.route["points"][1]
group.route["points"][3] = group.route["points"][1]
group.route["points"][1]["y"] = routeVec.z
group.route["points"][1]["x"] = routeVec.x
group.route["points"][1]["alt"] = alt
group.route["points"][2]["y"] = nextRouteVec.z
group.route["points"][2]["x"] = nextRouteVec.x
group.route["points"][2]["alt"] = alt
group.route["points"][3]["y"] = droneTurnPoint.z
group.route["points"][3]["x"] = droneTurnPoint.x
group.route["points"][3]["alt"] = alt
group.countryId = 56
group.category = 'AIRPLANE'
mist.dynAdd(group)
end
function pg.attack (vars)
targetID = vars[1]
samGroup = vars[2]
AttackUnit = {
id = 'AttackUnit',
params = {
unitId = targetID,
attackQtyLimit = true,
attackQty = 1,
}
}
local controller = samGroup:getController()
controller:pushTask(AttackUnit)
end
function pg.radarOff ()
group = Group.getByName(pg.name)
local controller = group:getController()
controller:setOption(9,1)
end
function pg.radarOn ()
group = Group.getByName(pg.name)
local controller = group:getController()
controller:setOption(9,0)
end
DroneClone=
{
["modulation"] = 0,
["tasks"] =
{
}, -- end of ["tasks"]
["task"] = "Reconnaissance",
["uncontrolled"] = false,
["route"] =
{
["points"] =
{
[1] =
{
["alt"] = 2000,
["action"] = "Turning Point",
["alt_type"] = "BARO",
["speed"] = 82.222222222222,
["task"] =
{
["id"] = "ComboTask",
["params"] =
{
["tasks"] =
{}, -- end of ["tasks"]
}, -- end of ["params"]
}, -- end of ["task"]
["type"] = "Turning Point",
["ETA"] = 0,
["ETA_locked"] = true,
["y"] = 0,
["x"] = 0,
["formation_template"] = "",
["speed_locked"] = true,
}, -- end of [1]
[2] =
{
["alt"] = 2000,
["action"] = "Turning Point",
["alt_type"] = "BARO",
["speed"] = 82.222222222222,
["task"] =
{
["id"] = "ComboTask",
["params"] =
{
["tasks"] =
{
}, -- end of ["tasks"]
}, -- end of ["params"]
}, -- end of ["task"]
["type"] = "Turning Point",
["ETA"] = 157.20107538291,
["ETA_locked"] = false,
["y"] = 0,
["x"] = 0,
["formation_template"] = "",
["speed_locked"] = true,
}, -- end of [2]
}, -- end of ["points"]
}, -- end of ["route"]
--["groupId"] = 1,
["hidden"] = pg.hidden,
["units"] =
{
[1] =
{
["alt"] = 2000,
["alt_type"] = "BARO",
["livery_id"] = "'camo' scheme",
["skill"] = "High",
["speed"] = 82.222222222222,
["type"] = "MQ-9 Reaper",
--["unitId"] = 1,
--["psi"] = -3.129323330636,
["y"] = 0,
["x"] = 0,
["payload"] =
{
["pylons"] =
{
}, -- end of ["pylons"]
["fuel"] = 1300,
["flare"] = 0,
["chaff"] = 0,
["gun"] = 100,
}, -- end of ["payload"]
["heading"] = 0.5,
["callsign"] =
{
[1] = 1,
[2] = 1,
[3] = 1,
["name"] = "Enfield11",
}, -- end of ["callsign"]
["onboard_num"] = "010",
}, -- end of [1]
}, -- end of ["units"]
["y"] = 0,
["x"] = 0,
["communication"] = true,
["start_time"] = 0,
["frequency"] = 124,
}
local function protectedCall(...)
local status, retval = pcall(...)
if not status then
end
end
function handler:onEvent(event)
protectedCall(pg.eventHandler, event)
end
function pg.eventHandler (event)
if (26 == event.id) then --this is when someone types into a mark
local vec3 = mist.utils.makeVec3GL(event.pos)
pg.fakeSam (vec3)
end
end
function handler:onEvent(event)
protectedCall(pg.eventHandler, event)
end
do
longRangeShots = missionCommands.addSubMenu("SAM")
missionCommands.addCommand ("Generate pole", longRangeShots, pg.fakeSam)
world.addEventHandler(handler)
end
pg.notify("poleGen.lua",10)

319
scripts/raisedShots.lua Normal file
View File

@ -0,0 +1,319 @@
shots = {} --https://www.youtube.com/watch?v=XNtTEibFvlQ mandatory terrible listening
shots.shooterName = "TestInfantry"
shots.targetName = "TestTarget1"
function shots.notify(message, displayFor)
trigger.action.outText(message, displayFor, false)
end
--infantry
function shots.set556 () --red
roundVelocity = 910
unitBarrelHeight = 1
shotsToFire = 5
shotDelay = 4.5
shots.notify("5.56 M4 Georgia", 2)
shots.fire()
end
function shots.set556SAW () --red
roundVelocity = 915
unitBarrelHeight = 0.4
shotsToFire = 5
shotDelay = 4.5
shots.notify("5.56 M249 SAW", 2)
shots.fire()
end
function shots.setAk74() --red
roundVelocity = 900
unitBarrelHeight = 0.9
shotsToFire = 5
shotDelay = 4.5
shots.notify("Ak74", 2)
shots.fire()
end
--technicals
function shots.hmmwv() --red
roundVelocity = 928
unitBarrelHeight = 2.6
shotsToFire = 5
shotDelay = 2.5
shots.notify("Humm drumm Vee", 2)
shots.fire()
shots.notify(unitBarrelHeight,2)
end
function shots.technicalDHSKA() --green
roundVelocity = 928
unitBarrelHeight = 2.2
shotsToFire = 5
shotDelay = 2.5
shots.notify("technicalDHSKA", 2)
shots.fire()
shots.notify(unitBarrelHeight,2)
end
function shots.cobra() --green
roundVelocity = 928
unitBarrelHeight = 2.85
shotsToFire = 5
shotDelay = 2.6
shots.notify("Cobra", 2)
shots.fire()
shots.notify(unitBarrelHeight,2)
end
--IFVs
function shots.setWarrior() --white
roundVelocity = 1070
unitBarrelHeight = 2.28
shotsToFire = 3
shotDelay = 6.3
shots.fire()
end
function shots.setBMP2() --red
roundVelocity = 970
unitBarrelHeight = 1.95
shotsToFire = 3
shotDelay = 6
shots.fire()
end
--Tanks
function shots.m1a1() --red
roundVelocity = 928
unitBarrelHeight = 2.15
shotsToFire = 5
shotDelay = 3
shots.notify("Abrams 50 cal", 2)
shots.fire()
shots.notify(unitBarrelHeight,2)
end
function shots.t55() --red and green
roundVelocity = 928
unitBarrelHeight = 1.75
shotsToFire = 5
shotDelay = 2.6
shots.notify("T-72B", 2)
shots.fire()
shots.notify(unitBarrelHeight,2)
end
---aaaaaaaaaaaaaaaa
function shots.ZSU57() --red
roundVelocity = 1070
shotsToFire = 2
shotDelay = 10.5
shots.notify("ZSU57", 2)
unitMaxRange = 6000
shots.fireAAA()
end
function shots.ZSU23() --red
roundVelocity = 1050
shotsToFire = 2
shotDelay = 12
shots.notify("ZSU23", 2)
unitMaxRange = 2000
shots.fireAAA()
end
function shots.vulcan() --red
roundVelocity = 1030
shotsToFire = 5
shotDelay = 5
shots.notify("Vulcan M163", 2)
unitMaxRange = 1500
shots.fireAAA()
end
function shots.flak18() --red and green
roundVelocity = 870
shotsToFire = 1
shotDelay = 10.5
shots.notify("Flak 18", 2)
unitMaxRange = 4000
shots.fireAAA()
end
-- This one is really obvious, however I set towards the end of this file the "parameters" of the shots.
function shots.fire()
unit = Unit.getByName(shots.shooterName)
target = Unit.getByName(shots.targetName)
local targetMotionVec = Object.getVelocity(target) --if you don't want to do this i.e. shoot a point send a nil or a vec3 of 0's
--local targetMotionVec = nil
local targetPos = target:getPosition().p
shots.calculateAngle(roundVelocity, unit, targetPos, unitBarrelHeight, shotsToFire,shotDelay, targetMotionVec)
end
--main bit that does the maths for simulating a "roughly level" fire fight, not to be used when aiming AAA at aircraft
function shots.calculateAngle(v, unit, targetPos, unitBarrelHeight, shotsToFire,shotDelay, targetMotionVector)
--v muzzle velocity
--unit is unit object you want shooting
--targetPos is a position on the ground, doesn't have to be a targets actual location
--unitBarrelHeigh is the height the gun is at when it fires
--shotsToFire is how many rounds to shoot, 5 is a nice number except for large calibre slow guns
--shotDelay how long it on average takes to aim from scratch at something and shoot, mostly used in aiming lead
--targetMotionVector a vec3 of the targets motion if nil just shoots at a spot
g = 9.81 -- gravity, change if on the moon veltro you comment reading prick
local unitPos = unit:getPosition().p
local x = mist.utils.get2DDist(unitPos,targetPos) -- horizontal range
local x3d = mist.utils.get3DDist(unitPos,targetPos) -- slant range
y = targetPos.y - unitPos.y
y = y - unitBarrelHeight
--works out some stuff for trig later, like x,y and hypoteneueussueee
if targetMotionVector == nil then
--no moving? nothing to ammend
else --work out where target will be when the bullet arrives
shotDelay = shotDelay + x3d/v --time taken to aim and time for bullet to fly to spot
newPosition = mist.utils.tableShow(targetMotionVector)
targetPos.x = targetPos.x + targetMotionVector.x*shotDelay
targetPos.y = targetPos.y + targetMotionVector.y*shotDelay
targetPos.z = targetPos.z + targetMotionVector.z*shotDelay
end
x = x - 10 --we actually are aiming 10m in front always so need to remove this
local inner = v^4 - g * (g * x^2 + 2 * y * v^2) -- this is the inner bit of the quadratic equation for ease of code
if inner < 0 then
-- No solution exists for these parameters, too far away do nothing we can't hit it, saves us crashing if sqrt of negative
else
local angle2 = math.atan((v^2 - math.sqrt(inner)) / (g * x)) -- do the whole quadratic equation
-- we didn't need to do the +- sqrt b^2..... bits as we care about the flat path not the one shot miles up falling down
local aimUp = 10 * math.tan(angle2)*math.cos(angle2) -- we have to tell dcs to "aim up" at a point 10m ahead of it, this is distance * tan(angle) , so where the fuck has the cos come from? That is because aim correction for shooting up and down is basically modfied by cos(angle) so lazy correction and dcs can't shoot vertically up
local xPosDifference = (targetPos.x - unitPos.x)
local zPosDifference = (targetPos.z - unitPos.z)
local hyp = math.sqrt((xPosDifference*xPosDifference) + (zPosDifference*zPosDifference))
xPosDifference = (xPosDifference /hyp) * 10
zPosDifference = (zPosDifference / hyp) * 10
unitPos.x = unitPos.x + xPosDifference
unitPos.z = unitPos.z + zPosDifference
--that was all basic trig maths
local controller = unit:getController()
FireAtPoint = {
id = 'FireAtPoint',
params = {
point = {x = unitPos.x, y = unitPos.z},
radius = 0.0001,
expendQty = shotsToFire,
expendQtyEnabled = true,
altitude = unitPos.y+unitBarrelHeight +aimUp, --this is a realtive to sea level shot, so we can shoot down
alt_type = 0, --0 = sea level, 1 = ground level
}
}
controller:pushTask(FireAtPoint) --FIREEEEEE
end
end
function shots.fireAAA()
unit = Unit.getByName(shots.shooterName)
target = Unit.getByName(shots.targetName)
targetMotionVec = Object.getVelocity(target) --if you don't want to do this i.e. shoot a point send a nil or a vec3 of 0's
--local targetMotionVec = nil
targetPos = target:getPosition().p
shots.aaa(roundVelocity, unit, unitMaxRange, targetPos, shotsToFire,shotDelay, targetMotionVec)
end
--aaa fires almost straight up, no line of sight fakery needed or working out lobbing bullets onto random points
--if in range just needs to be told to shoot where the target will be in a few seconds
--if out of range, we just need to extrapolate back and fire inside max range and randomise the up and down, then let it miss
function shots.aaa(v, unit, unitMaxRange, targetPos, shotsToFire,shotDelay, targetMotionVector)
local unitPos = unit:getPosition().p
local x = mist.utils.get2DDist(unitPos,targetPos) -- horizontal range
local x3d = mist.utils.get3DDist(unitPos,targetPos) -- slant range
if x3d > unitMaxRange then
if targetMotionVector == nil then
--no moving? nothing to ammend
else --work out where target will be when the bullet arrives
shotDelay = shotDelay + x3d/(v/2) --time taken to aim and time for bullet to fly to spot long range roughly 50% slowdown
newPosition = mist.utils.tableShow(targetMotionVector)
targetPos.x = targetPos.x + targetMotionVector.x*shotDelay
targetPos.y = targetPos.y + targetMotionVector.y*shotDelay
targetPos.z = targetPos.z + targetMotionVector.z*shotDelay
end
difference = mist.vec.sub(targetPos,unitPos)
unitVec = mist.vec.getUnitVec(difference)
extendPath = mist.vec.scalar_mult(unitVec ,unitMaxRange)
targetPos = mist.vec.add(extendPath,unitPos)
local controller = unit:getController()
FireAtPoint = {
id = 'FireAtPoint',
params = {
point = {x = targetPos.x, y = targetPos.z},
radius = 0.0001,
expendQty = shotsToFire,
expendQtyEnabled = true,
altitude = targetPos.y+math.random(1,500), --this is a realtive to sea level shot, so we can shoot down
alt_type = 0, --0 = sea level, 1 = ground level
}
}
controller:pushTask(FireAtPoint) --FIREEEEEE
else
if targetMotionVector == nil then
--no moving? nothing to ammend
else --work out where target will be when the bullet arrives
shotDelay = shotDelay + x3d/v --time taken to aim and time for bullet to fly to spot
newPosition = mist.utils.tableShow(targetMotionVector)
targetPos.x = targetPos.x + targetMotionVector.x*shotDelay
targetPos.y = targetPos.y + targetMotionVector.y*shotDelay
targetPos.z = targetPos.z + targetMotionVector.z*shotDelay
end
local controller = unit:getController()
FireAtPoint = {
id = 'FireAtPoint',
params = {
point = {x = targetPos.x, y = targetPos.z},
radius = 0.0001,
expendQty = shotsToFire,
expendQtyEnabled = true,
altitude = targetPos.y, --this is a realtive to sea level shot, so we can shoot down
alt_type = 0, --0 = sea level, 1 = ground level
}
}
controller:pushTask(FireAtPoint) --FIREEEEEE
end
end
do
longRangeShots = missionCommands.addSubMenu("Firefight")
missionCommands.addCommand ("Fire", longRangeShots, shots.vulcan)
end
shots.notify("raisedShots.lua ran", 2)

540
scripts/samSimulator.lua Normal file
View File

@ -0,0 +1,540 @@
--Spawn a SAM integrated with IADS
--Spawn a normal SAM
--SAM bubble shields
samSim = {}
samSim.samSuffix = 1
do -- needs to go early on
redIADS = SkynetIADS:create('Red')
redIADS:setUpdateInterval(5)
redIADS:activate()
--redIADS:addRadioMenu()
end
function samSim.genSAten() --gens an SA 10 as you can imagine,
unit = Unit.getByName("Test")
local pointVec3Gl = unit:getPosition().p -- this is just to find where my aircraft is and whack an SA10 below it, lazy not relevant
local isHiddenCheck = math.random(100)
if isHiddenCheck > 10 then
isHidden = false
else
isHidden = true -- fairly obvious hides from F10 and F7 view
end
mist.dynAdd(
{
country = 'USSR',
category = 'vehicle',
name = "SAM " .. samSim.samSuffix,
groupName = "SAM " .. samSim.samSuffix,
groupId = 10000+samSim.samSuffix,
hidden = isHidden,
units =
{ [1] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 40B6MD sr", --search radar needs to be first always for avoiding a skynet bug
["y"] = pointVec3Gl.z + 50,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [1]
[2] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 40B6M tr",
["y"] = pointVec3Gl.z,
["x"] = pointVec3Gl.x,
["heading"] = 4.7123889803847,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [2]
[3] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 54K6 cp",
["y"] = pointVec3Gl.z + 100,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [3]
[4] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 64H6E sr",
["y"] = pointVec3Gl.z - 50,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [4]
[5] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 5P85C ln",
["y"] = pointVec3Gl.z +200 ,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [5]
[6] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 5P85C ln",
["y"] = pointVec3Gl.z -200,
["x"] = pointVec3Gl.x,
["heading"] = 3.3161255787892,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [6]
[7] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S-300PS 5P85C ln",
["y"] = pointVec3Gl.z ,
["x"] = pointVec3Gl.x + 200,
["heading"] = 2.9670597283904,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [7]
[8] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Excellent",
["type"] = "S-300PS 5P85C ln",
["y"] = pointVec3Gl.z,
["x"] = pointVec3Gl.x -200,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [8]
[9] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "generator_5i57",
["y"] = pointVec3Gl.z +200,
["x"] = pointVec3Gl.x + 200,
["heading"] = 6.1086523819802,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [9]
[10] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "ATZ-5",
["y"] = pointVec3Gl.z -200,
["x"] = pointVec3Gl.x -200,
["heading"] = 0.17453292519943,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [10]
[11] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "ATZ-5",
["y"] = pointVec3Gl.z +550,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [11]
[12] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "GAZ-66",
["y"] = pointVec3Gl.z +580,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [12]
[13] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "ATZ-60_Maz",
["y"] = pointVec3Gl.z +600,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [13]
[14] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "KAMAZ Truck",
["y"] = pointVec3Gl.z +500,
["x"] = pointVec3Gl.x + 20,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [14]
}, -- end of units
} -- end of function
)
redIADS:addSAMSite("SAM " .. samSim.samSuffix) --skynet bit
local detectChance = math.random(50,90)
local goLiveRange = math.random(50,90)
local harmStop = math.random(2)
if harmStop == 1 then
harmStopping = true
else
harmStopping = false
end
redIADS:getSAMSiteByGroupName("SAM " .. samSim.samSuffix):setHARMDetectionChance(detectChance) -- doesn't bloody work no idea, don't care want to reinvent this myself
redIADS:getSAMSiteByGroupName("SAM " .. samSim.samSuffix):setGoLiveRangeInPercent(goLiveRange) -- doesn't bloody work no idea, don't care want to reinvent this myself
redIADS:getSAMSiteByGroupName("SAM " .. samSim.samSuffix):setCanEngageHARM(harmStopping) -- doesn't bloody work no idea, don't care want to reinvent this myself
samSim.samSuffix = samSim.samSuffix + 1
end
function samSim.genSAtwo()
unit = Unit.getByName("Test")
local pointVec3Gl = unit:getPosition().p -- this is just to find where my aircraft is and whack an SA10 below it, lazy not relevant
local isHiddenCheck = math.random(100)
if isHiddenCheck > 50 then
isHidden = false
else
isHidden = true
end
mist.dynAdd(
{
country = 'USSR',
category = 'vehicle',
name = "SAM " .. samSim.samSuffix,
groupName = "SAM " .. samSim.samSuffix,
groupId = 10000+samSim.samSuffix,
hidden = isHidden,
units =
{
[1] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "SNR_75V",
["y"] = pointVec3Gl.z,
["x"] = pointVec3Gl.x,
["heading"] = 4.7123889803847,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [1]
[2] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S_75M_Volhov",
["y"] = pointVec3Gl.z + 50,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [2]
[3] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S_75M_Volhov",
["y"] = pointVec3Gl.z + 100,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [3]
[4] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S_75M_Volhov",
["y"] = pointVec3Gl.z - 50,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [4]
[5] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S_75M_Volhov",
["y"] = pointVec3Gl.z +200 ,
["x"] = pointVec3Gl.x,
["heading"] = 3.1415926535898,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [5]
[6] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "S_75M_Volhov",
["y"] = pointVec3Gl.z -200,
["x"] = pointVec3Gl.x,
["heading"] = 3.3161255787892,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [6]
[7] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "SKP-11",
["y"] = pointVec3Gl.z ,
["x"] = pointVec3Gl.x + 200,
["heading"] = 2.9670597283904,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [7]
[8] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Excellent",
["type"] = "SKP-11",
["y"] = pointVec3Gl.z,
["x"] = pointVec3Gl.x -200,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [8]
[9] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "p-19 s-125 sr",
["y"] = pointVec3Gl.z +200,
["x"] = pointVec3Gl.x + 200,
["heading"] = 6.1086523819802,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [9]
[10] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "Ural-4320 APA-5D",
["y"] = pointVec3Gl.z -200,
["x"] = pointVec3Gl.x -200,
["heading"] = 0.17453292519943,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [10]
[11] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "ATMZ-5",
["y"] = pointVec3Gl.z +550,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [11]
[12] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "Ural-4320T",
["y"] = pointVec3Gl.z +580,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [12]
[13] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "Ural-4320T",
["y"] = pointVec3Gl.z +600,
["x"] = pointVec3Gl.x,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [13]
[14] =
{
["transportable"] =
{
["randomTransportable"] = false,
}, -- end of ["transportable"]
["skill"] = "Random",
["type"] = "ATMZ-5",
["y"] = pointVec3Gl.z +500,
["x"] = pointVec3Gl.x + 20,
["heading"] = 0,
["playerCanDrive"] = true,
livery_id = "desert",
}, -- end of [14]
}, -- end of units
} -- end of function
)
redIADS:addSAMSite("SAM " .. samSim.samSuffix)
local detectChance = math.random(75,100)
local goLiveRange = math.random(50,90)
redIADS:getSAMSiteByGroupName("SAM " .. samSim.samSuffix):setHARMDetectionChance(detectChance)
redIADS:getSAMSiteByGroupName("SAM " .. samSim.samSuffix):setGoLiveRangeInPercent(goLiveRange)
samSim.samSuffix = samSim.samSuffix + 1
end
function samSim.genCMD()
unit = Unit.getByName("Test")
local pointVec3Gl = unit:getPosition().p
mist.dynAddStatic(
{
country = 'USSR',
category = 'Fortifications',
name = "CMD " .. samSim.samSuffix,
type = ".Command Center",
x = pointVec3Gl.x,
y = pointVec3Gl.z,
heading = math.pi*3/2,
} -- end of function
)
nameToAdd = "CMD ".. samSim.samSuffix --.. " " .. "unit1"
local commandCenter = StaticObject.getByName(nameToAdd)
redIADS:addCommandCenter(commandCenter)
redIADS = SkynetIADS:create(nameToAdd)
redIADS:activate()
samSim.samSuffix = samSim.samSuffix + 1
end
function samSim.genEWR()
unit = Unit.getByName("Test")
local pointVec3Gl = unit:getPosition().p
mist.dynAdd(
{
country = 'USSR',
category = 'vehicle',
groupName = "EW " .. samSim.samSuffix,
name = "EW " .. samSim.samSuffix,
groupId = 20000+samSim.samSuffix,
units =
{
[1] =
{
["skill"] = "Random",
["type"] = "55G6 EWR",
["y"] = pointVec3Gl.z,
["x"] = pointVec3Gl.x,
livery_id = "",
["heading"] = 0,
["playerCanDrive"] = true,
},
}, -- end of units
} -- end of function
)
nameToAdd = "EW ".. samSim.samSuffix .. " " .. "unit1" -- oddly this is the unit name not the group, if you don't use this naming convention change it
redIADS:addEarlyWarningRadar(nameToAdd)
--redIADS:addEarlyWarningRadarsByPrefix("EW")
samSim.samSuffix = samSim.samSuffix + 1
end
do
samSims = missionCommands.addSubMenu("Sam stuff")
missionCommands.addCommand ("Spawn SA 10", samSims, samSim.genSAten)
missionCommands.addCommand ("Spawn EWR", samSims, samSim.genEWR)
missionCommands.addCommand ("Spawn SA 2", samSims, samSim.genSAtwo)
missionCommands.addCommand ("Spawn Command Centre and activate", samSims, samSim.genCMD)
end

View File

@ -63,11 +63,13 @@ void Aircraft::changeAltitude(wstring change)
void Aircraft::setTargetSpeed(double newTargetSpeed) {
targetSpeed = newTargetSpeed;
addMeasure(L"targetSpeed", json::value(targetSpeed));
goToDestination();
if (activeDestination != NULL)
goToDestination();
}
void Aircraft::setTargetAltitude(double newTargetAltitude) {
targetAltitude = newTargetAltitude;
addMeasure(L"targetAltitude", json::value(targetAltitude));
goToDestination();
if (activeDestination != NULL)
goToDestination();
}

View File

@ -149,7 +149,7 @@ bool AirUnit::updateActivePath(bool looping)
/* Push the next destination in the queue to the front */
if (looping)
pushActivePathBack(activePath.front());
activePath.pop_front();
popActivePathFront();
log(unitName + L" active path front popped");
return true;
}

View File

@ -179,7 +179,35 @@ void Server::handle_put(http_request request)
void Server::task()
{
http_listener listener(wstring(REST_ADDRESS) + L"/" + wstring(REST_URI));
wstring address = wstring(REST_ADDRESS);
wstring modLocation;
char* buf = nullptr;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
{
std::ifstream ifstream(string(buf) + "\\olympus.json");
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
json::value config = json::value::parse(to_wstring(ss.str()), errorCode);
if (config.is_object() && config.has_object_field(L"server") &&
config[L"server"].has_string_field(L"address") && config[L"server"].has_number_field(L"port"))
{
address = L"http://" + config[L"server"][L"address"].as_string() + L":" + to_wstring(config[L"server"][L"port"].as_number().to_int32());
log(L"Starting server on " + address);
}
else
{
log(L"Error reading configuration file. Starting server on " + address);
}
free(buf);
}
else
{
log(L"DCSOLYMPUS_PATH environment variable is missing, starting server on " + address);
}
http_listener listener(address + L"/" + wstring(REST_URI));
std::function<void(http_request)> handle_options = std::bind(&Server::handle_options, this, std::placeholders::_1);
std::function<void(http_request)> handle_get = std::bind(&Server::handle_get, this, std::placeholders::_1);

View File

@ -201,7 +201,6 @@ void Unit::popActivePathFront()
setActivePath(path);
}
void Unit::setCoalitionID(int newCoalitionID)
{
if (newCoalitionID == 0)