/* Author: Brazilian Armed Forces File: fn_flirControls.sqf Objetivo: - Atualizar indicadores de AZ (direção) e EZ (elevação) do POD FLIR em relação ao corpo da aeronave - Atualizar indicação de Norte geográfico relativa ao centro do apontamento (compasso) Padrão adotado: - Mesmo padrão (carrot/tape): * ler ctrlPosition * calcular posição com BEG/DIS/OFFSET * ctrlSetPosition + ctrlCommit 0 Observação: - Este script assume que: * os controles estão acessíveis via _display displayCtrl * existem constantes BEG/DIS/OFFSET para a régua horizontal (AZ) e vertical (EZ) */ #define IGUI_GROUP 170 #define BRAF_ELEV_ARROW 1901 #define BRAF_ELEV_TXT 1902 #define BRAF_AZ_ARROW 1903 #define BRAF_AZ_TXT 1904 #define BRAF_NORTH_ARROW 1905 #define BRAF_HDG_VALUE 1907 #define BRAF_IAS_VALUE 1909 #define BRAF_GS_VALUE 1911 #define BRAF_RALT_VALUE 1913 #define BRAF_BARO_VALUE 1915 #define BRAF_ROLL_VALUE 1917 #define BRAF_PTCH_VALUE 1919 #define BRAF_MIN_TURN -180 #define BRAF_MAX_TURN 180 #define BRAF_MIN_ELEV -120 #define BRAF_MAX_ELEV 30 #define BRAF_AZ_BEG (0.04 * safeZoneW) #define BRAF_AZ_DIS (0.5375 * safeZoneW) #define BRAF_AZ_NUM_OFFSET (0.5 * safeZoneW) #define BRAF_AZ_TXT_Y_OFFSET (-1 * 0.025 * safeZoneH) #define BRAF_EZ_BEG (0.215 * safeZoneH) #define BRAF_EZ_DIS (0.52 * safeZoneH) #define BRAF_EZ_NUM_OFFSET (0 * safeZoneH) disableSerialization; params ["_display"]; // Segurança: display inválido if (isNull _display) exitWith {}; // Segurança: só atualiza quando estiver em optics if (cameraView != "GUNNER") exitWith {}; // Veículo base (corpo) private _veh = vehicle player; if (isNull _veh) exitWith {}; // CORREÇÃO: Validar que os controles customizados existem antes de acessá-los // Previne crashes se os IDCs não foram criados corretamente na config if (isNull (_display displayCtrl BRAF_ELEV_ARROW)) exitWith { systemChat "[BRAF A-29] ERRO: Controle de seta de elevação (IDC 1901) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_AZ_ARROW)) exitWith { systemChat "[BRAF A-29] ERRO: Controle de seta de azimute (IDC 1903) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_ELEV_TXT)) exitWith { systemChat "[BRAF A-29] ERRO: Controle de texto de elevação (IDC 1902) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_AZ_TXT)) exitWith { systemChat "[BRAF A-29] ERRO: Controle de texto de azimute (IDC 1904) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_NORTH_ARROW)) exitWith { systemChat "[BRAF A-29] ERRO: Controle da bússola norte (IDC 1905) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_HDG_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle HDG (IDC 1907) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_IAS_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle IAS (IDC 1909) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_GS_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle GS (IDC 1911) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_RALT_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle RALT (IDC 1913) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_BARO_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle BARO (IDC 1915) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_ROLL_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle ROLL (IDC 1917) não encontrado!"; }; if (isNull (_display displayCtrl BRAF_PTCH_VALUE)) exitWith { systemChat "[BRAF A-29] ERRO: Controle PTCH (IDC 1919) não encontrado!"; }; // ====================================================================== // 1) Captura da direção REAL da câmera (mundo) e conversão para o corpo // ====================================================================== // Vetor forward real da câmera ativa (mundo) private _p0 = positionCameraToWorld [0, 0, 0]; private _p1 = positionCameraToWorld [0, 0, 1]; private _vW = _p1 vectorDiff _p0; private _lenW = vectorMagnitude _vW; if (_lenW < 0.0001) exitWith {}; _vW = _vW vectorMultiply (1/_lenW); // Direção absoluta (mundo) em RADIANOS para o compasso // atan2 retorna radianos: 0 = norte, π/2 = leste, π ou -π = sul, -π/2 = oeste private _absDir_rad = (_vW select 0) atan2 (_vW select 1); // Normalizar para [0, 2π) para ficar positivo if (_absDir_rad < 0) then { _absDir_rad = _absDir_rad + (2 * pi); }; // Converte vetor para o referencial do veículo (corpo) private _vM = _veh vectorWorldToModel _vW; private _lenM = vectorMagnitude _vM; if (_lenM < 0.0001) exitWith {}; _vM = _vM vectorMultiply (1/_lenM); private _x = _vM select 0; private _y = _vM select 1; private _z = _vM select 2; // AZIMUTH (yaw) relativo ao corpo: [-180..+180] em GRAUS private _azimuth = (_x atan2 _y); if (_azimuth > 180) then { _azimuth = _azimuth - 360; }; if (_azimuth < -180) then { _azimuth = _azimuth + 360; }; // ELEVATION (pitch) relativo ao corpo, permitindo < -90 em GRAUS private _h = sqrt (_x*_x + _y*_y); private _signY = if (_y < 0) then { -1 } else { 1 }; private _yPrime = _h * _signY; private _elevation = (_z atan2 _yPrime); // Clamp nos limites do POD _azimuth = _azimuth max BRAF_MIN_TURN min BRAF_MAX_TURN; // -180..+180 _elevation = _elevation max BRAF_MIN_ELEV min BRAF_MAX_ELEV; // -120..+30 // ====================================================================== // 2) TURRET AZ (Azimute/Direção Horizontal) // ====================================================================== private _turretAZcarrotCtrlPos = ctrlPosition (_display displayCtrl BRAF_AZ_ARROW); private _turretAZtextCtrlPos = ctrlPosition (_display displayCtrl BRAF_AZ_TXT); // X do carrot na régua de -180..+180 // CORREÇÃO: Referências de constantes alteradas para BRAF_AZ_BEG e BRAF_AZ_DIS private _azPosX = BRAF_AZ_BEG + (((_azimuth + 180) / 360) * BRAF_AZ_DIS); // Atualizar posição da seta horizontal (carrot) - IDC 1903 (_display displayCtrl BRAF_AZ_ARROW) ctrlSetPosition [ _azPosX, _turretAZcarrotCtrlPos select 1, _turretAZcarrotCtrlPos select 2, _turretAZcarrotCtrlPos select 3 ]; (_display displayCtrl BRAF_AZ_ARROW) ctrlCommit 0; // Atualizar valor numérico do azimute - IDC 1904 // O texto usa o mesmo centro X da seta e fica acima dela. (_display displayCtrl BRAF_AZ_TXT) ctrlSetText str (round _azimuth); private _azArrowW = _turretAZcarrotCtrlPos select 2; private _azTextW = _turretAZtextCtrlPos select 2; (_display displayCtrl BRAF_AZ_TXT) ctrlSetPosition [ _azPosX + ((_azArrowW - _azTextW) / 2), (_turretAZcarrotCtrlPos select 1) + BRAF_AZ_TXT_Y_OFFSET, _azTextW, _turretAZtextCtrlPos select 3 ]; (_display displayCtrl BRAF_AZ_TXT) ctrlCommit 0; // ====================================================================== // 3) TURRET EZ (Elevação/pitch Vertical) // Régua: +30 (topo) -> -120 (base) // ====================================================================== private _turretEZcarrotCtrlPos = ctrlPosition (_display displayCtrl BRAF_ELEV_ARROW); private _turretEZtextCtrlPos = ctrlPosition (_display displayCtrl BRAF_ELEV_TXT); // tEl: 0 no topo (+30), 1 na base (-120) private _tEl = (BRAF_MAX_ELEV - _elevation) / (BRAF_MAX_ELEV - BRAF_MIN_ELEV); if (_tEl < 0) then { _tEl = 0; }; if (_tEl > 1) then { _tEl = 1; }; // Y da régua // CORREÇÃO: Referências de constantes alteradas para BRAF_EZ_BEG e BRAF_EZ_DIS private _elevPos = BRAF_EZ_BEG + (_tEl * BRAF_EZ_DIS); // Atualizar posição da seta vertical (carrot) - IDC 1901 (_display displayCtrl BRAF_ELEV_ARROW) ctrlSetPosition [ _turretEZcarrotCtrlPos select 0, _elevPos, _turretEZcarrotCtrlPos select 2, _turretEZcarrotCtrlPos select 3 ]; (_display displayCtrl BRAF_ELEV_ARROW) ctrlCommit 0; // Atualizar valor numérico da elevação - IDC 1902 (_display displayCtrl BRAF_ELEV_TXT) ctrlSetText str (round _elevation); (_display displayCtrl BRAF_ELEV_TXT) ctrlSetPosition [ _turretEZtextCtrlPos select 0, _elevPos + BRAF_EZ_NUM_OFFSET, _turretEZtextCtrlPos select 2, _turretEZtextCtrlPos select 3 ]; // CORREÇÃO: Referência de constante alterada para BRAF_EZ_NUM_OFFSET (_display displayCtrl BRAF_ELEV_TXT) ctrlCommit 0; // ====================================================================== // 4) AIRCRAFT DATA - HDG / IAS / GS / RALT / BARO / ROLL / PTCH // ====================================================================== private _hdg = round (getDir _veh); private _ias = round (speed _veh); private _gs = round ((vectorMagnitude (velocity _veh)) * 3.6); private _ralt = round ((getPosATL _veh) select 2); private _baro = round ((getPosASL _veh) select 2); private _pitchBank = _veh call BIS_fnc_getPitchBank; private _ptch = round (_pitchBank select 0); private _roll = round (_pitchBank select 1); private _ctrlHDG = _display displayCtrl BRAF_HDG_VALUE; private _ctrlIAS = _display displayCtrl BRAF_IAS_VALUE; private _ctrlGS = _display displayCtrl BRAF_GS_VALUE; private _ctrlRALT = _display displayCtrl BRAF_RALT_VALUE; private _ctrlBARO = _display displayCtrl BRAF_BARO_VALUE; private _ctrlROLL = _display displayCtrl BRAF_ROLL_VALUE; private _ctrlPTCH = _display displayCtrl BRAF_PTCH_VALUE; if (!isNull _ctrlHDG) then { _ctrlHDG ctrlSetText format ["%1", _hdg]; }; if (!isNull _ctrlIAS) then { _ctrlIAS ctrlSetText format ["%1", _ias]; }; if (!isNull _ctrlGS) then { _ctrlGS ctrlSetText format ["%1", _gs]; }; if (!isNull _ctrlRALT) then { _ctrlRALT ctrlSetText format ["%1", _ralt]; }; if (!isNull _ctrlBARO) then { _ctrlBARO ctrlSetText format ["%1", _baro]; }; if (!isNull _ctrlROLL) then { _ctrlROLL ctrlSetText format ["%1", _roll]; }; if (!isNull _ctrlPTCH) then { _ctrlPTCH ctrlSetText format ["%1", _ptch]; }; // ====================================================================== // 5) COMPASS N (Bússola Norte Geográfico) // ====================================================================== // CORREÇÃO: Referência de IDC alterada: // COMPASS_N_ARROW → BRAF_NORTH_ARROW (IDC 1905) // Motivo: Alinhar com nomenclatura definida em braf_constants.h // // A fórmula: rotação_seta = -_absDir_rad // Isso faz a seta apontar para o NORTE true em relação ao que a câmera vê: // - Se câmera aponta NORTE: -0° → seta aponta PARA CIMA (norte) // - Se câmera aponta LESTE: -π/2 → seta aponta PARA A ESQUERDA (norte relativo) // - Se câmera aponta SUL: -π → seta aponta PARA BAIXO (norte relativo) // - Se câmera aponta OESTE: -(-π/2) = +π/2 → seta aponta PARA A DIREITA (norte relativo) (_display displayCtrl BRAF_NORTH_ARROW) ctrlSetAngle [ -_absDir_rad, 0.5, 0.5 ];