mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
fix: Added missing commander restrictions
This commit is contained in:
parent
69e8fed623
commit
b3e53d07dd
@ -377,6 +377,10 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
{
|
||||
vector<CloneOptions> cloneOptions;
|
||||
bool deleteOriginal = value[L"deleteOriginal"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) return;
|
||||
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
unsigned int ID = unit[L"ID"].as_integer();
|
||||
|
||||
@ -28,6 +28,7 @@ import {
|
||||
TACAN,
|
||||
} from "../interfaces";
|
||||
import { MapOptionsChangedEvent, ServerStatusUpdatedEvent, WrongCredentialsEvent } from "../events";
|
||||
import { Coalition } from "../types/types";
|
||||
|
||||
export class ServerManager {
|
||||
#connected: boolean = false;
|
||||
@ -341,9 +342,10 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
cloneUnits(units: { ID: number; location: LatLng }[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
cloneUnits(units: { ID: number; location: LatLng }[], deleteOriginal: boolean, spawnPoints: number, coalition: Coalition, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
units: units,
|
||||
coalition: coalition,
|
||||
deleteOriginal: deleteOriginal,
|
||||
spawnPoints: spawnPoints,
|
||||
};
|
||||
|
||||
@ -122,8 +122,8 @@ export function SpawnContextMenu(props: {}) {
|
||||
setXPosition(xPosition - 60);
|
||||
setYPosition(yPosition - 40);
|
||||
}
|
||||
}, [blueprint, translated])
|
||||
useEffect(translateMenu, [blueprint, translated])
|
||||
}, [blueprint, translated]);
|
||||
useEffect(translateMenu, [blueprint, translated]);
|
||||
|
||||
/* Filter the blueprints according to the label */
|
||||
const filteredBlueprints: UnitBlueprint[] = [];
|
||||
@ -306,6 +306,9 @@ export function SpawnContextMenu(props: {}) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blueprints.length === 0 && <span className={`
|
||||
text-gray-200
|
||||
`}>No aircraft available</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@ -353,6 +356,9 @@ export function SpawnContextMenu(props: {}) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blueprints.length === 0 && <span className={`
|
||||
text-gray-200
|
||||
`}>No helicopter available</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@ -403,6 +409,9 @@ export function SpawnContextMenu(props: {}) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blueprints.length === 0 && <span className={`
|
||||
text-gray-200
|
||||
`}>No air defence unit available</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@ -453,6 +462,9 @@ export function SpawnContextMenu(props: {}) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blueprints.length === 0 && <span className={`
|
||||
text-gray-200
|
||||
`}>No ground unit available</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@ -500,10 +512,13 @@ export function SpawnContextMenu(props: {}) {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blueprints.length === 0 && <span className={`
|
||||
text-gray-200
|
||||
`}>No navy unit available</span>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{openAccordion === CategoryGroup.EFFECT && (
|
||||
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode === GAME_MASTER && (
|
||||
<>
|
||||
<div
|
||||
className={`
|
||||
@ -530,6 +545,11 @@ export function SpawnContextMenu(props: {}) {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode !== GAME_MASTER && (
|
||||
<div className="text-white">
|
||||
Not available in this mode
|
||||
</div>
|
||||
)}
|
||||
{openAccordion === CategoryGroup.SEARCH && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<OlSearchBar onChange={(value) => setFilterString(value)} text={filterString} />
|
||||
|
||||
@ -117,10 +117,9 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
<div key={idx}>
|
||||
{Object.keys(runway.headings[0]).map((runwayName) => {
|
||||
return (
|
||||
<div
|
||||
key={`${idx}-${runwayName}`}
|
||||
className={`flex w-full justify-between`}
|
||||
>
|
||||
<div key={`${idx}-${runwayName}`} className={`
|
||||
flex w-full justify-between
|
||||
`}>
|
||||
<span>
|
||||
{" "}
|
||||
<span className="text-gray-400">RWY</span> {runwayName}
|
||||
@ -213,6 +212,9 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "aircraft").length === 0 && (
|
||||
<span className={`text-gray-400`}>No aircraft available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -264,6 +266,9 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "helicopter").length === 0 && (
|
||||
<span className={`text-gray-400`}>No helicopter available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
</div>
|
||||
|
||||
@ -124,12 +124,19 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
<h2 className="mb-4 font-bold">Spawn menu</h2>
|
||||
<p>The spawn menu allows you to spawn new units in the current mission.</p>
|
||||
<p>Moreover, it allows you to spawn effects like smokes and explosions.</p>
|
||||
<p className="mt-2">You can use the search bar to quickly find a specific unit. Otherwise, open the category you are interested in, and use the filters to refine your selection. </p>
|
||||
<img src="images/training/unitfilter.png" className={`
|
||||
mx-auto my-4 w-[80%] rounded-lg
|
||||
drop-shadow-[0_0px_7px_rgba(255,255,255,0.07)]
|
||||
`} />
|
||||
<div className="mt-2">Click on a unit to enter the spawn properties menu. The menu is divided into multiple sections:
|
||||
<p className="mt-2">
|
||||
You can use the search bar to quickly find a specific unit. Otherwise, open the category you are interested in, and use the filters to refine your
|
||||
selection.{" "}
|
||||
</p>
|
||||
<img
|
||||
src="images/training/unitfilter.png"
|
||||
className={`
|
||||
mx-auto my-4 w-[80%] rounded-lg
|
||||
drop-shadow-[0_0px_7px_rgba(255,255,255,0.07)]
|
||||
`}
|
||||
/>
|
||||
<div className="mt-2">
|
||||
Click on a unit to enter the spawn properties menu. The menu is divided into multiple sections:
|
||||
<ul className="ml-4 mt-2 list-inside list-decimal">
|
||||
<li>Unit name and short description</li>
|
||||
<li>Quick access name </li>
|
||||
@ -139,11 +146,18 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
</div>
|
||||
<p>To get more info on each control, hover your cursor on it.</p>
|
||||
<h2 className="my-4 font-bold">Quick access</h2>
|
||||
<p>If you plan on reusing the same spawn multiple times during the mission, you can "star" the spawn properties. This will allow you to reuse them quickly multiple times. The starred spawn will save all settings, so you can create starred spawn with multiple variations, e.g. loadouts, or skill levels.</p>
|
||||
<img src="images/training/starred.png" className={`
|
||||
mx-auto my-4 w-[80%] rounded-lg
|
||||
drop-shadow-[0_0px_7px_rgba(255,255,255,0.07)]
|
||||
`} />
|
||||
<p>
|
||||
If you plan on reusing the same spawn multiple times during the mission, you can "star" the spawn properties. This will allow you to reuse them
|
||||
quickly multiple times. The starred spawn will save all settings, so you can create starred spawn with multiple variations, e.g. loadouts, or
|
||||
skill levels.
|
||||
</p>
|
||||
<img
|
||||
src="images/training/starred.png"
|
||||
className={`
|
||||
mx-auto my-4 w-[80%] rounded-lg
|
||||
drop-shadow-[0_0px_7px_rgba(255,255,255,0.07)]
|
||||
`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
@ -202,6 +216,9 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "aircraft").length === 0 && (
|
||||
<span className={`text-gray-400`}>No aircraft available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -254,6 +271,9 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "helicopter").length === 0 && (
|
||||
<span className={`text-gray-400`}>No helicopter available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -285,6 +305,9 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "groundunit" && blueprint.type === "SAM Site").length === 0 && (
|
||||
<span className={`text-gray-400`}>No SAM sites available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -316,6 +339,9 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.canAAA).length === 0 && <span className={`
|
||||
text-gray-400
|
||||
`}>No AAA unit available</span>}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -371,6 +397,9 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "groundunit" && blueprint.type !== "SAM Site").length === 0 && (
|
||||
<span className={`text-gray-400`}>No ground unit available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
@ -423,41 +452,46 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredBlueprints.filter((blueprint) => blueprint.category === "navyunit").length === 0 && (
|
||||
<span className={`text-gray-400`}>No navy unit available</span>
|
||||
)}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
title="Effects (smokes, explosions etc)"
|
||||
open={openAccordion == CategoryAccordion.EFFECT}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.EFFECT ? CategoryAccordion.NONE : CategoryAccordion.EFFECT);
|
||||
setSelectedRole(null);
|
||||
setSelectedType(null);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
{commandModeOptions.commandMode === GAME_MASTER && (
|
||||
<OlAccordion
|
||||
title="Effects (smokes, explosions etc)"
|
||||
open={openAccordion == CategoryAccordion.EFFECT}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.EFFECT ? CategoryAccordion.NONE : CategoryAccordion.EFFECT);
|
||||
setSelectedRole(null);
|
||||
setSelectedType(null);
|
||||
}}
|
||||
>
|
||||
<OlEffectListEntry
|
||||
key={"explosion"}
|
||||
icon={faExplosion}
|
||||
label={"Explosion"}
|
||||
onClick={() => {
|
||||
setEffect("explosion");
|
||||
}}
|
||||
/>
|
||||
<OlEffectListEntry
|
||||
key={"smoke"}
|
||||
icon={faSmog}
|
||||
label={"Smoke"}
|
||||
onClick={() => {
|
||||
setEffect("smoke");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
>
|
||||
<OlEffectListEntry
|
||||
key={"explosion"}
|
||||
icon={faExplosion}
|
||||
label={"Explosion"}
|
||||
onClick={() => {
|
||||
setEffect("explosion");
|
||||
}}
|
||||
/>
|
||||
<OlEffectListEntry
|
||||
key={"smoke"}
|
||||
icon={faSmog}
|
||||
label={"Smoke"}
|
||||
onClick={() => {
|
||||
setEffect("smoke");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</OlAccordion>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
msToKnots,
|
||||
} from "../other/utils";
|
||||
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
|
||||
import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, OlympusState, UnitControlSubState } from "../constants/constants";
|
||||
import { BLUE_COMMANDER, DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, OlympusState, RED_COMMANDER, UnitControlSubState } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { citiesDatabase } from "./databases/citiesdatabase";
|
||||
import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
|
||||
@ -39,6 +39,7 @@ import {
|
||||
import { UnitDatabase } from "./databases/unitdatabase";
|
||||
import * as turf from "@turf/turf";
|
||||
import { PathMarker } from "../map/markers/pathmarker";
|
||||
import { Coalition } from "../types/types";
|
||||
|
||||
/** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only
|
||||
* result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows
|
||||
@ -1257,12 +1258,20 @@ export class UnitsManager {
|
||||
if (units === null) units = this.getSelectedUnits();
|
||||
units = units.filter((unit) => !unit.getHuman());
|
||||
|
||||
// TODO: maybe check units are all of same coalition?
|
||||
|
||||
let callback = (units) => {
|
||||
onExecution();
|
||||
if (this.getUnitsCategories(units).length == 1) {
|
||||
var unitsData: { ID: number; location: LatLng }[] = [];
|
||||
units.forEach((unit: Unit) => unitsData.push({ ID: unit.ID, location: unit.getPosition() }));
|
||||
getApp().getServerManager().cloneUnits(unitsData, true, 0 /* No spawn points, we delete the original units */);
|
||||
|
||||
/* Determine the coalition */
|
||||
let coalition = "all";
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode === BLUE_COMMANDER) coalition = "blue";
|
||||
else if (getApp().getMissionManager().getCommandModeOptions().commandMode === RED_COMMANDER) coalition = "red";
|
||||
|
||||
getApp().getServerManager().cloneUnits(unitsData, true, 0 /* No spawn points, we delete the original units */, coalition as Coalition);
|
||||
this.#showActionMessage(units, `created a group`);
|
||||
} else {
|
||||
getApp().addInfoMessage(`Groups can only be created from units of the same category`);
|
||||
@ -1469,9 +1478,13 @@ export class UnitsManager {
|
||||
units.push({ ID: unit.ID, location: position });
|
||||
});
|
||||
|
||||
let coalition = "all";
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode === BLUE_COMMANDER) coalition = "blue";
|
||||
else if (getApp().getMissionManager().getCommandModeOptions().commandMode === RED_COMMANDER) coalition = "red";
|
||||
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.cloneUnits(units, false, spawnPoints, (res: any) => {
|
||||
.cloneUnits(units, false, getApp().getMissionManager().getCommandModeOptions().commandMode === GAME_MASTER? 0: spawnPoints, coalition as Coalition, (res: any) => {
|
||||
if (res !== undefined) {
|
||||
markers.forEach((marker: TemporaryUnitMarker) => {
|
||||
marker.setCommandHash(res);
|
||||
@ -1655,7 +1668,7 @@ export class UnitsManager {
|
||||
getApp().addInfoMessage("Aircrafts can be air spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
spawnPoints = getApp().getMissionManager().getCommandModeOptions().commandMode === GAME_MASTER? 0: units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + this.getDatabase().getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () => getApp().getServerManager().spawnAircrafts(units, coalition, airbase, country, immediate, spawnPoints, callback);
|
||||
@ -1664,7 +1677,7 @@ export class UnitsManager {
|
||||
getApp().addInfoMessage("Helicopters can be air spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
spawnPoints = getApp().getMissionManager().getCommandModeOptions().commandMode === GAME_MASTER? 0: units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + this.getDatabase().getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () => getApp().getServerManager().spawnHelicopters(units, coalition, airbase, country, immediate, spawnPoints, callback);
|
||||
@ -1673,7 +1686,7 @@ export class UnitsManager {
|
||||
getApp().addInfoMessage("Ground units can be spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
spawnPoints = getApp().getMissionManager().getCommandModeOptions().commandMode === GAME_MASTER? 0: units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + this.getDatabase().getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () => getApp().getServerManager().spawnGroundUnits(units, coalition, country, immediate, spawnPoints, callback);
|
||||
@ -1682,7 +1695,7 @@ export class UnitsManager {
|
||||
getApp().addInfoMessage("Navy units can be spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
spawnPoints = getApp().getMissionManager().getCommandModeOptions().commandMode === GAME_MASTER? 0: units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + this.getDatabase().getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () => getApp().getServerManager().spawnNavyUnits(units, coalition, country, immediate, spawnPoints, callback);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user