diff --git a/ace_fcs.dll b/ace_fcs.dll new file mode 100644 index 0000000000..9907d9e1a0 Binary files /dev/null and b/ace_fcs.dll differ diff --git a/addons/fcs/functions/fnc_keyUp.sqf b/addons/fcs/functions/fnc_keyUp.sqf index fc76ff2639..2621455916 100644 --- a/addons/fcs/functions/fnc_keyUp.sqf +++ b/addons/fcs/functions/fnc_keyUp.sqf @@ -105,59 +105,28 @@ if (_viewDiff != 0) then { _FCSAzimuth = (atan (_distance / _viewDiff) - (abs _viewDiff / _viewDiff) * 90) + _movingAzimuth; }; -// CALCULATE OFFSET FOR CURRENT WEAPON +// CALCULATE OFFSET _FCSMagazines = []; _FCSElevation = []; -_magazineType = currentMagazine _vehicle; -_ammoType = getText (configFile >> "CfgMagazines" >> _magazineType >> "ammo"); -if !(getText (configFile >> "CfgAmmo" >> _ammoType >> "simulation") == "shotMissile") then { - _maxElev = getNumber (configFile >> "CfgVehicles" >> typeOf _vehicle >> "Turrets" >> "MainTurret" >> "maxElev"); - _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineType >> "initSpeed"); - _airFriction = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "airFriction"); - _timeToLive = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "timeToLive"); - _simulationStep = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "simulationStep"); +{ + _ammoType = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); + if !(getText (configFile >> "CfgAmmo" >> _ammoType >> "simulation") == "shotMissile") then { + _maxElev = getNumber (configFile >> "CfgVehicles" >> typeOf _vehicle >> "Turrets" >> "MainTurret" >> "maxElev"); + _initSpeed = getNumber (configFile >> "CfgMagazines" >> _x >> "initSpeed"); + _airFriction = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "airFriction"); - _offset = [_distance, _angleTarget, _maxElev, _initSpeed, _airFriction, _timeToLive, _simulationStep] call FUNC(getAngle); + _offset = "ace_fcs" callExtension format ["%1,%2,%3,%4", _initSpeed, _airFriction, _angleTarget, _distance]; + _offset = parseNumber _offset; - _FCSMagazines = _FCSMagazines + [_magazineType]; - _FCSElevation = _FCSElevation + [_offset]; -}; + _FCSMagazines = _FCSMagazines + [_x]; + _FCSElevation = _FCSElevation + [_offset]; + }; +} forEach _magazines; _vehicle setVariable [QGVAR(Distance), _distance, true]; _vehicle setVariable [QGVAR(Magazines), _FCSMagazines, true]; _vehicle setVariable [QGVAR(Elevation), _FCSElevation, true]; _vehicle setVariable [QGVAR(Azimuth), _FCSAzimuth, true]; -// CALCULATE OFFSETS FOR OTHER WEAPONS IN THE BACKGROUND -GVAR(backgroundCalculation) = [_vehicle, _magazines, _distance, _angleTarget, _FCSMagazines, _FCSElevation] spawn { - _vehicle = _this select 0; - _magazines = _this select 1; - _distance = _this select 2; - _angleTarget = _this select 3; - _FCSMagazines = _this select 4; - _FCSElevation = _this select 5; - - { - if !(_x in _FCSMagazines) then { - _ammoType = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); - if !(getText (configFile >> "CfgAmmo" >> _ammoType >> "simulation") == "shotMissile") then { - _maxElev = getNumber (configFile >> "CfgVehicles" >> typeOf _vehicle >> "Turrets" >> "MainTurret" >> "maxElev"); - _initSpeed = getNumber (configFile >> "CfgMagazines" >> _x >> "initSpeed"); - _airFriction = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "airFriction"); - _timeToLive = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "timeToLive"); - _simulationStep = getNumber (configFile >> "CfgAmmo" >> _ammoType >> "simulationStep"); - - _offset = [_distance, _angleTarget, _maxElev, _initSpeed, _airFriction, _timeToLive, _simulationStep] call FUNC(getAngle); - - _FCSMagazines = _FCSMagazines + [_x]; - _FCSElevation = _FCSElevation + [_offset]; - }; - }; - } forEach _magazines; - - _vehicle setVariable [QGVAR(Magazines), _FCSMagazines, true]; - _vehicle setVariable [QGVAR(Elevation), _FCSElevation, true]; -}; - [format ["%1: %2", localize "STR_ACE_FCS_ZeroedTo", _distance]] call EFUNC(common,displayTextStructured); diff --git a/extensions/ace_fcs.cpp b/extensions/ace_fcs.cpp new file mode 100644 index 0000000000..0b6788e7d1 --- /dev/null +++ b/extensions/ace_fcs.cpp @@ -0,0 +1,117 @@ +/* + * ace_fcs.cpp + * + * Calculates firing solution. + * + * Takes: + * initSpeed,airFriction,angle,distance as string + * Example: "900,-0.0004,2,1050" + * + * Returns: + * Correction to angle + */ + +#include "stdafx.h" + +#define _USE_MATH_DEFINES + +#include +#include +#include +#include + +#define MAXELEVATION 20 +#define SIMULATIONSTEP 0.05 +#define MAXITERATIONS 120 +#define PRECISION 0.1 +#define RADIANS(X) (X / (180 / M_PI)) + +static char version[] = "1.0"; + +extern "C" { + __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); +}; + +std::vector splitString(std::string input) { + std::istringstream ss(input); + std::string token; + + std::vector output; + while (std::getline(ss, token, ',')) { + output.push_back(token); + } + + return output; +} + +double traceBullet(double initSpeed, double airFriction, double angle, double angleTarget, double distance) { + double velX, velY, posX, posY, posTargetX, posTargetY, velMag; + velX = cos(RADIANS(angle)) * initSpeed; + velY = sin(RADIANS(angle)) * initSpeed; + posX = 0; + posY = 0; + posTargetX = cos(RADIANS(angleTarget)) * distance; + posTargetY = sin(RADIANS(angleTarget)) * distance; + + int i = 0; + while (i < MAXITERATIONS) { + velMag = sqrt(pow(velX, 2) + pow(velY, 2)); + velX += SIMULATIONSTEP * (velX * velMag * airFriction); + velY += SIMULATIONSTEP * (velY * velMag * airFriction - 9.81); + posX += velX * SIMULATIONSTEP; + posY += velY * SIMULATIONSTEP; + if (posX >= posTargetX) { break; } + i++; + } + + return posY - posTargetY; +} + +double getSolution(double initSpeed, double airFriction, double angleTarget, double distance) { + double posTargetX, posTargetY; + posTargetX = cos(RADIANS(angleTarget)) * distance; + posTargetY = sin(RADIANS(angleTarget)) * distance; + + if (traceBullet(initSpeed, airFriction, MAXELEVATION, angleTarget, distance) < 0) { + return MAXELEVATION - angleTarget; + } + + double a1 = angleTarget; + double a2 = MAXELEVATION; + double f1, f2, tmp; + f1 = traceBullet(initSpeed, airFriction, a1, angleTarget, distance); + if (fabs(f1) <= PRECISION) { return 0; } + while (fabs(f1) > PRECISION) { + f2 = traceBullet(initSpeed, airFriction, a2, angleTarget, distance); + tmp = a2 - f2 * (a2 - a1) / (f2 - f1); + a1 = a2; + a2 = tmp; + f1 = f2; + } + + return a2 - angleTarget; +} + +// i like to live dangerously. jk, fix strncpy sometime pls. +#pragma warning( push ) +#pragma warning( disable : 4996 ) + +void __stdcall RVExtension(char *output, int outputSize, const char *function) { + if (!strcmp(function, "version")) { + strncpy(output, version, outputSize); + } else { + std::vector argStrings = splitString(function); + double initSpeed = std::stod(argStrings[0]); + double airFriction = std::stod(argStrings[1]); + double angleTarget = std::stod(argStrings[2]); + double distance = std::stod(argStrings[3]); + + double result = getSolution(initSpeed, airFriction, angleTarget, distance); + std::string resultString = std::to_string(result); + + strcpy(output, resultString.c_str()); + output[outputSize - 1] = '\0'; + } +} + +#pragma warning( pop ) diff --git a/extensions/stdafx.cpp b/extensions/stdafx.cpp new file mode 100644 index 0000000000..e1e622b65d --- /dev/null +++ b/extensions/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ace_fcs.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/extensions/stdafx.h b/extensions/stdafx.h new file mode 100644 index 0000000000..f3a07375c7 --- /dev/null +++ b/extensions/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here