diff --git a/backend/core/include/datatypes.h b/backend/core/include/datatypes.h index c0e1c86e..fec3cb5b 100644 --- a/backend/core/include/datatypes.h +++ b/backend/core/include/datatypes.h @@ -13,6 +13,7 @@ namespace DataIndex { country, name, unitName, + callsign, groupName, state, task, diff --git a/backend/core/include/unit.h b/backend/core/include/unit.h index 5ba64e7c..a4ded619 100644 --- a/backend/core/include/unit.h +++ b/backend/core/include/unit.h @@ -71,6 +71,7 @@ public: virtual void setCountry(unsigned char newValue) { updateValue(country, newValue, DataIndex::country); } virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); } virtual void setUnitName(string newValue) { updateValue(unitName, newValue, DataIndex::unitName); } + virtual void setCallsign(string newValue) { updateValue(callsign, newValue, DataIndex::callsign); } virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); } virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); }; virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); } @@ -117,6 +118,7 @@ public: virtual unsigned char getCoalition() { return coalition; } virtual unsigned char getCountry() { return country; } virtual string getName() { return name; } + virtual string getCallsign() { return callsign; } virtual string getUnitName() { return unitName; } virtual string getGroupName() { return groupName; } virtual unsigned char getState() { return state; } @@ -167,6 +169,7 @@ protected: unsigned char country = NULL; string name = ""; string unitName = ""; + string callsign = ""; string groupName = ""; unsigned char state = State::NONE; string task = ""; diff --git a/backend/core/src/unit.cpp b/backend/core/src/unit.cpp index f35c5c1f..4bd03fba 100644 --- a/backend/core/src/unit.cpp +++ b/backend/core/src/unit.cpp @@ -37,6 +37,9 @@ void Unit::initialize(json::value json) if (json.has_string_field(L"groupName")) setGroupName(to_string(json[L"groupName"])); + if (json.has_string_field(L"callsign")) + setCallsign(to_string(json[L"callsign"])); + if (json.has_number_field(L"coalitionID")) setCoalition(json[L"coalitionID"].as_number().to_int32()); @@ -255,6 +258,7 @@ void Unit::getData(stringstream& ss, unsigned long long time) case DataIndex::country: appendNumeric(ss, datumIndex, country); break; case DataIndex::name: appendString(ss, datumIndex, name); break; case DataIndex::unitName: appendString(ss, datumIndex, unitName); break; + case DataIndex::callsign: appendString(ss, datumIndex, callsign); break; case DataIndex::groupName: appendString(ss, datumIndex, groupName); break; case DataIndex::state: appendNumeric(ss, datumIndex, state); break; case DataIndex::task: appendString(ss, datumIndex, task); break; diff --git a/frontend/server/public/stylesheets/markers/units.css b/frontend/server/public/stylesheets/markers/units.css index e2cba54d..119150c9 100644 --- a/frontend/server/public/stylesheets/markers/units.css +++ b/frontend/server/public/stylesheets/markers/units.css @@ -160,6 +160,8 @@ column-gap: 6px; display: flex; flex-wrap: wrap; + flex-direction: column; + align-items: flex-end; font-size: 11px; font-weight: bold; justify-content: right; @@ -173,18 +175,22 @@ -1px 1px 0 #000, 1px 1px 0 #000; right: 100%; - width: fit-content; + width: max-content; } [data-hide-labels] [data-object|="unit"] .unit-summary { display: none; } +[data-hide-original-callsign] [data-object|="unit"] .unit-original-callsign { + display: none; +} + [data-object|="unit"] .unit-summary>* { padding: 1px; } -[data-object|="unit"] .unit-summary .unit-callsign { +[data-object|="unit"] .unit-summary .unit-callsign .unit-group { color: white; overflow: hidden; text-align: right; diff --git a/frontend/website/src/constants/constants.ts b/frontend/website/src/constants/constants.ts index 7d411761..fddb20b6 100644 --- a/frontend/website/src/constants/constants.ts +++ b/frontend/website/src/constants/constants.ts @@ -251,6 +251,7 @@ export const SHOW_UNIT_PATHS = "Show selected unit paths"; export const SHOW_UNIT_TARGETS = "Show selected unit targets"; export const DCS_LINK_PORT = "DCS Camera link port"; export const DCS_LINK_RATIO = "DCS Camera zoom"; +export const SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN = "Show human controlled unit original callsign"; export enum DataIndexes { startOfData = 0, @@ -262,6 +263,7 @@ export enum DataIndexes { country, name, unitName, + callsign, groupName, state, task, diff --git a/frontend/website/src/interfaces.ts b/frontend/website/src/interfaces.ts index ef60bd07..fc38ff01 100644 --- a/frontend/website/src/interfaces.ts +++ b/frontend/website/src/interfaces.ts @@ -90,6 +90,7 @@ export interface ObjectIconOptions { showAmmo: boolean, showSummary: boolean, showCallsign: boolean, + showOriginalCallsign?: boolean, rotateToHeading: boolean } @@ -144,6 +145,7 @@ export interface UnitData { country: number; name: string; unitName: string; + callsign: string; groupName: string; state: string; task: string; diff --git a/frontend/website/src/map/map.ts b/frontend/website/src/map/map.ts index 35c240e8..39e6c0d4 100644 --- a/frontend/website/src/map/map.ts +++ b/frontend/website/src/map/map.ts @@ -12,7 +12,7 @@ import { DestinationPreviewMarker } from "./markers/destinationpreviewmarker"; import { TemporaryUnitMarker } from "./markers/temporaryunitmarker"; import { ClickableMiniMap } from "./clickableminimap"; import { SVGInjector } from '@tanem/svg-injector' -import { defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, MAP_MARKER_CONTROLS, DCS_LINK_PORT, DCS_LINK_RATIO, defaultMapMirrors } from "../constants/constants"; +import { defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, MAP_MARKER_CONTROLS, DCS_LINK_PORT, DCS_LINK_RATIO, defaultMapMirrors, SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN } from "../constants/constants"; import { CoalitionArea } from "./coalitionarea/coalitionarea"; import { CoalitionAreaContextMenu } from "../contextmenus/coalitionareacontextmenu"; import { DrawingCursor } from "./coalitionarea/drawingcursor"; @@ -152,6 +152,9 @@ export class Map extends L.Map { /* Init the state machine */ this.#state = IDLE; + /* By default let's hide human controlled unit original callsign */ + this.getContainer().toggleAttribute("data-hide-original-callsign", !this.getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN]); + /* Register event handles */ this.on("click", (e: any) => this.#onClick(e)); this.on("dblclick", (e: any) => this.#onDoubleClick(e)); @@ -212,6 +215,7 @@ export class Map extends L.Map { document.addEventListener("mapOptionsChanged", () => { this.getContainer().toggleAttribute("data-hide-labels", !this.getVisibilityOptions()[SHOW_UNIT_LABELS]); + this.getContainer().toggleAttribute("data-hide-original-callsign", !this.getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN]); this.#cameraControlPort = this.getVisibilityOptions()[DCS_LINK_PORT] as number; this.#cameraZoomRatio = 50 / (20 + (this.getVisibilityOptions()[DCS_LINK_RATIO] as number)); @@ -303,6 +307,7 @@ export class Map extends L.Map { this.addVisibilityOption(SHOW_UNITS_ENGAGEMENT_RINGS, true); this.addVisibilityOption(SHOW_UNITS_ACQUISITION_RINGS, true); this.addVisibilityOption(HIDE_UNITS_SHORT_RANGE_RINGS, true); + this.addVisibilityOption(SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN, false); /* this.addVisibilityOption(FILL_SELECTED_RING, false); Removed since currently broken: TODO fix!*/ } diff --git a/frontend/website/src/unit/unit.ts b/frontend/website/src/unit/unit.ts index ab8f8b9a..a85a1eaa 100644 --- a/frontend/website/src/unit/unit.ts +++ b/frontend/website/src/unit/unit.ts @@ -5,7 +5,7 @@ import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; import { UnitDatabase } from './databases/unitdatabase'; import { TargetMarker } from '../map/markers/targetmarker'; -import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, GROUPING_ZOOM_TRANSITION, MAX_SHOTS_SCATTER, SHOTS_SCATTER_DEGREES, GROUND_UNIT_AIR_DEFENCE_REGEX } from '../constants/constants'; +import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, GROUPING_ZOOM_TRANSITION, MAX_SHOTS_SCATTER, SHOTS_SCATTER_DEGREES, GROUND_UNIT_AIR_DEFENCE_REGEX, SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN } from '../constants/constants'; import { DataExtractor } from '../server/dataextractor'; import { groundUnitDatabase } from './databases/groundunitdatabase'; import { navyUnitDatabase } from './databases/navyunitdatabase'; @@ -36,6 +36,7 @@ export abstract class Unit extends CustomMarker { #country: number = 0; #name: string = ""; #unitName: string = ""; + #callsign: string = ""; #groupName: string = ""; #state: string = states[0]; #task: string = "" @@ -119,6 +120,7 @@ export abstract class Unit extends CustomMarker { getCountry() { return this.#country }; getName() { return this.#name }; getUnitName() { return this.#unitName }; + getCallsign() { return this.#callsign }; getGroupName() { return this.#groupName }; getState() { return this.#state }; getTask() { return this.#task }; @@ -279,6 +281,7 @@ export abstract class Unit extends CustomMarker { case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break; case DataIndexes.name: this.#name = dataExtractor.extractString(); break; case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break; + case DataIndexes.callsign: this.#callsign = dataExtractor.extractString(); break; case DataIndexes.groupName: this.#groupName = dataExtractor.extractString(); updateMarker = true; break; case DataIndexes.state: this.#state = enumToState(dataExtractor.extractUInt8()); updateMarker = true; break; case DataIndexes.task: this.#task = dataExtractor.extractString(); break; @@ -358,6 +361,7 @@ export abstract class Unit extends CustomMarker { country: this.#country, name: this.#name, unitName: this.#unitName, + callsign: this.#callsign, groupName: this.#groupName, state: this.#state, task: this.#task, @@ -423,7 +427,7 @@ export abstract class Unit extends CustomMarker { setSelected(selected: boolean) { /* Only alive units can be selected that belong to the commanded coalition can be selected */ if ((this.#alive || !selected) && this.belongsToCommandedCoalition() && this.getSelected() != selected) { - this.#selected = selected; + this.#selected = selected; /* If selected, update the marker to show the selected effects, else clear all the drawings that are only shown for selected units. */ if (selected) { @@ -678,13 +682,20 @@ export abstract class Unit extends CustomMarker { if (iconOptions.showSummary) { var summary = document.createElement("div"); summary.classList.add("unit-summary"); + + var originalCallsign = document.createElement("div"); + originalCallsign.classList.add("unit-original-callsign"); + originalCallsign.innerText = this.#callsign; + var callsign = document.createElement("div"); callsign.classList.add("unit-callsign"); callsign.innerText = this.#unitName; + var altitude = document.createElement("div"); altitude.classList.add("unit-altitude"); var speed = document.createElement("div"); speed.classList.add("unit-speed"); + if (this.#human) summary.appendChild(originalCallsign); if (iconOptions.showCallsign) summary.appendChild(callsign); summary.appendChild(altitude); summary.appendChild(speed); @@ -1485,6 +1496,7 @@ export abstract class Unit extends CustomMarker { export abstract class AirUnit extends Unit { getIconOptions() { var belongsToCommandedCoalition = this.belongsToCommandedCoalition(); + var showHumanControlledUnitGroup = getApp().getMap().getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN] as boolean; return { showState: belongsToCommandedCoalition, showVvi: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), @@ -1496,6 +1508,7 @@ export abstract class AirUnit extends Unit { showAmmo: belongsToCommandedCoalition, showSummary: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showCallsign: belongsToCommandedCoalition, + showOriginalCallsign: showHumanControlledUnitGroup, rotateToHeading: false }; } diff --git a/scripts/lua/backend/OlympusCommand.lua b/scripts/lua/backend/OlympusCommand.lua index 390abf57..e1615965 100644 --- a/scripts/lua/backend/OlympusCommand.lua +++ b/scripts/lua/backend/OlympusCommand.lua @@ -1074,6 +1074,8 @@ function Olympus.setUnitsData(arg, time) else table["unitName"] = unit:getName() end + -- In case of AI units the callSign and the unitName will be the same + table["callsign"] = unit:getName() table["groupName"] = group:getName() table["isHuman"] = (unit:getPlayerName() ~= nil) table["hasTask"] = controller:hasTask()