mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
fix: Fixed multiple errors in scenic AAA modes
This commit is contained in:
parent
5acc0e8ac5
commit
f0826bbdba
@ -62,6 +62,8 @@ public:
|
||||
bool hasFreshData(unsigned long long time);
|
||||
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
|
||||
|
||||
unsigned int computeTotalAmmo();
|
||||
|
||||
/********** Setters **********/
|
||||
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
|
||||
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
|
||||
@ -240,26 +242,29 @@ protected:
|
||||
unsigned char shotsIntensity = 2;
|
||||
unsigned char health = 100;
|
||||
double timeToNextTasking = 0;
|
||||
double barrelHeight = 1.0; /* m */
|
||||
double muzzleVelocity = 860; /* m/s */
|
||||
double aimTime = 10; /* s */
|
||||
unsigned int shotsToFire = 10;
|
||||
double shotsBaseInterval = 15; /* s */
|
||||
double shotsBaseScatter = 2; /* degs */
|
||||
double engagementRange = 10000; /* m */
|
||||
double targetingRange = 0; /* m */
|
||||
double aimMethodRange = 0; /* m */
|
||||
double acquisitionRange = 0; /* m */
|
||||
double barrelHeight = 0;
|
||||
double muzzleVelocity = 0;
|
||||
double aimTime = 0;
|
||||
unsigned int shotsToFire = 0;
|
||||
double shotsBaseInterval = 0;
|
||||
double shotsBaseScatter = 0;
|
||||
double engagementRange = 0;
|
||||
double targetingRange = 0;
|
||||
double aimMethodRange = 0;
|
||||
double acquisitionRange = 0;
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
unsigned int internalCounter = 0;
|
||||
Unit* missOnPurposeTarget = nullptr;
|
||||
bool hasTaskAssigned = false;
|
||||
double initialFuel = 0;
|
||||
map<unsigned char, unsigned long long> updateTimeMap;
|
||||
unsigned long long lastLoopTime = 0;
|
||||
bool enableTaskFailedCheck = false;
|
||||
unsigned long nextTaskingMilliseconds = 0;
|
||||
unsigned int totalShellsFired = 0;
|
||||
unsigned int shellsFiredAtTasking = 0;
|
||||
unsigned int oldAmmo = 0;
|
||||
|
||||
/********** Private methods **********/
|
||||
virtual void AIloop() = 0;
|
||||
|
||||
@ -113,4 +113,10 @@ class Bomb : public Weapon
|
||||
{
|
||||
public:
|
||||
Bomb(json::value json, unsigned int ID);
|
||||
};
|
||||
|
||||
class Shell : public Weapon
|
||||
{
|
||||
public:
|
||||
Shell(json::value json, unsigned int ID);
|
||||
};
|
||||
@ -168,6 +168,18 @@ void GroundUnit::setState(unsigned char newState)
|
||||
void GroundUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
unsigned long timeNow = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
|
||||
|
||||
double currentAmmo = computeTotalAmmo();
|
||||
/* Out of ammo */
|
||||
if (currentAmmo <= shotsToFire && state != State::IDLE) {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
|
||||
/* Account for unit reloading */
|
||||
if (currentAmmo < oldAmmo)
|
||||
totalShellsFired += oldAmmo - currentAmmo;
|
||||
oldAmmo = currentAmmo;
|
||||
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
@ -241,7 +253,11 @@ void GroundUnit::AIloop()
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
string taskString = "";
|
||||
|
||||
if (internalCounter == 0 && targetPosition != Coords(NULL) && scheduler->getLoad() < 30) {
|
||||
if (
|
||||
(totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) &&
|
||||
targetPosition != Coords(NULL) &&
|
||||
scheduler->getLoad() < 30
|
||||
) {
|
||||
/* Get the distance and bearing to the target */
|
||||
Coords scatteredTargetPosition = targetPosition;
|
||||
double distance;
|
||||
@ -249,9 +265,12 @@ void GroundUnit::AIloop()
|
||||
double bearing2;
|
||||
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, scatteredTargetPosition.lat, scatteredTargetPosition.lng, distance, bearing1, bearing2);
|
||||
|
||||
/* Apply a scatter to the aim */
|
||||
bearing1 += RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter + 1) * 10;
|
||||
|
||||
/* Compute the scattered position applying a random scatter to the shot */
|
||||
double scatterDistance = distance * tan(10 /* degs */ * (ShotsScatter::LOW - shotsScatter) / 57.29577 + 2 / 57.29577 /* degs */) * RANDOM_MINUS_ONE_TO_ONE;
|
||||
Geodesic::WGS84().Direct(scatteredTargetPosition.lat, scatteredTargetPosition.lng, bearing1 + 90, scatterDistance, scatteredTargetPosition.lat, scatteredTargetPosition.lng);
|
||||
Geodesic::WGS84().Direct(scatteredTargetPosition.lat, scatteredTargetPosition.lng, bearing1, scatterDistance, scatteredTargetPosition.lat, scatteredTargetPosition.lng);
|
||||
|
||||
/* Recover the data from the database */
|
||||
bool indirectFire = false;
|
||||
@ -267,9 +286,10 @@ void GroundUnit::AIloop()
|
||||
log(unitName + "(" + name + ")" + " simulating fire fight with indirect fire");
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << scatteredTargetPosition.lat << ", lng = " << scatteredTargetPosition.lng << ", radius = 100}";
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << scatteredTargetPosition.lat << ", lng = " << scatteredTargetPosition.lng << ", radius = 0.01}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
}
|
||||
/* Otherwise use the aim method */
|
||||
@ -281,18 +301,17 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
|
||||
/* Wait an amout of time depending on the shots intensity */
|
||||
internalCounter = static_cast<unsigned int>(((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + aimTime) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
|
||||
if (targetPosition == Coords(NULL))
|
||||
setState(State::IDLE);
|
||||
|
||||
/* Fallback if something went wrong */
|
||||
if (internalCounter == 0)
|
||||
internalCounter = static_cast<unsigned int>(3 / FRAMERATE_TIME_INTERVAL);
|
||||
internalCounter--;
|
||||
if (timeNow >= nextTaskingMilliseconds)
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(3 * 1000);
|
||||
|
||||
setTimeToNextTasking(internalCounter * FRAMERATE_TIME_INTERVAL);
|
||||
setTimeToNextTasking(((nextTaskingMilliseconds - timeNow) / 1000.0));
|
||||
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
@ -303,7 +322,8 @@ void GroundUnit::AIloop()
|
||||
string taskString = "";
|
||||
|
||||
/* Only perform scenic functions when the scheduler is "free" */
|
||||
if (((!getHasTask() && scheduler->getLoad() < 30) || internalCounter == 0)) {
|
||||
if ((totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) &&
|
||||
scheduler->getLoad() < 30) {
|
||||
double distance = 0;
|
||||
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
|
||||
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
|
||||
@ -341,17 +361,18 @@ void GroundUnit::AIloop()
|
||||
taskString += "Scenic AAA. Bearing: " + to_string((int)round(randomBearing)) + "deg";
|
||||
}
|
||||
|
||||
taskString += ". Aim point elevation " + to_string((int) round(barrelElevation)) + "m AGL";
|
||||
taskString += ". Aim point elevation " + to_string((int) round(barrelElevation - position.alt)) + "m AGL";
|
||||
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << barrelElevation << ", radius = 0.001, expendQty = " << shotsToFire << " }";
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << barrelElevation << ", radius = 0.001 }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
|
||||
/* Wait an amout of time depending on the shots intensity */
|
||||
internalCounter = static_cast<unsigned int>(((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + aimTime) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else {
|
||||
if (target == nullptr)
|
||||
@ -361,11 +382,10 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = static_cast<unsigned int>(3 / FRAMERATE_TIME_INTERVAL);
|
||||
internalCounter--;
|
||||
if (timeNow >= nextTaskingMilliseconds)
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(3 * 1000);
|
||||
|
||||
setTimeToNextTasking(internalCounter * FRAMERATE_TIME_INTERVAL);
|
||||
setTimeToNextTasking((nextTaskingMilliseconds - timeNow) / 1000.0);
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
|
||||
@ -385,7 +405,8 @@ void GroundUnit::AIloop()
|
||||
if (canAAA) {
|
||||
/* Only perform scenic functions when the scheduler is "free" */
|
||||
/* Only run this when the internal counter reaches 0 to avoid excessive computations when no nearby target */
|
||||
if (scheduler->getLoad() < 30 && internalCounter == 0) {
|
||||
if ((totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) &&
|
||||
scheduler->getLoad() < 30) {
|
||||
double distance = 0;
|
||||
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
|
||||
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
|
||||
@ -422,9 +443,10 @@ void GroundUnit::AIloop()
|
||||
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
|
||||
internalCounter = static_cast<unsigned int>((correctedAimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
/* Else, do miss on purpose */
|
||||
else {
|
||||
@ -443,14 +465,15 @@ void GroundUnit::AIloop()
|
||||
/* 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 << " }";
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001 }";
|
||||
|
||||
taskString += ". Aiming altitude " + to_string((int)round((aimAlt - position.alt) / 0.3048)) + "ft AGL";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
internalCounter = static_cast<unsigned int>((correctedAimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else if (distance < aimMethodRange) {
|
||||
taskString += ". Range is less than aim method range (" + to_string((int)round(aimMethodRange / 0.3048)) + "ft), using AIM method.";
|
||||
@ -460,7 +483,7 @@ void GroundUnit::AIloop()
|
||||
taskString += aimMethodTask;
|
||||
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
internalCounter = static_cast<unsigned int>((correctedAimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else {
|
||||
taskString += ". Target is not in range of weapon, waking up unit to get ready for tasking.";
|
||||
@ -471,11 +494,12 @@ void GroundUnit::AIloop()
|
||||
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);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
setTargetPosition(Coords(NULL));
|
||||
|
||||
/* Don't wait too long before checking again */
|
||||
internalCounter = static_cast<unsigned int>(5 / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(5 * 1000);
|
||||
}
|
||||
}
|
||||
missOnPurposeTarget = target;
|
||||
@ -488,24 +512,24 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
|
||||
/* If no valid target was detected */
|
||||
if (internalCounter == 0) {
|
||||
if (timeNow >= nextTaskingMilliseconds) {
|
||||
double alertnessTimeConstant = 10; /* s */
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
|
||||
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
|
||||
}
|
||||
internalCounter = static_cast<unsigned int>((5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant) / FRAMERATE_TIME_INTERVAL);
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>((5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant) * 1000L);
|
||||
missOnPurposeTarget = nullptr;
|
||||
setTargetPosition(Coords(NULL));
|
||||
}
|
||||
internalCounter--;
|
||||
|
||||
}
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
|
||||
setTimeToNextTasking(internalCounter * FRAMERATE_TIME_INTERVAL);
|
||||
setTimeToNextTasking((nextTaskingMilliseconds - timeNow) / 1000.0);
|
||||
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
@ -528,20 +552,6 @@ string GroundUnit::aimAtPoint(Coords aimTarget) {
|
||||
/* Aim point distance */
|
||||
double r = 15; /* m */
|
||||
|
||||
/* Default gun values */
|
||||
double barrelHeight = 1.0; /* m */
|
||||
double muzzleVelocity = 860; /* m/s */
|
||||
double shotsBaseScatter = 5; /* degs */
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"barrelHeight") && databaseEntry.has_number_field(L"muzzleVelocity")) {
|
||||
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
|
||||
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
|
||||
}
|
||||
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
|
||||
shotsBaseScatter = databaseEntry[L"shotsBaseScatter"].as_number().to_double();
|
||||
}
|
||||
|
||||
/* Compute the elevation angle of the gun*/
|
||||
double deltaHeight = (aimTarget.alt - (position.alt + barrelHeight));
|
||||
double alpha = 9.81 / 2 * dist * dist / (muzzleVelocity * muzzleVelocity);
|
||||
@ -564,6 +574,7 @@ string GroundUnit::aimAtPoint(Coords aimTarget) {
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation + barrelHeight << ", radius = 0.001}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -825,3 +825,11 @@ void Unit::setHasTaskAssigned(bool newHasTaskAssigned) {
|
||||
void Unit::triggerUpdate(unsigned char datumIndex) {
|
||||
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
unsigned int Unit::computeTotalAmmo()
|
||||
{
|
||||
unsigned int totalShells = 0;
|
||||
for (auto const& ammoItem : ammo)
|
||||
totalShells += ammoItem.quantity;
|
||||
return totalShells;
|
||||
}
|
||||
|
||||
@ -113,4 +113,11 @@ Bomb::Bomb(json::value json, unsigned int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Bomb created with ID: " + to_string(ID));
|
||||
setCategory("Bomb");
|
||||
};
|
||||
|
||||
/* Shell */
|
||||
Shell::Shell(json::value json, unsigned int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Shell created with ID: " + to_string(ID));
|
||||
setCategory("Shell");
|
||||
};
|
||||
@ -41,6 +41,8 @@ void WeaponsManager::update(json::value& json, double dt)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Missile(p.second, ID));
|
||||
else if (category.compare("Bomb") == 0)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Bomb(p.second, ID));
|
||||
else if (category.compare("Shell") == 0)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Shell(p.second, ID));
|
||||
|
||||
/* Initialize the weapon if creation was successfull */
|
||||
if (weapons.count(ID) != 0) {
|
||||
|
||||
@ -129,7 +129,7 @@
|
||||
"canRearm": false,
|
||||
"muzzleVelocity": 1000,
|
||||
"barrelHeight": 2,
|
||||
"aimTime": 5,
|
||||
"aimTime": 7,
|
||||
"shotsToFire": 10,
|
||||
"cost": null,
|
||||
"tags": "Optical, Radar, CA",
|
||||
@ -587,7 +587,7 @@
|
||||
"abilities": "Combined arms, Amphibious, Transport, AA",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"aimTime": 5,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -819,7 +819,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.2,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -955,7 +955,7 @@
|
||||
"acquisitionRange": 3000,
|
||||
"engagementRange": 1000,
|
||||
"description": "Armoured car, MRAP. Wheeled. Amphibious. 12.7 mm machine gun.",
|
||||
"abilities": "Combined arms, Amphibious, AA",
|
||||
"abilities": "Combined arms, Amphibious",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2,
|
||||
@ -969,7 +969,7 @@
|
||||
"shotsBaseInterval": 6,
|
||||
"shotsBaseScatter": 10,
|
||||
"alertnessTimeConstant": 4,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"Dog Ear radar": {
|
||||
"name": "Dog Ear radar",
|
||||
@ -1188,7 +1188,7 @@
|
||||
"abilities": "Combined arms, AA",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"aimTime": 8,
|
||||
"aimTime": 7,
|
||||
"shotsToFire": 5,
|
||||
"cost": null,
|
||||
"tags": "Radar, CA",
|
||||
@ -2280,7 +2280,7 @@
|
||||
"abilities": "AA, Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"tags": "Russian type 1",
|
||||
"markerFile": "groundunit-infantry",
|
||||
@ -2789,7 +2789,7 @@
|
||||
"shotsBaseInterval": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"aimTime": 5,
|
||||
"aimTime": 7,
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 4,
|
||||
@ -2931,7 +2931,7 @@
|
||||
"aimMethodRange": 300,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 3,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"M-109": {
|
||||
"name": "M-109",
|
||||
@ -3096,7 +3096,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.8,
|
||||
"muzzleVelocity": 950,
|
||||
"aimTime": 5,
|
||||
"aimTime": 2.5,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -3265,7 +3265,7 @@
|
||||
"markerFile": "groundunit-tactical",
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 2500,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"shotsBaseInterval": 5,
|
||||
"shotsBaseScatter": 5,
|
||||
@ -3368,7 +3368,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 3,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 2.7,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -3800,7 +3800,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.05,
|
||||
"muzzleVelocity": 800,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -3845,13 +3845,13 @@
|
||||
},
|
||||
"acquisitionRange": 3000,
|
||||
"engagementRange": 1000,
|
||||
"description": "Marder Infantry FIghting Vehicle. Tracked. Amphibious. 20 mm gun and 7.62 mm machine gun.",
|
||||
"description": "Marder Infantry Fighting Vehicle. Tracked. Amphibious. 20 mm gun and 7.62 mm machine gun.",
|
||||
"abilities": "Combined arms, Transport, Amphibious",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.82,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 9,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -3917,7 +3917,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Russian paratrooper carrying AKS-74.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 0.9,
|
||||
@ -3926,7 +3926,7 @@
|
||||
"shotsToFire": 5,
|
||||
"tags": "Russian Para",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 2000,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -3955,7 +3955,7 @@
|
||||
"shotsToFire": 1,
|
||||
"tags": "Russian Para",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 50,
|
||||
"aimMethodRange": 750,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -5613,7 +5613,7 @@
|
||||
"abilities": "AA, Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"aimTime": 5,
|
||||
"aimTime": 2.5,
|
||||
"shotsToFire": 5,
|
||||
"tags": "Russian type 4",
|
||||
"markerFile": "groundunit-infantry",
|
||||
@ -5679,7 +5679,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Solider carrying M249.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"muzzleVelocity": 915,
|
||||
@ -5688,7 +5688,7 @@
|
||||
"barrelHeight": 0.25,
|
||||
"tags": "US",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 2000,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -5758,7 +5758,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Solider carrying M4.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 0.95,
|
||||
@ -5767,7 +5767,7 @@
|
||||
"shotsToFire": 5,
|
||||
"tags": "Georgia",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 2000,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -5829,7 +5829,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Solider carrying M4.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 1,
|
||||
@ -5838,7 +5838,7 @@
|
||||
"shotsToFire": 5,
|
||||
"tags": "US",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 2000,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -5909,7 +5909,7 @@
|
||||
"shotsToFire": 1,
|
||||
"tags": "Russian",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"targetingRange": 50,
|
||||
"aimMethodRange": 750,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -6200,7 +6200,7 @@
|
||||
"aimMethodRange": 2500,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 6,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"T-72B": {
|
||||
"name": "T-72B",
|
||||
@ -6234,7 +6234,7 @@
|
||||
"muzzleVelocity": 700,
|
||||
"aimMethodRange": 2500,
|
||||
"alertnessTimeConstant": 4,
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"tags": "CA"
|
||||
},
|
||||
"T-80UD": {
|
||||
@ -6310,7 +6310,7 @@
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 5,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"T-90": {
|
||||
"name": "T-90",
|
||||
@ -6374,7 +6374,7 @@
|
||||
"shotsToFire": 5,
|
||||
"shotsBaseInterval": 8,
|
||||
"tags": "CA",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"alertnessTimeConstant": 3,
|
||||
"shotsBaseScatter": 5,
|
||||
"aimMethodRange": 3000
|
||||
@ -6406,7 +6406,7 @@
|
||||
"shotsBaseInterval": 5,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 5,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"Tigr_233036": {
|
||||
"name": "Tigr_233036",
|
||||
@ -6757,7 +6757,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 8,
|
||||
"aimTime": 6,
|
||||
"muzzleVelocity": 1000,
|
||||
"barrelHeight": 3,
|
||||
"cost": null,
|
||||
@ -6795,7 +6795,7 @@
|
||||
"cost": null,
|
||||
"barrelHeight": 3,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 8,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-aaa",
|
||||
@ -7028,7 +7028,7 @@
|
||||
"cost": null,
|
||||
"barrelHeight": 2.5,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 8,
|
||||
"shotsToFire": 5,
|
||||
"tags": "Radar, CA",
|
||||
"markerFile": "groundunit-aaa",
|
||||
@ -7240,7 +7240,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 1.8,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 9,
|
||||
"aimTime": 13,
|
||||
"shotsToFire": 5,
|
||||
"cost": null,
|
||||
"tags": "Radar, CA",
|
||||
@ -7325,7 +7325,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 9,
|
||||
"aimTime": 6,
|
||||
"muzzleVelocity": 1000,
|
||||
"barrelHeight": 1.5,
|
||||
"cost": null,
|
||||
@ -7377,7 +7377,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 9,
|
||||
"aimTime": 6,
|
||||
"muzzleVelocity": 1000,
|
||||
"barrelHeight": 1.5,
|
||||
"cost": null,
|
||||
@ -7413,7 +7413,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 9,
|
||||
"aimTime": 6,
|
||||
"muzzleVelocity": 1000,
|
||||
"barrelHeight": 1.5,
|
||||
"cost": null,
|
||||
@ -7795,7 +7795,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Insurgent solider carrying AK-74.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 0.9,
|
||||
@ -7804,7 +7804,7 @@
|
||||
"shotsToFire": 5,
|
||||
"tags": "Insurgent",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"aimMethodRange": 2000,
|
||||
"targetingRange": 100,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -7958,7 +7958,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 0.9,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"tags": "Russian type 2",
|
||||
"markerFile": "groundunit-infantry",
|
||||
@ -8047,7 +8047,7 @@
|
||||
"acquisitionRange": 2500,
|
||||
"engagementRange": 300,
|
||||
"description": "Russian solider carrying AK-74.",
|
||||
"abilities": "AA, Embark",
|
||||
"abilities": "Embark",
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"barrelHeight": 0.9,
|
||||
@ -8056,7 +8056,7 @@
|
||||
"shotsToFire": 5,
|
||||
"tags": "Russian type 3",
|
||||
"markerFile": "groundunit-infantry",
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"aimMethodRange": 2000,
|
||||
"targetingRange": 100,
|
||||
"shotsBaseInterval": 5,
|
||||
@ -8227,7 +8227,7 @@
|
||||
"tags": "CA",
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
"canAAA": true,
|
||||
"canAAA": false,
|
||||
"alertnessTimeConstant": 3
|
||||
},
|
||||
"LiAZ Bus": {
|
||||
@ -8619,24 +8619,25 @@
|
||||
"countries": "All"
|
||||
}
|
||||
},
|
||||
"acquisitionRange": 16000,
|
||||
"engagementRange": 2000,
|
||||
"acquisitionRange": 30000,
|
||||
"engagementRange": 21000,
|
||||
"description": "KS-19. 100 mm AAA gun. Fixed manually aimed large calibre anti aircraft gun.",
|
||||
"abilities": "AA",
|
||||
"canTargetPoint": false,
|
||||
"canRearm": false,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 25,
|
||||
"aimTime": 15,
|
||||
"shotsToFire": 5,
|
||||
"barrelHeight": 5,
|
||||
"cost": null,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true,
|
||||
"targetingRange": 100,
|
||||
"aimMethodRange": 15000,
|
||||
"aimMethodRange": 100,
|
||||
"shotsBaseInterval": 5,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 5
|
||||
"alertnessTimeConstant": 5,
|
||||
"flak": true
|
||||
},
|
||||
"SON_9": {
|
||||
"name": "SON_9",
|
||||
@ -8969,7 +8970,7 @@
|
||||
"cost": null,
|
||||
"barrelHeight": 2,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 5,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-aaa",
|
||||
@ -9016,7 +9017,7 @@
|
||||
"cost": null,
|
||||
"barrelHeight": 2,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 5,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-aaa",
|
||||
@ -9329,7 +9330,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.6,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -9520,7 +9521,7 @@
|
||||
"canRearm": false,
|
||||
"muzzleVelocity": 1200,
|
||||
"barrelHeight": 3,
|
||||
"aimTime": 20,
|
||||
"aimTime": 10,
|
||||
"shotsToFire": 5,
|
||||
"cost": null,
|
||||
"tags": "CA",
|
||||
@ -9558,7 +9559,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"muzzleVelocity": 1000,
|
||||
"aimTime": 5,
|
||||
"aimTime": 10,
|
||||
"shotsToFire": 5,
|
||||
"barrelHeight": 2,
|
||||
"cost": null,
|
||||
@ -9645,7 +9646,7 @@
|
||||
"barrelHeight": 2.7,
|
||||
"shotsBaseInterval": 8,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 3,
|
||||
"aimMethodRange": 3000,
|
||||
@ -9771,7 +9772,7 @@
|
||||
"canRearm": false,
|
||||
"barrelHeight": 2.8,
|
||||
"muzzleVelocity": 900,
|
||||
"aimTime": 5,
|
||||
"aimTime": 4,
|
||||
"shotsToFire": 5,
|
||||
"tags": "CA",
|
||||
"markerFile": "groundunit-apc",
|
||||
@ -10634,7 +10635,7 @@
|
||||
"countries": "All"
|
||||
}
|
||||
},
|
||||
"aimTime": 25,
|
||||
"aimTime": 15,
|
||||
"shotsToFire": 2,
|
||||
"acquisitionRange": 15000,
|
||||
"engagementRange": 12000,
|
||||
@ -10649,9 +10650,10 @@
|
||||
"canAAA": true,
|
||||
"shotsBaseInterval": 10,
|
||||
"shotsBaseScatter": 5,
|
||||
"aimMethodRange": 15000,
|
||||
"targetingRange": 200,
|
||||
"alertnessTimeConstant": 15
|
||||
"aimMethodRange": 100,
|
||||
"targetingRange": 100,
|
||||
"alertnessTimeConstant": 15,
|
||||
"flak": true
|
||||
},
|
||||
"Pz_IV_H": {
|
||||
"name": "Pz_IV_H",
|
||||
@ -10768,7 +10770,7 @@
|
||||
"aimMethodRange": 3000,
|
||||
"barrelHeight": 2.7,
|
||||
"muzzleVelocity": 700,
|
||||
"aimTime": 5,
|
||||
"aimTime": 3,
|
||||
"shotsToFire": 5,
|
||||
"shotsBaseInterval": 6,
|
||||
"tags": "CA",
|
||||
@ -10879,7 +10881,7 @@
|
||||
"barrelHeight": 2.7,
|
||||
"shotsBaseInterval": 7,
|
||||
"tags": "CA",
|
||||
"aimTime": 5,
|
||||
"aimTime": 6,
|
||||
"shotsToFire": 5,
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
@ -10957,7 +10959,7 @@
|
||||
"barrelHeight": 2.7,
|
||||
"shotsBaseInterval": 7,
|
||||
"shotsToFire": 5,
|
||||
"aimTime": 5,
|
||||
"aimTime": 8,
|
||||
"tags": "CA",
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
@ -11195,7 +11197,7 @@
|
||||
"alertnessTimeConstant": 3,
|
||||
"shotsBaseScatter": 5,
|
||||
"aimMethodRange": 3000,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"ZBD04A": {
|
||||
"name": "ZBD04A",
|
||||
@ -11357,7 +11359,7 @@
|
||||
"aimMethodRange": 3000,
|
||||
"shotsBaseScatter": 5,
|
||||
"alertnessTimeConstant": 6,
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"Kubelwagen_82": {
|
||||
"name": "Kubelwagen_82",
|
||||
@ -11860,7 +11862,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"Flakscheinwerfer_37": {
|
||||
"name": "Flakscheinwerfer_37",
|
||||
@ -11896,7 +11898,8 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": true,
|
||||
"flak": true
|
||||
},
|
||||
"Maschinensatz_33": {
|
||||
"name": "Maschinensatz_33",
|
||||
@ -11932,7 +11935,7 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": false
|
||||
},
|
||||
"soldier_mauser98": {
|
||||
"name": "soldier_mauser98",
|
||||
@ -12516,7 +12519,8 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": true,
|
||||
"aimTime": 6
|
||||
},
|
||||
"Allies_Director": {
|
||||
"name": "Allies_Director",
|
||||
@ -12886,7 +12890,8 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": true,
|
||||
"aimTime": 6
|
||||
},
|
||||
"M1_37mm": {
|
||||
"name": "M1_37mm",
|
||||
@ -12922,7 +12927,8 @@
|
||||
"canTargetPoint": true,
|
||||
"canRearm": false,
|
||||
"markerFile": "groundunit-aaa",
|
||||
"canAAA": true
|
||||
"canAAA": true,
|
||||
"aimTime": 5
|
||||
},
|
||||
"DR_50Ton_Flat_Wagon": {
|
||||
"name": "DR_50Ton_Flat_Wagon",
|
||||
@ -13069,7 +13075,8 @@
|
||||
"name": "Winter",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flak": true
|
||||
},
|
||||
"flak36": {
|
||||
"name": "flak36",
|
||||
@ -13097,7 +13104,8 @@
|
||||
"name": "Winter",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flak": true
|
||||
},
|
||||
"flak37": {
|
||||
"name": "flak37",
|
||||
@ -13125,7 +13133,8 @@
|
||||
"name": "Winter",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flak": true
|
||||
},
|
||||
"flak38": {
|
||||
"name": "flak38",
|
||||
@ -13153,7 +13162,8 @@
|
||||
"name": "Winter",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flak": true
|
||||
},
|
||||
"flak41": {
|
||||
"name": "flak41",
|
||||
@ -13181,7 +13191,8 @@
|
||||
"name": "Winter",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flak": true
|
||||
},
|
||||
"HEMTT_C-RAM_Phalanx": {
|
||||
"name": "HEMTT_C-RAM_Phalanx",
|
||||
|
||||
43
frontend/react/public/images/units/map/awacs/blue/shell.svg
Normal file
43
frontend/react/public/images/units/map/awacs/blue/shell.svg
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shell.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.26"
|
||||
inkscape:cx="25.03075"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 24.992747,19.632095 c 1.718432,1.191442 1.737049,6.906456 1.741766,10.585026 h -3.483451 c 0.07653,-3.377681 -0.03261,-9.113527 1.741685,-10.585026 z"
|
||||
fill="#5ca7ff"
|
||||
stroke="#082e44"
|
||||
stroke-width="0.814233"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cccc"
|
||||
style="fill:#424242;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shell.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.26"
|
||||
inkscape:cx="25.03075"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 24.992747,19.632095 c 1.718432,1.191442 1.737049,6.906456 1.741766,10.585026 h -3.483451 c 0.07653,-3.377681 -0.03261,-9.113527 1.741685,-10.585026 z"
|
||||
fill="#5ca7ff"
|
||||
stroke="#082e44"
|
||||
stroke-width="0.814233"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cccc"
|
||||
style="fill:#424242;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
43
frontend/react/public/images/units/map/normal/blue/shell.svg
Normal file
43
frontend/react/public/images/units/map/normal/blue/shell.svg
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shell.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.26"
|
||||
inkscape:cx="25.03075"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 24.992747,19.632095 c 1.718432,1.191442 1.737049,6.906456 1.741766,10.585026 h -3.483451 c 0.07653,-3.377681 -0.03261,-9.113527 1.741685,-10.585026 z"
|
||||
fill="#5ca7ff"
|
||||
stroke="#082e44"
|
||||
stroke-width="0.814233"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cccc"
|
||||
style="fill:#424242;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shell.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.26"
|
||||
inkscape:cx="25.03075"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 24.992747,19.632095 c 1.718432,1.191442 1.737049,6.906456 1.741766,10.585026 h -3.483451 c 0.07653,-3.377681 -0.03261,-9.113527 1.741685,-10.585026 z"
|
||||
fill="#5ca7ff"
|
||||
stroke="#082e44"
|
||||
stroke-width="0.814233"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cccc"
|
||||
style="fill:#424242;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
43
frontend/react/public/images/units/map/normal/red/shell.svg
Normal file
43
frontend/react/public/images/units/map/normal/red/shell.svg
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 50 50"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shell.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.26"
|
||||
inkscape:cx="25.03075"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 24.992747,19.632095 c 1.718432,1.191442 1.737049,6.906456 1.741766,10.585026 h -3.483451 c 0.07653,-3.377681 -0.03261,-9.113527 1.741685,-10.585026 z"
|
||||
fill="#5ca7ff"
|
||||
stroke="#082e44"
|
||||
stroke-width="0.814233"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="cccc"
|
||||
style="fill:#424242;fill-opacity:1;stroke:#000000;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -507,11 +507,6 @@ export class Map extends L.Map {
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
});
|
||||
|
||||
/* Periodically check if the camera control endpoint is available */
|
||||
this.#cameraControlTimer = window.setInterval(() => {
|
||||
this.#checkCameraPort();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
setLayerName(layerName: string) {
|
||||
@ -1298,33 +1293,6 @@ export class Map extends L.Map {
|
||||
return minimapBoundaries;
|
||||
}
|
||||
|
||||
#setSlaveDCSCameraAvailable(newSlaveDCSCameraAvailable: boolean) {
|
||||
this.#slaveDCSCameraAvailable = newSlaveDCSCameraAvailable;
|
||||
}
|
||||
|
||||
/* Check if the camera control plugin is available. Right now this will only change the color of the button, no changes in functionality */
|
||||
#checkCameraPort() {
|
||||
if (this.#cameraOptionsXmlHttp?.readyState !== 4) this.#cameraOptionsXmlHttp?.abort();
|
||||
|
||||
this.#cameraOptionsXmlHttp = new XMLHttpRequest();
|
||||
|
||||
/* Using 127.0.0.1 instead of localhost because the LuaSocket version used in DCS only listens to IPv4. This avoids the lag caused by the
|
||||
browser if it first tries to send the request on the IPv6 address for localhost */
|
||||
this.#cameraOptionsXmlHttp.open("OPTIONS", `http://127.0.0.1:${this.#cameraControlPort}`);
|
||||
this.#cameraOptionsXmlHttp.onload = (res: any) => {
|
||||
if (this.#cameraOptionsXmlHttp !== null && this.#cameraOptionsXmlHttp.status == 204) this.#setSlaveDCSCameraAvailable(true);
|
||||
else this.#setSlaveDCSCameraAvailable(false);
|
||||
};
|
||||
this.#cameraOptionsXmlHttp.onerror = (res: any) => {
|
||||
this.#setSlaveDCSCameraAvailable(false);
|
||||
};
|
||||
this.#cameraOptionsXmlHttp.ontimeout = (res: any) => {
|
||||
this.#setSlaveDCSCameraAvailable(false);
|
||||
};
|
||||
this.#cameraOptionsXmlHttp.timeout = 500;
|
||||
this.#cameraOptionsXmlHttp.send("");
|
||||
}
|
||||
|
||||
#drawIPToTargetLine() {
|
||||
if (this.#targetPoint && this.#IPPoint) {
|
||||
if (!this.#IPToTargetLine) {
|
||||
|
||||
@ -188,6 +188,8 @@ export abstract class Unit extends CustomMarker {
|
||||
#targetingRange: number = 0;
|
||||
#aimMethodRange: number = 0;
|
||||
#acquisitionRange: number = 0;
|
||||
#totalAmmo: number = 0;
|
||||
#previousTotalAmmo: number = 0;
|
||||
|
||||
/* Inputs timers */
|
||||
#debounceTimeout: number | null = null;
|
||||
@ -654,6 +656,8 @@ export abstract class Unit extends CustomMarker {
|
||||
break;
|
||||
case DataIndexes.ammo:
|
||||
this.#ammo = dataExtractor.extractAmmo();
|
||||
this.#previousTotalAmmo = this.#totalAmmo;
|
||||
this.#totalAmmo = this.#ammo.reduce((prev: number, ammo: Ammo) => prev + ammo.quantity, 0);
|
||||
break;
|
||||
case DataIndexes.contacts:
|
||||
this.#contacts = dataExtractor.extractContacts();
|
||||
|
||||
@ -43,6 +43,7 @@ export abstract class Weapon extends CustomMarker {
|
||||
static getConstructor(type: string) {
|
||||
if (type === "Missile") return Missile;
|
||||
if (type === "Bomb") return Bomb;
|
||||
if (type === "Shell") return Shell;
|
||||
}
|
||||
|
||||
constructor(ID: number) {
|
||||
@ -330,3 +331,40 @@ export class Bomb extends Weapon {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Shell extends Weapon {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Shell";
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)) return "shell";
|
||||
else return "aircraft";
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return {
|
||||
showState: false,
|
||||
showVvi:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showHealth: false,
|
||||
showHotgroup: false,
|
||||
showUnitIcon: this.belongsToCommandedCoalition() || this.getDetectionMethods().some((value) => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value)),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showCallsign: false,
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ export class WeaponsManager {
|
||||
/** Add a new weapon to the manager
|
||||
*
|
||||
* @param ID ID of the new weapon
|
||||
* @param category Either "Missile" or "Bomb". Determines what class will be used to create the new unit accordingly.
|
||||
* @param category Either "Missile", "Bomb" or "Shell". Determines what class will be used to create the new unit accordingly.
|
||||
*/
|
||||
addWeapon(ID: number, category: string) {
|
||||
if (category) {
|
||||
|
||||
@ -1415,6 +1415,8 @@ function Olympus.setWeaponsData(arg, time)
|
||||
table["category"] = "Missile"
|
||||
elseif weapon:getDesc().category == Weapon.Category.BOMB then
|
||||
table["category"] = "Bomb"
|
||||
elseif weapon:getDesc().category == Weapon.Category.SHELL then
|
||||
table["category"] = "Shell"
|
||||
end
|
||||
else
|
||||
weapons[ID] = {isAlive = false}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user