Merge pull request #1108 from Pax1601/1104-add-an-option-to-automatically-show-unit-engagement-range-when-selected

1104 add an option to automatically show unit engagement range when selected
This commit is contained in:
Pax1601 2025-05-18 14:06:51 +02:00 committed by GitHub
commit 71750c43bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 138 additions and 21 deletions

View File

@ -16,6 +16,8 @@ namespace DataIndex {
name,
unitName,
callsign,
unitID,
groupID,
groupName,
state,
task,

View File

@ -75,6 +75,8 @@ public:
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 setUnitID(unsigned char newValue) { updateValue(unitID, newValue, DataIndex::unitID); }
virtual void setGroupID(unsigned char newValue) { updateValue(groupID, newValue, DataIndex::groupID); }
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); }
@ -141,6 +143,8 @@ public:
virtual string getCallsign() { return callsign; }
virtual string getUnitName() { return unitName; }
virtual string getGroupName() { return groupName; }
virtual unsigned char getUnitID() { return unitID; }
virtual unsigned char getGroupID() { return groupID; }
virtual unsigned char getState() { return state; }
virtual string getTask() { return task; }
virtual bool getHasTask() { return hasTask; }
@ -206,6 +210,8 @@ protected:
string name = "";
string unitName = "";
string callsign = "";
unsigned char unitID = NULL;
unsigned char groupID = NULL;
string groupName = "";
unsigned char state = State::NONE;
unsigned char alarmState = AlarmState::AUTO;

View File

@ -40,16 +40,6 @@ GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID)
void GroundUnit::setDefaults(bool force)
{
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */
setState(State::IDLE);
/* Set the default options */
setROE(ROE::WEAPON_FREE, force);
setOnOff(onOff, force);
setFollowRoads(followRoads, force);
/* Load gun values from database */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
@ -74,6 +64,16 @@ void GroundUnit::setDefaults(bool force)
if (databaseEntry.has_number_field(L"acquisitionRange"))
setAcquisitionRange(databaseEntry[L"acquisitionRange"].as_number().to_double());
}
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */
setState(State::IDLE);
/* Set the default options */
setROE(ROE::WEAPON_FREE, force);
setOnOff(onOff, force);
setFollowRoads(followRoads, force);
}
void GroundUnit::setState(unsigned char newState)

View File

@ -37,6 +37,31 @@ NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID)
void NavyUnit::setDefaults(bool force)
{
/* Load gun values from database */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight"))
setBarrelHeight(databaseEntry[L"barrelHeight"].as_number().to_double());
if (databaseEntry.has_number_field(L"muzzleVelocity"))
setMuzzleVelocity(databaseEntry[L"muzzleVelocity"].as_number().to_double());
if (databaseEntry.has_number_field(L"aimTime"))
setAimTime(databaseEntry[L"aimTime"].as_number().to_double());
if (databaseEntry.has_number_field(L"shotsToFire"))
setShotsToFire(databaseEntry[L"shotsToFire"].as_number().to_uint32());
if (databaseEntry.has_number_field(L"engagementRange"))
setEngagementRange(databaseEntry[L"engagementRange"].as_number().to_double());
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
setShotsBaseInterval(databaseEntry[L"shotsBaseInterval"].as_number().to_double());
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
setShotsBaseScatter(databaseEntry[L"shotsBaseScatter"].as_number().to_double());
if (databaseEntry.has_number_field(L"targetingRange"))
setTargetingRange(databaseEntry[L"targetingRange"].as_number().to_double());
if (databaseEntry.has_number_field(L"aimMethodRange"))
setAimMethodRange(databaseEntry[L"aimMethodRange"].as_number().to_double());
if (databaseEntry.has_number_field(L"acquisitionRange"))
setAcquisitionRange(databaseEntry[L"acquisitionRange"].as_number().to_double());
}
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */

View File

@ -41,6 +41,11 @@ void Unit::update(json::value json, double dt)
if (json.has_string_field(L"unitName"))
setUnitName(to_string(json[L"unitName"]));
if (json.has_number_field(L"groupID"))
setGroupID(json[L"groupID"].as_number().to_int32());
if (json.has_number_field(L"unitID"))
setUnitID(json[L"unitID"].as_number().to_int32());
if (json.has_string_field(L"groupName"))
setGroupName(to_string(json[L"groupName"]));
@ -49,8 +54,8 @@ void Unit::update(json::value json, double dt)
if (json.has_number_field(L"coalitionID"))
setCoalition(json[L"coalitionID"].as_number().to_int32());
//if (json.has_number_field(L"Country"))
// setCountry(json[L"Country"].as_number().to_int32());
if (json.has_number_field(L"country"))
setCountry(json[L"country"].as_number().to_int32());
/* All units which contain the name "Olympus" are automatically under AI control */
if (getUnitName().find("Olympus") != string::npos)
@ -267,6 +272,8 @@ void Unit::getData(stringstream& ss, unsigned long long time)
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::unitID: appendNumeric(ss, datumIndex, unitID); break;
case DataIndex::groupID: appendNumeric(ss, datumIndex, groupID); 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;

View File

@ -406,6 +406,7 @@ export const MAP_OPTIONS_DEFAULTS: MapOptions = {
showUnitLabels: true,
showUnitsEngagementRings: true,
showUnitsAcquisitionRings: true,
showUnitsTemporaryEngagementRings: true,
showRacetracks: true,
fillSelectedRing: false,
showMinimap: false,
@ -462,6 +463,8 @@ export enum DataIndexes {
name,
unitName,
callsign,
unitID,
groupID,
groupName,
state,
task,

View File

@ -45,3 +45,7 @@
direction: rtl !important;
}
.range-circle {
filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.8));
}

View File

@ -232,6 +232,8 @@ export interface UnitData {
name: string;
unitName: string;
callsign: string;
unitID: number;
groupID: number;
groupName: string;
state: string;
task: string;

View File

@ -18,6 +18,7 @@ export type MapOptions = {
showUnitLabels: boolean;
showUnitsEngagementRings: boolean;
showUnitsAcquisitionRings: boolean;
showUnitsTemporaryEngagementRings: boolean;
showRacetracks: boolean;
fillSelectedRing: boolean;
showMinimap: boolean;

View File

@ -160,6 +160,17 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; childre
<OlCheckbox checked={mapOptions.showUnitsAcquisitionRings} onChange={() => {}}></OlCheckbox>
<span className="my-auto">Show detection rings</span>
</div>
<div
className={`
group flex cursor-pointer flex-row content-center justify-start
gap-4 rounded-md p-2
dark:hover:bg-olympus-400
`}
onClick={() => getApp().getMap().setOption("showUnitsTemporaryEngagementRings", !mapOptions.showUnitsTemporaryEngagementRings)}
>
<OlCheckbox checked={mapOptions.showUnitsTemporaryEngagementRings} onChange={() => {}}></OlCheckbox>
<span className="my-auto">Show temporary engagement rings</span>
</div>
<div
className={`
group flex cursor-pointer flex-row content-center justify-start

View File

@ -97,6 +97,8 @@ export abstract class Unit extends CustomMarker {
#name: string = "";
#unitName: string = "";
#callsign: string = "";
#unitID: number = 0;
#groupID: number = 0;
#groupName: string = "";
#state: string = states[0];
#task: string = "";
@ -170,6 +172,7 @@ export abstract class Unit extends CustomMarker {
#contactsPolylines: Polyline[] = [];
#engagementCircle: RangeCircle;
#acquisitionCircle: RangeCircle;
#temporaryEngagementCircle: RangeCircle;
#miniMapMarker: CircleMarker | null = null;
#targetPositionMarker: TargetMarker;
#targetPositionPolyline: Polyline;
@ -235,6 +238,12 @@ export abstract class Unit extends CustomMarker {
getCallsign() {
return this.#callsign;
}
getUnitID() {
return this.#unitID;
}
getGroupID() {
return this.#groupID;
}
getGroupName() {
return this.#groupName;
}
@ -442,6 +451,15 @@ export abstract class Unit extends CustomMarker {
interactive: false,
bubblingMouseEvents: false,
});
this.#temporaryEngagementCircle = new RangeCircle(this.getPosition(), {
radius: 0,
weight: 4,
opacity: 1,
fillOpacity: 0,
dashArray: "4 8",
interactive: false,
bubblingMouseEvents: false,
});
this.#racetrackPolylines = [
new Polyline([], { color: colors.WHITE, weight: 3, smoothFactor: 1, dashArray: "5, 5" }),
@ -511,6 +529,10 @@ export abstract class Unit extends CustomMarker {
});
if (this.getSelected()) this.drawLines();
if (mapOptions.showUnitsEngagementRings || mapOptions.showUnitsAcquisitionRings) {
this.hideTemporaryEngagementRing();
}
});
CommandModeOptionsChangedEvent.on((commandModeOptions) => {
@ -595,6 +617,14 @@ export abstract class Unit extends CustomMarker {
case DataIndexes.callsign:
this.#callsign = dataExtractor.extractString();
break;
case DataIndexes.unitID:
this.#unitID = dataExtractor.extractUInt8();
updateMarker = true;
break;
case DataIndexes.groupID:
this.#groupID = dataExtractor.extractUInt8();
updateMarker = true;
break;
case DataIndexes.groupName:
this.#groupName = dataExtractor.extractString();
updateMarker = true;
@ -835,6 +865,8 @@ export abstract class Unit extends CustomMarker {
name: this.#name,
unitName: this.#unitName,
callsign: this.#callsign,
unitID: this.#unitID,
groupID: this.#groupID,
groupName: this.#groupName,
state: this.#state,
task: this.#task,
@ -921,12 +953,14 @@ export abstract class Unit extends CustomMarker {
/* If selected, update the marker to show the selected effects, else clear all the drawings that are only shown for selected units. */
if (selected) {
this.#updateMarker();
this.showTemporaryEngagementRing();
} else {
this.#clearContacts();
this.#clearPath();
this.#clearTargetPosition();
this.#clearRacetrack();
this.#clearSpots();
this.hideTemporaryEngagementRing();
}
/* When the group leader is selected, if grouping is active, all the other group members are also selected */
@ -1604,6 +1638,34 @@ export abstract class Unit extends CustomMarker {
if (!this.#human) getApp().getServerManager().setRacetrack(this.ID, length, anchor, bearing, callback);
}
/** Show temporary engagement ring when unit is selected */
showTemporaryEngagementRing() {
if (!getApp().getMap().getOptions().showUnitsEngagementRings
&& !getApp().getMap().getOptions().showUnitsAcquisitionRings
&& getApp().getMap().getOptions().showUnitsTemporaryEngagementRings
&& this.#engagementRange > 0) {
this.#temporaryEngagementCircle.setLatLng(this.getPosition());
this.#temporaryEngagementCircle.setRadius(this.#engagementRange);
switch (this.getCoalition()) {
case "red":
this.#temporaryEngagementCircle.options.color = adjustBrightness(colors.RED_COALITION, -20);
break;
case "blue":
this.#temporaryEngagementCircle.options.color = adjustBrightness(colors.BLUE_COALITION, -20);
break;
default:
this.#temporaryEngagementCircle.options.color = adjustBrightness(colors.NEUTRAL_COALITION, -20);
break;
}
this.#temporaryEngagementCircle.addTo(getApp().getMap());
}
}
/** Hide temporary engagement ring */
hideTemporaryEngagementRing() {
this.#temporaryEngagementCircle.removeFrom(getApp().getMap());
}
/***********************************************/
onAdd(map: Map): this {
super.onAdd(map);
@ -1680,8 +1742,6 @@ export abstract class Unit extends CustomMarker {
if (this.#debounceTimeout) window.clearTimeout(this.#debounceTimeout);
this.#debounceTimeout = window.setTimeout(() => {
console.log(`Left short click on ${this.getUnitName()}`);
if (getApp().getState() === OlympusState.UNIT_CONTROL && getApp().getMap().getContextAction()) {
if (getApp().getMap().getContextAction()?.getTarget() === ContextActionTarget.UNIT) getApp().getMap().executeContextAction(this, null, e.originalEvent);
else getApp().getMap().executeContextAction(null, this.getPosition(), e.originalEvent);
@ -1693,8 +1753,6 @@ export abstract class Unit extends CustomMarker {
}
#onLeftLongClick(e: any) {
console.log(`Left long click on ${this.getUnitName()}`);
if (getApp().getState() === OlympusState.IDLE) {
this.setSelected(!this.getSelected());
@ -1719,8 +1777,6 @@ export abstract class Unit extends CustomMarker {
}
#onRightShortClick(e: any) {
console.log(`Right short click on ${this.getUnitName()}`);
window.clearTimeout(this.#rightMouseDownTimeout);
if (
getApp().getState() === OlympusState.UNIT_CONTROL &&
@ -1731,7 +1787,7 @@ export abstract class Unit extends CustomMarker {
}
#onRightLongClick(e: any) {
console.log(`Right long click on ${this.getUnitName()}`);
// console.log(`Right long click on ${this.getUnitName()}`);
}
#onDoubleClick(e: any) {
@ -1739,8 +1795,6 @@ export abstract class Unit extends CustomMarker {
DomEvent.preventDefault(e);
e.originalEvent.stopImmediatePropagation();
console.log(`Double click on ${this.getUnitName()}`);
if (this.#debounceTimeout) window.clearTimeout(this.#debounceTimeout);
/* Select all matching units in the viewport */

View File

@ -1249,6 +1249,7 @@ function Olympus.setUnitsData(arg, time)
local airborne = unit:inAir()
-- Fill the data table
table["unitID"] = unit:getID()
table["name"] = unit:getTypeName()
table["coalitionID"] = unit:getCoalition()
table["position"] = {}
@ -1323,6 +1324,7 @@ function Olympus.setUnitsData(arg, time)
end
-- In case of AI units the callSign and the unitName will be the same
table["callsign"] = unit:getName()
table["groupID"] = group:getID()
table["groupName"] = group:getName()
table["isHuman"] = (unit:getPlayerName() ~= nil)
table["hasTask"] = controller:hasTask()