Added effect of acquisition range to wake units up

Note: alertness time constant suppressed
This commit is contained in:
Pax1601 2023-11-23 16:40:18 +01:00
parent 6e84423032
commit dcbfdf8666
5 changed files with 4202 additions and 2265 deletions

6369
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1120,7 +1120,8 @@
"cost": 15000000,
"tags": "Radar, CA",
"markerFile": "groundunit-aaa",
"canAAA": true
"canAAA": true,
"shotsBaseScatter": null
},
"Grad-URAL": {
"name": "Grad-URAL",
@ -2387,7 +2388,8 @@
"shotsToFire": 100,
"tags": "Russian type 1",
"markerFile": "groundunit-infantry",
"canAAA": true
"canAAA": true,
"aimMethodRange": 3600
},
"KAMAZ Truck": {
"name": "KAMAZ Truck",
@ -7238,7 +7240,8 @@
"shotsToFire": 100,
"tags": "Insurgent",
"markerFile": "groundunit-infantry",
"canAAA": true
"canAAA": true,
"aimMethodRange": 3600
},
"MLRS FDDM": {
"name": "MLRS FDDM",
@ -7283,7 +7286,8 @@
"shotsToFire": 100,
"tags": "Russian type 2",
"markerFile": "groundunit-infantry",
"canAAA": true
"canAAA": true,
"aimMethodRange": 3600
},
"Infantry AK ver3": {
"name": "Infantry AK ver3",
@ -7306,7 +7310,8 @@
"shotsToFire": 100,
"tags": "Russian type 3",
"markerFile": "groundunit-infantry",
"canAAA": true
"canAAA": true,
"aimMethodRange": 3600
},
"Smerch_HE": {
"name": "Smerch_HE",
@ -8039,7 +8044,7 @@
"canRearm": false,
"muzzleVelocity": 1200,
"barrelHeight": 3,
"aimTime": 11,
"aimTime": 20,
"shotsToFire": 100,
"cost": 750000,
"tags": "CA",

View File

@ -148,9 +148,14 @@ export class UnitControlPanel extends Panel {
/* This is for when a ctrl-click happens on the map for deselection and we need to remove the selected unit from the panel */
document.addEventListener("unitsDeselection", (ev: CustomEventInit) => {
this.show();
this.addButtons();
this.#updateRapidControls();
if (ev.detail.length > 0) {
this.show();
this.addButtons();
this.#updateRapidControls();
} else {
this.hide();
this.#updateRapidControls();
}
});
window.addEventListener("resize", (e: any) => this.#calculateMaxHeight());
@ -233,13 +238,13 @@ export class UnitControlPanel extends Panel {
element.toggleAttribute("data-show-roe", !isTanker && !isAWACS);
element.toggleAttribute("data-show-threat", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-shots-scatter", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-shots-intensity", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-shots-scatter", this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-shots-intensity", this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-tanker-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isTanker(); }) === true);
element.toggleAttribute("data-show-AWACS-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isAWACS(); }) === true);
element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")));
element.toggleAttribute("data-show-operate-as", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getCoalition() }) === "neutral");
element.toggleAttribute("data-show-operate-as", this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit") && getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getCoalition() }) === "neutral");
if (this.#units.length == 1) {
if (isAWACS)

View File

@ -17,7 +17,7 @@ public:
virtual void setOnOff(bool newOnOff, bool force = false);
virtual void setFollowRoads(bool newFollowRoads, bool force = false);
void aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier = 1, double verticalScatterMultiplier = 1);
void aimAtPoint(Coords aimTarget);
protected:
virtual void AIloop();

View File

@ -192,7 +192,7 @@ void GroundUnit::AIloop()
setTask("Simulating fire fight");
if (internalCounter == 0) {
aimAtPoint(targetPosition, 3.0, 0.0);
aimAtPoint(targetPosition);
}
if (internalCounter == 0)
@ -261,6 +261,7 @@ void GroundUnit::AIloop()
double engagementRange = 10000; /* m */
double targetingRange = 0; /* m */
double aimMethodRange = 0; /* m */
double acquisitionRange = 0; /* m */
/* Load gun values from database */
if (database.has_object_field(to_wstring(name))) {
@ -283,11 +284,14 @@ void GroundUnit::AIloop()
targetingRange = databaseEntry[L"targetingRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"aimMethodRange"))
aimMethodRange = databaseEntry[L"aimMethodRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"acquisitionRange"))
acquisitionRange = databaseEntry[L"acquisitionRange"].as_number().to_double();
}
/* Get all the units in range and select one at random */
double range = aimMethodRange > engagementRange ? aimMethodRange : engagementRange;
double range = max(max(engagementRange, aimMethodRange), acquisitionRange);
map<Unit*, double> targets = unitsManager->getUnitsInRange(this, targetCoalition, { "Aircraft", "Helicopter" }, range);
Unit* target = nullptr;
unsigned int index = static_cast<unsigned int>((RANDOM_ZERO_TO_ONE * (targets.size() - 1)));
for (auto const& p : targets) {
@ -303,8 +307,6 @@ void GroundUnit::AIloop()
if (muzzleVelocity != 0)
aimTime += distance / muzzleVelocity;
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
/* If the target is in targeting range and we are in highest precision mode, target it */
if (distance < targetingRange && shotsScatter == ShotsScatter::LOW) {
/* Send the command */
@ -314,38 +316,51 @@ void GroundUnit::AIloop()
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
}
/* Else, do miss on purpose */
else {
/* Compute where the target will be in aimTime seconds. */
double aimDistance = target->getHorizontalVelocity() * aimTime;
/* Compute where the target will be in aimTime seconds, plus the effect of scatter. */
double scatterDistance = distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * (RANDOM_ZERO_TO_ONE - 0.1);
double aimDistance = target->getHorizontalVelocity() * aimTime + scatterDistance;
double aimLat = 0;
double aimLng = 0;
Geodesic::WGS84().Direct(target->getPosition().lat, target->getPosition().lng, target->getHeading() * 57.29577, aimDistance, aimLat, aimLng); /* TODO make util to convert degrees and radians function */
double aimAlt = target->getPosition().alt + target->getVerticalVelocity() * aimTime;
double aimAlt = target->getPosition().alt + target->getVerticalVelocity() * aimTime + distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_ZERO_TO_ONE; // Force to always miss high never low
/* Send the command */
if (distance > engagementRange) {
aimAtPoint(Coords(aimLat, aimLng, aimAlt));
}
else {
/* Compute a random scattering depending on the distance and the selected shots scatter */
double scatterDistance = distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_MINUS_ONE_TO_ONE;
double scatterAngle = 180 * RANDOM_MINUS_ONE_TO_ONE;
Geodesic::WGS84().Direct(aimLat, aimLng, scatterAngle, scatterDistance, aimLat, aimLng); /* TODO make util function */
aimAlt = aimAlt + distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_MINUS_ONE_TO_ONE;
if (distance < engagementRange) {
/* If the unit is closer than the engagement range, use the fire at point method */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001, expendQty = " << shotsToFire << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
}
else if (distance < aimMethodRange) {
/* If the unit is closer than the aim method range, use the aim method range */
aimAtPoint(Coords(aimLat, aimLng, aimAlt));
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
}
else {
/* Else just wake the unit up with an impossible command */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << 0 << ", lng = " << 0 << ", alt = " << 0 << ", radius = 0.001, expendQty = " << 0 << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
setTargetPosition(Coords(NULL));
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
/* Don't wait too long before checking again */
internalCounter = 5 / FRAMERATE_TIME_INTERVAL;
}
}
missOnPurposeTarget = target;
}
else {
@ -362,7 +377,7 @@ void GroundUnit::AIloop()
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
}
internalCounter = (5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant) / FRAMERATE_TIME_INTERVAL;
internalCounter = (5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant * 0 /* TODO: remove to enable alertness again */) / FRAMERATE_TIME_INTERVAL;
missOnPurposeTarget = nullptr;
setTargetPosition(Coords(NULL));
}
@ -380,7 +395,7 @@ void GroundUnit::AIloop()
}
void GroundUnit::aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier, double verticalScatterMultiplier) {
void GroundUnit::aimAtPoint(Coords aimTarget) {
double dist;
double bearing1;
double bearing2;
@ -411,12 +426,11 @@ void GroundUnit::aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier
/* Check we can reach the target*/
if (inner > 0) {
/* Compute elevation and bearing */
double barrelElevation = r * tan(atan((dist - sqrt(inner)) / (2 * alpha)) + RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter) * verticalScatterMultiplier);
double barrelElevation = r * (dist - sqrt(inner)) / (2 * alpha);
double lat = 0;
double lng = 0;
double randomBearing = bearing1 + RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter) * horizontalScatterMultiplier;
Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
Geodesic::WGS84().Direct(position.lat, position.lng, bearing1, r, lat, lng);
std::ostringstream taskSS;
taskSS.precision(10);